#include "Debug/RuntimeStatistics.hpp"
#include "Lib/Environment.hpp"
#include "Lib/Int.hpp"
#include "Lib/Random.hpp"
#include "Kernel/Term.hpp"
#include "Kernel/Clause.hpp"
#include "Shell/Statistics.hpp"
#include "Shell/Options.hpp"
#if OUTPUT_LRS_DETAILS
#include <iostream>
#endif
#include "AWPassiveClauseContainers.hpp"
namespace Saturation
{
using namespace std;
using namespace Lib;
using namespace Kernel;
static Comparison compareWeight(Clause* cl1, Clause* cl2, const Options& opt)
{
return Int::compare(cl1->weightForClauseSelection(opt), cl2->weightForClauseSelection(opt));
}
bool AgeQueue::lessThan(Clause* c1,Clause* c2)
{
if (c1->age() < c2->age()) {
return true;
}
if (c2->age() < c1->age()) {
return false;
}
Comparison weightCmp=compareWeight(c1, c2, _opt);
if (weightCmp!=EQUAL) {
return weightCmp==LESS;
}
if (c1->inputType() < c2->inputType()) {
return false;
}
if (c2->inputType() < c1->inputType()) {
return true;
}
return c1->number() < c2->number();
}
AgeQueue::OrdVal AgeQueue::getOrdVal(Clause* cl) const
{
return std::make_pair(cl->age(),cl->weightForClauseSelection(_opt));
}
bool WeightQueue::lessThan(Clause* c1,Clause* c2)
{
Comparison weightCmp=compareWeight(c1, c2, _opt);
if (weightCmp!=EQUAL) {
return weightCmp==LESS;
}
if (c1->age() < c2->age()) {
return true;
}
if (c2->age() < c1->age()) {
return false;
}
if (c1->inputType() < c2->inputType()) {
return false;
}
if (c2->inputType() < c1->inputType()) {
return true;
}
return c1->number() < c2->number();
}
WeightQueue::OrdVal WeightQueue::getOrdVal(Clause* cl) const
{
return std::make_pair(cl->weightForClauseSelection(_opt),cl->age());
}
AWPassiveClauseContainer::AWPassiveClauseContainer(bool isOutermost, const Shell::Options& opt, std::string name) :
PassiveClauseContainer(isOutermost, opt, name),
_ageQueue(opt),
_weightQueue(opt),
_ageRatio(opt.ageRatio()),
_weightRatio(opt.weightRatio()),
_balance(0),
_size(0),
_simulationBalance(0),
_simulationCurrAgeIt(_ageQueue),
_simulationCurrWeightIt(_weightQueue),
_simulationCurrAgeCl(nullptr),
_simulationCurrWeightCl(nullptr),
_ageSelectionMaxAge(UINT_MAX),
_ageSelectionMaxWeight(UINT_MAX),
_weightSelectionMaxWeight(UINT_MAX)
{
ASS_G(_ageRatio, 0);
ASS_G(_weightRatio, 0);
}
AWPassiveClauseContainer::~AWPassiveClauseContainer()
{
ClauseQueue::Iterator cit(_ageQueue);
while (cit.hasNext())
{
Clause* cl=cit.next();
ASS(!_isOutermost || cl->store()==Clause::PASSIVE);
cl->setStore(Clause::NONE);
}
}
void AWPassiveClauseContainer::add(Clause* cl)
{
ASS(cl->store() == Clause::PASSIVE);
_ageQueue.insert(cl);
_weightQueue.insert(cl);
_size++;
if (_isOutermost) {
addedEvent.fire(cl);
}
}
void AWPassiveClauseContainer::remove(Clause* cl)
{
if (_isOutermost) {
ASS(cl->store()==Clause::PASSIVE);
}
_ageQueue.remove(cl);
if (_weightQueue.remove(cl)) { _size--;
}
if (_isOutermost) {
removedEvent.fire(cl);
ASS(cl->store()!=Clause::PASSIVE);
}
}
bool AWPassiveClauseContainer::byWeight(int balance)
{
if (balance > 0) {
return true;
} else if (balance < 0) {
return false;
} else {
return (_ageRatio <= _weightRatio);
}
}
Clause* AWPassiveClauseContainer::popSelected()
{
ASS(!isEmpty());
_size--;
Clause* cl;
bool selByWeight = _opt.randomAWR() ?
(Random::getInteger(_ageRatio+_weightRatio) < _weightRatio) :
byWeight(_balance);
if (selByWeight) {
_balance -= _ageRatio;
cl = _weightQueue.pop();
_ageQueue.remove(cl);
} else {
_balance += _weightRatio;
cl = _ageQueue.pop();
_weightQueue.remove(cl);
}
if (_isOutermost) {
selectedEvent.fire(cl);
}
return cl;
}
void AWPassiveClauseContainer::onLimitsUpdated()
{
if (!ageLimited() || !weightLimited()) {
return;
}
static Stack<Clause*> toRemove(256);
ClauseQueue::Iterator wit(_weightQueue);
while (wit.hasNext()) {
Clause* cl=wit.next();
if (exceedsAllLimits(cl)) {
toRemove.push(cl);
} else if (allChildrenNecessarilyExceedLimits(cl, cl->length())) {
toRemove.push(cl);
}
}
#if OUTPUT_LRS_DETAILS
if (toRemove.isNonEmpty()) {
cout<<toRemove.size()<<" passive deleted, "<< (size()-toRemove.size()) <<" remains\n";
}
#endif
while (toRemove.isNonEmpty()) {
Clause* removed=toRemove.pop();
RSTAT_CTR_INC("clauses discarded from passive on age/weight limit update");
env.statistics->discardedNonRedundantClauses++;
remove(removed);
}
}
void AWPassiveClauseContainer::simulationInit()
{
_simulationBalance = _balance;
_simulationCurrAgeIt = ClauseQueue::Iterator(_ageQueue);
_simulationCurrAgeCl = _simulationCurrAgeIt.hasNext() ? _simulationCurrAgeIt.next() : nullptr;
_simulationCurrWeightIt = ClauseQueue::Iterator(_weightQueue);
_simulationCurrWeightCl = _simulationCurrWeightIt.hasNext() ? _simulationCurrWeightIt.next() : nullptr;
ASS(_simulationCurrAgeCl != nullptr || _simulationCurrWeightCl == nullptr);
ASS(_simulationCurrAgeCl == nullptr || _simulationCurrWeightCl != nullptr);
}
bool AWPassiveClauseContainer::simulationHasNext()
{
ASS(_simulationCurrAgeCl != nullptr || _simulationCurrWeightCl == nullptr);
ASS(_simulationCurrAgeCl == nullptr || _simulationCurrWeightCl != nullptr);
if (_simulationCurrAgeCl == nullptr)
{
return false;
}
while (_simulationCurrAgeCl->hasAux() && _simulationCurrAgeIt.hasNext())
{
_simulationCurrAgeCl = _simulationCurrAgeIt.next();
}
ASS(_simulationCurrAgeCl != nullptr);
while (_simulationCurrWeightCl->hasAux() && _simulationCurrWeightIt.hasNext())
{
_simulationCurrWeightCl = _simulationCurrWeightIt.next();
}
ASS(_simulationCurrWeightCl != nullptr);
ASS(!_simulationCurrAgeCl->hasAux() || _simulationCurrWeightCl->hasAux());
ASS(_simulationCurrAgeCl->hasAux() || !_simulationCurrWeightCl->hasAux());
return !_simulationCurrAgeCl->hasAux();
}
void AWPassiveClauseContainer::simulationPopSelected()
{
if (byWeight(_simulationBalance)) {
_simulationBalance -= _ageRatio;
ASS(!_simulationCurrWeightCl->hasAux());
_simulationCurrWeightCl->setAux();
} else {
_simulationBalance += _weightRatio;
ASS(!_simulationCurrAgeCl->hasAux());
_simulationCurrAgeCl->setAux();
}
}
bool AWPassiveClauseContainer::setLimitsToMax()
{
return setLimits(UINT_MAX, UINT_MAX, UINT_MAX);
}
bool AWPassiveClauseContainer::setLimitsFromSimulation()
{
ASS(_simulationCurrAgeCl != nullptr || _simulationCurrWeightCl == nullptr);
ASS(_simulationCurrAgeCl == nullptr || _simulationCurrWeightCl != nullptr);
if (_simulationCurrAgeCl == nullptr)
{
return setLimitsToMax();
}
else
{
ASS(!_simulationCurrAgeCl->hasAux() || _simulationCurrWeightCl->hasAux());
ASS(_simulationCurrAgeCl->hasAux() || !_simulationCurrWeightCl->hasAux());
}
unsigned maxAgeQueueAge;
unsigned maxAgeQueueWeight;
unsigned maxWeightQueueWeight;
if (_simulationCurrAgeIt.hasNext())
{
maxAgeQueueAge = _simulationCurrAgeCl->age();
maxAgeQueueWeight = _simulationCurrAgeCl->weightForClauseSelection(_opt);
}
else
{
maxAgeQueueAge = UINT_MAX;
maxAgeQueueWeight = UINT_MAX;
}
if (_simulationCurrWeightIt.hasNext())
{
maxWeightQueueWeight = _simulationCurrWeightCl->weightForClauseSelection(_opt);
}
else
{
maxWeightQueueWeight = UINT_MAX;
}
if (_opt.lrsWeightLimitOnly())
{
maxAgeQueueAge = 0;
maxAgeQueueWeight = 0;
}
return setLimits(maxAgeQueueAge, maxAgeQueueWeight,maxWeightQueueWeight);
}
bool AWPassiveClauseContainer::allChildrenNecessarilyExceedLimits(Clause* cl, unsigned upperBoundNumSelLits) const
{
if (cl->age() >= _ageSelectionMaxAge)
{
Inference inf = FromInput(UnitInputType::CONJECTURE); inf.setAge(cl->age() + 1);
int maxSelWeight=0;
for(unsigned i=0;i<upperBoundNumSelLits;i++) {
maxSelWeight=max((int)(*cl)[i]->weight(),maxSelWeight);
}
unsigned weightLowerBound = cl->weight() - maxSelWeight; unsigned numPositiveLiteralsParent = cl->numPositiveLiterals();
unsigned numPositiveLiteralsLowerBound = numPositiveLiteralsParent > 0 ? numPositiveLiteralsParent-1 : numPositiveLiteralsParent; if (exceedsWeightLimit(weightLowerBound, numPositiveLiteralsLowerBound, inf)) {
return true;
}
}
return false;
}
bool AWPassiveClauseContainer::setLimits(unsigned newAgeSelectionMaxAge, unsigned newAgeSelectionMaxWeight, unsigned newWeightSelectionMaxWeight)
{
bool atLeastOneTightened = false;
if(newAgeSelectionMaxAge != _ageSelectionMaxAge || newAgeSelectionMaxWeight != _ageSelectionMaxWeight) {
if(newAgeSelectionMaxAge < _ageSelectionMaxAge) {
atLeastOneTightened = true;
} else if (newAgeSelectionMaxAge == _ageSelectionMaxAge && newAgeSelectionMaxWeight < _ageSelectionMaxWeight) {
atLeastOneTightened = true;
}
_ageSelectionMaxAge=newAgeSelectionMaxAge;
_ageSelectionMaxWeight=newAgeSelectionMaxWeight;
}
if(newWeightSelectionMaxWeight != _weightSelectionMaxWeight) {
if(newWeightSelectionMaxWeight < _weightSelectionMaxWeight) {
atLeastOneTightened = true;
}
_weightSelectionMaxWeight=newWeightSelectionMaxWeight;
}
return atLeastOneTightened;
}
bool AWPassiveClauseContainer::ageLimited() const
{
return _ageSelectionMaxAge != UINT_MAX && _ageSelectionMaxWeight != UINT_MAX;
}
bool AWPassiveClauseContainer::weightLimited() const
{
return _weightSelectionMaxWeight != UINT_MAX;
}
bool AWPassiveClauseContainer::exceedsAgeLimit(unsigned, const Inference& inference, bool&) const
{
const unsigned age = inference.age();
return age > _ageSelectionMaxAge;
}
bool AWPassiveClauseContainer::exceedsWeightLimit(unsigned w, unsigned numPositiveLiterals, const Inference& inference) const
{
if (_weightSelectionMaxWeight == UINT_MAX) return false;
const unsigned numeralWeight = 0; const unsigned splitWeight = 0;
const bool derivedFromGoal = inference.derivedFromGoal();
unsigned weightForClauseSelection = Clause::computeWeightForClauseSelection(w, splitWeight, numeralWeight, derivedFromGoal, _opt);
return weightForClauseSelection > _weightSelectionMaxWeight;
}
bool AWPassiveClauseContainer::exceedsAllLimits(Clause* cl) const
{
unsigned age = cl->age();
if (age < _ageSelectionMaxAge) return false;
unsigned weightForClauseSelection = cl->weightForClauseSelection(_opt);
if (weightForClauseSelection <= _weightSelectionMaxWeight) return false;
if (age > _ageSelectionMaxAge) return true;
ASS_EQ(age,_ageSelectionMaxAge);
return weightForClauseSelection > _ageSelectionMaxWeight;
}
}