1 //
2 // Copyright (c) 2006-2017 Benjamin Kaufmann
3 //
4 // This file is part of Clasp. See http://www.cs.uni-potsdam.de/clasp/
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to
8 // deal in the Software without restriction, including without limitation the
9 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 // sell copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 // IN THE SOFTWARE.
23 //
24 #include <clasp/solver.h>
25 #include <clasp/clause.h>
26 #include POTASSCO_EXT_INCLUDE(unordered_set)
27 namespace Clasp {
28 namespace {
29 	typedef POTASSCO_EXT_NS::unordered_set<Constraint*> ConstraintSet;
30 	struct InSet {
operator ()Clasp::__anonc4147af90111::InSet31 		bool operator()(Constraint* c)        const { return set->find(c) != set->end(); }
operator ()Clasp::__anonc4147af90111::InSet32 		bool operator()(const ClauseWatch& w) const { return (*this)(w.head); }
operator ()Clasp::__anonc4147af90111::InSet33 		bool operator()(const GenericWatch&w) const { return (*this)(w.con);  }
34 		const ConstraintSet* set;
35 	};
36 }
~DecisionHeuristic()37 DecisionHeuristic::~DecisionHeuristic() {}
38 static SelectFirst null_heuristic_g;
39 /////////////////////////////////////////////////////////////////////////////////////////
40 // CCMinRecursive
41 /////////////////////////////////////////////////////////////////////////////////////////
42 struct CCMinRecursive {
43 	enum State { state_open = 0, state_removable = 1, state_poison = 2 };
encodeStateClasp::CCMinRecursive44 	uint32 encodeState(State st)     const { return open + uint32(st); }
decodeStateClasp::CCMinRecursive45 	State  decodeState(uint32 epoch) const { return epoch <= open ? state_open : static_cast<State>(epoch - open); }
pushClasp::CCMinRecursive46 	void    push(Literal p) { todo.push_back(p); }
popClasp::CCMinRecursive47 	Literal pop()           { Literal p = todo.back(); todo.pop_back(); return p; }
48 	LitVec todo;
49 	uint32 open;
50 };
51 /////////////////////////////////////////////////////////////////////////////////////////
52 // SelectFirst selection strategy
53 /////////////////////////////////////////////////////////////////////////////////////////
54 // selects the first free literal
doSelect(Solver & s)55 Literal SelectFirst::doSelect(Solver& s) {
56 	for (Var i = 1; i <= s.numVars(); ++i) {
57 		if (s.value(i) == value_free) {
58 			return selectLiteral(s, i, 0);
59 		}
60 	}
61 	assert(!"SelectFirst::doSelect() - precondition violated!\n");
62 	return Literal();
63 }
64 /////////////////////////////////////////////////////////////////////////////////////////
65 // Dirty list
66 /////////////////////////////////////////////////////////////////////////////////////////
67 struct Solver::Dirty {
68 	static const std::size_t min_size = static_cast<std::size_t>(4);
DirtyClasp::Solver::Dirty69 	Dirty() : last(0) {}
addClasp::Solver::Dirty70 	bool add(Literal p, WatchList& wl, Constraint* c) {
71 		if (wl.right_size() <= min_size) { return false; }
72 		uintp o = wl.left_size() > 0 ? reinterpret_cast<uintp>(wl.left_begin()->head) : 0;
73 		if (add(wl.right_begin()->con, o, c)) { dirty.push_left(p); }
74 		return true;
75 	}
addClasp::Solver::Dirty76 	bool add(Literal p, WatchList& wl, ClauseHead* c) {
77 		if (wl.left_size() <= min_size) { return false; }
78 		uintp o = wl.right_size() > 0 ? reinterpret_cast<uintp>(wl.right_begin()->con) : 0;
79 		if (add(wl.left_begin()->head, o, c)) { dirty.push_left(p); }
80 		return true;
81 	}
addClasp::Solver::Dirty82 	bool add(uint32 dl, ConstraintDB& wl, Constraint* c) {
83 		if (wl.size() <= min_size) { return false; }
84 		if (add(wl[0], 0, c)) { dirty.push_right(dl); }
85 		return true;
86 	}
87 	template <class T>
addClasp::Solver::Dirty88 	bool add(T*& list, uintp other, Constraint* c) {
89 		other |= reinterpret_cast<uintp>(list);
90 		list = reinterpret_cast<T*>( set_bit(reinterpret_cast<uintp>(list), 0) );
91 		if (c != last) { cons.insert(last = c); }
92 		return !test_bit(other, 0);
93 	}
94 	template <class T>
test_and_clearClasp::Solver::Dirty95 	bool test_and_clear(T*& x) const {
96 		uintp old = reinterpret_cast<uintp>(x);
97 		return test_bit(old, 0) && (x = reinterpret_cast<T*>(clear_bit(old, 0))) != 0;
98 	}
cleanupClasp::Solver::Dirty99 	void cleanup(Watches& watches, DecisionLevels& levels) {
100 		InSet inCons = { &cons };
101 		const uint32 maxId = (uint32)watches.size();
102 		for (DirtyList::left_iterator it = dirty.left_begin(), end = dirty.left_end(); it != end; ++it) {
103 			uint32 id = it->id();
104 			if (id >= maxId)
105 				continue;
106 			WatchList& wl = watches[id];
107 			if (wl.left_size() && test_and_clear(wl.left_begin()->head)) { wl.shrink_left(std::remove_if(wl.left_begin(), wl.left_end(), inCons)); }
108 			if (wl.right_size()&& test_and_clear(wl.right_begin()->con)) { wl.shrink_right(std::remove_if(wl.right_begin(), wl.right_end(), inCons)); }
109 		}
110 		ConstraintDB* db = 0;
111 		for (DirtyList::right_iterator it = dirty.right_begin(), end = dirty.right_end(); it != end; ++it) {
112 			if (*it < levels.size() && !(db = levels[*it].undo)->empty() && test_and_clear(*db->begin())) {
113 				db->erase(std::remove_if(db->begin(), db->end(), inCons), db->end());
114 			}
115 		}
116 		dirty.clear();
117 		cons.clear();
118 		last = 0;
119 	}
120 	typedef bk_lib::left_right_sequence<Literal, uint32, 0> DirtyList;
121 	DirtyList     dirty;
122 	ConstraintSet cons;
123 	Constraint*   last;
124 };
125 /////////////////////////////////////////////////////////////////////////////////////////
126 // Solver: Construction/Destruction/Setup
127 /////////////////////////////////////////////////////////////////////////////////////////
128 #define FOR_EACH_POST(x, head) \
129 	for (PostPropagator** __r__ = (head), *x; (x = *__r__) != 0; __r__ = (x == *__r__) ? &x->next : __r__)
130 
131 static PostPropagator* sent_list;
Solver(SharedContext * ctx,uint32 id)132 Solver::Solver(SharedContext* ctx, uint32 id)
133 	: shared_(ctx)
134 	, heuristic_(&null_heuristic_g, Ownership_t::Retain)
135 	, ccMin_(0)
136 	, postHead_(&sent_list)
137 	, undoHead_(0)
138 	, enum_(0)
139 	, memUse_(0)
140 	, lazyRem_(0)
141 	, ccInfo_(Constraint_t::Conflict)
142 	, dbIdx_(0)
143 	, lastSimp_(0)
144 	, shufSimp_(0)
145 	, initPost_(0){
146 	Var trueVar = assign_.addVar();
147 	assign_.setValue(trueVar, value_true);
148 	markSeen(trueVar);
149 	strategy_.id = id;
150 }
151 
~Solver()152 Solver::~Solver() {
153 	freeMem();
154 }
155 
freeMem()156 void Solver::freeMem() {
157 	std::for_each( constraints_.begin(), constraints_.end(), DestroyObject());
158 	std::for_each( learnts_.begin(), learnts_.end(), DestroyObject() );
159 	constraints_.clear();
160 	learnts_.clear();
161 	post_.clear();
162 	if (enum_) { enum_->destroy(); }
163 	resetHeuristic(0);
164 	PodVector<WatchList>::destruct(watches_);
165 	// free undo lists
166 	// first those still in use
167 	for (DecisionLevels::size_type i = 0; i != levels_.size(); ++i) {
168 		delete levels_[i].undo;
169 	}
170 	// then those in the free list
171 	for (ConstraintDB* x = undoHead_; x; ) {
172 		ConstraintDB* t = x;
173 		x = (ConstraintDB*)x->front();
174 		delete t;
175 	}
176 	delete ccMin_;
177 	ccMin_  = 0;
178 	memUse_ = 0;
179 }
180 
satPrepro() const181 SatPreprocessor*    Solver::satPrepro()     const { return shared_->satPrepro.get(); }
searchConfig() const182 const SolveParams&  Solver::searchConfig()  const { return shared_->configuration()->search(id()); }
183 
reset()184 void Solver::reset() {
185 	SharedContext* myCtx = shared_;
186 	uint32         myId  = strategy_.id;
187 	this->~Solver();
188 	new (this) Solver(myCtx, myId);
189 }
setHeuristic(DecisionHeuristic * h,Ownership_t::Type t)190 void Solver::setHeuristic(DecisionHeuristic* h, Ownership_t::Type t) {
191 	POTASSCO_REQUIRE(h, "Heuristic must not be null");
192 	resetHeuristic(this, h, t);
193 }
resetHeuristic(Solver * s,DecisionHeuristic * h,Ownership_t::Type t)194 void Solver::resetHeuristic(Solver* s, DecisionHeuristic* h, Ownership_t::Type t) {
195 	if (s && heuristic_.get()) { heuristic_->detach(*this); }
196 	if (!h) { h = &null_heuristic_g; t = Ownership_t::Retain; }
197 	HeuristicPtr(h, t).swap(heuristic_);
198 }
resetConfig()199 void Solver::resetConfig() {
200 	if (strategy_.hasConfig) {
201 		if (PostPropagator* pp = getPost(PostPropagator::priority_reserved_look)) { pp->destroy(this, true); }
202 		delete ccMin_;
203 		ccMin_ = 0;
204 	}
205 	strategy_.hasConfig = 0;
206 }
startInit(uint32 numConsGuess,const SolverParams & params)207 void Solver::startInit(uint32 numConsGuess, const SolverParams& params) {
208 	assert(!lazyRem_ && decisionLevel() == 0);
209 	if (watches_.empty()) {
210 		assign_.trail.reserve(shared_->numVars() + 2);
211 		watches_.reserve((shared_->numVars() + 2)<<1);
212 		assign_.reserve(shared_->numVars() + 2);
213 	}
214 	updateVars();
215 	// pre-allocate some memory
216 	constraints_.reserve(numConsGuess/2);
217 	levels_.reserve(25);
218 	if (undoHead_ == 0)  {
219 		for (uint32 i = 0; i != 25; ++i) {
220 			undoFree(new ConstraintDB(10));
221 		}
222 	}
223 	if (!popRootLevel(rootLevel())) { return; }
224 	if (!strategy_.hasConfig) {
225 		uint32 id           = this->id();
226 		uint32 hId          = strategy_.heuId; // remember active heuristic
227 		strategy_           = params;
228 		strategy_.id        = id; // keep id
229 		strategy_.hasConfig = 1;  // strategy is now "up to date"
230 		if      (!params.ccMinRec)  { delete ccMin_; ccMin_ = 0; }
231 		else if (!ccMin_)           { ccMin_ = new CCMinRecursive; }
232 		if (id == params.id || !shared_->seedSolvers()) {
233 			rng.srand(params.seed);
234 		}
235 		else {
236 			RNG x(14182940); for (uint32 i = 0; i != id; ++i) { x.rand(); }
237 			rng.srand(x.seed());
238 		}
239 		if (hId != params.heuId) { // heuristic has changed
240 			resetHeuristic(this);
241 		}
242 		else if (heuristic_.is_owner()) {
243 			heuristic_->setConfig(params.heuristic);
244 		}
245 	}
246 	if (heuristic_.get() == &null_heuristic_g) {
247 		heuristic_.reset(shared_->configuration()->heuristic(id()));
248 	}
249 	postHead_ = &sent_list; // disable post propagators during setup
250 	heuristic_->startInit(*this);
251 }
252 
updateVars()253 void Solver::updateVars() {
254 	if (numVars() > shared_->numVars()) {
255 		popVars(numVars() - shared_->numVars(), false, 0);
256 	}
257 	else {
258 		assign_.resize(shared_->numVars() + 1);
259 		watches_.resize(assign_.numVars()<<1);
260 	}
261 }
262 
cloneDB(const ConstraintDB & db)263 bool Solver::cloneDB(const ConstraintDB& db) {
264 	while (dbIdx_ < (uint32)db.size() && !hasConflict()) {
265 		if (Constraint* c = db[dbIdx_++]->cloneAttach(*this)) {
266 			constraints_.push_back(c);
267 		}
268 	}
269 	return !hasConflict();
270 }
preparePost()271 bool Solver::preparePost() {
272 	if (hasConflict()) { return false; }
273 	if (initPost_ == 0){
274 		initPost_ = 1;
275 		FOR_EACH_POST(x, post_.head()) {
276 			if (!x->init(*this)) { return false; }
277 		}
278 	}
279 	return shared_->configuration()->addPost(*this);
280 }
281 
endInit()282 bool Solver::endInit() {
283 	if (hasConflict()) { return false; }
284 	heuristic_->endInit(*this);
285 	if (strategy_.signFix) {
286 		for (Var v = 1; v <= numVars(); ++v) {
287 			Literal x = DecisionHeuristic::selectLiteral(*this, v, 0);
288 			setPref(v, ValueSet::user_value, x.sign() ? value_false : value_true);
289 		}
290 	}
291 	postHead_ = post_.head(); // enable all post propagators
292 	return propagate() && simplify();
293 }
294 
endStep(uint32 top,const SolverParams & params)295 bool Solver::endStep(uint32 top, const SolverParams& params) {
296 	initPost_ = 0; // defer calls to PostPropagator::init()
297 	if (!popRootLevel(rootLevel())) { return false; }
298 	popAuxVar();
299 	Literal x = shared_->stepLiteral();
300 	top = std::min(top, (uint32)lastSimp_);
301 	if (PostPropagator* pp = getPost(PostPropagator::priority_reserved_look)) {
302 		pp->destroy(this, true);
303 	}
304 	if ((value(x.var()) != value_free || force(~x)) && simplify() && this != shared_->master() && shared_->ok()) {
305 		Solver& m = *shared_->master();
306 		for (uint32 end = (uint32)assign_.trail.size(); top < end; ++top) {
307 			Literal u = assign_.trail[top];
308 			if (u.var() != x.var() && !m.force(u)) { break; }
309 		}
310 	}
311 	if (params.forgetLearnts())   { reduceLearnts(1.0f); }
312 	if (params.forgetHeuristic()) { resetHeuristic(this); }
313 	if (params.forgetSigns())     { resetPrefs(); }
314 	if (params.forgetActivities()){ resetLearntActivities(); }
315 	return true;
316 }
317 
add(Constraint * c)318 void Solver::add(Constraint* c) {
319 	constraints_.push_back(c);
320 }
add(const ClauseRep & c,bool isNew)321 bool Solver::add(const ClauseRep& c, bool isNew) {
322 	typedef ShortImplicationsGraph::ImpType ImpType;
323 	if (c.prep == 0) {
324 		return ClauseCreator::create(*this, c, ClauseCreator::clause_force_simplify).ok();
325 	}
326 	int added = 0;
327 	if (c.size > 1) {
328 		if (allowImplicit(c)) { added = shared_->addImp(static_cast<ImpType>(c.size), c.lits, c.info.type()); }
329 		else                  { return ClauseCreator::create(*this, c, ClauseCreator::clause_explicit).ok(); }
330 	}
331 	else {
332 		Literal u = c.size ? c.lits[0] : lit_false();
333 		uint32  ts= sizeVec(trail());
334 		force(u);
335 		added     = int(ts != trail().size());
336 	}
337 	if (added > 0 && isNew && c.info.learnt()) {
338 		stats.addLearnt(c.size, c.info.type());
339 		distribute(c.lits, c.size, c.info);
340 	}
341 	return !hasConflict();
342 }
addPost(PostPropagator * p,bool init)343 bool Solver::addPost(PostPropagator* p, bool init) {
344 	post_.add(p);
345 	return !init || p->init(*this);
346 }
addPost(PostPropagator * p)347 bool Solver::addPost(PostPropagator* p)   { return addPost(p, initPost_ != 0); }
removePost(PostPropagator * p)348 void Solver::removePost(PostPropagator* p){ post_.remove(p); }
getPost(uint32 prio) const349 PostPropagator* Solver::getPost(uint32 prio) const { return post_.find(prio); }
receive(SharedLiterals ** out,uint32 maxOut) const350 uint32 Solver::receive(SharedLiterals** out, uint32 maxOut) const {
351 	if (shared_->distributor.get()) {
352 		return shared_->distributor->receive(*this, out, maxOut);
353 	}
354 	return 0;
355 }
distribute(const Literal * lits,uint32 size,const ConstraintInfo & extra)356 SharedLiterals* Solver::distribute(const Literal* lits, uint32 size, const ConstraintInfo& extra) {
357 	if (shared_->distributor.get() && !extra.aux() && (size <= 3 || shared_->distributor->isCandidate(size, extra.lbd(), extra.type()))) {
358 		uint32 initialRefs = shared_->concurrency() - (size <= ClauseHead::MAX_SHORT_LEN || !shared_->physicalShare(extra.type()));
359 		SharedLiterals* x  = SharedLiterals::newShareable(lits, size, extra.type(), initialRefs);
360 		shared_->distributor->publish(*this, x);
361 		stats.addDistributed(extra.lbd(), extra.type());
362 		return initialRefs == shared_->concurrency() ? x : 0;
363 	}
364 	return 0;
365 }
setEnumerationConstraint(Constraint * c)366 void Solver::setEnumerationConstraint(Constraint* c) {
367 	if (enum_) enum_->destroy(this, true);
368 	enum_ = c;
369 }
370 
numConstraints() const371 uint32 Solver::numConstraints() const {
372 	return static_cast<uint32>(constraints_.size())
373 		+ (shared_ ? shared_->numBinary()+shared_->numTernary() : 0);
374 }
375 
pushAuxVar()376 Var Solver::pushAuxVar() {
377 	assert(!lazyRem_);
378 	Var aux = assign_.addVar();
379 	setPref(aux, ValueSet::def_value, value_false);
380 	watches_.insert(watches_.end(), 2, WatchList());
381 	heuristic_->updateVar(*this, aux, 1);
382 	return aux;
383 }
384 
acquireProblemVar(Var var)385 void Solver::acquireProblemVar(Var var) {
386 	if (validVar(var) || shared_->frozen() || numProblemVars() <= numVars() || !shared_->ok())
387 		return;
388 	shared_->startAddConstraints();
389 }
390 
popAuxVar(uint32 num,ConstraintDB * auxCons)391 void Solver::popAuxVar(uint32 num, ConstraintDB* auxCons) {
392 	num = numVars() >= shared_->numVars() ? std::min(numVars() - shared_->numVars(), num) : 0;
393 	if (!num) { return; }
394 	shared_->report("removing aux vars", this);
395 	Dirty dirty;
396 	lazyRem_ = &dirty;
397 	popVars(num, true, auxCons);
398 	lazyRem_ = 0;
399 	shared_->report("removing aux watches", this);
400 	dirty.cleanup(watches_, levels_);
401 }
popVars(uint32 num,bool popLearnt,ConstraintDB * popAux)402 Literal Solver::popVars(uint32 num, bool popLearnt, ConstraintDB* popAux) {
403 	Literal pop = posLit(assign_.numVars() - num);
404 	uint32  dl  = decisionLevel() + 1;
405 	for (ImpliedList::iterator it = impliedLits_.begin(); it != impliedLits_.end(); ++it) {
406 		if (!(it->lit < pop)) { dl = std::min(dl, it->level); }
407 	}
408 	for (Var v = pop.var(), end = pop.var()+num; v != end; ++v) {
409 		if (value(v) != value_free) { dl = std::min(dl, level(v)); }
410 	}
411 	// 1. remove aux vars from assignment and watch lists
412 	if (dl > rootLevel()) {
413 		undoUntil(dl-1, undo_pop_proj_level);
414 	}
415 	else {
416 		popRootLevel((rootLevel() - dl) + 1);
417 		if (dl == 0) { // top-level has aux vars - cleanup manually
418 			uint32 j = shared_->numUnary();
419 			uint32 nUnits = assign_.units(), nFront = assign_.front, nSimps = lastSimp_;
420 			for (uint32 i = j, end = sizeVec(assign_.trail), endUnits = nUnits, endFront = nFront, endSimps = lastSimp_; i != end; ++i) {
421 				if (assign_.trail[i] < pop) { assign_.trail[j++] = assign_.trail[i]; }
422 				else {
423 					nUnits -= (i < endUnits);
424 					nFront -= (i < endFront);
425 					nSimps -= (i < endSimps);
426 				}
427 			}
428 			shrinkVecTo(assign_.trail, j);
429 			assign_.front = nFront;
430 			assign_.setUnits(nUnits);
431 			lastSimp_ = nSimps;
432 		}
433 	}
434 	for (uint32 n = num; n--;) {
435 		watches_.back().clear(true);
436 		watches_.pop_back();
437 		watches_.back().clear(true);
438 		watches_.pop_back();
439 	}
440 	// 2. remove learnt constraints over aux
441 	if (popLearnt) {
442 		shared_->report("removing aux constraints", this);
443 		ConstraintDB::size_type i, j, end = learnts_.size();
444 		LitVec cc;
445 		for (i = j = 0; i != end; ++i) {
446 			learnts_[j++] = learnts_[i];
447 			ClauseHead* c = learnts_[i]->clause();
448 			if (c && c->aux()) {
449 				cc.clear();
450 				c->toLits(cc);
451 				if (std::find_if(cc.begin(), cc.end(), std::not1(std::bind2nd(std::less<Literal>(), pop))) != cc.end()) {
452 					c->destroy(this, true);
453 					--j;
454 				}
455 			}
456 		}
457 		learnts_.erase(learnts_.begin()+j, learnts_.end());
458 	}
459 	if (popAux) { destroyDB(*popAux); }
460 	// 3. remove vars from solver and heuristic
461 	assign_.resize(assign_.numVars()-num);
462 	if (!validVar(tag_.var())) { tag_ = lit_true(); }
463 	heuristic_->updateVar(*this, pop.var(), num);
464 	return pop;
465 }
466 
pushRoot(const LitVec & path)467 bool Solver::pushRoot(const LitVec& path) {
468 	// make sure we are on the current root level
469 	if (!popRootLevel(0) || !simplify() || !propagate()) { return false; }
470 	// push path
471 	stats.addPath(path.size());
472 	for (LitVec::const_iterator it = path.begin(), end = path.end(); it != end; ++it) {
473 		if (!pushRoot(*it)) { return false; }
474 	}
475 	ccInfo_.setActivity(1);
476 	return true;
477 }
478 
pushRoot(Literal x)479 bool Solver::pushRoot(Literal x) {
480 	if (hasConflict())                 { return false; }
481 	if (decisionLevel()!= rootLevel()) { popRootLevel(0);  }
482 	if (queueSize() && !propagate())   { return false;    }
483 	if (value(x.var()) != value_free)  { return isTrue(x);}
484 	assume(x); --stats.choices;
485 	pushRootLevel();
486 	return propagate();
487 }
488 
popRootLevel(uint32 n,LitVec * popped,bool aux)489 bool Solver::popRootLevel(uint32 n, LitVec* popped, bool aux)  {
490 	clearStopConflict();
491 	uint32 newRoot = levels_.root - std::min(n, rootLevel());
492 	if (popped && newRoot < rootLevel()) {
493 		for (uint32 i = newRoot+1; i <= rootLevel(); ++i) {
494 			Literal x = decision(i);
495 			if (aux || !auxVar(x.var())) { popped->push_back(x); }
496 		}
497 	}
498 	if (n) { ccInfo_.setActivity(1); }
499 	levels_.root = newRoot;
500 	levels_.flip = rootLevel();
501 	levels_.mode = 0;
502 	impliedLits_.front = 0;
503 	bool tagActive     = isTrue(tagLiteral());
504 	// go back to new root level and re-assert still implied literals
505 	undoUntil(rootLevel(), undo_pop_proj_level);
506 	if (tagActive && !isTrue(tagLiteral())) {
507 		removeConditional();
508 	}
509 	return !hasConflict();
510 }
511 
clearAssumptions()512 bool Solver::clearAssumptions()  {
513 	return popRootLevel(rootLevel())
514 		&& simplify();
515 }
516 
clearStopConflict()517 void Solver::clearStopConflict() {
518 	if (hasStopConflict()) {
519 		levels_.root  = conflict_[1].rep();
520 		levels_.flip  = conflict_[2].rep();
521 		assign_.front = conflict_[3].rep();
522 		conflict_.clear();
523 	}
524 }
525 
setStopConflict()526 void Solver::setStopConflict() {
527 	if (!hasConflict()) {
528 		// we use the nogood {FALSE} to represent the unrecoverable conflict -
529 		// note that {FALSE} can otherwise never be a violated nogood because
530 		// TRUE is always true in every solver
531 		conflict_.push_back(lit_false());
532 		// remember the current root-level
533 		conflict_.push_back(Literal::fromRep(rootLevel()));
534 		// remember the current bt-level
535 		conflict_.push_back(Literal::fromRep(backtrackLevel()));
536 		// remember the current propagation queue
537 		conflict_.push_back(Literal::fromRep(assign_.front));
538 	}
539 	// artificially increase root level -
540 	// this way, the solver is prevented from resolving the conflict
541 	pushRootLevel(decisionLevel());
542 }
543 
copyGuidingPath(LitVec & gpOut)544 void Solver::copyGuidingPath(LitVec& gpOut) {
545 	uint32 aux = rootLevel()+1;
546 	gpOut.clear();
547 	for (uint32 i = 1, end = rootLevel()+1; i != end; ++i) {
548 		Literal x = decision(i);
549 		if      (!auxVar(x.var())) { gpOut.push_back(x); }
550 		else if (i < aux)          { aux = i; }
551 	}
552 	for (ImpliedList::iterator it = impliedLits_.begin(); it != impliedLits_.end(); ++it) {
553 		if (it->level <= rootLevel() && (it->ante.ante().isNull() || it->level < aux) && !auxVar(it->lit.var())) {
554 			gpOut.push_back(it->lit);
555 		}
556 	}
557 }
splittable() const558 bool Solver::splittable() const {
559 	if (decisionLevel() == rootLevel() || frozenLevel(rootLevel()+1)) { return false; }
560 	if (numAuxVars()) { // check if gp would contain solver local aux var
561 		uint32 minAux = rootLevel() + 2;
562 		for (uint32 i = 1; i != minAux; ++i) {
563 			if (auxVar(decision(i).var()) && decision(i) != tag_) { return false; }
564 		}
565 		for (ImpliedList::iterator it = impliedLits_.begin(); it != impliedLits_.end(); ++it) {
566 			if (it->ante.ante().isNull() && it->level < minAux && auxVar(it->lit.var()) && it->lit != tag_) { return false; }
567 		}
568 	}
569 	return true;
570 }
split(LitVec & out)571 bool Solver::split(LitVec& out) {
572 	if (!splittable()) { return false; }
573 	copyGuidingPath(out);
574 	pushRootLevel();
575 	out.push_back(~decision(rootLevel()));
576 	stats.addSplit();
577 	return true;
578 }
579 /////////////////////////////////////////////////////////////////////////////////////////
580 // Solver: Watch management
581 ////////////////////////////////////////////////////////////////////////////////////////
numWatches(Literal p) const582 uint32 Solver::numWatches(Literal p) const {
583 	assert( validVar(p.var()) );
584 	if (!validWatch(p)) return 0;
585 	uint32 n = static_cast<uint32>(watches_[p.id()].size());
586 	if (!auxVar(p.var())){
587 		n += shared_->shortImplications().numEdges(p);
588 	}
589 	return n;
590 }
591 
hasWatch(Literal p,Constraint * c) const592 bool Solver::hasWatch(Literal p, Constraint* c) const {
593 	return getWatch(p, c) != 0;
594 }
595 
hasWatch(Literal p,ClauseHead * h) const596 bool Solver::hasWatch(Literal p, ClauseHead* h) const {
597 	if (!validWatch(p)) return false;
598 	const WatchList& pList = watches_[p.id()];
599 	return !pList.empty() && std::find_if(pList.left_begin(), pList.left_end(), ClauseWatch::EqHead(h)) != pList.left_end();
600 }
601 
getWatch(Literal p,Constraint * c) const602 GenericWatch* Solver::getWatch(Literal p, Constraint* c) const {
603 	if (!validWatch(p)) return 0;
604 	const WatchList& pList = watches_[p.id()];
605 	WatchList::const_right_iterator it = std::find_if(pList.right_begin(), pList.right_end(), GenericWatch::EqConstraint(c));
606 	return it != pList.right_end()
607 		? &const_cast<GenericWatch&>(*it)
608 		: 0;
609 }
610 
removeWatch(const Literal & p,Constraint * c)611 void Solver::removeWatch(const Literal& p, Constraint* c) {
612 	if (!validWatch(p)) { return; }
613 	WatchList& pList = watches_[p.id()];
614 	if (!lazyRem_ || !lazyRem_->add(p, pList, c)) {
615 		pList.erase_right(std::find_if(pList.right_begin(), pList.right_end(), GenericWatch::EqConstraint(c)));
616 	}
617 }
618 
removeWatch(const Literal & p,ClauseHead * h)619 void Solver::removeWatch(const Literal& p, ClauseHead* h) {
620 	if (!validWatch(p)) { return; }
621 	WatchList& pList = watches_[p.id()];
622 	if (!lazyRem_ || !lazyRem_->add(p, pList, h)) {
623 		pList.erase_left(std::find_if(pList.left_begin(), pList.left_end(), ClauseWatch::EqHead(h)));
624 	}
625 }
626 
removeUndoWatch(uint32 dl,Constraint * c)627 bool Solver::removeUndoWatch(uint32 dl, Constraint* c) {
628 	assert(dl != 0 && dl <= decisionLevel() );
629 	if (levels_[dl-1].undo) {
630 		ConstraintDB& uList = *levels_[dl-1].undo;
631 		if (!lazyRem_ || !lazyRem_->add(dl - 1, uList, c)) {
632 			ConstraintDB::iterator it = std::find(uList.begin(), uList.end(), c);
633 			if (it != uList.end()) {
634 				*it = uList.back();
635 				uList.pop_back();
636 				return true;
637 			}
638 		}
639 	}
640 	return false;
641 }
destroyDB(ConstraintDB & db)642 void Solver::destroyDB(ConstraintDB& db) {
643 	if (!db.empty()) {
644 		Dirty dirty;
645 		if (!lazyRem_) { lazyRem_ = &dirty; }
646 		for (ConstraintDB::const_iterator it = db.begin(), end = db.end(); it != end; ++it) {
647 			(*it)->destroy(this, true);
648 		}
649 		db.clear();
650 		if (lazyRem_ == &dirty) {
651 			lazyRem_ = 0;
652 			dirty.cleanup(watches_, levels_);
653 		}
654 	}
655 }
656 /////////////////////////////////////////////////////////////////////////////////////////
657 // Solver: Basic DPLL-functions
658 ////////////////////////////////////////////////////////////////////////////////////////
659 
660 // removes all satisfied binary and ternary clauses as well
661 // as all constraints for which Constraint::simplify returned true.
simplify()662 bool Solver::simplify() {
663 	if (decisionLevel() != 0) return true;
664 	if (hasConflict())        return false;
665 	if (lastSimp_ != (uint32)assign_.trail.size()) {
666 		uint32 old = lastSimp_;
667 		if (!simplifySAT()) { return false; }
668 		assert(lastSimp_ == (uint32)assign_.trail.size());
669 		heuristic_->simplify(*this, old);
670 	}
671 	if (shufSimp_) { simplifySAT(); }
672 	return true;
673 }
pushTagVar(bool pushToRoot)674 Var  Solver::pushTagVar(bool pushToRoot) {
675 	if (isSentinel(tag_)) { tag_ = posLit(pushAuxVar()); }
676 	if (pushToRoot)       { pushRoot(tag_); }
677 	return tag_.var();
678 }
removeConditional()679 void Solver::removeConditional() {
680 	Literal p = ~tagLiteral();
681 	if (!isSentinel(p)) {
682 		ConstraintDB::size_type i, j, end = learnts_.size();
683 		for (i = j = 0; i != end; ++i) {
684 			ClauseHead* c = learnts_[i]->clause();
685 			if (!c || !c->tagged()) {
686 				learnts_[j++] = learnts_[i];
687 			}
688 			else {
689 				c->destroy(this, true);
690 			}
691 		}
692 		learnts_.erase(learnts_.begin()+j, learnts_.end());
693 	}
694 }
695 
strengthenConditional()696 void Solver::strengthenConditional() {
697 	Literal p = ~tagLiteral();
698 	if (!isSentinel(p)) {
699 		ConstraintDB::size_type i, j, end = learnts_.size();
700 		for (i = j = 0; i != end; ++i) {
701 			ClauseHead* c = learnts_[i]->clause();
702 			if (!c || !c->tagged() || !c->strengthen(*this, p, true).second) {
703 				learnts_[j++] = learnts_[i];
704 			}
705 			else {
706 				assert((decisionLevel() == rootLevel() || !c->locked(*this)) && "Solver::strengthenConditional(): must not remove locked constraint!");
707 				c->destroy(this, false);
708 			}
709 		}
710 		learnts_.erase(learnts_.begin()+j, learnts_.end());
711 	}
712 }
713 
simplifySAT()714 bool Solver::simplifySAT() {
715 	if (queueSize() > 0 && !propagate()) {
716 		return false;
717 	}
718 	assert(assign_.qEmpty());
719 	uint32 start  = lastSimp_;
720 	assign_.front = start;
721 	lastSimp_     = (uint32)assign_.trail.size();
722 	for (Literal p; !assign_.qEmpty(); ) {
723 		p = assign_.qPop();
724 		releaseVec(watches_[p.id()]);
725 		releaseVec(watches_[(~p).id()]);
726 	}
727 	bool shuffle = shufSimp_ != 0;
728 	shufSimp_    = 0;
729 	if (shuffle) {
730 		std::random_shuffle(constraints_.begin(), constraints_.end(), rng);
731 		std::random_shuffle(learnts_.begin(), learnts_.end(), rng);
732 	}
733 	if (isMaster()) { shared_->simplify(start, shuffle); }
734 	else            { simplifyDB(*this, constraints_, shuffle); }
735 	simplifyDB(*this, learnts_, shuffle);
736 	FOR_EACH_POST(x, postHead_) {
737 		if (x->simplify(*this, shuffle)) {
738 			post_.remove(x);
739 			x->destroy(this, false);
740 		}
741 	}
742 	if (enum_ && enum_->simplify(*this, shuffle)) {
743 		enum_->destroy(this, false);
744 		enum_ = 0;
745 	}
746 	return true;
747 }
748 
setConflict(Literal p,const Antecedent & a,uint32 data)749 void Solver::setConflict(Literal p, const Antecedent& a, uint32 data) {
750 	++stats.conflicts;
751 	conflict_.push_back(~p);
752 	if (searchMode() != SolverStrategies::no_learning && !a.isNull()) {
753 		if (data == UINT32_MAX) {
754 			a.reason(*this, p, conflict_);
755 		}
756 		else {
757 			// temporarily replace old data with new data
758 			uint32 saved = assign_.data(p.var());
759 			assign_.setData(p.var(), data);
760 			// extract conflict using new data
761 			a.reason(*this, p, conflict_);
762 			// restore old data
763 			assign_.setData(p.var(), saved);
764 		}
765 	}
766 }
force(const ImpliedLiteral & p)767 bool Solver::force(const ImpliedLiteral& p) {
768 	// Already implied?
769 	if (isTrue(p.lit)) {
770 		if (level(p.lit.var()) <= p.level) { return true; }
771 		if (ImpliedLiteral* x = impliedLits_.find(p.lit)) {
772 			if (x->level > p.level) {
773 				*x = p;
774 				setReason(p.lit, p.ante.ante(), p.ante.data());
775 			}
776 			return true;
777 		}
778 	}
779 	if (undoUntil(p.level) != p.level) {
780 		// Logically the implication is on level p.level.
781 		// Store enough information so that p can be re-assigned once we backtrack.
782 		impliedLits_.add(decisionLevel(), p);
783 	}
784 	return (isTrue(p.lit) && setReason(p.lit, p.ante.ante(), p.ante.data())) || force(p.lit, p.ante.ante(), p.ante.data());
785 }
786 
assume(const Literal & p)787 bool Solver::assume(const Literal& p) {
788 	if (value(p.var()) == value_free) {
789 		assert(decisionLevel() != assign_.maxLevel());
790 		++stats.choices;
791 		levels_.push_back(DLevel(numAssignedVars(), 0));
792 		return assign_.assign(p, decisionLevel(), Antecedent());
793 	}
794 	return isTrue(p);
795 }
796 
cancelPropagation()797 void Solver::cancelPropagation() {
798 	assign_.qReset();
799 	for (PostPropagator* r = *postHead_; r; r = r->next) { r->reset(); }
800 }
801 
propagate()802 bool Solver::propagate() {
803 	if (unitPropagate() && postPropagate(0)) {
804 		assert(queueSize() == 0);
805 		return true;
806 	}
807 	cancelPropagation();
808 	return false;
809 }
810 
propagateUntil(PostPropagator * p)811 bool Solver::propagateUntil(PostPropagator* p) {
812 	assert((!p || *postHead_) && "OP not allowed during init!");
813 	return unitPropagate() && (p == *postHead_ || postPropagate(p));
814 }
815 
propagate(Solver & s,Literal p,uint32 &)816 Constraint::PropResult ClauseHead::propagate(Solver& s, Literal p, uint32&) {
817 	Literal* head = head_;
818 	uint32 wLit   = (head[1] == ~p); // pos of false watched literal
819 	if (s.isTrue(head[1-wLit])) {
820 		return Constraint::PropResult(true, true);
821 	}
822 	else if (!s.isFalse(head[2])) {
823 		assert(!isSentinel(head[2]) && "Invalid ClauseHead!");
824 		head[wLit] = head[2];
825 		head[2]    = ~p;
826 		s.addWatch(~head[wLit], ClauseWatch(this));
827 		return Constraint::PropResult(true, false);
828 	}
829 	else if (updateWatch(s, wLit)) {
830 		assert(!s.isFalse(head_[wLit]));
831 		s.addWatch(~head[wLit], ClauseWatch(this));
832 		return Constraint::PropResult(true, false);
833 	}
834 	return PropResult(s.force(head_[1^wLit], this), true);
835 }
836 
unitPropagate()837 bool Solver::unitPropagate() {
838 	assert(!hasConflict());
839 	Literal p, q, r;
840 	uint32 idx, ignore, DL = decisionLevel();
841 	const ShortImplicationsGraph& btig = shared_->shortImplications();
842 	const uint32 maxIdx = btig.size();
843 	while ( !assign_.qEmpty() ) {
844 		p             = assign_.qPop();
845 		idx           = p.id();
846 		WatchList& wl = watches_[idx];
847 		// first: short clause BCP
848 		if (idx < maxIdx && !btig.propagate(*this, p)) {
849 			return false;
850 		}
851 		// second: clause BCP
852 		if (wl.left_size() != 0) {
853 			WatchList::left_iterator it, end, j = wl.left_begin();
854 			Constraint::PropResult res;
855 			for (it = wl.left_begin(), end = wl.left_end();  it != end;  ) {
856 				ClauseWatch& w = *it++;
857 				res = w.head->ClauseHead::propagate(*this, p, ignore);
858 				if (res.keepWatch) {
859 					*j++ = w;
860 				}
861 				if (!res.ok) {
862 					wl.shrink_left(std::copy(it, end, j));
863 					return false;
864 				}
865 			}
866 			wl.shrink_left(j);
867 		}
868 		// third: general constraint BCP
869 		if (wl.right_size() != 0) {
870 			WatchList::right_iterator it, end, j = wl.right_begin();
871 			Constraint::PropResult res;
872 			for (it = wl.right_begin(), end = wl.right_end(); it != end; ) {
873 				GenericWatch& w = *it++;
874 				res = w.propagate(*this, p);
875 				if (res.keepWatch) {
876 					*j++ = w;
877 				}
878 				if (!res.ok) {
879 					wl.shrink_right(std::copy(it, end, j));
880 					return false;
881 				}
882 			}
883 			wl.shrink_right(j);
884 		}
885 	}
886 	return DL || assign_.markUnits();
887 }
888 
postPropagate(PostPropagator * stop)889 bool Solver::postPropagate(PostPropagator* stop) {
890 	for (PostPropagator** r = postHead_, *t; *r != stop;) {
891 		t = *r;
892 		if (!t->propagateFixpoint(*this, stop)) { return false; }
893 		assert(queueSize() == 0);
894 		if (t == *r) { r = &t->next; }
895 		// else: t was removed during propagate
896 	}
897 	return true;
898 }
899 
test(Literal p,PostPropagator * c)900 bool Solver::test(Literal p, PostPropagator* c) {
901 	assert(value(p.var()) == value_free && !hasConflict());
902 	assume(p); --stats.choices;
903 	uint32 pLevel = decisionLevel();
904 	freezeLevel(pLevel); // can't split-off this level
905 	if (propagateUntil(c)) {
906 		assert(decisionLevel() == pLevel && "Invalid PostPropagators");
907 		if (c) c->undoLevel(*this);
908 		undoUntil(pLevel-1);
909 		return true;
910 	}
911 	assert(decisionLevel() == pLevel && "Invalid PostPropagators");
912 	unfreezeLevel(pLevel);
913 	cancelPropagation();
914 	return false;
915 }
916 
resolveConflict()917 bool Solver::resolveConflict() {
918 	assert(hasConflict());
919 	if (decisionLevel() > rootLevel()) {
920 		if (decisionLevel() != backtrackLevel() && searchMode() != SolverStrategies::no_learning) {
921 			uint32 uipLevel = analyzeConflict();
922 			stats.addConflict(decisionLevel(), uipLevel, backtrackLevel(), ccInfo_.lbd());
923 			if (shared_->reportMode()) {
924 				sharedContext()->report(NewConflictEvent(*this, cc_, ccInfo_));
925 			}
926 			undoUntil( uipLevel );
927 			return ClauseCreator::create(*this, cc_, ClauseCreator::clause_no_prepare, ccInfo_);
928 		}
929 		else {
930 			return backtrack();
931 		}
932 	}
933 	return false;
934 }
935 
backtrack()936 bool Solver::backtrack() {
937 	Literal lastChoiceInverted;
938 	do {
939 		if (decisionLevel() == rootLevel()) {
940 			setStopConflict();
941 			return false;
942 		}
943 		lastChoiceInverted = ~decision(decisionLevel());
944 		undoUntil(decisionLevel() - 1, undo_pop_proj_level);
945 		setBacktrackLevel(decisionLevel(), undo_pop_bt_level);
946 	} while (hasConflict() || !force(lastChoiceInverted, 0));
947 	// remember flipped literal for copyGuidingPath()
948 	impliedLits_.add(decisionLevel(), ImpliedLiteral(lastChoiceInverted, decisionLevel(), 0));
949 	return true;
950 }
951 
assign(Solver & s)952 bool ImpliedList::assign(Solver& s) {
953 	assert(front <= lits.size());
954 	bool ok             = !s.hasConflict();
955 	const uint32 DL     = s.decisionLevel();
956 	VecType::iterator j = lits.begin() + front;
957 	for (VecType::iterator it = j, end = lits.end(); it != end; ++it) {
958 		if(it->level <= DL) {
959 			ok = ok && s.force(it->lit, it->ante.ante(), it->ante.data());
960 			if (it->level < DL || it->ante.ante().isNull()) { *j++ = *it; }
961 		}
962 	}
963 	lits.erase(j, lits.end());
964 	level = DL * uint32(!lits.empty());
965 	front = level > s.rootLevel() ? front  : sizeVec(lits);
966 	return ok;
967 }
isUndoLevel() const968 bool Solver::isUndoLevel() const {
969 	return decisionLevel() > backtrackLevel();
970 }
undoUntilImpl(uint32 level,bool forceSave)971 uint32 Solver::undoUntilImpl(uint32 level, bool forceSave) {
972 	level      = std::max( level, backtrackLevel() );
973 	if (level >= decisionLevel()) { return decisionLevel(); }
974 	uint32& n  = (levels_.jump = decisionLevel() - level);
975 	bool sp    = forceSave || (strategy_.saveProgress > 0 && ((uint32)strategy_.saveProgress) <= n);
976 	bool ok    = conflict_.empty() && levels_.back().freeze == 0;
977 	conflict_.clear();
978 	heuristic_->undoUntil( *this, levels_[level].trailPos);
979 	undoLevel(sp && ok);
980 	while (--n) { undoLevel(sp); }
981 	return level;
982 }
undoUntil(uint32 level,uint32 mode)983 uint32 Solver::undoUntil(uint32 level, uint32 mode) {
984 	assert(backtrackLevel() >= rootLevel());
985 	if (level < backtrackLevel() && mode >= levels_.mode) {
986 		levels_.flip = std::max(rootLevel(), level);
987 	}
988 	level = undoUntilImpl(level, (mode & undo_save_phases) != 0);
989 	if (impliedLits_.active(level)) {
990 		impliedLits_.assign(*this);
991 	}
992 	return level;
993 }
estimateBCP(const Literal & p,int rd) const994 uint32 Solver::estimateBCP(const Literal& p, int rd) const {
995 	if (value(p.var()) != value_free) return 0;
996 	LitVec::size_type first = assign_.assigned();
997 	LitVec::size_type i     = first;
998 	Solver& self            = const_cast<Solver&>(*this);
999 	self.assign_.setValue(p.var(), trueValue(p));
1000 	self.assign_.trail.push_back(p);
1001 	const ShortImplicationsGraph& btig = shared_->shortImplications();
1002 	const uint32 maxIdx = btig.size();
1003 	do {
1004 		Literal x = assign_.trail[i++];
1005 		if (x.id() < maxIdx && !btig.propagateBin(self.assign_, x, 0)) {
1006 			break;
1007 		}
1008 	} while (i < assign_.assigned() && rd-- != 0);
1009 	i = assign_.assigned()-first;
1010 	while (self.assign_.assigned() != first) {
1011 		self.assign_.undoLast();
1012 	}
1013 	return (uint32)i;
1014 }
1015 
inDegree(WeightLitVec & out)1016 uint32 Solver::inDegree(WeightLitVec& out) {
1017 	if (decisionLevel() == 0) { return 1; }
1018 	assert(!hasConflict());
1019 	out.reserve((numAssignedVars()-levelStart(1))/10);
1020 	uint32 maxIn = 1;
1021 	uint32 i = sizeVec(assign_.trail), stop = levelStart(1);
1022 	for (LitVec temp; i-- != stop; ) {
1023 		Literal x    = assign_.trail[i];
1024 		uint32  xLev = assign_.level(x.var());
1025 		uint32  xIn  = 0;
1026 		Antecedent xAnte = assign_.reason(x.var());
1027 		if (!xAnte.isNull() && xAnte.type() != Antecedent::Binary) {
1028 			xAnte.reason(*this, x, temp);
1029 			for (LitVec::const_iterator it = temp.begin(); it != temp.end(); ++it) {
1030 				xIn += level(it->var()) != xLev;
1031 			}
1032 			if (xIn) {
1033 				out.push_back(WeightLiteral(x, xIn));
1034 				maxIn = std::max(xIn, maxIn);
1035 			}
1036 			temp.clear();
1037 		}
1038 	}
1039 	return maxIn;
1040 }
1041 /////////////////////////////////////////////////////////////////////////////////////////
1042 // Solver: Private helper functions
1043 ////////////////////////////////////////////////////////////////////////////////////////
allocUndo(Constraint * c)1044 Solver::ConstraintDB* Solver::allocUndo(Constraint* c) {
1045 	if (undoHead_ == 0) {
1046 		return new ConstraintDB(1, c);
1047 	}
1048 	assert(undoHead_->size() == 1);
1049 	ConstraintDB* r = undoHead_;
1050 	undoHead_ = (ConstraintDB*)undoHead_->front();
1051 	r->clear();
1052 	r->push_back(c);
1053 	return r;
1054 }
undoFree(ConstraintDB * x)1055 void Solver::undoFree(ConstraintDB* x) {
1056 	// maintain a single-linked list of undo lists
1057 	x->clear();
1058 	x->push_back((Constraint*)undoHead_);
1059 	undoHead_ = x;
1060 }
1061 // removes the current decision level
undoLevel(bool sp)1062 void Solver::undoLevel(bool sp) {
1063 	assert(decisionLevel() != 0 && levels_.back().trailPos != assign_.trail.size() && "Decision Level must not be empty");
1064 	assign_.undoTrail(levels_.back().trailPos, sp);
1065 	if (levels_.back().undo) {
1066 		const ConstraintDB& undoList = *levels_.back().undo;
1067 		for (ConstraintDB::size_type i = 0, end = undoList.size(); i != end; ++i) {
1068 			undoList[i]->undoLevel(*this);
1069 		}
1070 		undoFree(levels_.back().undo);
1071 	}
1072 	levels_.pop_back();
1073 }
1074 
clause(const Antecedent & ante)1075 inline ClauseHead* clause(const Antecedent& ante) {
1076 	return ante.isNull() || ante.type() != Antecedent::Generic ? 0 : ante.constraint()->clause();
1077 }
1078 
resolveToFlagged(const LitVec & in,uint8 vf,LitVec & out,uint32 & outLbd) const1079 bool Solver::resolveToFlagged(const LitVec& in, uint8 vf, LitVec& out, uint32& outLbd) const {
1080 	return const_cast<Solver&>(*this).resolveToFlagged(in, vf, out, outLbd);
1081 }
resolveToFlagged(const LitVec & in,const uint8 vf,LitVec & out,uint32 & outLbd)1082 bool Solver::resolveToFlagged(const LitVec& in, const uint8 vf, LitVec& out, uint32& outLbd) {
1083 	const LitVec& trail = assign_.trail;
1084 	const LitVec* rhs   = &in;
1085 	LitVec temp; out.clear();
1086 	bool ok = true, first = true;
1087 	for (LitVec::size_type tp = trail.size(), resolve = 0;; first = false) {
1088 		Literal p; Var v;
1089 		for (LitVec::const_iterator it = rhs->begin(), end = rhs->end(); it != end; ++it) {
1090 			p = *it ^ first; v = p.var();
1091 			if (!seen(v)) {
1092 				markSeen(v);
1093 				if      (varInfo(v).hasAll(vf)) { markLevel(level(v)); out.push_back(~p); }
1094 				else if (!reason(p).isNull())   { ++resolve; }
1095 				else                            { clearSeen(v); ok = false; break; }
1096 			}
1097 		}
1098 		if (resolve-- == 0) { break; }
1099 		// find next literal to resolve
1100 		while (!seen(trail[--tp]) || varInfo(trail[tp].var()).hasAll(vf)) { ; }
1101 		clearSeen((p = trail[tp]).var());
1102 		reason(p, temp);
1103 		rhs = &temp;
1104 	}
1105 	LitVec::size_type outSize = out.size();
1106 	if (ok && !first) {
1107 		const uint32 ccAct = strategy_.ccMinKeepAct;
1108 		const uint32 antes = SolverStrategies::all_antes;
1109 		strategy_.ccMinKeepAct = 1;
1110 		if (ccMin_) { ccMinRecurseInit(*ccMin_); }
1111 		for (LitVec::size_type i = 0; i != outSize;) {
1112 			if (!ccRemovable(~out[i], antes, ccMin_)) { ++i; }
1113 			else {
1114 				std::swap(out[i], out[--outSize]);
1115 			}
1116 		}
1117 		strategy_.ccMinKeepAct = ccAct;
1118 	}
1119 	POTASSCO_ASSERT(!ok || outSize != 0, "Invalid empty clause - was %u!\n", out.size());
1120 	outLbd = 0;
1121 	for (uint32 i = 0, dl, root = 0; i != outSize; ++i) {
1122 		Var v = out[i].var();
1123 		dl    = level(v);
1124 		clearSeen(v);
1125 		if (dl && hasLevel(dl)) {
1126 			unmarkLevel(dl);
1127 			outLbd += (dl > rootLevel()) || (++root == 1);
1128 		}
1129 	}
1130 	for (Var v; outSize != out.size(); out.pop_back()) {
1131 		clearSeen(v = out.back().var());
1132 		unmarkLevel(level(v));
1133 	}
1134 	return ok;
1135 }
resolveToCore(LitVec & out)1136 void Solver::resolveToCore(LitVec& out) {
1137 	POTASSCO_REQUIRE(hasConflict() && !hasStopConflict(), "Function requires valid conflict");
1138 	cc_.clear();
1139 	std::swap(cc_, conflict_);
1140 	if (searchMode() == SolverStrategies::no_learning) {
1141 		for (uint32 i = 1, end = decisionLevel() + 1; i != end; ++i) { cc_.push_back(decision(i)); }
1142 	}
1143 	const LitVec& trail = assign_.trail;
1144 	const LitVec* r = &cc_;
1145 	// resolve all-last uip
1146 	for (uint32 marked = 0, tPos = (uint32)trail.size();; r = &conflict_) {
1147 		for (LitVec::const_iterator it = r->begin(), end = r->end(); it != end; ++it) {
1148 			if (!seen(it->var())) {
1149 				assert(level(it->var()) <= decisionLevel());
1150 				markSeen(it->var());
1151 				++marked;
1152 			}
1153 		}
1154 		if (marked-- == 0) { break; }
1155 		// search for the last marked literal
1156 		while (!seen(trail[--tPos].var())) { ; }
1157 		Literal p = trail[tPos];
1158 		uint32 dl = level(p.var());
1159 		assert(dl);
1160 		clearSeen(p.var());
1161 		conflict_.clear();
1162 		if      (!reason(p).isNull()) { reason(p).reason(*this, p, conflict_); }
1163 		else if (p == decision(dl))   { out.push_back(p); }
1164 	}
1165 	// restore original conflict
1166 	std::swap(cc_, conflict_);
1167 }
1168 
1169 // computes the First-UIP clause and stores it in cc_, where cc_[0] is the asserting literal (inverted UIP)
1170 // and cc_[1] is a literal from the asserting level (if > 0)
1171 // RETURN: asserting level of the derived conflict clause
analyzeConflict()1172 uint32 Solver::analyzeConflict() {
1173 	// must be called here, because we unassign vars during analyzeConflict
1174 	heuristic_->undoUntil( *this, levels_.back().trailPos );
1175 	uint32 onLevel  = 0;        // number of literals from the current DL in resolvent
1176 	uint32 resSize  = 0;        // size of current resolvent
1177 	Literal p;                  // literal to be resolved out next
1178 	cc_.assign(1, p);           // will later be replaced with asserting literal
1179 	Antecedent lhs, rhs, last;  // resolve operands
1180 	const bool doOtfs = strategy_.otfs > 0;
1181 	for (bumpAct_.clear();;) {
1182 		uint32 lhsSize = resSize;
1183 		uint32 rhsSize = 0;
1184 		heuristic_->updateReason(*this, conflict_, p);
1185 		for (LitVec::size_type i = 0; i != conflict_.size(); ++i) {
1186 			Literal& q = conflict_[i];
1187 			uint32 cl  = level(q.var());
1188 			rhsSize   += (cl != 0);
1189 			if (!seen(q.var())) {
1190 				++resSize;
1191 				assert(isTrue(q) && "Invalid literal in reason set!");
1192 				assert(cl > 0 && "Top-Level implication not marked!");
1193 				markSeen(q.var());
1194 				if (cl == decisionLevel()) {
1195 					++onLevel;
1196 				}
1197 				else {
1198 					cc_.push_back(~q);
1199 					markLevel(cl);
1200 				}
1201 			}
1202 		}
1203 		if (resSize != lhsSize) { lhs = 0; }
1204 		if (rhsSize != resSize) { rhs = 0; }
1205 		if (doOtfs && (!rhs.isNull() || !lhs.isNull())) {
1206 			// resolvent subsumes rhs and possibly also lhs
1207 			otfs(lhs, rhs, p, onLevel == 1);
1208 		}
1209 		assert(onLevel > 0 && "CONFLICT MUST BE ANALYZED ON CONFLICT LEVEL!");
1210 		// search for the last assigned literal that needs to be analyzed...
1211 		while (!seen(assign_.last().var())) {
1212 			assign_.undoLast();
1213 		}
1214 		p   = assign_.last();
1215 		rhs = reason(p);
1216 		clearSeen(p.var());
1217 		if (--onLevel == 0) {
1218 			break;
1219 		}
1220 		--resSize; // p will be resolved out next
1221 		last = rhs;
1222 		reason(p, conflict_);
1223 	}
1224 	cc_[0] = ~p; // store the 1-UIP
1225 	assert(decisionLevel() == level(cc_[0].var()));
1226 	ClauseHead* lastRes = 0;
1227 	if (strategy_.otfs > 1 || !lhs.isNull()) {
1228 		if (!lhs.isNull()) {
1229 			lastRes = clause(lhs);
1230 		}
1231 		else if (cc_.size() <= (conflict_.size()+1)) {
1232 			lastRes = clause(last);
1233 		}
1234 	}
1235 	if (strategy_.bumpVarAct && reason(p).learnt()) {
1236 		bumpAct_.push_back(WeightLiteral(p, reason(p).constraint()->activity().lbd()));
1237 	}
1238 	return simplifyConflictClause(cc_, ccInfo_, lastRes);
1239 }
1240 
otfs(Antecedent & lhs,const Antecedent & rhs,Literal p,bool final)1241 void Solver::otfs(Antecedent& lhs, const Antecedent& rhs, Literal p, bool final) {
1242 	ClauseHead* cLhs = clause(lhs), *cRhs = clause(rhs);
1243 	ClauseHead::BoolPair x;
1244 	if (cLhs) {
1245 		x = cLhs->strengthen(*this, ~p, !final);
1246 		if (!x.first || x.second) {
1247 			cLhs = !x.first ? 0 : otfsRemove(cLhs, 0);
1248 		}
1249 	}
1250 	lhs = cLhs;
1251 	if (cRhs) {
1252 		x = cRhs->strengthen(*this, p, !final);
1253 		if (!x.first || (x.second && otfsRemove(cRhs, 0) == 0)) {
1254 			if (x.first && reason(p) == cRhs) { setReason(p, 0); }
1255 			cRhs = 0;
1256 		}
1257 		if (cLhs && cRhs) {
1258 			// lhs and rhs are now equal - only one of them is needed
1259 			if (!cLhs->learnt()) {
1260 				std::swap(cLhs, cRhs);
1261 			}
1262 			otfsRemove(cLhs, 0);
1263 		}
1264 		lhs = cRhs;
1265 	}
1266 }
1267 
otfsRemove(ClauseHead * c,const LitVec * newC)1268 ClauseHead* Solver::otfsRemove(ClauseHead* c, const LitVec* newC) {
1269 	bool remStatic = !newC || (newC->size() <= 3 && shared_->allowImplicit(Constraint_t::Conflict));
1270 	if (c->learnt() || remStatic) {
1271 		ConstraintDB& db = (c->learnt() ? learnts_ : constraints_);
1272 		ConstraintDB::iterator it;
1273 		if ((it = std::find(db.begin(), db.end(), c)) != db.end()) {
1274 			if (isMaster() && &db == &constraints_) {
1275 				shared_->removeConstraint(static_cast<uint32>(it - db.begin()), true);
1276 			}
1277 			else {
1278 				db.erase(it);
1279 				c->destroy(this, true);
1280 			}
1281 			c = 0;
1282 		}
1283 	}
1284 	return c;
1285 }
1286 
1287 // minimizes the conflict clause in cc w.r.t selected strategies.
1288 // PRE:
1289 //  - cc is a valid conflict clause and cc[0] is the UIP-literal
1290 //  - all literals in cc except cc[0] are marked
1291 //  - all decision levels of literals in cc are marked
1292 //  - rhs is 0 or a clause that might be subsumed by cc
1293 // RETURN: finalizeConflictClause(cc, info)
simplifyConflictClause(LitVec & cc,ConstraintInfo & info,ClauseHead * rhs)1294 uint32 Solver::simplifyConflictClause(LitVec& cc, ConstraintInfo& info, ClauseHead* rhs) {
1295 	// 1. remove redundant literals from conflict clause
1296 	temp_.clear();
1297 	uint32 onAssert = ccMinimize(cc, temp_, strategy_.ccMinAntes, ccMin_);
1298 	uint32 jl       = cc.size() > 1 ? level(cc[1].var()) : 0;
1299 	// clear seen flags of removed literals - keep levels marked
1300 	for (LitVec::size_type x = 0, stop = temp_.size(); x != stop; ++x) {
1301 		clearSeen(temp_[x].var());
1302 	}
1303 	// 2. check for inverse arcs
1304 	if (onAssert == 1 && strategy_.reverseArcs > 0) {
1305 		uint32 maxN = (uint32)strategy_.reverseArcs;
1306 		if      (maxN > 2) maxN = UINT32_MAX;
1307 		else if (maxN > 1) maxN = static_cast<uint32>(cc.size() / 2);
1308 		markSeen(cc[0].var());
1309 		Antecedent ante = ccHasReverseArc(cc[1], jl, maxN);
1310 		if (!ante.isNull()) {
1311 			// resolve with inverse arc
1312 			conflict_.clear();
1313 			ante.reason(*this, ~cc[1], conflict_);
1314 			ccResolve(cc, 1, conflict_);
1315 		}
1316 		clearSeen(cc[0].var());
1317 	}
1318 	// 3. check if final clause subsumes rhs
1319 	if (rhs) {
1320 		conflict_.clear();
1321 		rhs->toLits(conflict_);
1322 		uint32 open   = (uint32)cc.size();
1323 		markSeen(cc[0].var());
1324 		for (LitVec::const_iterator it = conflict_.begin(), end = conflict_.end(); it != end && open; ++it) {
1325 			// NOTE: at this point the DB might not be fully simplified,
1326 			//       e.g. because of mt or lookahead, hence we must explicitly
1327 			//       check for literals assigned on DL 0
1328 			open -= level(it->var()) > 0 && seen(it->var());
1329 		}
1330 		rhs = open ? 0 : otfsRemove(rhs, &cc);
1331 		if (rhs) { // rhs is subsumed by cc but could not be removed.
1332 			// TODO: we could reuse rhs instead of learning cc
1333 			//       but this would complicate the calling code.
1334 			ClauseHead::BoolPair r(true, false);
1335 			if (cc_.size() < conflict_.size()) {
1336 				//     For now, we only try to strengthen rhs.
1337 				for (LitVec::const_iterator it = conflict_.begin(), end = conflict_.end(); it != end && r.first; ++it) {
1338 					if (!seen(it->var()) || level(it->var()) == 0) {
1339 						r = rhs->strengthen(*this, *it, false);
1340 					}
1341 				}
1342 				if (!r.first) { rhs = 0; }
1343 			}
1344 		}
1345 		clearSeen(cc[0].var());
1346 	}
1347 	// 4. finalize
1348 	uint32 repMode = cc.size() < std::max(strategy_.compress, decisionLevel()+1) ? 0 : strategy_.ccRepMode;
1349 	jl = finalizeConflictClause(cc, info, repMode);
1350 	// 5. bump vars implied by learnt constraints with small lbd
1351 	if (!bumpAct_.empty()) {
1352 		WeightLitVec::iterator j = bumpAct_.begin();
1353 		weight_t newLbd = info.lbd();
1354 		for (WeightLitVec::iterator it = bumpAct_.begin(), end = bumpAct_.end(); it != end; ++it) {
1355 			if (it->second < newLbd) {
1356 				it->second = 1 + (it->second <= 2);
1357 				*j++ = *it;
1358 			}
1359 		}
1360 		bumpAct_.erase(j, bumpAct_.end());
1361 		heuristic_->bump(*this, bumpAct_, 1.0);
1362 	}
1363 	bumpAct_.clear();
1364 	// 6. clear level flags of redundant literals
1365 	for (LitVec::size_type x = 0, stop = temp_.size(); x != stop; ++x) {
1366 		unmarkLevel(level(temp_[x].var()));
1367 	}
1368 	temp_.clear();
1369 	return jl;
1370 }
1371 
1372 // conflict clause minimization
1373 // PRE:
1374 //  - cc is an asserting clause and cc[0] is the asserting literal
1375 //  - all literals in cc are marked as seen
1376 //  -  if ccMin != 0, all decision levels of literals in cc are marked
1377 // POST:
1378 //  - redundant literals were added to removed
1379 //  - if (cc.size() > 1): cc[1] is a literal from the asserting level
1380 // RETURN
1381 //  - the number of literals from the asserting level
ccMinimize(LitVec & cc,LitVec & removed,uint32 antes,CCMinRecursive * ccMin)1382 uint32 Solver::ccMinimize(LitVec& cc, LitVec& removed, uint32 antes, CCMinRecursive* ccMin) {
1383 	if (ccMin) { ccMinRecurseInit(*ccMin); }
1384 	// skip the asserting literal
1385 	LitVec::size_type j = 1;
1386 	uint32 assertLevel  = 0;
1387 	uint32 assertPos    = 1;
1388 	uint32 onAssert     = 0;
1389 	uint32 varLevel     = 0;
1390 	for (LitVec::size_type i = 1; i != cc.size(); ++i) {
1391 		if (antes == SolverStrategies::no_antes || !ccRemovable(~cc[i], antes, ccMin)) {
1392 			if ( (varLevel = level(cc[i].var())) > assertLevel ) {
1393 				assertLevel = varLevel;
1394 				assertPos   = static_cast<uint32>(j);
1395 				onAssert    = 0;
1396 			}
1397 			onAssert += (varLevel == assertLevel);
1398 			cc[j++] = cc[i];
1399 		}
1400 		else {
1401 			removed.push_back(cc[i]);
1402 		}
1403 	}
1404 	cc.erase(cc.begin()+j, cc.end());
1405 	if (assertPos != 1) {
1406 		std::swap(cc[1], cc[assertPos]);
1407 	}
1408 	return onAssert;
1409 }
ccMinRecurseInit(CCMinRecursive & ccMin)1410 void Solver::ccMinRecurseInit(CCMinRecursive& ccMin) {
1411 	ccMin.open = incEpoch(numVars() + 1, 2) - 2;
1412 }
ccMinRecurse(CCMinRecursive & ccMin,Literal p) const1413 bool Solver::ccMinRecurse(CCMinRecursive& ccMin, Literal p) const {
1414 	CCMinRecursive::State st = ccMin.decodeState(epoch_[p.var()]);
1415 	if (st == CCMinRecursive::state_poison) { return false; }
1416 	if (st == CCMinRecursive::state_open)   { ccMin.push(p.unflag()); }
1417 	return true;
1418 }
1419 
1420 // returns true if p is redundant in current conflict clause
ccRemovable(Literal p,uint32 antes,CCMinRecursive * ccMin)1421 bool Solver::ccRemovable(Literal p, uint32 antes, CCMinRecursive* ccMin) {
1422 	const Antecedent& ante = reason(p);
1423 	if (ante.isNull() || !(antes <= (uint32)ante.type())) {
1424 		return false;
1425 	}
1426 	if (!ccMin) { return ante.minimize(*this, p, 0); }
1427 	// recursive minimization
1428 	assert(ccMin->todo.empty());
1429 	CCMinRecursive::State dfsState = CCMinRecursive::state_removable;
1430 	ccMin->push(p.unflag());
1431 	for (Literal x;; ) {
1432 		x = ccMin->pop();
1433 		assert(!seen(x.var()) || x == p);
1434 		if (x.flagged()) {
1435 			if (x == p) return dfsState == CCMinRecursive::state_removable;
1436 			epoch_[x.var()] = ccMin->encodeState(dfsState);
1437 		}
1438 		else if (dfsState != CCMinRecursive::state_poison) {
1439 			CCMinRecursive::State temp = ccMin->decodeState(epoch_[x.var()]);
1440 			if (temp == CCMinRecursive::state_open) {
1441 				assert(value(x.var()) != value_free && hasLevel(level(x.var())));
1442 				ccMin->push(x.flag());
1443 				const Antecedent& next = reason(x);
1444 				if (next.isNull() || !(antes <= (uint32)next.type()) || !next.minimize(*this, x, ccMin)) {
1445 					dfsState = CCMinRecursive::state_poison;
1446 				}
1447 			}
1448 			else if (temp == CCMinRecursive::state_poison) {
1449 				dfsState = temp;
1450 			}
1451 		}
1452 	}
1453 }
1454 
1455 // checks whether there is a valid "inverse arc" for the given literal p that can be used
1456 // to resolve p out of the current conflict clause
1457 // PRE:
1458 //  - all literals in the current conflict clause are marked
1459 //  - p is a literal of the current conflict clause and level(p) == maxLevel
1460 // RETURN
1461 //  - An antecedent that is an "inverse arc" for p or null if no such antecedent exists.
ccHasReverseArc(Literal p,uint32 maxLevel,uint32 maxNew)1462 Antecedent Solver::ccHasReverseArc(Literal p, uint32 maxLevel, uint32 maxNew) {
1463 	assert(seen(p.var()) && isFalse(p) && level(p.var()) == maxLevel);
1464 	const ShortImplicationsGraph& btig = shared_->shortImplications();
1465 	Antecedent ante;
1466 	if (p.id() < btig.size() && btig.reverseArc(*this, p, maxLevel, ante)) { return ante; }
1467 	WatchList& wl = watches_[p.id()];
1468 	for (WatchList::left_iterator it = wl.left_begin(), end = wl.left_end();  it != end;  ++it) {
1469 		if (it->head->isReverseReason(*this, ~p, maxLevel, maxNew)) {
1470 			return it->head;
1471 		}
1472 	}
1473 	return ante;
1474 }
1475 
1476 // removes cc[pos] by resolving cc with reason
ccResolve(LitVec & cc,uint32 pos,const LitVec & reason)1477 void Solver::ccResolve(LitVec& cc, uint32 pos, const LitVec& reason) {
1478 	heuristic_->updateReason(*this, reason, cc[pos]);
1479 	Literal x;
1480 	for (LitVec::size_type i = 0; i != reason.size(); ++i) {
1481 		x = reason[i];
1482 		assert(isTrue(x));
1483 		if (!seen(x.var())) {
1484 			markLevel(level(x.var()));
1485 			cc.push_back(~x);
1486 		}
1487 	}
1488 	clearSeen(cc[pos].var());
1489 	unmarkLevel(level(cc[pos].var()));
1490 	cc[pos] = cc.back();
1491 	cc.pop_back();
1492 }
1493 
1494 // computes asserting level and lbd of cc and clears flags.
1495 // POST:
1496 //  - literals and decision levels in cc are no longer marked
1497 //  - if cc.size() > 1: cc[1] is a literal from the asserting level
1498 // RETURN: asserting level of conflict clause.
finalizeConflictClause(LitVec & cc,ConstraintInfo & info,uint32 ccRepMode)1499 uint32 Solver::finalizeConflictClause(LitVec& cc, ConstraintInfo& info, uint32 ccRepMode) {
1500 	// 2. clear flags and compute lbd
1501 	uint32  lbd         = 1;
1502 	uint32  onRoot      = 0;
1503 	uint32  varLevel    = 0;
1504 	uint32  assertLevel = 0;
1505 	uint32  assertPos   = 1;
1506 	uint32  maxVar      = cc[0].var();
1507 	Literal tagLit      = ~tagLiteral();
1508 	bool    tagged      = false;
1509 	for (LitVec::size_type i = 1; i != cc.size(); ++i) {
1510 		Var v = cc[i].var();
1511 		clearSeen(v);
1512 		if (cc[i] == tagLit) { tagged = true; }
1513 		if (v > maxVar)      { maxVar = v;    }
1514 		if ( (varLevel = level(v)) > assertLevel ) {
1515 			assertLevel = varLevel;
1516 			assertPos   = static_cast<uint32>(i);
1517 		}
1518 		if (hasLevel(varLevel)) {
1519 			unmarkLevel(varLevel);
1520 			lbd += (varLevel > rootLevel()) || (++onRoot == 1);
1521 		}
1522 	}
1523 	if (assertPos != 1) { std::swap(cc[1], cc[assertPos]); }
1524 	if (ccRepMode == SolverStrategies::cc_rep_dynamic) {
1525 		ccRepMode = double(lbd)/double(decisionLevel()) > .66 ? SolverStrategies::cc_rep_decision : SolverStrategies::cc_rep_uip;
1526 	}
1527 	if (ccRepMode) {
1528 		maxVar = cc[0].var(), tagged = false, lbd = 1;
1529 		if (ccRepMode == SolverStrategies::cc_rep_decision) {
1530 			// replace cc with decision sequence
1531 			cc.resize(assertLevel+1);
1532 			for (uint32 i = assertLevel; i;){
1533 				Literal x = ~decision(i--);
1534 				cc[lbd++] = x;
1535 				if (x == tagLit)     { tagged = true; }
1536 				if (x.var() > maxVar){ maxVar = x.var(); }
1537 			}
1538 		}
1539 		else {
1540 			// replace cc with all uip clause
1541 			uint32 marked = sizeVec(cc) - 1;
1542 			while (cc.size() > 1) { markSeen(~cc.back()); cc.pop_back(); }
1543 			for (LitVec::const_iterator tr = assign_.trail.end(), next, stop; marked;) {
1544 				while (!seen(*--tr)) { ; }
1545 				bool n = --marked != 0 && !reason(*tr).isNull();
1546 				clearSeen(tr->var());
1547 				if (n) { for (next = tr, stop = assign_.trail.begin() + levelStart(level(tr->var())); next-- != stop && !seen(*next);) { ; } }
1548 				if (!n || level(next->var()) != level(tr->var())) {
1549 					cc.push_back(~*tr);
1550 					if (tr->var() == tagLit.var()){ tagged = true; }
1551 					if (tr->var() > maxVar)       { maxVar = tr->var(); }
1552 				}
1553 				else {
1554 					for (reason(*tr, conflict_); !conflict_.empty(); conflict_.pop_back()) {
1555 						if (!seen(conflict_.back())) { ++marked; markSeen(conflict_.back()); }
1556 					}
1557 				}
1558 			}
1559 			lbd = sizeVec(cc);
1560 		}
1561 	}
1562 	info.setScore(makeScore(ccInfo_.activity(), lbd));
1563 	info.setTagged(tagged);
1564 	info.setAux(auxVar(maxVar));
1565 	return assertLevel;
1566 }
1567 
1568 // (inefficient) default implementation
minimize(Solver & s,Literal p,CCMinRecursive * rec)1569 bool Constraint::minimize(Solver& s, Literal p, CCMinRecursive* rec) {
1570 	LitVec temp;
1571 	reason(s, p, temp);
1572 	for (LitVec::size_type i = 0; i != temp.size(); ++i) {
1573 		if (!s.ccMinimize(temp[i], rec)) {
1574 			return false;
1575 		}
1576 	}
1577 	return true;
1578 }
1579 
1580 // Selects next branching literal
decideNextBranch(double f)1581 bool Solver::decideNextBranch(double f) {
1582 	if (f <= 0.0 || rng.drand() >= f || numFreeVars() == 0) {
1583 		return heuristic_->select(*this);
1584 	}
1585 	// select randomly
1586 	Literal choice;
1587 	uint32 maxVar = numVars() + 1;
1588 	for (uint32 v = rng.irand(maxVar);;) {
1589 		if (value(v) == value_free) {
1590 			choice    = heuristic_->selectLiteral(*this, v, 0);
1591 			break;
1592 		}
1593 		if (++v == maxVar) { v = 1; }
1594 	}
1595 	return assume(choice);
1596 }
resetLearntActivities()1597 void Solver::resetLearntActivities() {
1598 	for (ConstraintDB::size_type i = 0, end = learnts_.size(); i != end; ++i) {
1599 		learnts_[i]->resetActivity();
1600 	}
1601 }
1602 // Removes up to remFrac% of the learnt nogoods but
1603 // keeps those that are locked or are highly active.
reduceLearnts(float remFrac,const ReduceStrategy & rs)1604 Solver::DBInfo Solver::reduceLearnts(float remFrac, const ReduceStrategy& rs) {
1605 	uint32 oldS = numLearntConstraints();
1606 	uint32 remM = static_cast<uint32>(oldS * std::max(0.0f, remFrac));
1607 	DBInfo r    = {0,0,0};
1608 	CmpScore cmp(learnts_, (ReduceStrategy::Score)rs.score, rs.glue, rs.protect);
1609 	if (remM >= oldS || !remM || rs.algo == ReduceStrategy::reduce_sort) {
1610 		r = reduceSortInPlace(remM, cmp, false);
1611 	}
1612 	else if (rs.algo == ReduceStrategy::reduce_stable) { r = reduceSort(remM, cmp);  }
1613 	else if (rs.algo == ReduceStrategy::reduce_heap)   { r = reduceSortInPlace(remM, cmp, true);}
1614 	else                                               { r = reduceLinear(remM, cmp); }
1615 	stats.addDeleted(oldS - r.size);
1616 	shrinkVecTo(learnts_, r.size);
1617 	return r;
1618 }
1619 // Removes up to maxR of the learnt nogoods.
1620 // Keeps those that are locked or have a high activity and
1621 // does not reorder learnts_.
reduceLinear(uint32 maxR,const CmpScore & sc)1622 Solver::DBInfo Solver::reduceLinear(uint32 maxR, const CmpScore& sc) {
1623 	// compute average activity
1624 	uint64 scoreSum = 0;
1625 	for (LitVec::size_type i = 0; i != learnts_.size(); ++i) {
1626 		scoreSum += sc.score(learnts_[i]->activity());
1627 	}
1628 	double avgAct = (scoreSum / (double) numLearntConstraints());
1629 	// constraints with socre > 1.5 times the average are "active"
1630 	double scoreThresh = avgAct * 1.5;
1631 	double scoreMax    = (double)sc.score(makeScore(Clasp::ACT_MAX, 1));
1632 	if (scoreThresh > scoreMax) {
1633 		scoreThresh = (scoreMax + (scoreSum / (double) numLearntConstraints())) / 2.0;
1634 	}
1635 	// remove up to maxR constraints but keep "active" and locked once
1636 	DBInfo res = {0,0,0};
1637 	typedef ConstraintScore ScoreType;
1638 	for (LitVec::size_type i = 0; i != learnts_.size(); ++i) {
1639 		Constraint* c = learnts_[i];
1640 		ScoreType a   = c->activity();
1641 		bool isLocked = c->locked(*this);
1642 		bool isGlue   = sc.score(a) > scoreThresh || sc.isGlue(a);
1643 		if (maxR == 0 || isLocked || isGlue || sc.isFrozen(a)) {
1644 			res.pinned += isGlue;
1645 			res.locked += isLocked;
1646 			learnts_[res.size++] = c;
1647 			c->decreaseActivity();
1648 		}
1649 		else {
1650 			--maxR;
1651 			c->destroy(this, true);
1652 		}
1653 	}
1654 	return res;
1655 }
1656 
1657 // Sorts learnt constraints by score and removes the
1658 // maxR constraints with the lowest score without
1659 // reordering learnts_.
reduceSort(uint32 maxR,const CmpScore & sc)1660 Solver::DBInfo Solver::reduceSort(uint32 maxR, const CmpScore& sc) {
1661 	typedef PodVector<CmpScore::ViewPair>::type HeapType;
1662 	DBInfo   res  = {0,0,0};
1663 	HeapType heap;
1664 	heap.reserve(maxR = std::min(maxR, (uint32)learnts_.size()));
1665 	bool isGlue, isLocked;
1666 	for (LitVec::size_type i = 0; i != learnts_.size(); ++i) {
1667 		Constraint* c = learnts_[i];
1668 		CmpScore::ViewPair vp(toU32(i), c->activity());
1669 		res.pinned += (isGlue   = sc.isGlue(vp.second));
1670 		res.locked += (isLocked = c->locked(*this));
1671 		if (!isLocked && !isGlue && !sc.isFrozen(vp.second)) {
1672 			if (maxR) { // populate heap with first maxR constraints
1673 				heap.push_back(vp);
1674 				if (--maxR == 0) { std::make_heap(heap.begin(), heap.end(), sc); }
1675 			}
1676 			else if (sc(vp, heap[0])) { // replace max element in heap
1677 				std::pop_heap(heap.begin(), heap.end(), sc);
1678 				heap.back() = vp;
1679 				std::push_heap(heap.begin(), heap.end(), sc);
1680 			}
1681 		}
1682 	}
1683 	// Remove all constraints in heap - those are "inactive".
1684 	for (HeapType::const_iterator it = heap.begin(), end = heap.end(); it != end; ++it) {
1685 		learnts_[it->first]->destroy(this, true);
1686 		learnts_[it->first] = 0;
1687 	}
1688 	// Cleanup db and decrease activity of remaining constraints.
1689 	uint32 j = 0;
1690 	for (LitVec::size_type i = 0; i != learnts_.size(); ++i) {
1691 		if (Constraint* c = learnts_[i]) {
1692 			c->decreaseActivity();
1693 			learnts_[j++] = c;
1694 		}
1695 	}
1696 	res.size = j;
1697 	return res;
1698 }
1699 
1700 // Sorts the learnt db by score and removes the first
1701 // maxR constraints (those with the lowest score).
reduceSortInPlace(uint32 maxR,const CmpScore & sc,bool partial)1702 Solver::DBInfo Solver::reduceSortInPlace(uint32 maxR, const CmpScore& sc, bool partial) {
1703 	DBInfo res = {0,0,0};
1704 	ConstraintDB::iterator nEnd = learnts_.begin();
1705 	maxR = std::min(maxR, (uint32)learnts_.size());
1706 	bool isGlue, isLocked;
1707 	typedef ConstraintScore ScoreType;
1708 	if (!partial) {
1709 		// sort whole db and remove first maxR constraints
1710 		if (maxR && maxR != learnts_.size()) std::stable_sort(learnts_.begin(), learnts_.end(), sc);
1711 		for (ConstraintDB::iterator it = learnts_.begin(), end = learnts_.end(); it != end; ++it) {
1712 			Constraint* c = *it;
1713 			ScoreType a = c->activity();
1714 			res.pinned += (isGlue = sc.isGlue(a));
1715 			res.locked += (isLocked = c->locked(*this));
1716 			if (!maxR || isLocked || isGlue || sc.isFrozen(a)) {
1717 				c->decreaseActivity();
1718 				*nEnd++ = c;
1719 			}
1720 			else {
1721 				c->destroy(this, true);
1722 				--maxR;
1723 			}
1724 		}
1725 	}
1726 	else {
1727 		ConstraintDB::iterator hBeg = learnts_.begin();
1728 		ConstraintDB::iterator hEnd = learnts_.begin();
1729 		for (ConstraintDB::iterator it = learnts_.begin(), end = learnts_.end(); it != end; ++it) {
1730 			Constraint* c = *it;
1731 			ScoreType a = c->activity();
1732 			res.pinned += (isGlue = sc.isGlue(a));
1733 			res.locked += (isLocked = c->locked(*this));
1734 			if      (isLocked || isGlue || sc.isFrozen(a)) { continue; }
1735 			else if (maxR) {
1736 				*it     = *hEnd;
1737 				*hEnd++ = c;
1738 				if (--maxR == 0) { std::make_heap(hBeg, hEnd, sc); }
1739 			}
1740 			else if (sc(c, learnts_[0])) {
1741 				std::pop_heap(hBeg, hEnd, sc);
1742 				*it      = *(hEnd-1);
1743 				*(hEnd-1)= c;
1744 				std::push_heap(hBeg, hEnd, sc);
1745 			}
1746 		}
1747 		// remove all constraints in heap
1748 		for (ConstraintDB::iterator it = hBeg; it != hEnd; ++it) {
1749 			(*it)->destroy(this, true);
1750 		}
1751 		// copy remaining constraints down
1752 		for (ConstraintDB::iterator it = hEnd, end = learnts_.end(); it != end; ++it) {
1753 			Constraint* c = *it;
1754 			c->decreaseActivity();
1755 			*nEnd++ = c;
1756 		}
1757 	}
1758 	res.size = static_cast<uint32>(std::distance(learnts_.begin(), nEnd));
1759 	return res;
1760 }
incEpoch(uint32 size,uint32 n)1761 uint32 Solver::incEpoch(uint32 size, uint32 n) {
1762 	if (size > epoch_.size())         { epoch_.resize(size, 0u); }
1763 	if ((UINT32_MAX - epoch_[0]) < n) { epoch_.assign(epoch_.size(), 0u); }
1764 	return epoch_[0] += n;
1765 }
countLevels(const Literal * first,const Literal * last,uint32 maxLevel)1766 uint32 Solver::countLevels(const Literal* first, const Literal* last, uint32 maxLevel) {
1767 	if (maxLevel < 2) { return uint32(maxLevel && first != last); }
1768 	POTASSCO_ASSERT(!ccMin_ || ccMin_->todo.empty(), "Must not be called during minimization!");
1769 	uint32 n = 0;
1770 	for (uint32 epoch = incEpoch(sizeVec(levels_) + 1); first != last; ++first) {
1771 		assert(value(first->var()) != value_free);
1772 		uint32& levEpoch = epoch_[level(first->var())];
1773 		if (levEpoch != epoch) {
1774 			levEpoch = epoch;
1775 			if (++n == maxLevel) { break; }
1776 		}
1777 	}
1778 	return n;
1779 }
1780 
updateBranch(uint32 n)1781 void Solver::updateBranch(uint32 n) {
1782 	int32 dl = (int32)decisionLevel(), xl = static_cast<int32>(cflStamp_.size())-1;
1783 	if      (xl > dl) { do { n += cflStamp_.back(); cflStamp_.pop_back(); } while (--xl != dl); }
1784 	else if (dl > xl) { cflStamp_.insert(cflStamp_.end(), dl - xl, 0); }
1785 	cflStamp_.back() += n;
1786 }
reduceReached(const SearchLimits & limits) const1787 bool Solver::reduceReached(const SearchLimits& limits) const {
1788 	return numLearntConstraints() > limits.learnts || memUse_ > limits.memory;
1789 }
restartReached(const SearchLimits & limits) const1790 bool Solver::restartReached(const SearchLimits& limits) const {
1791 	uint64 n = !limits.restart.local || cflStamp_.empty() ? limits.used : cflStamp_.back();
1792 	return n >= limits.restart.conflicts || (limits.restart.dynamic && limits.restart.dynamic->reached());
1793 }
1794 /////////////////////////////////////////////////////////////////////////////////////////
1795 // The basic DPLL-like search-function
1796 /////////////////////////////////////////////////////////////////////////////////////////
search(SearchLimits & limit,double rf)1797 ValueRep Solver::search(SearchLimits& limit, double rf) {
1798 	assert(!isFalse(tagLiteral()));
1799 	SearchLimits::BlockPtr block = limit.restart.block;
1800 	rf = std::max(0.0, std::min(1.0, rf));
1801 	lower.reset();
1802 	if (limit.restart.local && decisionLevel() == rootLevel()) { cflStamp_.assign(decisionLevel()+1, 0); }
1803 	do {
1804 		for (bool conflict = hasConflict() || !propagate() || !simplify(), local = limit.restart.local;;) {
1805 			if (conflict) {
1806 				uint32 n = 1, ts;
1807 				do {
1808 					if (block && block->push(ts = numAssignedVars()) && ts > block->scaled()) {
1809 						if (limit.restart.dynamic) { limit.restart.dynamic->resetRun(); }
1810 						else                       { limit.restart.conflicts += block->inc; }
1811 						block->next = block->n + block->inc;
1812 					}
1813 				} while (resolveConflict() && !propagate() && (++n, true));
1814 				limit.used += n;
1815 				if (local) { updateBranch(n); }
1816 				if (hasConflict() || (decisionLevel() == 0 && !simplify())) { return value_false; }
1817 				if (numFreeVars()) {
1818 					if (limit.used >= limit.conflicts) { return value_free; }
1819 					if (restartReached(limit))         { return value_free; }
1820 					if (reduceReached(limit))          { return value_free; }
1821 				}
1822 			}
1823 			if (decideNextBranch(rf)) { conflict = !propagate(); }
1824 			else                      { break; }
1825 		}
1826 	} while (!isModel());
1827 	temp_.clear();
1828 	model.clear(); model.reserve(numVars()+1);
1829 	for (Var v = 0; v <= numVars(); ++v) { model.push_back(value(v)); }
1830 	if (satPrepro()) { satPrepro()->extendModel(model, temp_); }
1831 	return value_true;
1832 }
search(uint64 maxC,uint32 maxL,bool local,double rp)1833 ValueRep Solver::search(uint64 maxC, uint32 maxL, bool local, double rp) {
1834 	SearchLimits limit;
1835 	limit.restart.conflicts = maxC;
1836 	limit.restart.local     = local;
1837 	limit.learnts = maxL;
1838 	return search(limit, rp);
1839 }
isModel()1840 bool Solver::isModel() {
1841 	if (hasConflict()) { return false; }
1842 	FOR_EACH_POST(x, post_.head()) {
1843 		if (!x->isModel(*this)) { return false; }
1844 	}
1845 	return !enumerationConstraint() || enumerationConstraint()->valid(*this);
1846 }
1847 /////////////////////////////////////////////////////////////////////////////////////////
1848 // Free functions
1849 /////////////////////////////////////////////////////////////////////////////////////////
destroyDB(Solver::ConstraintDB & db,Solver * s,bool detach)1850 void destroyDB(Solver::ConstraintDB& db, Solver* s, bool detach) {
1851 	if (s && detach) {
1852 		s->destroyDB(db);
1853 		return;
1854 	}
1855 	while (!db.empty()) {
1856 		db.back()->destroy(s, detach);
1857 		db.pop_back();
1858 	}
1859 }
1860 }
1861