1
2 /*
3 * File Interpolants.cpp.
4 *
5 * This file is part of the source code of the software program
6 * Vampire. It is protected by applicable
7 * copyright laws.
8 *
9 * This source code is distributed under the licence found here
10 * https://vprover.github.io/license.html
11 * and in the source directory
12 *
13 * In summary, you are allowed to use Vampire for non-commercial
14 * purposes but not allowed to distribute, modify, copy, create derivatives,
15 * or use in competitions.
16 * For other uses of Vampire please contact developers for a different
17 * licence, which we will make an effort to provide.
18 */
19 /**
20 * @file Interpolants.cpp
21 * Implements class Interpolants.
22 */
23
24 #include "Lib/DHMap.hpp"
25 #include "Lib/Stack.hpp"
26 #include "Lib/SharedSet.hpp"
27
28 #include "Kernel/Clause.hpp"
29 #include "Kernel/ColorHelper.hpp"
30 #include "Kernel/Formula.hpp"
31 #include "Kernel/Inference.hpp"
32 #include "Kernel/InferenceStore.hpp"
33 #include "Kernel/SubstHelper.hpp"
34 #include "Kernel/Term.hpp"
35 #include "Kernel/Unit.hpp"
36 #include "Kernel/FormulaUnit.hpp"
37
38 #include "Flattening.hpp"
39 #include "SimplifyFalseTrue.hpp"
40 #include "NNF.hpp"
41
42 #include "Interpolants.hpp"
43
44 #define TRACE(x)
45
46 /** surprising colors occur when a clause which is a consequence of transparent clauses, is colored */
47 #define ALLOW_SURPRISING_COLORS 1
48
49 namespace Shell
50 {
51
52 using namespace Lib;
53 using namespace Kernel;
54
55 typedef pair<Formula*, Formula*> UIPair; //pair of unit U and the U-interpolant
56 typedef List<UIPair> UIPairList;
57
getParents(Unit * u)58 VirtualIterator<Unit*> Interpolants::getParents(Unit* u)
59 {
60 CALL("Interpolants::getParents");
61
62 if(!_slicedOff) {
63 return InferenceStore::instance()->getParents(u);
64 }
65
66 static Stack<Unit*> toDo;
67 static Stack<Unit*> parents;
68
69 toDo.reset();
70 parents.reset();
71
72 for(;;) {
73 UnitIterator pit = InferenceStore::instance()->getParents(u);
74 while(pit.hasNext()) {
75 Unit* par = pit.next();
76 if(_slicedOff->find(par)) {
77 toDo.push(par);
78 }
79 else {
80 parents.push(par);
81 }
82 }
83 if(toDo.isEmpty()) {
84 break;
85 }
86 u = toDo.pop();
87 }
88
89 return getPersistentIterator(Stack<Unit*>::BottomFirstIterator(parents));
90 }
91
92 struct Interpolants::ItemState
93 {
ItemStateShell::Interpolants::ItemState94 ItemState() {}
95
ItemStateShell::Interpolants::ItemState96 ItemState(Unit* us) : parCnt(0), inheritedColor(COLOR_TRANSPARENT), interpolant(0),
97 leftInts(0), rightInts(0), processed(false), _us(us)
98 {
99 CALL("ItemState::ItemState");
100 _usColor = us->getColor();
101 }
102
destroyShell::Interpolants::ItemState103 void destroy()
104 {
105 CALL("ItemState::destroy");
106
107 List<UIPair>::destroy(leftInts);
108 List<UIPair>::destroy(rightInts);
109 }
110
usShell::Interpolants::ItemState111 Unit* us() const { return _us; }
usColorShell::Interpolants::ItemState112 Color usColor() const { return _usColor; }
113 /** Parents that remain to be traversed
114 *
115 * Parents in the sense of inferencing, but children in the sense of DFS traversal */
116 VirtualIterator<Unit*> pars;
117 /** number of parents */
118 int parCnt;
119 /** Color of premise formulas, or the declared color for input formulas */
120 Color inheritedColor;
121 /** If non-zero, interpolant of the current formula. */
122 Formula* interpolant;
123 /** Left interpolants of parent formulas */
124 List<UIPair>* leftInts;
125 /** Right interpolants of parent formulas */
126 List<UIPair>* rightInts;
127 /** This state was processed, and if it should have its invarient generated,
128 * it was generated */
129 bool processed;
130 private:
131 /** The current formula */
132 Unit* _us;
133 Color _usColor;
134 };
135
compareUIP(const UIPair & a,const UIPair & b)136 Comparison compareUIP(const UIPair& a, const UIPair& b)
137 {
138 CALL("compareUIP");
139
140 Comparison res = Int::compare(a.first, b.first);
141 if(res==EQUAL) {
142 res = Int::compare(a.second, b.second);
143 }
144 return res;
145 }
146
147 /**
148 * Assuming arguments are lists ordered by the @c compareUIP() function,
149 * add non-destructively new elements from @c src into @c tgt.
150 */
mergeCopy(UIPairList * & tgt,UIPairList * src)151 void mergeCopy(UIPairList*& tgt, UIPairList* src)
152 {
153 CALL("mergeCopy");
154 if(!tgt) {
155 tgt = UIPairList::copy(src);
156 return;
157 }
158
159 UIPairList** curr = &tgt;
160 UIPairList::Iterator sit(src);
161 while(sit.hasNext()) {
162 UIPair spl = sit.next();
163 retry_curr:
164 if(*curr) {
165 Comparison cmp = compareUIP((*curr)->head(), spl);
166 if(cmp!=GREATER) {
167 curr = (*curr)->tailPtr();
168 if(cmp==EQUAL) {
169 continue;
170 }
171 else {
172 goto retry_curr;
173 }
174 }
175 }
176 *curr = new UIPairList(spl, *curr);
177 curr = (*curr)->tailPtr();
178 }
179 }
180
181 /**
182 * Any pre-processing of the refutation before interpolation is considered.
183 *
184 * We remove the leafs corresponding to the conjecture
185 * and leave the negated_conjecture child of this unit as the leaf instead.
186 * (Inference::NEGATED_CONJECTURE is not sound).
187 */
removeConjectureNodesFromRefutation(Unit * refutation)188 void Interpolants::removeConjectureNodesFromRefutation(Unit* refutation)
189 {
190 CALL("Interpolants::removeConjectureNodesFromRefutation");
191
192 Stack<Unit*> todo;
193 DHSet<Unit*> seen;
194
195 todo.push(refutation);
196 while (todo.isNonEmpty()) {
197 Unit* cur = todo.pop();
198 if (!seen.insert(cur)) {
199 continue;
200 }
201
202 if (cur->inference().rule() == InferenceRule::NEGATED_CONJECTURE) {
203 VirtualIterator<Unit*> pars = InferenceStore::instance()->getParents(cur);
204
205 // negating the conjecture is not a sound inference,
206 // we want to consider the proof only from the point where it has been done already
207
208 ASS(pars.hasNext()); // negating a conjecture should have exactly one parent
209 Unit* par = pars.next();
210
211 // so we steal parent's inherited color
212 cur->setInheritedColor(par->inheritedColor());
213
214 // and pretend there is no parent
215
216 ASS(!pars.hasNext()); // negating a conjecture should have exactly one parent
217
218 cur->inference().destroy();
219 cur->inference() = Inference(NonspecificInference0(UnitInputType::NEGATED_CONJECTURE,InferenceRule::NEGATED_CONJECTURE)); // negated conjecture without a parent (non-standard, but nobody will see it)
220 }
221
222 todo.loadFromIterator(InferenceStore::instance()->getParents(cur));
223 }
224 }
225
226 /**
227 * For any input unit marked as properly colored but which is, in fact, transparent,
228 * we add an artificial parent which is forced to pretend it was truly colored that way,
229 * so that InterpolantMinimizer can consider this input unit as a result of a symbol eliminating inference.
230 * (Without this, InterpolantMinimizer does not work properly in such cases.)
231 */
fakeNodesFromRightButGrayInputsRefutation(Unit * refutation)232 void Interpolants::fakeNodesFromRightButGrayInputsRefutation(Unit* refutation)
233 {
234 CALL("Interpolants::fakeNodesFromRightButGrayInputsRefutation");
235
236 Stack<Unit*> todo;
237 DHSet<Unit*> seen;
238
239 todo.push(refutation);
240 while (todo.isNonEmpty()) {
241 Unit* cur = todo.pop();
242 if (!seen.insert(cur)) {
243 continue;
244 }
245
246 {
247 VirtualIterator<Unit*> pars = InferenceStore::instance()->getParents(cur);
248
249 if (!pars.hasNext() && // input-like, because no parents
250 cur->inheritedColor() != COLOR_INVALID && cur->inheritedColor() != COLOR_TRANSPARENT && // proper inherited color
251 cur->getColor() == COLOR_TRANSPARENT) { // but in fact transparent
252
253 Clause* fakeParent = Clause::fromIterator(LiteralIterator::getEmpty(), NonspecificInference0(cur->inputType(),InferenceRule::INPUT));
254 fakeParent->setInheritedColor(cur->inheritedColor());
255 fakeParent->updateColor(cur->inheritedColor());
256
257 cur->inference().destroy();
258 cur->inference() = Inference(NonspecificInference1(InferenceRule::INPUT,fakeParent)); // input inference with a parent (non-standard, but nobody will see it)
259 cur->invalidateInheritedColor();
260 }
261 }
262
263 todo.loadFromIterator(InferenceStore::instance()->getParents(cur));
264 }
265 }
266
267
268 /**
269 * Turn all Units in a refutation into FormulaUnits (casting Clauses to Formulas and wrapping these as Units).
270 *
271 * Keep the old refutation (= non-destructive). Possible sharing of the formula part of the original refutation.
272 *
273 * Assume that once we have formula on a parent path we can't go back to a clause.
274 *
275 */
formulifyRefutation(Unit * refutation)276 Unit* Interpolants::formulifyRefutation(Unit* refutation)
277 {
278 CALL("Interpolants::formulifyRefutation");
279
280 Stack<Unit*> todo;
281 DHMap<Unit*,Unit*> translate; // for caching results (we deal with a DAG in general), but also to distinguish the first call from the next
282
283 todo.push(refutation);
284 while (todo.isNonEmpty()) {
285 Unit* cur = todo.top();
286
287 if (translate.find(cur)) { // the DAG hit case
288 todo.pop();
289
290 continue;
291 }
292
293 if (!cur->isClause()) { // the formula case
294 todo.pop();
295
296 translate.insert(cur,cur);
297 continue;
298 }
299
300 // are all children done?
301 bool allDone = true;
302 Inference& inf = cur->inference();
303 Inference::Iterator iit = inf.iterator();
304 while (inf.hasNext(iit)) {
305 Unit* premUnit=inf.next(iit);
306 if (!translate.find(premUnit)) {
307 allDone = false;
308 break;
309 }
310 }
311
312 if (allDone) { // ready to return
313 todo.pop();
314
315 List<Unit*>* prems = 0;
316
317 Inference::Iterator iit = inf.iterator();
318 while (inf.hasNext(iit)) {
319 Unit* premUnit=inf.next(iit);
320
321 List<Unit*>::push(translate.get(premUnit), prems);
322 }
323
324 InferenceRule rule=inf.rule();
325 prems = List<Unit*>::reverse(prems); //we want items in the same order
326
327 Formula* f = Formula::fromClause(cur->asClause());
328 FormulaUnit* fu = new FormulaUnit(f,NonspecificInferenceMany(rule,prems));
329
330 if (cur->inheritedColor() != COLOR_INVALID) {
331 fu->setInheritedColor(cur->inheritedColor());
332 }
333
334 translate.insert(cur,fu);
335 } else { // need "recursive" calls first
336
337 Inference::Iterator iit = inf.iterator();
338 while (inf.hasNext(iit)) {
339 Unit* premUnit=inf.next(iit);
340 todo.push(premUnit);
341 }
342 }
343 }
344
345 return translate.get(refutation);
346 }
347
getInterpolant(Unit * unit)348 Formula* Interpolants::getInterpolant(Unit* unit)
349 {
350 CALL("Interpolants::getInterpolant");
351
352 typedef DHMap<Unit*,ItemState> ProcMap;
353 ProcMap processed;
354
355 TRACE(cout << "===== getInterpolant for " << unit->toString() << endl);
356
357 Stack<ItemState> sts;
358
359 Unit* curr= unit;
360
361 Formula* resultInterpolant = 0;
362
363 int ctr=0;
364
365 for(;;) {
366 ItemState st;
367
368 if(processed.find(curr)) {
369 st = processed.get(curr);
370 ASS(st.us()==curr);
371 ASS(st.processed);
372 ASS(!st.pars.hasNext());
373 }
374 else {
375 st = ItemState(curr);
376 st.pars = getParents(curr);
377 }
378
379 TRACE(cout << "curr " << curr->toString() << endl);
380 TRACE(cout << "cu_ic " << curr->inheritedColor() << endl);
381 TRACE(cout << "st_co " << st.usColor() << endl);
382
383 if(curr->inheritedColor()!=COLOR_INVALID) {
384 //set premise-color information for input clauses
385 st.inheritedColor=ColorHelper::combine(curr->inheritedColor(), st.usColor());
386 ASS_NEQ(st.inheritedColor, COLOR_INVALID);
387 }
388 #if ALLOW_SURPRISING_COLORS
389 else {
390 //we set inherited color to the color of the unit.
391 //in the case of clause being conclusion of
392 //transparent parents, the assigned color should be
393 //transparent as well, but there are some corner cases
394 //coming from proof transformations which can yield us
395 //a colored clause in such case (when the colored premise
396 //was removed by the transformation).
397 st.inheritedColor=st.usColor();
398 }
399 #else
400 else if(!st.processed && !st.pars.hasNext()) {
401 //we have unit without any parents. This case is reserved for
402 //units introduced by some naming. In this case we need to set
403 //the inherited color to the color of the unit.
404 st.inheritedColor=st.usColor();
405 }
406 #endif
407
408 TRACE(cout << "st_ic " << st.inheritedColor << endl);
409
410 if(sts.isNonEmpty()) {
411 //update premise color information in the level above
412 ItemState& pst=sts.top(); //parent state
413 pst.parCnt++;
414 if(pst.inheritedColor==COLOR_TRANSPARENT) {
415 pst.inheritedColor=st.usColor();
416
417 TRACE(cout << "updated parent's inh col to " << pst.inheritedColor << endl);
418 TRACE(cout << "parent " << pst.us()->toString() << endl);
419
420 }
421 #if VDEBUG
422 else {
423 Color clr=st.usColor();
424 ASS_REP2(pst.inheritedColor==clr || clr==COLOR_TRANSPARENT, pst.us()->toString(), curr->toString());
425 }
426 ASS_EQ(curr->getColor(),st.usColor());
427 #endif
428 }
429
430 // keep initializing splitting components
431 if (curr->isClause()) {
432 Clause* cl = curr->asClause();
433
434 if (cl->isComponent()) {
435 SplitSet* splits = cl->splits();
436 ASS_EQ(splits->size(),1);
437 _splittingComponents.insert(splits->sval(),cl);
438 }
439 }
440
441 sts.push(st);
442
443 for(;;) {
444 if(sts.top().pars.hasNext()) {
445 curr=sts.top().pars.next();
446 break;
447 }
448 //we're done with all children, now we can process what we've gathered
449 st=sts.pop();
450 ctr++;
451 Color color = st.usColor();
452 if(!st.processed) {
453 if(st.inheritedColor!=color || sts.isEmpty()) {
454 //we either have a transparent clause justified by A or B, or the refutation
455 // ASS_EQ(color,COLOR_TRANSPARENT);
456 TRACE(cout<<"generate interpolant of transparent clause: "<<st.us()->toString()<<"\n");
457 ASS_REP2(color==COLOR_TRANSPARENT, st.us()->toString(), st.inheritedColor);
458 generateInterpolant(st);
459 }
460 st.processed = true;
461 processed.insert(st.us(), st);
462 }
463
464 if(sts.isNonEmpty()) {
465 //pass interpolants to the level above
466 if(color!=COLOR_LEFT) {
467 mergeCopy(sts.top().leftInts, st.leftInts);
468 }
469 if(color!=COLOR_RIGHT) {
470 mergeCopy(sts.top().rightInts, st.rightInts);
471 }
472 }
473 else {
474 //empty sts (so refutation) with clause st justified by A or B (st is false).
475 //interpolant was already generated in st.interpolant
476 //we have now the interpolant for refutation
477 resultInterpolant = st.interpolant;
478 goto fin;
479 }
480 }
481 }
482
483 fin:
484
485 //clean-up
486 ProcMap::Iterator destrIt(processed);
487 while(destrIt.hasNext()) {
488 destrIt.next().destroy();
489 }
490
491 TRACE(cout << "result interpolant (before false/true - simplification) " << resultInterpolant->toString() << endl);
492
493 cout << "Before simplification: " << resultInterpolant->toString() << endl;
494 cout << "Weight before simplification: " << resultInterpolant->weight() << endl;
495
496 //simplify the interpolant and exit
497 return Flattening::flatten(NNF::ennf(Flattening::flatten(SimplifyFalseTrue::simplify(resultInterpolant)),true));
498 // return resultInterpolant;
499 }
500
generateInterpolant(ItemState & st)501 void Interpolants::generateInterpolant(ItemState& st)
502 {
503 CALL("Interpolants::generateInterpolant");
504
505 Unit* u=st.us();
506
507 TRACE(cout << "GenerateInterpolant for " << u->toString() << endl);
508
509 Color color=st.usColor();
510 ASS_EQ(color, COLOR_TRANSPARENT);
511
512 Formula* interpolant;
513 Formula* unitFormula=u->getFormula();//st.us().prop());
514
515 // add assertions from splitting
516 if (u->isClause()) {
517 Clause* cl = u->asClause();
518
519 if (cl->splits()) {
520 FormulaList* disjuncts = FormulaList::empty();
521 SplitSet::Iterator it(*cl->splits());
522 while(it.hasNext()) {
523 SplitLevel lv=it.next();
524 Clause* ass = _splittingComponents.get(lv);
525 FormulaList::push(new NegatedFormula(Formula::fromClause(ass)),disjuncts);
526 }
527 if (FormulaList::isNonEmpty(disjuncts)) {
528 FormulaList::push(unitFormula,disjuncts);
529
530 unitFormula = JunctionFormula::generalJunction(OR, disjuncts);
531 }
532 }
533 }
534
535 TRACE(cout <<"unitFormula: "<<unitFormula->toString()<<endl);
536
537 if(st.parCnt) {
538 //interpolants from refutation proof with at least one inference (there are premises, i.e. parents)
539 FormulaList* conj=0;
540 List<UIPair>* src= (st.inheritedColor==COLOR_LEFT) //source of relevant parent interpolants
541 ? st.rightInts
542 : st.leftInts;
543 //construct the common part of the interpolant
544 List<UIPair>::Iterator sit(src);
545 while(sit.hasNext()) {
546 UIPair uip=sit.next();
547 FormulaList* disj=0;
548 FormulaList::push(uip.first, disj);
549 FormulaList::push(uip.second, disj);
550 FormulaList::push(JunctionFormula::generalJunction(OR, disj), conj);
551 }
552
553 if(st.inheritedColor==COLOR_LEFT) {
554 //u is justified by A
555 FormulaList* innerConj=0;
556 List<UIPair>::Iterator sit2(src);
557 while(sit2.hasNext()) {
558 UIPair uip=sit2.next();
559 FormulaList::push(uip.first, innerConj);
560 }
561 FormulaList::push(new NegatedFormula(JunctionFormula::generalJunction(AND, innerConj)), conj);
562 }
563 else {
564 //u is justified by B or a refutation
565 }
566 interpolant=JunctionFormula::generalJunction(AND, conj);
567 }
568 else {
569 //trivial interpolants (when there are no premises)
570 if(st.inheritedColor==COLOR_RIGHT) {
571 interpolant=new NegatedFormula(unitFormula); //this is for TRUE interpolant if the unitFormula is False
572 }
573 else {
574 //a formula coming from left or a refutation
575 interpolant=unitFormula; //this is for FALSE interpolant if the unitFormula is False
576 }
577 }
578 st.interpolant=interpolant;
579 TRACE(cout<<"Unit "<<u->toString()
580 <<"\nto Formula "<<unitFormula->toString()
581 <<"\ninterpolant "<<interpolant->toString()<<endl<<endl);
582 UIPair uip=make_pair(unitFormula, interpolant);
583 if(st.inheritedColor==COLOR_LEFT) {
584 List<UIPair>::destroy(st.leftInts);
585 st.leftInts=0;
586 List<UIPair>::push(uip,st.leftInts);
587 }
588 else if(st.inheritedColor==COLOR_RIGHT) {
589 List<UIPair>::destroy(st.rightInts);
590 st.rightInts=0;
591 List<UIPair>::push(uip,st.rightInts);
592 }
593 }
594
595 }
596