///////////////////////////////////////////////////////////////////////////////////////// // solve ///////////////////////////////////////////////////////////////////////////////////////// bool solve(Solver& s, const SolveParams& p) { s.stats.solve.reset(); if (s.hasConflict()) return false; double maxLearnts = p.computeReduceBase(s); double boundLearnts = p.reduce.max(); RestartStrategy rs(p.restart); ValueRep result; uint32 randRuns = p.randRuns(); double randFreq = randRuns == 0 ? p.randomProbability() : 1.0; uint64 maxCfl = randRuns == 0 ? rs.next() : p.randConflicts(); uint32 shuffle = p.shuffleBase(); do { result = p.enumerator()->search(s, maxCfl, (uint32)maxLearnts, randFreq, p.restart.local); if ((result & value_true) != 0) { if (!p.enumerator()->backtrackFromModel(s)) { break; // No more models requested } else { // continue enumeration // but cancel remaining probings randRuns = 0; randFreq = p.randomProbability(); if (p.restart.resetOnModel) { rs.reset(); maxCfl = rs.next(); } if (!p.restart.bounded && s.backtrackLevel() > 0) { // After the first solution was found, we allow further restarts only if this // is compatible with the enumerator used. maxCfl = static_cast<uint64>(-1); } } } else if (result == value_free){ // restart search if (randRuns == 0) { maxCfl = rs.next(); if (p.reduce.reduceOnRestart) { s.reduceLearnts(.33f); } if (maxLearnts != (double)std::numeric_limits<uint32>::max() && maxLearnts < boundLearnts && (s.numLearntConstraints()+maxCfl) > maxLearnts) { maxLearnts = std::min(maxLearnts*p.reduce.inc(), (double)std::numeric_limits<uint32>::max()); } if (++s.stats.solve.restarts == shuffle) { shuffle += p.shuffleNext(); s.shuffleOnNextSimplify(); } } else if (--randRuns == 0) { maxCfl = rs.next(); randFreq = p.randomProbability(); } } } while (result < value_false); store_clear_bit(result, Enumerator::LIMIT_BIT); bool more = result == value_free || s.decisionLevel() > s.rootLevel(); p.enumerator()->endSearch(s, !more); s.undoUntil(0); return more; }
ValueRep SolveAlgorithm::solvePath(Solver& s, const SolveParams& p, SolveLimits& lim) { if (s.hasConflict()) return value_false; if (lim.reached()) return value_free; struct ConflictLimits { uint64 restart; // current restart limit uint64 reduce; // current reduce limit uint64 grow; // current limit for next growth operation uint64 global; // current global limit uint64 min() const { return std::min(std::min(restart, grow), std::min(reduce, global)); } void update(uint64 x) { restart -= x; reduce -= x; grow -= x; global -= x; } } cLimit; typedef Range<double> RangeD; typedef SolvePathEvent EventType; SearchLimits sLimit; WeightLitVec inDegree; ScheduleStrategy ds = p.reduce.cflSched; ScheduleStrategy dg = p.reduce.growSched; ScheduleStrategy rs = p.restart.sched; Solver::DBInfo db = {0,0,0}; ValueRep result = value_free; uint64 lastC = s.stats.conflicts; uint64 lastR = s.stats.restarts; uint64 nextUp = 16000; s.stats.cflLast = s.stats.analyzed; uint32 shuffle = p.restart.shuffle; RangeD dbSizeLimit = !dg.disabled() || dg.defaulted() ? RangeD(p.reduce.initLimit(*s.sharedContext()), p.reduce.maxLimit(*s.sharedContext())) : RangeD(p.reduce.maxRange, p.reduce.maxRange); uint32 dbRedInit = ds.disabled() ? 0 : p.reduce.initLimit(*s.sharedContext()); if (dbSizeLimit.lo < s.numLearntConstraints()) { dbSizeLimit.lo = dbSizeLimit.clamp(s.numLearntConstraints() + p.reduce.initRange.lo); } if (dbSizeLimit.lo > p.reduce.maxRange) { dbSizeLimit.lo = p.reduce.maxRange; } if (dbSizeLimit.hi > p.reduce.maxRange) { dbSizeLimit.hi = p.reduce.maxRange; } if (dbRedInit && ds.type != ScheduleStrategy::luby_schedule) { if (dbRedInit < ds.base) { dbRedInit = std::min(ds.base, std::max(dbRedInit,(uint32)5000)); ds.grow = dbRedInit != ds.base ? std::min(ds.grow, dbRedInit/2.0f) : ds.grow; ds.base = dbRedInit; } dbRedInit = 0; } double dbMax = dbSizeLimit.lo; cLimit.grow = dg.current(); cLimit.reduce = ds.current() + dbRedInit; cLimit.global = lim.conflicts; cLimit.restart = UINT64_MAX; uint64& rsLimit = p.restart.local() ? sLimit.local : cLimit.restart; uint64 nRestart = 0; rsLimit = rs.current(); if (p.restart.dynamic()) { s.stats.enableQueue(rs.base); s.stats.queue->reset(); sLimit.xLbd = (float)rs.grow; rsLimit = nextUp; } EventType progress(s, SolvePathEvent::event_restart, 0, 0); while (result == value_free && cLimit.global) { pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_testcancel(); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); uint64 minLimit = cLimit.min(); assert(minLimit); sLimit.learnts = (uint32)dbSizeLimit.clamp(dbMax + (db.pinned*p.reduce.strategy.noGlue)); sLimit.conflicts= minLimit; progress.cLimit = std::min(minLimit, sLimit.local); progress.lLimit = sLimit.learnts; if (progress.evType) { s.sharedContext()->reportProgress(progress); } result = s.search(sLimit, p.randomProbability()); minLimit = (minLimit - sLimit.conflicts); // number of actual conflicts cLimit.update(minLimit); if (result == value_true && backtrackFromModel(s)) { result = value_free; // continue enumeration if (p.restart.resetOnModel()) { rs.reset(); } // After the first solution was found, we allow further restarts only if this // is compatible with the enumerator used. cLimit.restart = std::max(cLimit.restart, rs.current()); cLimit.reduce = ds.current() + dbRedInit; cLimit.grow = std::max(cLimit.grow, uint64(1)); progress.evType = SolvePathEvent::event_model; if (!p.restart.bounded() && s.backtrackLevel() > s.rootLevel()) { sLimit = SearchLimits(); cLimit.restart= UINT64_MAX; } } else if (result == value_free){ // limit reached minLimit = 0; progress.evType = SolvePathEvent::event_none; if (rsLimit == 0 || sLimit.dynamicRestart(s.stats)) { // restart reached - do restart ++s.stats.restarts; ++nRestart; if (p.restart.counterRestart && (nRestart % p.restart.counterRestart) == 0 ) { inDegree.clear(); s.heuristic()->bump(s, inDegree, p.restart.counterBump / (double)s.inDegree(inDegree)); } if (p.restart.dynamic()) { uint64 num = s.stats.restarts - lastR; uint64 cfl = s.stats.conflicts - lastC; if (cfl >= nextUp) { float& lim = sLimit.xLbd != 0.0f ? sLimit.xLbd : sLimit.xCfl; double avg = cfl / double(num); bool sx = (s.stats.analyzed - s.stats.cflLast) >= nextUp; bool tog = rs.len != 0 && (s.stats.avgLbd() > rs.len) == (lim == sLimit.xLbd); lastR = s.stats.restarts; lastC = s.stats.conflicts; if (avg >= 16000.0) { lim += 0.1f; nextUp = 16000; } else if (sx) { lim += 0.05f; nextUp = std::max(uint64(16000), nextUp-10000); } else if (avg >= 4000.0) { lim += 0.05f; } else if (avg >= 1000.0) { nextUp += 10000u; } else if (lim > rs.grow) { lim -= 0.05f; } if (tog) { lim = (float)rs.grow; nextUp = 16000; std::swap(sLimit.xLbd, sLimit.xCfl); } } rsLimit = nextUp;; minLimit = s.stats.queue->samples; s.stats.queue->reset(); } s.undoUntil(0); if (rsLimit == 0) { rsLimit = rs.next(); } if (!minLimit) { minLimit= rs.current(); } if (p.reduce.strategy.fRestart){ db = s.reduceLearnts(p.reduce.fRestart(), p.reduce.strategy); } if (nRestart == shuffle) { shuffle+= p.restart.shuffleNext; s.shuffleOnNextSimplify();} if (nRestart == lim.restarts) { break; } s.stats.cflLast = s.stats.analyzed; progress.evType = SolvePathEvent::event_restart; } if (cLimit.reduce == 0 || s.learntLimit(sLimit)) { // reduction reached - remove learnt constraints db = s.reduceLearnts(p.reduce.fReduce(), p.reduce.strategy); cLimit.reduce = dbRedInit + (cLimit.reduce == 0 ? ds.next() : ds.current()); progress.evType = std::max(progress.evType, SolvePathEvent::event_deletion); if (s.learntLimit(sLimit) || db.pinned >= dbMax) { ReduceStrategy t; t.algo = 2; t.score = 2; t.glue = 0; db.pinned /= 2; db.size = s.reduceLearnts(0.5f, t).size; if (db.size >= sLimit.learnts) { dbMax = dbSizeLimit.clamp(dbMax + std::max(100.0, s.numLearntConstraints()/10.0)); } } } if (cLimit.grow == 0 || (dg.defaulted() && progress.evType == SolvePathEvent::event_restart)) { // grow sched reached - increase max db size if (cLimit.grow == 0) { cLimit.grow = dg.next(); minLimit = cLimit.grow; } if ((s.numLearntConstraints() + minLimit) > dbMax){ dbMax *= p.reduce.fGrow; progress.evType = std::max(progress.evType, SolvePathEvent::event_grow); } if (dbMax > dbSizeLimit.hi) { dbMax = dbSizeLimit.hi; cLimit.grow = UINT64_MAX; dg = ScheduleStrategy::none(); } } } } s.stats.cflLast = s.stats.analyzed - s.stats.cflLast; if (lim.conflicts != UINT64_MAX) { lim.conflicts = cLimit.global; } if (lim.restarts != UINT64_MAX) { lim.restarts -= nRestart; } return result; }