00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
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
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();
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
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) {
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) {
00255 subLit = negLit(0);
00256 return true;
00257 }
00258 else if (last.var() > it->var()) {
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 }