wip: feat: start cdsat solver

This commit is contained in:
Simon Cruanes 2022-10-23 23:51:16 -04:00
parent 4a5ccffc7a
commit cd9aa883b2
No known key found for this signature in database
GPG key ID: EBFFF6F283F3A2B4
9 changed files with 209 additions and 0 deletions

106
src/cdsat/TVar.ml Normal file
View file

@ -0,0 +1,106 @@
type t = int
type var = t
let pp = Fmt.int
module Vec_of = Veci
(* TODO: GC API, + reuse existing slots that have been GC'd at the
next [new_var_] allocation *)
type store = {
tst: Term.store;
of_term: t Term.Weak_map.t;
term: Term.t Vec.t;
level: Veci.t;
value: Value.t option Vec.t;
reason: reason Vec.t;
has_value: Bitvec.t;
new_vars: Vec_of.t;
}
and reason =
| Decide
| Propagate of { level: int; hyps: Vec_of.t; proof: Sidekick_proof.step_id }
(* create a new variable *)
let new_var_ (self : store) ~term:(term_for_v : Term.t) () : t =
let v : t = Vec.size self.term in
let { tst = _; of_term = _; term; level; value; reason; has_value; new_vars }
=
self
in
Vec.push term term_for_v;
Veci.push level (-1);
Vec.push value None;
Vec.push reason Decide;
(* fake *)
Bitvec.ensure_size has_value (v + 1);
Bitvec.set has_value v false;
Vec_of.push new_vars v;
v
let of_term (self : store) (t : Term.t) : t =
match Term.Weak_map.find_opt self.of_term t with
| Some v -> v
| None ->
let v = new_var_ self ~term:t () in
Term.Weak_map.add self.of_term t v;
(* TODO: map sub-terms to variables. Perhaps preprocess-like hooks that
will allow the variable to be properly defined in one theory? *)
v
let has_value (self : store) (v : t) : bool = Bitvec.get self.has_value v
let level (self : store) (v : t) : int = Veci.get self.level v
let value (self : store) (v : t) : _ option = Vec.get self.value v
let term (self : store) (v : t) : Term.t = Vec.get self.term v
let reason (self : store) (v : t) : reason = Vec.get self.reason v
let pop_new_var self : _ option =
if Vec_of.is_empty self.new_vars then
None
else
Some (Vec_of.pop self.new_vars)
module Reason = struct
type t = reason =
| Decide
| Propagate of { level: int; hyps: Vec_of.t; proof: Sidekick_proof.step_id }
let pp out (self : t) : unit =
match self with
| Decide -> Fmt.string out "decide"
| Propagate { level; hyps; proof = _ } ->
Fmt.fprintf out "(@[propagate[lvl=%d]@ :n-hyps %d@])" level
(Vec_of.size hyps)
let decide : t = Decide
let[@inline] propagate_ level v proof : t =
Propagate { level; hyps = v; proof }
let propagate_v store v proof : t =
let level = Vec_of.fold_left (fun l v -> max l (level store v)) 0 v in
propagate_ level v proof
let propagate_l store l proof : t =
let v = Vec_of.create ~cap:(List.length l) () in
List.iter (Vec_of.push v) l;
propagate_v store v proof
end
module Store = struct
type t = store
let create tst : t =
{
tst;
of_term = Term.Weak_map.create 256;
reason = Vec.create ();
term = Vec.create ();
level = Veci.create ();
value = Vec.create ();
has_value = Bitvec.create ();
new_vars = Vec_of.create ();
}
end

52
src/cdsat/TVar.mli Normal file
View file

@ -0,0 +1,52 @@
(** Variables.
A variable is a term in the finite basis for CDSAT. It must be assigned
a value before the solver can answer "sat".
*)
type t = private int
type var = t
(** Store of variables *)
module Store : sig
type t
val create : Term.store -> t
(** Create a new store *)
end
module Vec_of : Vec_sig.S with type elt := t
(** Vector of variables *)
type store = Store.t
(** Reason for assignment *)
module Reason : sig
type t =
| Decide
| Propagate of { level: int; hyps: Vec_of.t; proof: Sidekick_proof.step_id }
include Sidekick_sigs.PRINT with type t := t
val decide : t
val propagate_v : store -> Vec_of.t -> Sidekick_proof.step_id -> t
val propagate_l : store -> var list -> Sidekick_proof.step_id -> t
end
val of_term : store -> Term.t -> t
(** Obtain a variable for this term. *)
val term : store -> t -> Term.t
(** Term for this variable *)
val has_value : store -> t -> bool
(** Does the variable have a value in the current assignment? *)
val level : store -> t -> int
(** Level of the current assignment, or [-1] *)
val value : store -> t -> Value.t option
(** Value in the current assignment *)
val pop_new_var : store -> t option
(** Pop a new variable if any, or return [None] *)

8
src/cdsat/dune Normal file
View file

@ -0,0 +1,8 @@
(library
(name sidekick_cdsat)
(public_name sidekick.cdsat)
(synopsis "CDSAT-based SMT core for sidekick")
(flags :standard -open Sidekick_util -open Sidekick_core)
(private_modules types_)
(libraries containers sidekick.util sidekick.core sidekick.sigs
sidekick.proof sidekick.abstract-solver))

View file

@ -0,0 +1,6 @@
(** CDSAT core *)
module Trail = Trail
module TVar = TVar
module Reason = TVar.Reason
module Value = Value

22
src/cdsat/trail.ml Normal file
View file

@ -0,0 +1,22 @@
module VVec = TVar.Vec_of
type t = { vars: VVec.t; levels: Veci.t }
let create () : t = { vars = VVec.create (); levels = Veci.create () }
let[@inline] push_assignment (self : t) (v : TVar.t) : unit =
VVec.push self.vars v
let[@inline] var_at (self : t) (i : int) : TVar.t = VVec.get self.vars i
let[@inline] n_levels self = Veci.size self.levels
let push_level (self : t) : unit = Veci.push self.levels (VVec.size self.vars)
let pop_levels (self : t) (n : int) ~f : unit =
if n <= n_levels self then (
let idx = Veci.get self.levels n in
Veci.shrink self.levels n;
while VVec.size self.vars > idx do
let elt = VVec.pop self.vars in
f elt
done
)

9
src/cdsat/trail.mli Normal file
View file

@ -0,0 +1,9 @@
(** Trail *)
type t
val create : unit -> t
val var_at : t -> int -> TVar.t
val push_assignment : t -> TVar.t -> unit
include Sidekick_sigs.BACKTRACKABLE0_CB with type t := t and type elt := TVar.t

0
src/cdsat/types_.ml Normal file
View file

1
src/cdsat/value.ml Normal file
View file

@ -0,0 +1 @@
include Term

5
src/cdsat/value.mli Normal file
View file

@ -0,0 +1,5 @@
(** Values *)
type t = Term.t
include Sidekick_sigs.EQ_ORD_HASH_PRINT with type t := t