Support for SMT-LIBv2 (get-proof), CVC-style DUMP_PROOF command, SmtEngine::getProof...
authorMorgan Deters <mdeters@gmail.com>
Sat, 29 Oct 2011 05:21:49 +0000 (05:21 +0000)
committerMorgan Deters <mdeters@gmail.com>
Sat, 29 Oct 2011 05:21:49 +0000 (05:21 +0000)
18 files changed:
src/expr/command.cpp
src/expr/command.h
src/parser/cvc/Cvc.g
src/parser/smt2/Smt2.g
src/proof/proof.h
src/proof/proof_manager.cpp
src/proof/proof_manager.h
src/proof/sat_proof.cpp
src/proof/sat_proof.h
src/smt/smt_engine.cpp
src/smt/smt_engine.h
src/util/Makefile.am
src/util/proof.h [new file with mode: 0644]
test/regress/regress0/Makefile.am
test/regress/regress0/boolean.cvc
test/regress/regress0/hole6.cvc
test/regress/regress0/wiki.05.cvc
test/regress/run_regression

index 61702561aeb1db8242d8b123315fe14711678dc0..345d7f9562412e99a6ec4c4db635de1e3d49e30a 100644 (file)
@@ -423,6 +423,23 @@ void GetAssignmentCommand::printResult(std::ostream& out) const {
   out << d_result << endl;
 }
 
+/* class GetProofCommand */
+
+GetProofCommand::GetProofCommand() {
+}
+
+void GetProofCommand::invoke(SmtEngine* smtEngine) {
+  d_result = smtEngine->getProof();
+}
+
+Proof* GetProofCommand::getResult() const {
+  return d_result;
+}
+
+void GetProofCommand::printResult(std::ostream& out) const {
+  d_result->toStream(out);
+}
+
 /* class GetAssertionsCommand */
 
 GetAssertionsCommand::GetAssertionsCommand() {
index 5cf4f6fa01cac42f3889b39d59eabf89eddcc8ce..b686025fe42edd9ec89af3d1dc85e7baa7e2ca1f 100644 (file)
@@ -35,6 +35,7 @@
 #include "util/result.h"
 #include "util/sexpr.h"
 #include "util/datatype.h"
+#include "util/proof.h"
 
 namespace CVC4 {
 
@@ -232,6 +233,16 @@ public:
   void printResult(std::ostream& out) const;
 };/* class GetAssignmentCommand */
 
+class CVC4_PUBLIC GetProofCommand : public Command {
+protected:
+  Proof* d_result;
+public:
+  GetProofCommand();
+  void invoke(SmtEngine* smtEngine);
+  Proof* getResult() const;
+  void printResult(std::ostream& out) const;
+};/* class GetProofCommand */
+
 class CVC4_PUBLIC GetAssertionsCommand : public Command {
 protected:
   std::string d_result;
index 96c0933d8b17ee1a9cfd6bada6716e29d26debca..22cf368eb6680ca837d7fce32d036a21e8fa43b7 100644 (file)
@@ -705,8 +705,10 @@ mainCommand[CVC4::Command*& cmd]
     | { PARSER_STATE->parseError("No filename given to INCLUDE command"); }
     )
 
-  | ( DUMP_PROOF_TOK
-    | DUMP_ASSUMPTIONS_TOK
+  | DUMP_PROOF_TOK
+    { cmd = new GetProofCommand(); }
+
+  | ( DUMP_ASSUMPTIONS_TOK
     | DUMP_SIG_TOK
     | DUMP_TCC_TOK
     | DUMP_TCC_ASSUMPTIONS_TOK
index 7fb671bb06e7968493c035184e0af544a825abfe..974de29b2bd574a2baf4f838590dc591d83d4886 100644 (file)
@@ -297,7 +297,7 @@ command returns [CVC4::Command* cmd = NULL]
     { cmd = new GetAssertionsCommand; }
   | /* get-proof */
     GET_PROOF_TOK
-    { UNSUPPORTED("get-proof command not yet supported"); }
+    { cmd = new GetProofCommand; }
   | /* get-unsat-core */
     GET_UNSAT_CORE_TOK
     { UNSUPPORTED("unsat cores not yet supported"); }
index 3e5b54cc7a57af5966118107333429b42e5f6c2c..a3270c4c0b87d1f9754ac0a5257a9bfa67c9891d 100644 (file)
@@ -16,8 +16,8 @@
  ** Proof manager
  **/
 
-#ifndef __CVC4__PROOF_H
-#define __CVC4__PROOF_H
+#ifndef __CVC4__PROOF__PROOF_H
+#define __CVC4__PROOF__PROOF_H
 
 #include "util/options.h"
 
@@ -33,4 +33,4 @@
 
 
 
-#endif /* __CVC4__PROOF_H */
+#endif /* __CVC4__PROOF__PROOF_H */
index 2d7432cbc632756cccfc8295e92d565800e019c2..4191d1046d0c993edbb9b574a04100e14518bd7f 100644 (file)
@@ -18,6 +18,7 @@
  **/
 
 #include "proof/proof_manager.h"
+#include "util/proof.h"
 #include "proof/sat_proof.h"
 #include "proof/cnf_proof.h"
 #include "util/Assert.h"
@@ -40,7 +41,12 @@ ProofManager* ProofManager::currentPM() {
     proofManager = new ProofManager();
     isInitialized = true; 
     return proofManager; 
-    }
+  }
+}
+
+Proof* ProofManager::getProof() {
+  // for now, this is just the SAT proof
+  return getSatProof();
 }
 
 SatProof* ProofManager::getSatProof() {
index c79d26fed908a2c54a6fc9be1705cd11f443eb34..e23fbd600b9e6b5eb41ed836dd0e7522b8d0ccf4 100644 (file)
@@ -22,7 +22,7 @@
 #define __CVC4__PROOF_MANAGER_H
 
 #include <iostream> 
-#include "proof.h"
+#include "proof/proof.h"
 
 // forward declarations
 namespace Minisat {
@@ -33,6 +33,7 @@ namespace CVC4 {
 namespace prop {
 class CnfStream;
 }
+class Proof;
 class SatProof;
 class CnfProof;
 
@@ -56,6 +57,7 @@ public:
   static void      initSatProof(Minisat::Solver* solver); 
   static void      initCnfProof(CVC4::prop::CnfStream* cnfStream);
 
+  static Proof* getProof();
   static SatProof* getSatProof();
   static CnfProof* getCnfProof();
 
index 57bb96513260b4c6c7f17d515f10efe33ddd2564..37a3a97061c3a14c49aa39a8c858a088099d7154 100644 (file)
@@ -524,8 +524,9 @@ ClauseId SatProof::resolveUnit(Lit lit) {
   return unit_id; 
 }
 
-void SatProof::printProof() {
+void SatProof::toStream(std::ostream& out) {
   Debug("proof:sat") << "SatProof::printProof\n";
+  Unimplemented("native proof printing not supported yet");
 }
 
 void SatProof::finalizeProof(CRef conflict_ref) {
@@ -543,7 +544,6 @@ void SatProof::finalizeProof(CRef conflict_ref) {
     res->addStep(lit, res_id, !sign(lit)); 
   }
   registerResolution(d_emptyClauseId, res);
-  printProof(); 
 }
 
 /// CRef manager
@@ -693,8 +693,7 @@ void LFSCSatProof::printVariables() {
 }
 
 
-void LFSCSatProof::flush() {
-  ostringstream out;
+void LFSCSatProof::flush(std::ostream& out) {
   out << "(check \n";
   d_paren <<")"; 
   out << d_varSS.str();
@@ -703,11 +702,10 @@ void LFSCSatProof::flush() {
   out << d_lemmaSS.str(); 
   d_paren << "))";
   out << d_paren.str();
-  out << ";"; //to comment out the solver's answer 
-  std::cout << out.str(); 
+  out << "\n";
 }
 
-void LFSCSatProof::printProof() {
+void LFSCSatProof::toStream(std::ostream& out) {
   Debug("proof:sat") << " LFSCSatProof::printProof \n";
 
   // first collect lemmas to print in reverse order
@@ -722,8 +720,7 @@ void LFSCSatProof::printProof() {
 
   printClauses();
   printVariables();
-  flush();
-  
+  flush(out);
 }
 
 } /* CVC4 namespace */
index 4641ea4ccafded35654770431839cf42d0799173..051266df8fe71504f3f427e8d2820aaaf636add4 100644 (file)
@@ -32,6 +32,7 @@ typedef uint32_t CRef;
 }
 
 #include "prop/minisat/core/SolverTypes.h"
+#include "util/proof.h"
 
 namespace std {
 using namespace __gnu_cxx;
@@ -99,7 +100,7 @@ public:
   void updateCRef(::Minisat::CRef oldref, ::Minisat::CRef newref);
 };
 
-class SatProof {
+class SatProof : public Proof {
 protected:
   ::Minisat::Solver*    d_solver;
   // clauses 
@@ -144,8 +145,8 @@ protected:
   ::Minisat::Lit  getUnit(ClauseId id);
   ClauseId      getUnitId(::Minisat::Lit lit); 
   ::Minisat::Clause& getClause(ClauseId id);
-  virtual void printProof();
-  
+  virtual void toStream(std::ostream& out);
+
   bool checkResolution(ClauseId id);
   /** 
    * Constructs a resolution tree that proves lit
@@ -237,7 +238,7 @@ private:
 
   void printVariables();
   void printClauses();
-  void flush();
+  void flush(std::ostream& out);
   
 public:
   LFSCSatProof(::Minisat::Solver* solver, bool checkRes = false):
@@ -249,7 +250,7 @@ public:
     d_seenLemmas(),
     d_seenInput()
   {} 
-  void printProof();  
+  virtual void toStream(std::ostream& out);  
 };
 
 }
index 96ee5b59bf8e8e5eecbf574f1ec3bcbbea9b2394..7ea22ce8f8b41158f2ffd31960567791f7af0501 100644 (file)
@@ -34,6 +34,8 @@
 #include "smt/no_such_function_exception.h"
 #include "smt/smt_engine.h"
 #include "theory/theory_engine.h"
+#include "proof/proof_manager.h"
+#include "util/proof.h"
 #include "util/boolean_simplification.h"
 #include "util/configuration.h"
 #include "util/exception.h"
@@ -987,7 +989,7 @@ Expr SmtEngine::getValue(const Expr& e)
      d_status.asSatisfiabilityResult() != Result::SAT ||
      d_problemExtended) {
     const char* msg =
-      "Cannot get value unless immediately proceded by SAT/INVALID response.";
+      "Cannot get value unless immediately preceded by SAT/INVALID response.";
     throw ModalException(msg);
   }
   if(type.isFunction() || type.isPredicate() ||
@@ -1040,6 +1042,7 @@ bool SmtEngine::addToAssignment(const Expr& e) throw(AssertionException) {
 
 SExpr SmtEngine::getAssignment() throw(ModalException, AssertionException) {
   Trace("smt") << "SMT getAssignment()" << endl;
+  NodeManagerScope nms(d_nodeManager);
   if(Dump.isOn("benchmark")) {
     Dump("benchmark") << GetAssignmentCommand() << endl;
   }
@@ -1053,7 +1056,8 @@ SExpr SmtEngine::getAssignment() throw(ModalException, AssertionException) {
      d_status.asSatisfiabilityResult() != Result::SAT ||
      d_problemExtended) {
     const char* msg =
-      "Cannot get value unless immediately proceded by SAT/INVALID response.";
+      "Cannot get the current assignment unless immediately "
+      "preceded by SAT/INVALID response.";
     throw ModalException(msg);
   }
 
@@ -1061,7 +1065,6 @@ SExpr SmtEngine::getAssignment() throw(ModalException, AssertionException) {
     return SExpr();
   }
 
-  NodeManagerScope nms(d_nodeManager);
   vector<SExpr> sexprs;
   TypeNode boolType = d_nodeManager->booleanType();
   for(AssignmentSet::const_iterator i = d_assignments->begin(),
@@ -1093,6 +1096,32 @@ SExpr SmtEngine::getAssignment() throw(ModalException, AssertionException) {
   return SExpr(sexprs);
 }
 
+Proof* SmtEngine::getProof() throw(ModalException, AssertionException) {
+  Trace("smt") << "SMT getProof()" << endl;
+  NodeManagerScope nms(d_nodeManager);
+  if(Dump.isOn("benchmark")) {
+    Dump("benchmark") << GetProofCommand() << endl;
+  }
+#ifdef CVC4_PROOF
+  if(!Options::current()->proof) {
+    const char* msg =
+      "Cannot get a proof when produce-proofs option is off.";
+    throw ModalException(msg);
+  }
+  if(d_status.isNull() ||
+     d_status.asSatisfiabilityResult() != Result::UNSAT ||
+     d_problemExtended) {
+    const char* msg =
+      "Cannot get a proof unless immediately preceded by UNSAT/VALID response.";
+    throw ModalException(msg);
+  }
+
+  return ProofManager::getProof();
+#else /* CVC4_PROOF */
+  throw ModalException("This build of CVC4 doesn't have proof support.");
+#endif /* CVC4_PROOF */
+}
+
 vector<Expr> SmtEngine::getAssertions()
   throw(ModalException, AssertionException) {
   if(Dump.isOn("benchmark")) {
index 5d8f31d3c8ff632ea0c17a2710fc4a3fda620aa7..90593569b10cc1c1ff7a739bc26a10671970b6e6 100644 (file)
@@ -28,6 +28,7 @@
 #include "context/cdset_forward.h"
 #include "expr/expr.h"
 #include "expr/expr_manager.h"
+#include "util/proof.h"
 #include "smt/bad_option_exception.h"
 #include "smt/modal_exception.h"
 #include "smt/no_such_function_exception.h"
@@ -36,7 +37,6 @@
 #include "util/result.h"
 #include "util/sexpr.h"
 #include "util/stats.h"
-#include "proof/proof_manager.h"
 
 // In terms of abstraction, this is below (and provides services to)
 // ValidityChecker and above (and requires the services of)
@@ -318,6 +318,13 @@ public:
    */
   SExpr getAssignment() throw(ModalException, AssertionException);
 
+  /**
+   * Get the last proof (only if immediately preceded by an UNSAT
+   * or VALID query).  Only permitted if CVC4 was built with proof
+   * support and produce-proofs is on.
+   */
+  Proof* getProof() throw(ModalException, AssertionException);
+
   /**
    * Get the current set of assertions.  Only permitted if the
    * SmtEngine is set to operate interactively.
index e915fe48306dbb84e6bae8661b1e5391474e141f..c5a20cd5d5030feb1c57228fa4e29b50561ce5b1 100644 (file)
@@ -28,6 +28,7 @@ libutil_la_SOURCES = \
        exception.h \
        hash.h \
        bool.h \
+       proof.h \
        options.h \
        options.cpp \
        output.cpp \
diff --git a/src/util/proof.h b/src/util/proof.h
new file mode 100644 (file)
index 0000000..be833e3
--- /dev/null
@@ -0,0 +1,36 @@
+/*********************                                                        */
+/*! \file proof.h
+ ** \verbatim
+ ** Original author: mdeters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011  The Analysis of Computer Systems Group (ACSys)
+ ** Courant Institute of Mathematical Sciences
+ ** New York University
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief [[ Add one-line brief description here ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include "cvc4_public.h"
+
+#ifndef __CVC4__PROOF_H
+#define __CVC4__PROOF_H
+
+#include <iostream>
+
+namespace CVC4 {
+
+class CVC4_PUBLIC Proof {
+public:
+  virtual void toStream(std::ostream& out) = 0;
+};/* class Proof */
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__PROOF_H */
index 3a4583805dba7d13cbae50ff4d2a8f8f5a89498d..e564b567ad75d56a55c3a9ad77218a961ed5878b 100644 (file)
@@ -45,6 +45,7 @@ SMT2_TESTS = \
 
 # Regression tests for PL inputs
 CVC_TESTS = \
+       boolean.cvc \
        boolean-prec.cvc \
        hole6.cvc \
        ite.cvc \
index d6f428bdb3f0302e5c9fa078d33afbeca9a1bbd1..2d0eb59b2361cd5ebf6eaccc1903b89c10d0aea0 100644 (file)
@@ -804,5 +804,5 @@ a288 : BOOLEAN =
         ELSE FALSE
         ENDIF;
 QUERY a288;
-% EXIT: 20
 % PROOF
+% EXIT: 20
index 31204a6c1d2f5d8656073d20811a7891236d0fea..ece29e17ca540d2d55bf4f28359eadbaf9855ff6 100644 (file)
@@ -177,5 +177,5 @@ ASSERT x_42 OR x_41 OR x_40 OR x_39 OR x_38 OR x_37;
 
 
 QUERY FALSE;
-% EXIT: 20
 % PROOF
+% EXIT: 20
index 1aedcbe2b09752c552e63598326cd0b6ce518191..04c7dafe0f884dc67c77e98ecafa85078e630008 100644 (file)
@@ -2,5 +2,5 @@ a, b, c : BOOLEAN;
 
 % EXPECT: valid
 QUERY a OR (a AND b) <=> a;
-% EXIT: 20
 % PROOF
+% EXIT: 20
index b836b39f621b1a869edbb7b251ee2eeabfc72ec1..6c06175d206ac006bb092d4e33905e7c0a89972b 100755 (executable)
@@ -52,6 +52,8 @@ function gettemp {
 
 tmpbenchmark=
 if expr "$benchmark" : '.*\.smt$' &>/dev/null; then
+  proof_command=PROOFS-NOT-SUPPORTED-IN-SMTLIB-V1
+  lang=smt
   if test -e "$benchmark.expect"; then
     expected_proof=`grep -q '^% PROOF' "$benchmark.expect" && echo yes`
     expected_output=`grep '^% EXPECT: ' "$benchmark.expect" | sed 's,^% EXPECT: ,,'`
@@ -68,9 +70,8 @@ if expr "$benchmark" : '.*\.smt$' &>/dev/null; then
     expected_exit_status=`grep -m 1 '^% EXIT: ' "$benchmark" | perl -pe 's,^% EXIT: ,,;s,\r,,'`
     command_line=`grep '^% COMMAND-LINE: ' "$benchmark" | sed 's,^% COMMAND-LINE: ,,'`
     # old mktemp from coreutils 7.x is broken, can't do XXXX in the middle
-    # this frustrates our auto-language-detection, so add explicit --lang
+    # this frustrates our auto-language-detection
     gettemp tmpbenchmark cvc4_benchmark.smt.$$.XXXXXXXXXX
-    command_line="${command_line:+$command_line }--lang=smt"
     grep -v '^% \(PROOF\|EXPECT\|EXPECT-ERROR\|EXIT\|COMMAND-LINE\): ' "$benchmark" >"$tmpbenchmark"
     if [ -z "$expected_exit_status" ]; then
       error "cannot determine expected exit status of \`$benchmark': please use \`% EXIT:' gesture"
@@ -90,6 +91,8 @@ if expr "$benchmark" : '.*\.smt$' &>/dev/null; then
     error "cannot determine status of \`$benchmark'"
   fi
 elif expr "$benchmark" : '.*\.smt2$' &>/dev/null; then
+  proof_command='(get-proof)'
+  lang=smt2
   if test -e "$benchmark.expect"; then
     expected_proof=`grep -q '^% PROOF' "$benchmark.expect" && echo yes`
     expected_output=`grep '^% EXPECT: ' "$benchmark.expect" | sed 's,^% EXPECT: ,,'`
@@ -106,9 +109,8 @@ elif expr "$benchmark" : '.*\.smt2$' &>/dev/null; then
     expected_exit_status=`grep -m 1 '^% EXIT: ' "$benchmark" | perl -pe 's,^% EXIT: ,,;s,\r,,'`
     command_line=`grep '^% COMMAND-LINE: ' "$benchmark" | sed 's,^% COMMAND-LINE: ,,'`
     # old mktemp from coreutils 7.x is broken, can't do XXXX in the middle
-    # this frustrates our auto-language-detection, so add explicit --lang
+    # this frustrates our auto-language-detection
     gettemp tmpbenchmark cvc4_benchmark.smt2.$$.XXXXXXXXXX
-    command_line="${command_line:+$command_line }--lang=smt2"
     grep -v '^% \(EXPECT\|EXPECT-ERROR\|EXIT\|COMMAND-LINE\): ' "$benchmark" >"$tmpbenchmark"
     if [ -z "$expected_exit_status" ]; then
       error "cannot determine expected exit status of \`$benchmark': please use \`% EXIT:' gesture"
@@ -128,6 +130,8 @@ elif expr "$benchmark" : '.*\.smt2$' &>/dev/null; then
     error "cannot determine status of \`$benchmark'"
   fi
 elif expr "$benchmark" : '.*\.cvc$' &>/dev/null; then
+  proof_command='DUMP_PROOF;'
+  lang=cvc4
   expected_proof=`grep -q '^% PROOF' "$benchmark" && echo yes`
   expected_output=$(grep '^% EXPECT: ' "$benchmark")
   expected_error=`grep '^% EXPECT-ERROR: ' "$benchmark" | sed 's,^% EXPECT-ERROR: ,,'`
@@ -145,6 +149,8 @@ else
   error "benchmark \`$benchmark' must be *.cvc or *.smt or *.smt2"
 fi
 
+command_line="${command_line:+$command_line }--lang=$lang"
+
 gettemp expoutfile cvc4_expect_stdout.$$.XXXXXXXXXX
 gettemp experrfile cvc4_expect_stderr.$$.XXXXXXXXXX
 gettemp outfile cvc4_stdout.$$.XXXXXXXXXX
@@ -203,19 +209,27 @@ if [ "$exit_status" != "$expected_exit_status" ]; then
 fi
 
 if [ "$proof" = yes -a "$expected_proof" = yes ]; then
-  echo running $cvc4full $CVC4_REGRESSION_ARGS $command_line --proof --segv-nospin `basename "$benchmark"` [from working dir `dirname "$benchmark"`]
-  ( cd `dirname "$benchmark"`;
-    "$cvc4full" $CVC4_REGRESSION_ARGS $command_line --proof --segv-nospin `basename "$benchmark"`;
+  gettemp pfbenchmark cvc4_pfbenchmark.$$.XXXXXXXXXX
+  cp "$benchmark" "$pfbenchmark";
+  echo "$proof_command" >>"$pfbenchmark";
+  echo running $cvc4full $CVC4_REGRESSION_ARGS $command_line --proof --segv-nospin `basename "$pfbenchmark"` [from working dir `dirname "$pfbenchmark"`]
+  ( cd `dirname "$pfbenchmark"`;
+    "$cvc4full" $CVC4_REGRESSION_ARGS $command_line --proof --segv-nospin `basename "$pfbenchmark"`;
     echo $? >"$exitstatusfile"
   ) > "$outfile" 2> "$errfile"
 
-  if [ ! -s "$outfile" ]; then
+  gettemp pfoutfile cvc4_proof.$$.XXXXXXXXXX
+  diff --unchanged-group-format='' \
+       --old-group-format='' \
+       --new-group-format='%>' \
+       "$expoutfile" "$outfile" > "$pfoutfile"
+  if [ ! -s "$pfoutfile" ]; then
     echo "$prog: error: proof generation failed with empty output (stderr follows)"
     cat "$errfile"
     exitcode=1
   else
-    echo running $LFSC "$outfile" [from working dir `dirname "$benchmark"`]
-    if ! $LFSC "$outfile" &> "$errfile"; then
+    echo running $LFSC "$pfoutfile" [from working dir `dirname "$pfbenchmark"`]
+    if ! $LFSC "$pfoutfile" &> "$errfile"; then
       echo "$prog: error: proof checker failed (output follows)"
       cat "$errfile"
       exitcode=1