mirror of
https://github.com/c-cube/sidekick.git
synced 2025-12-07 11:45:41 -05:00
162 lines
4.8 KiB
OCaml
162 lines
4.8 KiB
OCaml
|
|
(** {1 Main theory} *)
|
|
|
|
(** Combine the congruence closure with a number of plugins *)
|
|
|
|
open Solver_types
|
|
|
|
module Proof = struct
|
|
type t = Solver_types.proof
|
|
let default = Proof_default
|
|
end
|
|
|
|
module Formula = Lit
|
|
module Eq_class = CC.N
|
|
module Expl = CC.Expl
|
|
|
|
type formula = Lit.t
|
|
type proof = Proof.t
|
|
type conflict = Theory.conflict
|
|
|
|
type theory_state =
|
|
| Th_state : ('a Theory.t1 * 'a) -> theory_state
|
|
|
|
(* TODO: first-class module instead *)
|
|
type t = {
|
|
tst: Term.state; (** state for managing terms *)
|
|
cc: CC.t lazy_t; (** congruence closure *)
|
|
stat: Stat.t;
|
|
count_axiom: int Stat.counter;
|
|
count_conflict: int Stat.counter;
|
|
count_propagate: int Stat.counter;
|
|
mutable theories : theory_state list; (** Set of theories *)
|
|
}
|
|
|
|
let[@inline] cc (t:t) = Lazy.force t.cc
|
|
let[@inline] tst t = t.tst
|
|
let[@inline] theories (self:t) : theory_state Iter.t =
|
|
fun k -> List.iter k self.theories
|
|
|
|
(** {2 Interface with the SAT solver} *)
|
|
|
|
(* handle a literal assumed by the SAT solver *)
|
|
let assert_lits_ ~final (self:t) acts (lits:Lit.t Iter.t) : unit =
|
|
Msat.Log.debugf 2
|
|
(fun k->k "(@[<hv1>@{<green>th_combine.assume_lits@}%s@ %a@])"
|
|
(if final then "[final]" else "") (Util.pp_seq ~sep:"; " Lit.pp) lits);
|
|
(* transmit to CC *)
|
|
let cc = cc self in
|
|
if not final then (
|
|
CC.assert_lits cc lits;
|
|
);
|
|
(* transmit to theories. *)
|
|
CC.check cc acts;
|
|
let module A = struct
|
|
let cc = cc
|
|
let[@inline] raise_conflict c : 'a =
|
|
Stat.incr self.count_conflict;
|
|
acts.Msat.acts_raise_conflict c Proof_default
|
|
let[@inline] propagate p cs : unit =
|
|
Stat.incr self.count_propagate;
|
|
acts.Msat.acts_propagate p (Msat.Consequence (fun () -> cs(), Proof_default))
|
|
let[@inline] propagate_l p cs : unit = propagate p (fun()->cs)
|
|
let[@inline] add_local_axiom lits : unit =
|
|
Stat.incr self.count_axiom;
|
|
acts.Msat.acts_add_clause ~keep:false lits Proof_default
|
|
let[@inline] add_persistent_axiom lits : unit =
|
|
Stat.incr self.count_axiom;
|
|
acts.Msat.acts_add_clause ~keep:true lits Proof_default
|
|
let[@inline] add_lit lit : unit = acts.Msat.acts_mk_lit lit
|
|
end in
|
|
let acts = (module A : Theory.ACTIONS) in
|
|
theories self
|
|
(fun (Th_state ((module Th),st)) ->
|
|
(* give new merges, then call {final,partial}-check *)
|
|
if final then Th.final_check st acts lits else Th.partial_check st acts lits);
|
|
()
|
|
|
|
let[@inline] iter_atoms_ acts : _ Iter.t =
|
|
fun f ->
|
|
acts.Msat.acts_iter_assumptions
|
|
(function
|
|
| Msat.Lit a -> f a
|
|
| Msat.Assign _ -> assert false)
|
|
|
|
(* propagation from the bool solver *)
|
|
let check_ ~final (self:t) (acts:_ Msat.acts) =
|
|
let iter = iter_atoms_ acts in
|
|
(* TODO if Config.progress then print_progress(); *)
|
|
Msat.Log.debugf 5 (fun k->k "(th_combine.assume :len %d)" (Iter.length iter));
|
|
assert_lits_ ~final self acts iter
|
|
|
|
let add_formula (self:t) (lit:Lit.t) =
|
|
let t = Lit.term lit in
|
|
let lazy cc = self.cc in
|
|
let n = CC.add_term cc t in
|
|
CC.set_as_lit cc n (Lit.abs lit);
|
|
()
|
|
|
|
(* propagation from the bool solver *)
|
|
let[@inline] partial_check (self:t) (acts:_ Msat.acts) : unit =
|
|
check_ ~final:false self acts
|
|
|
|
(* perform final check of the model *)
|
|
let[@inline] final_check (self:t) (acts:_ Msat.acts) : unit =
|
|
check_ ~final:true self acts
|
|
|
|
let push_level (self:t) : unit =
|
|
CC.push_level (cc self);
|
|
theories self (fun (Th_state ((module Th), st)) -> Th.push_level st)
|
|
|
|
let pop_levels (self:t) n : unit =
|
|
CC.pop_levels (cc self) n;
|
|
theories self (fun (Th_state ((module Th), st)) -> Th.pop_levels st n)
|
|
|
|
let mk_model (self:t) lits : Model.t =
|
|
let m =
|
|
Iter.fold
|
|
(fun m (Th_state ((module Th),st)) -> Th.mk_model st lits m)
|
|
Model.empty (theories self)
|
|
in
|
|
(* now complete model using CC *)
|
|
CC.mk_model (cc self) m
|
|
|
|
(** {2 Interface to Congruence Closure} *)
|
|
|
|
(** {2 Main} *)
|
|
|
|
(* create a new theory combination *)
|
|
let create ?(stat=Stat.global) () : t =
|
|
Log.debug 5 "th_combine.create";
|
|
let rec self = {
|
|
tst=Term.create ~size:1024 ();
|
|
cc = lazy (
|
|
(* lazily tie the knot *)
|
|
(* TODO: pass theories *)
|
|
CC.create ~size:`Big self.tst;
|
|
);
|
|
theories = [];
|
|
stat;
|
|
count_axiom = Stat.mk_int stat "th-axioms";
|
|
count_propagate = Stat.mk_int stat "th-propagations";
|
|
count_conflict = Stat.mk_int stat "th-conflicts";
|
|
} in
|
|
ignore (Lazy.force @@ self.cc : CC.t);
|
|
self
|
|
|
|
let check_invariants (self:t) =
|
|
if Util._CHECK_INVARIANTS then (
|
|
CC.check_invariants (cc self);
|
|
)
|
|
|
|
let add_theory (self:t) (th:Theory.t) : unit =
|
|
let (module Th) = th in
|
|
Log.debugf 2
|
|
(fun k-> k "(@[th_combine.add_th@ :name %S@])" Th.name);
|
|
let st = Th.create self.tst in
|
|
(* add micro theories *)
|
|
List.iter (CC.add_th (cc self)) (Th.cc_th st);
|
|
(* re-pack as a [Theory.t1] *)
|
|
self.theories <- (Th_state ((module Th),st)) :: self.theories
|
|
|
|
let add_theory_l self = List.iter (add_theory self)
|