123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347(*
* Set, polymorphic version.
* Adapted from set.ml in the ocaml distribution.
*)(* This is the original copyright: *)(***********************************************************************)(* *)(* Objective Caml *)(* *)(* 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 Library General Public License, with *)(* the special exception on linking described in file ../LICENSE. *)(* *)(***********************************************************************)(* $Id: set.ml 6694 2004-11-25 00:06:06Z doligez $ *)(* Sets over ordered types *)type'acmp='a->'a->inttype'atree=Empty|Nodeof'atree*'a*'atree*inttype'at={cmp:'acmp;tree:'atree;}letcheck_cmpmsgs1s2=ifs1.cmp!=s2.cmpthenfailwith(Printf.sprintf"Setp.%s: arguments have different comparison functions."msg)elses1.cmp(* Sets are represented by balanced binary trees (the heights of the
children differ by at most 2 *)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,(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(ll,lv,lr,_)->ifheightll>=heightlrthencreatelllv(createlrvr)elsebeginmatchlrwithEmpty->invalid_arg"Set.bal"|Node(lrl,lrv,lrr,_)->create(createlllvlrl)lrv(createlrrvr)endendelseifhr>hl+2thenbeginmatchrwithEmpty->invalid_arg"Set.bal"|Node(rl,rv,rr,_)->ifheightrr>=heightrlthencreate(createlvrl)rvrrelsebeginmatchrlwithEmpty->invalid_arg"Set.bal"|Node(rll,rlv,rlr,_)->create(createlvrll)rlv(createrlrrvrr)endendelseNode(l,v,r,(ifhl>=hrthenhl+1elsehr+1))(* Insertion of one element *)letrecaddcmpx=functionEmpty->Node(Empty,x,Empty,1)|Node(l,v,r,_)ast->letc=cmpxvinifc=0thentelseifc<0thenbal(addcmpxl)vrelseballv(addcmpxr)(* Same as create and bal, but no assumptions are made on the
relative heights of l and r. *)letrecjoincmplvr=match(l,r)with(Empty,_)->addcmpvr|(_,Empty)->addcmpvl|(Node(ll,lv,lr,lh),Node(rl,rv,rr,rh))->iflh>rh+2thenballllv(joincmplrvr)elseifrh>lh+2thenbal(joincmplvrl)rvrrelsecreatelvr(* Smallest and greatest element of a set *)letrecmin_elt=functionEmpty->raiseNot_found|Node(Empty,v,r,_)->v|Node(l,v,r,_)->min_eltlletrecmax_elt=functionEmpty->raiseNot_found|Node(l,v,Empty,_)->v|Node(l,v,r,_)->max_eltr(* Remove the smallest element of the given set *)letrecremove_min_elt=functionEmpty->invalid_arg"Set.remove_min_elt"|Node(Empty,v,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. *)letconcatcmpt1t2=match(t1,t2)with(Empty,t)->t|(t,Empty)->t|(_,_)->joincmpt1(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. *)letrecsplitcmpx=functionEmpty->(Empty,false,Empty)|Node(l,v,r,_)->letc=cmpxvinifc=0then(l,true,r)elseifc<0thenlet(ll,pres,rl)=splitcmpxlin(ll,pres,joincmprlvr)elselet(lr,pres,rr)=splitcmpxrin(joincmplvlr,pres,rr)(* Implementation of the set operations *)letemptycmp={cmp;tree=Empty}letis_emptys=matchs.treewithEmpty->true|_->falseletrecmemcmpx=functionEmpty->false|Node(l,v,r,_)->letc=cmpxvinc=0||memcmpx(ifc<0thenlelser)letrecfindcmpx=function|Empty->raiseNot_found|Node(l,v,r,_)->letc=cmpxvinifc=0thenvelsefindcmpx(ifc<0thenlelser)letsingletoncmpx={cmp;tree=Node(Empty,x,Empty,1)}letrecremovecmpx=functionEmpty->Empty|Node(l,v,r,_)->letc=cmpxvinifc=0thenmergelrelseifc<0thenbal(removecmpxl)vrelseballv(removecmpxr)letrecunioncmps1s2=match(s1,s2)with(Empty,t2)->t2|(t1,Empty)->t1|(Node(l1,v1,r1,h1),Node(l2,v2,r2,h2))->ifh1>=h2thenifh2=1thenaddcmpv2s1elsebeginlet(l2,_,r2)=splitcmpv1s2injoincmp(unioncmpl1l2)v1(unioncmpr1r2)endelseifh1=1thenaddcmpv1s2elsebeginlet(l1,_,r1)=splitcmpv2s1injoincmp(unioncmpl1l2)v2(unioncmpr1r2)endletrecintercmps1s2=match(s1,s2)with(Empty,t2)->Empty|(t1,Empty)->Empty|(Node(l1,v1,r1,_),t2)->matchsplitcmpv1t2with(l2,false,r2)->concatcmp(intercmpl1l2)(intercmpr1r2)|(l2,true,r2)->joincmp(intercmpl1l2)v1(intercmpr1r2)letrecdiffcmps1s2=match(s1,s2)with(Empty,t2)->Empty|(t1,Empty)->t1|(Node(l1,v1,r1,_),t2)->matchsplitcmpv1t2with(l2,false,r2)->joincmp(diffcmpl1l2)v1(diffcmpr1r2)|(l2,true,r2)->concatcmp(diffcmpl1l2)(diffcmpr1r2)type'aenumeration=End|Moreof'a*'atree*'aenumerationletreccons_enumse=matchswithEmpty->e|Node(l,v,r,_)->cons_enuml(More(v,r,e))letreccompare_auxcmpe1e2=match(e1,e2)with(End,End)->0|(End,_)->-1|(_,End)->1|(More(v1,r1,e1),More(v2,r2,e2))->letc=cmpv1v2inifc<>0thencelsecompare_auxcmp(cons_enumr1e1)(cons_enumr2e2)letcompares1s2=letcmp=check_cmp"compare"s1s2incompare_auxcmp(cons_enums1.treeEnd)(cons_enums2.treeEnd)letequals1s2=compares1s2=0letrecsubsetcmps1s2=match(s1,s2)withEmpty,_->true|_,Empty->false|Node(l1,v1,r1,_),(Node(l2,v2,r2,_)ast2)->letc=cmpv1v2inifc=0thensubsetcmpl1l2&&subsetcmpr1r2elseifc<0thensubsetcmp(Node(l1,v1,Empty,0))l2&&subsetcmpr1t2elsesubsetcmp(Node(Empty,v1,r1,0))r2&&subsetcmpl1t2letreciterf=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||existsprletfiltercmpps=letrecfiltaccu=function|Empty->accu|Node(l,v,r,_)->filt(filt(ifpvthenaddcmpvaccuelseaccu)l)rinfiltEmptysletpartitioncmpps=letrecpart(t,fasaccu)=function|Empty->accu|Node(l,v,r,_)->part(part(ifpvthen(addcmpvt,f)else(t,addcmpvf))l)rinpart(Empty,Empty)sletreccardinal=functionEmpty->0|Node(l,v,r,_)->cardinall+1+cardinalrletrecelements_auxaccu=functionEmpty->accu|Node(l,v,r,_)->elements_aux(v::elements_auxaccur)lletelementss=elements_aux[]sletmemxs=mems.cmpxs.treeletfindxs=finds.cmpxs.treeletaddxs={cmp=s.cmp;tree=adds.cmpxs.tree}letremovexs={cmp=s.cmp;tree=removes.cmpxs.tree}(* It is not worth factorizing the following few definitions...for the moment. *)letunions1s2={cmp=check_cmp"union"s1s2;tree=unions1.cmps1.trees2.tree}letinters1s2={cmp=check_cmp"inter"s1s2;tree=inters1.cmps1.trees2.tree}letdiffs1s2={cmp=check_cmp"diff"s1s2;tree=diffs1.cmps1.trees2.tree}letsubsets1s2=subset(check_cmp"subset"s1s2)s1.trees2.treeletiterfs=iterfs.treeletfoldfsa=foldfs.treealetfor_allfs=for_allfs.treeletexistsfs=existsfs.treeletfilterfs={cmp=s.cmp;tree=filters.cmpfs.tree}letpartitionfs=let(tree1,tree2)=partitions.cmpfs.treein{cmp=s.cmp;tree=tree1},{cmp=s.cmp;tree=tree2}letsplitxs=let(tree1,flag,tree2)=splits.cmpxs.treein{cmp=s.cmp;tree=tree1},flag,{cmp=s.cmp;tree=tree2}letcardinals=cardinals.treeletelementss=elementss.treeletmin_elts=min_elts.treeletmax_elts=max_elts.treeletchoose=min_elt