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/PersistentArray.ml.html

Source file PersistentArray.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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
(**************************************************************************)
(*  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).                      *)
(*                                                                        *)
(**************************************************************************)

module IntHashtable = VersionedPersistentArray.IntHashtable

module type S = sig
  type 'a t

  val init: int -> (int -> 'a) -> 'a t
  val make: int -> 'a -> 'a t
  val of_array: 'a array -> 'a t
  val of_list: 'a list -> 'a t

  val size: 'a t -> int
  val get: 'a t -> int -> 'a
  val set: 'a t -> int -> 'a -> 'a t
  val pretty:
      ?pp_sep:(Format.formatter -> unit -> unit) ->
      (Format.formatter -> 'a -> unit) ->
      Format.formatter -> 'a t -> unit

  val diff: 'a t -> 'a t -> ('a * 'a) IntHashtable.t * 'a t option
  val diff_key: 'a t -> 'a t -> unit IntHashtable.t * 'a t option

  val append: 'a t -> 'a array -> unit
  val extend: 'a t -> int -> 'a -> unit

  val map: ('a -> 'b) -> 'a t -> 'b t
  val iter: ('a -> unit) -> 'a t -> unit
  val fold: ('acc -> 'a -> 'acc) -> 'acc -> 'a t -> 'acc
end

type 'a t = 'a data ref
and 'a data =
  | Arr of 'a array (* we could also use Dynarray.t *)
  | Diff of int * 'a * 'a t

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

let mk x = ref (Arr x)
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 with
  | Arr _ -> k t
  | Diff (i, v, t') ->
      reroot t' (function t' -> match !t' with
        | Arr a as n ->
            t' := Diff (i, a.(i), t);
            a.(i) <- v;
            t := n;
            k t
        | Diff _ -> assert false)
let reroot t = reroot t ignore

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

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

let set t i v =
  reroot t;
  match !t with
  | Arr arr ->
      if arr.(i) = v then t (* No-op update *)
      else ref (Diff(i, v, t))
  | Diff _ -> assert false

let diff t1 t2 =
  reroot t1;
  match !t1 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 = function
        | Arr _ as n' -> assert (n == n') (* 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;
            iterate !next
      in iterate !t2;
      table, None

let diff_key t1 t2 =
  reroot t1;
  match !t1 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 = function
        | Arr _ as n' -> assert (n == n') (* 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;
            iterate !next
      in iterate !t2;
      table, None

let pretty ?(pp_sep=(fun fmt () -> Format.fprintf fmt ";@ ")) pp_elt fmt t =
  reroot t;
  match !t 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 with
  | Diff _ -> assert false
  | Arr a -> t := 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 with
  | Diff _ -> assert false
  | Arr a ->
      let len = Array.length a in
      t := 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 with
  | Diff _ -> assert false
  | Arr a -> ref (Arr (Array.map f a))

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

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

module Versioned = VersionedPersistentArray