Source file refine.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
module type DECOMPOSABLE = sig
type 'a t
val is_empty : 'a t -> bool
val compare : 'a t -> 'a t -> int
val compare_minimum : 'a t -> 'a t -> int
val sorted_union : 'a t list -> 'a t
end
module type S = sig
type 'a t
val partition : 'a t list -> 'a t list
val annotated_partition : ('a t * 'b) list -> ('a t * 'b list) list
val partition_and_total : 'a t list -> 'a t list * 'a t
val annotated_partition_and_total : ('a t * 'b) list -> ('a t * 'b list) list * 'a t
val iter_decomposition : ('a t * 'b) list -> ('a t -> (('b -> unit) -> unit) -> unit) -> unit
val iter_merged_decomposition : ('a t * 'b) list -> ('a t -> 'b list -> unit) -> unit
end
module Make (Set : DECOMPOSABLE) : S with type 'a t := 'a Set.t = struct
module Heap = Heap.Make(struct
type 'a t = 'a Set.t
let compare = Set.compare_minimum
end)
let compute_parts xs =
let heap, _ = List.fold_left
(fun (h, i) s -> Heap.insert s (IntSet.singleton i) h, i + 1)
(Heap.empty, 0) xs
in
let rec aux parts heap =
match Heap.pop2 heap with
| Head (s1, k1, s2, k2, heap) ->
let sp, s1 = Set.extract_unique_prefix s1 s2 in
let sc, (s1, s2) = Set.extract_shared_prefix s1 s2 in
let parts =
if not (Set.is_empty sp) then (sp, k1) :: parts else parts
in
let heap =
if not (Set.is_empty sc)
then Heap.insert sc (IntSet.union k1 k2) heap
else heap
in
let heap =
if not (Set.is_empty s1) then Heap.insert s1 k1 heap else heap
in
let heap =
if not (Set.is_empty s2) then Heap.insert s2 k2 heap else heap
in
aux parts heap
| Tail (k, v) -> (k, v) :: parts
| Done -> parts
in
aux [] heap
let union_parts parts =
match List.sort (fun (_, k1) (_, k2) -> IntSet.compare k1 k2) parts with
| [] -> []
| (s1, k1) :: rest ->
let rec merge acc ss key = function
| [] -> Set.sorted_union ss :: acc
| (s, key') :: rest ->
if IntSet.equal key key' then
merge acc (s :: ss) key rest
else
merge (Set.sorted_union ss :: acc) [s] key' rest
in
merge [] [s1] k1 rest
let partition xs = union_parts (compute_parts xs)
let partition_and_total xs =
let parts = compute_parts xs in
let total = Set.sorted_union (List.rev_map fst parts) in
let union = union_parts parts in
union, total
let keyed_union_parts parts =
match List.sort (fun (_, k1) (_, k2) -> IntSet.compare k1 k2) parts with
| [] -> []
| (s1, k1) :: rest ->
let rec merge acc ss key = function
| [] -> (Set.sorted_union ss, key) :: acc
| (s, key') :: rest ->
if IntSet.equal key key' then
merge acc (s :: ss) key rest
else
merge ((Set.sorted_union ss, key) :: acc) [s] key' rest
in
merge [] [s1] k1 rest
let annotated_partition xs =
let sets, annotations = List.split xs in
let annotations = Array.of_list annotations in
let parts = compute_parts sets in
let union = keyed_union_parts parts in
let annotate key =
List.rev (IntSet.fold (fun i acc -> annotations.(i) :: acc) key [])
in
List.map (fun (set, key) -> set, annotate key) union
let annotated_partition_and_total xs =
let sets, annotations = List.split xs in
let annotations = Array.of_list annotations in
let parts = compute_parts sets in
let total = Set.sorted_union (List.rev_map fst parts) in
let union = keyed_union_parts parts in
let annotate key =
IntSet.fold (fun i acc -> annotations.(i) :: acc) key []
in
(List.map (fun (set, key) -> set, annotate key) union, total)
type 'a join_tree =
| Leaf of 'a
| Join of 'a join_tree * 'a join_tree
let rec iter_join_tree t f = match t with
| Leaf x -> f x
| Join (l, r) ->
iter_join_tree l f;
iter_join_tree r f
let iter_decomposition (xs : ('a Set.t * 'b) list) (f : 'a Set.t -> _ -> unit) : unit =
let heap = List.fold_left (fun h (s,a) -> Heap.insert s (Leaf a) h) Heap.empty xs in
let rec aux heap =
match Heap.pop2 heap with
| Head (s1, k1, s2, k2, heap) ->
let sp, s1 = Set.extract_unique_prefix s1 s2 in
let sc, (s1, s2) = Set.extract_shared_prefix s1 s2 in
if not (Set.is_empty sp) then
f sp (iter_join_tree k1);
let heap =
if not (Set.is_empty sc)
then Heap.insert sc (Join (k1, k2)) heap
else heap
in
let heap =
if not (Set.is_empty s1) then Heap.insert s1 k1 heap else heap
in
let heap =
if not (Set.is_empty s2) then Heap.insert s2 k2 heap else heap
in
aux heap
| Tail (k, v) -> f k (iter_join_tree v)
| Done -> ()
in
aux heap
let rec merge_uniq compare xxs yys =
match xxs, yys with
| [], l | l, [] -> l
| x :: xs, y :: ys ->
let c = compare x y in
if c = 0 then
x :: merge_uniq compare xs ys
else if c < 0 then
x :: merge_uniq compare xs yys
else
y :: merge_uniq compare xxs ys
let iter_merged_decomposition (xs : ('a Set.t * 'b) list) (f : 'a Set.t -> 'b list -> unit) : unit =
let heap =
let count = ref 0 in
List.fold_left (fun h (s,a) ->
let result = Heap.insert s [!count, a] h in
incr count;
result
) Heap.empty xs
in
let cmp (i1, _) (i2, _) =
Int.compare i1 i2
in
let rec aux heap =
match Heap.pop2 heap with
| Head (s1, k1, s2, k2, heap) ->
process s1 k1 s2 k2 heap
| Tail (k, v) -> f k (List.map snd v)
| Done -> ()
and process s1 k1 s2 k2 = function
| Heap.Node (l, s3, k3, r, _) when Set.compare s2 s3 = 0 ->
process s1 k1 s2 (merge_uniq cmp k2 k3) (Heap.merge l r)
| heap ->
let sp, s1 = Set.extract_unique_prefix s1 s2 in
let sc, (s1, s2) = Set.extract_shared_prefix s1 s2 in
if not (Set.is_empty sp) then
f sp (List.map snd k1);
let heap =
if not (Set.is_empty sc)
then Heap.insert sc (merge_uniq cmp k1 k2) heap
else heap
in
let heap =
if not (Set.is_empty s1) then Heap.insert s1 k1 heap else heap
in
let heap =
if not (Set.is_empty s2) then Heap.insert s2 k2 heap else heap
in
aux heap
in
aux heap
end