summaryrefslogtreecommitdiff
path: root/src/proof/resolution_bitvector_proof.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/proof/resolution_bitvector_proof.cpp')
-rw-r--r--src/proof/resolution_bitvector_proof.cpp522
1 files changed, 522 insertions, 0 deletions
diff --git a/src/proof/resolution_bitvector_proof.cpp b/src/proof/resolution_bitvector_proof.cpp
new file mode 100644
index 000000000..667d630f8
--- /dev/null
+++ b/src/proof/resolution_bitvector_proof.cpp
@@ -0,0 +1,522 @@
+/********************* */
+/*! \file resolution_bitvector_proof.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Liana Hadarean, Guy Katz, Paul Meng
+ ** 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
+ **
+ ** [[ Add lengthier description here ]]
+
+ ** \todo document this file
+
+**/
+
+#include "proof/resolution_bitvector_proof.h"
+#include "options/bv_options.h"
+#include "options/proof_options.h"
+#include "proof/array_proof.h"
+#include "proof/bitvector_proof.h"
+#include "proof/clause_id.h"
+#include "proof/lfsc_proof_printer.h"
+#include "proof/proof_output_channel.h"
+#include "proof/proof_utils.h"
+#include "proof/sat_proof_implementation.h"
+#include "prop/bvminisat/bvminisat.h"
+#include "theory/bv/bitblast/bitblaster.h"
+#include "theory/bv/theory_bv.h"
+#include "theory/bv/theory_bv_rewrite_rules.h"
+
+#include <iostream>
+#include <sstream>
+
+using namespace CVC4::theory;
+using namespace CVC4::theory::bv;
+
+namespace CVC4 {
+
+namespace proof {
+
+ResolutionBitVectorProof::ResolutionBitVectorProof(
+ theory::bv::TheoryBV* bv, TheoryProofEngine* proofEngine)
+ : BitVectorProof(bv, proofEngine),
+ d_resolutionProof(),
+ d_isAssumptionConflict(false)
+{
+}
+
+void ResolutionBitVectorProof::initSatProof(CVC4::BVMinisat::Solver* solver)
+{
+ Assert(d_resolutionProof == NULL);
+ d_resolutionProof.reset(new BVSatProof(solver, &d_fakeContext, "bb", true));
+}
+
+theory::TheoryId ResolutionBitVectorProof::getTheoryId()
+{
+ return theory::THEORY_BV;
+}
+
+void ResolutionBitVectorProof::initCnfProof(prop::CnfStream* cnfStream,
+ context::Context* cnf)
+{
+ 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();
+}
+
+BVSatProof* ResolutionBitVectorProof::getSatProof()
+{
+ Assert(d_resolutionProof != NULL);
+ return d_resolutionProof.get();
+}
+
+void ResolutionBitVectorProof::startBVConflict(
+ CVC4::BVMinisat::Solver::TCRef cr)
+{
+ d_resolutionProof->startResChain(cr);
+}
+
+void ResolutionBitVectorProof::startBVConflict(
+ CVC4::BVMinisat::Solver::TLit lit)
+{
+ d_resolutionProof->startResChain(lit);
+}
+
+void ResolutionBitVectorProof::endBVConflict(
+ const CVC4::BVMinisat::Solver::TLitVec& confl)
+{
+ Debug("pf::bv") << "ResolutionBitVectorProof::endBVConflict called"
+ << std::endl;
+
+ std::vector<Expr> expr_confl;
+ for (int i = 0; i < confl.size(); ++i)
+ {
+ prop::SatLiteral lit = prop::BVMinisatSatSolver::toSatLiteral(confl[i]);
+ Expr atom = d_cnfProof->getAtom(lit.getSatVariable()).toExpr();
+ Expr expr_lit = lit.isNegated() ? atom.notExpr() : atom;
+ expr_confl.push_back(expr_lit);
+ }
+
+ Expr conflict = utils::mkSortedExpr(kind::OR, expr_confl);
+ Debug("pf::bv") << "Make conflict for " << conflict << std::endl;
+
+ if (d_bbConflictMap.find(conflict) != d_bbConflictMap.end())
+ {
+ Debug("pf::bv") << "Abort...already conflict for " << conflict << std::endl;
+ // This can only happen when we have eager explanations in the bv solver
+ // if we don't get to propagate p before ~p is already asserted
+ d_resolutionProof->cancelResChain();
+ return;
+ }
+
+ // we don't need to check for uniqueness in the sat solver then
+ ClauseId clause_id = d_resolutionProof->registerAssumptionConflict(confl);
+ d_bbConflictMap[conflict] = clause_id;
+ d_resolutionProof->endResChain(clause_id);
+ Debug("pf::bv") << "ResolutionBitVectorProof::endBVConflict id" << clause_id
+ << " => " << conflict << "\n";
+ d_isAssumptionConflict = false;
+}
+
+void ResolutionBitVectorProof::finalizeConflicts(std::vector<Expr>& conflicts)
+{
+ if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER)
+ {
+ Debug("pf::bv") << "Construct full proof." << std::endl;
+ d_resolutionProof->constructProof();
+ return;
+ }
+
+ for (unsigned i = 0; i < conflicts.size(); ++i)
+ {
+ Expr confl = conflicts[i];
+ Debug("pf::bv") << "Finalize conflict #" << i << ": " << confl << std::endl;
+
+ // Special case: if the conflict has a (true) or a (not false) in it, it is
+ // trivial...
+ bool ignoreConflict = false;
+ if ((confl.isConst() && confl.getConst<bool>())
+ || (confl.getKind() == kind::NOT && confl[0].isConst()
+ && !confl[0].getConst<bool>()))
+ {
+ ignoreConflict = true;
+ }
+ else if (confl.getKind() == kind::OR)
+ {
+ for (unsigned k = 0; k < confl.getNumChildren(); ++k)
+ {
+ if ((confl[k].isConst() && confl[k].getConst<bool>())
+ || (confl[k].getKind() == kind::NOT && confl[k][0].isConst()
+ && !confl[k][0].getConst<bool>()))
+ {
+ ignoreConflict = true;
+ }
+ }
+ }
+ if (ignoreConflict)
+ {
+ Debug("pf::bv") << "Ignoring conflict due to (true) or (not false)"
+ << std::endl;
+ continue;
+ }
+
+ if (d_bbConflictMap.find(confl) != d_bbConflictMap.end())
+ {
+ ClauseId id = d_bbConflictMap[confl];
+ d_resolutionProof->collectClauses(id);
+ }
+ else
+ {
+ // There is no exact match for our conflict, but maybe it is a subset of
+ // another conflict
+ ExprToClauseId::const_iterator it;
+ bool matchFound = false;
+ for (it = d_bbConflictMap.begin(); it != d_bbConflictMap.end(); ++it)
+ {
+ Expr possibleMatch = it->first;
+ if (possibleMatch.getKind() != kind::OR)
+ {
+ // This is a single-node conflict. If this node is in the conflict
+ // we're trying to prove, we have a match.
+ for (unsigned k = 0; k < confl.getNumChildren(); ++k)
+ {
+ if (confl[k] == possibleMatch)
+ {
+ matchFound = true;
+ d_resolutionProof->collectClauses(it->second);
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (possibleMatch.getNumChildren() > confl.getNumChildren()) continue;
+
+ unsigned k = 0;
+ bool matching = true;
+ for (unsigned j = 0; j < possibleMatch.getNumChildren(); ++j)
+ {
+ // j is the index in possibleMatch
+ // k is the index in confl
+ while (k < confl.getNumChildren() && confl[k] != possibleMatch[j])
+ {
+ ++k;
+ }
+ if (k == confl.getNumChildren())
+ {
+ // We couldn't find a match for possibleMatch[j], so not a match
+ matching = false;
+ break;
+ }
+ }
+
+ if (matching)
+ {
+ Debug("pf::bv")
+ << "Collecting info from a sub-conflict" << std::endl;
+ d_resolutionProof->collectClauses(it->second);
+ matchFound = true;
+ break;
+ }
+ }
+ }
+
+ if (!matchFound)
+ {
+ Debug("pf::bv") << "Do not collect clauses for " << confl << std::endl
+ << "Dumping existing conflicts:" << std::endl;
+
+ i = 0;
+ for (it = d_bbConflictMap.begin(); it != d_bbConflictMap.end(); ++it)
+ {
+ ++i;
+ Debug("pf::bv") << "\tConflict #" << i << ": " << it->first
+ << std::endl;
+ }
+
+ Unreachable();
+ }
+ }
+ }
+}
+
+void LFSCBitVectorProof::printTheoryLemmaProof(std::vector<Expr>& lemma,
+ std::ostream& os,
+ std::ostream& paren,
+ const ProofLetMap& map)
+{
+ Debug("pf::bv") << "(pf::bv) LFSCBitVectorProof::printTheoryLemmaProof called"
+ << std::endl;
+ Expr conflict = utils::mkSortedExpr(kind::OR, lemma);
+ Debug("pf::bv") << "\tconflict = " << conflict << std::endl;
+
+ if (d_bbConflictMap.find(conflict) != d_bbConflictMap.end())
+ {
+ std::ostringstream lemma_paren;
+ for (unsigned i = 0; i < lemma.size(); ++i)
+ {
+ Expr lit = lemma[i];
+
+ if (lit.getKind() == kind::NOT)
+ {
+ os << "(intro_assump_t _ _ _ ";
+ }
+ else
+ {
+ os << "(intro_assump_f _ _ _ ";
+ }
+ lemma_paren << ")";
+ // print corresponding literal in main sat solver
+ ProofManager* pm = ProofManager::currentPM();
+ CnfProof* cnf = pm->getCnfProof();
+ prop::SatLiteral main_lit = cnf->getLiteral(lit);
+ os << pm->getLitName(main_lit);
+ os << " ";
+ // print corresponding literal in bv sat solver
+ prop::SatVariable bb_var = d_cnfProof->getLiteral(lit).getSatVariable();
+ os << pm->getAtomName(bb_var, "bb");
+ os << "(\\ unit" << bb_var << "\n";
+ lemma_paren << ")";
+ }
+ Expr lem = utils::mkOr(lemma);
+ Assert(d_bbConflictMap.find(lem) != d_bbConflictMap.end());
+ ClauseId lemma_id = d_bbConflictMap[lem];
+ proof::LFSCProofPrinter::printAssumptionsResolution(
+ d_resolutionProof.get(), lemma_id, os, lemma_paren);
+ os << lemma_paren.str();
+ }
+ else
+ {
+ Debug("pf::bv") << "Found a non-recorded conflict. Looking for a matching "
+ "sub-conflict..."
+ << std::endl;
+
+ bool matching;
+
+ ExprToClauseId::const_iterator it;
+ unsigned i = 0;
+ for (it = d_bbConflictMap.begin(); it != d_bbConflictMap.end(); ++it)
+ {
+ // Our conflict is sorted, and the records are also sorted.
+ ++i;
+ Expr possibleMatch = it->first;
+
+ if (possibleMatch.getKind() != kind::OR)
+ {
+ // This is a single-node conflict. If this node is in the conflict we're
+ // trying to prove, we have a match.
+ matching = false;
+
+ for (unsigned k = 0; k < conflict.getNumChildren(); ++k)
+ {
+ if (conflict[k] == possibleMatch)
+ {
+ matching = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (possibleMatch.getNumChildren() > conflict.getNumChildren())
+ continue;
+
+ unsigned k = 0;
+
+ matching = true;
+ for (unsigned j = 0; j < possibleMatch.getNumChildren(); ++j)
+ {
+ // j is the index in possibleMatch
+ // k is the index in conflict
+ while (k < conflict.getNumChildren()
+ && conflict[k] != possibleMatch[j])
+ {
+ ++k;
+ }
+ if (k == conflict.getNumChildren())
+ {
+ // We couldn't find a match for possibleMatch[j], so not a match
+ matching = false;
+ break;
+ }
+ }
+ }
+
+ if (matching)
+ {
+ Debug("pf::bv") << "Found a match with conflict #" << i << ": "
+ << std::endl
+ << possibleMatch << std::endl;
+ // The rest is just a copy of the usual handling, if a precise match is
+ // found. We only use the literals that appear in the matching conflict,
+ // though, and not in the original lemma - as these may not have even
+ // been bit blasted!
+ std::ostringstream lemma_paren;
+
+ if (possibleMatch.getKind() == kind::OR)
+ {
+ for (unsigned i = 0; i < possibleMatch.getNumChildren(); ++i)
+ {
+ Expr lit = possibleMatch[i];
+
+ if (lit.getKind() == kind::NOT)
+ {
+ os << "(intro_assump_t _ _ _ ";
+ }
+ else
+ {
+ os << "(intro_assump_f _ _ _ ";
+ }
+ lemma_paren << ")";
+ // print corresponding literal in main sat solver
+ ProofManager* pm = ProofManager::currentPM();
+ CnfProof* cnf = pm->getCnfProof();
+ prop::SatLiteral main_lit = cnf->getLiteral(lit);
+ os << pm->getLitName(main_lit);
+ os << " ";
+ // print corresponding literal in bv sat solver
+ prop::SatVariable bb_var =
+ d_cnfProof->getLiteral(lit).getSatVariable();
+ os << pm->getAtomName(bb_var, "bb");
+ os << "(\\ unit" << bb_var << "\n";
+ lemma_paren << ")";
+ }
+ }
+ else
+ {
+ // The conflict only consists of one node, either positive or
+ // negative.
+ Expr lit = possibleMatch;
+ if (lit.getKind() == kind::NOT)
+ {
+ os << "(intro_assump_t _ _ _ ";
+ }
+ else
+ {
+ os << "(intro_assump_f _ _ _ ";
+ }
+ lemma_paren << ")";
+ // print corresponding literal in main sat solver
+ ProofManager* pm = ProofManager::currentPM();
+ CnfProof* cnf = pm->getCnfProof();
+ prop::SatLiteral main_lit = cnf->getLiteral(lit);
+ os << pm->getLitName(main_lit);
+ os << " ";
+ // print corresponding literal in bv sat solver
+ prop::SatVariable bb_var =
+ d_cnfProof->getLiteral(lit).getSatVariable();
+ os << pm->getAtomName(bb_var, "bb");
+ os << "(\\ unit" << bb_var << "\n";
+ lemma_paren << ")";
+ }
+
+ ClauseId lemma_id = it->second;
+ proof::LFSCProofPrinter::printAssumptionsResolution(
+ d_resolutionProof.get(), lemma_id, os, lemma_paren);
+ os << lemma_paren.str();
+
+ return;
+ }
+ }
+
+ // We failed to find a matching sub conflict. The last hope is that the
+ // conflict has a FALSE assertion in it; this can happen in some corner
+ // cases, where the FALSE is the result of a rewrite.
+
+ for (unsigned i = 0; i < lemma.size(); ++i)
+ {
+ if (lemma[i].getKind() == kind::NOT && lemma[i][0] == utils::mkFalse())
+ {
+ Debug("pf::bv") << "Lemma has a (not false) literal" << std::endl;
+ os << "(clausify_false ";
+ os << ProofManager::getLitName(lemma[i]);
+ os << ")";
+ return;
+ }
+ }
+
+ Debug("pf::bv") << "Failed to find a matching sub-conflict..." << std::endl
+ << "Dumping existing conflicts:" << std::endl;
+
+ i = 0;
+ for (it = d_bbConflictMap.begin(); it != d_bbConflictMap.end(); ++it)
+ {
+ ++i;
+ Debug("pf::bv") << "\tConflict #" << i << ": " << it->first << std::endl;
+ }
+
+ Unreachable();
+ }
+}
+
+void LFSCBitVectorProof::calculateAtomsInBitblastingProof()
+{
+ // Collect the input clauses used
+ IdToSatClause used_lemmas;
+ IdToSatClause used_inputs;
+ d_resolutionProof->collectClausesUsed(used_inputs, used_lemmas);
+ d_cnfProof->collectAtomsForClauses(used_inputs, d_atomsInBitblastingProof);
+ Assert(used_lemmas.empty());
+}
+
+void LFSCBitVectorProof::printResolutionProof(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;
+
+ std::set<Node>::iterator atomIt;
+ Debug("pf::bv") << std::endl
+ << "BV Dumping atoms from inputs: " << std::endl
+ << std::endl;
+ for (atomIt = d_atomsInBitblastingProof.begin();
+ atomIt != d_atomsInBitblastingProof.end();
+ ++atomIt)
+ {
+ Debug("pf::bv") << "\tAtom: " << *atomIt << std::endl;
+ }
+ Debug("pf::bv") << std::endl;
+
+ // first print bit-blasting
+ printBitblasting(os, paren);
+
+ // print CNF conversion proof for bit-blasted facts
+ IdToSatClause used_lemmas;
+ IdToSatClause used_inputs;
+ d_resolutionProof->collectClausesUsed(used_inputs, used_lemmas);
+
+ d_cnfProof->printAtomMapping(d_atomsInBitblastingProof, os, paren, letMap);
+ os << std::endl << ";; Bit-blasting definitional clauses \n" << std::endl;
+ for (IdToSatClause::iterator it = used_inputs.begin();
+ it != used_inputs.end();
+ ++it)
+ {
+ d_cnfProof->printCnfProofForClause(it->first, it->second, os, paren);
+ }
+
+ os << std::endl << " ;; Bit-blasting learned clauses \n" << std::endl;
+ proof::LFSCProofPrinter::printResolutions(d_resolutionProof.get(), os, paren);
+}
+
+} /* namespace proof */
+
+} /* namespace CVC4 */
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback