···1122+33+ - :exclamation: [Traverse]: fixed [Dfs.fold] and [Dfs.fold_component],
44+ which were not implementing a proper DFS
25 - [Classic]: new functions [cycle] and [grid]
36 - [Eulerian]: Eulerian paths (new module)
47 - [Components]: strong articulation points (see functors [Connectivity]
+19-18
src/traverse.ml
···3131module Dfs(G : G) = struct
3232 module H = Hashtbl.Make(G.V)
33333434- let fold f i g =
3434+ let fold f acc g =
3535 let h = H.create 97 in
3636 let s = Stack.create () in
3737- let push v =
3838- if not (H.mem h v) then begin H.add h v (); Stack.push v s end
3939- in
4037 let rec loop acc =
4138 if not (Stack.is_empty s) then
4239 let v = Stack.pop s in
4343- let ns = f v acc in
4444- G.iter_succ push g v;
4545- loop ns
4040+ if not (H.mem h v) then begin
4141+ H.add h v ();
4242+ let acc = f v acc in
4343+ G.iter_succ (fun w -> Stack.push w s) g v;
4444+ loop acc
4545+ end else
4646+ loop acc
4647 else
4748 acc
4849 in
4949- G.fold_vertex (fun v s -> push v; loop s) g i
5050+ G.fold_vertex (fun v acc -> Stack.push v s; loop acc) g acc
50515152 let iter ?(pre=fun _ -> ()) ?(post=fun _ -> ()) g =
5253 let h = H.create 97 in
···62636364 let postfix post g = iter ~post g
64656565- let fold_component f i g v0 =
6666+ let fold_component f acc g v0 =
6667 let h = H.create 97 in
6768 let s = Stack.create () in
6868- (* invariant: [h] contains exactly the vertices which have been pushed *)
6969- let push v =
7070- if not (H.mem h v) then begin H.add h v (); Stack.push v s end
7171- in
7272- push v0;
6969+ Stack.push v0 s;
7370 let rec loop acc =
7471 if not (Stack.is_empty s) then
7572 let v = Stack.pop s in
7676- let ns = f v acc in
7777- G.iter_succ push g v;
7878- loop ns
7373+ if not (H.mem h v) then begin
7474+ H.add h v ();
7575+ let acc = f v acc in
7676+ G.iter_succ (fun w -> Stack.push w s) g v;
7777+ loop acc
7878+ end else
7979+ loop acc
7980 else
8081 acc
8182 in
8282- loop i
8383+ loop acc
83848485 let iter_component ?(pre=fun _ -> ()) ?(post=fun _ -> ()) g v =
8586 let h = H.create 97 in
···11+22+(* Stack-based DFS is tricky to get right. See
33+ https://11011110.github.io/blog/2013/12/17/stack-based-graph-traversal.html
44+55+ On this graph,
66+77+ 0
88+ / \
99+ / \
1010+ v v
1111+ 1---2---3 (All edges are undirected,
1212+ |\ /| apart from 0->1 0->3 1->5 and 3->6.)
1313+ | \ / |
1414+ | 4 |
1515+ | / \ |
1616+ v / \ v
1717+ 5 6
1818+1919+ an incorrect stack-based DFS starting from 0 would first mark 1 and 3,
2020+ and then would not go as deep as possible in the traversal.
2121+2222+ In the following, we check that, whenever 2 and 4 are visited,
2323+ then necessarily both 1 and 3 are already visited.
2424+*)
2525+2626+open Format
2727+open Graph
2828+open Pack.Digraph
2929+3030+let debug = false
3131+3232+let g = create ()
3333+let v = Array.init 7 V.create
3434+let () = Array.iter (add_vertex g) v
3535+let adde x y = add_edge g v.(x) v.(y)
3636+let addu x y = adde x y; adde y x
3737+let () = adde 0 1; adde 0 3
3838+let () = addu 1 2; addu 2 3
3939+let () = adde 1 5; adde 3 6
4040+let () = addu 1 4; addu 4 3; addu 5 4; addu 4 6
4141+4242+let () = assert (Dfs.has_cycle g)
4343+4444+let marked = Array.make 7 false
4545+let reset () = Array.fill marked 0 7 false
4646+let mark v =
4747+ let i = V.label v in
4848+ marked.(i) <- true;
4949+ if marked.(2) && marked.(4) then assert (marked.(1) && marked.(3))
5050+5151+let pre v = if debug then printf "pre %d@." (V.label v); mark v
5252+let post v = if debug then printf "post %d@." (V.label v)
5353+let f v () = if debug then printf "fold %d@." (V.label v); mark v
5454+5555+let () = reset (); Dfs.iter ~pre ~post g
5656+let () = reset (); Dfs.prefix pre g
5757+let () = reset (); Dfs.postfix post g
5858+let () = reset (); Dfs.iter_component ~pre ~post g v.(0)
5959+let () = reset (); Dfs.prefix_component pre g v.(0)
6060+let () = reset (); Dfs.postfix_component post g v.(0)
6161+let () = reset (); Dfs.fold f () g
6262+let () = reset (); Dfs.fold_component f () g v.(0)
6363+6464+module D = Traverse.Dfs(Pack.Digraph)
6565+6666+let rec visit it =
6767+ let v = D.get it in
6868+ mark v;
6969+ visit (D.step it)
7070+7171+let () = try visit (D.start g) with Exit -> ()
7272+7373+let () = printf "All tests succeeded.@."