123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702openCoreopenInt.Replace_polymorphic_compareincludeSplay_tree0_intfmoduleMake_with_reduction(Key:Key)(Data:Data)(R:Reduction_operationwithtypekey=Key.tandtypedata=Data.t)=structtypekey=Key.t[@@derivingsexp]typedata=Data.t[@@derivingsexp]typeaccum=R.accum(* [Kernel] ensures that all [Node]s
- are annotated with the correct size, and
- are annotated with the right accumulator, based on their children
*)moduleKernel:sig(** tree size *)typesizetypet=private|Empty|Nodeof{left:t;key:key;data:data;right:t;size:size;accum:accum}vallength:t->intvalnode:t->key->data->t->tvalempty:tvalaccum:t->accumend=structtypesize=inttypet=|Empty|Nodeof{left:t;key:key;data:data;right:t;size:int;accum:accum}letlength=function|Empty->0|Node{size;_}->size;;letaccum=function|Empty->R.identity|Node{accum;_}->accum;;letnodeleftkeydataright=Node{left;key;data;right;size=lengthleft+lengthright+1;accum=R.combine(R.combine(accumleft)(R.singleton~key~data))(accumright)};;letempty=EmptyendmoduleTree=structincludeKernelletis_empty=function|Empty->true|Node_->false;;(* [ctx] represents the positions of a subtree within its containing tree. You can
also think of the context like a phantom node placeholder within the larger tree.
*)typectx=|Top|Fstofctx*key*data*t|Sndoft*key*data*ctx(* [plug t ctx] restores the overall tree from the subtree [t] and its context [ctx].
NOTE: this definition is used nowhere in the remainder of this file. It serves
only to indicate what a context /means/.
*)letrec_plugt=function|Top->t|Fst(ctx,k,v,r)->_plug(nodetkvr)ctx|Snd(l,k,v,ctx)->_plug(nodelkvt)ctx;;(* Traverse tree downwards, converting parents into ctx *)(* The downward tree traversal methods find a subtree and its [ctx] (position with the
larger tree. If no subtree is returned, it is assumed to be the empty tree. One can
reconstruct the original tree by [_plug t ctx] or splay the found node to the root
with [splay_to_tree (ctx, t)]. *)letfind_ctx:t->key->ctx*t=funtx->letrecloopctxthis=matchthiswith|Empty->ctx,this|Node{left;key;data;right;_}->letcmp=Key.comparexkeyinifcmp<0thenloop(Fst(ctx,key,data,right))leftelseifcmp>0thenloop(Snd(left,key,data,ctx))rightelsectx,thisinloopTopt;;letfind_leftmost_ctxt=letreclooptctx=matchtwith|Empty->ctx|Node{left;key;data;right;_}->loopleft(Fst(ctx,key,data,right))inlooptTop;;letfind_rightmost_ctxt=letrecloopctxt=matchtwith|Empty->ctx|Node{left;key;data;right;_}->loop(Snd(left,key,data,ctx))rightinloopTopt;;letnth_ctxti=letrecloopctxthisi=matchthiswith|Empty->ctx,this|Node{left;key;data;right;_}->letlsize=lengthleftinifi<lsizethenloop(Fst(ctx,key,data,right))leftielseifi=lsizethenctx,thiselse(* i > lsize *)loop(Snd(left,key,data,ctx))right(i-lsize-1)inloopTopti;;letsearch_ctxt~f=letrecloopctxthis~left:left_ctx~right:right_ctx=matchthiswith|Empty->ctx,this|Node{left;key;data;right;_}->letleft_combined=R.combineleft_ctx(accumleft)inletright_combined=R.combineright_ctx(accumright)inletright_with_node=R.combine(R.singleton~key~data)right_combinedin(matchf~left:left_combined~right:right_with_nodewith|`Left->loop(Fst(ctx,key,data,right))left~left:left_ctx~right:right_with_node|`Right->letleft_with_node=R.combineleft_combined(R.singleton~key~data)in(matchf~left:left_with_node~right:right_combinedwith|`Left->ctx,this|`Right->loop(Snd(left,key,data,ctx))right~left:left_with_node~right:right_ctx))inloopTopt~left:R.identity~right:R.identity;;(* Traverse tree upwards, converting ctx to parents *)(* [splay l r ctx = (l', r')] performs the splay operation.
It pulls a phantom node [x] from its position at [ctx] up to the
top of the tree by doing double and single rotations.
: (ctx) (top)
: ...
: [x] ==> [x]
: / \ / \
: l r l' r'
*)letrecsplaylr=function|Top->l,r|Fst(Top,y,yv,c)->leta=linletb=rin(*
: y [x]
: / \ / \
: [x] c => a y
: / \ / \
: a b b c
*)a,nodebyyvc|Snd(a,y,yv,Top)->letb=linletc=rin(*
: y [x]
: / \ / \
: a [x] => y c
: / \ / \
: b c a b
*)nodeayyvb,c|Fst(Fst(ctx,z,zv,d),y,yv,c)->leta=linletb=rin(*
: z [x]
: / \ / \
: y d a y
: / \ => / \
: [x] c b z
: / \ / \
: a b c d
*)splaya(nodebyyv(nodeczzvd))ctx|Snd(b,y,yv,Snd(a,z,zv,ctx))->letc=linletd=rin(*
: z [x]
: / \ / \
: a y y d
: / \ => / \
: b [x] z c
: / \ / \
: c d a b
*)splay(node(nodeazzvb)yyvc)dctx|Snd(a,y,yv,Fst(ctx,z,zv,d))|Fst(Snd(a,y,yv,ctx),z,zv,d)->letb=linletc=rin(*
: z y
: / \ [x] / \
: y d / \ a z
: / \ => y z <= / \
: a [x] / \ / \ [x] d
: / \ a b c d / \
: b c b c
*)splay(nodeayyvb)(nodeczzvd)ctx;;(* Splay a node up to the root *)letsplay_nodelkvrctx=letl,r=splaylrctxinnodelkvr;;(* Splay an empty leaf up, letting its parent become the root *)letsplay_emptyctx=matchctxwith|Top->empty|Fst(ctx,k,v,r)->splay_nodeemptykvrctx|Snd(l,k,v,ctx)->splay_nodelkvemptyctx;;(* Splay the phantom node to the root, splitting the tree into the left side with
lesser keys and the right side with greater keys *)letsplay_to_triplefound=letinjectv(left,right)=left,v,rightinmatchfoundwith|ctx,Node{left;key;data;right;_}->inject(Some(key,data))(splayleftrightctx)|ctx,Empty->injectNone(splayemptyemptyctx);;(* Splay the phantom node to the root, splitting off the greater keys as the right
side *)letsplay_split_leq_gt=function|ctx,Node{left;key;data;right;_}->letl,r=splayleftrightctxinnodelkeydataempty,r|ctx,Empty->splayemptyemptyctx;;(* Splay the phantom node to the root, splitting off the lesser keys as the left side
*)letsplay_split_lt_geq=function|ctx,Node{left;key;data;right;_}->letl,r=splayleftrightctxinl,nodeemptykeydatar|ctx,Empty->splayemptyemptyctx;;(* Splay the tree back together with the found node at the root *)letsplay_to_tree=function|ctx,Node{left;key;data;right;_}->splay_nodeleftkeydatarightctx|ctx,Empty->splay_emptyctx;;(* Splay the tree back together, but keep aside a reference to the node contents, if
any *)letsplay_to_result=function|ctx,Node{left;key;data;right;_}->splay_nodeleftkeydatarightctx,Some(key,data)|ctx,Empty->splay_emptyctx,None;;(* Point-wise mutation operations *)letsett~key~data=letl,_,r=find_ctxtkey|>splay_to_tripleinnodelkeydatar;;letaddt~key~data=matchfind_ctxtkey|>splay_to_triplewith|l,None,r->Some(nodelkeydatar)|_,Some_,_->None;;letremove_mint=matchfind_leftmost_ctxtwith|Top->None|Snd_->(* find_leftmost_ctx only accumulates Top and Fst constructors *)assertfalse|Fst(ctx,x,xv,right)->(matchsplayemptyrightctxwith|Empty,r->Some(x,xv,r)|Node_,_->(* when [ctx] contains only Top and Fst constructors, as it
does here since it was returned by [find_leftmost_ctx], then
[fst (splay Empty t ctx)] will always be [Empty] for all [t]. *)assertfalse);;letremove_maxt=matchfind_rightmost_ctxtwith|Top->None|Fst_->(* find_rightmost_ctx only accumulates Top and Snd constructors *)assertfalse|Snd(left,x,xv,ctx)->(matchsplayleftemptyctxwith|l,Empty->(* order reversed here to give the same type as [remove_min] *)Some(x,xv,l)|_,Node_->(* when [ctx] contains only Top and Snd constructors, as it
does here since it was returned by [find_rightmost_ctx], then
[snd (splay Empty t ctx)] will always be [Empty] for all [t]. *)assertfalse);;letconcat_uncheckedleftright=matchremove_minrightwith|None->left|Some(x,xv,right)->nodeleftxxvright;;letconcat_value_uncheckedleftkeydataright=matchdatawith|None->concat_uncheckedleftright|Somedata->nodeleftkeydataright;;letconcat_triple_uncheckedleftkvright=matchkvwith|None->concat_uncheckedleftright|Some(k,v)->nodeleftkvright;;letremovetk=matchfind_ctxtkwith|ctx,Empty->splay_emptyctx|ctx,Node{left;right;_}->(* Remove the node before splaying to reduce unnecessary node churn *)splay_to_tree(ctx,concat_uncheckedleftright);;(* [remove_after] and [remove_before] return an [Either.t] so that even if the removal
fails, the tree can still benefit from the splay operation *)letremove_beforetk=letbefore,at,after=find_ctxtk|>splay_to_tripleinmatchremove_maxbeforewith|Some(res_k,res_v,before)->First(res_k,res_v,concat_triple_uncheckedbeforeatafter)|None->Second(concat_triple_uncheckedbeforeatafter);;letremove_aftertk=letbefore,at,after=find_ctxtk|>splay_to_tripleinmatchremove_minafterwith|Some(res_k,res_v,after)->First(res_k,res_v,concat_triple_uncheckedbeforeatafter)|None->Second(concat_triple_uncheckedbeforeatafter);;(* Folding *)letfold_right:'b.t->init:'b->f:(key:key->data:data->'b->'b)->'b=funt~init~f->letrecloopacc=function|[]->acc|`Elem(key,data)::to_visit->loop(f~key~dataacc)to_visit|`TreeEmpty::to_visit->loopaccto_visit|`Tree(Node{left;key;data;right;_})::to_visit->loopacc(`Treeright::`Elem(key,data)::`Treeleft::to_visit)inloopinit[`Treet];;(* Querying *)letdatat=fold_rightt~init:[]~f:(fun~key:_~dataacc->data::acc)letkeyst=fold_rightt~init:[]~f:(fun~key~data:_acc->key::acc)letmemtx=lett,res=find_ctxtx|>splay_to_resultint,Option.is_someres;;letfindtx=lett,res=find_ctxtx|>splay_to_resultint,Option.map~f:sndres;;letnthtn=nth_ctxtn|>splay_to_resultletranktkey=lett=find_ctxtkey|>splay_to_treeinletresult=matchtwith|Empty->0|Node{left;key=root;_}->ifKey.comparerootkey<0thenlengthleft+1elselengthleftint,result;;letsearcht~f=search_ctxt~f|>splay_to_result(* Conversions *)letto_alistt=fold_rightt~init:[]~f:(fun~key~dataacc->(key,data)::acc)letof_alistl=List.fold_resultl~init:empty~f:(funt(key,data)->matchaddt~key~datawith|None->error_s[%message"Duplicate key"(key:Key.t)]|Somet->Okt);;letof_alist_exnl=Or_error.ok_exn(of_alistl)lett_of_sexpsexp=of_alist_exn([%of_sexp:(key*data)list]sexp)letsexp_of_tt=Sexp.List(fold_rightt~init:[]~f:(fun~key~dataacc->Sexp.List[sexp_of_keykey;sexp_of_datadata]::acc));;(* Range mutation operations *)modulePartition=structtypenonrect={lt:t;mid:t;gt:t}endletpartition?min_key?max_keyt=letlt,geq=matchmin_keywith|None->empty,t|Somemin_key->find_ctxtmin_key|>splay_split_lt_geqinletmid,gt=matchmax_keywith|None->geq,empty|Somemax_key->find_ctxgeqmax_key|>splay_split_leq_gtin{Partition.lt;mid;gt};;letsubrange?min_key?max_keyt=(partition?min_key?max_keyt).midletrecmergeleftright~f=matchleft,rightwith|Empty,Empty->empty|Empty,Node{left;key;data;right;_}->letl'=merge~femptyleftinletv'=f~key(`Rightdata)inletr'=merge~femptyrightinconcat_value_uncheckedl'keyv'r'|Node{left;key;data;right;_},Empty->letl'=merge~fleftemptyinletv'=f~key(`Leftdata)inletr'=merge~frightemptyinconcat_value_uncheckedl'keyv'r'|Node{left=l1;key;data=v1;right=r1;_},Node_->letl2,kv2,r2=find_ctxrightkey|>splay_to_tripleinletv=matchkv2with|None->`Leftv1|Some(k2,v2)->assert(Key.comparekeyk2=0);(* Sanity check *)`Both(v1,v2)inletl'=merge~fl1l2inletv'=f~keyvinletr'=merge~fr1r2inconcat_value_uncheckedl'keyv'r';;letsplittk=letl,v,r=find_ctxtk|>splay_to_tripleinl,Option.map~f:sndv,r;;letjoinlr=matchfind_rightmost_ctxl,remove_minrwith|_,None->Okl|Top,_->Okr|Fst_,_->(* [find_rightmost_ctx] never creates [Fst] constructors *)assertfalse|Snd(_,k1,_,_),Some(k2,v2,r)->ifKey.comparek1k2>=0thenerror_s[%message"Trees were overlapping"~left_max:(k1:key)~right_min:(k2:key)]elseOk(nodelk2v2r);;letjoin_exnlr=Or_error.ok_exn(joinlr)(* Mapping *)(* this is in CPS so that it is tail-recursive *)letrecmap_cps:'r.t->f:(data->data)->(t->'r)->'r=funt~fk->matchtwith|Empty->kempty|Node{left;key;data;right;_}->map_cpsleft~f(funl->letdata=fdatainmap_cpsright~f(funr->k(nodelkeydatar)));;letmapt~f=map_cpst~fFn.idletmap_ranget~min_key~max_key~f=letold_range,t=let{Partition.lt;mid;gt}=partition~min_key~max_keytinto_alistmid,concat_uncheckedltgtinletnew_range=fold_rangeinList.foldnew_range~init:t~f:(funt(key,data)->sett~key~data);;endmoduleT:sigtypet[@@derivingsexp]valcreate:Tree.t->tvalupdate:t->Tree.t*'a->'avalpack:t->Tree.t->tvalunpack:t->Tree.tend=structtypet={mutabletree:Tree.t}[@@derivingsexp]letcreatetree={tree}letpack(_:t)tree={tree}letupdatet(tree,res)=t.tree<-tree;res;;letunpackt=t.treeendopenTreeincludeTletempty=createemptyletof_alistl=Or_error.map~f:create(of_alistl)letof_alist_exnl=create(of_alist_exnl)letto_alistt=to_alist(unpackt)letis_emptyt=is_empty(unpackt)letlengtht=length(unpackt)letaccumt=accum(unpackt)letkeyst=keys(unpackt)letdatat=data(unpackt)letmemtk=updatet(mem(unpackt)k)letfindtk=updatet(find(unpackt)k)letsett~key~data=packt(set(unpackt)~key~data)letremovetk=packt(remove(unpackt)k)letpack_removet=function|None->None|Some(a,b,tree)->Some(a,b,packttree);;letremove_mint=pack_removet(remove_min(unpackt))letremove_maxt=pack_removet(remove_max(unpackt))letpack_remove_eithert=function|First(a,b,tree)->Some(a,b,packttree)|Secondtree->updatet(tree,None);;letremove_aftertk=pack_remove_eithert(remove_after(unpackt)k)letremove_beforetk=pack_remove_eithert(remove_before(unpackt)k)letmapt~f=packt(map(unpackt)~f)letmap_ranget~min_key~max_key~f=packt(map_range(unpackt)~min_key~max_key~f);;letnthtidx=updatet(nth(unpackt)idx)letranktkey=updatet(rank(unpackt)key)letsearcht~f=updatet(search(unpackt)~f)modulePartition=structtypenonrect={lt:t;mid:t;gt:t}endletpartition?min_key?max_keyt=let{Tree.Partition.lt;mid;gt}=partition?min_key?max_key(unpackt)in{Partition.lt=packtlt;mid=packtmid;gt=packtgt};;letsubrange?min_key?max_keyt=packt(subrange?min_key?max_key(unpackt))letsplittk=letl,v,r=split(unpackt)kinpacktl,v,packtr;;letmergeab~f=create(merge~f(unpacka)(unpackb))letjoinab=Or_error.map~f:create(join(unpacka)(unpackb))letjoin_exnab=create(join_exn(unpacka)(unpackb))endmoduleMake_without_reduction(Key:Key)(Data:Data):Swithtypekey=Key.tandtypedata=Data.tandtypeaccum=unit=Make_with_reduction(Key)(Data)(structtypekey=Key.ttypedata=Data.ttypeaccum=unitletidentity=()letsingleton~key:_~data:_=()letcombine()()=()end)moduleReduction_operations=structletreduce2(typekdab)(moduleR1:Reduction_operationwithtypekey=kandtypedata=dandtypeaccum=a)(moduleR2:Reduction_operationwithtypekey=kandtypedata=dandtypeaccum=b)=(modulestructtypekey=ktypedata=dtypeaccum=a*bletidentity=R1.identity,R2.identityletsingleton~key~data=R1.singleton~key~data,R2.singleton~key~dataletcombine(l1,l2)(r1,r2)=R1.combinel1r1,R2.combinel2r2end:Reduction_operationwithtypekey=kandtypedata=dandtypeaccum=a*b);;end