package union-find-lattice

  1. Overview
  2. Docs
Persistent union-find data-structures with lattice operations (order, meet, join)

Install

dune-project
 Dependency

Authors

Maintainers

Sources

union-find-lattice-0.1.0.tbz
sha256=ecaf1444cd0e9d21174d854da0d2eea56d685180cc1e098016e2c66bc809f8ab
sha512=f12612357504879f78094ffa623bf44ec87c7f7adeeea1809c0b74fdf41e51a88958634d51d3f8bd8881c577a635ef81beaff91d0361195f9a65a5724ce096a9

doc/src/union-find-lattice.persistent-array/VersionedPersistentArray.ml.html

Source file VersionedPersistentArray.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
(**************************************************************************)
(*  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 'a t = { mutable cell:'a data; version: int }
and 'a data =
  | Arr of 'a array
  | Diff of int * 'a * 'a t

(** {1 Array creation}                                                        *)
(******************************************************************************)

let mk x = { cell=Arr x; version=0 }
let init n f = Array.init n f |> mk
let make n x = Array.make n x |> mk
let of_array arr = Array.copy arr |> mk
let of_list l = Array.of_list l |> 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 *)
let rec reroot t k =
  match t.cell with
  | Arr _ -> k t
  | Diff (i, v, t') ->
      reroot t' (function t' -> match t'.cell with
        | Arr a as n ->
            t'.cell <- Diff (i, a.(i), t);
            a.(i) <- v;
            t.cell <- n;
            k t
        | Diff _ -> assert false)
let reroot t = reroot t ignore

let size t =
  reroot t;
  match t.cell with
  | Arr arr -> Array.length arr
  | _ -> assert false

let get t i =
  reroot t;
  match t.cell with
  | Arr arr -> arr.(i)
  | Diff _ -> assert false

let set t i v =
  reroot t;
  match t.cell with
  | Arr arr ->
      if arr.(i) = v then t (* No-op update *)
      else { cell=Diff(i, v, t); version=t.version + 1 }
  | Diff _ -> assert false

module IntHashtable = Hashtbl.Make(struct
  type t = int
  let hash = Fun.id
  let equal = Int.equal
end)

let diff t1 t2 =
  reroot t1;
  match t1.cell with
  | Diff _ -> assert false
  | Arr a as n ->
      let table = IntHashtable.create 100 in (* MAYBE: select size based on Array.length a? *)
      let rec iterate minv = function
        | Arr _ as n' -> assert (n == n'); minv (* Check the roots match *)
        | Diff(i, v, next) ->
            begin match IntHashtable.find table i with
            | _ -> () (* We already encountered a change at i from t2 to t1, ignore this older change *)
            | exception Not_found -> IntHashtable.add table i (a.(i), v)
            end;
            let minv = if minv.version > next.version then next else minv in
            iterate minv next.cell
      in
      let minv = iterate t2 t2.cell in
      table, Some minv

let diff_key t1 t2 =
  reroot t1;
  match t1.cell with
  | Diff _ -> assert false
  | Arr a as n ->
      let table = IntHashtable.create 100 in (* MAYBE: select size based on Array.length a? *)
      let rec iterate minv = function
        | Arr _ as n' -> assert (n == n'); minv (* Check the roots match *)
        | Diff(i, v, next) ->
            begin match IntHashtable.find table i with
            | () -> () (* We already encountered a change at i from t2 to t1, ignore this older change *)
            | exception Not_found -> IntHashtable.add table i ()
            end;
            let minv = if minv.version > next.version then next else minv in
            iterate minv next.cell
      in
      let minv = iterate t2 t2.cell in
      table, Some minv

let pretty ?(pp_sep=(fun fmt () -> Format.fprintf fmt ";@ ")) pp_elt fmt t =
  reroot t;
  match t.cell with
  | Diff _ -> assert false
  | Arr a -> Format.pp_print_list ~pp_sep pp_elt fmt (Array.to_list a)

(** {1 Array resizing}                                                        *)
(******************************************************************************)

let append t arr =
  reroot t;
  match t.cell with
  | Diff _ -> assert false
  | Arr a -> t.cell <- Arr (Array.append a arr)

let extend t n x =
  if n < 0 then raise (Invalid_argument "PersistentArray.extend by negative amount");
  reroot t;
  match t.cell with
  | Diff _ -> assert false
  | Arr a ->
      let len = Array.length a in
      t.cell <- Arr (Array.init (len+n) (fun i -> if i < len then Array.unsafe_get a i else x))

(** {1 Iterators}                                                             *)
(******************************************************************************)

let map f t =
  reroot t;
  match t.cell with
  | Diff _ -> assert false
  | Arr a -> { cell=Arr (Array.map f a); version=0 }

let iter f t =
  reroot t;
  match t.cell with
  | Diff _ -> assert false
  | Arr a -> Array.iter f a

let fold f init t =
  reroot t;
  match t.cell with
  | Diff _ -> assert false
  | Arr a -> Array.fold_left f init a