1 
2 /*
3  * File Clause.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 Clause.cpp
21  * Implements class Clause for units consisting of clauses
22  *
23  * @since 18/05/2007 Manchester
24  */
25 
26 #include <ostream>
27 
28 #include "Debug/RuntimeStatistics.hpp"
29 
30 #include "Lib/Allocator.hpp"
31 #include "Lib/DArray.hpp"
32 #include "Lib/Environment.hpp"
33 #include "Lib/Int.hpp"
34 #include "Lib/SharedSet.hpp"
35 #include "Lib/Stack.hpp"
36 #include "Lib/BitUtils.hpp"
37 
38 #include "Saturation/ClauseContainer.hpp"
39 #include "Saturation/Splitter.hpp"
40 
41 #include "SAT/SATClause.hpp"
42 
43 #include "Shell/Options.hpp"
44 
45 #include "Inference.hpp"
46 #include "Signature.hpp"
47 #include "Term.hpp"
48 #include "TermIterators.hpp"
49 
50 #include "Clause.hpp"
51 
52 #undef RSTAT_COLLECTION
53 #define RSTAT_COLLECTION 1
54 
55 namespace Kernel
56 {
57 
58 using namespace Lib;
59 using namespace Saturation;
60 using namespace Shell;
61 
62 size_t Clause::_auxCurrTimestamp = 0;
63 #if VDEBUG
64 bool Clause::_auxInUse = false;
65 #endif
66 
67 
68 /** New clause */
Clause(unsigned length,const Inference & inf)69 Clause::Clause(unsigned length,const Inference& inf)
70   : Unit(Unit::CLAUSE,inf),
71     _length(length),
72     _color(COLOR_INVALID),
73     _extensionality(false),
74     _extensionalityTag(false),
75     _component(false),
76     _store(NONE),
77     _numSelected(0),
78     _weight(0),
79     _weightForClauseSelection(0),
80     _refCnt(0),
81     _reductionTimestamp(0),
82     _literalPositions(0),
83     _numActiveSplits(0),
84     _auxTimestamp(0)
85 {
86   // MS: TODO: not sure if this belongs here and whether EXTENSIONALITY_AXIOM input types ever appear anywhere (as a vampire-extension TPTP formula role)
87   if(inference().inputType() == UnitInputType::EXTENSIONALITY_AXIOM){
88     //cout << "Setting extensionality" << endl;
89     _extensionalityTag = true;
90     inference().setInputType(UnitInputType::AXIOM);
91   }
92 }
93 
94 /**
95  * Allocate a clause having lits literals.
96  * @since 18/05/2007 Manchester
97  */
operator new(size_t sz,unsigned lits)98 void* Clause::operator new(size_t sz, unsigned lits)
99 {
100   CALL("Clause::operator new");
101   ASS_EQ(sz,sizeof(Clause));
102 
103   RSTAT_CTR_INC("clauses created");
104 
105   //We have to get sizeof(Clause) + (_length-1)*sizeof(Literal*)
106   //this way, because _length-1 wouldn't behave well for
107   //_length==0 on x64 platform.
108   size_t size = sizeof(Clause) + lits * sizeof(Literal*);
109   size -= sizeof(Literal*);
110 
111   return ALLOC_KNOWN(size,"Clause");
112 }
113 
operator delete(void * ptr,unsigned length)114 void Clause::operator delete(void* ptr,unsigned length)
115 {
116   CALL("Clause::operator delete");
117 
118   RSTAT_CTR_INC("clauses deleted by delete operator");
119 
120   //We have to get sizeof(Clause) + (_length-1)*sizeof(Literal*)
121   //this way, because _length-1 wouldn't behave well for
122   //_length==0 on x64 platform.
123   size_t size = sizeof(Clause) + length * sizeof(Literal*);
124   size -= sizeof(Literal*);
125 
126   DEALLOC_KNOWN(ptr, size,"Clause");
127 }
128 
destroyExceptInferenceObject()129 void Clause::destroyExceptInferenceObject()
130 {
131   if (_literalPositions) {
132     delete _literalPositions;
133   }
134 
135   RSTAT_CTR_INC("clauses deleted");
136 
137   //We have to get sizeof(Clause) + (_length-1)*sizeof(Literal*)
138   //this way, because _length-1 wouldn't behave well for
139   //_length==0 on x64 platform.
140   size_t size = sizeof(Clause) + _length * sizeof(Literal*);
141   size -= sizeof(Literal*);
142 
143   DEALLOC_KNOWN(this, size,"Clause");
144 }
145 
146 
fromStack(const Stack<Literal * > & lits,const Inference & inf)147 Clause* Clause::fromStack(const Stack<Literal*>& lits, const Inference& inf)
148 {
149   CALL("Clause::fromStack");
150 
151   unsigned clen = lits.size();
152   Clause* res = new (clen) Clause(clen, inf);
153 
154   for(unsigned i = 0; i < clen; i++) {
155     (*res)[i] = lits[i];
156   }
157 
158   return res;
159 }
160 
161 /**
162  * Create a clause with the same content as @c c. The inference of the
163  * created clause refers to @c c using the REORDER_LITERALS inference.
164  *
165  * The age of @c c is used, however the selected literals are not kept.
166  *
167  * BDDs and splitting history from @c c is also copied into the new clause.
168  */
fromClause(Clause * c)169 Clause* Clause::fromClause(Clause* c)
170 {
171   CALL("Clause::fromClause");
172 
173   Clause* res = fromIterator(Clause::Iterator(*c), SimplifyingInference1(InferenceRule::REORDER_LITERALS, c));
174 
175   if (c->splits()) {
176     res->setSplits(c->splits());
177   }
178 
179   return res;
180 }
181 
shouldBeDestroyed()182 bool Clause::shouldBeDestroyed()
183 {
184   return (_store == NONE) && _refCnt == 0 &&
185     !isFromPreprocessing();
186 }
187 
188 /**
189  * If storage is set to NONE, there are no references to this clause,
190  * an it is not an input clause, destroy it.
191  */
destroyIfUnnecessary()192 void Clause::destroyIfUnnecessary()
193 {
194   if (shouldBeDestroyed()) {
195     destroy();
196   }
197 }
198 
199 /**
200  * Destroy the clause by deleting the clause itself and all of its
201  * literals.
202  * @since 19/05/2007 Manchester
203  */
destroy()204 void Clause::destroy()
205 {
206   CALL("Clause::destroy");
207 
208   static Stack<Clause*> toDestroy(32);
209   Clause* cl = this;
210   for(;;) {
211     Inference::Iterator it = cl->_inference.iterator();
212     while (cl->_inference.hasNext(it)) {
213       Unit* refU = cl->_inference.next(it);
214       if (!refU->isClause()) {
215         continue;
216       }
217       Clause* refCl = static_cast<Clause*> (refU);
218       refCl->_refCnt--;
219       if (refCl->shouldBeDestroyed()) {
220         toDestroy.push(refCl);
221       }
222     }
223     cl->_inference.destroyDirectlyOwned();
224     cl->destroyExceptInferenceObject();
225     if (toDestroy.isEmpty()) {
226       break;
227     }
228     cl = toDestroy.pop();
229   }
230 } // Clause::destroy
231 
232 /** Set the store to @b s
233  *
234  * Can lead to clause deletion if the store is @b NONE
235  * and there Clause's reference counter is zero. */
setStore(Store s)236 void Clause::setStore(Store s)
237 {
238   CALL("Clause::setStore");
239 
240 #if VDEBUG
241   //assure there is one selected clause
242   static Clause* selected=0;
243   if (_store==SELECTED) {
244     ASS_EQ(selected, this);
245     selected=0;
246   }
247   if (s==SELECTED) {
248     ASS_EQ(selected, 0);
249     selected=this;
250   }
251 #endif
252   _store = s;
253   destroyIfUnnecessary();
254 }
255 
256 /**
257  * Return true iff clause contains no variables
258  */
isGround()259 bool Clause::isGround()
260 {
261   CALL("Clause::isGround");
262 
263   Iterator it(*this);
264   while (it.hasNext()) {
265     if (!it.next()->ground()) {
266       return false;
267     }
268   }
269   return true;
270 }
271 
272 /**
273  * Return true iff clause contains no literals of non-zero arity
274  */
isPropositional()275 bool Clause::isPropositional()
276 {
277   CALL("Clause::isPropositional");
278 
279   Iterator it(*this);
280   while (it.hasNext()) {
281     if (it.next()->arity() > 0) {
282       return false;
283     }
284   }
285   return true;
286 }
287 
288 /**
289  * Return true iff clause is Horn
290  */
isHorn()291 bool Clause::isHorn()
292 {
293   CALL("Clause::isHorn");
294 
295   bool posFound=false;
296   Iterator it(*this);
297   while (it.hasNext()) {
298     if (it.next()->isPositive()) {
299       if (posFound) {
300         return false;
301       }
302       else {
303         posFound=true;
304       }
305     }
306   }
307   return true;
308 }
309 
310 /**
311  * Return iterator over clause variables
312  */
getVariableIterator()313 VirtualIterator<unsigned> Clause::getVariableIterator()
314 {
315   CALL("Clause::getVariableIterator");
316 
317   return pvi( getUniquePersistentIterator(
318       getMappingIterator(
319 	  getMapAndFlattenIterator(
320 	      Iterator(*this),
321 	      VariableIteratorFn()),
322 	  OrdVarNumberExtractorFn())));
323 }
324 
325 /**
326  * Return true if the clause does not depend on any splits
327  * in the backtracking splitting.
328  */
noSplits() const329 bool Clause::noSplits() const
330 {
331   CALL("Clause::noSplits");
332 
333   return !_inference.splits() || _inference.splits()->isEmpty();
334 }
335 
336 /**
337  * Convert non-propositional part of the clause to vstring.
338  */
literalsOnlyToString() const339 vstring Clause::literalsOnlyToString() const
340 {
341   CALL("Clause::literalsOnlyToString");
342 
343   if (_length == 0) {
344     return "$false";
345   } else {
346     vstring result;
347     result += _literals[0]->toString();
348     for(unsigned i = 1; i < _length; i++) {
349       result += " | ";
350       result += _literals[i]->toString();
351     }
352     return result;
353   }
354 }
355 
356 /**
357  * Convert the clause to the TPTP-compatible vstring representation.
358  *
359  * The split history is omitted.
360  */
toTPTPString() const361 vstring Clause::toTPTPString() const
362 {
363   CALL("Clause::toTPTPString()");
364 
365   vstring result = literalsOnlyToString();
366 
367   return result;
368 }
369 
370 /**
371  * Convert the clause to easily readable vstring representation.
372  */
toNiceString() const373 vstring Clause::toNiceString() const
374 {
375   CALL("Clause::toNiceString()");
376 
377   vstring result = literalsOnlyToString();
378 
379   if (splits() && !splits()->isEmpty()) {
380     result += vstring(" {") + splits()->toString() + "}";
381   }
382 
383   return result;
384 }
385 
386 /**
387  * Convert the clause to the vstring representation
388  * Includes splitting, age, weight, selected and inference
389  */
toString() const390 vstring Clause::toString() const
391 {
392   CALL("Clause::toString()");
393 
394   // print id and literals of clause
395   vstring result = Int::toString(_number) + ". " + literalsOnlyToString();
396 
397   // print avatar components clause depends on
398   if (splits() && !splits()->isEmpty()) {
399     result += vstring(" <- (") + Splitter::splitsToString(splits()) + ")";
400   }
401 
402   // print inference and ids of parent clauses
403   result += " " + inferenceAsString();
404 
405   if(env.options->proofExtra()!=Options::ProofExtra::OFF){
406     // print statistics: each entry should have the form key:value
407     result += vstring(" {");
408 
409     result += vstring("a:") + Int::toString(age());
410     unsigned weight = (_weight ? _weight : computeWeight());
411     result += vstring(",w:") + Int::toString(weight);
412 
413     unsigned weightForClauseSelection = (_weightForClauseSelection ? _weightForClauseSelection : computeWeightForClauseSelection(*env.options));
414     if(weightForClauseSelection!=weight){
415       result += vstring(",wCS:") + Int::toString(weightForClauseSelection);
416     }
417 
418     if (numSelected()>0) {
419       result += vstring(",nSel:") + Int::toString(numSelected());
420     }
421 
422     if (env.colorUsed) {
423       result += vstring(",col:") + Int::toString(color());
424     }
425 
426     if(derivedFromGoal()){
427       result += vstring(",goal:1");
428     }
429     if(isPureTheoryDescendant()){
430       result += vstring(",ptD:1");
431     }
432 
433     if(env.options->induction() != Shell::Options::Induction::NONE){
434       result += vstring(",inD:") + Int::toString(_inference.inductionDepth());
435     }
436     result += ",thAx:" + Int::toString((int)(_inference.th_ancestors));
437     result += ",allAx:" + Int::toString((int)(_inference.all_ancestors));
438     result += ",thDist:" + Int::toString( _inference.th_ancestors * env.options->theorySplitQueueExpectedRatioDenom() - _inference.all_ancestors);
439     result += vstring("}");
440   }
441 
442   return result;
443 }
444 
445 /**
446  * Convert the clause into sequence of strings, each containing
447  * a proper clause
448  */
toSimpleClauseStrings()449 VirtualIterator<vstring> Clause::toSimpleClauseStrings()
450 {
451   CALL("toSimpleClauseStrings");
452     return pvi(getSingletonIterator(literalsOnlyToString()));
453 
454 }
455 
456 /**
457  * Return true iff the clause is skipped for the purpose
458  * of symbol elimination reporting.
459  */
skip() const460 bool Clause::skip() const
461 {
462   unsigned clen = length();
463   for(unsigned i = 0; i < clen; i++) {
464     const Literal* lit = (*this)[i];
465     if (!lit->skip()) {
466       return false;
467     }
468   }
469   return true;
470 }
471 
472 /**
473  * Compute the color of the clause and store it in @b _color
474  * @pre All literals are shared, so their color is computed properly.
475  */
computeColor() const476 void Clause::computeColor() const
477 {
478   CALL("Clause::computeColor");
479   ASS_EQ(_color, COLOR_INVALID);
480 
481   Color color = COLOR_TRANSPARENT;
482 
483   if (env.colorUsed) {
484     unsigned clen=length();
485     for(unsigned i=0;i<clen;i++) {
486       color = static_cast<Color>(color | (*this)[i]->color());
487     }
488     ASS_L(color, COLOR_INVALID);
489   }
490 
491   _color=color;
492 }
493 
494 /**
495  * Compute the weight of the clause.
496  * @pre All literals are shared, so their weight is computed properly.
497  * @since 02/01/2008 Manchester.
498  * @since 22/01/2015 include splitWeight in weight
499  */
computeWeight() const500 unsigned Clause::computeWeight() const
501 {
502   CALL("Clause::computeWeight");
503 
504   unsigned result = 0;
505   for (int i = _length-1; i >= 0; i--) {
506     ASS(_literals[i]->shared());
507     result += _literals[i]->weight();
508   }
509 
510   return result;
511 } // Clause::computeWeight
512 
513 
514 /**
515  * Return weight of the split part of the clause
516  *
517  * This weight is not included in the number returned by the
518  * @b weight() function.
519  */
splitWeight() const520 unsigned Clause::splitWeight() const
521 {
522   return splits() ? splits()->size() : 0;
523 }
524 
525 /**
526  * Returns the numeral weight of a clause. The weight is defined as the sum of
527  * binary sizes of all integers occurring in this clause.
528  * @warning Each call to this function recomputes the numeral weight, so the call may
529  *          potentially result in traversing the whole clause
530  * @since 04/05/2013 Manchester, updated to use new NonVariableIterator
531  * @author Andrei Voronkov
532  */
getNumeralWeight() const533 unsigned Clause::getNumeralWeight() const
534 {
535   CALL("Clause::getNumeralWeight");
536 
537   unsigned res=0;
538   Iterator litIt(*this);
539   while (litIt.hasNext()) {
540     Literal* lit=litIt.next();
541     if (!lit->hasInterpretedConstants()) {
542       continue;
543     }
544     NonVariableIterator nvi(lit);
545     while (nvi.hasNext()) {
546       const Term* t = nvi.next().term();
547       if (t->arity() != 0) {
548 	continue;
549       }
550       IntegerConstantType intVal;
551       if (theory->tryInterpretConstant(t,intVal)) {
552 	int w = BitUtils::log2(abs(intVal.toInner()))-1;
553 	if (w > 0) {
554 	  res += w;
555 	}
556 	continue;
557       }
558       RationalConstantType ratVal;
559       RealConstantType realVal;
560       bool haveRat = false;
561       if (theory->tryInterpretConstant(t,ratVal)) {
562 	haveRat = true;
563       }
564       else if (theory->tryInterpretConstant(t,realVal)) {
565 	ratVal = RationalConstantType(realVal);
566 	haveRat = true;
567       }
568       if (!haveRat) {
569 	continue;
570       }
571       int wN = BitUtils::log2(abs(ratVal.numerator().toInner()))-1;
572       int wD = BitUtils::log2(abs(ratVal.denominator().toInner()))-1;
573       int v = wN + wD;
574       if (v > 0) {
575 	res += v;
576       }
577     }
578   }
579   return res;
580 } // getNumeralWeight
581 
582 /**
583  * compute weight of the clause used by clause selection and cache it
584  */
computeWeightForClauseSelection(const Options & opt) const585 unsigned Clause::computeWeightForClauseSelection(const Options& opt) const
586 {
587   CALL("Clause::computeWeightForClauseSelection");
588 
589   unsigned w = 0;
590   if (_weight) {
591     w = _weight;
592   } else {
593     w = computeWeight();
594   }
595 
596   unsigned splWeight = 0;
597   if (opt.nonliteralsInClauseWeight()) {
598     splWeight = splitWeight(); // no longer includes propWeight
599   }
600 
601   // hack: computation of getNumeralWeight is potentially expensive, so we only compute it if
602   // the option increasedNumeralWeight is set to true.
603   unsigned numeralWeight = 0;
604   if (opt.increasedNumeralWeight())
605   {
606     numeralWeight = getNumeralWeight();
607   }
608 
609   bool derivedFromGoal = Unit::derivedFromGoal();
610   if(derivedFromGoal && opt.restrictNWCtoGC()){
611     bool found = false;
612     for(unsigned i=0;i<_length;i++){
613       TermFunIterator it(_literals[i]);
614       it.next(); // skip literal symbol
615       while(it.hasNext()){
616         found |= env.signature->getFunction(it.next())->inGoal();
617       }
618     }
619     if(!found){ derivedFromGoal=false; }
620   }
621 
622   return Clause::computeWeightForClauseSelection(w, splWeight, numeralWeight, derivedFromGoal, opt);
623 }
624 
625 /*
626  * note: we currently assume in Clause::computeWeightForClauseSelection(opt) that numeralWeight is only used here if
627  * the option increasedNumeralWeight() is set to true.
628  */
computeWeightForClauseSelection(unsigned w,unsigned splitWeight,unsigned numeralWeight,bool derivedFromGoal,const Shell::Options & opt)629 unsigned Clause::computeWeightForClauseSelection(unsigned w, unsigned splitWeight, unsigned numeralWeight, bool derivedFromGoal, const Shell::Options& opt)
630 {
631   static unsigned nongoalWeightCoeffNum = opt.nongoalWeightCoefficientNumerator();
632   static unsigned nongoalWeightCoefDenom = opt.nongoalWeightCoefficientDenominator();
633 
634   w += splitWeight;
635 
636   if (opt.increasedNumeralWeight()) {
637     w = (2 * w + numeralWeight);
638   }
639   return w * ( !derivedFromGoal ? nongoalWeightCoeffNum : nongoalWeightCoefDenom);
640 }
641 
collectVars(DHSet<unsigned> & acc)642 void Clause::collectVars(DHSet<unsigned>& acc)
643 {
644   CALL("Clause::collectVars");
645 
646   Iterator it(*this);
647   while (it.hasNext()) {
648     Literal* lit = it.next();
649     VariableIterator vit(lit);
650     while (vit.hasNext()) {
651       TermList var = vit.next();
652       ASS(var.isOrdinaryVar());
653       acc.insert(var.var());
654     }
655   }
656 }
657 
varCnt()658 unsigned Clause::varCnt()
659 {
660   CALL("Clause::varCnt");
661 
662   static DHSet<unsigned> vars;
663   vars.reset();
664   collectVars(vars);
665   return vars.size();
666 }
667 
maxVar()668 unsigned Clause::maxVar()
669 {
670   CALL("Clause::maxVar()");
671 
672   unsigned max = 0;
673   VirtualIterator<unsigned> it = getVariableIterator();
674 
675   while (it.hasNext()) {
676     unsigned n = it.next();
677     max = n > max ? n : max;
678   }
679   return max;
680 }
681 
numPositiveLiterals()682 unsigned Clause::numPositiveLiterals()
683 {
684   CALL("Clause::numPositiveLiterals");
685   unsigned count = 0;
686   for (int i = 0; i < _length; i++)
687   {
688     Literal *lit = (*this)[i];
689     if (lit->isPositive())
690     {
691       count++;
692     }
693   }
694   return count;
695 }
696 
697 /**
698  * Return index of @b lit in the clause
699  *
700  * @b lit has to be present in the clause
701  */
getLiteralPosition(Literal * lit)702 unsigned Clause::getLiteralPosition(Literal* lit)
703 {
704   switch(length()) {
705   case 1:
706     ASS_EQ(lit,(*this)[0]);
707     return 0;
708   case 2:
709     if (lit==(*this)[0]) {
710       return 0;
711     } else {
712       ASS_EQ(lit,(*this)[1]);
713       return 1;
714     }
715   case 3:
716     if (lit==(*this)[0]) {
717       return 0;
718     } else if (lit==(*this)[1]) {
719       return 1;
720     } else {
721       ASS_EQ(lit,(*this)[2]);
722       return 2;
723     }
724 #if VDEBUG
725   case 0:
726     ASSERTION_VIOLATION;
727 #endif
728   default:
729     if (!_literalPositions) {
730       _literalPositions=new InverseLookup<Literal>(_literals,length());
731     }
732     return static_cast<unsigned>(_literalPositions->get(lit));
733   }
734 }
735 
736 /**
737  * This method should be called when literals of the clause are
738  * reordered (e.g. after literal selection), so that the information
739  * about literal positions can be updated.
740  */
notifyLiteralReorder()741 void Clause::notifyLiteralReorder()
742 {
743   CALL("Clause::notifyLiteralReorder");
744   if (_literalPositions) {
745     _literalPositions->update(_literals);
746   }
747 }
748 
749 #if VDEBUG
750 
assertValid()751 void Clause::assertValid()
752 {
753   ASS_ALLOC_TYPE(this, "Clause");
754   if (_literalPositions) {
755     unsigned clen=length();
756     for (unsigned i = 0; i<clen; i++) {
757       ASS_EQ(getLiteralPosition((*this)[i]),i);
758     }
759   }
760 }
761 
762 #endif
763 
contains(Literal * lit)764 bool Clause::contains(Literal* lit)
765 {
766   for (int i = _length-1; i >= 0; i--) {
767     if (_literals[i]==lit) {
768       return true;
769     }
770   }
771   return false;
772 }
773 
774 }
775