123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353(******************************************************************************)(* *)(* Menhir *)(* *)(* Copyright Inria. All rights reserved. This file is distributed under *)(* the terms of the GNU General Public License version 2, as described in *)(* the file LICENSE. *)(* *)(******************************************************************************)(* This module provides an implementation of Tarjan's algorithm for
finding the strongly connected components of a graph.
The algorithm runs when the functor is applied. Its complexity is
$O(V+E)$, where $V$ is the number of vertices in the graph $G$, and
$E$ is the number of edges. *)moduleRun(G:sigtypenode(* We assume each node has a unique index. Indices must range from
$0$ to $n-1$, where $n$ is the number of nodes in the graph. *)valn:intvalindex:node->int(* Iterating over a node's immediate successors. *)valsuccessors:(node->unit)->node->unit(* Iterating over all nodes. *)valiter:(node->unit)->unitend)=struct(* Define the internal data structure associated with each node. *)typedata={(* Each node carries a flag which tells whether it appears
within the SCC stack (which is defined below). *)mutablestacked:bool;(* Each node carries a number. Numbers represent the order in
which nodes were discovered. *)mutablenumber:int;(* Each node [x] records the lowest number associated to a node
already detected within [x]'s SCC. *)mutablelow:int;(* Each node carries a pointer to a representative element of
its SCC. This field is used by the algorithm to store its
results. *)mutablerepresentative:G.node;(* Each representative node carries a list of the nodes in
its SCC. This field is used by the algorithm to store its
results. *)mutablescc:G.nodelist}(* Define a mapping from external nodes to internal ones. Here, we
simply use each node's index as an entry into a global array. *)lettable=(* Create the array. We initially fill it with [None], of type
[data option], because we have no meaningful initial value of
type [data] at hand. *)lettable=Array.makeG.nNonein(* Initialize the array. *)G.iter(funx->table.(G.indexx)<-Some{stacked=false;number=0;low=0;representative=x;scc=[]});(* Define a function which gives easy access to the array. It maps
each node to its associated piece of internal data. *)functionx->matchtable.(G.indexx)with|Somedx->dx|None->assertfalse(* Indices do not cover the range $0\ldots n$, as expected. *)(* Create an empty stack, used to record all nodes which belong to
the current SCC. *)letscc_stack=Stack.create()(* Initialize a function which allocates numbers for (internal)
nodes. A new number is assigned to each node the first time it is
visited. Numbers returned by this function start at 1 and
increase. Initially, all nodes have number 0, so they are
considered unvisited. *)letmark=letcounter=ref0infundx->incrcounter;dx.number<-!counter;dx.low<-!counter(* This reference will hold a list of all representative nodes.
The components that have been identified last appear at the
head of the list. *)letrepresentatives=ref[](* Look at all nodes of the graph, one after the other. Any
unvisited nodes become roots of the search forest. *)let()=G.iter(funroot->letdroot=tablerootinifdroot.number=0thenbegin(* This node hasn't been visited yet. Start a depth-first walk
from it. *)markdroot;droot.stacked<-true;Stack.pushdrootscc_stack;letrecwalkx=letdx=tablexinG.successors(funy->letdy=tableyinifdy.number=0thenbegin(* $y$ hasn't been visited yet, so $(x,y)$ is a regular
edge, part of the search forest. *)markdy;dy.stacked<-true;Stack.pushdyscc_stack;(* Continue walking, depth-first. *)walky;ifdy.low<dx.lowthendx.low<-dy.lowendelseif(dy.low<dx.low)&&dy.stackedthenbegin(* The first condition above indicates that $y$ has been
visited before $x$, so $(x, y)$ is a backwards or
transverse edge. The second condition indicates that
$y$ is inside the same SCC as $x$; indeed, if it
belongs to another SCC, then the latter has already
been identified and moved out of [scc_stack]. *)ifdy.number<dx.lowthendx.low<-dy.numberend)x;(* We are done visiting $x$'s neighbors. *)ifdx.low=dx.numberthenbegin(* $x$ is the entry point of a SCC. The whole SCC is now
available; move it out of the stack. We pop elements out
of the SCC stack until $x$ itself is found. *)letrecloop()=letelement=Stack.popscc_stackinelement.stacked<-false;dx.scc<-element.representative::dx.scc;element.representative<-x;ifelement!=dxthenloop()inloop();representatives:=x::!representativesendinwalkrootend)(* There only remains to make our results accessible to the outside. *)letrepresentativex=(tablex).representativeletsccx=(tablex).sccletrepresentatives=Array.of_list!representatives(* The array [representatives] contains a representative for each component.
The components that have been identified last appear first in this array.
A component is identified only after its successors have been identified;
therefore, this array is naturally in topological order. *)letyieldactionx=letdata=tablexinassert(data.representative==x);(* a sanity check *)assert(data.scc<>[]);(* a sanity check *)actionxdata.sccletiteraction=Array.iter(yieldaction)representativesletrev_topological_iteraction=fori=Array.lengthrepresentatives-1downto0doyieldactionrepresentatives.(i)doneletmapaction=Array.map(yieldaction)representatives|>Array.to_listletrev_mapaction=letaccu=ref[]inrev_topological_iter(funreprlabels->accu:=actionreprlabels::!accu);!accuendopenFix.IndexingmoduletypeSCC=sigtypenodetypenvaln:ncardinalvalrepresentatives:(n,nodeindex)vectorvalnodes:(n,nodeUtils.IndexSet.t)vectorvalcomponent:(node,nindex)vectorendmoduleIndexedSCC(G:sigincludeCARDINALvalsuccessors:(nindex->unit)->nindex->unitend)=structmoduleSCC=Run(structtypenode=G.nindexletn=cardinalG.nletindexn=(n:_index:>int)letsuccessors=G.successorsletiterf=Index.iterG.nfend)moduleRepr=Vector.Of_array(structtypea=G.nindexletarray=SCC.representativesend)typenode=G.ntypen=Repr.nletn=Vector.lengthRepr.vectorletrepresentatives=Repr.vectorletnodes=Vector.map(funnode->Utils.IndexSet.of_list(SCC.sccnode))representativesletcomponent=Vector.make'G.n(fun()->Index.of_intn0)let()=Vector.iteri(funsccnodes'->Utils.IndexSet.iter(funnode->Vector.setcomponentnodescc)nodes')nodesendopenUtilsopenMisctype'nscc=(moduleSCCwithtypenode='n)letindexed_scc(typen)(n:ncardinal)~succ:nscc=letmoduleScc=IndexedSCC(structtypenonrecn=nletn=nletsuccessors=succend)in(moduleScc)letindexset_bind:'aindexset->('aindex->'bindexset)->'bindexset=funsf->IndexSet.fold_right(funacclr1->IndexSet.union(flr1)acc)IndexSet.emptysletclose_forward(typean)((moduleScc):nscc)~(succ:(nindex->unit)->nindex->unit)(rel:(n,aindexset)vector)=Vector.rev_iteribeginfun_sccnodes->letsccs=refIndexSet.emptyinIndexSet.rev_iterbeginfuni->succ(funj->sccs:=IndexSet.addScc.component.:(j)!sccs)iendnodes;letsccs=!sccsinletset=indexset_bindsccs(funscc->rel.:(Scc.representatives.:(scc)))inletset=IndexSet.union(indexset_bindnodes(Vector.getrel))setinIndexSet.iter(funi->rel.:(i)<-set)nodesendScc.nodesletclose_backward(typean)((moduleScc):nscc)~(pred:(nindex->unit)->nindex->unit)(rel:(n,aindexset)vector)=Vector.iteribeginfun_sccnodes->letsccs=refIndexSet.emptyinIndexSet.rev_iterbeginfuni->pred(funj->sccs:=IndexSet.addScc.component.:(j)!sccs)iendnodes;letsccs=!sccsinletset=indexset_bindsccs(funscc->rel.:(Scc.representatives.:(scc)))inletset=IndexSet.union(indexset_bindnodes(Vector.getrel))setinIndexSet.iter(funi->rel.:(i)<-set)nodesendScc.nodesletclose_relation(typena)(succ:(nindex->unit)->nindex->unit)(rel:(n,aindexset)vector)=close_forward(indexed_scc(Vector.lengthrel)~succ)~succrel