Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file path.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382(**************************************************************************)(* *)(* Ocamlgraph: a generic graph library for OCaml *)(* Copyright (C) 2004-2010 *)(* Sylvain Conchon, Jean-Christophe Filliatre and Julien Signoles *)(* *)(* This software is free software; you can redistribute it and/or *)(* modify it under the terms of the GNU Library General Public *)(* License version 2.1, with the special exception on linking *)(* described in file LICENSE. *)(* *)(* This software 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. *)(* *)(**************************************************************************)(* $Id: path.ml,v 1.6 2005-07-18 07:10:35 filliatr Exp $ *)moduletypeG=sigtypetmoduleV:Sig.COMPARABLEmoduleE:sigtypettypelabelvallabel:t->labelvalsrc:t->V.tvaldst:t->V.tvalcreate:V.t->label->V.t->tendvaliter_vertex:(V.t->unit)->t->unitvalfold_vertex:(V.t->'a->'a)->t->'a->'avaliter_succ:(V.t->unit)->t->V.t->unitvaliter_succ_e:(E.t->unit)->t->V.t->unitvalfold_edges_e:(E.t->'a->'a)->t->'a->'avalnb_vertex:t->intend(** Weight signature for Johnson's algorithm. *)moduletypeWJ=sigincludeSig.WEIGHTvalsub:t->t->t(** Subtraction of weights. *)endmoduleDijkstra(G:G)(W:Sig.WEIGHTwithtypeedge=G.E.t)=structopenG.EmoduleH=Hashtbl.Make(G.V)moduleElt=structtypet=W.t*G.V.t*G.E.tlist(* weights are compared first, and minimal weights come first in the
queue *)letcompare(w1,v1,_)(w2,v2,_)=letcw=W.comparew2w1inifcw!=0thencwelseG.V.comparev1v2endmodulePQ=Heap.Imperative(Elt)letshortest_pathgv1v2=letvisited=H.create97inletdist=H.create97inletq=PQ.create17inletrecloop()=ifPQ.is_emptyqthenraiseNot_found;let(w,v,p)=PQ.pop_maximumqinifG.V.comparevv2=0thenList.revp,welsebeginifnot(H.memvisitedv)thenbeginH.addvisitedv();G.iter_succ_e(fune->letev=dsteinifnot(H.memvisitedev)thenbeginletdev=W.addw(W.weighte)inletimprovement=tryW.comparedev(H.finddistev)<0withNot_found->trueinifimprovementthenbeginH.replacedistevdev;PQ.addq(dev,ev,e::p)endend)gvend;loop()endinPQ.addq(W.zero,v1,[]);H.adddistv1W.zero;loop()end(* The following module is a contribution of Yuto Takei (University of Tokyo) *)moduleBellmanFord(G:G)(W:Sig.WEIGHTwithtypeedge=G.E.t)=structopenG.EmoduleH=Hashtbl.Make(G.V)exceptionNegativeCycleofG.E.tlistletall_shortest_pathsgvs=letdist=H.create97inH.adddistvsW.zero;letadmissible=H.create97inletbuild_cycle_fromx0=letrectraverse_parentxret=lete=H.findadmissiblexinlets=srceinifG.V.equalsx0thene::retelsetraverse_parents(e::ret)intraverse_parentx0[]inletfind_cyclex0=letvisited=H.create97inletrecvisitx=ifH.memvisitedxthenbuild_cycle_fromxelsebeginH.addvisitedx();lete=H.findadmissiblexinvisit(srce)endinvisitx0inletrecrelaxi=letupdate=G.fold_edges_e(funex->letev1=srceinletev2=dsteintrybeginletdev1=H.finddistev1inletdev2=W.adddev1(W.weighte)inletimprovement=tryW.comparedev2(H.finddistev2)<0withNot_found->trueinifimprovementthenbeginH.replacedistev2dev2;H.replaceadmissibleev2e;Someev2endelsexendwithNot_found->x)gNoneinmatchupdatewith|Somex->ifi==G.nb_vertexgthenraise(NegativeCycle(find_cyclex))elserelax(i+1)|None->distinrelax0letfind_negative_cycle_fromgvs=trylet_=all_shortest_pathsgvsinraiseNot_foundwithNegativeCyclel->lmoduleComp=Components.Make(G)(* This is rather inefficient implementation. Indeed, for each
strongly connected component, we run a full Bellman-Ford
algorithm using one of its vertex as source, taking all edges
into consideration. Instead, we could limit ourselves to the
edges of the component. *)letfind_negative_cycleg=letreciter=function|[]->raiseNot_found|(x::_)::cl->begintryfind_negative_cycle_fromgxwithNot_found->iterclend|[]::_->assertfalse(* a component is not empty *)initer(Comp.scc_listg)endmoduleJohnson(G:G)(W:WJwithtypeedge=G.E.t)=structmoduleHVV=Hashtbl.Make(Util.HTProduct(G.V)(G.V))moduleG'=structtypet=G.tmoduleV=structtypet=New|OldofG.V.tletcomparevu=matchv,uwith|New,New->0|New,Old_->-1|Old_,New->1|Oldv,Oldu->G.V.comparevulethashv=matchvwith|Oldv->G.V.hashv|New->42letequalvu=matchv,uwith|New,New->true|New,Old_|Old_,New->false|Oldv,Oldu->G.V.equalvuendmoduleE=structtypelabel=G.E.labeltypet=NewEofV.t|OldEofG.E.tletsrce=matchewith|NewE_->V.New|OldEe->V.Old(G.E.srce)letdste=matchewith|NewEv->v|OldEe->V.Old(G.E.dste)letlabele=matchewith|NewE_->assertfalse|OldEe->G.E.labeleletcreatevlu=matchv,uwith|V.New,V.Oldu->NewE(V.Oldu)|V.Oldv,V.Oldu->OldE(G.E.createvlu)|_,_->assertfalseendletiter_vertexfg=fV.New;G.iter_vertex(funv->f(V.Oldv))gletfold_vertexfgacc=letacc'=fV.NewaccinG.fold_vertex(funva->f(V.Oldv)a)gacc'letiter_succfgv=matchvwith|V.New->G.iter_vertex(funu->f(V.Oldu))g|V.Oldv->G.iter_succ(funu->f(V.Oldu))gvletiter_succ_efgv=matchvwith|V.New->G.iter_vertex(funu->f(E.NewE(V.Oldu)))g|V.Oldv->G.iter_succ_e(fune->f(E.OldEe))gvletfold_edges_efgacc=letacc'=G.fold_vertex(funx_->f(E.NewE(V.Oldx))acc)gaccinG.fold_edges_e(funedg->letv1=G.E.srcedginletv2=G.E.dstedginletl=G.E.labeledginf(E.create(V.Oldv1)l(V.Oldv2)))gacc'letnb_vertexg=G.nb_vertexg+1endmoduleW'=structopenG'.Etypeedge=G'.E.ttypet=W.tletzero=W.zeroletweighte=matchewith|NewE_->zero|OldEe->W.weighteletcompare=W.compareletadd=W.addendmoduleBF=BellmanFord(G')(W')letall_pairs_shortest_pathsg=letpairs_dist=HVV.create97inletbf_res=BF.all_shortest_pathsgG'.V.NewinletmoduleW''=structtypeedge=W.edgetypet=W.tletadd=W.addletsub=W.subletweighte=letv1=G.E.srceinletv2=G.E.dsteinadd(W.weighte)(W.sub(BF.H.findbf_res(G'.V.Oldv1))(BF.H.findbf_res(G'.V.Oldv2)))letcompare=W.compareletzero=W.zeroendinletmoduleD=Dijkstra(G)(W'')inG.iter_vertex(funv->G.iter_vertex(funu->trylet(_,d)=D.shortest_pathgvuinHVV.addpairs_dist(v,u)(W''.addd(W''.sub(BF.H.findbf_res(G'.V.Oldu))(BF.H.findbf_res(G'.V.Oldv))))withNot_found->())g)g;pairs_distendmoduleCheck(G:sigtypetmoduleV:Sig.COMPARABLEvaliter_succ:(V.t->unit)->t->V.t->unitend)=structmoduleHV=Hashtbl.Make(G.V)moduleHVV=Hashtbl.Make(Util.HTProduct(G.V)(G.V))(* the cache contains the path tests already computed *)typepath_checker={cache:boolHVV.t;graph:G.t}letcreateg={cache=HVV.create97;graph=g}letcheck_pathpcv1v2=tryHVV.findpc.cache(v1,v2)withNot_found->(* the path is not in cache; we check it with a BFS *)letvisited=HV.create97inletq=Queue.create()in(* [visited] contains exactly the vertices that have been added to [q] *)letpushv=ifnot(HV.memvisitedv)then(HV.addvisitedv();Queue.addvq)inletrecloop()=ifQueue.is_emptyqthenbeginHVV.addpc.cache(v1,v2)false;falseendelsebeginletv=Queue.popqinHVV.addpc.cache(v1,v)true;G.V.comparevv2=0||matchHVV.find_optpc.cache(v,v2)with|Sometrue->HVV.addpc.cache(v1,v2)true;true|_->G.iter_succpushpc.graphv;loop()endinpushv1;loop()end(** 0-1 BFS
When edge weights are limited to 0 or 1, this is more efficient than
running Dijkstra's algorithm. *)moduleBfs01(G:sigtypetmoduleV:Sig.COMPARABLEmoduleE:sigtypetvaldst:t->V.tendvaliter_succ_e:(E.t->unit)->t->V.t->unitend)=structmoduleH=Hashtbl.Make(G.V)letiterfg~zeros=letvisited=H.create16inletd=Deque.create()inDeque.push_frontd(s,0);H.addvisiteds();whileDeque.lengthd>0doletv,n=Deque.pop_frontdinfvn;G.iter_succ_e(fune->letw=G.E.dsteinifnot(H.memvisitedw)then(H.addvisitedw();ifzeroethenDeque.push_frontd(w,n)elseDeque.push_backd(w,n+1)))gvdoneend