Source file b_selection.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
type selected =
| Range of (int * int)
type t = selected list
let empty = []
let card = List.length
let range (a,b) = Range (a,b)
let of_range (Range (a,b)) = (a,b)
let to_list sel =
List.map of_range sel
let compare (Range (r1,_)) (Range (r2,_)) =
Stdlib.compare r1 r2
let sort sel =
List.sort compare sel
let sanitize sel =
let rec loop sl new_sl =
match sl with
| [] -> List.rev new_sl
| Range (i1,i2)::rest when i2 < i1 -> loop rest new_sl
| s::rest -> loop rest (s::new_sl) in
loop sel []
let normalize sel =
let rec loop current sl new_sl =
match current, sl with
| _, [] -> List.rev (current::new_sl)
| Range (i1,i2), Range (j1,j2)::rest ->
if i2+1 < j1 then loop (Range (j1,j2)) rest (current::new_sl)
else loop (Range (i1, max i2 j2)) rest new_sl
in
match sort (sanitize sel) with
| [] -> []
| first::rest -> loop first rest []
let of_list list =
List.map range list
|> normalize
let proj1 (Range (r1, _)) = r1
let proj2 (Range (_, r2)) = r2
let first_unsorted = function
| [] -> invalid_arg "[Selection.first_unsorted] selection should not be empty."
| (Range (r1, _)) :: rest ->
List.map proj1 rest
|> List.fold_left min r1
let first = function
| [] -> invalid_arg "[Selection.first] selection should not be empty."
| (Range (r1, _))::_ -> r1
let last = function
| [] -> invalid_arg "[Selection.last] selection should not be empty."
| (Range (_, r2)) :: rest ->
List.map proj2 rest
|> List.fold_left max r2
let mem sel i =
let rec loop sl =
match sl with
| [] -> false
| Range (i1,i2)::rest -> if i1<=i && i<=i2 then true else loop rest
in
loop sel
let remove sel i =
let rec loop sl new_sl =
match sl with
| [] -> List.rev new_sl
| Range (i1,i2)::rest when i=i1 && i=i2 ->
List.rev_append new_sl rest
| Range (i1,i2)::rest when i=i1 ->
List.rev_append new_sl (Range (i1+1,i2)::rest)
| Range (i1,i2)::rest when i=i2 ->
List.rev_append new_sl (Range (i1,i2-1)::rest)
| Range (i1,i2)::rest when i1<i && i<i2 ->
List.rev_append new_sl (Range (i1,i-1)::(Range (i+1,i2)::rest))
| Range (i1,i2)::rest -> loop rest (Range (i1,i2)::new_sl)
in
loop sel []
let add sel i =
let rec loop sl new_sl =
match sl with
| [] -> List.rev (Range (i,i)::new_sl)
| Range (i1,_)::_ when i+1<i1 ->
List.rev_append new_sl ((Range (i,i))::sl)
| Range (i1,i2)::rest when i+1=i1 ->
List.rev_append new_sl (Range (i,i2)::rest)
| Range (i1,i2)::(Range (j1,j2))::rest when i=i2+1 && j1=i2+2 ->
List.rev_append new_sl (Range (i1,j2)::rest)
| Range (i1,i2)::rest when i=i2+1 ->
List.rev_append new_sl (Range (i1,i)::rest)
| Range (i1,i2)::_ when i1<=i && i<=i2 ->
List.rev_append new_sl sl
| r::rest ->
loop rest (r::new_sl)
in
loop sel []
let toggle sel i =
if mem sel i then remove sel i else add sel i
let union_brute sel1 sel2 =
normalize (List.rev_append sel2 sel1)
let rec union sel1 sel2 =
match sel1, sel2 with
| [], _ -> sel2
| _, [] -> sel1
| (Range (r1,r2))::rest1, (Range (s1,s2))::rest2 ->
if r1 > s1 then union sel2 sel1
else if r2 < s1-1 then Range (r1,r2) :: union rest1 sel2
else if s2 <= r2 then union sel1 rest2
else union (Range (r1,s2) :: rest2) rest1
let rec intersect sel1 sel2 =
match sel1, sel2 with
| [], _
| _, [] -> []
| (Range (r1,r2))::rest1, (Range (s1,s2))::rest2 ->
if r1 > s1 then intersect sel2 sel1
else if r2 < s1 then intersect rest1 sel2
else if r2 <= s2 then Range (s1,r2) :: intersect rest1 sel2
else Range (s1,s2) :: intersect sel1 rest2
let contains sel1 sel2 =
intersect sel1 sel2 = sel1
let (<<=) = contains
let iter (f : int -> unit) sel =
let rec loop sl =
match sl with
| [] -> ()
| Range (i1,i2)::rest when i2<i1 -> loop rest
| Range (i1,i2)::rest -> f i1; loop (Range (i1+1,i2)::rest)
in
loop sel
let sprint_entry (Range (i1,i2)) =
if i1=i2 then string_of_int i1
else Printf.sprintf "%d..%d" i1 i2
let sprint sel =
List.map sprint_entry sel
|> String.concat ", "
|> Printf.sprintf "{%s}"
let random ?(bad = 0) len gap maxi =
let gap = max 1 gap in
let len = max 0 len in
let rec loop x list =
let r1 = x + 1 + Random.int (2*gap-1) - bad in
let r2 = r1 + Random.int (2*len+1) in
if r2 > maxi then list
else loop (r2+1) (Range (r1, r2) :: list) in
List.rev (loop (Random.int (maxi/2+1)) [])
let list_remove l i =
let rec loop j acc = function
| [] -> invalid_arg "[Selection.list_remove] selection should not be empty."
| x::rest -> if i = j then x, List.rev_append acc rest
else loop (j+1) (x::acc) rest in
loop 0 [] l
let shuffle list =
let rec loop acc len = function
| [] -> acc
| l -> let i = Random.int len in
let x, rest = list_remove l i in
loop (x::acc) (len-1) rest in
loop [] (List.length list) list
let time name f =
let t0 = Unix.gettimeofday () in
let y = f () in
Printf.printf "Time %s = %f\n" name (Unix.gettimeofday () -. t0);
y
let test () =
let len, gap, maxi = 1000, 100, 10000000 in
let r = time "random" (fun () -> random len gap maxi) in
assert (r = normalize r);
let rs = shuffle r in
let rn = time "normalize shuffle" (fun () -> normalize rs) in
assert (r = rn);
let bad = random ~bad:(gap/2) len gap maxi |> shuffle in
let bn = time "normalize bad" (fun () -> normalize bad) in
assert (bn = normalize bn);
print_endline "Test first";
assert (first bn = first_unsorted bad);
let s = random len gap maxi in
let u1 = time "union" (fun () -> union r s) in
let u2 = time "union_brute" (fun () -> union_brute r s) in
assert (u1 = u2);
let i = time "intersect" (fun () -> intersect r s) in
assert (intersect i r = intersect i s);
print_endline "Test toggle";
let x = Random.int maxi in
assert (r = toggle (toggle r x) x);
print_endline "Test iter";
let e = ref empty in
let t = random 1000 100 100000 in
iter (fun i -> e := add !e i) t;
assert (!e = t);
print_endline "Selection Test passed OK."