diff options
author | Andres Noetzli <andres.noetzli@gmail.com> | 2019-01-14 17:02:53 -0800 |
---|---|---|
committer | Andres Noetzli <andres.noetzli@gmail.com> | 2019-01-14 17:02:53 -0800 |
commit | c8664731adc61ab3967b74fe90ad44fb464dc556 (patch) | |
tree | 495766d37af08f4f587ed18ac224deaae5402b1b | |
parent | 2771dce1fe1933537f80d68966642ecf3bf95f77 (diff) | |
parent | 8d9c190ccf806460bfc336daee33ed56f151e563 (diff) |
Merge remote-tracking branch 'fork/loopProcessOpts' into cav2019strings
86 files changed, 5589 insertions, 1636 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 3265830cc..33e06840e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -212,15 +212,6 @@ if(NOT ENABLE_ASSERTIONS) set(ENABLE_UNIT_TESTING OFF) endif() -# Never build unit tests as static binaries, otherwise we'll end up with -# ~300MB per unit test. -if(ENABLE_UNIT_TESTING) - if(NOT ENABLE_SHARED) - message(WARNING "Disabling static build since unit testing is enabled.") - endif() - set(ENABLE_SHARED ON) -endif() - #-----------------------------------------------------------------------------# # Shared/static libraries # @@ -239,6 +230,13 @@ else() # This is required to force find_package(Boost) to use static libraries. set(Boost_USE_STATIC_LIBS ON) cvc4_set_option(ENABLE_STATIC_BINARY ON) + + # Never build unit tests as static binaries, otherwise we'll end up with + # ~300MB per unit test. + if(ENABLE_UNIT_TESTING) + message(WARNING "Disabling unit tests since static build is enabled.") + set(ENABLE_UNIT_TESTING OFF) + endif() endif() #-----------------------------------------------------------------------------# diff --git a/cmake/FindDrat2Er.cmake b/cmake/FindDrat2Er.cmake index e0bc8d446..a7c2538a5 100644 --- a/cmake/FindDrat2Er.cmake +++ b/cmake/FindDrat2Er.cmake @@ -19,13 +19,21 @@ find_library(Drat2Er_LIBRARIES NAMES libdrat2er.a PATHS ${Drat2Er_HOME}/lib NO_DEFAULT_PATH) +find_library(DratTrim_LIBRARIES + NAMES libdrat-trim.a + PATHS ${Drat2Er_HOME}/lib + NO_DEFAULT_PATH) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Drat2Er DEFAULT_MSG - Drat2Er_INCLUDE_DIR Drat2Er_LIBRARIES) + Drat2Er_INCLUDE_DIR Drat2Er_LIBRARIES DratTrim_LIBRARIES) -mark_as_advanced(Drat2Er_INCLUDE_DIR Drat2Er_LIBRARIES) +mark_as_advanced(Drat2Er_INCLUDE_DIR Drat2Er_LIBRARIES DratTrim_LIBRARIES) if(Drat2Er_LIBRARIES) message(STATUS "Found Drat2Er libs: ${Drat2Er_LIBRARIES}") endif() +if(DratTrim_LIBRARIES) + message(STATUS "Found DratTrim libs: ${DratTrim_LIBRARIES}") + list(APPEND Drat2Er_LIBRARIES ${DratTrim_LIBRARIES}) +endif() diff --git a/examples/api/combination-new.cpp b/examples/api/combination-new.cpp index 2956d76e6..8c968c95e 100644 --- a/examples/api/combination-new.cpp +++ b/examples/api/combination-new.cpp @@ -59,8 +59,8 @@ int main() Term p = slv.mkVar("p", intPred); // Constants - Term zero = slv.mkInteger(0); - Term one = slv.mkInteger(1); + Term zero = slv.mkReal(0); + Term one = slv.mkReal(1); // Terms Term f_x = slv.mkTerm(APPLY_UF, f, x); diff --git a/examples/api/datatypes-new.cpp b/examples/api/datatypes-new.cpp index b6a816db4..48560e894 100644 --- a/examples/api/datatypes-new.cpp +++ b/examples/api/datatypes-new.cpp @@ -39,7 +39,7 @@ void test(Solver& slv, Sort& consListSort) Term t = slv.mkTerm( APPLY_CONSTRUCTOR, consList.getConstructorTerm("cons"), - slv.mkInteger(0), + slv.mkReal(0), slv.mkTerm(APPLY_CONSTRUCTOR, consList.getConstructorTerm("nil"))); std::cout << "t is " << t << std::endl @@ -127,7 +127,7 @@ void test(Solver& slv, Sort& consListSort) << "sort of cons is " << paramConsList.getConstructorTerm("cons").getSort() << std::endl << std::endl; - Term assertion = slv.mkTerm(GT, head_a, slv.mkInteger(50)); + Term assertion = slv.mkTerm(GT, head_a, slv.mkReal(50)); std::cout << "Assert " << assertion << std::endl; slv.assertFormula(assertion); std::cout << "Expect sat." << std::endl; diff --git a/examples/api/linear_arith-new.cpp b/examples/api/linear_arith-new.cpp index ef8faade9..d643b85bc 100644 --- a/examples/api/linear_arith-new.cpp +++ b/examples/api/linear_arith-new.cpp @@ -40,8 +40,8 @@ int main() Term y = slv.mkVar("y", real); // Constants - Term three = slv.mkInteger(3); - Term neg2 = slv.mkInteger(-2); + Term three = slv.mkReal(3); + Term neg2 = slv.mkReal(-2); Term two_thirds = slv.mkReal(2, 3); // Terms diff --git a/examples/api/sets-new.cpp b/examples/api/sets-new.cpp index be35bcc21..2dcfbbc02 100644 --- a/examples/api/sets-new.cpp +++ b/examples/api/sets-new.cpp @@ -70,9 +70,9 @@ int main() // Find me an element in {1, 2} intersection {2, 3}, if there is one. { - Term one = slv.mkInteger(1); - Term two = slv.mkInteger(2); - Term three = slv.mkInteger(3); + Term one = slv.mkReal(1); + Term two = slv.mkReal(2); + Term three = slv.mkReal(3); Term singleton_one = slv.mkTerm(SINGLETON, one); Term singleton_two = slv.mkTerm(SINGLETON, two); diff --git a/examples/api/strings-new.cpp b/examples/api/strings-new.cpp index 2010c6909..c88ccc9c0 100644 --- a/examples/api/strings-new.cpp +++ b/examples/api/strings-new.cpp @@ -57,7 +57,7 @@ int main() // Length of y: |y| Term leny = slv.mkTerm(STRING_LENGTH, y); // |y| >= 0 - Term formula2 = slv.mkTerm(GEQ, leny, slv.mkInteger(0)); + Term formula2 = slv.mkTerm(GEQ, leny, slv.mkReal(0)); // Regular expression: (ab[c-e]*f)|g|h Term r = slv.mkTerm(REGEXP_UNION, diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 889260045..d9fc80a92 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -130,13 +130,19 @@ libcvc4_add_sources( proof/array_proof.h proof/bitvector_proof.cpp proof/bitvector_proof.h + proof/clausal_bitvector_proof.cpp + proof/clausal_bitvector_proof.h proof/clause_id.h proof/cnf_proof.cpp proof/cnf_proof.h + proof/drat/drat_proof.cpp + proof/drat/drat_proof.h proof/lemma_proof.cpp proof/lemma_proof.h proof/lfsc_proof_printer.cpp proof/lfsc_proof_printer.h + proof/lrat/lrat_proof.cpp + proof/lrat/lrat_proof.h proof/proof.h proof/proof_manager.cpp proof/proof_manager.h diff --git a/src/api/cvc4cpp.cpp b/src/api/cvc4cpp.cpp index cd604a25c..123613797 100644 --- a/src/api/cvc4cpp.cpp +++ b/src/api/cvc4cpp.cpp @@ -16,6 +16,7 @@ #include "api/cvc4cpp.h" +#include "base/configuration.h" #include "base/cvc4_assert.h" #include "base/cvc4_check.h" #include "expr/expr.h" @@ -28,10 +29,12 @@ #include "options/options.h" #include "smt/model.h" #include "smt/smt_engine.h" +#include "theory/logic_info.h" #include "util/random.h" #include "util/result.h" #include "util/utility.h" +#include <cstring> #include <sstream> namespace CVC4 { @@ -639,6 +642,10 @@ class CVC4ApiExceptionStream CVC4_API_CHECK(!isNull()) << "Invalid call to '" << __PRETTY_FUNCTION__ \ << "', expected non-null object"; +#define CVC4_API_ARG_CHECK_NOT_NULL(arg) \ + CVC4_API_CHECK(arg != nullptr) \ + << "Invalid null argument for '" << #arg << "'"; + #define CVC4_API_KIND_CHECK(kind) \ CVC4_API_CHECK(isDefinedKind(kind)) \ << "Invalid kind '" << kindToString(kind) << "'"; @@ -665,12 +672,12 @@ class CVC4ApiExceptionStream & CVC4ApiExceptionStream().ostream() \ << "Invalid size of argument '" << #arg << "', expected " -#define CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(cond, what, arg, idx) \ - CVC4_PREDICT_FALSE(cond) \ - ? (void)0 \ - : OstreamVoider() \ - & CVC4ApiExceptionStream().ostream() \ - << "Invalid " << what << "'" << arg << "' at index" << idx \ +#define CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(cond, what, arg, idx) \ + CVC4_PREDICT_FALSE(cond) \ + ? (void)0 \ + : OstreamVoider() \ + & CVC4ApiExceptionStream().ostream() \ + << "Invalid " << what << " '" << arg << "' at index" << idx \ << ", expected " } // namespace @@ -751,12 +758,16 @@ std::ostream& operator<<(std::ostream& out, const Result& r) Sort::Sort(const CVC4::Type& t) : d_type(new CVC4::Type(t)) {} +Sort::Sort() : d_type(new CVC4::Type()) {} + Sort::~Sort() {} bool Sort::operator==(const Sort& s) const { return *d_type == *s.d_type; } bool Sort::operator!=(const Sort& s) const { return *d_type != *s.d_type; } +bool Sort::isNull() const { return d_type->isNull(); } + bool Sort::isBoolean() const { return d_type->isBoolean(); } bool Sort::isInteger() const { return d_type->isInteger(); } @@ -1025,9 +1036,11 @@ Term Term::notTerm() const { try { - return d_expr->notExpr(); + Term res = d_expr->notExpr(); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; } - catch (TypeCheckingException& e) + catch (const CVC4::TypeCheckingException& e) { throw CVC4ApiException(e.getMessage()); } @@ -1037,9 +1050,11 @@ Term Term::andTerm(const Term& t) const { try { - return d_expr->andExpr(*t.d_expr); + Term res = d_expr->andExpr(*t.d_expr); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; } - catch (TypeCheckingException& e) + catch (const CVC4::TypeCheckingException& e) { throw CVC4ApiException(e.getMessage()); } @@ -1049,9 +1064,11 @@ Term Term::orTerm(const Term& t) const { try { - return d_expr->orExpr(*t.d_expr); + Term res = d_expr->orExpr(*t.d_expr); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; } - catch (TypeCheckingException& e) + catch (const CVC4::TypeCheckingException& e) { throw CVC4ApiException(e.getMessage()); } @@ -1061,9 +1078,11 @@ Term Term::xorTerm(const Term& t) const { try { - return d_expr->xorExpr(*t.d_expr); + Term res = d_expr->xorExpr(*t.d_expr); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; } - catch (TypeCheckingException& e) + catch (const CVC4::TypeCheckingException& e) { throw CVC4ApiException(e.getMessage()); } @@ -1073,9 +1092,11 @@ Term Term::eqTerm(const Term& t) const { try { - return d_expr->eqExpr(*t.d_expr); + Term res = d_expr->eqExpr(*t.d_expr); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; } - catch (TypeCheckingException& e) + catch (const CVC4::TypeCheckingException& e) { throw CVC4ApiException(e.getMessage()); } @@ -1085,9 +1106,11 @@ Term Term::impTerm(const Term& t) const { try { - return d_expr->impExpr(*t.d_expr); + Term res = d_expr->impExpr(*t.d_expr); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; } - catch (TypeCheckingException& e) + catch (const CVC4::TypeCheckingException& e) { throw CVC4ApiException(e.getMessage()); } @@ -1097,9 +1120,11 @@ Term Term::iteTerm(const Term& then_t, const Term& else_t) const { try { - return d_expr->iteExpr(*then_t.d_expr, *else_t.d_expr); + Term res = d_expr->iteExpr(*then_t.d_expr, *else_t.d_expr); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; } - catch (TypeCheckingException& e) + catch (const CVC4::TypeCheckingException& e) { throw CVC4ApiException(e.getMessage()); } @@ -1451,6 +1476,14 @@ DatatypeConstructor::DatatypeConstructor(const CVC4::DatatypeConstructor& ctor) DatatypeConstructor::~DatatypeConstructor() {} +bool DatatypeConstructor::isResolved() const { return d_ctor->isResolved(); } + +Term DatatypeConstructor::getConstructorTerm() const +{ + CVC4_API_CHECK(isResolved()) << "Expected resolved datatype constructor."; + return Term(d_ctor->getConstructor()); +} + DatatypeSelector DatatypeConstructor::operator[](const std::string& name) const { // CHECK: selector with name exists? @@ -1573,6 +1606,13 @@ Datatype::Datatype(const CVC4::Datatype& dtype) Datatype::~Datatype() {} +DatatypeConstructor Datatype::operator[](size_t idx) const +{ + // CHECK (maybe): is resolved? + CVC4_API_CHECK(idx < getNumConstructors()) << "Index out of bounds."; + return (*d_dtype)[idx]; +} + DatatypeConstructor Datatype::operator[](const std::string& name) const { // CHECK: cons with name exists? @@ -1725,6 +1765,8 @@ Solver::~Solver() {} /* Sorts Handling */ /* -------------------------------------------------------------------------- */ +Sort Solver::getNullSort(void) const { return Type(); } + Sort Solver::getBooleanSort(void) const { return d_exprMgr->booleanType(); } Sort Solver::getIntegerSort(void) const { return d_exprMgr->integerType(); } @@ -1744,6 +1786,10 @@ Sort Solver::getRoundingmodeSort(void) const Sort Solver::mkArraySort(Sort indexSort, Sort elemSort) const { + CVC4_API_ARG_CHECK_EXPECTED(!indexSort.isNull(), indexSort) + << "non-null index sort"; + CVC4_API_ARG_CHECK_EXPECTED(!elemSort.isNull(), elemSort) + << "non-null element sort"; return d_exprMgr->mkArrayType(*indexSort.d_type, *elemSort.d_type); } @@ -1769,6 +1815,8 @@ Sort Solver::mkDatatypeSort(DatatypeDecl dtypedecl) const Sort Solver::mkFunctionSort(Sort domain, Sort codomain) const { + CVC4_API_ARG_CHECK_EXPECTED(!codomain.isNull(), codomain) + << "non-null codomain sort"; CVC4_API_ARG_CHECK_EXPECTED(domain.isFirstClass(), domain) << "first-class sort as domain sort for function sort"; CVC4_API_ARG_CHECK_EXPECTED(codomain.isFirstClass(), codomain) @@ -1784,9 +1832,14 @@ Sort Solver::mkFunctionSort(const std::vector<Sort>& sorts, Sort codomain) const for (size_t i = 0, size = sorts.size(); i < size; ++i) { CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED( + !sorts[i].isNull(), "parameter sort", sorts[i], i) + << "non-null sort"; + CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED( sorts[i].isFirstClass(), "parameter sort", sorts[i], i) << "first-class sort as parameter sort for function sort"; } + CVC4_API_ARG_CHECK_EXPECTED(!codomain.isNull(), codomain) + << "non-null codomain sort"; CVC4_API_ARG_CHECK_EXPECTED(codomain.isFirstClass(), codomain) << "first-class sort as codomain sort for function sort"; Assert(!codomain.isFunction()); /* A function sort is not first-class. */ @@ -1806,6 +1859,9 @@ Sort Solver::mkPredicateSort(const std::vector<Sort>& sorts) const for (size_t i = 0, size = sorts.size(); i < size; ++i) { CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED( + !sorts[i].isNull(), "parameter sort", sorts[i], i) + << "non-null sort"; + CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED( sorts[i].isFirstClass(), "parameter sort", sorts[i], i) << "first-class sort as parameter sort for predicate sort"; } @@ -1817,8 +1873,13 @@ Sort Solver::mkRecordSort( const std::vector<std::pair<std::string, Sort>>& fields) const { std::vector<std::pair<std::string, Type>> f; + size_t i = 0; for (const auto& p : fields) { + CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED( + !p.second.isNull(), "parameter sort", p.second, i) + << "non-null sort"; + i += 1; f.emplace_back(p.first, *p.second.d_type); } return d_exprMgr->mkRecordType(Record(f)); @@ -1826,6 +1887,8 @@ Sort Solver::mkRecordSort( Sort Solver::mkSetSort(Sort elemSort) const { + CVC4_API_ARG_CHECK_EXPECTED(!elemSort.isNull(), elemSort) + << "non-null element sort"; return d_exprMgr->mkSetType(*elemSort.d_type); } @@ -1846,6 +1909,9 @@ Sort Solver::mkTupleSort(const std::vector<Sort>& sorts) const for (size_t i = 0, size = sorts.size(); i < size; ++i) { CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED( + !sorts[i].isNull(), "parameter sort", sorts[i], i) + << "non-null sort"; + CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED( !sorts[i].isFunctionLike(), "parameter sort", sorts[i], i) << "non-function-like sort as parameter sort for tuple sort"; } @@ -1873,328 +1939,439 @@ Term Solver::mkFalse(void) const { return d_exprMgr->mkConst<bool>(false); } Term Solver::mkBoolean(bool val) const { return d_exprMgr->mkConst<bool>(val); } -Term Solver::mkInteger(const char* s, uint32_t base) const -{ - return d_exprMgr->mkConst(Rational(s, base)); -} - -Term Solver::mkInteger(const std::string& s, uint32_t base) const -{ - return d_exprMgr->mkConst(Rational(s, base)); -} - -Term Solver::mkInteger(int32_t val) const -{ - return d_exprMgr->mkConst(Rational(val)); -} - -Term Solver::mkInteger(uint32_t val) const -{ - return d_exprMgr->mkConst(Rational(val)); -} - -Term Solver::mkInteger(int64_t val) const +Term Solver::mkPi() const { - return d_exprMgr->mkConst(Rational(val)); + try + { + Term res = + d_exprMgr->mkNullaryOperator(d_exprMgr->realType(), CVC4::kind::PI); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } } -Term Solver::mkInteger(uint64_t val) const +template <typename T> +Term Solver::mkConstHelper(T t) const { - return d_exprMgr->mkConst(Rational(val)); + try + { + Term res = d_exprMgr->mkConst(t); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } } -Term Solver::mkPi() const +/* Split out to avoid nested API calls (problematic with API tracing). */ +Term Solver::mkRealFromStrHelper(std::string s) const { - return d_exprMgr->mkNullaryOperator(d_exprMgr->realType(), CVC4::kind::PI); + /* CLN and GMP handle this case differently, CLN interprets it as 0, GMP + * throws an std::invalid_argument exception. For consistency, we treat it + * as invalid. */ + CVC4_API_ARG_CHECK_EXPECTED(s != ".", s) + << "a string representing an integer, real or rational value."; + try + { + CVC4::Rational r = s.find('/') != std::string::npos + ? CVC4::Rational(s) + : CVC4::Rational::fromDecimal(s); + return mkConstHelper<CVC4::Rational>(r); + } + catch (const std::invalid_argument& e) + { + throw CVC4ApiException(e.what()); + } } -Term Solver::mkReal(const char* s, uint32_t base) const +Term Solver::mkReal(const char* s) const { - return d_exprMgr->mkConst(Rational(s, base)); + CVC4_API_ARG_CHECK_NOT_NULL(s); + return mkRealFromStrHelper(std::string(s)); } -Term Solver::mkReal(const std::string& s, uint32_t base) const +Term Solver::mkReal(const std::string& s) const { - return d_exprMgr->mkConst(Rational(s, base)); + return mkRealFromStrHelper(s); } Term Solver::mkReal(int32_t val) const { - return d_exprMgr->mkConst(Rational(val)); + try + { + return mkConstHelper<CVC4::Rational>(CVC4::Rational(val)); + } + catch (const std::invalid_argument& e) + { + throw CVC4ApiException(e.what()); + } } Term Solver::mkReal(int64_t val) const { - return d_exprMgr->mkConst(Rational(val)); + try + { + return mkConstHelper<CVC4::Rational>(CVC4::Rational(val)); + } + catch (const std::invalid_argument& e) + { + throw CVC4ApiException(e.what()); + } } Term Solver::mkReal(uint32_t val) const { - return d_exprMgr->mkConst(Rational(val)); + try + { + return mkConstHelper<CVC4::Rational>(CVC4::Rational(val)); + } + catch (const std::invalid_argument& e) + { + throw CVC4ApiException(e.what()); + } } Term Solver::mkReal(uint64_t val) const { - return d_exprMgr->mkConst(Rational(val)); + try + { + return mkConstHelper<CVC4::Rational>(CVC4::Rational(val)); + } + catch (const std::invalid_argument& e) + { + throw CVC4ApiException(e.what()); + } } Term Solver::mkReal(int32_t num, int32_t den) const { - return d_exprMgr->mkConst(Rational(num, den)); + try + { + return mkConstHelper<CVC4::Rational>(CVC4::Rational(num, den)); + } + catch (const std::invalid_argument& e) + { + throw CVC4ApiException(e.what()); + } } Term Solver::mkReal(int64_t num, int64_t den) const { - return d_exprMgr->mkConst(Rational(num, den)); + try + { + return mkConstHelper<CVC4::Rational>(CVC4::Rational(num, den)); + } + catch (const std::invalid_argument& e) + { + throw CVC4ApiException(e.what()); + } } Term Solver::mkReal(uint32_t num, uint32_t den) const { - return d_exprMgr->mkConst(Rational(num, den)); + try + { + return mkConstHelper<CVC4::Rational>(CVC4::Rational(num, den)); + } + catch (const std::invalid_argument& e) + { + throw CVC4ApiException(e.what()); + } } Term Solver::mkReal(uint64_t num, uint64_t den) const { - return d_exprMgr->mkConst(Rational(num, den)); + try + { + return mkConstHelper<CVC4::Rational>(CVC4::Rational(num, den)); + } + catch (const std::invalid_argument& e) + { + throw CVC4ApiException(e.what()); + } } Term Solver::mkRegexpEmpty() const { - return d_exprMgr->mkExpr(CVC4::kind::REGEXP_EMPTY, std::vector<Expr>()); + try + { + Term res = + d_exprMgr->mkExpr(CVC4::kind::REGEXP_EMPTY, std::vector<CVC4::Expr>()); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } } Term Solver::mkRegexpSigma() const { - return d_exprMgr->mkExpr(CVC4::kind::REGEXP_SIGMA, std::vector<Expr>()); + try + { + Term res = + d_exprMgr->mkExpr(CVC4::kind::REGEXP_SIGMA, std::vector<CVC4::Expr>()); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } } Term Solver::mkEmptySet(Sort s) const { - return d_exprMgr->mkConst(EmptySet(*s.d_type)); + CVC4_API_ARG_CHECK_EXPECTED(s.isNull() || s.isSet(), s) + << "null sort or set sort"; + return mkConstHelper<CVC4::EmptySet>(CVC4::EmptySet(*s.d_type)); } Term Solver::mkSepNil(Sort sort) const { - return d_exprMgr->mkNullaryOperator(*sort.d_type, CVC4::kind::SEP_NIL); + try + { + CVC4_API_ARG_CHECK_EXPECTED(!sort.isNull(), sort) << "non-null sort"; + Term res = d_exprMgr->mkNullaryOperator(*sort.d_type, CVC4::kind::SEP_NIL); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } } -Term Solver::mkString(const char* s) const +Term Solver::mkString(const char* s, bool useEscSequences) const { - return d_exprMgr->mkConst(String(s)); + return mkConstHelper<CVC4::String>(CVC4::String(s, useEscSequences)); } -Term Solver::mkString(const std::string& s) const +Term Solver::mkString(const std::string& s, bool useEscSequences) const { - return d_exprMgr->mkConst(String(s)); + return mkConstHelper<CVC4::String>(CVC4::String(s, useEscSequences)); } Term Solver::mkString(const unsigned char c) const { - return d_exprMgr->mkConst(String(std::string(1, c))); + return mkConstHelper<CVC4::String>(CVC4::String(std::string(1, c))); } Term Solver::mkString(const std::vector<unsigned>& s) const { - return d_exprMgr->mkConst(String(s)); + return mkConstHelper<CVC4::String>(CVC4::String(s)); } Term Solver::mkUniverseSet(Sort sort) const { - return d_exprMgr->mkNullaryOperator(*sort.d_type, CVC4::kind::UNIVERSE_SET); + try + { + CVC4_API_ARG_CHECK_EXPECTED(!sort.isNull(), sort) << "non-null sort"; + Term res = + d_exprMgr->mkNullaryOperator(*sort.d_type, CVC4::kind::UNIVERSE_SET); + // TODO(#2771): Reenable? + // (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } } -Term Solver::mkBitVector(uint32_t size) const +/* Split out to avoid nested API calls (problematic with API tracing). */ +Term Solver::mkBVFromIntHelper(uint32_t size, uint64_t val) const { - return d_exprMgr->mkConst(BitVector(size)); + CVC4_API_ARG_CHECK_EXPECTED(size > 0, size) << "a bit-width > 0"; + try + { + return mkConstHelper<CVC4::BitVector>(CVC4::BitVector(size, val)); + } + catch (const std::invalid_argument& e) + { + throw CVC4ApiException(e.what()); + } } -Term Solver::mkBitVector(uint32_t size, uint32_t val) const +Term Solver::mkBitVector(uint32_t size, uint64_t val) const { - return d_exprMgr->mkConst(BitVector(size, val)); + return mkBVFromIntHelper(size, val); } -Term Solver::mkBitVector(uint32_t size, uint64_t val) const +/* Split out to avoid nested API calls (problematic with API tracing). */ +Term Solver::mkBVFromStrHelper(std::string s, uint32_t base) const { - return d_exprMgr->mkConst(BitVector(size, val)); + CVC4_API_ARG_CHECK_EXPECTED(!s.empty(), s) << "a non-empty string"; + CVC4_API_ARG_CHECK_EXPECTED(base == 2 || base == 10 || base == 16, s) + << "base 2, 10, or 16"; + try + { + return mkConstHelper<CVC4::BitVector>(CVC4::BitVector(s, base)); + } + catch (const std::invalid_argument& e) + { + throw CVC4ApiException(e.what()); + } +} + +Term Solver::mkBVFromStrHelper(uint32_t size, + std::string s, + uint32_t base) const +{ + CVC4_API_ARG_CHECK_EXPECTED(!s.empty(), s) << "a non-empty string"; + CVC4_API_ARG_CHECK_EXPECTED(base == 2 || base == 10 || base == 16, s) + << "base 2, 10, or 16"; + try + { + Integer val(s, base); + CVC4_API_CHECK(val.modByPow2(size) == val) + << "Overflow in bitvector construction (specified bitvector size " + << size << " too small to hold value " << s << ")"; + return mkConstHelper<CVC4::BitVector>(CVC4::BitVector(size, val)); + } + catch (const std::invalid_argument& e) + { + throw CVC4ApiException(e.what()); + } } Term Solver::mkBitVector(const char* s, uint32_t base) const { - return d_exprMgr->mkConst(BitVector(s, base)); + CVC4_API_ARG_CHECK_NOT_NULL(s); + return mkBVFromStrHelper(std::string(s), base); } -Term Solver::mkBitVector(std::string& s, uint32_t base) const +Term Solver::mkBitVector(const std::string& s, uint32_t base) const { - return d_exprMgr->mkConst(BitVector(s, base)); + return mkBVFromStrHelper(s, base); } -Term Solver::mkConst(RoundingMode rm) const +Term Solver::mkBitVector(uint32_t size, const char* s, uint32_t base) const { - return d_exprMgr->mkConst(s_rmodes.at(rm)); + CVC4_API_ARG_CHECK_NOT_NULL(s); + return mkBVFromStrHelper(size, s, base); } -Term Solver::mkConst(Kind kind, Sort arg) const +Term Solver::mkBitVector(uint32_t size, std::string& s, uint32_t base) const { - CVC4_API_KIND_CHECK_EXPECTED(kind == EMPTYSET, kind) << "EMPTY_SET"; - return d_exprMgr->mkConst(CVC4::EmptySet(*arg.d_type)); + return mkBVFromStrHelper(size, s, base); } -Term Solver::mkConst(Kind kind, Sort arg1, int32_t arg2) const +Term Solver::mkPosInf(uint32_t exp, uint32_t sig) const { - CVC4_API_KIND_CHECK_EXPECTED(kind == UNINTERPRETED_CONSTANT, kind) - << "UNINTERPRETED_CONSTANT"; - return d_exprMgr->mkConst(CVC4::UninterpretedConstant(*arg1.d_type, arg2)); + CVC4_API_CHECK(Configuration::isBuiltWithSymFPU()) + << "Expected CVC4 to be compiled with SymFPU support"; + return mkConstHelper<CVC4::FloatingPoint>( + FloatingPoint::makeInf(FloatingPointSize(exp, sig), false)); } -Term Solver::mkConst(Kind kind, bool arg) const +Term Solver::mkNegInf(uint32_t exp, uint32_t sig) const { - CVC4_API_KIND_CHECK_EXPECTED(kind == CONST_BOOLEAN, kind) << "CONST_BOOLEAN"; - return d_exprMgr->mkConst<bool>(arg); + CVC4_API_CHECK(Configuration::isBuiltWithSymFPU()) + << "Expected CVC4 to be compiled with SymFPU support"; + return mkConstHelper<CVC4::FloatingPoint>( + FloatingPoint::makeInf(FloatingPointSize(exp, sig), true)); } -Term Solver::mkConst(Kind kind, const char* arg) const +Term Solver::mkNaN(uint32_t exp, uint32_t sig) const { - CVC4_API_KIND_CHECK_EXPECTED(kind == CONST_STRING, kind) << "CONST_STRING"; - return d_exprMgr->mkConst(CVC4::String(arg)); + CVC4_API_CHECK(Configuration::isBuiltWithSymFPU()) + << "Expected CVC4 to be compiled with SymFPU support"; + return mkConstHelper<CVC4::FloatingPoint>( + FloatingPoint::makeNaN(FloatingPointSize(exp, sig))); } -Term Solver::mkConst(Kind kind, const std::string& arg) const +Term Solver::mkPosZero(uint32_t exp, uint32_t sig) const { - CVC4_API_KIND_CHECK_EXPECTED(kind == CONST_STRING, kind) << "CONST_STRING"; - return d_exprMgr->mkConst(CVC4::String(arg)); + CVC4_API_CHECK(Configuration::isBuiltWithSymFPU()) + << "Expected CVC4 to be compiled with SymFPU support"; + return mkConstHelper<CVC4::FloatingPoint>( + FloatingPoint::makeZero(FloatingPointSize(exp, sig), false)); } -Term Solver::mkConst(Kind kind, const char* arg1, uint32_t arg2) const +Term Solver::mkNegZero(uint32_t exp, uint32_t sig) const { - CVC4_API_KIND_CHECK_EXPECTED(kind == ABSTRACT_VALUE || kind == CONST_RATIONAL - || kind == CONST_BITVECTOR, - kind) - << "ABSTRACT_VALUE or CONST_RATIONAL or CONST_BITVECTOR"; - if (kind == ABSTRACT_VALUE) - { - return d_exprMgr->mkConst(CVC4::AbstractValue(Integer(arg1, arg2))); - } - if (kind == CONST_RATIONAL) - { - return d_exprMgr->mkConst(CVC4::Rational(arg1, arg2)); - } - return d_exprMgr->mkConst(CVC4::BitVector(arg1, arg2)); + CVC4_API_CHECK(Configuration::isBuiltWithSymFPU()) + << "Expected CVC4 to be compiled with SymFPU support"; + return mkConstHelper<CVC4::FloatingPoint>( + FloatingPoint::makeZero(FloatingPointSize(exp, sig), true)); } -Term Solver::mkConst(Kind kind, const std::string& arg1, uint32_t arg2) const +Term Solver::mkRoundingMode(RoundingMode rm) const { - CVC4_API_KIND_CHECK_EXPECTED(kind == ABSTRACT_VALUE || kind == CONST_RATIONAL - || kind == CONST_BITVECTOR, - kind) - << "ABSTRACT_VALUE or CONST_RATIONAL or CONST_BITVECTOR"; - if (kind == ABSTRACT_VALUE) - { - return d_exprMgr->mkConst(CVC4::AbstractValue(Integer(arg1, arg2))); - } - if (kind == CONST_RATIONAL) - { - return d_exprMgr->mkConst(CVC4::Rational(arg1, arg2)); - } - return d_exprMgr->mkConst(CVC4::BitVector(arg1, arg2)); + return mkConstHelper<CVC4::RoundingMode>(s_rmodes.at(rm)); } -Term Solver::mkConst(Kind kind, uint32_t arg) const +Term Solver::mkUninterpretedConst(Sort sort, int32_t index) const { - CVC4_API_KIND_CHECK_EXPECTED(kind == ABSTRACT_VALUE || kind == CONST_RATIONAL - || kind == CONST_BITVECTOR, - kind) - << "ABSTRACT_VALUE or CONST_RATIONAL or CONST_BITVECTOR"; - if (kind == ABSTRACT_VALUE) + CVC4_API_ARG_CHECK_EXPECTED(!sort.isNull(), sort) << "non-null sort"; + return mkConstHelper<CVC4::UninterpretedConstant>( + CVC4::UninterpretedConstant(*sort.d_type, index)); +} + +Term Solver::mkAbstractValue(const std::string& index) const +{ + CVC4_API_ARG_CHECK_EXPECTED(!index.empty(), index) << "a non-empty string"; + try { - return d_exprMgr->mkConst(CVC4::AbstractValue(Integer(arg))); + CVC4::Integer idx(index, 10); + CVC4_API_ARG_CHECK_EXPECTED(idx > 0, index) + << "a string representing an integer > 0"; + return d_exprMgr->mkConst(CVC4::AbstractValue(idx)); + // do not call getType(), for abstract values, type can not be computed + // until it is substituted away } - if (kind == CONST_RATIONAL) + catch (const std::invalid_argument& e) { - return d_exprMgr->mkConst(CVC4::Rational(arg)); + throw CVC4ApiException(e.what()); } - return d_exprMgr->mkConst(CVC4::BitVector(arg)); -} - -Term Solver::mkConst(Kind kind, int32_t arg) const -{ - CVC4_API_KIND_CHECK_EXPECTED(kind == ABSTRACT_VALUE || kind == CONST_RATIONAL, - kind) - << "ABSTRACT_VALUE or CONST_RATIONAL"; - if (kind == ABSTRACT_VALUE) + catch (const CVC4::TypeCheckingException& e) { - return d_exprMgr->mkConst(CVC4::AbstractValue(Integer(arg))); + throw CVC4ApiException(e.getMessage()); } - return d_exprMgr->mkConst(CVC4::Rational(arg)); } -Term Solver::mkConst(Kind kind, int64_t arg) const +Term Solver::mkAbstractValue(uint64_t index) const { - CVC4_API_KIND_CHECK_EXPECTED(kind == ABSTRACT_VALUE || kind == CONST_RATIONAL, - kind) - << "ABSTRACT_VALUE or CONST_RATIONAL"; - if (kind == ABSTRACT_VALUE) + try { - return d_exprMgr->mkConst(CVC4::AbstractValue(Integer(arg))); + CVC4_API_ARG_CHECK_EXPECTED(index > 0, index) << "an integer > 0"; + return d_exprMgr->mkConst(CVC4::AbstractValue(Integer(index))); + // do not call getType(), for abstract values, type can not be computed + // until it is substituted away } - return d_exprMgr->mkConst(CVC4::Rational(arg)); -} - -Term Solver::mkConst(Kind kind, uint64_t arg) const -{ - CVC4_API_KIND_CHECK_EXPECTED(kind == ABSTRACT_VALUE || kind == CONST_RATIONAL, - kind) - << "ABSTRACT_VALUE or CONST_RATIONAL"; - if (kind == ABSTRACT_VALUE) + catch (const std::invalid_argument& e) { - return d_exprMgr->mkConst(CVC4::AbstractValue(Integer(arg))); + throw CVC4ApiException(e.what()); + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); } - return d_exprMgr->mkConst(CVC4::Rational(arg)); -} - -Term Solver::mkConst(Kind kind, uint32_t arg1, uint32_t arg2) const -{ - CVC4_API_KIND_CHECK_EXPECTED(kind == CONST_RATIONAL, kind) - << "CONST_RATIONAL"; - return d_exprMgr->mkConst(CVC4::Rational(arg1, arg2)); -} - -Term Solver::mkConst(Kind kind, int32_t arg1, int32_t arg2) const -{ - CVC4_API_KIND_CHECK_EXPECTED(kind == CONST_RATIONAL, kind) - << "CONST_RATIONAL"; - return d_exprMgr->mkConst(CVC4::Rational(arg1, arg2)); -} - -Term Solver::mkConst(Kind kind, int64_t arg1, int64_t arg2) const -{ - CVC4_API_KIND_CHECK_EXPECTED(kind == CONST_RATIONAL, kind) - << "CONST_RATIONAL"; - return d_exprMgr->mkConst(CVC4::Rational(arg1, arg2)); -} - -Term Solver::mkConst(Kind kind, uint64_t arg1, uint64_t arg2) const -{ - CVC4_API_KIND_CHECK_EXPECTED(kind == CONST_RATIONAL, kind) - << "CONST_RATIONAL"; - return d_exprMgr->mkConst(CVC4::Rational(arg1, arg2)); -} - -Term Solver::mkConst(Kind kind, uint32_t arg1, uint64_t arg2) const -{ - CVC4_API_KIND_CHECK_EXPECTED(kind == CONST_BITVECTOR, kind) - << "CONST_BITVECTOR"; - return d_exprMgr->mkConst(CVC4::BitVector(arg1, arg2)); } -Term Solver::mkConst(Kind kind, uint32_t arg1, uint32_t arg2, Term arg3) const +Term Solver::mkFloatingPoint(uint32_t exp, uint32_t sig, Term val) const { - CVC4_API_KIND_CHECK_EXPECTED(kind == CONST_FLOATINGPOINT, kind) - << "CONST_FLOATINGPOINT"; + CVC4_API_CHECK(Configuration::isBuiltWithSymFPU()) + << "Expected CVC4 to be compiled with SymFPU support"; + CVC4_API_ARG_CHECK_EXPECTED(exp > 0, exp) << "a value > 0"; + CVC4_API_ARG_CHECK_EXPECTED(sig > 0, sig) << "a value > 0"; + uint32_t bw = exp + sig; + CVC4_API_ARG_CHECK_EXPECTED(bw == val.getSort().getBVSize(), val) + << "a bit-vector constant with bit-width '" << bw << "'"; + CVC4_API_ARG_CHECK_EXPECTED(!val.isNull(), val) << "non-null term"; CVC4_API_ARG_CHECK_EXPECTED( - arg3.getSort().isBitVector() && arg3.d_expr->isConst(), arg3) + val.getSort().isBitVector() && val.d_expr->isConst(), val) << "bit-vector constant"; - return d_exprMgr->mkConst( - CVC4::FloatingPoint(arg1, arg2, arg3.d_expr->getConst<BitVector>())); + return mkConstHelper<CVC4::FloatingPoint>( + CVC4::FloatingPoint(exp, sig, val.d_expr->getConst<BitVector>())); } /* Create variables */ @@ -2202,19 +2379,62 @@ Term Solver::mkConst(Kind kind, uint32_t arg1, uint32_t arg2, Term arg3) const Term Solver::mkVar(const std::string& symbol, Sort sort) const { - return d_exprMgr->mkVar(symbol, *sort.d_type); + try + { + CVC4_API_ARG_CHECK_EXPECTED(!sort.isNull(), sort) << "non-null sort"; + Term res = d_exprMgr->mkVar(symbol, *sort.d_type); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } } -Term Solver::mkVar(Sort sort) const { return d_exprMgr->mkVar(*sort.d_type); } +Term Solver::mkVar(Sort sort) const +{ + try + { + CVC4_API_ARG_CHECK_EXPECTED(!sort.isNull(), sort) << "non-null sort"; + Term res = d_exprMgr->mkVar(*sort.d_type); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } +} Term Solver::mkBoundVar(const std::string& symbol, Sort sort) const { - return d_exprMgr->mkBoundVar(symbol, *sort.d_type); + try + { + CVC4_API_ARG_CHECK_EXPECTED(!sort.isNull(), sort) << "non-null sort"; + Term res = d_exprMgr->mkBoundVar(symbol, *sort.d_type); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } } Term Solver::mkBoundVar(Sort sort) const { - return d_exprMgr->mkBoundVar(*sort.d_type); + try + { + CVC4_API_ARG_CHECK_EXPECTED(!sort.isNull(), sort) << "non-null sort"; + Term res = d_exprMgr->mkBoundVar(*sort.d_type); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } } /* Create terms */ @@ -2269,88 +2489,218 @@ void Solver::checkMkOpTerm(OpTerm opTerm, uint32_t nchildren) const Term Solver::mkTerm(Kind kind) const { - CVC4_API_KIND_CHECK_EXPECTED( - kind == PI || kind == REGEXP_EMPTY || kind == REGEXP_SIGMA, kind) - << "PI or REGEXP_EMPTY or REGEXP_SIGMA"; - if (kind == REGEXP_EMPTY || kind == REGEXP_SIGMA) + try { - CVC4::Kind k = extToIntKind(kind); - Assert(isDefinedIntKind(k)); - return d_exprMgr->mkExpr(k, std::vector<Expr>()); + CVC4_API_KIND_CHECK_EXPECTED( + kind == PI || kind == REGEXP_EMPTY || kind == REGEXP_SIGMA, kind) + << "PI or REGEXP_EMPTY or REGEXP_SIGMA"; + Term res; + if (kind == REGEXP_EMPTY || kind == REGEXP_SIGMA) + { + CVC4::Kind k = extToIntKind(kind); + Assert(isDefinedIntKind(k)); + res = d_exprMgr->mkExpr(k, std::vector<Expr>()); + } + else + { + Assert(kind == PI); + res = d_exprMgr->mkNullaryOperator(d_exprMgr->realType(), CVC4::kind::PI); + } + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); } - Assert(kind == PI); - return d_exprMgr->mkNullaryOperator(d_exprMgr->realType(), CVC4::kind::PI); } Term Solver::mkTerm(Kind kind, Sort sort) const { - CVC4_API_KIND_CHECK_EXPECTED(kind == SEP_NIL || kind == UNIVERSE_SET, kind) - << "SEP_NIL or UNIVERSE_SET"; - return d_exprMgr->mkNullaryOperator(*sort.d_type, extToIntKind(kind)); + try + { + CVC4_API_KIND_CHECK_EXPECTED(kind == SEP_NIL, kind) << "SEP_NIL"; + Term res = d_exprMgr->mkNullaryOperator(*sort.d_type, extToIntKind(kind)); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } } Term Solver::mkTerm(Kind kind, Term child) const { - checkMkTerm(kind, 1); - return d_exprMgr->mkExpr(extToIntKind(kind), *child.d_expr); + try + { + CVC4_API_ARG_CHECK_EXPECTED(!child.isNull(), child) << "non-null term"; + checkMkTerm(kind, 1); + Term res = d_exprMgr->mkExpr(extToIntKind(kind), *child.d_expr); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } } Term Solver::mkTerm(Kind kind, Term child1, Term child2) const { - checkMkTerm(kind, 2); - return d_exprMgr->mkExpr(extToIntKind(kind), *child1.d_expr, *child2.d_expr); + try + { + CVC4_API_ARG_CHECK_EXPECTED(!child1.isNull(), child1) << "non-null term"; + CVC4_API_ARG_CHECK_EXPECTED(!child2.isNull(), child2) << "non-null term"; + checkMkTerm(kind, 2); + Term res = + d_exprMgr->mkExpr(extToIntKind(kind), *child1.d_expr, *child2.d_expr); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } } Term Solver::mkTerm(Kind kind, Term child1, Term child2, Term child3) const { - checkMkTerm(kind, 3); - std::vector<Expr> echildren{*child1.d_expr, *child2.d_expr, *child3.d_expr}; - CVC4::Kind k = extToIntKind(kind); - Assert(isDefinedIntKind(k)); - return kind::isAssociative(k) ? d_exprMgr->mkAssociative(k, echildren) - : d_exprMgr->mkExpr(k, echildren); + try + { + CVC4_API_ARG_CHECK_EXPECTED(!child1.isNull(), child1) << "non-null term"; + CVC4_API_ARG_CHECK_EXPECTED(!child2.isNull(), child2) << "non-null term"; + CVC4_API_ARG_CHECK_EXPECTED(!child3.isNull(), child3) << "non-null term"; + checkMkTerm(kind, 3); + std::vector<Expr> echildren{*child1.d_expr, *child2.d_expr, *child3.d_expr}; + CVC4::Kind k = extToIntKind(kind); + Assert(isDefinedIntKind(k)); + Term res = kind::isAssociative(k) ? d_exprMgr->mkAssociative(k, echildren) + : d_exprMgr->mkExpr(k, echildren); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } } Term Solver::mkTerm(Kind kind, const std::vector<Term>& children) const { - checkMkTerm(kind, children.size()); - std::vector<Expr> echildren = termVectorToExprs(children); - CVC4::Kind k = extToIntKind(kind); - Assert(isDefinedIntKind(k)); - return kind::isAssociative(k) ? d_exprMgr->mkAssociative(k, echildren) - : d_exprMgr->mkExpr(k, echildren); -} - -Term Solver::mkTerm(OpTerm opTerm) const -{ - checkMkOpTerm(opTerm, 0); - return d_exprMgr->mkExpr(*opTerm.d_expr); + try + { + for (size_t i = 0, size = children.size(); i < size; ++i) + { + CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED( + !children[i].isNull(), "parameter term", children[i], i) + << "non-null term"; + } + checkMkTerm(kind, children.size()); + std::vector<Expr> echildren = termVectorToExprs(children); + CVC4::Kind k = extToIntKind(kind); + Assert(isDefinedIntKind(k)); + Term res = kind::isAssociative(k) ? d_exprMgr->mkAssociative(k, echildren) + : d_exprMgr->mkExpr(k, echildren); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } } Term Solver::mkTerm(OpTerm opTerm, Term child) const { - checkMkOpTerm(opTerm, 1); - return d_exprMgr->mkExpr(*opTerm.d_expr, *child.d_expr); + try + { + CVC4_API_ARG_CHECK_EXPECTED(!child.isNull(), child) << "non-null term"; + checkMkOpTerm(opTerm, 1); + Term res = d_exprMgr->mkExpr(*opTerm.d_expr, *child.d_expr); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } } Term Solver::mkTerm(OpTerm opTerm, Term child1, Term child2) const { - checkMkOpTerm(opTerm, 2); - return d_exprMgr->mkExpr(*opTerm.d_expr, *child1.d_expr, *child2.d_expr); + try + { + CVC4_API_ARG_CHECK_EXPECTED(!child1.isNull(), child1) << "non-null term"; + CVC4_API_ARG_CHECK_EXPECTED(!child2.isNull(), child2) << "non-null term"; + checkMkOpTerm(opTerm, 2); + Term res = + d_exprMgr->mkExpr(*opTerm.d_expr, *child1.d_expr, *child2.d_expr); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } } Term Solver::mkTerm(OpTerm opTerm, Term child1, Term child2, Term child3) const { - checkMkOpTerm(opTerm, 3); - return d_exprMgr->mkExpr( - *opTerm.d_expr, *child1.d_expr, *child2.d_expr, *child3.d_expr); + try + { + CVC4_API_ARG_CHECK_EXPECTED(!child1.isNull(), child1) << "non-null term"; + CVC4_API_ARG_CHECK_EXPECTED(!child2.isNull(), child2) << "non-null term"; + CVC4_API_ARG_CHECK_EXPECTED(!child3.isNull(), child3) << "non-null term"; + checkMkOpTerm(opTerm, 3); + Term res = d_exprMgr->mkExpr( + *opTerm.d_expr, *child1.d_expr, *child2.d_expr, *child3.d_expr); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } } Term Solver::mkTerm(OpTerm opTerm, const std::vector<Term>& children) const { - checkMkOpTerm(opTerm, children.size()); - std::vector<Expr> echildren = termVectorToExprs(children); - return d_exprMgr->mkExpr(*opTerm.d_expr, echildren); + try + { + for (size_t i = 0, size = children.size(); i < size; ++i) + { + CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED( + !children[i].isNull(), "parameter term", children[i], i) + << "non-null term"; + } + checkMkOpTerm(opTerm, children.size()); + std::vector<Expr> echildren = termVectorToExprs(children); + Term res = d_exprMgr->mkExpr(*opTerm.d_expr, echildren); + (void)res.d_expr->getType(true); /* kick off type checking */ + return res; + } + catch (const CVC4::TypeCheckingException& e) + { + throw CVC4ApiException(e.getMessage()); + } +} + +Term Solver::mkTuple(const std::vector<Sort>& sorts, + const std::vector<Term>& terms) const +{ + CVC4_API_CHECK(sorts.size() == terms.size()) + << "Expected the same number of sorts and elements"; + std::vector<Term> args; + for (size_t i = 0, size = sorts.size(); i < size; i++) + { + args.push_back(ensureTermSort(terms[i], sorts[i])); + } + + Sort s = mkTupleSort(sorts); + Datatype dt = s.getDatatype(); + args.insert(args.begin(), dt[0].getConstructorTerm()); + return mkTerm(APPLY_CONSTRUCTOR, args); } std::vector<Expr> Solver::termVectorToExprs( @@ -2370,14 +2720,15 @@ std::vector<Expr> Solver::termVectorToExprs( OpTerm Solver::mkOpTerm(Kind kind, Kind k) { CVC4_API_KIND_CHECK_EXPECTED(kind == CHAIN_OP, kind) << "CHAIN_OP"; - return d_exprMgr->mkConst(CVC4::Chain(extToIntKind(k))); + return *mkConstHelper<CVC4::Chain>(CVC4::Chain(extToIntKind(k))).d_expr.get(); } OpTerm Solver::mkOpTerm(Kind kind, const std::string& arg) { CVC4_API_KIND_CHECK_EXPECTED(kind == RECORD_UPDATE_OP, kind) << "RECORD_UPDATE_OP"; - return d_exprMgr->mkConst(CVC4::RecordUpdate(arg)); + return *mkConstHelper<CVC4::RecordUpdate>(CVC4::RecordUpdate(arg)) + .d_expr.get(); } OpTerm Solver::mkOpTerm(Kind kind, uint32_t arg) @@ -2386,39 +2737,60 @@ OpTerm Solver::mkOpTerm(Kind kind, uint32_t arg) OpTerm res; switch (kind) { - case DIVISIBLE_OP: res = d_exprMgr->mkConst(CVC4::Divisible(arg)); break; + case DIVISIBLE_OP: + res = *mkConstHelper<CVC4::Divisible>(CVC4::Divisible(arg)).d_expr.get(); + break; case BITVECTOR_REPEAT_OP: - res = d_exprMgr->mkConst(CVC4::BitVectorRepeat(arg)); + res = *mkConstHelper<CVC4::BitVectorRepeat>(CVC4::BitVectorRepeat(arg)) + .d_expr.get(); break; case BITVECTOR_ZERO_EXTEND_OP: - res = d_exprMgr->mkConst(CVC4::BitVectorZeroExtend(arg)); + res = *mkConstHelper<CVC4::BitVectorZeroExtend>( + CVC4::BitVectorZeroExtend(arg)) + .d_expr.get(); break; case BITVECTOR_SIGN_EXTEND_OP: - res = d_exprMgr->mkConst(CVC4::BitVectorSignExtend(arg)); + res = *mkConstHelper<CVC4::BitVectorSignExtend>( + CVC4::BitVectorSignExtend(arg)) + .d_expr.get(); break; case BITVECTOR_ROTATE_LEFT_OP: - res = d_exprMgr->mkConst(CVC4::BitVectorRotateLeft(arg)); + res = *mkConstHelper<CVC4::BitVectorRotateLeft>( + CVC4::BitVectorRotateLeft(arg)) + .d_expr.get(); break; case BITVECTOR_ROTATE_RIGHT_OP: - res = d_exprMgr->mkConst(CVC4::BitVectorRotateRight(arg)); + res = *mkConstHelper<CVC4::BitVectorRotateRight>( + CVC4::BitVectorRotateRight(arg)) + .d_expr.get(); break; case INT_TO_BITVECTOR_OP: - res = d_exprMgr->mkConst(CVC4::IntToBitVector(arg)); + res = *mkConstHelper<CVC4::IntToBitVector>(CVC4::IntToBitVector(arg)) + .d_expr.get(); break; case FLOATINGPOINT_TO_UBV_OP: - res = d_exprMgr->mkConst(CVC4::FloatingPointToUBV(arg)); + res = *mkConstHelper<CVC4::FloatingPointToUBV>( + CVC4::FloatingPointToUBV(arg)) + .d_expr.get(); break; case FLOATINGPOINT_TO_UBV_TOTAL_OP: - res = d_exprMgr->mkConst(CVC4::FloatingPointToUBVTotal(arg)); + res = *mkConstHelper<CVC4::FloatingPointToUBVTotal>( + CVC4::FloatingPointToUBVTotal(arg)) + .d_expr.get(); break; case FLOATINGPOINT_TO_SBV_OP: - res = d_exprMgr->mkConst(CVC4::FloatingPointToSBV(arg)); + res = *mkConstHelper<CVC4::FloatingPointToSBV>( + CVC4::FloatingPointToSBV(arg)) + .d_expr.get(); break; case FLOATINGPOINT_TO_SBV_TOTAL_OP: - res = d_exprMgr->mkConst(CVC4::FloatingPointToSBVTotal(arg)); + res = *mkConstHelper<CVC4::FloatingPointToSBVTotal>( + CVC4::FloatingPointToSBVTotal(arg)) + .d_expr.get(); break; case TUPLE_UPDATE_OP: - res = d_exprMgr->mkConst(CVC4::TupleUpdate(arg)); + res = *mkConstHelper<CVC4::TupleUpdate>(CVC4::TupleUpdate(arg)) + .d_expr.get(); break; default: CVC4_API_KIND_CHECK_EXPECTED(false, kind) @@ -2435,29 +2807,39 @@ OpTerm Solver::mkOpTerm(Kind kind, uint32_t arg1, uint32_t arg2) switch (kind) { case BITVECTOR_EXTRACT_OP: - res = d_exprMgr->mkConst(CVC4::BitVectorExtract(arg1, arg2)); + res = *mkConstHelper<CVC4::BitVectorExtract>( + CVC4::BitVectorExtract(arg1, arg2)) + .d_expr.get(); break; case FLOATINGPOINT_TO_FP_IEEE_BITVECTOR_OP: - res = - d_exprMgr->mkConst(CVC4::FloatingPointToFPIEEEBitVector(arg1, arg2)); + res = *mkConstHelper<CVC4::FloatingPointToFPIEEEBitVector>( + CVC4::FloatingPointToFPIEEEBitVector(arg1, arg2)) + .d_expr.get(); break; case FLOATINGPOINT_TO_FP_FLOATINGPOINT_OP: - res = - d_exprMgr->mkConst(CVC4::FloatingPointToFPFloatingPoint(arg1, arg2)); + res = *mkConstHelper<CVC4::FloatingPointToFPFloatingPoint>( + CVC4::FloatingPointToFPFloatingPoint(arg1, arg2)) + .d_expr.get(); break; case FLOATINGPOINT_TO_FP_REAL_OP: - res = d_exprMgr->mkConst(CVC4::FloatingPointToFPReal(arg1, arg2)); + res = *mkConstHelper<CVC4::FloatingPointToFPReal>( + CVC4::FloatingPointToFPReal(arg1, arg2)) + .d_expr.get(); break; case FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR_OP: - res = d_exprMgr->mkConst( - CVC4::FloatingPointToFPSignedBitVector(arg1, arg2)); + res = *mkConstHelper<CVC4::FloatingPointToFPSignedBitVector>( + CVC4::FloatingPointToFPSignedBitVector(arg1, arg2)) + .d_expr.get(); break; case FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR_OP: - res = d_exprMgr->mkConst( - CVC4::FloatingPointToFPUnsignedBitVector(arg1, arg2)); + res = *mkConstHelper<CVC4::FloatingPointToFPUnsignedBitVector>( + CVC4::FloatingPointToFPUnsignedBitVector(arg1, arg2)) + .d_expr.get(); break; case FLOATINGPOINT_TO_FP_GENERIC_OP: - res = d_exprMgr->mkConst(CVC4::FloatingPointToFPGeneric(arg1, arg2)); + res = *mkConstHelper<CVC4::FloatingPointToFPGeneric>( + CVC4::FloatingPointToFPGeneric(arg1, arg2)) + .d_expr.get(); break; default: CVC4_API_KIND_CHECK_EXPECTED(false, kind) @@ -2993,26 +3375,70 @@ void Solver::reset(void) const { d_smtEngine->reset(); } */ void Solver::resetAssertions(void) const { d_smtEngine->resetAssertions(); } +// TODO: issue #2781 +void Solver::setLogicHelper(const std::string& logic) const +{ + CVC4_API_CHECK(!d_smtEngine->isFullyInited()) + << "Invalid call to 'setLogic', solver is already fully initialized"; + try + { + CVC4::LogicInfo logic_info(logic); + d_smtEngine->setLogic(logic_info); + } + catch (CVC4::IllegalArgumentException& e) + { + throw CVC4ApiException(e.getMessage()); + } +} + /** * ( set-info <attribute> ) */ void Solver::setInfo(const std::string& keyword, const std::string& value) const { - // CHECK: - // if keyword == "cvc4-logic": value must be string - // if keyword == "status": must be sat, unsat or unknown - // if keyword == "smt-lib-version": supported? + bool is_cvc4_keyword = false; + + /* Check for CVC4-specific info keys (prefixed with "cvc4-" or "cvc4_") */ + if (keyword.length() > 5) + { + std::string prefix = keyword.substr(0, 5); + if (prefix == "cvc4-" || prefix == "cvc4_") + { + is_cvc4_keyword = true; + std::string cvc4key = keyword.substr(5); + CVC4_API_ARG_CHECK_EXPECTED(cvc4key == "logic", keyword) + << "keyword 'cvc4-logic'"; + setLogicHelper(value); + } + } + if (!is_cvc4_keyword) + { + CVC4_API_ARG_CHECK_EXPECTED( + keyword == "source" || keyword == "category" || keyword == "difficulty" + || keyword == "filename" || keyword == "license" + || keyword == "name" || keyword == "notes" + || keyword == "smt-lib-version" || keyword == "status", + keyword) + << "'source', 'category', 'difficulty', 'filename', 'license', 'name', " + "'notes', 'smt-lib-version' or 'status'"; + CVC4_API_ARG_CHECK_EXPECTED(keyword != "smt-lib-version" || value == "2" + || value == "2.0" || value == "2.5" + || value == "2.6" || value == "2.6.1", + value) + << "'2.0', '2.5', '2.6' or '2.6.1'"; + CVC4_API_ARG_CHECK_EXPECTED(keyword != "status" || value == "sat" + || value == "unsat" || value == "unknown", + value) + << "'sat', 'unsat' or 'unknown'"; + } + d_smtEngine->setInfo(keyword, value); } /** * ( set-logic <symbol> ) */ -void Solver::setLogic(const std::string& logic) const -{ - // CHECK: !d_smtEngine->d_fullyInited - d_smtEngine->setLogic(logic); -} +void Solver::setLogic(const std::string& logic) const { setLogicHelper(logic); } /** * ( set-option <option> ) @@ -3020,9 +3446,41 @@ void Solver::setLogic(const std::string& logic) const void Solver::setOption(const std::string& option, const std::string& value) const { - // CHECK: option exists? - // CHECK: !d_smtEngine->d_fullInited, else option can't be set - d_smtEngine->setOption(option, value); + CVC4_API_CHECK(!d_smtEngine->isFullyInited()) + << "Invalid call to 'setOption', solver is already fully initialized"; + try + { + d_smtEngine->setOption(option, value); + } + catch (CVC4::OptionException& e) + { + throw CVC4ApiException(e.getMessage()); + } +} + +Term Solver::ensureTermSort(const Term& t, const Sort& s) const +{ + CVC4_API_CHECK(t.getSort() == s || (t.getSort().isInteger() && s.isReal())) + << "Expected conversion from Int to Real"; + + if (t.getSort() == s) + { + return t; + } + + // Integers are reals, too + Assert(t.getSort().isReal()); + Term res = t; + if (t.getSort().isInteger()) + { + // Must cast to Real to ensure correct type is passed to parametric type + // constructors. We do this cast using division with 1. This has the + // advantage wrt using TO_REAL since (constant) division is always included + // in the theory. + res = mkTerm(DIVISION, *t.d_expr, mkReal(1)); + } + Assert(res.getSort() == s); + return res; } /** diff --git a/src/api/cvc4cpp.h b/src/api/cvc4cpp.h index d06955a05..a06f2e415 100644 --- a/src/api/cvc4cpp.h +++ b/src/api/cvc4cpp.h @@ -24,8 +24,8 @@ #include <map> #include <memory> #include <set> -#include <string> #include <sstream> +#include <string> #include <unordered_map> #include <unordered_set> #include <vector> @@ -53,9 +53,10 @@ class CVC4_PUBLIC CVC4ApiException : public std::exception { public: CVC4ApiException(const std::string& str) : d_msg(str) {} - CVC4ApiException(const std::stringstream& stream) :d_msg(stream.str()) {} + CVC4ApiException(const std::stringstream& stream) : d_msg(stream.str()) {} std::string getMessage() const { return d_msg; } const char* what() const noexcept override { return d_msg.c_str(); } + private: std::string d_msg; }; @@ -192,6 +193,11 @@ class CVC4_PUBLIC Sort Sort(const CVC4::Type& t); /** + * Constructor. + */ + Sort(); + + /** * Destructor. */ ~Sort(); @@ -211,6 +217,11 @@ class CVC4_PUBLIC Sort bool operator!=(const Sort& s) const; /** + * @return true if this Sort is a null sort. + */ + bool isNull() const; + + /** * Is this a Boolean sort? * @return true if the sort is a Boolean sort */ @@ -1125,7 +1136,7 @@ class CVC4_PUBLIC DatatypeConstructor /** * Constructor. * @param ctor the internal datatype constructor to be wrapped - * @return thte DatatypeConstructor + * @return the DatatypeConstructor */ DatatypeConstructor(const CVC4::DatatypeConstructor& ctor); @@ -1135,6 +1146,17 @@ class CVC4_PUBLIC DatatypeConstructor ~DatatypeConstructor(); /** + * @return true if this datatype constructor has been resolved. + */ + bool isResolved() const; + + /** + * Get the constructor operator of this datatype constructor. + * @return the constructor operator + */ + Term getConstructorTerm() const; + + /** * Get the datatype selector with the given name. * This is a linear search through the selectors, so in case of * multiple, similarly-named selectors, the first is returned. @@ -1276,6 +1298,13 @@ class CVC4_PUBLIC Datatype ~Datatype(); /** + * Get the datatype constructor at a given index. + * @param idx the index of the datatype constructor to return + * @return the datatype constructor with the given index + */ + DatatypeConstructor operator[](size_t idx) const; + + /** * Get the datatype constructor with the given name. * This is a linear search through the constructors, so in case of multiple, * similarly-named constructors, the first is returned. @@ -1511,6 +1540,11 @@ class CVC4_PUBLIC Solver /* .................................................................... */ /** + * @return sort null + */ + Sort getNullSort() const; + + /** * @return sort Boolean */ Sort getBooleanSort() const; @@ -1691,14 +1725,6 @@ class CVC4_PUBLIC Solver Term mkTerm(Kind kind, const std::vector<Term>& children) const; /** - * Create term with no children from a given operator term. - * Create operator terms with mkOpTerm(). - * @param the operator term - * @return the Term - */ - Term mkTerm(OpTerm opTerm) const; - - /** * Create unary term from a given operator term. * Create operator terms with mkOpTerm(). * @param the operator term @@ -1737,6 +1763,16 @@ class CVC4_PUBLIC Solver */ Term mkTerm(OpTerm opTerm, const std::vector<Term>& children) const; + /** + * Create a tuple term. Terms are automatically converted if sorts are + * compatible. + * @param sorts The sorts of the elements in the tuple + * @param terms The elements in the tuple + * @return the tuple Term + */ + Term mkTuple(const std::vector<Sort>& sorts, + const std::vector<Term>& terms) const; + /* .................................................................... */ /* Create Operator Terms */ /* .................................................................... */ @@ -1819,128 +1855,84 @@ class CVC4_PUBLIC Solver Term mkBoolean(bool val) const; /** - * Create an Integer constant. - * @param s the string represetntation of the constant - * @param base the base of the string representation - * @return the Integer constant - */ - Term mkInteger(const char* s, uint32_t base = 10) const; - - /** - * Create an Integer constant. - * @param s the string represetntation of the constant - * @param base the base of the string representation - * @return the Integer constant - */ - Term mkInteger(const std::string& s, uint32_t base = 10) const; - - /** - * Create an Integer constant. - * @param val the value of the constant - * @return the Integer constant - */ - Term mkInteger(int32_t val) const; - - /** - * Create an Integer constant. - * @param val the value of the constant - * @return the Integer constant - */ - Term mkInteger(uint32_t val) const; - - /** - * Create an Integer constant. - * @param val the value of the constant - * @return the Integer constant - */ - Term mkInteger(int64_t val) const; - - /** - * Create an Integer constant. - * @param val the value of the constant - * @return the Integer constant - */ - Term mkInteger(uint64_t val) const; - - /** * Create a constant representing the number Pi. * @return a constant representing Pi */ Term mkPi() const; /** - * Create an Real constant. - * @param s the string represetntation of the constant - * @param base the base of the string representation - * @return the Real constant + * Create a real constant from a string. + * @param s the string representation of the constant, may represent an + * integer (e.g., "123") or real constant (e.g., "12.34" or "12/34"). + * @return a constant of sort Real or Integer (if 's' represents an integer) */ - Term mkReal(const char* s, uint32_t base = 10) const; + Term mkReal(const char* s) const; /** - * Create an Real constant. - * @param s the string represetntation of the constant - * @param base the base of the string representation - * @return the Real constant + * Create a real constant from a string. + * @param s the string representation of the constant, may represent an + * integer (e.g., "123") or real constant (e.g., "12.34" or "12/34"). + * @return a constant of sort Real or Integer (if 's' represents an integer) */ - Term mkReal(const std::string& s, uint32_t base = 10) const; + Term mkReal(const std::string& s) const; /** - * Create an Real constant. + * Create a real constant from an integer. * @param val the value of the constant - * @return the Real constant + * @return a constant of sort Integer */ Term mkReal(int32_t val) const; /** - * Create an Real constant. + * Create a real constant from an integer. * @param val the value of the constant - * @return the Real constant + * @return a constant of sort Integer */ Term mkReal(int64_t val) const; /** - * Create an Real constant. + * Create a real constant from an unsigned integer. * @param val the value of the constant - * @return the Real constant + * @return a constant of sort Integer */ Term mkReal(uint32_t val) const; /** - * Create an Real constant. + * Create a real constant from an unsigned integer. * @param val the value of the constant - * @return the Real constant + * @return a constant of sort Integer */ Term mkReal(uint64_t val) const; /** - * Create an Rational constant. + * Create a real constant from a rational. * @param num the value of the numerator * @param den the value of the denominator - * @return the Rational constant + * @return a constant of sort Real or Integer (if 'num' is divisible by 'den') */ Term mkReal(int32_t num, int32_t den) const; /** - * Create an Rational constant. + * Create a real constant from a rational. * @param num the value of the numerator * @param den the value of the denominator - * @return the Rational constant + * @return a constant of sort Real or Integer (if 'num' is divisible by 'den') */ Term mkReal(int64_t num, int64_t den) const; /** - * Create an Rational constant. + * Create a real constant from a rational. * @param num the value of the numerator * @param den the value of the denominator - * @return the Rational constant + * @return a constant of sort Real or Integer (if 'num' is divisible by 'den') */ Term mkReal(uint32_t num, uint32_t den) const; /** - * Create an Rational constant. + * Create a real constant from a rational. * @param num the value of the numerator * @param den the value of the denominator - * @return the Rational constant + * @return a constant of sort Real or Integer (if 'num' is divisible by 'den') */ Term mkReal(uint64_t num, uint64_t den) const; @@ -1973,16 +1965,20 @@ class CVC4_PUBLIC Solver /** * Create a String constant. * @param s the string this constant represents + * @param useEscSequences determines whether escape sequences in \p s should + * be converted to the corresponding character * @return the String constant */ - Term mkString(const char* s) const; + Term mkString(const char* s, bool useEscSequences = false) const; /** * Create a String constant. * @param s the string this constant represents + * @param useEscSequences determines whether escape sequences in \p s should + * be converted to the corresponding character * @return the String constant */ - Term mkString(const std::string& s) const; + Term mkString(const std::string& s, bool useEscSequences = false) const; /** * Create a String constant. @@ -2006,222 +2002,125 @@ class CVC4_PUBLIC Solver Term mkUniverseSet(Sort sort) const; /** - * Create a bit-vector constant of given size with value 0. - * @param size the bit-width of the bit-vector sort - * @return the bit-vector constant - */ - Term mkBitVector(uint32_t size) const; - - /** - * Create a bit-vector constant of given size and value. - * @param size the bit-width of the bit-vector sort - * @param val the value of the constant - * @return the bit-vector constant - */ - Term mkBitVector(uint32_t size, uint32_t val) const; - - /** * Create a bit-vector constant of given size and value. * @param size the bit-width of the bit-vector sort * @param val the value of the constant * @return the bit-vector constant */ - Term mkBitVector(uint32_t size, uint64_t val) const; + Term mkBitVector(uint32_t size, uint64_t val = 0) const; /** * Create a bit-vector constant from a given string. - * @param s the string represetntation of the constant - * @param base the base of the string representation + * @param s the string representation of the constant + * @param base the base of the string representation (2, 10, or 16) * @return the bit-vector constant */ Term mkBitVector(const char* s, uint32_t base = 2) const; /** * Create a bit-vector constant from a given string. - * @param s the string represetntation of the constant - * @param base the base of the string representation + * @param s the string representation of the constant + * @param base the base of the string representation (2, 10, or 16) * @return the bit-vector constant */ - Term mkBitVector(std::string& s, uint32_t base = 2) const; - - /** - * Create constant of kind: - * - CONST_ROUNDINGMODE - * @param rm the floating point rounding mode this constant represents - */ - Term mkConst(RoundingMode rm) const; - - /* - * Create constant of kind: - * - EMPTYSET - * See enum Kind for a description of the parameters. - * @param kind the kind of the constant - * @param arg the argument to this kind - */ - Term mkConst(Kind kind, Sort arg) const; - - /** - * Create constant of kind: - * - UNINTERPRETED_CONSTANT - * See enum Kind for a description of the parameters. - * @param kind the kind of the constant - * @param arg1 the first argument to this kind - * @param arg2 the second argument to this kind - */ - Term mkConst(Kind kind, Sort arg1, int32_t arg2) const; - - /** - * Create constant of kind: - * - BOOLEAN - * See enum Kind for a description of the parameters. - * @param kind the kind of the constant - * @param arg the argument to this kind - */ - Term mkConst(Kind kind, bool arg) const; + Term mkBitVector(const std::string& s, uint32_t base = 2) const; /** - * Create constant of kind: - * - CONST_STRING - * See enum Kind for a description of the parameters. - * @param kind the kind of the constant - * @param arg the argument to this kind - */ - Term mkConst(Kind kind, const char* arg) const; - - /** - * Create constant of kind: - * - CONST_STRING - * See enum Kind for a description of the parameters. - * @param kind the kind of the constant - * @param arg the argument to this kind - */ - Term mkConst(Kind kind, const std::string& arg) const; - - /** - * Create constant of kind: - * - ABSTRACT_VALUE - * - CONST_RATIONAL (for integers, reals) - * - CONST_BITVECTOR - * See enum Kind for a description of the parameters. - * @param kind the kind of the constant - * @param arg1 the first argument to this kind - * @param arg2 the second argument to this kind + * Create a bit-vector constant of a given bit-width from a given string. + * @param size the bit-width of the constant + * @param s the string representation of the constant + * @param base the base of the string representation (2, 10, or 16) + * @return the bit-vector constant */ - Term mkConst(Kind kind, const char* arg1, uint32_t arg2 = 10) const; + Term mkBitVector(uint32_t size, const char* s, uint32_t base) const; /** - * Create constant of kind: - * - ABSTRACT_VALUE - * - CONST_RATIONAL (for integers, reals) - * - CONST_BITVECTOR - * See enum Kind for a description of the parameters. - * @param kind the kind of the constant - * @param arg1 the first argument to this kind - * @param arg2 the second argument to this kind + * Create a bit-vector constant of a given bit-width from a given string. + * @param size the bit-width of the constant + * @param s the string representation of the constant + * @param base the base of the string representation (2, 10, or 16) + * @return the bit-vector constant */ - Term mkConst(Kind kind, const std::string& arg1, uint32_t arg2 = 10) const; + Term mkBitVector(uint32_t size, std::string& s, uint32_t base) const; /** - * Create constant of kind: - * - ABSTRACT_VALUE - * - CONST_RATIONAL (for integers, reals) - * - CONST_BITVECTOR - * See enum Kind for a description of the parameters. - * @param kind the kind of the constant - * @param arg the argument to this kind + * Create a positive infinity floating-point constant. Requires CVC4 to be + * compiled with SymFPU support. + * @param exp Number of bits in the exponent + * @param sig Number of bits in the significand + * @return the floating-point constant */ - Term mkConst(Kind kind, uint32_t arg) const; + Term mkPosInf(uint32_t exp, uint32_t sig) const; /** - * Create constant of kind: - * - ABSTRACT_VALUE - * - CONST_RATIONAL (for integers, reals) - * See enum Kind for a description of the parameters. - * @param kind the kind of the constant - * @param arg the argument to this kind + * Create a negative infinity floating-point constant. Requires CVC4 to be + * compiled with SymFPU support. + * @param exp Number of bits in the exponent + * @param sig Number of bits in the significand + * @return the floating-point constant */ - Term mkConst(Kind kind, int32_t arg) const; + Term mkNegInf(uint32_t exp, uint32_t sig) const; /** - * Create constant of kind: - * - ABSTRACT_VALUE - * - CONST_RATIONAL (for integers, reals) - * See enum Kind for a description of the parameters. - * @param kind the kind of the constant - * @param arg the argument to this kind + * Create a not-a-number (NaN) floating-point constant. Requires CVC4 to be + * compiled with SymFPU support. + * @param exp Number of bits in the exponent + * @param sig Number of bits in the significand + * @return the floating-point constant */ - Term mkConst(Kind kind, int64_t arg) const; + Term mkNaN(uint32_t exp, uint32_t sig) const; /** - * Create constant of kind: - * - ABSTRACT_VALUE - * - CONST_RATIONAL (for integers, reals) - * See enum Kind for a description of the parameters. - * @param kind the kind of the constant - * @param arg the argument to this kind + * Create a positive zero (+0.0) floating-point constant. Requires CVC4 to be + * compiled with SymFPU support. + * @param exp Number of bits in the exponent + * @param sig Number of bits in the significand + * @return the floating-point constant */ - Term mkConst(Kind kind, uint64_t arg) const; + Term mkPosZero(uint32_t exp, uint32_t sig) const; /** - * Create constant of kind: - * - CONST_RATIONAL (for rationals) - * See enum Kind for a description of the parameters. - * @param kind the kind of the constant - * @param arg1 the first argument to this kind - * @param arg2 the second argument to this kind + * Create a negative zero (-0.0) floating-point constant. Requires CVC4 to be + * compiled with SymFPU support. + * @param exp Number of bits in the exponent + * @param sig Number of bits in the significand + * @return the floating-point constant */ - Term mkConst(Kind kind, int32_t arg1, int32_t arg2) const; + Term mkNegZero(uint32_t exp, uint32_t sig) const; /** - * Create constant of kind: - * - CONST_RATIONAL (for rationals) - * See enum Kind for a description of the parameters. - * @param kind the kind of the constant - * @param arg1 the first argument to this kind - * @param arg2 the second argument to this kind + * Create a roundingmode constant. + * @param rm the floating point rounding mode this constant represents */ - Term mkConst(Kind kind, int64_t arg1, int64_t arg2) const; + Term mkRoundingMode(RoundingMode rm) const; /** - * Create constant of kind: - * - CONST_RATIONAL (for rationals) - * See enum Kind for a description of the parameters. - * @param kind the kind of the constant - * @param arg1 the first argument to this kind - * @param arg2 the second argument to this kind + * Create uninterpreted constant. + * @param arg1 Sort of the constant + * @param arg2 Index of the constant */ - Term mkConst(Kind kind, uint32_t arg1, uint32_t arg2) const; + Term mkUninterpretedConst(Sort sort, int32_t index) const; /** - * Create constant of kind: - * - CONST_RATIONAL (for rationals) - * See enum Kind for a description of the parameters. - * @param kind the kind of the constant - * @param arg1 the first argument to this kind - * @param arg2 the second argument to this kind + * Create an abstract value constant. + * @param index Index of the abstract value */ - Term mkConst(Kind kind, uint64_t arg1, uint64_t arg2) const; + Term mkAbstractValue(const std::string& index) const; /** - * Create constant of kind: - * - CONST_BITVECTOR - * See enum Kind for a description of the parameters. - * @param kind the kind of the constant - * @param arg1 the first argument to this kind - * @param arg2 the second argument to this kind + * Create an abstract value constant. + * @param index Index of the abstract value */ - Term mkConst(Kind kind, uint32_t arg1, uint64_t arg2) const; + Term mkAbstractValue(uint64_t index) const; /** - * Create constant of kind: - * - CONST_FLOATINGPOINT - * See enum Kind for a description of the parameters. - * @param kind the kind of the constant - * @param arg1 the first argument to this kind - * @param arg2 the second argument to this kind - * @param arg3 the third argument to this kind + * Create a floating-point constant (requires CVC4 to be compiled with symFPU + * support). + * @param exp Size of the exponent + * @param sig Size of the significand + * @param val Value of the floating-point constant as a bit-vector term */ - Term mkConst(Kind kind, uint32_t arg1, uint32_t arg2, Term arg3) const; + Term mkFloatingPoint(uint32_t exp, uint32_t sig, Term val) const; /* .................................................................... */ /* Create Variables */ @@ -2339,9 +2238,8 @@ class CVC4_PUBLIC Solver * @param ctors the constructor declarations of the datatype sort * @return the datatype sort */ - Sort declareDatatype( - const std::string& symbol, - const std::vector<DatatypeConstructorDecl>& ctors) const; + Sort declareDatatype(const std::string& symbol, + const std::vector<DatatypeConstructorDecl>& ctors) const; /** * Declare 0-arity function symbol. @@ -2564,6 +2462,15 @@ class CVC4_PUBLIC Solver */ void setOption(const std::string& option, const std::string& value) const; + /** + * If needed, convert this term to a given sort. Note that the sort of the + * term must be convertible into the target sort. Currently only Int to Real + * conversions are supported. + * @param s the target sort + * @return the term wrapped into a sort conversion if needed + */ + Term ensureTermSort(const Term& t, const Sort& s) const; + // !!! This is only temporarily available until the parser is fully migrated // to the new API. !!! ExprManager* getExprManager(void) const; @@ -2581,6 +2488,28 @@ class CVC4_PUBLIC Solver void checkMkOpTerm(OpTerm opTerm, uint32_t nchildren) const; /* Helper to check for API misuse in mkOpTerm functions. */ void checkMkTerm(Kind kind, uint32_t nchildren) const; + /* Helper for mk-functions that call d_exprMgr->mkConst(). */ + template <typename T> + Term mkConstHelper(T t) const; + /* Helper for mkReal functions that take a string as argument. */ + Term mkRealFromStrHelper(std::string s) const; + /* Helper for mkBitVector functions that take a string as argument. */ + Term mkBVFromStrHelper(std::string s, uint32_t base) const; + /* Helper for mkBitVector functions that take a string and a size as + * arguments. */ + Term mkBVFromStrHelper(uint32_t size, std::string s, uint32_t base) const; + /* Helper for mkBitVector functions that take an integer as argument. */ + Term mkBVFromIntHelper(uint32_t size, uint64_t val) const; + /* Helper for setLogic. */ + void setLogicHelper(const std::string& logic) const; + + /** + * Helper function that ensures that a given term is of sort real (as opposed + * to being of sort integer). + * @param term a term of sort integer or real + * @return a term of sort real + */ + Term ensureRealSort(Term expr) const; /* The expression manager of this solver. */ std::unique_ptr<ExprManager> d_exprMgr; diff --git a/src/api/cvc4cppkind.h b/src/api/cvc4cppkind.h index f91f934f9..a7f6926bb 100644 --- a/src/api/cvc4cppkind.h +++ b/src/api/cvc4cppkind.h @@ -62,7 +62,7 @@ enum CVC4_PUBLIC Kind : int32_t * -[1]: Sort of the constant * -[2]: Index of the constant * Create with: - * mkConst(Kind, Sort, int32_t) + * mkUninterpretedConst(Sort sort, int32_t index) */ UNINTERPRETED_CONSTANT, /** @@ -70,12 +70,8 @@ enum CVC4_PUBLIC Kind : int32_t * Parameters: 1 * -[1]: Index of the abstract value * Create with: - * mkConst(Kind kind, const char* s, uint32_t base = 10) - * mkConst(Kind kind, const std::string& s, uint32_t base = 10) - * mkConst(Kind kind, uint32_t arg) - * mkConst(Kind kind, int32_t arg) - * mkConst(Kind kind, int64_t arg) - * mkConst(Kind kind, uint64_t arg) + * mkAbstractValue(const std::string& index); + * mkAbstractValue(uint64_t index); */ ABSTRACT_VALUE, #if 0 @@ -204,7 +200,6 @@ enum CVC4_PUBLIC Kind : int32_t * mkTrue() * mkFalse() * mkBoolean(bool val) - * mkConst(Kind kind, bool arg) */ CONST_BOOLEAN, /* Logical not. @@ -568,20 +563,10 @@ enum CVC4_PUBLIC Kind : int32_t * mkReal(int64_t val) * mkReal(uint32_t val) * mkReal(uint64_t val) - * mkRational(int32_t num, int32_t den) - * mkRational(int64_t num, int64_t den) - * mkRational(uint32_t num, uint32_t den) - * mkRational(uint64_t num, uint64_t den) - * mkConst(Kind kind, const char* s, uint32_t base = 10) - * mkConst(Kind kind, const std::string& s, uint32_t base = 10) - * mkConst(Kind kind, uint32_t arg) - * mkConst(Kind kind, int64_t arg) - * mkConst(Kind kind, uint64_t arg) - * mkConst(Kind kind, int32_t arg) - * mkConst(Kind kind, int32_t arg1, int32_t arg2) - * mkConst(Kind kind, int64_t arg1, int64_t arg2) - * mkConst(Kind kind, uint32_t arg1, uint32_t arg2) - * mkConst(Kind kind, uint64_t arg1, uint64_t arg2) + * mkReal(int32_t num, int32_t den) + * mkReal(int64_t num, int64_t den) + * mkReal(uint32_t num, uint32_t den) + * mkReal(uint64_t num, uint64_t den) */ CONST_RATIONAL, /** @@ -658,15 +643,9 @@ enum CVC4_PUBLIC Kind : int32_t * Parameters: * See mkBitVector(). * Create with: - * mkBitVector(uint32_t size) - * mkBitVector(uint32_t size, uint32_t val) * mkBitVector(uint32_t size, uint64_t val) * mkBitVector(const char* s, uint32_t base = 2) * mkBitVector(std::string& s, uint32_t base = 2) - * mkConst(Kind kind, const char* s, uint32_t base = 10) - * mkConst(Kind kind, const std::string& s, uint32_t base = 10) - * mkConst(Kind kind, uint32_t arg) - * mkConst(Kind kind, uint32_t arg1, uint64_t arg2) */ CONST_BITVECTOR, /** @@ -1169,13 +1148,13 @@ enum CVC4_PUBLIC Kind : int32_t * -[2]: Size of the significand * -[3]: Value of the floating-point constant as a bit-vector term * Create with: - * mkConst(Kind kind, uint32_t arg1, uint32_t arg2, Term arg3) + * mkFloatingPoint(uint32_t sig, uint32_t exp, Term val) */ CONST_FLOATINGPOINT, /** * Floating-point rounding mode term. * Create with: - * mkConst(RoundingMode rm) + * mkRoundingMode(RoundingMode rm) */ CONST_ROUNDINGMODE, /** @@ -1833,7 +1812,6 @@ enum CVC4_PUBLIC Kind : int32_t * -[1]: Sort of the set elements * Create with: * mkEmptySet(Sort sort) - * mkConst(Sort sort) */ EMPTYSET, /** @@ -1922,7 +1900,6 @@ enum CVC4_PUBLIC Kind : int32_t * All set variables must be interpreted as subsets of it. * Create with: * mkUniverseSet(Sort sort) - * mkTerm(Kind kind, Sort sort) */ UNIVERSE_SET, /** @@ -2125,8 +2102,6 @@ enum CVC4_PUBLIC Kind : int32_t * mkString(const std::string& s) * mkString(const unsigned char c) * mkString(const std::vector<unsigned>& s) - * mkConst(Kind kind, const char* s) - * mkConst(Kind kind, const std::string& s) */ CONST_STRING, /** diff --git a/src/options/CMakeLists.txt b/src/options/CMakeLists.txt index b86db8d00..fc725978e 100644 --- a/src/options/CMakeLists.txt +++ b/src/options/CMakeLists.txt @@ -37,6 +37,8 @@ libcvc4_add_sources( set_language.h smt_modes.cpp smt_modes.h + strings_process_loop_mode.cpp + strings_process_loop_mode.h sygus_out_mode.h theoryof_mode.cpp theoryof_mode.h diff --git a/src/options/bv_bitblast_mode.cpp b/src/options/bv_bitblast_mode.cpp index 9cfa2d6d3..59a97c5a2 100644 --- a/src/options/bv_bitblast_mode.cpp +++ b/src/options/bv_bitblast_mode.cpp @@ -68,4 +68,17 @@ std::ostream& operator<<(std::ostream& out, theory::bv::SatSolverMode solver) { return out; } +std::ostream& operator<<(std::ostream& out, theory::bv::BvProofFormat format) +{ + switch (format) + { + case theory::bv::BITVECTOR_PROOF_ER: out << "BITVECTOR_PROOF_ER"; break; + case theory::bv::BITVECTOR_PROOF_DRAT: out << "BITVECTOR_PROOF_DRAT"; break; + case theory::bv::BITVECTOR_PROOF_LRAT: out << "BITVECTOR_PROOF_LRAT"; break; + default: out << "BvProofFormat:UNKNOWN![" << unsigned(format) << "]"; + } + + return out; +} + }/* CVC4 namespace */ diff --git a/src/options/bv_bitblast_mode.h b/src/options/bv_bitblast_mode.h index 530632674..fa5791ac9 100644 --- a/src/options/bv_bitblast_mode.h +++ b/src/options/bv_bitblast_mode.h @@ -68,12 +68,33 @@ enum SatSolverMode SAT_SOLVER_CADICAL, }; /* enum SatSolver */ +/** + * When the BV solver does eager bitblasting backed by CryptoMiniSat, proofs + * can be written in a variety of formats. + */ +enum BvProofFormat +{ + /** + * Write extended resolution proofs. + */ + BITVECTOR_PROOF_ER, + /** + * Write DRAT proofs. + */ + BITVECTOR_PROOF_DRAT, + /** + * Write LRAT proofs. + */ + BITVECTOR_PROOF_LRAT, +}; + }/* CVC4::theory::bv namespace */ }/* CVC4::theory namespace */ std::ostream& operator<<(std::ostream& out, theory::bv::BitblastMode mode); std::ostream& operator<<(std::ostream& out, theory::bv::BvSlicerMode mode); std::ostream& operator<<(std::ostream& out, theory::bv::SatSolverMode mode); +std::ostream& operator<<(std::ostream& out, theory::bv::BvProofFormat format); }/* CVC4 namespace */ diff --git a/src/options/bv_options.toml b/src/options/bv_options.toml index 00290da7d..0422ae06f 100644 --- a/src/options/bv_options.toml +++ b/src/options/bv_options.toml @@ -3,6 +3,17 @@ name = "Bitvector theory" header = "options/bv_options.h" [[option]] + name = "bvProofFormat" + category = "expert" + long = "bv-proof-format=MODE" + type = "CVC4::theory::bv::BvProofFormat" + default = "CVC4::theory::bv::BITVECTOR_PROOF_LRAT" + handler = "stringToBvProofFormat" + predicates = ["satSolverEnabledBuild"] + includes = ["options/bv_bitblast_mode.h"] + help = "choose which UNSAT proof format to use, see --bv-sat-solver=help" + +[[option]] name = "bvSatSolver" smt_name = "bv-sat-solver" category = "expert" diff --git a/src/options/options_handler.cpp b/src/options/options_handler.cpp index 36144e70e..32f77a09f 100644 --- a/src/options/options_handler.cpp +++ b/src/options/options_handler.cpp @@ -1203,6 +1203,48 @@ theory::bv::SatSolverMode OptionsHandler::stringToSatSolver(std::string option, } } +const std::string OptionsHandler::s_bvProofFormatHelp = + "\ +Proof formats currently supported by the --bv-proof-format option:\n\ +\n\ + lrat : DRAT with unit propagation hints to accelerate checking (default)\n\ +\n\ + drat : Deletion and Resolution Asymmetric Tautology Additions \n\ +\n\ + er : Extended Resolution, i.e. resolution with new variable definitions\n\ +\n\ +This option controls which underlying UNSAT proof format is used in BV proofs.\n\ +\n\ +Note: Currently this option does nothing. BV proofs are a work in progress!\ +"; + +theory::bv::BvProofFormat OptionsHandler::stringToBvProofFormat( + std::string option, std::string optarg) +{ + if (optarg == "er") + { + return theory::bv::BITVECTOR_PROOF_ER; + } + else if (optarg == "lrat") + { + return theory::bv::BITVECTOR_PROOF_LRAT; + } + else if (optarg == "drat") + { + return theory::bv::BITVECTOR_PROOF_DRAT; + } + else if (optarg == "help") + { + puts(s_bvProofFormatHelp.c_str()); + exit(1); + } + else + { + throw OptionException(std::string("unknown option for --bv-proof-format: `") + + optarg + "'. Try --bv-proof-format=help."); + } +} + const std::string OptionsHandler::s_bitblastingModeHelp = "\ Bit-blasting modes currently supported by the --bitblast option:\n\ \n\ @@ -1295,6 +1337,61 @@ theory::bv::BvSlicerMode OptionsHandler::stringToBvSlicerMode( } } +const std::string OptionsHandler::s_stringToStringsProcessLoopModeHelp = + "Loop processing modes supported by the --strings-process-loop-mode " + "option:\n" + "\n" + "full (default)\n" + "+ Perform full processing of looping word equations\n" + "\n" + "simple\n" + "+ Omit normal loop breaking\n" + "\n" + "simple-abort\n" + "+ Abort when normal loop breaking is required\n" + "\n" + "none\n" + "+ Omit loop processing\n" + "\n" + "abort\n" + "+ Abort if looping word equations are encountered\n"; + +theory::strings::ProcessLoopMode OptionsHandler::stringToStringsProcessLoopMode( + std::string option, std::string optarg) +{ + if (optarg == "full") + { + return theory::strings::ProcessLoopMode::FULL; + } + else if (optarg == "simple") + { + return theory::strings::ProcessLoopMode::SIMPLE; + } + else if (optarg == "simple-abort") + { + return theory::strings::ProcessLoopMode::SIMPLE_ABORT; + } + else if (optarg == "none") + { + return theory::strings::ProcessLoopMode::NONE; + } + else if (optarg == "abort") + { + return theory::strings::ProcessLoopMode::ABORT; + } + else if (optarg == "help") + { + puts(s_stringToStringsProcessLoopModeHelp.c_str()); + exit(1); + } + else + { + throw OptionException( + std::string("unknown option for --strings-process-loop-mode: `") + + optarg + "'. Try --strings-process-loop-mode=help."); + } +} + const std::string OptionsHandler::s_boolToBVModeHelp = "\ BoolToBV pass modes supported by the --bool-to-bv option:\n\ diff --git a/src/options/options_handler.h b/src/options/options_handler.h index f96632696..8b2629db7 100644 --- a/src/options/options_handler.h +++ b/src/options/options_handler.h @@ -37,6 +37,7 @@ #include "options/printer_modes.h" #include "options/quantifiers_modes.h" #include "options/smt_modes.h" +#include "options/strings_process_loop_mode.h" #include "options/sygus_out_mode.h" #include "options/theoryof_mode.h" #include "options/ufss_mode.h" @@ -145,6 +146,12 @@ public: theory::bv::SatSolverMode stringToSatSolver(std::string option, std::string optarg); + theory::bv::BvProofFormat stringToBvProofFormat(std::string option, + std::string optarg); + + theory::strings::ProcessLoopMode stringToStringsProcessLoopMode( + std::string option, std::string optarg); + // theory/uf/options_handlers.h theory::uf::UfssMode stringToUfssMode(std::string option, std::string optarg); @@ -230,8 +237,10 @@ public: /* Help strings */ static const std::string s_bitblastingModeHelp; static const std::string s_bvSatSolverHelp; + static const std::string s_bvProofFormatHelp; static const std::string s_booleanTermConversionModeHelp; static const std::string s_bvSlicerModeHelp; + static const std::string s_stringToStringsProcessLoopModeHelp; static const std::string s_boolToBVModeHelp; static const std::string s_cegqiFairModeHelp; static const std::string s_decisionModeHelp; diff --git a/src/options/strings_options.toml b/src/options/strings_options.toml index 414a9cfa6..bc5fbedd6 100644 --- a/src/options/strings_options.toml +++ b/src/options/strings_options.toml @@ -129,22 +129,14 @@ header = "options/strings_options.h" help = "check entailment between length terms to reduce splitting" [[option]] - name = "stringProcessLoop" - category = "regular" - long = "strings-process-loop" - type = "bool" - default = "true" - read_only = true - help = "reduce looping word equations to regular expressions" - -[[option]] - name = "stringAbortLoop" - category = "regular" - long = "strings-abort-loop" - type = "bool" - default = "false" - read_only = true - help = "abort when a looping word equation is encountered" + name = "stringProcessLoopMode" + category = "expert" + long = "strings-process-loop-mode=MODE" + type = "CVC4::theory::strings::ProcessLoopMode" + default = "CVC4::theory::strings::ProcessLoopMode::FULL" + handler = "stringToStringsProcessLoopMode" + includes = ["options/strings_process_loop_mode.h"] + help = "choose how to process looping string equations, see --strings-process-loop-mode=help for details" [[option]] name = "stringInferAsLemmas" diff --git a/src/options/strings_process_loop_mode.cpp b/src/options/strings_process_loop_mode.cpp new file mode 100644 index 000000000..a1a81bbf3 --- /dev/null +++ b/src/options/strings_process_loop_mode.cpp @@ -0,0 +1,46 @@ +/********************* */ +/*! \file strings_process_loop_mode.cpp + ** \verbatim + ** Top contributors (to current version): + ** Andres Noetzli + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2019 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 Modes for processing looping word equations in the string solver. + ** + ** Modes for processing looping word equations in the string solver. + **/ + +#include "options/strings_process_loop_mode.h" + +#include <iostream> + +namespace CVC4 { + +std::ostream& operator<<(std::ostream& out, + theory::strings::ProcessLoopMode mode) +{ + switch (mode) + { + case theory::strings::ProcessLoopMode::FULL: + out << "ProcessLoopMode::FULL"; + break; + case theory::strings::ProcessLoopMode::SIMPLE: + out << "ProcessLoopMode::SIMPLE"; + break; + case theory::strings::ProcessLoopMode::SIMPLE_ABORT: + out << "ProcessLoopMode::SIMPLE_ABORT"; + break; + case theory::strings::ProcessLoopMode::NONE: + out << "ProcessLoopMode::NONE"; + break; + case theory::strings::ProcessLoopMode::ABORT: + out << "ProcessLoopMode::ABORT"; + break; + } +} + +} // namespace CVC4 diff --git a/src/options/strings_process_loop_mode.h b/src/options/strings_process_loop_mode.h new file mode 100644 index 000000000..2933e034f --- /dev/null +++ b/src/options/strings_process_loop_mode.h @@ -0,0 +1,55 @@ +/********************* */ +/*! \file strings_process_loop_mode.h + ** \verbatim + ** Top contributors (to current version): + ** Andres Noetzli + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2019 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 Modes for processing looping word equations in the string solver. + ** + ** Modes for processing looping word equations in the string solver. + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__STRINGS__PROCESS_LOOP_MODE_H +#define __CVC4__THEORY__STRINGS__PROCESS_LOOP_MODE_H + +#include <iosfwd> + +namespace CVC4 { +namespace theory { +namespace strings { + +/** Enumeration of bit-blasting modes */ +enum class ProcessLoopMode +{ + /** Perform full loop processing. */ + FULL, + + /** Omit normal loop breaking. */ + SIMPLE, + + /** Abort if normal loop breaking is required. */ + SIMPLE_ABORT, + + /** Omit loop processing. */ + NONE, + + /** Abort if looping word equations are encountered. */ + ABORT +}; // enum ProcessLoopMode + +} // namespace strings +} // namespace theory + +std::ostream& operator<<(std::ostream& out, + theory::strings::ProcessLoopMode mode); + +} // namespace CVC4 + +#endif /* __CVC4__THEORY__BV__BITBLAST_MODE_H */ diff --git a/src/parser/parser.cpp b/src/parser/parser.cpp index 8ddefb2f4..71d226c98 100644 --- a/src/parser/parser.cpp +++ b/src/parser/parser.cpp @@ -81,6 +81,8 @@ ExprManager* Parser::getExprManager() const return d_solver->getExprManager(); } +api::Solver* Parser::getSolver() const { return d_solver; } + Expr Parser::getSymbol(const std::string& name, SymbolType type) { checkDeclaration(name, CHECK_DECLARED, type); assert(isDeclared(name, type)); diff --git a/src/parser/parser.h b/src/parser/parser.h index f22fc3789..8c18055a7 100644 --- a/src/parser/parser.h +++ b/src/parser/parser.h @@ -269,6 +269,9 @@ public: /** Get the associated <code>ExprManager</code>. */ ExprManager* getExprManager() const; + /** Get the associated solver. */ + api::Solver* getSolver() const; + /** Get the associated input. */ inline Input* getInput() const { return d_input; diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g index 7143824d6..c72a4f99b 100644 --- a/src/parser/smt2/Smt2.g +++ b/src/parser/smt2/Smt2.g @@ -100,6 +100,10 @@ namespace CVC4 { };/* struct myExpr */ }/* CVC4::parser::smt2 namespace */ }/* CVC4::parser namespace */ + + namespace api { + class Term; + } }/* CVC4 namespace */ }/* @parser::includes */ @@ -112,6 +116,7 @@ namespace CVC4 { #include <unordered_set> #include <vector> +#include "api/cvc4cpp.h" #include "base/output.h" #include "expr/expr.h" #include "expr/kind.h" @@ -141,6 +146,8 @@ using namespace CVC4::parser; #define MK_EXPR EXPR_MANAGER->mkExpr #undef MK_CONST #define MK_CONST EXPR_MANAGER->mkConst +#undef SOLVER +#define SOLVER PARSER_STATE->getSolver() #define UNSUPPORTED PARSER_STATE->unimplementedFeature static bool isClosed(const Expr& e, std::set<Expr>& free, std::unordered_set<Expr, ExprHashFunction>& closedCache) { @@ -878,7 +885,7 @@ sygusGTerm[CVC4::SygusGTerm& sgt, std::string& fun] std::vector< Expr > let_vars; bool readingLet = false; std::string s; - CVC4::Expr atomExpr; + CVC4::api::Term atomTerm; } : LPAREN_TOK //read operator @@ -973,15 +980,16 @@ sygusGTerm[CVC4::SygusGTerm& sgt, std::string& fun] PARSER_STATE->popScope(); } } - | termAtomic[atomExpr] { - Debug("parser-sygus") << "Sygus grammar " << fun << " : atomic " - << "expression " << atomExpr << std::endl; - std::stringstream ss; - ss << atomExpr; - sgt.d_expr = atomExpr; - sgt.d_name = ss.str(); - sgt.d_gterm_type = SygusGTerm::gterm_op; - } + | termAtomic[atomTerm] + { + Debug("parser-sygus") << "Sygus grammar " << fun << " : atomic " + << "expression " << atomTerm << std::endl; + std::stringstream ss; + ss << atomTerm; + sgt.d_expr = atomTerm.getExpr(); + sgt.d_name = ss.str(); + sgt.d_gterm_type = SygusGTerm::gterm_op; + } | symbol[name,CHECK_NONE,SYM_VARIABLE] { if( name[0] == '-' ){ //hack for unary minus @@ -1709,6 +1717,7 @@ termNonVariable[CVC4::Expr& expr, CVC4::Expr& expr2] std::vector<Type> match_ptypes; Type type; Type type2; + api::Term atomTerm; } : /* a built-in operator application */ LPAREN_TOK builtinOp[kind] termList[args,expr] RPAREN_TOK @@ -2207,19 +2216,17 @@ termNonVariable[CVC4::Expr& expr, CVC4::Expr& expr2] | LPAREN_TOK TUPLE_CONST_TOK termList[args,expr] RPAREN_TOK { - std::vector<Type> types; - for (std::vector<Expr>::const_iterator i = args.begin(); i != args.end(); - ++i) + std::vector<api::Sort> sorts; + std::vector<api::Term> terms; + for (const Expr& arg : args) { - types.push_back((*i).getType()); + sorts.emplace_back(arg.getType()); + terms.emplace_back(arg); } - DatatypeType t = EXPR_MANAGER->mkTupleType(types); - const Datatype& dt = t.getDatatype(); - args.insert(args.begin(), dt[0].getConstructor()); - expr = MK_EXPR(kind::APPLY_CONSTRUCTOR, args); + expr = SOLVER->mkTuple(sorts, terms).getExpr(); } | /* an atomic term (a term with no subterms) */ - termAtomic[expr] + termAtomic[atomTerm] { expr = atomTerm.getExpr(); } ; @@ -2227,128 +2234,145 @@ termNonVariable[CVC4::Expr& expr, CVC4::Expr& expr2] * Matches an atomic term (a term with no subterms). * @return the expression expr representing the term or formula. */ -termAtomic[CVC4::Expr& expr] +termAtomic[CVC4::api::Term& atomTerm] @init { - std::vector<Expr> args; Type type; Type type2; std::string s; } /* constants */ : INTEGER_LITERAL - { expr = MK_CONST( AntlrInput::tokenToInteger($INTEGER_LITERAL) ); } - + { + std::string intStr = AntlrInput::tokenText($INTEGER_LITERAL); + atomTerm = SOLVER->mkReal(intStr); + } | DECIMAL_LITERAL - { // FIXME: This doesn't work because an SMT rational is not a - // valid GMP rational string - expr = MK_CONST( AntlrInput::tokenToRational($DECIMAL_LITERAL) ); - if(expr.getType().isInteger()) { - // Must cast to Real to ensure correct type is passed to parametric type constructors. - // We do this cast using division with 1. - // This has the advantage wrt using TO_REAL since (constant) division is always included in the theory. - expr = MK_EXPR(kind::DIVISION, expr, MK_CONST(Rational(1))); - } + { + std::string realStr = AntlrInput::tokenText($DECIMAL_LITERAL); + atomTerm = SOLVER->ensureTermSort(SOLVER->mkReal(realStr), + SOLVER->getRealSort()); } + // Pi constant + | REAL_PI_TOK { atomTerm = SOLVER->mkPi(); } + + // Constants using indexed identifiers, e.g. (_ +oo 8 24) (positive infinity + // as a 32-bit floating-point constant) | LPAREN_TOK INDEX_TOK ( bvLit=SIMPLE_SYMBOL size=INTEGER_LITERAL - { if(AntlrInput::tokenText($bvLit).find("bv") == 0) { - expr = MK_CONST( AntlrInput::tokenToBitvector($bvLit, $size) ); - } else { + { + if(AntlrInput::tokenText($bvLit).find("bv") == 0) + { + std::string bvStr = AntlrInput::tokenTextSubstr($bvLit, 2); + uint32_t bvSize = AntlrInput::tokenToUnsigned($size); + atomTerm = SOLVER->mkBitVector(bvSize, bvStr, 10); + } + else + { PARSER_STATE->parseError("Unexpected symbol `" + AntlrInput::tokenText($bvLit) + "'"); } } + + // Floating-point constants | FP_PINF_TOK eb=INTEGER_LITERAL sb=INTEGER_LITERAL - { expr = MK_CONST(FloatingPoint::makeInf(FloatingPointSize(AntlrInput::tokenToUnsigned($eb), - AntlrInput::tokenToUnsigned($sb)), - false)); } + { + atomTerm = SOLVER->mkPosInf(AntlrInput::tokenToUnsigned($eb), + AntlrInput::tokenToUnsigned($sb)); + } | FP_NINF_TOK eb=INTEGER_LITERAL sb=INTEGER_LITERAL - { expr = MK_CONST(FloatingPoint::makeInf(FloatingPointSize(AntlrInput::tokenToUnsigned($eb), - AntlrInput::tokenToUnsigned($sb)), - true)); } + { + atomTerm = SOLVER->mkNegInf(AntlrInput::tokenToUnsigned($eb), + AntlrInput::tokenToUnsigned($sb)); + } | FP_NAN_TOK eb=INTEGER_LITERAL sb=INTEGER_LITERAL - { expr = MK_CONST(FloatingPoint::makeNaN(FloatingPointSize(AntlrInput::tokenToUnsigned($eb), - AntlrInput::tokenToUnsigned($sb)))); } - + { + atomTerm = SOLVER->mkNaN(AntlrInput::tokenToUnsigned($eb), + AntlrInput::tokenToUnsigned($sb)); + } | FP_PZERO_TOK eb=INTEGER_LITERAL sb=INTEGER_LITERAL - { expr = MK_CONST(FloatingPoint::makeZero(FloatingPointSize(AntlrInput::tokenToUnsigned($eb), - AntlrInput::tokenToUnsigned($sb)), - false)); } + { + atomTerm = SOLVER->mkPosZero(AntlrInput::tokenToUnsigned($eb), + AntlrInput::tokenToUnsigned($sb)); + } | FP_NZERO_TOK eb=INTEGER_LITERAL sb=INTEGER_LITERAL - { expr = MK_CONST(FloatingPoint::makeZero(FloatingPointSize(AntlrInput::tokenToUnsigned($eb), - AntlrInput::tokenToUnsigned($sb)), - true)); } + { + atomTerm = SOLVER->mkNegZero(AntlrInput::tokenToUnsigned($eb), + AntlrInput::tokenToUnsigned($sb)); + } + + // Empty heap constant in seperation logic | EMP_TOK sortSymbol[type,CHECK_DECLARED] sortSymbol[type2,CHECK_DECLARED] { - Expr v1 = PARSER_STATE->mkVar("_emp1", type); - Expr v2 = PARSER_STATE->mkVar("_emp2", type2); - expr = MK_EXPR(kind::SEP_EMP,v1,v2); + api::Term v1 = SOLVER->mkVar("_emp1", api::Sort(type)); + api::Term v2 = SOLVER->mkVar("_emp2", api::Sort(type2)); + atomTerm = SOLVER->mkTerm(api::SEP_EMP, v1, v2); } - // NOTE: Theory parametric constants go here + // NOTE: Theory parametric constants go here ) RPAREN_TOK + // Bit-vector constants | HEX_LITERAL - { assert( AntlrInput::tokenText($HEX_LITERAL).find("#x") == 0 ); - std::string hexString = AntlrInput::tokenTextSubstr($HEX_LITERAL, 2); - expr = MK_CONST( BitVector(hexString, 16) ); } - - | BINARY_LITERAL - { assert( AntlrInput::tokenText($BINARY_LITERAL).find("#b") == 0 ); - std::string binString = AntlrInput::tokenTextSubstr($BINARY_LITERAL, 2); - expr = MK_CONST( BitVector(binString, 2) ); } - - | str[s,false] - { expr = MK_CONST( ::CVC4::String(s, true) ); } - | FP_RNE_TOK { expr = MK_CONST(roundNearestTiesToEven); } - | FP_RNA_TOK { expr = MK_CONST(roundNearestTiesToAway); } - | FP_RTP_TOK { expr = MK_CONST(roundTowardPositive); } - | FP_RTN_TOK { expr = MK_CONST(roundTowardNegative); } - | FP_RTZ_TOK { expr = MK_CONST(roundTowardZero); } - | FP_RNE_FULL_TOK { expr = MK_CONST(roundNearestTiesToEven); } - | FP_RNA_FULL_TOK { expr = MK_CONST(roundNearestTiesToAway); } - | FP_RTP_FULL_TOK { expr = MK_CONST(roundTowardPositive); } - | FP_RTN_FULL_TOK { expr = MK_CONST(roundTowardNegative); } - | FP_RTZ_FULL_TOK { expr = MK_CONST(roundTowardZero); } - - | REAL_PI_TOK { - expr = EXPR_MANAGER->mkNullaryOperator(EXPR_MANAGER->realType(), kind::PI); + { + assert(AntlrInput::tokenText($HEX_LITERAL).find("#x") == 0); + std::string hexStr = AntlrInput::tokenTextSubstr($HEX_LITERAL, 2); + atomTerm = SOLVER->mkBitVector(hexStr, 16); } - - | RENOSTR_TOK - { std::vector< Expr > nvec; - expr = MK_EXPR( CVC4::kind::REGEXP_EMPTY, nvec ); + | BINARY_LITERAL + { + assert(AntlrInput::tokenText($BINARY_LITERAL).find("#b") == 0); + std::string binStr = AntlrInput::tokenTextSubstr($BINARY_LITERAL, 2); + atomTerm = SOLVER->mkBitVector(binStr, 2); + } + + // Floating-point rounding mode constants + | FP_RNE_TOK { atomTerm = SOLVER->mkRoundingMode(api::ROUND_NEAREST_TIES_TO_EVEN); } + | FP_RNA_TOK { atomTerm = SOLVER->mkRoundingMode(api::ROUND_NEAREST_TIES_TO_AWAY); } + | FP_RTP_TOK { atomTerm = SOLVER->mkRoundingMode(api::ROUND_TOWARD_POSITIVE); } + | FP_RTN_TOK { atomTerm = SOLVER->mkRoundingMode(api::ROUND_TOWARD_NEGATIVE); } + | FP_RTZ_TOK { atomTerm = SOLVER->mkRoundingMode(api::ROUND_TOWARD_ZERO); } + | FP_RNE_FULL_TOK { atomTerm = SOLVER->mkRoundingMode(api::ROUND_NEAREST_TIES_TO_EVEN); } + | FP_RNA_FULL_TOK { atomTerm = SOLVER->mkRoundingMode(api::ROUND_NEAREST_TIES_TO_AWAY); } + | FP_RTP_FULL_TOK { atomTerm = SOLVER->mkRoundingMode(api::ROUND_TOWARD_POSITIVE); } + | FP_RTN_FULL_TOK { atomTerm = SOLVER->mkRoundingMode(api::ROUND_TOWARD_NEGATIVE); } + | FP_RTZ_FULL_TOK { atomTerm = SOLVER->mkRoundingMode(api::ROUND_TOWARD_ZERO); } + + // String constant + | str[s,false] { atomTerm = SOLVER->mkString(s, true); } + + // Regular expression constants + | RENOSTR_TOK { atomTerm = SOLVER->mkRegexpEmpty(); } + | REALLCHAR_TOK { atomTerm = SOLVER->mkRegexpSigma(); } + + // Set constants + | EMPTYSET_TOK { atomTerm = SOLVER->mkEmptySet(SOLVER->getNullSort()); } + | UNIVSET_TOK + { + // the Boolean sort is a placeholder here since we don't have type info + // without type annotation + atomTerm = SOLVER->mkUniverseSet(SOLVER->getBooleanSort()); } - | REALLCHAR_TOK - { std::vector< Expr > nvec; - expr = MK_EXPR( CVC4::kind::REGEXP_SIGMA, nvec ); + // Separation logic constants + | NILREF_TOK + { + // the Boolean sort is a placeholder here since we don't have type info + // without type annotation + atomTerm = SOLVER->mkSepNil(SOLVER->getBooleanSort()); } - | EMPTYSET_TOK - { expr = MK_CONST( ::CVC4::EmptySet(Type())); } - - | UNIVSET_TOK - { //booleanType is placeholder here since we don't have type info without type annotation - expr = EXPR_MANAGER->mkNullaryOperator(EXPR_MANAGER->booleanType(), kind::UNIVERSE_SET); } - - | NILREF_TOK - { //booleanType is placeholder here since we don't have type info without type annotation - expr = EXPR_MANAGER->mkNullaryOperator(EXPR_MANAGER->booleanType(), kind::SEP_NIL); } - // NOTE: Theory constants go here + // NOTE: Theory constants go here + // Empty tuple constant | TUPLE_CONST_TOK - { std::vector<Type> types; - DatatypeType t = EXPR_MANAGER->mkTupleType(types); - const Datatype& dt = t.getDatatype(); - args.insert(args.begin(), dt[0].getConstructor()); - expr = MK_EXPR(kind::APPLY_CONSTRUCTOR, args); + { + atomTerm = SOLVER->mkTuple(std::vector<api::Sort>(), + std::vector<api::Term>()); } - ; /** diff --git a/src/printer/cvc/cvc_printer.cpp b/src/printer/cvc/cvc_printer.cpp index 6fa7eadeb..e6ff02f10 100644 --- a/src/printer/cvc/cvc_printer.cpp +++ b/src/printer/cvc/cvc_printer.cpp @@ -917,6 +917,7 @@ void CvcPrinter::toStream( case kind::STRING_LENGTH: out << "LENGTH"; break; + case kind::STRING_SUBSTR: out << "SUBSTR"; break; default: Warning() << "Kind printing not implemented for the case of " << n.getKind() << endl; diff --git a/src/proof/arith_proof.cpp b/src/proof/arith_proof.cpp index 1d51f99e1..0d2bb5be0 100644 --- a/src/proof/arith_proof.cpp +++ b/src/proof/arith_proof.cpp @@ -19,10 +19,14 @@ #include <memory> #include <stack> +#include "expr/node.h" #include "proof/proof_manager.h" #include "proof/theory_proof.h" +#include "theory/arith/constraint_forward.h" #include "theory/arith/theory_arith.h" +#define CVC4_ARITH_VAR_TERM_PREFIX "term." + namespace CVC4 { inline static Node eqNode(TNode n1, TNode n2) { @@ -674,151 +678,169 @@ void LFSCArithProof::printOwnedTerm(Expr term, std::ostream& os, const ProofLetM // !d_realMode <--> term.getType().isInteger() Assert (theory::Theory::theoryOf(term) == theory::THEORY_ARITH); - switch (term.getKind()) { + switch (term.getKind()) + { + case kind::CONST_RATIONAL: + { + Assert(term.getNumChildren() == 0); + Assert(term.getType().isInteger() || term.getType().isReal()); - case kind::CONST_RATIONAL: { - Assert (term.getNumChildren() == 0); - Assert (term.getType().isInteger() || term.getType().isReal()); + const Rational& r = term.getConst<Rational>(); + bool neg = (r < 0); - const Rational& r = term.getConst<Rational>(); - bool neg = (r < 0); + os << (!d_realMode ? "(a_int " : "(a_real "); - os << (!d_realMode ? "(a_int " : "(a_real "); + if (neg) + { + os << "(~ "; + } - if (neg) { - os << "(~ "; - } + if (!d_realMode) + { + os << r.abs(); + } + else + { + printRational(os, r.abs()); + } - if (!d_realMode) { - os << r.abs(); - } else { - os << r.abs().getNumerator(); - os << "/"; - os << r.getDenominator(); + if (neg) + { + os << ") "; + } + + os << ") "; + return; } - if (neg) { + case kind::UMINUS: + { + Assert(term.getNumChildren() == 1); + Assert(term.getType().isInteger() || term.getType().isReal()); + os << (!d_realMode ? "(u-_Int " : "(u-_Real "); + d_proofEngine->printBoundTerm(term[0], os, map); os << ") "; + return; } - os << ") "; - return; - } + case kind::PLUS: + { + Assert(term.getNumChildren() >= 2); - case kind::UMINUS: { - Assert (term.getNumChildren() == 1); - Assert (term.getType().isInteger() || term.getType().isReal()); - os << (!d_realMode ? "(u-_Int " : "(u-_Real "); - d_proofEngine->printBoundTerm(term[0], os, map); - os << ") "; - return; - } + std::stringstream paren; + for (unsigned i = 0; i < term.getNumChildren() - 1; ++i) + { + os << (!d_realMode ? "(+_Int " : "(+_Real "); + d_proofEngine->printBoundTerm(term[i], os, map); + os << " "; + paren << ") "; + } - case kind::PLUS: { - Assert (term.getNumChildren() >= 2); + d_proofEngine->printBoundTerm(term[term.getNumChildren() - 1], os, map); + os << paren.str(); + return; + } - std::stringstream paren; - for (unsigned i = 0; i < term.getNumChildren() - 1; ++i) { - os << (!d_realMode ? "(+_Int " : "(+_Real "); - d_proofEngine->printBoundTerm(term[i], os, map); - os << " "; - paren << ") "; + case kind::MINUS: + { + Assert(term.getNumChildren() >= 2); + + std::stringstream paren; + for (unsigned i = 0; i < term.getNumChildren() - 1; ++i) + { + os << (!d_realMode ? "(-_Int " : "(-_Real "); + d_proofEngine->printBoundTerm(term[i], os, map); + os << " "; + paren << ") "; + } + + d_proofEngine->printBoundTerm(term[term.getNumChildren() - 1], os, map); + os << paren.str(); + return; } - d_proofEngine->printBoundTerm(term[term.getNumChildren() - 1], os, map); - os << paren.str(); - return; - } + case kind::MULT: + { + Assert(term.getNumChildren() >= 2); - case kind::MINUS: { - Assert (term.getNumChildren() >= 2); + std::stringstream paren; + for (unsigned i = 0; i < term.getNumChildren() - 1; ++i) + { + os << (!d_realMode ? "(*_Int " : "(*_Real "); + d_proofEngine->printBoundTerm(term[i], os, map); + os << " "; + paren << ") "; + } - std::stringstream paren; - for (unsigned i = 0; i < term.getNumChildren() - 1; ++i) { - os << (!d_realMode ? "(-_Int " : "(-_Real "); - d_proofEngine->printBoundTerm(term[i], os, map); - os << " "; - paren << ") "; + d_proofEngine->printBoundTerm(term[term.getNumChildren() - 1], os, map); + os << paren.str(); + return; } - d_proofEngine->printBoundTerm(term[term.getNumChildren() - 1], os, map); - os << paren.str(); - return; - } + case kind::DIVISION: + case kind::DIVISION_TOTAL: + { + Assert(term.getNumChildren() >= 2); - case kind::MULT: { - Assert (term.getNumChildren() >= 2); + std::stringstream paren; + for (unsigned i = 0; i < term.getNumChildren() - 1; ++i) + { + os << (!d_realMode ? "(/_Int " : "(/_Real "); + d_proofEngine->printBoundTerm(term[i], os, map); + os << " "; + paren << ") "; + } - std::stringstream paren; - for (unsigned i = 0; i < term.getNumChildren() - 1; ++i) { - os << (!d_realMode ? "(*_Int " : "(*_Real "); - d_proofEngine->printBoundTerm(term[i], os, map); - os << " "; - paren << ") "; + d_proofEngine->printBoundTerm(term[term.getNumChildren() - 1], os, map); + os << paren.str(); + return; } - d_proofEngine->printBoundTerm(term[term.getNumChildren() - 1], os, map); - os << paren.str(); - return; - } + case kind::GT: + Assert(term.getNumChildren() == 2); + os << (!d_realMode ? "(>_Int " : "(>_Real "); + d_proofEngine->printBoundTerm(term[0], os, map); + os << " "; + d_proofEngine->printBoundTerm(term[1], os, map); + os << ") "; + return; - case kind::DIVISION: - case kind::DIVISION_TOTAL: { - Assert (term.getNumChildren() >= 2); + case kind::GEQ: + Assert(term.getNumChildren() == 2); + os << (!d_realMode ? "(>=_Int " : "(>=_Real "); + d_proofEngine->printBoundTerm(term[0], os, map); + os << " "; + d_proofEngine->printBoundTerm(term[1], os, map); + os << ") "; + return; - std::stringstream paren; - for (unsigned i = 0; i < term.getNumChildren() - 1; ++i) { - os << (!d_realMode ? "(/_Int " : "(/_Real "); - d_proofEngine->printBoundTerm(term[i], os, map); + case kind::LT: + Assert(term.getNumChildren() == 2); + os << (!d_realMode ? "(<_Int " : "(<_Real "); + d_proofEngine->printBoundTerm(term[0], os, map); os << " "; - paren << ") "; - } + d_proofEngine->printBoundTerm(term[1], os, map); + os << ") "; + return; - d_proofEngine->printBoundTerm(term[term.getNumChildren() - 1], os, map); - os << paren.str(); - return; - } + case kind::LEQ: + Assert(term.getNumChildren() == 2); + os << (!d_realMode ? "(<=_Int " : "(<=_Real "); + d_proofEngine->printBoundTerm(term[0], os, map); + os << " "; + d_proofEngine->printBoundTerm(term[1], os, map); + os << ") "; + return; - case kind::GT: - Assert (term.getNumChildren() == 2); - os << (!d_realMode ? "(>_Int " : "(>_Real "); - d_proofEngine->printBoundTerm(term[0], os, map); - os << " "; - d_proofEngine->printBoundTerm(term[1], os, map); - os << ") "; - return; - - case kind::GEQ: - Assert (term.getNumChildren() == 2); - os << (!d_realMode ? "(>=_Int " : "(>=_Real "); - d_proofEngine->printBoundTerm(term[0], os, map); - os << " "; - d_proofEngine->printBoundTerm(term[1], os, map); - os << ") "; - return; - - case kind::LT: - Assert (term.getNumChildren() == 2); - os << (!d_realMode ? "(<_Int " : "(<_Real "); - d_proofEngine->printBoundTerm(term[0], os, map); - os << " "; - d_proofEngine->printBoundTerm(term[1], os, map); - os << ") "; - return; - - case kind::LEQ: - Assert (term.getNumChildren() == 2); - os << (!d_realMode ? "(<=_Int " : "(<=_Real "); - d_proofEngine->printBoundTerm(term[0], os, map); - os << " "; - d_proofEngine->printBoundTerm(term[1], os, map); - os << ") "; - return; + case kind::VARIABLE: + case kind::SKOLEM: + os << CVC4_ARITH_VAR_TERM_PREFIX << ProofManager::sanitize(term); + return; - default: - Debug("pf::arith") << "Default printing of term: " << term << std::endl; - os << term; - return; + default: + Debug("pf::arith") << "Default printing of term: " << term << std::endl; + os << term; + return; } } @@ -833,26 +855,327 @@ void LFSCArithProof::printOwnedSort(Type type, std::ostream& os) { } } -void LFSCArithProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren, const ProofLetMap& map) { - os << " ;; Arith Theory Lemma \n;;"; - for (unsigned i = 0; i < lemma.size(); ++i) { - os << lemma[i] <<" "; +void LFSCArithProof::printRational(std::ostream& o, const Rational& r) +{ + if (r.sgn() < 0) + { + o << "(~ " << r.getNumerator().abs() << "/" << r.getDenominator().abs() + << ")"; + } + else + { + o << r.getNumerator() << "/" << r.getDenominator(); + } +} + +void LFSCArithProof::printLinearPolynomialNormalizer(std::ostream& o, + const Node& n) +{ + switch (n.getKind()) + { + case kind::PLUS: + { + // Since our axioms are binary, but n may be n-ary, we rig up + // a right-associative tree. + size_t nchildren = n.getNumChildren(); + for (size_t i = 0; i < nchildren; ++i) + { + if (i < nchildren - 1) + { + o << "\n (pn_+ _ _ _ _ _ "; + } + printLinearMonomialNormalizer(o, n[i]); + } + std::fill_n(std::ostream_iterator<char>(o), nchildren - 1, ')'); + break; + } + case kind::MULT: + case kind::VARIABLE: + case kind::CONST_RATIONAL: + case kind::SKOLEM: + { + printLinearMonomialNormalizer(o, n); + break; + } + default: +#ifdef CVC4_ASSERTIONS + std::ostringstream msg; + msg << "Invalid operation " << n.getKind() << " in linear polynomial"; + Unreachable(msg.str().c_str()); +#endif // CVC4_ASSERTIONS + break; + } +} + +void LFSCArithProof::printLinearMonomialNormalizer(std::ostream& o, + const Node& n) +{ + switch (n.getKind()) + { + case kind::MULT: { +#ifdef CVC4_ASSERTIONS + std::ostringstream s; + s << "node " << n << " is not a linear monomial"; + s << " " << n[0].getKind() << " " << n[1].getKind(); + Assert((n[0].getKind() == kind::CONST_RATIONAL + && (n[1].getKind() == kind::VARIABLE + || n[1].getKind() == kind::SKOLEM)), + s.str().c_str()); +#endif // CVC4_ASSERTIONS + + o << "\n (pn_mul_c_L _ _ _ "; + printConstRational(o, n[0]); + o << " "; + printVariableNormalizer(o, n[1]); + o << ")"; + break; + } + case kind::CONST_RATIONAL: + { + o << "\n (pn_const "; + printConstRational(o, n); + o << ")"; + break; + } + case kind::VARIABLE: + case kind::SKOLEM: + { + o << "\n "; + printVariableNormalizer(o, n); + break; + } + default: +#ifdef CVC4_ASSERTIONS + std::ostringstream msg; + msg << "Invalid operation " << n.getKind() << " in linear monomial"; + Unreachable(msg.str().c_str()); +#endif // CVC4_ASSERTIONS + break; + } +} + +void LFSCArithProof::printConstRational(std::ostream& o, const Node& n) +{ + Assert(n.getKind() == kind::CONST_RATIONAL); + const Rational value = n.getConst<Rational>(); + printRational(o, value); +} + +void LFSCArithProof::printVariableNormalizer(std::ostream& o, const Node& n) +{ + std::ostringstream msg; + msg << "Invalid variable kind " << n.getKind() << " in linear monomial"; + Assert(n.getKind() == kind::VARIABLE || n.getKind() == kind::SKOLEM, + msg.str().c_str()); + o << "(pn_var " << n << ")"; +} + +void LFSCArithProof::printLinearPolynomialPredicateNormalizer(std::ostream& o, + const Node& n) +{ + Assert(n.getKind() == kind::GEQ, + "can only print normalization witnesses for (>=) nodes"); + Assert(n[1].getKind() == kind::CONST_RATIONAL); + o << "(poly_formula_norm_>= _ _ _ "; + o << "\n (pn_- _ _ _ _ _ "; + printLinearPolynomialNormalizer(o, n[0]); + o << "\n (pn_const "; + printConstRational(o, n[1]); + o << ")))"; +} + +void LFSCArithProof::printTheoryLemmaProof(std::vector<Expr>& lemma, + std::ostream& os, + std::ostream& paren, + const ProofLetMap& map) +{ + Debug("pf::arith") << "Printing proof for lemma " << lemma << std::endl; + // Prefixes for the names of linearity witnesses + const char* linearityWitnessPrefix = "lp"; + const char* linearizedProofPrefix = "pf_lp"; + std::ostringstream lemmaParen; + + // Construct the set of conflicting literals + std::set<Node> conflictSet; + std::transform(lemma.begin(), + lemma.end(), + std::inserter(conflictSet, conflictSet.begin()), + [](const Expr& e) { + return NodeManager::currentNM()->fromExpr(e).negate(); + }); + + // If we have Farkas coefficients stored for this lemma, use them to write a + // proof. Otherwise, just `trust` the lemma. + if (d_recorder.hasFarkasCoefficients(conflictSet)) + { + // Get farkas coefficients & literal order + const auto& farkasInfo = d_recorder.getFarkasCoefficients(conflictSet); + const Node& conflict = farkasInfo.first; + theory::arith::RationalVectorCP farkasCoefficients = farkasInfo.second; + Assert(farkasCoefficients != theory::arith::RationalVectorCPSentinel); + Assert(conflict.getNumChildren() == farkasCoefficients->size()); + const size_t nAntecedents = conflict.getNumChildren(); + + // Print proof + os << "\n;; Farkas Proof" << std::endl; + + // Construct witness that the literals are linear polynomials + os << "; Linear Polynomial Normalization Witnesses" << std::endl; + for (size_t i = 0; i != nAntecedents; ++i) + { + const Node& antecedent = conflict[i]; + const Rational farkasC = (*farkasCoefficients)[i]; + os << "\n; " << antecedent << " w/ farkas c = " << farkasC << std::endl; + os << " (@ " + << ProofManager::getLitName(antecedent.negate(), + linearityWitnessPrefix) + << " "; + const Node& nonneg = + antecedent.getKind() == kind::NOT ? antecedent[0] : antecedent; + printLinearPolynomialPredicateNormalizer(os, nonneg); + lemmaParen << ")"; + } + + // Prove linear polynomial constraints + os << "\n; Linear Polynomial Proof Conversions"; + for (size_t i = 0; i != nAntecedents; ++i) + { + const Node& antecedent = conflict[i]; + os << "\n (@ " + << ProofManager::getLitName(antecedent.negate(), linearizedProofPrefix) + << " "; + lemmaParen << ")"; + switch (conflict[i].getKind()) + { + case kind::NOT: + { + Assert(conflict[i][0].getKind() == kind::GEQ); + os << "(poly_flip_not_>= _ _ " + << "(poly_form_not _ _ " + << ProofManager::getLitName(antecedent.negate(), + linearityWitnessPrefix) + << " " << ProofManager::getLitName(antecedent.negate(), "") + << "))"; + break; + } + case kind::GEQ: + { + os << "(poly_form _ _ " + << ProofManager::getLitName(antecedent.negate(), + linearityWitnessPrefix) + << " " << ProofManager::getLitName(antecedent.negate(), "") << ")"; + break; + } + default: Unreachable(); + } + } + + /* Combine linear polynomial constraints to derive a contradiction. + * + * The linear polynomial constraints are refered to as **antecedents**, + * since they are antecedents to the contradiction. + * + * The structure of the combination is a tree + * + * (=> <=) + * | + * + 0 + * / \ + * * + 1 + * / \ + * * + 2 + * / \ + * * ... i + * \ + * + n-1 + * / \ + * * (0 >= 0) + * + * Where each * is a linearized antecedant being scaled by a farkas + * coefficient and each + is the sum of inequalities. The tricky bit is that + * each antecedent can be strict (>) or relaxed (>=) and the axiom used for + * each * and + depends on this... The axiom for * depends on the + * strictness of its linear polynomial input, and the axiom for + depends + * on the strictness of **both** its inputs. The contradiction axiom is + * also a function of the strictness of its input. + * + * There are n *s and +s and we precompute + * 1. The strictness of the ith antecedant (`ith_antecedent_is_strict`) + * 2. The strictness of the right argument of the ith sum + * (`ith_acc_is_strict`) + * 3. The strictness of the final result (`strict_contradiction`) + * + * Precomupation is helpful since + * the computation is post-order, + * but printing is pre-order. + */ + std::vector<bool> ith_antecedent_is_strict(nAntecedents, false); + std::vector<bool> ith_acc_is_strict(nAntecedents, false); + for (int i = nAntecedents - 1; i >= 0; --i) + { + ith_antecedent_is_strict[i] = conflict[i].getKind() == kind::NOT; + if (i == (int)nAntecedents - 1) + { + ith_acc_is_strict[i] = false; + } + else + { + ith_acc_is_strict[i] = + ith_acc_is_strict[i + 1] || ith_antecedent_is_strict[i + 1]; + } + } + bool strict_contradiction = + ith_acc_is_strict[0] || ith_antecedent_is_strict[0]; + + // Now, print the proof + os << "\n; Farkas Combination"; + // Choose the appropriate contradiction axiom + os << "\n (lra_contra_" << (strict_contradiction ? ">" : ">=") << " _ "; + for (size_t i = 0; i != nAntecedents; ++i) + { + const Node& lit = conflict[i]; + const char* ante_op = ith_antecedent_is_strict[i] ? ">" : ">="; + const char* acc_op = ith_acc_is_strict[i] ? ">" : ">="; + os << "\n (lra_add_" << ante_op << "_" << acc_op << " _ _ _ "; + os << "\n (lra_mul_c_" << ante_op << " _ _ "; + printRational(os, (*farkasCoefficients)[i].abs()); + os << " " << ProofManager::getLitName(lit.negate(), linearizedProofPrefix) + << ")" + << " ; " << lit; + } + + // The basis, at least, is always the same... + os << "\n (lra_axiom_>= 0/1)"; + std::fill_n(std::ostream_iterator<char>(os), + nAntecedents, + ')'); // close lra_add_*_* + os << ")"; // close lra_contra_* + + os << lemmaParen.str(); // close normalizers and proof-normalizers + } + else + { + os << "\n; Arithmetic proofs which use reasoning more complex than Farkas " + "proofs are currently unsupported\n(clausify_false trust)\n"; } - os <<"\n"; - //os << " (clausify_false trust)"; - ArithProof::printTheoryLemmaProof(lemma, os, paren, map); } void LFSCArithProof::printSortDeclarations(std::ostream& os, std::ostream& paren) { + // Nothing to do here at this point. } void LFSCArithProof::printTermDeclarations(std::ostream& os, std::ostream& paren) { - for (ExprSet::const_iterator it = d_declarations.begin(); it != d_declarations.end(); ++it) { + for (ExprSet::const_iterator it = d_declarations.begin(); + it != d_declarations.end(); + ++it) + { Expr term = *it; Assert(term.isVariable()); - os << "(% " << ProofManager::sanitize(term) << " "; - os << "(term "; - os << term.getType() << ")\n"; + os << "(% " << ProofManager::sanitize(term) << " var_real\n"; + os << "(@ " << CVC4_ARITH_VAR_TERM_PREFIX << ProofManager::sanitize(term) + << " "; + os << "(a_var_real " << ProofManager::sanitize(term) << ")\n"; + paren << ")"; paren << ")"; } } diff --git a/src/proof/arith_proof.h b/src/proof/arith_proof.h index a58294998..640d2db8d 100644 --- a/src/proof/arith_proof.h +++ b/src/proof/arith_proof.h @@ -64,7 +64,7 @@ protected: ExprSet d_declarations; // all the variable/function declarations /** - * @brief Where farkas proofs of lemmas are stored. + * Where farkas proofs of lemmas are stored. */ proof::ArithProofRecorder d_recorder; @@ -86,6 +86,76 @@ public: std::ostream& os, const ProofLetMap& map) override; void printOwnedSort(Type type, std::ostream& os) override; + + /** + * Print a rational number in LFSC format. + * e.g. 5/8 or (~ 1/1) + * + * @param o ostream to print to. + * @param r the rational to print + */ + static void printRational(std::ostream& o, const Rational& r); + + /** + * Print a value of type poly_formula_norm + * + * @param o ostream to print to + * @param n node (asserted to be of the form [linear polynomial >= constant]) + */ + static void printLinearPolynomialPredicateNormalizer(std::ostream& o, + const Node& n); + + /** + * Print a value of type poly_norm + * + * @param o ostream to print to + * @param n node (asserted to be a linear polynomial) + */ + static void printLinearPolynomialNormalizer(std::ostream& o, const Node& n); + + /** + * Print a value of type poly_norm + * + * @param o ostream to print to + * @param n node (asserted to be a linear monomial) + */ + static void printLinearMonomialNormalizer(std::ostream& o, const Node& n); + + /** + * Print a LFSC rational + * + * @param o ostream to print to + * @param n node (asserted to be a const rational) + */ + static void printConstRational(std::ostream& o, const Node& n); + + /** + * print the pn_var normalizer for n (type poly_norm) + * + * @param o the ostream to print to + * @param n the node to print (asserted to be a variable) + */ + static void printVariableNormalizer(std::ostream& o, const Node& n); + /** + * print a proof of the lemma + * + * First, we print linearity witnesses, i.e. witnesses that each literal has + * the form: + * [linear polynomial] >= 0 OR + * [linear polynomial] > 0 + * + * Then we use those witnesses to prove that the above linearized constraints + * hold. + * + * Then we use the farkas coefficients to combine the literals into a + * variable-free contradiction. The literals may be a mix of strict and + * relaxed inequalities. + * + * @param lemma the set of literals disjoined in the lemma + * @param os stream to print the proof to + * @param paren global closing stream (unused) + * @param map let map (unused) + */ void printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren, diff --git a/src/proof/arith_proof_recorder.cpp b/src/proof/arith_proof_recorder.cpp index d654ea073..097fdb51e 100644 --- a/src/proof/arith_proof_recorder.cpp +++ b/src/proof/arith_proof_recorder.cpp @@ -30,17 +30,25 @@ ArithProofRecorder::ArithProofRecorder() : d_lemmasToFarkasCoefficients() void ArithProofRecorder::saveFarkasCoefficients( Node conflict, theory::arith::RationalVectorCP farkasCoefficients) { + // Verify that the conflict is a conjuction of (possibly negated) real bounds + // Verify that the conflict is a conjunciton ... Assert(conflict.getKind() == kind::AND); Assert(conflict.getNumChildren() == farkasCoefficients->size()); - for (size_t i = 0; i < conflict.getNumChildren(); ++i) + for (size_t i = 0, nchildren = conflict.getNumChildren(); i < nchildren; ++i) { const Node& child = conflict[i]; - Assert(child.getType().isBoolean() && child[0].getType().isReal()); + // ... of possibly negated ... + const Node& nonNegativeChild = + child.getKind() == kind::NOT ? child[0] : child; + // ... real bounds + Assert(nonNegativeChild.getType().isBoolean() + && nonNegativeChild[0].getType().isReal()); } Debug("pf::arith") << "Saved Farkas Coefficients:" << std::endl; if (Debug.isOn("pf::arith")) { - for (size_t i = 0; i < conflict.getNumChildren(); ++i) + for (size_t i = 0, nchildren = conflict.getNumChildren(); i < nchildren; + ++i) { const Node& child = conflict[i]; const Rational& r = (*farkasCoefficients)[i]; diff --git a/src/proof/bitvector_proof.cpp b/src/proof/bitvector_proof.cpp index ba3533cc3..90c0c9b30 100644 --- a/src/proof/bitvector_proof.cpp +++ b/src/proof/bitvector_proof.cpp @@ -18,10 +18,13 @@ #include "options/proof_options.h" #include "proof/proof_output_channel.h" #include "proof/theory_proof.h" +#include "prop/sat_solver_types.h" #include "theory/bv/bitblast/bitblaster.h" #include "theory/bv/theory_bv.h" namespace CVC4 { + +namespace proof { BitVectorProof::BitVectorProof(theory::bv::TheoryBV* bv, TheoryProofEngine* proofEngine) : TheoryProof(bv, proofEngine), @@ -118,13 +121,6 @@ std::string BitVectorProof::getBBTermName(Expr expr) return os.str(); } -void BitVectorProof::initCnfProof(prop::CnfStream* cnfStream, - context::Context* cnf) -{ - Assert(d_cnfProof == nullptr); - d_cnfProof.reset(new LFSCCnfProof(cnfStream, cnf, "bb")); -} - void BitVectorProof::printOwnedTerm(Expr term, std::ostream& os, const ProofLetMap& map) @@ -709,6 +705,8 @@ void BitVectorProof::printBitblasting(std::ostream& os, std::ostream& paren) } } +theory::TheoryId BitVectorProof::getTheoryId() { return theory::THEORY_BV; } + const std::set<Node>* BitVectorProof::getAtomsInBitblastingProof() { return &d_atomsInBitblastingProof; @@ -774,4 +772,6 @@ void BitVectorProof::printRewriteProof(std::ostream& os, os << ")"; } +} // namespace proof + } // namespace CVC4 diff --git a/src/proof/bitvector_proof.h b/src/proof/bitvector_proof.h index 466efa6a7..4b897a6c6 100644 --- a/src/proof/bitvector_proof.h +++ b/src/proof/bitvector_proof.h @@ -24,14 +24,28 @@ #include <unordered_map> #include <unordered_set> #include <vector> + #include "expr/expr.h" #include "proof/cnf_proof.h" #include "proof/theory_proof.h" -#include "theory/bv/bitblast/bitblaster.h" +#include "prop/sat_solver.h" #include "theory/bv/theory_bv.h" +// Since TBitblaster and BitVectorProof are cyclically dependent, we need this +// forward declaration +namespace CVC4 { +namespace theory { +namespace bv { +template <class T> +class TBitblaster; +} +} // namespace theory +} // namespace CVC4 + namespace CVC4 { +namespace proof { + typedef std::unordered_set<Expr, ExprHashFunction> ExprSet; typedef std::unordered_map<Expr, ClauseId, ExprHashFunction> ExprToClauseId; typedef std::unordered_map<Expr, unsigned, ExprHashFunction> ExprToId; @@ -118,6 +132,8 @@ class BitVectorProof : public TheoryProof */ std::unique_ptr<CnfProof> d_cnfProof; + theory::TheoryId getTheoryId() override; + public: void printOwnedTerm(Expr term, std::ostream& os, @@ -132,6 +148,28 @@ class BitVectorProof : public TheoryProof virtual void calculateAtomsInBitblastingProof() = 0; /** + * Prints out a declaration of the bit-blasting, and the subsequent + * conversion of the result to CNF + * + * @param os the stream to print to + * @param paren a stream that will be placed at the back of the proof (for + * closing parens) + * @param letMap The let-map, which contains information about LFSC + * identifiers and the values they reference. + */ + virtual void printBBDeclarationAndCnf(std::ostream& os, + std::ostream& paren, + ProofLetMap& letMap) = 0; + + /** + * Prints a proof of the empty clause. + * + * @param os the stream to print to + * @param paren any parentheses to add to the end of the global proof + */ + virtual void printEmptyClauseProof(std::ostream& os, std::ostream& paren) = 0; + + /** * Read the d_atomsInBitblastingProof member. * See its documentation. */ @@ -153,13 +191,41 @@ class BitVectorProof : public TheoryProof /** * This must be done before registering any terms or atoms, since the CNF * proof must reflect the result of bitblasting those + * + * Feeds the SAT solver's true and false variables into the CNF stream. */ - virtual void initCnfProof(prop::CnfStream* cnfStream, context::Context* ctx); + virtual void initCnfProof(prop::CnfStream* cnfStream, + context::Context* cnf, + prop::SatVariable trueVar, + prop::SatVariable falseVar) = 0; CnfProof* getCnfProof() { return d_cnfProof.get(); } + /** + * Attaches this BVP to the given SAT solver, initializing a SAT proof. + * + * This must be invoked before `initCnfProof` because a SAT proof must already + * exist to initialize a CNF proof. + */ + virtual void attachToSatSolver(prop::SatSolver& sat_solver) = 0; + void setBitblaster(theory::bv::TBitblaster<Node>* bb); + /** + * Kind of a mess. Used for resulution-based BVP's, where in eager mode this + * must be invoked before printing a proof of the empty clause. In lazy mode + * the behavior and purpose are both highly unclear. + * + * This exists as a virtual method of BitVectorProof, and not + * ResolutionBitVectorProof, because the machinery that invokes it is + * high-level enough that it doesn't know the difference between clausal and + * resolution proofs. + * + * TODO(aozdemir) figure out what is going on and clean this up + * Issue: https://github.com/CVC4/CVC4/issues/2789 + */ + virtual void finalizeConflicts(std::vector<Expr>& conflicts){}; + private: ExprToString d_exprToVariableName; @@ -206,6 +272,8 @@ class BitVectorProof : public TheoryProof const Node& n2) override; }; +} // namespace proof + }/* CVC4 namespace */ #endif /* __CVC4__BITVECTOR__PROOF_H */ diff --git a/src/proof/clausal_bitvector_proof.cpp b/src/proof/clausal_bitvector_proof.cpp new file mode 100644 index 000000000..bb875d1d8 --- /dev/null +++ b/src/proof/clausal_bitvector_proof.cpp @@ -0,0 +1,115 @@ +/********************* */ +/*! \file clausal_bitvector_proof.cpp + ** \verbatim + ** Top contributors (to current version): + ** Alex Ozdemir + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2019 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 Bitvector proof using the DRAT proof format + ** + ** Contains DRAT-specific printing logic. + **/ + +#include "cvc4_private.h" + +#include <algorithm> +#include <iterator> +#include <set> +#include "options/bv_options.h" +#include "proof/clausal_bitvector_proof.h" +#include "proof/drat/drat_proof.h" +#include "proof/lfsc_proof_printer.h" +#include "theory/bv/theory_bv.h" + +namespace CVC4 { + +namespace proof { + +ClausalBitVectorProof::ClausalBitVectorProof(theory::bv::TheoryBV* bv, + TheoryProofEngine* proofEngine) + : BitVectorProof(bv, proofEngine), d_usedClauses(), d_binaryDratProof() +{ +} + +void ClausalBitVectorProof::attachToSatSolver(prop::SatSolver& sat_solver) +{ + sat_solver.setClausalProofLog(this); +} + +void ClausalBitVectorProof::initCnfProof(prop::CnfStream* cnfStream, + context::Context* cnf, + prop::SatVariable trueVar, + prop::SatVariable falseVar) +{ + Assert(d_cnfProof == nullptr); + d_cnfProof.reset(new LFSCCnfProof(cnfStream, cnf, "bb")); + + // Create a clause which forces the true variable to be true, and register it + int trueClauseId = ClauseId(ProofManager::currentPM()->nextId()); + // with the CNF proof + d_cnfProof->registerTrueUnitClause(trueClauseId); + // and with (this) bit-vector proof + prop::SatClause c{prop::SatLiteral(trueVar, false)}; + registerUsedClause(trueClauseId, c); + + // The same for false. + int falseClauseId = ClauseId(ProofManager::currentPM()->nextId()); + d_cnfProof->registerFalseUnitClause(falseClauseId); + c[0] = prop::SatLiteral(falseVar, true); + registerUsedClause(falseClauseId, c); +} + +void ClausalBitVectorProof::registerUsedClause(ClauseId id, + prop::SatClause& clause) +{ + d_usedClauses.emplace_back( + id, std::unique_ptr<prop::SatClause>(new prop::SatClause(clause))); +}; + +void ClausalBitVectorProof::calculateAtomsInBitblastingProof() +{ + if (Debug.isOn("bv::clausal")) + { + std::string serializedDratProof = d_binaryDratProof.str(); + Debug("bv::clausal") << "binary DRAT proof byte count: " + << serializedDratProof.size() << std::endl; + Debug("bv::clausal") << "Parsing DRAT proof ... " << std::endl; + drat::DratProof dratProof = + drat::DratProof::fromBinary(serializedDratProof); + + Debug("bv::clausal") << "Printing DRAT proof ... " << std::endl; + dratProof.outputAsText(Debug("bv::clausal")); + } + Unimplemented(); +} + +void LfscClausalBitVectorProof::printTheoryLemmaProof(std::vector<Expr>& lemma, + std::ostream& os, + std::ostream& paren, + const ProofLetMap& map) +{ + Unreachable( + "Clausal bit-vector proofs should only be used in combination with eager " + "bitblasting, which **does not use theory lemmas**"); +} + +void LfscClausalBitVectorProof::printBBDeclarationAndCnf(std::ostream& os, + std::ostream& paren, + ProofLetMap& letMap) +{ + Unimplemented(); +} + +void LfscClausalBitVectorProof::printEmptyClauseProof(std::ostream& os, + std::ostream& paren) +{ + Unimplemented(); +} + +} // namespace proof + +}; // namespace CVC4 diff --git a/src/proof/clausal_bitvector_proof.h b/src/proof/clausal_bitvector_proof.h new file mode 100644 index 000000000..85e409e0d --- /dev/null +++ b/src/proof/clausal_bitvector_proof.h @@ -0,0 +1,97 @@ +/********************* */ +/*! \file clausal_bitvector_proof.h + ** \verbatim + ** Top contributors (to current version): + ** Alex Ozdemir + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2019 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 Bitvector proof for clausal (DRAT/LRAT) formats + ** + ** An internal string stream is hooked up to CryptoMiniSat, which spits out a + ** binary DRAT proof. Depending on which kind of proof we're going to turn + ** that into, we process it in different ways. + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__PROOF__CLAUSAL_BITVECTOR_PROOF_H +#define __CVC4__PROOF__CLAUSAL_BITVECTOR_PROOF_H + +#include <iostream> +#include <sstream> +#include <unordered_map> + +#include "expr/expr.h" +#include "proof/bitvector_proof.h" +#include "proof/drat/drat_proof.h" +#include "proof/lrat/lrat_proof.h" +#include "proof/theory_proof.h" +#include "prop/cnf_stream.h" +#include "prop/sat_solver_types.h" +#include "theory/bv/theory_bv.h" + +namespace CVC4 { + +namespace proof { + +class ClausalBitVectorProof : public BitVectorProof +{ + public: + ClausalBitVectorProof(theory::bv::TheoryBV* bv, + TheoryProofEngine* proofEngine); + + ~ClausalBitVectorProof() = default; + + void attachToSatSolver(prop::SatSolver& sat_solver) override; + + void initCnfProof(prop::CnfStream* cnfStream, + context::Context* cnf, + prop::SatVariable trueVar, + prop::SatVariable falseVar) override; + + std::ostream& getDratOstream() { return d_binaryDratProof; } + + void registerUsedClause(ClauseId id, prop::SatClause& clause); + + void calculateAtomsInBitblastingProof() override; + + protected: + // A list of all clauses and their ids which are passed into the SAT solver + std::vector<std::pair<ClauseId, std::unique_ptr<prop::SatClause>>> + d_usedClauses; + // Stores the proof recieved from the SAT solver. + std::ostringstream d_binaryDratProof; +}; + +/** + * A representation of a clausal proof of a bitvector problem's UNSAT nature + */ +class LfscClausalBitVectorProof : public ClausalBitVectorProof +{ + public: + LfscClausalBitVectorProof(theory::bv::TheoryBV* bv, + TheoryProofEngine* proofEngine) + : ClausalBitVectorProof(bv, proofEngine) + { + // That's all! + } + + void printTheoryLemmaProof(std::vector<Expr>& lemma, + std::ostream& os, + std::ostream& paren, + const ProofLetMap& map) override; + void printBBDeclarationAndCnf(std::ostream& os, + std::ostream& paren, + ProofLetMap& letMap) override; + void printEmptyClauseProof(std::ostream& os, std::ostream& paren) override; +}; + +} // namespace proof + +} // namespace CVC4 + +#endif /* __CVC4__PROOF__CLAUSAL_BITVECTOR_PROOF_H */ diff --git a/src/proof/cnf_proof.cpp b/src/proof/cnf_proof.cpp index 016198735..4e8d20162 100644 --- a/src/proof/cnf_proof.cpp +++ b/src/proof/cnf_proof.cpp @@ -105,6 +105,30 @@ void CnfProof::registerConvertedClause(ClauseId clause, bool explanation) { setClauseDefinition(clause, current_expr); } +void CnfProof::registerTrueUnitClause(ClauseId clauseId) +{ + Node trueNode = NodeManager::currentNM()->mkConst<bool>(true); + pushCurrentAssertion(trueNode); + pushCurrentDefinition(trueNode); + registerConvertedClause(clauseId); + popCurrentAssertion(); + popCurrentDefinition(); + d_cnfStream->ensureLiteral(trueNode); + d_trueUnitClause = clauseId; +} + +void CnfProof::registerFalseUnitClause(ClauseId clauseId) +{ + Node falseNode = NodeManager::currentNM()->mkConst<bool>(false).notNode(); + pushCurrentAssertion(falseNode); + pushCurrentDefinition(falseNode); + registerConvertedClause(clauseId); + popCurrentAssertion(); + popCurrentDefinition(); + d_cnfStream->ensureLiteral(falseNode); + d_falseUnitClause = clauseId; +} + void CnfProof::setClauseAssertion(ClauseId clause, Node expr) { Debug("proof:cnf") << "CnfProof::setClauseAssertion " << clause << " assertion " << expr << std::endl; diff --git a/src/proof/cnf_proof.h b/src/proof/cnf_proof.h index 32833d9a1..78ddeebd0 100644 --- a/src/proof/cnf_proof.h +++ b/src/proof/cnf_proof.h @@ -78,6 +78,11 @@ protected: ClauseIdSet d_explanations; + // The clause ID of the unit clause defining the true SAT literal. + ClauseId d_trueUnitClause; + // The clause ID of the unit clause defining the false SAT literal. + ClauseId d_falseUnitClause; + bool isDefinition(Node node); Node getDefinitionForClause(ClauseId clause); @@ -110,6 +115,14 @@ public: // already in CNF void registerConvertedClause(ClauseId clause, bool explanation=false); + // The CNF proof has a special relationship to true and false. + // In particular, it need to know the identity of clauses defining + // canonical true and false literals in the underlying SAT solver. + void registerTrueUnitClause(ClauseId clauseId); + void registerFalseUnitClause(ClauseId clauseId); + inline ClauseId getTrueUnitClause() { return d_trueUnitClause; }; + inline ClauseId getFalseUnitClause() { return d_falseUnitClause; }; + /** Clause is one of the clauses defining the node expression*/ void setClauseDefinition(ClauseId clause, Node node); diff --git a/src/proof/drat/drat_proof.cpp b/src/proof/drat/drat_proof.cpp new file mode 100644 index 000000000..c2f2fa49e --- /dev/null +++ b/src/proof/drat/drat_proof.cpp @@ -0,0 +1,287 @@ +/********************* */ +/*! \file drat_proof.cpp + ** \verbatim + ** Top contributors (to current version): + ** Alex Ozdemir + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2018 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 DRAT Proof Format + ** + ** Defines deserialization for DRAT proofs. + **/ + +#include "proof/drat/drat_proof.h" + +#include <algorithm> +#include <bitset> +#include <iostream> + +#include "proof/proof_manager.h" + +namespace CVC4 { +namespace proof { +namespace drat { + +// helper functions for parsing the binary DRAT format. + +/** + * Parses a binary literal which starts at `start` and must not go beyond `end` + * + * Leaves the iterator one past the last byte that is a part of the clause. + * + * If the literal overruns `end`, then raises a `InvalidDratProofException`. + */ +SatLiteral parse_binary_literal(std::string::const_iterator& start, + const std::string::const_iterator& proof_end) +{ + // lit is encoded as uint represented by a variable-length byte sequence + uint64_t literal_represented_as_uint = 0; + for (uint8_t shift = 0; start != proof_end; ++start, shift += 7) + { + // Check whether shift is so large that we're going to lose some + // information + if (shift + 7 >= 64) + { + throw InvalidDratProofException( + "While parsing a DRAT proof, encountered a literal that was too " + "long"); + } + unsigned char byte = *start; + // The MSB of the byte is an indicator of whether the sequence continues + bool continued = (byte >> 7) & 1; + uint64_t numeric_part = byte & 0x7f; + literal_represented_as_uint |= numeric_part << shift; + if (!continued) + { + // LSB of `literal_represented_as_uint` indicates negation. + bool negated = literal_represented_as_uint & 1; + // Rest is the literal number + SatVariable var_number = literal_represented_as_uint >> 1; + ++start; + // Internal clauses start at 0, external ones start at 1. + return SatLiteral(var_number - 1, negated); + } + } + throw InvalidDratProofException( + "Literal in DRAT proof was not done when " + "EOF was encountered"); +} + +/** + * Parses a binary clause which starts at `start` and must not go beyond `end` + * + * Leaves the iterator one past the last byte that is a part of the clause. + * That is, one past the null byte. + * + * If the clause overruns `end`, then raises a `InvalidDratProofException`. + */ +SatClause parse_binary_clause(std::string::const_iterator& start, + const std::string::const_iterator& proof_end) +{ + SatClause clause; + // A clause is a 0-terminated sequence of literals + while (start != proof_end) + { + // Is the clause done? + if (*start == 0) + { + ++start; + return clause; + } + else + { + // If not, parse another literal + clause.emplace_back(parse_binary_literal(start, proof_end)); + } + } + // We've overrun the end of the byte stream. + throw InvalidDratProofException( + "Clause in DRAT proof was not done when " + "EOF was encountered"); +} + +/** + * Writes this SAT literal in the textual DIMACS format. i.e. as a non-zero + * integer. + * + * Since internally +0 and -0 are valid literals, we add one to each + * literal's number (SAT variable) when outputtting it. + * + * @param os the stream to write to + * @param l the literal to write + */ +void outputLiteralAsDimacs(std::ostream& os, SatLiteral l) +{ + if (l.isNegated()) + { + os << '-'; + } + // add 1 to convert between internal literals and their DIMACS + // representaations. + os << l.getSatVariable() + 1; +} + +// DratInstruction implementation + +DratInstruction::DratInstruction(DratInstructionKind kind, SatClause clause) + : d_kind(kind), d_clause(clause) +{ + // All intialized +} + +void DratInstruction::outputAsText(std::ostream& os) const +{ + switch (d_kind) + { + case DratInstructionKind::ADDITION: + { + for (const SatLiteral& l : d_clause) + { + outputLiteralAsDimacs(os, l); + os << ' '; + } + os << '0' << std::endl; + break; + } + case DratInstructionKind::DELETION: + { + os << "d "; + for (const SatLiteral& l : d_clause) + { + outputLiteralAsDimacs(os, l); + os << ' '; + } + os << '0' << std::endl; + break; + } + default: { Unreachable("Unknown DRAT instruction kind"); + } + } +} + +// DratProof implementation + +DratProof::DratProof() : d_instructions() {} + +// See the "binary format" section of +// https://www.cs.utexas.edu/~marijn/drat-trim/ +DratProof DratProof::fromBinary(const std::string& s) +{ + DratProof proof; + if (Debug.isOn("pf::drat")) + { + Debug("pf::drat") << "Parsing binary DRAT proof" << std::endl; + Debug("pf::drat") << "proof length: " << s.length() << " bytes" + << std::endl; + Debug("pf::drat") << "proof as bytes: "; + for (char i : s) + { + if (i == 'a' || i == 'd') + { + Debug("pf::drat") << std::endl << " " << std::bitset<8>(i); + } + else + { + Debug("pf::drat") << " " << std::bitset<8>(i); + } + } + Debug("pf::drat") << std::endl << "parsing proof..." << std::endl; + } + + // For each instruction + for (auto i = s.cbegin(), end = s.cend(); i != end;) + { + switch (*i) + { + case 'a': + { + ++i; + proof.d_instructions.emplace_back(ADDITION, + parse_binary_clause(i, end)); + break; + } + case 'd': + { + ++i; + proof.d_instructions.emplace_back(DELETION, + parse_binary_clause(i, end)); + break; + } + default: + { + std::ostringstream s; + s << "Invalid instruction in Drat proof. Instruction bits: " + << std::bitset<8>(*i) + << ". Expected 'a' (01100001) or 'd' " + "(01100100)."; + throw InvalidDratProofException(s.str()); + } + } + } + + if (Debug.isOn("pf::drat")) + { + Debug("pf::drat") << "Printing out DRAT in textual format:" << std::endl; + proof.outputAsText(Debug("pf::drat")); + } + + return proof; +}; + +const std::vector<DratInstruction>& DratProof::getInstructions() const +{ + return d_instructions; +}; + +void DratProof::outputAsText(std::ostream& os) const +{ + for (const DratInstruction& instruction : d_instructions) + { + instruction.outputAsText(os); + os << "\n"; + } +}; + +void DratProof::outputAsLfsc(std::ostream& os, uint8_t indentation) const +{ + for (const DratInstruction& i : d_instructions) + { + if (indentation > 0) + { + std::fill_n(std::ostream_iterator<char>(os), indentation, ' '); + } + os << "("; + switch (i.d_kind) + { + case ADDITION: + { + os << "DRATProofa"; + break; + } + case DELETION: + { + os << "DRATProofd"; + break; + } + default: { Unreachable("Unrecognized DRAT instruction kind"); + } + } + for (const SatLiteral& l : i.d_clause) + { + os << "(clc (" << (l.isNegated() ? "neg " : "pos ") + << ProofManager::getVarName(l.getSatVariable()) << ") "; + } + os << "cln"; + std::fill_n(std::ostream_iterator<char>(os), i.d_clause.size(), ')'); + os << "\n"; + } + os << "DRATProofn"; + std::fill_n(std::ostream_iterator<char>(os), d_instructions.size(), ')'); +} +} // namespace drat +} // namespace proof +} // namespace CVC4 diff --git a/src/proof/drat/drat_proof.h b/src/proof/drat/drat_proof.h new file mode 100644 index 000000000..4715b38f4 --- /dev/null +++ b/src/proof/drat/drat_proof.h @@ -0,0 +1,140 @@ +/********************* */ +/*! \file drat_proof.h + ** \verbatim + ** Top contributors (to current version): + ** Alex Ozdemir + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2018 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 DRAT Proof Format + ** + ** Declares C++ types that represent a DRAT proof. + ** Defines serialization for these types. + ** + ** You can find an introduction to DRAT in the drat-trim paper: + ** http://www.cs.utexas.edu/~marijn/publications/drat-trim.pdf + ** + **/ + +#ifndef __CVC4__PROOF__DRAT__DRAT_PROOF_H +#define __CVC4__PROOF__DRAT__DRAT_PROOF_H + +#include "cvc4_private.h" +#include "prop/sat_solver.h" +#include "prop/sat_solver_types.h" + +namespace CVC4 { +namespace proof { +namespace drat { + +using CVC4::prop::SatClause; +using CVC4::prop::SatLiteral; +using CVC4::prop::SatVariable; + +class CVC4_PUBLIC InvalidDratProofException : public CVC4::Exception +{ + public: + InvalidDratProofException() : Exception("Invalid DRAT Proof") {} + + InvalidDratProofException(const std::string& msg) : Exception(msg) {} + + InvalidDratProofException(const char* msg) : Exception(msg) {} +}; /* class InvalidDratProofException */ + +enum DratInstructionKind +{ + ADDITION, + DELETION +}; + +struct DratInstruction +{ + DratInstruction(DratInstructionKind kind, SatClause clause); + + /** + * Write the DRAT instruction in textual format. + * The format is described in: + * http://www.cs.utexas.edu/~marijn/publications/drat-trim.pdf + * + * @param os the stream to write to + */ + void outputAsText(std::ostream& os) const; + + DratInstructionKind d_kind; + SatClause d_clause; +}; + +class DratProof +{ + public: + DratProof(const DratProof&) = default; + + DratProof(DratProof&&) = default; + + ~DratProof() = default; + + /** + * Parses a DRAT proof from the **binary format**. + * The format is described at: + * https://www.cs.utexas.edu/~marijn/drat-trim/#contact + * + * What do the standard authors mean by the format being "binary"? + * They just mean that proofs in this format should be understood as + * sequences of bytes, not sequences of ASCII/Unicode/your favorite character + * set characters. + * + * @param binaryProof a string containing the bytes of the binary proof. + * Even though the proof isn't text, it's safe to store it in a string + * because C++ strings don't make any gaurantees about the encoding of + * their contents. This makes them (effectively) just byte sequences. + * + * @return the parsed proof + */ + static DratProof fromBinary(const std::string& binaryProof); + + /** + * @return The instructions in this proof + */ + const std::vector<DratInstruction>& getInstructions() const; + + /** + * Write the DRAT proof in textual format. + * The format is described in: + * http://www.cs.utexas.edu/~marijn/publications/drat-trim.pdf + * + * @param os the stream to write to + */ + void outputAsText(std::ostream& os) const; + + /** + * Write the DRAT proof as an LFSC value + * The format is from the LFSC signature drat.plf + * + * Reads the current `ProofManager` to determine what the variables should be + * named. + * + * @param os the stream to write to + * @param indentation the number of spaces to indent each proof instruction + */ + void outputAsLfsc(std::ostream& os, uint8_t indentation) const; + + private: + /** + * Create an DRAT proof with no instructions. + */ + DratProof(); + + /** + * The instructions of the DRAT proof. + */ + std::vector<DratInstruction> d_instructions; +}; + +} // namespace drat +} // namespace proof +} // namespace CVC4 + +#endif // __CVC4__PROOF__DRAT__DRAT_PROOF_H diff --git a/src/proof/lfsc_proof_printer.cpp b/src/proof/lfsc_proof_printer.cpp index e1fa3acdb..be1259837 100644 --- a/src/proof/lfsc_proof_printer.cpp +++ b/src/proof/lfsc_proof_printer.cpp @@ -16,7 +16,9 @@ #include "proof/lfsc_proof_printer.h" +#include <algorithm> #include <iostream> +#include <iterator> #include "prop/bvminisat/core/Solver.h" #include "prop/minisat/core/Solver.h" @@ -144,6 +146,45 @@ void LFSCProofPrinter::printResolutionEmptyClause(TSatProof<Solver>* satProof, printResolution(satProof, satProof->getEmptyClauseId(), out, paren); } +void LFSCProofPrinter::printSatInputProof(const std::vector<ClauseId>& clauses, + std::ostream& out, + const std::string& namingPrefix) +{ + for (auto i = clauses.begin(), end = clauses.end(); i != end; ++i) + { + out << "\n (cnfc_proof _ _ _ " + << ProofManager::getInputClauseName(*i, namingPrefix) << " "; + } + out << "cnfn_proof"; + std::fill_n(std::ostream_iterator<char>(out), clauses.size(), ')'); +} + +void LFSCProofPrinter::printCMapProof(const std::vector<ClauseId>& clauses, + std::ostream& out, + const std::string& namingPrefix) +{ + for (size_t i = 0, n = clauses.size(); i < n; ++i) + { + out << "\n (CMapc_proof " << (i + 1) << " _ _ _ " + << ProofManager::getInputClauseName(clauses[i], namingPrefix) << " "; + } + out << "CMapn_proof"; + std::fill_n(std::ostream_iterator<char>(out), clauses.size(), ')'); +} + +void LFSCProofPrinter::printSatClause(const prop::SatClause& clause, + std::ostream& out, + const std::string& namingPrefix) +{ + for (auto i = clause.cbegin(); i != clause.cend(); ++i) + { + out << "(clc " << (i->isNegated() ? "(neg " : "(pos ") + << ProofManager::getVarName(i->getSatVariable(), namingPrefix) << ") "; + } + out << "cln"; + std::fill_n(std::ostream_iterator<char>(out), clause.size(), ')'); +} + // Template specializations template void LFSCProofPrinter::printAssumptionsResolution( TSatProof<CVC4::Minisat::Solver>* satProof, diff --git a/src/proof/lfsc_proof_printer.h b/src/proof/lfsc_proof_printer.h index bf4bfabad..36a3490f7 100644 --- a/src/proof/lfsc_proof_printer.h +++ b/src/proof/lfsc_proof_printer.h @@ -74,7 +74,56 @@ class LFSCProofPrinter std::ostream& out, std::ostream& paren); + /** + * The SAT solver is given a list of clauses. + * Assuming that each clause has alreay been individually proven, + * defines a proof of the input to the SAT solver. + * + * Prints an LFSC value corresponding to the proof, i.e. a value of type + * (cnf_holds ...) + * + * @param clauses The clauses to print a proof of + * @param out The stream to print to + * @param namingPrefix The prefix for LFSC names + */ + static void printSatInputProof(const std::vector<ClauseId>& clauses, + std::ostream& out, + const std::string& namingPrefix); + + /** + * The LRAT proof signature uses the concept of a _clause map_ (CMap), which + * represents an indexed collection of (conjoined) clauses. + * + * Specifically, the signatures rely on a proof that a CMap containing the + * clauses given to the SAT solver hold. + * + * Assuming that the individual clauses already have proofs, this function + * prints a proof of the CMap mapping 1 to the first clause, 2 to the second, + * and so on. + * + * That is, it prints a value of type (CMap_holds ...) + * + * @param clauses The clauses to print a proof of + * @param out The stream to print to + * @param namingPrefix The prefix for LFSC names + */ + static void printCMapProof(const std::vector<ClauseId>& clauses, + std::ostream& out, + const std::string& namingPrefix); + + /** + * Prints a clause + * + * @param clause The clause to print + * @param out The stream to print to + * @param namingPrefix The prefix for LFSC names + */ + static void printSatClause(const prop::SatClause& clause, + std::ostream& out, + const std::string& namingPrefix); + private: + /** * Maps a clause id to a string identifier used in the LFSC proof. * diff --git a/src/proof/lrat/lrat_proof.cpp b/src/proof/lrat/lrat_proof.cpp new file mode 100644 index 000000000..3b4bac3f0 --- /dev/null +++ b/src/proof/lrat/lrat_proof.cpp @@ -0,0 +1,385 @@ +/********************* */ +/*! \file lrat_proof.cpp + ** \verbatim + ** Top contributors (to current version): + ** Alex Ozdemir + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2018 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 DRAT Proof Format + ** + ** Defines deserialization for DRAT proofs. + **/ + +#include "proof/lrat/lrat_proof.h" + +#include <algorithm> +#include <cstdlib> +#include <fstream> +#include <iostream> +#include <memory> +#include <sstream> +#include <unordered_map> + +#include "base/cvc4_assert.h" +#include "base/output.h" +#include "proof/lfsc_proof_printer.h" + +#if CVC4_USE_DRAT2ER +#include "drat2er_options.h" +#include "drat_trim_interface.h" +#endif + +namespace CVC4 { +namespace proof { +namespace lrat { + +using prop::SatClause; +using prop::SatLiteral; +using prop::SatVariable; + +namespace { +// Prints the literal as a (+) or (-) int +// Not operator<< b/c that represents negation as ~ +std::ostream& textOut(std::ostream& o, const SatLiteral& l) +{ + if (l.isNegated()) + { + o << "-"; + } + return o << l.getSatVariable(); +} + +// Prints the clause as a space-separated list of ints +// Not operator<< b/c that represents negation as ~ +std::ostream& textOut(std::ostream& o, const SatClause& c) +{ + for (const auto l : c) + { + textOut(o, l) << " "; + } + return o << "0"; +} + +// Prints the trace as a space-separated list of (+) ints with a space at the +// end. +std::ostream& operator<<(std::ostream& o, const LratUPTrace& trace) +{ + for (const auto& i : trace) + { + o << i << " "; + } + return o; +} + +/** + * Print a list of clause indices to go to while doing UP. + * + * i.e. a value of type Trace + * + * @param o where to print to + * @param trace the trace (list of clauses) to print + */ +void printTrace(std::ostream& o, const LratUPTrace& trace) +{ + for (ClauseIdx idx : trace) + { + o << "(Tracec " << idx << " "; + } + o << "Tracen"; + std::fill_n(std::ostream_iterator<char>(o), trace.size(), ')'); +} + +/** + * Print the RAT hints for a clause addition. + * + * i.e. prints an LFSC value of type RATHints + * + * @param o where to print to + * @param hints the RAT hints to print + */ +void printHints(std::ostream& o, + const std::vector<std::pair<ClauseIdx, LratUPTrace>>& hints) +{ + for (auto& hint : hints) + { + o << "\n (RATHintsc " << hint.first << " "; + printTrace(o, hint.second); + o << " "; + } + o << "RATHintsn"; + std::fill_n(std::ostream_iterator<char>(o), hints.size(), ')'); +} + +/** + * Print an index list + * + * i.e. prints an LFSC value of type CIList + * + * @param o where to print to + * @param indices the list of indices to print + */ +void printIndices(std::ostream& o, const std::vector<ClauseIdx>& indices) +{ + // Verify that the indices are sorted! + for (size_t i = 0, n = indices.size() - 1; i < n; ++i) + { + Assert(indices[i] < indices[i + 1]); + } + + for (ClauseIdx idx : indices) + { + o << "(CIListc " << idx << " "; + } + o << "CIListn"; + std::fill_n(std::ostream_iterator<char>(o), indices.size(), ')'); +} + +} // namespace + +// Prints the LRAT addition line in textual format + +LratProof LratProof::fromDratProof( + const std::unordered_map<ClauseId, SatClause*>& usedClauses, + const std::vector<ClauseId>& clauseOrder, + const std::string& dratBinary) +{ + std::ostringstream cmd; + char formulaFilename[] = "/tmp/cvc4-dimacs-XXXXXX"; + char dratFilename[] = "/tmp/cvc4-drat-XXXXXX"; + char lratFilename[] = "/tmp/cvc4-lrat-XXXXXX"; + int r; + r = mkstemp(formulaFilename); + AlwaysAssert(r > 0); + close(r); + r = mkstemp(dratFilename); + AlwaysAssert(r > 0); + close(r); + r = mkstemp(lratFilename); + AlwaysAssert(r > 0); + close(r); + std::ofstream formStream(formulaFilename); + size_t maxVar = 0; + for (auto& c : usedClauses) + { + for (auto l : *(c.second)) + { + if (l.getSatVariable() + 1 > maxVar) + { + maxVar = l.getSatVariable() + 1; + } + } + } + formStream << "p cnf " << maxVar << " " << usedClauses.size() << '\n'; + for (auto ci : clauseOrder) + { + auto iterator = usedClauses.find(ci); + Assert(iterator != usedClauses.end()); + for (auto l : *(iterator->second)) + { + if (l.isNegated()) + { + formStream << '-'; + } + formStream << l.getSatVariable() + 1 << " "; + } + formStream << "0\n"; + } + formStream.close(); + + std::ofstream dratStream(dratFilename); + dratStream << dratBinary; + dratStream.close(); + +#if CVC4_USE_DRAT2ER + drat2er::drat_trim::CheckAndConvertToLRAT( + formulaFilename, dratFilename, lratFilename, drat2er::options::QUIET); +#else + Unimplemented("LRAT proof production requires drat2er.\n" + "Run contrib/get-drat2er, reconfigure with --drat2er, and rebuild"); +#endif + + std::ifstream lratStream(lratFilename); + LratProof lrat(lratStream); + remove(formulaFilename); + remove(dratFilename); + remove(lratFilename); + return lrat; +} + +std::istream& operator>>(std::istream& in, SatLiteral& l) +{ + int64_t i; + in >> i; + l = SatLiteral(std::abs(i), i < 0); + return in; +} + +// This parser is implemented to parse the textual RAT format found in +// "Efficient Certified RAT Verification", by Cruz-Filipe et. All +LratProof::LratProof(std::istream& textualProof) +{ + for (size_t line = 0;; ++line) + { + // Read beginning of instruction. EOF indicates that we're done. + size_t clauseIdx; + textualProof >> clauseIdx; + if (textualProof.eof()) + { + return; + } + + // Read the first word of the instruction. A 'd' indicates deletion. + std::string first; + textualProof >> first; + Trace("pf::lrat") << "First word: " << first << std::endl; + Assert(textualProof.good()); + if (first == "d") + { + std::vector<ClauseIdx> clauses; + while (true) + { + ClauseIdx di; + textualProof >> di; + Assert(textualProof.good()); + if (di == 0) + { + break; + } + clauses.push_back(di); + } + std::sort(clauses.begin(), clauses.end()); + std::unique_ptr<LratInstruction> instr( + new LratDeletion(clauseIdx, std::move(clauses))); + d_instructions.push_back(std::move(instr)); + } + else + { + // We need to reparse the first word as a literal to read the clause + // we're parsing. It ends with a 0; + std::istringstream firstS(first); + SatLiteral lit; + firstS >> lit; + Trace("pf::lrat") << "First lit: " << lit << std::endl; + Assert(!firstS.fail(), "Couldn't parse first literal from addition line"); + + SatClause clause; + for (; lit != 0; textualProof >> lit) + { + Assert(textualProof.good()); + clause.emplace_back(lit.getSatVariable() - 1, lit.isNegated()); + } + + // Now we read the AT UP trace. It ends at the first non-(+) # + std::vector<ClauseIdx> atTrace; + int64_t i; + textualProof >> i; + for (; i > 0; textualProof >> i) + { + Assert(textualProof.good()); + atTrace.push_back(i); + } + + // For each RAT hint... (each RAT hint starts with a (-)). + std::vector<std::pair<ClauseIdx, LratUPTrace>> resolvants; + for (; i<0; textualProof>> i) + { + Assert(textualProof.good()); + // Create an entry in the RAT hint list + resolvants.emplace_back(-i, std::vector<ClauseIdx>()); + + // Record the UP trace. It ends with a (-) or 0. + textualProof >> i; + for (; i > 0; textualProof >> i) + { + resolvants.back().second.push_back(i); + } + } + // Pairs compare based on the first element, so this sorts by the + // resolution target index + std::sort(resolvants.begin(), resolvants.end()); + std::unique_ptr<LratInstruction> instr( + new LratAddition(clauseIdx, + std::move(clause), + std::move(atTrace), + std::move(resolvants))); + d_instructions.push_back(std::move(instr)); + } + } +} + +void LratProof::outputAsLfsc(std::ostream& o) const +{ + std::ostringstream closeParen; + for (const auto& i : d_instructions) + { + i->outputAsLfsc(o, closeParen); + } + o << "LRATProofn"; + o << closeParen.str(); +} + +void LratAddition::outputAsText(std::ostream& o) const +{ + o << d_idxOfClause << " "; + textOut(o, d_clause) << " "; + o << d_atTrace; // Inludes a space at the end. + for (const auto& rat : d_resolvants) + { + o << "-" << rat.first << " "; + o << rat.second; // Includes a space at the end. + } + o << "0\n"; +} + +void LratAddition::outputAsLfsc(std::ostream& o, std::ostream& closeParen) const +{ + o << "\n (LRATProofa " << d_idxOfClause << " "; + closeParen << ")"; + LFSCProofPrinter::printSatClause(d_clause, o, "bb"); + o << " "; + printTrace(o, d_atTrace); + o << " "; + printHints(o, d_resolvants); + o << " "; +} + +void LratDeletion::outputAsText(std::ostream& o) const +{ + o << d_idxOfClause << " d "; + for (const auto& idx : d_clauses) + { + o << idx << " "; + } + o << "0\n"; +} + +void LratDeletion::outputAsLfsc(std::ostream& o, std::ostream& closeParen) const +{ + o << "\n (LRATProofd "; + closeParen << ")"; + printIndices(o, d_clauses); + o << " "; +} + +std::ostream& operator<<(std::ostream& o, const LratProof& p) +{ + for (const auto& instr : p.getInstructions()) + { + o << *instr; + } + return o; +} + +std::ostream& operator<<(std::ostream& o, const LratInstruction& i) +{ + i.outputAsText(o); + return o; +} + +} // namespace lrat +} // namespace proof +} // namespace CVC4 diff --git a/src/proof/lrat/lrat_proof.h b/src/proof/lrat/lrat_proof.h new file mode 100644 index 000000000..fb05bd71b --- /dev/null +++ b/src/proof/lrat/lrat_proof.h @@ -0,0 +1,182 @@ +/********************* */ +/*! \file lrat_proof.h + ** \verbatim + ** Top contributors (to current version): + ** Alex Ozdemir + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2018 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 LRAT Proof Format + ** + ** Declares C++ types that represent a LRAT proof. + ** Defines serialization for these types. + ** + ** Represents an **abstract** LRAT proof. + ** Does **not** represent an LFSC LRAT proof, or an LRAT proof being used to + ** prove things about bit-vectors. + ** + ** Paper on LRAT: https://www.cs.utexas.edu/~marijn/publications/lrat.pdf + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__PROOF__LRAT__LRAT_PROOF_H +#define __CVC4__PROOF__LRAT__LRAT_PROOF_H + +#include <iosfwd> +#include <string> +#include <unordered_map> +#include <vector> + +#include "proof/clause_id.h" +// Included because we need operator<< for the SAT types +#include "prop/sat_solver.h" + +namespace CVC4 { +namespace proof { +namespace lrat { + +// Refers to clause position within an LRAT proof +using ClauseIdx = size_t; + +// This is conceptually an Either<Addition,Deletion> +class LratInstruction +{ + public: + /** + * Write this LRAT instruction in textual format + * + * @param out the stream to write to + */ + virtual void outputAsText(std::ostream& out) const = 0; + /** + * Write this LRAT instruction as an LFSC value + * + * @param out the stream to write to + * @param closeParen the stream to write any closing parentheses to + * + */ + virtual void outputAsLfsc(std::ostream& o, + std::ostream& closeParen) const = 0; + virtual ~LratInstruction() = default; +}; + +class LratDeletion : public LratInstruction +{ + public: + LratDeletion(ClauseIdx idxOfClause, std::vector<ClauseIdx>&& clauses) + : d_idxOfClause(idxOfClause), d_clauses(clauses) + { + // Nothing left to do + } + + LratDeletion() = default; + + void outputAsText(std::ostream& out) const override; + void outputAsLfsc(std::ostream& o, std::ostream& closeParen) const override; + + private: + // This idx doesn't really matter, but it's in the format anyway, so we parse + // it. + ClauseIdx d_idxOfClause; + + // Clauses to delete + std::vector<ClauseIdx> d_clauses; +}; + +// A sequence of locations that will contain unit clauses during unit +// propegation +using LratUPTrace = std::vector<ClauseIdx>; + +class LratAddition : public LratInstruction +{ + public: + LratAddition(ClauseIdx idxOfClause, + prop::SatClause&& clause, + LratUPTrace&& atTrace, + std::vector<std::pair<ClauseIdx, LratUPTrace>> resolvants) + : d_idxOfClause(idxOfClause), + d_clause(clause), + d_atTrace(atTrace), + d_resolvants(resolvants) + { + // Nothing left to do + } + + void outputAsText(std::ostream& out) const override; + void outputAsLfsc(std::ostream& o, std::ostream& closeParen) const override; + + private: + // The idx for the new clause + ClauseIdx d_idxOfClause; + // The new clause + prop::SatClause d_clause; + // UP trace based on the negation of that clause + LratUPTrace d_atTrace; + + // Clauses that can resolve with `clause` on its first variable, + // together with a UP trace after that resolution. + // Used for RAT checks. + std::vector<std::pair<ClauseIdx, LratUPTrace>> d_resolvants; +}; + +class LratProof +{ + public: + /** + * @brief Construct an LRAT proof from a DRAT proof, using drat-trim + * + * @param usedClauses The CNF formula that we're deriving bottom from. + * It's a map because other parts of the system represent + * it this way. + * @param clauseOrder A record of the order in which those clauses were + * given to the SAT solver. + * @param dratBinary The DRAT proof from the SAT solver, as a binary stream. + */ + static LratProof fromDratProof( + const std::unordered_map<ClauseId, prop::SatClause*>& usedClauses, + const std::vector<ClauseId>& clauseOrder, + const std::string& dratBinary); + /** + * @brief Construct an LRAT proof from its textual representation + * + * @param textualProof the textual encoding of the LRAT proof. See the paper + * in the file's header comment. + */ + LratProof(std::istream& textualProof); + + /** + * Construct a LRAT proof from an explicit instruction list + * + * @param instructions + */ + LratProof(std::vector<std::unique_ptr<LratInstruction>>&& instructions) + : d_instructions(std::move(instructions)) + { + // Nothing else + } + + const std::vector<std::unique_ptr<LratInstruction>>& getInstructions() const + { + return d_instructions; + } + + void outputAsLfsc(std::ostream& o) const; + + private: + // The instructions in the proof. Each is a deletion or addition. + std::vector<std::unique_ptr<LratInstruction>> d_instructions; +}; + +// Prints the LRAT proof in textual format +std::ostream& operator<<(std::ostream& o, const LratProof& p); +std::ostream& operator<<(std::ostream& o, const LratInstruction& i); + +} // namespace lrat +} // namespace proof +} // namespace CVC4 + +#endif diff --git a/src/proof/resolution_bitvector_proof.cpp b/src/proof/resolution_bitvector_proof.cpp index 667d630f8..1db673949 100644 --- a/src/proof/resolution_bitvector_proof.cpp +++ b/src/proof/resolution_bitvector_proof.cpp @@ -26,6 +26,7 @@ #include "proof/proof_utils.h" #include "proof/sat_proof_implementation.h" #include "prop/bvminisat/bvminisat.h" +#include "prop/sat_solver_types.h" #include "theory/bv/bitblast/bitblaster.h" #include "theory/bv/theory_bv.h" #include "theory/bv/theory_bv_rewrite_rules.h" @@ -54,32 +55,22 @@ void ResolutionBitVectorProof::initSatProof(CVC4::BVMinisat::Solver* solver) d_resolutionProof.reset(new BVSatProof(solver, &d_fakeContext, "bb", true)); } -theory::TheoryId ResolutionBitVectorProof::getTheoryId() +void ResolutionBitVectorProof::initCnfProof(prop::CnfStream* cnfStream, + context::Context* cnf, + prop::SatVariable trueVar, + prop::SatVariable falseVar) { - return theory::THEORY_BV; + Assert(d_resolutionProof != NULL); + Assert(d_cnfProof == nullptr); + d_cnfProof.reset(new LFSCCnfProof(cnfStream, cnf, "bb")); + + d_cnfProof->registerTrueUnitClause(d_resolutionProof->getTrueUnit()); + d_cnfProof->registerFalseUnitClause(d_resolutionProof->getFalseUnit()); } -void ResolutionBitVectorProof::initCnfProof(prop::CnfStream* cnfStream, - context::Context* cnf) +void ResolutionBitVectorProof::attachToSatSolver(prop::SatSolver& sat_solver) { - Assert(d_resolutionProof != NULL); - BitVectorProof::initCnfProof(cnfStream, cnf); - - // true and false have to be setup in a special way - Node true_node = NodeManager::currentNM()->mkConst<bool>(true); - Node false_node = NodeManager::currentNM()->mkConst<bool>(false).notNode(); - - d_cnfProof->pushCurrentAssertion(true_node); - d_cnfProof->pushCurrentDefinition(true_node); - d_cnfProof->registerConvertedClause(d_resolutionProof->getTrueUnit()); - d_cnfProof->popCurrentAssertion(); - d_cnfProof->popCurrentDefinition(); - - d_cnfProof->pushCurrentAssertion(false_node); - d_cnfProof->pushCurrentDefinition(false_node); - d_cnfProof->registerConvertedClause(d_resolutionProof->getFalseUnit()); - d_cnfProof->popCurrentAssertion(); - d_cnfProof->popCurrentDefinition(); + sat_solver.setResolutionProofLog(this); } BVSatProof* ResolutionBitVectorProof::getSatProof() @@ -258,13 +249,15 @@ void ResolutionBitVectorProof::finalizeConflicts(std::vector<Expr>& conflicts) } } -void LFSCBitVectorProof::printTheoryLemmaProof(std::vector<Expr>& lemma, - std::ostream& os, - std::ostream& paren, - const ProofLetMap& map) +void LfscResolutionBitVectorProof::printTheoryLemmaProof( + std::vector<Expr>& lemma, + std::ostream& os, + std::ostream& paren, + const ProofLetMap& map) { - Debug("pf::bv") << "(pf::bv) LFSCBitVectorProof::printTheoryLemmaProof called" - << std::endl; + Debug("pf::bv") + << "(pf::bv) LfscResolutionBitVectorProof::printTheoryLemmaProof called" + << std::endl; Expr conflict = utils::mkSortedExpr(kind::OR, lemma); Debug("pf::bv") << "\tconflict = " << conflict << std::endl; @@ -467,7 +460,7 @@ void LFSCBitVectorProof::printTheoryLemmaProof(std::vector<Expr>& lemma, } } -void LFSCBitVectorProof::calculateAtomsInBitblastingProof() +void LfscResolutionBitVectorProof::calculateAtomsInBitblastingProof() { // Collect the input clauses used IdToSatClause used_lemmas; @@ -477,9 +470,9 @@ void LFSCBitVectorProof::calculateAtomsInBitblastingProof() Assert(used_lemmas.empty()); } -void LFSCBitVectorProof::printResolutionProof(std::ostream& os, - std::ostream& paren, - ProofLetMap& letMap) +void LfscResolutionBitVectorProof::printBBDeclarationAndCnf(std::ostream& os, + std::ostream& paren, + ProofLetMap& letMap) { // print mapping between theory atoms and internal SAT variables os << std::endl << ";; BB atom mapping\n" << std::endl; @@ -517,6 +510,16 @@ void LFSCBitVectorProof::printResolutionProof(std::ostream& os, proof::LFSCProofPrinter::printResolutions(d_resolutionProof.get(), os, paren); } -} /* namespace proof */ +void LfscResolutionBitVectorProof::printEmptyClauseProof(std::ostream& os, + std::ostream& paren) +{ + Assert(options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER, + "the BV theory should only be proving bottom directly in the eager " + "bitblasting mode"); + proof::LFSCProofPrinter::printResolutionEmptyClause( + d_resolutionProof.get(), os, paren); +} + +} // namespace proof } /* namespace CVC4 */ diff --git a/src/proof/resolution_bitvector_proof.h b/src/proof/resolution_bitvector_proof.h index ccb288f6e..6c2ae589f 100644 --- a/src/proof/resolution_bitvector_proof.h +++ b/src/proof/resolution_bitvector_proof.h @@ -24,32 +24,16 @@ #include "context/context.h" #include "expr/expr.h" #include "proof/bitvector_proof.h" +#include "proof/sat_proof.h" #include "proof/theory_proof.h" #include "prop/bvminisat/core/Solver.h" +#include "prop/cnf_stream.h" +#include "prop/sat_solver_types.h" +#include "theory/bv/bitblast/bitblaster.h" +#include "theory/bv/theory_bv.h" namespace CVC4 { -namespace theory { -namespace bv { -class TheoryBV; -template <class T> -class TBitblaster; -} // namespace bv -} // namespace theory - -// TODO(aozdemir) break the sat_solver - resolution_bitvectorproof - cnf_stream -// header cycle and remove this. -namespace prop { -class CnfStream; -} - -} /* namespace CVC4 */ - - -namespace CVC4 { - -template <class Solver> -class TSatProof; typedef TSatProof<CVC4::BVMinisat::Solver> BVSatProof; namespace proof { @@ -76,13 +60,7 @@ class ResolutionBitVectorProof : public BitVectorProof BVSatProof* getSatProof(); - /** - * Kind of a mess. - * In eager mode this must be invoked before printing a proof of the empty - * clause. In lazy mode the behavior is ??? - * TODO(aozdemir) clean this up. - */ - void finalizeConflicts(std::vector<Expr>& conflicts); + void finalizeConflicts(std::vector<Expr>& conflicts) override; void startBVConflict(CVC4::BVMinisat::Solver::TCRef cr); void startBVConflict(CVC4::BVMinisat::Solver::TLit lit); @@ -91,13 +69,14 @@ class ResolutionBitVectorProof : public BitVectorProof void markAssumptionConflict() { d_isAssumptionConflict = true; } bool isAssumptionConflict() const { return d_isAssumptionConflict; } - virtual void printResolutionProof(std::ostream& os, - std::ostream& paren, - ProofLetMap& letMap) = 0; - - void initCnfProof(prop::CnfStream* cnfStream, context::Context* cnf) override; + void initCnfProof(prop::CnfStream* cnfStream, + context::Context* cnf, + prop::SatVariable trueVar, + prop::SatVariable falseVar) override; protected: + void attachToSatSolver(prop::SatSolver& sat_solver) override; + context::Context d_fakeContext; // The CNF formula that results from bit-blasting will need a proof. @@ -106,13 +85,13 @@ class ResolutionBitVectorProof : public BitVectorProof bool d_isAssumptionConflict; - theory::TheoryId getTheoryId() override; }; -class LFSCBitVectorProof : public ResolutionBitVectorProof +class LfscResolutionBitVectorProof : public ResolutionBitVectorProof { public: - LFSCBitVectorProof(theory::bv::TheoryBV* bv, TheoryProofEngine* proofEngine) + LfscResolutionBitVectorProof(theory::bv::TheoryBV* bv, + TheoryProofEngine* proofEngine) : ResolutionBitVectorProof(bv, proofEngine) { } @@ -120,9 +99,10 @@ class LFSCBitVectorProof : public ResolutionBitVectorProof std::ostream& os, std::ostream& paren, const ProofLetMap& map) override; - void printResolutionProof(std::ostream& os, - std::ostream& paren, - ProofLetMap& letMap) override; + void printBBDeclarationAndCnf(std::ostream& os, + std::ostream& paren, + ProofLetMap& letMap) override; + void printEmptyClauseProof(std::ostream& os, std::ostream& paren) override; void calculateAtomsInBitblastingProof() override; }; diff --git a/src/proof/theory_proof.cpp b/src/proof/theory_proof.cpp index ee06fbfa0..fe9acfef3 100644 --- a/src/proof/theory_proof.cpp +++ b/src/proof/theory_proof.cpp @@ -22,6 +22,7 @@ #include "options/proof_options.h" #include "proof/arith_proof.h" #include "proof/array_proof.h" +#include "proof/clausal_bitvector_proof.h" #include "proof/clause_id.h" #include "proof/cnf_proof.h" #include "proof/proof_manager.h" @@ -46,7 +47,7 @@ namespace CVC4 { -using proof::LFSCBitVectorProof; +using proof::LfscResolutionBitVectorProof; using proof::ResolutionBitVectorProof; unsigned CVC4::ProofLetCount::counter = 0; @@ -80,9 +81,20 @@ void TheoryProofEngine::registerTheory(theory::Theory* th) { } if (id == theory::THEORY_BV) { - auto bv_theory = static_cast<theory::bv::TheoryBV*>(th); - ResolutionBitVectorProof* bvp = new LFSCBitVectorProof(bv_theory, this); - d_theoryProofTable[id] = bvp; + auto thBv = static_cast<theory::bv::TheoryBV*>(th); + if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER + && options::bvSatSolver() == theory::bv::SAT_SOLVER_CRYPTOMINISAT) + { + proof::BitVectorProof* bvp = + new proof::LfscClausalBitVectorProof(thBv, this); + d_theoryProofTable[id] = bvp; + } + else + { + proof::BitVectorProof* bvp = + new proof::LfscResolutionBitVectorProof(thBv, this); + d_theoryProofTable[id] = bvp; + } return; } @@ -105,10 +117,11 @@ void TheoryProofEngine::finishRegisterTheory(theory::Theory* th) { if (th) { theory::TheoryId id = th->getId(); if (id == theory::THEORY_BV) { + theory::bv::TheoryBV* bv_th = static_cast<theory::bv::TheoryBV*>(th); Assert(d_theoryProofTable.find(id) != d_theoryProofTable.end()); - ResolutionBitVectorProof* bvp = - (ResolutionBitVectorProof*)d_theoryProofTable[id]; - ((theory::bv::TheoryBV*)th)->setResolutionProofLog(bvp); + proof::BitVectorProof* bvp = + static_cast<proof::BitVectorProof*>(d_theoryProofTable[id]); + bv_th->setProofLog(bvp); return; } } @@ -533,9 +546,8 @@ void LFSCTheoryProofEngine::finalizeBvConflicts(const IdToSatClause& lemmas, std } } - ResolutionBitVectorProof* bv = ProofManager::getBitVectorProof(); + proof::BitVectorProof* bv = ProofManager::getBitVectorProof(); bv->finalizeConflicts(bv_lemmas); - // bv->printResolutionProof(os, paren, letMap); } void LFSCTheoryProofEngine::printTheoryLemmas(const IdToSatClause& lemmas, @@ -550,7 +562,7 @@ void LFSCTheoryProofEngine::printTheoryLemmas(const IdToSatClause& lemmas, } // finalizeBvConflicts(lemmas, os, paren, map); - ProofManager::getBitVectorProof()->printResolutionProof(os, paren, map); + ProofManager::getBitVectorProof()->printBBDeclarationAndCnf(os, paren, map); if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) { Assert (lemmas.size() == 1); diff --git a/src/prop/bvminisat/bvminisat.cpp b/src/prop/bvminisat/bvminisat.cpp index 55710092b..57ef8ef30 100644 --- a/src/prop/bvminisat/bvminisat.cpp +++ b/src/prop/bvminisat/bvminisat.cpp @@ -104,7 +104,8 @@ void BVMinisatSatSolver::popAssumption() { d_minisat->popAssumption(); } -void BVMinisatSatSolver::setProofLog(proof::ResolutionBitVectorProof* bvp) +void BVMinisatSatSolver::setResolutionProofLog( + proof::ResolutionBitVectorProof* bvp) { d_minisat->setProofLog( bvp ); } diff --git a/src/prop/bvminisat/bvminisat.h b/src/prop/bvminisat/bvminisat.h index 16489b172..efb90a3f0 100644 --- a/src/prop/bvminisat/bvminisat.h +++ b/src/prop/bvminisat/bvminisat.h @@ -119,7 +119,7 @@ public: void popAssumption() override; - void setProofLog(proof::ResolutionBitVectorProof* bvp) override; + void setResolutionProofLog(proof::ResolutionBitVectorProof* bvp) override; private: /* Disable the default constructor. */ diff --git a/src/prop/cnf_stream.cpp b/src/prop/cnf_stream.cpp index cdb850ce2..84c315547 100644 --- a/src/prop/cnf_stream.cpp +++ b/src/prop/cnf_stream.cpp @@ -79,19 +79,22 @@ void CnfStream::assertClause(TNode node, SatClause& c) { } } - PROOF(if (d_cnfProof) d_cnfProof->pushCurrentDefinition(node);); + if (PROOF_ON() && d_cnfProof) + { + d_cnfProof->pushCurrentDefinition(node); + } ClauseId clause_id = d_satSolver->addClause(c, d_removable); if (clause_id == ClauseIdUndef) return; // nothing to store (no clause was added) - PROOF - ( - if (d_cnfProof) { - Assert (clause_id != ClauseIdError); - d_cnfProof->registerConvertedClause(clause_id); - d_cnfProof->popCurrentDefinition(); - } - ); + if (PROOF_ON() && d_cnfProof) + { + if (clause_id != ClauseIdError) + { + d_cnfProof->registerConvertedClause(clause_id); + } + d_cnfProof->popCurrentDefinition(); + }; } void CnfStream::assertClause(TNode node, SatLiteral a) { diff --git a/src/prop/cryptominisat.cpp b/src/prop/cryptominisat.cpp index df5a20791..c04fb8b56 100644 --- a/src/prop/cryptominisat.cpp +++ b/src/prop/cryptominisat.cpp @@ -62,10 +62,11 @@ void toInternalClause(SatClause& clause, CryptoMinisatSolver::CryptoMinisatSolver(StatisticsRegistry* registry, const std::string& name) -: d_solver(new CMSat::SATSolver()) -, d_numVariables(0) -, d_okay(true) -, d_statistics(registry, name) + : d_solver(new CMSat::SATSolver()), + d_bvp(nullptr), + d_numVariables(0), + d_okay(true), + d_statistics(registry, name) { d_true = newVar(); d_false = newVar(); @@ -117,9 +118,17 @@ ClauseId CryptoMinisatSolver::addClause(SatClause& clause, bool removable){ std::vector<CMSat::Lit> internal_clause; toInternalClause(clause, internal_clause); - bool res = d_solver->add_clause(internal_clause); - d_okay &= res; - return ClauseIdError; + bool nowOkay = d_solver->add_clause(internal_clause); + ClauseId freshId = ClauseId(ProofManager::currentPM()->nextId()); + + THEORY_PROOF( + // If this clause results in a conflict, then `nowOkay` may be false, but + // we still need to register this clause as used. Thus, we look at + // `d_okay` instead + if (d_bvp && d_okay) { d_bvp->registerUsedClause(freshId, clause); }) + + d_okay &= nowOkay; + return freshId; } bool CryptoMinisatSolver::ok() const { @@ -193,6 +202,12 @@ unsigned CryptoMinisatSolver::getAssertionLevel() const { return -1; } +void CryptoMinisatSolver::setClausalProofLog(proof::ClausalBitVectorProof* bvp) +{ + d_bvp = bvp; + d_solver->set_drat(&bvp->getDratOstream(), false); +} + // Satistics for CryptoMinisatSolver CryptoMinisatSolver::Statistics::Statistics(StatisticsRegistry* registry, diff --git a/src/prop/cryptominisat.h b/src/prop/cryptominisat.h index c5345cb86..17cc1568c 100644 --- a/src/prop/cryptominisat.h +++ b/src/prop/cryptominisat.h @@ -21,6 +21,7 @@ #ifdef CVC4_USE_CRYPTOMINISAT +#include "proof/clausal_bitvector_proof.h" #include "prop/sat_solver.h" // Cryptominisat has name clashes with the other Minisat implementations since @@ -39,6 +40,7 @@ class CryptoMinisatSolver : public SatSolver { private: std::unique_ptr<CMSat::SATSolver> d_solver; + proof::ClausalBitVectorProof* d_bvp; unsigned d_numVariables; bool d_okay; SatVariable d_true; @@ -71,6 +73,7 @@ public: SatValue modelValue(SatLiteral l) override; unsigned getAssertionLevel() const override; + void setClausalProofLog(proof::ClausalBitVectorProof* bvp) override; class Statistics { public: diff --git a/src/prop/sat_solver.h b/src/prop/sat_solver.h index 49064c20f..70e46eceb 100644 --- a/src/prop/sat_solver.h +++ b/src/prop/sat_solver.h @@ -26,7 +26,6 @@ #include "context/cdlist.h" #include "context/context.h" #include "expr/node.h" -#include "proof/resolution_bitvector_proof.h" #include "proof/clause_id.h" #include "prop/sat_solver_types.h" #include "prop/bv_sat_solver_notify.h" @@ -34,6 +33,11 @@ namespace CVC4 { +namespace proof { +class ClausalBitVectorProof; +class ResolutionBitVectorProof; +} // namespace proof + namespace prop { class TheoryProxy; @@ -97,7 +101,9 @@ public: /** Check if the solver is in an inconsistent state */ virtual bool ok() const = 0; - virtual void setProofLog(proof::ResolutionBitVectorProof* bvp) {} + virtual void setResolutionProofLog(proof::ResolutionBitVectorProof* bvp) {} + + virtual void setClausalProofLog(proof::ClausalBitVectorProof* drat_proof) {} };/* class SatSolver */ diff --git a/src/smt/smt_engine.h b/src/smt/smt_engine.h index 5aa59fad7..e53d1eb55 100644 --- a/src/smt/smt_engine.h +++ b/src/smt/smt_engine.h @@ -217,8 +217,8 @@ class CVC4_PUBLIC SmtEngine { /** * Whether or not this SmtEngine is fully initialized (post-construction). * This post-construction initialization is automatically triggered by the - * use of the SmtEngine; e.g. when setLogic() is called, or the first - * assertion is made, etc. + * use of the SmtEngine; e.g. when the first formula is asserted, a call + * to simplify() is issued, a scope is pushed, etc. */ bool d_fullyInited; @@ -457,6 +457,14 @@ class CVC4_PUBLIC SmtEngine { ~SmtEngine(); /** + * Return true if this SmtEngine is fully initialized (post-construction). + * This post-construction initialization is automatically triggered by the + * use of the SmtEngine; e.g. when the first formula is asserted, a call + * to simplify() is issued, a scope is pushed, etc. + */ + bool isFullyInited() { return d_fullyInited; } + + /** * Set the logic of the script. */ void setLogic( diff --git a/src/theory/arith/constraint.cpp b/src/theory/arith/constraint.cpp index 352ba0f36..297e3de37 100644 --- a/src/theory/arith/constraint.cpp +++ b/src/theory/arith/constraint.cpp @@ -499,6 +499,35 @@ bool Constraint::hasFarkasProof() const { return getProofType() == FarkasAP; } +bool Constraint::hasSimpleFarkasProof() const +{ + Debug("constraints::hsfp") << "hasSimpleFarkasProof " << this << std::endl; + if (!hasFarkasProof()) + { + Debug("constraints::hsfp") << "There is no simple Farkas proof because " + "there is no farkas proof." + << std::endl; + return false; + } + const ConstraintRule& rule = getConstraintRule(); + AntecedentId antId = rule.d_antecedentEnd; + ConstraintCP antecdent = d_database->getAntecedent(antId); + while (antecdent != NullConstraint) + { + if (antecdent->getProofType() != AssumeAP) + { + Debug("constraints::hsfp") << "There is no simple Farkas proof b/c there " + "is an antecdent w/ rule "; + antecdent->getConstraintRule().print(Debug("constraints::hsfp")); + Debug("constraints::hsfp") << std::endl; + return false; + } + --antId; + antecdent = d_database->getAntecedent(antId); + } + return true; +} + bool Constraint::hasIntHoleProof() const { return getProofType() == IntHoleAP; } @@ -568,8 +597,9 @@ void ConstraintRule::print(std::ostream& out) const { out << d_constraint << std::endl; out << "d_proofType= " << d_proofType << ", " << std::endl; out << "d_antecedentEnd= "<< d_antecedentEnd << std::endl; - - if(d_constraint != NullConstraint){ + + if (d_constraint != NullConstraint && d_antecedentEnd != AntecedentIdSentinel) + { const ConstraintDatabase& database = d_constraint->getDatabase(); size_t coeffIterator = (coeffs != RationalVectorCPSentinel) ? coeffs->size()-1 : 0; @@ -597,7 +627,7 @@ void ConstraintRule::print(std::ostream& out) const { out << " * (" << *(d_constraint->getNegation()) << ")"; out << " [not d_constraint] " << endl; } - out << "}"; + out << "}"; } bool Constraint::wellFormedFarkasProof() const { @@ -1188,6 +1218,8 @@ void Constraint::impliedByIntHole(ConstraintCP a, bool nowInConflict){ Assert(!hasProof()); Assert(negationHasProof() == nowInConflict); Assert(a->hasProof()); + Debug("pf::arith") << "impliedByIntHole(" << this << ", " << a << ")" + << std::endl; d_database->d_antecedents.push_back(NullConstraint); d_database->d_antecedents.push_back(a); @@ -1339,6 +1371,7 @@ Node Constraint::externalExplainByAssertions(const ConstraintCPVec& b){ } Node Constraint::externalExplainConflict() const{ + Debug("pf::arith") << this << std::endl; Assert(inConflict()); NodeBuilder<> nb(kind::AND); externalExplainByAssertions(nb); @@ -1407,6 +1440,13 @@ void Constraint::externalExplain(NodeBuilder<>& nb, AssertionOrder order) const{ Assert(!isAssumption() || assertedToTheTheory()); Assert(!isInternalAssumption()); + if (Debug.isOn("pf::arith")) + { + Debug("pf::arith") << "Explaining: " << this << " with rule "; + getConstraintRule().print(Debug("pf::arith")); + Debug("pf::arith") << std::endl; + } + if(assertedBefore(order)){ nb << getWitness(); }else if(hasEqualityEngineProof()){ @@ -1417,6 +1457,7 @@ void Constraint::externalExplain(NodeBuilder<>& nb, AssertionOrder order) const{ ConstraintCP antecedent = d_database->d_antecedents[p]; while(antecedent != NullConstraint){ + Debug("pf::arith") << "Explain " << antecedent << std::endl; antecedent->externalExplain(nb, order); --p; antecedent = d_database->d_antecedents[p]; diff --git a/src/theory/arith/constraint.h b/src/theory/arith/constraint.h index d411f2d34..51575bb2f 100644 --- a/src/theory/arith/constraint.h +++ b/src/theory/arith/constraint.h @@ -258,7 +258,7 @@ struct PerVariableDatabase{ struct ConstraintRule { ConstraintP d_constraint; ArithProofType d_proofType; - AntecedentId d_antecedentEnd; + AntecedentId d_antecedentEnd; /** * In this comment, we abbreviate ConstraintDatabase::d_antecedents @@ -266,37 +266,38 @@ struct ConstraintRule { * * This list is always empty if proofs are not enabled. * - * If proofs are enabled, the proof of constraint c at p in ans[p] of length n is - * (NullConstraint, ans[p-(n-1)], ... , ans[p-1], ans[p]) - * - * Farkas' proofs show a contradiction with the negation of c, c_not = c->getNegation(). + * If proofs are enabled, the proof of constraint c at p in ans[p] of length n + * is (NullConstraint, ans[p-(n-1)], ... , ans[p-1], ans[p]) + * + * Farkas' proofs show a contradiction with the negation of c, c_not = + * c->getNegation(). * - * We treat the position for NullConstraint (p-n) as the position for the farkas - * coefficient for so we pretend c_not is ans[p-n]. - * So this correlation for the constraints we are going to use: - * (c_not, ans[p-(n-1)], ... , ans[p-1], ans[p]) - * With the coefficients at positions: - * (fc[0], fc[1)], ... fc[n]) + * We treat the position for NullConstraint (p-n) as the position for the + * farkas coefficient for so we pretend c_not is ans[p-n]. So this correlation + * for the constraints we are going to use: (c_not, ans[p-n+(1)], ... , + * ans[p-n+(n-1)], ans[p-n+(n)]) With the coefficients at positions: (fc[0], + * fc[1)], ... fc[n]) * - * The index of the constraints in the proof are {i | i <= 0 <= n] } (with c_not being p-n). - * Partition the indices into L, U, and E, the lower bounds, the upper bounds and equalities. + * The index of the constraints in the proof are {i | i <= 0 <= n] } (with + * c_not being p-n). Partition the indices into L, U, and E, the lower bounds, + * the upper bounds and equalities. * - * We standardize the proofs to be upper bound oriented following the convention: - * A x <= b - * with the proof witness of the form - * (lambda) Ax <= (lambda) b and lambda >= 0. + * We standardize the proofs to be upper bound oriented following the + * convention: A x <= b with the proof witness of the form (lambda) Ax <= + * (lambda) b and lambda >= 0. * - * To accomplish this cleanly, the fc coefficients must be negative for lower bounds. - * The signs of equalities can be either positive or negative. + * To accomplish this cleanly, the fc coefficients must be negative for lower + * bounds. The signs of equalities can be either positive or negative. * * Thus the proof corresponds to (with multiplication over inequalities): * \sum_{u in U} fc[u] ans[p-n+u] + \sum_{e in E} fc[e] ans[p-n+e] * + \sum_{l in L} fc[l] ans[p-n+l] * |= 0 < 0 * where fc[u] > 0, fc[l] < 0, and fc[e] != 0 (i.e. it can be either +/-). - * + * * There is no requirement that the proof is minimal. - * We do however use all of the constraints by requiring non-zero coefficients. + * We do however use all of the constraints by requiring non-zero + * coefficients. */ #if IS_PROOFS_BUILD RationalVectorCP d_farkasCoefficients; @@ -346,88 +347,10 @@ struct ConstraintRule { }; /* class ConstraintRule */ class Constraint { -private: - /** The ArithVar associated with the constraint. */ - const ArithVar d_variable; - - /** The type of the Constraint. */ - const ConstraintType d_type; - - /** The DeltaRational value with the constraint. */ - const DeltaRational d_value; - - /** A pointer to the associated database for the Constraint. */ - ConstraintDatabase* d_database; - - /** - * The node to be communicated with the TheoryEngine. - * - * This is not context dependent, but may be set once. - * - * This must be set if the constraint canBePropagated(). - * This must be set if the constraint assertedToTheTheory(). - * Otherwise, this may be null(). - */ - Node d_literal; - - /** Pointer to the negation of the Constraint. */ - ConstraintP d_negation; - - /** - * This is true if the associated node can be propagated. - * - * This should be enabled if the node has been preregistered. - * - * Sat Context Dependent. - * This is initially false. - */ - bool d_canBePropagated; - - /** - * This is the order the constraint was asserted to the theory. - * If this has been set, the node can be used in conflicts. - * If this is c.d_assertedOrder < d.d_assertedOrder, then c can be used in the - * explanation of d. - * - * This should be set after the literal is dequeued by Theory::get(). - * - * Sat Context Dependent. - * This is initially AssertionOrderSentinel. - */ - AssertionOrder d_assertionOrder; - - /** - * This is guaranteed to be on the fact queue. - * For example if x + y = x + 1 is on the fact queue, then use this - */ - TNode d_witness; - - /** - * The position of the constraint in the constraint rule id. - * - * Sat Context Dependent. - * This is initially - */ - ConstraintRuleID d_crid; - - - /** - * True if the equality has been split. - * Only meaningful if ConstraintType == Equality. - * - * User Context Dependent. - * This is initially false. - */ - bool d_split; - - /** - * Position in sorted constraint set for the variable. - * Unset if d_type is Disequality. - */ - SortedConstraintMapIterator d_variablePosition; friend class ConstraintDatabase; + public: /** * This begins construction of a minimal constraint. * @@ -444,86 +367,6 @@ private: */ ~Constraint(); - /** Returns true if the constraint has been initialized. */ - bool initialized() const; - - /** - * This initializes the fields that cannot be set in the constructor due to - * circular dependencies. - */ - void initialize(ConstraintDatabase* db, SortedConstraintMapIterator v, ConstraintP negation); - - - - class ConstraintRuleCleanup { - public: - inline void operator()(ConstraintRule* crp){ - Assert(crp != NULL); - ConstraintP constraint = crp->d_constraint; - Assert(constraint->d_crid != ConstraintRuleIdSentinel); - constraint->d_crid = ConstraintRuleIdSentinel; - - PROOF(if(crp->d_farkasCoefficients != RationalVectorCPSentinel){ - delete crp->d_farkasCoefficients; - }); - } - }; - - class CanBePropagatedCleanup { - public: - inline void operator()(ConstraintP* p){ - ConstraintP constraint = *p; - Assert(constraint->d_canBePropagated); - constraint->d_canBePropagated = false; - } - }; - - class AssertionOrderCleanup { - public: - inline void operator()(ConstraintP* p){ - ConstraintP constraint = *p; - Assert(constraint->assertedToTheTheory()); - constraint->d_assertionOrder = AssertionOrderSentinel; - constraint->d_witness = TNode::null(); - Assert(!constraint->assertedToTheTheory()); - } - }; - - class SplitCleanup { - public: - inline void operator()(ConstraintP* p){ - ConstraintP constraint = *p; - Assert(constraint->d_split); - constraint->d_split = false; - } - }; - - /** - * Returns true if the node is safe to garbage collect. - * Both it and its negation must have no context dependent data set. - */ - bool safeToGarbageCollect() const; - - /** - * Returns true if the constraint has no context dependent data set. - */ - bool contextDependentDataIsSet() const; - - /** - * Returns true if the node correctly corresponds to the constraint that is - * being set. - */ - bool sanityChecking(Node n) const; - - /** Returns a reference to the map for d_variable. */ - SortedConstraintMap& constraintSet() const; - - /** Returns coefficients for the proofs for farkas cancellation. */ - static std::pair<int, int> unateFarkasSigns(ConstraintCP a, ConstraintCP b); - - -public: - static ConstraintType constraintTypeOfComparison(const Comparison& cmp); inline ConstraintType getType() const { @@ -648,6 +491,26 @@ public: /** Returns true if the node has a Farkas' proof. */ bool hasFarkasProof() const; + /** + * @brief Returns whether this constraint is provable using a Farkas + * proof that has input assertions as its antecedents. + * + * An example of a constraint that has a simple Farkas proof: + * x <= 0 proven from x + y <= 0 and x - y <= 0. + * + * An example of a constraint that does not have a simple Farkas proof: + * x <= 0 proven from x + y <= 0 and x - y <= 0.5 for integers x, y + * (since integer reasoning is also required!). + * Another example of a constraint that might be proven without a simple + * Farkas proof: + * x < 0 proven from not(x == 0) and not(x > 0). + * + * This could be proven internally by the arithmetic theory using + * `TrichotomyAP` as the proof type. + * + */ + bool hasSimpleFarkasProof() const; + /** Returns true if the node has a int hole proof. */ bool hasIntHoleProof() const; @@ -735,22 +598,6 @@ public: */ Node externalExplainConflict() const; -private: - Node externalExplain(AssertionOrder order) const; - - /** - * Returns an explanation of that was assertedBefore(order). - * The constraint must have a proof. - * The constraint cannot be selfExplaining(). - * - * This is the minimum fringe of the implication tree - * s.t. every constraint is assertedBefore(order) or hasEqualityEngineProof(). - */ - void externalExplain(NodeBuilder<>& nb, AssertionOrder order) const; - - static Node externalExplain(const ConstraintCPVec& b, AssertionOrder order); - -public: /** The constraint is known to be true. */ inline bool hasProof() const { @@ -791,7 +638,6 @@ public: */ ConstraintP getFloor(); - static ConstraintP makeNegation(ArithVar v, ConstraintType t, const DeltaRational& r); const ValueCollection& getValueCollection() const; @@ -896,11 +742,109 @@ public: */ const ConstraintDatabase& getDatabase() const; -private: - /** Returns the constraint rule at the position. */ const ConstraintRule& getConstraintRule() const; - + + private: + /** Returns true if the constraint has been initialized. */ + bool initialized() const; + + /** + * This initializes the fields that cannot be set in the constructor due to + * circular dependencies. + */ + void initialize(ConstraintDatabase* db, + SortedConstraintMapIterator v, + ConstraintP negation); + + class ConstraintRuleCleanup + { + public: + inline void operator()(ConstraintRule* crp) + { + Assert(crp != NULL); + ConstraintP constraint = crp->d_constraint; + Assert(constraint->d_crid != ConstraintRuleIdSentinel); + constraint->d_crid = ConstraintRuleIdSentinel; + + PROOF(if (crp->d_farkasCoefficients != RationalVectorCPSentinel) { + delete crp->d_farkasCoefficients; + }); + } + }; + + class CanBePropagatedCleanup + { + public: + inline void operator()(ConstraintP* p) + { + ConstraintP constraint = *p; + Assert(constraint->d_canBePropagated); + constraint->d_canBePropagated = false; + } + }; + + class AssertionOrderCleanup + { + public: + inline void operator()(ConstraintP* p) + { + ConstraintP constraint = *p; + Assert(constraint->assertedToTheTheory()); + constraint->d_assertionOrder = AssertionOrderSentinel; + constraint->d_witness = TNode::null(); + Assert(!constraint->assertedToTheTheory()); + } + }; + + class SplitCleanup + { + public: + inline void operator()(ConstraintP* p) + { + ConstraintP constraint = *p; + Assert(constraint->d_split); + constraint->d_split = false; + } + }; + + /** + * Returns true if the node is safe to garbage collect. + * Both it and its negation must have no context dependent data set. + */ + bool safeToGarbageCollect() const; + + /** + * Returns true if the constraint has no context dependent data set. + */ + bool contextDependentDataIsSet() const; + + /** + * Returns true if the node correctly corresponds to the constraint that is + * being set. + */ + bool sanityChecking(Node n) const; + + /** Returns a reference to the map for d_variable. */ + SortedConstraintMap& constraintSet() const; + + /** Returns coefficients for the proofs for farkas cancellation. */ + static std::pair<int, int> unateFarkasSigns(ConstraintCP a, ConstraintCP b); + + Node externalExplain(AssertionOrder order) const; + + /** + * Returns an explanation of that was assertedBefore(order). + * The constraint must have a proof. + * The constraint cannot be selfExplaining(). + * + * This is the minimum fringe of the implication tree + * s.t. every constraint is assertedBefore(order) or hasEqualityEngineProof(). + */ + void externalExplain(NodeBuilder<>& nb, AssertionOrder order) const; + + static Node externalExplain(const ConstraintCPVec& b, AssertionOrder order); + inline ArithProofType getProofType() const { return getConstraintRule().d_proofType; } @@ -934,7 +878,85 @@ private: */ bool wellFormedFarkasProof() const; - + + /** The ArithVar associated with the constraint. */ + const ArithVar d_variable; + + /** The type of the Constraint. */ + const ConstraintType d_type; + + /** The DeltaRational value with the constraint. */ + const DeltaRational d_value; + + /** A pointer to the associated database for the Constraint. */ + ConstraintDatabase* d_database; + + /** + * The node to be communicated with the TheoryEngine. + * + * This is not context dependent, but may be set once. + * + * This must be set if the constraint canBePropagated(). + * This must be set if the constraint assertedToTheTheory(). + * Otherwise, this may be null(). + */ + Node d_literal; + + /** Pointer to the negation of the Constraint. */ + ConstraintP d_negation; + + /** + * This is true if the associated node can be propagated. + * + * This should be enabled if the node has been preregistered. + * + * Sat Context Dependent. + * This is initially false. + */ + bool d_canBePropagated; + + /** + * This is the order the constraint was asserted to the theory. + * If this has been set, the node can be used in conflicts. + * If this is c.d_assertedOrder < d.d_assertedOrder, then c can be used in the + * explanation of d. + * + * This should be set after the literal is dequeued by Theory::get(). + * + * Sat Context Dependent. + * This is initially AssertionOrderSentinel. + */ + AssertionOrder d_assertionOrder; + + /** + * This is guaranteed to be on the fact queue. + * For example if x + y = x + 1 is on the fact queue, then use this + */ + TNode d_witness; + + /** + * The position of the constraint in the constraint rule id. + * + * Sat Context Dependent. + * This is initially + */ + ConstraintRuleID d_crid; + + /** + * True if the equality has been split. + * Only meaningful if ConstraintType == Equality. + * + * User Context Dependent. + * This is initially false. + */ + bool d_split; + + /** + * Position in sorted constraint set for the variable. + * Unset if d_type is Disequality. + */ + SortedConstraintMapIterator d_variablePosition; + }; /* class ConstraintValue */ std::ostream& operator<<(std::ostream& o, const Constraint& c); diff --git a/src/theory/arith/kinds b/src/theory/arith/kinds index 3073d0078..95d1aa9c1 100644 --- a/src/theory/arith/kinds +++ b/src/theory/arith/kinds @@ -107,6 +107,7 @@ typerule ABS ::CVC4::theory::arith::IntOperatorTypeRule typerule INTS_DIVISION ::CVC4::theory::arith::IntOperatorTypeRule typerule INTS_MODULUS ::CVC4::theory::arith::IntOperatorTypeRule typerule DIVISIBLE ::CVC4::theory::arith::IntUnaryPredicateTypeRule +typerule DIVISIBLE_OP ::CVC4::theory::arith::DivisibleOpTypeRule typerule DIVISION_TOTAL ::CVC4::theory::arith::ArithOperatorTypeRule typerule INTS_DIVISION_TOTAL ::CVC4::theory::arith::IntOperatorTypeRule diff --git a/src/theory/arith/theory_arith_private.cpp b/src/theory/arith/theory_arith_private.cpp index 89550295a..48d1b0188 100644 --- a/src/theory/arith/theory_arith_private.cpp +++ b/src/theory/arith/theory_arith_private.cpp @@ -2138,6 +2138,7 @@ Node flattenAndSort(Node n){ /** Outputs conflicts to the output channel. */ void TheoryArithPrivate::outputConflicts(){ + Debug("arith::conflict") << "outputting conflicts" << std::endl; Assert(anyConflict()); static unsigned int conflicts = 0; @@ -2145,13 +2146,39 @@ void TheoryArithPrivate::outputConflicts(){ Assert(!d_conflicts.empty()); for(size_t i = 0, i_end = d_conflicts.size(); i < i_end; ++i){ ConstraintCP confConstraint = d_conflicts[i]; + bool hasProof = confConstraint->hasProof(); Assert(confConstraint->inConflict()); + const ConstraintRule& pf = confConstraint->getConstraintRule(); + if (Debug.isOn("arith::conflict")) + { + pf.print(std::cout); + std::cout << std::endl; + } Node conflict = confConstraint->externalExplainConflict(); ++conflicts; Debug("arith::conflict") << "d_conflicts[" << i << "] " << conflict - // << "("<<conflicts<<")" - << endl; + << " has proof: " << hasProof << endl; + PROOF(if (d_containing.d_proofRecorder && confConstraint->hasFarkasProof() + && pf.d_farkasCoefficients->size() + == conflict.getNumChildren()) { + // The Farkas coefficients and the children of `conflict` seem to be in + // opposite orders... There is some relevant documentation in the + // comment for the d_farkasCoefficients field in "constraint.h" + // + // Anyways, we reverse the children in `conflict` here. + NodeBuilder<> conflictInFarkasCoefficientOrder(kind::AND); + for (size_t i = 0, nchildren = conflict.getNumChildren(); i < nchildren; + ++i) + { + conflictInFarkasCoefficientOrder + << conflict[conflict.getNumChildren() - i - 1]; + } + + Assert(conflict.getNumChildren() == pf.d_farkasCoefficients->size()); + d_containing.d_proofRecorder->saveFarkasCoefficients( + conflictInFarkasCoefficientOrder, pf.d_farkasCoefficients); + }) if(Debug.isOn("arith::normalize::external")){ conflict = flattenAndSort(conflict); Debug("arith::conflict") << "(normalized to) " << conflict << endl; @@ -2174,7 +2201,9 @@ void TheoryArithPrivate::outputConflicts(){ (d_containing.d_out)->conflict(bb); } } + void TheoryArithPrivate::outputLemma(TNode lem) { + Debug("arith::lemma") << "Arith Lemma: " << lem << std::endl; (d_containing.d_out)->lemma(lem); } @@ -4809,11 +4838,41 @@ bool TheoryArithPrivate::rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, C PROOF(d_farkasBuffer.clear()); RationalVectorP coeffs = NULLPROOF(&d_farkasBuffer); - + + // After invoking `propegateRow`: + // * coeffs[0] is for implied + // * coeffs[i+1] is for explain[i] d_linEq.propagateRow(explain, ridx, rowUp, implied, coeffs); if(d_tableau.getRowLength(ridx) <= options::arithPropAsLemmaLength()){ Node implication = implied->externalImplication(explain); Node clause = flattenImplication(implication); + PROOF(if (d_containing.d_proofRecorder + && coeffs != RationalVectorCPSentinel + && coeffs->size() == clause.getNumChildren()) { + Debug("arith::prop") << "implied : " << implied << std::endl; + Debug("arith::prop") << "implication: " << implication << std::endl; + Debug("arith::prop") << "coeff len: " << coeffs->size() << std::endl; + Debug("arith::prop") << "exp : " << explain << std::endl; + Debug("arith::prop") << "clause : " << clause << std::endl; + Debug("arith::prop") + << "clause len: " << clause.getNumChildren() << std::endl; + Debug("arith::prop") << "exp len: " << explain.size() << std::endl; + // Using the information from the above comment we assemble a conflict + // AND in coefficient order + NodeBuilder<> conflictInFarkasCoefficientOrder(kind::AND); + conflictInFarkasCoefficientOrder << implication[1].negate(); + for (const Node& antecedent : implication[0]) + { + Debug("arith::prop") << " ante: " << antecedent << std::endl; + conflictInFarkasCoefficientOrder << antecedent; + } + + Assert(coeffs != RationalVectorPSentinel); + Assert(conflictInFarkasCoefficientOrder.getNumChildren() + == coeffs->size()); + d_containing.d_proofRecorder->saveFarkasCoefficients( + conflictInFarkasCoefficientOrder, coeffs); + }) outputLemma(clause); }else{ Assert(!implied->negationHasProof()); diff --git a/src/theory/arith/theory_arith_type_rules.h b/src/theory/arith/theory_arith_type_rules.h index 2e998010c..bde1730a2 100644 --- a/src/theory/arith/theory_arith_type_rules.h +++ b/src/theory/arith/theory_arith_type_rules.h @@ -169,6 +169,18 @@ public: } };/* class RealNullaryOperatorTypeRule */ +class DivisibleOpTypeRule +{ + public: + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + Assert(n.getKind() == kind::DIVISIBLE_OP); + return nodeManager->builtinOperatorType(); + } +}; /* class DivisibleOpTypeRule */ + }/* CVC4::theory::arith namespace */ }/* CVC4::theory namespace */ }/* CVC4 namespace */ diff --git a/src/theory/bv/bitblast/bitblaster.h b/src/theory/bv/bitblast/bitblaster.h index 73b4d19c7..b1fc084ed 100644 --- a/src/theory/bv/bitblast/bitblaster.h +++ b/src/theory/bv/bitblast/bitblaster.h @@ -24,6 +24,7 @@ #include <vector> #include "expr/node.h" +#include "proof/bitvector_proof.h" #include "prop/bv_sat_solver_notify.h" #include "prop/sat_solver_types.h" #include "theory/bv/bitblast/bitblast_strategies_template.h" @@ -31,6 +32,7 @@ #include "theory/valuation.h" #include "util/resource_manager.h" + namespace CVC4 { namespace theory { namespace bv { @@ -59,6 +61,10 @@ class TBitblaster // caches and mappings TermDefMap d_termCache; ModelCache d_modelCache; + // sat solver used for bitblasting and associated CnfStream + std::unique_ptr<context::Context> d_nullContext; + std::unique_ptr<prop::CnfStream> d_cnfStream; + proof::BitVectorProof* d_bvp; void initAtomBBStrategies(); void initTermBBStrategies(); @@ -69,6 +75,8 @@ class TBitblaster TermBBStrategy d_termBBStrategies[kind::LAST_KIND]; AtomBBStrategy d_atomBBStrategies[kind::LAST_KIND]; virtual Node getModelFromSatSolver(TNode node, bool fullModel) = 0; + virtual prop::SatSolver* getSatSolver() = 0; + public: TBitblaster(); @@ -83,6 +91,8 @@ class TBitblaster bool hasBBTerm(TNode node) const; void getBBTerm(TNode node, Bits& bits) const; virtual void storeBBTerm(TNode term, const Bits& bits); + void setProofLog(proof::BitVectorProof* bvp); + /** * Return a constant representing the value of a in the model. * If fullModel is true set unconstrained bits to 0. If not return @@ -171,7 +181,12 @@ void TBitblaster<T>::initTermBBStrategies() } template <class T> -TBitblaster<T>::TBitblaster() : d_termCache(), d_modelCache() +TBitblaster<T>::TBitblaster() + : d_termCache(), + d_modelCache(), + d_nullContext(new context::Context()), + d_cnfStream(), + d_bvp(nullptr) { initAtomBBStrategies(); initTermBBStrategies(); @@ -202,6 +217,20 @@ void TBitblaster<T>::invalidateModelCache() } template <class T> +void TBitblaster<T>::setProofLog(proof::BitVectorProof* bvp) +{ + if (THEORY_PROOF_ON()) + { + d_bvp = bvp; + prop::SatSolver* satSolver = getSatSolver(); + bvp->attachToSatSolver(*satSolver); + prop::SatVariable t = satSolver->trueVar(); + prop::SatVariable f = satSolver->falseVar(); + bvp->initCnfProof(d_cnfStream.get(), d_nullContext.get(), t, f); + } +} + +template <class T> Node TBitblaster<T>::getTermModel(TNode node, bool fullModel) { if (d_modelCache.find(node) != d_modelCache.end()) return d_modelCache[node]; diff --git a/src/theory/bv/bitblast/eager_bitblaster.cpp b/src/theory/bv/bitblast/eager_bitblaster.cpp index 019918c2f..1e557bb64 100644 --- a/src/theory/bv/bitblast/eager_bitblaster.cpp +++ b/src/theory/bv/bitblast/eager_bitblaster.cpp @@ -32,11 +32,8 @@ namespace bv { EagerBitblaster::EagerBitblaster(TheoryBV* theory_bv, context::Context* c) : TBitblaster<Node>(), d_context(c), - d_nullContext(new context::Context()), d_satSolver(), d_bitblastingRegistrar(new BitblastingRegistrar(this)), - d_cnfStream(), - d_bvp(nullptr), d_bv(theory_bv), d_bbAtoms(), d_variables(), @@ -268,13 +265,6 @@ bool EagerBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) return true; } -void EagerBitblaster::setResolutionProofLog( - proof::ResolutionBitVectorProof* bvp) -{ - THEORY_PROOF(d_bvp = bvp; d_satSolver->setProofLog(bvp); - bvp->initCnfProof(d_cnfStream.get(), d_nullContext.get());) -} - bool EagerBitblaster::isSharedTerm(TNode node) { return d_bv->d_sharedTermsSet.find(node) != d_bv->d_sharedTermsSet.end(); } diff --git a/src/theory/bv/bitblast/eager_bitblaster.h b/src/theory/bv/bitblast/eager_bitblaster.h index 3299ffc54..1c183b509 100644 --- a/src/theory/bv/bitblast/eager_bitblaster.h +++ b/src/theory/bv/bitblast/eager_bitblaster.h @@ -55,19 +55,13 @@ class EagerBitblaster : public TBitblaster<Node> bool solve(); bool solve(const std::vector<Node>& assumptions); bool collectModelInfo(TheoryModel* m, bool fullModel); - void setResolutionProofLog(proof::ResolutionBitVectorProof* bvp); private: context::Context* d_context; - std::unique_ptr<context::Context> d_nullContext; typedef std::unordered_set<TNode, TNodeHashFunction> TNodeSet; - // sat solver used for bitblasting and associated CnfStream std::unique_ptr<prop::SatSolver> d_satSolver; std::unique_ptr<BitblastingRegistrar> d_bitblastingRegistrar; - std::unique_ptr<prop::CnfStream> d_cnfStream; - - BitVectorProof* d_bvp; TheoryBV* d_bv; TNodeSet d_bbAtoms; @@ -77,6 +71,7 @@ class EagerBitblaster : public TBitblaster<Node> std::unique_ptr<MinisatEmptyNotify> d_notify; Node getModelFromSatSolver(TNode a, bool fullModel) override; + prop::SatSolver* getSatSolver() override { return d_satSolver.get(); } bool isSharedTerm(TNode node); }; diff --git a/src/theory/bv/bitblast/lazy_bitblaster.cpp b/src/theory/bv/bitblast/lazy_bitblaster.cpp index 529f0373b..2a47c2315 100644 --- a/src/theory/bv/bitblast/lazy_bitblaster.cpp +++ b/src/theory/bv/bitblast/lazy_bitblaster.cpp @@ -64,10 +64,8 @@ TLazyBitblaster::TLazyBitblaster(context::Context* c, bool emptyNotify) : TBitblaster<Node>(), d_bv(bv), - d_bvp(nullptr), d_ctx(c), d_nullRegistrar(new prop::NullRegistrar()), - d_nullContext(new context::Context()), d_assertedAtoms(new (true) context::CDList<prop::SatLiteral>(c)), d_explanations(new (true) ExplanationMap(c)), d_variables(), @@ -566,11 +564,12 @@ bool TLazyBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) return true; } -void TLazyBitblaster::setProofLog(proof::ResolutionBitVectorProof* bvp) +void TLazyBitblaster::setProofLog(proof::BitVectorProof* bvp) { - d_bvp = bvp; - d_satSolver->setProofLog( bvp ); - bvp->initCnfProof(d_cnfStream.get(), d_nullContext.get()); + THEORY_PROOF(d_bvp = bvp; bvp->attachToSatSolver(*d_satSolver); + prop::SatVariable t = d_satSolver->trueVar(); + prop::SatVariable f = d_satSolver->falseVar(); + bvp->initCnfProof(d_cnfStream.get(), d_nullContext.get(), t, f)); } void TLazyBitblaster::clearSolver() { diff --git a/src/theory/bv/bitblast/lazy_bitblaster.h b/src/theory/bv/bitblast/lazy_bitblaster.h index 1195d3590..9af74d8db 100644 --- a/src/theory/bv/bitblast/lazy_bitblaster.h +++ b/src/theory/bv/bitblast/lazy_bitblaster.h @@ -77,7 +77,7 @@ class TLazyBitblaster : public TBitblaster<Node> * constants to equivalence classes that don't already have them */ bool collectModelInfo(TheoryModel* m, bool fullModel); - void setProofLog(proof::ResolutionBitVectorProof* bvp); + void setProofLog(proof::BitVectorProof* bvp); typedef TNodeSet::const_iterator vars_iterator; vars_iterator beginVars() { return d_variables.begin(); } @@ -126,15 +126,11 @@ class TLazyBitblaster : public TBitblaster<Node> }; TheoryBV* d_bv; - proof::ResolutionBitVectorProof* d_bvp; context::Context* d_ctx; std::unique_ptr<prop::NullRegistrar> d_nullRegistrar; - std::unique_ptr<context::Context> d_nullContext; - // sat solver used for bitblasting and associated CnfStream std::unique_ptr<prop::BVSatSolverInterface> d_satSolver; std::unique_ptr<prop::BVSatSolverNotify> d_satSolverNotify; - std::unique_ptr<prop::CnfStream> d_cnfStream; AssertionList* d_assertedAtoms; /**< context dependent list storing the atoms @@ -155,6 +151,7 @@ class TLazyBitblaster : public TBitblaster<Node> void addAtom(TNode atom); bool hasValue(TNode a); Node getModelFromSatSolver(TNode a, bool fullModel) override; + prop::SatSolver* getSatSolver() override { return d_satSolver.get(); } class Statistics { diff --git a/src/theory/bv/bv_eager_solver.cpp b/src/theory/bv/bv_eager_solver.cpp index 119195c4a..336529dfd 100644 --- a/src/theory/bv/bv_eager_solver.cpp +++ b/src/theory/bv/bv_eager_solver.cpp @@ -56,7 +56,7 @@ void EagerBitblastSolver::initialize() { } else { d_bitblaster.reset(new EagerBitblaster(d_bv, d_context)); THEORY_PROOF(if (d_bvp) { - d_bitblaster->setResolutionProofLog(d_bvp); + d_bitblaster->setProofLog(d_bvp); d_bvp->setBitblaster(d_bitblaster.get()); }); } @@ -127,8 +127,7 @@ bool EagerBitblastSolver::collectModelInfo(TheoryModel* m, bool fullModel) return d_bitblaster->collectModelInfo(m, fullModel); } -void EagerBitblastSolver::setResolutionProofLog( - proof::ResolutionBitVectorProof* bvp) +void EagerBitblastSolver::setProofLog(proof::BitVectorProof* bvp) { d_bvp = bvp; } diff --git a/src/theory/bv/bv_eager_solver.h b/src/theory/bv/bv_eager_solver.h index 7f688b3ae..0b518ca4a 100644 --- a/src/theory/bv/bv_eager_solver.h +++ b/src/theory/bv/bv_eager_solver.h @@ -48,7 +48,7 @@ class EagerBitblastSolver { bool isInitialized(); void initialize(); bool collectModelInfo(theory::TheoryModel* m, bool fullModel); - void setResolutionProofLog(proof::ResolutionBitVectorProof* bvp); + void setProofLog(proof::BitVectorProof* bvp); private: context::CDHashSet<Node, NodeHashFunction> d_assertionSet; @@ -61,7 +61,7 @@ class EagerBitblastSolver { bool d_useAig; TheoryBV* d_bv; - proof::ResolutionBitVectorProof* d_bvp; + proof::BitVectorProof* d_bvp; }; // class EagerBitblastSolver } // namespace bv diff --git a/src/theory/bv/bv_subtheory.h b/src/theory/bv/bv_subtheory.h index 31c542e0b..e2b649841 100644 --- a/src/theory/bv/bv_subtheory.h +++ b/src/theory/bv/bv_subtheory.h @@ -26,7 +26,7 @@ namespace CVC4 { namespace proof { -class ResolutionBitVectorProof; +class BitVectorProof; } namespace theory { @@ -93,7 +93,7 @@ class SubtheorySolver { return res; } virtual void assertFact(TNode fact) { d_assertionQueue.push_back(fact); } - virtual void setProofLog(proof::ResolutionBitVectorProof* bvp) {} + virtual void setProofLog(proof::BitVectorProof* bvp) {} AssertionQueue::const_iterator assertionsBegin() { return d_assertionQueue.begin(); } diff --git a/src/theory/bv/bv_subtheory_bitblast.cpp b/src/theory/bv/bv_subtheory_bitblast.cpp index ff9dd52c2..ceb02af40 100644 --- a/src/theory/bv/bv_subtheory_bitblast.cpp +++ b/src/theory/bv/bv_subtheory_bitblast.cpp @@ -276,7 +276,7 @@ void BitblastSolver::setConflict(TNode conflict) { d_bv->setConflict(final_conflict); } -void BitblastSolver::setProofLog(proof::ResolutionBitVectorProof* bvp) +void BitblastSolver::setProofLog(proof::BitVectorProof* bvp) { d_bitblaster->setProofLog( bvp ); bvp->setBitblaster(d_bitblaster.get()); diff --git a/src/theory/bv/bv_subtheory_bitblast.h b/src/theory/bv/bv_subtheory_bitblast.h index aa2c90c43..e028dbbdc 100644 --- a/src/theory/bv/bv_subtheory_bitblast.h +++ b/src/theory/bv/bv_subtheory_bitblast.h @@ -79,7 +79,7 @@ public: void bitblastQueue(); void setAbstraction(AbstractionModule* module); uint64_t computeAtomWeight(TNode atom); - void setProofLog(proof::ResolutionBitVectorProof* bvp) override; + void setProofLog(proof::BitVectorProof* bvp) override; }; } /* namespace CVC4::theory::bv */ diff --git a/src/theory/bv/kinds b/src/theory/bv/kinds index 66ee02c63..fe451603b 100644 --- a/src/theory/bv/kinds +++ b/src/theory/bv/kinds @@ -36,101 +36,118 @@ well-founded BITVECTOR_TYPE \ "(*CVC4::theory::TypeEnumerator(%TYPE%))" \ "theory/type_enumerator.h" +### non-parameterized operator kinds ------------------------------------------ + +## concatentation kind operator BITVECTOR_CONCAT 2: "concatenation of two or more bit-vectors" + +## bit-wise kinds operator BITVECTOR_AND 2: "bitwise and of two or more bit-vectors" +operator BITVECTOR_COMP 2 "equality comparison of two bit-vectors (returns one bit)" operator BITVECTOR_OR 2: "bitwise or of two or more bit-vectors" operator BITVECTOR_XOR 2: "bitwise xor of two or more bit-vectors" operator BITVECTOR_NOT 1 "bitwise not of a bit-vector" operator BITVECTOR_NAND 2 "bitwise nand of two bit-vectors" operator BITVECTOR_NOR 2 "bitwise nor of two bit-vectors" operator BITVECTOR_XNOR 2 "bitwise xnor of two bit-vectors" -operator BITVECTOR_COMP 2 "equality comparison of two bit-vectors (returns one bit)" + +## arithmetic kinds operator BITVECTOR_MULT 2: "multiplication of two or more bit-vectors" +operator BITVECTOR_NEG 1 "unary negation of a bit-vector" operator BITVECTOR_PLUS 2: "addition of two or more bit-vectors" operator BITVECTOR_SUB 2 "subtraction of two bit-vectors" -operator BITVECTOR_NEG 1 "unary negation of a bit-vector" operator BITVECTOR_UDIV 2 "unsigned division of two bit-vectors, truncating towards 0 (undefined if divisor is 0)" operator BITVECTOR_UREM 2 "unsigned remainder from truncating division of two bit-vectors (undefined if divisor is 0)" operator BITVECTOR_SDIV 2 "2's complement signed division" -operator BITVECTOR_SREM 2 "2's complement signed remainder (sign follows dividend)" operator BITVECTOR_SMOD 2 "2's complement signed remainder (sign follows divisor)" +operator BITVECTOR_SREM 2 "2's complement signed remainder (sign follows dividend)" # total division kinds operator BITVECTOR_UDIV_TOTAL 2 "unsigned division of two bit-vectors, truncating towards 0 (defined to be the all-ones bit pattern, if divisor is 0)" operator BITVECTOR_UREM_TOTAL 2 "unsigned remainder from truncating division of two bit-vectors (defined to be equal to the dividend, if divisor is 0)" -operator BITVECTOR_SHL 2 "bit-vector shift left (the two bit-vector parameters must have same width)" -operator BITVECTOR_LSHR 2 "bit-vector logical shift right (the two bit-vector parameters must have same width)" +## shift kinds operator BITVECTOR_ASHR 2 "bit-vector arithmetic shift right (the two bit-vector parameters must have same width)" +operator BITVECTOR_LSHR 2 "bit-vector logical shift right (the two bit-vector parameters must have same width)" +operator BITVECTOR_SHL 2 "bit-vector shift left (the two bit-vector parameters must have same width)" -operator BITVECTOR_ULT 2 "bit-vector unsigned less than (the two bit-vector parameters must have same width)" +## inequality kinds operator BITVECTOR_ULE 2 "bit-vector unsigned less than or equal (the two bit-vector parameters must have same width)" -operator BITVECTOR_UGT 2 "bit-vector unsigned greater than (the two bit-vector parameters must have same width)" +operator BITVECTOR_ULT 2 "bit-vector unsigned less than (the two bit-vector parameters must have same width)" operator BITVECTOR_UGE 2 "bit-vector unsigned greater than or equal (the two bit-vector parameters must have same width)" -operator BITVECTOR_SLT 2 "bit-vector signed less than (the two bit-vector parameters must have same width)" +operator BITVECTOR_UGT 2 "bit-vector unsigned greater than (the two bit-vector parameters must have same width)" operator BITVECTOR_SLE 2 "bit-vector signed less than or equal (the two bit-vector parameters must have same width)" -operator BITVECTOR_SGT 2 "bit-vector signed greater than (the two bit-vector parameters must have same width)" +operator BITVECTOR_SLT 2 "bit-vector signed less than (the two bit-vector parameters must have same width)" operator BITVECTOR_SGE 2 "bit-vector signed greater than or equal (the two bit-vector parameters must have same width)" - +operator BITVECTOR_SGT 2 "bit-vector signed greater than (the two bit-vector parameters must have same width)" +# inequalities with return type bit-vector of size 1 operator BITVECTOR_ULTBV 2 "bit-vector unsigned less than but returns bv of size 1 instead of boolean" operator BITVECTOR_SLTBV 2 "bit-vector signed less than but returns bv of size 1 instead of boolean" -operator BITVECTOR_ITE 3 "same semantics as regular ITE, but condition is bv of size 1 instead of Boolean" -operator BITVECTOR_REDOR 1 "bit-vector redor" +## reduction kinds operator BITVECTOR_REDAND 1 "bit-vector redand" +operator BITVECTOR_REDOR 1 "bit-vector redor" -operator BITVECTOR_EAGER_ATOM 1 "formula to be treated as a bv atom via eager bit-blasting (internal-only symbol)" +## if-then-else kind +operator BITVECTOR_ITE 3 "same semantics as regular ITE, but condition is bv of size 1 instead of Boolean" + +## conversion kinds +operator BITVECTOR_TO_NAT 1 "bit-vector conversion to (nonnegative) integer; parameter is a bit-vector" + +## internal kinds operator BITVECTOR_ACKERMANNIZE_UDIV 1 "term to be treated as a variable; used for eager bit-blasting Ackermann expansion of bvudiv (internal-only symbol)" operator BITVECTOR_ACKERMANNIZE_UREM 1 "term to be treated as a variable; used for eager bit-blasting Ackermann expansion of bvurem (internal-only symbol)" +operator BITVECTOR_EAGER_ATOM 1 "formula to be treated as a bv atom via eager bit-blasting (internal-only symbol)" + +### parameterized operator kinds ---------------------------------------------- constant BITVECTOR_BITOF_OP \ ::CVC4::BitVectorBitOf \ ::CVC4::BitVectorBitOfHashFunction \ "util/bitvector.h" \ "operator for the bit-vector boolean bit extract; payload is an instance of the CVC4::BitVectorBitOf class" +parameterized BITVECTOR_BITOF BITVECTOR_BITOF_OP 1 "bit-vector boolean bit extract; first parameter is a BITVECTOR_BITOF_OP, second is a bit-vector term" constant BITVECTOR_EXTRACT_OP \ ::CVC4::BitVectorExtract \ ::CVC4::BitVectorExtractHashFunction \ "util/bitvector.h" \ "operator for the bit-vector extract; payload is an instance of the CVC4::BitVectorExtract class" +parameterized BITVECTOR_EXTRACT BITVECTOR_EXTRACT_OP 1 "bit-vector extract; first parameter is a BITVECTOR_EXTRACT_OP, second is a bit-vector term" constant BITVECTOR_REPEAT_OP \ ::CVC4::BitVectorRepeat \ "::CVC4::UnsignedHashFunction< ::CVC4::BitVectorRepeat >" \ "util/bitvector.h" \ "operator for the bit-vector repeat; payload is an instance of the CVC4::BitVectorRepeat class" - -constant BITVECTOR_ZERO_EXTEND_OP \ - ::CVC4::BitVectorZeroExtend \ - "::CVC4::UnsignedHashFunction< ::CVC4::BitVectorZeroExtend >" \ - "util/bitvector.h" \ - "operator for the bit-vector zero-extend; payload is an instance of the CVC4::BitVectorZeroExtend class" - -constant BITVECTOR_SIGN_EXTEND_OP \ - ::CVC4::BitVectorSignExtend \ - "::CVC4::UnsignedHashFunction< ::CVC4::BitVectorSignExtend >" \ - "util/bitvector.h" \ - "operator for the bit-vector sign-extend; payload is an instance of the CVC4::BitVectorSignExtend class" +parameterized BITVECTOR_REPEAT BITVECTOR_REPEAT_OP 1 "bit-vector repeat; first parameter is a BITVECTOR_REPEAT_OP, second is a bit-vector term" constant BITVECTOR_ROTATE_LEFT_OP \ ::CVC4::BitVectorRotateLeft \ "::CVC4::UnsignedHashFunction< ::CVC4::BitVectorRotateLeft >" \ "util/bitvector.h" \ "operator for the bit-vector rotate left; payload is an instance of the CVC4::BitVectorRotateLeft class" +parameterized BITVECTOR_ROTATE_LEFT BITVECTOR_ROTATE_LEFT_OP 1 "bit-vector rotate left; first parameter is a BITVECTOR_ROTATE_LEFT_OP, second is a bit-vector term" constant BITVECTOR_ROTATE_RIGHT_OP \ ::CVC4::BitVectorRotateRight \ "::CVC4::UnsignedHashFunction< ::CVC4::BitVectorRotateRight >" \ "util/bitvector.h" \ "operator for the bit-vector rotate right; payload is an instance of the CVC4::BitVectorRotateRight class" +parameterized BITVECTOR_ROTATE_RIGHT BITVECTOR_ROTATE_RIGHT_OP 1 "bit-vector rotate right; first parameter is a BITVECTOR_ROTATE_RIGHT_OP, second is a bit-vector term" -parameterized BITVECTOR_BITOF BITVECTOR_BITOF_OP 1 "bit-vector boolean bit extract; first parameter is a BITVECTOR_BITOF_OP, second is a bit-vector term" -parameterized BITVECTOR_EXTRACT BITVECTOR_EXTRACT_OP 1 "bit-vector extract; first parameter is a BITVECTOR_EXTRACT_OP, second is a bit-vector term" -parameterized BITVECTOR_REPEAT BITVECTOR_REPEAT_OP 1 "bit-vector repeat; first parameter is a BITVECTOR_REPEAT_OP, second is a bit-vector term" -parameterized BITVECTOR_ZERO_EXTEND BITVECTOR_ZERO_EXTEND_OP 1 "bit-vector zero-extend; first parameter is a BITVECTOR_ZERO_EXTEND_OP, second is a bit-vector term" +constant BITVECTOR_SIGN_EXTEND_OP \ + ::CVC4::BitVectorSignExtend \ + "::CVC4::UnsignedHashFunction< ::CVC4::BitVectorSignExtend >" \ + "util/bitvector.h" \ + "operator for the bit-vector sign-extend; payload is an instance of the CVC4::BitVectorSignExtend class" parameterized BITVECTOR_SIGN_EXTEND BITVECTOR_SIGN_EXTEND_OP 1 "bit-vector sign-extend; first parameter is a BITVECTOR_SIGN_EXTEND_OP, second is a bit-vector term" -parameterized BITVECTOR_ROTATE_LEFT BITVECTOR_ROTATE_LEFT_OP 1 "bit-vector rotate left; first parameter is a BITVECTOR_ROTATE_LEFT_OP, second is a bit-vector term" -parameterized BITVECTOR_ROTATE_RIGHT BITVECTOR_ROTATE_RIGHT_OP 1 "bit-vector rotate right; first parameter is a BITVECTOR_ROTATE_RIGHT_OP, second is a bit-vector term" + +constant BITVECTOR_ZERO_EXTEND_OP \ + ::CVC4::BitVectorZeroExtend \ + "::CVC4::UnsignedHashFunction< ::CVC4::BitVectorZeroExtend >" \ + "util/bitvector.h" \ + "operator for the bit-vector zero-extend; payload is an instance of the CVC4::BitVectorZeroExtend class" +parameterized BITVECTOR_ZERO_EXTEND BITVECTOR_ZERO_EXTEND_OP 1 "bit-vector zero-extend; first parameter is a BITVECTOR_ZERO_EXTEND_OP, second is a bit-vector term" constant INT_TO_BITVECTOR_OP \ ::CVC4::IntToBitVector \ @@ -138,67 +155,87 @@ constant INT_TO_BITVECTOR_OP \ "util/bitvector.h" \ "operator for the integer conversion to bit-vector; payload is an instance of the CVC4::IntToBitVector class" parameterized INT_TO_BITVECTOR INT_TO_BITVECTOR_OP 1 "integer conversion to bit-vector; first parameter is an INT_TO_BITVECTOR_OP, second is an integer term" -operator BITVECTOR_TO_NAT 1 "bit-vector conversion to (nonnegative) integer; parameter is a bit-vector" + +### type rules for non-parameterized operator kinds --------------------------- typerule CONST_BITVECTOR ::CVC4::theory::bv::BitVectorConstantTypeRule +## concatentation kind +typerule BITVECTOR_CONCAT ::CVC4::theory::bv::BitVectorConcatTypeRule + +## bit-wise kinds typerule BITVECTOR_AND ::CVC4::theory::bv::BitVectorFixedWidthTypeRule -typerule BITVECTOR_OR ::CVC4::theory::bv::BitVectorFixedWidthTypeRule -typerule BITVECTOR_XOR ::CVC4::theory::bv::BitVectorFixedWidthTypeRule -typerule BITVECTOR_NOT ::CVC4::theory::bv::BitVectorFixedWidthTypeRule +typerule BITVECTOR_COMP ::CVC4::theory::bv::BitVectorBVPredTypeRule typerule BITVECTOR_NAND ::CVC4::theory::bv::BitVectorFixedWidthTypeRule typerule BITVECTOR_NOR ::CVC4::theory::bv::BitVectorFixedWidthTypeRule +typerule BITVECTOR_NOT ::CVC4::theory::bv::BitVectorFixedWidthTypeRule +typerule BITVECTOR_OR ::CVC4::theory::bv::BitVectorFixedWidthTypeRule typerule BITVECTOR_XNOR ::CVC4::theory::bv::BitVectorFixedWidthTypeRule +typerule BITVECTOR_XOR ::CVC4::theory::bv::BitVectorFixedWidthTypeRule +## arithmetic kinds typerule BITVECTOR_MULT ::CVC4::theory::bv::BitVectorFixedWidthTypeRule +typerule BITVECTOR_NEG ::CVC4::theory::bv::BitVectorFixedWidthTypeRule typerule BITVECTOR_PLUS ::CVC4::theory::bv::BitVectorFixedWidthTypeRule typerule BITVECTOR_SUB ::CVC4::theory::bv::BitVectorFixedWidthTypeRule -typerule BITVECTOR_NEG ::CVC4::theory::bv::BitVectorFixedWidthTypeRule - typerule BITVECTOR_UDIV ::CVC4::theory::bv::BitVectorFixedWidthTypeRule typerule BITVECTOR_UREM ::CVC4::theory::bv::BitVectorFixedWidthTypeRule -typerule BITVECTOR_UDIV_TOTAL ::CVC4::theory::bv::BitVectorFixedWidthTypeRule -typerule BITVECTOR_UREM_TOTAL ::CVC4::theory::bv::BitVectorFixedWidthTypeRule typerule BITVECTOR_SDIV ::CVC4::theory::bv::BitVectorFixedWidthTypeRule -typerule BITVECTOR_SREM ::CVC4::theory::bv::BitVectorFixedWidthTypeRule typerule BITVECTOR_SMOD ::CVC4::theory::bv::BitVectorFixedWidthTypeRule -typerule BITVECTOR_SHL ::CVC4::theory::bv::BitVectorFixedWidthTypeRule -typerule BITVECTOR_LSHR ::CVC4::theory::bv::BitVectorFixedWidthTypeRule +typerule BITVECTOR_SREM ::CVC4::theory::bv::BitVectorFixedWidthTypeRule +# total division kinds +typerule BITVECTOR_UDIV_TOTAL ::CVC4::theory::bv::BitVectorFixedWidthTypeRule +typerule BITVECTOR_UREM_TOTAL ::CVC4::theory::bv::BitVectorFixedWidthTypeRule + +## shift kinds typerule BITVECTOR_ASHR ::CVC4::theory::bv::BitVectorFixedWidthTypeRule -typerule BITVECTOR_ROTATE_LEFT ::CVC4::theory::bv::BitVectorFixedWidthTypeRule -typerule BITVECTOR_ROTATE_RIGHT ::CVC4::theory::bv::BitVectorFixedWidthTypeRule +typerule BITVECTOR_LSHR ::CVC4::theory::bv::BitVectorFixedWidthTypeRule +typerule BITVECTOR_SHL ::CVC4::theory::bv::BitVectorFixedWidthTypeRule -typerule BITVECTOR_ULT ::CVC4::theory::bv::BitVectorPredicateTypeRule +## inequality kinds typerule BITVECTOR_ULE ::CVC4::theory::bv::BitVectorPredicateTypeRule -typerule BITVECTOR_UGT ::CVC4::theory::bv::BitVectorPredicateTypeRule +typerule BITVECTOR_ULT ::CVC4::theory::bv::BitVectorPredicateTypeRule typerule BITVECTOR_UGE ::CVC4::theory::bv::BitVectorPredicateTypeRule -typerule BITVECTOR_SLT ::CVC4::theory::bv::BitVectorPredicateTypeRule +typerule BITVECTOR_UGT ::CVC4::theory::bv::BitVectorPredicateTypeRule typerule BITVECTOR_SLE ::CVC4::theory::bv::BitVectorPredicateTypeRule -typerule BITVECTOR_SGT ::CVC4::theory::bv::BitVectorPredicateTypeRule +typerule BITVECTOR_SLT ::CVC4::theory::bv::BitVectorPredicateTypeRule typerule BITVECTOR_SGE ::CVC4::theory::bv::BitVectorPredicateTypeRule - -typerule BITVECTOR_COMP ::CVC4::theory::bv::BitVectorBVPredTypeRule +typerule BITVECTOR_SGT ::CVC4::theory::bv::BitVectorPredicateTypeRule +# inequalities with return type bit-vector of size 1 typerule BITVECTOR_ULTBV ::CVC4::theory::bv::BitVectorBVPredTypeRule typerule BITVECTOR_SLTBV ::CVC4::theory::bv::BitVectorBVPredTypeRule + +## if-then-else kind typerule BITVECTOR_ITE ::CVC4::theory::bv::BitVectorITETypeRule -typerule BITVECTOR_REDOR ::CVC4::theory::bv::BitVectorUnaryPredicateTypeRule +## reduction kinds typerule BITVECTOR_REDAND ::CVC4::theory::bv::BitVectorUnaryPredicateTypeRule +typerule BITVECTOR_REDOR ::CVC4::theory::bv::BitVectorUnaryPredicateTypeRule +## conversion kinds +typerule BITVECTOR_TO_NAT ::CVC4::theory::bv::BitVectorConversionTypeRule -typerule BITVECTOR_EAGER_ATOM ::CVC4::theory::bv::BitVectorEagerAtomTypeRule +## internal kinds typerule BITVECTOR_ACKERMANNIZE_UDIV ::CVC4::theory::bv::BitVectorAckermanizationUdivTypeRule typerule BITVECTOR_ACKERMANNIZE_UREM ::CVC4::theory::bv::BitVectorAckermanizationUremTypeRule +typerule BITVECTOR_EAGER_ATOM ::CVC4::theory::bv::BitVectorEagerAtomTypeRule + +### type rules for parameterized operator kinds ------------------------------- +typerule BITVECTOR_BITOF_OP ::CVC4::theory::bv::BitVectorBitOfOpTypeRule +typerule BITVECTOR_BITOF ::CVC4::theory::bv::BitVectorBitOfTypeRule typerule BITVECTOR_EXTRACT_OP ::CVC4::theory::bv::BitVectorExtractOpTypeRule typerule BITVECTOR_EXTRACT ::CVC4::theory::bv::BitVectorExtractTypeRule -typerule BITVECTOR_BITOF ::CVC4::theory::bv::BitVectorBitOfTypeRule -typerule BITVECTOR_CONCAT ::CVC4::theory::bv::BitVectorConcatTypeRule +typerule BITVECTOR_REPEAT_OP ::CVC4::theory::bv::BitVectorRepeatOpTypeRule typerule BITVECTOR_REPEAT ::CVC4::theory::bv::BitVectorRepeatTypeRule -typerule BITVECTOR_ZERO_EXTEND ::CVC4::theory::bv::BitVectorExtendTypeRule +typerule BITVECTOR_ROTATE_LEFT_OP ::CVC4::theory::bv::BitVectorRotateLeftOpTypeRule +typerule BITVECTOR_ROTATE_LEFT ::CVC4::theory::bv::BitVectorFixedWidthTypeRule +typerule BITVECTOR_ROTATE_RIGHT_OP ::CVC4::theory::bv::BitVectorRotateRightOpTypeRule +typerule BITVECTOR_ROTATE_RIGHT ::CVC4::theory::bv::BitVectorFixedWidthTypeRule +typerule BITVECTOR_SIGN_EXTEND_OP ::CVC4::theory::bv::BitVectorSignExtendOpTypeRule typerule BITVECTOR_SIGN_EXTEND ::CVC4::theory::bv::BitVectorExtendTypeRule - -typerule BITVECTOR_TO_NAT ::CVC4::theory::bv::BitVectorConversionTypeRule +typerule BITVECTOR_ZERO_EXTEND_OP ::CVC4::theory::bv::BitVectorZeroExtendOpTypeRule +typerule BITVECTOR_ZERO_EXTEND ::CVC4::theory::bv::BitVectorExtendTypeRule typerule INT_TO_BITVECTOR_OP ::CVC4::theory::bv::IntToBitVectorOpTypeRule typerule INT_TO_BITVECTOR ::CVC4::theory::bv::BitVectorConversionTypeRule diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp index 949a3d738..04a6cf52c 100644 --- a/src/theory/bv/theory_bv.cpp +++ b/src/theory/bv/theory_bv.cpp @@ -986,10 +986,10 @@ bool TheoryBV::applyAbstraction(const std::vector<Node>& assertions, std::vector return changed; } -void TheoryBV::setResolutionProofLog(proof::ResolutionBitVectorProof* bvp) +void TheoryBV::setProofLog(proof::BitVectorProof* bvp) { if( options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER ){ - d_eagerSolver->setResolutionProofLog(bvp); + d_eagerSolver->setProofLog(bvp); }else{ for( unsigned i=0; i< d_subtheories.size(); i++ ){ d_subtheories[i]->setProofLog( bvp ); diff --git a/src/theory/bv/theory_bv.h b/src/theory/bv/theory_bv.h index afa9f4b4f..3d151cfb1 100644 --- a/src/theory/bv/theory_bv.h +++ b/src/theory/bv/theory_bv.h @@ -31,6 +31,14 @@ #include "util/hash.h" #include "util/statistics_registry.h" +// Forward declarations, needed because the BV theory and the BV Proof classes +// are cyclically dependent +namespace CVC4 { +namespace proof { +class BitVectorProof; +} +} // namespace CVC4 + namespace CVC4 { namespace theory { namespace bv { @@ -104,7 +112,7 @@ public: bool applyAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions); - void setResolutionProofLog(proof::ResolutionBitVectorProof* bvp); + void setProofLog(proof::BitVectorProof* bvp); private: diff --git a/src/theory/bv/theory_bv_type_rules.h b/src/theory/bv/theory_bv_type_rules.h index 817099752..616a03f6b 100644 --- a/src/theory/bv/theory_bv_type_rules.h +++ b/src/theory/bv/theory_bv_type_rules.h @@ -2,7 +2,7 @@ /*! \file theory_bv_type_rules.h ** \verbatim ** Top contributors (to current version): - ** Dejan Jovanovic, Morgan Deters, Tim King + ** Aina Niemetz, Dejan Jovanovic, Morgan Deters ** This file is part of the CVC4 project. ** Copyright (c) 2009-2018 by the authors listed in the file AUTHORS ** in the top-level source directory) and their institutional affiliations. @@ -25,90 +25,67 @@ namespace CVC4 { namespace theory { namespace bv { -class BitVectorConstantTypeRule { - public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, - bool check) { - if (check) { - if (n.getConst<BitVector>().getSize() == 0) { - throw TypeCheckingExceptionPrivate(n, "constant of size 0"); - } - } - return nodeManager->mkBitVectorType(n.getConst<BitVector>().getSize()); - } -}; /* class BitVectorConstantTypeRule */ +/* -------------------------------------------------------------------------- */ -class BitVectorBitOfTypeRule { +class CardinalityComputer +{ public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, - bool check) { - if (check) { - BitVectorBitOf info = n.getOperator().getConst<BitVectorBitOf>(); - TypeNode t = n[0].getType(check); + inline static Cardinality computeCardinality(TypeNode type) + { + Assert(type.getKind() == kind::BITVECTOR_TYPE); - if (!t.isBitVector()) { - throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term"); - } - if (info.bitIndex >= t.getBitVectorSize()) { - throw TypeCheckingExceptionPrivate( - n, "extract index is larger than the bitvector size"); - } + unsigned size = type.getConst<BitVectorSize>(); + if (size == 0) + { + return 0; } - return nodeManager->booleanType(); + Integer i = Integer(2).pow(size); + return i; } -}; /* class BitVectorBitOfTypeRule */ +}; /* class CardinalityComputer */ -class BitVectorBVPredTypeRule { - public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, - bool check) { - if (check) { - TypeNode lhs = n[0].getType(check); - TypeNode rhs = n[1].getType(check); - if (!lhs.isBitVector() || lhs != rhs) { - throw TypeCheckingExceptionPrivate( - n, "expecting bit-vector terms of the same width"); - } - } - return nodeManager->mkBitVectorType(1); - } -}; /* class BitVectorBVPredTypeRule */ +/* -------------------------------------------------------------------------- */ -class BitVectorITETypeRule { +class BitVectorConstantTypeRule +{ public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, - bool check) { - Assert(n.getNumChildren() == 3); - TypeNode thenpart = n[1].getType(check); - if (check) { - TypeNode cond = n[0].getType(check); - if (cond != nodeManager->mkBitVectorType(1)) { - throw TypeCheckingExceptionPrivate( - n, "expecting condition to be bit-vector term size 1"); - } - TypeNode elsepart = n[2].getType(check); - if (thenpart != elsepart) { - throw TypeCheckingExceptionPrivate( - n, "expecting then and else parts to have same type"); + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + if (check) + { + if (n.getConst<BitVector>().getSize() == 0) + { + throw TypeCheckingExceptionPrivate(n, "constant of size 0"); } } - return thenpart; + return nodeManager->mkBitVectorType(n.getConst<BitVector>().getSize()); } -}; /* class BitVectorITETypeRule */ +}; /* class BitVectorConstantTypeRule */ -class BitVectorFixedWidthTypeRule { +/* -------------------------------------------------------------------------- */ + +class BitVectorFixedWidthTypeRule +{ public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, - bool check) { + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { TNode::iterator it = n.begin(); TypeNode t = (*it).getType(check); - if (check) { - if (!t.isBitVector()) { + if (check) + { + if (!t.isBitVector()) + { throw TypeCheckingExceptionPrivate(n, "expecting bit-vector terms"); } TNode::iterator it_end = n.end(); - for (++it; it != it_end; ++it) { - if ((*it).getType(check) != t) { + for (++it; it != it_end; ++it) + { + if ((*it).getType(check) != t) + { throw TypeCheckingExceptionPrivate( n, "expecting bit-vector terms of the same width"); } @@ -118,17 +95,25 @@ class BitVectorFixedWidthTypeRule { } }; /* class BitVectorFixedWidthTypeRule */ -class BitVectorPredicateTypeRule { +/* -------------------------------------------------------------------------- */ + +class BitVectorPredicateTypeRule +{ public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, - bool check) { - if (check) { + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + if (check) + { TypeNode lhsType = n[0].getType(check); - if (!lhsType.isBitVector()) { + if (!lhsType.isBitVector()) + { throw TypeCheckingExceptionPrivate(n, "expecting bit-vector terms"); } TypeNode rhsType = n[1].getType(check); - if (lhsType != rhsType) { + if (lhsType != rhsType) + { throw TypeCheckingExceptionPrivate( n, "expecting bit-vector terms of the same width"); } @@ -137,13 +122,18 @@ class BitVectorPredicateTypeRule { } }; /* class BitVectorPredicateTypeRule */ -class BitVectorUnaryPredicateTypeRule { +class BitVectorUnaryPredicateTypeRule +{ public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, - bool check) { - if (check) { + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + if (check) + { TypeNode type = n[0].getType(check); - if (!type.isBitVector()) { + if (!type.isBitVector()) + { throw TypeCheckingExceptionPrivate(n, "expecting bit-vector terms"); } } @@ -151,68 +141,166 @@ class BitVectorUnaryPredicateTypeRule { } }; /* class BitVectorUnaryPredicateTypeRule */ -class BitVectorEagerAtomTypeRule { +class BitVectorBVPredTypeRule +{ public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, - bool check) { - if (check) { - TypeNode lhsType = n[0].getType(check); - if (!lhsType.isBoolean()) { - throw TypeCheckingExceptionPrivate(n, "expecting boolean term"); + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + if (check) + { + TypeNode lhs = n[0].getType(check); + TypeNode rhs = n[1].getType(check); + if (!lhs.isBitVector() || lhs != rhs) + { + throw TypeCheckingExceptionPrivate( + n, "expecting bit-vector terms of the same width"); } } - return nodeManager->booleanType(); + return nodeManager->mkBitVectorType(1); } -}; /* class BitVectorEagerAtomTypeRule */ +}; /* class BitVectorBVPredTypeRule */ -class BitVectorAckermanizationUdivTypeRule { +/* -------------------------------------------------------------------------- */ +/* non-parameterized operator kinds */ +/* -------------------------------------------------------------------------- */ + +class BitVectorConcatTypeRule +{ public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, - bool check) { - TypeNode lhsType = n[0].getType(check); - if (check) { - if (!lhsType.isBitVector()) { - throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term"); + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + unsigned size = 0; + TNode::iterator it = n.begin(); + TNode::iterator it_end = n.end(); + for (; it != it_end; ++it) + { + TypeNode t = (*it).getType(check); + // NOTE: We're throwing a type-checking exception here even + // when check is false, bc if we don't check that the arguments + // are bit-vectors the result type will be inaccurate + if (!t.isBitVector()) + { + throw TypeCheckingExceptionPrivate(n, "expecting bit-vector terms"); } + size += t.getBitVectorSize(); } - return lhsType; + return nodeManager->mkBitVectorType(size); } -}; /* class BitVectorAckermanizationUdivTypeRule */ +}; /* class BitVectorConcatTypeRule */ -class BitVectorAckermanizationUremTypeRule { +class BitVectorITETypeRule +{ public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, - bool check) { - TypeNode lhsType = n[0].getType(check); - if (check) { - if (!lhsType.isBitVector()) { + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + Assert(n.getNumChildren() == 3); + TypeNode thenpart = n[1].getType(check); + if (check) + { + TypeNode cond = n[0].getType(check); + if (cond != nodeManager->mkBitVectorType(1)) + { + throw TypeCheckingExceptionPrivate( + n, "expecting condition to be bit-vector term size 1"); + } + TypeNode elsepart = n[2].getType(check); + if (thenpart != elsepart) + { + throw TypeCheckingExceptionPrivate( + n, "expecting then and else parts to have same type"); + } + } + return thenpart; + } +}; /* class BitVectorITETypeRule */ + +/* -------------------------------------------------------------------------- */ +/* parameterized operator kinds */ +/* -------------------------------------------------------------------------- */ + +class BitVectorBitOfOpTypeRule +{ + public: + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + Assert(n.getKind() == kind::BITVECTOR_BITOF_OP); + return nodeManager->builtinOperatorType(); + } +}; /* class BitVectorBitOfOpTypeRule */ + +class BitVectorBitOfTypeRule +{ + public: + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + if (check) + { + BitVectorBitOf info = n.getOperator().getConst<BitVectorBitOf>(); + TypeNode t = n[0].getType(check); + + if (!t.isBitVector()) + { throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term"); } + if (info.bitIndex >= t.getBitVectorSize()) + { + throw TypeCheckingExceptionPrivate( + n, "extract index is larger than the bitvector size"); + } } - return lhsType; + return nodeManager->booleanType(); } -}; /* class BitVectorAckermanizationUremTypeRule */ +}; /* class BitVectorBitOfTypeRule */ -class BitVectorExtractTypeRule { +class BitVectorExtractOpTypeRule +{ public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, - bool check) { + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + Assert(n.getKind() == kind::BITVECTOR_EXTRACT_OP); + return nodeManager->builtinOperatorType(); + } +}; /* class BitVectorExtractOpTypeRule */ + +class BitVectorExtractTypeRule +{ + public: + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { BitVectorExtract extractInfo = n.getOperator().getConst<BitVectorExtract>(); // NOTE: We're throwing a type-checking exception here even // if check is false, bc if we allow high < low the resulting // type will be illegal - if (extractInfo.high < extractInfo.low) { + if (extractInfo.high < extractInfo.low) + { throw TypeCheckingExceptionPrivate( n, "high extract index is smaller than the low extract index"); } - if (check) { + if (check) + { TypeNode t = n[0].getType(check); - if (!t.isBitVector()) { + if (!t.isBitVector()) + { throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term"); } - if (extractInfo.high >= t.getBitVectorSize()) { + if (extractInfo.high >= t.getBitVectorSize()) + { throw TypeCheckingExceptionPrivate( n, "high extract index is bigger than the size of the bit-vector"); } @@ -221,45 +309,31 @@ class BitVectorExtractTypeRule { } }; /* class BitVectorExtractTypeRule */ -class BitVectorExtractOpTypeRule { +class BitVectorRepeatOpTypeRule +{ public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, - bool check) { - Assert(n.getKind() == kind::BITVECTOR_EXTRACT_OP); + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + Assert(n.getKind() == kind::BITVECTOR_REPEAT_OP); return nodeManager->builtinOperatorType(); } -}; /* class BitVectorExtractOpTypeRule */ - -class BitVectorConcatTypeRule { - public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, - bool check) { - unsigned size = 0; - TNode::iterator it = n.begin(); - TNode::iterator it_end = n.end(); - for (; it != it_end; ++it) { - TypeNode t = (*it).getType(check); - // NOTE: We're throwing a type-checking exception here even - // when check is false, bc if we don't check that the arguments - // are bit-vectors the result type will be inaccurate - if (!t.isBitVector()) { - throw TypeCheckingExceptionPrivate(n, "expecting bit-vector terms"); - } - size += t.getBitVectorSize(); - } - return nodeManager->mkBitVectorType(size); - } -}; /* class BitVectorConcatTypeRule */ +}; /* class BitVectorRepeatOpTypeRule */ -class BitVectorRepeatTypeRule { +class BitVectorRepeatTypeRule +{ public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, - bool check) { + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { TypeNode t = n[0].getType(check); // NOTE: We're throwing a type-checking exception here even // when check is false, bc if the argument isn't a bit-vector // the result type will be inaccurate - if (!t.isBitVector()) { + if (!t.isBitVector()) + { throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term"); } unsigned repeatAmount = n.getOperator().getConst<BitVectorRepeat>(); @@ -267,15 +341,67 @@ class BitVectorRepeatTypeRule { } }; /* class BitVectorRepeatTypeRule */ -class BitVectorExtendTypeRule { +class BitVectorRotateLeftOpTypeRule +{ + public: + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + Assert(n.getKind() == kind::BITVECTOR_ROTATE_LEFT); + return nodeManager->builtinOperatorType(); + } +}; /* class BitVectorRotateLeftOpTypeRule */ + +class BitVectorRotateRightOpTypeRule +{ + public: + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + Assert(n.getKind() == kind::BITVECTOR_ROTATE_RIGHT); + return nodeManager->builtinOperatorType(); + } +}; /* class BitVectorRotateRightOpTypeRule */ + +class BitVectorSignExtendOpTypeRule +{ public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, - bool check) { + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + Assert(n.getKind() == kind::BITVECTOR_SIGN_EXTEND_OP); + return nodeManager->builtinOperatorType(); + } +}; /* class BitVectorSignExtendOpTypeRule */ + +class BitVectorZeroExtendOpTypeRule +{ + public: + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + Assert(n.getKind() == kind::BITVECTOR_ZERO_EXTEND_OP); + return nodeManager->builtinOperatorType(); + } +}; /* class BitVectorZeroExtendOpTypeRule */ + +class BitVectorExtendTypeRule +{ + public: + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { TypeNode t = n[0].getType(check); // NOTE: We're throwing a type-checking exception here even // when check is false, bc if the argument isn't a bit-vector // the result type will be inaccurate - if (!t.isBitVector()) { + if (!t.isBitVector()) + { throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term"); } unsigned extendAmount = @@ -286,20 +412,45 @@ class BitVectorExtendTypeRule { } }; /* class BitVectorExtendTypeRule */ -class BitVectorConversionTypeRule { +class IntToBitVectorOpTypeRule +{ public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, - bool check) { - if (n.getKind() == kind::BITVECTOR_TO_NAT) { - if (check && !n[0].getType(check).isBitVector()) { + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + if (n.getKind() == kind::INT_TO_BITVECTOR_OP) + { + size_t bvSize = n.getConst<IntToBitVector>(); + return nodeManager->mkFunctionType(nodeManager->integerType(), + nodeManager->mkBitVectorType(bvSize)); + } + + InternalError("bv-conversion typerule invoked for non-bv-conversion kind"); + } +}; /* class IntToBitVectorOpTypeRule */ + +class BitVectorConversionTypeRule +{ + public: + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + if (n.getKind() == kind::BITVECTOR_TO_NAT) + { + if (check && !n[0].getType(check).isBitVector()) + { throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term"); } return nodeManager->integerType(); } - if (n.getKind() == kind::INT_TO_BITVECTOR) { + if (n.getKind() == kind::INT_TO_BITVECTOR) + { size_t bvSize = n.getOperator().getConst<IntToBitVector>(); - if (check && !n[0].getType(check).isInteger()) { + if (check && !n[0].getType(check).isInteger()) + { throw TypeCheckingExceptionPrivate(n, "expecting integer term"); } return nodeManager->mkBitVectorType(bvSize); @@ -309,35 +460,69 @@ class BitVectorConversionTypeRule { } }; /* class BitVectorConversionTypeRule */ -class IntToBitVectorOpTypeRule { -public: - inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) { +/* -------------------------------------------------------------------------- */ +/* internal */ +/* -------------------------------------------------------------------------- */ - if(n.getKind() == kind::INT_TO_BITVECTOR_OP) { - size_t bvSize = n.getConst<IntToBitVector>(); - return nodeManager->mkFunctionType( nodeManager->integerType(), nodeManager->mkBitVectorType(bvSize) ); +class BitVectorEagerAtomTypeRule +{ + public: + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + if (check) + { + TypeNode lhsType = n[0].getType(check); + if (!lhsType.isBoolean()) + { + throw TypeCheckingExceptionPrivate(n, "expecting boolean term"); + } } - - InternalError("bv-conversion typerule invoked for non-bv-conversion kind"); + return nodeManager->booleanType(); } -}; /* class IntToBitVectorOpTypeRule */ +}; /* class BitVectorEagerAtomTypeRule */ -class CardinalityComputer { +class BitVectorAckermanizationUdivTypeRule +{ public: - inline static Cardinality computeCardinality(TypeNode type) { - Assert(type.getKind() == kind::BITVECTOR_TYPE); + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + TypeNode lhsType = n[0].getType(check); + if (check) + { + if (!lhsType.isBitVector()) + { + throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term"); + } + } + return lhsType; + } +}; /* class BitVectorAckermanizationUdivTypeRule */ - unsigned size = type.getConst<BitVectorSize>(); - if (size == 0) { - return 0; +class BitVectorAckermanizationUremTypeRule +{ + public: + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + TypeNode lhsType = n[0].getType(check); + if (check) + { + if (!lhsType.isBitVector()) + { + throw TypeCheckingExceptionPrivate(n, "expecting bit-vector term"); + } } - Integer i = Integer(2).pow(size); - return i; + return lhsType; } -}; /* class CardinalityComputer */ +}; /* class BitVectorAckermanizationUremTypeRule */ -} /* CVC4::theory::bv namespace */ -} /* CVC4::theory namespace */ -} /* CVC4 namespace */ +} // namespace bv +} // namespace theory +} // namespace CVC4 #endif /* __CVC4__THEORY__BV__THEORY_BV_TYPE_RULES_H */ diff --git a/src/theory/datatypes/datatypes_rewriter.cpp b/src/theory/datatypes/datatypes_rewriter.cpp index 4469f0fe9..a2458e2eb 100644 --- a/src/theory/datatypes/datatypes_rewriter.cpp +++ b/src/theory/datatypes/datatypes_rewriter.cpp @@ -428,7 +428,7 @@ RewriteResponse DatatypesRewriter::rewriteTester(TNode in) NodeManager::currentNM()->mkConst(result)); } const Datatype& dt = static_cast<DatatypeType>(in[0].getType().toType()).getDatatype(); - if (dt.getNumConstructors() == 1) + if (dt.getNumConstructors() == 1 && !dt.isSygus()) { // only one constructor, so it must be Trace("datatypes-rewrite") diff --git a/src/theory/datatypes/kinds b/src/theory/datatypes/kinds index b83e9616a..a0b00bcb0 100644 --- a/src/theory/datatypes/kinds +++ b/src/theory/datatypes/kinds @@ -91,6 +91,7 @@ constant TUPLE_UPDATE_OP \ "util/tuple.h" \ "operator for a tuple update; payload is an instance of the CVC4::TupleUpdate class" parameterized TUPLE_UPDATE TUPLE_UPDATE_OP 2 "tuple update; first parameter is a TUPLE_UPDATE_OP (which references an index), second is the tuple, third is the element to store in the tuple at the given index" +typerule TUPLE_UPDATE_OP ::CVC4::theory::datatypes::TupleUpdateOpTypeRule typerule TUPLE_UPDATE ::CVC4::theory::datatypes::TupleUpdateTypeRule constant RECORD_UPDATE_OP \ @@ -99,6 +100,7 @@ constant RECORD_UPDATE_OP \ "expr/record.h" \ "operator for a record update; payload is an instance CVC4::RecordUpdate class" parameterized RECORD_UPDATE RECORD_UPDATE_OP 2 "record update; first parameter is a RECORD_UPDATE_OP (which references a field), second is a record term to update, third is the element to store in the record in the given field" +typerule RECORD_UPDATE_OP ::CVC4::theory::datatypes::RecordUpdateOpTypeRule typerule RECORD_UPDATE ::CVC4::theory::datatypes::RecordUpdateTypeRule diff --git a/src/theory/datatypes/theory_datatypes_type_rules.h b/src/theory/datatypes/theory_datatypes_type_rules.h index 140ebe158..8a5849010 100644 --- a/src/theory/datatypes/theory_datatypes_type_rules.h +++ b/src/theory/datatypes/theory_datatypes_type_rules.h @@ -273,6 +273,18 @@ struct TupleUpdateTypeRule { } }; /* struct TupleUpdateTypeRule */ +class TupleUpdateOpTypeRule +{ + public: + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + Assert(n.getKind() == kind::TUPLE_UPDATE_OP); + return nodeManager->builtinOperatorType(); + } +}; /* class TupleUpdateOpTypeRule */ + struct RecordUpdateTypeRule { inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) { @@ -298,6 +310,18 @@ struct RecordUpdateTypeRule { } }; /* struct RecordUpdateTypeRule */ +class RecordUpdateOpTypeRule +{ + public: + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + Assert(n.getKind() == kind::RECORD_UPDATE_OP); + return nodeManager->builtinOperatorType(); + } +}; /* class RecordUpdateOpTypeRule */ + class DtSizeTypeRule { public: inline static TypeNode computeType(NodeManager* nodeManager, TNode n, diff --git a/src/theory/fp/theory_fp_rewriter.cpp b/src/theory/fp/theory_fp_rewriter.cpp index f77291a05..21644161e 100644 --- a/src/theory/fp/theory_fp_rewriter.cpp +++ b/src/theory/fp/theory_fp_rewriter.cpp @@ -175,8 +175,9 @@ namespace rewrite { if (node[0] == node[1]) { return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(true)); } else if (!isPreRewrite && (node[0] > node[1])) { - Node normal = NodeManager::currentNM()->mkNode(kind::EQUAL,node[1],node[0]); - return RewriteResponse(REWRITE_DONE, normal); + Node normal = + NodeManager::currentNM()->mkNode(kind::EQUAL, node[1], node[0]); + return RewriteResponse(REWRITE_DONE, normal); } else { return RewriteResponse(REWRITE_DONE, node); } @@ -191,7 +192,7 @@ namespace rewrite { (k == kind::FLOATINGPOINT_MIN_TOTAL) || (k == kind::FLOATINGPOINT_MAX_TOTAL)); #endif if (node[0] == node[1]) { - return RewriteResponse(REWRITE_DONE, node[0]); + return RewriteResponse(REWRITE_AGAIN, node[0]); } else { return RewriteResponse(REWRITE_DONE, node); } @@ -249,7 +250,7 @@ namespace rewrite { (childKind == kind::FLOATINGPOINT_ABS)) { Node rewritten = NodeManager::currentNM()->mkNode(node.getKind(),node[0][0]); - return RewriteResponse(REWRITE_AGAIN, rewritten); + return RewriteResponse(REWRITE_AGAIN_FULL, rewritten); } else { return RewriteResponse(REWRITE_DONE, node); } @@ -276,8 +277,11 @@ namespace rewrite { // Lift negation out of the LHS so it can be cancelled out if (working[0].getKind() == kind::FLOATINGPOINT_NEG) { NodeManager * nm = NodeManager::currentNM(); - working = nm->mkNode(kind::FLOATINGPOINT_NEG, - nm->mkNode(kind::FLOATINGPOINT_REM, working[0][0], working[1])); + working = nm->mkNode( + kind::FLOATINGPOINT_NEG, + nm->mkNode(kind::FLOATINGPOINT_REM, working[0][0], working[1])); + // in contrast to other rewrites here, this requires rewrite again full + return RewriteResponse(REWRITE_AGAIN_FULL, working); } return RewriteResponse(REWRITE_DONE, working); diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp index c52069a31..cb60b6342 100644 --- a/src/theory/strings/theory_strings.cpp +++ b/src/theory/strings/theory_strings.cpp @@ -3083,15 +3083,29 @@ void TheoryStrings::processSimpleNEq( std::vector< std::vector< Node > > &normal Trace("strings-solve-debug") << "Non-simple Case 2 : must compare strings" << std::endl; int loop_in_i = -1; int loop_in_j = -1; + ProcessLoopResult plr = ProcessLoopResult::SKIPPED; if( detectLoop( normal_forms, i, j, index, loop_in_i, loop_in_j, rproc ) ){ if( !isRev ){ //FIXME getExplanationVectorForPrefixEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, -1, -1, isRev, info.d_ant ); //set info - if( processLoop( normal_forms, normal_form_src, i, j, loop_in_i!=-1 ? i : j, loop_in_i!=-1 ? j : i, loop_in_i!=-1 ? loop_in_i : loop_in_j, index, info ) ){ + plr = processLoop(normal_forms, + normal_form_src, + i, + j, + loop_in_i != -1 ? i : j, + loop_in_i != -1 ? j : i, + loop_in_i != -1 ? loop_in_i : loop_in_j, + index, + info); + if (plr == ProcessLoopResult::INFERENCE) + { info_valid = true; } } - }else{ + } + + if (plr == ProcessLoopResult::SKIPPED) + { //AJR: length entailment here? if( normal_forms[i][index].getKind() == kind::CONST_STRING || normal_forms[j][index].getKind() == kind::CONST_STRING ){ unsigned const_k = normal_forms[i][index].getKind() == kind::CONST_STRING ? i : j; @@ -3310,18 +3324,26 @@ bool TheoryStrings::detectLoop( std::vector< std::vector< Node > > &normal_forms } //xs(zy)=t(yz)xr -bool TheoryStrings::processLoop( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src, - int i, int j, int loop_n_index, int other_n_index, int loop_index, int index, InferInfo& info ){ - if( options::stringAbortLoop() ){ - std::stringstream ss; - ss << "Looping word equation encountered." << std::endl; - throw LogicException(ss.str()); - } - if (!options::stringProcessLoop()) +TheoryStrings::ProcessLoopResult TheoryStrings::processLoop( + const std::vector<std::vector<Node> >& normal_forms, + const std::vector<Node>& normal_form_src, + int i, + int j, + int loop_n_index, + int other_n_index, + int loop_index, + int index, + InferInfo& info) +{ + if (options::stringProcessLoopMode() == ProcessLoopMode::ABORT) { - d_out->setIncomplete(); - return false; + throw LogicException("Looping word equation encountered."); + } + else if (options::stringProcessLoopMode() == ProcessLoopMode::NONE) + { + return ProcessLoopResult::SKIPPED; } + NodeManager* nm = NodeManager::currentNM(); Node conc; Trace("strings-loop") << "Detected possible loop for " @@ -3330,12 +3352,12 @@ bool TheoryStrings::processLoop( std::vector< std::vector< Node > > &normal_form << std::endl; Trace("strings-loop") << " ... T(Y.Z)= "; - std::vector<Node>& veci = normal_forms[loop_n_index]; + const std::vector<Node>& veci = normal_forms[loop_n_index]; std::vector<Node> vec_t(veci.begin() + index, veci.begin() + loop_index); Node t_yz = mkConcat(vec_t); Trace("strings-loop") << " (" << t_yz << ")" << std::endl; Trace("strings-loop") << " ... S(Z.Y)= "; - std::vector<Node>& vecoi = normal_forms[other_n_index]; + const std::vector<Node>& vecoi = normal_forms[other_n_index]; std::vector<Node> vec_s(vecoi.begin() + index + 1, vecoi.end()); Node s_zy = mkConcat(vec_s); Trace("strings-loop") << s_zy << std::endl; @@ -3365,7 +3387,7 @@ bool TheoryStrings::processLoop( std::vector< std::vector< Node > > &normal_form Trace("strings-loop") << "Strings::Loop: tails are different." << std::endl; sendInference(info.d_ant, conc, "Loop Conflict", true); - return false; + return ProcessLoopResult::CONFLICT; } } @@ -3383,7 +3405,7 @@ bool TheoryStrings::processLoop( std::vector< std::vector< Node > > &normal_form // try to make t equal to empty to avoid loop info.d_conc = nm->mkNode(kind::OR, split_eq, split_eq.negate()); info.d_id = INFER_LEN_SPLIT_EMP; - return true; + return ProcessLoopResult::INFERENCE; } else { @@ -3463,6 +3485,15 @@ bool TheoryStrings::processLoop( std::vector< std::vector< Node > > &normal_form } else { + if (options::stringProcessLoopMode() == ProcessLoopMode::SIMPLE_ABORT) + { + throw LogicException("Normal loop breaking not allowed"); + } + else if (options::stringProcessLoopMode() == ProcessLoopMode::SIMPLE) + { + return ProcessLoopResult::SKIPPED; + } + Trace("strings-loop") << "Strings::Loop: Normal Loop Breaking." << std::endl; // right @@ -3504,7 +3535,7 @@ bool TheoryStrings::processLoop( std::vector< std::vector< Node > > &normal_form info.d_id = INFER_FLOOP; info.d_nf_pair[0] = normal_form_src[i]; info.d_nf_pair[1] = normal_form_src[j]; - return true; + return ProcessLoopResult::INFERENCE; } //return true for lemma, false if we succeed diff --git a/src/theory/strings/theory_strings.h b/src/theory/strings/theory_strings.h index aa86f1bc1..70e75db54 100644 --- a/src/theory/strings/theory_strings.h +++ b/src/theory/strings/theory_strings.h @@ -409,6 +409,7 @@ private: LENGTH_ONE, LENGTH_GEQ_ONE }; + /** register length * * This method is called on non-constant string terms n. It sends a lemma @@ -520,8 +521,31 @@ private: void getNormalForms( Node &eqc, std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src, std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend ); bool detectLoop( std::vector< std::vector< Node > > &normal_forms, int i, int j, int index, int &loop_in_i, int &loop_in_j, unsigned rproc ); - bool processLoop( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src, - int i, int j, int loop_n_index, int other_n_index,int loop_index, int index, InferInfo& info ); + + /** + * Result of processLoop() below. + */ + enum class ProcessLoopResult + { + /** Loop processing made an inference */ + INFERENCE, + /** Loop processing detected a conflict */ + CONFLICT, + /** Loop not processed or no loop detected */ + SKIPPED, + }; + + ProcessLoopResult processLoop( + const std::vector<std::vector<Node> >& normal_forms, + const std::vector<Node>& normal_form_src, + int i, + int j, + int loop_n_index, + int other_n_index, + int loop_index, + int index, + InferInfo& info); + void processNEqc( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src, std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend ); void processReverseNEq( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src, diff --git a/test/regress/CMakeLists.txt b/test/regress/CMakeLists.txt index 95e4b8875..e6e28336e 100644 --- a/test/regress/CMakeLists.txt +++ b/test/regress/CMakeLists.txt @@ -1640,6 +1640,7 @@ set(regress_1_tests regress1/sygus/sygus-lambda-fv.sy regress1/sygus/sygus-uf-ex.sy regress1/sygus/t8.sy + regress1/sygus/temp_input_to_synth_ic-error-121418.sy regress1/sygus/tl-type-0.sy regress1/sygus/tl-type-4x.sy regress1/sygus/tl-type.sy @@ -1747,6 +1748,7 @@ set(regress_2_tests regress2/sygus/inv_gen_n_c11.sy regress2/sygus/lustre-real.sy regress2/sygus/max2-univ.sy + regress2/sygus/min_IC_1.sy regress2/sygus/mpg_guard1-dd.sy regress2/sygus/multi-udiv.sy regress2/sygus/nia-max-square.sy diff --git a/test/regress/regress1/sygus/temp_input_to_synth_ic-error-121418.sy b/test/regress/regress1/sygus/temp_input_to_synth_ic-error-121418.sy new file mode 100644 index 000000000..4efd90314 --- /dev/null +++ b/test/regress/regress1/sygus/temp_input_to_synth_ic-error-121418.sy @@ -0,0 +1,26 @@ +; REQUIRES: symfpu +; EXPECT: unsat +; COMMAND-LINE: --sygus-out=status +(set-logic ALL) +(define-sort FP () (_ FloatingPoint 3 5)) +(synth-fun IC ((t FP)) Bool + ((Start Bool ( + true + false + (fp.isZero StartFP) + (ite Start Start Start) + )) + (StartFP FP ( + t + (fp.sub StartRM StartFP StartFP) + (fp.max StartFP StartFP) + )) + (StartRM RoundingMode + (RNE)) +)) + +(constraint (not (IC (fp #b0 #b110 #b1001) ))) +(constraint (not (IC (fp #b1 #b101 #b1101) ))) +(constraint (not (IC (fp #b1 #b001 #b0110) ))) +(constraint (IC (fp #b0 #b001 #b0001) )) +(check-synth) diff --git a/test/regress/regress2/sygus/min_IC_1.sy b/test/regress/regress2/sygus/min_IC_1.sy new file mode 100644 index 000000000..92e171312 --- /dev/null +++ b/test/regress/regress2/sygus/min_IC_1.sy @@ -0,0 +1,25 @@ +; REQUIRES: symfpu +; EXPECT: unsat +; COMMAND-LINE: --sygus-out=status +(set-logic ALL) +(define-sort FP () (_ FloatingPoint 3 5)) +(define-fun IC ((t FP)) Bool (=> (fp.isInfinite t) (fp.isNegative t))) + +(synth-fun simpIC ((t FP)) Bool + ((Start Bool ( + (and Start Start) + (not Start) + + (fp.isInfinite StartFP) + (fp.isNegative StartFP) + + (ite Start Start Start) + )) + (StartFP FP ( + t + )) +)) + +(declare-var x FP) +(constraint (= (simpIC x) (IC x))) +(check-synth) diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 4ba7205a5..4659f2647 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -89,5 +89,6 @@ add_subdirectory(expr) add_subdirectory(main) add_subdirectory(parser) add_subdirectory(prop) +add_subdirectory(proof) add_subdirectory(theory) add_subdirectory(util) diff --git a/test/unit/api/CMakeLists.txt b/test/unit/api/CMakeLists.txt index 8a6be70b9..ca3c59750 100644 --- a/test/unit/api/CMakeLists.txt +++ b/test/unit/api/CMakeLists.txt @@ -1,7 +1,8 @@ #-----------------------------------------------------------------------------# # Add unit tests +cvc4_add_unit_test_black(datatype_api_black api) +cvc4_add_unit_test_black(opterm_black api) cvc4_add_unit_test_black(solver_black api) cvc4_add_unit_test_black(sort_black api) cvc4_add_unit_test_black(term_black api) -cvc4_add_unit_test_black(opterm_black api) diff --git a/test/unit/api/datatype_api_black.h b/test/unit/api/datatype_api_black.h new file mode 100644 index 000000000..bca6a35ce --- /dev/null +++ b/test/unit/api/datatype_api_black.h @@ -0,0 +1,57 @@ +/********************* */ +/*! \file datatype_api_black.h + ** \verbatim + ** Top contributors (to current version): + ** Andres Noetzli + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2019 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 Black box testing of the datatype classes of the C++ API. + ** + ** Black box testing of the datatype classes of the C++ API. + **/ + +#include <cxxtest/TestSuite.h> + +#include "api/cvc4cpp.h" + +using namespace CVC4::api; + +class DatatypeBlack : public CxxTest::TestSuite +{ + public: + void setUp() override; + void tearDown() override; + + void testMkDatatypeSort(); + + private: + Solver d_solver; +}; + +void DatatypeBlack::setUp() {} + +void DatatypeBlack::tearDown() {} + +void DatatypeBlack::testMkDatatypeSort() +{ + DatatypeDecl dtypeSpec("list"); + DatatypeConstructorDecl cons("cons"); + DatatypeSelectorDecl head("head", d_solver.getIntegerSort()); + cons.addSelector(head); + dtypeSpec.addConstructor(cons); + DatatypeConstructorDecl nil("nil"); + dtypeSpec.addConstructor(nil); + Sort listSort = d_solver.mkDatatypeSort(dtypeSpec); + Datatype d = listSort.getDatatype(); + DatatypeConstructor consConstr = d[0]; + DatatypeConstructor nilConstr = d[1]; + TS_ASSERT_THROWS(d[2], CVC4ApiException&); + TS_ASSERT(consConstr.isResolved()); + TS_ASSERT(nilConstr.isResolved()); + TS_ASSERT_THROWS_NOTHING(consConstr.getConstructorTerm()); + TS_ASSERT_THROWS_NOTHING(nilConstr.getConstructorTerm()); +} diff --git a/test/unit/api/solver_black.h b/test/unit/api/solver_black.h index b0249b8a0..d2226f278 100644 --- a/test/unit/api/solver_black.h +++ b/test/unit/api/solver_black.h @@ -1,5 +1,5 @@ /********************* */ -/*! \file api_guards_black.h +/*! \file solver_black.h ** \verbatim ** Top contributors (to current version): ** Aina Niemetz @@ -9,14 +9,15 @@ ** All rights reserved. See the file COPYING in the top-level source ** directory for licensing information.\endverbatim ** - ** \brief Black box testing of the guards of the C++ API functions. + ** \brief Black box testing of the Solver class of the C++ API. ** - ** Black box testing of the guards of the C++ API functions. + ** Black box testing of the Solver class of the C++ API. **/ #include <cxxtest/TestSuite.h> #include "api/cvc4cpp.h" +#include "base/configuration.h" using namespace CVC4::api; @@ -28,320 +29,794 @@ class SolverBlack : public CxxTest::TestSuite void testGetBooleanSort(); void testGetIntegerSort(); + void testGetNullSort(); void testGetRealSort(); void testGetRegExpSort(); - void testGetStringSort(); void testGetRoundingmodeSort(); + void testGetStringSort(); void testMkArraySort(); void testMkBitVectorSort(); void testMkFloatingPointSort(); void testMkDatatypeSort(); void testMkFunctionSort(); + void testMkOpTerm(); void testMkParamSort(); void testMkPredicateSort(); void testMkRecordSort(); void testMkSetSort(); void testMkSortConstructorSort(); - void testMkUninterpretedSort(); void testMkTupleSort(); + void testMkUninterpretedSort(); + + void testMkAbstractValue(); + void testMkBitVector(); + void testMkBoolean(); + void testMkBoundVar(); + void testMkEmptySet(); + void testMkFalse(); + void testMkFloatingPoint(); + void testMkNaN(); + void testMkNegInf(); + void testMkNegZero(); + void testMkPi(); + void testMkPosInf(); + void testMkPosZero(); + void testMkReal(); + void testMkRegexpEmpty(); + void testMkRegexpSigma(); + void testMkRoundingMode(); + void testMkSepNil(); + void testMkString(); + void testMkTerm(); + void testMkTrue(); + void testMkTuple(); + void testMkUninterpretedConst(); + void testMkUniverseSet(); + void testMkVar(); void testDeclareFun(); void testDefineFun(); void testDefineFunRec(); void testDefineFunsRec(); - void testMkRegexpEmpty(); - void testMkRegexpSigma(); + void testSetInfo(); + void testSetLogic(); + void testSetOption(); private: - Solver d_solver; + std::unique_ptr<Solver> d_solver; }; -void SolverBlack::setUp() {} +void SolverBlack::setUp() { d_solver.reset(new Solver()); } void SolverBlack::tearDown() {} void SolverBlack::testGetBooleanSort() { - TS_ASSERT_THROWS_NOTHING(d_solver.getBooleanSort()); + TS_ASSERT_THROWS_NOTHING(d_solver->getBooleanSort()); } void SolverBlack::testGetIntegerSort() { - TS_ASSERT_THROWS_NOTHING(d_solver.getIntegerSort()); + TS_ASSERT_THROWS_NOTHING(d_solver->getIntegerSort()); +} + +void SolverBlack::testGetNullSort() +{ + TS_ASSERT_THROWS_NOTHING(d_solver->getNullSort()); } void SolverBlack::testGetRealSort() { - TS_ASSERT_THROWS_NOTHING(d_solver.getRealSort()); + TS_ASSERT_THROWS_NOTHING(d_solver->getRealSort()); } void SolverBlack::testGetRegExpSort() { - TS_ASSERT_THROWS_NOTHING(d_solver.getRegExpSort()); + TS_ASSERT_THROWS_NOTHING(d_solver->getRegExpSort()); } void SolverBlack::testGetStringSort() { - TS_ASSERT_THROWS_NOTHING(d_solver.getStringSort()); + TS_ASSERT_THROWS_NOTHING(d_solver->getStringSort()); } void SolverBlack::testGetRoundingmodeSort() { - TS_ASSERT_THROWS_NOTHING(d_solver.getRoundingmodeSort()); + TS_ASSERT_THROWS_NOTHING(d_solver->getRoundingmodeSort()); } void SolverBlack::testMkArraySort() { - Sort boolSort = d_solver.getBooleanSort(); - Sort intSort = d_solver.getIntegerSort(); - Sort realSort = d_solver.getRealSort(); - Sort bvSort = d_solver.mkBitVectorSort(32); - Sort fpSort = d_solver.mkFloatingPointSort(3, 5); - TS_ASSERT_THROWS_NOTHING(d_solver.mkArraySort(boolSort, boolSort)); - TS_ASSERT_THROWS_NOTHING(d_solver.mkArraySort(intSort, intSort)); - TS_ASSERT_THROWS_NOTHING(d_solver.mkArraySort(realSort, realSort)); - TS_ASSERT_THROWS_NOTHING(d_solver.mkArraySort(bvSort, bvSort)); - TS_ASSERT_THROWS_NOTHING(d_solver.mkArraySort(fpSort, fpSort)); - TS_ASSERT_THROWS_NOTHING(d_solver.mkArraySort(boolSort, intSort)); - TS_ASSERT_THROWS_NOTHING(d_solver.mkArraySort(realSort, bvSort)); - TS_ASSERT_THROWS_NOTHING(d_solver.mkArraySort(bvSort, fpSort)); + Sort boolSort = d_solver->getBooleanSort(); + Sort intSort = d_solver->getIntegerSort(); + Sort realSort = d_solver->getRealSort(); + Sort bvSort = d_solver->mkBitVectorSort(32); + Sort fpSort = d_solver->mkFloatingPointSort(3, 5); + TS_ASSERT_THROWS_NOTHING(d_solver->mkArraySort(boolSort, boolSort)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkArraySort(intSort, intSort)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkArraySort(realSort, realSort)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkArraySort(bvSort, bvSort)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkArraySort(fpSort, fpSort)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkArraySort(boolSort, intSort)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkArraySort(realSort, bvSort)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkArraySort(bvSort, fpSort)); } void SolverBlack::testMkBitVectorSort() { - TS_ASSERT_THROWS_NOTHING(d_solver.mkBitVectorSort(32)); - TS_ASSERT_THROWS(d_solver.mkBitVectorSort(0), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(d_solver->mkBitVectorSort(32)); + TS_ASSERT_THROWS(d_solver->mkBitVectorSort(0), CVC4ApiException&); } void SolverBlack::testMkFloatingPointSort() { - TS_ASSERT_THROWS_NOTHING(d_solver.mkFloatingPointSort(4, 8)); - TS_ASSERT_THROWS(d_solver.mkFloatingPointSort(0, 8), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.mkFloatingPointSort(4, 0), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(d_solver->mkFloatingPointSort(4, 8)); + TS_ASSERT_THROWS(d_solver->mkFloatingPointSort(0, 8), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkFloatingPointSort(4, 0), CVC4ApiException&); } void SolverBlack::testMkDatatypeSort() { DatatypeDecl dtypeSpec("list"); DatatypeConstructorDecl cons("cons"); - DatatypeSelectorDecl head("head", d_solver.getIntegerSort()); + DatatypeSelectorDecl head("head", d_solver->getIntegerSort()); cons.addSelector(head); dtypeSpec.addConstructor(cons); DatatypeConstructorDecl nil("nil"); dtypeSpec.addConstructor(nil); - TS_ASSERT_THROWS_NOTHING(d_solver.mkDatatypeSort(dtypeSpec)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkDatatypeSort(dtypeSpec)); DatatypeDecl throwsDtypeSpec("list"); - TS_ASSERT_THROWS(d_solver.mkDatatypeSort(throwsDtypeSpec), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkDatatypeSort(throwsDtypeSpec), + CVC4ApiException&); } void SolverBlack::testMkFunctionSort() { - TS_ASSERT_THROWS_NOTHING(d_solver.mkFunctionSort( - d_solver.mkUninterpretedSort("u"), d_solver.getIntegerSort())); - Sort funSort = d_solver.mkFunctionSort(d_solver.mkUninterpretedSort("u"), - d_solver.getIntegerSort()); - TS_ASSERT_THROWS(d_solver.mkFunctionSort(funSort, d_solver.getIntegerSort()), - CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.mkFunctionSort(d_solver.getIntegerSort(), funSort), - CVC4ApiException&); - TS_ASSERT_THROWS_NOTHING(d_solver.mkFunctionSort( - {d_solver.mkUninterpretedSort("u"), d_solver.getIntegerSort()}, - d_solver.getIntegerSort())); - Sort funSort2 = d_solver.mkFunctionSort(d_solver.mkUninterpretedSort("u"), - d_solver.getIntegerSort()); + TS_ASSERT_THROWS_NOTHING(d_solver->mkFunctionSort( + d_solver->mkUninterpretedSort("u"), d_solver->getIntegerSort())); + Sort funSort = d_solver->mkFunctionSort(d_solver->mkUninterpretedSort("u"), + d_solver->getIntegerSort()); TS_ASSERT_THROWS( - d_solver.mkFunctionSort({funSort2, d_solver.mkUninterpretedSort("u")}, - d_solver.getIntegerSort()), + d_solver->mkFunctionSort(funSort, d_solver->getIntegerSort()), + CVC4ApiException&); + TS_ASSERT_THROWS( + d_solver->mkFunctionSort(d_solver->getIntegerSort(), funSort), + CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(d_solver->mkFunctionSort( + {d_solver->mkUninterpretedSort("u"), d_solver->getIntegerSort()}, + d_solver->getIntegerSort())); + Sort funSort2 = d_solver->mkFunctionSort(d_solver->mkUninterpretedSort("u"), + d_solver->getIntegerSort()); + TS_ASSERT_THROWS( + d_solver->mkFunctionSort({funSort2, d_solver->mkUninterpretedSort("u")}, + d_solver->getIntegerSort()), + CVC4ApiException&); + TS_ASSERT_THROWS( + d_solver->mkFunctionSort( + {d_solver->getIntegerSort(), d_solver->mkUninterpretedSort("u")}, + funSort2), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.mkFunctionSort({d_solver.getIntegerSort(), - d_solver.mkUninterpretedSort("u")}, - funSort2), - CVC4ApiException&); } void SolverBlack::testMkParamSort() { - TS_ASSERT_THROWS_NOTHING(d_solver.mkParamSort("T")); - TS_ASSERT_THROWS_NOTHING(d_solver.mkParamSort("")); + TS_ASSERT_THROWS_NOTHING(d_solver->mkParamSort("T")); + TS_ASSERT_THROWS_NOTHING(d_solver->mkParamSort("")); } void SolverBlack::testMkPredicateSort() { TS_ASSERT_THROWS_NOTHING( - d_solver.mkPredicateSort({d_solver.getIntegerSort()})); - TS_ASSERT_THROWS(d_solver.mkPredicateSort({}), CVC4ApiException&); - Sort funSort = d_solver.mkFunctionSort(d_solver.mkUninterpretedSort("u"), - d_solver.getIntegerSort()); + d_solver->mkPredicateSort({d_solver->getIntegerSort()})); + TS_ASSERT_THROWS(d_solver->mkPredicateSort({}), CVC4ApiException&); + Sort funSort = d_solver->mkFunctionSort(d_solver->mkUninterpretedSort("u"), + d_solver->getIntegerSort()); TS_ASSERT_THROWS( - d_solver.mkPredicateSort({d_solver.getIntegerSort(), funSort}), + d_solver->mkPredicateSort({d_solver->getIntegerSort(), funSort}), CVC4ApiException&); } void SolverBlack::testMkRecordSort() { std::vector<std::pair<std::string, Sort>> fields = { - std::make_pair("b", d_solver.getBooleanSort()), - std::make_pair("bv", d_solver.mkBitVectorSort(8)), - std::make_pair("i", d_solver.getIntegerSort())}; + std::make_pair("b", d_solver->getBooleanSort()), + std::make_pair("bv", d_solver->mkBitVectorSort(8)), + std::make_pair("i", d_solver->getIntegerSort())}; std::vector<std::pair<std::string, Sort>> empty; - TS_ASSERT_THROWS_NOTHING(d_solver.mkRecordSort(fields)); - TS_ASSERT_THROWS_NOTHING(d_solver.mkRecordSort(empty)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkRecordSort(fields)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkRecordSort(empty)); } void SolverBlack::testMkSetSort() { - TS_ASSERT_THROWS_NOTHING(d_solver.mkSetSort(d_solver.getBooleanSort())); - TS_ASSERT_THROWS_NOTHING(d_solver.mkSetSort(d_solver.getIntegerSort())); - TS_ASSERT_THROWS_NOTHING(d_solver.mkSetSort(d_solver.mkBitVectorSort(4))); + TS_ASSERT_THROWS_NOTHING(d_solver->mkSetSort(d_solver->getBooleanSort())); + TS_ASSERT_THROWS_NOTHING(d_solver->mkSetSort(d_solver->getIntegerSort())); + TS_ASSERT_THROWS_NOTHING(d_solver->mkSetSort(d_solver->mkBitVectorSort(4))); } void SolverBlack::testMkUninterpretedSort() { - TS_ASSERT_THROWS_NOTHING(d_solver.mkUninterpretedSort("u")); - TS_ASSERT_THROWS_NOTHING(d_solver.mkUninterpretedSort("")); + TS_ASSERT_THROWS_NOTHING(d_solver->mkUninterpretedSort("u")); + TS_ASSERT_THROWS_NOTHING(d_solver->mkUninterpretedSort("")); } void SolverBlack::testMkSortConstructorSort() { - TS_ASSERT_THROWS_NOTHING(d_solver.mkSortConstructorSort("s", 2)); - TS_ASSERT_THROWS_NOTHING(d_solver.mkSortConstructorSort("", 2)); - TS_ASSERT_THROWS(d_solver.mkSortConstructorSort("", 0), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(d_solver->mkSortConstructorSort("s", 2)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkSortConstructorSort("", 2)); + TS_ASSERT_THROWS(d_solver->mkSortConstructorSort("", 0), CVC4ApiException&); } void SolverBlack::testMkTupleSort() { - TS_ASSERT_THROWS_NOTHING(d_solver.mkTupleSort({d_solver.getIntegerSort()})); - Sort funSort = d_solver.mkFunctionSort(d_solver.mkUninterpretedSort("u"), - d_solver.getIntegerSort()); - TS_ASSERT_THROWS(d_solver.mkTupleSort({d_solver.getIntegerSort(), funSort}), + TS_ASSERT_THROWS_NOTHING(d_solver->mkTupleSort({d_solver->getIntegerSort()})); + Sort funSort = d_solver->mkFunctionSort(d_solver->mkUninterpretedSort("u"), + d_solver->getIntegerSort()); + TS_ASSERT_THROWS(d_solver->mkTupleSort({d_solver->getIntegerSort(), funSort}), + CVC4ApiException&); +} + +void SolverBlack::testMkBitVector() +{ + uint32_t size0 = 0, size1 = 8, size2 = 32, val1 = 2; + uint64_t val2 = 2; + TS_ASSERT_THROWS(d_solver->mkBitVector(size0, val1), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkBitVector(size0, val2), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkBitVector("", 2), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkBitVector("10", 3), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkBitVector("20", 2), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(d_solver->mkBitVector(size1, val1)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkBitVector(size2, val2)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkBitVector("1010", 2)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkBitVector("1010", 16)); + TS_ASSERT_THROWS(d_solver->mkBitVector(8, "101010101", 2), CVC4ApiException&); + TS_ASSERT_EQUALS(d_solver->mkBitVector(8, "01010101", 2).toString(), + "0bin01010101"); + TS_ASSERT_EQUALS(d_solver->mkBitVector(8, "F", 16).toString(), + "0bin00001111"); +} + +void SolverBlack::testMkBoundVar() +{ + Sort boolSort = d_solver->getBooleanSort(); + Sort intSort = d_solver->getIntegerSort(); + Sort funSort = d_solver->mkFunctionSort(intSort, boolSort); + TS_ASSERT_THROWS(d_solver->mkBoundVar(Sort()), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(d_solver->mkBoundVar(boolSort)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkBoundVar(funSort)); + TS_ASSERT_THROWS(d_solver->mkBoundVar("a", Sort()), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(d_solver->mkBoundVar(std::string("b"), boolSort)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkBoundVar("", funSort)); +} + +void SolverBlack::testMkBoolean() +{ + TS_ASSERT_THROWS_NOTHING(d_solver->mkBoolean(true)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkBoolean(false)); +} + +void SolverBlack::testMkRoundingMode() +{ + TS_ASSERT_THROWS_NOTHING( + d_solver->mkRoundingMode(RoundingMode::ROUND_TOWARD_ZERO)); +} + +void SolverBlack::testMkUninterpretedConst() +{ + TS_ASSERT_THROWS_NOTHING( + d_solver->mkUninterpretedConst(d_solver->getBooleanSort(), 1)); + TS_ASSERT_THROWS(d_solver->mkUninterpretedConst(Sort(), 1), + CVC4ApiException&); +} + +void SolverBlack::testMkAbstractValue() +{ + TS_ASSERT_THROWS_NOTHING(d_solver->mkAbstractValue(std::string("1"))); + TS_ASSERT_THROWS(d_solver->mkAbstractValue(std::string("0")), + CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkAbstractValue(std::string("-1")), + CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkAbstractValue(std::string("1.2")), + CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkAbstractValue("1/2"), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkAbstractValue("asdf"), CVC4ApiException&); + + TS_ASSERT_THROWS_NOTHING(d_solver->mkAbstractValue((uint32_t)1)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkAbstractValue((int32_t)1)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkAbstractValue((uint64_t)1)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkAbstractValue((int64_t)1)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkAbstractValue((int32_t)-1)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkAbstractValue((int64_t)-1)); + TS_ASSERT_THROWS(d_solver->mkAbstractValue(0), CVC4ApiException&); +} + +void SolverBlack::testMkFloatingPoint() +{ + Term t1 = d_solver->mkBitVector(8); + Term t2 = d_solver->mkBitVector(4); + Term t3 = d_solver->mkReal(2); + if (CVC4::Configuration::isBuiltWithSymFPU()) + { + TS_ASSERT_THROWS_NOTHING(d_solver->mkFloatingPoint(3, 5, t1)); + } + else + { + TS_ASSERT_THROWS(d_solver->mkFloatingPoint(3, 5, t1), CVC4ApiException&); + } + TS_ASSERT_THROWS(d_solver->mkFloatingPoint(0, 5, Term()), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkFloatingPoint(0, 5, t1), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkFloatingPoint(3, 0, t1), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkFloatingPoint(3, 5, t2), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkFloatingPoint(3, 5, t2), CVC4ApiException&); +} + +void SolverBlack::testMkEmptySet() +{ + TS_ASSERT_THROWS(d_solver->mkEmptySet(d_solver->getBooleanSort()), + CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(d_solver->mkEmptySet(Sort())); +} + +void SolverBlack::testMkFalse() +{ + TS_ASSERT_THROWS_NOTHING(d_solver->mkFalse()); + TS_ASSERT_THROWS_NOTHING(d_solver->mkFalse()); +} + +void SolverBlack::testMkNaN() +{ + if (CVC4::Configuration::isBuiltWithSymFPU()) + { + TS_ASSERT_THROWS_NOTHING(d_solver->mkNaN(3, 5)); + } + else + { + TS_ASSERT_THROWS(d_solver->mkNaN(3, 5), CVC4ApiException&); + } +} + +void SolverBlack::testMkNegZero() +{ + if (CVC4::Configuration::isBuiltWithSymFPU()) + { + TS_ASSERT_THROWS_NOTHING(d_solver->mkNegZero(3, 5)); + } + else + { + TS_ASSERT_THROWS(d_solver->mkNegZero(3, 5), CVC4ApiException&); + } +} + +void SolverBlack::testMkNegInf() +{ + if (CVC4::Configuration::isBuiltWithSymFPU()) + { + TS_ASSERT_THROWS_NOTHING(d_solver->mkNegInf(3, 5)); + } + else + { + TS_ASSERT_THROWS(d_solver->mkNegInf(3, 5), CVC4ApiException&); + } +} + +void SolverBlack::testMkPosInf() +{ + if (CVC4::Configuration::isBuiltWithSymFPU()) + { + TS_ASSERT_THROWS_NOTHING(d_solver->mkPosInf(3, 5)); + } + else + { + TS_ASSERT_THROWS(d_solver->mkPosInf(3, 5), CVC4ApiException&); + } +} + +void SolverBlack::testMkPosZero() +{ + if (CVC4::Configuration::isBuiltWithSymFPU()) + { + TS_ASSERT_THROWS_NOTHING(d_solver->mkPosZero(3, 5)); + } + else + { + TS_ASSERT_THROWS(d_solver->mkPosZero(3, 5), CVC4ApiException&); + } +} + +void SolverBlack::testMkOpTerm() +{ + // mkOpTerm(Kind kind, Kind k) + TS_ASSERT_THROWS_NOTHING(d_solver->mkOpTerm(CHAIN_OP, EQUAL)); + TS_ASSERT_THROWS(d_solver->mkOpTerm(BITVECTOR_EXTRACT_OP, EQUAL), + CVC4ApiException&); + + // mkOpTerm(Kind kind, const std::string& arg) + TS_ASSERT_THROWS_NOTHING(d_solver->mkOpTerm(RECORD_UPDATE_OP, "asdf")); + TS_ASSERT_THROWS(d_solver->mkOpTerm(BITVECTOR_EXTRACT_OP, "asdf"), + CVC4ApiException&); + + // mkOpTerm(Kind kind, uint32_t arg) + TS_ASSERT_THROWS_NOTHING(d_solver->mkOpTerm(DIVISIBLE_OP, 1)); + TS_ASSERT_THROWS(d_solver->mkOpTerm(BITVECTOR_EXTRACT_OP, 1), + CVC4ApiException&); + + // mkOpTerm(Kind kind, uint32_t arg1, uint32_t arg2) + TS_ASSERT_THROWS_NOTHING(d_solver->mkOpTerm(BITVECTOR_EXTRACT_OP, 1, 1)); + TS_ASSERT_THROWS(d_solver->mkOpTerm(DIVISIBLE_OP, 1, 2), CVC4ApiException&); +} + +void SolverBlack::testMkPi() { TS_ASSERT_THROWS_NOTHING(d_solver->mkPi()); } + +void SolverBlack::testMkReal() +{ + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal("123")); + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal("1.23")); + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal("1/23")); + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal("12/3")); + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal(".2")); + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal("2.")); + TS_ASSERT_THROWS(d_solver->mkReal(nullptr), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkReal(""), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkReal("asdf"), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkReal("1.2/3"), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkReal("."), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkReal("/"), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkReal("2/"), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkReal("/2"), CVC4ApiException&); + + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal(std::string("123"))); + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal(std::string("1.23"))); + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal(std::string("1/23"))); + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal(std::string("12/3"))); + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal(std::string(".2"))); + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal(std::string("2."))); + TS_ASSERT_THROWS(d_solver->mkReal(std::string("")), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkReal(std::string("asdf")), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkReal(std::string("1.2/3")), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkReal(std::string(".")), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkReal(std::string("/")), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkReal(std::string("2/")), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkReal(std::string("/2")), CVC4ApiException&); + + int32_t val1 = 1; + int64_t val2 = -1; + uint32_t val3 = 1; + uint64_t val4 = -1; + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal(val1)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal(val2)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal(val3)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal(val4)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal(val4)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal(val1, val1)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal(val2, val2)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal(val3, val3)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkReal(val4, val4)); +} + +void SolverBlack::testMkRegexpEmpty() +{ + Sort strSort = d_solver->getStringSort(); + Term s = d_solver->mkVar("s", strSort); + TS_ASSERT_THROWS_NOTHING( + d_solver->mkTerm(STRING_IN_REGEXP, s, d_solver->mkRegexpEmpty())); +} + +void SolverBlack::testMkRegexpSigma() +{ + Sort strSort = d_solver->getStringSort(); + Term s = d_solver->mkVar("s", strSort); + TS_ASSERT_THROWS_NOTHING( + d_solver->mkTerm(STRING_IN_REGEXP, s, d_solver->mkRegexpSigma())); +} + +void SolverBlack::testMkSepNil() +{ + TS_ASSERT_THROWS_NOTHING(d_solver->mkSepNil(d_solver->getBooleanSort())); + TS_ASSERT_THROWS(d_solver->mkSepNil(Sort()), CVC4ApiException&); +} + +void SolverBlack::testMkString() +{ + TS_ASSERT_THROWS_NOTHING(d_solver->mkString("")); + TS_ASSERT_THROWS_NOTHING(d_solver->mkString("asdfasdf")); + TS_ASSERT_EQUALS(d_solver->mkString("asdf\\nasdf").toString(), + "\"asdf\\\\nasdf\""); + TS_ASSERT_EQUALS(d_solver->mkString("asdf\\nasdf", true).toString(), + "\"asdf\\nasdf\""); +} + +void SolverBlack::testMkTerm() +{ + Sort bv32 = d_solver->mkBitVectorSort(32); + Term a = d_solver->mkVar("a", bv32); + Term b = d_solver->mkVar("b", bv32); + std::vector<Term> v1 = {a, b}; + std::vector<Term> v2 = {a, Term()}; + std::vector<Term> v3 = {a, d_solver->mkTrue()}; + std::vector<Term> v4 = {d_solver->mkReal(1), d_solver->mkReal(2)}; + std::vector<Term> v5 = {d_solver->mkReal(1), Term()}; + OpTerm opterm1 = d_solver->mkOpTerm(BITVECTOR_EXTRACT_OP, 2, 1); + OpTerm opterm2 = d_solver->mkOpTerm(DIVISIBLE_OP, 1); + OpTerm opterm3 = d_solver->mkOpTerm(CHAIN_OP, EQUAL); + + // mkTerm(Kind kind) const + TS_ASSERT_THROWS_NOTHING(d_solver->mkTerm(PI)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkTerm(REGEXP_EMPTY)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkTerm(REGEXP_SIGMA)); + TS_ASSERT_THROWS(d_solver->mkTerm(CONST_BITVECTOR), CVC4ApiException&); + + // mkTerm(Kind kind, Sort sort) const + TS_ASSERT_THROWS_NOTHING( + d_solver->mkTerm(SEP_NIL, d_solver->getBooleanSort())); + TS_ASSERT_THROWS_NOTHING(d_solver->mkTerm(SEP_NIL, Sort())); + + // mkTerm(Kind kind, Term child) const + TS_ASSERT_THROWS_NOTHING(d_solver->mkTerm(NOT, d_solver->mkTrue())); + TS_ASSERT_THROWS(d_solver->mkTerm(NOT, Term()), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkTerm(NOT, a), CVC4ApiException&); + + // mkTerm(Kind kind, Term child1, Term child2) const + TS_ASSERT_THROWS_NOTHING(d_solver->mkTerm(EQUAL, a, b)); + TS_ASSERT_THROWS(d_solver->mkTerm(EQUAL, Term(), b), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkTerm(EQUAL, a, Term()), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkTerm(EQUAL, a, d_solver->mkTrue()), + CVC4ApiException&); + + // mkTerm(Kind kind, Term child1, Term child2, Term child3) const + TS_ASSERT_THROWS_NOTHING(d_solver->mkTerm( + ITE, d_solver->mkTrue(), d_solver->mkTrue(), d_solver->mkTrue())); + TS_ASSERT_THROWS( + d_solver->mkTerm(ITE, Term(), d_solver->mkTrue(), d_solver->mkTrue()), + CVC4ApiException&); + TS_ASSERT_THROWS( + d_solver->mkTerm(ITE, d_solver->mkTrue(), Term(), d_solver->mkTrue()), + CVC4ApiException&); + TS_ASSERT_THROWS( + d_solver->mkTerm(ITE, d_solver->mkTrue(), d_solver->mkTrue(), Term()), + CVC4ApiException&); + TS_ASSERT_THROWS( + d_solver->mkTerm(ITE, d_solver->mkTrue(), d_solver->mkTrue(), b), + CVC4ApiException&); + + // mkTerm(Kind kind, const std::vector<Term>& children) const + TS_ASSERT_THROWS_NOTHING(d_solver->mkTerm(EQUAL, v1)); + TS_ASSERT_THROWS(d_solver->mkTerm(EQUAL, v2), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkTerm(EQUAL, v3), CVC4ApiException&); + + // mkTerm(OpTerm opTerm, Term child) const + TS_ASSERT_THROWS_NOTHING(d_solver->mkTerm(opterm1, a)); + TS_ASSERT_THROWS(d_solver->mkTerm(opterm2, a), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkTerm(opterm1, Term()), CVC4ApiException&); + + // mkTerm(OpTerm opTerm, Term child1, Term child2) const + TS_ASSERT_THROWS_NOTHING( + d_solver->mkTerm(opterm3, d_solver->mkReal(1), d_solver->mkReal(2))); + TS_ASSERT_THROWS(d_solver->mkTerm(opterm1, a, b), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkTerm(opterm3, d_solver->mkReal(1), Term()), + CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkTerm(opterm3, Term(), d_solver->mkReal(1)), + CVC4ApiException&); + + // mkTerm(OpTerm opTerm, Term child1, Term child2, Term child3) const + TS_ASSERT_THROWS_NOTHING(d_solver->mkTerm( + opterm3, d_solver->mkReal(1), d_solver->mkReal(1), d_solver->mkReal(2))); + TS_ASSERT_THROWS(d_solver->mkTerm(opterm1, a, b, a), CVC4ApiException&); + TS_ASSERT_THROWS( + d_solver->mkTerm( + opterm3, d_solver->mkReal(1), d_solver->mkReal(1), Term()), + CVC4ApiException&); + + // mkTerm(OpTerm opTerm, const std::vector<Term>& children) const + TS_ASSERT_THROWS_NOTHING(d_solver->mkTerm(opterm3, v4)); + TS_ASSERT_THROWS(d_solver->mkTerm(opterm3, v5), CVC4ApiException&); +} + +void SolverBlack::testMkTrue() +{ + TS_ASSERT_THROWS_NOTHING(d_solver->mkTrue()); + TS_ASSERT_THROWS_NOTHING(d_solver->mkTrue()); +} + +void SolverBlack::testMkTuple() +{ + TS_ASSERT_THROWS_NOTHING(d_solver->mkTuple( + {d_solver->mkBitVectorSort(3)}, {d_solver->mkBitVector("101", 2)})); + TS_ASSERT_THROWS_NOTHING( + d_solver->mkTuple({d_solver->getRealSort()}, {d_solver->mkReal("5")})); + + TS_ASSERT_THROWS(d_solver->mkTuple({}, {d_solver->mkBitVector("101", 2)}), + CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkTuple({d_solver->mkBitVectorSort(4)}, + {d_solver->mkBitVector("101", 2)}), + CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->mkTuple({d_solver->getIntegerSort()}, + {d_solver->mkReal("5.3")}), CVC4ApiException&); } +void SolverBlack::testMkUniverseSet() +{ + TS_ASSERT_THROWS(d_solver->mkUniverseSet(Sort()), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(d_solver->mkUniverseSet(d_solver->getBooleanSort())); +} + +void SolverBlack::testMkVar() +{ + Sort boolSort = d_solver->getBooleanSort(); + Sort intSort = d_solver->getIntegerSort(); + Sort funSort = d_solver->mkFunctionSort(intSort, boolSort); + TS_ASSERT_THROWS(d_solver->mkVar(Sort()), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(d_solver->mkVar(boolSort)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkVar(funSort)); + TS_ASSERT_THROWS(d_solver->mkVar("a", Sort()), CVC4ApiException&); + TS_ASSERT_THROWS_NOTHING(d_solver->mkVar(std::string("b"), boolSort)); + TS_ASSERT_THROWS_NOTHING(d_solver->mkVar("", funSort)); +} + void SolverBlack::testDeclareFun() { - Sort bvSort = d_solver.mkBitVectorSort(32); - Sort funSort = d_solver.mkFunctionSort(d_solver.mkUninterpretedSort("u"), - d_solver.getIntegerSort()); - TS_ASSERT_THROWS_NOTHING(d_solver.declareFun("f1", bvSort)); - TS_ASSERT_THROWS_NOTHING(d_solver.declareFun("f2", funSort)); + Sort bvSort = d_solver->mkBitVectorSort(32); + Sort funSort = d_solver->mkFunctionSort(d_solver->mkUninterpretedSort("u"), + d_solver->getIntegerSort()); + TS_ASSERT_THROWS_NOTHING(d_solver->declareFun("f1", bvSort)); + TS_ASSERT_THROWS_NOTHING(d_solver->declareFun("f2", funSort)); TS_ASSERT_THROWS_NOTHING( - d_solver.declareFun("f3", {bvSort, d_solver.getIntegerSort()}, bvSort)); - TS_ASSERT_THROWS(d_solver.declareFun("f4", {bvSort, funSort}, bvSort), + d_solver->declareFun("f3", {bvSort, d_solver->getIntegerSort()}, bvSort)); + TS_ASSERT_THROWS(d_solver->declareFun("f4", {bvSort, funSort}, bvSort), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.declareFun("f5", {bvSort, bvSort}, funSort), + TS_ASSERT_THROWS(d_solver->declareFun("f5", {bvSort, bvSort}, funSort), CVC4ApiException&); } void SolverBlack::testDefineFun() { - Sort bvSort = d_solver.mkBitVectorSort(32); - Sort funSort1 = d_solver.mkFunctionSort({bvSort, bvSort}, bvSort); - Sort funSort2 = d_solver.mkFunctionSort(d_solver.mkUninterpretedSort("u"), - d_solver.getIntegerSort()); - Term b1 = d_solver.mkBoundVar("b1", bvSort); - Term b11 = d_solver.mkBoundVar("b1", bvSort); - Term b2 = d_solver.mkBoundVar("b2", d_solver.getIntegerSort()); - Term b3 = d_solver.mkBoundVar("b3", funSort2); - Term v1 = d_solver.mkBoundVar("v1", bvSort); - Term v2 = d_solver.mkBoundVar("v2", d_solver.getIntegerSort()); - Term v3 = d_solver.mkVar("v3", funSort2); - Term f1 = d_solver.declareFun("f1", funSort1); - Term f2 = d_solver.declareFun("f2", funSort2); - Term f3 = d_solver.declareFun("f3", bvSort); - TS_ASSERT_THROWS_NOTHING(d_solver.defineFun("f", {}, bvSort, v1)); - TS_ASSERT_THROWS_NOTHING(d_solver.defineFun("ff", {b1, b2}, bvSort, v1)); - TS_ASSERT_THROWS_NOTHING(d_solver.defineFun(f1, {b1, b11}, v1)); - TS_ASSERT_THROWS(d_solver.defineFun("fff", {b1}, bvSort, v3), + Sort bvSort = d_solver->mkBitVectorSort(32); + Sort funSort1 = d_solver->mkFunctionSort({bvSort, bvSort}, bvSort); + Sort funSort2 = d_solver->mkFunctionSort(d_solver->mkUninterpretedSort("u"), + d_solver->getIntegerSort()); + Term b1 = d_solver->mkBoundVar("b1", bvSort); + Term b11 = d_solver->mkBoundVar("b1", bvSort); + Term b2 = d_solver->mkBoundVar("b2", d_solver->getIntegerSort()); + Term b3 = d_solver->mkBoundVar("b3", funSort2); + Term v1 = d_solver->mkBoundVar("v1", bvSort); + Term v2 = d_solver->mkBoundVar("v2", d_solver->getIntegerSort()); + Term v3 = d_solver->mkVar("v3", funSort2); + Term f1 = d_solver->declareFun("f1", funSort1); + Term f2 = d_solver->declareFun("f2", funSort2); + Term f3 = d_solver->declareFun("f3", bvSort); + TS_ASSERT_THROWS_NOTHING(d_solver->defineFun("f", {}, bvSort, v1)); + TS_ASSERT_THROWS_NOTHING(d_solver->defineFun("ff", {b1, b2}, bvSort, v1)); + TS_ASSERT_THROWS_NOTHING(d_solver->defineFun(f1, {b1, b11}, v1)); + TS_ASSERT_THROWS(d_solver->defineFun("fff", {b1}, bvSort, v3), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.defineFun("ffff", {b1}, funSort2, v3), + TS_ASSERT_THROWS(d_solver->defineFun("ffff", {b1}, funSort2, v3), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.defineFun("fffff", {b1, b3}, bvSort, v1), + TS_ASSERT_THROWS(d_solver->defineFun("fffff", {b1, b3}, bvSort, v1), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.defineFun(f1, {b1}, v1), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.defineFun(f1, {b1, b11}, v2), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.defineFun(f1, {b1, b11}, v3), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.defineFun(f2, {b1}, v2), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.defineFun(f3, {b1}, v1), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->defineFun(f1, {b1}, v1), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->defineFun(f1, {b1, b11}, v2), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->defineFun(f1, {b1, b11}, v3), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->defineFun(f2, {b1}, v2), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->defineFun(f3, {b1}, v1), CVC4ApiException&); } void SolverBlack::testDefineFunRec() { - Sort bvSort = d_solver.mkBitVectorSort(32); - Sort funSort1 = d_solver.mkFunctionSort({bvSort, bvSort}, bvSort); - Sort funSort2 = d_solver.mkFunctionSort(d_solver.mkUninterpretedSort("u"), - d_solver.getIntegerSort()); - Term b1 = d_solver.mkBoundVar("b1", bvSort); - Term b11 = d_solver.mkBoundVar("b1", bvSort); - Term b2 = d_solver.mkBoundVar("b2", d_solver.getIntegerSort()); - Term b3 = d_solver.mkBoundVar("b3", funSort2); - Term v1 = d_solver.mkBoundVar("v1", bvSort); - Term v2 = d_solver.mkBoundVar("v2", d_solver.getIntegerSort()); - Term v3 = d_solver.mkVar("v3", funSort2); - Term f1 = d_solver.declareFun("f1", funSort1); - Term f2 = d_solver.declareFun("f2", funSort2); - Term f3 = d_solver.declareFun("f3", bvSort); - TS_ASSERT_THROWS_NOTHING(d_solver.defineFunRec("f", {}, bvSort, v1)); - TS_ASSERT_THROWS_NOTHING(d_solver.defineFunRec("ff", {b1, b2}, bvSort, v1)); - TS_ASSERT_THROWS_NOTHING(d_solver.defineFunRec(f1, {b1, b11}, v1)); - TS_ASSERT_THROWS(d_solver.defineFunRec("fff", {b1}, bvSort, v3), + Sort bvSort = d_solver->mkBitVectorSort(32); + Sort funSort1 = d_solver->mkFunctionSort({bvSort, bvSort}, bvSort); + Sort funSort2 = d_solver->mkFunctionSort(d_solver->mkUninterpretedSort("u"), + d_solver->getIntegerSort()); + Term b1 = d_solver->mkBoundVar("b1", bvSort); + Term b11 = d_solver->mkBoundVar("b1", bvSort); + Term b2 = d_solver->mkBoundVar("b2", d_solver->getIntegerSort()); + Term b3 = d_solver->mkBoundVar("b3", funSort2); + Term v1 = d_solver->mkBoundVar("v1", bvSort); + Term v2 = d_solver->mkBoundVar("v2", d_solver->getIntegerSort()); + Term v3 = d_solver->mkVar("v3", funSort2); + Term f1 = d_solver->declareFun("f1", funSort1); + Term f2 = d_solver->declareFun("f2", funSort2); + Term f3 = d_solver->declareFun("f3", bvSort); + TS_ASSERT_THROWS_NOTHING(d_solver->defineFunRec("f", {}, bvSort, v1)); + TS_ASSERT_THROWS_NOTHING(d_solver->defineFunRec("ff", {b1, b2}, bvSort, v1)); + TS_ASSERT_THROWS_NOTHING(d_solver->defineFunRec(f1, {b1, b11}, v1)); + TS_ASSERT_THROWS(d_solver->defineFunRec("fff", {b1}, bvSort, v3), + CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->defineFunRec("ffff", {b1}, funSort2, v3), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.defineFunRec("ffff", {b1}, funSort2, v3), + TS_ASSERT_THROWS(d_solver->defineFunRec("fffff", {b1, b3}, bvSort, v1), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.defineFunRec("fffff", {b1, b3}, bvSort, v1), + TS_ASSERT_THROWS(d_solver->defineFunRec(f1, {b1}, v1), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->defineFunRec(f1, {b1, b11}, v2), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.defineFunRec(f1, {b1}, v1), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.defineFunRec(f1, {b1, b11}, v2), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.defineFunRec(f1, {b1, b11}, v3), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.defineFunRec(f2, {b1}, v2), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.defineFunRec(f3, {b1}, v1), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->defineFunRec(f1, {b1, b11}, v3), + CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->defineFunRec(f2, {b1}, v2), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->defineFunRec(f3, {b1}, v1), CVC4ApiException&); } void SolverBlack::testDefineFunsRec() { - Sort uSort = d_solver.mkUninterpretedSort("u"); - Sort bvSort = d_solver.mkBitVectorSort(32); - Sort funSort1 = d_solver.mkFunctionSort({bvSort, bvSort}, bvSort); - Sort funSort2 = d_solver.mkFunctionSort(uSort, d_solver.getIntegerSort()); - Term b1 = d_solver.mkBoundVar("b1", bvSort); - Term b11 = d_solver.mkBoundVar("b1", bvSort); - Term b2 = d_solver.mkBoundVar("b2", d_solver.getIntegerSort()); - Term b3 = d_solver.mkBoundVar("b3", funSort2); - Term b4 = d_solver.mkBoundVar("b4", uSort); - Term v1 = d_solver.mkBoundVar("v1", bvSort); - Term v2 = d_solver.mkBoundVar("v2", d_solver.getIntegerSort()); - Term v3 = d_solver.mkVar("v3", funSort2); - Term v4 = d_solver.mkVar("v4", uSort); - Term f1 = d_solver.declareFun("f1", funSort1); - Term f2 = d_solver.declareFun("f2", funSort2); - Term f3 = d_solver.declareFun("f3", bvSort); + Sort uSort = d_solver->mkUninterpretedSort("u"); + Sort bvSort = d_solver->mkBitVectorSort(32); + Sort funSort1 = d_solver->mkFunctionSort({bvSort, bvSort}, bvSort); + Sort funSort2 = d_solver->mkFunctionSort(uSort, d_solver->getIntegerSort()); + Term b1 = d_solver->mkBoundVar("b1", bvSort); + Term b11 = d_solver->mkBoundVar("b1", bvSort); + Term b2 = d_solver->mkBoundVar("b2", d_solver->getIntegerSort()); + Term b3 = d_solver->mkBoundVar("b3", funSort2); + Term b4 = d_solver->mkBoundVar("b4", uSort); + Term v1 = d_solver->mkBoundVar("v1", bvSort); + Term v2 = d_solver->mkBoundVar("v2", d_solver->getIntegerSort()); + Term v3 = d_solver->mkVar("v3", funSort2); + Term v4 = d_solver->mkVar("v4", uSort); + Term f1 = d_solver->declareFun("f1", funSort1); + Term f2 = d_solver->declareFun("f2", funSort2); + Term f3 = d_solver->declareFun("f3", bvSort); TS_ASSERT_THROWS_NOTHING( - d_solver.defineFunsRec({f1, f2}, {{b1, b11}, {b4}}, {v1, v2})); + d_solver->defineFunsRec({f1, f2}, {{b1, b11}, {b4}}, {v1, v2})); TS_ASSERT_THROWS( - d_solver.defineFunsRec({f1, f3}, {{b1, b11}, {b4}}, {v1, v2}), + d_solver->defineFunsRec({f1, f3}, {{b1, b11}, {b4}}, {v1, v2}), CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.defineFunsRec({f1, f2}, {{b1}, {b4}}, {v1, v2}), - CVC4ApiException&); - TS_ASSERT_THROWS(d_solver.defineFunsRec({f1, f2}, {{b1, b2}, {b4}}, {v1, v2}), + TS_ASSERT_THROWS(d_solver->defineFunsRec({f1, f2}, {{b1}, {b4}}, {v1, v2}), CVC4ApiException&); TS_ASSERT_THROWS( - d_solver.defineFunsRec({f1, f2}, {{b1, b11}, {b4}}, {v1, v4}), + d_solver->defineFunsRec({f1, f2}, {{b1, b2}, {b4}}, {v1, v2}), + CVC4ApiException&); + TS_ASSERT_THROWS( + d_solver->defineFunsRec({f1, f2}, {{b1, b11}, {b4}}, {v1, v4}), CVC4ApiException&); } -void SolverBlack::testMkRegexpEmpty() +void SolverBlack::testSetInfo() { - Sort strSort = d_solver.getStringSort(); - Term s = d_solver.mkVar("s", strSort); - TS_ASSERT_THROWS_NOTHING( - d_solver.mkTerm(STRING_IN_REGEXP, s, d_solver.mkRegexpEmpty())); + TS_ASSERT_THROWS_NOTHING(d_solver->setInfo("cvc4-logic", "QF_BV")); + TS_ASSERT_THROWS_NOTHING(d_solver->setInfo("cvc4_logic", "QF_BV")); + TS_ASSERT_THROWS(d_solver->setInfo("cvc4-lagic", "QF_BV"), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->setInfo("cvc2-logic", "QF_BV"), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->setInfo("cvc4-logic", "asdf"), CVC4ApiException&); + + TS_ASSERT_THROWS_NOTHING(d_solver->setInfo("source", "asdf")); + TS_ASSERT_THROWS_NOTHING(d_solver->setInfo("category", "asdf")); + TS_ASSERT_THROWS_NOTHING(d_solver->setInfo("difficulty", "asdf")); + TS_ASSERT_THROWS_NOTHING(d_solver->setInfo("filename", "asdf")); + TS_ASSERT_THROWS_NOTHING(d_solver->setInfo("license", "asdf")); + TS_ASSERT_THROWS_NOTHING(d_solver->setInfo("name", "asdf")); + TS_ASSERT_THROWS_NOTHING(d_solver->setInfo("notes", "asdf")); + + TS_ASSERT_THROWS_NOTHING(d_solver->setInfo("smt-lib-version", "2")); + TS_ASSERT_THROWS_NOTHING(d_solver->setInfo("smt-lib-version", "2.0")); + TS_ASSERT_THROWS_NOTHING(d_solver->setInfo("smt-lib-version", "2.5")); + TS_ASSERT_THROWS_NOTHING(d_solver->setInfo("smt-lib-version", "2.6")); + TS_ASSERT_THROWS_NOTHING(d_solver->setInfo("smt-lib-version", "2.6.1")); + TS_ASSERT_THROWS(d_solver->setInfo("smt-lib-version", ".0"), + CVC4ApiException&); + + TS_ASSERT_THROWS_NOTHING(d_solver->setInfo("status", "sat")); + TS_ASSERT_THROWS_NOTHING(d_solver->setInfo("status", "unsat")); + TS_ASSERT_THROWS_NOTHING(d_solver->setInfo("status", "unknown")); + TS_ASSERT_THROWS(d_solver->setInfo("status", "asdf"), CVC4ApiException&); + + d_solver->assertFormula(d_solver->mkTrue()); + TS_ASSERT_THROWS(d_solver->setInfo("cvc4-logic", "QF_BV"), CVC4ApiException&); + TS_ASSERT_THROWS(d_solver->setInfo("cvc4_logic", "QF_BV"), CVC4ApiException&); } -void SolverBlack::testMkRegexpSigma() +void SolverBlack::testSetLogic() { - Sort strSort = d_solver.getStringSort(); - Term s = d_solver.mkVar("s", strSort); - TS_ASSERT_THROWS_NOTHING( - d_solver.mkTerm(STRING_IN_REGEXP, s, d_solver.mkRegexpSigma())); + TS_ASSERT_THROWS_NOTHING(d_solver->setLogic("AUFLIRA")); + TS_ASSERT_THROWS(d_solver->setLogic("AF_BV"), CVC4ApiException&); + d_solver->assertFormula(d_solver->mkTrue()); + TS_ASSERT_THROWS(d_solver->setLogic("AUFLIRA"), CVC4ApiException&); +} + +void SolverBlack::testSetOption() +{ + TS_ASSERT_THROWS_NOTHING(d_solver->setOption("bv-sat-solver", "minisat")); + TS_ASSERT_THROWS(d_solver->setOption("bv-sat-solver", "1"), + CVC4ApiException&); + d_solver->assertFormula(d_solver->mkTrue()); + TS_ASSERT_THROWS(d_solver->setOption("bv-sat-solver", "minisat"), + CVC4ApiException&); } diff --git a/test/unit/api/term_black.h b/test/unit/api/term_black.h index ae1dfe7ba..a7f735651 100644 --- a/test/unit/api/term_black.h +++ b/test/unit/api/term_black.h @@ -77,7 +77,7 @@ void TermBlack::testGetKind() Term p = d_solver.mkVar("p", funSort2); TS_ASSERT_THROWS_NOTHING(p.getKind()); - Term zero = d_solver.mkInteger(0); + Term zero = d_solver.mkReal(0); TS_ASSERT_THROWS_NOTHING(zero.getKind()); Term f_x = d_solver.mkTerm(APPLY_UF, f, x); @@ -116,7 +116,7 @@ void TermBlack::testGetSort() TS_ASSERT_THROWS_NOTHING(p.getSort()); TS_ASSERT(p.getSort() == funSort2); - Term zero = d_solver.mkInteger(0); + Term zero = d_solver.mkReal(0); TS_ASSERT_THROWS_NOTHING(zero.getSort()); TS_ASSERT(zero.getSort() == intSort); @@ -161,7 +161,7 @@ void TermBlack::testNotTerm() TS_ASSERT_THROWS(f.notTerm(), CVC4ApiException&); Term p = d_solver.mkVar("p", funSort2); TS_ASSERT_THROWS(p.notTerm(), CVC4ApiException&); - Term zero = d_solver.mkInteger(0); + Term zero = d_solver.mkReal(0); TS_ASSERT_THROWS(zero.notTerm(), CVC4ApiException&); Term f_x = d_solver.mkTerm(APPLY_UF, f, x); TS_ASSERT_THROWS(f_x.notTerm(), CVC4ApiException&); @@ -195,7 +195,7 @@ void TermBlack::testAndTerm() TS_ASSERT_THROWS(p.andTerm(x), CVC4ApiException&); TS_ASSERT_THROWS(p.andTerm(f), CVC4ApiException&); TS_ASSERT_THROWS(p.andTerm(p), CVC4ApiException&); - Term zero = d_solver.mkInteger(0); + Term zero = d_solver.mkReal(0); TS_ASSERT_THROWS(zero.andTerm(b), CVC4ApiException&); TS_ASSERT_THROWS(zero.andTerm(x), CVC4ApiException&); TS_ASSERT_THROWS(zero.andTerm(f), CVC4ApiException&); @@ -259,7 +259,7 @@ void TermBlack::testOrTerm() TS_ASSERT_THROWS(p.orTerm(x), CVC4ApiException&); TS_ASSERT_THROWS(p.orTerm(f), CVC4ApiException&); TS_ASSERT_THROWS(p.orTerm(p), CVC4ApiException&); - Term zero = d_solver.mkInteger(0); + Term zero = d_solver.mkReal(0); TS_ASSERT_THROWS(zero.orTerm(b), CVC4ApiException&); TS_ASSERT_THROWS(zero.orTerm(x), CVC4ApiException&); TS_ASSERT_THROWS(zero.orTerm(f), CVC4ApiException&); @@ -323,7 +323,7 @@ void TermBlack::testXorTerm() TS_ASSERT_THROWS(p.xorTerm(x), CVC4ApiException&); TS_ASSERT_THROWS(p.xorTerm(f), CVC4ApiException&); TS_ASSERT_THROWS(p.xorTerm(p), CVC4ApiException&); - Term zero = d_solver.mkInteger(0); + Term zero = d_solver.mkReal(0); TS_ASSERT_THROWS(zero.xorTerm(b), CVC4ApiException&); TS_ASSERT_THROWS(zero.xorTerm(x), CVC4ApiException&); TS_ASSERT_THROWS(zero.xorTerm(f), CVC4ApiException&); @@ -387,7 +387,7 @@ void TermBlack::testEqTerm() TS_ASSERT_THROWS(p.eqTerm(x), CVC4ApiException&); TS_ASSERT_THROWS(p.eqTerm(f), CVC4ApiException&); TS_ASSERT_THROWS_NOTHING(p.eqTerm(p)); - Term zero = d_solver.mkInteger(0); + Term zero = d_solver.mkReal(0); TS_ASSERT_THROWS(zero.eqTerm(b), CVC4ApiException&); TS_ASSERT_THROWS(zero.eqTerm(x), CVC4ApiException&); TS_ASSERT_THROWS(zero.eqTerm(f), CVC4ApiException&); @@ -451,7 +451,7 @@ void TermBlack::testImpTerm() TS_ASSERT_THROWS(p.impTerm(x), CVC4ApiException&); TS_ASSERT_THROWS(p.impTerm(f), CVC4ApiException&); TS_ASSERT_THROWS(p.impTerm(p), CVC4ApiException&); - Term zero = d_solver.mkInteger(0); + Term zero = d_solver.mkReal(0); TS_ASSERT_THROWS(zero.impTerm(b), CVC4ApiException&); TS_ASSERT_THROWS(zero.impTerm(x), CVC4ApiException&); TS_ASSERT_THROWS(zero.impTerm(f), CVC4ApiException&); @@ -515,7 +515,7 @@ void TermBlack::testIteTerm() Term p = d_solver.mkVar("p", funSort2); TS_ASSERT_THROWS(p.iteTerm(b, b), CVC4ApiException&); TS_ASSERT_THROWS(p.iteTerm(x, b), CVC4ApiException&); - Term zero = d_solver.mkInteger(0); + Term zero = d_solver.mkReal(0); TS_ASSERT_THROWS(zero.iteTerm(x, x), CVC4ApiException&); TS_ASSERT_THROWS(zero.iteTerm(x, b), CVC4ApiException&); Term f_x = d_solver.mkTerm(APPLY_UF, f, x); diff --git a/test/unit/proof/CMakeLists.txt b/test/unit/proof/CMakeLists.txt new file mode 100644 index 000000000..00c893bdb --- /dev/null +++ b/test/unit/proof/CMakeLists.txt @@ -0,0 +1,6 @@ +#-----------------------------------------------------------------------------# +# Add unit tests + +cvc4_add_unit_test_black(drat_proof_black proof) +cvc4_add_unit_test_black(lrat_proof_black proof) +cvc4_add_unit_test_black(lfsc_proof_printer_black proof) diff --git a/test/unit/proof/drat_proof_black.h b/test/unit/proof/drat_proof_black.h new file mode 100644 index 000000000..63c8839b9 --- /dev/null +++ b/test/unit/proof/drat_proof_black.h @@ -0,0 +1,187 @@ +/********************* */ +/*! \file drat_proof_black.h + ** \verbatim + ** Top contributors (to current version): + ** Alex Ozdemir + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2018 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 Black box testing of the DRAT proof class + ** + ** In particular, tests DRAT binary parsing. + **/ + +#include <cxxtest/TestSuite.h> + +#include <cctype> + +#include "proof/drat/drat_proof.h" + +using namespace CVC4::proof::drat; + +class DratProofBlack : public CxxTest::TestSuite +{ + public: + void setUp() override {} + void tearDown() override {} + + void testParseOneAdd(); + void testParseOneMediumAdd(); + void testParseOneBigAdd(); + void testParseLiteralIsTooBig(); + void testParseLiteralOverflow(); + void testParseClauseOverflow(); + + void testParseTwo(); + + void testOutputTwoAsText(); + void testOutputTwoAsLfsc(); +}; + +void DratProofBlack::testParseOneAdd() +{ + // a 1; + std::string input("a\x02\x00", 3); + DratProof proof = DratProof::fromBinary(input); + + TS_ASSERT_EQUALS(proof.getInstructions()[0].d_kind, ADDITION); + TS_ASSERT_EQUALS(proof.getInstructions()[0].d_clause.size(), 1); + TS_ASSERT_EQUALS(proof.getInstructions()[0].d_clause[0], + SatLiteral(0, false)); +} + +void DratProofBlack::testParseOneMediumAdd() +{ + // a -255; + std::string input("a\xff\x01\x00", 4); + DratProof proof = DratProof::fromBinary(input); + + TS_ASSERT_EQUALS(proof.getInstructions()[0].d_kind, ADDITION); + TS_ASSERT_EQUALS(proof.getInstructions()[0].d_clause.size(), 1); + TS_ASSERT_EQUALS(proof.getInstructions()[0].d_clause[0], + SatLiteral(126, true)); +} + +void DratProofBlack::testParseOneBigAdd() +{ + // a -2199023255551; + std::string input("a\xff\xff\xff\xff\xff\x7f\x00", 8); + DratProof proof = DratProof::fromBinary(input); + + TS_ASSERT_EQUALS(proof.getInstructions()[0].d_kind, ADDITION); + TS_ASSERT_EQUALS(proof.getInstructions()[0].d_clause.size(), 1); + TS_ASSERT_EQUALS(proof.getInstructions()[0].d_clause[0], + SatLiteral(2199023255550, true)); +} + +void DratProofBlack::testParseLiteralIsTooBig() +{ + std::string input("a\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x7f\x00", + 14); + TS_ASSERT_THROWS(DratProof::fromBinary(input), InvalidDratProofException); +} + +void DratProofBlack::testParseLiteralOverflow() +{ + std::string input("a\x80", 2); + TS_ASSERT_THROWS(DratProof::fromBinary(input), InvalidDratProofException); +} + +void DratProofBlack::testParseClauseOverflow() +{ + std::string input("a\x80\x01", 3); + TS_ASSERT_THROWS(DratProof::fromBinary(input), InvalidDratProofException); +} + +void DratProofBlack::testParseTwo() +{ + // d -63 -8193 + // 129 -8191 + std::string input("\x64\x7f\x83\x80\x01\x00\x61\x82\x02\xff\x7f\x00", 12); + DratProof proof = DratProof::fromBinary(input); + + TS_ASSERT_EQUALS(proof.getInstructions()[0].d_kind, DELETION); + TS_ASSERT_EQUALS(proof.getInstructions()[0].d_clause.size(), 2); + TS_ASSERT_EQUALS(proof.getInstructions()[0].d_clause[0], + SatLiteral(62, true)); + TS_ASSERT_EQUALS(proof.getInstructions()[0].d_clause[1], + SatLiteral(8192, true)); + + TS_ASSERT_EQUALS(proof.getInstructions()[1].d_kind, ADDITION); + TS_ASSERT_EQUALS(proof.getInstructions()[1].d_clause.size(), 2); + TS_ASSERT_EQUALS(proof.getInstructions()[1].d_clause[0], + SatLiteral(128, false)); + TS_ASSERT_EQUALS(proof.getInstructions()[1].d_clause[1], + SatLiteral(8190, true)); +} + +void DratProofBlack::testOutputTwoAsText() +{ + // d -63 -8193 + // 129 -8191 + std::string input("\x64\x7f\x83\x80\x01\x00\x61\x82\x02\xff\x7f\x00", 12); + DratProof proof = DratProof::fromBinary(input); + + std::ostringstream output; + proof.outputAsText(output); + + std::istringstream tokens(output.str()); + std::string token; + + tokens >> token; + TS_ASSERT_EQUALS(token, "d"); + + tokens >> token; + TS_ASSERT_EQUALS(token, "-63"); + + tokens >> token; + TS_ASSERT_EQUALS(token, "-8193"); + + tokens >> token; + TS_ASSERT_EQUALS(token, "0"); + + tokens >> token; + TS_ASSERT_EQUALS(token, "129"); + + tokens >> token; + TS_ASSERT_EQUALS(token, "-8191"); + + tokens >> token; + TS_ASSERT_EQUALS(token, "0"); +} + +void DratProofBlack::testOutputTwoAsLfsc() +{ + // d -63 -8193 + // 129 -8191 + std::string input("\x64\x7f\x83\x80\x01\x00\x61\x82\x02\xff\x7f\x00", 12); + DratProof proof = DratProof::fromBinary(input); + std::ostringstream lfsc; + proof.outputAsLfsc(lfsc, 2); + std::ostringstream lfscWithoutWhitespace; + for (char c : lfsc.str()) + { + if (!std::isspace(c)) + { + lfscWithoutWhitespace << c; + } + } + std::string expectedLfsc = + "(DRATProofd (clc (neg .v62) (clc (neg .v8192) cln))" + "(DRATProofa (clc (pos .v128) (clc (neg .v8190) cln))" + "DRATProofn))"; + std::ostringstream expectedLfscWithoutWhitespace; + for (char c : expectedLfsc) + { + if (!std::isspace(c)) + { + expectedLfscWithoutWhitespace << c; + } + } + + TS_ASSERT_EQUALS(lfscWithoutWhitespace.str(), + expectedLfscWithoutWhitespace.str()); +} diff --git a/test/unit/proof/lfsc_proof_printer_black.h b/test/unit/proof/lfsc_proof_printer_black.h new file mode 100644 index 000000000..27372b62d --- /dev/null +++ b/test/unit/proof/lfsc_proof_printer_black.h @@ -0,0 +1,118 @@ +/********************* */ +/*! \file lfsc_proof_printer_black.h + ** \verbatim + ** Top contributors (to current version): + ** Alex Ozdemir + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2018 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 Black box testing of LFSC proof printing + **/ + +#include <cxxtest/TestSuite.h> + +#include "proof/lfsc_proof_printer.h" +#include "prop/sat_solver_types.h" +#include "proof/clause_id.h" + +using namespace CVC4::proof; +using namespace CVC4::prop; + +class LfscProofPrinterBlack : public CxxTest::TestSuite +{ + public: + void setUp() override {} + void tearDown() override {} + + void testPrintClause(); + void testPrintSatInputProof(); + void testPrintCMapProof(); +}; + +void LfscProofPrinterBlack::testPrintClause() +{ + SatClause clause{ + SatLiteral(0, false), SatLiteral(1, true), SatLiteral(3, false)}; + std::ostringstream lfsc; + + LFSCProofPrinter::printSatClause(clause, lfsc, ""); + + std::string expectedLfsc = + "(clc (pos .v0) " + "(clc (neg .v1) " + "(clc (pos .v3) " + "cln)))"; + + TS_ASSERT_EQUALS(lfsc.str(), expectedLfsc); +} + +void LfscProofPrinterBlack::testPrintSatInputProof() +{ + std::vector<CVC4::ClauseId> ids{2, 40, 3}; + std::ostringstream lfsc; + + LFSCProofPrinter::printSatInputProof(ids, lfsc, ""); + + std::string expectedLfsc = + "(cnfc_proof _ _ _ .pb2 " + "(cnfc_proof _ _ _ .pb40 " + "(cnfc_proof _ _ _ .pb3 " + "cnfn_proof)))"; + + std::ostringstream lfscWithoutWhitespace; + for (char c : lfsc.str()) + { + if (!std::isspace(c)) + { + lfscWithoutWhitespace << c; + } + } + std::ostringstream expectedLfscWithoutWhitespace; + for (char c : expectedLfsc) + { + if (!std::isspace(c)) + { + expectedLfscWithoutWhitespace << c; + } + } + + TS_ASSERT_EQUALS(lfscWithoutWhitespace.str(), + expectedLfscWithoutWhitespace.str()); +} + +void LfscProofPrinterBlack::testPrintCMapProof() +{ + std::vector<CVC4::ClauseId> ids{2, 40, 3}; + std::ostringstream lfsc; + + LFSCProofPrinter::printCMapProof(ids, lfsc, ""); + + std::string expectedLfsc = + "(CMapc_proof 1 _ _ _ .pb2 " + "(CMapc_proof 2 _ _ _ .pb40 " + "(CMapc_proof 3 _ _ _ .pb3 " + "CMapn_proof)))"; + + std::ostringstream lfscWithoutWhitespace; + for (char c : lfsc.str()) + { + if (!std::isspace(c)) + { + lfscWithoutWhitespace << c; + } + } + std::ostringstream expectedLfscWithoutWhitespace; + for (char c : expectedLfsc) + { + if (!std::isspace(c)) + { + expectedLfscWithoutWhitespace << c; + } + } + + TS_ASSERT_EQUALS(lfscWithoutWhitespace.str(), + expectedLfscWithoutWhitespace.str()); +} diff --git a/test/unit/proof/lrat_proof_black.h b/test/unit/proof/lrat_proof_black.h new file mode 100644 index 000000000..49d18ac53 --- /dev/null +++ b/test/unit/proof/lrat_proof_black.h @@ -0,0 +1,113 @@ +/********************* */ +/*! \file lrat_proof_black.h + ** \verbatim + ** Top contributors (to current version): + ** Alex Ozdemir + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2019 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 Black box testing of the LRAT proof class + ** + ** In particular, tests LRAT LFSC output. + **/ + +#include <cxxtest/TestSuite.h> + +#include <algorithm> +#include <cctype> +#include <iostream> +#include <iterator> + +#include "proof/lrat/lrat_proof.h" +#include "prop/sat_solver_types.h" + +using namespace CVC4::proof::lrat; +using namespace CVC4::prop; + +class LfscProofBlack : public CxxTest::TestSuite +{ + public: + void setUp() override {} + void tearDown() override {} + + void testOutputAsLfsc(); +}; + +/** + * Creates a new stream with whitespace removed. + * + * @param s the source string + * + * @return a string without whitespace + */ +std::string filterWhitespace(const std::string& s) +{ + std::string out; + std::copy_if(s.cbegin(), s.cend(), std::inserter(out, out.end()), [](char c) { + return !std::isspace(c); + }); + return out; +} + +void LfscProofBlack::testOutputAsLfsc() +{ + std::vector<std::unique_ptr<LratInstruction>> instructions; + + // 6 d 1 2 + std::vector<ClauseIdx> clausesToDelete{1, 2}; + std::unique_ptr<LratDeletion> deletion = std::unique_ptr<LratDeletion>( + new LratDeletion(6, std::move(clausesToDelete))); + instructions.push_back(std::move(deletion)); + + // 7 1 2 0 5 2 0 + std::vector<SatLiteral> firstAddedClause{SatLiteral(1, false), + SatLiteral(2, false)}; + LratUPTrace firstTrace{5, 2}; + std::vector<std::pair<ClauseIdx, LratUPTrace>> firstHints; + std::unique_ptr<LratAddition> add1 = + std::unique_ptr<LratAddition>(new LratAddition( + 7, std::move(firstAddedClause), std::move(firstTrace), firstHints)); + instructions.push_back(std::move(add1)); + + // 8 2 0 -1 3 -5 2 0 + std::vector<SatLiteral> secondAddedClause{SatLiteral(2, false)}; + LratUPTrace secondTrace; + std::vector<std::pair<ClauseIdx, LratUPTrace>> secondHints; + LratUPTrace secondHints0Trace{3}; + secondHints.emplace_back(1, secondHints0Trace); + LratUPTrace secondHints1Trace{2}; + secondHints.emplace_back(5, secondHints1Trace); + std::unique_ptr<LratAddition> add2 = std::unique_ptr<LratAddition>( + new LratAddition(8, + std::move(secondAddedClause), + std::move(secondTrace), + secondHints)); + instructions.push_back(std::move(add2)); + + LratProof proof(std::move(instructions)); + + std::ostringstream lfsc; + proof.outputAsLfsc(lfsc); + + // 6 d 1 2 + // 7 1 2 0 5 2 0 + // 8 2 0 -1 3 -5 2 0 + std::string expectedLfsc = + "(LRATProofd (CIListc 1 (CIListc 2 CIListn)) " + "(LRATProofa 7 " + " (clc (pos bb.v1) (clc (pos bb.v2) cln))" + " (Tracec 5 (Tracec 2 Tracen))" + " RATHintsn " + "(LRATProofa 8 " + " (clc (pos bb.v2) cln)" + " Tracen " + " (RATHintsc 1 (Tracec 3 Tracen)" + " (RATHintsc 5 (Tracec 2 Tracen)" + " RATHintsn)) " + "LRATProofn)))"; + + TS_ASSERT_EQUALS(filterWhitespace(lfsc.str()), filterWhitespace(expectedLfsc)); +} |