123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720open!BasemoduleT:sigtype+'atvalcreate:(size:int->random:Splittable_random.State.t->'a)->'atvalgenerate:'at->size:int->random:Splittable_random.State.t->'aend=structtype'at=(size:int->random:Splittable_random.State.t->'a)Staged.tletcreatef:_t=Staged.stagefletgenerate(t:_t)~size~random=ifsize<0thenraise_s[%message"Base_quickcheck.Generator.generate: size < 0"(size:int)]elseStaged.unstaget~size~random;;endincludeTletsize=create(fun~size~random:_->size)letfndomrng=create(fun~size~random->letrandom=Splittable_random.State.splitrandominfunx->lethash=Observer0.observedomx~size~hash:(Hash.alloc())inletrandom=Splittable_random.State.copyrandominSplittable_random.State.perturbrandom(Hash.get_hash_valuehash);generaterng~size~random);;letwith_sizet~size=create(fun~size:_~random->generatet~size~random)letperturbtsalt=create(fun~size~random->Splittable_random.State.perturbrandomsalt;generatet~size~random);;letfilter_mapt~f=letrecloop~size~random=letx=generatet~size~randominmatchfxwith|Somey->y|None->loop~size:(size+1)~randomincreateloop;;letfiltert~f=filter_mapt~f:(funx->iffxthenSomexelseNone)letreturnx=create(fun~size:_~random:_->x)letmapt~f=create(fun~size~random->f(generatet~size~random))letapplytftx=create(fun~size~random->letf=generatetf~size~randominletx=generatetx~size~randominfx);;letbindt~f=create(fun~size~random->letx=generatet~size~randomingenerate(fx)~size~random);;letalllist=create(fun~size~random->List.maplist~f:(generate~size~random))letall_unitlist=create(fun~size~random->List.iterlist~f:(generate~size~random));;moduleFor_applicative=Applicative.Make(structtypenonrec'at='atletreturn=returnletapply=applyletmap=`Custommapend)letboth=For_applicative.bothletmap2=For_applicative.map2letmap3=For_applicative.map3moduleApplicative_infix=For_applicative.Applicative_infixincludeApplicative_infixmoduleFor_monad=Monad.Make(structtypenonrec'at='atletreturn=returnletbind=bindletmap=`Custommapend)letignore_m=For_monad.ignore_mletjoin=For_monad.joinmoduleMonad_infix=For_monad.Monad_infixincludeMonad_infixmoduleLet_syntax=For_monad.Let_syntaxopenLet_syntaxletof_listlist=ifList.is_emptylistthenError.raise_s[%message"Base_quickcheck.Generator.of_list: empty list"];letarray=Array.of_listlistinletlo=0inlethi=Array.lengtharray-1increate(fun~size:_~random->letindex=Splittable_random.intrandom~lo~hiinarray.(index));;letunionlist=join(of_listlist)letof_weighted_listalist=ifList.is_emptyalistthenError.raise_s[%message"Base_quickcheck.Generator.of_weighted_list: empty list"];letweights,values=List.unzipalistinletvalue_array=Array.of_listvaluesinlettotal_weight,cumulative_weight_array=letarray=Array.init(Array.lengthvalue_array)~f:(fun_->0.)inletsum=List.foldiweights~init:0.~f:(funindexaccweight->ifnot(Float.is_finiteweight)thenError.raise_s[%message"Base_quickcheck.Generator.of_weighted_list: weight is not finite"(weight:float)];ifFloat.(<)weight0.thenError.raise_s[%message"Base_quickcheck.Generator.of_weighted_list: weight is negative"(weight:float)];letcumulative=acc+.weightinarray.(index)<-cumulative;cumulative)inifFloat.(<=)sum0.thenError.raise_s[%message"Base_quickcheck.Generator.of_weighted_list: total weight is zero"];sum,arrayincreate(fun~size:_~random->letchoice=Splittable_random.floatrandom~lo:0.~hi:total_weightinmatchArray.binary_searchcumulative_weight_array~compare:Float.compare`First_greater_than_or_equal_tochoicewith|Someindex->value_array.(index)|None->assertfalse);;letweighted_unionalist=join(of_weighted_listalist)letof_lazylazy_t=create(fun~size~random->generate(forcelazy_t)~size~random)letfixed_pointof_generator=letreclazy_t=lazy(of_generator(of_lazylazy_t))inforcelazy_t;;letweighted_recursive_unionnonrec_list~f=fixed_point(funself->letrec_list=List.map(fself)~f:(fun(w,t)->(w,let%bindn=sizeinwith_size~size:(n-1)t))inifList.is_emptynonrec_list||List.is_emptyrec_listthenraise_s[%message"Base_quickcheck.Generator.weighted_recursive_union: lists must be non-empty"];letnonrec_gen=weighted_unionnonrec_listinletrec_gen=weighted_union(nonrec_list@rec_list)inmatch%bindsizewith|0->nonrec_gen|_->rec_gen);;letrecursive_unionnonrec_list~f=letweightedlist=List.maplist~f:(funt->1.,t)inweighted_recursive_union(weightednonrec_list)~f:(funself->weighted(fself));;letsizes?(min_length=0)?(max_length=Int.max_value)()=create(fun~size~random->assert(min_length<=max_length);letupper_bound=min_length+sizeinletmax_length=ifupper_bound>=min_length(* guard against overflow *)thenminmax_lengthupper_boundelsemax_lengthin(* pick a length, weighted low so that most of the size is spent on elements *)letlen=Splittable_random.Log_uniform.intrandom~lo:min_length~hi:max_lengthin(* if there are no elements return an empty array, otherwise return a non-empty array
with the size distributed among the elements *)iflen=0then[]else(letsizes=Array.initlen~f:(fun_->0)inletremaining=size-(len-min_length)inletmax_index=len-1infor_=1toremainingdo(* pick an index, weighted low so that we see unbalanced distributions often *)letindex=Splittable_random.Log_uniform.intrandom~lo:0~hi:max_indexinsizes.(index)<-sizes.(index)+1done;(* permute the array so that no index is favored over another *)fori=0tomax_index-1doletj=Splittable_random.intrandom~lo:i~hi:max_indexinArray.swapsizesijdone;assert(Array.sum(moduleInt)sizes~f:Fn.id+(len-min_length)=size);Array.to_listsizes));;letunit=return()letbool=create(fun~size:_~random->Splittable_random.boolrandom)letoptionvalue_t=union[returnNone;mapvalue_t~f:Option.return]leteitherfst_tsnd_t=union[mapfst_t~f:Either.first;mapsnd_t~f:Either.second]letresultok_terr_t=map(eitherok_terr_t)~f:(function|Firstok->Okok|Seconderr->Errorerr);;letlist_generic?min_length?max_lengthelt_gen=let%bindsizes=sizes?min_length?max_length()inList.mapsizes~f:(funsize->with_size~sizeelt_gen)|>all;;letlistelt_gen=list_genericelt_genletlist_non_emptyelt_gen=list_generic~min_length:1elt_genletlist_with_lengthelt_gen~length=list_generic~min_length:length~max_length:lengthelt_gen;;letlist_filteredelts=letelts=Array.of_listeltsinletlength_of_input=Array.lengtheltsincreate(fun~size:_~random->letlength_of_output=Splittable_random.intrandom~lo:0~hi:length_of_inputinletindices=Array.initlength_of_input~f:Fn.idin(* Choose [length_of_output] random values in the prefix of [indices]. *)fori=0tolength_of_output-1doletj=Splittable_random.intrandom~lo:i~hi:(length_of_input-1)inArray.swapindicesijdone;(* Sort the chosen indices because we don't want to reorder them. *)Array.sortindices~pos:0~len:length_of_output~compare:Int.compare;(* Return the chosen elements. *)List.initlength_of_output~f:(funi->elts.(indices.(i))));;letlist_permutationslist=create(fun~size:_~random->letarray=Array.of_listlistinfori=1toArray.lengtharray-1doletj=Splittable_random.intrandom~lo:0~hi:iinArray.swaparrayijdone;Array.to_listarray);;letchar_uniform_inclusivelohi=create(fun~size:_~random->Splittable_random.intrandom~lo:(Char.to_intlo)~hi:(Char.to_inthi)|>Char.unsafe_of_int);;letchar_uppercase=char_uniform_inclusive'A''Z'letchar_lowercase=char_uniform_inclusive'a''z'letchar_digit=char_uniform_inclusive'0''9'letchar_print_uniform=char_uniform_inclusive' ''~'letchar_uniform=char_uniform_inclusiveChar.min_valueChar.max_valueletchar_alpha=union[char_lowercase;char_uppercase]letchar_alphanum=weighted_union(* Most people probably expect this to be a uniform distribution, not weighted
toward digits like we would get with [union] (since there are fewer digits than
letters). *)[52.,char_alpha;10.,char_digit];;letchar_whitespace=of_list(List.filterChar.all~f:Char.is_whitespace)letchar_print=weighted_union[10.,char_alphanum;1.,char_print_uniform]letchar=weighted_union[100.,char_print;10.,char_uniform;1.,returnChar.min_value;1.,returnChar.max_value];;(* Produces a number from 0 or 1 to size + 1, weighted high. We have found this
distribution empirically useful for string lengths. *)letsmall_int~allow_zero=create(fun~size~random->letlower_bound=ifallow_zerothen0else1inletupper_bound=size+1inletweighted_low=Splittable_random.Log_uniform.intrandom~lo:0~hi:(upper_bound-lower_bound)inletweighted_high=upper_bound-weighted_lowinweighted_high);;letsmall_positive_or_zero_int=small_int~allow_zero:trueletsmall_strictly_positive_int=small_int~allow_zero:falsemoduletypeInt_with_random=sigincludeInt.Svaluniform:Splittable_random.State.t->lo:t->hi:t->tvallog_uniform:Splittable_random.State.t->lo:t->hi:t->tendmoduleFor_integer(Integer:Int_with_random)=structletuniform_inclusivelohi=create(fun~size:_~random->Integer.uniformrandom~lo~hi);;letlog_uniform_inclusivelohi=create(fun~size:_~random->Integer.log_uniformrandom~lo~hi);;letnon_uniformflohi=weighted_union[0.05,returnlo;0.05,returnhi;0.9,flohi];;letinclusive=non_uniformuniform_inclusiveletlog_inclusive=non_uniformlog_uniform_inclusiveletuniform_all=uniform_inclusiveInteger.min_valueInteger.max_valueletall=[%mapletnegative=boolandmagnitude=log_inclusiveInteger.zeroInteger.max_valueinifnegativethenInteger.bit_notmagnitudeelsemagnitude];;endmoduleFor_int=For_integer(structincludeIntletuniform=Splittable_random.intletlog_uniform=Splittable_random.Log_uniform.intend)letint=For_int.allletint_uniform=For_int.uniform_allletint_inclusive=For_int.inclusiveletint_uniform_inclusive=For_int.uniform_inclusiveletint_log_inclusive=For_int.log_inclusiveletint_log_uniform_inclusive=For_int.log_uniform_inclusivemoduleFor_int32=For_integer(structincludeInt32letuniform=Splittable_random.int32letlog_uniform=Splittable_random.Log_uniform.int32end)letint32=For_int32.allletint32_uniform=For_int32.uniform_allletint32_inclusive=For_int32.inclusiveletint32_uniform_inclusive=For_int32.uniform_inclusiveletint32_log_inclusive=For_int32.log_inclusiveletint32_log_uniform_inclusive=For_int32.log_uniform_inclusivemoduleFor_int63=For_integer(structincludeInt63letuniform=Splittable_random.int63letlog_uniform=Splittable_random.Log_uniform.int63end)letint63=For_int63.allletint63_uniform=For_int63.uniform_allletint63_inclusive=For_int63.inclusiveletint63_uniform_inclusive=For_int63.uniform_inclusiveletint63_log_inclusive=For_int63.log_inclusiveletint63_log_uniform_inclusive=For_int63.log_uniform_inclusivemoduleFor_int64=For_integer(structincludeInt64letuniform=Splittable_random.int64letlog_uniform=Splittable_random.Log_uniform.int64end)letint64=For_int64.allletint64_uniform=For_int64.uniform_allletint64_inclusive=For_int64.inclusiveletint64_uniform_inclusive=For_int64.uniform_inclusiveletint64_log_inclusive=For_int64.log_inclusiveletint64_log_uniform_inclusive=For_int64.log_uniform_inclusivemoduleFor_nativeint=For_integer(structincludeNativeintletuniform=Splittable_random.nativeintletlog_uniform=Splittable_random.Log_uniform.nativeintend)letnativeint=For_nativeint.allletnativeint_uniform=For_nativeint.uniform_allletnativeint_inclusive=For_nativeint.inclusiveletnativeint_uniform_inclusive=For_nativeint.uniform_inclusiveletnativeint_log_inclusive=For_nativeint.log_inclusiveletnativeint_log_uniform_inclusive=For_nativeint.log_uniform_inclusiveletfloat_zero_exponent=Float.ieee_exponent0.letfloat_zero_mantissa=Float.ieee_mantissa0.letfloat_max_positive_subnormal_value=Float.one_ulp`DownFloat.min_positive_normal_value;;letfloat_subnormal_exponent=Float.ieee_exponentFloat.min_positive_subnormal_valueletfloat_min_subnormal_mantissa=Float.ieee_mantissaFloat.min_positive_subnormal_valueletfloat_max_subnormal_mantissa=Float.ieee_mantissafloat_max_positive_subnormal_valueletfloat_max_positive_normal_value=Float.max_finite_valueletfloat_min_normal_exponent=Float.ieee_exponentFloat.min_positive_normal_valueletfloat_max_normal_exponent=Float.ieee_exponentfloat_max_positive_normal_valueletfloat_max_normal_mantissa=Float.ieee_mantissafloat_max_positive_normal_valueletfloat_inf_exponent=Float.ieee_exponentFloat.infinityletfloat_inf_mantissa=Float.ieee_mantissaFloat.infinityletfloat_nan_exponent=Float.ieee_exponentFloat.nanletfloat_min_nan_mantissa=Int63.succfloat_inf_mantissaletfloat_max_nan_mantissa=float_max_normal_mantissaletfloat_num_mantissa_bits=52(* We weight mantissas so that "integer-like" values, and values with only a few digits
past the decimal, are reasonably common. *)letfloat_normal_mantissa=let%bindnum_bits=For_int.uniform_inclusive0float_num_mantissa_bitsinlet%mapbits=For_int63.inclusiveInt63.zero(Int63.pred(Int63.shift_leftInt63.onenum_bits))inInt63.shift_leftbits(Int.(-)float_num_mantissa_bitsnum_bits);;letfloat_exponent_weighted_lowlower_boundupper_bound=let%mapoffset=For_int.log_inclusive0(Int.(-)upper_boundlower_bound)inInt.(+)lower_boundoffset;;letfloat_exponent_weighted_highlower_boundupper_bound=let%mapoffset=For_int.log_inclusive0(Int.(-)upper_boundlower_bound)inInt.(-)upper_boundoffset;;(* We weight exponents such that values near 1 are more likely. *)letfloat_exponent=letmidpoint=Float.ieee_exponent1.inunion[float_exponent_weighted_highfloat_min_normal_exponentmidpoint;float_exponent_weighted_lowmidpointfloat_max_normal_exponent];;letfloat_zero=let%mapnegative=boolinFloat.create_ieee_exn~negative~exponent:float_zero_exponent~mantissa:float_zero_mantissa;;letfloat_subnormal=let%mapnegative=boolandexponent=returnfloat_subnormal_exponentandmantissa=For_int63.log_inclusivefloat_min_subnormal_mantissafloat_max_subnormal_mantissainFloat.create_ieee_exn~negative~exponent~mantissa;;letfloat_normal=let%mapnegative=boolandexponent=float_exponentandmantissa=float_normal_mantissainFloat.create_ieee_exn~negative~exponent~mantissa;;letfloat_infinite=let%mapnegative=boolinFloat.create_ieee_exn~negative~exponent:float_inf_exponent~mantissa:float_inf_mantissa;;letfloat_nan=let%mapnegative=boolandexponent=returnfloat_nan_exponentandmantissa=For_int63.inclusivefloat_min_nan_mantissafloat_max_nan_mantissainFloat.create_ieee_exn~negative~exponent~mantissa;;letfloat_of_classc=match(c:Float.Class.t)with|Zero->float_zero|Subnormal->float_subnormal|Normal->float_normal|Infinite->float_infinite|Nan->float_nan;;letfloat_weight_of_classc=match(c:Float.Class.t)with|Zero->1.|Subnormal->10.|Normal->100.|Infinite->1.|Nan->1.;;letfloat_matching_classesfilter=List.filter_mapFloat.Class.all~f:(func->iffiltercthenSome(float_weight_of_classc,float_of_classc)elseNone)|>weighted_union;;letfloat_finite=float_matching_classes(function|Zero|Subnormal|Normal->true|Infinite|Nan->false);;letfloat_without_nan=float_matching_classes(function|Zero|Subnormal|Normal|Infinite->true|Nan->false);;letfloat=float_matching_classes(fun_->true)letfloat_finite_non_zero=float_matching_classes(function|Subnormal|Normal->true|Zero|Infinite|Nan->false);;letfloat_strictly_positive=let%mapt=float_finite_non_zeroinFloat.abst;;letfloat_strictly_negative=let%mapt=float_finite_non_zeroin~-.(Float.abst);;letfloat_positive_or_zero=let%mapt=float_finiteinFloat.abst;;letfloat_negative_or_zero=let%mapt=float_finitein~-.(Float.abst);;letfloat_uniform_exclusivelower_boundupper_bound=letopenFloat.Oinif(not(Float.is_finitelower_bound))||not(Float.is_finiteupper_bound)thenraise_s[%message"Float.uniform_exclusive: bounds are not finite"(lower_bound:float)(upper_bound:float)];letlower_inclusive=Float.one_ulp`Uplower_boundinletupper_inclusive=Float.one_ulp`Downupper_boundiniflower_inclusive>upper_inclusivethenraise_s[%message"Float.uniform_exclusive: requested range is empty"(lower_bound:float)(upper_bound:float)];create(fun~size:_~random->Splittable_random.floatrandom~lo:lower_inclusive~hi:upper_inclusive);;letfloat_inclusivelower_boundupper_bound=weighted_union[0.05,returnlower_bound;0.05,returnupper_bound;0.9,float_uniform_exclusivelower_boundupper_bound];;letstring_with_length_ofchar_gen~length=list_with_lengthchar_gen~length|>map~f:String.of_char_list;;letstring_ofchar_gen=bindsmall_positive_or_zero_int~f:(funlength->string_with_length_ofchar_gen~length);;letstring_non_empty_ofchar_gen=bindsmall_strictly_positive_int~f:(funlength->string_with_length_ofchar_gen~length);;letstring=string_ofcharletstring_non_empty=string_non_empty_ofcharletstring_with_length~length=string_with_length_ofchar~lengthletsexp_ofatom=fixed_point(funself->let%bindsize=sizein(* choose a number weighted low so we have a decreasing, but not vanishing, chance
to generate atoms as size grows *)match%bindFor_int.log_uniform_inclusive0(size+1)with(* generate an atom using the given size *)|0->let%mapatom=atominSexp.Atomatom(* relying on [List.gen] to distribute [size] over sub-sexps *)|_->let%maplist=listselfinSexp.Listlist);;letsexp=sexp_ofstringletmap_tree_using_comparator~comparatorkey_gendata_gen=let%bindkeys=listkey_geninletkeys=List.dedup_and_sortkeys~compare:comparator.Comparator.compareinlet%binddata=list_with_lengthdata_gen~length:(List.lengthkeys)inreturn(Map.Using_comparator.Tree.of_alist_exn~comparator(List.zip_exnkeysdata));;letset_tree_using_comparator~comparatorelt_gen=map(listelt_gen)~f:(Set.Using_comparator.Tree.of_list~comparator);;letcomparator_of_m(typeac)(moduleM:Comparator.Swithtypet=aandtypecomparator_witness=c)=M.comparator;;letmap_t_mmkey_gendata_gen=letcomparator=comparator_of_mminmap_tree_using_comparator~comparatorkey_gendata_gen|>map~f:(Map.Using_comparator.of_tree~comparator);;letset_t_mmelt_gen=letcomparator=comparator_of_mminset_tree_using_comparator~comparatorelt_gen|>map~f:(Set.Using_comparator.of_tree~comparator);;letbigarray1tkindlayout=let%mapelts=listtinletelts=Array.of_listeltsinletdim=Array.lengtheltsinletoffset=Bigarray_helpers.Layout.offsetlayoutinBigarray_helpers.Array1.initkindlayoutdim~f:(funi->elts.(i-offset));;letbigstring=bigarray1charCharC_layoutletfloat32_vec=bigarray1floatFloat32Fortran_layoutletfloat64_vec=bigarray1floatFloat64Fortran_layoutletbigarray2_dim=match%bindsizewith|0->return(0,0)|max_total_size->let%binda=(* choose a dimension up to [max_total_size], weighted low to give the other
dimension a good chance of being comparatively high *)int_log_uniform_inclusive1max_total_sizeinlet%bindb=(* choose a dimension up to [max_total_size / a], weighted high to reach close to
[max_total_size] most of the time *)letmax_b=max_total_size/ainlet%mapb_weighted_low=int_log_uniform_inclusive0max_binmax_b-b_weighted_lowin(* avoid any skew of a vs b by randomly swapping *)if%mapboolthena,belseb,a;;letbigarray2tkindlayout=let%binddim1,dim2=bigarray2_diminlet%mapelts=list_with_length~length:dim1(list_with_length~length:dim2t)inletelts=Array.of_list_map~f:Array.of_listeltsinletoffset=Bigarray_helpers.Layout.offsetlayoutinBigarray_helpers.Array2.initkindlayoutdim1dim2~f:(funij->elts.(i-offset).(j-offset));;letfloat32_mat=bigarray2floatFloat32Fortran_layoutletfloat64_mat=bigarray2floatFloat64Fortran_layout