···330330331331end
332332333333+module type G = sig
334334+ type t
335335+ module V : Sig.COMPARABLE
336336+ val nb_vertex : t -> int
337337+ val iter_vertex : (V.t -> unit) -> t -> unit
338338+ val iter_succ : (V.t -> unit) -> t -> V.t -> unit
339339+ val fold_succ : (V.t -> 'a -> 'a) -> t -> V.t -> 'a -> 'a
340340+end
341341+342342+343343+module Johnson (G: G) : sig
344344+345345+ val iter_cycles : (G.V.t list -> unit) -> G.t -> unit
346346+347347+ val fold_cycles : (G.V.t list -> 'a -> 'a) -> G.t -> 'a -> 'a
348348+349349+end = struct
350350+351351+ module VMap = struct
352352+ module VH = Hashtbl.Make(G.V)
353353+354354+ let create = VH.create
355355+ let find = VH.find
356356+ let add = VH.add
357357+ let iter = VH.iter
358358+ end
359359+360360+ (* The algorithm visits each vertex.
361361+ For each vertex, it does a depth-first search to find all paths back to
362362+ the same vertex. *)
363363+364364+ type vinfo = {
365365+ (* records whether the vertex has been visited *)
366366+ mutable visited : bool;
367367+368368+ (* [blocked] and [blist are used to avoid uselessly iterating over a
369369+ subgraph from which a cycle can (no longer) be found. *)
370370+ mutable blocked : bool;
371371+ mutable blist : G.V.t list;
372372+ }
373373+374374+ (* map each vertex to the information above *)
375375+ let find tbl key =
376376+ try
377377+ VMap.find tbl key
378378+ with Not_found ->
379379+ let info = { visited = false; blocked = false; blist = [] } in
380380+ VMap.add tbl key info;
381381+ info
382382+383383+ let iter_cycles f_cycle g =
384384+ let info = VMap.create (G.nb_vertex g) in
385385+386386+ (* recursively unblock a subgraph *)
387387+ let rec unblock vi =
388388+ if vi.blocked then begin
389389+ vi.blocked <- false;
390390+ List.iter (fun w -> unblock (find info w)) vi.blist;
391391+ vi.blist <- [];
392392+ end
393393+ in
394394+395395+ let cycles_from_vertex s =
396396+397397+ let rec circuit path v vi =
398398+399399+ let check_succ w cycle_found =
400400+ if G.V.equal w s (* a cycle is found *)
401401+ then (f_cycle path; true)
402402+ else (* keep looking *)
403403+ let wi = find info w in
404404+ if not (wi.blocked || wi.visited) then circuit (w::path) w wi
405405+ else cycle_found
406406+ in
407407+408408+ (* v should be unblocked if any of its successors are, since a cycle
409409+ from v may be found via a newly unblocked successor. *)
410410+ let unblock_on w =
411411+ let wi = find info w in
412412+ wi.blist <- v :: wi.blist
413413+ in
414414+415415+ (* not (yet) interested in cycles back to v that do not pass via s *)
416416+ vi.blocked <- true;
417417+ if G.fold_succ check_succ g v false (* DFS on successors *)
418418+ (* if we found a cycle through v then unblock it *)
419419+ then (unblock vi; true)
420420+ (* otherwise there's no reason to try again unless something changes *)
421421+ else (G.iter_succ unblock_on g v; false)
422422+ in
423423+424424+ VMap.iter (fun _ info ->
425425+ info.blocked <- false;
426426+ info.blist <- []) info;
427427+ let si = find info s in
428428+ (* look for elementary cycles back to s *)
429429+ ignore (circuit [s] s si);
430430+ si.visited <- true
431431+ in
432432+ G.iter_vertex cycles_from_vertex g
433433+434434+ let fold_cycles f g i =
435435+ let acc = ref i in
436436+ iter_cycles (fun cycle -> acc := f cycle !acc) g;
437437+ !acc
438438+439439+end
440440+
+33
src/cycles.mli
···6969 val feedback_arc_set : GB.G.t -> GB.G.edge list
7070end
71717272+(** Minimal graph signature required by {!Johnson}.
7373+ Sub-signature of {!Sig.G}. *)
7474+module type G = sig
7575+ type t
7676+ module V : Sig.COMPARABLE
7777+ val nb_vertex : t -> int
7878+ val iter_vertex : (V.t -> unit) -> t -> unit
7979+ val iter_succ : (V.t -> unit) -> t -> V.t -> unit
8080+ val fold_succ : (V.t -> 'a -> 'a) -> t -> V.t -> 'a -> 'a
8181+end
8282+8383+(** Implementation of Johnson's 1975 algoirthm for "Finding all the Elementary
8484+ Cycles of a Directed Graph". It does not do any preprocessing, i.e., no
8585+ removal of self-loops and no dissection into strongly connected
8686+ components.
8787+8888+ Be aware that a graph with n verticies may contain an exponential number
8989+ of elementary cycles. *)
9090+module Johnson (G: G) : sig
9191+9292+ (** Calls the callback function for every elemental cycle in the given
9393+ graph. The argument is the list of vertexes in the cycle in {b reverse
9494+ order} with no duplicates. For each generated list of vertexes
9595+ [v0; ...; vi; vj; ...; vn], there exist edges for all [vj] to [vi],
9696+ and also from [v0] back to [vn]. Use {!Sig.G.find_edge} to recover
9797+ the edges. *)
9898+ val iter_cycles : (G.V.t list -> unit) -> G.t -> unit
9999+100100+ (** A functional interface to [iter_cycles]. *)
101101+ val fold_cycles : (G.V.t list -> 'a -> 'a) -> G.t -> 'a -> 'a
102102+103103+end
104104+