Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <clasp/enumerator.h>
00021 #include <clasp/solver.h>
00022 namespace Clasp {
00023
00025
00027 EnumerationConstraint::EnumerationConstraint(Solver&, MinimizeConstraint* min) : mini_(min), flags_(0), root_(0) {
00028 setDisjoint(false);
00029 }
00030 MinimizeConstraint* EnumerationConstraint::cloneMinimizer(Solver& s) const {
00031 return mini_ ? static_cast<MinimizeConstraint*>(mini_->cloneAttach(s)) : 0;
00032 }
00033 EnumerationConstraint::~EnumerationConstraint() { }
00034 void EnumerationConstraint::destroy(Solver* s, bool x) { if (mini_) { mini_->destroy(s, x); mini_ = 0; } Constraint::destroy(s, x); }
00035 bool EnumerationConstraint::simplify(Solver& s, bool reinit){ if (mini_) { mini_->simplify(s, reinit); } return false; }
00036 bool EnumerationConstraint::valid(Solver& s) { return !optimize() || mini_->valid(s); }
00037 bool EnumerationConstraint::integrateBound(Solver& s) const { return !mini_ || mini_->integrate(s); }
00038 bool EnumerationConstraint::optimize() const { return mini_ && mini_->shared()->optimize(); }
00039 void EnumerationConstraint::setDisjoint(bool x) {
00040 if (x) { flags_ |= uint32(flag_path_disjoint); }
00041 else { flags_ &= ~uint32(flag_path_disjoint); }
00042 }
00043 void EnumerationConstraint::end(Solver& s) {
00044 if (mini_) { mini_->relax(s, disjointPath()); }
00045 flags_ = 0;
00046 next_.clear();
00047 if (s.rootLevel() > root_) { s.popRootLevel(s.rootLevel() - root_); }
00048 }
00049 bool EnumerationConstraint::start(Solver& s, const LitVec& path, bool disjoint) {
00050 flags_ = 0;
00051 root_ = s.rootLevel();
00052 setDisjoint(disjoint);
00053 if (s.pushRoot(path)) {
00054 integrateBound(s);
00055 return true;
00056 }
00057 return false;
00058 }
00059 bool EnumerationConstraint::update(Solver& s) {
00060 ValueRep st = state();
00061 if (st == value_true) {
00062 if (s.strategy.restartOnModel) { s.undoUntil(0); }
00063 if (optimize()) { s.strengthenConditional(); }
00064 }
00065 else if (st == value_false && !s.pushRoot(next_)) {
00066 if (!s.hasConflict()) { s.setStopConflict(); }
00067 return false;
00068 }
00069 flags_ &= uint32(clear_state_mask);
00070 next_.clear();
00071 do {
00072 if (!s.hasConflict() && doUpdate(s) && integrateBound(s)) {
00073 if (st == value_true && optimize()) { mini_->shared()->heuristic(s, (s.strategy.optHeu & SolverStrategies::opt_model) != 0); }
00074 return true;
00075 }
00076 } while (st != value_free && s.hasConflict() && s.resolveConflict());
00077 return false;
00078 }
00079
00080 bool EnumerationConstraint::commitModel(Enumerator& ctx, Solver& s) {
00081 if (state() == value_true) { return !next_.empty() && (s.satPrepro()->extendModel(s.model, next_), true); }
00082 if (mini_ && !mini_->handleModel(s)){ return false; }
00083 if (!ctx.tentative()) { doCommitModel(ctx, s); }
00084 next_ = s.symmetric();
00085 flags_|= value_true;
00086 return true;
00087 }
00088 bool EnumerationConstraint::commitUnsat(Enumerator&, Solver& s) {
00089 next_.clear();
00090 flags_ |= value_false;
00091 return mini_ && mini_->handleUnsat(s, !disjointPath(), next_);
00092 }
00094
00096 Enumerator::Enumerator() : mini_(0) {}
00097 Enumerator::~Enumerator() { if (mini_) mini_->release(); }
00098 void Enumerator::setDisjoint(Solver& s, bool b)const { constraint(s)->setDisjoint(b); }
00099 void Enumerator::setIgnoreSymmetric(bool b) { model_.sym = static_cast<uint32>(b == false); }
00100 void Enumerator::end(Solver& s) const { constraint(s)->end(s); }
00101 void Enumerator::doReset() {}
00102 void Enumerator::reset() {
00103 if (mini_) { mini_->release(); mini_ = 0; }
00104 model_.values= 0;
00105 model_.costs = 0;
00106 model_.num = 0;
00107 model_.opt = 0;
00108 model_.sym = 1;
00109 model_.type = uint32(modelType());
00110 model_.sId = 0;
00111 doReset();
00112 }
00113 int Enumerator::init(SharedContext& ctx, SharedMinimizeData* min, int limit) {
00114 typedef MinimizeConstraint* MinPtr;
00115 ctx.master()->setEnumerationConstraint(0);
00116 reset();
00117 if (min && min->mode() == MinimizeMode_t::ignore){ min->release(); min = 0; }
00118 model_.costs = (mini_ = min);
00119 MinPtr mc = mini_ ? mini_->attach(*ctx.master()) : 0;
00120 limit = limit >= 0 ? limit : 1 - int(exhaustive());
00121 if (limit != 1) { ctx.setPreserveModels(true); }
00122 ConPtr c = doInit(ctx, mc, limit);
00123 bool optEnum = tentative();
00124 bool cons = model_.consequences();
00125 if (limit) {
00126 if (optimize() && !optEnum){ ctx.report(warning(Event::subsystem_prepare, "#models not 0: optimality of last model not guaranteed.")); }
00127 if (cons) { ctx.report(warning(Event::subsystem_prepare, "#models not 0: last model may not cover consequences.")); }
00128 }
00129 if (optEnum) { model_.type = Model::model_sat; }
00130 else if (cons && optimize()) { ctx.report(warning(Event::subsystem_prepare, "Optimization: Consequences may depend on enumeration order.")); }
00131 ctx.master()->setEnumerationConstraint(c);
00132 return limit;
00133 }
00134 Enumerator::ConPtr Enumerator::constraint(const Solver& s) const {
00135 return static_cast<ConPtr>(s.enumerationConstraint());
00136 }
00137 bool Enumerator::start(Solver& s, const LitVec& path, bool disjointPath) const {
00138 return constraint(s)->start(s, path, disjointPath);
00139 }
00140 ValueRep Enumerator::commit(Solver& s) {
00141 if (s.hasConflict() && s.decisionLevel() == s.rootLevel()) { return commitUnsat(s) ? value_free : value_false; }
00142 else if (s.numFreeVars() == 0 && s.queueSize() == 0 && !s.hasConflict()){ return commitModel(s) ? value_true : value_free; }
00143 return value_free;
00144 }
00145 bool Enumerator::commitModel(Solver& s) {
00146 assert(s.numFreeVars() == 0 && !s.hasConflict() && s.queueSize() == 0 && constraint(s));
00147 if (constraint(s)->commitModel(*this, s)) {
00148 s.stats.addModel(s.decisionLevel());
00149 ++model_.num;
00150 model_.values = &s.model;
00151 model_.sId = s.id();
00152 return true;
00153 }
00154 return false;
00155 }
00156 bool Enumerator::commitSymmetric(Solver& s){ return model_.sym && !optimize() && commitModel(s); }
00157 bool Enumerator::commitUnsat(Solver& s) { return constraint(s)->commitUnsat(*this, s); }
00158 bool Enumerator::commitComplete() {
00159 if (enumerated()) {
00160 if (tentative()) {
00161 mini_->markOptimal();
00162 model_.opt = 1;
00163 model_.num = 0;
00164 model_.type= uint32(modelType());
00165 return false;
00166 }
00167 else if (model_.consequences() || (!model_.opt && optimize())) {
00168 model_.opt = uint32(optimize());
00169 model_.num = 1;
00170 }
00171 }
00172 return true;
00173 }
00174
00175 bool Enumerator::update(Solver& s) const {
00176 return constraint(s)->update(s);
00177 }
00179
00181 Enumerator* EnumOptions::createEnumerator() const {
00182 if (consequences()) { return createConsEnumerator(*this); }
00183 else if (type <= enum_record) { return createModelEnumerator(*this); }
00184 else { return 0; }
00185 }
00186 Enumerator* EnumOptions::nullEnumerator() {
00187 struct NullEnum : Enumerator {
00188 ConPtr doInit(SharedContext& ctx, MinimizeConstraint* m, int) {
00189 struct Constraint : public EnumerationConstraint {
00190 Constraint(Solver& s, MinimizeConstraint* min) : EnumerationConstraint(s, min) {}
00191 bool doUpdate(Solver& s) { s.setStopConflict(); return false; }
00192 Constraint* cloneAttach(Solver& s){ return new Constraint(s, cloneMinimizer(s)); }
00193 };
00194 return new Constraint(*ctx.master(), m);
00195 }
00196 };
00197 return new NullEnum;
00198 }
00199 }