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