123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128(* This code is based on the MLton library set/disjoint.fun, which has the
following copyright notice.
*)(* Copyright (C) 1999-2005 Henry Cejtin, Matthew Fluet, Suresh
* Jagannathan, and Stephen Weeks.
*
* MLton is released under a BSD-style license.
* See the file MLton-LICENSE for details.
*)open!Import(*
{v
Root
|
Inner
/ .. | .. \
Inner Inner Inner
/|\ /|\ /|\
... ... ...
v}
We construct the `inverted' tree in the ML representation.
The direction of the edges is UPWARDS.
Starting with any ['a t] we can step directly to its parent.
But we can't (and don't need to) start from the root and step to its children.
*)(*
[rank] is an upper bound on the depth of any node in the up-tree.
Imagine an unlucky sequence of operations in which you create N
individual [t]-values and then union them together in such a way
that you always pick the root of each tree to union together, so that
no path compression takes place. If you don't take care to somehow
balance the resulting up-tree, it is possible that you end up with one
big long chain of N links, and then calling [representative] on the
deepest node takes Theta(N) time. With the balancing scheme of never
increasing the rank of a node unnecessarily, it would take O(log N).
*)type'aroot={mutablevalue:'a;mutablerank:int}type'at={mutablenode:'anode}and'anode=|Innerof'at(* [Inner x] is a node whose parent is [x]. *)|Rootof'arootletinvariant_t=letreclooptdepth=matcht.nodewith|Innert->loopt(depth+1)|Rootr->assert(depth<=r.rank)inloopt0;;letcreatev={node=Root{value=v;rank=0}}(* invariants:
[inner.node] = [inner_node] = [Inner t].
[descendants] are the proper descendants of [inner] we've visited.
*)letreccompresst~inner_node~inner~descendants=matcht.nodewith|Rootr->(* t is the root of the tree.
Re-point all descendants directly to it by setting them to [Inner t].
Note: we don't re-point [inner] as it already points there. *)List.iterdescendants~f:(funt->t.node<-inner_node);t,r|Innert'asnode->compresst'~inner_node:node~inner:t~descendants:(inner::descendants);;letrepresentativet=matcht.nodewith|Rootr->t,r|Innert'asnode->compresst'~inner_node:node~inner:t~descendants:[];;letroott=matcht.nodewith|Rootr->(* avoid tuple allocation in the fast path *)r|_->snd(representativet);;letrankt=(roott).rankletgett=(roott).valueletsettv=(roott).value<-vletsame_classt1t2=phys_equal(roott1)(roott2)letuniont1t2=lett1,r1=representativet1inlett2,r2=representativet2inifphys_equalr1r2then()else(letn1=r1.rankinletn2=r2.rankinifn1<n2thent1.node<-Innert2else(t2.node<-Innert1;ifn1=n2thenr1.rank<-r1.rank+1));;letis_compressedt=invariantignoret;matcht.nodewith|Root_->true|Innert->(matcht.nodewith|Root_->true|Inner_->false);;modulePrivate=structletis_compressed=is_compressedletrank=rankend