123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194(**************************************************************************)(* This file is part of the Codex semantics library *)(* (Union-find lattice subcomponent). *)(* *)(* Copyright (C) 2026 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 3.0 *)(* for more details (enclosed in the file LICENSE). *)(* *)(**************************************************************************)moduleIntHashtable=VersionedPersistentArray.IntHashtablemoduletypeS=sigtype'atvalinit:int->(int->'a)->'atvalmake:int->'a->'atvalof_array:'aarray->'atvalof_list:'alist->'atvalsize:'at->intvalget:'at->int->'avalset:'at->int->'a->'atvalpretty:?pp_sep:(Format.formatter->unit->unit)->(Format.formatter->'a->unit)->Format.formatter->'at->unitvaldiff:'at->'at->('a*'a)IntHashtable.t*'atoptionvaldiff_key:'at->'at->unitIntHashtable.t*'atoptionvalappend:'at->'aarray->unitvalextend:'at->int->'a->unitvalmap:('a->'b)->'at->'btvaliter:('a->unit)->'at->unitvalfold:('acc->'a->'acc)->'acc->'at->'accendtype'at='adatarefand'adata=|Arrof'aarray(* we could also use Dynarray.t *)|Diffofint*'a*'at(** {1 Array creation} *)(******************************************************************************)letmkx=ref(Arrx)letinitnf=Array.initnf|>mkletmakenx=Array.makenx|>mkletof_arrayarr=Array.copyarr|>mkletof_listl=Array.of_listl|>mk(** {1 Array operations} *)(******************************************************************************)(* let rec reroot t =
match !t with
| Arr arr -> ()
| Diff (i, v, t') ->
reroot t';
match !t' with
| Arr a as n ->
t' := Diff (i, a.(i), t);
a.(i) <- v;
t := n
| Diff _ -> assert false *)(** Rewrote reroot in continuation passing style, to avoid stack-overflows on large reroots *)letrecreroottk=match!twith|Arr_->kt|Diff(i,v,t')->reroott'(functiont'->match!t'with|Arraasn->t':=Diff(i,a.(i),t);a.(i)<-v;t:=n;kt|Diff_->assertfalse)letreroott=reroottignoreletsizet=reroott;match!twith|Arrarr->Array.lengtharr|_->assertfalseletgetti=reroott;match!twith|Arrarr->arr.(i)|Diff_->assertfalseletsettiv=reroott;match!twith|Arrarr->ifarr.(i)=vthent(* No-op update *)elseref(Diff(i,v,t))|Diff_->assertfalseletdifft1t2=reroott1;match!t1with|Diff_->assertfalse|Arraasn->lettable=IntHashtable.create100in(* MAYBE: select size based on Array.length a? *)letreciterate=function|Arr_asn'->assert(n==n')(* Check the roots match *)|Diff(i,v,next)->beginmatchIntHashtable.findtableiwith|_->()(* We already encountered a change at i from t2 to t1, ignore this older change *)|exceptionNot_found->IntHashtable.addtablei(a.(i),v)end;iterate!nextiniterate!t2;table,Noneletdiff_keyt1t2=reroott1;match!t1with|Diff_->assertfalse|Arraasn->lettable=IntHashtable.create100in(* MAYBE: select size based on Array.length a? *)letreciterate=function|Arr_asn'->assert(n==n')(* Check the roots match *)|Diff(i,v,next)->beginmatchIntHashtable.findtableiwith|()->()(* We already encountered a change at i from t2 to t1, ignore this older change *)|exceptionNot_found->IntHashtable.addtablei()end;iterate!nextiniterate!t2;table,Noneletpretty?(pp_sep=(funfmt()->Format.fprintffmt";@ "))pp_eltfmtt=reroott;match!twith|Diff_->assertfalse|Arra->Format.pp_print_list~pp_seppp_eltfmt(Array.to_lista)(** {1 Array resizing} *)(******************************************************************************)letappendtarr=reroott;match!twith|Diff_->assertfalse|Arra->t:=Arr(Array.appendaarr)letextendtnx=ifn<0thenraise(Invalid_argument"PersistentArray.extend by negative amount");reroott;match!twith|Diff_->assertfalse|Arra->letlen=Array.lengthaint:=Arr(Array.init(len+n)(funi->ifi<lenthenArray.unsafe_getaielsex))(** {1 Iterators} *)(******************************************************************************)letmapft=reroott;match!twith|Diff_->assertfalse|Arra->ref(Arr(Array.mapfa))letiterft=reroott;match!twith|Diff_->assertfalse|Arra->Array.iterfaletfoldfinitt=reroott;match!twith|Diff_->assertfalse|Arra->Array.fold_leftfinitamoduleVersioned=VersionedPersistentArray