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