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
(** {1 Random Generators} *)
open CCShims_
include Random
type state = Random.State.t
type 'a t = state -> 'a
type 'a random_gen = 'a t
let return x _st = x
let flat_map f g st = f (g st) st
let (>>=) g f st = flat_map f g st
let map f g st = f (g st)
let (>|=) g f st = map f g st
let delay f st = f () st
let _choose_array a st =
if Array.length a = 0 then invalid_arg "CCRandom.choose_array";
a.(Random.State.int st (Array.length a))
let choose_array a st =
try Some (_choose_array a st st) with Invalid_argument _ -> None
let choose l =
let a = Array.of_list l in
choose_array a
let choose_exn l =
let a = Array.of_list l in
fun st -> _choose_array a st st
let choose_return l = _choose_array (Array.of_list l)
exception Pick_from_empty
let pick_list l =
let n = List.length l in
if n=0 then raise Pick_from_empty;
fun st ->
List.nth l (Random.State.int st n)
let pick_array a =
let n = Array.length a in
if n=0 then raise Pick_from_empty;
fun st -> Array.get a (Random.State.int st n)
let int i st = Random.State.int st i
let small_int = int 100
let int_range i j st = i + Random.State.int st (j-i+1)
let float f st = Random.State.float st f
let small_float = float 100.0
let float_range i j st = i +. Random.State.float st (j-.i)
let replicate n g st =
let rec aux acc n =
if n = 0 then acc else aux (g st :: acc) (n-1)
in aux [] n
let sample_without_duplicates (type elt) ~cmp k (rng:elt t) st=
let module S = Set.Make(struct type t=elt let compare = cmp end) in
let rec aux s k =
if k <= 0 then
S.elements s
else
let x = rng st in
if S.mem x s then
aux s k
else
aux (S.add x s) (k-1)
in
if k<=0 then invalid_arg "sample_without_duplicates";
aux S.empty k
let sample_without_replacement ~compare k rng =
sample_without_duplicates ~cmp:compare k rng
let list_seq l st = List.map (fun f -> f st) l
let split i st =
if i < 2 then None
else
let j = 1 + Random.State.int st (i-1) in
Some (j, i-j)
let _diff_list ~last l =
let rec diff_list acc = function
| [a] -> Some ( (last - a)::acc )
| a::( b::_ as r ) -> diff_list ( (b-a)::acc ) r
| [] -> None
in
diff_list [] l
let split_list i ~len st =
if len <= 1 then invalid_arg "Random.split_list";
if i >= len then (
let xs = sample_without_replacement ~compare (len-1) (int_range 1 (i-1)) st in
_diff_list ~last:i (0::xs)
) else
None
let retry ?(max=10) g st =
let rec aux n =
match g st with
| None when n=0 -> None
| None -> aux (n-1)
| Some _ as res -> res
in
aux max
let rec try_successively l st = match l with
| [] -> None
| g :: l' ->
begin match g st with
| None -> try_successively l' st
| Some _ as res -> res
end
let (<?>) a b = try_successively [a;b]
exception Backtrack
let _choose_array_call a f st =
try
f (_choose_array a st)
with Invalid_argument _ -> raise Backtrack
let fix ?(sub1=[]) ?(sub2=[]) ?(subn=[]) ~base fuel st =
let sub1 = Array.of_list sub1
and sub2 = Array.of_list sub2
and subn = Array.of_list subn in
let rec make fuel st =
if fuel=0 then raise Backtrack
else if fuel=1 then base st
else
_try_otherwise 0
[| _choose_array_call sub1 (fun f -> f (make (fuel-1)) st)
; _choose_array_call sub2
(fun f ->
match split fuel st with
| None -> raise Backtrack
| Some (i,j) -> f (make i) (make j) st
)
; _choose_array_call subn
(fun (len,f) ->
let len = len st in
match split_list fuel ~len st with
| None -> raise Backtrack
| Some l' ->
f (fun st -> List.map (fun x -> make x st) l') st
)
; base
|]
and _try_otherwise i a =
if i=Array.length a then raise Backtrack
else try
a.(i) st
with Backtrack ->
_try_otherwise (i+1) a
in
make (fuel st) st
let pure x _st = x
let (<*>) f g st = f st (g st)
include CCShimsMkLet_.Make(struct
type nonrec 'a t = 'a t
let (>>=) = (>>=)
let (>|=) = (>|=)
let monoid_product a1 a2 st = a1 st, a2 st
end)
let __default_state = Random.State.make_self_init ()
let run ?(st=__default_state) g = g st
let uniformity_test ?(size_hint=10) k rng st =
let histogram = Hashtbl.create size_hint in
let add x = let n = try Hashtbl.find histogram x with Not_found -> 0 in
Hashtbl.replace histogram x (n + 1) in
let () =
for _i = 0 to ( k - 1 ) do
add (rng st)
done in
let cardinal = float_of_int (Hashtbl.length histogram) in
let kf = float_of_int k in
let average = kf /. cardinal in
let p = 1. /. cardinal in
let variance = p *. (1. -. p ) in
let confidence = 4. in
let std = confidence *. (sqrt (kf *. variance)) in
let predicate _key n acc =
let (<) (a : float) b = Stdlib.(<) a b in
acc && abs_float (average -. float_of_int n) < std in
Hashtbl.fold predicate histogram true