@@ -248,27 +248,27 @@ module Gen = struct
248248 List. sort (fun (w1 , _ ) (w2 , _ ) -> poly_compare w1 w2) samples |> List. rev_map snd
249249
250250 let range_subset ~size low high st =
251- if not (low < = high && size < = high - low + 1 ) then invalid_arg " Gen.range_subset" ;
251+ let range_size = high - low + 1 in
252+ if not (0 < = size && size < = range_size) then
253+ invalid_arg " Gen.range_subset" ;
252254 (* The algorithm below is attributed to Floyd, see for example
253255 https://eyalsch.wordpress.com/2010/04/01/random-sample/
254256 https://math.stackexchange.com/questions/178690
255257
256- Note: the code be made faster by checking membership in [arr]
257- directly instead of using an additional Set. None of our
258- dependencies implements dichotomic search, so using Set is
259- easier.
258+ Note: the code is easier to read when drawing from [0..range_size-1]
259+ rather than [low..high]. We draw in [0..bound], and shift the
260+ results by adding [low] when writing them to the result array.
260261 *)
261262 let module ISet = Set. Make (Int ) in
262263 let s = ref ISet. empty in
263- let arr = Array. make size 0 in
264- for i = high - size to high do
265- let pos = int_range high i st in
266- let choice =
267- if ISet. mem pos ! s then i else pos
268- in
269- arr.(i - low) < - choice;
264+ for i = range_size - size to range_size - 1 do
265+ let pos = int_range 0 i st in
266+ let choice = if ISet. mem pos ! s then i else pos in
270267 s := ISet. add choice ! s;
271268 done ;
269+ let arr = Array. make size 0 in
270+ let idx = ref 0 in
271+ ISet. iter (fun choice -> arr.(! idx) < - low + choice; incr idx) ! s;
272272 arr
273273
274274 let array_subset size arr st =
@@ -334,31 +334,36 @@ module Gen = struct
334334
335335 (* nat splitting *)
336336
337- let nat_split2 n st =
338- if (n < 2 ) then invalid_arg " nat_split2 " ;
337+ let pos_split2 n st =
338+ if (n < 2 ) then invalid_arg " pos_split2 " ;
339339 let n1 = int_range 1 (n - 1 ) st in
340340 (n1, n - n1)
341341
342- let pos_split2 n st =
342+ let nat_split2 n st =
343343 let n1 = int_range 0 n st in
344344 (n1, n - n1)
345345
346346 let pos_split ~size :k n st =
347- if (k > n) then invalid_arg " nat_split" ;
348- (* To split n into n{0}+n{1}+..+n{k-1}, we draw distinct "boundaries"
349- b{-1}..b{k-1}, with b{-1}=0 and b{k-1} = n
350- and the k-1 intermediate boundaries b{0}..b{k-2}
351- chosen randomly distinct in [1;n-1].
352-
353- Then each n{i} is defined as b{i}-b{i-1}. *)
354- let b = range_subset ~size: (k-1 ) 1 (n - 1 ) st in
355- Array. init k (fun i ->
356- if i = 0 then b.(0 )
357- else if i = k-1 then n - b.(i-1 )
358- else b.(i) - b.(i-1 )
359- )
347+ if 0 = k && 0 = n then [||]
348+ else begin
349+ if not (0 < k && k < = n) then invalid_arg " pos_split" ;
350+ (* To split n into n{0}+n{1}+..+n{k-1}, we draw distinct "boundaries"
351+ b{-1}..b{k-1}, with b{-1}=0 and b{k-1} = n
352+ and the k-1 intermediate boundaries b{0}..b{k-2}
353+ chosen randomly distinct in [1;n-1].
354+
355+ Then each n{i} is defined as b{i}-b{i-1}. *)
356+ let b = range_subset ~size: (k-1 ) 1 (n - 1 ) st in
357+ if k = 1 then [|n|]
358+ else Array. init k (fun i ->
359+ if i = 0 then b.(0 )
360+ else if i = k-1 then n - b.(i-1 )
361+ else b.(i) - b.(i-1 )
362+ )
363+ end
360364
361365 let nat_split ~size :k n st =
366+ if not (0 < = k && 0 < = n) then invalid_arg " nat_split" ;
362367 pos_split ~size: k (n+ k) st
363368 |> Array. map (fun v -> v - 1 )
364369
0 commit comments