package idds
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file idd.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
open Base type t = Dd.t let ident = Dd.ctrue let empty = Dd.cfalse let equal = Dd.equal module Pair = struct type t = int * int [@@deriving sexp, compare, hash] end type manager = { dd : Dd.manager; bdd : Bdd.manager; union_cache : (Pair.t, t) Hashtbl.t; seq_cache : (Pair.t, t) Hashtbl.t; } let manager ?bdd_mgr () : manager = let bdd = Option.value bdd_mgr ~default:(Bdd.manager ()) in { bdd; dd = Bdd.get_dd_manager bdd; union_cache = Hashtbl.create (module Pair); seq_cache = Hashtbl.create (module Pair); } let get_bdd_manager mgr = mgr.bdd let test mgr i b = Dd.branch mgr.dd (Var.inp i) (if b then Dd.ctrue else Dd.cfalse) (if b then Dd.cfalse else Dd.ctrue) let set mgr i b = Dd.branch mgr.dd (Var.out i) (if b then Dd.ctrue else Dd.cfalse) (if b then Dd.cfalse else Dd.ctrue) let rec eval' expl (tree:t) (env:Var.t -> bool) (n:int) = match tree with | False -> false | True -> Sequence.range 0 n |> Sequence.for_all ~f:(fun i -> Set.mem expl i || Bool.equal (env (Var.inp i)) (env (Var.out i)) ) | Branch { var; hi; lo; _ } -> let expl = if Var.is_inp var then expl else Set.add expl (Var.index var) in eval' expl (if (env var) then hi else lo) env n let eval = eval' (Set.empty (module Int)) (* let enforce_ordered (t0 : t) : t = let rec ordered (x : Var.t) (t0 : t) = match t0 with | True | False -> true | Branch { var=y; hi; lo; _ } -> begin match Var.closer_to_root x y with | Left -> ordered y hi && ordered y lo | _ -> false end in match t0 with | True | False -> t0 | Branch { var; hi; lo; _ } -> if ordered var hi && ordered var lo then t0 else failwith ("unordered: " ^ Dd.to_string t0) *) let branch (mgr : manager) (x : Var.t) (hi : t) (lo : t) : t = (* enforce_ordered ( *) if Var.is_out x then begin match hi, lo with | False, False -> hi | _ -> Dd.branch mgr.dd x hi lo end else (* Var.is_inp var *) if equal hi lo then hi else let x' = Var.to_out x in (* make identity x=x' implicit *) let hi = match hi with | Branch { hi; lo=False; var; _ } when Var.(equal var x') -> hi | _ -> hi in let lo = match lo with | Branch { hi=False; lo; var; _ } when Var.(equal var x') -> lo | _ -> lo in (* is testing x redundant? *) if equal hi lo then hi else begin match hi, lo with | Branch { hi=False; lo=lo'; var; _ }, _ when Var.(equal var x') && equal lo lo' -> hi | _, Branch { hi=hi'; lo=False; var; _ } when Var.(equal var x') && equal hi hi' -> lo | _ -> Dd.branch mgr.dd x hi lo end (* ) *) let extract (d:t) (side:bool) : t = match d with | False | True -> d | Branch { hi; lo; _ } -> if side then hi else lo (** [split d root] are the four subtrees of [d] corresponding to the four possible values of the variable pair [(inp root, out root)], i.e. [(1, 1), (1, 0), (0, 1), (0, 0)]. - requires: [Var.idx_closer_to_root root (Dd.index d)] or [root = Dd.index d] *) let split (d:t) (root:int) = if Var.idx_strictly_closer_to_root root (Dd.index d) then (d, empty, empty, d) else match d with | Branch { var; hi; lo; _ } when Var.is_out var -> (hi, lo, hi, lo) | Branch { hi; lo; _ } -> (* var is input variable *) let d11, d10 = if Dd.index hi = root then extract hi true, extract hi false else hi, empty in let d01, d00 = if Dd.index lo = root then extract lo true, extract lo false else empty, lo in d11, d10, d01, d00 | _ -> failwith "Impossible" (* by precondition + if guard *) let rec apply mgr (op : bool -> bool -> bool) (d0 : t) (d1 : t) = match d0, d1 with | False, False | False, True | True, False | True, True -> let val0 = equal d0 ident in let val1 = equal d1 ident in if op val0 val1 then ident else empty | Branch _, _ | _, Branch _ -> let root_index = if Var.idx_strictly_closer_to_root (Dd.index d0) (Dd.index d1) then Dd.index d0 else Dd.index d1 in let (d0_11, d0_10, d0_01, d0_00) = split d0 root_index in let (d1_11, d1_10, d1_01, d1_00) = split d1 root_index in Var.(branch mgr (inp root_index) (branch mgr (out root_index) (apply mgr op d0_11 d1_11) (apply mgr op d0_10 d1_10)) (branch mgr (out root_index) (apply mgr op d0_01 d1_01) (apply mgr op d0_00 d1_00))) let rec union mgr (d0 : t) (d1 : t) = match d0, d1 with | False, d | d, False -> d | True, True -> d0 | _ -> let id0, id1 = Dd.id d0, Dd.id d1 in (* union is idempotent... *) if id0 = id1 then d0 else (* ... and commutative *) let key = if id0 <= id1 then (id0, id1) else (id1, id0) in Hashtbl.find_or_add mgr.union_cache key ~default:(fun () -> let root_index = if Var.idx_strictly_closer_to_root (Dd.index d0) (Dd.index d1) then Dd.index d0 else Dd.index d1 in let (d0_11, d0_10, d0_01, d0_00) = split d0 root_index in let (d1_11, d1_10, d1_01, d1_00) = split d1 root_index in Var.(branch mgr (inp root_index) (branch mgr (out root_index) (union mgr d0_11 d1_11) (union mgr d0_10 d1_10)) (branch mgr (out root_index) (union mgr d0_01 d1_01) (union mgr d0_00 d1_00))) ) let rec seq mgr (d0:t) (d1:t) = match d0, d1 with | (False as d), _ | _, (False as d) | True, d | d, True -> d | Branch { id=id1; _ }, Branch { id=id2; _ } -> Hashtbl.find_or_add mgr.seq_cache (id1, id2) ~default:(fun () -> let root_index = if Var.idx_strictly_closer_to_root (Dd.index d0) (Dd.index d1) then Dd.index d0 else Dd.index d1 in let (d0_11, d0_10, d0_01, d0_00) = split d0 root_index in let (d1_11, d1_10, d1_01, d1_00) = split d1 root_index in branch mgr (Var.inp root_index) (branch mgr (Var.out root_index) (union mgr (seq mgr d0_11 d1_11) (seq mgr d0_10 d1_01)) (union mgr (seq mgr d0_11 d1_10) (seq mgr d0_10 d1_00))) (branch mgr (Var.out root_index) (union mgr (seq mgr d0_01 d1_11) (seq mgr d0_00 d1_01)) (union mgr (seq mgr d0_01 d1_10) (seq mgr d0_00 d1_00))) ) let star mgr (d0:t) = let rec loop curr prev = if equal curr prev then prev else loop (seq mgr curr curr) curr in loop (union mgr ident d0) ident let subseteq mgr (d0:t) (d1:t) = equal (union mgr d0 d1) d1 let of_bdd (bdd:Bdd.t) : t = (bdd :> Dd.t)