Source file interval_map.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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
type order = Asc | Desc
module type Comparable = Comparable.S
exception Invalid_interval = Interval.Invalid_interval
module Make (Bound_compare : Comparable) = struct
module Bound = Bound.Make (Bound_compare)
module Interval = Interval.Make (Bound)
module Tree = struct
type 'v node = {
interval : Interval.t;
left : 'v t;
right : 'v t;
height : int;
max : Bound.t;
min : Bound.t;
values : 'v list;
}
and 'v t = 'v node option
let height node = match node with None -> 0 | Some n -> n.height
let max_bound (interval : Interval.t) left right =
let mid = interval.high in
match (left, right) with
| None, None -> mid
| None, Some r -> Bound.max_upper mid r.max
| Some l, None -> Bound.max_upper mid l.max
| Some l, Some r -> Bound.max_upper mid (Bound.max_upper l.max r.max)
let min_bound (interval : Interval.t) left right =
let mid = interval.low in
match (left, right) with
| None, None -> mid
| None, Some r -> Bound.min_lower mid r.min
| Some l, None -> Bound.min_lower mid l.min
| Some l, Some r -> Bound.min_lower mid (Bound.min_lower l.min r.min)
let create interval left right values =
let height = max (height left) (height right) + 1 in
let max = max_bound interval left right in
let min = min_bound interval left right in
{ interval; left; right; height; max; min; values }
let leaf interval values = Some (create interval None None values)
let size = function
| None -> 0
| Some node ->
let rec go { left; right; values; _ } size =
let size = size + List.length values in
match (left, right) with
| None, None -> size
| Some lt, None -> go lt size
| None, Some rt -> go rt size
| Some lf, Some rt ->
let size = go lf size in
go rt size
in
go node 0
let rec find interval = function
| None -> None
| Some node ->
let ivl_cmp = Interval.compare interval node.interval in
if ivl_cmp = 0 then Some node
else if ivl_cmp < 0 then find interval node.left
else find interval node.right
let balance_factor { left; right; _ } = height left - height right
let replace_left node new_left =
create node.interval new_left node.right node.values
let replace_right node new_right =
create node.interval node.left new_right node.values
let rotate_right node =
let pivot = Option.get node.left in
let new_right = replace_left node pivot.right in
replace_right pivot (Some new_right)
let rotate_left node =
let pivot = Option.get node.right in
let new_left = replace_right node pivot.left in
replace_left pivot (Some new_left)
let balance node =
let bf = balance_factor node in
if bf < -1 then
let right = Option.get node.right in
if balance_factor right > 0 then
replace_right node (Some (rotate_right right)) |> rotate_left
else rotate_left node
else if bf > 1 then
let left = Option.get node.left in
if balance_factor left < 0 then
replace_left node (Some (rotate_left left)) |> rotate_right
else rotate_right node
else node
let rec add interval value = function
| None -> leaf interval [ value ]
| Some node ->
let ivl_cmp = Interval.compare interval node.interval in
let res =
if ivl_cmp < 0 then
let insert_left =
match node.left with
| None -> leaf interval [ value ]
| lt -> add interval value lt
in
replace_left node insert_left
else if ivl_cmp > 0 then
let insert_right =
match node.right with
| None -> leaf interval [ value ]
| rt -> add interval value rt
in
replace_right node insert_right
else { node with values = value :: node.values }
in
Some (balance res)
let rec add_replace_all interval values = function
| None -> leaf interval values
| Some node ->
let ivl_cmp = Interval.compare interval node.interval in
let res =
if ivl_cmp < 0 then
let insert_left =
match node.left with
| None -> leaf interval values
| lt -> add_replace_all interval values lt
in
replace_left node insert_left
else if ivl_cmp > 0 then
let insert_right =
match node.right with
| None -> leaf interval values
| rt -> add_replace_all interval values rt
in
replace_right node insert_right
else { node with values }
in
Some (balance res)
let rec min_interval node =
match node.left with None -> node.interval | Some lt -> min_interval lt
let remove_by interval value_rm_fn = function
| None -> None
| Some node ->
let rec remove node =
let ivl_cmp = Interval.compare interval node.interval in
let res =
if ivl_cmp = 0 then
let values =
List.filter (fun v -> not (value_rm_fn v)) node.values
in
match (values, node.left, node.right) with
| _ :: _, _, _ -> Some { node with values }
| _, None, None -> None
| _, Some lt, None -> Some lt
| _, None, Some rt -> Some rt
| _, Some _, Some rt ->
let successor = min_interval rt in
let rt = remove rt in
let node = create successor node.left rt values in
Some node
else if ivl_cmp < 0 then
match node.left with
| None -> Some node
| Some lt ->
let lt = remove lt in
Some (replace_left node lt)
else
match node.right with
| None -> Some node
| Some rt ->
let rt = remove rt in
Some (replace_right node rt)
in
match res with None -> None | Some n -> Some (balance n)
in
remove node
let fold_bf fn acc = function
| None -> acc
| Some node ->
let queue = Queue.create () in
Queue.add node queue;
let rec iter acc =
match Queue.take_opt queue with
| None -> acc
| Some node ->
Option.iter (fun lt -> Queue.add lt queue) node.left;
Option.iter (fun rt -> Queue.add rt queue) node.right;
let acc = fn acc node in
iter acc
in
iter acc
end
module Gen = struct
open Tree
type 'v t = {
node : 'v node option;
stack : 'v node list;
order : order;
go_left : 'v node -> bool;
go_right : 'v node -> bool;
emit : 'v node -> bool;
}
let go _node = true
let create ?(go_left = go) ?(go_right = go) ?(emit = go) order node =
{ node; stack = []; order; go_left; go_right; emit }
let filter_option fn = function
| Some v as opt -> if fn v then opt else None
| None -> None
let rec next { node; stack; order; go_left; go_right; emit } =
match (node, stack) with
| Some node, stack ->
let stack = node :: stack in
let next_node =
match order with
| Asc -> filter_option go_left node.left
| Desc -> filter_option go_right node.right
in
next { node = next_node; stack; order; go_left; go_right; emit }
| None, node :: stack ->
let next_node =
match order with
| Asc -> filter_option go_right node.right
| Desc -> filter_option go_left node.left
in
if emit node then
Some
( (node.interval, node.values),
{ node = next_node; stack; order; go_left; go_right; emit } )
else next { node = next_node; stack; order; go_left; go_right; emit }
| None, [] -> None
let fold fn acc gen =
let rec iter acc = function
| Some ((ivl, values), gen) ->
let acc = fn acc ivl values in
iter acc (next gen)
| None -> acc
in
iter acc (next gen)
end
type 'v t = 'v Tree.t
let empty = None
let size = Tree.size
let cardinal = size
let add = Tree.add
let find_opt interval map =
let open Tree in
Tree.find interval map |> Option.map (fun n -> n.values)
let find interval map =
match find_opt interval map with None -> raise Not_found | Some v -> v
let mem interval map = Tree.find interval map |> Option.is_some
let query_interval ?(order = Asc) query =
let open Interval in
let open Tree in
let go_left left =
match (left.max, query.low) with
| Included max, Included low -> Bound.C.compare max low >= 0
| Included max, Excluded low
| Excluded max, Included low
| Excluded max, Excluded low ->
Bound.C.compare max low > 0
| _ -> true
in
let go_right right =
match (right.min, query.high) with
| Included min, Included high -> Bound.C.compare min high <= 0
| Included min, Excluded high
| Excluded min, Included high
| Excluded min, Excluded high ->
Bound.C.compare min high < 0
| _ -> true
in
let emit node = Interval.overlaps query node.interval in
Gen.create ~go_left ~go_right ~emit order
let query_interval_list query map =
query_interval ~order:Desc query map
|> Gen.fold (fun xs ivl values -> (ivl, values) :: xs) []
let remove_by = Tree.remove_by
let remove_interval interval = remove_by interval (fun _ -> true)
let generator ?(order = Asc) map = Gen.create order map
let fold fn map acc =
Gen.create Asc map |> Gen.fold (fun acc ivl values -> fn ivl values acc) acc
let mapi fn =
Tree.fold_bf
(fun map node ->
Tree.add_replace_all node.interval
Tree.(fn node.interval node.values)
map)
empty
let map fn = mapi (fun _ values -> fn values)
let iteri fn map =
Gen.create Asc map |> Gen.fold (fun () ivl values -> fn ivl values) ()
let iter fn = iteri (fun _ivl values -> fn values)
let to_list map =
Gen.create Desc map
|> Gen.fold (fun xs ivl values -> (ivl, values) :: xs) []
let rec seq_unfold f u () =
let open Seq in
match f u with None -> Nil | Some (x, u) -> Cons (x, seq_unfold f u)
let to_seq map = Gen.create Asc map |> seq_unfold Gen.next
end