123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234(******************************************************************************)(* *)(* Fix *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright Inria. All rights reserved. This file is distributed under the *)(* terms of the GNU Library General Public License version 2, with a *)(* special exception on linking, as described in the file LICENSE. *)(* *)(******************************************************************************)moduleRun(G:sig(**The type of vertices, or nodes. *)typenode(**[n] is the number of nodes in the graph. *)valn:int(**Each node must have a unique integer index. These indices must range
from 0 (included) to [n] (excluded). The function [index] maps a node
to its integer index. *)valindex:node->int(**[iter] enumerates all nodes in the graph. That is, [iter yield]
applies the function [yield] to every node in the graph. *)valiter:(node->unit)->unit(**[successors] enumerates the immediate successors of a node. That is, if
[v] is a node then [successors yield v] applies the function [yield] to
every node [w] such that there exists an edge from [v] to [w]. *)valsuccessors:(node->unit)->node->unitend)=struct(* Define the internal data structure associated with each node. *)typedata={mutablestacked:bool;(**Each node carries a flag which tells whether it appears
within the SCC stack (which is defined below). *)mutablenumber:int;(**Each node carries a number. Numbers represent the order in
which nodes were discovered. *)mutablelow:int;(**Each node [x] records the lowest number associated to a node
already detected within [x]'s SCC. *)mutablerepresentative:G.node;(**Each node carries a pointer to a representative element of
its SCC. This field is used by the algorithm to store its
results. *)mutablescc:G.nodelist(**Each representative node carries a list of the nodes in
its SCC. This field is used by the algorithm to store its
results. *)}(* 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:G.node->data=(* 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)withSomedx->dx|None->assertfalse(* Create an empty stack, used to record all nodes which belong to
the current SCC. *)letscc_stack:dataStack.t=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.
The numbers returned by this function start at 1 and increase.
Initially, all nodes have number 0, so they are considered
unvisited. *)letmark:data->unit=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:G.nodelistref=ref[](* [walk] performs the depth-first search traversal
that forms the heart of the algorithm. *)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::!representativesend(* Enumerate all nodes of the graph. At every unvisited node, start
a depth-first traversal. *)let()=G.iter@@funroot->letdroot=tablerootinifdroot.number=0thenbegin(* This node has not been visited yet. *)markdroot;droot.stacked<-true;Stack.pushdrootscc_stack;walkrootend(* 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. *)let[@inline]processyieldx=letdata=tablexinassert(data.representative==x);(* a sanity check *)assert(data.scc<>[]);(* a sanity check *)yieldxdata.sccletiteryield=Array.iter(processyield)representativesletrev_topological_iteryield=fori=Array.lengthrepresentatives-1downto0doprocessyieldrepresentatives.(i)doneletmapyield=Array.map(processyield)representatives|>Array.to_listletrev_mapyield=letaccu=ref[]inrev_topological_iter(funreprlabels->accu:=yieldreprlabels::!accu);!accuend