{-# LANGUAGE CPP #-}moduleData.Graph.SCC(scc,sccList,sccListR,sccGraph,stronglyConnComp,stronglyConnCompR)where#ifdef USE_MAPSimportData.Graph.MapSCC#elseimportData.Graph.ArraySCC#endifimportData.Graph(SCC(..),Graph,Vertex,graphFromEdges')importData.ArrayasAimportData.List(nub)-- | Compute the list of strongly connected components of a graph.-- The components are topologically sorted:-- if v1 in C1 points to v2 in C2, then C2 will come before C1 in the list.sccList::Graph->[SCCVertex]sccListg=reverse$map(to_sccglkp)cswhere(cs,lkp)=sccg-- | Compute the list of strongly connected components of a graph.-- Each component contains the adjecency information from the original graph.-- The components are topologically sorted:-- if v1 in C1 points to v2 in C2, then C2 will come before C1 in the list.sccListR::Graph->[SCC(Vertex,[Vertex])]sccListRg=reverse$mapcvtcswhere(cs,lkp)=sccgcvt(n,[v])=letadj=g!vinifn`elem`maplkpadjthenCyclicSCC[(v,adj)]elseAcyclicSCC(v,adj)cvt(_,vs)=CyclicSCC[(v,g!v)|v<-vs]-- | Quotient a graph with the relation that relates vertices that-- belong to the same SCC. The vertices in the new graph are the-- SCCs of the old graph, and there is an edge between two components,-- if there is an edge between any of their vertices.-- The entries in the resulting list are in reversed-topologically sorted:-- if v1 in C1 points to v2 in C2, then C1 will come before C2 in the list.sccGraph::Graph->[(SCCInt,Int,[Int])]sccGraphg=mapto_nodecswhere(cs,lkp)=sccgto_nodex@(n,this)=(to_sccglkpx,n,nub$concatMap(maplkp.(g!))this)stronglyConnComp::Ordkey=>[(node,key,[key])]->[SCCnode]stronglyConnCompes=reverse$mapcvtcswhere(g,back)=graphFromEdges'es(cs,lkp)=sccgcvt(n,[v])=let(node,_,_)=backvinifn`elem`maplkp(g!v)thenCyclicSCC[node]elseAcyclicSCCnodecvt(_,vs)=CyclicSCC[node|(node,_,_)<-mapbackvs]stronglyConnCompR::Ordkey=>[(node,key,[key])]->[SCC(node,key,[key])]stronglyConnCompRes=reverse$mapcvtcswhere(g,back)=graphFromEdges'es(cs,lkp)=sccgcvt(n,[v])=ifn`elem`maplkp(g!v)thenCyclicSCC[backv]elseAcyclicSCC(backv)cvt(_,vs)=CyclicSCC(mapbackvs)--------------------------------------------------------------------------------to_scc::Graph->(Vertex->Int)->(Int,[Vertex])->SCCVertexto_sccglkp(n,[v])=ifn`elem`maplkp(g!v)thenCyclicSCC[v]elseAcyclicSCCvto_scc__(_,vs)=CyclicSCCvs