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