123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170(******************************************************************************)(* OASIS: architecture for building OCaml libraries and applications *)(* *)(* Copyright (C) 2011-2016, Sylvain Le Gall *)(* Copyright (C) 2008-2011, OCamlCore SARL *)(* *)(* This library is free software; you can redistribute it and/or modify it *)(* under the terms of the GNU Lesser General Public License as published by *)(* the Free Software Foundation; either version 2.1 of the License, or (at *)(* your option) any later version, with the OCaml static compilation *)(* exception. *)(* *)(* This library is distributed in the hope that it will be useful, but *)(* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *)(* or FITNESS FOR A PARTICULAR PURPOSE. See the file COPYING for more *)(* details. *)(* *)(* You should have received a copy of the GNU Lesser General Public License *)(* along with this library; if not, write to the Free Software Foundation, *)(* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *)(******************************************************************************)typevertex=intmoduleSetInt=Set.Make(structtypet=intletcompare=(-)end)type'at={mutablevertexes:('a*SetInt.tref)array;values:('a,int)Hashtbl.t;}letcreatelen={vertexes=[||];values=Hashtbl.createlen;}letcopyt={vertexes=Array.copyt.vertexes;values=Hashtbl.copyt.values;}letvalue_of_vertextv=if0<=v&&v<Array.lengtht.vertexesthenfst(Array.unsafe_gett.vertexesv)elseinvalid_arg"get_vertex"letvertex_of_valuete=Hashtbl.findt.valueseletadd_vertexte=ifHashtbl.memt.valuesethenHashtbl.findt.valueseelsebeginletv=Array.lengtht.vertexesinletnvertexes=Array.init(v+1)(funi->ifi=vthene,refSetInt.emptyelset.vertexes.(i))int.vertexes<-nvertexes;Hashtbl.addt.valuesev;vendletadd_edgetv1v2=letsize=Array.lengtht.vertexesinif0<=v1&&v1<size&&0<=v2&&v2<sizethenbeginlet_,edges=t.vertexes.(v1)inedges:=SetInt.addv2!edgesendelseinvalid_arg"add_edge"lettopological_sortt=letsize=Array.lengtht.vertexesin(* Empty list that will contain the sorted vertexes *)letl=ref[]in(* Visited vertexes *)letvisited=Array.makesizefalseinletreverted_edges=letarr=Array.makesize[]inforv1=0tosize-1doSetInt.iter(funv2->arr.(v2)<-v1::arr.(v2))!(sndt.vertexes.(v1))done;arrinletrecvisitv=ifnotvisited.(v)thenbeginvisited.(v)<-true;List.itervisitreverted_edges.(v);l:=v::!lendin(* Go through all vertexes with no outgoing edges *)forv=0tosize-1dovisitvdone;!lletfold_edgesftacc=letracc=refaccinforv1=0toArray.lengtht.vertexes-1doSetInt.iter(funv2->racc:=fv1v2!racc)!(sndt.vertexes.(v1))done;!racclettransitive_closuret=letsize=Array.lengtht.vertexesinletvisited=Array.makesizefalseinletrecvisitsetv=ifnotvisited.(v)thenbeginlet()=visited.(v)<-truein(* The set of outgoing edges is not complete *)letcurrent_set=sndt.vertexes.(v)inletset'=SetInt.fold(funvset'->visitset'v)!current_set!current_setincurrent_set:=set';SetInt.unionsetset'endelsebegin(* The set is complete *)SetInt.unionset!(sndt.vertexes.(v))endinforv=0tosize-1dolet_set:SetInt.t=visitSetInt.emptyvin()done