package codex
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
The Codex library for building static analysers based on abstract interpretation
Install
dune-project
Dependency
Authors
Maintainers
Sources
1.0-rc4.tar.gz
md5=bc7266a140c6886add673ede90e335d3
sha512=8da42c0ff2c1098c5f9cb2b5b43b306faf7ac93b8f5ae00c176918cee761f249ff45b29309f31a05bbcf6312304f86a0d5a000eb3f1094d3d3c2b9b4c7f5c386
doc/src/codex.union_find/imperative.ml.html
Source file imperative.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 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298(**************************************************************************) (* This file is part of the Codex semantics library. *) (* *) (* Copyright (C) 2013-2025 *) (* 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 2.1 *) (* for more details (enclosed in the file LICENSE). *) (* *) (**************************************************************************) (** {1 Nodes} *) (** {2 Nodes without values (simple nodes)} *) module MakeNode (Elt : Parameters.SIMPLE_GENERIC_ELT) (Relation : Parameters.GENERIC_GROUP) = struct type 'a t = { mutable parent : 'a parent; payload : 'a Elt.t } and 'a parent = | Node : 'b t * ('a, 'b) Relation.t -> 'a parent | Root let polyeq a b = Elt.polyeq a.payload b.payload module Relation = Relation let get_parent x = x.parent let set_parent x v = x.parent <- v let payload x = x.payload let make_node payload = { payload; parent = Root } end module MakeNumberedNode (Elt : HetHashtbl.HETEROGENEOUS_HASHED_TYPE) (Relation : Parameters.GENERIC_GROUP) () = struct include MakeNode(Elt)(Relation) module H = HetHashtbl.Make(Elt)(struct type nonrec ('a, _) t = 'a t end) let nodes : unit H.t = H.create 100 let make_node payload = let nd = make_node payload in H.add nodes payload nd; nd let get_node payload = H.find_opt nodes payload let get_or_make_node payload = match get_node payload with | Some t -> t | None -> make_node payload end (** {2 Nodes with values} *) module MakeValuedNode (Elt : Parameters.SIMPLE_GENERIC_ELT) (Relation : Parameters.GENERIC_GROUP) (Value : Parameters.SIMPLE_GENERIC_VALUE with type ('a,'b) relation = ('a,'b) Relation.t) = struct type 'a t = { mutable parent : 'a parent; payload : 'a Elt.t } and 'a parent = | Node : 'b t * ('a, 'b) Relation.t -> 'a parent | Root of 'a root and 'a root = { mutable value : 'a Value.t; mutable size : int } let polyeq a b = Elt.polyeq a.payload b.payload module Relation = Relation module Value = Value let get_parent x = x.parent let set_parent x v = x.parent <- v let payload x = x.payload let make_node payload value = { payload; parent = Root { value; size = 1 } } end module MakeValuedNumberedNode (Elt : HetHashtbl.HETEROGENEOUS_HASHED_TYPE) (Relation : Parameters.GENERIC_GROUP) (Value : Parameters.SIMPLE_GENERIC_VALUE with type ('a,'b) relation = ('a,'b) Relation.t) () = struct include MakeValuedNode(Elt)(Relation)(Value) module H = HetHashtbl.Make(Elt)(struct type nonrec ('a, _) t = 'a t end) let nodes : unit H.t = H.create 100 let make_node payload value = let nd = make_node payload value in H.add nodes payload nd; nd let get_node payload = H.find_opt nodes payload let get_or_make_node payload value = match get_node payload with | Some t -> t | None -> make_node payload value end module HashtblSimpleNode (Elt: HetHashtbl.HETEROGENEOUS_HASHED_TYPE) (Relation: Parameters.GENERIC_GROUP) = struct type 'a t = 'a Elt.t type 'a parent = | Node: 'b t * ('a, 'b) Relation.t -> 'a parent | Root let polyeq = Elt.polyeq module H = HetHashtbl.Make(Elt)(struct type ('a, _) t = 'a parent end) let table: unit H.t = H.create 125 let get_parent x = match H.find table x with | x -> x | exception Not_found -> Root let set_parent x = function | Root -> H.remove table x | n -> H.replace table x n module Relation = Relation end (** {1 Union find structures} *) module GenericRelationalValued(Node: Parameters.UF_NODE_WITH_VALUE) = struct open Node type 'a t = 'a Node.t type ('a, 'b) relation = ('a, 'b) Relation.t type 'a value = 'a Value.t type 'a ret = Exists_b : 'b t * 'b root * ('a, 'b) Relation.t -> 'a ret let ( ** ) = Relation.compose let ( ~~ ) = Relation.inverse let rec find_repr : type a. a t -> a ret = fun n -> match get_parent n with | Root r -> Exists_b (n, r, Relation.identity) | Node (parent, rel_parent) -> let (Exists_b (repr, root, rel_repr)) = find_repr parent in let rel = rel_repr ** rel_parent in let () = set_parent n (Node (repr, rel)) in Exists_b (repr, root, rel) type 'a node_through_relation = NodeThoughRelation : 'b t * ('a, 'b) Relation.t -> 'a node_through_relation type 'a value_through_relation = ValueThroughRelation : 'b Value.t * ('a, 'b) Relation.t -> 'a value_through_relation type 'a node_and_value_through_relation = NodeValueThroughRelation : 'b t * 'b Value.t * ('a, 'b) Relation.t -> 'a node_and_value_through_relation let find_representative n = let (Exists_b (repr, _, rel)) = find_repr n in NodeThoughRelation (repr, rel) let find_value n = let (Exists_b (_, root, rel)) = find_repr n in ValueThroughRelation (root.value, rel) let find n = let (Exists_b (repr, root, rel)) = find_repr n in NodeValueThroughRelation (repr, root.value, rel) let a b = let Exists_b(ra, _, rel_a) = find_repr a in let Exists_b(rb, _, rel_b) = find_repr b in match polyeq ra rb with | Eq -> Some(~~rel_b ** rel_a) | Diff -> None let add_value a v = let Exists_b(_, root, rel) = find_repr a in let v = Value.apply v rel in root.value <- Value.meet root.value v (** Using the following diagram: a --(rel)--> b | | rel_a rel_b | | V v repr_a repr_b => repr_a --(inv rel_a; rel; rel_b)--> repr_b (where ";" is composition) => repr_b --(inv rel_b; inv rel; rel_a)--> repr_a We do need to flip the arguments, as R.compose as the opposite argument order. A good thing about generic types is that the typechecker ensure we generate a valid relation here. *) let union a b rel = let (Exists_b (repr_a, root_a, rel_a)) = find_repr a in let (Exists_b (repr_b, root_b, rel_b)) = find_repr b in match polyeq repr_a repr_b with | Eq -> let old_rel = ~~rel_b ** rel_a in if Relation.equal rel old_rel then Ok () else Error old_rel | Diff -> (* Favor making [a] a child of [b] over the reverse, as this avoids a relation flip. *) begin if root_b.size >= root_a.size then ( let rel = rel_b ** rel ** ~~rel_a in root_b.size <- root_b.size + root_a.size; root_b.value <- Value.meet root_b.value (Value.apply root_a.value rel); set_parent repr_a (Node (repr_b, rel))) else let rel = rel_a ** ~~rel ** ~~rel_b in root_a.size <- root_b.size + root_a.size; root_a.value <- Value.meet root_a.value (Value.apply root_b.value rel); set_parent repr_b (Node (repr_a, rel)) end; Ok () end module GenericRelational (Node : Parameters.UF_NODE) = struct open Node type 'a t = 'a Node.t type ('a, 'b) relation = ('a, 'b) Relation.t let ( ** ) = Relation.compose let ( ~~ ) = Relation.inverse type 'a node_through_relation = | NodeThoughRelation : 'b t * ('a, 'b) Relation.t -> 'a node_through_relation let rec find_representative : type a. a t -> a node_through_relation = fun n -> match get_parent n with | Root -> NodeThoughRelation (n, Relation.identity) | Node (parent, rel_parent) -> let (NodeThoughRelation (repr, rel_repr)) = find_representative parent in let rel = rel_repr ** rel_parent in let () = set_parent n (Node (repr, rel)) in NodeThoughRelation (repr, rel) let a b = let NodeThoughRelation(ra, rel_a) = find_representative a in let NodeThoughRelation(rb, rel_b) = find_representative b in match polyeq ra rb with | Eq -> Some(~~rel_b ** rel_a) | Diff -> None (** Using the following diagram: a --(rel)--> b | | rel_a rel_b | | V v repr_a repr_b => repr_a --(inv rel_a; rel; rel_b)--> repr_b (where ";" is composition) => repr_b --(inv rel_b; inv rel; rel_a)--> repr_a We do need to flip the arguments, as R.compose as the opposite argument order. A good thing about generic types is that the typechecker ensure we generate a valid relation here. *) let union a b rel = let NodeThoughRelation(repr_a, rel_a) = find_representative a in let NodeThoughRelation(repr_b, rel_b) = find_representative b in match polyeq repr_a repr_b with | Eq -> let old_rel = ~~rel_b ** rel_a in if Relation.equal rel old_rel then Ok () else Error old_rel | Diff -> (* Favor making [a] a child of [b] over the reverse, as this avoids a relation flip. *) (* begin *) let rel = rel_b ** rel ** ~~rel_a in (* root_b.size <- root_b.size + root_a.size; *) set_parent repr_a (Node (repr_b, rel)); (* else let rel = rel_a ** ~~rel ** ~~rel_b in root_a.size <- root_b.size + root_a.size; set_parent repr_b (Node (repr_a, rel)) end; *) Ok () end
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>