123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736(*
This file is derived from the set.ml file from the OCaml distribution.
Changes are marked with the [MOPSA] symbol.
Modifications are Copyright (C) 2017-2019 The MOPSA Project.
Original copyright follows.
*)(**************************************************************************)(* *)(* OCaml *)(* *)(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)(* *)(* Copyright 1996 Institut National de Recherche en Informatique et *)(* en Automatique. *)(* *)(* All rights reserved. This file is distributed under the terms of *)(* the GNU Lesser General Public License version 2.1, with the *)(* special exception on linking described in the file LICENSE. *)(* *)(**************************************************************************)(** Sets with polymorphic values *)(* Sets are represented by balanced binary trees (the heights of the
children differ by at most 2 *)type'aset=Empty|Nodeof{l:'aset;v:'a;r:'aset;h:int}type'acompare='a->'a->inttype'at={set:'aset;compare:'acompare;}typeset_printer={print_empty:string;(** Special text for empty sets *)print_begin:string;(** Text before the first element *)print_sep:string;(** Text between two elements *)print_end:string;(** Text after the last element *)}letheight=functionEmpty->0|Node{h}->h(* Creates a new node with left son l, value v and right son r.
We must have all elements of l < v < all elements of r.
l and r must be balanced and | height l - height r | <= 2.
Inline expansion of height for better speed. *)letcreatelvr=lethl=matchlwithEmpty->0|Node{h}->hinlethr=matchrwithEmpty->0|Node{h}->hinNode{l;v;r;h=(ifhl>=hrthenhl+1elsehr+1)}(* Same as create, but performs one step of rebalancing if necessary.
Assumes l and r balanced and | height l - height r | <= 3.
Inline expansion of create for better speed in the most frequent case
where no rebalancing is required. *)letballvr=lethl=matchlwithEmpty->0|Node{h}->hinlethr=matchrwithEmpty->0|Node{h}->hinifhl>hr+2thenbeginmatchlwithEmpty->invalid_arg"Set.bal"|Node{l=ll;v=lv;r=lr}->ifheightll>=heightlrthencreatelllv(createlrvr)elsebeginmatchlrwithEmpty->invalid_arg"Set.bal"|Node{l=lrl;v=lrv;r=lrr}->create(createlllvlrl)lrv(createlrrvr)endendelseifhr>hl+2thenbeginmatchrwithEmpty->invalid_arg"Set.bal"|Node{l=rl;v=rv;r=rr}->ifheightrr>=heightrlthencreate(createlvrl)rvrrelsebeginmatchrlwithEmpty->invalid_arg"Set.bal"|Node{l=rll;v=rlv;r=rlr}->create(createlvrll)rlv(createrlrrvrr)endendelseNode{l;v;r;h=(ifhl>=hrthenhl+1elsehr+1)}(* Insertion of one element *)letrecaddcomparex=functionEmpty->Node{l=Empty;v=x;r=Empty;h=1}|Node{l;v;r}ast->letc=comparexvinifc=0thentelseifc<0thenletll=addcomparexlinifl==llthentelseballlvrelseletrr=addcomparexrinifr==rrthentelseballvrrletsingletonx=Node{l=Empty;v=x;r=Empty;h=1}(* Beware: those two functions assume that the added v is *strictly*
smaller (or bigger) than all the present elements in the tree; it
does not test for equality with the current min (or max) element.
Indeed, they are only used during the "join" operation which
respects this precondition.
*)letrecadd_min_elementx=function|Empty->singletonx|Node{l;v;r}->bal(add_min_elementxl)vrletrecadd_max_elementx=function|Empty->singletonx|Node{l;v;r}->ballv(add_max_elementxr)(* Same as create and bal, but no assumptions are made on the
relative heights of l and r. *)letrecjoinlvr=match(l,r)with(Empty,_)->add_min_elementvr|(_,Empty)->add_max_elementvl|(Node{l=ll;v=lv;r=lr;h=lh},Node{l=rl;v=rv;r=rr;h=rh})->iflh>rh+2thenballllv(joinlrvr)elseifrh>lh+2thenbal(joinlvrl)rvrrelsecreatelvr(* Smallest and greatest element of a set *)letrecmin_elt=functionEmpty->raiseNot_found|Node{l=Empty;v}->v|Node{l}->min_eltlletrecmin_elt_opt=functionEmpty->None|Node{l=Empty;v}->Somev|Node{l}->min_elt_optlletrecmax_elt=functionEmpty->raiseNot_found|Node{v;r=Empty}->v|Node{r}->max_eltrletrecmax_elt_opt=functionEmpty->None|Node{v;r=Empty}->Somev|Node{r}->max_elt_optr(* Remove the smallest element of the given set *)letrecremove_min_elt=functionEmpty->invalid_arg"Set.remove_min_elt"|Node{l=Empty;r}->r|Node{l;v;r}->bal(remove_min_eltl)vr(* Merge two trees l and r into one.
All elements of l must precede the elements of r.
Assume | height l - height r | <= 2. *)letmerget1t2=match(t1,t2)with(Empty,t)->t|(t,Empty)->t|(_,_)->balt1(min_eltt2)(remove_min_eltt2)(* Merge two trees l and r into one.
All elements of l must precede the elements of r.
No assumption on the heights of l and r. *)letconcatt1t2=match(t1,t2)with(Empty,t)->t|(t,Empty)->t|(_,_)->joint1(min_eltt2)(remove_min_eltt2)(* Splitting. split x s returns a triple (l, present, r) where
- l is the set of elements of s that are < x
- r is the set of elements of s that are > x
- present is false if s contains no element equal to x,
or true if s contains an element equal to x. *)letrecsplitcomparex=functionEmpty->(Empty,false,Empty)|Node{l;v;r}->letc=comparexvinifc=0then(l,true,r)elseifc<0thenlet(ll,pres,rl)=splitcomparexlin(ll,pres,joinrlvr)elselet(lr,pres,rr)=splitcomparexrin(joinlvlr,pres,rr)(* Implementation of the set operations *)letempty=Emptyletis_empty=functionEmpty->true|_->falseletrecmemcomparex=functionEmpty->false|Node{l;v;r}->letc=comparexvinc=0||memcomparex(ifc<0thenlelser)letrecremovecomparex=functionEmpty->Empty|(Node{l;v;r}ast)->letc=comparexvinifc=0thenmergelrelseifc<0thenletll=removecomparexlinifl==llthentelseballlvrelseletrr=removecomparexrinifr==rrthentelseballvrrletrecunioncompares1s2=ifs1==s2thens1(* [MOPSA] *)elsematch(s1,s2)with(Empty,t2)->t2|(t1,Empty)->t1|(Node{l=l1;v=v1;r=r1;h=h1},Node{l=l2;v=v2;r=r2;h=h2})->ifh1>=h2thenifh2=1thenaddcomparev2s1elsebeginlet(l2,_,r2)=splitcomparev1s2injoin(unioncomparel1l2)v1(unioncomparer1r2)endelseifh1=1thenaddcomparev1s2elsebeginlet(l1,_,r1)=splitcomparev2s1injoin(unioncomparel1l2)v2(unioncomparer1r2)endletrecintercompares1s2=ifs1==s2thens1(* [MOPSA] *)elsematch(s1,s2)with(Empty,_)->Empty|(_,Empty)->Empty|(Node{l=l1;v=v1;r=r1},t2)->matchsplitcomparev1t2with(l2,false,r2)->concat(intercomparel1l2)(intercomparer1r2)|(l2,true,r2)->join(intercomparel1l2)v1(intercomparer1r2)letrecdiffcompares1s2=ifs1==s2thenEmpty(* [MOPSA] *)elsematch(s1,s2)with(Empty,_)->Empty|(t1,Empty)->t1|(Node{l=l1;v=v1;r=r1},t2)->matchsplitcomparev1t2with(l2,false,r2)->join(diffcomparel1l2)v1(diffcomparer1r2)|(l2,true,r2)->concat(diffcomparel1l2)(diffcomparer1r2)type'aenumeration=End|Moreof'a*'aset*'aenumerationletreccons_enumse=matchswithEmpty->e|Node{l;v;r}->cons_enuml(More(v,r,e))letreciterf=functionEmpty->()|Node{l;v;r}->iterfl;fv;iterfrletrecfoldfsaccu=matchswithEmpty->accu|Node{l;v;r}->foldfr(fv(foldflaccu))letrecfor_allp=functionEmpty->true|Node{l;v;r}->pv&&for_allpl&&for_allprletrecexistsp=functionEmpty->false|Node{l;v;r}->pv||existspl||existsprletrecfilterp=functionEmpty->Empty|(Node{l;v;r})ast->(* call [p] in the expected left-to-right order *)letl'=filterplinletpv=pvinletr'=filterprinifpvthenifl==l'&&r==r'thentelsejoinl'vr'elseconcatl'r'letrecpartitionp=functionEmpty->(Empty,Empty)|Node{l;v;r}->(* call [p] in the expected left-to-right order *)let(lt,lf)=partitionplinletpv=pvinlet(rt,rf)=partitionprinifpvthen(joinltvrt,concatlfrf)else(concatltrt,joinlfvrf)letreccardinal=functionEmpty->0|Node{l;r}->cardinall+1+cardinalrletrecelements_auxaccu=functionEmpty->accu|Node{l;v;r}->elements_aux(v::elements_auxaccur)lletelementss=elements_aux[]sletchoose=min_eltletchoose_opt=min_elt_optletrecfindcomparex=functionEmpty->raiseNot_found|Node{l;v;r}->letc=comparexvinifc=0thenvelsefindcomparex(ifc<0thenlelser)letrecfind_first_auxv0f=functionEmpty->v0|Node{l;v;r}->iffvthenfind_first_auxvflelsefind_first_auxv0frletrecfind_firstf=functionEmpty->raiseNot_found|Node{l;v;r}->iffvthenfind_first_auxvflelsefind_firstfrletrecfind_first_opt_auxv0f=functionEmpty->Somev0|Node{l;v;r}->iffvthenfind_first_opt_auxvflelsefind_first_opt_auxv0frletrecfind_first_optf=functionEmpty->None|Node{l;v;r}->iffvthenfind_first_opt_auxvflelsefind_first_optfrletrecfind_last_auxv0f=functionEmpty->v0|Node{l;v;r}->iffvthenfind_last_auxvfrelsefind_last_auxv0flletrecfind_lastf=functionEmpty->raiseNot_found|Node{l;v;r}->iffvthenfind_last_auxvfrelsefind_lastflletrecfind_last_opt_auxv0f=functionEmpty->Somev0|Node{l;v;r}->iffvthenfind_last_opt_auxvfrelsefind_last_opt_auxv0flletrecfind_last_optf=functionEmpty->None|Node{l;v;r}->iffvthenfind_last_opt_auxvfrelsefind_last_optflletrecfind_optcomparex=functionEmpty->None|Node{l;v;r}->letc=comparexvinifc=0thenSomevelsefind_optcomparex(ifc<0thenlelser)lettry_joincomparelvr=(* [join l v r] can only be called when (elements of l < v <
elements of r); use [try_join l v r] when this property may
not hold, but you hope it does hold in the common case *)if(l=Empty||compare(max_eltl)v<0)&&(r=Empty||comparev(min_eltr)<0)thenjoinlvrelseunioncomparel(addcomparevr)letrecmapcomparef=function|Empty->Empty|Node{l;v;r}ast->(* enforce left-to-right evaluation order *)letl'=mapcompareflinletv'=fvinletr'=mapcomparefrinifl==l'&&v==v'&&r==r'thentelsetry_joincomparel'v'r'letof_sorted_listl=letrecsubnl=matchn,lwith|0,l->Empty,l|1,x0::l->Node{l=Empty;v=x0;r=Empty;h=1},l|2,x0::x1::l->Node{l=Node{l=Empty;v=x0;r=Empty;h=1};v=x1;r=Empty;h=2},l|3,x0::x1::x2::l->Node{l=Node{l=Empty;v=x0;r=Empty;h=1};v=x1;r=Node{l=Empty;v=x2;r=Empty;h=1};h=2},l|n,l->letnl=n/2inletleft,l=subnllinmatchlwith|[]->assertfalse|mid::l->letright,l=sub(n-nl-1)lincreateleftmidright,linfst(sub(List.lengthl)l)letof_listcomparel=matchlwith|[]->empty|[x0]->singletonx0|[x0;x1]->addcomparex1(singletonx0)|[x0;x1;x2]->addcomparex2(addcomparex1(singletonx0))|[x0;x1;x2;x3]->addcomparex3(addcomparex2(addcomparex1(singletonx0)))|[x0;x1;x2;x3;x4]->addcomparex4(addcomparex3(addcomparex2(addcomparex1(singletonx0))))|_->of_sorted_list(List.sort_uniqcomparel)(* [MOPSA] additions *)(* ***************** *)(* internal function *)(* similar to split, but returns unbalanced trees *)letreccutcomparek=functionEmpty->Empty,false,Empty|Node{l=l1;v=k1;r=r1;h=h1;}->letc=comparekk1inifc<0thenletl2,d2,r2=cutcomparekl1in(l2,d2,Node{l=r2;v=k1;r=r1;h=h1})elseifc>0thenletl2,d2,r2=cutcomparekr1in(Node{l=l1;v=k1;r=l2;h=h1;},d2,r2)else(l1,true,r1)(* binary operations *)letreciter2comparef1f2fs1s2=matchs1with|Empty->iterf2s2|Node{l=l1;r=r1;v=k;}->letl2,t,r2=cutcompareks2initer2comparef1f2fl1l2;iftthenfkelsef1k;iter2comparef1f2fr1r2letrecfold2comparef1f2fs1s2acc=matchs1with|Empty->foldf2s2acc|Node{l=l1;r=r1;v=k;}->letl2,t,r2=cutcompareks2inletacc=fold2comparef1f2fl1l2accinletacc=iftthenfkaccelsef1kaccinfold2comparef1f2fr1r2accletrecfor_all2comparef1f2fs1s2=matchs1with|Empty->for_allf2s2|Node{l=l1;r=r1;v=k;}->letl2,t,r2=cutcompareks2in(for_all2comparef1f2fl1l2)&&(iftthenfkelsef1k)&&(for_all2comparef1f2fr1r2)letrecexists2comparef1f2fs1s2=matchs1with|Empty->existsf2s2|Node{l=l1;r=r1;v=k;}->letl2,t,r2=cutcompareks2in(exists2comparef1f2fl1l2)||(iftthenfkelsef1k)||(exists2comparef1f2fr1r2)(* the _diff functions ignore elements present in both
sets; they can thus skip physically equal subtrees,
which improves efficiency when the two sets are similar
*)letreciter2_diffcomparef1f2s1s2=ifs1==s2then()elsematchs1with|Empty->iterf2s2|Node{l=l1;r=r1;v=k;}->letl2,t,r2=cutcompareks2initer2_diffcomparef1f2l1l2;ifnottthenf1k;iter2_diffcomparef1f2r1r2letrecfold2_diffcomparef1f2s1s2acc=ifs1==s2thenaccelsematchs1with|Empty->foldf2s2acc|Node{l=l1;r=r1;v=k;}->letl2,t,r2=cutcompareks2inletacc=fold2_diffcomparef1f2l1l2accinletacc=iftthenaccelsef1kaccinfold2_diffcomparef1f2r1r2accletrecfor_all2_diffcomparef1f2s1s2=ifs1==s2thentrueelsematchs1with|Empty->for_allf2s2|Node{l=l1;r=r1;v=k;}->letl2,t,r2=cutcompareks2in(for_all2_diffcomparef1f2l1l2)&&(t||f1k)&&(for_all2_diffcomparef1f2r1r2)letrecexists2_diffcomparef1f2s1s2=ifs1==s2thentrueelsematchs1with|Empty->existsf2s2|Node{l=l1;r=r1;v=k;}->letl2,t,r2=cutcompareks2in(exists2_diffcomparef1f2l1l2)||(f1k)||(exists2_diffcomparef1f2r1r2)letdiff_listcompares1s2=fold2_diffcompare(funxl->x::l)(fun_l->l)s1s2[]letsym_diff_listcompares1s2=fold2_diffcompare(funx(l1,l2)->x::l1,l2)(funx(l1,l2)->l1,x::l2)s1s2([],[])letadd_sym_diffcompares2(a,r)=List.fold_left(funsx->addcomparexs)(List.fold_left(funsx->removecomparexs)s2r)a(* these versions are limited to elements between two bounds *)letreciter_slicecomparefmlohi=matchmwith|Empty->()|Node{l;v;r}->letc1,c2=comparevlo,comparevhiinifc1>0theniter_slicecomparefllohi;ifc1>=0&&c2<=0thenfv;ifc2<0theniter_slicecomparefrlohiletrecfold_slicecomparefmlohiacc=matchmwith|Empty->acc|Node{l;v;r}->letc1,c2=comparevlo,comparevhiinletacc=ifc1>0thenfold_slicecomparefllohiaccelseaccinletacc=ifc1>=0&&c2<=0thenfvaccelseaccinifc2<0thenfold_slicecomparefrlohiaccelseaccletrecfor_all_slicecomparefmlohi=matchmwith|Empty->true|Node{l;v;r}->letc1,c2=comparevlo,comparevhiin(c1<=0||for_all_slicecomparefllohi)&&(c1<0||c2>0||fv)&&(c2>=0||for_all_slicecomparefrlohi)letrecexists_slicecomparefmlohi=matchmwith|Empty->false|Node{l;v;r}->letc1,c2=comparevlo,comparevhiin(c1>0&&exists_slicecomparefllohi)||(c1>=0&&c2<=0&&fv)||(c2<0&&exists_slicecomparefrlohi)(* new versions, optimised with _diff functions *)letequalcompares1s2=for_all2_diffcompare(fun_->false)(fun_->false)s1s2letsubsetcompares1s2=for_all2_diffcompare(fun_->false)(fun_->true)s1s2letcomparecmps1s2=letr=ref0intryiter2_diffcmp(fun_->r:=1;raiseExit)(fun_->r:=-1;raiseExit)s1s2;!rwithExit->!r(* printing *)letprint_genoprinterkeychs=ifs=Emptythenochprinter.print_emptyelse(letfirst=reftrueinochprinter.print_begin;iter(funk->if!firstthenfirst:=falseelseochprinter.print_sep;keychk)s;ochprinter.print_end)(* internal printing helper *)letprintprinterkeychl=print_genoutput_stringprinterkeychlletbprintprinterkeychl=print_genBuffer.add_stringprinterkeychlletfprintprinterkeychl=print_gen(funfmts->Format.fprintffmt"%s@,"s)printerkeychlletto_stringprinterkeyl=letb=Buffer.create10inprint_gen(fun()s->Buffer.add_stringbs)printer(fun()k->Buffer.add_stringb(keyk))()l;Buffer.contentsbletprinter_default={print_empty="{}";print_begin="{";print_sep=",";print_end="}";}(** [MOPSA] Print as set: {elem1,...,elemn} *)letemptycompare={set=empty;compare}letis_emptys=is_emptys.setletmemxs=mems.comparexs.setletaddxs=letset=adds.comparexs.setinifset==s.setthenselse{swithset}letsingletoncomparex={set=singletonx;compare}letremovexs=letset=removes.comparexs.setinifset==s.setthenselse{swithset}letunions1s2={s1withset=unions1.compares1.sets2.set}letinters1s2={s1withset=inters1.compares1.sets2.set}letdiffs1s2={s1withset=diffs1.compares1.sets2.set}letcompares1s2=compares1.compares1.sets2.setletequals1s2=equals1.compares1.sets2.setletsubsets1s2=subsets1.compares1.sets2.setletiterfs=iterfs.setletmapfs={swithset=maps.comparefs.set}letfoldfsx=foldfs.setxletfor_allfs=for_allfs.setletexistsfs=existsfs.setletfilterfs={swithset=filterfs.set}letpartitionfs=letset1,set2=partitionfs.setin{swithset=set1},{swithset=set1}letcardinals=cardinals.setletelementss=elementss.setletmin_elts=min_elts.setletmin_elt_opts=min_elt_opts.setletmax_elts=max_elts.setletmax_elt_opts=max_elt_opts.setletchooses=chooses.setletchoose_opts=choose_opts.setletsplitxs=letset1,b,set2=splits.comparexs.setin{swithset=set1},b,{swithset=set2}letfindxs=finds.comparexs.setletfind_optxs=find_opts.comparexs.setletfind_firstfs=find_firstfs.setletfind_first_optfs=find_first_optfs.setletfind_lastfs=find_lastfs.setletfind_last_optfs=find_last_optfs.setletof_listcomparel={set=of_listcomparel;compare}