123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120(**************************************************************************)(* *)(* Copyright (C) Jean-Christophe Filliatre *)(* *)(* This software is free software; you can redistribute it and/or *)(* modify it under the terms of the GNU Library General Public *)(* License version 2.1, with the special exception on linking *)(* described in file LICENSE.puf. *)(* *)(* This software 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. *)(* *)(**************************************************************************)(* Persistent union-find = Tarjan's algorithm with persistent arrays *)(* persistent arrays; see the https://www.lri.fr/~filliatr/ftp/ocaml/ds/parray.ml.html for explanations *)modulePa=structtypet=datarefanddata=|Arrayofintarray|Diffofint*int*tletcreatenv=ref(Array(Array.makenv))letinitnf=ref(Array(Array.initnf))(* reroot t ensures that t becomes an Array node *)letrecrerootktk=match!twith|Array_->k()|Diff(i,v,t')->rerootkt'(fun()->beginmatch!t'with|Arrayaasn->letv'=a.(i)ina.(i)<-v;t:=n;t':=Diff(i,v',t)|Diff_->assertfalseend;k())letreroott=rerootkt(fun()->())letgetti=match!twith|Arraya->a.(i)|Diff_->reroott;beginmatch!twithArraya->a.(i)|Diff_->assertfalseendletsettiv=reroott;match!twith|Arrayaasn->letold=a.(i)inifold==vthentelsebegina.(i)<-v;letres=refnint:=Diff(i,old,res);resend|Diff_->assertfalseend(* Tarjan's algorithm *)typet={mutablefather:Pa.t;(* mutable to allow path compression *)c:Pa.t;(* ranks *)}letcreaten={c=Pa.createn0;father=Pa.initn(funi->i)}letrecfind_auxfi=letfi=Pa.getfiiniffi==ithenf,ielseletf,r=find_auxffiinletf=Pa.setfirinf,rletfindhx=letf,rx=find_auxh.fatherxinh.father<-f;rxletunionhxy=letrx=findhxinletry=findhyinifrx!=rythenbeginletrxc=Pa.geth.crxinletryc=Pa.geth.cryinifrxc>rycthen{hwithfather=Pa.seth.fatherryrx}elseifrxc<rycthen{hwithfather=Pa.seth.fatherrxry}else{c=Pa.seth.crx(rxc+1);father=Pa.seth.fatherryrx}endelseh(* tests *)(***
let t = create 10
let () = assert (find t 0 <> find t 1)
let t = union t 0 1
let () = assert (find t 0 = find t 1)
let () = assert (find t 0 <> find t 2)
let t = union t 2 3
let t = union t 0 3
let () = assert (find t 1 = find t 2)
let t = union t 4 4
let () = assert (find t 4 <> find t 3)
***)