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/clause.h>
25 #include <clasp/solver.h>
26 #include <clasp/util/misc_types.h>
27 #include <algorithm>
28 
29 namespace Clasp { namespace Detail {
30 struct GreaterLevel {
GreaterLevelClasp::Detail::GreaterLevel31 	GreaterLevel(const Solver& s) : solver_(s) {}
operator ()Clasp::Detail::GreaterLevel32 	bool operator()(const Literal& p1, const Literal& p2) const {
33 		assert(solver_.value(p1.var()) != value_free && solver_.value(p2.var()) != value_free);
34 		return solver_.level(p1.var()) > solver_.level(p2.var());
35 	}
36 private:
37 	GreaterLevel& operator=(const GreaterLevel&);
38 	const Solver& solver_;
39 };
40 
41 struct Sink {
SinkClasp::Detail::Sink42 	explicit Sink(SharedLiterals* c) : clause(c) {}
~SinkClasp::Detail::Sink43 	~Sink() { if (clause) clause->release(); }
44 	SharedLiterals* clause;
45 };
46 
alloc(uint32 size)47 void* alloc(uint32 size) {
48 	POTASSCO_PRAGMA_TODO("replace with CACHE_LINE_ALIGNED alloc")
49 	return ::operator new(size);
50 }
free(void * mem)51 void free(void* mem) {
52 	::operator delete(mem);
53 }
54 
55 } // namespace Detail
56 
57 /////////////////////////////////////////////////////////////////////////////////////////
58 // SharedLiterals
59 /////////////////////////////////////////////////////////////////////////////////////////
newShareable(const Literal * lits,uint32 size,ConstraintType t,uint32 numRefs)60 SharedLiterals* SharedLiterals::newShareable(const Literal* lits, uint32 size, ConstraintType t, uint32 numRefs) {
61 	void* m = Detail::alloc(sizeof(SharedLiterals)+(size*sizeof(Literal)));
62 	return new (m) SharedLiterals(lits, size, t, numRefs);
63 }
64 
SharedLiterals(const Literal * a_lits,uint32 size,ConstraintType t,uint32 refs)65 SharedLiterals::SharedLiterals(const Literal* a_lits, uint32 size, ConstraintType t, uint32 refs)
66 	: size_type_( (size << 2) + t ) {
67 	refCount_ = std::max(uint32(1),refs);
68 	std::memcpy(lits_, a_lits, size*sizeof(Literal));
69 }
70 
simplify(Solver & s)71 uint32 SharedLiterals::simplify(Solver& s) {
72 	bool   removeFalse = unique();
73 	uint32   newSize   = 0;
74 	Literal* r         = lits_;
75 	Literal* e         = lits_+size();
76 	ValueRep v;
77 	for (Literal* c = r; r != e; ++r) {
78 		if ( (v = s.value(r->var())) == value_free ) {
79 			if (c != r) *c = *r;
80 			++c; ++newSize;
81 		}
82 		else if (v == trueValue(*r)) {
83 			newSize = 0; break;
84 		}
85 		else if (!removeFalse) ++c;
86 	}
87 	if (removeFalse && newSize != size()) {
88 		size_type_ = (newSize << 2) | (size_type_ & uint32(3));
89 	}
90 	return newSize;
91 }
92 
release(uint32 n)93 void SharedLiterals::release(uint32 n) {
94 	if ((refCount_ -= n) == 0) {
95 		this->~SharedLiterals();
96 		Detail::free(this);
97 	}
98 }
share()99 SharedLiterals* SharedLiterals::share() {
100 	++refCount_;
101 	return this;
102 }
103 /////////////////////////////////////////////////////////////////////////////////////////
104 // ClauseCreator
105 /////////////////////////////////////////////////////////////////////////////////////////
ClauseCreator(Solver * s)106 ClauseCreator::ClauseCreator(Solver* s)
107 	: solver_(s)
108 	, flags_(0){
109 }
110 
start(ConstraintType t)111 ClauseCreator& ClauseCreator::start(ConstraintType t) {
112 	assert(solver_ && (solver_->decisionLevel() == 0 || t != Constraint_t::Static));
113 	literals_.clear();
114 	extra_ = ConstraintInfo(t);
115 	return *this;
116 }
117 
watchOrder(const Solver & s,Literal p)118 uint32 ClauseCreator::watchOrder(const Solver& s, Literal p) {
119 	ValueRep value_p = s.value(p.var());
120 	// DL+1,  if isFree(p)
121 	// DL(p), if isFalse(p)
122 	// ~DL(p),if isTrue(p)
123 	uint32   abstr_p = value_p == value_free ? s.decisionLevel()+1 : s.level(p.var()) ^ -(value_p==trueValue(p));
124 	assert(abstr_p > 0 || (s.isFalse(p) && s.level(p.var()) == 0));
125 	return abstr_p;
126 }
127 
prepare(Solver & s,const Literal * in,uint32 inSize,const ConstraintInfo & e,uint32 flags,Literal * out,uint32 outMax)128 ClauseRep ClauseCreator::prepare(Solver& s, const Literal* in, uint32 inSize, const ConstraintInfo& e, uint32 flags, Literal* out, uint32 outMax) {
129 	assert(out && outMax > 2);
130 	ClauseRep ret  = ClauseRep::prepared(out, 0, e);
131 	uint32 abst_w1 = 0, abst_w2 = 0;
132 	bool simplify  = ((flags & clause_force_simplify) != 0) && inSize > 2 && outMax >= inSize;
133 	Literal tag    = ~s.tagLiteral();
134 	Var     vMax   = 0;
135 	for (uint32 i = 0, j = 0, MAX_OUT = outMax - 1; i != inSize; ++i) {
136 		Literal p     = in[i];
137 		uint32 abst_p = watchOrder(s, p);
138 		if ((abst_p + 1) > 1 && (!simplify || !s.seen(p.var()))) {
139 			out[j] = p;
140 			if (p == tag)         { ret.info.setTagged(true); }
141 			if (p.var() > vMax)   { vMax = p.var();}
142 			if (simplify)         { s.markSeen(p); }
143 			if (abst_p > abst_w1) { std::swap(abst_p, abst_w1); std::swap(out[0], out[j]); }
144 			if (abst_p > abst_w2) { std::swap(abst_p, abst_w2); std::swap(out[1], out[j]); }
145 			if (j != MAX_OUT)     { ++j;  }
146 			++ret.size;
147 		}
148 		else if (abst_p == UINT32_MAX || (simplify && abst_p && s.seen(~p))) {
149 			abst_w1 = UINT32_MAX;
150 			break;
151 		}
152 	}
153 	if (simplify) {
154 		for (uint32 x = 0, end = ret.size; x != end; ++x) { s.clearSeen(out[x].var()); }
155 	}
156 	if (abst_w1 == UINT32_MAX || (abst_w2 && out[0].var() == out[1].var())) {
157 		out[0]   = abst_w1 == UINT32_MAX || out[0] == ~out[1] ? lit_true() : out[0];
158 		ret.size = 1;
159 	}
160 	ret.info.setAux(s.auxVar(vMax));
161 	return ret;
162 }
163 
164 
prepare(Solver & s,LitVec & lits,uint32 flags,const ConstraintInfo & info)165 ClauseRep ClauseCreator::prepare(Solver& s, LitVec& lits, uint32 flags, const ConstraintInfo& info) {
166 	if (lits.empty()) { lits.push_back(lit_false()); }
167 	if ((flags & clause_no_prepare) == 0 || (flags & clause_force_simplify) != 0) {
168 		ClauseRep x = prepare(s, &lits[0], (uint32)lits.size(), info, flags, &lits[0]);
169 		shrinkVecTo(lits, x.size);
170 		return x;
171 	}
172 	return ClauseRep::prepared(&lits[0], (uint32)lits.size(), info);
173 }
174 
prepare(bool forceSimplify)175 ClauseRep ClauseCreator::prepare(bool forceSimplify) {
176 	return prepare(*solver_, literals_, forceSimplify ? clause_force_simplify : 0, extra_);
177 }
178 
status(const Solver & s,const Literal * clause_begin,const Literal * clause_end)179 ClauseCreator::Status ClauseCreator::status(const Solver& s, const Literal* clause_begin, const Literal* clause_end) {
180 	if (clause_end <= clause_begin) { return status_empty; }
181 	Literal temp[3];
182 	ClauseRep x = prepare(const_cast<Solver&>(s), clause_begin, uint32(clause_end - clause_begin), ConstraintInfo(), 0, temp, 3);
183 	return status(s, x);
184 }
185 
status(const Solver & s,const ClauseRep & c)186 ClauseCreator::Status ClauseCreator::status(const Solver& s, const ClauseRep& c) {
187 	uint32 dl = s.decisionLevel();
188 	uint32 fw = c.size     ? watchOrder(s, c.lits[0]) : 0;
189 	if (fw == UINT32_MAX) { return status_subsumed; }
190 	uint32 sw = c.size > 1 ? watchOrder(s, c.lits[1]) : 0;
191 	uint32 st = status_open;
192 	if      (fw > varMax)   { st|= status_sat; fw = ~fw; }
193 	else if (fw <= dl)      { st|= (fw ? status_unsat : status_empty); }
194 	if (sw <= dl && fw > sw){ st|= status_unit;  }
195 	return static_cast<Status>(st);
196 }
197 
ignoreClause(const Solver & s,const ClauseRep & c,Status st,uint32 flags)198 bool ClauseCreator::ignoreClause(const Solver& s, const ClauseRep& c, Status st, uint32 flags) {
199 	uint32 x = (st & (status_sat|status_unsat));
200 	if (x == status_open)  { return false; }
201 	if (x == status_unsat) { return st != status_empty && (flags & clause_not_conflict) != 0; }
202 	return st == status_subsumed || (st == status_sat && ( (flags & clause_not_sat) != 0 || ((flags & clause_not_root_sat) != 0 && s.level(c.lits[0].var()) <= s.rootLevel())));
203 }
204 
end(uint32 flags)205 ClauseCreator::Result ClauseCreator::end(uint32 flags) {
206 	assert(solver_);
207 	flags |= flags_;
208 	return ClauseCreator::create_prepared(*solver_, prepare(*solver_, literals_, flags, extra_), flags);
209 }
210 
newProblemClause(Solver & s,const ClauseRep & clause,uint32 flags)211 ClauseHead* ClauseCreator::newProblemClause(Solver& s, const ClauseRep& clause, uint32 flags) {
212 	ClauseHead* ret;
213 	Solver::WatchInitMode wMode = s.watchInitMode();
214 	if      (flags&clause_watch_first){ wMode = SolverStrategies::watch_first;}
215 	else if (flags&clause_watch_rand) { wMode = SolverStrategies::watch_rand; }
216 	else if (flags&clause_watch_least){ wMode = SolverStrategies::watch_least;}
217 	if (clause.size > 2 && wMode != SolverStrategies::watch_first) {
218 		uint32 fw = 0, sw = 1;
219 		if (wMode == SolverStrategies::watch_rand) {
220 			fw = s.rng.irand(clause.size);
221 			do { sw = s.rng.irand(clause.size); } while (sw == fw);
222 		}
223 		else if (wMode == SolverStrategies::watch_least) {
224 			uint32 cw1 = s.numWatches(~clause.lits[0]);
225 			uint32 cw2 = s.numWatches(~clause.lits[1]);
226 			if (cw1 > cw2) { std::swap(fw, sw); std::swap(cw1, cw2); }
227 			for (uint32 i = 2; i != clause.size && cw2; ++i) {
228 				uint32 p   = i;
229 				uint32 cwp = s.numWatches(~clause.lits[i]);
230 				if (cwp < cw1) { std::swap(cwp, cw1); std::swap(fw, p); }
231 				if (cwp < cw2) { std::swap(cwp, cw2); std::swap(sw, p); }
232 			}
233 		}
234 		std::swap(clause.lits[0], clause.lits[fw]);
235 		std::swap(clause.lits[1], clause.lits[sw]);
236 	}
237 	if (clause.size <= Clause::MAX_SHORT_LEN || !s.sharedContext()->physicalShareProblem()) {
238 		ret = Clause::newClause(s, clause);
239 	}
240 	else {
241 		ret = Clause::newShared(s, SharedLiterals::newShareable(clause.lits, clause.size, clause.info.type(), 1), clause.info, clause.lits, false);
242 	}
243 	if ( (flags & clause_no_add) == 0 ) {
244 		assert(!clause.info.aux());
245 		s.add(ret);
246 	}
247 	return ret;
248 }
249 
newLearntClause(Solver & s,const ClauseRep & clause,uint32 flags)250 ClauseHead* ClauseCreator::newLearntClause(Solver& s, const ClauseRep& clause, uint32 flags) {
251 	ClauseHead* ret;
252 	Detail::Sink sharedPtr(0);
253 	sharedPtr.clause = s.distribute(clause.lits, clause.size, clause.info);
254 	if (clause.size <= Clause::MAX_SHORT_LEN || sharedPtr.clause == 0) {
255 		if (!s.isFalse(clause.lits[1]) || clause.size < s.compressLimit()) {
256 			ret = Clause::newClause(s, clause);
257 		}
258 		else {
259 			ret = Clause::newContractedClause(s, clause, 2, true);
260 		}
261 	}
262 	else {
263 		ret              = Clause::newShared(s, sharedPtr.clause, clause.info, clause.lits, false);
264 		sharedPtr.clause = 0;
265 	}
266 	if ( (flags & clause_no_add) == 0 ) {
267 		s.addLearnt(ret, clause.size, clause.info.type());
268 	}
269 	return ret;
270 }
271 
newUnshared(Solver & s,SharedLiterals * clause,const Literal * w,const ConstraintInfo & e)272 ClauseHead* ClauseCreator::newUnshared(Solver& s, SharedLiterals* clause, const Literal* w, const ConstraintInfo& e) {
273 	LitVec temp; temp.reserve(clause->size());
274 	temp.assign(w, w+2);
275 	for (const Literal* x = clause->begin(), *end = clause->end(); x != end; ++x) {
276 		if (watchOrder(s, *x) > 0 && *x != temp[0] && *x != temp[1]) {
277 			temp.push_back(*x);
278 		}
279 	}
280 	return Clause::newClause(s, ClauseRep::prepared(&temp[0], (uint32)temp.size(), e));
281 }
282 
create_prepared(Solver & s,const ClauseRep & clause,uint32 flags)283 ClauseCreator::Result ClauseCreator::create_prepared(Solver& s, const ClauseRep& clause, uint32 flags) {
284 	assert(s.decisionLevel() == 0 || (clause.info.learnt() && clause.prep));
285 	Status x = status(s, clause);
286 	if (ignoreClause(s, clause, x, flags)){
287 		return Result(0, x);
288 	}
289 	if (clause.size > 1) {
290 		Result ret(0, x);
291 		if (!clause.info.learnt() && s.satPrepro() && !s.sharedContext()->frozen()) {
292 			return Result(0, s.satPrepro()->addClause(clause.lits, clause.size) ? x : status_unsat);
293 		}
294 		if ((flags & clause_no_heuristic) == 0) { s.heuristic()->newConstraint(s, clause.lits, clause.size, clause.info.type()); }
295 		if (clause.size > 3 || (flags&clause_explicit) != 0 || !s.allowImplicit(clause)) {
296 			ret.local = clause.info.learnt() ? newLearntClause(s, clause, flags) : newProblemClause(s, clause, flags);
297 		}
298 		else {
299 			// add implicit short rep
300 			s.add(clause);
301 		}
302 		if ((x & (status_unit|status_unsat)) != 0) {
303 			Antecedent ante(ret.local);
304 			if (!ret.local){ ante = clause.size == 3 ? Antecedent(~clause.lits[1], ~clause.lits[2]) : Antecedent(~clause.lits[1]); }
305 			ret.status = s.force(clause.lits[0], s.level(clause.lits[1].var()), ante) ? status_unit : status_unsat;
306 		}
307 		return ret;
308 	}
309 	s.add(clause);
310 	return Result(0, !s.hasConflict() ? status_unit : status_unsat);
311 }
312 
create(Solver & s,LitVec & lits,uint32 flags,const ConstraintInfo & extra)313 ClauseCreator::Result ClauseCreator::create(Solver& s, LitVec& lits, uint32 flags, const ConstraintInfo& extra) {
314 	return create_prepared(s, prepare(s, lits, flags, extra), flags);
315 }
316 
create(Solver & s,const ClauseRep & rep,uint32 flags)317 ClauseCreator::Result ClauseCreator::create(Solver& s, const ClauseRep& rep, uint32 flags) {
318 	return create_prepared(s, (rep.prep == 0 && (flags & clause_no_prepare) == 0
319 		? prepare(s, rep.lits, rep.size, rep.info, flags, rep.lits)
320 		: ClauseRep::prepared(rep.lits, rep.size, rep.info)), flags);
321 }
322 
integrate(Solver & s,SharedLiterals * clause,uint32 modeFlags,ConstraintType t)323 ClauseCreator::Result ClauseCreator::integrate(Solver& s, SharedLiterals* clause, uint32 modeFlags, ConstraintType t) {
324 	assert(!s.hasConflict() && "ClauseCreator::integrate() - precondition violated!");
325 	Detail::Sink shared( (modeFlags & clause_no_release) == 0 ? clause : 0);
326 	// determine state of clause
327 	Literal temp[Clause::MAX_SHORT_LEN]; temp[0] = temp[1] = lit_false();
328 	ClauseRep x    = prepare(s, clause->begin(), clause->size(), ConstraintInfo(t), 0, temp, Clause::MAX_SHORT_LEN);
329 	uint32 impSize = (modeFlags & clause_explicit) != 0 || !s.allowImplicit(x) ? 1 : 3;
330 	Status xs      = status(s, x);
331 	if (ignoreClause(s, x, xs, modeFlags)) {
332 		return Result(0, xs);
333 	}
334 	Result result(0, xs);
335 	if ((modeFlags & clause_no_heuristic) == 0) { s.heuristic()->newConstraint(s, clause->begin(), clause->size(), t); }
336 	if (x.size > Clause::MAX_SHORT_LEN && s.sharedContext()->physicalShare(t)) {
337 		result.local  = Clause::newShared(s, clause, x.info, temp, shared.clause == 0);
338 		shared.clause = 0;
339 	}
340 	else if (x.size > impSize) {
341 		result.local  = x.size <= Clause::MAX_SHORT_LEN ? Clause::newClause(s, x) : newUnshared(s, clause, temp, x.info);
342 	}
343 	else {
344 		// unary clause or implicitly shared via binary/ternary implication graph;
345 		// only check for implication/conflict but do not create
346 		// a local representation for the clause
347 		s.stats.addLearnt(x.size, x.info.type());
348 		modeFlags |= clause_no_add;
349 	}
350 	if ((modeFlags & clause_no_add) == 0) { s.addLearnt(result.local, x.size, x.info.type()); }
351 	if ((xs & (status_unit|status_unsat)) != 0) {
352 		Antecedent ante = result.local ? Antecedent(result.local) : Antecedent(~temp[1], ~temp[2]);
353 		uint32 impLevel = s.level(temp[1].var());
354 		result.status   = s.force(temp[0], impLevel, ante) ? status_unit : status_unsat;
355 		if (result.local && (modeFlags & clause_int_lbd) != 0) {
356 			uint32 lbd = s.countLevels(clause->begin(), clause->end());
357 			result.local->resetScore(makeScore(x.info.activity(), lbd));
358 		}
359 	}
360 	return result;
361 }
integrate(Solver & s,SharedLiterals * clause,uint32 modeFlags)362 ClauseCreator::Result ClauseCreator::integrate(Solver& s, SharedLiterals* clause, uint32 modeFlags) {
363 	return integrate(s, clause, modeFlags, clause->type());
364 }
365 /////////////////////////////////////////////////////////////////////////////////////////
366 // Clause
367 /////////////////////////////////////////////////////////////////////////////////////////
alloc(Solver & s,uint32 lits,bool learnt)368 void* Clause::alloc(Solver& s, uint32 lits, bool learnt) {
369 	if (lits <= Clause::MAX_SHORT_LEN) {
370 		if (learnt) { s.addLearntBytes(32); }
371 		return s.allocSmall();
372 	}
373 	uint32 extra = std::max((uint32)ClauseHead::HEAD_LITS, lits) - ClauseHead::HEAD_LITS;
374 	uint32 bytes = sizeof(Clause) + (extra)*sizeof(Literal);
375 	if (learnt) { s.addLearntBytes(bytes); }
376 	return Detail::alloc(bytes);
377 }
378 
newClause(void * mem,Solver & s,const ClauseRep & rep)379 ClauseHead* Clause::newClause(void* mem, Solver& s, const ClauseRep& rep) {
380 	assert(rep.size >= 2 && mem);
381 	return new (mem) Clause(s, rep);
382 }
383 
newShared(Solver & s,SharedLiterals * shared_lits,const InfoType & e,const Literal * lits,bool addRef)384 ClauseHead* Clause::newShared(Solver& s, SharedLiterals* shared_lits, const InfoType& e, const Literal* lits, bool addRef) {
385 	return mt::SharedLitsClause::newClause(s, shared_lits, e, lits, addRef);
386 }
387 
newContractedClause(Solver & s,const ClauseRep & rep,uint32 tailStart,bool extend)388 ClauseHead* Clause::newContractedClause(Solver& s, const ClauseRep& rep, uint32 tailStart, bool extend) {
389 	assert(rep.size >= 2);
390 	if (extend) { std::stable_sort(rep.lits+tailStart, rep.lits+rep.size, Detail::GreaterLevel(s)); }
391 	return new (alloc(s, rep.size, rep.info.learnt())) Clause(s, rep, tailStart, extend);
392 }
init(uint32 sz)393 void ClauseHead::Local::init(uint32 sz) {
394 	std::memset(mem, 0, sizeof(mem));
395 	if (sz > ClauseHead::MAX_SHORT_LEN) { mem[0] = (sz << 3) + 1; }
396 	assert(isSmall() == (sz <= ClauseHead::MAX_SHORT_LEN));
397 }
Clause(Solver & s,const ClauseRep & rep,uint32 tail,bool extend)398 Clause::Clause(Solver& s, const ClauseRep& rep, uint32 tail, bool extend)
399 	: ClauseHead(rep.info) {
400 	assert(tail >= rep.size || s.isFalse(rep.lits[tail]));
401 	local_.init(rep.size);
402 	if (!isSmall()) {
403 		// copy literals
404 		std::memcpy(head_, rep.lits, rep.size*sizeof(Literal));
405 		tail = std::max(tail, (uint32)ClauseHead::HEAD_LITS);
406 		if (tail < rep.size) {       // contracted clause
407 			head_[rep.size-1].flag();  // mark last literal of clause
408 			Literal t = head_[tail];
409 			if (s.level(t.var()) > 0) {
410 				local_.markContracted();
411 				if (extend) {
412 					s.addUndoWatch(s.level(t.var()), this);
413 				}
414 			}
415 			local_.setSize(tail);
416 		}
417 	}
418 	else {
419 		std::memcpy(head_, rep.lits, std::min(rep.size, (uint32)ClauseHead::HEAD_LITS)*sizeof(Literal));
420 		small()[0] = rep.size > ClauseHead::HEAD_LITS   ? rep.lits[ClauseHead::HEAD_LITS]   : lit_false();
421 		small()[1] = rep.size > ClauseHead::HEAD_LITS+1 ? rep.lits[ClauseHead::HEAD_LITS+1] : lit_false();
422 		assert(isSmall() && Clause::size() == rep.size);
423 	}
424 	attach(s);
425 }
426 
Clause(Solver & s,const Clause & other)427 Clause::Clause(Solver& s, const Clause& other) : ClauseHead(other.info_) {
428 	uint32 oSize = other.size();
429 	local_.init(oSize);
430 	if      (!isSmall())      { std::memcpy(head_, other.head_, oSize*sizeof(Literal)); }
431 	else if (other.isSmall()) { std::memcpy(&local_, &other.local_, (ClauseHead::MAX_SHORT_LEN+1)*sizeof(Literal)); }
432 	else { // this is small, other is not
433 		std::memcpy(head_, other.head_, ClauseHead::HEAD_LITS*sizeof(Literal));
434 		std::memcpy(&local_, other.head_+ClauseHead::HEAD_LITS, 2*sizeof(Literal));
435 	}
436 	attach(s);
437 }
438 
cloneAttach(Solver & other)439 Constraint* Clause::cloneAttach(Solver& other) {
440 	assert(!learnt());
441 	return new (alloc(other, Clause::size(), false)) Clause(other, *this);
442 }
small()443 Literal* Clause::small()          { return static_cast<Literal*>(static_cast<void*>(&local_)); }
contracted() const444 bool Clause::contracted()   const { return local_.contracted(); }
isSmall() const445 bool Clause::isSmall()      const { return local_.isSmall(); }
strengthened() const446 bool Clause::strengthened() const { return local_.strengthened(); }
destroy(Solver * s,bool detachFirst)447 void Clause::destroy(Solver* s, bool detachFirst) {
448 	if (s) {
449 		if (detachFirst) { Clause::detach(*s); }
450 		if (learnt())    { s->freeLearntBytes(computeAllocSize()); }
451 	}
452 	void* mem   = static_cast<Constraint*>(this);
453 	bool  small = isSmall();
454 	this->~Clause();
455 	if (!small) { Detail::free(mem); }
456 	else if (s) { s->freeSmall(mem); }
457 }
458 
detach(Solver & s)459 void Clause::detach(Solver& s) {
460 	if (contracted()) {
461 		Literal* eoc = end();
462 		if (s.isFalse(*eoc) && s.level(eoc->var()) != 0) {
463 			s.removeUndoWatch(s.level(eoc->var()), this);
464 		}
465 	}
466 	ClauseHead::detach(s);
467 }
468 
computeAllocSize() const469 uint32 Clause::computeAllocSize() const {
470 	if (isSmall()) { return 32; }
471 	uint32 rt = sizeof(Clause) - (ClauseHead::HEAD_LITS*sizeof(Literal));
472 	uint32 sz = local_.size();
473 	uint32 nw = contracted() + strengthened();
474 	if (nw != 0u) {
475 		const Literal* eoc = head_ + sz;
476 		do { nw -= eoc++->flagged(); } while (nw);
477 		sz = static_cast<uint32>(eoc - head_);
478 	}
479 	return rt + (sz*sizeof(Literal));
480 }
481 
updateWatch(Solver & s,uint32 pos)482 bool Clause::updateWatch(Solver& s, uint32 pos) {
483 	Literal* it;
484 	if (!isSmall()) {
485 		for (Literal* begin = head_ + ClauseHead::HEAD_LITS, *end = this->end(), *first = begin + local_.mem[1];;) {
486 			for (it = first; it < end; ++it) {
487 				if (!s.isFalse(*it)) {
488 					std::swap(*it, head_[pos]);
489 					local_.mem[1] = static_cast<uint32>(++it - begin);
490 					return true;
491 				}
492 			}
493 			if (first == begin) { break; }
494 			end = first;
495 			first = begin;
496 		}
497 	}
498 	else if (!s.isFalse(*(it = this->small())) || !s.isFalse(*++it)) {
499 #if defined(__GNUC__) && __GNUC__ == 7 && __GNUC_MINOR__ < 2
500 		// Add compiler barrier to prevent gcc Bug 81365:
501 		// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81365
502 		asm volatile("" ::: "memory");
503 #endif
504 		std::swap(head_[pos], *it);
505 		return true;
506 	}
507 	return false;
508 }
tail()509 Clause::LitRange Clause::tail() {
510 	if (!isSmall()) { return LitRange(head_+ClauseHead::HEAD_LITS, end()); }
511 	Literal* tBeg = small(), *tEnd = tBeg;
512 	if (*tEnd != lit_false()) ++tEnd;
513 	if (*tEnd != lit_false()) ++tEnd;
514 	return LitRange(tBeg, tEnd);
515 }
reason(Solver & s,Literal p,LitVec & out)516 void Clause::reason(Solver& s, Literal p, LitVec& out) {
517 	out.push_back(~head_[p == head_[0]]);
518 	if (!isSentinel(head_[2])) {
519 		out.push_back(~head_[2]);
520 		LitRange t = tail();
521 		for (const Literal* r = t.first; r != t.second; ++r) {
522 			out.push_back(~*r);
523 		}
524 		if (contracted()) {
525 			const Literal* r = t.second;
526 			do { out.push_back(~*r); } while (!r++->flagged());
527 		}
528 	}
529 	if (learnt()) {
530 		s.updateOnReason(info_.score(), p, out);
531 	}
532 }
533 
minimize(Solver & s,Literal p,CCMinRecursive * rec)534 bool Clause::minimize(Solver& s, Literal p, CCMinRecursive* rec) {
535 	s.updateOnMinimize(info_.score());
536 	uint32 other = p == head_[0];
537 	if (!s.ccMinimize(~head_[other], rec) || !s.ccMinimize(~head_[2], rec)) { return false; }
538 	LitRange t = tail();
539 	for (const Literal* r = t.first; r != t.second; ++r) {
540 		if (!s.ccMinimize(~*r, rec)) { return false; }
541 	}
542 	if (contracted()) {
543 		do {
544 			if (!s.ccMinimize(~*t.second, rec)) { return false; }
545 		} while (!t.second++->flagged());
546 	}
547 	return true;
548 }
549 
isReverseReason(const Solver & s,Literal p,uint32 maxL,uint32 maxN)550 bool Clause::isReverseReason(const Solver& s, Literal p, uint32 maxL, uint32 maxN) {
551 	uint32 other   = p == head_[0];
552 	if (!isRevLit(s, head_[other], maxL) || !isRevLit(s, head_[2], maxL)) { return false; }
553 	uint32 notSeen = !s.seen(head_[other].var()) + !s.seen(head_[2].var());
554 	LitRange t     = tail();
555 	for (const Literal* r = t.first; r != t.second && notSeen <= maxN; ++r) {
556 		if (!isRevLit(s, *r, maxL)) { return false; }
557 		notSeen += !s.seen(r->var());
558 	}
559 	if (contracted()) {
560 		const Literal* r = t.second;
561 		do { notSeen += !s.seen(r->var()); } while (notSeen <= maxN && !r++->flagged());
562 	}
563 	return notSeen <= maxN;
564 }
565 
simplify(Solver & s,bool reinit)566 bool Clause::simplify(Solver& s, bool reinit) {
567 	assert(s.decisionLevel() == 0 && s.queueSize() == 0);
568 	if (ClauseHead::satisfied(s)) {
569 		detach(s);
570 		return true;
571 	}
572 	LitRange t = tail();
573 	Literal* it= t.first - !isSmall(), *j;
574 	// skip free literals
575 	while (it != t.second && s.value(it->var()) == value_free) { ++it; }
576 	// copy remaining free literals
577 	for (j = it; it != t.second; ++it) {
578 		if      (s.value(it->var()) == value_free) { *j++ = *it; }
579 		else if (s.isTrue(*it)) { Clause::detach(s); return true;}
580 	}
581 	// replace any false lits with sentinels
582 	for (Literal* r = j; r != t.second; ++r) { *r = lit_false(); }
583 	if (!isSmall()) {
584 		uint32 size = std::max((uint32)ClauseHead::HEAD_LITS, static_cast<uint32>(j-head_));
585 		local_.setSize(size);
586 		local_.clearIdx();
587 		if (j != t.second && learnt() && !strengthened()) {
588 			// mark last literal so that we can recompute alloc size later
589 			t.second[-1].flag();
590 			local_.markStrengthened();
591 		}
592 		if (reinit && size > 3) {
593 			detach(s);
594 			std::random_shuffle(head_, j, s.rng);
595 			attach(s);
596 		}
597 	}
598 	else if (s.isFalse(head_[2])) {
599 		head_[2]   = t.first[0];
600 		t.first[0] = t.first[1];
601 		t.first[1] = lit_false();
602 		--j;
603 	}
604 	return j <= t.first && ClauseHead::toImplication(s);
605 }
606 
isOpen(const Solver & s,const TypeSet & x,LitVec & freeLits)607 uint32 Clause::isOpen(const Solver& s, const TypeSet& x, LitVec& freeLits) {
608 	if (!x.inSet(ClauseHead::type()) || ClauseHead::satisfied(s)) {
609 		return 0;
610 	}
611 	assert(s.queueSize() == 0 && "Watches might be false!");
612 	freeLits.push_back(head_[0]);
613 	freeLits.push_back(head_[1]);
614 	if (!s.isFalse(head_[2])) freeLits.push_back(head_[2]);
615 	ValueRep v;
616 	LitRange t = tail();
617 	for (Literal* r = t.first; r != t.second; ++r) {
618 		if ( (v = s.value(r->var())) == value_free) {
619 			freeLits.push_back(*r);
620 		}
621 		else if (v == trueValue(*r)) {
622 			std::swap(head_[2], *r);
623 			return 0;
624 		}
625 	}
626 	return ClauseHead::type();
627 }
628 
undoLevel(Solver & s)629 void Clause::undoLevel(Solver& s) {
630 	assert(!isSmall());
631 	uint32   t = local_.size();
632 	uint32  ul = s.jumpLevel();
633 	Literal* r = head_+t;
634 	while (!r->flagged() && (s.value(r->var()) == value_free || s.level(r->var()) > ul)) {
635 		++t;
636 		++r;
637 	}
638 	if (r->flagged() || s.level(r->var()) == 0) {
639 		r->unflag();
640 		t += !isSentinel(*r);
641 		local_.clearContracted();
642 	}
643 	else {
644 		s.addUndoWatch(s.level(r->var()), this);
645 	}
646 	local_.setSize(t);
647 }
648 
toLits(LitVec & out) const649 void Clause::toLits(LitVec& out) const {
650 	out.insert(out.end(), head_, (head_+ClauseHead::HEAD_LITS)-isSentinel(head_[2]));
651 	LitRange t = const_cast<Clause&>(*this).tail();
652 	if (contracted()) { while (!t.second++->flagged()) {;} }
653 	out.insert(out.end(), t.first, t.second);
654 }
655 
strengthen(Solver & s,Literal p,bool toShort)656 ClauseHead::BoolPair Clause::strengthen(Solver& s, Literal p, bool toShort) {
657 	LitRange t  = tail();
658 	Literal* eoh= head_+ClauseHead::HEAD_LITS;
659 	Literal* eot= t.second;
660 	Literal* it = std::find(head_, eoh, p);
661 	BoolPair ret(false, false);
662 	if (it != eoh) {
663 		if (it != head_+2) { // update watch
664 			*it = head_[2];
665 			s.removeWatch(~p, this);
666 			Literal* best = it, *n;
667 			for (n = t.first; n != eot && s.isFalse(*best); ++n) {
668 				if (!s.isFalse(*n) || s.level(n->var()) > s.level(best->var())) {
669 					best = n;
670 				}
671 			}
672 			std::swap(*it, *best);
673 			s.addWatch(~*it, ClauseWatch(this));
674 			it = head_+2;
675 		}
676 		// replace cache literal with literal from tail
677 		if ((*it  = *t.first) != lit_false()) {
678 			eot     = removeFromTail(s, t.first, eot);
679 		}
680 		ret.first = true;
681 	}
682 	else if ((it = std::find(t.first, eot, p)) != eot) {
683 		eot       = removeFromTail(s, it, eot);
684 		ret.first = true;
685 	}
686 	else if (contracted()) {
687 		for (; *it != p && !it->flagged(); ++it) { ; }
688 		ret.first = *it == p;
689 		eot       = *it == p ? removeFromTail(s, it, eot) : it + 1;
690 	}
691 	if (ret.first && ~p == s.tagLiteral()) {
692 		clearTagged();
693 	}
694 	ret.second = toShort && eot == t.first && toImplication(s);
695 	return ret;
696 }
697 
removeFromTail(Solver & s,Literal * it,Literal * end)698 Literal* Clause::removeFromTail(Solver& s, Literal* it, Literal* end) {
699 	assert(it != end || contracted());
700 	if (!contracted()) {
701 		*it  = *--end;
702 		*end = lit_false();
703 		if (!isSmall()) {
704 			local_.setSize(local_.size()-1);
705 			local_.clearIdx();
706 		}
707 	}
708 	else {
709 		uint32 uLev  = s.level(end->var());
710 		Literal* j   = it;
711 		while ( !j->flagged() ) { *j++ = *++it; }
712 		*j           = lit_false();
713 		uint32 nLev  = s.level(end->var());
714 		if (uLev != nLev && s.removeUndoWatch(uLev, this) && nLev != 0) {
715 			s.addUndoWatch(nLev, this);
716 		}
717 		if (j != end) { (j-1)->flag(); }
718 		else          { local_.clearContracted(); }
719 		end = j;
720 	}
721 	if (learnt() && !isSmall() && !strengthened()) {
722 		end->flag();
723 		local_.markStrengthened();
724 	}
725 	return end;
726 }
size() const727 uint32 Clause::size() const {
728 	LitRange t = const_cast<Clause&>(*this).tail();
729 	return !isSentinel(head_[2])
730 		? 3u + static_cast<uint32>(t.second - t.first)
731 		: 2u;
732 }
733 /////////////////////////////////////////////////////////////////////////////////////////
734 // mt::SharedLitsClause
735 /////////////////////////////////////////////////////////////////////////////////////////
736 namespace mt {
newClause(Solver & s,SharedLiterals * shared_lits,const InfoType & e,const Literal * lits,bool addRef)737 ClauseHead* SharedLitsClause::newClause(Solver& s, SharedLiterals* shared_lits, const InfoType& e, const Literal* lits, bool addRef) {
738 	return new (s.allocSmall()) SharedLitsClause(s, shared_lits, lits, e, addRef);
739 }
740 
SharedLitsClause(Solver & s,SharedLiterals * shared_lits,const Literal * w,const InfoType & e,bool addRef)741 SharedLitsClause::SharedLitsClause(Solver& s, SharedLiterals* shared_lits, const Literal* w, const InfoType& e, bool addRef)
742 	: ClauseHead(e) {
743 	static_assert(sizeof(SharedLitsClause) <= 32, "Unsupported Padding");
744 	shared_ = addRef ? shared_lits->share() : shared_lits;
745 	std::memcpy(head_, w, std::min((uint32)ClauseHead::HEAD_LITS, shared_lits->size())*sizeof(Literal));
746 	attach(s);
747 	if (learnt()) { s.addLearntBytes(32); }
748 }
749 
cloneAttach(Solver & other)750 Constraint* SharedLitsClause::cloneAttach(Solver& other) {
751 	return SharedLitsClause::newClause(other, shared_, InfoType(this->type()), head_);
752 }
753 
updateWatch(Solver & s,uint32 pos)754 bool SharedLitsClause::updateWatch(Solver& s, uint32 pos) {
755 	Literal  other = head_[1^pos];
756 	for (const Literal* r = shared_->begin(), *end = shared_->end(); r != end; ++r) {
757 		// at this point we know that head_[2] is false so we only need to check
758 		// that we do not watch the other watched literal twice!
759 		if (!s.isFalse(*r) && *r != other) {
760 			head_[pos] = *r; // replace watch
761 			// try to replace cache literal
762 			switch( std::min(static_cast<uint32>(8), static_cast<uint32>(end-r)) ) {
763 				case 8: if (!s.isFalse(*++r) && *r != other) { head_[2] = *r; return true; } // FALLTHRU
764 				case 7: if (!s.isFalse(*++r) && *r != other) { head_[2] = *r; return true; } // FALLTHRU
765 				case 6: if (!s.isFalse(*++r) && *r != other) { head_[2] = *r; return true; } // FALLTHRU
766 				case 5: if (!s.isFalse(*++r) && *r != other) { head_[2] = *r; return true; } // FALLTHRU
767 				case 4: if (!s.isFalse(*++r) && *r != other) { head_[2] = *r; return true; } // FALLTHRU
768 				case 3: if (!s.isFalse(*++r) && *r != other) { head_[2] = *r; return true; } // FALLTHRU
769 				case 2: if (!s.isFalse(*++r) && *r != other) { head_[2] = *r; return true; } // FALLTHRU
770 				default: return true;
771 			}
772 		}
773 	}
774 	return false;
775 }
776 
reason(Solver & s,Literal p,LitVec & out)777 void SharedLitsClause::reason(Solver& s, Literal p, LitVec& out) {
778 	for (const Literal* r = shared_->begin(), *end = shared_->end(); r != end; ++r) {
779 		assert(s.isFalse(*r) || *r == p);
780 		if (*r != p) { out.push_back(~*r); }
781 	}
782 	if (learnt()) {
783 		s.updateOnReason(info_.score(), p, out);
784 	}
785 }
786 
minimize(Solver & s,Literal p,CCMinRecursive * rec)787 bool SharedLitsClause::minimize(Solver& s, Literal p, CCMinRecursive* rec) {
788 	s.updateOnMinimize(info_.score());
789 	for (const Literal* r = shared_->begin(), *end = shared_->end(); r != end; ++r) {
790 		if (*r != p && !s.ccMinimize(~*r, rec)) { return false; }
791 	}
792 	return true;
793 }
794 
isReverseReason(const Solver & s,Literal p,uint32 maxL,uint32 maxN)795 bool SharedLitsClause::isReverseReason(const Solver& s, Literal p, uint32 maxL, uint32 maxN) {
796 	uint32 notSeen = 0;
797 	for (const Literal* r = shared_->begin(), *end = shared_->end(); r != end; ++r) {
798 		if (*r == p) continue;
799 		if (!isRevLit(s, *r, maxL)) return false;
800 		if (!s.seen(r->var()) && ++notSeen > maxN) return false;
801 	}
802 	return true;
803 }
804 
simplify(Solver & s,bool reinit)805 bool SharedLitsClause::simplify(Solver& s, bool reinit) {
806 	if (ClauseHead::satisfied(s)) {
807 		detach(s);
808 		return true;
809 	}
810 	uint32 optSize = shared_->simplify(s);
811 	if (optSize == 0) {
812 		detach(s);
813 		return true;
814 	}
815 	else if (optSize <= Clause::MAX_SHORT_LEN) {
816 		Literal lits[Clause::MAX_SHORT_LEN];
817 		Literal* j = lits;
818 		for (const Literal* r = shared_->begin(), *e = shared_->end(); r != e; ++r) {
819 			if (!s.isFalse(*r)) *j++ = *r;
820 		}
821 		// safe extra data
822 		InfoType myInfo = info_;
823 		// detach & destroy but do not release memory
824 		detach(s);
825 		SharedLitsClause::destroy(0, false);
826 		// construct short clause in "this"
827 		ClauseHead* h = Clause::newClause(this, s, ClauseRep::prepared(lits, static_cast<uint32>(j-lits), myInfo));
828 		return h->simplify(s, reinit);
829 	}
830 	else if (s.isFalse(head_[2])) {
831 		// try to replace cache lit with non-false literal
832 		for (const Literal* r = shared_->begin(), *e = shared_->end(); r != e; ++r) {
833 			if (!s.isFalse(*r) && std::find(head_, head_+2, *r) == head_+2) {
834 				head_[2] = *r;
835 				break;
836 			}
837 		}
838 	}
839 	return false;
840 }
841 
destroy(Solver * s,bool detachFirst)842 void SharedLitsClause::destroy(Solver* s, bool detachFirst) {
843 	if (s) {
844 		if (detachFirst) { ClauseHead::detach(*s); }
845 		if (learnt())    { s->freeLearntBytes(32); }
846 	}
847 	shared_->release();
848 	void* mem = this;
849 	this->~SharedLitsClause();
850 	if (s) { s->freeSmall(mem); }
851 }
852 
isOpen(const Solver & s,const TypeSet & x,LitVec & freeLits)853 uint32 SharedLitsClause::isOpen(const Solver& s, const TypeSet& x, LitVec& freeLits) {
854 	if (!x.inSet(ClauseHead::type()) || ClauseHead::satisfied(s)) {
855 		return 0;
856 	}
857 	Literal* head = head_;
858 	ValueRep v;
859 	for (const Literal* r = shared_->begin(), *end = shared_->end(); r != end; ++r) {
860 		if ( (v = s.value(r->var())) == value_free ) {
861 			freeLits.push_back(*r);
862 		}
863 		else if (v == trueValue(*r)) {
864 			head[2] = *r; // remember as cache literal
865 			return 0;
866 		}
867 	}
868 	return ClauseHead::type();
869 }
870 
toLits(LitVec & out) const871 void SharedLitsClause::toLits(LitVec& out) const {
872 	out.insert(out.end(), shared_->begin(), shared_->end());
873 }
874 
strengthen(Solver &,Literal,bool)875 ClauseHead::BoolPair SharedLitsClause::strengthen(Solver&, Literal, bool) {
876 	return BoolPair(false, false);
877 }
878 
size() const879 uint32 SharedLitsClause::size() const { return shared_->size(); }
880 } // end namespace mt
881 
882 /////////////////////////////////////////////////////////////////////////////////////////
883 // LoopFormula
884 /////////////////////////////////////////////////////////////////////////////////////////
newLoopFormula(Solver & s,const ClauseRep & c1,const Literal * atoms,uint32 nAtoms,bool heu)885 LoopFormula* LoopFormula::newLoopFormula(Solver& s, const ClauseRep& c1, const Literal* atoms, uint32 nAtoms, bool heu) {
886 	uint32 bytes = sizeof(LoopFormula) + (c1.size + nAtoms + 2) * sizeof(Literal);
887 	void* mem = Detail::alloc(bytes);
888 	s.addLearntBytes(bytes);
889 	return new (mem)LoopFormula(s, c1, atoms, nAtoms, heu);
890 }
LoopFormula(Solver & s,const ClauseRep & c1,const Literal * atoms,uint32 nAtoms,bool heu)891 LoopFormula::LoopFormula(Solver& s, const ClauseRep& c1, const Literal* atoms, uint32 nAtoms, bool heu) {
892 	act_ = c1.info.score();
893 	lits_[0] = lit_true(); // Starting sentinel
894 	std::memcpy(lits_ + 1, c1.lits, c1.size * sizeof(Literal));
895 	lits_[end_ = c1.size + 1] = lit_true(); // Ending sentinel
896 	s.addWatch(~lits_[2], this, (2 << 1) + 1);
897 	lits_[2].flag();
898 	size_  = c1.size + nAtoms + 2;
899 	str_   = 0;
900 	xPos_  = 1;
901 	other_ = 1;
902 	for (uint32 i = 0, x = end_ + 1; i != nAtoms; ++i, ++x) {
903 		act_.bumpActivity();
904 		s.addWatch(~(lits_[x] = atoms[i]), this, (1 << 1) + 1);
905 		if (heu) {
906 			lits_[1] = atoms[i];
907 			s.heuristic()->newConstraint(s, lits_ + 1, c1.size, Constraint_t::Loop);
908 		}
909 	}
910 	(lits_[1] = c1.lits[0]).flag();
911 }
destroy(Solver * s,bool detach)912 void LoopFormula::destroy(Solver* s, bool detach) {
913 	if (s) {
914 		if (detach) { this->detach(*s); }
915 		if (str_)   { while (lits_[size_++].rep() != 3u) { ; } }
916 		s->freeLearntBytes(sizeof(LoopFormula) + (size_ * sizeof(Literal)));
917 	}
918 	void* mem = static_cast<Constraint*>(this);
919 	this->~LoopFormula();
920 	Detail::free(mem);
921 }
detach(Solver & s)922 void LoopFormula::detach(Solver& s) {
923 	for (Literal* it = begin() + xPos_; !isSentinel(*it); ++it) {
924 		if (it->flagged()) { s.removeWatch(~*it, this); it->unflag(); }
925 	}
926 	for (Literal* it = xBegin(), *end = xEnd(); it != end; ++it) {
927 		s.removeWatch(~*it, this);
928 	}
929 }
otherIsSat(const Solver & s)930 bool LoopFormula::otherIsSat(const Solver& s) {
931 	if (other_ != xPos_)          { return s.isTrue(lits_[other_]); }
932 	if (!s.isTrue(lits_[other_])) { return false; }
933 	for (Literal* it = xBegin(), *end = xEnd(); it != end; ++it) {
934 		if (!s.isTrue(*it)) {
935 			if (lits_[xPos_].flagged()){ (lits_[xPos_] = *it).flag(); }
936 			else                       { lits_[xPos_] = *it; }
937 			return false;
938 		}
939 	}
940 	return true;
941 }
propagate(Solver & s,Literal p,uint32 & data)942 Constraint::PropResult LoopFormula::propagate(Solver& s, Literal p, uint32& data) {
943 	if (otherIsSat(s)) { // already satisfied?
944 		return PropResult(true, true);
945 	}
946 	uint32 idx = data >> 1;
947 	Literal* w = lits_ + idx;
948 	bool  head = idx == xPos_;
949 	if (head) { // p is one of the atoms - move to active part
950 		p = ~p;
951 		if (*w != p && s.isFalse(*w)) { return PropResult(true, true); }
952 		if (!w->flagged())            { *w = p; return PropResult(true, true); }
953 		(*w = p).flag();
954 	}
955 	for (int bounds = 0, dir = ((data & 1) << 1) - 1;;) {
956 		// search non-false literal - sentinels guarantee termination
957 		for (w += dir; s.isFalse(*w); w += dir) {;}
958 		if (!isSentinel(*w)) {
959 			uint32 nIdx = static_cast<uint32>(w - lits_);
960 			// other watched literal?
961 			if (w->flagged()) { other_ = nIdx; continue; }
962 			// replace watch
963 			lits_[idx].unflag();
964 			w->flag();
965 			// add new watch only w is not one of the atoms
966 			// and keep previous watch if p is one of the atoms
967 			if (nIdx != xPos_) { s.addWatch(~*w, this, (nIdx << 1) + (dir==1)); }
968 			return PropResult(true, head);
969 		}
970 		else if (++bounds == 1) {
971 			w     = lits_ + idx; // Halfway through, restart search, but
972 			dir  *= -1;          // this time walk in the opposite direction.
973 			data ^= 1;           // Save new direction of watch
974 		}
975 		else { // clause is unit
976 			bool ok = s.force(lits_[other_], this);
977 			if (other_ == xPos_ && ok) { // all lits in inactive part are implied
978 				for (Literal* it = xBegin(), *end = xEnd(); it != end && (ok = s.force(*it, this)) == true; ++it) { ; }
979 			}
980 			return PropResult(ok, true);
981 		}
982 	}
983 }
reason(Solver & s,Literal p,LitVec & lits)984 void LoopFormula::reason(Solver& s, Literal p, LitVec& lits) {
985 	// p = body: all literals in active clause
986 	// p = atom: only bodies
987 	for (Literal* it = begin() + (other_ == xPos_); !isSentinel(*it); ++it) {
988 		if (*it != p) { lits.push_back(~*it); }
989 	}
990 	s.updateOnReason(act_, p, lits);
991 }
minimize(Solver & s,Literal p,CCMinRecursive * rec)992 bool LoopFormula::minimize(Solver& s, Literal p, CCMinRecursive* rec) {
993 	s.updateOnMinimize(act_);
994 	for (Literal* it = begin() + (other_ == xPos_); !isSentinel(*it); ++it) {
995 		if (*it != p && !s.ccMinimize(~*it, rec)) { return false; }
996 	}
997 	return true;
998 }
size() const999 uint32 LoopFormula::size() const {
1000 	return size_ - (2 + xPos_);
1001 }
locked(const Solver & s) const1002 bool LoopFormula::locked(const Solver& s) const {
1003 	if (other_ != xPos_ || !s.isTrue(lits_[other_])) {
1004 		return s.isTrue(lits_[other_]) && s.reason(lits_[other_]) == this;
1005 	}
1006 	LoopFormula& self = const_cast<LoopFormula&>(*this);
1007 	for (const Literal* it = self.xBegin(), *end = self.xEnd(); it != end; ++it) {
1008 		if (s.isTrue(*it) && s.reason(*it) == this) { return true; }
1009 	}
1010 	return false;
1011 }
isOpen(const Solver & s,const TypeSet & xs,LitVec & freeLits)1012 uint32 LoopFormula::isOpen(const Solver& s, const TypeSet& xs, LitVec& freeLits) {
1013 	if (!xs.inSet(Constraint_t::Loop) || otherIsSat(s)) {
1014 		return 0;
1015 	}
1016 	for (Literal* it = begin() + xPos_; !isSentinel(*it); ++it) {
1017 		if      (s.value(it->var()) == value_free) { freeLits.push_back(*it); }
1018 		else if (s.isTrue(*it))                    { other_ = static_cast<uint32>(it-lits_); return 0; }
1019 	}
1020 	for (Literal* it = xBegin(), *end = xEnd(); it != end; ++it) {
1021 		if (s.value(it->var()) == value_free) { freeLits.push_back(*it); }
1022 	}
1023 	return Constraint_t::Loop;
1024 }
simplify(Solver & s,bool)1025 bool LoopFormula::simplify(Solver& s, bool) {
1026 	if (otherIsSat(s) || (other_ != xPos_ && (other_ = xPos_) != 0 && otherIsSat(s))) {
1027 		detach(s);
1028 		return true;
1029 	}
1030 	Literal* it = begin(), *j, *end = xEnd();
1031 	while (s.value(it->var()) == value_free) { ++it; }
1032 	if (!isSentinel(*(j=it))) {
1033 		// simplify active clause
1034 		if (*it == lits_[xPos_]){ xPos_ = 0; }
1035 		for (GenericWatch* w; !isSentinel(*it); ++it) {
1036 			if (s.value(it->var()) == value_free) {
1037 				if (it->flagged() && (w = s.getWatch(~*it, this)) != 0) {
1038 					w->data = (static_cast<uint32>(j - lits_) << 1) + (w->data&1);
1039 				}
1040 				*j++ = *it;
1041 			}
1042 			else if (s.isTrue(*it)) { detach(s); return true; }
1043 			else                    { assert(!it->flagged() && "Constraint not propagated!"); }
1044 		}
1045 		*j   = lit_true();
1046 		end_ = static_cast<uint32>(j - lits_);
1047 	}
1048 	// simplify extra part
1049 	for (++it, ++j; it != end; ++it) {
1050 		if (s.value(it->var()) == value_free && xPos_) { *j++ = *it; }
1051 		else { s.removeWatch(~*it, this); }
1052 	}
1053 	bool isClause = static_cast<uint32>(j - xBegin()) == 1;
1054 	if (isClause) { --j; }
1055 	if (j != end) { // size changed?
1056 		if (!str_)   { (end-1)->rep() = 3u; str_ = 1u; }
1057 		if (isClause){
1058 			assert(xPos_ && *j == lits_[xPos_]);
1059 			if (!lits_[xPos_].flagged()) { s.removeWatch(~*j, this); }
1060 			xPos_ = 0;
1061 		}
1062 		size_ = static_cast<uint32>((end = j) - lits_);
1063 	}
1064 	assert(!isClause || xPos_ == 0);
1065 	other_ = xPos_ + 1;
1066 	ClauseRep act = ClauseRep::create(begin(), end_ - 1, Constraint_t::Loop);
1067 	if (act.isImp() && s.allowImplicit(act)) {
1068 		detach(s);
1069 		ClauseCreator::Result res;
1070 		for (it = xBegin(); it != end && res.ok() && !res.local; ++it) {
1071 			lits_[xPos_] = *it;
1072 			res = ClauseCreator::create(s, act, ClauseCreator::clause_no_add);
1073 			POTASSCO_ASSERT(lits_[xPos_] == *it, "LOOP MUST NOT CONTAIN ASSIGNED VARS!");
1074 		}
1075 		if (!xPos_) { res = ClauseCreator::create(s, act, ClauseCreator::clause_no_add); }
1076 		POTASSCO_ASSERT(res.ok() && !res.local, "LOOP MUST NOT CONTAIN AUX VARS!");
1077 		return true;
1078 	}
1079 	return false;
1080 }
1081 
1082 }
1083