00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <clasp/weight_constraint.h>
00022 #include <clasp/clause.h>
00023 #include <clasp/solver.h>
00024 #include <clasp/util/misc_types.h>
00025 #include <algorithm>
00026
00027 namespace Clasp {
00029
00031
00032
00033
00034 WeightLitsRep WeightLitsRep::create(Solver& s, WeightLitVec& lits, weight_t bound) {
00035
00036 LitVec::size_type j = 0, other;
00037 const weight_t MAX_W= std::numeric_limits<weight_t>::max();
00038 for (LitVec::size_type i = 0; i != lits.size(); ++i) {
00039 lits[i].first.clearWatch();
00040 Literal x = lits[i].first;
00041 if (lits[i].second != 0 && s.topValue(x.var()) == value_free) {
00042 if (lits[i].second < 0) {
00043 lits[i].second = -lits[i].second;
00044 lits[i].first = x = ~lits[i].first;
00045 CLASP_ASSERT_CONTRACT_MSG(bound < 0 || (MAX_W-bound) >= lits[i].second, "bound out of range");
00046 bound += lits[i].second;
00047 }
00048 if (!s.seen(x.var())) {
00049 if (i != j) lits[j] = lits[i];
00050 s.markSeen(x);
00051 ++j;
00052 }
00053 else if (!s.seen(~x)) {
00054 for (other = 0; other != j && lits[other].first != x; ++other) { ; }
00055 lits[other].second += lits[i].second;
00056 }
00057 else {
00058 for (other = 0; other != j && lits[other].first != ~x; ++other) { ; }
00059 bound -= lits[i].second;
00060 lits[other].second -= lits[i].second;
00061 if (lits[other].second < 0) {
00062 lits[other].first = x;
00063 lits[other].second = -lits[other].second;
00064 s.clearSeen(x.var());
00065 s.markSeen(x);
00066 bound += lits[other].second;
00067 }
00068 else if (lits[other].second == 0) {
00069 s.clearSeen(x.var());
00070 std::memmove(&lits[0]+other, &lits[0]+other+1, (j-other-1)*sizeof(lits[other]));
00071 --j;
00072 }
00073 }
00074 }
00075 else if (s.isTrue(x)) { bound -= lits[i].second; }
00076 }
00077 lits.erase(lits.begin()+j, lits.end());
00078 if (bound < 0) { bound = 0; }
00079
00080 weight_t sumW = 0;
00081 weight_t minW = MAX_W, maxW = 1;
00082 weight_t B = std::max(bound, 1);
00083 for (LitVec::size_type i = 0; i != lits.size(); ++i) {
00084 assert(lits[i].second > 0);
00085 s.clearSeen(lits[i].first.var());
00086 if (lits[i].second > maxW) { maxW = lits[i].second = std::min(lits[i].second, B); }
00087 if (lits[i].second < minW) { minW = lits[i].second; }
00088 CLASP_ASSERT_CONTRACT_MSG((MAX_W - sumW) >= lits[i].second, "Sum of weights out of range");
00089 sumW += lits[i].second;
00090 }
00091
00092 if (maxW != minW) {
00093 std::stable_sort(lits.begin(), lits.end(), compose22(
00094 std::greater<weight_t>(),
00095 select2nd<WeightLiteral>(),
00096 select2nd<WeightLiteral>()));
00097 }
00098 else if (minW != 1) {
00099
00100 bound = (bound+(minW-1))/minW;
00101 sumW = (sumW+(minW-1))/minW;
00102 for (LitVec::size_type i = 0; i != lits.size(); ++i) { lits[i].second = 1; }
00103 }
00104 WeightLitsRep result = { !lits.empty() ? &lits[0] : 0, (uint32)lits.size(), bound, sumW };
00105 return result;
00106 }
00107
00108
00109 bool WeightLitsRep::propagate(Solver& s, Literal W) {
00110 if (bound <= 0) { return s.force(W); }
00111 else if (bound > reach) { return s.force(~W);}
00112 else if (s.topValue(W.var()) == value_free) {
00113 return true;
00114 }
00115
00116 bool bpTrue = s.isTrue(W);
00117 weight_t B = bpTrue ? (reach-bound)+1 : bound;
00118 while (lits->second >= B) {
00119 reach -= lits->second;
00120 if (!s.force(bpTrue ? lits->first : ~lits->first, 0)) { return false; }
00121 if ((bpTrue && (bound -= lits->second) <= 0) || --size == 0) { return true; }
00122 ++lits;
00123 }
00124 if (lits->second > 1 && lits->second == lits[size-1].second) {
00125 B = lits->second;
00126 bound = (bound + (B-1)) / B;
00127 reach = (reach + (B-1)) / B;
00128 for (uint32 i = 0; i != size && lits[i].second != 1; ++i) { lits[i].second = 1; }
00129 }
00130 return true;
00131 }
00133
00135 WeightConstraint::WL::WL(uint32 s, bool shared, bool hasW) : sz(s), rc(shared), w(hasW) { }
00136 uint8* WeightConstraint::WL::address() { return reinterpret_cast<unsigned char*>(this) - (sizeof(uint32) * rc); }
00137 WeightConstraint::WL* WeightConstraint::WL::clone(){
00138 if (shareable()) {
00139 ++*reinterpret_cast<Clasp::atomic<uint32>*>(address());
00140 return this;
00141 }
00142 else {
00143 uint32 litSize = (size() << uint32(weights()))*sizeof(Literal);
00144 WL* x = new (::operator new(sizeof(WL) + litSize)) WL(size(), false, weights());
00145 std::memcpy(x->lits, this->lits, litSize);
00146 return x;
00147 }
00148 }
00149 void WeightConstraint::WL::release() {
00150 unsigned char* x = address();
00151 if (!shareable() || --*reinterpret_cast<Clasp::atomic<uint32>*>(x) == 0) {
00152 ::operator delete(x);
00153 }
00154 }
00155 uint32 WeightConstraint::WL::refCount() const {
00156 assert(shareable());
00157 return *reinterpret_cast<const Clasp::atomic<uint32>*>(const_cast<WL*>(this)->address());
00158 }
00160
00162 WeightConstraint::CPair WeightConstraint::create(Solver& s, Literal W, WeightLitVec& lits, weight_t bound, uint32 flags) {
00163 return WeightConstraint::create(s, W, WeightLitsRep::create(s, lits, bound), flags);
00164 }
00165 WeightConstraint::CPair WeightConstraint::create(Solver& s, Literal W, WeightLitsRep rep, uint32 flags) {
00166 CPair res;
00167 if (!s.sharedContext()->physicalShareProblem()) { flags |= create_no_share; }
00168 if (s.sharedContext()->frozen()) { flags |= (create_no_freeze|create_no_share); }
00169 res.con[0] = createImpl(s, W, rep, flags);
00170 if ((flags & create_eq_bound) != 0 && res.ok()) {
00171
00172 ++rep.bound;
00173 res.con[1] = createImpl(s, ~W, rep, flags);
00174 }
00175 return res;
00176 }
00177
00178 WeightConstraint* WeightConstraint::createImpl(Solver& s, Literal W, WeightLitsRep& rep, uint32 flags) {
00179 WeightConstraint* conflict = (WeightConstraint*)0x1;
00180 bool sat = (flags&create_sat) != 0 && rep.size;
00181 if (!rep.propagate(s, W)) { return conflict; }
00182 if (rep.unsat() || (rep.sat() && !sat)){ return 0; }
00183 if ((rep.bound == 1 || rep.bound == rep.reach) && (flags & create_explicit) == 0) {
00184 LitVec clause; clause.reserve(1 + rep.size);
00185 Literal bin[2];
00186 bool disj = rep.bound == 1;
00187 bool sat = false;
00188 clause.push_back(W ^ disj);
00189 for (LitVec::size_type i = 0; i != rep.size; ++i) {
00190 bin[0] = ~clause[0];
00191 bin[1] = rep.lits[i].first ^ disj;
00192 if (bin[0] != ~bin[1]) {
00193 if (bin[0] != bin[1]) { clause.push_back(~bin[1]); }
00194 if (!s.add(ClauseRep::create(bin, 2))){ return conflict; }
00195 }
00196 else { sat = true; }
00197 }
00198 return (sat || ClauseCreator::create(s, clause, 0)) ? 0 : conflict;
00199 }
00200 assert(rep.open() || (rep.sat() && sat));
00201 bool hasW = rep.hasWeights();
00202 uint32 size = 1 + rep.size;
00203 uint32 nb = sizeof(WeightConstraint) + (size+hasW)*sizeof(UndoInfo);
00204 uint32 wls = sizeof(WL) + (size << uint32(hasW))*sizeof(Literal);
00205 void* m = 0;
00206 WL* sL = 0;
00207 if ((flags & create_no_share) != 0) {
00208 nb = ((nb + 3) / 4)*4;
00209 m = ::operator new (nb + wls);
00210 sL = new (reinterpret_cast<unsigned char*>(m)+nb) WL(size, false, hasW);
00211 }
00212 else {
00213 static_assert(sizeof(Clasp::atomic<uint32>) == sizeof(uint32), "Invalid size!");
00214 m = ::operator new(nb);
00215 uint8* t = (uint8*)::operator new(wls + sizeof(uint32));
00216 *(new (t) Clasp::atomic<uint32>()) = 1;
00217 sL = new (t+sizeof(uint32)) WL(size, true, hasW);
00218 }
00219 assert(m && (reinterpret_cast<uintp>(m) & 7u) == 0);
00220 SharedContext* ctx = (flags & create_no_freeze) == 0 ? const_cast<SharedContext*>(s.sharedContext()) : 0;
00221 WeightConstraint* c = new (m) WeightConstraint(s, ctx, W, rep, sL);
00222 if (!c->integrateRoot(s)) {
00223 c->destroy(&s, true);
00224 return conflict;
00225 }
00226 if ((flags & create_no_add) == 0) { s.add(c); }
00227 return c;
00228 }
00229 WeightConstraint::WeightConstraint(Solver& s, SharedContext* ctx, Literal W, const WeightLitsRep& rep, WL* out) {
00230 const bool hasW = rep.hasWeights();
00231 lits_ = out;
00232 ownsLit_ = !out->shareable();
00233 Literal* p = lits_->lits;
00234 Literal* h = (Literal*)undo_;
00235 weight_t w = 1;
00236 Var mv = W.var();
00237 bound_[FFB_BTB] = (rep.reach-rep.bound)+1;
00238 bound_[FTB_BFB] = rep.bound;
00239 *p++ = ~W;
00240 if (hasW) *p++ = Literal::fromRep(w);
00241 if (ctx) ctx->setFrozen(W.var(), true);
00242 active_ = s.topValue(W.var())==value_free
00243 ? NOT_ACTIVE
00244 : FFB_BTB+s.isFalse(W);
00245 for (uint32 i = 0, j = 1, end = rep.size; i != end; ++i, ++j) {
00246 *p++ = h[j] = rep.lits[i].first;
00247 w = rep.lits[i].second;
00248 if (hasW) *p++= Literal::fromRep(w);
00249 addWatch(s, j, FTB_BFB);
00250 addWatch(s, j, FFB_BTB);
00251 if (ctx) ctx->setFrozen(h[j].var(), true);
00252 mv = std::max(mv, h[j].var());
00253 }
00254 if (hasW) s.requestData(mv+1);
00255
00256 uint32 off = active_ != NOT_ACTIVE;
00257 h[0] = W;
00258 s.heuristic()->newConstraint(s, h+off, rep.size+(1-off), Constraint_t::static_constraint);
00259
00260 up_ = undoStart();
00261 undo_[0].data = 0;
00262 undo_[up_].data = 0;
00263 setBpIndex(1);
00264 if (active_ == NOT_ACTIVE) {
00265 addWatch(s, 0, FTB_BFB);
00266 addWatch(s, 0, FFB_BTB);
00267 }
00268 else {
00269 uint32 d = active_;
00270 WeightConstraint::propagate(s, ~lit(0, (ActiveConstraint)active_), d);
00271 }
00272 }
00273
00274 WeightConstraint::WeightConstraint(Solver& s, const WeightConstraint& other) {
00275 lits_ = other.lits_->clone();
00276 ownsLit_ = 0;
00277 Literal* heu = (Literal*)undo_;
00278 heu[0] = ~lits_->lit(0);
00279 bound_[0] = other.bound_[0];
00280 bound_[1] = other.bound_[1];
00281 active_ = other.active_;
00282 if (active_ == NOT_ACTIVE && s.value(heu[0].var()) == value_free) {
00283 addWatch(s, 0, FTB_BFB);
00284 addWatch(s, 0, FFB_BTB);
00285 }
00286 for (uint32 i = 1, end = size(); i < end; ++i) {
00287 heu[i] = lits_->lit(i);
00288 if (s.value(heu[i].var()) == value_free) {
00289 addWatch(s, i, FTB_BFB);
00290 addWatch(s, i, FFB_BTB);
00291 }
00292 }
00293
00294 uint32 off = active_ != NOT_ACTIVE;
00295 s.heuristic()->newConstraint(s, heu+off, size()-off, Constraint_t::static_constraint);
00296
00297 std::memcpy(undo_, other.undo_, sizeof(UndoInfo)*(size()+isWeight()));
00298 up_ = other.up_;
00299 }
00300
00301 WeightConstraint::~WeightConstraint() {}
00302 Constraint* WeightConstraint::cloneAttach(Solver& other) {
00303 void* m = ::operator new(sizeof(WeightConstraint) + (size()+isWeight())*sizeof(UndoInfo));
00304 return new (m) WeightConstraint(other, *this);
00305 }
00306
00307 bool WeightConstraint::integrateRoot(Solver& s) {
00308 if (!s.decisionLevel() || highestUndoLevel(s) >= s.rootLevel() || s.hasConflict()) { return !s.hasConflict(); }
00309
00310 uint32 low = s.decisionLevel(), vDL;
00311 uint32 np = 0;
00312 for (uint32 i = 0, end = size(); i != end; ++i) {
00313 Var v = lits_->var(i);
00314 if (s.value(v) != value_free && (vDL = s.level(v)) != 0) {
00315 ++np;
00316 s.markSeen(v);
00317 low = std::min(low, vDL);
00318 }
00319 }
00320
00321 const LitVec& trail = s.trail();
00322 const uint32 end = trail.size() - s.queueSize();
00323 GenericWatch* w = 0;
00324 for (uint32 i = s.levelStart(low); i != end && np; ++i) {
00325 Literal p = trail[i];
00326 if (s.seen(p) && np--) {
00327 s.clearSeen(p.var());
00328 if (!s.hasConflict() && (w = s.getWatch(trail[i], this)) != 0) {
00329 w->propagate(s, p);
00330 }
00331 }
00332 }
00333 for (uint32 i = end; i != trail.size() && np; ++i) {
00334 if (s.seen(trail[i].var())) { --np; s.clearSeen(trail[i].var()); }
00335 }
00336 return !s.hasConflict();
00337 }
00338 void WeightConstraint::addWatch(Solver& s, uint32 idx, ActiveConstraint c) {
00339
00340 if (uint32(c^1) != active_) {
00341
00342 s.addWatch(~lit(idx, c), this, (idx<<1)+c);
00343 }
00344 }
00345
00346 void WeightConstraint::destroy(Solver* s, bool detach) {
00347 if (s && detach) {
00348 for (uint32 i = 0, end = size(); i != end; ++i) {
00349 s->removeWatch( lits_->lit(i), this );
00350 s->removeWatch(~lits_->lit(i), this );
00351 }
00352 for (uint32 i = s->decisionLevel(); i; --i) {
00353 s->removeUndoWatch(i, this);
00354 }
00355 }
00356 if (ownsLit_ == 0) { lits_->release(); }
00357 void* mem = static_cast<Constraint*>(this);
00358 this->~WeightConstraint();
00359 ::operator delete(mem);
00360 }
00361
00362 void WeightConstraint::setBpIndex(uint32 n){
00363 if (isWeight()) undo_[0].data = (n<<1)+(undo_[0].data&1);
00364 }
00365
00366
00367 uint32 WeightConstraint::highestUndoLevel(Solver& s) const {
00368 return up_ != undoStart()
00369 ? s.level(lits_->var(undoTop().idx()))
00370 : 0;
00371 }
00372
00373
00374
00375
00376 void WeightConstraint::updateConstraint(Solver& s, uint32 idx, ActiveConstraint c) {
00377 bound_[c] -= weight(idx);
00378 if (highestUndoLevel(s) != s.decisionLevel()) {
00379 s.addUndoWatch(s.decisionLevel(), this);
00380 }
00381 undo_[up_].data = (idx<<2) + (c<<1) + (undo_[up_].data & 1);
00382 ++up_;
00383 assert(!litSeen(idx));
00384 toggleLitSeen(idx);
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407 Constraint::PropResult WeightConstraint::propagate(Solver& s, Literal, uint32& d) {
00408
00409 ActiveConstraint c = (ActiveConstraint)(d&1);
00410 Literal body = lit(0, c);
00411 if ( uint32(c^1) == active_ || s.isTrue(body) ) {
00412
00413
00414 return PropResult(true, true);
00415 }
00416
00417
00418 updateConstraint(s, d >> 1, c);
00419 if (bound_[c] <= 0 || (isWeight() && litSeen(0))) {
00420 uint32 reasonData = !isWeight() ? UINT32_MAX : up_;
00421 if (!litSeen(0)) {
00422
00423 active_ = c;
00424 return PropResult(s.force(body, this, reasonData), true);
00425 }
00426 else {
00427
00428 uint32 n = getBpIndex();
00429 for (const uint32 end = size(); n != end && (bound_[c] - weight(n)) < 0; ++n) {
00430 if (!litSeen(n)) {
00431 active_ = c;
00432 Literal x = lit(n, c);
00433 if (!s.force(x, this, reasonData)) {
00434 return PropResult(false, true);
00435 }
00436 }
00437 }
00438 assert(n == 1 || n == size() || isWeight());
00439 setBpIndex(n);
00440 }
00441 }
00442 return PropResult(true, true);
00443 }
00444
00445
00446
00447
00448 void WeightConstraint::reason(Solver& s, Literal p, LitVec& r) {
00449 assert(active_ != NOT_ACTIVE);
00450 Literal x;
00451 uint32 stop = !isWeight() ? up_ : s.reasonData(p);
00452 assert(stop <= up_);
00453 for (uint32 i = undoStart(); i != stop; ++i) {
00454 UndoInfo u = undo_[i];
00455
00456 if (u.constraint() == (ActiveConstraint)active_) {
00457 x = lit(u.idx(), u.constraint());
00458 r.push_back( ~x );
00459 }
00460 }
00461 }
00462
00463 bool WeightConstraint::minimize(Solver& s, Literal p, CCMinRecursive* rec) {
00464 assert(active_ != NOT_ACTIVE);
00465 Literal x;
00466 uint32 stop = !isWeight() ? up_ : s.reasonData(p);
00467 assert(stop <= up_);
00468 for (uint32 i = undoStart(); i != stop; ++i) {
00469 UndoInfo u = undo_[i];
00470
00471 if (u.constraint() == (ActiveConstraint)active_) {
00472 x = lit(u.idx(), u.constraint());
00473 if (!s.ccMinimize(~x, rec)) {
00474 return false;
00475 }
00476 }
00477 }
00478 return true;
00479 }
00480
00481
00482 void WeightConstraint::undoLevel(Solver& s) {
00483 setBpIndex(1);
00484 for (UndoInfo u; up_ != undoStart() && s.value(lits_->var((u=undoTop()).idx())) == value_free;) {
00485 assert(litSeen(u.idx()));
00486 toggleLitSeen(u.idx());
00487 bound_[u.constraint()] += weight(u.idx());
00488 --up_;
00489 }
00490 if (!litSeen(0)) active_ = NOT_ACTIVE;
00491 }
00492
00493 bool WeightConstraint::simplify(Solver& s, bool) {
00494 if (bound_[0] <= 0 || bound_[1] <= 0) {
00495 for (uint32 i = 0, end = size(); i != end; ++i) {
00496 s.removeWatch( lits_->lit(i), this );
00497 s.removeWatch(~lits_->lit(i), this );
00498 }
00499 return true;
00500 }
00501 else if (s.value(lits_->var(0)) != value_free && (active_ == NOT_ACTIVE || isWeight())) {
00502 if (active_ == NOT_ACTIVE) {
00503 Literal W = ~lits_->lit(0);
00504 active_ = FFB_BTB+s.isFalse(W);
00505 }
00506 for (uint32 i = 0, end = size(); i != end; ++i) {
00507 s.removeWatch(lit(i, (ActiveConstraint)active_), this);
00508 }
00509 }
00510 if (lits_->unique() && size() > 4 && (up_ - undoStart()) > size()/2) {
00511 Literal* lits = lits_->lits;
00512 const uint32 inc = 1 + lits_->weights();
00513 uint32 end = lits_->size()*inc;
00514 uint32 i, j, idx = 1;
00515
00516 for (i = inc; s.value(lits[i].var()) == value_free; i += inc) {
00517 assert(!litSeen(idx));
00518 ++idx;
00519 }
00520
00521
00522 for (j = i, i += inc; i != end; i += inc) {
00523 if (s.value(lits[i].var()) == value_free) {
00524 lits[j] = lits[i];
00525 if (lits_->weights()) { lits[j+1] = lits[i+1]; }
00526 undo_[idx].data = 0;
00527 assert(!litSeen(idx));
00528 if (Clasp::GenericWatch* w = s.getWatch(lits[i], this)) {
00529 w->data = (idx<<1) + 1;
00530 }
00531 if (Clasp::GenericWatch* w = s.getWatch(~lits[i], this)) {
00532 w->data = (idx<<1) + 0;
00533 }
00534 j += inc;
00535 ++idx;
00536 }
00537 else {
00538 s.removeWatch(lits[i], this);
00539 s.removeWatch(~lits[i], this);
00540 }
00541 }
00542
00543 up_ = undoStart();
00544 setBpIndex(1);
00545 lits_->sz = idx;
00546 }
00547 return false;
00548 }
00549
00550 uint32 WeightConstraint::estimateComplexity(const Solver& s) const {
00551 weight_t B = std::min(bound_[0], bound_[1]);
00552 uint32 r = 2;
00553 for (uint32 i = 1; i != size() && B > 0; ++i) {
00554 if (s.value(lits_->var(i)) == value_free) {
00555 ++r;
00556 B -= weight(i);
00557 }
00558 }
00559 return r;
00560 }
00561 }