123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173(**************************************************************************)(* 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). *)(* *)(**************************************************************************)type'at={mutablecell:'adata;version:int}and'adata=|Arrof'aarray|Diffofint*'a*'at(** {1 Array creation} *)(******************************************************************************)letmkx={cell=Arrx;version=0}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=matcht.cellwith|Arr_->kt|Diff(i,v,t')->reroott'(functiont'->matcht'.cellwith|Arraasn->t'.cell<-Diff(i,a.(i),t);a.(i)<-v;t.cell<-n;kt|Diff_->assertfalse)letreroott=reroottignoreletsizet=reroott;matcht.cellwith|Arrarr->Array.lengtharr|_->assertfalseletgetti=reroott;matcht.cellwith|Arrarr->arr.(i)|Diff_->assertfalseletsettiv=reroott;matcht.cellwith|Arrarr->ifarr.(i)=vthent(* No-op update *)else{cell=Diff(i,v,t);version=t.version+1}|Diff_->assertfalsemoduleIntHashtable=Hashtbl.Make(structtypet=intlethash=Fun.idletequal=Int.equalend)letdifft1t2=reroott1;matcht1.cellwith|Diff_->assertfalse|Arraasn->lettable=IntHashtable.create100in(* MAYBE: select size based on Array.length a? *)letreciterateminv=function|Arr_asn'->assert(n==n');minv(* 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;letminv=ifminv.version>next.versionthennextelseminviniterateminvnext.cellinletminv=iteratet2t2.cellintable,Someminvletdiff_keyt1t2=reroott1;matcht1.cellwith|Diff_->assertfalse|Arraasn->lettable=IntHashtable.create100in(* MAYBE: select size based on Array.length a? *)letreciterateminv=function|Arr_asn'->assert(n==n');minv(* 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;letminv=ifminv.version>next.versionthennextelseminviniterateminvnext.cellinletminv=iteratet2t2.cellintable,Someminvletpretty?(pp_sep=(funfmt()->Format.fprintffmt";@ "))pp_eltfmtt=reroott;matcht.cellwith|Diff_->assertfalse|Arra->Format.pp_print_list~pp_seppp_eltfmt(Array.to_lista)(** {1 Array resizing} *)(******************************************************************************)letappendtarr=reroott;matcht.cellwith|Diff_->assertfalse|Arra->t.cell<-Arr(Array.appendaarr)letextendtnx=ifn<0thenraise(Invalid_argument"PersistentArray.extend by negative amount");reroott;matcht.cellwith|Diff_->assertfalse|Arra->letlen=Array.lengthaint.cell<-Arr(Array.init(len+n)(funi->ifi<lenthenArray.unsafe_getaielsex))(** {1 Iterators} *)(******************************************************************************)letmapft=reroott;matcht.cellwith|Diff_->assertfalse|Arra->{cell=Arr(Array.mapfa);version=0}letiterft=reroott;matcht.cellwith|Diff_->assertfalse|Arra->Array.iterfaletfoldfinitt=reroott;matcht.cellwith|Diff_->assertfalse|Arra->Array.fold_leftfinita