123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)(** An imperative implementation of partitions via Union-Find *)(** Paths are compressed imperatively at each lookup of a
canonical representative. Each union also modifies in-place
the partition structure.
Nota: For the moment we use Pervasive's comparison for
choosing the smallest object as representative. This could
be made more generic.
*)moduletypePartitionSig=sig(** The type of elements in the partition *)typeelt(** A set structure over elements *)typeset(** The type of partitions *)typet(** Initialise an empty partition *)valcreate:unit->t(** Add (in place) an element in the partition, or do nothing
if the element is already in the partition. *)valadd:elt->t->unit(** Find the canonical representative of an element.
Raise [not_found] if the element isn't known yet. *)valfind:elt->t->elt(** Merge (in place) the equivalence classes of two elements.
This will add the elements in the partition if necessary. *)valunion:elt->elt->t->unit(** Merge (in place) the equivalence classes of many elements. *)valunion_set:set->t->unit(** Listing the different components of the partition *)valpartition:t->setlistendmoduletypeSetS=sigtypettypeeltvalsingleton:elt->tvalunion:t->t->tvalchoose:t->eltvaliter:(elt->unit)->t->unitendmoduletypeMapS=sigtypekeytype+'atvalempty:'atvalfind:key->'at->'avaladd:key->'a->'at->'atvalmem:key->'at->boolvalfold:(key->'a->'b->'b)->'at->'b->'bendmoduleMake(S:SetS)(M:MapSwithtypekey=S.elt)=structtypeelt=S.elttypeset=S.ttypenode=|Canonofset|Equivofelttypet=noderefM.trefletcreate()=ref(M.empty:noderefM.t)letfreshxp=letnode=ref(Canon(S.singletonx))inp:=M.addxnode!p;x,nodeletreclookupxp=letnode=M.findx!pinmatch!nodewith|Canon_->x,node|Equivy->let((z,_)asres)=lookupypinifnot(z==y)thennode:=Equivz;resletaddxp=ifnot(M.memx!p)thenignore(freshxp)letfindxp=fst(lookupxp)letcanonicalxp=trylookupxpwithNot_found->freshxpletunionxyp=let((x,_)asxcan)=canonicalxpinlet((y,_)asycan)=canonicalypinifx=ythen()elseletxcan,ycan=ifx<ythenxcan,ycanelseycan,xcaninletx,xnode=xcanandy,ynode=ycaninmatch!xnode,!ynodewith|Canonlx,Canonly->xnode:=Canon(S.unionlxly);ynode:=Equivx;|_->assertfalseletunion_setsp=tryletx=S.choosesinS.iter(funy->unionxyp)swithNot_found->()letpartitionp=List.rev(M.fold(funxnodeacc->match!nodewith|Equiv_->acc|Canonlx->lx::acc)!p[])end