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 }