123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247(* This file is free software, part of containers. See file "license" for more details. *)(** {1 Random Generators} *)openCCShims_includeRandomtypestate=Random.State.ttype'at=state->'atype'arandom_gen='atletreturnx_st=xletflat_mapfgst=f(gst)stlet(>>=)gfst=flat_mapfgstletmapfgst=f(gst)let(>|=)gfst=mapfgstletdelayfst=f()stlet_choose_arrayast=ifArray.lengtha=0theninvalid_arg"CCRandom.choose_array";a.(Random.State.intst(Array.lengtha))letchoose_arrayast=trySome(_choose_arrayastst)withInvalid_argument_->Noneletchoosel=leta=Array.of_listlinchoose_arrayaletchoose_exnl=leta=Array.of_listlinfunst->_choose_arrayaststletchoose_returnl=_choose_array(Array.of_listl)exceptionPick_from_emptyletpick_listl=letn=List.lengthlinifn=0thenraisePick_from_empty;funst->List.nthl(Random.State.intstn)(*$Q
Q.(list small_int) (fun l -> \
l=[] || List.mem (run (pick_list l)) l)
*)letpick_arraya=letn=Array.lengthainifn=0thenraisePick_from_empty;funst->Array.geta(Random.State.intstn)letintist=Random.State.intstiletsmall_int=int100letint_rangeijst=i+Random.State.intst(j-i+1)letfloatfst=Random.State.floatstfletsmall_float=float100.0letfloat_rangeijst=i+.Random.State.floatst(j-.i)(* TODO: sample functions *)letreplicatengst=letrecauxaccn=ifn=0thenaccelseaux(gst::acc)(n-1)inaux[]n(* Sample without replacement using rejection sampling. *)letsample_without_duplicates(typeelt)~cmpk(rng:eltt)st=letmoduleS=Set.Make(structtypet=eltletcompare=cmpend)inletrecauxsk=ifk<=0thenS.elementsselseletx=rngstinifS.memxsthenauxskelseaux(S.addxs)(k-1)inifk<=0theninvalid_arg"sample_without_duplicates";auxS.emptyk(* deprecated *)letsample_without_replacement~comparekrng=sample_without_duplicates~cmp:comparekrngletlist_seqlst=List.map(funf->fst)lletsplitist=ifi<2thenNoneelseletj=1+Random.State.intst(i-1)inSome(j,i-j)let_diff_list~lastl=letrecdiff_listacc=function|[a]->Some((last-a)::acc)|a::(b::_asr)->diff_list((b-a)::acc)r|[]->Noneindiff_list[]l(* Partition of an int into [len] integers uniformly.
We first sample (len-1) points from the set {1,..i-1} without replacement.
We sort these points and add back 0 and i, we have thus
x_0 = 0 < x_1 < x_2 < ... < x_{len-1} < i = x_{len}.
If we define, y_k = x_{k+1} - x_{k} for k in 0..(len-1), then by construction
∑_k y_k = ∑_k (x_{k+1} - x_k ) = x_{len} - x_0 = i. *)letsplit_listi~lenst=iflen<=1theninvalid_arg"Random.split_list";ifi>=lenthen(letxs=sample_without_replacement~compare(len-1)(int_range1(i-1))stin_diff_list~last:i(0::xs))elseNone(*$Q
Q.(pair small_int small_int) (fun (i,j) -> \
let len, n = 2+min i j, max i j in \
let l = QCheck.Gen.generate1 (split_list n ~len) in \
match l with None -> true | Some l -> l<> [] && List.for_all (fun x->x>0) l)
*)letretry?(max=10)gst=letrecauxn=matchgstwith|Nonewhenn=0->None|None->aux(n-1)(* retry *)|Some_asres->resinauxmaxletrectry_successivelylst=matchlwith|[]->None|g::l'->beginmatchgstwith|None->try_successivelyl'st|Some_asres->resendlet(<?>)ab=try_successively[a;b]exceptionBacktracklet_choose_array_callafst=tryf(_choose_arrayast)withInvalid_argument_->raiseBacktrackletfix?(sub1=[])?(sub2=[])?(subn=[])~basefuelst=letsub1=Array.of_listsub1andsub2=Array.of_listsub2andsubn=Array.of_listsubnin(* recursive function with fuel *)letrecmakefuelst=iffuel=0thenraiseBacktrackelseiffuel=1thenbasestelse_try_otherwise0[|_choose_array_callsub1(funf->f(make(fuel-1))st);_choose_array_callsub2(funf->matchsplitfuelstwith|None->raiseBacktrack|Some(i,j)->f(makei)(makej)st);_choose_array_callsubn(fun(len,f)->letlen=lenstinmatchsplit_listfuel~lenstwith|None->raiseBacktrack|Somel'->f(funst->List.map(funx->makexst)l')st);base(* base case then *)|]and_try_otherwiseia=ifi=Array.lengthathenraiseBacktrackelsetrya.(i)stwithBacktrack->_try_otherwise(i+1)ainmake(fuelst)stletpurex_st=xlet(<*>)fgst=fst(gst)includeCCShimsMkLet_.Make(structtypenonrec'at='atlet(>>=)=(>>=)let(>|=)=(>|=)letmonoid_producta1a2st=a1st,a2stend)let__default_state=Random.State.make_self_init()letrun?(st=__default_state)g=gstletuniformity_test?(size_hint=10)krngst=lethistogram=Hashtbl.createsize_hintinletaddx=letn=tryHashtbl.findhistogramxwithNot_found->0inHashtbl.replacehistogramx(n+1)inlet()=for_i=0to(k-1)doadd(rngst)doneinletcardinal=float_of_int(Hashtbl.lengthhistogram)inletkf=float_of_intkin(* average number of points assuming an uniform distribution *)letaverage=kf/.cardinalin(* The number of points is a sum of random variables with binomial distribution *)letp=1./.cardinalin(* The variance of a binomial distribution with average p is *)letvariance=p*.(1.-.p)in(* Central limit theorem: a confidence interval of 4σ provides a false positive rate
of 0.00634% *)letconfidence=4.inletstd=confidence*.(sqrt(kf*.variance))inletpredicate_keynacc=let(<)(a:float)b=Stdlib.(<)abinacc&&abs_float(average-.float_of_intn)<stdinHashtbl.foldpredicatehistogramtrue(*$T split_list
run ~st:(QCheck_runner.random_state()) ( uniformity_test 50_000 (split_list 10 ~len:3) )
*)(*$R
let open Containers in
ignore @@ List.random_choose [1;2;3] (Random.get_state())
*)