bool BitvectorTheory::handleITE(const FormulaT& ifterm, const types::TermType& thenterm, const types::TermType& elseterm, types::TermType& result, TheoryError& errors) { types::BVTerm thent; types::BVTerm elset; if (!termConverter(thenterm, thent)) { errors.next() << "Failed to construct ITE, the then-term \"" << thenterm << "\" is unsupported."; return false; } if (!termConverter(elseterm, elset)) { errors.next() << "Failed to construct ITE, the else-term \"" << elseterm << "\" is unsupported."; return false; } if (thent.width() != elset.width()) { errors.next() << "Failed to construct ITE, the then-term \"" << thent << "\" and the else-term \"" << elset << "\" have different widths."; return false; } if (ifterm.isTrue()) { result = thent; return true; } if (ifterm.isFalse()) { result = elset; return true; } carl::SortManager& sm = carl::SortManager::getInstance(); carl::Variable var = carl::freshVariable(carl::VariableType::VT_BITVECTOR); state->artificialVariables.emplace_back(var); carl::BVVariable bvvar(var, sm.index(this->bvSort, {thent.width()})); state->auxiliary_variables.insert(bvvar); types::BVTerm vart = types::BVTerm(carl::BVTermType::VARIABLE, bvvar); FormulaT consThen = FormulaT(types::BVConstraint::create(carl::BVCompareRelation::EQ, vart, thent)); FormulaT consElse = FormulaT(types::BVConstraint::create(carl::BVCompareRelation::EQ, vart, elset)); state->global_formulas.emplace_back(FormulaT(carl::FormulaType::IMPLIES, {ifterm, consThen})); state->global_formulas.emplace_back(FormulaT(carl::FormulaType::IMPLIES, {FormulaT(carl::FormulaType::NOT,ifterm), consElse})); result = vart; return true; }
FormulaT MixedSignEncoder::findSubEncoding(const ConstraintT& constraint) { FormulaT chosenEncoding; bool hasEncoded = false; if (mShortFormulaEncoder.canEncode(constraint)) { boost::optional<FormulaT> shortEncoding = mShortFormulaEncoder.encode(constraint); if (shortEncoding) { chosenEncoding = *shortEncoding; hasEncoded = true; } } else if (mCardinalityEncoder.canEncode(constraint)) { boost::optional<FormulaT> cardinalityEncoding = mCardinalityEncoder.encode(constraint); if (cardinalityEncoding) { chosenEncoding = *cardinalityEncoding; hasEncoded = true; } } else if (mLongFormulaEncoder.canEncode(constraint)) { boost::optional<FormulaT> longEncoding = mLongFormulaEncoder.encode(constraint); if (longEncoding) { chosenEncoding = *longEncoding; hasEncoded = true; } } if (!hasEncoded) { chosenEncoding = FormulaT(constraint); } return chosenEncoding; }
bool apply(const std::vector<FormulaT>& arguments, types::TermType& result, TheoryError& errors) const { if (arguments.size() != 2) { errors.next() << "Operator \"implies\" may only have a single argument."; return false; } result = FormulaT(carl::FormulaType::IMPLIES, {arguments[0], arguments[1]}); return true; }
bool apply(const std::vector<types::BVTerm>& arguments, types::TermType& result, TheoryError& errors) const { if (arguments.size() != 2) { errors.next() << "The operator \"" << type << "\" expects exactly two arguments."; return false; } result = FormulaT(types::BVConstraint::create(type, arguments[0], arguments[1])); return true; }
bool CoreTheory::handleDistinct(const std::vector<types::TermType>& arguments, types::TermType& result, TheoryError& errors) { std::vector<FormulaT> args; if (!convertArguments(arguments, args, errors)) return false; result = expandDistinct(args, [](const FormulaT& a, const FormulaT& b){ return FormulaT(carl::FormulaType::XOR, {a, b}); }); return true; }
bool BitvectorTheory::handleDistinct(const std::vector<types::TermType>& arguments, types::TermType& result, TheoryError& errors) { std::vector<carl::BVTerm> args; if (!vectorConverter(arguments, args, errors)) return false; result = expandDistinct(args, [](const carl::BVTerm& a, const carl::BVTerm& b){ return FormulaT(carl::BVConstraint::create(carl::BVCompareRelation::NEQ, a, b)); }); return true; }
bool CoreTheory::functionCall(const Identifier& identifier, const std::vector<types::TermType>& arguments, types::TermType& result, TheoryError& errors) { std::vector<FormulaT> args; if (!convertArguments(arguments, args, errors)) return false; if (boost::iequals(identifier.symbol, "=")) { result = FormulaT(carl::FormulaType::IFF, FormulasT(args.begin(), args.end())); return true; } return false; }
bool BitvectorTheory::functionCall(const Identifier& identifier, const std::vector<types::TermType>& arguments, types::TermType& result, TheoryError& errors) { if (identifier.symbol == "=") { if (arguments.size() == 2) { std::vector<types::BVTerm> args; if (!vectorConverter(arguments, args, errors)) return false; result = FormulaT(types::BVConstraint::create(carl::BVCompareRelation::EQ, args[0], args[1])); return true; } errors.next() << "Operator \"" << identifier << "\" expects exactly two arguments, but got " << arguments.size() << "."; return false; } errors.next() << "Invalid operator \"" << identifier << "\"."; return false; }
bool CoreTheory::handleITE(const FormulaT& ifterm, const types::TermType& thenterm, const types::TermType& elseterm, types::TermType& result, TheoryError& errors) { FormulaT thenf; FormulaT elsef; if (!convertTerm(thenterm, thenf)) { errors.next() << "Failed to construct ITE, the then-term \"" << thenterm << "\" is unsupported."; return false; } if (!convertTerm(elseterm, elsef)) { errors.next() << "Failed to construct ITE, the else-term \"" << elseterm << "\" is unsupported."; return false; } result = FormulaT(carl::FormulaType::ITE, {ifterm, thenf, elsef}); return true; }
bool CoreTheory::convertTerm(const types::TermType& term, FormulaT& result) { if (boost::get<FormulaT>(&term) != nullptr) { result = boost::get<FormulaT>(term); return true; } else if (boost::get<carl::Variable>(&term) != nullptr) { if (boost::get<carl::Variable>(term).getType() == carl::VariableType::VT_BOOL) { result = FormulaT(boost::get<carl::Variable>(term)); return true; } else { return false; } } else { return false; } }
FormulaT MCBModule<Settings>::applyReplacements(const FormulaT& f) { if (mChoices.empty()) return f; std::set<AVar> variables; std::map<FormulaT, FormulaT> repl; for (const auto& r: mChoices) { variables.insert(r.first); for (const auto& f: r.second) { BVar v = f.second.first; const FormulaT& form = f.second.second; repl.emplace(form, FormulaT(v)); } } carl::FormulaSubstitutor<FormulaT> subs; SMTRAT_LOG_DEBUG("smtrat.mcb", "Applying " << repl << " on \n\t" << f); FormulaT res = subs.substitute(f, repl); SMTRAT_LOG_DEBUG("smtrat.mcb", "Resulting in\n\t" << res); mRemaining.clear(); res.allVars(mRemaining); FormulasT equiv; for (const auto& v: variables) { if (mRemaining.count(v) > 0) { // Variable is still in the formula for (const auto& r: mChoices.at(v)) { equiv.push_back(FormulaT(carl::FormulaType::IFF, {FormulaT(r.second.first), r.second.second})); } } else { // Variable has been eliminated ModelVariable var(v); std::map<BVar,Rational> assignment; for (const auto& c: mChoices.at(v)) { assignment.emplace(c.second.first, c.first); } SMTRAT_LOG_DEBUG("smtrat.mcb", "Adding " << var << " = " << assignment); mAssignments.emplace(var, carl::createSubstitution<Rational,Poly,MCBModelSubstitution>(assignment)); } for (const auto& c1: mChoices.at(v)) { for (const auto& c2: mChoices.at(v)) { if (c1.second.first >= c2.second.first) continue; equiv.push_back(FormulaT(carl::FormulaType::OR, {FormulaT(c1.second.first).negated(), FormulaT(c2.second.first).negated()})); SMTRAT_LOG_DEBUG("smtrat.mcb", "Adding exclusion " << equiv.back()); } } } if (equiv.empty()) return res; SMTRAT_LOG_DEBUG("smtrat.mcb", "Adding equivalences " << equiv); equiv.push_back(res); return FormulaT(carl::FormulaType::AND, std::move(equiv)); }
Answer MCBModule<Settings>::checkCore() { mRemaining.clear(); mChoices.clear(); carl::FormulaVisitor<FormulaT> visitor; auto receivedFormula = firstUncheckedReceivedSubformula(); while (receivedFormula != rReceivedFormula().end()) { visitor.visit(receivedFormula->formula(), collectChoicesFunction); receivedFormula++; } FormulaT newFormula = applyReplacements(FormulaT(rReceivedFormula())); clearPassedFormula(); addSubformulaToPassedFormula(newFormula); Answer ans = runBackends(); if (ans == UNSAT) { generateTrivialInfeasibleSubset(); } return ans; }
boost::optional<FormulaT> MixedSignEncoder::doEncode(const ConstraintT& constraint) { // first partition into positive and negative terms std::vector<TermT> positiveTerms; std::vector<TermT> negativeTerms; for (const auto& term : constraint.lhs()) { if (term.isConstant()) continue; if (term.coeff() > 0) { positiveTerms.push_back(term); } else { negativeTerms.push_back(term); } } Poly lhs; Poly rhs; for (const auto& term : positiveTerms) { lhs += term; } for (const auto& term : negativeTerms) { rhs -= term; } if (constraint.relation() == carl::Relation::LEQ) { // we assume mixed signs // x1 + x2 - x3 - x4 - 1 <= 0 iff x1 + x2 -1 <= x3 + x4 // lhsValues -1, 0, 1 // rhs Value 0, 1, 2 // x1 + x2 - 1 >= -1 impl. x3 + x4 >= - 1 // x1 + x2 - 1 >= 0 impl x3 + x4 >= 0 // x1 + x2 - 1 >= 1 impl x3 + x4 >= 1 // now we can express the constraint as sum of positive terms <= negative sum of negative terms - constantPart // this holds iff // take all possible subsetsums of our new lhs. For each of these sums b_i we construct // encode(lhs + constant >= b_i) implies encode(rhs >= b_i) std::vector<Rational> subsetsums = calculateSubsetsums(positiveTerms); FormulasT conjunction; for (const auto& sum : subsetsums) { ConstraintT lhsImplication(lhs - sum, carl::Relation::GEQ); // poly lhs + constantPart >= bi ConstraintT rhsImplication(rhs - sum - constraint.constantPart(), carl::Relation::GEQ); // rhs >= bi FormulaT chosenLhsEncoding = findSubEncoding(mNormalizer.trim(lhsImplication)); FormulaT chosenRhsEncoding = findSubEncoding(mNormalizer.trim(rhsImplication)); conjunction.push_back(FormulaT(carl::FormulaType::IMPLIES, chosenLhsEncoding, chosenRhsEncoding)); } return FormulaT(carl::FormulaType::AND, conjunction); } if (constraint.relation() == carl::Relation::EQ) { // x1 + x2 - x3 - x4 - 1= 0 iff x1 + x2 -1 = x3 + x4 // positiveSums: -1, 0, 1 // negativeSums: 0, 1, 2 // x3 + x4 = 0 impl. x1 + x2 -1 = 0 // x3 + x4 = 1 impl. x1 + x2 -1 = 1 // x3 + x4 = 2 impl. x1 + x2 -1 = 2 // x1 + x2 -1 = -1 impl. x3 + x4 = -1 // x1 + x2 -1 = 0 impl. x3 + x4 = 0 // x1 + x2 -1 = 1 impl. x3 + x4 = 1 std::vector<Rational> subsetsumsPositive = calculateSubsetsums(positiveTerms); std::vector<Rational> subsetsumsNegative = calculateSubsetsums(negativeTerms); FormulasT conjunction; for (const auto& sum : subsetsumsPositive) { ConstraintT lhsImplication(lhs - sum, carl::Relation::EQ); ConstraintT rhsImplication(rhs - sum - constraint.constantPart(), carl::Relation::EQ); FormulaT chosenLhsEncoding = findSubEncoding(mNormalizer.trim(lhsImplication)); FormulaT chosenRhsEncoding = findSubEncoding(mNormalizer.trim(rhsImplication)); conjunction.push_back(FormulaT(carl::FormulaType::IMPLIES, chosenLhsEncoding, chosenRhsEncoding)); } for (const auto& sum : subsetsumsNegative) { ConstraintT lhsImplication(lhs - constraint.constantPart() - sum, carl::Relation::EQ); ConstraintT rhsImplication(rhs - sum, carl::Relation::EQ); FormulaT chosenLhsEncoding = findSubEncoding(mNormalizer.trim(lhsImplication)); FormulaT chosenRhsEncoding = findSubEncoding(mNormalizer.trim(rhsImplication)); conjunction.push_back(FormulaT(carl::FormulaType::IMPLIES, chosenRhsEncoding, chosenLhsEncoding)); } return FormulaT(carl::FormulaType::AND, conjunction); } return {}; }
Answer CubeLIAModule<Settings>::checkCore() { #ifdef DEBUG_CUBELIAMODULE print(); #endif Answer ans; if( !rReceivedFormula().isRealConstraintConjunction() ) { #ifdef DEBUG_CUBELIAMODULE std::cout << "Call internal LRAModule:" << std::endl; mLRA.print(); #endif mLRA.clearLemmas(); mLRAFormula->updateProperties(); ans = mLRA.check( false, mFullCheck, mMinimizingCheck ); switch( ans ) { case SAT: { clearModel(); // Get the model of mLRA mLRA.updateModel(); const Model& relaxedModel = mLRA.model(); auto iter = mRealToIntVarMap.begin(); for( auto& ass : relaxedModel ) { assert( iter != mRealToIntVarMap.end() ); // Round the result to the next integer mModel.emplace_hint( mModel.end(), iter->second, carl::round( ass.second.asRational() ) ); ++iter; } // Check if the rounded model satisfies the received formula bool receivedFormulaSatisfied = true; for( const FormulaWithOrigins& fwo : rReceivedFormula() ) { unsigned res = satisfies( mModel, fwo.formula() ); switch( res ) { case 0: case 2: receivedFormulaSatisfied = false; default: break; } if( !receivedFormulaSatisfied ) break; } // If we found a model, we know that the formula is satisfiable, otherwise, we have to call the backends on the received formula if( receivedFormulaSatisfied ) { mModelUpdated = true; return SAT; } clearModel(); break; } case UNSAT: { if( Settings::exclude_unsatisfiable_cube_space ) { // Exclude the space for which mLRA has detected unsatisfiability for( auto& infsubset : mLRA.infeasibleSubsets() ) { FormulasT formulas; for( auto& formula : infsubset ) formulas.push_back( formula.negated() ); addLemma( FormulaT( carl::FormulaType::OR, formulas ) ); } } break; } default: assert( false ); } } #ifdef DEBUG_CUBELIAMODULE std::cout << "Call Backends:" << std::endl; #endif // Run backends on received formula ans = runBackends(); if( ans == UNSAT ) getInfeasibleSubsets(); else if( ans == SAT ) mModelUpdated = false; return ans; }
void CoreTheory::addConstants(qi::symbols<char, types::ConstType>& constants) { constants.add("true", types::ConstType(FormulaT(carl::FormulaType::TRUE))); constants.add("false", types::ConstType(FormulaT(carl::FormulaType::FALSE))); }
virtual FormulaT representingFormula( const ModelVariable& mv ) { assert(false); return FormulaT(); }
bool apply(const std::vector<FormulaT>& arguments, types::TermType& result, TheoryError& ) const { result = FormulaT(type, arguments); return true; }