@@ -99,30 +99,46 @@ module Make(B : Builder.S) = struct
9999 in
100100 add g1 (B. copy g2)
101101
102- let replace_by_transitive_reduction ?(reflexive =false ) g0 =
103- (* first compute reachability in g0 using a DFS from each vertex *)
102+ (* source: tred.c from Graphviz
103+ time and space O(VE) *)
104+ let replace_by_transitive_reduction ?(reflexive =false ) g =
104105 let module H = Hashtbl. Make (G. V ) in
105- let module D = Traverse. Dfs (G ) in
106- let reachable = H. create (G. nb_vertex g0) in
107- let path_from v =
108- let s = H. create 8 in
109- H. add reachable v s;
110- D. prefix_component (fun w -> H. add s w () ) g0 v in
111- G. iter_vertex path_from g0;
112- let path u v = H. mem (H. find reachable u) v in
113- (* then remove redundant edges *)
114- let phi v g =
115- let g = if reflexive then B. remove_edge g v v else g in
116- G. fold_succ
117- (fun sv g ->
118- G. fold_succ
119- (fun sv' g ->
120- if not (G.V. equal sv sv') && path sv sv'
121- then B. remove_edge g v sv' else g)
122- g v g)
123- g v g
106+ let reduce g v0 =
107+ (* runs a DFS from v0 and records the length (=1 or >1) of paths from
108+ v0 for reachable vertices *)
109+ let nv = G. nb_vertex g in
110+ let dist = H. create nv in
111+ G. iter_vertex (fun w -> H. add dist w 0 ) g;
112+ let update v w = H. replace dist w (1 + min 1 (H. find dist v)) in
113+ let onstack = H. create nv in
114+ let push v st = H. replace onstack v () ; (v, G. succ g v) :: st in
115+ let rec dfs = function
116+ | [] -> ()
117+ | (v , [] ) :: st ->
118+ H. remove onstack v; dfs st
119+ | (v , w :: sv ) :: st when G.V. equal w v || H. mem onstack w ->
120+ dfs ((v, sv) :: st)
121+ | (v , w :: sv ) :: st ->
122+ if H. find dist w = 0 then (
123+ update v w;
124+ dfs (push w ((v, sv) :: st))
125+ ) else (
126+ if H. find dist w = 1 then update v w;
127+ dfs ((v, sv) :: st)
128+ ) in
129+ dfs (push v0 [] );
130+ (* then delete any edge v0->v when the distance for v is >1 *)
131+ let delete g v =
132+ if G.V. equal v v0 && reflexive || H. find dist v > 1
133+ then B. remove_edge g v0 v else g in
134+ let sv0 = G. fold_succ (fun v sv0 -> v :: sv0) g v0 [] in
135+ (* CAVEAT: iterate *then* modify *)
136+ List. fold_left delete g sv0
124137 in
125- G. fold_vertex phi g0 g0
138+ (* run the above from any vertex *)
139+ let vl = G. fold_vertex (fun v vl -> v :: vl) g [] in
140+ (* CAVEAT: iterate *then* modify *)
141+ List. fold_left reduce g vl
126142
127143 let transitive_reduction ?(reflexive =false ) g0 =
128144 replace_by_transitive_reduction ~reflexive (B. copy g0)
0 commit comments