program_builder.cpp
Go to the documentation of this file.
00001 //
00002 // Copyright (c) 2006, 2007, 2012 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 #include <clasp/program_builder.h>
00021 #include <clasp/shared_context.h>
00022 #include <clasp/solver.h>
00023 #include <clasp/clause.h>
00024 #include <clasp/minimize_constraint.h>
00025 #include <clasp/weight_constraint.h>
00026 #include <clasp/parser.h>
00027 #include <limits>
00028 namespace Clasp {
00029 
00031 // class ProgramBuilder
00033 ProgramBuilder::ProgramBuilder() : ctx_(0), min_(0), minCon_(0), frozen_(true) {}
00034 ProgramBuilder::~ProgramBuilder() {}
00035 bool ProgramBuilder::ok() const { return ctx_ && ctx_->ok(); }
00036 bool ProgramBuilder::startProgram(SharedContext& ctx) {
00037         ctx.report(message(Event::subsystem_load, "Reading"));
00038         ctx_    = &ctx;
00039         min_    = 0;
00040         minCon_ = 0;
00041         frozen_ = ctx.frozen();
00042         return ctx_->ok() && doStartProgram();
00043 }
00044 bool ProgramBuilder::updateProgram() {
00045         CLASP_ASSERT_CONTRACT_MSG(ctx_, "startProgram() not called!");
00046         bool up = frozen();
00047         bool ok = ctx_->ok() && ctx_->unfreeze() && doUpdateProgram();
00048         frozen_ = ctx_->frozen();
00049         min_    = 0;
00050         if (minCon_.get())  { minCon_->resetBounds(); }
00051         if (up && !frozen()){ ctx_->report(message(Event::subsystem_load, "Reading")); }
00052         return ok;
00053 }
00054 bool ProgramBuilder::endProgram() {
00055         CLASP_ASSERT_CONTRACT_MSG(ctx_, "startProgram() not called!");
00056         bool ok = ctx_->ok();
00057         if (ok && !frozen_) {
00058                 ctx_->report(message(Event::subsystem_prepare, "Preprocessing"));
00059                 ok      = doEndProgram();
00060                 frozen_ = true;
00061         }
00062         return ok;
00063 }
00064 void ProgramBuilder::getAssumptions(LitVec& out) const {
00065         CLASP_ASSERT_CONTRACT(ctx_ && frozen());
00066         if (!isSentinel(ctx_->stepLiteral())) {
00067                 out.push_back(ctx_->stepLiteral());
00068         }
00069         doGetAssumptions(out);
00070 }
00071 bool ProgramBuilder::parseProgram(StreamSource& prg) {
00072         CLASP_ASSERT_CONTRACT(ctx_ && !frozen());
00073         return doParse(prg);
00074 }
00075 bool ProgramBuilder::parseProgram(std::istream& prg) {
00076         StreamSource input(prg);
00077         return parseProgram(input);
00078 }
00079 void ProgramBuilder::addMinLit(WeightLiteral lit)         { if (!min_.get()) { min_ = new MinimizeBuilder(); } min_->addLit(0, lit); }
00080 void ProgramBuilder::addMinRule(const WeightLitVec& lits) { if (!min_.get()) { min_ = new MinimizeBuilder(); } min_->addRule(lits);  }
00081 void ProgramBuilder::disposeMin()                         { min_ = 0; }
00082 void ProgramBuilder::disposeMinimizeConstraint()          { minCon_ = 0; }
00083 void ProgramBuilder::getMinBound(SumVec&) const           {}
00084 SharedMinimizeData* ProgramBuilder::getMinimizeConstraint(SumVec* bound) const {
00085         if (min_.get() && min_->hasRules()) {
00086                 if (bound) getMinBound(*bound);
00087                 minCon_ = min_->build(*ctx_);
00088                 min_    = 0;
00089         }
00090         return minCon_.get(); 
00091 }
00093 // class SatBuilder
00095 SatBuilder::SatBuilder(bool maxSat) : ProgramBuilder(), hardWeight_(0), vars_(0), pos_(0), maxSat_(maxSat) {}
00096 bool SatBuilder::markAssigned() {
00097         if (pos_ == ctx()->master()->trail().size()) { return true; }
00098         bool ok = ctx()->ok() && ctx()->master()->propagate();
00099         for (const LitVec& trail = ctx()->master()->trail(); pos_ < trail.size(); ++pos_) {
00100                 markLit(~trail[pos_]);
00101         }
00102         return ok;
00103 }
00104 void SatBuilder::prepareProblem(uint32 numVars, wsum_t cw, uint32 clauseHint) {
00105         CLASP_ASSERT_CONTRACT_MSG(ctx(), "startProgram() not called!");
00106         ctx()->resizeVars(numVars + 1);
00107         ctx()->symbolTable().startInit();
00108         ctx()->symbolTable().endInit(SymbolTable::map_direct, numVars+1);
00109         ctx()->startAddConstraints(std::min(clauseHint, uint32(10000)));
00110         varState_.resize(numVars + 1);
00111         vars_       = ctx()->numVars();
00112         hardWeight_ = cw;
00113         markAssigned();
00114 }
00115 bool SatBuilder::addClause(LitVec& clause, wsum_t cw) {
00116         if (!ctx()->ok() || satisfied(clause)) { return ctx()->ok(); }
00117         CLASP_ASSERT_CONTRACT_MSG(cw >= 0 && (cw <= std::numeric_limits<weight_t>::max() || cw == hardWeight_), "Clause weight out of bounds!");
00118         if (cw == 0 && maxSat_) { cw = 1; }
00119         if (cw == hardWeight_ || clause.empty()) {
00120                 return ClauseCreator::create(*ctx()->master(), clause, Constraint_t::static_constraint).ok() && markAssigned();
00121         }
00122         else {
00123                 // Store weight, relaxtion var, and (optionally) clause
00124                 softClauses_.push_back(Literal::fromRep((uint32)cw));
00125                 if (clause.size() != 1) { softClauses_.push_back(posLit(++vars_)); softClauses_.insert(softClauses_.end(), clause.begin(), clause.end()); }
00126                 else                    { softClauses_.push_back(~clause.back());  }
00127                 softClauses_.back().watch(); // mark end of clause
00128         }
00129         return true;
00130 }
00131 bool SatBuilder::satisfied(LitVec& cc) {
00132         bool sat = false;
00133         LitVec::iterator j = cc.begin();
00134         for (LitVec::const_iterator it = cc.begin(), end = cc.end(); it != end; ++it) {
00135                 Literal x = *it;
00136                 uint32  m = 1+x.sign();
00137                 uint32  n = uint32(varState_[it->var()] & 3u) + m;
00138                 if      (n == m) { varState_[it->var()] |= m; x.clearWatch(); *j++ = x; }
00139                 else if (n == 3u){ sat = true; break; } 
00140         }
00141         cc.erase(j, cc.end());
00142         for (LitVec::const_iterator it = cc.begin(), end = cc.end(); it != end; ++it) { 
00143                 if (!sat) { varState_[it->var()] |= (varState_[it->var()] & 3u) << 2; }
00144                 varState_[it->var()] &= ~3u;
00145         }
00146         return sat;
00147 }
00148 bool SatBuilder::doStartProgram() {
00149         vars_ = ctx()->numVars();
00150         pos_  = 0;
00151         return markAssigned();
00152 }
00153 bool SatBuilder::doParse(StreamSource& prg) { return DimacsParser(*this).parse(prg); }
00154 bool SatBuilder::doEndProgram() {
00155         bool ok = ctx()->ok();
00156         if (!softClauses_.empty() && ok) {
00157                 ctx()->setPreserveModels(true);
00158                 ctx()->resizeVars(vars_+1);
00159                 ctx()->startAddConstraints();
00160                 LitVec cc; 
00161                 for (LitVec::const_iterator it = softClauses_.begin(), end = softClauses_.end(); it != end && ok; ++it) {
00162                         weight_t w     = (weight_t)it->asUint();
00163                         Literal  relax = *++it;
00164                         if (!relax.watched()) { 
00165                                 cc.assign(1, relax);
00166                                 do { cc.push_back(*++it); } while (!cc.back().watched());
00167                                 cc.back().clearWatch();
00168                                 ok = ClauseCreator::create(*ctx()->master(), cc, Constraint_t::static_constraint).ok();
00169                         }
00170                         relax.clearWatch();
00171                         addMinLit(WeightLiteral(relax, w));
00172                 }
00173                 LitVec().swap(softClauses_);
00174         }
00175         if (ok && !ctx()->preserveModels()) {
00176                 uint32 p    = 12;
00177                 for (Var v  = 1; v != (Var)varState_.size() && ok; ++v) {
00178                         uint32 m  = varState_[v];
00179                         if ( (m & p) != p ) { ok = ctx()->addUnary(Literal(v, ((m>>2) & 1u) != 1)); }
00180                 }
00181         }
00182         return ok;
00183 }
00185 // class PBBuilder
00187 PBBuilder::PBBuilder() : nextVar_(0) {}
00188 void PBBuilder::prepareProblem(uint32 numVars, uint32 numProd, uint32 numSoft, uint32 numCons) {
00189         CLASP_ASSERT_CONTRACT_MSG(ctx(), "startProgram() not called!");
00190         uint32 maxVar = numVars + numProd + numSoft;
00191         nextVar_      = numVars;
00192         maxVar_       = maxVar;
00193         ctx()->resizeVars(maxVar + 1);
00194         ctx()->symbolTable().startInit();
00195         ctx()->symbolTable().endInit(SymbolTable::map_direct, numVars+1);
00196         ctx()->startAddConstraints(numCons);
00197 }
00198 uint32 PBBuilder::getNextVar() {
00199         CLASP_ASSERT_CONTRACT_MSG(ctx()->validVar(nextVar_+1), "Variables out of bounds");
00200         return ++nextVar_;
00201 }
00202 bool PBBuilder::addConstraint(WeightLitVec& lits, weight_t bound, bool eq, weight_t cw) {
00203         if (!ctx()->ok()) { return false; }
00204         Var eqVar = 0;
00205         if (cw > 0) { // soft constraint
00206                 if (lits.size() != 1) {
00207                         eqVar = getNextVar();
00208                         addMinLit(WeightLiteral(negLit(eqVar), cw));
00209                 }
00210                 else {
00211                         if (lits[0].second < 0)    { bound += (lits[0].second = -lits[0].second); lits[0].first = ~lits[0].first; }
00212                         if (lits[0].second < bound){ lits[0].first = negLit(0); }
00213                         addMinLit(WeightLiteral(~lits[0].first, cw));
00214                         return true;
00215                 }
00216         }
00217         return WeightConstraint::create(*ctx()->master(), posLit(eqVar), lits, bound, !eq ? 0 : WeightConstraint::create_eq_bound).ok();
00218 }
00219 
00220 bool PBBuilder::addObjective(const WeightLitVec& min) {
00221         addMinRule(min);
00222         return ctx()->ok();
00223 }
00224 
00225 bool PBBuilder::setSoftBound(wsum_t b) {
00226         if (b > 0) { soft_ = b-1; }
00227         return true;
00228 }
00229 
00230 void PBBuilder::getMinBound(SumVec& out) const {
00231         if (soft_ != std::numeric_limits<wsum_t>::max()) {
00232                 if      (out.empty())   { out.push_back(soft_); }
00233                 else if (out[0] > soft_){ out[0] = soft_; }
00234         }
00235 }
00236 
00237 Literal PBBuilder::addProduct(LitVec& lits) {
00238         if (!ctx()->ok()) { return negLit(0); }
00239         Literal prodLit;
00240         if (productSubsumed(lits, prodLit)){ return prodLit; }
00241         ProductIndex::iterator it = products_.find(lits);
00242         if (it != products_.end()) { return it->second; }
00243         prodLit = posLit(getNextVar());
00244         products_.insert(it, ProductIndex::value_type(lits, prodLit));
00245         addProductConstraints(prodLit, lits);
00246         return prodLit;
00247 }
00248 bool PBBuilder::productSubsumed(LitVec& lits, Literal& subLit) {
00249         Literal last       = posLit(0);
00250         LitVec::iterator j = lits.begin();
00251         Solver& s          = *ctx()->master();
00252         subLit             = posLit(0);
00253         for (LitVec::const_iterator it = lits.begin(), end = lits.end(); it != end; ++it) {
00254                 if (s.isFalse(*it) || ~*it == last) { // product is always false
00255                         subLit = negLit(0);
00256                         return true;
00257                 }
00258                 else if (last.var() > it->var()) { // not sorted - redo with sorted product
00259                         std::sort(lits.begin(), lits.end());
00260                         return productSubsumed(lits, subLit);
00261                 }
00262                 else if (!s.isTrue(*it) && last != *it) {
00263                         last  = *it;
00264                         *j++  = last;
00265                 }
00266         }
00267         lits.erase(j, lits.end());
00268         if (lits.size() == 1) { subLit = lits[0]; }
00269         return lits.size() < 2;
00270 }
00271 void PBBuilder::addProductConstraints(Literal eqLit, LitVec& lits) {
00272         Solver& s = *ctx()->master();
00273         assert(s.value(eqLit.var()) == value_free);
00274         bool ok   = ctx()->ok();
00275         for (LitVec::iterator it = lits.begin(), end = lits.end(); it != end && ok; ++it) {
00276                 assert(s.value(it->var()) == value_free);
00277                 ok    = ctx()->addBinary(~eqLit, *it);
00278                 *it   = ~*it;
00279         }
00280         lits.push_back(eqLit);
00281         if (ok) { ClauseCreator::create(s, lits, ClauseCreator::clause_no_prepare, ClauseInfo()); }
00282 }
00283 
00284 bool PBBuilder::doStartProgram() {
00285         nextVar_ = ctx()->numVars();
00286         soft_    = std::numeric_limits<wsum_t>::max();
00287         return true;
00288 }
00289 bool PBBuilder::doEndProgram() {
00290         while (nextVar_ < maxVar_) {
00291                 if (!ctx()->addUnary(negLit(++nextVar_))) { return false; }
00292         }
00293         return true;
00294 }
00295 bool PBBuilder::doParse(StreamSource& prg) { return OPBParser(*this).parse(prg); }
00296 
00297 }


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