weight_constraint.cpp
Go to the documentation of this file.
00001 // 
00002 // Copyright (c) 2006-2011, Benjamin Kaufmann
00003 // 
00004 // This file is part of Clasp. See http://www.cs.uni-potsdam.de/clasp/ 
00005 // 
00006 // Clasp is free software; you can redistribute it and/or modify
00007 // it under the terms of the GNU General Public License as published by
00008 // the Free Software Foundation; either version 2 of the License, or
00009 // (at your option) any later version.
00010 // 
00011 // Clasp is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU General Public License for more details.
00015 // 
00016 // You should have received a copy of the GNU General Public License
00017 // along with Clasp; if not, write to the Free Software
00018 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
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 // WeightLitsRep
00031 // Removes assigned and merges duplicate/complementary literals.
00032 // return: achievable weight
00033 // post  : lits is sorted by decreasing weights
00034 WeightLitsRep WeightLitsRep::create(Solver& s, WeightLitVec& lits, weight_t bound) {
00035         // Step 1: remove assigned/superfluous literals and merge duplicate/complementary ones
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())) { // first time we see x, keep and mark x
00049                                 if (i != j) lits[j] = lits[i];
00050                                 s.markSeen(x);
00051                                 ++j;
00052                         }
00053                         else if (!s.seen(~x)) { // multi-occurrences of x, merge
00054                                 for (other = 0; other != j && lits[other].first != x; ++other) { ; }
00055                                 lits[other].second += lits[i].second;
00056                         }
00057                         else {                  // complementary literals ~x x
00058                                 for (other = 0; other != j && lits[other].first != ~x; ++other) { ; }
00059                                 bound              -= lits[i].second; // decrease by min(w(~x), w(x)) ; assume w(~x) > w(x)
00060                                 lits[other].second -= lits[i].second; // keep ~x, 
00061                                 if (lits[other].second < 0) {         // actually, w(x) > w(~x), 
00062                                         lits[other].first  = x;             // replace ~x with x
00063                                         lits[other].second = -lits[other].second;
00064                                         s.clearSeen(x.var());
00065                                         s.markSeen(x);
00066                                         bound += lits[other].second;        // and correct the bound
00067                                 }
00068                                 else if (lits[other].second == 0) {   // w(~x) == w(x) - drop both lits
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         // Step 2: compute min,max, achievable weight and clear flags set in step 1
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         // Step 3: sort by decreasing weight
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                 // disguised cardinality constraint
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 // Propagates top-level assignment.
00109 bool WeightLitsRep::propagate(Solver& s, Literal W) {
00110         if      (bound <= 0)    { return s.force(W); } // trivially SAT
00111         else if (bound > reach) { return s.force(~W);} // trivially UNSAT
00112         else if (s.topValue(W.var()) == value_free) { 
00113                 return true; 
00114         }
00115         // backward propagate
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 // WeightConstraint::WL
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 // WeightConstraint
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                 // Adds constraints for W == (lits == bound)
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; // con == disjunction or con == conjunction
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; // ffb-btb
00238         bound_[FTB_BFB] = rep.bound;               // ftb-bfb
00239         *p++            = ~W;                      // store constraint literal
00240         if (hasW) *p++  = Literal::fromRep(w);     // and weight if necessary
00241         if (ctx) ctx->setFrozen(W.var(), true);    // exempt from variable elimination
00242         active_ = s.topValue(W.var())==value_free  // if unassigned
00243                 ? NOT_ACTIVE                             // both constraints are relevant
00244                 : FFB_BTB+s.isFalse(W);                  // otherwise only one is relevant
00245         for (uint32 i = 0, j = 1, end = rep.size; i != end; ++i, ++j) {
00246                 *p++ = h[j] = rep.lits[i].first;         // store constraint literal
00247                 w    = rep.lits[i].second;               // followed by weight 
00248                 if (hasW) *p++= Literal::fromRep(w);     // if necessary
00249                 addWatch(s, j, FTB_BFB);                 // watches  lits[idx]
00250                 addWatch(s, j, FFB_BTB);                 // watches ~lits[idx]
00251                 if (ctx) ctx->setFrozen(h[j].var(), true);// exempt from variable elimination
00252                 mv   = std::max(mv, h[j].var());
00253         }
00254         if (hasW) s.requestData(mv+1);         // weight constraints can become unit more than once
00255         // init heuristic
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         // init undo stack
00260         up_                 = undoStart();     // undo stack is initially empty
00261         undo_[0].data       = 0;
00262         undo_[up_].data     = 0;
00263         setBpIndex(1);                         // where to start back propagation
00264         if (active_ == NOT_ACTIVE) {
00265                 addWatch(s, 0, FTB_BFB);             // watch con in both phases
00266                 addWatch(s, 0, FFB_BTB);             // in order to allow for backpropagation
00267         }
00268         else {
00269                 uint32 d = active_;                  // propagate con
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);  // watch con in both phases
00284                 addWatch(s, 0, FFB_BTB);  // in order to allow for backpropagation
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);  // watches  lits[i]
00290                         addWatch(s, i, FFB_BTB);  // watches ~lits[i]
00291                 }
00292         }
00293         // Initialize heuristic with literals (no weights) in constraint.
00294         uint32 off = active_ != NOT_ACTIVE;
00295         s.heuristic()->newConstraint(s, heu+off, size()-off, Constraint_t::static_constraint);
00296         // Init undo stack
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         // check if constraint has assigned literals
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         // propagate assigned literals in assignment order
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         // Add watch only if c is relevant.
00340         if (uint32(c^1) != active_) {
00341                 // Use LSB to store the constraint that watches the literal.
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 // Returns the numerical highest decision level watched by this constraint.
00367 uint32 WeightConstraint::highestUndoLevel(Solver& s) const {
00368         return up_ != undoStart() 
00369                 ? s.level(lits_->var(undoTop().idx()))
00370                 : 0;
00371 }
00372 
00373 // Updates the bound of sub-constraint c and adds the literal at index idx to the 
00374 // undo stack. If the current decision level is not watched, an undo watch is added
00375 // so that the bound can be adjusted once the solver backtracks.
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 // Since clasp uses an eager assignment strategy where literals are assigned as soon
00388 // as they are added to the propagation queue, we distinguish processed from unprocessed literals.
00389 // Processed literals are those for which propagate was already called and the corresponding bound 
00390 // was updated; they are flagged in updateConstraint(). 
00391 // Unprocessed literals are either free or were not yet propagated. During propagation
00392 // we treat all unprocessed literals as free. This way, conflicts are detected early.
00393 // Consider: x :- 3 [a=3, b=2, c=1,d=1] and PropQ: b, ~Body, c. 
00394 // Initially b, ~Body, c are unprocessed and the bound is 3.
00395 // Step 1: propagate(b)    : b is marked as processed and bound is reduced to 1.
00396 //   Now, although we already know that the body is false, we do not backpropagate yet
00397 //   because the body is unprocessed. Deferring backpropagation until the body is processed
00398 //   makes reason computation easier.
00399 // Step 2: propagate(~Body): ~body is marked as processed and bound is reduced to 0.
00400 //   Since the body is now part of our reason set, we can start backpropagation.
00401 //   First we assign the unprocessed and free literal ~a. Literal ~b is skipped, because
00402 //   its complementary literal was already successfully processed. Finally, we force 
00403 //   the unprocessed but false literal ~c to true. This will generate a conflict and 
00404 //   propagation is stopped. Without the distinction between processed and unprocessed
00405 //   lits we would have to skip ~c. We would then have to manually trigger the conflict
00406 //   {b, ~Body, c} in step 3, when propagate(c) sets the bound to -1.
00407 Constraint::PropResult WeightConstraint::propagate(Solver& s, Literal, uint32& d) {
00408         // determine the affected constraint and its body literal
00409         ActiveConstraint c  = (ActiveConstraint)(d&1);
00410         Literal body        = lit(0, c);
00411         if ( uint32(c^1) == active_ || s.isTrue(body) ) {
00412                 // the other constraint is active or this constraint is already satisfied; 
00413                 // nothing to do
00414                 return PropResult(true, true);          
00415         }
00416         // the constraint is not yet satisfied; update it and
00417         // check if we can now propagate any literals.
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                         // forward propagate constraint to true
00423                         active_ = c;
00424                         return PropResult(s.force(body, this, reasonData), true);
00425                 }
00426                 else {
00427                         // backward propagate false constraint
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 // Builds the reason for p from the undo stack of this constraint.
00446 // The reason will only contain literals that were processed by the 
00447 // active sub-constraint.
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                 // Consider only lits that are relevant to the active constraint
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                 // Consider only lits that are relevant to the active constraint
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 // undoes processed assignments 
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                 // find first assigned literal - must be there otherwise undo stack would be empty
00516                 for (i = inc; s.value(lits[i].var()) == value_free; i += inc) {
00517                         assert(!litSeen(idx));
00518                         ++idx;
00519                 }
00520                 // move unassigned literals down
00521                 // update watches because indices have changed
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                 // clear undo stack & update to new size
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 }


clasp
Author(s): Benjamin Kaufmann
autogenerated on Thu Aug 27 2015 12:41:40