1 
2 /*
3  * File AWPassiveClauseContainer.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 AWPassiveClauseContainer.cpp
21  * Implements class AWPassiveClauseContainer for the queue of passive clauses.
22  * @since 30/12/2007 Manchester
23  */
24 
25 #include <math.h>
26 
27 #include "Debug/RuntimeStatistics.hpp"
28 
29 #include "Lib/Environment.hpp"
30 #include "Lib/Int.hpp"
31 #include "Lib/Timer.hpp"
32 #include "Kernel/Term.hpp"
33 #include "Kernel/Clause.hpp"
34 #include "Kernel/Signature.hpp"
35 #include "Kernel/TermIterators.hpp"
36 #include "Shell/Statistics.hpp"
37 #include "Shell/Options.hpp"
38 
39 #include "SaturationAlgorithm.hpp"
40 
41 #if VDEBUG
42 #include <iostream>
43 #endif
44 
45 #include "AWPassiveClauseContainer.hpp"
46 
47 namespace Saturation
48 {
49 using namespace Lib;
50 using namespace Kernel;
51 
AWPassiveClauseContainer(bool isOutermost,const Shell::Options & opt,vstring name)52 AWPassiveClauseContainer::AWPassiveClauseContainer(bool isOutermost, const Shell::Options& opt, vstring name) :
53   PassiveClauseContainer(isOutermost, opt, name),
54   _ageQueue(opt),
55   _weightQueue(opt),
56   _ageRatio(opt.ageRatio()),
57   _weightRatio(opt.weightRatio()),
58   _balance(0),
59   _size(0),
60 
61   _simulationBalance(0),
62   _simulationCurrAgeIt(_ageQueue),
63   _simulationCurrWeightIt(_weightQueue),
64   _simulationCurrAgeCl(nullptr),
65   _simulationCurrWeightCl(nullptr),
66 
67   _ageSelectionMaxAge(UINT_MAX),
68   _ageSelectionMaxWeight(UINT_MAX),
69   _weightSelectionMaxWeight(UINT_MAX),
70   _weightSelectionMaxAge(UINT_MAX)
71 {
72   CALL("AWPassiveClauseContainer::AWPassiveClauseContainer");
73 
74   if(_opt.ageWeightRatioShape() == Options::AgeWeightRatioShape::CONVERGE) {
75     _ageRatio = 1;
76     _weightRatio = 1;
77   }
78   ASS_GE(_ageRatio, 0);
79   ASS_GE(_weightRatio, 0);
80   ASS(_ageRatio > 0 || _weightRatio > 0);
81 }
82 
~AWPassiveClauseContainer()83 AWPassiveClauseContainer::~AWPassiveClauseContainer()
84 {
85   ClauseQueue::Iterator cit(_ageQueue);
86   while (cit.hasNext())
87   {
88     Clause* cl=cit.next();
89     ASS(!_isOutermost || cl->store()==Clause::PASSIVE);
90     cl->setStore(Clause::NONE);
91   }
92 }
93 
94 /**
95  * Weight comparison of clauses.
96  * @return the result of comparison (LESS, EQUAL or GREATER)
97  * @warning if the option increased_numeral_weight is on, then each comparison
98  *          recomputes the numeral weight of clauses, see Clause::getNumeralWeight(), so it
99  *          it can be expensive
100  */
compareWeight(Clause * cl1,Clause * cl2,const Options & opt)101 Comparison AWPassiveClauseContainer::compareWeight(Clause* cl1, Clause* cl2, const Options& opt)
102 {
103   CALL("AWPassiveClauseContainer::compareWeight");
104 
105   return Int::compare(cl1->weightForClauseSelection(opt), cl2->weightForClauseSelection(opt));
106 }
107 
108 /**
109  * Comparison of clauses. The comparison uses four orders in the
110  * following order:
111  * <ol><li>by weight;</li>
112  *     <li>by age;</li>
113  *     <li>by input type;</li>
114  *     <li>by number.</li>
115  * </ol>
116  * @since 30/12/2007 Manchester
117  */
lessThan(Clause * c1,Clause * c2)118 bool WeightQueue::lessThan(Clause* c1,Clause* c2)
119 {
120   CALL("WeightQueue::lessThan");
121 
122   Comparison weightCmp=AWPassiveClauseContainer::compareWeight(c1, c2, _opt);
123   if (weightCmp!=EQUAL) {
124     return weightCmp==LESS;
125   }
126 
127   if (c1->age() < c2->age()) {
128     return true;
129   }
130   if (c2->age() < c1->age()) {
131     return false;
132   }
133   if (c1->inputType() < c2->inputType()) {
134     return false;
135   }
136   if (c2->inputType() < c1->inputType()) {
137     return true;
138   }
139   return c1->number() < c2->number();
140 } // WeightQueue::lessThan
141 
142 
143 /**
144  * Comparison of clauses. The comparison uses four orders in the
145  * following order:
146  * <ol><li>by age;</li>
147  *     <li>by weight;</li>
148  *     <li>by input type;</li>
149  *     <li>by number.</li>
150  * </ol>
151  * @since 30/12/2007 Manchester
152  */
lessThan(Clause * c1,Clause * c2)153 bool AgeQueue::lessThan(Clause* c1,Clause* c2)
154 {
155   CALL("AgeQueue::lessThan");
156 
157   if (c1->age() < c2->age()) {
158     return true;
159   }
160   if (c2->age() < c1->age()) {
161     return false;
162   }
163 
164   Comparison weightCmp=AWPassiveClauseContainer::compareWeight(c1, c2, _opt);
165   if (weightCmp!=EQUAL) {
166     return weightCmp==LESS;
167   }
168 
169   if (c1->inputType() < c2->inputType()) {
170     return false;
171   }
172   if (c2->inputType() < c1->inputType()) {
173     return true;
174   }
175 
176   return c1->number() < c2->number();
177 } // WeightQueue::lessThan
178 
179 /**
180  * Add @b c clause in the queue.
181  * @since 31/12/2007 Manchester
182  */
add(Clause * cl)183 void AWPassiveClauseContainer::add(Clause* cl)
184 {
185   CALL("AWPassiveClauseContainer::add");
186   ASS(_ageRatio > 0 || _weightRatio > 0);
187   ASS(cl->store() == Clause::PASSIVE);
188 
189   if (_ageRatio) {
190     _ageQueue.insert(cl);
191   }
192   if (_weightRatio) {
193     _weightQueue.insert(cl);
194   }
195   _size++;
196 
197   if (_isOutermost)
198   {
199     addedEvent.fire(cl);
200   }
201 } // AWPassiveClauseContainer::add
202 
203 /**
204  * Remove Clause from the Passive store. Should be called only
205  * when the Clause is no longer needed by the inference process
206  * (i.e. was backward subsumed/simplified), as it can result in
207  * deletion of the clause.
208  */
remove(Clause * cl)209 void AWPassiveClauseContainer::remove(Clause* cl)
210 {
211   CALL("AWPassiveClauseContainer::remove");
212   if (_isOutermost)
213   {
214     ASS(cl->store()==Clause::PASSIVE);
215   }
216   ASS(_ageRatio > 0 || _weightRatio > 0);
217   bool wasRemoved; // will be assigned, since at least one of the following checks succeeds
218   if (_ageRatio) {
219     wasRemoved = _ageQueue.remove(cl);
220   }
221   if (_weightRatio) {
222     wasRemoved = _weightQueue.remove(cl);
223   }
224 
225   if (wasRemoved) {
226     _size--;
227   }
228 
229   if (_isOutermost)
230   {
231     removedEvent.fire(cl);
232     ASS(cl->store()!=Clause::PASSIVE);
233   }
234 }
235 
byWeight(int balance)236 bool AWPassiveClauseContainer::byWeight(int balance)
237 {
238   CALL("AWPassiveClauseContainer::byWeight");
239 
240   if (! _ageRatio) {
241     return true;
242   }
243   else if (! _weightRatio) {
244     return false;
245   }
246   else if (balance > 0) {
247     return true;
248   }
249   else if (balance < 0) {
250     return false;
251   }
252   else {
253     return (_ageRatio <= _weightRatio);
254   }
255 }
256 
257 /**
258  * Return the next selected clause and remove it from the queue.
259  * @since 31/12/2007 Manchester
260  */
popSelected()261 Clause* AWPassiveClauseContainer::popSelected()
262 {
263   CALL("AWPassiveClauseContainer::popSelected");
264   ASS( ! isEmpty());
265 
266   auto shape = _opt.ageWeightRatioShape();
267   unsigned frequency = _opt.ageWeightRatioShapeFrequency();
268   static unsigned count = 0;
269   count++;
270 
271   bool is_converging = shape == Options::AgeWeightRatioShape::CONVERGE;
272   int targetAgeRatio = is_converging ? _opt.ageRatio() : 1;
273   int targetWeightRatio = is_converging ? _opt.weightRatio() : 1;
274 
275   if(count % frequency == 0) {
276     switch(shape) {
277     case Options::AgeWeightRatioShape::CONSTANT:
278       break;
279     case Options::AgeWeightRatioShape::DECAY:
280     case Options::AgeWeightRatioShape::CONVERGE:
281       int ageDifference = targetAgeRatio - _ageRatio;
282       int weightDifference = targetWeightRatio - _weightRatio;
283       int bonus = is_converging ? 1 : -1;
284       int ageUpdate = (ageDifference + bonus) / 2;
285       int weightUpdate = (weightDifference + bonus) / 2;
286 
287       _ageRatio += ageUpdate;
288       _weightRatio += weightUpdate;
289    }
290   }
291   //std::cerr << _ageRatio << "\t" << _weightRatio << std::endl;
292   _size--;
293 
294   Clause* cl;
295   if (byWeight(_balance)) {
296     _balance -= _ageRatio;
297     cl = _weightQueue.pop();
298     _ageQueue.remove(cl);
299   } else {
300     _balance += _weightRatio;
301     cl = _ageQueue.pop();
302     _weightQueue.remove(cl);
303   }
304 
305   if (_isOutermost) {
306     selectedEvent.fire(cl);
307   }
308 
309   return cl;
310 } // AWPassiveClauseContainer::popSelected
311 
onLimitsUpdated()312 void AWPassiveClauseContainer::onLimitsUpdated()
313 {
314   CALL("AWPassiveClauseContainer::onLimitsUpdated");
315 
316   if ( (!ageLimited() && _ageRatio) || (!weightLimited() && _weightRatio) ) {
317     return;
318   }
319 
320   //Here we rely on (and maintain) the invariant, that
321   //_weightQueue and _ageQueue contain the same set
322   //of clauses, differing only in their order.
323   //(unless one of _ageRation or _weightRatio is equal to 0)
324 
325   static Stack<Clause*> toRemove(256);
326   ClauseQueue::Iterator wit(_weightQueue);
327   while (wit.hasNext()) {
328     Clause* cl=wit.next();
329     if (!fulfilsAgeLimit(cl) && !fulfilsWeightLimit(cl)) {
330       toRemove.push(cl);
331     } else if (!childrenPotentiallyFulfilLimits(cl, cl->length())) {
332       toRemove.push(cl);
333     }
334   }
335 
336 #if OUTPUT_LRS_DETAILS
337   if (toRemove.isNonEmpty()) {
338     cout<<toRemove.size()<<" passive deleted, "<< (size()-toRemove.size()) <<" remains\n";
339   }
340 #endif
341 
342   while (toRemove.isNonEmpty()) {
343     Clause* removed=toRemove.pop();
344     RSTAT_CTR_INC("clauses discarded from passive on weight limit update");
345     env.statistics->discardedNonRedundantClauses++;
346     remove(removed);
347   }
348 }
349 
simulationInit()350 void AWPassiveClauseContainer::simulationInit()
351 {
352   CALL("AWPassiveClauseContainer::simulationInit");
353   _simulationBalance = _balance;
354 
355   // initialize iterators
356   _simulationCurrAgeIt = ClauseQueue::Iterator(_ageQueue);
357   _simulationCurrWeightIt = ClauseQueue::Iterator(_weightQueue);
358   _simulationCurrAgeCl = _simulationCurrAgeIt.hasNext() ? _simulationCurrAgeIt.next() : nullptr;
359   _simulationCurrWeightCl = _simulationCurrWeightIt.hasNext() ? _simulationCurrWeightIt.next() : nullptr;
360 
361   // have to consider two possibilities for simulation:
362   // standard case: both container are initially non-empty, then have invariants
363   // - _simulationCurrAgeCl != nullptr
364   // - _simulationCurrWeightCl != nullptr
365   // degenerate case: both containers are initially empty, then have invariant
366   // - _simulationCurrAgeCl == nullptr
367   // - _simulationCurrWeightCl == nullptr
368   ASS(_simulationCurrAgeCl != nullptr || _simulationCurrWeightCl == nullptr);
369   ASS(_simulationCurrAgeCl == nullptr || _simulationCurrWeightCl != nullptr);
370 }
371 
simulationHasNext()372 bool AWPassiveClauseContainer::simulationHasNext()
373 {
374   CALL("AWPassiveClauseContainer::simulationHasNext");
375 
376   ASS(_simulationCurrAgeCl != nullptr || _simulationCurrWeightCl == nullptr);
377   ASS(_simulationCurrAgeCl == nullptr || _simulationCurrWeightCl != nullptr);
378   if (_simulationCurrAgeCl == nullptr)
379   {
380     // degenerate case, both containers are empty, so return false
381     return false;
382   }
383 
384   // advance _simulationCurrAgeIt, until _simulationCurrAgeCl points to a
385   // clause which has not been deleted in the simulation or _simulationCurrAgeIt
386   // reaches the end of the age-queue
387   // establishes invariant: if there is a clause which is not deleted in the simulation, then _simulationCurrAgeCl is not deleted.
388   while (_simulationCurrAgeCl->hasAux() && _simulationCurrAgeIt.hasNext())
389   {
390     _simulationCurrAgeCl = _simulationCurrAgeIt.next();
391   }
392   // same for weight-queue
393   while (_simulationCurrWeightCl->hasAux() && _simulationCurrWeightIt.hasNext())
394   {
395     _simulationCurrWeightCl = _simulationCurrWeightIt.next();
396   }
397 
398   ASS(_simulationCurrAgeCl != nullptr);
399   ASS(_simulationCurrWeightCl != nullptr);
400   ASS(!_simulationCurrAgeCl->hasAux() || _simulationCurrWeightCl->hasAux());
401   ASS(_simulationCurrAgeCl->hasAux() || !_simulationCurrWeightCl->hasAux());
402 
403   return !_simulationCurrAgeCl->hasAux();
404 }
405 
406 // assumes that simulationHasNext() has been called before and returned true,
407 // so both iterators point to a clause which is not deleted in the simulation
simulationPopSelected()408 void AWPassiveClauseContainer::simulationPopSelected()
409 {
410   CALL("AWPassiveClauseContainer::simulationPopSelected");
411   // invariant: both queues contain the same clauses and
412   // the fact that both queues share the aux-field which denotes whether a clause was deleted during the simulation.
413   if (byWeight(_simulationBalance)) {
414     // simulate selection by weight
415     _simulationBalance -= _ageRatio;
416     ASS(!_simulationCurrWeightCl->hasAux());
417     _simulationCurrWeightCl->setAux();
418   } else {
419     // simulate selection by age
420     _simulationBalance += _weightRatio;
421     ASS(!_simulationCurrAgeCl->hasAux());
422     _simulationCurrAgeCl->setAux();
423   }
424 }
425 
setLimitsToMax()426 bool AWPassiveClauseContainer::setLimitsToMax()
427 {
428   CALL("AWPassiveClauseContainer::setLimitsToMax");
429   return setLimits(UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX);
430 }
431 
setLimitsFromSimulation()432 bool AWPassiveClauseContainer::setLimitsFromSimulation()
433 {
434   CALL("AWPassiveClauseContainer::setLimitsFromSimulation");
435 
436   ASS(_simulationCurrAgeCl != nullptr || _simulationCurrWeightCl == nullptr);
437   ASS(_simulationCurrAgeCl == nullptr || _simulationCurrWeightCl != nullptr);
438   if (_simulationCurrAgeCl == nullptr)
439   {
440     // degenerate case: both queues are empty (independently from the simulation), so set limits to max.
441     return setLimitsToMax();
442   }
443 
444   ASS(!_simulationCurrAgeCl->hasAux() || _simulationCurrWeightCl->hasAux());
445   ASS(_simulationCurrAgeCl->hasAux() || !_simulationCurrWeightCl->hasAux());
446 
447   unsigned maxAgeQueueAge;
448   unsigned maxAgeQueueWeight;
449   unsigned maxWeightQueueWeight;
450   unsigned maxWeightQueueAge;
451 
452   // compute limits for age-queue
453   if (_ageRatio != 0)
454   {
455     if (_simulationCurrAgeIt.hasNext())
456     {
457       // the age-queue is in use and the simulation didn't get to the end of the age-queue => set limits on age-queue
458       maxAgeQueueAge = _simulationCurrAgeCl->age();
459       maxAgeQueueWeight = _simulationCurrAgeCl->weightForClauseSelection(_opt);
460     }
461     else
462     {
463       // the age-queue is in use and the simulation got to the end of the age-queue => set no limits on age-queue
464       maxAgeQueueAge = UINT_MAX;
465       maxAgeQueueWeight = UINT_MAX;
466     }
467   }
468   else
469   {
470     // the age-queue is not in use, so no clause will be selected from the age-queue => set tighest possible bound on age-queue
471     maxAgeQueueAge = 0;
472     maxAgeQueueWeight = 0;
473   }
474 
475   // compute limits for weight-queue
476   if (_weightRatio != 0)
477   {
478     if (_simulationCurrWeightIt.hasNext())
479     {
480       // the weight-queue is in use and the simulation didn't get to the end of the weight-queue => set limits on weight-queue
481       maxWeightQueueWeight = _simulationCurrWeightCl->weightForClauseSelection(_opt);
482       maxWeightQueueAge = _simulationCurrWeightCl->age();
483     }
484     else
485     {
486       // the weight-queue is in use and the simulation got to the end of the weight-queue => set no limits on weight-queue
487       maxWeightQueueWeight = UINT_MAX;
488       maxWeightQueueAge = UINT_MAX;
489     }
490   }
491   else
492   {
493     // the weight-queue is not in use, so no clause will be selected from the weight-queue => set tighest possible bound on weight-queue
494     maxWeightQueueWeight = 0;
495     maxWeightQueueAge = 0;
496   }
497 
498   // note: we ignore the option lrsWeightLimitOnly() if weightRatio is set to 0
499   // TODO: force in Options that weightRatio is positive if lrsWeightLimitOnly() is set to 'on'.
500   if (_opt.lrsWeightLimitOnly() && _weightRatio!=0)
501   {
502     // if the option lrsWeightLimitOnly() is set, we want to discard all clauses which are too heavy, regardless of the age.
503     // we therefore make sure that ageLimited() always fails.
504     maxAgeQueueAge = 0;
505     maxAgeQueueWeight = 0;
506   }
507 
508   return setLimits(maxAgeQueueAge, maxAgeQueueWeight,maxWeightQueueWeight, maxWeightQueueAge);
509 }
510 
childrenPotentiallyFulfilLimits(Clause * cl,unsigned upperBoundNumSelLits) const511 bool AWPassiveClauseContainer::childrenPotentiallyFulfilLimits(Clause* cl, unsigned upperBoundNumSelLits) const
512 {
513   CALL("AWPassiveClauseContainer::childrenPotentiallyFulfilLimits");
514   if (cl->age() == _ageSelectionMaxAge)
515   {
516     // creating a fake inference to represent our current (pessimistic) estimate potential
517     // FromInput - so that there is no Unit ownership issue
518     Inference inf = FromInput(UnitInputType::CONJECTURE); // CONJECTURE, so that derivedFromGoal is estimated as true
519     inf.setAge(cl->age() + 1); // clauses inferred from the clause as generating inferences will be over age limit...
520 
521     int maxSelWeight=0;
522     for(unsigned i=0;i<upperBoundNumSelLits;i++) {
523       maxSelWeight=max((int)(*cl)[i]->weight(),maxSelWeight);
524     }
525     // TODO: this lower bound is not correct:
526     //       if Avatar is used, then the child-clause could become splittable,
527     //       in which case we don't know any lower bound on the resulting components.
528     unsigned weightLowerBound = cl->weight() - maxSelWeight; // heuristic: we assume that at most one literal will be removed from the clause.
529     unsigned numPositiveLiteralsParent = cl->numPositiveLiterals();
530     unsigned numPositiveLiteralsLowerBound = numPositiveLiteralsParent > 0 ? numPositiveLiteralsParent-1 : numPositiveLiteralsParent; // heuristic: we assume that at most one literal will be removed from the clause
531     if (!fulfilsWeightLimit(weightLowerBound, numPositiveLiteralsLowerBound, inf)) {
532       //and also over weight limit
533       return false;
534     }
535   }
536   return true;
537 }
538 
setLimits(unsigned newAgeSelectionMaxAge,unsigned newAgeSelectionMaxWeight,unsigned newWeightSelectionMaxWeight,unsigned newWeightSelectionMaxAge)539 bool AWPassiveClauseContainer::setLimits(unsigned newAgeSelectionMaxAge, unsigned newAgeSelectionMaxWeight, unsigned newWeightSelectionMaxWeight, unsigned newWeightSelectionMaxAge)
540 {
541   CALL("AWPassiveClauseContainer::setLimits");
542 
543   bool atLeastOneTightened = false;
544   if(newAgeSelectionMaxAge != _ageSelectionMaxAge || newAgeSelectionMaxWeight != _ageSelectionMaxWeight) {
545     if(newAgeSelectionMaxAge < _ageSelectionMaxAge) {
546       atLeastOneTightened = true;
547     } else if (newAgeSelectionMaxAge == _ageSelectionMaxAge && newAgeSelectionMaxWeight < _ageSelectionMaxWeight) {
548       atLeastOneTightened = true;
549     }
550     _ageSelectionMaxAge=newAgeSelectionMaxAge;
551     _ageSelectionMaxWeight=newAgeSelectionMaxWeight;
552   }
553   if(newWeightSelectionMaxWeight != _weightSelectionMaxWeight || newWeightSelectionMaxAge != _weightSelectionMaxAge) {
554     if(newWeightSelectionMaxWeight < _weightSelectionMaxWeight) {
555       atLeastOneTightened = true;
556     } else if (newWeightSelectionMaxWeight == _weightSelectionMaxWeight && newWeightSelectionMaxAge < _weightSelectionMaxAge) {
557       atLeastOneTightened = true;
558     }
559     _weightSelectionMaxWeight=newWeightSelectionMaxWeight;
560     _weightSelectionMaxAge=newWeightSelectionMaxAge;
561   }
562   return atLeastOneTightened;
563 }
564 
ageLimited() const565 bool AWPassiveClauseContainer::ageLimited() const
566 {
567   CALL("AWPassiveClauseContainer::ageLimited");
568 
569   return _ageSelectionMaxAge != UINT_MAX && _ageSelectionMaxWeight != UINT_MAX;
570 }
571 
weightLimited() const572 bool AWPassiveClauseContainer::weightLimited() const
573 {
574   CALL("AWPassiveClauseContainer::weightLimited");
575   return _weightSelectionMaxWeight != UINT_MAX && _weightSelectionMaxAge != UINT_MAX;
576 }
577 
fulfilsAgeLimit(Clause * cl) const578 bool AWPassiveClauseContainer::fulfilsAgeLimit(Clause* cl) const
579 {
580   CALL("AWPassiveClauseContainer::fulfilsAgeLimit(Clause*)");
581 
582   // don't want to reuse fulfilsAgeLimit(unsigned age,..) here, since we don't want to recompute weightForClauseSelection
583   unsigned age = cl->age();
584   unsigned weightForClauseSelection = cl->weightForClauseSelection(_opt);
585   return age <= _ageSelectionMaxAge || (age == _ageSelectionMaxAge && weightForClauseSelection <= _ageSelectionMaxWeight);
586 }
587 
fulfilsAgeLimit(unsigned w,unsigned numPositiveLiterals,const Inference & inference) const588 bool AWPassiveClauseContainer::fulfilsAgeLimit(unsigned w, unsigned numPositiveLiterals, const Inference& inference) const
589 {
590   CALL("AWPassiveClauseContainer::fulfilsAgeLimit(unsigned, unsigned, const Inference&)");
591 
592   const unsigned age = inference.age();
593   const unsigned numeralWeight = 0; // heuristic: we don't want to compute the numeral weight during estimates and conservatively assume that it is 0.
594   const unsigned splitWeight = 0; // also conservatively assuming 0
595   /* In principle, we could compute this from the Inference (and it's not so expensive)
596    * but it's only relevant with avatar on (and avatar would later compute the splitset of the new clause again)
597    * and nonliteralsInClauseWeight on, which is not the default. So keeping the cheap version for now.
598    */
599   const bool derivedFromGoal = inference.derivedFromGoal();
600   // If the caller was too lazy to supply an Inference object we conservatively assume that the result is a goal-clause.
601   unsigned weightForClauseSelection = Clause::computeWeightForClauseSelection(w, splitWeight, numeralWeight, derivedFromGoal, _opt);
602   return age <= _ageSelectionMaxAge || (age == _ageSelectionMaxAge && weightForClauseSelection <= _ageSelectionMaxWeight);
603 }
604 
fulfilsWeightLimit(Clause * cl) const605 bool AWPassiveClauseContainer::fulfilsWeightLimit(Clause* cl) const
606 {
607   CALL("AWPassiveClauseContainer::fulfilsWeightLimit(Clause*)");
608 
609   // don't want to reuse fulfilsWeightLimit(unsigned w,..) here, since we don't want to recompute weightForClauseSelection
610   unsigned weightForClauseSelection = cl->weightForClauseSelection(_opt);
611   unsigned age = cl->age();
612   return weightForClauseSelection <= _weightSelectionMaxWeight || (weightForClauseSelection == _weightSelectionMaxWeight && age <= _weightSelectionMaxAge);
613 }
614 
fulfilsWeightLimit(unsigned w,unsigned numPositiveLiterals,const Inference & inference) const615 bool AWPassiveClauseContainer::fulfilsWeightLimit(unsigned w, unsigned numPositiveLiterals, const Inference& inference) const
616 {
617   CALL("AWPassiveClauseContainer::fulfilsWeightLimit(unsigned, unsigned, const Inference&)");
618 
619   const unsigned age = inference.age();
620   const unsigned numeralWeight = 0; // heuristic: we don't want to compute the numeral weight during estimates and conservatively assume that it is 0.
621   const unsigned splitWeight = 0; // also conservatively assuming 0
622   /* In principle, we could compute this from the Inference (and it's not so expensive)
623    * but it's only relevant with avatar on (and avatar would later compute the splitset of the new clause again)
624    * and nonliteralsInClauseWeight on, which is not the default. So keeping the cheap version for now.
625    */
626   const bool derivedFromGoal = inference.derivedFromGoal();
627   // If the caller was too lazy to supply an Inference object we conservatively assume that the result is a goal-clause.
628   unsigned weightForClauseSelection = Clause::computeWeightForClauseSelection(w, splitWeight, numeralWeight, derivedFromGoal, _opt);
629   return weightForClauseSelection <= _weightSelectionMaxWeight || (weightForClauseSelection == _weightSelectionMaxWeight && age <= _weightSelectionMaxAge);
630 }
631 
AWClauseContainer(const Options & opt)632 AWClauseContainer::AWClauseContainer(const Options& opt)
633 : _ageQueue(opt), _weightQueue(opt), _ageRatio(1), _weightRatio(1), _balance(0), _size(0)
634 {
635 }
636 
isEmpty() const637 bool AWClauseContainer::isEmpty() const
638 {
639   CALL("AWClauseContainer::isEmpty");
640 
641   ASS(!_ageRatio || !_weightRatio || _ageQueue.isEmpty()==_weightQueue.isEmpty());
642   return _ageQueue.isEmpty() && _weightQueue.isEmpty();
643 }
644 
645 /**
646  * Add @b c clause in the queue.
647  * @since 31/12/2007 Manchester
648  */
add(Clause * cl)649 void AWClauseContainer::add(Clause* cl)
650 {
651   CALL("AWClauseContainer::add");
652   ASS(_ageRatio > 0 || _weightRatio > 0);
653 
654   if (_ageRatio) {
655     _ageQueue.insert(cl);
656   }
657   if (_weightRatio) {
658     _weightQueue.insert(cl);
659   }
660   _size++;
661   addedEvent.fire(cl);
662 }
663 
664 /**
665  * Remove Clause from the container.
666  */
remove(Clause * cl)667 bool AWClauseContainer::remove(Clause* cl)
668 {
669   CALL("AWClauseContainer::remove");
670 
671   bool removed;
672   if (_ageRatio) {
673     removed = _ageQueue.remove(cl);
674     if (_weightRatio) {
675       ALWAYS(_weightQueue.remove(cl)==removed);
676     }
677   }
678   else {
679     ASS(_weightRatio);
680     removed = _weightQueue.remove(cl);
681   }
682 
683   if (removed) {
684     _size--;
685     removedEvent.fire(cl);
686   }
687   return removed;
688 }
689 
690 
691 /**
692  * Return the next selected clause and remove it from the queue.
693  */
popSelected()694 Clause* AWClauseContainer::popSelected()
695 {
696   CALL("AWClauseContainer::popSelected");
697   ASS( ! isEmpty());
698 
699   _size--;
700 
701   bool byWeight;
702   if (! _ageRatio) {
703     byWeight = true;
704   }
705   else if (! _weightRatio) {
706     byWeight = false;
707   }
708   else if (_balance > 0) {
709     byWeight = true;
710   }
711   else if (_balance < 0) {
712     byWeight = false;
713   }
714   else {
715     byWeight = (_ageRatio <= _weightRatio);
716   }
717 
718   Clause* cl;
719   if (byWeight) {
720     _balance -= _ageRatio;
721     cl = _weightQueue.pop();
722     ALWAYS(_ageQueue.remove(cl));
723   }
724   else {
725     _balance += _weightRatio;
726     cl = _ageQueue.pop();
727     ALWAYS(_weightQueue.remove(cl));
728   }
729   selectedEvent.fire(cl);
730   return cl;
731 }
732 
733 
734 
735 }
736