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