bool Prober::propagate(Lit& failed) { if (solver->conf.otfHyperbin) { //Set timeout for ONE enqueue. This used so that in case ONE enqueue //takes too long (usually because of hyper-bin), we exit early uint64_t timeout = std::numeric_limits<uint64_t>::max(); if (!solver->drat->enabled()) { timeout = solver->propStats.otfHyperTime + solver->propStats.bogoProps + single_prop_tout; } //DFS is expensive, actually. So do BFS 50% of the time if (solver->conf.doStamp && (force_stamp >= 1 || (solver->mtrand.randInt(1) == 0 && force_stamp == -1)) ) { StampType stampType; if (force_stamp == 2) { stampType = StampType::STAMP_IRRED; } else if (force_stamp == 1) { stampType = StampType::STAMP_RED; } else { stampType = solver->mtrand.randInt(1) ? StampType::STAMP_IRRED : StampType::STAMP_RED; } failed = solver->propagate_dfs(stampType, timeout); } else { failed = solver->propagate_bfs(timeout); } if (check_timeout_due_to_hyperbin()) { return false; } } else { //No hyper-bin so we use regular propagate and regular analyze PropBy confl = solver->propagate<true>(); if (!confl.isNULL()) { uint32_t glue; uint32_t backtrack_level; solver->analyze_conflict<true>( confl , backtrack_level //return backtrack level here , glue //return glue here ); if (solver->learnt_clause.empty()) { solver->ok = false; return false; } assert(solver->learnt_clause.size() == 1); failed = ~(solver->learnt_clause[0]); } } return true; }
//Analyze why did we fail at decision level 1 Lit HyperEngine::analyzeFail(const PropBy propBy) { //Clear out the datastructs we will be usin currAncestors.clear(); //First, we set the ancestors, based on the clause //Each literal in the clause is an ancestor. So just 'push' them inside the //'currAncestors' variable switch(propBy.getType()) { case tertiary_t : { const Lit lit = ~propBy.lit3(); if (varData[lit.var()].level != 0) currAncestors.push_back(lit); //intentionally falling through here //i.e. there is no 'break' here for a reason } case binary_t: { const Lit lit = ~propBy.lit2(); if (varData[lit.var()].level != 0) currAncestors.push_back(lit); if (varData[failBinLit.var()].level != 0) currAncestors.push_back(~failBinLit); break; } case clause_t: { const uint32_t offset = propBy.get_offset(); const Clause& cl = *cl_alloc.ptr(offset); for(size_t i = 0; i < cl.size(); i++) { if (varData[cl[i].var()].level != 0) currAncestors.push_back(~cl[i]); } break; } case xor_t: { //in the future, we'll have XOR clauses. Not yet. assert(false); exit(-1); break; } case null_clause_t: assert(false); break; } Lit foundLit = deepest_common_ancestor(); return foundLit; }
ClOffset DistillerLong::try_distill_clause_and_return_new( ClOffset offset , const bool red , const ClauseStats& stats ) { #ifdef DRAT_DEBUG if (solver->conf.verbosity >= 6) { cout << "Trying to distill clause:" << lits << endl; } #endif //Try to enqueue the literals in 'queueByBy' amounts and see if we fail solver->detachClause(offset, false); Clause& cl = *solver->cl_alloc.ptr(offset); (*solver->drat) << deldelay << cl << fin; uint32_t orig_size = cl.size(); uint32_t i = 0; uint32_t j = 0; for (uint32_t sz = cl.size(); i < sz; i++) { if (solver->value(cl[i]) != l_False) { cl[j++] = cl[i]; } } cl.resize(j); solver->new_decision_level(); bool True_confl = false; PropBy confl; i = 0; j = 0; for (uint32_t sz = cl.size(); i < sz; i++) { const Lit lit = cl[i]; lbool val = solver->value(lit); if (val == l_Undef) { solver->enqueue(~lit); cl[j++] = cl[i]; maxNumProps -= 5; confl = solver->propagate<true>(); if (!confl.isNULL()) { break; } } else if (val == l_False) { // skip } else { assert(val == l_True); cl[j++] = cl[i]; True_confl = true; confl = solver->varData[cl[i].var()].reason; break; } } assert(solver->ok); cl.resize(j); //Couldn't simplify the clause if (j == orig_size && !True_confl && confl.isNULL()) { solver->cancelUntil<false, true>(0); solver->attachClause(cl); solver->drat->forget_delay(); return offset; } #ifdef VERBOSE_DEBUG if (j < i && solver->conf.verbosity >= 5) { cout << "c Distillation branch effective." << endl << "c --> shortened cl:" << cl<< endl << "c --> orig size:" << orig_size << endl << "c --> new size:" << j << endl; } #endif bool lits_set = false; if (red && j > 1 && (!confl.isNULL() || True_confl)) { #ifdef VERBOSE_DEBUG if (solver->conf.verbosity >= 5) { cout << "c Distillation even more effective." << endl << "c --> orig shortened cl:" << cl << endl; } #endif maxNumProps -= 20; lits.clear(); if (True_confl) { lits.push_back(cl[cl.size()-1]); } solver->simple_create_learnt_clause(confl, lits, True_confl); if (lits.size() < cl.size()) { #ifdef VERBOSE_DEBUG if (solver->conf.verbosity >= 5) { cout << "c --> more shortened cl:" << lits << endl; } #endif lits_set = true; } } solver->cancelUntil<false, true>(0); runStats.numLitsRem += orig_size - cl.size(); runStats.numClShorten++; //Make new clause if (!lits_set) { lits.resize(cl.size()); std::copy(cl.begin(), cl.end(), lits.begin()); } solver->cl_alloc.clauseFree(offset); Clause *cl2 = solver->add_clause_int(lits, red, stats); (*solver->drat) << findelay; if (cl2 != NULL) { cl2->set_distilled(true); return solver->cl_alloc.get_offset(cl2); } else { //it became a bin/unit/zero return CL_OFFSET_MAX; } }
PropBy PropEngine::propagateBinFirst( #ifdef STATS_NEEDED AvgCalc<size_t>* watchListSizeTraversed #endif ) { PropBy confl; #ifdef VERBOSE_DEBUG_PROP cout << "Propagation started" << endl; #endif uint32_t qheadlong = qhead; startAgain: //Propagate binary clauses first while (qhead < trail.size() && confl.isNULL()) { const Lit p = trail[qhead++]; // 'p' is enqueued fact to propagate. watch_subarray_const ws = watches[(~p).toInt()]; #ifdef STATS_NEEDED if (watchListSizeTraversed) watchListSizeTraversed->push(ws.size()); #endif watch_subarray::const_iterator i = ws.begin(); watch_subarray_const::const_iterator end = ws.end(); propStats.bogoProps += ws.size()/10 + 1; for (; i != end; i++) { //Propagate binary clause if (i->isBinary()) { if (!propBinaryClause(i, p, confl)) { break; } continue; } //Pre-fetch long clause if (i->isClause()) { if (value(i->getBlockedLit()) != l_True) { const ClOffset offset = i->get_offset(); __builtin_prefetch(cl_alloc.ptr(offset)); } continue; } //end CLAUSE } } PropResult ret = PROP_NOTHING; while (qheadlong < qhead && confl.isNULL()) { const Lit p = trail[qheadlong]; // 'p' is enqueued fact to propagate. watch_subarray ws = watches[(~p).toInt()]; watch_subarray::iterator i = ws.begin(); watch_subarray::iterator j = ws.begin(); watch_subarray_const::const_iterator end = ws.end(); propStats.bogoProps += ws.size()/4 + 1; for (; i != end; i++) { //Skip binary clauses if (i->isBinary()) { *j++ = *i; continue; } if (i->isTri()) { *j++ = *i; //Propagate tri clause ret = propTriClause(i, p, confl); if (ret == PROP_SOMETHING || ret == PROP_FAIL) { //Conflict or propagated something i++; break; } else { //Didn't propagate anything, continue assert(ret == PROP_NOTHING); continue; } } //end TRICLAUSE if (i->isClause()) { ret = propNormalClause(i, j, p, confl); if (ret == PROP_SOMETHING || ret == PROP_FAIL) { //Conflict or propagated something i++; break; } else { //Didn't propagate anything, continue assert(ret == PROP_NOTHING); continue; } } //end CLAUSE } while (i != end) { *j++ = *i++; } ws.shrink_(end-j); //If propagated something, goto start if (ret == PROP_SOMETHING) { goto startAgain; } qheadlong++; } #ifdef VERBOSE_DEBUG cout << "Propagation (propagateBinFirst) ended." << endl; #endif return confl; }
PropBy PropEngine::propagateAnyOrder() { PropBy confl; #ifdef VERBOSE_DEBUG_PROP cout << "Fast Propagation started" << endl; #endif while (qhead < trail.size() && confl.isNULL()) { const Lit p = trail[qhead]; // 'p' is enqueued fact to propagate. watch_subarray ws = watches[(~p).toInt()]; /* //propagate bin & tri for (watch_subarray::iterator i = ws.begin(), end = ws.end(); i != end; i++) { if (i->isBinary()) { if (!propBinaryClause(i, p, confl)) { return confl; } continue; } //Propagate tri clause if (i->isTri()) { if (!propTriClauseAnyOrder(i, p, confl)) { return confl; } continue; } }*/ watch_subarray::iterator i = ws.begin(); watch_subarray::iterator j = ws.begin(); watch_subarray_const::const_iterator end = ws.end(); if (update_bogoprops) { propStats.bogoProps += ws.size()/4 + 1; } for (; i != end; i++) { if (i->isBinary()) { *j++ = *i; if (!propBinaryClause<update_bogoprops>(i, p, confl)) { i++; break; } continue; } //Propagate tri clause if (i->isTri()) { *j++ = *i; if (!propTriClauseAnyOrder<update_bogoprops>(i, p, confl)) { i++; break; } continue; } //propagate normal clause if (i->isClause()) { if (!propNormalClauseAnyOrder<update_bogoprops>(i, j, p, confl)) { i++; break; } continue; }/* else { *j++ = *i; }*/ assert(false); } while (i != end) { *j++ = *i++; } ws.shrink_(end-j); qhead++; } #ifdef VERBOSE_DEBUG cout << "Propagation (propagateAnyOrder) ended." << endl; #endif return confl; }
bool Prober::try_this(const Lit lit, const bool first, const uint64_t orig_num_props_to_do) { //Clean state if this is the 1st of two if (first) { clear_up_before_first_set(); } toEnqueue.clear(); runStats.numProbed++; solver->new_decision_level(); solver->enqueue(lit); solver->varData[lit.var()].depth = 0; if (solver->conf.verbosity >= 6) { cout << "c Probing lit " << lit << endl; } Lit failed = lit_Undef; if (solver->conf.otfHyperbin) { //Set timeout for ONE enqueue. This used so that in case ONE enqueue //takes too long (usually because of hyper-bin), we exit early uint64_t timeout = std::numeric_limits<uint64_t>::max(); if (!solver->drup->enabled()) { timeout = solver->propStats.otfHyperTime + solver->propStats.bogoProps + (double)orig_num_props_to_do*solver->conf.single_probe_time_limit_perc; } //DFS is expensive, actually. So do BFS 50% of the time if (solver->conf.doStamp && solver->mtrand.randInt(1) == 0) { const StampType stampType = solver->mtrand.randInt(1) ? StampType::STAMP_IRRED : StampType::STAMP_RED; failed = solver->propagate_dfs( stampType , timeout //early-abort timeout ); } else { failed = solver->propagate_bfs( timeout //early-abort timeout ); } if (check_timeout_due_to_hyperbin()) { return solver->okay(); } } else { //No hyper-bin so we use regular propagate and regular analyze PropBy confl = solver->propagate<true>(); if (!confl.isNULL()) { uint32_t glue; uint32_t backtrack_level; solver->analyze_conflict( confl , backtrack_level //return backtrack level here , glue //return glue here ); if (solver->learnt_clause.empty()) { solver->ok = false; return false; } assert(solver->learnt_clause.size() == 1); failed = ~(solver->learnt_clause[0]); } } if (failed != lit_Undef) { handle_failed_lit(lit, failed); return solver->ok; } else { if (solver->conf.verbosity >= 6) cout << "c Did not fail on lit " << lit << endl; } //Fill bothprop, cache assert(solver->decisionLevel() > 0); size_t numElemsSet = solver->trail_size() - solver->trail_lim[0]; for (int64_t c = solver->trail_size()-1 ; c != (int64_t)solver->trail_lim[0] - 1 ; c-- ) { extraTime += 2; const Lit thisLit = solver->trail[c]; const Var var = thisLit.var(); check_and_set_both_prop(var, first); visitedAlready[thisLit.toInt()] = 1; if (!solver->conf.otfHyperbin) continue; update_cache(thisLit, lit, numElemsSet); } if (!solver->conf.otfHyperbin && solver->conf.doCache ) { add_rest_of_lits_to_cache(lit); } solver->cancelUntil<false>(0); runStats.addedBin += solver->hyper_bin_res_all(); std::pair<size_t, size_t> tmp = solver->remove_useless_bins(); runStats.removedIrredBin += tmp.first; runStats.removedRedBin += tmp.second; //Add toEnqueue assert(solver->ok); runStats.bothSameAdded += toEnqueue.size(); extraTime += 3*toEnqueue.size(); return solver->fully_enqueue_these(toEnqueue); }