123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102type'at={cmp:'a->'a->int;(* comparison function of bin limit type *)bin_limits:'aarray;(* bin limits, length is n+1 for n bins *)counts:floatarray(* counts, length n for n bins *)}letcopyhist={cmp=hist.cmp;bin_limits=Array.copyhist.bin_limits;counts=Array.copyhist.counts}letmakecmpbins=letrecis_orderedl=matchlwith|[]->true|_::[]->true|x1::x2::l->matchcmpx1x2with|xwhenx<0->is_ordered(x2::l)|_->falseinifis_orderedbinsthenSome{cmp=cmp;bin_limits=Array.of_listbins;counts=Array.create~len:(List.lengthbins-1)0.0}elseNoneletlimits_to_binsbl=letbl=Array.to_listblinletrecloopansbl=matchblwith|[]->failwith"impossible to get here"|_::[]->ans|lo::hi::bl->loop((lo,hi)::ans)(hi::bl)inList.rev(loop[]bl)letto_listhist=List.zip_exn(limits_to_binshist.bin_limits)(Array.to_listhist.counts)letbin_exnhistk=ifk>=Array.lengthhist.countstheninvalid_argf"invalid bin number %d"k()elsehist.bin_limits.(k),hist.bin_limits.(k+1)letbinhistk=trySome(bin_exnhistk)with_->Noneletcount_exnhistk=ifk>=Array.lengthhist.countstheninvalid_argf"invalid bin number %d"k()elsehist.counts.(k)letcounthistk=Option.try_with(fun()->count_exnhistk)letnum_binshist=Array.lengthhist.countsletminimumhist=hist.bin_limits.(0)letmaximumhist=hist.bin_limits.(Array.lengthhist.bin_limits-1)letfind_bin_indexhistx=leti=ref(-1)inlet()=forj=0toArray.lengthhist.bin_limits-2doletcmp_lo=hist.cmpxhist.bin_limits.(j)inletcmp_hi=hist.cmpxhist.bin_limits.(j+1)inif(cmp_lo=1||cmp_lo=0)&&(cmp_hi=-1)theni:=jdoneinif!i>=0thenSome!ielseNoneletincrement?(delt=1.0)histx=lethist=copyhistinmatchfind_bin_indexhistxwith|None->hist|Somei->hist.counts.(i)<-hist.counts.(i)+.delt;histletresethist={histwithcounts=Array.create~len:(Array.lengthhist.counts)0.}letin_rangehistx=letcmp_lo=hist.cmpx(minimumhist)inletcmp_hi=hist.cmpx(maximumhist)in(cmp_lo=1||cmp_lo=0)&&(cmp_hi=-1)letmake_uniformminmaxn=ifFloat.(>=)minmaxthenError(sprintf"minimum %.3f must be strictly less than maximum %.3f"minmax)elseifn<1thenError(sprintf"cannot create histogram with %d bins"n)elsebeginletdelt=(max-.min)/.(Float.of_intn)inletbins=Array.init(n+1)~f:(funi->min+.(delt*.Float.of_inti))inbins.(Array.lengthbins-1)<-max;Result.of_option(makeStdlib.compare(Array.to_listbins))~error:"not ordered"end