1 
2 /*
3  * File HyperSuperposition.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 HyperSuperposition.cpp
21  * Implements class HyperSuperposition.
22  */
23 
24 #include <algorithm>
25 
26 #include "Debug/RuntimeStatistics.hpp"
27 
28 #include "Lib/Environment.hpp"
29 #include "Lib/Metaiterators.hpp"
30 #include "Lib/PairUtils.hpp"
31 #include "Lib/TimeCounter.hpp"
32 #include "Lib/VirtualIterator.hpp"
33 
34 #include "Kernel/Clause.hpp"
35 #include "Kernel/ColorHelper.hpp"
36 #include "Kernel/EqHelper.hpp"
37 #include "Kernel/Inference.hpp"
38 #include "Kernel/RobSubstitution.hpp"
39 #include "Kernel/SortHelper.hpp"
40 #include "Kernel/Term.hpp"
41 #include "Kernel/TermIterators.hpp"
42 #include "Kernel/Unit.hpp"
43 
44 #include "Indexing/Index.hpp"
45 #include "Indexing/LiteralIndex.hpp"
46 #include "Indexing/IndexManager.hpp"
47 
48 #include "Saturation/SaturationAlgorithm.hpp"
49 
50 #include "Shell/Options.hpp"
51 #include "Shell/Statistics.hpp"
52 
53 #include "BinaryResolution.hpp"
54 #include "EqualityResolution.hpp"
55 
56 #include "HyperSuperposition.hpp"
57 
58 namespace Inferences
59 {
60 
61 using namespace Lib;
62 using namespace Kernel;
63 using namespace Indexing;
64 using namespace Saturation;
65 
attach(SaturationAlgorithm * salg)66 void HyperSuperposition::attach(SaturationAlgorithm* salg)
67 {
68   CALL("HyperSuperposition::attach");
69   ASS(!_index);
70 
71 //  GeneratingInferenceEngine::attach(salg);
72   ForwardSimplificationEngine::attach(salg);
73   _index=static_cast<UnitClauseLiteralIndex*> (
74 	  _salg->getIndexManager()->request(SIMPLIFYING_UNIT_CLAUSE_SUBST_TREE) );
75 }
76 
detach()77 void HyperSuperposition::detach()
78 {
79   CALL("HyperSuperposition::detach");
80   ASS(_salg);
81 
82   _index=0;
83   _salg->getIndexManager()->release(SIMPLIFYING_UNIT_CLAUSE_SUBST_TREE);
84 //  GeneratingInferenceEngine::detach();
85   ForwardSimplificationEngine::detach();
86 }
87 
88 /**
89  * Return true if weight of the first term is less for p1 than for p2.
90  *
91  * We use this to sort elements on the rewriter stack, so that larger rewrites get done first.
92  */
rewriterEntryComparator(RewriterEntry p1,RewriterEntry p2)93 bool HyperSuperposition::rewriterEntryComparator(RewriterEntry p1, RewriterEntry p2)
94 {
95   CALL("HyperSuperposition::rewriterEntryComparator");
96 
97   unsigned w1 = p1.first.first.isVar() ? 1 : p1.first.first.term()->weight();
98   unsigned w2 = p2.first.first.isVar() ? 1 : p2.first.first.term()->weight();
99 
100   return w1<w2;
101 }
102 
tryToUnifyTwoTermPairs(RobSubstitution & subst,TermList tp1t1,int bank11,TermList tp1t2,int bank12,TermList tp2t1,int bank21,TermList tp2t2,int bank22)103 bool HyperSuperposition::tryToUnifyTwoTermPairs(RobSubstitution& subst, TermList tp1t1, int bank11,
104     TermList tp1t2, int bank12, TermList tp2t1, int bank21, TermList tp2t2, int bank22)
105 {
106   CALL("HyperSuperposition::tryToUnifyTwoTermPairs");
107 
108   BacktrackData btData;
109   subst.bdRecord(btData);
110 
111   if(!subst.unify(tp1t1, bank11, tp1t2, bank12)) {
112     subst.bdDone();
113     ASS(btData.isEmpty());
114     return false;
115   }
116   if(!subst.unify(tp2t1, bank21, tp2t2, bank22)) {
117     subst.bdDone();
118     btData.backtrack();
119     return false;
120   }
121 
122   subst.bdDone();
123   subst.bdCommit(btData);
124   ASS(btData.isEmpty());
125   return true;
126 }
127 
tryMakeTopUnifiableByRewriter(TermList t1,TermList t2,int t2Bank,int & nextAvailableBank,ClauseStack & premises,RewriterStack & rewriters,RobSubstitution & subst,Color & infClr)128 bool HyperSuperposition::tryMakeTopUnifiableByRewriter(TermList t1, TermList t2, int t2Bank, int& nextAvailableBank, ClauseStack& premises,
129       RewriterStack& rewriters, RobSubstitution& subst, Color& infClr)
130 {
131   CALL("HyperSuperposition::tryGetTopRewriter");
132 
133   if(subst.unify(t1, 0, t2, t2Bank)) {
134     return true;
135   }
136 
137   TermList ut1 = subst.apply(t1, 0);
138   TermList ut2 = subst.apply(t2, t2Bank);
139 
140   ASS(ut1.isTerm() || ut2.isTerm());
141 
142   unsigned srt;
143   if(ut1.isTerm()) {
144     srt = SortHelper::getResultSort(ut1.term());
145   }
146   else {
147     ASS(ut2.isTerm());
148     srt = SortHelper::getResultSort(ut2.term());
149   }
150   Literal* queryEq = Literal::createEquality(true, ut1, ut2, srt);
151 
152   SLQueryResultIterator srqi = _index->getUnifications(queryEq, false, false);
153   if(!srqi.hasNext()) {
154     return false;
155   }
156   //for now we just get the first result
157   SLQueryResult qr = srqi.next();
158   Color clr = ColorHelper::combine(infClr, qr.clause->color());
159   if(clr==COLOR_INVALID) {
160     return false;
161   }
162   infClr = clr;
163 
164   Literal* rwrLit = qr.literal;
165 
166   TermList rwrT1 = *rwrLit->nthArgument(0);
167   TermList rwrT2 = *rwrLit->nthArgument(1);
168 
169   int rwrBankIdx = nextAvailableBank++;
170   if(!tryToUnifyTwoTermPairs(subst, t1, 0, rwrT1, rwrBankIdx, t2, t2Bank, rwrT2, rwrBankIdx)) {
171     std::swap(rwrT1, rwrT2);
172     ALWAYS(tryToUnifyTwoTermPairs(subst, t1, 0, rwrT1, rwrBankIdx, t2, t2Bank, rwrT2, rwrBankIdx));
173   }
174 
175   rewriters.push(make_pair(TermPair(rwrT1,rwrT2), rwrBankIdx));
176   premises.push(qr.clause);
177   return true;
178 }
179 
180 /**
181  * the content of the reference arguments is undefined in case of failure
182  */
tryGetRewriters(Term * t1,Term * t2,int t2Bank,int & nextAvailableBank,ClauseStack & premises,RewriterStack & rewriters,RobSubstitution & subst,Color & infClr)183 bool HyperSuperposition::tryGetRewriters(Term* t1, Term* t2, int t2Bank, int& nextAvailableBank, ClauseStack& premises,
184       RewriterStack& rewriters, RobSubstitution& subst, Color& infClr)
185 {
186   CALL("HyperSuperposition::tryGetRewriters");
187   ASS_EQ(t1->isLiteral(),t2->isLiteral());
188 
189 //for this we'll need to handle some corner cases in rewriter application
190 //  if(!t1->isLiteral()) {
191 //    if(tryMakeTopUnifiableByRewriter(TermList(t1), TermList(t2), t2Bank, nextAvailableBank, premises, rewriters, subst, infClr)) {
192 //      return true;
193 //    }
194 //  }
195   if(t1->functor()!=t2->functor()) {
196     return false;
197   }
198 
199   SubtermIterator t1it(t1);
200   SubtermIterator t2it(t2);
201   while(t1it.hasNext()) {
202     ALWAYS(t2it.hasNext());
203     TermList st1 = t1it.next();
204     TermList st2 = t2it.next();
205     if(tryMakeTopUnifiableByRewriter(st1, st2, t2Bank, nextAvailableBank, premises, rewriters, subst, infClr)) {
206       t1it.right();
207       t2it.right();
208       continue;
209     }
210     if(!TermList::sameTopFunctor(st1, st2)) {
211       return false;
212     }
213   }
214   ASS(!t2it.hasNext());
215   return true;
216 }
217 
218 /**
219  * Determine which terms need to be made equal to make terms/literals
220  * t1 and t2 unify, try to find unit equalities that would unify these two terms
221  * and if successful, apply the necessary substitution to clause @c cl and
222  * the rewritings to t1 and this then to the literal at @c literalIndex. The
223  * order of literals in the clause is preserved.
224  *
225  * If @c disjointVariables is true, the variables in t2 are considered to be disjoint
226  * from variables of the clause and term t1.
227  * Variables of t1 are always considered to conincide with variables of the clause.
228  */
tryUnifyingSuperpositioins(Clause * cl,unsigned literalIndex,Term * t1,Term * t2,bool disjointVariables,ClauseStack & acc)229 void HyperSuperposition::tryUnifyingSuperpositioins(Clause* cl, unsigned literalIndex, Term* t1, Term* t2,
230     bool disjointVariables, ClauseStack& acc)
231 {
232   CALL("HyperSuperposition::tryUnifyingSuperpositioins");
233 
234   ASS_EQ(t1->isLiteral(),t2->isLiteral());
235   ASS(!t1->isLiteral() || t1->functor()==t2->functor());
236 
237   Color clauseClr = cl->color();
238 
239   static RobSubstitution subst;
240   subst.reset();
241 
242   int bank2 = disjointVariables ? 1 : 0;
243   int nextAvailBank = bank2+1;
244 
245   static ClauseStack premises;
246   premises.reset();
247   //the int is a variable bank index
248   typedef pair<TermPair, int> RewriterEntry;
249   typedef Stack<RewriterEntry> RewriterStack;
250   static RewriterStack rewriters;
251   rewriters.reset();
252 
253   if(!tryGetRewriters(t1, t2, bank2, nextAvailBank, premises, rewriters, subst, clauseClr)) {
254     //we couldn't get the rewriters
255     return;
256   }
257 
258   if(rewriters.isEmpty()) {
259     //there is no need for rewriting
260     return;
261   }
262 
263   //we need to process heavier terms first, so we don't change some subterms of
264   //later terms during rewriting (thus making the rewriting impossible)
265   std::sort(rewriters.begin(), rewriters.end(), rewriterEntryComparator);
266 
267   Term* t1Subst;
268   if(t1->isLiteral()) {
269     t1Subst = subst.apply(static_cast<Literal*>(t1),0);
270   }
271   else {
272     t1Subst = subst.apply(TermList(t1), 0).term();
273   }
274 
275   Term* t1Rwr = t1Subst;
276   RewriterStack::TopFirstIterator rwrIt(rewriters);
277   while(rwrIt.hasNext()) {
278     RewriterEntry rwr = rwrIt.next();
279     int rwrBank = rwr.second;
280     TermList srcBase = rwr.first.first;
281     TermList tgtBase = rwr.first.second;
282     TermList src = subst.apply(srcBase, rwrBank);
283     TermList tgt = subst.apply(tgtBase, rwrBank);
284     t1Rwr = EqHelper::replace(t1Rwr, src, tgt);
285   }
286 
287   static RobSubstitution checkerSubst;
288   checkerSubst.reset();
289   if(!checkerSubst.unifyArgs(t1Rwr, 0, t2, bank2)) {
290     return;
291   }
292 
293   static LiteralStack resLits;
294   resLits.reset();
295 
296   unsigned clen = cl->length();
297   for(unsigned i=0; i<clen; i++) {
298     Literal* lit0 = (*cl)[i];
299     if(i==literalIndex) {
300       if(t1->isLiteral()) {
301 	ASS_EQ(lit0, t1);
302 	resLits.push(static_cast<Literal*>(t1Rwr));
303       }
304       else {
305 	Literal* lSubst = subst.apply(lit0, 0);
306 	Literal* lRwr = EqHelper::replace(lSubst, TermList(t1Subst), TermList(t1Rwr));
307 	resLits.push(lRwr);
308       }
309     }
310     else {
311       Literal* lSubst = subst.apply(lit0, 0);
312       resLits.push(lSubst);
313     }
314   }
315 
316   UnitList* premLst = 0;
317   UnitList::pushFromIterator(ClauseStack::Iterator(premises), premLst);
318   UnitList::push(cl, premLst);
319 
320   Clause* res = Clause::fromStack(resLits, GeneratingInferenceMany(InferenceRule::HYPER_SUPERPOSITION_GENERATING, premLst));
321   // MS: keeping the original semantics (GeneratingInferenceMany would compute max over all parents+1)
322   res->setAge(cl->age()+1);
323 
324   RSTAT_CTR_INC("hyper-superposition");
325 
326   _salg->onNewClause(res);
327   acc.push(res);
328 }
329 
tryUnifyingNonequality(Clause * cl,unsigned literalIndex,ClausePairStack & acc)330 void HyperSuperposition::tryUnifyingNonequality(Clause* cl, unsigned literalIndex, ClausePairStack& acc)
331 {
332   CALL("HyperSuperposition::tryUnifyingNonequality");
333 
334   Literal* lit = (*cl)[literalIndex];
335   ASS(lit->isEquality());
336   ASS(lit->isNegative());
337 
338   TermList t1 = *lit->nthArgument(0);
339   TermList t2 = *lit->nthArgument(1);
340   if(t1.isVar() || t2.isVar()) {
341     //this unifies without any problems
342     return;
343   }
344 
345   static ClauseStack localRes;
346   tryUnifyingSuperpositioins(cl, literalIndex, t1.term(), t2.term(), false, localRes);
347 
348   while(localRes.isNonEmpty()) {
349     Clause* ocl = localRes.pop();
350     Clause* resCl = EqualityResolution::tryResolveEquality(ocl, (*ocl)[literalIndex]);
351     ASS(resCl);
352     acc.push(ClausePair(ocl, resCl));
353   }
354 }
355 
getUnifQueryLit(Literal * base)356 Literal* HyperSuperposition::getUnifQueryLit(Literal* base)
357 {
358   CALL("HyperSuperposition::getUnifQueryLit");
359 
360   unsigned arity = base->arity();
361   static TermStack varArgs;
362   for(unsigned i=varArgs.size(); i<arity; i++) {
363     varArgs.push(TermList(i, false));
364   }
365   Literal* res = Literal::create(base, varArgs.begin());
366   return res;
367 }
368 
resolveFixedLiteral(Clause * cl,unsigned litIndex,ClausePairStack & acc)369 void HyperSuperposition::resolveFixedLiteral(Clause* cl, unsigned litIndex, ClausePairStack& acc)
370 {
371   CALL("HyperSuperposition::resolveFixedLiteral");
372 
373   Literal* lit = (*cl)[litIndex];
374   SLQueryResultIterator unifs = _index->getUnifications(lit, true, true);
375   while(unifs.hasNext()) {
376     SLQueryResult qr = unifs.next();
377     Clause* genCl = BinaryResolution::generateClause(cl, lit, qr, getOptions());
378     acc.push(ClausePair(cl, genCl));
379   }
380 }
381 
tryUnifyingToResolveWithUnit(Clause * cl,unsigned literalIndex,ClausePairStack & acc)382 void HyperSuperposition::tryUnifyingToResolveWithUnit(Clause* cl, unsigned literalIndex, ClausePairStack& acc)
383 {
384   CALL("HyperSuperposition::tryUnifyingToResolveWithUnit");
385 
386   Literal* lit = (*cl)[literalIndex];
387   if(lit->isEquality()) {
388     //now we don't bother with the argument normalization that is done in equalities
389     return;
390   }
391   Literal* queryLit = getUnifQueryLit(lit);
392   SLQueryResultIterator unifIt = _index->getUnifications(queryLit, true, false);
393 
394   static ClauseStack localRes;
395 
396   while(unifIt.hasNext()) {
397     SLQueryResult unifRes = unifIt.next();
398     localRes.reset();
399     tryUnifyingSuperpositioins(cl, literalIndex, lit, unifRes.literal, true, localRes);
400     while(localRes.isNonEmpty()) {
401       Clause* resolvableCl = localRes.pop();
402       resolveFixedLiteral(resolvableCl, literalIndex, acc);
403     }
404   }
405 }
406 
407 /**
408  * Interface for a generating inference
409  */
generateClauses(Clause * cl)410 ClauseIterator HyperSuperposition::generateClauses(Clause* cl)
411 {
412   CALL("HyperSuperposition::generateClauses");
413 
414   TimeCounter tc(TC_HYPER_SUPERPOSITION);
415 
416   static ClausePairStack res;
417   res.reset();
418 
419   unsigned clen = cl->length();
420   for(unsigned i=0; i<clen; i++) {
421     Literal* lit = (*cl)[i];
422     if(lit->isEquality() && lit->isNegative()) {
423       tryUnifyingNonequality(cl, i, res);
424     }
425   }
426   if(clen==1) {
427     tryUnifyingToResolveWithUnit(cl, 0, res);
428   }
429 
430   return getPersistentIterator(getMappingIterator(ClausePairStack::Iterator(res), SecondOfPairFn<ClausePair>()));
431 }
432 
433 
tryGetUnifyingPremises(Term * t1,Term * t2,Color clr,bool disjointVariables,ClauseStack & premises)434 bool HyperSuperposition::tryGetUnifyingPremises(Term* t1, Term* t2, Color clr, bool disjointVariables, ClauseStack& premises)
435 {
436   CALL("HyperSuperposition::tryGetUnifyingPremises");
437   ASS_EQ(t1->isLiteral(),t2->isLiteral());
438   ASS(!t1->isLiteral() || t1->functor()==t2->functor());
439 
440   Color clauseClr = clr;
441 
442   static RobSubstitution subst;
443   subst.reset();
444 
445   int bank2 = disjointVariables ? 1 : 0;
446   int nextAvailBank = bank2+1;
447 
448   static RewriterStack rewriters;
449   rewriters.reset();
450 
451   return tryGetRewriters(t1, t2, bank2, nextAvailBank, premises, rewriters, subst, clauseClr);
452 }
453 
tryGetContradictionFromUnification(Clause * cl,Term * t1,Term * t2,bool disjointVariables,ClauseStack & premStack)454 Clause* HyperSuperposition::tryGetContradictionFromUnification(Clause* cl, Term* t1, Term* t2, bool disjointVariables,
455     ClauseStack& premStack)
456 {
457   CALL("HyperSuperposition::tryGetContradictionFromUnification");
458 
459   Color clr = cl->color();
460   ClauseStack::Iterator cit(premStack);
461   while(cit.hasNext()) {
462     Clause* prem = cit.next();
463     clr = ColorHelper::combine(clr, prem->color());
464   }
465   if(clr==COLOR_INVALID) {
466     return 0;
467   }
468   if(!tryGetUnifyingPremises(t1, t2, clr, disjointVariables, premStack)) {
469     return 0;
470   }
471   UnitList* premLst = 0;
472   UnitList::pushFromIterator(ClauseStack::Iterator(premStack), premLst);
473   UnitList::push(cl, premLst);
474   Clause* res = Clause::fromIterator(LiteralIterator::getEmpty(),
475       GeneratingInferenceMany(InferenceRule::HYPER_SUPERPOSITION_SIMPLIFYING, premLst));
476   // MS: keeping the original semantics (GeneratingInferenceMany would compute max over all parents+1)
477   res->setAge(cl->age());
478   return res;
479 }
480 
trySimplifyingFromUnification(Clause * cl,Term * t1,Term * t2,bool disjointVariables,ClauseStack & premStack,Clause * & replacement,ClauseIterator & premises)481 bool HyperSuperposition::trySimplifyingFromUnification(Clause* cl, Term* t1, Term* t2, bool disjointVariables, ClauseStack& premStack,
482     Clause*& replacement, ClauseIterator& premises)
483 {
484   CALL("HyperSuperposition::trySimplifyingFromUnification");
485 
486 
487   Clause* res = tryGetContradictionFromUnification(cl, t1, t2, false, premStack);
488   if(!res) {
489     return false;
490   }
491 
492   ClauseStack::Iterator premIt(premStack);
493   while(premIt.hasNext()) {
494     Clause* pr = premIt.next();
495     if(!ColorHelper::compatible(cl->color(), pr->color())) {
496       return false;
497     }
498   }
499 
500   RSTAT_CTR_INC("hyper-superposition");
501 
502   replacement = res;
503   premises = pvi(ClauseStack::Iterator(premStack));
504   return true;
505 }
506 
tryUnifyingNonequalitySimpl(Clause * cl,Clause * & replacement,ClauseIterator & premises)507 bool HyperSuperposition::tryUnifyingNonequalitySimpl(Clause* cl, Clause*& replacement, ClauseIterator& premises)
508 {
509   CALL("HyperSuperposition::tryUnifyingNonequalitySimpl");
510   ASS_EQ(cl->length(), 1);
511 
512   Literal* lit = (*cl)[0];
513   ASS(lit->isEquality());
514   ASS(lit->isNegative());
515 
516   TermList t1 = *lit->nthArgument(0);
517   TermList t2 = *lit->nthArgument(1);
518   if(t1.isVar() || t2.isVar()) {
519     //this unifies without any problems
520     return false;
521   }
522 
523   static ClauseStack premStack;
524   premStack.reset();
525 
526   return trySimplifyingFromUnification(cl, t1.term(), t2.term(), false, premStack, replacement, premises);
527 }
528 
tryUnifyingToResolveSimpl(Clause * cl,Clause * & replacement,ClauseIterator & premises)529 bool HyperSuperposition::tryUnifyingToResolveSimpl(Clause* cl, Clause*& replacement, ClauseIterator& premises)
530 {
531   CALL("HyperSuperposition::tryUnifyingToResolveSimpl");
532   ASS_EQ(cl->length(), 1);
533 
534   Literal* lit = (*cl)[0];
535   if(lit->isEquality()) {
536     //now we don't bother with the argument normalization that is done in equalities
537     return false;
538   }
539   Literal* queryLit = getUnifQueryLit(lit);
540   SLQueryResultIterator unifIt = _index->getUnifications(queryLit, true, false);
541 
542   static ClauseStack prems;
543 
544   while(unifIt.hasNext()) {
545     SLQueryResult unifRes = unifIt.next();
546     prems.reset();
547     prems.push(unifRes.clause);
548 
549     if(trySimplifyingFromUnification(cl, lit, unifRes.literal, true, prems, replacement, premises)) {
550       return true;
551     }
552   }
553   return false;
554 }
555 
556 /**
557  * Interface for a fw simplifying inference
558  */
perform(Clause * cl,Clause * & replacement,ClauseIterator & premises)559 bool HyperSuperposition::perform(Clause* cl, Clause*& replacement, ClauseIterator& premises)
560 {
561   CALL("HyperSuperposition::perform");
562   if(cl->length()!=1) {
563     return false;
564   }
565 
566   TimeCounter tc(TC_HYPER_SUPERPOSITION);
567 
568   Literal* lit = (*cl)[0];
569 
570   if(lit->isEquality() && lit->isNegative()) {
571     if(tryUnifyingNonequalitySimpl(cl, replacement, premises)) {
572       return true;
573     }
574   }
575   return tryUnifyingToResolveSimpl(cl, replacement, premises);
576 }
577 
578 }
579