12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738# 1 "Baby.cppo.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)includeSignatures(* -------------------------------------------------------------------------- *)(* The functor [Baby.Make] constructs balanced binary search trees
based on a user-supplied balancing scheme. *)module[@inline]Make(E:OrderedType)(T:COREwithtypekey=E.t)=structincludeT# 1 "Macros.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* Derived macros. *)(* [EMPTY(t)] determines whether the tree [t] is empty, that is, a leaf. *)# 19 "Macros.frag.ml"(* [BOTH_EMPTY(l,r)] determines whether the trees [l] and [r] are both empty. *)# 1 "Common.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* -------------------------------------------------------------------------- *)(* Types. *)typeelt=keytypeset=treetypet=set(* -------------------------------------------------------------------------- *)(* Operations. *)# 1 "Empty.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)letempty:tree=leafletis_empty(t:tree):bool=match# 17 "Empty.frag.ml"(viewt)# 17 "Empty.frag.ml"with|# 18 "Empty.frag.ml"Leaf# 18 "Empty.frag.ml"->true|# 20 "Empty.frag.ml"Node(_,_,_)# 20 "Empty.frag.ml"->false# 1 "MinMax.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)letrecmin_elt_1(default:key)(t:tree):key=match# 14 "MinMax.frag.ml"(viewt)# 14 "MinMax.frag.ml"with|# 15 "MinMax.frag.ml"Leaf# 15 "MinMax.frag.ml"->default|# 17 "MinMax.frag.ml"Node(l,v,_)# 17 "MinMax.frag.ml"->min_elt_1vlletmin_elt(t:tree):key=match# 21 "MinMax.frag.ml"(viewt)# 21 "MinMax.frag.ml"with|# 22 "MinMax.frag.ml"Leaf# 22 "MinMax.frag.ml"->raiseNot_found|# 24 "MinMax.frag.ml"Node(l,v,_)# 24 "MinMax.frag.ml"->min_elt_1vlletrecmin_elt_opt_1(default:key)(t:tree):keyoption=match# 28 "MinMax.frag.ml"(viewt)# 28 "MinMax.frag.ml"with|# 29 "MinMax.frag.ml"Leaf# 29 "MinMax.frag.ml"->Somedefault|# 31 "MinMax.frag.ml"Node(l,v,_)# 31 "MinMax.frag.ml"->min_elt_opt_1vlletmin_elt_opt(t:tree):keyoption=match# 35 "MinMax.frag.ml"(viewt)# 35 "MinMax.frag.ml"with|# 36 "MinMax.frag.ml"Leaf# 36 "MinMax.frag.ml"->None|# 38 "MinMax.frag.ml"Node(l,v,_)# 38 "MinMax.frag.ml"->min_elt_opt_1vlletrecmax_elt_1(default:key)(t:tree):key=match# 42 "MinMax.frag.ml"(viewt)# 42 "MinMax.frag.ml"with|# 43 "MinMax.frag.ml"Leaf# 43 "MinMax.frag.ml"->default|# 45 "MinMax.frag.ml"Node(_,v,r)# 45 "MinMax.frag.ml"->max_elt_1vrletmax_elt(t:tree):key=match# 49 "MinMax.frag.ml"(viewt)# 49 "MinMax.frag.ml"with|# 50 "MinMax.frag.ml"Leaf# 50 "MinMax.frag.ml"->raiseNot_found|# 52 "MinMax.frag.ml"Node(_,v,r)# 52 "MinMax.frag.ml"->max_elt_1vrletrecmax_elt_opt_1(default:key)(t:tree):keyoption=match# 56 "MinMax.frag.ml"(viewt)# 56 "MinMax.frag.ml"with|# 57 "MinMax.frag.ml"Leaf# 57 "MinMax.frag.ml"->Somedefault|# 59 "MinMax.frag.ml"Node(_,v,r)# 59 "MinMax.frag.ml"->max_elt_opt_1vrletmax_elt_opt(t:tree):keyoption=match# 63 "MinMax.frag.ml"(viewt)# 63 "MinMax.frag.ml"with|# 64 "MinMax.frag.ml"Leaf# 64 "MinMax.frag.ml"->None|# 66 "MinMax.frag.ml"Node(_,v,r)# 66 "MinMax.frag.ml"->max_elt_opt_1vr(* As in OCaml's Set library, [choose] and [choose_opt] choose the minimum
element of the set. This is slow (logarithmic time), but guarantees that
[choose] respects equality: that is, if the sets [s1] and [s2] are equal
then [choose s1] and [choose s2] are equal. *)letchoose=min_eltletchoose_opt=min_elt_opt# 1 "Mem.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* -------------------------------------------------------------------------- *)(* Membership. *)letrecmem(x:key)(t:tree):bool=match# 18 "Mem.frag.ml"(viewt)# 18 "Mem.frag.ml"with|# 19 "Mem.frag.ml"Leaf# 19 "Mem.frag.ml"->false|# 21 "Mem.frag.ml"Node(l,v,r)# 21 "Mem.frag.ml"->letc=E.comparexvinc=0||memx(ifc<0thenlelser)# 1 "Find.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)letrecfind(x:key)(t:tree):key=match# 14 "Find.frag.ml"(viewt)# 14 "Find.frag.ml"with|# 15 "Find.frag.ml"Leaf# 15 "Find.frag.ml"->raiseNot_found|# 17 "Find.frag.ml"Node(l,v,r)# 17 "Find.frag.ml"->letc=E.comparexvinifc=0thenvelseifc<0thenfindxlelsefindxrletrecfind_opt(x:key)(t:tree):keyoption=match# 27 "Find.frag.ml"(viewt)# 27 "Find.frag.ml"with|# 28 "Find.frag.ml"Leaf# 28 "Find.frag.ml"->None|# 30 "Find.frag.ml"Node(l,v,r)# 30 "Find.frag.ml"->letc=E.comparexvinifc=0thenSomevelseifc<0thenfind_optxlelsefind_optxr(* -------------------------------------------------------------------------- *)(* [find_first] and its variants are as in OCaml's Set library. *)(* A lot of repetitive code. *)(* It is worth noting that [find_first] is not a naive linear search.
Instead, it assumes that [f] is a monotonically increasing function
of elements to Booleans. This implies that there is at most one
position in the increasing sequence of the set elements where the
value of [f] changes, and it changes from [false] to [true]. This
position can be found in logarithmic time. *)letrecfind_first_auxv0f(t:tree)=match# 53 "Find.frag.ml"(viewt)# 53 "Find.frag.ml"with|# 54 "Find.frag.ml"Leaf# 54 "Find.frag.ml"->v0|# 56 "Find.frag.ml"Node(l,v,r)# 56 "Find.frag.ml"->iffvthenfind_first_auxvflelsefind_first_auxv0frletrecfind_firstf(t:tree)=match# 63 "Find.frag.ml"(viewt)# 63 "Find.frag.ml"with|# 64 "Find.frag.ml"Leaf# 64 "Find.frag.ml"->raiseNot_found|# 66 "Find.frag.ml"Node(l,v,r)# 66 "Find.frag.ml"->iffvthenfind_first_auxvflelsefind_firstfrletrecfind_first_opt_auxv0f(t:tree)=match# 73 "Find.frag.ml"(viewt)# 73 "Find.frag.ml"with|# 74 "Find.frag.ml"Leaf# 74 "Find.frag.ml"->Somev0|# 76 "Find.frag.ml"Node(l,v,r)# 76 "Find.frag.ml"->iffvthenfind_first_opt_auxvflelsefind_first_opt_auxv0frletrecfind_first_optf(t:tree)=match# 83 "Find.frag.ml"(viewt)# 83 "Find.frag.ml"with|# 84 "Find.frag.ml"Leaf# 84 "Find.frag.ml"->None|# 86 "Find.frag.ml"Node(l,v,r)# 86 "Find.frag.ml"->iffvthenfind_first_opt_auxvflelsefind_first_optfrletrecfind_last_auxv0f(t:tree)=match# 93 "Find.frag.ml"(viewt)# 93 "Find.frag.ml"with|# 94 "Find.frag.ml"Leaf# 94 "Find.frag.ml"->v0|# 96 "Find.frag.ml"Node(l,v,r)# 96 "Find.frag.ml"->iffvthenfind_last_auxvfrelsefind_last_auxv0flletrecfind_lastf(t:tree)=match# 103 "Find.frag.ml"(viewt)# 103 "Find.frag.ml"with|# 104 "Find.frag.ml"Leaf# 104 "Find.frag.ml"->raiseNot_found|# 106 "Find.frag.ml"Node(l,v,r)# 106 "Find.frag.ml"->iffvthenfind_last_auxvfrelsefind_lastflletrecfind_last_opt_auxv0f(t:tree)=match# 113 "Find.frag.ml"(viewt)# 113 "Find.frag.ml"with|# 114 "Find.frag.ml"Leaf# 114 "Find.frag.ml"->Somev0|# 116 "Find.frag.ml"Node(l,v,r)# 116 "Find.frag.ml"->iffvthenfind_last_opt_auxvfrelsefind_last_opt_auxv0flletrecfind_last_optf(t:tree)=match# 123 "Find.frag.ml"(viewt)# 123 "Find.frag.ml"with|# 124 "Find.frag.ml"Leaf# 124 "Find.frag.ml"->None|# 126 "Find.frag.ml"Node(l,v,r)# 126 "Find.frag.ml"->iffvthenfind_last_opt_auxvfrelsefind_last_optfl# 1 "Add.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* This is insertion in the style of BFS. *)(* (Disabled.)
let add (k : key) (t : tree) : tree =
let l, _, r = split k t in
join l k r
*)(* This is a less elegant but more efficient version of insertion. *)(* This implementation is taken from OCaml's Set library. *)letrecadd(x:key)(t:tree):tree=match# 28 "Add.frag.ml"(viewt)# 28 "Add.frag.ml"with|# 29 "Add.frag.ml"Leaf# 29 "Add.frag.ml"->singletonx|# 31 "Add.frag.ml"Node(l,v,r)# 31 "Add.frag.ml"->letc=E.comparexvinifc=0thentelseifc<0thenletl'=addxlinifl==l'thentelsejoin_neighborsl'vrelseletr'=addxrinifr==r'thentelsejoin_neighborslvr'# 1 "Remove.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* [remove_min_elt_1 l v r] removes the minimum element of the tree
[NODE(l, v, r)]. *)letrecremove_min_elt_1(l:tree)(v:key)(r:tree):tree=match# 17 "Remove.frag.ml"(viewl)# 17 "Remove.frag.ml"with|# 18 "Remove.frag.ml"Leaf# 18 "Remove.frag.ml"->r|# 20 "Remove.frag.ml"Node(ll,lv,lr)# 20 "Remove.frag.ml"->letl=remove_min_elt_1lllvlrinjoin_neighborslvr(* [remove_min_elt t] removes the minimum element of the tree [t]. *)letremove_min_elt(t:tree):tree=match# 27 "Remove.frag.ml"(viewt)# 27 "Remove.frag.ml"with|# 28 "Remove.frag.ml"Leaf# 28 "Remove.frag.ml"->raiseNot_found|# 30 "Remove.frag.ml"Node(l,v,r)# 30 "Remove.frag.ml"->remove_min_elt_1lvr(* [remove_max_elt_1 l v r] removes the maximum element of the tree
[NODE(l, v, r)]. *)letrecremove_max_elt_1(l:tree)(v:key)(r:tree):tree=match# 37 "Remove.frag.ml"(viewr)# 37 "Remove.frag.ml"with|# 38 "Remove.frag.ml"Leaf# 38 "Remove.frag.ml"->l|# 40 "Remove.frag.ml"Node(rl,rv,rr)# 40 "Remove.frag.ml"->letr=remove_max_elt_1rlrvrrinjoin_neighborslvr(* [remove_max_elt t] removes the maximum element of the tree [t]. *)letremove_max_elt(t:tree):tree=match# 47 "Remove.frag.ml"(viewt)# 47 "Remove.frag.ml"with|# 48 "Remove.frag.ml"Leaf# 48 "Remove.frag.ml"->raiseNot_found|# 50 "Remove.frag.ml"Node(l,v,r)# 50 "Remove.frag.ml"->remove_max_elt_1lvr(* [join2_siblings l r] is analogous to [join2 l r], but requires the
subtrees [l] and [r] to be siblings in a valid tree. *)(* [join2_siblings] is named [merge] in OCaml's Set library. *)(* This implementation arbitrarily chooses to place the minimum element of the
tree [r] at the root. One could also choose to place the maximum element of
the tree [l] at the root. One could imagine choosing between these
alternatives, based on the weights or heights of the trees [l] and [r], if
such a notion exists. That would remove the need for rebalancing. However,
this seems to make essentially no difference in practice. *)letjoin2_siblings(l:tree)(r:tree):tree=match# 66 "Remove.frag.ml"(viewl)# 66 "Remove.frag.ml",# 66 "Remove.frag.ml"(viewr)# 66 "Remove.frag.ml"with|_,# 67 "Remove.frag.ml"Leaf# 67 "Remove.frag.ml"->l|# 69 "Remove.frag.ml"Leaf# 69 "Remove.frag.ml",_->r|_,# 71 "Remove.frag.ml"Node(rl,rv,rr)# 71 "Remove.frag.ml"->join_neighborsl(min_elt_1rvrl)(* same as [min_elt r] *)(remove_min_elt_1rlrvrr)(* same as [remove_min_elt r] *)(* This is removal in the style of BFS. *)(* (Disabled.)
let remove (k : key) (t : tree) : tree =
let l, _, r = split k t in
join2 l r
*)(* This is a less elegant but more efficient version of removal. *)(* This implementation is taken from OCaml's Set library. *)letrecremove(x:key)(t:tree):tree=match# 92 "Remove.frag.ml"(viewt)# 92 "Remove.frag.ml"with|# 93 "Remove.frag.ml"Leaf# 93 "Remove.frag.ml"->empty|# 95 "Remove.frag.ml"Node(l,v,r)# 95 "Remove.frag.ml"->letc=E.comparexvinifc=0thenjoin2_siblingslrelseifc<0thenletl'=removexlinifl==l'thentelsejoin_neighborsl'vrelseletr'=removexrinifr==r'thentelsejoin_neighborslvr'# 1 "Split.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* [split] is implemented in the same way in OCaml's Set library and by BFS. *)(* We use the same code, but add a physical equality test that allows us to
preserve sharing (and avoid memory allocation) in some cases. *)letrecsplit(k:key)(t:tree):tree*bool*tree=match# 19 "Split.frag.ml"(viewt)# 19 "Split.frag.ml"with|# 20 "Split.frag.ml"Leaf# 20 "Split.frag.ml"->leaf,false,leaf|# 22 "Split.frag.ml"Node(l,m,r)# 22 "Split.frag.ml"->letc=E.comparekminifc=0thenl,true,relseifc<0thenletll,b,lr=splitklinll,b,(iflr==lthentelsejoinlrmr)elseletrl,b,rr=splitkrin(ifrl==rthentelsejoinlmrl),b,rr(* A specialized version of [split] that returns just the Boolean component
of the result is [mem]. *)(* [split13] is a variant of [split] that returns only the first and third
components of the result. *)letrecsplit13(k:key)(t:tree):tree*tree=match# 40 "Split.frag.ml"(viewt)# 40 "Split.frag.ml"with|# 41 "Split.frag.ml"Leaf# 41 "Split.frag.ml"->leaf,leaf|# 43 "Split.frag.ml"Node(l,m,r)# 43 "Split.frag.ml"->letc=E.comparekminifc=0thenl,relseifc<0thenletll,lr=split13klinll,(iflr==lthentelsejoinlrmr)elseletrl,rr=split13krin(ifrl==rthentelsejoinlmrl),rr(* [join2] is known as [concat] in OCaml's Set library. *)(* This is the code proposed by BFS. Their [split_last] function
corresponds to our functions [min_elt] and [remove_min_elt_1].
let rec split_last (l : tree) (k : key) (r : tree) : tree * key =
match VIEW(r) with
| LEAF ->
l, k
| NODE(l', k', r') ->
let r, m = split_last l' k' r' in
join l k r, m
let join2 (l : tree) (r : tree) : tree =
match VIEW(l) with
| LEAF ->
r
| NODE(ll, m, lr) ->
let l', k = split_last ll m lr in
join l' k r
*)(* [join2 l r] is implemented by extracting the maximum element of [l]
or the minimum element of [r] and letting [join] do the rest of the
work. *)(* In order to maintain a better balance, one might wish to extract an
element from the tree that seems larger. However, this seems to
bring no improvement in practice, so we avoid this complication. *)letjoin2(l:tree)(r:tree):tree=match# 86 "Split.frag.ml"(viewl)# 86 "Split.frag.ml",# 86 "Split.frag.ml"(viewr)# 86 "Split.frag.ml"with|# 87 "Split.frag.ml"Leaf# 87 "Split.frag.ml",_->r|_,# 89 "Split.frag.ml"Leaf# 89 "Split.frag.ml"->l|_,# 91 "Split.frag.ml"Node(rl,rv,rr)# 91 "Split.frag.ml"->joinl(min_elt_1rvrl)(* same as [min_elt r] *)(remove_min_elt_1rlrvrr)(* same as [remove_min_elt r] *)# 1 "Enum.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* -------------------------------------------------------------------------- *)(* Enumerations. *)moduleEnum=structtypetree=ttypeenum=|End|Moreofelt*t*enumtypet=enumletempty:enum=Endlet[@inline]is_empty(e:enum):bool=matchewith|End->true|More_->false(* [cat_tree_enum t e] concatenates the tree [t] in front of the
enumeration [e]. *)(* This function is named [cons_enum] in OCaml's Set library. *)letreccat_tree_enum(t:tree)(e:enum):enum=match# 41 "Enum.frag.ml"(viewt)# 41 "Enum.frag.ml"with|# 42 "Enum.frag.ml"Leaf# 42 "Enum.frag.ml"->e|# 44 "Enum.frag.ml"Node(l,v,r)# 44 "Enum.frag.ml"->cat_tree_enuml(More(v,r,e))(* [enum] converts a tree to an enumeration. *)let[@inline]enum(t:tree):enum=cat_tree_enumtempty(* [filter_tree low t e] constructs an enumeration whose elements are: 1-
the elements [x] of the tree [t] such that [low <= x] holds, followed
with 2- all elements of the enumeration [e]. *)(* In [filter_tree low t e], only the tree [t] is filtered by the constraint
[low <= x]. The enumeration [e] is not filtered (typically because it is
already known that all of its elements satisfy this constraint). This is
in contrast with [filter_tree_enum low t e] (below), where both [t] and
[e] are filtered. *)letrecfilter_tree(low:key)(t:tree)(e:enum):enum=match# 63 "Enum.frag.ml"(viewt)# 63 "Enum.frag.ml"with|# 64 "Enum.frag.ml"Leaf# 64 "Enum.frag.ml"->e|# 66 "Enum.frag.ml"Node(l,v,r)# 66 "Enum.frag.ml"->letc=E.comparevlowinifc=0thenMore(v,r,e)elseifc<0thenfilter_treelowreelsefilter_treelowl(More(v,r,e))let[@inline]from_enum(low:key)(t:tree):enum=filter_treelowtempty(* [filter_tree_enum low r e] extracts the elements [x] that satisfy the
constraint [low <= x] out of the sequence of the elements of the tree [r]
and of the enumeration [e]. *)(* Thus, it is equivalent to [from low (cat_tree_enum r e)],
but the function [from] has not been defined yet.
[filter_tree_enum] is in fact used to define [from]. *)(* Both the tree [r] and the enumeration [e] are filtered. *)letrecfilter_tree_enum(low:key)(r:tree)(e:enum):enum=(* Peek past [r] at the first element [v'] of [e], if there is one. *)matchewith|More(v',r',e')->letc=E.comparelowv'inifc>0then(* [v'] is below the threshold.
The subtree [r] and the value [v'] must be discarded.
Continue with [r'] and [e']. *)filter_tree_enumlowr'e'elseifc=0then(* [v'] is at the threshold.
The subtree [r] must be discarded. [e] must be kept. *)eelse(* c < 0 *)(* [v'] is above the threshold. *)(* No part of [e] must be discarded. *)(* Keep part of [r], followed with [e]. *)filter_treelowre|End->(* [e] is empty. Keep part of [r]. *)filter_treelowre(* [from low e] extracts from the enumeration [e]
the elements that lie at or above the threshold [low] . *)(* One could define [from low e] as [filter_tree_enum low leaf e].
However, the following code is slightly more efficient. *)letfrom(low:key)(e:enum):enum=matchewith|More(v,r,e')->ifE.comparelowv<=0then(* [v] is at or above the threshold. Keep all elements. *)eelse(* [v] is below the threshold. [v] must be discarded. *)filter_tree_enumlowre'|End->Endlethead(e:enum):key=matchewith|End->raiseNot_found|More(v,_,_)->vlettail(e:enum):enum=matchewith|End->raiseNot_found|More(_,r,e)->cat_tree_enumrelethead_opt(e:enum):keyoption=matchewith|End->None|More(v,_,_)->Somevlettail_opt(e:enum):enumoption=matchewith|End->None|More(_,r,e)->Some(cat_tree_enumre)(* [compare e1 e2] compares the enumerations [e1] and [e2]
according to a lexicographic ordering. *)letreccompare(e1:enum)(e2:enum):int=matche1,e2with|End,End->0|End,More_->-1|More_,End->1|More(v1,r1,e1),More(v2,r2,e2)->letc=E.comparev1v2inifc<>0thencelsecompare(cat_tree_enumr1e1)(cat_tree_enumr2e2)(* [to_seq] converts an enumeration to an OCaml sequence. *)letrecto_seq_node(e:enum):keySeq.node=matchewith|End->Seq.Nil|More(v,r,e)->Seq.Cons(v,fun()->to_seq_node(cat_tree_enumre))letto_seq(e:enum):keySeq.t=fun()->to_seq_nodee(* [elements] converts an enumeration back to a tree. *)(* It is the only function in this file that constructs a tree.
It exploits the construction function [join].
It performs no key comparisons. *)(* I believe, but have not proved, that, thanks to the remarkable
properties of [join], the time complexity of [elements] is only
O(log n). *)letrecelements(v:key)(r:tree)(e:enum):tree=matchewith|End->joinleafvr|More(v',r',e)->elementsv(joinrv'r')eletelements(e:enum):tree=matchewith|End->leaf|More(v,r,e)->elementsvre(* Disjointness. *)exceptionNotDisjoint(* [filter_tree_disjoint low t e] returns the same result as
[filter_tree low t e], except that it raises [NotDisjoint]
if the key [low] appears in its result. *)letrecfilter_tree_disjoint(low:key)(t:tree)(e:enum):enum=match# 210 "Enum.frag.ml"(viewt)# 210 "Enum.frag.ml"with|# 211 "Enum.frag.ml"Leaf# 211 "Enum.frag.ml"->e|# 213 "Enum.frag.ml"Node(l,v,r)# 213 "Enum.frag.ml"->letc=E.comparevlowinifc=0thenraiseNotDisjointelseifc<0thenfilter_tree_disjointlowreelsefilter_tree_disjointlowl(More(v,r,e))(* [filter_tree_enum_disjoint low r e] returns the same result as
[filter_tree_enum low r e], except that it raises [NotDisjoint]
if the key [low] appears in its result. *)letrecfilter_tree_enum_disjoint(low:key)(r:tree)(e:enum):enum=matchewith|More(v',r',e')->letc=E.comparelowv'inifc>0thenfilter_tree_enum_disjointlowr'e'elseifc=0thenraiseNotDisjointelsefilter_tree_disjointlowre|End->filter_tree_disjointlowre(* [disjoint_more_more v1 r1 e1 v2 r2 e2] requires [v1 < v2]. It determines
whether the enumerations [More (v1, r1, e1)] and [More (v2, r2, e2)] are
disjoint. It either returns [true] or raises [NotDisjoint]. *)(* This is Veldhuizen's leapfrog join algorithm. *)letrecdisjoint_more_morev1r1e1v2r2e2=assert(E.comparev1v2<0);(* Skip past [v2] in the enumeration [e1]. *)(* If [v2] appears in [e1], fail. *)lete1=filter_tree_enum_disjointv2r1e1inmatche1with|End->(* If [e1] is now empty, we are done. *)true|More(v1,r1,e1)->(* If [e1] is nonempty, then its front value [v1] must be greater than
[v2]. Exchange the roles of the two enumerations and continue. *)assert(E.comparev2v1<0);disjoint_more_morev2r2e2v1r1e1(* [disjoint e1 e2] determines whether the enumerations [e1] and [e2] are
disjoint. *)letdisjoint(e1:enum)(e2:enum):bool=matche1,e2with|End,_|_,End->true|More(v1,r1,e1),More(v2,r2,e2)->letc=E.comparev1v2inifc=0thenfalseelsetryifc<0thendisjoint_more_morev1r1e1v2r2e2elsedisjoint_more_morev2r2e2v1r1e1withNotDisjoint->false(* [length e] computes the length of the enumeration [e]. If we have
a constant-time [cardinal] function on sets, then its complexity
is logarithmic. Otherwise, its complexity is linear. *)letreclength_auxaccu(e:enum):int=matchewith|End->accu|More(_,r,e)->length_aux(accu+cardinalr+1)elet[@inline]length(e:enum):int=length_aux0eend(* Enum *)(* -------------------------------------------------------------------------- *)(* Enumerations in reverse (decreasing order). *)(* I would rather avoid this code duplication, but we must provide at least
[to_rev_seq], for compatibility with OCaml's Set library. *)moduleRevEnum=structtypetree=t(* In the enumeration [More (e, l, v)], we have [e < l < v], but the
enumeration is consumed (by the user) from the right to the left,
so [v] is produced first, followed with the elements of the tree
[l], followed with the elements of the enumeration [e]. *)typeenum=|End|Moreofenum*t*eltletempty:enum=End(* [cat_enum_tree e t] concatenates the enumeration [e] in front of
the tree [t]. It requires [e < t]. *)(* This function corresponds to [snoc_enum] in OCaml's Set library. *)letreccat_enum_tree(e:enum)(t:tree):enum=match# 326 "Enum.frag.ml"(viewt)# 326 "Enum.frag.ml"with|# 327 "Enum.frag.ml"Leaf# 327 "Enum.frag.ml"->e|# 329 "Enum.frag.ml"Node(l,v,r)# 329 "Enum.frag.ml"->cat_enum_tree(More(e,l,v))r(* [enum] converts a tree to an enumeration. *)let[@inline]enum(t:tree):enum=cat_enum_treeemptyt(* [to_seq] converts an enumeration to an OCaml sequence. *)letrecto_seq_node(e:enum):keySeq.node=matchewith|End->Seq.Nil|More(e,l,v)->Seq.Cons(v,fun()->to_seq_node(cat_enum_treeel))(* let to_seq (e : enum) : key Seq.t = *)(* fun () -> to_seq_node e *)end# 1 "Compare.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* -------------------------------------------------------------------------- *)(* Comparison. *)(* Instead of using enumerations of the trees [t1] and [t2], one could perform
a recursive traversal of [t1], while consuming an enumeration of [t2]. I
have benchmarked this variant: it allocates less memory, and can be faster,
but can also be about twice slower. *)letcompare(t1:tree)(t2:tree):int=ift1==t2then0else(* fast path *)Enum.(compare(enumt1)(enumt2))# 1 "Equal.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* -------------------------------------------------------------------------- *)(* Equality. *)(* Equality can be implemented in several ways. E.g., [equal t1 t2] could be
implemented in one line by [subset t1 t2 && subset t2 t1] or also in one
line by [is_empty (xor t1 t2)]. (The latter idea could be optimized, so
as to avoid actually constructing the tree [xor t1 t2] in memory.) Some
experiments suggest that either of these approaches is more expensive
than the following approach, which is based on [compare]. *)(* In weight-balanced trees, the weight of a tree can be determined in
constant time. This yields a fast path: if the weights and [t1] and [t2]
differ, then they cannot possibly be equal. In height-balanced trees, the
[weight] function returns a constant value, so this fast path is
disabled. *)let[@inline]equalt1t2=weightt1=weightt2&&(* fast path *)comparet1t2=0# 1 "Union.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* -------------------------------------------------------------------------- *)(* Union. *)(* This is the simple, elegant version of [union] given by BFS.
let rec union (t1 : tree) (t2 : tree) : tree =
match VIEW(t1), VIEW(t2) with
| LEAF, _
| _, LEAF ->
leaf
| NODE(_, _, _), NODE(l2, k2, r2) ->
let l1, r1 = split13 k2 t1 in
let l = union l1 l2
and r = union r1 r2 in
join l k2 r
*)(* Our implementation of [union] is in the same style as [inter].
It inherits two features of OCaml's Set library:
- the tree that seems smaller is split;
- if a subtree is a singleton then [union] degenerates to [add].
Furthermore, compared with OCaml's Set library, it is able to exploit
physical equality when present, and it offers a stronger guarantee
regarding the preservation of physical equality. *)(* The recursive function [union] ensures that if the result is
equal to [t2] then the result is physically equal to [t2]. *)(* In the case where [t2] is a singleton, we have already checked that
[t1] is neither empty nor a singleton, so the result of the union
cannot possibly be equal to [t2]. Thus, the obligation to preserve
sharing disappears in this case: using [add k2 t1] is safe. *)letrecunion(t1:tree)(t2:tree):tree=match# 49 "Union.frag.ml"(viewt1)# 49 "Union.frag.ml",# 49 "Union.frag.ml"(viewt2)# 49 "Union.frag.ml"with|# 50 "Union.frag.ml"Leaf# 50 "Union.frag.ml",_->t2|_,# 52 "Union.frag.ml"Leaf# 52 "Union.frag.ml"->t1|# 54 "Union.frag.ml"Node(l1,k1,r1)# 54 "Union.frag.ml",# 54 "Union.frag.ml"Node(l2,k2,r2)# 54 "Union.frag.ml"->if# 55 "Union.frag.ml"((match(viewl1)withLeaf->true|_->false)&&(match(viewr1)withLeaf->true|_->false))# 55 "Union.frag.ml"thenaddk1t2elseif# 56 "Union.frag.ml"((match(viewl2)withLeaf->true|_->false)&&(match(viewr2)withLeaf->true|_->false))# 56 "Union.frag.ml"thenaddk2t1elseletl1,r1=split13k2t1inletl=unionl1l2andr=unionr1r2inifl==l2&&r==r2thent2else(* preserve sharing *)joinlk2r(* This toplevel wrapper tests which of the two arguments seems larger. (With
weight-balanced trees, this is an exact test. With height-balanced trees,
it is a heuristic test.) This argument, one may hope, might also be the
result. Therefore, the recursive function [union] (above) is invoked with
this argument as its second argument. Compared with [inter], this is the
other way around. *)letuniont1t2=ift1==t2thent1else(* fast path *)ifseems_smallert1t2thenuniont1t2elseuniont2t1# 1 "Inter.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* -------------------------------------------------------------------------- *)(* Intersection. *)(* This is the simple, elegant version of [inter] given by BFS.
let rec inter (t1 : tree) (t2 : tree) : tree =
match VIEW(t1), VIEW(t2) with
| LEAF, _
| _, LEAF ->
leaf
| NODE(_, _, _), NODE(l2, k2, r2) ->
let l1, b, r1 = split k2 t1 in
let l = inter l1 l2
and r = inter r1 r2 in
if b then join l k2 r else join2 l r
*)(* The recursive function [inter] ensures that if the result is
equal to [t2] then the result is physically equal to [t2]. *)(* Compared with the simple version (above),
+ there is a fast path for the case where [t1 == t2] holds;
+ there is specialized code for the case where [t2] is a
singleton; in that case there is no need to use [split];
+ the code guarantees that if the result is equal to [t2]
then [t2] itself is returned. *)(* Adding specialized code for the case where [t1] is a singleton can lead
to small gains or losses in speed; the effect seems unclear. *)(* Adding specialized code for the cases where one of [l2] or [r2] is empty
saves a few percent in time, and is not worth the extra complexity. *)letrecinter(t1:tree)(t2:tree):tree=match# 50 "Inter.frag.ml"(viewt1)# 50 "Inter.frag.ml",# 50 "Inter.frag.ml"(viewt2)# 50 "Inter.frag.ml"with|# 51 "Inter.frag.ml"Leaf# 51 "Inter.frag.ml",_|_,# 52 "Inter.frag.ml"Leaf# 52 "Inter.frag.ml"->leaf|# 54 "Inter.frag.ml"Node(_,_,_)# 54 "Inter.frag.ml",# 54 "Inter.frag.ml"Node(l2,k2,r2)# 54 "Inter.frag.ml"->ift1==t2thent2else(* fast path *)if# 56 "Inter.frag.ml"((match(viewl2)withLeaf->true|_->false)&&(match(viewr2)withLeaf->true|_->false))# 56 "Inter.frag.ml"then(* The tree [t2] is [singleton k2]. *)ifmemk2t1thent2elseleafelseletl1,b,r1=splitk2t1inletl=interl1l2andr=interr1r2inifbthenifl==l2&&r==r2thent2else(* preserve sharing *)joinlk2relsejoin2lr(* This toplevel wrapper serves two purposes. First, it contains a fast path
for the case where [t1 == t2] holds. Second, it tests which of the two
arguments seems smaller. (With weight-balanced trees, this is an exact
test. With height-balanced trees, it is a heuristic test.) This argument,
one may hope, might also be the result. Therefore, the recursive function
[inter] (above) is invoked with this argument as its second argument. *)letintert1t2=ift1==t2thent1else(* fast path *)ifseems_smallert1t2thenintert2t1elseintert1t2# 1 "Diff.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* -------------------------------------------------------------------------- *)(* Difference. *)(* This is a simple, elegant version of [diff]. This version splits the
tree [t1].
let rec diff (t1 : tree) (t2 : tree) : tree =
match VIEW(t1), VIEW(t2) with
| LEAF, _ ->
leaf
| _, LEAF ->
t1
| NODE(_, _, _), NODE(l2, k2, r2) ->
let l1, r1 = split13 k2 t1 in
let l = diff l1 l2
and r = diff r1 r2 in
join2 l r
*)(* This version of [diff] guarantees that if the result is equal to [t1]
then [t1] itself is returned. *)letrecdiff(t1:tree)(t2:tree):tree=match# 38 "Diff.frag.ml"(viewt1)# 38 "Diff.frag.ml",# 38 "Diff.frag.ml"(viewt2)# 38 "Diff.frag.ml"with|# 39 "Diff.frag.ml"Leaf# 39 "Diff.frag.ml",_->leaf|_,# 41 "Diff.frag.ml"Leaf# 41 "Diff.frag.ml"->t1|# 43 "Diff.frag.ml"Node(l1,k1,r1)# 43 "Diff.frag.ml",# 43 "Diff.frag.ml"Node(l2,k2,r2)# 43 "Diff.frag.ml"->ift1==t2thenleafelse(* fast path *)if# 45 "Diff.frag.ml"((match(viewl1)withLeaf->true|_->false)&&(match(viewr1)withLeaf->true|_->false))# 45 "Diff.frag.ml"then(* [t1] is [singleton k1]. *)ifmemk1t2thenleafelset1elseif# 48 "Diff.frag.ml"((match(viewl2)withLeaf->true|_->false)&&(match(viewr2)withLeaf->true|_->false))# 48 "Diff.frag.ml"then(* [t2] is [singleton k2]. *)removek2t1elseletl2,b,r2=splitk1t2inletl=diffl1l2andr=diffr1r2inifbthenjoin2lrelseifl==l1&&r==r1thent1else(* preserve sharing *)joinlk1r# 1 "Xor.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* -------------------------------------------------------------------------- *)(* Symmetric difference. *)(* This is a simple, elegant version of [xor].
let rec xor (t1 : tree) (t2 : tree) : tree =
match VIEW(t1), VIEW(t2) with
| LEAF, _ ->
t2
| _, LEAF ->
t1
| NODE(_, _, _), NODE(l2, k2, r2) ->
let l1, b, r1 = split k2 t1 in
let l = xor l1 l2
and r = xor r1 r2 in
if b then join2 l r else join l k2 r
*)(* Except in the case where [t1] or [t2] is empty, [xor t1 t2] cannot be
equal to [t1] or [t2]. So there is no need to attempt to preserve
sharing when constructing new nodes. *)letrecxor(t1:tree)(t2:tree):tree=match# 38 "Xor.frag.ml"(viewt1)# 38 "Xor.frag.ml",# 38 "Xor.frag.ml"(viewt2)# 38 "Xor.frag.ml"with|# 39 "Xor.frag.ml"Leaf# 39 "Xor.frag.ml",_->t2|_,# 41 "Xor.frag.ml"Leaf# 41 "Xor.frag.ml"->t1|# 43 "Xor.frag.ml"Node(_,_,_)# 43 "Xor.frag.ml",# 43 "Xor.frag.ml"Node(l2,k2,r2)# 43 "Xor.frag.ml"->ift1==t2thenleafelse(* fast path *)if# 45 "Xor.frag.ml"((match(viewl2)withLeaf->true|_->false)&&(match(viewr2)withLeaf->true|_->false))# 45 "Xor.frag.ml"then(* [t2] is [singleton k2]. *)ifmemk2t1thenremovek2t1elseaddk2t1elseletl1,b,r1=splitk2t1inletl=xorl1l2andr=xorr1r2inifbthenjoin2lrelsejoinlk2r# 1 "Disjoint.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* -------------------------------------------------------------------------- *)(* Disjointness. *)(* This simple version of [disjoint] has the same structure as [inter]. *)(* (Disabled.)
let rec disjoint (t1 : tree) (t2 : tree) : bool =
match VIEW(t1), VIEW(t2) with
| LEAF, _
| _, LEAF ->
true
| NODE(_, _, _), NODE(l2, k2, r2) ->
let l1, b, r1 = split k2 t1 in
not b && disjoint l1 l2 && disjoint r1 r2
*)(* The above code can be improved by adding a fast path (based on physical
equality), by adding special cases for singletons, and by using a copy of
[split] that does not construct the subtrees [l] and [r] if the Boolean
result [b] is true. *)(* I have played with these variations, but I find them to be consistently
slower than the following approach, which is based on [Enum.disjoint]. *)letdisjointt1t2=match# 41 "Disjoint.frag.ml"(viewt1)# 41 "Disjoint.frag.ml",# 41 "Disjoint.frag.ml"(viewt2)# 41 "Disjoint.frag.ml"with|# 42 "Disjoint.frag.ml"Leaf# 42 "Disjoint.frag.ml",_|_,# 43 "Disjoint.frag.ml"Leaf# 43 "Disjoint.frag.ml"->true(* fast path *)|_,_->t1!=t2&&(* fast path *)Enum.(disjoint(enumt1)(enumt2))(* I have also played with a version of [disjoint] that does not use [split],
therefore does not construct new trees; it does not allocate memory or
perform rebalancing work. It can be fast, but I believe that its worst-case
time complexity is not optimal. *)# 1 "Subset.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* -------------------------------------------------------------------------- *)(* Inclusion. *)(* This simple version of [subset] has canonical structure. *)(* (Disabled.)
let rec subset (t1 : tree) (t2 : tree) : bool =
match VIEW(t1), VIEW(t2) with
| LEAF, _ ->
true
| _, LEAF ->
false
| NODE(_, _, _), NODE(l2, k2, r2) ->
let l1, r1 = split13 k2 t1 in
subset l1 l2 && subset r1 r2
*)(* This version adds a positive fast path (based on physical equality), a
negative fast path (based on weights), and a special treatment of the case
where [t1] is a singleton. (There is no need to add special treatment of
the case where [t2] is a singleton. Indeed, the subcases where [t1] is
empty or a singleton are taken care of already, and the subcase where [t1]
has more than one element is caught by the weight test.) *)(* In weight-balanced trees, the weight of a tree can be determined in time
O(1). This yields a negative fast path: if [weight t1 <= weight t2] does
not hold, then [subset t1 t2] returns false. In height-balanced trees, the
[weight] function returns a constant value, so this fast path is
disabled. *)letrecsubset(t1:tree)(t2:tree):bool=match# 47 "Subset.frag.ml"(viewt1)# 47 "Subset.frag.ml",# 47 "Subset.frag.ml"(viewt2)# 47 "Subset.frag.ml"with|# 48 "Subset.frag.ml"Leaf# 48 "Subset.frag.ml",_->true|_,# 50 "Subset.frag.ml"Leaf# 50 "Subset.frag.ml"->false|# 52 "Subset.frag.ml"Node(l1,k1,r1)# 52 "Subset.frag.ml",# 52 "Subset.frag.ml"Node(l2,k2,r2)# 52 "Subset.frag.ml"->t1==t2||(* fast path *)if# 54 "Subset.frag.ml"((match(viewl1)withLeaf->true|_->false)&&(match(viewr1)withLeaf->true|_->false))# 54 "Subset.frag.ml"then(* The tree [t1] is [singleton k1]. *)memk1t2elseweightt1<=weightt2&&(* fast path *)letl1,r1=split13k2t1insubsetl1l2&&subsetr1r2# 1 "Conversions.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* -------------------------------------------------------------------------- *)(* [elements] converts a set, in linear time, to a sorted list. *)letrecelements(t:tree)(k:eltlist):eltlist=match# 18 "Conversions.frag.ml"(viewt)# 18 "Conversions.frag.ml"with|# 19 "Conversions.frag.ml"Leaf# 19 "Conversions.frag.ml"->k|# 21 "Conversions.frag.ml"Node(l,v,r)# 21 "Conversions.frag.ml"->elementsl(v::elementsrk)let[@inline]elements(t:tree):eltlist=elementst[]letto_list=elements(* -------------------------------------------------------------------------- *)(* [to_seq] constructs the increasing sequence of the elements of the
tree [t]. *)letto_seq(t:tree):keySeq.t=fun()->Enum.(to_seq_node(enumt))(* [to_seq_from low t] constructs the increasing sequence of the
elements [x] of the tree [t] such that [low <= x] holds. *)letto_seq_from(low:key)(t:tree):keySeq.t=fun()->Enum.(to_seq_node(from_enumlowt))(* [to_rev_seq] constructs the decreasing sequence of the elements of
the tree [t]. *)letto_rev_seq(t:tree):keySeq.t=fun()->RevEnum.(to_seq_node(enumt))(* -------------------------------------------------------------------------- *)(* [to_array_slice t a i] writes the elements of the tree [t] to the
array slice determined by the array [a] and the start index [i].
It returns the end index of this slice. *)letrecto_array_slice(t:tree)ai:int=assert(0<=i&&i+cardinalt<=Array.lengtha);match# 58 "Conversions.frag.ml"(viewt)# 58 "Conversions.frag.ml"with|# 59 "Conversions.frag.ml"Leaf# 59 "Conversions.frag.ml"->i|# 61 "Conversions.frag.ml"Node(l,v,r)# 61 "Conversions.frag.ml"->leti=to_array_slicelaiina.(i)<-v;leti=i+1into_array_slicerai(* -------------------------------------------------------------------------- *)(* [to_array] converts a set, in linear time, to a sorted array. *)letto_array(t:tree):keyarray=match# 72 "Conversions.frag.ml"(viewt)# 72 "Conversions.frag.ml"with|# 73 "Conversions.frag.ml"Leaf# 73 "Conversions.frag.ml"->[||]|# 75 "Conversions.frag.ml"Node(_,dummy,_)# 75 "Conversions.frag.ml"->letn=cardinaltinleta=Array.makendummyinletj=to_array_sliceta0inassert(n=j);a(* -------------------------------------------------------------------------- *)(* [of_sorted_unique_array_slice a i j] requires the array slice defined by
array [a], start index [i], and end index [j] to be sorted and to contain
no duplicate elements. It converts this array slice, in linear time, to a
set. *)letrecof_sorted_unique_array_sliceaij=assert(0<=i&&i<=j&&j<=Array.lengtha);letn=j-iinmatchnwith|0->empty|1->letx=a.(i)insingletonx|2->letx=a.(i)andy=a.(i+1)indoubletonxy|3->letx=a.(i)andy=a.(i+1)andz=a.(i+2)intripletonxyz|_->letk=i+n/2inletl=of_sorted_unique_array_sliceaikandv=a.(k)andr=of_sorted_unique_array_slicea(k+1)jinjoin_weight_balancedlvr(* -------------------------------------------------------------------------- *)(* [of_sorted_unique_array a] requires the array [a] to be sorted and to
contain no duplicate elements. It converts this array, in linear time,
to a set. *)(* Because this function is unsafe (the user can provide an array that
is not sorted and/or that has duplicate elements), it is disabled.
[to_array] (below) is safe and is almost just as fast.
let[@inline] of_sorted_unique_array a =
of_sorted_unique_array_slice a 0 (Array.length a)
*)(* -------------------------------------------------------------------------- *)(* [of_array] converts an array to a set. This algorithm is adaptive. If the
array is sorted, then its time complexity is O(n). If the array is not
sorted, then its time complexity gradually degenerates to O(n.log n). *)(* Each run of consecutive increasing elements is converted to a set, in
linear time in the length of this run. Then, the union of these sets
is computed. *)letof_arraya=letyieldaccuij=unionaccu(of_sorted_unique_array_sliceaij)inArrayExtra.foreach_increasing_runE.compareyieldemptya(* -------------------------------------------------------------------------- *)(* [of_list] converts a list to a set. It is adaptive. *)(* OCaml's Set library constructs a sorted list (using [List.sort_uniq]) and
converts it directly to a tree. Instead, we convert the list to an array
and use [of_array]. On random data, our approach seems slower by about 50%.
On sorted data, our approach can be 2x or 3x faster. One drawback of our
approach is that it requires linear auxiliary storage. *)letof_listxs=xs|>Array.of_list|>of_array(* -------------------------------------------------------------------------- *)(* [of_seq] converts a sequence to a set. It is adaptive. *)(* [of_seq] in OCaml's Set library is implemented using [add_seq], which
itself is naively implemented by iterated insertions, so its complexity
is O(n.log n), whereas it could be O(n). *)letof_seqxs=xs|>Array.of_seq|>of_array(* [add_seq] inserts a sequence into a set. *)letadd_seqxst=union(of_seqxs)t# 1 "Map.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* -------------------------------------------------------------------------- *)(* [map] is defined in the same way as in OCaml's Set library. *)(* [tree_below_key] and [key_below_tree] invoke [min_elt] or [max_elt],
whose cost is the height of the subtree. The cumulative cost of
these calls, during the execution of [map], is of the form
1 * n/2 + 2 * n/4 + 3 * n/8 + ..., that is, O(n). *)(* If the function [f] is monotone, then the tests in [lax_join]
always succeed, so [join] is invoked at every node, and every
such call runs in constant time, since no rebalancing is
required. Thus, in this case, [map] runs in linear time. *)(* Otherwise, I believe (but have not carefully checked) that the
complexity of [map] is O(n.log n). *)let[@inline]tree_below_key(t:tree)(x:key):bool=match# 31 "Map.frag.ml"(viewt)# 31 "Map.frag.ml"with|# 32 "Map.frag.ml"Leaf# 32 "Map.frag.ml"->true|# 34 "Map.frag.ml"Node(_,v,r)# 34 "Map.frag.ml"->E.compare(max_elt_1vr)x<0let[@inline]key_below_tree(x:key)(t:tree):bool=match# 38 "Map.frag.ml"(viewt)# 38 "Map.frag.ml"with|# 39 "Map.frag.ml"Leaf# 39 "Map.frag.ml"->true|# 41 "Map.frag.ml"Node(l,v,_)# 41 "Map.frag.ml"->E.comparex(min_elt_1vl)<0(* [lax_join l v r] is analogous to [join l v r], but does not
require [l < v < r]. *)let[@inline]lax_joinlvr=iftree_below_keylv&&key_below_treevrthenjoinlvrelseunionl(addvr)letrecmapf(t:tree)=match# 54 "Map.frag.ml"(viewt)# 54 "Map.frag.ml"with|# 55 "Map.frag.ml"Leaf# 55 "Map.frag.ml"->leaf|# 57 "Map.frag.ml"Node(l,v,r)# 57 "Map.frag.ml"->(* Enforce left-to-right evaluation order. *)letl'=mapflinletv'=fvinletr'=mapfrinifl==l'&&v==v'&&r==r'thent(* preserve sharing *)elselax_joinl'v'r'(* -------------------------------------------------------------------------- *)(* [lax_join2] plays the role of [try_concat] in OCaml's Set library,
but is implemented in a slightly better way. *)letlax_join2t1t2=match# 71 "Map.frag.ml"(viewt1)# 71 "Map.frag.ml",# 71 "Map.frag.ml"(viewt2)# 71 "Map.frag.ml"with|# 72 "Map.frag.ml"Leaf# 72 "Map.frag.ml",_->t2|_,# 74 "Map.frag.ml"Leaf# 74 "Map.frag.ml"->t1|_,_->ifE.compare(max_eltt1)(min_eltt2)<0thenjoin2t1t2elseuniont1t2(* [filter_map] is defined in the same way as in OCaml's Set library. *)letrecfilter_mapf(t:tree)=match# 85 "Map.frag.ml"(viewt)# 85 "Map.frag.ml"with|# 86 "Map.frag.ml"Leaf# 86 "Map.frag.ml"->leaf|# 88 "Map.frag.ml"Node(l,v,r)# 88 "Map.frag.ml"->(* Enforce left-to-right evaluation order. *)letl'=filter_mapflinletv'=fvinletr'=filter_mapfrinmatchv'with|Somev'->ifl==l'&&v==v'&&r==r'thent(* preserve sharing *)elselax_joinl'v'r'|None->lax_join2l'r'# 1 "Filter.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* [filter] is the same as in OCaml's Set library. *)(* Because [join] and [join2] have logarithmic cost, this implementation
of [filter] has linear time complexity. *)(* One could imagine a completely different implementation of [filter],
also with linear time complexity, as follows: copy the data to an
array, filter the array, reconstruct a tree. However, this approach
would require linear auxiliary storage, may be slower in practice, and
would be less effective at preserving sharing in scenarios where many
elements are retained. *)letrecfilterp(t:tree):tree=match# 26 "Filter.frag.ml"(viewt)# 26 "Filter.frag.ml"with|# 27 "Filter.frag.ml"Leaf# 27 "Filter.frag.ml"->leaf|# 29 "Filter.frag.ml"Node(l,v,r)# 29 "Filter.frag.ml"->(* Enforce left-to-right evaluation order. *)letl'=filterplinletpv=pvinletr'=filterprinifpvthenifl==l'&&r==r'thentelsejoinl'vr'elsejoin2l'r'(* [partition] is the same as in OCaml's Set library, with one extra
optimization: as in [filter], we attempt to preserve sharing where
possible. *)letrecpartitionp(t:tree):tree*tree=match# 44 "Filter.frag.ml"(viewt)# 44 "Filter.frag.ml"with|# 45 "Filter.frag.ml"Leaf# 45 "Filter.frag.ml"->leaf,leaf|# 47 "Filter.frag.ml"Node(l,v,r)# 47 "Filter.frag.ml"->(* Enforce left-to-right evaluation order. *)letlt,lf=partitionplinletpv=pvinletrt,rf=partitionprinifpvthen(iflt==l&&rt==rthentelsejoinltvrt),join2lfrfelsejoin2ltrt,(iflf==l&&rf==rthentelsejoinlfvrf)# 1 "RandomAccess.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(* The functions in this file assume that we have a constant-time [cardinal]
function. *)(* -------------------------------------------------------------------------- *)(* Access to an element, based on its index. *)(* [get] has logarithmic complexity. *)(* If [cardinal] requires linear time then this implementation of [get] has
quadratic time complexity, which is unacceptable. In that case, it is
preferable to just use [to_array], which has linear time complexity,
followed with [Array.get]. *)letrecget(t:tree)(i:int):key=assert(0<=i&&i<cardinalt);match# 29 "RandomAccess.frag.ml"(viewt)# 29 "RandomAccess.frag.ml"with|# 30 "RandomAccess.frag.ml"Leaf# 30 "RandomAccess.frag.ml"->assertfalse|# 32 "RandomAccess.frag.ml"Node(l,v,r)# 32 "RandomAccess.frag.ml"->letcl=cardinallinifi=clthenvelseifi<clthengetlielsegetr(i-(cl+1))letget(t:tree)(i:int):key=ifconstant_time_cardinalthenif0<=i&&i<cardinaltthengettielsePrintf.sprintf"get: index %d is out of expected range [0, %d)"i(cardinalt)|>invalid_argelsefailwith"get: operation is not available"(* -------------------------------------------------------------------------- *)(* Discovering the index of an element, based on its value. *)(* [index] has logarithmic complexity. *)(* [index] is roughly analogous to [List.find_index], but has a different
type; [index] expects an element [x], whereas [List.find_index] expects
a predicate of type [elt -> bool]. *)(* We could offer [find_index] on sets, with linear time complexity, but
this seems pointless. The user can implement this function using an
enumeration, if she so wishes. *)letrecindex(i:int)(x:key)(t:tree):int=match# 67 "RandomAccess.frag.ml"(viewt)# 67 "RandomAccess.frag.ml"with|# 68 "RandomAccess.frag.ml"Leaf# 68 "RandomAccess.frag.ml"->raiseNot_found|# 70 "RandomAccess.frag.ml"Node(l,v,r)# 70 "RandomAccess.frag.ml"->letc=E.comparexvinifc<0thenindexixlelseleti=i+cardinallinifc=0thenielseindex(i+1)xrlet[@inline]indexxt=index0xtletindexxt=ifconstant_time_cardinalthenindexxtelsefailwith"index: operation is not available"(* -------------------------------------------------------------------------- *)(* Splitting by index -- in two parts. *)letreccut(t:tree)(i:int):tree*tree=assert(0<=i&&i<=cardinalt);ifi=0thenleaf,telseifi=cardinaltthent,leafelsematch# 101 "RandomAccess.frag.ml"(viewt)# 101 "RandomAccess.frag.ml"with|# 102 "RandomAccess.frag.ml"Leaf# 102 "RandomAccess.frag.ml"->assertfalse|# 104 "RandomAccess.frag.ml"Node(l,v,r)# 104 "RandomAccess.frag.ml"->letcl=cardinallinifi<=clthenletll,lr=cutliinassert(lr!=l);ll,joinlrvrelse(* [cl < i] *)letrl,rr=cutr(i-(cl+1))inassert(rl!=r);joinlvrl,rrletcut(t:tree)(i:int):tree*tree=ifconstant_time_cardinalthenif0<=i&&i<=cardinaltthencuttielsePrintf.sprintf"cut: index %d is out of expected range [0, %d]"i(cardinalt)|>invalid_argelsefailwith"cut: operation is not available"(* -------------------------------------------------------------------------- *)(* Splitting by index -- in three parts. *)letreccut_and_get(t:tree)(i:int):tree*key*tree=assert(0<=i&&i<cardinalt);match# 132 "RandomAccess.frag.ml"(viewt)# 132 "RandomAccess.frag.ml"with|# 133 "RandomAccess.frag.ml"Leaf# 133 "RandomAccess.frag.ml"->assertfalse|# 135 "RandomAccess.frag.ml"Node(l,v,r)# 135 "RandomAccess.frag.ml"->letcl=cardinallinifi=clthenl,v,relseifi<clthenletll,lv,lr=cut_and_getliinll,lv,joinlrvrelseletrl,rv,rr=cut_and_getr(i-(cl+1))injoinlvrl,rv,rrletcut_and_get(t:tree)(i:int):tree*key*tree=ifconstant_time_cardinalthenif0<=i&&i<cardinaltthencut_and_gettielsePrintf.sprintf"cut_and_get: index %d is out of expected range [0, %d)"i(cardinalt)|>invalid_argelsefailwith"cut_and_get: operation is not available"# 1 "Iter.frag.ml"(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)letreciterf(t:tree)=match# 14 "Iter.frag.ml"(viewt)# 14 "Iter.frag.ml"with|# 15 "Iter.frag.ml"Leaf# 15 "Iter.frag.ml"->()|# 17 "Iter.frag.ml"Node(l,v,r)# 17 "Iter.frag.ml"->iterfl;fv;iterfrletrecfoldf(t:tree)accu=match# 21 "Iter.frag.ml"(viewt)# 21 "Iter.frag.ml"with|# 22 "Iter.frag.ml"Leaf# 22 "Iter.frag.ml"->accu|# 24 "Iter.frag.ml"Node(l,v,r)# 24 "Iter.frag.ml"->foldfr(fv(foldflaccu))letrecfor_allp(t:tree)=match# 28 "Iter.frag.ml"(viewt)# 28 "Iter.frag.ml"with|# 29 "Iter.frag.ml"Leaf# 29 "Iter.frag.ml"->true|# 31 "Iter.frag.ml"Node(l,v,r)# 31 "Iter.frag.ml"->pv&&for_allpl&&for_allprletrecexistsp(t:tree)=match# 35 "Iter.frag.ml"(viewt)# 35 "Iter.frag.ml"with|# 36 "Iter.frag.ml"Leaf# 36 "Iter.frag.ml"->false|# 38 "Iter.frag.ml"Node(l,v,r)# 38 "Iter.frag.ml"->pv||existspl||existspr# 33 "Baby.cppo.ml"end(* -------------------------------------------------------------------------- *)(* The module [Baby.H] provides ready-made height-balanced binary
search trees. *)(* Unfortunately, the OCaml compiler is pretty bad at optimization. In my
experience, although it does usually inline functions when requested, it
does not subsequently perform the simplifications that one might naturally
expect. In particular, it does not simplify match-of-match, and cannot even
simplify match-of-constructor. *)(* For this reason, instead of applying the functor [Make] (above), we inline
it, using a preprocessor hack. Thus, we avoid the overhead of going through
a [view] function; instead, we have a [VIEW] macro. *)moduleH=H(* -------------------------------------------------------------------------- *)(* The module [Baby.W] provides ready-made weight-balanced binary
search trees. *)moduleW=W(* -------------------------------------------------------------------------- *)(* The following modules must be exported, because they are (or may be) used
in the benchmarks. Because they are somewhat unlikely to be useful to an
end user, their existence is not advertised. *)moduleHeight=HeightmoduleWeight=Weight