feat(core): change the way proofs work

Now a proof returns a `step_id` which identifies its resulting clause.
This might be a dummy value when proofs are disabled.

We attach a step_id to each new clause to make sure it's properly
tracked, but step_ids might outlive their clause (and the actual proof
data might be on disk, only keeping in ram a small unique identifier).
This commit is contained in:
Simon Cruanes 2021-09-29 22:16:22 -04:00
parent 313e9db026
commit 4621cc948f
No known key found for this signature in database
GPG key ID: 4AC01D0849AA62B6

View file

@ -147,86 +147,101 @@ end
(** Proofs for the congruence closure *) (** Proofs for the congruence closure *)
module type CC_PROOF = sig module type CC_PROOF = sig
type step_id
type t type t
type lit type lit
val lemma_cc : lit Iter.t -> t -> unit val lemma_cc : lit Iter.t -> t -> step_id
(** [lemma_cc proof lits] asserts that [lits] form a tautology for the theory (** [lemma_cc proof lits] asserts that [lits] form a tautology for the theory
of uninterpreted functions. *) of uninterpreted functions. *)
end end
(** Signature for SAT-solver proof emission, using DRUP. (** Signature for SAT-solver proof emission. *)
We do not store the resolution steps, just the stream of clauses deduced.
See {!Sidekick_drup} for checking these proofs. *)
module type SAT_PROOF = sig module type SAT_PROOF = sig
type t type t
(** The stored proof (possibly nil, possibly on disk, possibly in memory) *) (** The stored proof (possibly nil, possibly on disk, possibly in memory) *)
type step_id
(** identifier for a proof step *)
module Step_vec : Vec_sig.S with type elt = step_id
(** A vector of steps *)
type lit type lit
(** A boolean literal for the proof trace *) (** A boolean literal for the proof trace *)
type dproof = t -> unit type pstep = t -> step_id
(** A delayed proof, used to produce proofs on demand from theories. *) (** A proof step constructor, used to obtain proofs from theories *)
val with_proof : t -> (t -> unit) -> unit val enabled : t -> bool
(** Returns true if proof production is enabled *)
val with_proof : t -> (t -> 'a) -> 'a
(** If proof is enabled, call [f] on it to emit steps. (** If proof is enabled, call [f] on it to emit steps.
if proof is disabled, the callback won't even be called. *) if proof is disabled, the callback won't even be called, and
a dummy step is returned. *)
val emit_input_clause : lit Iter.t -> t -> unit val emit_input_clause : lit Iter.t -> pstep
(** Emit an input clause. *) (** Emit an input clause. *)
val emit_redundant_clause : lit Iter.t -> t -> unit val emit_redundant_clause : lit Iter.t -> hyps:step_id Iter.t -> pstep
(** Emit a clause deduced by the SAT solver, redundant wrt axioms. (** Emit a clause deduced by the SAT solver, redundant wrt previous clauses.
The clause must be RUP wrt previous clauses. *) The clause must be RUP wrt [hyps]. *)
val del_clause : lit Iter.t -> t -> unit val emit_unsat_core : lit Iter.t -> pstep
(** Produce a proof of the empty clause given this subset of the assumptions.
FIXME: probably needs the list of step_id that disprove the lits? *)
val emit_unsat : step_id -> t -> unit
(** Signal "unsat" result at the given step *)
val del_clause : step_id -> t -> unit
(** Forget a clause. Only useful for performance considerations. *) (** Forget a clause. Only useful for performance considerations. *)
(* TODO: replace with something index-based? *)
end end
(** Proofs of unsatisfiability. (** Proofs of unsatisfiability. *)
We use DRUP(T)-style traces where we simply emit clauses as we go,
annotating enough for the checker to reconstruct them.
This allows for low overhead proof production. *)
module type PROOF = sig module type PROOF = sig
type t type t
(** The abstract representation of a proof. A proof always proves (** The abstract representation of a proof. A proof always proves
a clause to be {b valid} (true in every possible interpretation a clause to be {b valid} (true in every possible interpretation
of the problem's assertions, and the theories) *) of the problem's assertions, and the theories) *)
type step_id
(** Identifier for a proof step (like a unique ID for a clause previously
added/proved) *)
type term type term
type lit type lit
type step = t -> step_id
include CC_PROOF include CC_PROOF
with type t := t with type t := t
and type lit := lit and type lit := lit
and type step_id := step_id
include SAT_PROOF include SAT_PROOF
with type t := t with type t := t
and type lit := lit and type lit := lit
and type step_id := step_id
val begin_subproof : t -> unit val define_term : term -> term -> step
(** Begins a subproof. The result of this will only be the (** [define_term cst u proof] defines the new constant [cst] as being equal
clause with which {!end_subproof} is called; all other intermediate to [u].
steps will be discarded. *) The result is a proof of the clause [cst = u] *)
val end_subproof : t -> unit val lemma_true : term -> step
(** [end_subproof p] ends the current active subproof, the last result (** [lemma_true (true) p] asserts the clause [(true)] *)
of which is kept. *)
val define_term : term -> term -> t -> unit val lemma_preprocess : term -> term -> using:step_id Iter.t -> step
(** [define_term p cst u] defines the new constant [cst] as being equal (** [lemma_preprocess t u ~using p] asserts that [t = u] is a tautology
to [u]. *)
val lemma_true : term -> t -> unit
(** [lemma_true p (true)] asserts the clause [(true)] *)
val lemma_preprocess : term -> term -> t -> unit
(** [lemma_preprocess p t u] asserts that [t = u] is a tautology
and that [t] has been preprocessed into [u]. and that [t] has been preprocessed into [u].
From now on, [t] and [u] will be used interchangeably. *)
The theorem [/\_{eqn in using} eqn |- t=u] is proved using congruence
closure, and then resolved against the clauses [using] to obtain
a unit equality.
From now on, [t] and [u] will be used interchangeably.
@return a step ID for the clause [(t=u)]. *)
end end
(** Literals (** Literals
@ -285,7 +300,8 @@ module type CC_ACTIONS = sig
module Lit : LIT with module T = T module Lit : LIT with module T = T
type proof type proof
type dproof = proof -> unit type step_id
type pstep = proof -> step_id
module P : CC_PROOF with type lit = Lit.t and type t = proof module P : CC_PROOF with type lit = Lit.t and type t = proof
type t type t
@ -293,13 +309,13 @@ module type CC_ACTIONS = sig
to perform the actions below. How it performs the actions to perform the actions below. How it performs the actions
is not specified and is solver-specific. *) is not specified and is solver-specific. *)
val raise_conflict : t -> Lit.t list -> dproof -> 'a val raise_conflict : t -> Lit.t list -> pstep -> 'a
(** [raise_conflict acts c pr] declares that [c] is a tautology of (** [raise_conflict acts c pr] declares that [c] is a tautology of
the theory of congruence. This does not return (it should raise an the theory of congruence. This does not return (it should raise an
exception). exception).
@param pr the proof of [c] being a tautology *) @param pr the proof of [c] being a tautology *)
val propagate : t -> Lit.t -> reason:(unit -> Lit.t list * dproof) -> unit val propagate : t -> Lit.t -> reason:(unit -> Lit.t list * pstep) -> unit
(** [propagate acts lit ~reason pr] declares that [reason() => lit] (** [propagate acts lit ~reason pr] declares that [reason() => lit]
is a tautology. is a tautology.
@ -315,11 +331,16 @@ module type CC_ARG = sig
module T : TERM module T : TERM
module Lit : LIT with module T = T module Lit : LIT with module T = T
type proof type proof
module P : CC_PROOF with type lit = Lit.t and type t = proof type step_id
module P : CC_PROOF
with type lit = Lit.t
and type t = proof
and type step_id = step_id
module Actions : CC_ACTIONS module Actions : CC_ACTIONS
with module T=T with module T=T
and module Lit = Lit and module Lit = Lit
and type proof = proof and type proof = proof
and type step_id = step_id
val cc_view : T.Term.t -> (T.Fun.t, T.Term.t, T.Term.t Iter.t) CC_view.t val cc_view : T.Term.t -> (T.Fun.t, T.Term.t, T.Term.t Iter.t) CC_view.t
(** View the term through the lens of the congruence closure *) (** View the term through the lens of the congruence closure *)
@ -347,12 +368,17 @@ module type CC_S = sig
module T : TERM module T : TERM
module Lit : LIT with module T = T module Lit : LIT with module T = T
type proof type proof
type dproof = proof -> unit type step_id
module P : CC_PROOF with type lit = Lit.t and type t = proof type pstep = proof -> step_id
module P : CC_PROOF
with type lit = Lit.t
and type t = proof
and type step_id = step_id
module Actions : CC_ACTIONS module Actions : CC_ACTIONS
with module T = T with module T = T
and module Lit = Lit and module Lit = Lit
and type proof = proof and type proof = proof
and type step_id = step_id
type term_store = T.Term.store type term_store = T.Term.store
type term = T.Term.t type term = T.Term.t
type fun_ = T.Fun.t type fun_ = T.Fun.t
@ -493,7 +519,7 @@ module type CC_S = sig
participating in the conflict are purely syntactic theories participating in the conflict are purely syntactic theories
like injectivity of constructors. *) like injectivity of constructors. *)
type ev_on_propagate = t -> lit -> (unit -> lit list * dproof) -> unit type ev_on_propagate = t -> lit -> (unit -> lit list * pstep) -> unit
(** [ev_on_propagate cc lit reason] is called whenever [reason() => lit] (** [ev_on_propagate cc lit reason] is called whenever [reason() => lit]
is a propagated lemma. See {!CC_ACTIONS.propagate}. *) is a propagated lemma. See {!CC_ACTIONS.propagate}. *)
@ -647,7 +673,8 @@ module type SOLVER_INTERNAL = sig
type ty_store = T.Ty.store type ty_store = T.Ty.store
type clause_pool type clause_pool
type proof type proof
type dproof = proof -> unit type step_id
type pstep = proof -> step_id
(** Delayed proof. This is used to build a proof step on demand. *) (** Delayed proof. This is used to build a proof step on demand. *)
(** {3 Proofs} *) (** {3 Proofs} *)
@ -749,7 +776,7 @@ module type SOLVER_INTERNAL = sig
val mk_lit : ?sign:bool -> term -> lit val mk_lit : ?sign:bool -> term -> lit
(** creates a new literal for a boolean term. *) (** creates a new literal for a boolean term. *)
val add_clause : lit list -> dproof -> unit val add_clause : lit list -> pstep -> unit
(** pushes a new clause into the SAT solver. *) (** pushes a new clause into the SAT solver. *)
val add_lit : ?default_pol:bool -> lit -> unit val add_lit : ?default_pol:bool -> lit -> unit
@ -782,7 +809,7 @@ module type SOLVER_INTERNAL = sig
(** {3 hooks for the theory} *) (** {3 hooks for the theory} *)
val raise_conflict : t -> theory_actions -> lit list -> dproof -> 'a val raise_conflict : t -> theory_actions -> lit list -> pstep -> 'a
(** Give a conflict clause to the solver *) (** Give a conflict clause to the solver *)
val push_decision : t -> theory_actions -> lit -> unit val push_decision : t -> theory_actions -> lit -> unit
@ -791,19 +818,19 @@ module type SOLVER_INTERNAL = sig
If the SAT solver backtracks, this (potential) decision is removed If the SAT solver backtracks, this (potential) decision is removed
and forgotten. *) and forgotten. *)
val propagate: t -> theory_actions -> lit -> reason:(unit -> lit list * dproof) -> unit val propagate: t -> theory_actions -> lit -> reason:(unit -> lit list * pstep) -> unit
(** Propagate a boolean using a unit clause. (** Propagate a boolean using a unit clause.
[expl => lit] must be a theory lemma, that is, a T-tautology *) [expl => lit] must be a theory lemma, that is, a T-tautology *)
val propagate_l: t -> theory_actions -> lit -> lit list -> dproof -> unit val propagate_l: t -> theory_actions -> lit -> lit list -> pstep -> unit
(** Propagate a boolean using a unit clause. (** Propagate a boolean using a unit clause.
[expl => lit] must be a theory lemma, that is, a T-tautology *) [expl => lit] must be a theory lemma, that is, a T-tautology *)
val add_clause_temp : t -> theory_actions -> lit list -> dproof -> unit val add_clause_temp : t -> theory_actions -> lit list -> pstep -> unit
(** Add local clause to the SAT solver. This clause will be (** Add local clause to the SAT solver. This clause will be
removed when the solver backtracks. *) removed when the solver backtracks. *)
val add_clause_permanent : t -> theory_actions -> lit list -> dproof -> unit val add_clause_permanent : t -> theory_actions -> lit list -> pstep -> unit
(** Add toplevel clause to the SAT solver. This clause will (** Add toplevel clause to the SAT solver. This clause will
not be backtracked. *) not be backtracked. *)
@ -867,7 +894,7 @@ module type SOLVER_INTERNAL = sig
val on_cc_conflict : t -> (CC.t -> th:bool -> lit list -> unit) -> unit val on_cc_conflict : t -> (CC.t -> th:bool -> lit list -> unit) -> unit
(** Callback called on every CC conflict *) (** Callback called on every CC conflict *)
val on_cc_propagate : t -> (CC.t -> lit -> (unit -> lit list * dproof) -> unit) -> unit val on_cc_propagate : t -> (CC.t -> lit -> (unit -> lit list * pstep) -> unit) -> unit
(** Callback called on every CC propagation *) (** Callback called on every CC propagation *)
val on_partial_check : t -> (t -> theory_actions -> lit Iter.t -> unit) -> unit val on_partial_check : t -> (t -> theory_actions -> lit Iter.t -> unit) -> unit
@ -914,7 +941,12 @@ module type SOLVER = sig
module T : TERM module T : TERM
module Lit : LIT with module T = T module Lit : LIT with module T = T
type proof type proof
module P : PROOF with type lit = Lit.t and type t = proof and type term = T.Term.t type step_id
module P : PROOF
with type lit = Lit.t
and type t = proof
and type step_id = step_id
and type term = T.Term.t
module Solver_internal module Solver_internal
: SOLVER_INTERNAL : SOLVER_INTERNAL
@ -931,8 +963,8 @@ module type SOLVER = sig
type term = T.Term.t type term = T.Term.t
type ty = T.Ty.t type ty = T.Ty.t
type lit = Lit.t type lit = Lit.t
type dproof = proof -> unit type pstep = proof -> step_id
(** Delayed proof. This is used to build a proof step on demand. *) (** Proof step. *)
(** {3 A theory} (** {3 A theory}
@ -1067,11 +1099,11 @@ module type SOLVER = sig
The proof of [|- lit = lit'] is directly added to the solver's proof. *) The proof of [|- lit = lit'] is directly added to the solver's proof. *)
val add_clause : t -> lit IArray.t -> dproof -> unit val add_clause : t -> lit IArray.t -> pstep -> unit
(** [add_clause solver cs] adds a boolean clause to the solver. (** [add_clause solver cs] adds a boolean clause to the solver.
Subsequent calls to {!solve} will need to satisfy this clause. *) Subsequent calls to {!solve} will need to satisfy this clause. *)
val add_clause_l : t -> lit list -> dproof -> unit val add_clause_l : t -> lit list -> pstep -> unit
(** Add a clause to the solver, given as a list. *) (** Add a clause to the solver, given as a list. *)
val assert_terms : t -> term list -> unit val assert_terms : t -> term list -> unit