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