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
(* SPDX-License-Identifier: AGPL-3.0-or-later *)
(* Copyright © 2021-2024 OCamlPro *)
(* Written by the Owi programmers *)

module Union_find = Union_find.Make (Smtml.Symbol)

type t = Smtml.Expr.Set.t Union_find.t

let empty : t = Union_find.empty

let add_one (condition : Smtml.Expr.t) pc : t =
  match Smtml.Expr.get_symbols [ condition ] with
  | hd :: tl ->
    (* We add the first symbol to the UF *)
    let pc =
      let c = Smtml.Expr.Set.singleton condition in
      Union_find.add ~merge:Smtml.Expr.Set.union hd c pc
    in
    (* We union-ize all symbols together, starting with the first one that has already been added *)
    let pc, _last_sym =
      List.fold_left
        (fun (pc, last_sym) sym ->
          (Union_find.union ~merge:Smtml.Expr.Set.union last_sym sym pc, sym) )
        (pc, hd) tl
    in
    pc
  | [] ->
    (* It means smtml did not properly simplified an expression! *)
    assert false

let add (condition : Symbolic_boolean.t) (pc : t) : t =
  (* we start by splitting the condition ((P & Q) & R) into a set {P; Q; R} before adding each of P, Q and R into the UF data structure, this way we maximize the independence of the PC *)
  let condition = Symbolic_boolean.to_expr condition in
  let splitted_condition = Smtml.Expr.split_conjunctions condition in
  Smtml.Expr.Set.fold add_one splitted_condition pc

(* Get all sub conditions of the path condition as a list of independent sets of constraints. *)
let slice pc = Union_find.explode pc

(* Return the set of constraints from [pc] that are relevant for [sym]. *)
let slice_on_symbol (sym : Smtml.Symbol.t) pc : Smtml.Expr.Set.t =
  match Union_find.find_opt sym pc with
  | Some s -> s
  | None ->
    (* if there is a symbol, it should have been added to the union-find structure before, otherwise it means `add` has not been called properly before *)
    assert false

(* Return the set of constraints from [pc] that are relevant for [c]. *)
let slice_on_condition (c : Symbolic_boolean.t) pc : Smtml.Expr.Set.t =
  let c = Symbolic_boolean.to_expr c in
  match Smtml.Expr.get_symbols [ c ] with
  | sym0 :: _tl ->
    (* we need only the first symbol as all the others should have been merged with it *)
    slice_on_symbol sym0 pc
  | [] ->
    (* It means smtml did not properly simplified a expression! *)
    assert false