(proof-new) Add SMT proof manager (#5054)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Sat, 12 Sep 2020 03:38:04 +0000 (22:38 -0500)
committerGitHub <noreply@github.com>
Sat, 12 Sep 2020 03:38:04 +0000 (22:38 -0500)
This module is responsible for constructing the proof checker, proof node manager, and implementing dumping and checking of the final proof.

This PR includes setting up some connections into the various modules for proof production.

src/CMakeLists.txt
src/options/smt_options.toml
src/preprocessing/assertion_pipeline.cpp
src/smt/assertions.cpp
src/smt/assertions.h
src/smt/proof_manager.cpp [new file with mode: 0644]
src/smt/proof_manager.h [new file with mode: 0644]
src/smt/smt_engine.cpp
src/smt/smt_engine.h
src/smt/smt_solver.cpp
src/smt/smt_solver.h

index a7c50d1e4911db7556787cf3eb19ba82623f485e..65ccabd892904d98e0c1cad3ed149790a64b055f 100644 (file)
@@ -222,6 +222,8 @@ libcvc4_add_sources(
   smt/preprocess_proof_generator.h
   smt/process_assertions.cpp
   smt/process_assertions.h
+  smt/proof_manager.cpp
+  smt/proof_manager.h
   smt/proof_post_processor.cpp
   smt/proof_post_processor.h
   smt/set_defaults.cpp
index 2c87158de4188796d809ab0e6ab073da3a32c2cc..4e1a89259b02bf7455d8466e5256400714e8bafb 100644 (file)
@@ -173,6 +173,34 @@ header = "options/smt_options.h"
   read_only  = true
   help       = "check proofs eagerly with proof-new for local debugging"
 
+[[option]]
+  name       = "proofGranularityMode"
+  category   = "regular"
+  long       = "proof-granularity=MODE"
+  type       = "ProofGranularityMode"
+  default    = "THEORY_REWRITE"
+  help       = "modes for proof granularity"
+  help_mode  = "Modes for proof granularity."
+[[option.mode.OFF]]
+  name = "off"
+  help = "Do not improve the granularity of proofs."
+[[option.mode.REWRITE]]
+  name = "rewrite"
+  help = "allow rewrite or substitution steps, expand macros."
+[[option.mode.THEORY_REWRITE]]
+  name = "theory-rewrite"
+  help = "allow theory rewrite steps, expand macros, rewrite and substitution steps."
+[[option.mode.DSL_REWRITE]]
+  name = "dsl-rewrite"
+  help = "Allow DSL rewrites and evaluation steps, expand macros, rewrite, substitution, and theory rewrite steps."
+
+[[option]]
+  name       = "checkProofsNew"
+  category   = "regular"
+  long       = "check-proofs-new"
+  type       = "bool"
+  help       = "after UNSAT/VALID, check the generated proof (with proof-new)"
+
 [[option]]
   name       = "dumpInstantiations"
   category   = "regular"
index a9e2d4d3658f9ee9240d4e25c146bd3fe3d155f9..735a93f5672807f36d9eafd72410d4a6837f7171 100644 (file)
@@ -72,7 +72,7 @@ void AssertionPipeline::pushBackTrusted(theory::TrustNode trn)
 {
   Assert(trn.getKind() == theory::TrustNodeKind::LEMMA);
   // push back what was proven
-  push_back(trn.getProven(), false, trn.getGenerator());
+  push_back(trn.getProven(), false, false, trn.getGenerator());
 }
 
 void AssertionPipeline::replace(size_t i, Node n, ProofGenerator* pgen)
index 8019c383de98be66720877db82637de85df610aa..714622bae37e566e0e291ff3c151fd0fe3cdd430 100644 (file)
@@ -197,7 +197,7 @@ void Assertions::addFormula(
   }
 
   // Add the normalized formula to the queue
-  d_assertions.push_back(n, isAssumption);
+  d_assertions.push_back(n, isAssumption, true);
 }
 
 void Assertions::addDefineFunRecDefinition(Node n, bool global)
@@ -234,5 +234,15 @@ void Assertions::ensureBoolean(const Node& n)
   }
 }
 
+void Assertions::setProofGenerator(smt::PreprocessProofGenerator* pppg)
+{
+  d_assertions.setProofGenerator(pppg);
+}
+
+bool Assertions::isProofEnabled() const
+{
+  return d_assertions.isProofEnabled();
+}
+
 }  // namespace smt
 }  // namespace CVC4
index a74c58bd83acee5ef8388d2ee755576a71c16f72..a73cd32d6cf40c41dcc6800215f3e80bff877a69 100644 (file)
@@ -109,6 +109,12 @@ class Assertions
   /** Flip the global negation flag. */
   void flipGlobalNegated();
 
+  //------------------------------------ for proofs
+  /** Set proof generator */
+  void setProofGenerator(smt::PreprocessProofGenerator* pppg);
+  /** Is proof enabled? */
+  bool isProofEnabled() const;
+  //------------------------------------ end for proofs
  private:
   /**
    * Fully type-check the argument, and also type-check that it's
diff --git a/src/smt/proof_manager.cpp b/src/smt/proof_manager.cpp
new file mode 100644 (file)
index 0000000..b78bb77
--- /dev/null
@@ -0,0 +1,150 @@
+/*********************                                                        */
+/*! \file proof_manager.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The proof manager of the SMT engine
+ **/
+
+#include "smt/proof_manager.h"
+
+#include "expr/proof_node_algorithm.h"
+#include "options/base_options.h"
+#include "options/smt_options.h"
+#include "smt/assertions.h"
+
+namespace CVC4 {
+namespace smt {
+
+PfManager::PfManager(SmtEngine* smte)
+    : d_pchecker(new ProofChecker(options::proofNewPedantic())),
+      d_pnm(new ProofNodeManager(d_pchecker.get())),
+      d_pppg(new PreprocessProofGenerator(d_pnm.get())),
+      d_pfpp(new ProofPostproccess(d_pnm.get(), smte, d_pppg.get())),
+      d_finalProof(nullptr)
+{
+  // add rules to eliminate here
+  if (options::proofGranularityMode() != options::ProofGranularityMode::OFF)
+  {
+    d_pfpp->setEliminateRule(PfRule::MACRO_SR_EQ_INTRO);
+    d_pfpp->setEliminateRule(PfRule::MACRO_SR_PRED_INTRO);
+    d_pfpp->setEliminateRule(PfRule::MACRO_SR_PRED_ELIM);
+    d_pfpp->setEliminateRule(PfRule::MACRO_SR_PRED_TRANSFORM);
+    if (options::proofGranularityMode()
+        != options::ProofGranularityMode::REWRITE)
+    {
+      d_pfpp->setEliminateRule(PfRule::SUBS);
+      d_pfpp->setEliminateRule(PfRule::REWRITE);
+      if (options::proofGranularityMode()
+          != options::ProofGranularityMode::THEORY_REWRITE)
+      {
+        // this eliminates theory rewriting steps with finer-grained DSL rules
+        d_pfpp->setEliminateRule(PfRule::THEORY_REWRITE);
+      }
+    }
+  }
+  d_false = NodeManager::currentNM()->mkConst(false);
+}
+
+PfManager::~PfManager() {}
+
+void PfManager::setFinalProof(ProofGenerator* pg, context::CDList<Node>* al)
+{
+  Assert(al != nullptr);
+  // Note this assumes that setFinalProof is only called once per unsat
+  // response. This method would need to cache its result otherwise.
+  Trace("smt-proof") << "SmtEngine::setFinalProof(): get proof body...\n";
+
+  // d_finalProof should just be a ProofNode
+  std::shared_ptr<ProofNode> body = pg->getProofFor(d_false)->clone();
+
+  if (Trace.isOn("smt-proof-debug"))
+  {
+    Trace("smt-proof-debug")
+        << "SmtEngine::setFinalProof(): Proof node for false:\n";
+    Trace("smt-proof-debug") << *body.get() << std::endl;
+    Trace("smt-proof-debug") << "=====" << std::endl;
+  }
+
+  if (Trace.isOn("smt-proof"))
+  {
+    std::vector<Node> fassumps;
+    expr::getFreeAssumptions(body.get(), fassumps);
+    Trace("smt-proof")
+        << "SmtEngine::setFinalProof(): initial free assumptions are:\n";
+    for (const Node& a : fassumps)
+    {
+      Trace("smt-proof") << "- " << a << std::endl;
+    }
+  }
+
+  std::vector<Node> assertions;
+  Trace("smt-proof") << "SmtEngine::setFinalProof(): assertions are:\n";
+  for (context::CDList<Node>::const_iterator i = al->begin(); i != al->end();
+       ++i)
+  {
+    Node n = *i;
+    Trace("smt-proof") << "- " << n << std::endl;
+    assertions.push_back(n);
+  }
+  Trace("smt-proof") << "=====" << std::endl;
+
+  Trace("smt-proof") << "SmtEngine::setFinalProof(): postprocess...\n";
+  Assert(d_pfpp != nullptr);
+  d_pfpp->process(body);
+
+  Trace("smt-proof") << "SmtEngine::setFinalProof(): make scope...\n";
+
+  // Now make the final scope, which ensures that the only open leaves
+  // of the proof are the assertions.
+  d_finalProof = d_pnm->mkScope(body, assertions);
+  Trace("smt-proof") << "SmtEngine::setFinalProof(): finished.\n";
+}
+
+void PfManager::printProof(ProofGenerator* pg, Assertions& as)
+{
+  Trace("smt-proof") << "PfManager::printProof: start" << std::endl;
+  std::shared_ptr<ProofNode> fp = getFinalProof(pg, as);
+  // TODO (proj #37) according to the proof format, post process the proof node
+  // TODO (proj #37) according to the proof format, print the proof node
+  // leanPrinter(out, fp.get());
+  std::ostream& out = *options::out();
+  out << "(proof\n";
+  out << *fp;
+  out << "\n)\n";
+}
+
+void PfManager::checkProof(ProofGenerator* pg, Assertions& as)
+{
+  Trace("smt-proof") << "PfManager::checkProof: start" << std::endl;
+  std::shared_ptr<ProofNode> fp = getFinalProof(pg, as);
+  Trace("smt-proof") << "PfManager::checkProof: returned " << *fp.get()
+                     << std::endl;
+}
+
+ProofChecker* PfManager::getProofChecker() const { return d_pchecker.get(); }
+
+ProofNodeManager* PfManager::getProofNodeManager() const { return d_pnm.get(); }
+
+smt::PreprocessProofGenerator* PfManager::getPreprocessProofGenerator() const
+{
+  return d_pppg.get();
+}
+
+std::shared_ptr<ProofNode> PfManager::getFinalProof(ProofGenerator* pg,
+                                                    Assertions& as)
+{
+  context::CDList<Node>* al = as.getAssertionList();
+  setFinalProof(pg, al);
+  Assert(d_finalProof);
+  return d_finalProof;
+}
+
+}  // namespace smt
+}  // namespace CVC4
diff --git a/src/smt/proof_manager.h b/src/smt/proof_manager.h
new file mode 100644 (file)
index 0000000..925d9fa
--- /dev/null
@@ -0,0 +1,103 @@
+/*********************                                                        */
+/*! \file proof_manager.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The proof manager of SmtEngine
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__SMT__PROOF_MANAGER_H
+#define CVC4__SMT__PROOF_MANAGER_H
+
+#include "context/cdlist.h"
+#include "expr/expr.h"
+#include "expr/node.h"
+#include "expr/proof_checker.h"
+#include "expr/proof_node.h"
+#include "expr/proof_node_manager.h"
+#include "smt/preprocess_proof_generator.h"
+#include "smt/proof_post_processor.h"
+
+namespace CVC4 {
+
+class SmtEngine;
+
+namespace smt {
+
+class Assertions;
+
+/**
+ * This class is responsible for managing the proof output of SmtEngine, as
+ * well as setting up the global proof checker and proof node manager.
+ */
+class PfManager
+{
+ public:
+  PfManager(SmtEngine* smte);
+  ~PfManager();
+  /**
+   * Print the proof on the output channel of the current options in scope.
+   *
+   * The argument pg is the module that can provide a proof for false in the
+   * current context.
+   *
+   * Throws an assertion failure if pg cannot provide a closed proof with
+   * respect to assertions in as.
+   */
+  void printProof(ProofGenerator* pg, Assertions& as);
+  /**
+   * Check proof, same as above, without printing.
+   */
+  void checkProof(ProofGenerator* pg, Assertions& as);
+
+  /**
+   * Get final proof.
+   *
+   * The argument pg is the module that can provide a proof for false in the
+   * current context.
+   */
+  std::shared_ptr<ProofNode> getFinalProof(ProofGenerator* pg, Assertions& as);
+  //--------------------------- access to utilities
+  /** Get a pointer to the ProofChecker owned by this. */
+  ProofChecker* getProofChecker() const;
+  /** Get a pointer to the ProofNodeManager owned by this. */
+  ProofNodeManager* getProofNodeManager() const;
+  /** Get the proof generator for proofs of preprocessing. */
+  smt::PreprocessProofGenerator* getPreprocessProofGenerator() const;
+  //--------------------------- end access to utilities
+ private:
+  /**
+   * Set final proof, which initializes d_finalProof to the proof of false
+   * from pg, postprocesses it, and stores it in d_finalProof.
+   */
+  void setFinalProof(ProofGenerator* pg, context::CDList<Node>* al);
+  /** The false node */
+  Node d_false;
+  /** For the new proofs module */
+  std::unique_ptr<ProofChecker> d_pchecker;
+  /** A proof node manager based on the above checker */
+  std::unique_ptr<ProofNodeManager> d_pnm;
+  /** The preprocess proof generator. */
+  std::unique_ptr<smt::PreprocessProofGenerator> d_pppg;
+  /** The proof post-processor */
+  std::unique_ptr<smt::ProofPostproccess> d_pfpp;
+  /**
+   * The final proof produced by the SMT engine.
+   * Combines the proofs of preprocessing, prop engine and theory engine, to be
+   * connected by setFinalProof().
+   */
+  std::shared_ptr<ProofNode> d_finalProof;
+}; /* class SmtEngine */
+
+}  // namespace smt
+}  // namespace CVC4
+
+#endif /* CVC4__SMT__PROOF_MANAGER_H */
index 81d4f594d128b87012948953e23ef282942f6463..7f824bff3d3330a597b56edc418fa07b96b5b2a4 100644 (file)
 #include "expr/node_builder.h"
 #include "expr/node_self_iterator.h"
 #include "expr/node_visitor.h"
-#include "options/arith_options.h"
-#include "options/arrays_options.h"
 #include "options/base_options.h"
-#include "options/booleans_options.h"
-#include "options/bv_options.h"
-#include "options/datatypes_options.h"
 #include "options/decision_options.h"
 #include "options/language.h"
 #include "options/main_options.h"
 #include "options/printer_options.h"
 #include "options/prop_options.h"
 #include "options/quantifiers_options.h"
-#include "options/sep_options.h"
 #include "options/set_language.h"
 #include "options/smt_options.h"
-#include "options/strings_options.h"
 #include "options/theory_options.h"
-#include "options/uf_options.h"
 #include "preprocessing/preprocessing_pass.h"
 #include "preprocessing/preprocessing_pass_context.h"
 #include "preprocessing/preprocessing_pass_registry.h"
@@ -89,6 +81,7 @@
 #include "smt/model_core_builder.h"
 #include "smt/options_manager.h"
 #include "smt/preprocessor.h"
+#include "smt/proof_manager.h"
 #include "smt/quant_elim_solver.h"
 #include "smt/smt_engine_scope.h"
 #include "smt/smt_engine_state.h"
 #include "smt/update_ostream.h"
 #include "smt_util/boolean_simplification.h"
 #include "smt_util/nary_builder.h"
-#include "theory/booleans/circuit_propagator.h"
-#include "theory/bv/theory_bv_rewriter.h"
 #include "theory/logic_info.h"
 #include "theory/rewriter.h"
 #include "theory/sort_inference.h"
-#include "theory/strings/theory_strings.h"
 #include "theory/substitutions.h"
 #include "theory/theory_engine.h"
 #include "theory/theory_model.h"
@@ -139,6 +129,7 @@ SmtEngine::SmtEngine(ExprManager* em, Options* optr)
       d_snmListener(new SmtNodeManagerListener(*d_dumpm.get())),
       d_smtSolver(nullptr),
       d_proofManager(nullptr),
+      d_pfManager(nullptr),
       d_rewriter(new theory::Rewriter()),
       d_definedFunctions(nullptr),
       d_sygusSolver(nullptr),
@@ -262,6 +253,20 @@ void SmtEngine::finishInit()
   // based on our heuristics.
   d_optm->finishInit(d_logic, d_isInternalSubsolver);
 
+  ProofNodeManager* pnm = nullptr;
+  if (options::proofNew())
+  {
+    d_pfManager.reset(new PfManager(this));
+    // use this proof node manager
+    pnm = d_pfManager->getProofNodeManager();
+    // enable proof support in the rewriter
+    d_rewriter->setProofNodeManager(pnm);
+    // enable it in the assertions pipeline
+    d_asserts->setProofGenerator(d_pfManager->getPreprocessProofGenerator());
+    // enable it in the SmtSolver
+    d_smtSolver->setProofNodeManager(pnm);
+  }
+
   Trace("smt-debug") << "SmtEngine::finishInit" << std::endl;
   d_smtSolver->finishInit(const_cast<const LogicInfo&>(d_logic));
 
index 5ef8b63c62009d26031f3636a1488f8acb88e351..e95e36c3da5292bcfbabc9dd00cbf788e1286db9 100644 (file)
@@ -117,6 +117,7 @@ class DefinedFunction;
 struct SmtEngineStatistics;
 class SmtScope;
 class ProcessAssertions;
+class PfManager;
 
 ProofManager* currentProofManager();
 }/* CVC4::smt namespace */
@@ -900,7 +901,10 @@ class CVC4_PUBLIC SmtEngine
   /** Get a pointer to the PropEngine owned by this SmtEngine. */
   prop::PropEngine* getPropEngine();
 
-  /** Get a pointer to the ProofManager owned by this SmtEngine. */
+  /**
+   * Get a pointer to the ProofManager owned by this SmtEngine.
+   * TODO (project #37): this is the old proof manager and will be deleted
+   */
   ProofManager* getProofManager() { return d_proofManager.get(); };
 
   /** Get a pointer to the StatisticsRegistry owned by this SmtEngine. */
@@ -1072,9 +1076,15 @@ class CVC4_PUBLIC SmtEngine
   /** The SMT solver */
   std::unique_ptr<smt::SmtSolver> d_smtSolver;
 
-  /** The proof manager */
+  /** The (old) proof manager TODO (project #37): delete this */
   std::unique_ptr<ProofManager> d_proofManager;
 
+  /**
+   * The proof manager, which manages all things related to checking,
+   * processing, and printing proofs.
+   */
+  std::unique_ptr<smt::PfManager> d_pfManager;
+
   /**
    * The rewriter associated with this SmtEngine. We have a different instance
    * of the rewriter for each SmtEngine instance. This is because rewriters may
index 706c184166b90f648d49d3593861e334c122d155..c64689be66e20d38a0721a81980c02fc1ea2d395 100644 (file)
@@ -35,6 +35,7 @@ SmtSolver::SmtSolver(SmtEngine& smt,
       d_rm(rm),
       d_pp(pp),
       d_stats(stats),
+      d_pnm(nullptr),
       d_theoryEngine(nullptr),
       d_propEngine(nullptr)
 {
@@ -245,6 +246,8 @@ void SmtSolver::processAssertions(Assertions& as)
   as.clearCurrent();
 }
 
+void SmtSolver::setProofNodeManager(ProofNodeManager* pnm) { d_pnm = pnm; }
+
 TheoryEngine* SmtSolver::getTheoryEngine() { return d_theoryEngine.get(); }
 
 prop::PropEngine* SmtSolver::getPropEngine() { return d_propEngine.get(); }
index 8d0644800bbf7fb8d8845946b0047c7dc16d56b5..07d81f92b14ef4fd188467afa752ae451c43909e 100644 (file)
@@ -28,6 +28,7 @@ namespace CVC4 {
 class SmtEngine;
 class TheoryEngine;
 class ResourceManager;
+class ProofNodeManager;
 
 namespace prop {
 class PropEngine;
@@ -108,6 +109,11 @@ class SmtSolver
    * into the SMT solver, and clears the buffer.
    */
   void processAssertions(Assertions& as);
+  /**
+   * Set proof node manager. Enables proofs in this SmtSolver. Should be
+   * called before finishInit.
+   */
+  void setProofNodeManager(ProofNodeManager* pnm);
   //------------------------------------------ access methods
   /** Get a pointer to the TheoryEngine owned by this solver. */
   TheoryEngine* getTheoryEngine();
@@ -125,6 +131,11 @@ class SmtSolver
   Preprocessor& d_pp;
   /** Reference to the statistics of SmtEngine */
   SmtEngineStatistics& d_stats;
+  /**
+   * Pointer to the proof node manager used by this SmtSolver. A non-null
+   * proof node manager indicates that proofs are enabled.
+   */
+  ProofNodeManager* d_pnm;
   /** The theory engine */
   std::unique_ptr<TheoryEngine> d_theoryEngine;
   /** The propositional engine */