1 /********************* */
2 /*! \file proof_manager.cpp
4 ** Top contributors (to current version):
5 ** Guy Katz, Liana Hadarean, Andres Noetzli
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
8 ** in the top-level source directory) and their institutional affiliations.
9 ** All rights reserved. See the file COPYING in the top-level source
10 ** directory for licensing information.\endverbatim
12 ** [[ Add lengthier description here ]]
14 ** \todo document this file
18 #include "proof/proof_manager.h"
20 #include "base/cvc4_assert.h"
21 #include "context/context.h"
22 #include "options/bv_options.h"
23 #include "options/proof_options.h"
24 #include "proof/bitvector_proof.h"
25 #include "proof/clause_id.h"
26 #include "proof/cnf_proof.h"
27 #include "proof/proof_utils.h"
28 #include "proof/sat_proof_implementation.h"
29 #include "proof/theory_proof.h"
30 #include "smt/smt_engine.h"
31 #include "smt/smt_engine_scope.h"
32 #include "smt_util/node_visitor.h"
33 #include "theory/arrays/theory_arrays.h"
34 #include "theory/output_channel.h"
35 #include "theory/term_registration_visitor.h"
36 #include "theory/uf/equality_engine.h"
37 #include "theory/uf/theory_uf.h"
38 #include "theory/valuation.h"
39 #include "util/hash.h"
40 #include "util/proof.h"
44 std::string
nodeSetToString(const std::set
<Node
>& nodes
) {
45 std::ostringstream os
;
46 std::set
<Node
>::const_iterator it
;
47 for (it
= nodes
.begin(); it
!= nodes
.end(); ++it
) {
53 std::string
append(const std::string
& str
, uint64_t num
) {
54 std::ostringstream os
;
59 ProofManager::ProofManager(context::Context
* context
, ProofFormat format
)
65 d_inputCoreFormulas(context
),
66 d_outputCoreFormulas(context
),
74 ProofManager::~ProofManager() {
75 if (d_satProof
) delete d_satProof
;
76 if (d_cnfProof
) delete d_cnfProof
;
77 if (d_theoryProof
) delete d_theoryProof
;
80 ProofManager
* ProofManager::currentPM() {
81 return smt::currentProofManager();
83 const Proof
& ProofManager::getProof(SmtEngine
* smt
)
85 if (!currentPM()->d_fullProof
)
87 Assert(currentPM()->d_format
== LFSC
);
88 currentPM()->d_fullProof
.reset(new LFSCProof(
90 static_cast<LFSCCoreSatProof
*>(getSatProof()),
91 static_cast<LFSCCnfProof
*>(getCnfProof()),
92 static_cast<LFSCTheoryProofEngine
*>(getTheoryProofEngine())));
94 return *(currentPM()->d_fullProof
);
97 CoreSatProof
* ProofManager::getSatProof() {
98 Assert (currentPM()->d_satProof
);
99 return currentPM()->d_satProof
;
102 CnfProof
* ProofManager::getCnfProof() {
103 Assert (currentPM()->d_cnfProof
);
104 return currentPM()->d_cnfProof
;
107 TheoryProofEngine
* ProofManager::getTheoryProofEngine() {
108 Assert (currentPM()->d_theoryProof
!= NULL
);
109 return currentPM()->d_theoryProof
;
112 UFProof
* ProofManager::getUfProof() {
113 Assert (options::proof());
114 TheoryProof
* pf
= getTheoryProofEngine()->getTheoryProof(theory::THEORY_UF
);
118 BitVectorProof
* ProofManager::getBitVectorProof() {
119 Assert (options::proof());
120 TheoryProof
* pf
= getTheoryProofEngine()->getTheoryProof(theory::THEORY_BV
);
121 return (BitVectorProof
*)pf
;
124 ArrayProof
* ProofManager::getArrayProof() {
125 Assert (options::proof());
126 TheoryProof
* pf
= getTheoryProofEngine()->getTheoryProof(theory::THEORY_ARRAYS
);
127 return (ArrayProof
*)pf
;
130 ArithProof
* ProofManager::getArithProof() {
131 Assert (options::proof());
132 TheoryProof
* pf
= getTheoryProofEngine()->getTheoryProof(theory::THEORY_ARITH
);
133 return (ArithProof
*)pf
;
136 SkolemizationManager
* ProofManager::getSkolemizationManager() {
137 Assert (options::proof() || options::unsatCores());
138 return &(currentPM()->d_skolemizationManager
);
141 void ProofManager::initSatProof(Minisat::Solver
* solver
) {
142 Assert (currentPM()->d_satProof
== NULL
);
143 Assert(currentPM()->d_format
== LFSC
);
144 currentPM()->d_satProof
= new LFSCCoreSatProof(solver
, d_context
, "");
147 void ProofManager::initCnfProof(prop::CnfStream
* cnfStream
,
148 context::Context
* ctx
) {
149 ProofManager
* pm
= currentPM();
150 Assert (pm
->d_cnfProof
== NULL
);
151 Assert (pm
->d_format
== LFSC
);
152 CnfProof
* cnf
= new LFSCCnfProof(cnfStream
, ctx
, "");
153 pm
->d_cnfProof
= cnf
;
154 Assert(pm
-> d_satProof
!= NULL
);
155 pm
->d_satProof
->setCnfProof(cnf
);
157 // true and false have to be setup in a special way
158 Node true_node
= NodeManager::currentNM()->mkConst
<bool>(true);
159 Node false_node
= NodeManager::currentNM()->mkConst
<bool>(false).notNode();
161 pm
->d_cnfProof
->pushCurrentAssertion(true_node
);
162 pm
->d_cnfProof
->pushCurrentDefinition(true_node
);
163 pm
->d_cnfProof
->registerConvertedClause(pm
->d_satProof
->getTrueUnit());
164 pm
->d_cnfProof
->popCurrentAssertion();
165 pm
->d_cnfProof
->popCurrentDefinition();
167 pm
->d_cnfProof
->pushCurrentAssertion(false_node
);
168 pm
->d_cnfProof
->pushCurrentDefinition(false_node
);
169 pm
->d_cnfProof
->registerConvertedClause(pm
->d_satProof
->getFalseUnit());
170 pm
->d_cnfProof
->popCurrentAssertion();
171 pm
->d_cnfProof
->popCurrentDefinition();
175 void ProofManager::initTheoryProofEngine() {
176 Assert (currentPM()->d_theoryProof
== NULL
);
177 Assert (currentPM()->d_format
== LFSC
);
178 currentPM()->d_theoryProof
= new LFSCTheoryProofEngine();
181 std::string
ProofManager::getInputClauseName(ClauseId id
,
182 const std::string
& prefix
) {
183 return append(prefix
+".pb", id
);
186 std::string
ProofManager::getLemmaClauseName(ClauseId id
,
187 const std::string
& prefix
) {
188 return append(prefix
+".lemc", id
);
191 std::string
ProofManager::getLemmaName(ClauseId id
, const std::string
& prefix
) {
192 return append(prefix
+"lem", id
);
195 std::string
ProofManager::getLearntClauseName(ClauseId id
,
196 const std::string
& prefix
) {
197 return append(prefix
+".cl", id
);
199 std::string
ProofManager::getVarName(prop::SatVariable var
,
200 const std::string
& prefix
) {
201 return append(prefix
+".v", var
);
203 std::string
ProofManager::getAtomName(prop::SatVariable var
,
204 const std::string
& prefix
) {
205 return append(prefix
+".a", var
);
207 std::string
ProofManager::getLitName(prop::SatLiteral lit
,
208 const std::string
& prefix
) {
209 return append(prefix
+".l", lit
.toInt());
212 std::string
ProofManager::getPreprocessedAssertionName(Node node
,
213 const std::string
& prefix
) {
214 if (currentPM()->d_assertionFilters
.find(node
) != currentPM()->d_assertionFilters
.end()) {
215 return currentPM()->d_assertionFilters
[node
];
218 node
= node
.getKind() == kind::BITVECTOR_EAGER_ATOM
? node
[0] : node
;
219 return append(prefix
+".PA", node
.getId());
221 std::string
ProofManager::getAssertionName(Node node
,
222 const std::string
& prefix
) {
223 return append(prefix
+".A", node
.getId());
225 std::string
ProofManager::getInputFormulaName(const Expr
& expr
) {
226 return currentPM()->d_inputFormulaToName
[expr
];
229 std::string
ProofManager::getAtomName(TNode atom
,
230 const std::string
& prefix
) {
231 prop::SatLiteral lit
= currentPM()->d_cnfProof
->getLiteral(atom
);
232 Assert(!lit
.isNegated());
233 return getAtomName(lit
.getSatVariable(), prefix
);
236 std::string
ProofManager::getLitName(TNode lit
,
237 const std::string
& prefix
) {
238 std::string litName
= getLitName(currentPM()->d_cnfProof
->getLiteral(lit
), prefix
);
239 if (currentPM()->d_rewriteFilters
.find(litName
) != currentPM()->d_rewriteFilters
.end()) {
240 return currentPM()->d_rewriteFilters
[litName
];
246 bool ProofManager::hasLitName(TNode lit
) {
247 return currentPM()->d_cnfProof
->hasLiteral(lit
);
250 std::string
ProofManager::sanitize(TNode node
) {
251 Assert (node
.isVar() || node
.isConst());
253 std::string name
= node
.toString();
255 std::replace(name
.begin(), name
.end(), ' ', '_');
256 } else if (node
.isConst()) {
257 name
.erase(std::remove(name
.begin(), name
.end(), '('), name
.end());
258 name
.erase(std::remove(name
.begin(), name
.end(), ')'), name
.end());
259 name
.erase(std::remove(name
.begin(), name
.end(), ' '), name
.end());
260 name
= "const" + name
;
266 void ProofManager::traceDeps(TNode n
, ExprSet
* coreAssertions
) {
267 Debug("cores") << "trace deps " << n
<< std::endl
;
268 if ((n
.isConst() && n
== NodeManager::currentNM()->mkConst
<bool>(true)) ||
269 (n
.getKind() == kind::NOT
&& n
[0] == NodeManager::currentNM()->mkConst
<bool>(false))) {
272 if(d_inputCoreFormulas
.find(n
.toExpr()) != d_inputCoreFormulas
.end()) {
273 // originating formula was in core set
274 Debug("cores") << " -- IN INPUT CORE LIST!" << std::endl
;
275 coreAssertions
->insert(n
.toExpr());
277 Debug("cores") << " -- NOT IN INPUT CORE LIST!" << std::endl
;
278 if(d_deps
.find(n
) == d_deps
.end()) {
279 if (options::allowEmptyDependencies()) {
280 Debug("cores") << " -- Could not track cause assertion. Failing silently." << std::endl
;
283 InternalError("Cannot trace dependence information back to input assertion:\n`%s'", n
.toString().c_str());
285 Assert(d_deps
.find(n
) != d_deps
.end());
286 std::vector
<Node
> deps
= (*d_deps
.find(n
)).second
;
287 for(std::vector
<Node
>::const_iterator i
= deps
.begin(); i
!= deps
.end(); ++i
) {
288 Debug("cores") << " + tracing deps: " << n
<< " -deps-on- " << *i
<< std::endl
;
289 if( !(*i
).isNull() ){
290 traceDeps(*i
, coreAssertions
);
296 void ProofManager::traceDeps(TNode n
, CDExprSet
* coreAssertions
) {
297 Debug("cores") << "trace deps " << n
<< std::endl
;
298 if ((n
.isConst() && n
== NodeManager::currentNM()->mkConst
<bool>(true)) ||
299 (n
.getKind() == kind::NOT
&& n
[0] == NodeManager::currentNM()->mkConst
<bool>(false))) {
302 if(d_inputCoreFormulas
.find(n
.toExpr()) != d_inputCoreFormulas
.end()) {
303 // originating formula was in core set
304 Debug("cores") << " -- IN INPUT CORE LIST!" << std::endl
;
305 coreAssertions
->insert(n
.toExpr());
307 Debug("cores") << " -- NOT IN INPUT CORE LIST!" << std::endl
;
308 if(d_deps
.find(n
) == d_deps
.end()) {
309 if (options::allowEmptyDependencies()) {
310 Debug("cores") << " -- Could not track cause assertion. Failing silently." << std::endl
;
313 InternalError("Cannot trace dependence information back to input assertion:\n`%s'", n
.toString().c_str());
315 Assert(d_deps
.find(n
) != d_deps
.end());
316 std::vector
<Node
> deps
= (*d_deps
.find(n
)).second
;
318 for(std::vector
<Node
>::const_iterator i
= deps
.begin(); i
!= deps
.end(); ++i
) {
319 Debug("cores") << " + tracing deps: " << n
<< " -deps-on- " << *i
<< std::endl
;
320 if( !(*i
).isNull() ){
321 traceDeps(*i
, coreAssertions
);
327 void ProofManager::traceUnsatCore() {
328 Assert (options::unsatCores());
329 d_satProof
->refreshProof();
330 IdToSatClause used_lemmas
;
331 IdToSatClause used_inputs
;
332 d_satProof
->collectClausesUsed(used_inputs
,
335 // At this point, there should be no assertions without a clause id
336 Assert(d_cnfProof
->isAssertionStackEmpty());
338 IdToSatClause::const_iterator it
= used_inputs
.begin();
339 for(; it
!= used_inputs
.end(); ++it
) {
340 Node node
= d_cnfProof
->getAssertionForClause(it
->first
);
341 ProofRule rule
= d_cnfProof
->getProofRule(node
);
343 Debug("cores") << "core input assertion " << node
<< std::endl
;
344 Debug("cores") << "with proof rule " << rule
<< std::endl
;
345 if (rule
== RULE_TSEITIN
||
346 rule
== RULE_GIVEN
) {
347 // trace dependences back to actual assertions
348 // (this adds them to the unsat core)
349 traceDeps(node
, &d_outputCoreFormulas
);
354 bool ProofManager::unsatCoreAvailable() const {
355 return d_satProof
->derivedEmptyClause();
358 std::vector
<Expr
> ProofManager::extractUnsatCore() {
359 std::vector
<Expr
> result
;
360 output_core_iterator it
= begin_unsat_core();
361 output_core_iterator end
= end_unsat_core();
362 while ( it
!= end
) {
363 result
.push_back(*it
);
369 void ProofManager::constructSatProof() {
370 if (!d_satProof
->proofConstructed()) {
371 d_satProof
->constructProof();
375 void ProofManager::getLemmasInUnsatCore(theory::TheoryId theory
, std::vector
<Node
> &lemmas
) {
376 Assert(PROOF_ON(), "Cannot compute unsat core when proofs are off");
377 Assert(unsatCoreAvailable(), "Cannot get unsat core at this time. Mabye the input is SAT?" );
381 IdToSatClause used_lemmas
;
382 IdToSatClause used_inputs
;
383 d_satProof
->collectClausesUsed(used_inputs
, used_lemmas
);
385 IdToSatClause::const_iterator it
;
388 Debug("pf::lemmasUnsatCore") << "Dumping all lemmas in unsat core" << std::endl
;
389 for (it
= used_lemmas
.begin(); it
!= used_lemmas
.end(); ++it
) {
390 std::set
<Node
> lemma
= satClauseToNodeSet(it
->second
);
391 Debug("pf::lemmasUnsatCore") << nodeSetToString(lemma
);
393 // TODO: we should be able to drop the "haveProofRecipe" check.
394 // however, there are some rewrite issues with the arith solver, resulting
395 // in non-registered recipes. For now we assume no one is requesting arith lemmas.
396 LemmaProofRecipe recipe
;
397 if (!getCnfProof()->haveProofRecipe(lemma
)) {
398 Debug("pf::lemmasUnsatCore") << "\t[no recipe]" << std::endl
;
402 recipe
= getCnfProof()->getProofRecipe(lemma
);
403 Debug("pf::lemmasUnsatCore") << "\t[owner = " << recipe
.getTheory()
404 << ", original = " << recipe
.getOriginalLemma() << "]" << std::endl
;
405 if (recipe
.simpleLemma() && recipe
.getTheory() == theory
&& seen
.find(recipe
.getOriginalLemma()) == seen
.end()) {
406 lemmas
.push_back(recipe
.getOriginalLemma());
407 seen
.insert(recipe
.getOriginalLemma());
412 std::set
<Node
> ProofManager::satClauseToNodeSet(prop::SatClause
* clause
) {
413 std::set
<Node
> result
;
414 for (unsigned i
= 0; i
< clause
->size(); ++i
) {
415 prop::SatLiteral lit
= (*clause
)[i
];
416 Node node
= getCnfProof()->getAtom(lit
.getSatVariable());
417 Expr atom
= node
.toExpr();
418 if (atom
!= utils::mkTrue())
419 result
.insert(lit
.isNegated() ? node
.notNode() : node
);
425 Node
ProofManager::getWeakestImplicantInUnsatCore(Node lemma
) {
426 Assert(PROOF_ON(), "Cannot compute unsat core when proofs are off");
427 Assert(unsatCoreAvailable(), "Cannot get unsat core at this time. Mabye the input is SAT?" );
429 // If we're doing aggressive minimization, work on all lemmas, not just conjunctions.
430 if (!options::aggressiveCoreMin() && (lemma
.getKind() != kind::AND
))
435 NodeBuilder
<> builder(kind::AND
);
437 IdToSatClause used_lemmas
;
438 IdToSatClause used_inputs
;
439 d_satProof
->collectClausesUsed(used_inputs
, used_lemmas
);
441 IdToSatClause::const_iterator it
;
442 std::set
<Node
>::iterator lemmaIt
;
444 if (!options::aggressiveCoreMin()) {
445 for (it
= used_lemmas
.begin(); it
!= used_lemmas
.end(); ++it
) {
446 std::set
<Node
> currentLemma
= satClauseToNodeSet(it
->second
);
448 // TODO: we should be able to drop the "haveProofRecipe" check.
449 // however, there are some rewrite issues with the arith solver, resulting
450 // in non-registered recipes. For now we assume no one is requesting arith lemmas.
451 LemmaProofRecipe recipe
;
452 if (!getCnfProof()->haveProofRecipe(currentLemma
))
455 recipe
= getCnfProof()->getProofRecipe(currentLemma
);
456 if (recipe
.getOriginalLemma() == lemma
) {
457 for (lemmaIt
= currentLemma
.begin(); lemmaIt
!= currentLemma
.end(); ++lemmaIt
) {
460 // Check that each conjunct appears in the original lemma.
462 for (unsigned i
= 0; i
< lemma
.getNumChildren(); ++i
) {
463 if (lemma
[i
] == *lemmaIt
)
474 for (it
= used_lemmas
.begin(); it
!= used_lemmas
.end(); ++it
) {
475 std::set
<Node
> currentLemma
= satClauseToNodeSet(it
->second
);
477 // TODO: we should be able to drop the "haveProofRecipe" check.
478 // however, there are some rewrite issues with the arith solver, resulting
479 // in non-registered recipes. For now we assume no one is requesting arith lemmas.
480 LemmaProofRecipe recipe
;
481 if (!getCnfProof()->haveProofRecipe(currentLemma
))
484 recipe
= getCnfProof()->getProofRecipe(currentLemma
);
485 if (recipe
.getOriginalLemma() == lemma
) {
486 NodeBuilder
<> disjunction(kind::OR
);
487 for (lemmaIt
= currentLemma
.begin(); lemmaIt
!= currentLemma
.end(); ++lemmaIt
) {
488 disjunction
<< *lemmaIt
;
491 Node conjunct
= (disjunction
.getNumChildren() == 1) ? disjunction
[0] : disjunction
;
497 AlwaysAssert(builder
.getNumChildren() != 0);
499 if (builder
.getNumChildren() == 1)
505 void ProofManager::addAssertion(Expr formula
) {
506 Debug("proof:pm") << "assert: " << formula
<< std::endl
;
507 d_inputFormulas
.insert(formula
);
508 std::ostringstream name
;
509 name
<< "A" << d_inputFormulaToName
.size();
510 d_inputFormulaToName
[formula
] = name
.str();
513 void ProofManager::addCoreAssertion(Expr formula
) {
514 Debug("cores") << "assert: " << formula
<< std::endl
;
515 d_deps
[Node::fromExpr(formula
)]; // empty vector of deps
516 d_inputCoreFormulas
.insert(formula
);
519 void ProofManager::addDependence(TNode n
, TNode dep
) {
521 Debug("cores") << "dep: " << n
<< " : " << dep
<< std::endl
;
522 if( !dep
.isNull() && d_deps
.find(dep
) == d_deps
.end()) {
523 Debug("cores") << "WHERE DID " << dep
<< " come from ??" << std::endl
;
525 std::vector
<Node
> deps
= d_deps
[n
].get();
531 void ProofManager::addUnsatCore(Expr formula
) {
532 Assert (d_inputCoreFormulas
.find(formula
) != d_inputCoreFormulas
.end());
533 d_outputCoreFormulas
.insert(formula
);
536 void ProofManager::addAssertionFilter(const Node
& node
, const std::string
& rewritten
) {
537 d_assertionFilters
[node
] = rewritten
;
540 void ProofManager::setLogic(const LogicInfo
& logic
) {
546 LFSCProof::LFSCProof(SmtEngine
* smtEngine
,
547 LFSCCoreSatProof
* sat
,
549 LFSCTheoryProofEngine
* theory
)
552 , d_theoryProof(theory
)
553 , d_smtEngine(smtEngine
)
556 void LFSCProof::toStream(std::ostream
& out
, const ProofLetMap
& map
) const
561 void LFSCProof::toStream(std::ostream
& out
) const
563 Assert(options::bitblastMode() != theory::bv::BITBLAST_MODE_EAGER
);
565 Assert(!d_satProof
->proofConstructed());
566 d_satProof
->constructProof();
568 // collecting leaf clauses in resolution proof
569 IdToSatClause used_lemmas
;
570 IdToSatClause used_inputs
;
571 d_satProof
->collectClausesUsed(used_inputs
,
574 IdToSatClause::iterator it2
;
575 Debug("pf::pm") << std::endl
<< "Used inputs: " << std::endl
;
576 for (it2
= used_inputs
.begin(); it2
!= used_inputs
.end(); ++it2
) {
577 Debug("pf::pm") << "\t input = " << *(it2
->second
) << std::endl
;
579 Debug("pf::pm") << std::endl
;
581 // Debug("pf::pm") << std::endl << "Used lemmas: " << std::endl;
582 // for (it2 = used_lemmas.begin(); it2 != used_lemmas.end(); ++it2) {
583 // Debug("pf::pm") << "\t lemma = " << *(it2->second) << std::endl;
585 // Debug("pf::pm") << std::endl;
586 Debug("pf::pm") << std::endl
<< "Used lemmas: " << std::endl
;
587 for (it2
= used_lemmas
.begin(); it2
!= used_lemmas
.end(); ++it2
) {
589 std::vector
<Expr
> clause_expr
;
590 for(unsigned i
= 0; i
< it2
->second
->size(); ++i
) {
591 prop::SatLiteral lit
= (*(it2
->second
))[i
];
592 Expr atom
= d_cnfProof
->getAtom(lit
.getSatVariable()).toExpr();
593 if (atom
.isConst()) {
594 Assert (atom
== utils::mkTrue());
597 Expr expr_lit
= lit
.isNegated() ? atom
.notExpr(): atom
;
598 clause_expr
.push_back(expr_lit
);
601 Debug("pf::pm") << "\t lemma " << it2
->first
<< " = " << *(it2
->second
) << std::endl
;
602 Debug("pf::pm") << "\t";
603 for (unsigned i
= 0; i
< clause_expr
.size(); ++i
) {
604 Debug("pf::pm") << clause_expr
[i
] << " ";
606 Debug("pf::pm") << std::endl
;
608 Debug("pf::pm") << std::endl
;
610 // collecting assertions that lead to the clauses being asserted
611 NodeSet used_assertions
;
612 d_cnfProof
->collectAssertionsForClauses(used_inputs
, used_assertions
);
614 NodeSet::iterator it3
;
615 Debug("pf::pm") << std::endl
<< "Used assertions: " << std::endl
;
616 for (it3
= used_assertions
.begin(); it3
!= used_assertions
.end(); ++it3
)
617 Debug("pf::pm") << "\t assertion = " << *it3
<< std::endl
;
619 std::set
<Node
> atoms
;
621 NodePairSet rewrites
;
622 // collects the atoms in the clauses
623 d_cnfProof
->collectAtomsAndRewritesForLemmas(used_lemmas
, atoms
, rewrites
);
625 if (!rewrites
.empty()) {
626 Debug("pf::pm") << std::endl
<< "Rewrites used in lemmas: " << std::endl
;
627 NodePairSet::const_iterator rewriteIt
;
628 for (rewriteIt
= rewrites
.begin(); rewriteIt
!= rewrites
.end(); ++rewriteIt
) {
629 Debug("pf::pm") << "\t" << rewriteIt
->first
<< " --> " << rewriteIt
->second
<< std::endl
;
631 Debug("pf::pm") << std::endl
<< "Rewrite printing done" << std::endl
;
633 Debug("pf::pm") << "No rewrites in lemmas found" << std::endl
;
636 // The derived/unrewritten atoms may not have CNF literals required later on.
637 // If they don't, add them.
638 std::set
<Node
>::const_iterator it
;
639 for (it
= atoms
.begin(); it
!= atoms
.end(); ++it
) {
640 Debug("pf::pm") << "Ensure literal for atom: " << *it
<< std::endl
;
641 if (!d_cnfProof
->hasLiteral(*it
)) {
642 // For arithmetic: these literals are not normalized, causing an error in Arith.
643 if (theory::Theory::theoryOf(*it
) == theory::THEORY_ARITH
) {
644 d_cnfProof
->ensureLiteral(*it
, true); // This disables preregistration with the theory solver.
646 d_cnfProof
->ensureLiteral(*it
); // Normal method, with theory solver preregisteration.
651 d_cnfProof
->collectAtomsForClauses(used_inputs
, atoms
);
652 d_cnfProof
->collectAtomsForClauses(used_lemmas
, atoms
);
654 // collects the atoms in the assertions
655 for (NodeSet::const_iterator it
= used_assertions
.begin();
656 it
!= used_assertions
.end(); ++it
) {
657 utils::collectAtoms(*it
, atoms
);
658 // utils::collectAtoms(*it, newAtoms);
661 std::set
<Node
>::iterator atomIt
;
662 Debug("pf::pm") << std::endl
<< "Dumping atoms from lemmas, inputs and assertions: "
663 << std::endl
<< std::endl
;
664 for (atomIt
= atoms
.begin(); atomIt
!= atoms
.end(); ++atomIt
) {
665 Debug("pf::pm") << "\tAtom: " << *atomIt
<< std::endl
;
667 smt::SmtScope
scope(d_smtEngine
);
668 std::ostringstream paren
;
671 out
<< " ;; Declarations\n";
673 // declare the theory atoms
674 Debug("pf::pm") << "LFSCProof::toStream: registering terms:" << std::endl
;
675 for(it
= atoms
.begin(); it
!= atoms
.end(); ++it
) {
676 Debug("pf::pm") << "\tTerm: " << (*it
).toExpr() << std::endl
;
677 d_theoryProof
->registerTerm((*it
).toExpr());
680 Debug("pf::pm") << std::endl
<< "Term registration done!" << std::endl
<< std::endl
;
682 Debug("pf::pm") << std::endl
<< "LFSCProof::toStream: starting to print assertions" << std::endl
;
684 // print out all the original assertions
685 d_theoryProof
->registerTermsFromAssertions();
686 d_theoryProof
->printSortDeclarations(out
, paren
);
687 d_theoryProof
->printTermDeclarations(out
, paren
);
688 d_theoryProof
->printAssertions(out
, paren
);
690 Debug("pf::pm") << std::endl
<< "LFSCProof::toStream: print assertions DONE" << std::endl
;
692 out
<< "(: (holds cln)\n\n";
695 // Have the theory proofs print deferred declarations, e.g. for skolem variables.
696 out
<< " ;; Printing deferred declarations \n\n";
697 d_theoryProof
->printDeferredDeclarations(out
, paren
);
699 out
<< "\n ;; Printing the global let map";
700 d_theoryProof
->finalizeBvConflicts(used_lemmas
, out
);
701 ProofManager::getBitVectorProof()->calculateAtomsInBitblastingProof();
702 ProofLetMap globalLetMap
;
703 if (options::lfscLetification()) {
704 ProofManager::currentPM()->printGlobalLetMap(atoms
, globalLetMap
, out
, paren
);
707 out
<< " ;; Printing aliasing declarations \n\n";
708 d_theoryProof
->printAliasingDeclarations(out
, paren
, globalLetMap
);
710 out
<< " ;; Rewrites for Lemmas \n";
711 d_theoryProof
->printLemmaRewrites(rewrites
, out
, paren
);
713 // print trust that input assertions are their preprocessed form
714 printPreprocessedAssertions(used_assertions
, out
, paren
, globalLetMap
);
716 // print mapping between theory atoms and internal SAT variables
717 out
<< ";; Printing mapping from preprocessed assertions into atoms \n";
718 d_cnfProof
->printAtomMapping(atoms
, out
, paren
, globalLetMap
);
720 Debug("pf::pm") << std::endl
<< "Printing cnf proof for clauses" << std::endl
;
722 IdToSatClause::const_iterator cl_it
= used_inputs
.begin();
723 // print CNF conversion proof for each clause
724 for (; cl_it
!= used_inputs
.end(); ++cl_it
) {
725 d_cnfProof
->printCnfProofForClause(cl_it
->first
, cl_it
->second
, out
, paren
);
728 Debug("pf::pm") << std::endl
<< "Printing cnf proof for clauses DONE" << std::endl
;
730 Debug("pf::pm") << "Proof manager: printing theory lemmas" << std::endl
;
731 d_theoryProof
->printTheoryLemmas(used_lemmas
, out
, paren
, globalLetMap
);
732 Debug("pf::pm") << "Proof manager: printing theory lemmas DONE!" << std::endl
;
734 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER
&& ProofManager::getBitVectorProof()) {
735 ProofManager::getBitVectorProof()->getSatProof()->printResolutionEmptyClause(out
, paren
);
737 // print actual resolution proof
738 d_satProof
->printResolutions(out
, paren
);
739 d_satProof
->printResolutionEmptyClause(out
, paren
);
746 void LFSCProof::printPreprocessedAssertions(const NodeSet
& assertions
,
749 ProofLetMap
& globalLetMap
) const
751 os
<< "\n ;; In the preprocessor we trust \n";
752 NodeSet::const_iterator it
= assertions
.begin();
753 NodeSet::const_iterator end
= assertions
.end();
755 Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions starting" << std::endl
;
757 if (options::fewerPreprocessingHoles()) {
758 // Check for assertions that did not get rewritten, and update the printing filter.
759 checkUnrewrittenAssertion(assertions
);
761 // For the remaining assertions, bind them to input assertions.
762 for (; it
!= end
; ++it
) {
763 // Rewrite preprocessing step if it cannot be eliminated
764 if (!ProofManager::currentPM()->have_input_assertion((*it
).toExpr())) {
765 os
<< "(th_let_pf _ (trust_f (iff ";
769 if (((*it
).isConst() && *it
== NodeManager::currentNM()->mkConst
<bool>(true)) ||
770 ((*it
).getKind() == kind::NOT
&& (*it
)[0] == NodeManager::currentNM()->mkConst
<bool>(false))) {
771 inputAssertion
= NodeManager::currentNM()->mkConst
<bool>(true).toExpr();
773 // Figure out which input assertion led to this assertion
774 ExprSet inputAssertions
;
775 ProofManager::currentPM()->traceDeps(*it
, &inputAssertions
);
777 Debug("pf::pm") << "Original assertions for " << *it
<< " are: " << std::endl
;
779 ProofManager::assertions_iterator assertionIt
;
780 for (assertionIt
= inputAssertions
.begin(); assertionIt
!= inputAssertions
.end(); ++assertionIt
) {
781 Debug("pf::pm") << "\t" << *assertionIt
<< std::endl
;
784 if (inputAssertions
.size() == 0) {
785 Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions: Count NOT find the assertion that caused this PA. Picking an arbitrary one..." << std::endl
;
786 // For now just use the first assertion...
787 inputAssertion
= *(ProofManager::currentPM()->begin_assertions());
789 if (inputAssertions
.size() != 1) {
790 Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions: Attention: more than one original assertion was found. Picking just one." << std::endl
;
792 inputAssertion
= *inputAssertions
.begin();
796 if (!ProofManager::currentPM()->have_input_assertion(inputAssertion
)) {
797 // The thing returned by traceDeps does not appear in the input assertions...
798 Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions: Count NOT find the assertion that caused this PA. Picking an arbitrary one..." << std::endl
;
799 // For now just use the first assertion...
800 inputAssertion
= *(ProofManager::currentPM()->begin_assertions());
803 Debug("pf::pm") << "Original assertion for " << *it
807 << ProofManager::currentPM()->getInputFormulaName(inputAssertion
)
810 ProofManager::currentPM()->getTheoryProofEngine()->printTheoryTerm(inputAssertion
, os
, globalLetMap
);
812 ProofManager::currentPM()->getTheoryProofEngine()->printTheoryTerm((*it
).toExpr(), os
, globalLetMap
);
815 os
<< "(\\ "<< ProofManager::getPreprocessedAssertionName(*it
, "") << "\n";
818 std::ostringstream rewritten
;
820 rewritten
<< "(or_elim_1 _ _ ";
821 rewritten
<< "(not_not_intro _ ";
822 rewritten
<< ProofManager::currentPM()->getInputFormulaName(inputAssertion
);
823 rewritten
<< ") (iff_elim_1 _ _ ";
824 rewritten
<< ProofManager::getPreprocessedAssertionName(*it
, "");
827 ProofManager::currentPM()->addAssertionFilter(*it
, rewritten
.str());
831 for (; it
!= end
; ++it
) {
832 os
<< "(th_let_pf _ ";
836 if (ProofManager::currentPM()->getTheoryProofEngine()->printsAsBool(*it
)) os
<< "(p_app ";
837 ProofManager::currentPM()->getTheoryProofEngine()->printTheoryTerm((*it
).toExpr(), os
, globalLetMap
);
838 if (ProofManager::currentPM()->getTheoryProofEngine()->printsAsBool(*it
)) os
<< ")";
841 os
<< "(\\ "<< ProofManager::getPreprocessedAssertionName(*it
, "") << "\n";
849 void LFSCProof::checkUnrewrittenAssertion(const NodeSet
& rewrites
) const
851 Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion starting" << std::endl
;
853 NodeSet::const_iterator rewrite
;
854 for (rewrite
= rewrites
.begin(); rewrite
!= rewrites
.end(); ++rewrite
) {
855 Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion: handling " << *rewrite
<< std::endl
;
856 if (ProofManager::currentPM()->have_input_assertion((*rewrite
).toExpr())) {
857 Assert(ProofManager::currentPM()->have_input_assertion((*rewrite
).toExpr()));
858 Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion: this assertion was NOT rewritten!" << std::endl
859 << "\tAdding filter: "
860 << ProofManager::getPreprocessedAssertionName(*rewrite
, "")
862 << ProofManager::currentPM()->getInputFormulaName((*rewrite
).toExpr())
864 ProofManager::currentPM()->addAssertionFilter(*rewrite
,
865 ProofManager::currentPM()->getInputFormulaName((*rewrite
).toExpr()));
867 Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion: this assertion WAS rewritten! " << *rewrite
<< std::endl
;
874 bool ProofManager::hasOp(TNode n
) const {
875 return d_bops
.find(n
) != d_bops
.end();
878 Node
ProofManager::lookupOp(TNode n
) const {
879 std::map
<Node
, Node
>::const_iterator i
= d_bops
.find(n
);
880 Assert(i
!= d_bops
.end());
884 Node
ProofManager::mkOp(TNode n
) {
885 Trace("mgd-pm-mkop") << "MkOp : " << n
<< " " << n
.getKind() << std::endl
;
886 if(n
.getKind() != kind::BUILTIN
) {
892 Assert((n
.getConst
<Kind
>() == kind::SELECT
) || (n
.getConst
<Kind
>() == kind::STORE
));
894 Debug("mgd-pm-mkop") << "making an op for " << n
<< "\n";
896 std::stringstream ss
;
898 std::string s
= ss
.str();
899 Debug("mgd-pm-mkop") << " : " << s
<< std::endl
;
900 std::vector
<TypeNode
> v
;
901 v
.push_back(NodeManager::currentNM()->integerType());
902 if(n
.getConst
<Kind
>() == kind::SELECT
) {
903 v
.push_back(NodeManager::currentNM()->integerType());
904 v
.push_back(NodeManager::currentNM()->integerType());
905 } else if(n
.getConst
<Kind
>() == kind::STORE
) {
906 v
.push_back(NodeManager::currentNM()->integerType());
907 v
.push_back(NodeManager::currentNM()->integerType());
908 v
.push_back(NodeManager::currentNM()->integerType());
910 TypeNode type
= NodeManager::currentNM()->mkFunctionType(v
);
911 Debug("mgd-pm-mkop") << "typenode is: " << type
<< "\n";
912 op
= NodeManager::currentNM()->mkSkolem(s
, type
, " ignore", NodeManager::SKOLEM_NO_NOTIFY
);
915 Debug("mgd-pm-mkop") << "returning the op: " << op
<< "\n";
918 //---end from Morgan---
920 bool ProofManager::wasPrinted(const Type
& type
) const {
921 return d_printedTypes
.find(type
) != d_printedTypes
.end();
924 void ProofManager::markPrinted(const Type
& type
) {
925 d_printedTypes
.insert(type
);
928 void ProofManager::addRewriteFilter(const std::string
&original
, const std::string
&substitute
) {
929 d_rewriteFilters
[original
] = substitute
;
932 bool ProofManager::haveRewriteFilter(TNode lit
) {
933 std::string litName
= getLitName(currentPM()->d_cnfProof
->getLiteral(lit
));
934 return d_rewriteFilters
.find(litName
) != d_rewriteFilters
.end();
937 void ProofManager::clearRewriteFilters() {
938 d_rewriteFilters
.clear();
941 std::ostream
& operator<<(std::ostream
& out
, CVC4::ProofRule k
) {
947 out
<< "RULE_DERIVED";
949 case RULE_RECONSTRUCT
:
950 out
<< "RULE_RECONSTRUCT";
956 out
<< "RULE_INVALID";
959 out
<< "RULE_CONFLICT";
962 out
<< "RULE_TSEITIN";
967 case RULE_ARRAYS_EXT
:
968 out
<< "RULE_ARRAYS";
970 case RULE_ARRAYS_ROW
:
971 out
<< "RULE_ARRAYS";
974 out
<< "ProofRule Unknown! [" << unsigned(k
) << "]";
980 void ProofManager::registerRewrite(unsigned ruleId
, Node original
, Node result
){
981 Assert (currentPM()->d_theoryProof
!= NULL
);
982 currentPM()->d_rewriteLog
.push_back(RewriteLogEntry(ruleId
, original
, result
));
985 void ProofManager::clearRewriteLog() {
986 Assert (currentPM()->d_theoryProof
!= NULL
);
987 currentPM()->d_rewriteLog
.clear();
990 std::vector
<RewriteLogEntry
> ProofManager::getRewriteLog() {
991 return currentPM()->d_rewriteLog
;
994 void ProofManager::dumpRewriteLog() const {
995 Debug("pf::rr") << "Dumpign rewrite log:" << std::endl
;
997 for (unsigned i
= 0; i
< d_rewriteLog
.size(); ++i
) {
998 Debug("pf::rr") << "\tRule " << d_rewriteLog
[i
].getRuleId()
1000 << d_rewriteLog
[i
].getOriginal()
1002 << d_rewriteLog
[i
].getResult() << std::endl
;
1006 void bind(Expr term
, ProofLetMap
& map
, Bindings
& letOrder
) {
1007 ProofLetMap::iterator it
= map
.find(term
);
1008 if (it
!= map
.end())
1011 for (unsigned i
= 0; i
< term
.getNumChildren(); ++i
)
1012 bind(term
[i
], map
, letOrder
);
1014 // Special case: chain operators. If we have and(a,b,c), it will be prineted as and(a,and(b,c)).
1015 // The subterm and(b,c) may repeat elsewhere, so we need to bind it, too.
1016 Kind k
= term
.getKind();
1017 if (((k
== kind::OR
) || (k
== kind::AND
)) && term
.getNumChildren() > 2) {
1018 Node currentExpression
= term
[term
.getNumChildren() - 1];
1019 for (int i
= term
.getNumChildren() - 2; i
>= 0; --i
) {
1020 NodeBuilder
<> builder(k
);
1022 builder
<< currentExpression
.toExpr();
1023 currentExpression
= builder
;
1024 bind(currentExpression
.toExpr(), map
, letOrder
);
1027 unsigned newId
= ProofLetCount::newId();
1028 ProofLetCount
letCount(newId
);
1029 map
[term
] = letCount
;
1030 letOrder
.push_back(LetOrderElement(term
, newId
));
1034 void ProofManager::printGlobalLetMap(std::set
<Node
>& atoms
,
1035 ProofLetMap
& letMap
,
1037 std::ostringstream
& paren
) {
1039 std::set
<Node
>::const_iterator atom
;
1040 for (atom
= atoms
.begin(); atom
!= atoms
.end(); ++atom
) {
1041 bind(atom
->toExpr(), letMap
, letOrder
);
1044 // TODO: give each theory a chance to add atoms. For now, just query BV directly...
1045 const std::set
<Node
>* additionalAtoms
= ProofManager::getBitVectorProof()->getAtomsInBitblastingProof();
1046 for (atom
= additionalAtoms
->begin(); atom
!= additionalAtoms
->end(); ++atom
) {
1047 bind(atom
->toExpr(), letMap
, letOrder
);
1050 for (unsigned i
= 0; i
< letOrder
.size(); ++i
) {
1051 Expr currentExpr
= letOrder
[i
].expr
;
1052 unsigned letId
= letOrder
[i
].id
;
1053 ProofLetMap::iterator it
= letMap
.find(currentExpr
);
1054 Assert(it
!= letMap
.end());
1055 out
<< "\n(@ let" << letId
<< " ";
1056 d_theoryProof
->printBoundTerm(currentExpr
, out
, letMap
);
1058 it
->second
.increment();
1061 out
<< std::endl
<< std::endl
;
1064 void ProofManager::ensureLiteral(Node node
) {
1065 d_cnfProof
->ensureLiteral(node
);
1068 } /* CVC4 namespace */