123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608(* This file is free software, part of containers. See file "license" for more details. *)(** {1 Array utils} *)type'aiter=('a->unit)->unittype'agen=unit->'aoptiontype'aequal='a->'a->booltype'aord='a->'a->inttype'arandom_gen=Random.State.t->'atype'aprinter=Format.formatter->'a->unit(** {2 Arrays} *)includeArrayletempty=[||]letget_safeai=ifi>=0&&i<Array.lengthathenSome(Array.unsafe_getai)elseNoneletmap_inplacefa=Array.iteri(funie->Array.unsafe_setai(fe))aletmapi_inplacefa=Array.iteri(funie->Array.unsafe_setai(fie))aletfold=Array.fold_leftletfoldifacca=letrecauxacci=ifi=Array.lengthathenaccelseaux(faccia.(i))(i+1)inauxacc0letfold_whilefacca=letrecfold_while_ifacci=ifi<Array.lengthathen(letacc,cont=facca.(i)inmatchcontwith|`Stop->acc|`Continue->fold_while_ifacc(i+1))elseaccinfold_while_ifacc0letfold_mapfacca=letn=lengthain(* need special case for initializing the result *)ifn=0thenacc,[||]else(letacc,b0=facca.(0)inletres=Array.makenb0inletacc=refaccinfori=1ton-1doletnew_acc,b=f!acca.(i)inacc:=new_acc;res.(i)<-bdone;!acc,res)letscan_leftfacca=letn=lengthainletres=Array.make(n+1)accinArray.iteri(funix->letnew_acc=fres.(i)xinres.(i+1)<-new_acc)a;resletreverse_in_placea=letlen=Array.lengthainiflen>0thenfork=0to(len-1)/2dolett=a.(k)ina.(k)<-a.(len-1-k);a.(len-1-k)<-tdoneletsortedcmpa=letb=Array.copyainArray.sortcmpb;bletsort_indicescmpa=letlen=Array.lengthainletb=Array.initlen(funk->k)inArray.sort(funk1k2->cmpa.(k1)a.(k2))b;bletsort_rankingcmpa=sort_indicescompare(sort_indicescmpa)letreva=letb=Array.copyainreverse_in_placeb;bexceptionFoundletmem?(eq=Stdlib.(=))elta=tryArray.iter(fune->ifeqeeltthenraise_notraceFound)a;falsewithFound->trueletrecfind_auxfai=ifi>=Array.lengthathenNoneelse(matchfia.(i)with|Some_asres->res|None->find_auxfa(i+1))[@@@ocaml.warning"-32"]letfind_mapfa=find_aux(fun_->f)a0letfind=find_mapletfind_map_ifa=find_auxfa0letfindi=find_map_i[@@@ocaml.warning"+32"]letfind_idxpa=find_aux(funix->ifpxthenSome(i,x)elseNone)a0letmaxcmpa=ifArray.lengtha=0thenNoneelseSome(fold(funaccelt->ifcmpaccelt<0theneltelseacc)a.(0)a)letmax_exncmpa=matchmaxcmpawith|None->invalid_arg"CCArray.max_exn"|Someelt->eltletargmaxcmpa=ifArray.lengtha=0thenNoneelseSome(foldi(funaccielt->ifcmpa.(acc)elt<0thenielseacc)0a)letargmax_exncmpa=matchargmaxcmpawith|None->invalid_arg"CCArray.argmax_exn"|Someelt->eltletmincmpa=ifArray.lengtha=0thenNoneelseSome(fold(funaccelt->ifcmpaccelt>0theneltelseacc)a.(0)a)letmin_exncmpa=matchmincmpawith|None->invalid_arg"CCArray.min_exn"|Someelt->eltletargmincmpa=ifArray.lengtha=0thenNoneelseSome(foldi(funaccielt->ifcmpa.(acc)elt>0thenielseacc)0a)letargmin_exncmpa=matchargmincmpawith|None->invalid_arg"CCArray.argmin_exn"|Someelt->eltletfilter_mapfa=letrecauxacci=ifi=Array.lengthathen(leta'=Array.of_listaccinreverse_in_placea';a')else(matchfa.(i)with|None->auxacc(i+1)|Somex->aux(x::acc)(i+1))inaux[]0letfilterpa=filter_map(funx->ifpxthenSomexelseNone)a(* append [rev a] in front of [acc] *)letrec__rev_append_listaacci=ifi=Array.lengthathenaccelse__rev_append_lista(a.(i)::acc)(i+1)letflat_mapfa=letrecauxacci=ifi=Array.lengthathen(leta'=Array.of_listaccinreverse_in_placea';a')else(leta'=fa.(i)inaux(__rev_append_lista'acc0)(i+1))inaux[]0letmonoid_productfa1a2=letna1=lengtha1ininit(na1*lengtha2)(funi_prod->leti=i_prodmodna1inletj=i_prod/na1infa1.(i)a2.(j))letrec_lookup_rec~cmpkaij=ifi>jthenraiseNot_foundelseifi=jthenifcmpka.(i)=0thenielseraiseNot_foundelse(letmiddle=(j+i)/2inmatchcmpka.(middle)with|0->middle|nwhenn<0->_lookup_rec~cmpkai(middle-1)|_->_lookup_rec~cmpka(middle+1)j)let_lookup_exn~cmpkaij=ifi>jthenraiseNot_found;matchcmpka.(i)with|0->i|nwhenn<0->raiseNot_found(* too low *)|_wheni=j->raiseNot_found(* too high *)|_->(matchcmpka.(j)with|0->j|nwhenn<0->_lookup_rec~cmpka(i+1)(j-1)|_->raiseNot_found)(* too high *)letlookup_exn~cmpka=_lookup_exn~cmpka0(Array.lengtha-1)letlookup~cmpka=trySome(_lookup_exn~cmpka0(Array.lengtha-1))withNot_found->Noneletbsearch~cmpka=letrecauxij=ifi>jthen`Just_afterjelse(letmiddle=i+((j-i)/2)in(* avoid overflow *)matchcmpka.(middle)with|0->`Atmiddle|nwhenn<0->auxi(middle-1)|_->aux(middle+1)j)inletn=Array.lengthainifn=0then`Emptyelse(matchcmpa.(0)k,cmpa.(n-1)kwith|c,_whenc>0->`All_bigger|_,cwhenc<0->`All_lower|_->aux0(n-1))letrec_for_all2pa1a2i1i2~len=len=0||(pa1.(i1)a2.(i2)&&_for_all2pa1a2(i1+1)(i2+1)~len:(len-1))letfor_all2pab=Array.lengtha=Array.lengthb&&_for_all2pab00~len:(Array.lengtha)letrec_exists2pa1a2i1i2~len=len>0&&(pa1.(i1)a2.(i2)||_exists2pa1a2(i1+1)(i2+1)~len:(len-1))letexists2pab=_exists2pab00~len:(Stdlib.min(Array.lengtha)(Array.lengthb))let_fold2faccabij~len=letrecauxacco=ifo=lenthenaccelse(letacc=facc(Array.geta(i+o))(Array.getb(j+o))inauxacc(o+1))inauxacc0letfold2faccab=iflengtha<>lengthbtheninvalid_arg"fold2";_fold2faccab00~len:(Array.lengtha)let(--)ij=ifi<=jthenArray.init(j-i+1)(funk->i+k)elseArray.init(i-j+1)(funk->i-k)let(--^)ij=ifi=jthen[||]elseifi>jthenArray.init(i-j)(funk->i-k)elseArray.init(j-i)(funk->i+k)(** all the elements of a, but the i-th, into a list *)letexcept_idxai=foldi(funaccjelt->ifi=jthenaccelseelt::acc)[]aletequaleqab=letrecauxi=ifi=Array.lengthathentrueelseeqa.(i)b.(i)&&aux(i+1)inArray.lengtha=Array.lengthb&&aux0letcomparecmpab=letrecauxi=ifi=Array.lengthathenifi=Array.lengthbthen0else-1elseifi=Array.lengthbthen1else(letc=cmpa.(i)b.(i)inifc=0thenaux(i+1)elsec)inaux0(* swap elements of array *)letswapaij=ifi<>jthen(lettmp=a.(i)ina.(i)<-a.(j);a.(j)<-tmp)(* shuffle a[i … j] using the given int random generator
See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle *)let_shuffle_rand_intaij=fork=j-1downtoi+1doletl=_rand_int(k+1)inlettmp=a.(l)ina.(l)<-a.(k);a.(k)<-tmpdoneletshufflea=_shuffleRandom.inta0(Array.lengtha)letshuffle_withsta=_shuffle(Random.State.intst)a0(Array.lengtha)letrandom_choosea=letn=Array.lengthainifn=0theninvalid_arg"Array.random_choose";funst->a.(Random.State.intstn)letrandom_lenngst=Array.initn(fun_->gst)letrandomgst=letn=Random.State.intst1_000inrandom_lenngstletrandom_non_emptygst=letn=1+Random.State.intst1_000inrandom_lenngstletpp?(pp_start=fun_()->())?(pp_stop=fun_()->())?(pp_sep=funout()->Format.fprintfout",@ ")pp_itemouta=pp_startout();fork=0toArray.lengtha-1doifk>0thenpp_sepout();pp_itemouta.(k)done;pp_stopout()letpp_i?(pp_start=fun_()->())?(pp_stop=fun_()->())?(pp_sep=funout()->Format.fprintfout",@ ")pp_itemouta=pp_startout();fork=0toArray.lengtha-1doifk>0thenpp_sepout();pp_itemkouta.(k)done;pp_stopout()letto_string?(sep=", ")item_to_stringa=Array.to_lista|>List.mapitem_to_string|>String.concatsepletto_seqa=letrecauxi()=ifi>=lengthathenSeq.NilelseSeq.Cons(a.(i),aux(i+1))inaux0letto_iterak=iterkaletto_gena=letk=ref0infun()->if!k<Array.lengthathen(letx=a.(!k)inincrk;Somex)elseNone(** {2 Generic Functions} *)moduletypeMONO_ARRAY=sigtypeelttypetvallength:t->intvalget:t->int->eltvalset:t->int->elt->unitend(* Dual Pivot Quicksort (Yaroslavskiy)
from "average case analysis of Java 7's Dual Pivot Quicksort" *)moduleSortGeneric(A:MONO_ARRAY)=structmoduleRand=Random.Stateletseed_=[|123456|]typestate={mutablel:int;(* left pointer *)mutableg:int;(* right pointer *)mutablek:int;}letrand_idx_randij=i+Rand.intrand(j-i)letswap_aij=ifi=jthen()else(lettmp=A.getaiinA.setai(A.getaj);A.setajtmp)letsort~cmpa=letrecinsert_aik=ifk<ithen()elseifcmp(A.getak)(A.geta(k+1))>0then(swap_ak(k+1);insert_ai(k-1))in(* recursive part of insertion sort *)letrecsort_insertion_recaijk=ifk<jthen(insert_ai(k-1);sort_insertion_recaij(k+1))in(* insertion sort, for small slices *)letsort_insertionaij=ifj-i>1thensort_insertion_recaij(i+1)inletrand=Rand.makeseed_in(* sort slice.
There is a chance that the two pivots are equal, but it's unlikely. *)letrecsort_slice_~staij=ifj-i>10then(st.l<-i;st.g<-j-1;st.k<-i;(* choose pivots *)letp=A.geta(rand_idx_randij)inletq=A.geta(rand_idx_randij)in(* invariant: st.p <= st.q, swap them otherwise *)letp,q=ifcmppq>0thenq,pelsep,qinwhilest.k<=st.gdoletcur=A.getast.kinifcmpcurp<0then((* insert in leftmost band *)ifst.k<>st.lthenswap_ast.kst.l;st.l<-st.l+1)elseifcmpcurq>0then((* insert in rightmost band *)whilest.k<st.g&&cmp(A.getast.g)q>0dost.g<-st.g-1done;swap_ast.kst.g;st.g<-st.g-1;(* the element swapped from the right might be in the first situation.
that is, < p (we know it's <= q already) *)ifcmp(A.getast.k)p<0then(ifst.k<>st.lthenswap_ast.kst.l;st.l<-st.l+1));st.k<-st.k+1done;(* save values before recursing *)letl=st.landg=st.gandsort_middle=cmppq<0insort_slice_~stail;ifsort_middlethensort_slice_~stal(g+1);sort_slice_~sta(g+1)j)elsesort_insertionaijinifA.lengtha>0then(letst={l=0;g=A.lengtha;k=0}insort_slice_~sta0(A.lengtha))endletsort_generic(typearrelt)(moduleA:MONO_ARRAYwithtypet=arrandtypeelt=elt)~cmpa=letmoduleS=SortGeneric(A)inS.sort~cmpamoduleInfix=structlet(>>=)af=flat_mapfalet(>>|)af=mapfalet(>|=)af=mapfalet(--)=(--)let(--^)=(--^)type'at='aarraylet(let*)=(>>=)let(let+)=(>|=)let[@inline](and+)a1a2=monoid_product(funxy->x,y)a1a2let(and*)=(and+)endincludeInfix