/** @brief Returns if we already know that var = lit Also checks if var = ~lit, in which it sets solver.ok = false */ bool VarReplacer::alreadyIn(const Var var, const Lit lit) { Lit lit2 = table[var]; if (lit2.var() == lit.var()) { if (lit2.sign() != lit.sign()) { #ifdef VERBOSE_DEBUG cout << "Inverted cycle in var-replacement -> UNSAT" << endl; #endif solver.ok = false; } return true; } lit2 = table[lit.var()]; if (lit2.var() == var) { if (lit2.sign() != lit.sign()) { #ifdef VERBOSE_DEBUG cout << "Inverted cycle in var-replacement -> UNSAT" << endl; #endif solver.ok = false; } return true; } return false; }
void SolutionExtender::replaceBackwardSet(const Lit toSet) { //set backward equiv map<uint32_t, vector<uint32_t> >::const_iterator revTable = solver->varReplacer->getReverseTable().find(toSet.var()); if (revTable != solver->varReplacer->getReverseTable().end()) { const vector<uint32_t>& toGoThrough = revTable->second; for (size_t i = 0; i < toGoThrough.size(); i++) { //Get sign of replacement const Lit lit = Lit(toGoThrough[i], false); Lit tmp = solver->varReplacer->get_lit_replaced_with(lit); //Set var enqueue(lit ^ tmp.sign() ^ toSet.sign()); } } }
void SolutionExtender::addClause(const vector<Lit>& lits, const Lit blockedOn) { const uint32_t blocked_on_inter = solver->map_outer_to_inter(blockedOn.var()); assert(solver->varData[blocked_on_inter].removed == Removed::elimed); assert(contains_lit(lits, blockedOn)); if (satisfied(lits)) return; #ifdef VERBOSE_DEBUG_SOLUTIONEXTENDER for(Lit lit: lits) { Lit lit_inter = solver->map_outer_to_inter(lit); cout << lit << ": " << solver->model_value(lit) << "(elim: " << removed_type_to_string(solver->varData[lit_inter.var()].removed) << ")" << ", "; } cout << "blocked on: " << blockedOn << endl; #endif if (solver->model_value(blockedOn) != l_Undef) { cout << "ERROR: Model value for var " << blockedOn.unsign() << " is " << solver->model_value(blockedOn) << " but that doesn't satisfy a v-elim clause on the stack!" << endl; } assert(solver->model_value(blockedOn) == l_Undef); solver->model[blockedOn.var()] = blockedOn.sign() ? l_False : l_True; if (solver->conf.verbosity >= 10) { cout << "Extending VELIM cls. -- setting model for var " << blockedOn.unsign() << " to " << solver->model[blockedOn.var()] << endl; } assert(satisfied(lits)); solver->varReplacer->extend_model(blockedOn.var()); }
void SolutionExtender::addClause(const vector<Lit>& lits, const Lit blockedOn) { const Var blocked_on_inter = solver->map_outer_to_inter(blockedOn.var()); assert(solver->varData[blocked_on_inter].removed == Removed::elimed); assert(contains_lit(lits, blockedOn)); if (satisfied(lits)) return; #ifdef VERBOSE_DEBUG_SOLUTIONEXTENDER for(Lit lit: lits) { Lit lit_inter = solver->map_outer_to_inter(lit); cout << lit << ": " << solver->model_value(lit) << "(elim: " << removed_type_to_string(solver->varData[lit_inter.var()].removed) << ")" << ", "; } cout << "blocked on: " << blockedOn << endl; #endif assert(solver->model_value(blockedOn) == l_Undef); solver->model[blockedOn.var()] = blockedOn.sign() ? l_False : l_True; assert(satisfied(lits)); solver->varReplacer->extend_model(blockedOn.var()); }
void CalcDefPolars::tallyVotesBinTri(const vector<vec<Watched> >& watches) { size_t wsLit = 0; for (vector<vec<Watched> >::const_iterator it = watches.begin(), end = watches.end() ; it != end ; it++, wsLit++ ) { Lit lit = Lit::toLit(wsLit); const vec<Watched>& ws = *it; for (vec<Watched>::const_iterator it2 = ws.begin(), end2 = ws.end(); it2 != end2; it2++) { //Only count bins once if (it2->isBinary() && lit < it2->lit2() && !it2->learnt() ) { if (lit.sign()) votes[lit.var()] += 0.5; else votes[lit.var()] -= 0.5; Lit lit2 = it2->lit2(); if (lit2.sign()) votes[lit2.var()] += 0.5; else votes[lit2.var()] -= 0.5; } //Only count TRI-s once if (it2->isTri() && lit < it2->lit2() && it2->lit2() < it2->lit3() && it2->learnt() ) { if (lit.sign()) votes[lit.var()] += 0.3; else votes[lit.var()] -= 0.3; Lit lit2 = it2->lit2(); if (lit2.sign()) votes[lit2.var()] += 0.3; else votes[lit2.var()] -= 0.3; Lit lit3 = it2->lit3(); if (lit3.sign()) votes[lit3.var()] += 0.3; else votes[lit3.var()] -= 0.3; } } } }
void CalcDefPolars::add_vote(const Lit lit, const double value) { if (lit.sign()) { votes[lit.var()] -= value; } else { votes[lit.var()] += value; } }
bool VarReplacer::handleAlreadyReplaced(const Lit lit1, const Lit lit2) { //OOps, already inside, but with inverse polarity, UNSAT if (lit1.sign() != lit2.sign()) { (*solver->drup) << ~lit1 << lit2 << fin << lit1 << ~lit2 << fin << lit1 << fin << ~lit1 << fin; solver->ok = false; return false; } //Already inside in the correct way, return return true; }
void SolutionExtender::enqueue(const Lit lit) { assigns[lit.var()] = boolToLBool(!lit.sign()); trail.push_back(lit); #ifdef VERBOSE_DEBUG_RECONSTRUCT cout << "c Enqueueing lit " << lit << " during solution reconstruction" << endl; #endif solver->varData[lit.var()].level = std::numeric_limits< uint32_t >::max(); }
const bool DataSync::shareUnitData() { uint32_t thisGotUnitData = 0; uint32_t thisSentUnitData = 0; SharedData& shared = *sharedData; shared.value.growTo(solver.nVars(), l_Undef); for (uint32_t var = 0; var < solver.nVars(); var++) { Lit thisLit = Lit(var, false); thisLit = solver.varReplacer->getReplaceTable()[thisLit.var()] ^ thisLit.sign(); const lbool thisVal = solver.value(thisLit); const lbool otherVal = shared.value[var]; if (thisVal == l_Undef && otherVal == l_Undef) continue; if (thisVal != l_Undef && otherVal != l_Undef) { if (thisVal != otherVal) { solver.ok = false; return false; } else { continue; } } if (otherVal != l_Undef) { assert(thisVal == l_Undef); Lit litToEnqueue = thisLit ^ (otherVal == l_False); if (solver.subsumer->getVarElimed()[litToEnqueue.var()] || solver.xorSubsumer->getVarElimed()[litToEnqueue.var()] ) continue; solver.uncheckedEnqueue(litToEnqueue); solver.ok = solver.propagate<false>().isNULL(); if (!solver.ok) return false; thisGotUnitData++; continue; } if (thisVal != l_Undef) { assert(otherVal == l_Undef); shared.value[var] = thisVal; thisSentUnitData++; continue; } } if (solver.conf.verbosity >= 3 && (thisGotUnitData > 0 || thisSentUnitData > 0)) { std::cout << "c got units " << std::setw(8) << thisGotUnitData << " sent units " << std::setw(8) << thisSentUnitData << std::endl; } recvUnitData += thisGotUnitData; sentUnitData += thisSentUnitData; return true; }
bool VarReplacer::update_table_and_reversetable(const Lit lit1, const Lit lit2) { if (reverseTable.find(lit1.var()) == reverseTable.end()) { reverseTable[lit2.var()].push_back(lit1.var()); table[lit1.var()] = lit2 ^ lit1.sign(); replacedVars++; return true; } if (reverseTable.find(lit2.var()) == reverseTable.end()) { reverseTable[lit1.var()].push_back(lit2.var()); table[lit2.var()] = lit1 ^ lit2.sign(); replacedVars++; return true; } //both have children setAllThatPointsHereTo(lit1.var(), lit2 ^ lit1.sign()); replacedVars++; return true; }
void ImplCache::handleNewData( vector<uint16_t>& val , Var var , Lit lit ) { //Unfortunately, we cannot add the clauses, because that could mess up //the watchlists, which are being traversed by the callers, so we add these //new truths as delayed clauses, and add them at the end vector<Lit> tmp; //a->b and (-a)->b, so 'b' if (val[lit.var()] == lit.sign()) { delayedClausesToAddNorm.push_back(lit); runStats.bProp++; } else { //a->b, and (-a)->(-b), so equivalent literal tmp.push_back(Lit(var, false)); tmp.push_back(Lit(lit.var(), false)); bool sign = lit.sign(); delayedClausesToAddXor.push_back(std::make_pair(tmp, sign)); runStats.bXProp++; } }
/** @brief Replaces vars in xorclauses */ bool VarReplacer::replace_set(vec<XorClause*>& cs) { XorClause **a = cs.getData(); XorClause **r = a; for (XorClause **end = a + cs.size(); r != end; r++) { XorClause& c = **r; bool changed = false; Var origVar1 = c[0].var(); Var origVar2 = c[1].var(); for (Lit *l = &c[0], *end2 = l + c.size(); l != end2; l++) { Lit newlit = table[l->var()]; if (newlit.var() != l->var()) { changed = true; *l = Lit(newlit.var(), false); c.invert(newlit.sign()); replacedLits++; } } if (changed && handleUpdatedClause(c, origVar1, origVar2)) { if (!solver.ok) { #ifdef VERBOSE_DEBUG cout << "contradiction while replacing lits in xor clause" << std::endl; #endif for(;r != end; r++) solver.clauseAllocator.clauseFree(*r); cs.shrink(r-a); return false; } //solver.clauseAllocator.clauseFree(&c); c.setRemoved(); solver.freeLater.push(&c); } else { #ifdef SILENT_DEBUG uint32_t numUndef = 0; for (uint32_t i = 0; i < c.size(); i++) { if (solver.value(c[i]) == l_Undef) numUndef++; } assert(numUndef >= 2 || numUndef == 0); #endif *a++ = *r; } } cs.shrink(r-a); return solver.ok; }
const bool DataSync::syncBinFromOthers(const Lit lit, const vector<Lit>& bins, uint32_t& finished, vec<Watched>& ws) { assert(solver.varReplacer->getReplaceTable()[lit.var()].var() == lit.var()); assert(solver.subsumer->getVarElimed()[lit.var()] == false); assert(solver.xorSubsumer->getVarElimed()[lit.var()] == false); vec<Lit> addedToSeen; for (vec<Watched>::iterator it = ws.getData(), end = ws.getDataEnd(); it != end; it++) { if (it->isBinary()) { addedToSeen.push(it->getOtherLit()); seen[it->getOtherLit().toInt()] = true; } } vec<Lit> lits(2); for (uint32_t i = finished; i < bins.size(); i++) { if (!seen[bins[i].toInt()]) { Lit otherLit = bins[i]; otherLit = solver.varReplacer->getReplaceTable()[otherLit.var()] ^ otherLit.sign(); if (solver.subsumer->getVarElimed()[otherLit.var()] || solver.xorSubsumer->getVarElimed()[otherLit.var()] || solver.value(otherLit.var()) != l_Undef ) continue; recvBinData++; lits[0] = lit; lits[1] = otherLit; solver.addClauseInt(lits, 0, true, 2, 0, true); lits.clear(); lits.growTo(2); if (!solver.ok) goto end; } } finished = bins.size(); end: for (uint32_t i = 0; i < addedToSeen.size(); i++) seen[addedToSeen[i].toInt()] = false; return solver.ok; }
/** @brief Replaces variables in normal clauses */ const bool VarReplacer::replace_set(vec<Clause*>& cs, const bool binClauses) { Clause **a = cs.getData(); Clause **r = a; for (Clause **end = a + cs.size(); r != end; r++) { Clause& c = **r; bool changed = false; Lit origLit1 = c[0]; Lit origLit2 = c[1]; Lit origLit3 = (c.size() == 3) ? c[2] : lit_Undef; for (Lit *l = c.getData(), *end2 = l + c.size(); l != end2; l++) { if (table[l->var()].var() != l->var()) { changed = true; *l = table[l->var()] ^ l->sign(); replacedLits++; } } if (changed && handleUpdatedClause(c, origLit1, origLit2, origLit3)) { if (!solver.ok) { for(;r != end; r++) solver.clauseAllocator.clauseFree(*r); cs.shrink(r-a); return false; } } else { if (!binClauses && c.size() == 2) { solver.detachClause(c); Clause *c2 = solver.clauseAllocator.Clause_new(c); solver.clauseAllocator.clauseFree(&c); solver.attachClause(*c2); solver.becameBinary++; solver.binaryClauses.push(c2); } else *a++ = *r; } } cs.shrink(r-a); return solver.ok; }
/** @brief Replaces vars in xorclauses */ const bool VarReplacer::replace_set(vec<XorClause*>& cs) { XorClause **a = cs.getData(); XorClause **r = a; for (XorClause **end = a + cs.size(); r != end; r++) { XorClause& c = **r; bool changed = false; Var origVar1 = c[0].var(); Var origVar2 = c[1].var(); for (Lit *l = &c[0], *end2 = l + c.size(); l != end2; l++) { Lit newlit = table[l->var()]; if (newlit.var() != l->var()) { changed = true; *l = Lit(newlit.var(), false); c.invert(newlit.sign()); replacedLits++; } } if (changed && handleUpdatedClause(c, origVar1, origVar2)) { if (!solver.ok) { for(;r != end; r++) solver.clauseAllocator.clauseFree(*r); cs.shrink(r-a); return false; } c.setRemoved(); solver.freeLater.push(&c); } else { *a++ = *r; } } cs.shrink(r-a); return solver.ok; }
/** @brief Replaces variables in normal clauses */ bool VarReplacer::replace_set(vec<Clause*>& cs) { Clause **a = cs.getData(); Clause **r = a; for (Clause **end = a + cs.size(); r != end; r++) { Clause& c = **r; assert(c.size() > 2); bool changed = false; Lit origLit1 = c[0]; Lit origLit2 = c[1]; Lit origLit3 = (c.size() == 3) ? c[2] : lit_Undef; for (Lit *l = c.getData(), *end2 = l + c.size(); l != end2; l++) { if (table[l->var()].var() != l->var()) { changed = true; *l = table[l->var()] ^ l->sign(); replacedLits++; } } if (changed && handleUpdatedClause(c, origLit1, origLit2, origLit3)) { if (!solver.ok) { #ifdef VERBOSE_DEBUG cout << "contradiction while replacing lits in normal clause" << std::endl; #endif for(;r != end; r++) solver.clauseAllocator.clauseFree(*r); cs.shrink(r-a); return false; } } else { *a++ = *r; } } cs.shrink(r-a); return solver.ok; }
// Propagating a literal. Type of literal and the (learned clause's)/(propagating clause's)/(etc) group must be given. Updates the proof graph and the statistics. note: the meaning of the variable 'group' depends on the type void Logger::propagation(const Lit lit, Clause* c) { first_begin(); assert(!(proof == NULL && proof_graph_on)); uint group; prop_type type; if (c == NULL) { if (S->decisionLevel() == 0) type = add_clause_type; else type = guess_type; group = std::numeric_limits<uint>::max(); } else { type = simple_propagation_type; group = c->getGroup(); } //graph if (proof_graph_on && (!mini_proof || type == guess_type)) { uniqueid++; fprintf(proof,"node%d [shape=box, label=\"",uniqueid);; if (lit.sign()) fprintf(proof,"-"); if (varnames[lit.var()] != "Noname") fprintf(proof,"%s\"];\n",varnames[lit.var()].c_str()); else fprintf(proof,"Var: %d\"];\n",lit.var()); fprintf(proof,"node%d -> node%d [label=\"",history[history.size()-1],uniqueid); switch (type) { case simple_propagation_type: fprintf(proof,"%s\"];\n", groupnames[group].c_str()); break; case add_clause_type: fprintf(proof,"red. from clause\"];\n"); break; case guess_type: fprintf(proof,"guess\",style=bold];\n"); break; } history.push_back(uniqueid); } if (statistics_on) { switch (type) { case simple_propagation_type: depths_of_propagations_for_group[group].sum += S->decisionLevel(); depths_of_propagations_for_group[group].num ++; if (S->decisionLevel() == 0) depths_of_propagations_unit[group] = true; times_group_caused_propagation[group]++; case add_clause_type: no_propagations++; times_var_propagated[lit.var()]++; depths_of_assigns_for_var[lit.var()].sum += S->decisionLevel(); depths_of_assigns_for_var[lit.var()].num ++; if (S->decisionLevel() == 0) depths_of_assigns_unit[lit.var()] = true; break; case guess_type: no_decisions++; times_var_guessed[lit.var()]++; depths_of_assigns_for_var[lit.var()].sum += S->decisionLevel(); depths_of_assigns_for_var[lit.var()].num ++; break; } } }
void PropEngine::enqueue(const Lit p, const PropBy from) { #ifdef DEBUG_ENQUEUE_LEVEL0 #ifndef VERBOSE_DEBUG if (decisionLevel() == 0) #endif //VERBOSE_DEBUG cout << "enqueue var " << p.var()+1 << " to val " << !p.sign() << " level: " << decisionLevel() << " sublevel: " << trail.size() << " by: " << from << endl; #endif //DEBUG_ENQUEUE_LEVEL0 #ifdef ENQUEUE_DEBUG //assert(trail.size() <= nVarsOuter()); //assert(decisionLevel() == 0 || varData[p.var()].removed == Removed::none); #endif const Var v = p.var(); assert(value(v) == l_Undef); if (!watches[(~p).toInt()].empty()) { watches.prefetch((~p).toInt()); } const bool sign = p.sign(); assigns[v] = boolToLBool(!sign); #ifdef STATS_NEEDED_EXTRA varData[v].stats.trailLevelHist.push(trail.size()); varData[v].stats.decLevelHist.push(decisionLevel()); #endif varData[v].reason = from; varData[v].level = decisionLevel(); trail.push_back(p); propStats.propagations++; if (update_bogoprops) { propStats.bogoProps += 1; } if (sign) { #ifdef STATS_NEEDED_EXTRA varData[v].stats.negPolarSet++; #endif #ifdef STATS_NEEDED propStats.varSetNeg++; #endif } else { #ifdef STATS_NEEDED_EXTRA varData[v].stats.posPolarSet++; #endif #ifdef STATS_NEEDED propStats.varSetPos++; #endif } if (varData[v].polarity != sign) { #ifdef UPDATE_AGILITY agility.update(true); #endif #ifdef STATS_NEEDED_EXTRA varData[v].stats.flippedPolarity++; #endif #ifdef STATS_NEEDED propStats.varFlipped++; #endif } else { #ifdef UPDATE_AGILITY agility.update(false); #endif } //Only update non-decision: this way, flipped decisions don't get saved if (update_polarity_and_activity && from != PropBy() ) { varData[v].polarity = !sign; } #ifdef ANIMATE3D std::cerr << "s " << v << " " << p.sign() << endl; #endif }
void FeaturesCalc::for_one_clause( const Watched& cl , const Lit lit , Function func_each_cl , Function2 func_each_lit ) const { unsigned neg_vars = 0; unsigned pos_vars = 0; unsigned size = 0; switch (cl.getType()) { case CMSat::watch_binary_t: { if (cl.red()) { //only irred cls break; } if (lit > cl.lit2()) { //only count once break; } pos_vars += !lit.sign(); pos_vars += !cl.lit2().sign(); size = 2; neg_vars = size - pos_vars; func_each_cl(size, pos_vars, neg_vars); func_each_lit(lit, size, pos_vars, neg_vars); func_each_lit(cl.lit2(), size, pos_vars, neg_vars); break; } case CMSat::watch_tertiary_t: { if (cl.red()) { //only irred cls break; } if (lit > cl.lit2()) { //only count once break; } assert(cl.lit2() < cl.lit3()); pos_vars += !lit.sign(); pos_vars += !cl.lit2().sign(); pos_vars += !cl.lit3().sign(); size = 3; neg_vars = size - pos_vars; func_each_cl(size, pos_vars, neg_vars); func_each_lit(lit, size, pos_vars, neg_vars); func_each_lit(cl.lit2(), size, pos_vars, neg_vars); func_each_lit(cl.lit3(), size, pos_vars, neg_vars); break; } case CMSat::watch_clause_t: { const Clause& clause = *solver->cl_alloc.ptr(cl.get_offset()); if (clause.red()) { //only irred cls break; } if (clause[0] < clause[1]) { //only count once break; } for (const Lit cl_lit : clause) { pos_vars += !cl_lit.sign(); } size = clause.size(); neg_vars = size - pos_vars; func_each_cl(size, pos_vars, neg_vars); for (const Lit cl_lit : clause) { func_each_lit(cl_lit, size, pos_vars, neg_vars); } break; } case CMSat::watch_idx_t: { // This should never be here assert(false); exit(-1); break; } } }
void ImplCache::tryVar( Solver* solver , Var var ) { //Sanity check assert(solver->ok); assert(solver->decisionLevel() == 0); //Convenience vector<uint16_t>& seen = solver->seen; vector<uint16_t>& val = solver->seen2; Lit lit = Lit(var, false); const vector<LitExtra>& cache1 = implCache[lit.toInt()].lits; assert(solver->watches.size() > (lit.toInt())); watch_subarray_const ws1 = solver->watches[lit.toInt()]; const vector<LitExtra>& cache2 = implCache[(~lit).toInt()].lits; watch_subarray_const ws2 = solver->watches[(~lit).toInt()]; //Fill 'seen' and 'val' from cache for (vector<LitExtra>::const_iterator it = cache1.begin(), end = cache1.end() ; it != end ; it++ ) { const Var var2 = it->getLit().var(); //A variable that has been really eliminated, skip if (solver->varData[var2].removed != Removed::none && solver->varData[var2].removed != Removed::queued_replacer ) { continue; } seen[it->getLit().var()] = 1; val[it->getLit().var()] = it->getLit().sign(); } //Fill 'seen' and 'val' from watch for (watch_subarray::const_iterator it = ws1.begin(), end = ws1.end() ; it != end ; it++ ) { if (!it->isBinary()) continue; const Lit otherLit = it->lit2(); if (!seen[otherLit.var()]) { seen[otherLit.var()] = 1; val[otherLit.var()] = otherLit.sign(); } else if (val[otherLit.var()] != otherLit.sign()) { //(a->b, a->-b) -> so 'a' delayedClausesToAddNorm.push_back(lit); } } //Okay, filled //Try to see if we propagate the same or opposite from the other end //Using cache for (vector<LitExtra>::const_iterator it = cache2.begin(), end = cache2.end() ; it != end ; it++ ) { assert(it->getLit().var() != var); const Var var2 = it->getLit().var(); //Only if the other one also contained it if (!seen[var2]) continue; //If var has been removed, skip if (solver->varData[var2].removed != Removed::none && solver->varData[var2].removed != Removed::queued_replacer ) continue; handleNewData(val, var, it->getLit()); } //Try to see if we propagate the same or opposite from the other end //Using binary clauses for (watch_subarray::const_iterator it = ws2.begin(), end = ws2.end(); it != end; it++) { if (!it->isBinary()) continue; assert(it->lit2().var() != var); const Var var2 = it->lit2().var(); assert(var2 < solver->nVars()); //Only if the other one also contained it if (!seen[var2]) continue; handleNewData(val, var, it->lit2()); } //Clear 'seen' and 'val' for (vector<LitExtra>::const_iterator it = cache1.begin(), end = cache1.end(); it != end; it++) { seen[it->getLit().var()] = false; val[it->getLit().var()] = false; } for (watch_subarray::const_iterator it = ws1.begin(), end = ws1.end(); it != end; it++) { if (!it->isBinary()) continue; seen[it->lit2().var()] = false; val[it->lit2().var()] = false; } }
const bool VarReplacer::replace(T& ps, const bool xorEqualFalse, const uint32_t group) { #ifdef VERBOSE_DEBUG std::cout << "replace() called with var " << ps[0].var()+1 << " and var " << ps[1].var()+1 << " with xorEqualFalse " << xorEqualFalse << std::endl; #endif assert(ps.size() == 2); assert(!ps[0].sign()); assert(!ps[1].sign()); #ifdef DEBUG_REPLACER assert(solver.assigns[ps[0].var()].isUndef()); assert(solver.assigns[ps[1].var()].isUndef()); #endif Var var = ps[0].var(); Lit lit = Lit(ps[1].var(), !xorEqualFalse); assert(var != lit.var()); //Detect circle if (alreadyIn(var, lit)) return solver.ok; Lit lit1 = table[var]; bool inverted = false; //This pointer is already set, try to invert if (lit1.var() != var) { Var tmp_var = var; var = lit.var(); lit = Lit(tmp_var, lit.sign()); inverted = true; } if (inverted) { Lit lit2 = table[var]; //Inversion is also set, triangular cycle //A->B, A->C, B->C. There is nothing to add if (lit1.var() == lit2.var()) { if ((lit1.sign() ^ lit2.sign()) != lit.sign()) { #ifdef VERBOSE_DEBUG cout << "Inverted cycle in var-replacement -> UNSAT" << endl; #endif return (solver.ok = false); } return true; } //Inversion is also set if (lit2.var() != var) { assert(table[lit1.var()].var() == lit1.var()); setAllThatPointsHereTo(lit1.var(), Lit(lit.var(), lit1.sign())); assert(table[lit2.var()].var() == lit2.var()); setAllThatPointsHereTo(lit2.var(), lit ^ lit2.sign()); table[lit.var()] = Lit(lit.var(), false); replacedVars++; addBinaryXorClause(ps, xorEqualFalse, group); return true; } } //Follow forwards Lit litX = table[lit.var()]; if (litX.var() != lit.var()) lit = litX ^ lit.sign(); //Follow backwards setAllThatPointsHereTo(var, lit); replacedVars++; addBinaryXorClause(ps, xorEqualFalse, group); return true; }
Lit VarReplacer::getLitReplacedWithOuter(Lit lit) const { Lit lit2 = table[lit.var()] ^ lit.sign(); return lit2; }
/** @brief The main function of search() doing almost everything in this class Tries to branch on both lit1 and lit2 and then both-propagates them, fail-lits them, and hyper-bin resolves them, etc. It is imperative that from the SAT point of view, EITHER lit1 or lit2 MUST hold. So, if lit1 = ~lit2, it's OK. Also, if there is a binary clause 'lit1 or lit2' it's also OK. */ bool FailedLitSearcher::tryBoth(const Lit lit1, const Lit lit2) { if (binXorFind) { if (lastTrailSize < solver.trail.size()) { for (uint32_t i = lastTrailSize; i != solver.trail.size(); i++) { removeVarFromXors(solver.trail[i].var()); } } lastTrailSize = solver.trail.size(); xorClauseTouched.setZero(); investigateXor.clear(); } propagated.removeThese(propagatedBitSet); #ifdef DEBUG_FAILEDLIT assert(propagated.isZero()); #endif propagatedBitSet.clear(); twoLongXors.clear(); bothSame.clear(); binXorToAdd.clear(); #ifdef DEBUG_HYPERBIN assert(propagatedVars.empty()); assert(unPropagatedBin.isZero()); #endif //DEBUG_HYPERBIN #ifdef DEBUG_USELESS_LEARNT_BIN_REMOVAL dontRemoveAncestor.isZero(); assert(uselessBin.empty()); #endif solver.newDecisionLevel(); solver.uncheckedEnqueueLight(lit1); failed = (!solver.propagate<false>(false).isNULL()); if (failed) { solver.cancelUntilLight(); numFailed++; solver.uncheckedEnqueue(~lit1); solver.ok = (solver.propagate<false>(false).isNULL()); if (!solver.ok) return false; return true; } assert(solver.decisionLevel() > 0); Solver::TransCache& lit1OTFCache = solver.transOTFCache[(~lit1).toInt()]; if (solver.conf.doCacheOTFSSR) { lit1OTFCache.conflictLastUpdated = solver.conflicts; lit1OTFCache.lits.clear(); } for (int c = solver.trail.size() - 1; c >= (int) solver.trail_lim[0]; c--) { Var x = solver.trail[c].var(); propagated.setBit(x); propagatedBitSet.push_back(x); if (solver.conf.doHyperBinRes) { unPropagatedBin.setBit(x); propagatedVars.push(x); } if (solver.assigns[x].getBool()) propValue.setBit(x); else propValue.clearBit(x); if (binXorFind) removeVarFromXors(x); if (solver.conf.doCacheOTFSSR && c != (int) solver.trail_lim[0]) { lit1OTFCache.lits.push_back(solver.trail[c]); } } if (binXorFind) { for (uint32_t *it = investigateXor.getData(), *end = investigateXor.getDataEnd(); it != end; it++) { if (xorClauseSizes[*it] == 2) twoLongXors.insert(getTwoLongXor(*solver.xorclauses[*it])); } for (int c = solver.trail.size() - 1; c >= (int) solver.trail_lim[0]; c--) { addVarFromXors(solver.trail[c].var()); } xorClauseTouched.setZero(); investigateXor.clear(); } solver.cancelUntilLight(); //Hyper-binary resolution, and its accompanying data-structure cleaning if (solver.conf.doHyperBinRes) { if (hyperbinProps < maxHyperBinProps) hyperBinResolution(lit1); unPropagatedBin.removeThese(propagatedVars); propagatedVars.clear(); } #ifdef DEBUG_HYPERBIN assert(propagatedVars.empty()); assert(unPropagatedBin.isZero()); #endif //DEBUG_HYPERBIN solver.newDecisionLevel(); solver.uncheckedEnqueueLight(lit2); failed = (!solver.propagate<false>(false).isNULL()); if (failed) { solver.cancelUntilLight(); numFailed++; solver.uncheckedEnqueue(~lit2); solver.ok = (solver.propagate<false>(false).isNULL()); if (!solver.ok) return false; return true; } assert(solver.decisionLevel() > 0); Solver::TransCache& lit2OTFCache = solver.transOTFCache[(~lit2).toInt()]; if (solver.conf.doCacheOTFSSR) { lit2OTFCache.conflictLastUpdated = solver.conflicts; lit2OTFCache.lits.clear(); } for (int c = solver.trail.size() - 1; c >= (int) solver.trail_lim[0]; c--) { Var x = solver.trail[c].var(); if (propagated[x]) { if (propValue[x] == solver.assigns[x].getBool()) { //they both imply the same bothSame.push(Lit(x, !propValue[x])); } else if (c != (int) solver.trail_lim[0]) { bool invert; if (lit1.var() == lit2.var()) { assert(lit1.sign() == false && lit2.sign() == true); tmpPs[0] = Lit(lit1.var(), false); tmpPs[1] = Lit(x, false); invert = propValue[x]; } else { tmpPs[0] = Lit(lit1.var(), false); tmpPs[1] = Lit(lit2.var(), false); invert = lit1.sign() ^ lit2.sign(); } binXorToAdd.push_back(BinXorToAdd(tmpPs[0], tmpPs[1], invert)); bothInvert += solver.varReplacer->getNewToReplaceVars() - toReplaceBefore; toReplaceBefore = solver.varReplacer->getNewToReplaceVars(); } } if (solver.conf.doHyperBinRes) { unPropagatedBin.setBit(x); propagatedVars.push(x); } if (solver.assigns[x].getBool()) propValue.setBit(x); else propValue.clearBit(x); if (binXorFind) removeVarFromXors(x); if (solver.conf.doCacheOTFSSR && c != (int) solver.trail_lim[0]) { lit2OTFCache.lits.push_back(solver.trail[c]); } } //We now add the two-long xors that have been found through longer //xor-shortening if (binXorFind) { if (twoLongXors.size() > 0) { for (uint32_t *it = investigateXor.getData(), *end = it + investigateXor.size(); it != end; it++) { if (xorClauseSizes[*it] == 2) { TwoLongXor tmp = getTwoLongXor(*solver.xorclauses[*it]); if (twoLongXors.find(tmp) != twoLongXors.end()) { tmpPs[0] = Lit(tmp.var[0], false); tmpPs[1] = Lit(tmp.var[1], false); binXorToAdd.push_back(BinXorToAdd(tmpPs[0], tmpPs[1], tmp.inverted)); newBinXor += solver.varReplacer->getNewToReplaceVars() - toReplaceBefore; toReplaceBefore = solver.varReplacer->getNewToReplaceVars(); } } } } for (int c = solver.trail.size() - 1; c >= (int) solver.trail_lim[0]; c--) { addVarFromXors(solver.trail[c].var()); } } solver.cancelUntilLight(); if (solver.conf.doHyperBinRes) { if (hyperbinProps < maxHyperBinProps) hyperBinResolution(lit2); unPropagatedBin.removeThese(propagatedVars); propagatedVars.clear(); } for (uint32_t i = 0; i != bothSame.size(); i++) { solver.uncheckedEnqueue(bothSame[i]); } goodBothSame += bothSame.size(); solver.ok = (solver.propagate<false>(false).isNULL()); if (!solver.ok) return false; if (solver.conf.doBXor) { for (uint32_t i = 0; i < binXorToAdd.size(); i++) { tmpPs[0] = binXorToAdd[i].lit1; tmpPs[1] = binXorToAdd[i].lit2; solver.addXorClauseInt(tmpPs, binXorToAdd[i].isEqualFalse); tmpPs.clear(); tmpPs.growTo(2); if (!solver.ok) return false; } } return true; }