1 /********************* */
2 /*! \file proof_manager.cpp
3 ** \verbatim
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-2019 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
11 **
12 ** [[ Add lengthier description here ]]
13
14 ** \todo document this file
15
16 **/
17
18 #include "proof/proof_manager.h"
19
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/clause_id.h"
25 #include "proof/cnf_proof.h"
26 #include "proof/lfsc_proof_printer.h"
27 #include "proof/proof_utils.h"
28 #include "proof/resolution_bitvector_proof.h"
29 #include "proof/sat_proof_implementation.h"
30 #include "proof/theory_proof.h"
31 #include "smt/smt_engine.h"
32 #include "smt/smt_engine_scope.h"
33 #include "smt/smt_statistics_registry.h"
34 #include "smt_util/node_visitor.h"
35 #include "theory/arrays/theory_arrays.h"
36 #include "theory/output_channel.h"
37 #include "theory/term_registration_visitor.h"
38 #include "theory/uf/equality_engine.h"
39 #include "theory/uf/theory_uf.h"
40 #include "theory/valuation.h"
41 #include "util/hash.h"
42 #include "util/proof.h"
43
44 namespace CVC4 {
45
nodeSetToString(const std::set<Node> & nodes)46 std::string nodeSetToString(const std::set<Node>& nodes) {
47 std::ostringstream os;
48 std::set<Node>::const_iterator it;
49 for (it = nodes.begin(); it != nodes.end(); ++it) {
50 os << *it << " ";
51 }
52 return os.str();
53 }
54
append(const std::string & str,uint64_t num)55 std::string append(const std::string& str, uint64_t num) {
56 std::ostringstream os;
57 os << str << num;
58 return os.str();
59 }
60
ProofManager(context::Context * context,ProofFormat format)61 ProofManager::ProofManager(context::Context* context, ProofFormat format)
62 : d_context(context),
63 d_satProof(NULL),
64 d_cnfProof(NULL),
65 d_theoryProof(NULL),
66 d_inputFormulas(),
67 d_inputCoreFormulas(context),
68 d_outputCoreFormulas(context),
69 d_nextId(0),
70 d_fullProof(),
71 d_format(format),
72 d_deps(context)
73 {
74 }
75
~ProofManager()76 ProofManager::~ProofManager() {
77 if (d_satProof) delete d_satProof;
78 if (d_cnfProof) delete d_cnfProof;
79 if (d_theoryProof) delete d_theoryProof;
80 }
81
currentPM()82 ProofManager* ProofManager::currentPM() {
83 return smt::currentProofManager();
84 }
getProof(SmtEngine * smt)85 const Proof& ProofManager::getProof(SmtEngine* smt)
86 {
87 if (!currentPM()->d_fullProof)
88 {
89 Assert(currentPM()->d_format == LFSC);
90 currentPM()->d_fullProof.reset(new LFSCProof(
91 smt,
92 static_cast<CoreSatProof*>(getSatProof()),
93 static_cast<LFSCCnfProof*>(getCnfProof()),
94 static_cast<LFSCTheoryProofEngine*>(getTheoryProofEngine())));
95 }
96 return *(currentPM()->d_fullProof);
97 }
98
getSatProof()99 CoreSatProof* ProofManager::getSatProof() {
100 Assert (currentPM()->d_satProof);
101 return currentPM()->d_satProof;
102 }
103
getCnfProof()104 CnfProof* ProofManager::getCnfProof() {
105 Assert (currentPM()->d_cnfProof);
106 return currentPM()->d_cnfProof;
107 }
108
getTheoryProofEngine()109 TheoryProofEngine* ProofManager::getTheoryProofEngine() {
110 Assert (currentPM()->d_theoryProof != NULL);
111 return currentPM()->d_theoryProof;
112 }
113
getUfProof()114 UFProof* ProofManager::getUfProof() {
115 Assert (options::proof());
116 TheoryProof* pf = getTheoryProofEngine()->getTheoryProof(theory::THEORY_UF);
117 return (UFProof*)pf;
118 }
119
getBitVectorProof()120 proof::ResolutionBitVectorProof* ProofManager::getBitVectorProof()
121 {
122 Assert (options::proof());
123 TheoryProof* pf = getTheoryProofEngine()->getTheoryProof(theory::THEORY_BV);
124 return static_cast<proof::ResolutionBitVectorProof*>(pf);
125 }
126
getArrayProof()127 ArrayProof* ProofManager::getArrayProof() {
128 Assert (options::proof());
129 TheoryProof* pf = getTheoryProofEngine()->getTheoryProof(theory::THEORY_ARRAYS);
130 return (ArrayProof*)pf;
131 }
132
getArithProof()133 ArithProof* ProofManager::getArithProof() {
134 Assert (options::proof());
135 TheoryProof* pf = getTheoryProofEngine()->getTheoryProof(theory::THEORY_ARITH);
136 return (ArithProof*)pf;
137 }
138
getSkolemizationManager()139 SkolemizationManager* ProofManager::getSkolemizationManager() {
140 Assert (options::proof() || options::unsatCores());
141 return &(currentPM()->d_skolemizationManager);
142 }
143
initSatProof(Minisat::Solver * solver)144 void ProofManager::initSatProof(Minisat::Solver* solver) {
145 Assert (currentPM()->d_satProof == NULL);
146 Assert(currentPM()->d_format == LFSC);
147 currentPM()->d_satProof = new CoreSatProof(solver, d_context, "");
148 }
149
initCnfProof(prop::CnfStream * cnfStream,context::Context * ctx)150 void ProofManager::initCnfProof(prop::CnfStream* cnfStream,
151 context::Context* ctx) {
152 ProofManager* pm = currentPM();
153 Assert(pm->d_satProof != NULL);
154 Assert (pm->d_cnfProof == NULL);
155 Assert (pm->d_format == LFSC);
156 CnfProof* cnf = new LFSCCnfProof(cnfStream, ctx, "");
157 pm->d_cnfProof = cnf;
158
159 // true and false have to be setup in a special way
160 Node true_node = NodeManager::currentNM()->mkConst<bool>(true);
161 Node false_node = NodeManager::currentNM()->mkConst<bool>(false).notNode();
162
163 pm->d_cnfProof->pushCurrentAssertion(true_node);
164 pm->d_cnfProof->pushCurrentDefinition(true_node);
165 pm->d_cnfProof->registerConvertedClause(pm->d_satProof->getTrueUnit());
166 pm->d_cnfProof->popCurrentAssertion();
167 pm->d_cnfProof->popCurrentDefinition();
168
169 pm->d_cnfProof->pushCurrentAssertion(false_node);
170 pm->d_cnfProof->pushCurrentDefinition(false_node);
171 pm->d_cnfProof->registerConvertedClause(pm->d_satProof->getFalseUnit());
172 pm->d_cnfProof->popCurrentAssertion();
173 pm->d_cnfProof->popCurrentDefinition();
174
175 }
176
initTheoryProofEngine()177 void ProofManager::initTheoryProofEngine() {
178 Assert (currentPM()->d_theoryProof == NULL);
179 Assert (currentPM()->d_format == LFSC);
180 currentPM()->d_theoryProof = new LFSCTheoryProofEngine();
181 }
182
getInputClauseName(ClauseId id,const std::string & prefix)183 std::string ProofManager::getInputClauseName(ClauseId id,
184 const std::string& prefix) {
185 return append(prefix+".pb", id);
186 }
187
getLemmaClauseName(ClauseId id,const std::string & prefix)188 std::string ProofManager::getLemmaClauseName(ClauseId id,
189 const std::string& prefix) {
190 return append(prefix+".lemc", id);
191 }
192
getLemmaName(ClauseId id,const std::string & prefix)193 std::string ProofManager::getLemmaName(ClauseId id, const std::string& prefix) {
194 return append(prefix+"lem", id);
195 }
196
getLearntClauseName(ClauseId id,const std::string & prefix)197 std::string ProofManager::getLearntClauseName(ClauseId id,
198 const std::string& prefix) {
199 return append(prefix+".cl", id);
200 }
getVarName(prop::SatVariable var,const std::string & prefix)201 std::string ProofManager::getVarName(prop::SatVariable var,
202 const std::string& prefix) {
203 return append(prefix+".v", var);
204 }
getAtomName(prop::SatVariable var,const std::string & prefix)205 std::string ProofManager::getAtomName(prop::SatVariable var,
206 const std::string& prefix) {
207 return append(prefix+".a", var);
208 }
getLitName(prop::SatLiteral lit,const std::string & prefix)209 std::string ProofManager::getLitName(prop::SatLiteral lit,
210 const std::string& prefix) {
211 return append(prefix+".l", lit.toInt());
212 }
213
getPreprocessedAssertionName(Node node,const std::string & prefix)214 std::string ProofManager::getPreprocessedAssertionName(Node node,
215 const std::string& prefix) {
216 if (currentPM()->d_assertionFilters.find(node) != currentPM()->d_assertionFilters.end()) {
217 return currentPM()->d_assertionFilters[node];
218 }
219
220 node = node.getKind() == kind::BITVECTOR_EAGER_ATOM ? node[0] : node;
221 return append(prefix+".PA", node.getId());
222 }
getAssertionName(Node node,const std::string & prefix)223 std::string ProofManager::getAssertionName(Node node,
224 const std::string& prefix) {
225 return append(prefix+".A", node.getId());
226 }
getInputFormulaName(const Expr & expr)227 std::string ProofManager::getInputFormulaName(const Expr& expr) {
228 return currentPM()->d_inputFormulaToName[expr];
229 }
230
getAtomName(TNode atom,const std::string & prefix)231 std::string ProofManager::getAtomName(TNode atom,
232 const std::string& prefix) {
233 prop::SatLiteral lit = currentPM()->d_cnfProof->getLiteral(atom);
234 Assert(!lit.isNegated());
235 return getAtomName(lit.getSatVariable(), prefix);
236 }
237
getLitName(TNode lit,const std::string & prefix)238 std::string ProofManager::getLitName(TNode lit,
239 const std::string& prefix) {
240 std::string litName = getLitName(currentPM()->d_cnfProof->getLiteral(lit), prefix);
241 if (currentPM()->d_rewriteFilters.find(litName) != currentPM()->d_rewriteFilters.end()) {
242 return currentPM()->d_rewriteFilters[litName];
243 }
244
245 return litName;
246 }
247
hasLitName(TNode lit)248 bool ProofManager::hasLitName(TNode lit) {
249 return currentPM()->d_cnfProof->hasLiteral(lit);
250 }
251
sanitize(TNode node)252 std::string ProofManager::sanitize(TNode node) {
253 Assert (node.isVar() || node.isConst());
254
255 std::string name = node.toString();
256 if (node.isVar()) {
257 std::replace(name.begin(), name.end(), ' ', '_');
258 } else if (node.isConst()) {
259 name.erase(std::remove(name.begin(), name.end(), '('), name.end());
260 name.erase(std::remove(name.begin(), name.end(), ')'), name.end());
261 name.erase(std::remove(name.begin(), name.end(), ' '), name.end());
262 name = "const" + name;
263 }
264
265 return name;
266 }
267
traceDeps(TNode n,ExprSet * coreAssertions)268 void ProofManager::traceDeps(TNode n, ExprSet* coreAssertions) {
269 Debug("cores") << "trace deps " << n << std::endl;
270 if ((n.isConst() && n == NodeManager::currentNM()->mkConst<bool>(true)) ||
271 (n.getKind() == kind::NOT && n[0] == NodeManager::currentNM()->mkConst<bool>(false))) {
272 return;
273 }
274 if(d_inputCoreFormulas.find(n.toExpr()) != d_inputCoreFormulas.end()) {
275 // originating formula was in core set
276 Debug("cores") << " -- IN INPUT CORE LIST!" << std::endl;
277 coreAssertions->insert(n.toExpr());
278 } else {
279 Debug("cores") << " -- NOT IN INPUT CORE LIST!" << std::endl;
280 if(d_deps.find(n) == d_deps.end()) {
281 if (options::allowEmptyDependencies()) {
282 Debug("cores") << " -- Could not track cause assertion. Failing silently." << std::endl;
283 return;
284 }
285 InternalError("Cannot trace dependence information back to input assertion:\n`%s'", n.toString().c_str());
286 }
287 Assert(d_deps.find(n) != d_deps.end());
288 std::vector<Node> deps = (*d_deps.find(n)).second;
289 for(std::vector<Node>::const_iterator i = deps.begin(); i != deps.end(); ++i) {
290 Debug("cores") << " + tracing deps: " << n << " -deps-on- " << *i << std::endl;
291 if( !(*i).isNull() ){
292 traceDeps(*i, coreAssertions);
293 }
294 }
295 }
296 }
297
traceDeps(TNode n,CDExprSet * coreAssertions)298 void ProofManager::traceDeps(TNode n, CDExprSet* coreAssertions) {
299 Debug("cores") << "trace deps " << n << std::endl;
300 if ((n.isConst() && n == NodeManager::currentNM()->mkConst<bool>(true)) ||
301 (n.getKind() == kind::NOT && n[0] == NodeManager::currentNM()->mkConst<bool>(false))) {
302 return;
303 }
304 if(d_inputCoreFormulas.find(n.toExpr()) != d_inputCoreFormulas.end()) {
305 // originating formula was in core set
306 Debug("cores") << " -- IN INPUT CORE LIST!" << std::endl;
307 coreAssertions->insert(n.toExpr());
308 } else {
309 Debug("cores") << " -- NOT IN INPUT CORE LIST!" << std::endl;
310 if(d_deps.find(n) == d_deps.end()) {
311 if (options::allowEmptyDependencies()) {
312 Debug("cores") << " -- Could not track cause assertion. Failing silently." << std::endl;
313 return;
314 }
315 InternalError("Cannot trace dependence information back to input assertion:\n`%s'", n.toString().c_str());
316 }
317 Assert(d_deps.find(n) != d_deps.end());
318 std::vector<Node> deps = (*d_deps.find(n)).second;
319
320 for(std::vector<Node>::const_iterator i = deps.begin(); i != deps.end(); ++i) {
321 Debug("cores") << " + tracing deps: " << n << " -deps-on- " << *i << std::endl;
322 if( !(*i).isNull() ){
323 traceDeps(*i, coreAssertions);
324 }
325 }
326 }
327 }
328
traceUnsatCore()329 void ProofManager::traceUnsatCore() {
330 Assert (options::unsatCores());
331 d_satProof->refreshProof();
332 IdToSatClause used_lemmas;
333 IdToSatClause used_inputs;
334 d_satProof->collectClausesUsed(used_inputs,
335 used_lemmas);
336
337 // At this point, there should be no assertions without a clause id
338 Assert(d_cnfProof->isAssertionStackEmpty());
339
340 IdToSatClause::const_iterator it = used_inputs.begin();
341 for(; it != used_inputs.end(); ++it) {
342 Node node = d_cnfProof->getAssertionForClause(it->first);
343 ProofRule rule = d_cnfProof->getProofRule(node);
344
345 Debug("cores") << "core input assertion " << node << std::endl;
346 Debug("cores") << "with proof rule " << rule << std::endl;
347 if (rule == RULE_TSEITIN ||
348 rule == RULE_GIVEN) {
349 // trace dependences back to actual assertions
350 // (this adds them to the unsat core)
351 traceDeps(node, &d_outputCoreFormulas);
352 }
353 }
354 }
355
unsatCoreAvailable() const356 bool ProofManager::unsatCoreAvailable() const {
357 return d_satProof->derivedEmptyClause();
358 }
359
extractUnsatCore()360 std::vector<Expr> ProofManager::extractUnsatCore() {
361 std::vector<Expr> result;
362 output_core_iterator it = begin_unsat_core();
363 output_core_iterator end = end_unsat_core();
364 while ( it != end ) {
365 result.push_back(*it);
366 ++it;
367 }
368 return result;
369 }
370
constructSatProof()371 void ProofManager::constructSatProof() {
372 if (!d_satProof->proofConstructed()) {
373 d_satProof->constructProof();
374 }
375 }
376
getLemmasInUnsatCore(theory::TheoryId theory,std::vector<Node> & lemmas)377 void ProofManager::getLemmasInUnsatCore(theory::TheoryId theory, std::vector<Node> &lemmas) {
378 Assert(PROOF_ON(), "Cannot compute unsat core when proofs are off");
379 Assert(unsatCoreAvailable(), "Cannot get unsat core at this time. Mabye the input is SAT?" );
380
381 constructSatProof();
382
383 IdToSatClause used_lemmas;
384 IdToSatClause used_inputs;
385 d_satProof->collectClausesUsed(used_inputs, used_lemmas);
386
387 IdToSatClause::const_iterator it;
388 std::set<Node> seen;
389
390 Debug("pf::lemmasUnsatCore") << "Dumping all lemmas in unsat core" << std::endl;
391 for (it = used_lemmas.begin(); it != used_lemmas.end(); ++it) {
392 std::set<Node> lemma = satClauseToNodeSet(it->second);
393 Debug("pf::lemmasUnsatCore") << nodeSetToString(lemma);
394
395 // TODO: we should be able to drop the "haveProofRecipe" check.
396 // however, there are some rewrite issues with the arith solver, resulting
397 // in non-registered recipes. For now we assume no one is requesting arith lemmas.
398 LemmaProofRecipe recipe;
399 if (!getCnfProof()->haveProofRecipe(lemma)) {
400 Debug("pf::lemmasUnsatCore") << "\t[no recipe]" << std::endl;
401 continue;
402 }
403
404 recipe = getCnfProof()->getProofRecipe(lemma);
405 Debug("pf::lemmasUnsatCore") << "\t[owner = " << recipe.getTheory()
406 << ", original = " << recipe.getOriginalLemma() << "]" << std::endl;
407 if (recipe.simpleLemma() && recipe.getTheory() == theory && seen.find(recipe.getOriginalLemma()) == seen.end()) {
408 lemmas.push_back(recipe.getOriginalLemma());
409 seen.insert(recipe.getOriginalLemma());
410 }
411 }
412 }
413
satClauseToNodeSet(prop::SatClause * clause)414 std::set<Node> ProofManager::satClauseToNodeSet(prop::SatClause* clause) {
415 std::set<Node> result;
416 for (unsigned i = 0; i < clause->size(); ++i) {
417 prop::SatLiteral lit = (*clause)[i];
418 Node node = getCnfProof()->getAtom(lit.getSatVariable());
419 Expr atom = node.toExpr();
420 if (atom != utils::mkTrue())
421 result.insert(lit.isNegated() ? node.notNode() : node);
422 }
423
424 return result;
425 }
426
getWeakestImplicantInUnsatCore(Node lemma)427 Node ProofManager::getWeakestImplicantInUnsatCore(Node lemma) {
428 Assert(PROOF_ON(), "Cannot compute unsat core when proofs are off");
429 Assert(unsatCoreAvailable(), "Cannot get unsat core at this time. Mabye the input is SAT?" );
430
431 // If we're doing aggressive minimization, work on all lemmas, not just conjunctions.
432 if (!options::aggressiveCoreMin() && (lemma.getKind() != kind::AND))
433 return lemma;
434
435 constructSatProof();
436
437 NodeBuilder<> builder(kind::AND);
438
439 IdToSatClause used_lemmas;
440 IdToSatClause used_inputs;
441 d_satProof->collectClausesUsed(used_inputs, used_lemmas);
442
443 IdToSatClause::const_iterator it;
444 std::set<Node>::iterator lemmaIt;
445
446 if (!options::aggressiveCoreMin()) {
447 for (it = used_lemmas.begin(); it != used_lemmas.end(); ++it) {
448 std::set<Node> currentLemma = satClauseToNodeSet(it->second);
449
450 // TODO: we should be able to drop the "haveProofRecipe" check.
451 // however, there are some rewrite issues with the arith solver, resulting
452 // in non-registered recipes. For now we assume no one is requesting arith lemmas.
453 LemmaProofRecipe recipe;
454 if (!getCnfProof()->haveProofRecipe(currentLemma))
455 continue;
456
457 recipe = getCnfProof()->getProofRecipe(currentLemma);
458 if (recipe.getOriginalLemma() == lemma) {
459 for (lemmaIt = currentLemma.begin(); lemmaIt != currentLemma.end(); ++lemmaIt) {
460 builder << *lemmaIt;
461
462 // Check that each conjunct appears in the original lemma.
463 bool found = false;
464 for (unsigned i = 0; i < lemma.getNumChildren(); ++i) {
465 if (lemma[i] == *lemmaIt)
466 found = true;
467 }
468
469 if (!found)
470 return lemma;
471 }
472 }
473 }
474 } else {
475 // Aggressive mode
476 for (it = used_lemmas.begin(); it != used_lemmas.end(); ++it) {
477 std::set<Node> currentLemma = satClauseToNodeSet(it->second);
478
479 // TODO: we should be able to drop the "haveProofRecipe" check.
480 // however, there are some rewrite issues with the arith solver, resulting
481 // in non-registered recipes. For now we assume no one is requesting arith lemmas.
482 LemmaProofRecipe recipe;
483 if (!getCnfProof()->haveProofRecipe(currentLemma))
484 continue;
485
486 recipe = getCnfProof()->getProofRecipe(currentLemma);
487 if (recipe.getOriginalLemma() == lemma) {
488 NodeBuilder<> disjunction(kind::OR);
489 for (lemmaIt = currentLemma.begin(); lemmaIt != currentLemma.end(); ++lemmaIt) {
490 disjunction << *lemmaIt;
491 }
492
493 Node conjunct = (disjunction.getNumChildren() == 1) ? disjunction[0] : disjunction;
494 builder << conjunct;
495 }
496 }
497 }
498
499 AlwaysAssert(builder.getNumChildren() != 0);
500
501 if (builder.getNumChildren() == 1)
502 return builder[0];
503
504 return builder;
505 }
506
addAssertion(Expr formula)507 void ProofManager::addAssertion(Expr formula) {
508 Debug("proof:pm") << "assert: " << formula << std::endl;
509 d_inputFormulas.insert(formula);
510 std::ostringstream name;
511 name << "A" << d_inputFormulaToName.size();
512 d_inputFormulaToName[formula] = name.str();
513 }
514
addCoreAssertion(Expr formula)515 void ProofManager::addCoreAssertion(Expr formula) {
516 Debug("cores") << "assert: " << formula << std::endl;
517 d_deps[Node::fromExpr(formula)]; // empty vector of deps
518 d_inputCoreFormulas.insert(formula);
519 }
520
addDependence(TNode n,TNode dep)521 void ProofManager::addDependence(TNode n, TNode dep) {
522 if(dep != n) {
523 Debug("cores") << "dep: " << n << " : " << dep << std::endl;
524 if( !dep.isNull() && d_deps.find(dep) == d_deps.end()) {
525 Debug("cores") << "WHERE DID " << dep << " come from ??" << std::endl;
526 }
527 std::vector<Node> deps = d_deps[n].get();
528 deps.push_back(dep);
529 d_deps[n].set(deps);
530 }
531 }
532
addUnsatCore(Expr formula)533 void ProofManager::addUnsatCore(Expr formula) {
534 Assert (d_inputCoreFormulas.find(formula) != d_inputCoreFormulas.end());
535 d_outputCoreFormulas.insert(formula);
536 }
537
addAssertionFilter(const Node & node,const std::string & rewritten)538 void ProofManager::addAssertionFilter(const Node& node, const std::string& rewritten) {
539 d_assertionFilters[node] = rewritten;
540 }
541
setLogic(const LogicInfo & logic)542 void ProofManager::setLogic(const LogicInfo& logic) {
543 d_logic = logic;
544 }
545
LFSCProof(SmtEngine * smtEngine,CoreSatProof * sat,LFSCCnfProof * cnf,LFSCTheoryProofEngine * theory)546 LFSCProof::LFSCProof(SmtEngine* smtEngine,
547 CoreSatProof* sat,
548 LFSCCnfProof* cnf,
549 LFSCTheoryProofEngine* theory)
550 : d_satProof(sat),
551 d_cnfProof(cnf),
552 d_theoryProof(theory),
553 d_smtEngine(smtEngine)
554 {}
555
toStream(std::ostream & out,const ProofLetMap & map) const556 void LFSCProof::toStream(std::ostream& out, const ProofLetMap& map) const
557 {
558 Unreachable();
559 }
560
toStream(std::ostream & out) const561 void LFSCProof::toStream(std::ostream& out) const
562 {
563 TimerStat::CodeTimer proofProductionTimer(
564 *ProofManager::currentPM()->getProofProductionTime());
565
566 Assert(!d_satProof->proofConstructed());
567 d_satProof->constructProof();
568
569 // collecting leaf clauses in resolution proof
570 IdToSatClause used_lemmas;
571 IdToSatClause used_inputs;
572 d_satProof->collectClausesUsed(used_inputs,
573 used_lemmas);
574
575 IdToSatClause::iterator it2;
576 Debug("pf::pm") << std::endl << "Used inputs: " << std::endl;
577 for (it2 = used_inputs.begin(); it2 != used_inputs.end(); ++it2) {
578 Debug("pf::pm") << "\t input = " << *(it2->second) << std::endl;
579 }
580 Debug("pf::pm") << std::endl;
581
582 // Debug("pf::pm") << std::endl << "Used lemmas: " << std::endl;
583 // for (it2 = used_lemmas.begin(); it2 != used_lemmas.end(); ++it2) {
584 // Debug("pf::pm") << "\t lemma = " << *(it2->second) << std::endl;
585 // }
586 // Debug("pf::pm") << std::endl;
587 Debug("pf::pm") << std::endl << "Used lemmas: " << std::endl;
588 for (it2 = used_lemmas.begin(); it2 != used_lemmas.end(); ++it2) {
589
590 std::vector<Expr> clause_expr;
591 for(unsigned i = 0; i < it2->second->size(); ++i) {
592 prop::SatLiteral lit = (*(it2->second))[i];
593 Expr atom = d_cnfProof->getAtom(lit.getSatVariable()).toExpr();
594 if (atom.isConst()) {
595 Assert (atom == utils::mkTrue());
596 continue;
597 }
598 Expr expr_lit = lit.isNegated() ? atom.notExpr(): atom;
599 clause_expr.push_back(expr_lit);
600 }
601
602 Debug("pf::pm") << "\t lemma " << it2->first << " = " << *(it2->second) << std::endl;
603 Debug("pf::pm") << "\t";
604 for (unsigned i = 0; i < clause_expr.size(); ++i) {
605 Debug("pf::pm") << clause_expr[i] << " ";
606 }
607 Debug("pf::pm") << std::endl;
608 }
609 Debug("pf::pm") << std::endl;
610
611 // collecting assertions that lead to the clauses being asserted
612 NodeSet used_assertions;
613 d_cnfProof->collectAssertionsForClauses(used_inputs, used_assertions);
614
615 NodeSet::iterator it3;
616 Debug("pf::pm") << std::endl << "Used assertions: " << std::endl;
617 for (it3 = used_assertions.begin(); it3 != used_assertions.end(); ++it3)
618 Debug("pf::pm") << "\t assertion = " << *it3 << std::endl;
619
620 std::set<Node> atoms;
621
622 NodePairSet rewrites;
623 // collects the atoms in the clauses
624 d_cnfProof->collectAtomsAndRewritesForLemmas(used_lemmas, atoms, rewrites);
625
626 if (!rewrites.empty()) {
627 Debug("pf::pm") << std::endl << "Rewrites used in lemmas: " << std::endl;
628 NodePairSet::const_iterator rewriteIt;
629 for (rewriteIt = rewrites.begin(); rewriteIt != rewrites.end(); ++rewriteIt) {
630 Debug("pf::pm") << "\t" << rewriteIt->first << " --> " << rewriteIt->second << std::endl;
631 }
632 Debug("pf::pm") << std::endl << "Rewrite printing done" << std::endl;
633 } else {
634 Debug("pf::pm") << "No rewrites in lemmas found" << std::endl;
635 }
636
637 // The derived/unrewritten atoms may not have CNF literals required later on.
638 // If they don't, add them.
639 std::set<Node>::const_iterator it;
640 for (it = atoms.begin(); it != atoms.end(); ++it) {
641 Debug("pf::pm") << "Ensure literal for atom: " << *it << std::endl;
642 if (!d_cnfProof->hasLiteral(*it)) {
643 // For arithmetic: these literals are not normalized, causing an error in Arith.
644 if (theory::Theory::theoryOf(*it) == theory::THEORY_ARITH) {
645 d_cnfProof->ensureLiteral(*it, true); // This disables preregistration with the theory solver.
646 } else {
647 d_cnfProof->ensureLiteral(*it); // Normal method, with theory solver preregisteration.
648 }
649 }
650 }
651
652 d_cnfProof->collectAtomsForClauses(used_inputs, atoms);
653 d_cnfProof->collectAtomsForClauses(used_lemmas, atoms);
654
655 // collects the atoms in the assertions
656 for (NodeSet::const_iterator it = used_assertions.begin();
657 it != used_assertions.end(); ++it) {
658 utils::collectAtoms(*it, atoms);
659 // utils::collectAtoms(*it, newAtoms);
660 }
661
662 std::set<Node>::iterator atomIt;
663 Debug("pf::pm") << std::endl << "Dumping atoms from lemmas, inputs and assertions: "
664 << std::endl << std::endl;
665 for (atomIt = atoms.begin(); atomIt != atoms.end(); ++atomIt) {
666 Debug("pf::pm") << "\tAtom: " << *atomIt << std::endl;
667 }
668 smt::SmtScope scope(d_smtEngine);
669 std::ostringstream paren;
670 out << "(check\n";
671 paren << ")";
672 out << " ;; Declarations\n";
673
674 // declare the theory atoms
675 Debug("pf::pm") << "LFSCProof::toStream: registering terms:" << std::endl;
676 for(it = atoms.begin(); it != atoms.end(); ++it) {
677 Debug("pf::pm") << "\tTerm: " << (*it).toExpr() << std::endl;
678 d_theoryProof->registerTerm((*it).toExpr());
679 }
680
681 Debug("pf::pm") << std::endl << "Term registration done!" << std::endl << std::endl;
682
683 Debug("pf::pm") << std::endl << "LFSCProof::toStream: starting to print assertions" << std::endl;
684
685 // print out all the original assertions
686 d_theoryProof->registerTermsFromAssertions();
687 d_theoryProof->printSortDeclarations(out, paren);
688 d_theoryProof->printTermDeclarations(out, paren);
689 d_theoryProof->printAssertions(out, paren);
690
691 Debug("pf::pm") << std::endl << "LFSCProof::toStream: print assertions DONE" << std::endl;
692
693 out << "(: (holds cln)\n\n";
694 paren << ")";
695
696 // Have the theory proofs print deferred declarations, e.g. for skolem variables.
697 out << " ;; Printing deferred declarations \n\n";
698 d_theoryProof->printDeferredDeclarations(out, paren);
699
700 out << "\n ;; Printing the global let map";
701 d_theoryProof->finalizeBvConflicts(used_lemmas, out);
702 ProofManager::getBitVectorProof()->calculateAtomsInBitblastingProof();
703 ProofLetMap globalLetMap;
704 if (options::lfscLetification()) {
705 ProofManager::currentPM()->printGlobalLetMap(atoms, globalLetMap, out, paren);
706 }
707
708 out << " ;; Printing aliasing declarations \n\n";
709 d_theoryProof->printAliasingDeclarations(out, paren, globalLetMap);
710
711 out << " ;; Rewrites for Lemmas \n";
712 d_theoryProof->printLemmaRewrites(rewrites, out, paren);
713
714 // print trust that input assertions are their preprocessed form
715 printPreprocessedAssertions(used_assertions, out, paren, globalLetMap);
716
717 // print mapping between theory atoms and internal SAT variables
718 out << ";; Printing mapping from preprocessed assertions into atoms \n";
719 d_cnfProof->printAtomMapping(atoms, out, paren, globalLetMap);
720
721 Debug("pf::pm") << std::endl << "Printing cnf proof for clauses" << std::endl;
722
723 IdToSatClause::const_iterator cl_it = used_inputs.begin();
724 // print CNF conversion proof for each clause
725 for (; cl_it != used_inputs.end(); ++cl_it) {
726 d_cnfProof->printCnfProofForClause(cl_it->first, cl_it->second, out, paren);
727 }
728
729 Debug("pf::pm") << std::endl << "Printing cnf proof for clauses DONE" << std::endl;
730
731 Debug("pf::pm") << "Proof manager: printing theory lemmas" << std::endl;
732 d_theoryProof->printTheoryLemmas(used_lemmas, out, paren, globalLetMap);
733 Debug("pf::pm") << "Proof manager: printing theory lemmas DONE!" << std::endl;
734
735 out << ";; Printing final unsat proof \n";
736 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER && ProofManager::getBitVectorProof()) {
737 ProofManager::getBitVectorProof()->printEmptyClauseProof(out, paren);
738 } else {
739 // print actual resolution proof
740 proof::LFSCProofPrinter::printResolutions(d_satProof, out, paren);
741 proof::LFSCProofPrinter::printResolutionEmptyClause(d_satProof, out, paren);
742 }
743
744 out << paren.str();
745 out << "\n;;\n";
746 }
747
printPreprocessedAssertions(const NodeSet & assertions,std::ostream & os,std::ostream & paren,ProofLetMap & globalLetMap) const748 void LFSCProof::printPreprocessedAssertions(const NodeSet& assertions,
749 std::ostream& os,
750 std::ostream& paren,
751 ProofLetMap& globalLetMap) const
752 {
753 os << "\n ;; In the preprocessor we trust \n";
754 NodeSet::const_iterator it = assertions.begin();
755 NodeSet::const_iterator end = assertions.end();
756
757 Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions starting" << std::endl;
758
759 if (options::fewerPreprocessingHoles()) {
760 // Check for assertions that did not get rewritten, and update the printing filter.
761 checkUnrewrittenAssertion(assertions);
762
763 // For the remaining assertions, bind them to input assertions.
764 for (; it != end; ++it) {
765 // Rewrite preprocessing step if it cannot be eliminated
766 if (!ProofManager::currentPM()->have_input_assertion((*it).toExpr())) {
767 os << "(th_let_pf _ (trust_f (iff ";
768
769 Expr inputAssertion;
770
771 if (((*it).isConst() && *it == NodeManager::currentNM()->mkConst<bool>(true)) ||
772 ((*it).getKind() == kind::NOT && (*it)[0] == NodeManager::currentNM()->mkConst<bool>(false))) {
773 inputAssertion = NodeManager::currentNM()->mkConst<bool>(true).toExpr();
774 } else {
775 // Figure out which input assertion led to this assertion
776 ExprSet inputAssertions;
777 ProofManager::currentPM()->traceDeps(*it, &inputAssertions);
778
779 Debug("pf::pm") << "Original assertions for " << *it << " are: " << std::endl;
780
781 ProofManager::assertions_iterator assertionIt;
782 for (assertionIt = inputAssertions.begin(); assertionIt != inputAssertions.end(); ++assertionIt) {
783 Debug("pf::pm") << "\t" << *assertionIt << std::endl;
784 }
785
786 if (inputAssertions.size() == 0) {
787 Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions: Count NOT find the assertion that caused this PA. Picking an arbitrary one..." << std::endl;
788 // For now just use the first assertion...
789 inputAssertion = *(ProofManager::currentPM()->begin_assertions());
790 } else {
791 if (inputAssertions.size() != 1) {
792 Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions: Attention: more than one original assertion was found. Picking just one." << std::endl;
793 }
794 inputAssertion = *inputAssertions.begin();
795 }
796 }
797
798 if (!ProofManager::currentPM()->have_input_assertion(inputAssertion)) {
799 // The thing returned by traceDeps does not appear in the input assertions...
800 Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions: Count NOT find the assertion that caused this PA. Picking an arbitrary one..." << std::endl;
801 // For now just use the first assertion...
802 inputAssertion = *(ProofManager::currentPM()->begin_assertions());
803 }
804
805 Debug("pf::pm") << "Original assertion for " << *it
806 << " is: "
807 << inputAssertion
808 << ", AKA "
809 << ProofManager::currentPM()->getInputFormulaName(inputAssertion)
810 << std::endl;
811
812 ProofManager::currentPM()->getTheoryProofEngine()->printTheoryTerm(inputAssertion, os, globalLetMap);
813 os << " ";
814 ProofManager::currentPM()->printTrustedTerm(*it, os, globalLetMap);
815 os << "))";
816 os << "(\\ "<< ProofManager::getPreprocessedAssertionName(*it, "") << "\n";
817 paren << "))";
818
819 std::ostringstream rewritten;
820
821 rewritten << "(or_elim_1 _ _ ";
822 rewritten << "(not_not_intro _ ";
823 rewritten << ProofManager::currentPM()->getInputFormulaName(inputAssertion);
824 rewritten << ") (iff_elim_1 _ _ ";
825 rewritten << ProofManager::getPreprocessedAssertionName(*it, "");
826 rewritten << "))";
827
828 ProofManager::currentPM()->addAssertionFilter(*it, rewritten.str());
829 }
830 }
831 } else {
832 for (; it != end; ++it) {
833 os << "(th_let_pf _ ";
834
835 //TODO
836 os << "(trust_f ";
837 ProofManager::currentPM()->printTrustedTerm(*it, os, globalLetMap);
838 os << ") ";
839
840 os << "(\\ "<< ProofManager::getPreprocessedAssertionName(*it, "") << "\n";
841 paren << "))";
842 }
843 }
844
845 os << "\n";
846 }
847
checkUnrewrittenAssertion(const NodeSet & rewrites) const848 void LFSCProof::checkUnrewrittenAssertion(const NodeSet& rewrites) const
849 {
850 Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion starting" << std::endl;
851
852 NodeSet::const_iterator rewrite;
853 for (rewrite = rewrites.begin(); rewrite != rewrites.end(); ++rewrite) {
854 Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion: handling " << *rewrite << std::endl;
855 if (ProofManager::currentPM()->have_input_assertion((*rewrite).toExpr())) {
856 Assert(ProofManager::currentPM()->have_input_assertion((*rewrite).toExpr()));
857 Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion: this assertion was NOT rewritten!" << std::endl
858 << "\tAdding filter: "
859 << ProofManager::getPreprocessedAssertionName(*rewrite, "")
860 << " --> "
861 << ProofManager::currentPM()->getInputFormulaName((*rewrite).toExpr())
862 << std::endl;
863 ProofManager::currentPM()->addAssertionFilter(*rewrite,
864 ProofManager::currentPM()->getInputFormulaName((*rewrite).toExpr()));
865 } else {
866 Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion: this assertion WAS rewritten! " << *rewrite << std::endl;
867 }
868 }
869 }
870
871 //---from Morgan---
872
hasOp(TNode n) const873 bool ProofManager::hasOp(TNode n) const {
874 return d_bops.find(n) != d_bops.end();
875 }
876
lookupOp(TNode n) const877 Node ProofManager::lookupOp(TNode n) const {
878 std::map<Node, Node>::const_iterator i = d_bops.find(n);
879 Assert(i != d_bops.end());
880 return (*i).second;
881 }
882
mkOp(TNode n)883 Node ProofManager::mkOp(TNode n) {
884 Trace("mgd-pm-mkop") << "MkOp : " << n << " " << n.getKind() << std::endl;
885 if(n.getKind() != kind::BUILTIN) {
886 return n;
887 }
888
889 Node& op = d_ops[n];
890 if(op.isNull()) {
891 Assert((n.getConst<Kind>() == kind::SELECT) || (n.getConst<Kind>() == kind::STORE));
892
893 Debug("mgd-pm-mkop") << "making an op for " << n << "\n";
894
895 std::stringstream ss;
896 ss << n;
897 std::string s = ss.str();
898 Debug("mgd-pm-mkop") << " : " << s << std::endl;
899 std::vector<TypeNode> v;
900 v.push_back(NodeManager::currentNM()->integerType());
901 if(n.getConst<Kind>() == kind::SELECT) {
902 v.push_back(NodeManager::currentNM()->integerType());
903 v.push_back(NodeManager::currentNM()->integerType());
904 } else if(n.getConst<Kind>() == kind::STORE) {
905 v.push_back(NodeManager::currentNM()->integerType());
906 v.push_back(NodeManager::currentNM()->integerType());
907 v.push_back(NodeManager::currentNM()->integerType());
908 }
909 TypeNode type = NodeManager::currentNM()->mkFunctionType(v);
910 Debug("mgd-pm-mkop") << "typenode is: " << type << "\n";
911 op = NodeManager::currentNM()->mkSkolem(s, type, " ignore", NodeManager::SKOLEM_NO_NOTIFY);
912 d_bops[op] = n;
913 }
914 Debug("mgd-pm-mkop") << "returning the op: " << op << "\n";
915 return op;
916 }
917 //---end from Morgan---
918
wasPrinted(const Type & type) const919 bool ProofManager::wasPrinted(const Type& type) const {
920 return d_printedTypes.find(type) != d_printedTypes.end();
921 }
922
markPrinted(const Type & type)923 void ProofManager::markPrinted(const Type& type) {
924 d_printedTypes.insert(type);
925 }
926
addRewriteFilter(const std::string & original,const std::string & substitute)927 void ProofManager::addRewriteFilter(const std::string &original, const std::string &substitute) {
928 d_rewriteFilters[original] = substitute;
929 }
930
haveRewriteFilter(TNode lit)931 bool ProofManager::haveRewriteFilter(TNode lit) {
932 std::string litName = getLitName(currentPM()->d_cnfProof->getLiteral(lit));
933 return d_rewriteFilters.find(litName) != d_rewriteFilters.end();
934 }
935
clearRewriteFilters()936 void ProofManager::clearRewriteFilters() {
937 d_rewriteFilters.clear();
938 }
939
operator <<(std::ostream & out,CVC4::ProofRule k)940 std::ostream& operator<<(std::ostream& out, CVC4::ProofRule k) {
941 switch(k) {
942 case RULE_GIVEN:
943 out << "RULE_GIVEN";
944 break;
945 case RULE_DERIVED:
946 out << "RULE_DERIVED";
947 break;
948 case RULE_RECONSTRUCT:
949 out << "RULE_RECONSTRUCT";
950 break;
951 case RULE_TRUST:
952 out << "RULE_TRUST";
953 break;
954 case RULE_INVALID:
955 out << "RULE_INVALID";
956 break;
957 case RULE_CONFLICT:
958 out << "RULE_CONFLICT";
959 break;
960 case RULE_TSEITIN:
961 out << "RULE_TSEITIN";
962 break;
963 case RULE_SPLIT:
964 out << "RULE_SPLIT";
965 break;
966 case RULE_ARRAYS_EXT:
967 out << "RULE_ARRAYS";
968 break;
969 case RULE_ARRAYS_ROW:
970 out << "RULE_ARRAYS";
971 break;
972 default:
973 out << "ProofRule Unknown! [" << unsigned(k) << "]";
974 }
975
976 return out;
977 }
978
registerRewrite(unsigned ruleId,Node original,Node result)979 void ProofManager::registerRewrite(unsigned ruleId, Node original, Node result){
980 Assert (currentPM()->d_theoryProof != NULL);
981 currentPM()->d_rewriteLog.push_back(RewriteLogEntry(ruleId, original, result));
982 }
983
clearRewriteLog()984 void ProofManager::clearRewriteLog() {
985 Assert (currentPM()->d_theoryProof != NULL);
986 currentPM()->d_rewriteLog.clear();
987 }
988
getRewriteLog()989 std::vector<RewriteLogEntry> ProofManager::getRewriteLog() {
990 return currentPM()->d_rewriteLog;
991 }
992
dumpRewriteLog() const993 void ProofManager::dumpRewriteLog() const {
994 Debug("pf::rr") << "Dumpign rewrite log:" << std::endl;
995
996 for (unsigned i = 0; i < d_rewriteLog.size(); ++i) {
997 Debug("pf::rr") << "\tRule " << d_rewriteLog[i].getRuleId()
998 << ": "
999 << d_rewriteLog[i].getOriginal()
1000 << " --> "
1001 << d_rewriteLog[i].getResult() << std::endl;
1002 }
1003 }
1004
bind(Expr term,ProofLetMap & map,Bindings & letOrder)1005 void bind(Expr term, ProofLetMap& map, Bindings& letOrder) {
1006 ProofLetMap::iterator it = map.find(term);
1007 if (it != map.end())
1008 return;
1009
1010 for (unsigned i = 0; i < term.getNumChildren(); ++i)
1011 bind(term[i], map, letOrder);
1012
1013 // Special case: chain operators. If we have and(a,b,c), it will be prineted as and(a,and(b,c)).
1014 // The subterm and(b,c) may repeat elsewhere, so we need to bind it, too.
1015 Kind k = term.getKind();
1016 if (((k == kind::OR) || (k == kind::AND)) && term.getNumChildren() > 2) {
1017 Node currentExpression = term[term.getNumChildren() - 1];
1018 for (int i = term.getNumChildren() - 2; i >= 0; --i) {
1019 NodeBuilder<> builder(k);
1020 builder << term[i];
1021 builder << currentExpression.toExpr();
1022 currentExpression = builder;
1023 bind(currentExpression.toExpr(), map, letOrder);
1024 }
1025 } else {
1026 unsigned newId = ProofLetCount::newId();
1027 ProofLetCount letCount(newId);
1028 map[term] = letCount;
1029 letOrder.push_back(LetOrderElement(term, newId));
1030 }
1031 }
1032
printGlobalLetMap(std::set<Node> & atoms,ProofLetMap & letMap,std::ostream & out,std::ostringstream & paren)1033 void ProofManager::printGlobalLetMap(std::set<Node>& atoms,
1034 ProofLetMap& letMap,
1035 std::ostream& out,
1036 std::ostringstream& paren) {
1037 Bindings letOrder;
1038 std::set<Node>::const_iterator atom;
1039 for (atom = atoms.begin(); atom != atoms.end(); ++atom) {
1040 bind(atom->toExpr(), letMap, letOrder);
1041 }
1042
1043 // TODO: give each theory a chance to add atoms. For now, just query BV directly...
1044 const std::set<Node>* additionalAtoms = ProofManager::getBitVectorProof()->getAtomsInBitblastingProof();
1045 for (atom = additionalAtoms->begin(); atom != additionalAtoms->end(); ++atom) {
1046 bind(atom->toExpr(), letMap, letOrder);
1047 }
1048
1049 for (unsigned i = 0; i < letOrder.size(); ++i) {
1050 Expr currentExpr = letOrder[i].expr;
1051 unsigned letId = letOrder[i].id;
1052 ProofLetMap::iterator it = letMap.find(currentExpr);
1053 Assert(it != letMap.end());
1054 out << "\n(@ let" << letId << " ";
1055 d_theoryProof->printBoundTerm(currentExpr, out, letMap);
1056 paren << ")";
1057 it->second.increment();
1058 }
1059
1060 out << std::endl << std::endl;
1061 }
1062
ensureLiteral(Node node)1063 void ProofManager::ensureLiteral(Node node) {
1064 d_cnfProof->ensureLiteral(node);
1065 }
printTrustedTerm(Node term,std::ostream & os,ProofLetMap & globalLetMap)1066 void ProofManager::printTrustedTerm(Node term,
1067 std::ostream& os,
1068 ProofLetMap& globalLetMap)
1069 {
1070 TheoryProofEngine* tpe = ProofManager::currentPM()->getTheoryProofEngine();
1071 if (tpe->printsAsBool(term)) os << "(p_app ";
1072 tpe->printTheoryTerm(term.toExpr(), os, globalLetMap);
1073 if (tpe->printsAsBool(term)) os << ")";
1074 }
1075
ProofManagerStatistics()1076 ProofManager::ProofManagerStatistics::ProofManagerStatistics()
1077 : d_proofProductionTime("proof::ProofManager::proofProductionTime")
1078 {
1079 smtStatisticsRegistry()->registerStat(&d_proofProductionTime);
1080 }
1081
~ProofManagerStatistics()1082 ProofManager::ProofManagerStatistics::~ProofManagerStatistics()
1083 {
1084 smtStatisticsRegistry()->unregisterStat(&d_proofProductionTime);
1085 }
1086
1087 } /* CVC4 namespace */
1088