Source file graph.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
open Utils
open List
module type G = sig
type t
type v
val vertices : t -> v list
val successors : t -> v -> v list
val equal : v -> v -> bool
val compare : v -> v -> int
end
module Make(G : G) = struct
open G
let rec assoc_opt_by p k = function
| [] -> None
| (k',v)::kvs ->
if p k k' then Some v
else assoc_opt_by p k kvs
let sccs : t -> v list list = fun t ->
let rec f cntr vns s p sccs (v : v) =
let ws = successors t v in
let vns = (v,cntr) :: vns in
let s = v :: s in
let p = (v,cntr) :: p in
let cntr = cntr + 1 in
let cntr, vns, s, p, sccs =
fold_left (fun (cntr, vns, s, p, sccs) w ->
match assoc_opt_by equal w vns with
| None -> f cntr vns s p sccs w
| Some n ->
let rec pop = function
| ((_,n')::_ as p) when n' <= n -> p
| _::vns -> pop vns
| [] -> assert false
in
cntr, vns, s, pop p, sccs) (cntr, vns, s, p, sccs) ws
in
match p with
| [] -> assert false
| (v',_) :: p when equal v v' ->
let rec pop scc = function
| v'::s ->
if equal v v' then (v'::scc), s
else pop (v'::scc) s
| _ -> assert false
in
let scc, s = pop [] s in
cntr, vns, s, p, scc::sccs
| _ -> cntr, vns, s, p, sccs
in
let vs = vertices t in
let _, _, _, sccs =
fold_left (fun (vns, s, p, sccs) v ->
match assoc_opt_by equal v vns with
| None ->
let _, vns, s, p, sccs = f 0 vns s p sccs v in
vns, s, p, sccs
| Some _ -> vns, s, p, sccs) ([], [], [], []) vs
in
sccs
let div_by_components : t -> v list list -> (v list * v list list) list = fun t cs ->
let succs_v c = sort_uniq compare @@ concat_map (fun v -> successors t v) c in
let mem v c = try ignore @@ find (equal v) c; true with Not_found -> false in
let comp v = find (mem v) cs in
let succs_c c = sort_uniq (fun c1 c2 -> compare (hd c1) (hd c2)) @@ map comp @@ succs_v c in
map (fun c -> c, succs_c c) cs
let toposort : t -> v list option = fun t ->
try
(fun x -> Some x) @@ fst @@ fold_left (fun (res, tmp) v ->
if mem v res then (res, tmp)
else
let rec visit res tmp v =
if mem v tmp then raise Exit
else if mem v res then (res, tmp)
else
let tmp' = v :: tmp in
let res, _ = fold_left (fun (res, tmp) v -> visit res tmp v) (res, tmp') (successors t v) in
(v :: res, tmp)
in
visit res tmp v) ([], []) @@ vertices t
with
| Exit -> None
end