#include "Splitter.hpp"
#include "Debug/RuntimeStatistics.hpp"
#include "Lib/DHSet.hpp"
#include "Lib/Environment.hpp"
#include "Lib/IntUnionFind.hpp"
#include "Lib/Metaiterators.hpp"
#include "Debug/TimeProfiling.hpp"
#include "Lib/Timer.hpp"
#include "Kernel/Signature.hpp"
#include "Kernel/Clause.hpp"
#include "Kernel/Inference.hpp"
#include "Kernel/InferenceStore.hpp"
#include "Kernel/RCClauseStack.hpp"
#include "Kernel/TermIterators.hpp"
#include "Kernel/Formula.hpp"
#include "Kernel/FormulaUnit.hpp"
#include "Kernel/MainLoop.hpp"
#include "Shell/AnswerLiteralManager.hpp"
#include "Shell/PartialRedundancyHandler.hpp"
#include "Shell/Options.hpp"
#include "Shell/Statistics.hpp"
#include "Shell/Shuffling.hpp"
#include "SAT/SATInference.hpp"
#include "SAT/MinimizingSolver.hpp"
#include "SAT/FallbackSolverWrapper.hpp"
#include "SAT/CadicalInterfacing.hpp"
#include "SAT/MinisatInterfacing.hpp"
#include "SAT/Z3Interfacing.hpp"
#include "DP/ShortConflictMetaDP.hpp"
#include "DP/SimpleCongruenceClosure.hpp"
#include "SaturationAlgorithm.hpp"
namespace Saturation
{
using namespace std;
using namespace Lib;
using namespace Kernel;
void SATClauseExtra::output(std::ostream &out) const {
out << "sat_clause_recorded";
}
void SplitDefinitionExtra::output(std::ostream &out) const {
out << component->number();
}
void SplittingBranchSelector::init()
{
_literalPolarityAdvice = _parent.getOptions().splittingLiteralPolarityAdvice();
SATSolver *inner;
switch(_parent.getOptions().satSolver()){
case Options::SatSolver::MINISAT:
inner = new MinisatInterfacing;
break;
case Options::SatSolver::CADICAL:
inner = new CadicalInterfacing;
break;
#if VZ3
case Options::SatSolver::Z3:
{
inner = new Z3Interfacing(_parent.getOptions(),_parent.satNaming(), false, _parent.getOptions().exportAvatarProblem(), _parent.getOptions().problemExportSyntax());
if(_parent.getOptions().satFallbackForSMT()){
SATSolver* fallback = new MinisatInterfacing;
inner = new FallbackSolverWrapper(inner, fallback);
}
}
break;
#endif
default:
ASSERTION_VIOLATION_REP(_parent.getOptions().satSolver());
}
if (_parent.getOptions().splittingMinimizeModel()) {
inner = new MinimizingSolver(inner);
}
if(_parent.getOptions().splittingCongruenceClosure()) {
_dp = new ShortConflictMetaDP(
new DP::SimpleCongruenceClosure(&_parent.getOrdering()), _parent.satNaming(), *inner);
}
::new(&_solver) ProofProducingSATSolver(inner);
}
void SplittingBranchSelector::updateVarCnt()
{
unsigned satVarCnt = _parent.maxSatVar();
unsigned splitLvlCnt = _parent.splitLevelCnt();
_selected.expand(splitLvlCnt+1);
_solver.ensureVarCount(satVarCnt);
}
void SplittingBranchSelector::considerPolarityAdvice(SATLiteral lit)
{
switch (_literalPolarityAdvice) {
case Options::SplittingLiteralPolarityAdvice::FALSE:
_solver.suggestPolarity(lit.var(),!lit.positive());
break;
case Options::SplittingLiteralPolarityAdvice::TRUE:
_solver.suggestPolarity(lit.var(), lit.positive());
break;
case Options::SplittingLiteralPolarityAdvice::NONE:
break;
case Options::SplittingLiteralPolarityAdvice::RANDOM:
_solver.suggestPolarity(lit.var(),Random::getBit());
break;
default:
ASSERTION_VIOLATION;
}
}
static Color colorFromPossiblyDeepFOConversion(SATClause* scl,Unit*& u)
{
if (scl->inference()->getType() != SATInference::FO_CONVERSION) {
ASS_EQ(scl->inference()->getType(),SATInference::PROP_INF);
PropInference* inf = static_cast<PropInference*>(scl->inference());
SATClauseList* premises = inf->getPremises();
ASS_EQ(SATClauseList::length(premises),1);
scl = premises->head();
}
SATInference* inf = scl->inference();
ASS_EQ(inf->getType(),SATInference::FO_CONVERSION);
u = static_cast<FOConversionInference*>(inf)->getOrigin();
const Inference& i = u->inference();
Inference::Iterator it = i.iterator();
ASS(i.hasNext(it));
Unit* u1 = i.next(it);
ASS(u1->isClause());
Clause* cl = u1->asClause();
return cl->color();
}
void SplittingBranchSelector::handleSatRefutation()
{
SATClause *proof = nullptr;
SATClauseList *satPremises = nullptr;
#if VZ3
if(_parent.hasSMTSolver) {
satPremises = _solver.minimizedPremises();
for(SATClause *&cl : iterTraits(satPremises->iter())) {
SATInference *inf = cl->inference();
if(inf->getType() == SATInference::InfType::PROP_INF) {
ASS_EQ(SATClauseList::length(inf->propInf()->getPremises()), 1)
cl = inf->propInf()->getPremises()->head();
}
ASS(cl->inference()->getType() == SATInference::InfType::FO_CONVERSION)
}
}
#endif
if(!satPremises) {
proof = _solver.proof();
SATInference::visitFOConversions(proof, [&](SATClause *cl) {
SATClauseList::push(cl, satPremises);
});
}
ASS(satPremises)
UnitList *foPremises = nullptr;
for(auto satPrem : iterTraits(satPremises->iter()))
UnitList::push(satPrem->inference()->foConversion()->getOrigin(), foPremises);
ASS(foPremises)
if (!env.colorUsed) { Clause *foRef = Clause::empty(
#if VZ3
_parent.hasSMTSolver
? NonspecificInferenceMany(InferenceRule::AVATAR_REFUTATION_SMT, foPremises)
:
#endif
Inference(InferenceOfASatClause(InferenceRule::AVATAR_REFUTATION, proof, foPremises))
);
throw MainLoop::RefutationFoundException(foRef);
} else { int colorCnts[3] = {0,0,0};
SATClauseList::Iterator it1(satPremises);
while (it1.hasNext()) {
SATClause* scl = it1.next();
Unit* dummy;
Color c = colorFromPossiblyDeepFOConversion(scl,dummy);
ASS_L(c,COLOR_INVALID);
colorCnts[c]++;
}
Color sndCol = COLOR_RIGHT;
if (colorCnts[COLOR_LEFT] < colorCnts[COLOR_RIGHT]) {
sndCol = COLOR_LEFT;
}
SATClauseStack first;
UnitList* first_prems = UnitList::empty();
SATClauseStack second;
UnitList* second_prems = UnitList::empty();
SATClauseList::Iterator it2(satPremises);
while (it2.hasNext()) {
SATClause* scl = it2.next();
Unit* u;
Color c = colorFromPossiblyDeepFOConversion(scl,u);
if (c == sndCol) {
second.push(scl);
UnitList::push(u,second_prems);
} else {
first.push(scl); UnitList::push(u,first_prems);
}
}
if (colorCnts[sndCol] == 0) { Inference foInf = NonspecificInferenceMany(InferenceRule::AVATAR_REFUTATION, first_prems);
Clause* foRef = Clause::fromIterator(LiteralIterator::getEmpty(), foInf);
throw MainLoop::RefutationFoundException(foRef);
}
SATClauseStack result;
MinisatInterfacing<>::interpolateViaAssumptions(_parent.maxSatVar(),first,second,result);
Formula* interpolant;
{
FormulaList* conjuncts = FormulaList::empty();
unsigned conj_cnt = 0;
SATClauseStack::Iterator it(result);
while(it.hasNext()) {
SATClause* cl = it.next();
FormulaList* disjuncts = FormulaList::empty();
for (unsigned i = 0; i < cl->size(); i++) {
SATLiteral lit = (*cl)[i];
bool negated = false;
SplitLevel lvl = _parent.getNameFromLiteralUnsafe(lit);
if (_parent._db[lvl] == 0) {
negated = true;
lvl = _parent.getNameFromLiteralUnsafe(lit.opposite());
ASS_NEQ(_parent._db[lvl],0);
}
Formula* litFla = Formula::fromClause(_parent._db[lvl]->component);
if (negated) {
litFla = new NegatedFormula(litFla);
}
FormulaList::push(litFla,disjuncts);
}
Formula* clFla;
if (cl->size() == 1) {
clFla = disjuncts->head();
FormulaList::destroy(disjuncts);
} else {
clFla = JunctionFormula::generalJunction(OR, disjuncts);
}
FormulaList::push(clFla,conjuncts);
conj_cnt++;
}
if (conj_cnt == 1) {
interpolant = conjuncts->head();
FormulaList::destroy(conjuncts);
} else {
interpolant = JunctionFormula::generalJunction(AND, conjuncts);
}
}
{
Inference elInf = NonspecificInferenceMany(InferenceRule::SAT_COLOR_ELIMINATION, second_prems);
FormulaUnit* interpolated = new FormulaUnit(interpolant,elInf);
UnitList::push(interpolated,first_prems);
Inference finalInf = NonspecificInferenceMany(InferenceRule::SAT_COLOR_ELIMINATION,first_prems);
Clause* foRef = Clause::fromIterator(LiteralIterator::getEmpty(), finalInf);
throw MainLoop::RefutationFoundException(foRef);
}
}
}
SAT::Status SplittingBranchSelector::processDPConflicts()
{
if(!_dp) {
return Status::SATISFIABLE;
}
SAT2FO& s2f = _parent.satNaming();
static LiteralStack gndAssignment;
static LiteralStack unsatCore;
while (true) { {
TIME_TRACE("congruence closure");
gndAssignment.reset();
s2f.collectAssignment(_solver, gndAssignment);
_dp->reset();
_dp->addLiterals(pvi( LiteralStack::ConstIterator(gndAssignment) ), false);
DecisionProcedure::Status dpStatus = _dp->getStatus(true);
if(dpStatus!=DecisionProcedure::UNSATISFIABLE) {
break;
}
unsigned unsatCoreCnt = _dp->getUnsatCoreCount();
for(unsigned i=0; i<unsatCoreCnt; i++) {
unsatCore.reset();
_dp->getUnsatCore(unsatCore, i);
SATClause* conflCl = s2f.createConflictClause(unsatCore);
_solver.addClause(conflCl);
}
RSTAT_CTR_INC("ssat_dp_conflict");
RSTAT_CTR_INC_MANY("ssat_dp_conflict_clauses",unsatCoreCnt);
}
{
TIME_TRACE(TimeTrace::AVATAR_SAT_SOLVER);
if (_solver.solve() == Status::UNSATISFIABLE) {
return Status::UNSATISFIABLE;
}
}
}
return Status::SATISFIABLE;
}
void SplittingBranchSelector::updateSelection(unsigned satVar, VarAssignment asgn,
SplitLevelStack& addedComps, SplitLevelStack& removedComps)
{
ASS_NEQ(asgn, VarAssignment::NOT_KNOWN);
SplitLevel posLvl = _parent.getNameFromLiteral(SATLiteral(satVar, true));
SplitLevel negLvl = _parent.getNameFromLiteral(SATLiteral(satVar, false));
bool posUsed = _parent.isUsedName(posLvl);
bool negUsed = _parent.isUsedName(negLvl);
switch(asgn) {
case VarAssignment::TRUE:
if(posUsed && !_selected.find(posLvl)) {
_selected.insert(posLvl);
addedComps.push(posLvl);
}
if(negUsed && _selected.find(negLvl)) {
_selected.remove(negLvl);
removedComps.push(negLvl);
}
break;
case VarAssignment::FALSE:
if(negUsed && !_selected.find(negLvl)) {
_selected.insert(negLvl);
addedComps.push(negLvl);
}
if(posUsed && _selected.find(posLvl)) {
_selected.remove(posLvl);
removedComps.push(posLvl);
}
break;
case VarAssignment::DONT_CARE:
{
bool posSticky = posUsed && _parent.isSticky(posLvl);
bool negSticky = negUsed && _parent.isSticky(negLvl);
{ if(posUsed && !posSticky && _selected.find(posLvl) ) {
_selected.remove(posLvl);
removedComps.push(posLvl);
}
if(negUsed && !negSticky && _selected.find(negLvl)) {
_selected.remove(negLvl);
removedComps.push(negLvl);
}
}
if(posSticky && !_selected.find(posLvl) ) {
_selected.insert(posLvl);
addedComps.push(posLvl);
}
if(negSticky && !_selected.find(negLvl) ) {
_selected.insert(negLvl);
addedComps.push(negLvl);
}
break;
}
default:
ASSERTION_VIOLATION;
}
}
void SplittingBranchSelector::addSatClauseToSolver(SATClause* cl)
{
cl = SATClause::removeDuplicateLiterals(cl);
if(!cl) {
RSTAT_CTR_INC("splitter_tautology");
return;
}
RSTAT_CTR_INC("ssat_sat_clauses");
_solver.addClause(cl);
}
void SplittingBranchSelector::recomputeModel(SplitLevelStack& addedComps, SplitLevelStack& removedComps)
{
ASS(addedComps.isEmpty());
ASS(removedComps.isEmpty());
unsigned maxSatVar = _parent.maxSatVar();
SAT::Status stat;
{
TIME_TRACE(TimeTrace::AVATAR_SAT_SOLVER);
stat = _solver.solve();
}
if (stat == Status::SATISFIABLE) {
stat = processDPConflicts();
}
if(stat == Status::UNSATISFIABLE) {
handleSatRefutation(); }
if(stat == Status::UNKNOWN){
env.statistics->smtReturnedUnknown=true;
throw MainLoop::MainLoopFinishedException(TerminationReason::REFUTATION_NOT_FOUND);
}
ASS_EQ(stat,Status::SATISFIABLE);
for(unsigned i=1; i<=maxSatVar; i++) {
VarAssignment asgn = _solver.getAssignment(i);
if (asgn == VarAssignment::NOT_KNOWN) {
env.statistics->smtDidNotEvaluate=true;
throw MainLoop::MainLoopFinishedException(TerminationReason::REFUTATION_NOT_FOUND);
}
updateSelection(i, asgn, addedComps, removedComps);
}
}
std::string Splitter::splPrefix = "";
Splitter::Splitter()
: _deleteDeactivated(Options::SplittingDeleteDeactivated::ON), _branchSelector(*this),
_clausesAdded(false)
{}
Splitter::~Splitter()
{
while(_db.isNonEmpty()) {
if(_db.top()) {
delete _db.top();
}
_db.pop();
}
}
const Options& Splitter::getOptions() const
{
ASS(_sa);
return _sa->getOptions();
}
Ordering& Splitter::getOrdering() const
{
ASS(_sa);
return _sa->getOrdering();
}
void Splitter::init(SaturationAlgorithm* sa)
{
_sa = sa;
const Options& opts = getOptions();
_branchSelector.init();
_showSplitting = opts.showSplitting();
_complBehavior = opts.splittingAddComplementary();
_nonsplComps = opts.splittingNonsplittableComponents();
_congruenceClosure = opts.splittingCongruenceClosure();
_shuffleComponents = opts.randomTraversals();
#if VZ3
hasSMTSolver = (opts.satSolver() == Options::SatSolver::Z3);
#endif
if (opts.splittingAvatimer() < 1.0) {
unsigned timeLimit = opts.simulatedTimeLimitInMilliseconds();
if (timeLimit == 0) {
timeLimit = opts.timeLimitInMilliseconds();
}
_stopSplittingAtTime = opts.splittingAvatimer() * timeLimit;
#if VAMPIRE_PERF_EXISTS
unsigned instrLimit = opts.simulatedInstructionLimit();
if (instrLimit == 0) {
instrLimit = opts.instructionLimit();
}
_stopSplittingAtInst = opts.splittingAvatimer() * instrLimit;
#endif
} else {
_stopSplittingAtTime = 0;
#if VAMPIRE_PERF_EXISTS
_stopSplittingAtInst = 0;
#endif
}
_deleteDeactivated = opts.splittingDeleteDeactivated();
_cleaveNonsplittables = opts.cleaveNonsplittables();
_componentIdx = new HashingClauseVariantIndex();
}
SplitLevel Splitter::getNameFromLiteral(SATLiteral lit) const
{
SplitLevel res = getNameFromLiteralUnsafe(lit);
ASS_L(res, _db.size());
return res;
}
SplitLevel Splitter::getNameFromLiteralUnsafe(SATLiteral lit) const
{
return (lit.var()-1)*2 + (lit.positive() ? 0 : 1);
}
SATLiteral Splitter::getLiteralFromName(SplitLevel compName)
{
unsigned var = compName/2 + 1;
bool polarity = (compName&1)==0;
return SATLiteral(var, polarity);
}
std::string Splitter::getFormulaStringFromName(SplitLevel compName, bool negated)
{
if (splPrefix.empty()) {
if(env.options->proof()==Options::Proof::TPTP){
unsigned spl = env.signature->addFreshFunction(0,"spl");
splPrefix = env.signature->functionName(spl)+"_";
}
}
SATLiteral lit = getLiteralFromName(compName);
if (negated) {
lit = lit.opposite();
}
return getFormulaStringFromLiteral(lit);
}
std::string Splitter::getFormulaStringFromLiteral(SATLiteral lit) {
if (lit.positive()) {
return splPrefix+Lib::Int::toString(lit.var());
} else {
return "~"+splPrefix+Lib::Int::toString(lit.var());
}
}
Unit* Splitter::getDefinitionFromName(SplitLevel compName) const
{
return _defs.get(compName & ~1);
}
void Splitter::collectDependenceLits(SplitSet* splits, SATLiteralStack& acc) const
{
auto sit = splits->iter();
while(sit.hasNext()) {
SplitLevel nm = sit.next();
acc.push(getLiteralFromName(nm).opposite());
}
}
Clause* Splitter::getComponentClause(SplitLevel name) const
{
ASS_L(name,_db.size());
ASS_NEQ(_db[name],0);
return _db[name]->component;
}
Clause* Splitter::reintroduceAvatarAssertions(Clause* cl) {
ASS(env.options->questionAnswering() == Options::QuestionAnsweringMode::SYNTHESIS);
RStack<Literal*> resLits;
resLits->loadFromIterator(cl->iterLits());
for (SplitLevel nm : iterTraits(cl->splits()->iter())) {
Clause* compCl = getComponentClause(nm);
ASS(compCl->length() == 1);
resLits->push(Literal::complementaryLiteral((*compCl)[0]));
}
return Clause::fromStack(*resLits, Inference(SimplifyingInference1(InferenceRule::AVATAR_ASSERTION_REINTRODUCTION, cl)));
}
void Splitter::onAllProcessed()
{
if(!_clausesAdded) {
return;
}
_clausesAdded = false;
static SplitLevelStack toAdd;
static SplitLevelStack toRemove;
toAdd.reset();
toRemove.reset();
_branchSelector.recomputeModel(toAdd, toRemove);
if (_showSplitting) { std::cout << "[AVATAR] recomputeModel: + ";
for (unsigned i = 0; i < toAdd.size(); i++) {
std::cout << getLiteralFromName(toAdd[i]) << ",";
}
std::cout << "\t - ";
for (unsigned i = 0; i < toRemove.size(); i++) {
std::cout << getLiteralFromName(toRemove[i]) << ",";
}
std::cout << std::endl;
}
{
TIME_TRACE("splitting model update");
if(toRemove.isNonEmpty()) {
removeComponents(toRemove);
}
if(toAdd.isNonEmpty()) {
addComponents(toAdd);
}
}
}
bool Splitter::shouldAddClauseForNonSplittable(Clause* cl, unsigned& compName, Clause*& compCl)
{
if((_congruenceClosure
#if VZ3
|| hasSMTSolver
#endif
)
&& cl->length()==1 && (*cl)[0]->ground() ) {
compName = tryGetComponentNameOrAddNew(cl->length(), cl->literals(), cl, compCl);
RSTAT_CTR_INC("ssat_ground_clauses_for_congruence");
return true;
}
if(_nonsplComps==Options::SplittingNonsplittableComponents::NONE) {
return false;
}
if(!tryGetExistingComponentName(cl->length(), cl->literals(), compName, compCl)) {
bool canCreate;
switch(_nonsplComps) {
case Options::SplittingNonsplittableComponents::ALL:
canCreate = true;
break;
case Options::SplittingNonsplittableComponents::ALL_DEPENDENT:
canCreate = !cl->splits()->isEmpty();
break;
case Options::SplittingNonsplittableComponents::KNOWN:
canCreate = false;
break;
default:
ASSERTION_VIOLATION;
}
if(!canCreate) {
return false;
}
RSTAT_CTR_INC("ssat_non_splittable_introduced_components");
compName = tryGetComponentNameOrAddNew(cl->length(), cl->literals(), cl, compCl);
}
ASS_NEQ(cl,compCl);
return true;
}
void Splitter::conjectureSingleton(Literal* theLit, Clause* orig)
{
unsigned db_before = _db.size();
Clause *compCl;
SplitLevel compName = tryGetComponentNameOrAddNew(1, &theLit, orig, compCl);
SATLiteral nameLit = getLiteralFromName(compName);
_branchSelector.trySetTrue(nameLit);
_db[compName]->sticky = true;
if(db_before < _db.size()) {
if (_showSplitting)
std::cout << "[AVATAR] conjectures: "<< compCl->toString() << std::endl;
_clausesAdded = true;
}
}
bool Splitter::handleNonSplittable(Clause* cl)
{
if (_cleaveNonsplittables && cl->length() > 1) {
auto it = cl->iterLits();
while (it.hasNext()) {
conjectureSingleton(it.next(),cl);
}
}
SplitLevel compName;
Clause* compCl;
if(!shouldAddClauseForNonSplittable(cl, compName, compCl)) {
return false;
}
SplitRecord& nameRec = *_db[compName];
ASS_EQ(nameRec.component,compCl);
ASS_REP2(compCl->store()==Clause::NONE || compCl->store()==Clause::ACTIVE ||
compCl->store()==Clause::PASSIVE || compCl->store()==Clause::UNPROCESSED, *compCl, compCl->store());
if(nameRec.active && compCl->store()==Clause::NONE) {
compCl->invalidateMyReductionRecords();
_sa->addNewClause(compCl);
}
SplitSet* sset = cl->splits();
ASS(sset->size()!=1 || _db[sset->sval()]->component!=cl);
if(sset->member(compName)) {
RSTAT_CTR_INC("ssat_self_dependent_component");
} else {
static SATLiteralStack satLits;
satLits.reset();
collectDependenceLits(cl->splits(), satLits);
satLits.push(getLiteralFromName(compName));
SATClause* nsClause = SATClause::fromStack(satLits);
nsClause->sort();
if(_already_added.contains(nsClause)) {
delete nsClause;
return true;
}
_already_added.insert(nsClause);
UnitList* ps = 0;
FormulaList* resLst=0;
UnitList::push(getDefinitionFromName(compName),ps);
FormulaList::push(new NamedFormula(getFormulaStringFromName(compName)),resLst);
auto sit = cl->splits()->iter();
while(sit.hasNext()) {
SplitLevel nm = sit.next();
UnitList::push(getDefinitionFromName(nm),ps);
FormulaList::push(new NamedFormula(getFormulaStringFromName(nm,true )),resLst);
}
UnitList::push(cl,ps);
Formula* f = JunctionFormula::generalJunction(OR,resLst);
FormulaUnit* scl = new FormulaUnit(f,NonspecificInferenceMany(InferenceRule::AVATAR_SPLIT_CLAUSE,ps));
if(env.options->proofExtra() == Options::ProofExtra::FULL)
env.proofExtra.insert(scl, new SATClauseExtra(nsClause));
nsClause->setInference(new FOConversionInference(scl));
if (_showSplitting) {
std::cout << "[AVATAR] registering a non-splittable: "<< cl->toString() << std::endl;
}
addSatClauseToSolver(nsClause);
RSTAT_CTR_INC("ssat_non_splittable_sat_clauses");
}
return true;
}
std::string Splitter::splitsToString(SplitSet* splits)
{
std::ostringstream res;
auto it = splits->iter();
while(it.hasNext()) {
res << getLiteralFromName(it.next());
if(it.hasNext()) {
res<<", ";
}
}
return res.str();
}
bool Splitter::getComponents(Clause* cl, Stack<LiteralStack>& acc, bool shuffle)
{
ASS_EQ(acc.size(), 0);
unsigned clen=cl->length();
ASS_G(clen,0);
if(clen<=1) {
return false;
}
static DHMap<unsigned, unsigned, IdentityHash, DefaultHash> varMasters;
varMasters.reset();
IntUnionFind components(clen);
for(unsigned i=0;i<clen;i++) {
Literal* lit=(*cl)[i];
VariableIterator vit(lit);
while(vit.hasNext()) {
unsigned master=varMasters.findOrInsert(vit.next().var(), i);
if(master!=i) {
components.doUnion(master, i);
}
}
}
components.evalComponents();
unsigned compCnt=components.getComponentCount();
if(compCnt==1) {
return false;
}
env.statistics->splitClauses++;
env.statistics->splitComponents+=compCnt;
IntUnionFind::ComponentIterator cit(components);
ASS(cit.hasNext());
while(cit.hasNext()) {
IntUnionFind::ElementIterator elit=cit.next();
acc.push(LiteralStack());
while(elit.hasNext()) {
int litIndex=elit.next();
Literal* lit = (*cl)[litIndex];
acc.top().push(lit);
}
}
ASS_EQ(acc.size(),compCnt);
if (shuffle) {
Shuffling::shuffleArray(acc.begin(),compCnt);
}
return true;
}
bool Splitter::doSplitting(Clause* cl)
{
static bool hasStopped = false;
if (hasStopped) {
return false;
}
static bool synthesis = (env.options->questionAnswering() == Options::QuestionAnsweringMode::SYNTHESIS);
if (synthesis && (cl->hasAnswerLiteral() || !static_cast<Shell::SynthesisALManager*>(Shell::SynthesisALManager::getInstance())->isComputable(cl))) {
return false;
}
if ((_stopSplittingAtTime && (unsigned)Timer::elapsedMilliseconds() >= _stopSplittingAtTime)
#if VAMPIRE_PERF_EXISTS
|| (_stopSplittingAtInst && Timer::elapsedMegaInstructions() >= _stopSplittingAtInst)
#endif
) {
if (_showSplitting) {
std::cout << "[AVATAR] Stopping the splitting process."<< std::endl;
}
hasStopped = true;
return false;
}
if(cl->isComponent()) {
return false;
}
static Stack<LiteralStack> comps;
comps.reset();
if(!getComponents(cl, comps, _shuffleComponents)) {
return handleNonSplittable(cl);
}
static SATLiteralStack satClauseLits;
satClauseLits.reset();
collectDependenceLits(cl->splits(), satClauseLits);
UnitList* ps = 0;
FormulaList* resLst=0;
unsigned compCnt = comps.size();
for(unsigned i=0; i<compCnt; ++i) {
const LiteralStack& comp = comps[i];
if (_cleaveNonsplittables && comp.size() > 1) {
auto it = comp.iter();
while (it.hasNext()) {
conjectureSingleton(it.next(),cl);
}
}
Clause* compCl;
SplitLevel compName = tryGetComponentNameOrAddNew(comp, cl, compCl);
SATLiteral nameLit = getLiteralFromName(compName);
satClauseLits.push(nameLit);
UnitList::push(getDefinitionFromName(compName),ps);
FormulaList::push(new NamedFormula(getFormulaStringFromName(compName)),resLst);
}
SATClause* splitClause = SATClause::fromStack(satClauseLits);
if (_showSplitting) {
std::cout << "[AVATAR] split a clause: "<< cl->toString() << std::endl;
}
auto sit = cl->splits()->iter();
while(sit.hasNext()) {
SplitLevel nm = sit.next();
UnitList::push(getDefinitionFromName(nm),ps);
FormulaList::push(new NamedFormula(getFormulaStringFromName(nm,true )),resLst);
}
UnitList::push(cl,ps);
Formula* f = JunctionFormula::generalJunction(OR,resLst);
FormulaUnit* scl = new FormulaUnit(f,NonspecificInferenceMany(InferenceRule::AVATAR_SPLIT_CLAUSE,ps));
if(env.options->proofExtra() == Options::ProofExtra::FULL)
env.proofExtra.insert(scl, new SATClauseExtra(splitClause));
splitClause->setInference(new FOConversionInference(scl));
addSatClauseToSolver(splitClause);
return true;
}
bool Splitter::tryGetExistingComponentName(unsigned size, Literal* const * lits, SplitLevel& comp, Clause*& compCl)
{
ClauseIterator existingComponents;
{
TIME_TRACE("splitting component index usage");
existingComponents = _componentIdx->retrieveVariants(lits, size);
}
if(!existingComponents.hasNext()) {
return false;
}
compCl = existingComponents.next();
ASS(!existingComponents.hasNext());
comp = compCl->splits()->sval();
return true;
}
Clause* Splitter::buildAndInsertComponentClause(SplitLevel name, unsigned size, Literal* const * lits, Clause* orig)
{
ASS_EQ(_db[name],0);
ASS(orig)
SplitLevel posName = (name&~1);
Unit* def_u;
UnitInputType inpType = orig->inputType();
if (!_defs.find(posName, def_u)) {
Literal* oplit;
Literal*const* possibly_flipped_lits = lits;
if (size == 1 && lits[0]->ground() && lits[0]->isNegative()) {
oplit = Literal::complementaryLiteral(lits[0]);
possibly_flipped_lits = &oplit;
}
std::string formula_name = getFormulaStringFromName(posName);
Clause* temp = Clause::fromIterator(arrayIter(possibly_flipped_lits, size),
NonspecificInference0(inpType,InferenceRule::AVATAR_DEFINITION));
Formula* def_f = new BinaryFormula(IFF,
new NamedFormula(formula_name),
Formula::fromClause(temp));
Inference def_u_i = NonspecificInference0(inpType,InferenceRule::AVATAR_DEFINITION);
def_u_i.setInductionDepth(orig->inference().inductionDepth());
def_u = new FormulaUnit(def_f,def_u_i);
InferenceStore::instance()->recordIntroducedSplitName(def_u,formula_name);
ALWAYS(_defs.insert(posName,def_u));
}
Clause* compCl = Clause::fromIterator(arrayIter(lits, size),
NonspecificInference1(InferenceRule::AVATAR_COMPONENT,def_u));
if(posName == name && env.options->proofExtra() == Options::ProofExtra::FULL)
env.proofExtra.insert(def_u, new SplitDefinitionExtra(compCl));
compCl->setAge(orig->age());
compCl->inference().th_ancestors = orig->inference().th_ancestors;
compCl->inference().all_ancestors = orig->inference().all_ancestors;
compCl->inference().setSineLevel(orig->inference().getSineLevel());
_db[name] = new SplitRecord(compCl);
compCl->setSplits(SplitSet::getSingleton(name));
compCl->setComponent(true);
if (_deleteDeactivated != Options::SplittingDeleteDeactivated::ON) {
_db[name]->children.push(compCl);
}
{
TIME_TRACE("splitting component index maintenance");
_componentIdx->insert(compCl);
}
return compCl;
}
SplitLevel Splitter::addNonGroundComponent(unsigned size, Literal* const * lits, Clause* orig, Clause*& compCl)
{
ASS_REP(_db.size()%2==0, _db.size());
ASS_G(size,0);
ASS(forAll(arrayIter(lits, size),
[] (Literal* l) { return !l->ground(); } ));
SATLiteral posLit(_sat2fo.createSpareSatVar(), true);
SplitLevel compName = getNameFromLiteralUnsafe(posLit);
ASS_EQ(compName&1,0); ASS_GE(compName,_db.size());
_db.push(0);
_db.push(0);
ASS_L(compName,_db.size());
_branchSelector.updateVarCnt();
_branchSelector.considerPolarityAdvice(posLit);
compCl = buildAndInsertComponentClause(compName, size, lits, orig);
return compName;
}
SplitLevel Splitter::addGroundComponent(Literal* lit, Clause* orig, Clause*& compCl)
{
ASS_REP(_db.size()%2==0, _db.size());
ASS(lit->ground());
SATLiteral satLit = _sat2fo.toSAT(lit);
SplitLevel compName = getNameFromLiteralUnsafe(satLit);
if(compName>=_db.size()) {
_db.push(0);
_db.push(0);
}
else {
ASS_EQ(_complBehavior,Options::SplittingAddComplementary::NONE);
}
ASS_L(compName,_db.size());
if(_complBehavior!=Options::SplittingAddComplementary::NONE) {
unsigned oppName = compName^1;
ASS_L(oppName,_db.size());
Literal* opposite = Literal::complementaryLiteral(lit);
buildAndInsertComponentClause(oppName, 1, &opposite, orig);
}
compCl = buildAndInsertComponentClause(compName, 1, &lit, orig);
_branchSelector.updateVarCnt();
_branchSelector.considerPolarityAdvice(satLit);
return compName;
}
SplitLevel Splitter::tryGetComponentNameOrAddNew(const LiteralStack& comp, Clause* orig, Clause*& compCl)
{
return tryGetComponentNameOrAddNew(comp.size(), comp.begin(), orig, compCl);
}
SplitLevel Splitter::tryGetComponentNameOrAddNew(unsigned size, Literal* const * lits, Clause* orig, Clause*& compCl)
{
SplitLevel res;
if(tryGetExistingComponentName(size, lits, res, compCl)) {
RSTAT_CTR_INC("ssat_reused_components");
}
else {
RSTAT_CTR_INC("ssat_new_components");
_clausesAdded = true;
if(size==1 && lits[0]->ground()) {
res = addGroundComponent(lits[0], orig, compCl);
}
else {
res = addNonGroundComponent(size, lits, orig, compCl);
}
}
return res;
}
static const int NOT_WORTH_REINTRODUCING = 0;
void Splitter::assignClauseSplitSet(Clause* cl, SplitSet* splits)
{
ASS(!cl->splits());
cl->setSplits(splits);
auto bsit = splits->iter();
bool should_reintroduce = false;
unsigned cl_weight = cl->weight();
while(bsit.hasNext()) {
SplitLevel slev=bsit.next();
_db[slev]->children.push(cl);
if (cl_weight <= _db[slev]->component->weight()) {
should_reintroduce = true;
}
}
if (_deleteDeactivated != Options::SplittingDeleteDeactivated::ON) {
cl->setNumActiveSplits(
(_deleteDeactivated == Options::SplittingDeleteDeactivated::OFF || should_reintroduce) ?
splits->size() : NOT_WORTH_REINTRODUCING);
}
}
void Splitter::onClauseReduction(Clause* cl, ClauseIterator premises, Clause* replacement)
{
ASS(cl);
if(!premises.hasNext()) {
ASS(!replacement || cl->splits()==replacement->splits() ||
((env.options->questionAnswering() == Options::QuestionAnsweringMode::SYNTHESIS) && cl->hasAnswerLiteral() && (replacement->inference().rule() == InferenceRule::AVATAR_ASSERTION_REINTRODUCTION || replacement->inference().rule() == InferenceRule::ANSWER_LITERAL_REMOVAL)));
return;
}
SplitSet* unionAll;
if(replacement) {
unionAll = replacement->splits();
ASS(forAll(std::move(premises),
[replacement] (Clause* premise) {
return premise->splits()->isSubsetOf(replacement->splits());
} ));
} else {
Clause* premise0 = premises.next();
unionAll=premise0->splits();
while(premises.hasNext()) {
Clause* premise=premises.next();
ASS(premise);
unionAll=unionAll->getUnion(premise->splits());
}
}
SplitSet* diff=unionAll->subtract(cl->splits());
ASS(allSplitLevelsActive(diff));
if(diff->isEmpty()) {
if (_deleteDeactivated != Options::SplittingDeleteDeactivated::ON) {
if (!cl->isComponent()) {
cl->setNumActiveSplits(NOT_WORTH_REINTRODUCING);
}
}
return;
}
RSTAT_CTR_INC("total_frozen");
cl->invalidateMyReductionRecords();
auto dit = diff->iter();
while(dit.hasNext()) {
SplitLevel slev=dit.next();
_db[slev]->addReduced(cl);
}
}
void Splitter::addPartialRedundancyEntry(SplitSet* splits, PartialRedundancyEntry* e)
{
auto sit = splits->iter();
while (sit.hasNext()) {
SplitLevel slev=sit.next();
e->obtain();
_db[slev]->partialRedundancyEntries.push(e);
}
}
bool Splitter::allSplitLevelsActive(SplitSet* s)
{
auto sit = s->iter();
while(sit.hasNext()) {
SplitLevel lev=sit.next();
ASS_REP(lev<_db.size(), lev);
ASS_REP(_db[lev]!=0, lev);
if (!_db[lev]->active) {
return false;
}
}
return true;
}
void Splitter::onNewClause(Clause* cl)
{
PartialRedundancyHandler::destroyClauseData(cl);
if (cl->inference().rule() == InferenceRule::AVATAR_ASSERTION_REINTRODUCTION) {
assignClauseSplitSet(cl, SplitSet::getEmpty());
} else {
if(!cl->splits()) {
SplitSet* splits=getNewClauseSplitSet(cl);
assignClauseSplitSet(cl, splits);
}
if (env.colorUsed) {
SplitSet* splits = cl->splits();
Color color = cl->color();
auto it = splits->iter();
while(it.hasNext()) {
SplitLevel lv=it.next();
SplitRecord* sr=_db[lv];
color = static_cast<Color>(color | sr->component->color());
}
cl->updateColor(color);
}
}
ASS(allSplitLevelsActive(cl->splits()));
}
SplitSet* Splitter::getNewClauseSplitSet(Clause* cl)
{
SplitSet* res;
Inference& inf= cl->inference();
Inference::Iterator it=inf.iterator();
res=SplitSet::getEmpty();
while(inf.hasNext(it)) {
Unit* premu=inf.next(it);
if(!premu->isClause()) {
continue;
}
Clause* prem=static_cast<Clause*>(premu);
if(!prem->splits()) {
continue;
}
res=res->getUnion(prem->splits());
}
return res;
}
Splitter::SplitRecord::~SplitRecord()
{
component->decRefCnt();
while(reduced.isNonEmpty()) {
Clause* cl = reduced.pop().clause;
cl->decRefCnt();
}
}
void Splitter::SplitRecord::addReduced(Clause* cl)
{
cl->incRefCnt(); reduced.push(ReductionRecord(cl));
}
void Splitter::addSatClauseToSolver(SATClause* cl) {
_clausesAdded = true;
_branchSelector.addSatClauseToSolver(cl);
}
bool Splitter::handleEmptyClause(Clause* cl)
{
if(cl->splits()->isEmpty()) {
return false;
}
static SATLiteralStack conflictLits;
conflictLits.reset();
collectDependenceLits(cl->splits(), conflictLits);
SATClause* confl = SATClause::fromStack(conflictLits);
FormulaList* resLst=0;
auto sit = cl->splits()->iter();
while(sit.hasNext()) {
SplitLevel nm = sit.next();
FormulaList::push(new NamedFormula(getFormulaStringFromName(nm,true )),resLst);
}
Formula* f = JunctionFormula::generalJunction(OR,resLst);
FormulaUnit* scl = new FormulaUnit(f,NonspecificInference1(InferenceRule::AVATAR_CONTRADICTION_CLAUSE,cl));
if(env.options->proofExtra() == Options::ProofExtra::FULL)
env.proofExtra.insert(scl, new SATClauseExtra(confl));
confl->setInference(new FOConversionInference(scl));
addSatClauseToSolver(confl);
if (_showSplitting) {
std::cout << "[AVATAR] proved ";
auto sit = cl->splits()->iter();
while(sit.hasNext()){
std::cout << (_db[sit.next()]->component)->toString();
if(sit.hasNext()){ std::cout << " | "; }
}
std::cout << endl;
}
env.statistics->satSplitRefutations++;
return true;
}
void Splitter::addComponents(const SplitLevelStack& toAdd)
{
SplitLevelStack::ConstIterator slit(toAdd);
while(slit.hasNext()) {
SplitLevel sl = slit.next();
SplitRecord* sr = _db[sl];
ASS(sr);
ASS(!sr->active);
sr->active = true;
if (_deleteDeactivated == Options::SplittingDeleteDeactivated::ON) {
ASS(sr->children.isEmpty());
sr->children.push(sr->component);
_sa->addNewClause(sr->component);
} else {
RCClauseStack::Iterator chit(sr->children);
while (chit.hasNext()) {
Clause* cl = chit.next();
cl->incNumActiveSplits();
if (cl->getNumActiveSplits() == (int)cl->splits()->size()) {
_sa->addNewClause(cl);
ASS(allSplitLevelsActive(cl->splits()));
}
}
}
}
}
void Splitter::removeComponents(const SplitLevelStack& toRemove)
{
ASS(_sa->clausesFlushed());
SplitSet* backtracked = SplitSet::getFromArray(toRemove.begin(), toRemove.size());
auto blit = backtracked->iter();
while(blit.hasNext()) {
SplitLevel bl=blit.next();
SplitRecord* sr=_db[bl];
ASS(sr);
RCClauseStack::DelIterator chit(sr->children);
while (chit.hasNext()) {
Clause* ccl=chit.next();
ASS(ccl->splits()->member(bl));
if(ccl->store()!=Clause::NONE) {
_sa->removeActiveOrPassiveClause(ccl);
ASS_EQ(ccl->store(), Clause::NONE);
} else {
}
ccl->invalidateMyReductionRecords();
ccl->decNumActiveSplits();
if (ccl->getNumActiveSplits() < NOT_WORTH_REINTRODUCING) {
RSTAT_CTR_INC("unworthy child removed");
chit.del();
}
}
if (_deleteDeactivated == Options::SplittingDeleteDeactivated::ON) {
sr->children.reset();
}
while (sr->partialRedundancyEntries.isNonEmpty()) {
auto pre = sr->partialRedundancyEntries.pop();
pre->deactivate();
pre->release();
}
}
auto blit2 = backtracked->iter();
while(blit2.hasNext()) {
SplitLevel bl=blit2.next();
SplitRecord* sr=_db[bl];
while(sr->reduced.isNonEmpty()) {
ReductionRecord rrec=sr->reduced.pop();
Clause* rcl=rrec.clause;
if(rcl->validReductionRecord(rrec.timestamp)) {
ASS(!rcl->splits()->hasIntersection(backtracked));
ASS_EQ(rcl->store(), Clause::NONE);
rcl->invalidateMyReductionRecords(); _sa->addNewClause(rcl);
RSTAT_CTR_INC("total_unfrozen");
#if VDEBUG
ASS(allSplitLevelsActive(rcl->splits()));
#endif
}
rcl->decRefCnt(); }
ASS(sr->active);
sr->active = false;
}
}
UnitList* Splitter::preprendCurrentlyAssumedComponentClauses(UnitList* clauses)
{
DHSet<Clause*> seen;
UnitList::FIFO res;
ArraySet::Iterator ait(_branchSelector._selected);
while(ait.hasNext()) {
unsigned level = ait.next();
Clause* cl = getComponentClause(level);
seen.insert(cl);
res.pushBack(cl);
}
UnitList::DestructiveIterator uit(clauses);
while (uit.hasNext()) {
Unit* u = uit.next();
Clause* cl = u->asClause();
if (seen.insert(cl)) {
res.pushBack(cl);
} else {
}
}
return res.list();
}
}