1 /*********************                                                        */
2 /*! \file sat_proof_implementation.h
3  ** \verbatim
4  ** Top contributors (to current version):
5  **   Liana Hadarean, Tim King, Guy Katz
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  ** \brief Resolution proof
13  **
14  ** Resolution proof
15  **/
16 
17 #include "cvc4_private.h"
18 
19 #ifndef __CVC4__SAT__PROOF_IMPLEMENTATION_H
20 #define __CVC4__SAT__PROOF_IMPLEMENTATION_H
21 
22 #include "proof/clause_id.h"
23 #include "proof/cnf_proof.h"
24 #include "proof/sat_proof.h"
25 #include "prop/bvminisat/bvminisat.h"
26 #include "prop/bvminisat/core/Solver.h"
27 #include "prop/minisat/core/Solver.h"
28 #include "prop/minisat/minisat.h"
29 #include "prop/sat_solver_types.h"
30 #include "smt/smt_statistics_registry.h"
31 
32 namespace CVC4 {
33 
34 template <class Solver>
printLit(typename Solver::TLit l)35 void printLit(typename Solver::TLit l) {
36   Debug("proof:sat") << (sign(l) ? "-" : "") << var(l) + 1;
37 }
38 
39 template <class Solver>
printClause(const typename Solver::TClause & c)40 void printClause(const typename Solver::TClause& c) {
41   for (int i = 0; i < c.size(); i++) {
42     Debug("proof:sat") << (sign(c[i]) ? "-" : "") << var(c[i]) + 1 << " ";
43   }
44 }
45 
46 template <class Solver>
printClause(const std::vector<typename Solver::TLit> & c)47 void printClause(const std::vector<typename Solver::TLit>& c) {
48   for (unsigned i = 0; i < c.size(); i++) {
49     Debug("proof:sat") << (sign(c[i]) ? "-" : "") << var(c[i]) + 1 << " ";
50   }
51 }
52 
53 template <class Solver>
printLitSet(const std::set<typename Solver::TLit> & s)54 void printLitSet(const std::set<typename Solver::TLit>& s) {
55   typename std::set<typename Solver::TLit>::const_iterator it = s.begin();
56   for (; it != s.end(); ++it) {
57     printLit<Solver>(*it);
58     Debug("proof:sat") << " ";
59   }
60   Debug("proof:sat") << std::endl;
61 }
62 
63 // purely debugging functions
64 template <class Solver>
printDebug(typename Solver::TLit l)65 void printDebug(typename Solver::TLit l) {
66   Debug("proof:sat") << (sign(l) ? "-" : "") << var(l) + 1 << std::endl;
67 }
68 template <class Solver>
printDebug(typename Solver::TClause & c)69 void printDebug(typename Solver::TClause& c) {
70   for (int i = 0; i < c.size(); i++) {
71     Debug("proof:sat") << (sign(c[i]) ? "-" : "") << var(c[i]) + 1 << " ";
72   }
73   Debug("proof:sat") << std::endl;
74 }
75 
76 /**
77  * Converts the clause associated to id to a set of literals
78  *
79  * @param id the clause id
80  * @param set the clause converted to a set of literals
81  */
82 template <class Solver>
createLitSet(ClauseId id,LitSet & set)83 void TSatProof<Solver>::createLitSet(ClauseId id, LitSet& set) {
84   Assert(set.empty());
85   if (isUnit(id)) {
86     set.insert(getUnit(id));
87     return;
88   }
89   if (id == d_emptyClauseId) {
90     return;
91   }
92   // if it's an assumption
93   if (d_assumptionConflictsDebug.find(id) != d_assumptionConflictsDebug.end()) {
94     LitVector* clause = d_assumptionConflictsDebug[id];
95     for (unsigned i = 0; i < clause->size(); ++i) {
96       set.insert(clause->operator[](i));
97     }
98     return;
99   }
100 
101   typename Solver::TCRef ref = getClauseRef(id);
102   const typename Solver::TClause& c = getClause(ref);
103   for (int i = 0; i < c.size(); i++) {
104     set.insert(c[i]);
105   }
106 }
107 
108 /**
109  * Resolves clause1 and clause2 on variable var and stores the
110  * result in clause1
111  * @param v
112  * @param clause1
113  * @param clause2
114  */
115 template <class Solver>
resolve(const typename Solver::TLit v,std::set<typename Solver::TLit> & clause1,std::set<typename Solver::TLit> & clause2,bool s)116 bool resolve(const typename Solver::TLit v,
117              std::set<typename Solver::TLit>& clause1,
118              std::set<typename Solver::TLit>& clause2, bool s) {
119   Assert(!clause1.empty());
120   Assert(!clause2.empty());
121   typename Solver::TLit var = sign(v) ? ~v : v;
122   if (s) {
123     // literal appears positive in the first clause
124     if (!clause2.count(~var)) {
125       if (Debug.isOn("proof:sat")) {
126         Debug("proof:sat") << "proof:resolve: Missing literal ";
127         printLit<Solver>(var);
128         Debug("proof:sat") << std::endl;
129       }
130       return false;
131     }
132     clause1.erase(var);
133     clause2.erase(~var);
134     typename std::set<typename Solver::TLit>::iterator it = clause2.begin();
135     for (; it != clause2.end(); ++it) {
136       clause1.insert(*it);
137     }
138   } else {
139     // literal appears negative in the first clause
140     if (!clause1.count(~var) || !clause2.count(var)) {
141       if (Debug.isOn("proof:sat")) {
142         Debug("proof:sat") << "proof:resolve: Missing literal ";
143         printLit<Solver>(var);
144         Debug("proof:sat") << std::endl;
145       }
146       return false;
147     }
148     clause1.erase(~var);
149     clause2.erase(var);
150     typename std::set<typename Solver::TLit>::iterator it = clause2.begin();
151     for (; it != clause2.end(); ++it) {
152       clause1.insert(*it);
153     }
154   }
155   return true;
156 }
157 
158 /// ResChain
159 template <class Solver>
ResChain(ClauseId start)160 ResChain<Solver>::ResChain(ClauseId start)
161     : d_start(start), d_steps(), d_redundantLits(NULL) {}
162 
163 template <class Solver>
~ResChain()164 ResChain<Solver>::~ResChain() {
165   if (d_redundantLits != NULL) {
166     delete d_redundantLits;
167   }
168 }
169 
170 template <class Solver>
addStep(typename Solver::TLit lit,ClauseId id,bool sign)171 void ResChain<Solver>::addStep(typename Solver::TLit lit, ClauseId id,
172                                bool sign) {
173   ResStep<Solver> step(lit, id, sign);
174   d_steps.push_back(step);
175 }
176 
177 template <class Solver>
addRedundantLit(typename Solver::TLit lit)178 void ResChain<Solver>::addRedundantLit(typename Solver::TLit lit) {
179   if (d_redundantLits) {
180     d_redundantLits->insert(lit);
181   } else {
182     d_redundantLits = new LitSet();
183     d_redundantLits->insert(lit);
184   }
185 }
186 
187 /// SatProof
188 template <class Solver>
TSatProof(Solver * solver,context::Context * context,const std::string & name,bool checkRes)189 TSatProof<Solver>::TSatProof(Solver* solver, context::Context* context,
190                              const std::string& name, bool checkRes)
191     : d_name(name),
192       d_emptyClauseId(ClauseIdEmpty),
193       d_seenLearnt(),
194       d_assumptionConflictsDebug(),
195       d_solver(solver),
196       d_context(context),
197       d_idClause(),
198       d_clauseId(),
199       d_idUnit(context),
200       d_unitId(context),
201       d_deleted(),
202       d_inputClauses(),
203       d_lemmaClauses(),
204       d_assumptions(),
205       d_assumptionConflicts(),
206       d_resolutionChains(d_context),
207       d_resStack(),
208       d_checkRes(checkRes),
209       d_nullId(-2),
210       d_temp_clauseId(),
211       d_temp_idClause(),
212       d_unitConflictId(context),
213       d_trueLit(ClauseIdUndef),
214       d_falseLit(ClauseIdUndef),
215       d_seenInputs(),
216       d_seenLemmas(),
217       d_satProofConstructed(false),
218       d_statistics(name) {
219 }
220 
221 template <class Solver>
~TSatProof()222 TSatProof<Solver>::~TSatProof() {
223   // FIXME: double free if deleted clause also appears in d_seenLemmas?
224   IdToSatClause::const_iterator it = d_deletedTheoryLemmas.begin();
225   IdToSatClause::const_iterator end = d_deletedTheoryLemmas.end();
226 
227   for (; it != end; ++it) {
228     ClauseId id = it->first;
229     // otherwise deleted in next loop
230     if (d_seenLemmas.find(id) == d_seenLemmas.end()) {
231       delete it->second;
232     }
233   }
234 
235   IdToSatClause::const_iterator seen_lemma_it = d_seenLemmas.begin();
236   IdToSatClause::const_iterator seen_lemma_end = d_seenLemmas.end();
237 
238   for (; seen_lemma_it != seen_lemma_end; ++seen_lemma_it) {
239     delete seen_lemma_it->second;
240   }
241 
242   IdToSatClause::const_iterator seen_input_it = d_seenInputs.begin();
243   IdToSatClause::const_iterator seen_input_end = d_seenInputs.end();
244 
245   for (; seen_input_it != seen_input_end; ++seen_input_it) {
246     delete seen_input_it->second;
247   }
248 
249   typedef typename IdResMap::const_iterator ResolutionChainIterator;
250   ResolutionChainIterator resolution_it = d_resolutionChains.begin();
251   ResolutionChainIterator resolution_it_end = d_resolutionChains.end();
252   for (; resolution_it != resolution_it_end; ++resolution_it) {
253     ResChain<Solver>* current = (*resolution_it).second;
254     delete current;
255   }
256 
257   // It could be the case that d_resStack is not empty at destruction time
258   // (for example in the SAT case).
259   typename ResStack::const_iterator resolution_stack_it = d_resStack.begin();
260   typename ResStack::const_iterator resolution_stack_it_end = d_resStack.end();
261   for (; resolution_stack_it != resolution_stack_it_end;
262        ++resolution_stack_it) {
263     ResChain<Solver>* current = *resolution_stack_it;
264     delete current;
265   }
266 }
267 
268 /**
269  * Returns true if the resolution chain corresponding to id
270  * does resolve to the clause associated to id
271  * @param id
272  *
273  * @return
274  */
275 template <class Solver>
checkResolution(ClauseId id)276 bool TSatProof<Solver>::checkResolution(ClauseId id) {
277   if (d_checkRes) {
278     bool validRes = true;
279     Assert(hasResolutionChain(id));
280     const ResolutionChain& res = getResolutionChain(id);
281     LitSet clause1;
282     createLitSet(res.getStart(), clause1);
283     const typename ResolutionChain::ResSteps& steps = res.getSteps();
284     for (unsigned i = 0; i < steps.size(); i++) {
285       typename Solver::TLit var = steps[i].lit;
286       LitSet clause2;
287       createLitSet(steps[i].id, clause2);
288       bool res = resolve<Solver>(var, clause1, clause2, steps[i].sign);
289       if (res == false) {
290         validRes = false;
291         break;
292       }
293     }
294     // compare clause we claimed to prove with the resolution result
295     if (isUnit(id)) {
296       // special case if it was a unit clause
297       typename Solver::TLit unit = getUnit(id);
298       validRes = clause1.size() == clause1.count(unit) && !clause1.empty();
299       return validRes;
300     }
301     if (id == d_emptyClauseId) {
302       return clause1.empty();
303     }
304 
305     LitVector c;
306     getLitVec(id, c);
307 
308     for (unsigned i = 0; i < c.size(); ++i) {
309       int count = clause1.erase(c[i]);
310       if (count == 0) {
311         if (Debug.isOn("proof:sat")) {
312           Debug("proof:sat")
313               << "proof:checkResolution::literal not in computed result ";
314           printLit<Solver>(c[i]);
315           Debug("proof:sat") << "\n";
316         }
317         validRes = false;
318       }
319     }
320     validRes = clause1.empty();
321     if (!validRes) {
322       if (Debug.isOn("proof:sat")) {
323         Debug("proof:sat") << "proof:checkResolution::Invalid Resolution, "
324                               "unremoved literals: \n";
325         printLitSet<Solver>(clause1);
326         Debug("proof:sat") << "proof:checkResolution:: result should be: \n";
327         printClause<Solver>(c);
328       }
329     }
330     return validRes;
331 
332   } else {
333     return true;
334   }
335 }
336 
337 /// helper methods
338 template <class Solver>
hasClauseIdForCRef(typename Solver::TCRef ref)339 bool TSatProof<Solver>::hasClauseIdForCRef(typename Solver::TCRef ref) const {
340   return d_clauseId.find(ref) != d_clauseId.end();
341 }
342 
343 template <class Solver>
getClauseIdForCRef(typename Solver::TCRef ref)344 ClauseId TSatProof<Solver>::getClauseIdForCRef(
345     typename Solver::TCRef ref) const {
346   if (d_clauseId.find(ref) == d_clauseId.end()) {
347     Debug("proof:sat") << "Missing clause \n";
348   }
349   Assert(hasClauseIdForCRef(ref));
350   return d_clauseId.find(ref)->second;
351 }
352 
353 template <class Solver>
hasClauseIdForLiteral(typename Solver::TLit lit)354 bool TSatProof<Solver>::hasClauseIdForLiteral(typename Solver::TLit lit) const {
355   return d_unitId.find(toInt(lit)) != d_unitId.end();
356 }
357 
358 template <class Solver>
getClauseIdForLiteral(typename Solver::TLit lit)359 ClauseId TSatProof<Solver>::getClauseIdForLiteral(
360     typename Solver::TLit lit) const {
361   Assert(hasClauseIdForLiteral(lit));
362   return (*d_unitId.find(toInt(lit))).second;
363 }
364 
365 template <class Solver>
hasClauseRef(ClauseId id)366 bool TSatProof<Solver>::hasClauseRef(ClauseId id) const {
367   return d_idClause.find(id) != d_idClause.end();
368 }
369 
370 template <class Solver>
getClauseRef(ClauseId id)371 typename Solver::TCRef TSatProof<Solver>::getClauseRef(ClauseId id) const {
372   if (!hasClauseRef(id)) {
373     Debug("proof:sat") << "proof:getClauseRef cannot find clause " << id << " "
374                        << ((d_deleted.find(id) != d_deleted.end()) ? "deleted"
375                                                                    : "")
376                        << (isUnit(id) ? "Unit" : "") << std::endl;
377   }
378   Assert(hasClauseRef(id));
379   return d_idClause.find(id)->second;
380 }
381 
382 template <class Solver>
getClause(typename Solver::TCRef ref)383 const typename Solver::TClause& TSatProof<Solver>::getClause(
384     typename Solver::TCRef ref) const {
385   Assert(ref != Solver::TCRef_Undef);
386   Assert(ref >= 0 && ref < d_solver->ca.size());
387   return d_solver->ca[ref];
388 }
389 
390 template <class Solver>
getLitVec(ClauseId id,LitVector & vec)391 void TSatProof<Solver>::getLitVec(ClauseId id, LitVector& vec) {
392   if (isUnit(id)) {
393     typename Solver::TLit lit = getUnit(id);
394     vec.push_back(lit);
395     return;
396   }
397   if (isAssumptionConflict(id)) {
398     vec = *(d_assumptionConflictsDebug[id]);
399     return;
400   }
401   typename Solver::TCRef cref = getClauseRef(id);
402   const typename Solver::TClause& cl = getClause(cref);
403   for (int i = 0; i < cl.size(); ++i) {
404     vec.push_back(cl[i]);
405   }
406 }
407 
408 template <class Solver>
isUnit(ClauseId id)409 bool TSatProof<Solver>::isUnit(ClauseId id) const {
410   return d_idUnit.find(id) != d_idUnit.end();
411 }
412 
413 template <class Solver>
getUnit(ClauseId id)414 typename Solver::TLit TSatProof<Solver>::getUnit(ClauseId id) const {
415   Assert(isUnit(id));
416   return (*d_idUnit.find(id)).second;
417 }
418 
419 template <class Solver>
isUnit(typename Solver::TLit lit)420 bool TSatProof<Solver>::isUnit(typename Solver::TLit lit) const {
421   return d_unitId.find(toInt(lit)) != d_unitId.end();
422 }
423 
424 template <class Solver>
getUnitId(typename Solver::TLit lit)425 ClauseId TSatProof<Solver>::getUnitId(typename Solver::TLit lit) const {
426   Assert(isUnit(lit));
427   return (*d_unitId.find(toInt(lit))).second;
428 }
429 
430 template <class Solver>
hasResolutionChain(ClauseId id)431 bool TSatProof<Solver>::hasResolutionChain(ClauseId id) const {
432   return d_resolutionChains.find(id) != d_resolutionChains.end();
433 }
434 
435 template <class Solver>
436 const typename TSatProof<Solver>::ResolutionChain&
getResolutionChain(ClauseId id)437 TSatProof<Solver>::getResolutionChain(ClauseId id) const {
438   Assert(hasResolutionChain(id));
439   const ResolutionChain* chain = (*d_resolutionChains.find(id)).second;
440   return *chain;
441 }
442 
443 template <class Solver>
isInputClause(ClauseId id)444 bool TSatProof<Solver>::isInputClause(ClauseId id) const {
445   return d_inputClauses.find(id) != d_inputClauses.end();
446 }
447 
448 template <class Solver>
isLemmaClause(ClauseId id)449 bool TSatProof<Solver>::isLemmaClause(ClauseId id) const {
450   return d_lemmaClauses.find(id) != d_lemmaClauses.end();
451 }
452 
453 template <class Solver>
isAssumptionConflict(ClauseId id)454 bool TSatProof<Solver>::isAssumptionConflict(ClauseId id) const {
455   return d_assumptionConflicts.find(id) != d_assumptionConflicts.end();
456 }
457 
458 template <class Solver>
print(ClauseId id)459 void TSatProof<Solver>::print(ClauseId id) const {
460   if (d_deleted.find(id) != d_deleted.end()) {
461     Debug("proof:sat") << "del" << id;
462   } else if (isUnit(id)) {
463     printLit<Solver>(getUnit(id));
464   } else if (id == d_emptyClauseId) {
465     Debug("proof:sat") << "empty " << std::endl;
466   } else {
467     typename Solver::TCRef ref = getClauseRef(id);
468     printClause<Solver>(getClause(ref));
469   }
470 }
471 
472 template <class Solver>
printRes(ClauseId id)473 void TSatProof<Solver>::printRes(ClauseId id) const {
474   Assert(hasResolutionChain(id));
475   Debug("proof:sat") << "id " << id << ": ";
476   printRes(getResolutionChain(id));
477 }
478 
479 template <class Solver>
printRes(const ResolutionChain & res)480 void TSatProof<Solver>::printRes(const ResolutionChain& res) const {
481   ClauseId start_id = res.getStart();
482 
483   if (Debug.isOn("proof:sat")) {
484     Debug("proof:sat") << "(";
485     print(start_id);
486   }
487 
488   const typename ResolutionChain::ResSteps& steps = res.getSteps();
489   for (unsigned i = 0; i < steps.size(); i++) {
490     typename Solver::TLit v = steps[i].lit;
491     ClauseId id = steps[i].id;
492 
493     if (Debug.isOn("proof:sat")) {
494       Debug("proof:sat") << "[";
495       printLit<Solver>(v);
496       Debug("proof:sat") << "] ";
497       print(id);
498     }
499   }
500   Debug("proof:sat") << ") \n";
501 }
502 
503 /// registration methods
504 template <class Solver>
registerClause(typename Solver::TCRef clause,ClauseKind kind)505 ClauseId TSatProof<Solver>::registerClause(typename Solver::TCRef clause,
506                                            ClauseKind kind) {
507   Assert(clause != Solver::TCRef_Undef);
508   typename ClauseIdMap::iterator it = d_clauseId.find(clause);
509   if (it == d_clauseId.end()) {
510     ClauseId newId = ProofManager::currentPM()->nextId();
511 
512     d_clauseId.insert(std::make_pair(clause, newId));
513     d_idClause.insert(std::make_pair(newId, clause));
514     if (kind == INPUT) {
515       Assert(d_inputClauses.find(newId) == d_inputClauses.end());
516       d_inputClauses.insert(newId);
517     }
518     if (kind == THEORY_LEMMA) {
519       Assert(d_lemmaClauses.find(newId) == d_lemmaClauses.end());
520       d_lemmaClauses.insert(newId);
521       Debug("pf::sat") << "TSatProof::registerClause registering a new lemma clause: "
522                        << newId << " = " << *buildClause(newId)
523                        << std::endl;
524     }
525   }
526 
527   ClauseId id = d_clauseId[clause];
528   Assert(kind != INPUT || d_inputClauses.count(id));
529   Assert(kind != THEORY_LEMMA || d_lemmaClauses.count(id));
530 
531   Debug("proof:sat:detailed") << "registerClause CRef: " << clause
532                               << " id: " << d_clauseId[clause]
533                               << "                kind: " << kind << "\n";
534   // ProofManager::currentPM()->setRegisteredClauseId( d_clauseId[clause] );
535   return id;
536 }
537 
538 template <class Solver>
registerUnitClause(typename Solver::TLit lit,ClauseKind kind)539 ClauseId TSatProof<Solver>::registerUnitClause(typename Solver::TLit lit,
540                                                ClauseKind kind) {
541   Debug("cores") << "registerUnitClause " << kind << std::endl;
542   typename UnitIdMap::iterator it = d_unitId.find(toInt(lit));
543   if (it == d_unitId.end()) {
544     ClauseId newId = ProofManager::currentPM()->nextId();
545 
546     if (d_unitId.find(toInt(lit)) == d_unitId.end())
547       d_unitId[toInt(lit)] = newId;
548     if (d_idUnit.find(newId) == d_idUnit.end())
549       d_idUnit[newId] = lit;
550 
551     if (kind == INPUT) {
552       Assert(d_inputClauses.find(newId) == d_inputClauses.end());
553       Debug("pf::sat") << "TSatProof::registerUnitClause: registering a new "
554                           "input (UNIT CLAUSE): "
555                        << lit << std::endl;
556       d_inputClauses.insert(newId);
557     }
558     if (kind == THEORY_LEMMA) {
559       Assert(d_lemmaClauses.find(newId) == d_lemmaClauses.end());
560       Debug("pf::sat") << "TSatProof::registerUnitClause: registering a new lemma (UNIT CLAUSE): "
561                        << lit
562                        << std::endl;
563       d_lemmaClauses.insert(newId);
564     }
565   }
566   ClauseId id = d_unitId[toInt(lit)];
567   Assert(kind != INPUT || d_inputClauses.count(id));
568   Assert(kind != THEORY_LEMMA || d_lemmaClauses.count(id));
569   Debug("proof:sat:detailed") << "registerUnitClause id: " << id
570                               << " kind: " << kind << "\n";
571   // ProofManager::currentPM()->setRegisteredClauseId( d_unitId[toInt(lit)] );
572   return id;
573 }
574 template <class Solver>
registerTrueLit(const typename Solver::TLit lit)575 void TSatProof<Solver>::registerTrueLit(const typename Solver::TLit lit) {
576   Assert(d_trueLit == ClauseIdUndef);
577   d_trueLit = registerUnitClause(lit, INPUT);
578 }
579 
580 template <class Solver>
registerFalseLit(const typename Solver::TLit lit)581 void TSatProof<Solver>::registerFalseLit(const typename Solver::TLit lit) {
582   Assert(d_falseLit == ClauseIdUndef);
583   d_falseLit = registerUnitClause(lit, INPUT);
584 }
585 
586 template <class Solver>
getTrueUnit()587 ClauseId TSatProof<Solver>::getTrueUnit() const {
588   Assert(d_trueLit != ClauseIdUndef);
589   return d_trueLit;
590 }
591 
592 template <class Solver>
getFalseUnit()593 ClauseId TSatProof<Solver>::getFalseUnit() const {
594   Assert(d_falseLit != ClauseIdUndef);
595   return d_falseLit;
596 }
597 
598 template <class Solver>
registerAssumption(const typename Solver::TVar var)599 void TSatProof<Solver>::registerAssumption(const typename Solver::TVar var) {
600   Assert(d_assumptions.find(var) == d_assumptions.end());
601   d_assumptions.insert(var);
602 }
603 
604 template <class Solver>
registerAssumptionConflict(const typename Solver::TLitVec & confl)605 ClauseId TSatProof<Solver>::registerAssumptionConflict(
606     const typename Solver::TLitVec& confl) {
607   Debug("proof:sat:detailed") << "registerAssumptionConflict " << std::endl;
608   // Uniqueness is checked in the bit-vector proof
609   // should be vars
610   for (int i = 0; i < confl.size(); ++i) {
611     Assert(d_assumptions.find(var(confl[i])) != d_assumptions.end());
612   }
613   ClauseId new_id = ProofManager::currentPM()->nextId();
614   d_assumptionConflicts.insert(new_id);
615   LitVector* vec_confl = new LitVector(confl.size());
616   for (int i = 0; i < confl.size(); ++i) {
617     vec_confl->operator[](i) = confl[i];
618   }
619   if (Debug.isOn("proof:sat:detailed")) {
620     printClause<Solver>(*vec_confl);
621     Debug("proof:sat:detailed") << "\n";
622   }
623 
624   d_assumptionConflictsDebug[new_id] = vec_confl;
625   return new_id;
626 }
627 
628 template <class Solver>
removedDfs(typename Solver::TLit lit,LitSet * removedSet,LitVector & removeStack,LitSet & inClause,LitSet & seen)629 void TSatProof<Solver>::removedDfs(typename Solver::TLit lit,
630                                    LitSet* removedSet, LitVector& removeStack,
631                                    LitSet& inClause, LitSet& seen) {
632   // if we already added the literal return
633   if (seen.count(lit)) {
634     return;
635   }
636 
637   typename Solver::TCRef reason_ref = d_solver->reason(var(lit));
638   if (reason_ref == Solver::TCRef_Undef) {
639     seen.insert(lit);
640     removeStack.push_back(lit);
641     return;
642   }
643 
644   int size = getClause(reason_ref).size();
645   for (int i = 1; i < size; i++) {
646     typename Solver::TLit v = getClause(reason_ref)[i];
647     if (inClause.count(v) == 0 && seen.count(v) == 0) {
648       removedDfs(v, removedSet, removeStack, inClause, seen);
649     }
650   }
651   if (seen.count(lit) == 0) {
652     seen.insert(lit);
653     removeStack.push_back(lit);
654   }
655 }
656 
657 template <class Solver>
removeRedundantFromRes(ResChain<Solver> * res,ClauseId id)658 void TSatProof<Solver>::removeRedundantFromRes(ResChain<Solver>* res,
659                                                ClauseId id) {
660   LitSet* removed = res->getRedundant();
661   if (removed == NULL) {
662     return;
663   }
664 
665   LitSet inClause;
666   createLitSet(id, inClause);
667 
668   LitVector removeStack;
669   LitSet seen;
670   for (typename LitSet::iterator it = removed->begin(); it != removed->end();
671        ++it) {
672     removedDfs(*it, removed, removeStack, inClause, seen);
673   }
674 
675   for (int i = removeStack.size() - 1; i >= 0; --i) {
676     typename Solver::TLit lit = removeStack[i];
677     typename Solver::TCRef reason_ref = d_solver->reason(var(lit));
678     ClauseId reason_id;
679 
680     if (reason_ref == Solver::TCRef_Undef) {
681       Assert(isUnit(~lit));
682       reason_id = getUnitId(~lit);
683     } else {
684       reason_id = registerClause(reason_ref, LEARNT);
685     }
686     res->addStep(lit, reason_id, !sign(lit));
687   }
688   removed->clear();
689 }
690 
691 template <class Solver>
registerResolution(ClauseId id,ResChain<Solver> * res)692 void TSatProof<Solver>::registerResolution(ClauseId id, ResChain<Solver>* res) {
693   Assert(res != NULL);
694 
695   removeRedundantFromRes(res, id);
696   Assert(res->redundantRemoved());
697 
698   // Because the SAT solver can add the same clause multiple times, it
699   // could be the case that a resolution chain for this clause already
700   // exists (e.g. when removing units in addClause).
701   if (hasResolutionChain(id)) {
702     ResChain<Solver>* current = (*d_resolutionChains.find(id)).second;
703     delete current;
704   }
705 
706   d_resolutionChains.insert(id, res);
707 
708   if (Debug.isOn("proof:sat")) {
709     printRes(id);
710   }
711   if (d_checkRes) {
712     Assert(checkResolution(id));
713   }
714 
715   PSTATS(uint64_t resolutionSteps =
716              static_cast<uint64_t>(res.getSteps().size());
717          d_statistics.d_resChainLengths << resolutionSteps;
718          d_statistics.d_avgChainLength.addEntry(resolutionSteps);
719          ++(d_statistics.d_numLearnedClauses);)
720 }
721 
722 /// recording resolutions
723 template <class Solver>
startResChain(typename Solver::TCRef start)724 void TSatProof<Solver>::startResChain(typename Solver::TCRef start) {
725   ClauseId id = getClauseIdForCRef(start);
726   ResolutionChain* res = new ResolutionChain(id);
727   d_resStack.push_back(res);
728 }
729 
730 template <class Solver>
startResChain(typename Solver::TLit start)731 void TSatProof<Solver>::startResChain(typename Solver::TLit start) {
732   ClauseId id = getUnitId(start);
733   ResolutionChain* res = new ResolutionChain(id);
734   d_resStack.push_back(res);
735 }
736 
737 template <class Solver>
addResolutionStep(typename Solver::TLit lit,typename Solver::TCRef clause,bool sign)738 void TSatProof<Solver>::addResolutionStep(typename Solver::TLit lit,
739                                           typename Solver::TCRef clause,
740                                           bool sign) {
741   ClauseId id = registerClause(clause, LEARNT);
742   ResChain<Solver>* res = d_resStack.back();
743   res->addStep(lit, id, sign);
744 }
745 
746 template <class Solver>
endResChain(ClauseId id)747 void TSatProof<Solver>::endResChain(ClauseId id) {
748   Debug("proof:sat:detailed") << "endResChain " << id << "\n";
749   Assert(d_resStack.size() > 0);
750   ResChain<Solver>* res = d_resStack.back();
751   registerResolution(id, res);
752   d_resStack.pop_back();
753 }
754 
755 template <class Solver>
endResChain(typename Solver::TLit lit)756 void TSatProof<Solver>::endResChain(typename Solver::TLit lit) {
757   Assert(d_resStack.size() > 0);
758   ClauseId id = registerUnitClause(lit, LEARNT);
759   Debug("proof:sat:detailed") << "endResChain unit " << id << "\n";
760   ResolutionChain* res = d_resStack.back();
761   d_glueMap[id] = 1;
762   registerResolution(id, res);
763   d_resStack.pop_back();
764 }
765 
766 template <class Solver>
cancelResChain()767 void TSatProof<Solver>::cancelResChain() {
768   Assert(d_resStack.size() > 0);
769   ResolutionChain* back = d_resStack.back();
770   delete back;
771   d_resStack.pop_back();
772 }
773 
774 template <class Solver>
storeLitRedundant(typename Solver::TLit lit)775 void TSatProof<Solver>::storeLitRedundant(typename Solver::TLit lit) {
776   Assert(d_resStack.size() > 0);
777   ResolutionChain* res = d_resStack.back();
778   res->addRedundantLit(lit);
779 }
780 
781 /// constructing resolutions
782 template <class Solver>
resolveOutUnit(typename Solver::TLit lit)783 void TSatProof<Solver>::resolveOutUnit(typename Solver::TLit lit) {
784   ClauseId id = resolveUnit(~lit);
785   ResChain<Solver>* res = d_resStack.back();
786   res->addStep(lit, id, !sign(lit));
787 }
788 template <class Solver>
storeUnitResolution(typename Solver::TLit lit)789 void TSatProof<Solver>::storeUnitResolution(typename Solver::TLit lit) {
790   Debug("cores") << "STORE UNIT RESOLUTION" << std::endl;
791   resolveUnit(lit);
792 }
793 template <class Solver>
resolveUnit(typename Solver::TLit lit)794 ClauseId TSatProof<Solver>::resolveUnit(typename Solver::TLit lit) {
795   // first check if we already have a resolution for lit
796 
797   if (isUnit(lit)) {
798     ClauseId id = getClauseIdForLiteral(lit);
799     Assert(hasResolutionChain(id) || isInputClause(id) || isLemmaClause(id));
800     return id;
801   }
802   typename Solver::TCRef reason_ref = d_solver->reason(var(lit));
803   Assert(reason_ref != Solver::TCRef_Undef);
804 
805   ClauseId reason_id = registerClause(reason_ref, LEARNT);
806 
807   ResChain<Solver>* res = new ResChain<Solver>(reason_id);
808   // Here, the call to resolveUnit() can reallocate memory in the
809   // clause allocator.  So reload reason ptr each time.
810   const typename Solver::TClause& initial_reason = getClause(reason_ref);
811   size_t current_reason_size = initial_reason.size();
812   for (size_t i = 0; i < current_reason_size; i++) {
813     const typename Solver::TClause& current_reason = getClause(reason_ref);
814     current_reason_size = current_reason.size();
815     typename Solver::TLit l = current_reason[i];
816     if (lit != l) {
817       ClauseId res_id = resolveUnit(~l);
818       res->addStep(l, res_id, !sign(l));
819     }
820   }
821   ClauseId unit_id = registerUnitClause(lit, LEARNT);
822   registerResolution(unit_id, res);
823   return unit_id;
824 }
825 
826 template <class Solver>
storeUnitConflict(typename Solver::TLit conflict_lit,ClauseKind kind)827 ClauseId TSatProof<Solver>::storeUnitConflict(
828     typename Solver::TLit conflict_lit, ClauseKind kind) {
829   Debug("cores") << "STORE UNIT CONFLICT" << std::endl;
830   Assert(!d_unitConflictId.isSet());
831   d_unitConflictId.set(registerUnitClause(conflict_lit, kind));
832   Debug("proof:sat:detailed") << "storeUnitConflict " << d_unitConflictId.get()
833                               << "\n";
834   return d_unitConflictId.get();
835 }
836 
837 template <class Solver>
finalizeProof(typename Solver::TCRef conflict_ref)838 void TSatProof<Solver>::finalizeProof(typename Solver::TCRef conflict_ref) {
839   Assert(d_resStack.size() == 0);
840   Assert(conflict_ref != Solver::TCRef_Undef);
841   ClauseId conflict_id;
842   if (conflict_ref == Solver::TCRef_Lazy) {
843     Assert(d_unitConflictId.isSet());
844     conflict_id = d_unitConflictId.get();
845 
846     ResChain<Solver>* res = new ResChain<Solver>(conflict_id);
847     typename Solver::TLit lit = d_idUnit[conflict_id];
848     ClauseId res_id = resolveUnit(~lit);
849     res->addStep(lit, res_id, !sign(lit));
850     registerResolution(d_emptyClauseId, res);
851     return;
852 
853   } else {
854     Assert(!d_unitConflictId.isSet());
855     conflict_id = registerClause(conflict_ref, LEARNT);  // FIXME
856   }
857 
858   if (Debug.isOn("proof:sat")) {
859     Debug("proof:sat") << "proof::finalizeProof Final Conflict ";
860     print(conflict_id);
861     Debug("proof:sat") << std::endl;
862   }
863 
864   ResChain<Solver>* res = new ResChain<Solver>(conflict_id);
865   // Here, the call to resolveUnit() can reallocate memory in the
866   // clause allocator.  So reload conflict ptr each time.
867   for (int i = 0; i < getClause(conflict_ref).size(); ++i) {
868     const typename Solver::TClause& conflict = getClause(conflict_ref);
869     typename Solver::TLit lit = conflict[i];
870     ClauseId res_id = resolveUnit(~lit);
871     res->addStep(lit, res_id, !sign(lit));
872   }
873 
874   registerResolution(d_emptyClauseId, res);
875 }
876 
877 /// CRef manager
878 template <class Solver>
updateCRef(typename Solver::TCRef oldref,typename Solver::TCRef newref)879 void TSatProof<Solver>::updateCRef(typename Solver::TCRef oldref,
880                                    typename Solver::TCRef newref) {
881   if (d_clauseId.find(oldref) == d_clauseId.end()) {
882     return;
883   }
884   ClauseId id = getClauseIdForCRef(oldref);
885   Assert(d_temp_clauseId.find(newref) == d_temp_clauseId.end());
886   Assert(d_temp_idClause.find(id) == d_temp_idClause.end());
887   d_temp_clauseId[newref] = id;
888   d_temp_idClause[id] = newref;
889 }
890 
891 template <class Solver>
finishUpdateCRef()892 void TSatProof<Solver>::finishUpdateCRef() {
893   d_clauseId.swap(d_temp_clauseId);
894   d_temp_clauseId.clear();
895 
896   d_idClause.swap(d_temp_idClause);
897   d_temp_idClause.clear();
898 }
899 
900 template <class Solver>
markDeleted(typename Solver::TCRef clause)901 void TSatProof<Solver>::markDeleted(typename Solver::TCRef clause) {
902   if (hasClauseIdForCRef(clause)) {
903     ClauseId id = getClauseIdForCRef(clause);
904     Assert(d_deleted.find(id) == d_deleted.end());
905     d_deleted.insert(id);
906     if (isLemmaClause(id)) {
907       const typename Solver::TClause& minisat_cl = getClause(clause);
908       prop::SatClause* sat_cl = new prop::SatClause();
909       toSatClause<Solver>(minisat_cl, *sat_cl);
910       d_deletedTheoryLemmas.insert(std::make_pair(id, sat_cl));
911     }
912   }
913 }
914 
915 // template<>
916 // void toSatClause< ::BVMinisat::Solver> (const BVMinisat::Solver::TClause&
917 // minisat_cl,
918 //                                         prop::SatClause& sat_cl) {
919 
920 //   prop::BVMinisatSatSolver::toSatClause(minisat_cl, sat_cl);
921 // }
922 
923 template <class Solver>
constructProof(ClauseId conflict)924 void TSatProof<Solver>::constructProof(ClauseId conflict) {
925   d_satProofConstructed = true;
926   collectClauses(conflict);
927 }
928 
929 template <class Solver>
refreshProof(ClauseId conflict)930 void TSatProof<Solver>::refreshProof(ClauseId conflict) {
931   IdToSatClause::const_iterator seen_lemma_it = d_seenLemmas.begin();
932   IdToSatClause::const_iterator seen_lemma_end = d_seenLemmas.end();
933 
934   for (; seen_lemma_it != seen_lemma_end; ++seen_lemma_it) {
935     if (d_deletedTheoryLemmas.find(seen_lemma_it->first) == d_deletedTheoryLemmas.end())
936       delete seen_lemma_it->second;
937   }
938 
939   IdToSatClause::const_iterator seen_input_it = d_seenInputs.begin();
940   IdToSatClause::const_iterator seen_input_end = d_seenInputs.end();
941 
942   for (; seen_input_it != seen_input_end; ++seen_input_it) {
943     delete seen_input_it->second;
944   }
945 
946   d_seenInputs.clear();
947   d_seenLemmas.clear();
948   d_seenLearnt.clear();
949 
950   collectClauses(conflict);
951 }
952 
953 template <class Solver>
proofConstructed()954 bool TSatProof<Solver>::proofConstructed() const {
955   return d_satProofConstructed;
956 }
957 
958 template <class Solver>
buildClause(ClauseId id)959 prop::SatClause* TSatProof<Solver>::buildClause(ClauseId id) {
960   if (isUnit(id)) {
961     typename Solver::TLit lit = getUnit(id);
962     prop::SatLiteral sat_lit = toSatLiteral<Solver>(lit);
963     prop::SatClause* clause = new prop::SatClause();
964     clause->push_back(sat_lit);
965     return clause;
966   }
967 
968   if (isDeleted(id)) {
969     prop::SatClause* clause = d_deletedTheoryLemmas.find(id)->second;
970     return clause;
971   }
972 
973   typename Solver::TCRef ref = getClauseRef(id);
974   const typename Solver::TClause& minisat_cl = getClause(ref);
975   prop::SatClause* clause = new prop::SatClause();
976   toSatClause<Solver>(minisat_cl, *clause);
977   return clause;
978 }
979 
980 template <class Solver>
derivedEmptyClause()981 bool TSatProof<Solver>::derivedEmptyClause() const {
982   return hasResolutionChain(d_emptyClauseId);
983 }
984 
985 template <class Solver>
collectClauses(ClauseId id)986 void TSatProof<Solver>::collectClauses(ClauseId id) {
987   if (d_seenInputs.find(id) != d_seenInputs.end() ||
988       d_seenLemmas.find(id) != d_seenLemmas.end() ||
989       d_seenLearnt.find(id) != d_seenLearnt.end()) {
990     return;
991   }
992 
993   if (isInputClause(id)) {
994     d_seenInputs.insert(std::make_pair(id, buildClause(id)));
995     return;
996   } else if (isLemmaClause(id)) {
997     d_seenLemmas.insert(std::make_pair(id, buildClause(id)));
998     return;
999   } else if (!isAssumptionConflict(id)) {
1000     d_seenLearnt.insert(id);
1001   }
1002 
1003   const ResolutionChain& res = getResolutionChain(id);
1004   const typename ResolutionChain::ResSteps& steps = res.getSteps();
1005   PSTATS(d_statistics.d_usedResChainLengths
1006              << ((uint64_t)steps.size());
1007          d_statistics.d_usedClauseGlue << ((uint64_t)d_glueMap[id]););
1008   ClauseId start = res.getStart();
1009   collectClauses(start);
1010 
1011   for (size_t i = 0; i < steps.size(); i++) {
1012     collectClauses(steps[i].id);
1013   }
1014 }
1015 
1016 template <class Solver>
collectClausesUsed(IdToSatClause & inputs,IdToSatClause & lemmas)1017 void TSatProof<Solver>::collectClausesUsed(IdToSatClause& inputs,
1018                                            IdToSatClause& lemmas) {
1019   inputs = d_seenInputs;
1020   lemmas = d_seenLemmas;
1021   PSTATS(d_statistics.d_numLearnedInProof.setData(d_seenLearnt.size());
1022          d_statistics.d_numLemmasInProof.setData(d_seenLemmas.size()););
1023 }
1024 
1025 template <class Solver>
storeClauseGlue(ClauseId clause,int glue)1026 void TSatProof<Solver>::storeClauseGlue(ClauseId clause, int glue) {
1027   Assert(d_glueMap.find(clause) == d_glueMap.end());
1028   d_glueMap.insert(std::make_pair(clause, glue));
1029 }
1030 
1031 template <class Solver>
Statistics(const std::string & prefix)1032 TSatProof<Solver>::Statistics::Statistics(const std::string& prefix)
1033     : d_numLearnedClauses("satproof::" + prefix + "::NumLearnedClauses", 0),
1034       d_numLearnedInProof("satproof::" + prefix + "::NumLearnedInProof", 0),
1035       d_numLemmasInProof("satproof::" + prefix + "::NumLemmasInProof", 0),
1036       d_avgChainLength("satproof::" + prefix + "::AvgResChainLength"),
1037       d_resChainLengths("satproof::" + prefix + "::ResChainLengthsHist"),
1038       d_usedResChainLengths("satproof::" + prefix +
1039                             "::UsedResChainLengthsHist"),
1040       d_clauseGlue("satproof::" + prefix + "::ClauseGlueHist"),
1041       d_usedClauseGlue("satproof::" + prefix + "::UsedClauseGlueHist") {
1042   smtStatisticsRegistry()->registerStat(&d_numLearnedClauses);
1043   smtStatisticsRegistry()->registerStat(&d_numLearnedInProof);
1044   smtStatisticsRegistry()->registerStat(&d_numLemmasInProof);
1045   smtStatisticsRegistry()->registerStat(&d_avgChainLength);
1046   smtStatisticsRegistry()->registerStat(&d_resChainLengths);
1047   smtStatisticsRegistry()->registerStat(&d_usedResChainLengths);
1048   smtStatisticsRegistry()->registerStat(&d_clauseGlue);
1049   smtStatisticsRegistry()->registerStat(&d_usedClauseGlue);
1050 }
1051 
1052 template <class Solver>
~Statistics()1053 TSatProof<Solver>::Statistics::~Statistics() {
1054   smtStatisticsRegistry()->unregisterStat(&d_numLearnedClauses);
1055   smtStatisticsRegistry()->unregisterStat(&d_numLearnedInProof);
1056   smtStatisticsRegistry()->unregisterStat(&d_numLemmasInProof);
1057   smtStatisticsRegistry()->unregisterStat(&d_avgChainLength);
1058   smtStatisticsRegistry()->unregisterStat(&d_resChainLengths);
1059   smtStatisticsRegistry()->unregisterStat(&d_usedResChainLengths);
1060   smtStatisticsRegistry()->unregisterStat(&d_clauseGlue);
1061   smtStatisticsRegistry()->unregisterStat(&d_usedClauseGlue);
1062 }
1063 
1064 inline std::ostream& operator<<(std::ostream& out, CVC4::ClauseKind k) {
1065   switch (k) {
1066     case CVC4::INPUT:
1067       out << "INPUT";
1068       break;
1069     case CVC4::THEORY_LEMMA:
1070       out << "THEORY_LEMMA";
1071       break;
1072     case CVC4::LEARNT:
1073       out << "LEARNT";
1074       break;
1075     default:
1076       out << "ClauseKind Unknown! [" << unsigned(k) << "]";
1077   }
1078 
1079   return out;
1080 }
1081 
1082 } /* CVC4 namespace */
1083 
1084 #endif /* __CVC4__SAT__PROOF_IMPLEMENTATION_H */
1085