00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef CLASP_SHARED_CONTEXT_H_INCLUDED
00021 #define CLASP_SHARED_CONTEXT_H_INCLUDED
00022 #ifdef _MSC_VER
00023 #pragma warning (disable : 4200) // nonstandard extension used : zero-sized array
00024 #pragma once
00025 #endif
00026
00027 #include <clasp/literal.h>
00028 #include <clasp/constraint.h>
00029 #include <clasp/util/left_right_sequence.h>
00030 #include <clasp/util/misc_types.h>
00031 #include <clasp/util/atomic.h>
00032 #include <clasp/solver_strategies.h>
00037 namespace Clasp {
00038 class Solver;
00039 class ClauseInfo;
00040 class Assignment;
00041 class SharedContext;
00042 class SharedLiterals;
00043 class SharedDependencyGraph;
00044 struct SolverStats;
00045
00050
00051 class SatPreprocessor {
00052 public:
00054 class Clause {
00055 public:
00056 static Clause* newClause(const Literal* lits, uint32 size);
00057 static uint64 abstractLit(Literal p) { return uint64(1) << ((p.var()-1) & 63); }
00058 uint32 size() const { return size_; }
00059 const Literal& operator[](uint32 x) const { return lits_[x]; }
00060 bool inQ() const { return inQ_ != 0; }
00061 uint64 abstraction() const { return data_.abstr; }
00062 Clause* next() const { return data_.next; }
00063 bool marked() const { return marked_ != 0;}
00064 Literal& operator[](uint32 x) { return lits_[x]; }
00065 void setInQ(bool b) { inQ_ = (uint32)b;}
00066 void setMarked(bool b) { marked_ = (uint32)b;}
00067 uint64& abstraction() { return data_.abstr; }
00068 Clause* linkRemoved(Clause* next) { data_.next = next; return this; }
00069 void strengthen(Literal p);
00070 void simplify(Solver& s);
00071 void destroy();
00072 private:
00073 Clause(const Literal* lits, uint32 size);
00074 union {
00075 uint64 abstr;
00076 Clause* next;
00077 } data_;
00078 uint32 size_ : 30;
00079 uint32 inQ_ : 1;
00080 uint32 marked_ : 1;
00081 Literal lits_[1];
00082 };
00083
00084 SatPreprocessor() : ctx_(0), elimTop_(0), seen_(1,1) {}
00085 virtual ~SatPreprocessor();
00086
00088
00091 virtual SatPreprocessor* clone() = 0;
00092
00093 uint32 numClauses() const { return (uint32)clauses_.size(); }
00095
00100 bool addClause(const LitVec& cl) { return addClause(!cl.empty() ? &cl[0] : 0, cl.size()); }
00101 bool addClause(const Literal* clause, uint32 size);
00103
00106 bool preprocess(SharedContext& ctx, SatPreParams& opts);
00107 bool preprocess(SharedContext& ctx);
00108
00110 void cleanUp(bool discardEliminated = false);
00111
00113 void extendModel(ValueVec& m, LitVec& open);
00114 struct Stats {
00115 Stats() : clRemoved(0), clAdded(0), litsRemoved(0) {}
00116 uint32 clRemoved;
00117 uint32 clAdded;
00118 uint32 litsRemoved;
00119 } stats;
00120 typedef SatPreParams Options;
00121 protected:
00122 typedef PodVector<Clause*>::type ClauseList;
00123 virtual bool initPreprocess(SatPreParams& opts) = 0;
00124 virtual bool doPreprocess() = 0;
00125 virtual void doExtendModel(ValueVec& m, LitVec& open) = 0;
00126 virtual void doCleanUp() = 0;
00127 Clause* clause(uint32 clId) { return clauses_[clId]; }
00128 const Clause* clause(uint32 clId) const { return clauses_[clId]; }
00129 void freezeSeen();
00130 void discardClauses(bool discardEliminated);
00131 void setClause(uint32 clId, const LitVec& cl) {
00132 clauses_[clId] = Clause::newClause(&cl[0], (uint32)cl.size());
00133 }
00134 void destroyClause(uint32 clId){
00135 clauses_[clId]->destroy();
00136 clauses_[clId] = 0;
00137 ++stats.clRemoved;
00138 }
00139 void eliminateClause(uint32 id){
00140 elimTop_ = clauses_[id]->linkRemoved(elimTop_);
00141 clauses_[id] = 0;
00142 ++stats.clRemoved;
00143 }
00144 SharedContext* ctx_;
00145 Clause* elimTop_;
00146 private:
00147 SatPreprocessor(const SatPreprocessor&);
00148 SatPreprocessor& operator=(const SatPreprocessor&);
00149 ClauseList clauses_;
00150 LitVec units_;
00151 Range32 seen_;
00152 };
00154
00159
00161
00164
00167 struct ProblemStats {
00168 ProblemStats() { reset(); }
00169 uint32 vars;
00170 uint32 vars_eliminated;
00171 uint32 vars_frozen;
00172 uint32 constraints;
00173 uint32 constraints_binary;
00174 uint32 constraints_ternary;
00175 uint32 complexity;
00176 void reset() { std::memset(this, 0, sizeof(*this)); }
00177 uint32 numConstraints() const { return constraints + constraints_binary + constraints_ternary; }
00178 void diff(const ProblemStats& o) {
00179 vars = std::max(vars, o.vars)-std::min(vars, o.vars);
00180 vars_eliminated = std::max(vars_eliminated, o.vars_eliminated)-std::min(vars_eliminated, o.vars_eliminated);
00181 vars_frozen = std::max(vars_frozen, o.vars_frozen)-std::min(vars_frozen, o.vars_frozen);
00182 constraints = std::max(constraints, o.constraints) - std::min(constraints, o.constraints);
00183 constraints_binary = std::max(constraints_binary, o.constraints_binary) - std::min(constraints_binary, o.constraints_binary);
00184 constraints_ternary= std::max(constraints_ternary, o.constraints_ternary) - std::min(constraints_ternary, o.constraints_ternary);
00185 }
00186 double operator[](const char* key) const;
00187 static const char* keys(const char* = 0);
00188 };
00189
00191 struct VarInfo {
00192 enum FLAG {
00193 MARK_P = 0x1u,
00194 MARK_N = 0x2u,
00195 NANT = 0x4u,
00196 PROJECT= 0x8u,
00197 BODY = 0x10u,
00198 EQ = 0x20u,
00199 DISJ = 0x40u,
00200 FROZEN = 0x80u
00201 };
00202 VarInfo() : rep(0) {}
00203
00205 VarType type() const { return has(VarInfo::EQ) ? Var_t::atom_body_var : VarType(Var_t::atom_var + has(VarInfo::BODY)); }
00207 bool nant() const { return has(VarInfo::NANT); }
00209 bool project() const { return has(VarInfo::PROJECT);}
00210 bool inDisj() const { return has(VarInfo::DISJ);}
00212 bool frozen() const { return has(VarInfo::FROZEN); }
00214
00217 bool preferredSign() const { return !has(VarInfo::BODY); }
00218
00219 bool has(FLAG f) const { return (rep & flag(f)) != 0; }
00220 bool has(uint32 f) const { return (rep & f) != 0; }
00221 void set(FLAG f) { rep |= flag(f); }
00222 void toggle(FLAG f) { rep ^= flag(f); }
00223 static uint8 flag(FLAG x) { return uint8(x); }
00224 uint8 rep;
00225 };
00226
00228 class ShortImplicationsGraph {
00229 public:
00230 ShortImplicationsGraph();
00231 ~ShortImplicationsGraph();
00232 enum ImpType { binary_imp = 2, ternary_imp = 3 };
00233
00235 void resize(uint32 nodes);
00237
00241 void markShared(bool b) { shared_ = b; }
00243
00246 bool add(ImpType t, bool learnt, const Literal* lits);
00247
00249
00252 void removeTrue(const Solver& s, Literal p);
00253
00255
00258 bool propagate(Solver& s, Literal p) const;
00260 bool propagateBin(Assignment& out, Literal p, uint32 dl) const;
00262 bool reverseArc(const Solver& s, Literal p, uint32 maxLev, Antecedent& out) const;
00263
00264 uint32 numBinary() const { return bin_[0]; }
00265 uint32 numTernary()const { return tern_[0]; }
00266 uint32 numLearnt() const { return bin_[1] + tern_[1]; }
00267 uint32 numEdges(Literal p) const;
00268 uint32 size() const { return graph_.size(); }
00270
00278 template <class OP>
00279 bool forEach(Literal p, const OP& op) const {
00280 const ImplicationList& x = graph_[p.index()];
00281 if (x.empty()) return true;
00282 ImplicationList::const_right_iterator rEnd = x.right_end();
00283 for (ImplicationList::const_left_iterator it = x.left_begin(), end = x.left_end(); it != end; ++it) {
00284 if (!op.unary(p, *it)) { return false; }
00285 }
00286 for (ImplicationList::const_right_iterator it = x.right_begin(); it != rEnd; ++it) {
00287 if (!op.binary(p, it->first, it->second)) { return false; }
00288 }
00289 #if WITH_THREADS
00290 for (Block* b = (x).learnt; b ; b = b->next) {
00291 p.watch(); bool r = true;
00292 for (Block::const_iterator imp = b->begin(), endOf = b->end(); imp != endOf; ) {
00293 if (!imp->watched()) { r = op.binary(p, imp[0], imp[1]); imp += 2; }
00294 else { r = op.unary(p, imp[0]); imp += 1; }
00295 if (!r) { return false; }
00296 }
00297 }
00298 #endif
00299 return true;
00300 }
00301 private:
00302 ShortImplicationsGraph(const ShortImplicationsGraph&);
00303 ShortImplicationsGraph& operator=(ShortImplicationsGraph&);
00304 struct Propagate;
00305 struct ReverseArc;
00306 #if WITH_THREADS
00307 struct Block {
00308 typedef Clasp::atomic<uint32> atomic_size;
00309 typedef Clasp::atomic<Block*> atomic_ptr;
00310 typedef const Literal* const_iterator;
00311 typedef Literal* iterator;
00312 enum { block_cap = (64 - (sizeof(atomic_size)+sizeof(atomic_ptr)))/sizeof(Literal) };
00313 explicit Block();
00314 const_iterator begin() const { return data; }
00315 const_iterator end() const { return data+size(); }
00316 iterator end() { return data+size(); }
00317 uint32 size() const { return size_lock >> 1; }
00318 bool tryLock(uint32& lockedSize);
00319 void addUnlock(uint32 lockedSize, const Literal* x, uint32 xs);
00320 atomic_ptr next;
00321 atomic_size size_lock;
00322 Literal data[block_cap];
00323 };
00324 typedef Block::atomic_ptr SharedBlockPtr;
00325 typedef bk_lib::left_right_sequence<Literal, std::pair<Literal,Literal>, 64-sizeof(SharedBlockPtr)> ImpListBase;
00326 struct ImplicationList : public ImpListBase {
00327 ImplicationList() : ImpListBase() { learnt = 0; }
00328 ImplicationList(const ImplicationList& other) : ImpListBase(other), learnt(other.learnt) {}
00329 ~ImplicationList();
00330 bool hasLearnt(Literal q, Literal r = negLit(0)) const;
00331 void addLearnt(Literal q, Literal r = negLit(0));
00332 void simplifyLearnt(const Solver& s);
00333 bool empty() const { return ImpListBase::empty() && learnt == 0; }
00334 void move(ImplicationList& other);
00335 void clear(bool b);
00336 SharedBlockPtr learnt;
00337 };
00338 #else
00339 typedef bk_lib::left_right_sequence<Literal, std::pair<Literal,Literal>, 64> ImplicationList;
00340 #endif
00341 ImplicationList& getList(Literal p) { return graph_[p.index()]; }
00342 void remove_bin(ImplicationList& w, Literal p);
00343 void remove_tern(ImplicationList& w, Literal p);
00344 typedef PodVector<ImplicationList>::type ImpLists;
00345 ImpLists graph_;
00346 uint32 bin_[2];
00347 uint32 tern_[2];
00348 bool shared_;
00349 };
00350
00352 class Distributor {
00353 public:
00354 struct Policy {
00355 enum Types {
00356 no = 0,
00357 conflict = Constraint_t::learnt_conflict,
00358 loop = Constraint_t::learnt_loop,
00359 all = conflict | loop,
00360 implicit = all + 1
00361 };
00362 Policy(uint32 a_sz = 0, uint32 a_lbd = 0, uint32 a_type = 0) : size(a_sz), lbd(a_lbd), types(a_type) {}
00363 uint32 size : 22;
00364 uint32 lbd : 7;
00365 uint32 types : 3;
00366 };
00367 static uint64 mask(uint32 i) { return uint64(1) << i; }
00368 static uint32 initSet(uint32 sz) { return (uint64(1) << sz) - 1; }
00369 static bool inSet(uint64 s, uint32 id) { return (s & mask(id)) != 0; }
00370 explicit Distributor(const Policy& p);
00371 virtual ~Distributor();
00372 bool isCandidate(uint32 size, uint32 lbd, uint32 type) const {
00373 return size <= policy_.size && lbd <= policy_.lbd && ((type & policy_.types) != 0);
00374 }
00375 virtual void publish(const Solver& source, SharedLiterals* lits) = 0;
00376 virtual uint32 receive(const Solver& in, SharedLiterals** out, uint32 maxOut) = 0;
00377 private:
00378 Distributor(const Distributor&);
00379 Distributor& operator=(const Distributor&);
00380 Policy policy_;
00381 };
00382
00384
00396 class SharedContext {
00397 public:
00398 typedef SharedDependencyGraph SDG;
00399 typedef PodVector<Solver*>::type SolverVec;
00400 typedef SingleOwnerPtr<SDG> SccGraph;
00401 typedef Configuration* ConfigPtr;
00402 typedef SingleOwnerPtr<Distributor> DistrPtr;
00403 typedef const ProblemStats& StatsRef;
00404 typedef SymbolTable& SymbolsRef;
00405 typedef LitVec::size_type size_type;
00406 typedef ShortImplicationsGraph ImpGraph;
00407 typedef const ImpGraph& ImpGraphRef;
00408 typedef EventHandler* LogPtr;
00409 typedef SingleOwnerPtr<SatPreprocessor>SatPrePtr;
00410 enum InitMode { init_share_symbols, init_copy_symbols };
00415
00416 explicit SharedContext();
00417 ~SharedContext();
00419 void reset();
00421 void setEventHandler(EventHandler* r) { progress_ = r; }
00423 void setShareMode(ContextParams::ShareMode m);
00425 void setShortMode(ContextParams::ShortMode m);
00427 void setConcurrency(uint32 numSolver);
00429 Solver& addSolver();
00431
00439 void enableStats(uint32 level);
00440 void accuStats();
00442 void setPreserveModels(bool b = true) { share_.satPreM = b ? SatPreParams::prepro_preserve_models : SatPreParams::prepro_preserve_sat; }
00444
00447 void setConfiguration(Configuration* c, bool own);
00448 SatPrePtr satPrepro;
00449 SccGraph sccGraph;
00451
00452 ConfigPtr configuration() const { return config_.get(); }
00454 LogPtr eventHandler() const { return progress_; }
00456 bool seedSolvers() const { return share_.seed != 0; }
00458 uint32 concurrency() const { return share_.count; }
00459 bool preserveModels() const { return static_cast<SatPreParams::Mode>(share_.satPreM) == SatPreParams::prepro_preserve_models; }
00461 bool physicalShare(ConstraintType t) const { return (share_.shareM & (1 + (t != Constraint_t::static_constraint))) != 0; }
00463 bool physicalShareProblem() const { return (share_.shareM & ContextParams::share_problem) != 0; }
00465 bool allowImplicit(ConstraintType t) const { return t != Constraint_t::static_constraint ? share_.shortM != ContextParams::short_explicit : !isShared(); }
00467
00473
00474 bool ok() const;
00476 bool frozen() const { return share_.frozen;}
00478 bool isShared() const { return frozen() && concurrency() > 1; }
00479 bool isExtended() const { return problem_.vars_frozen || symbolTable().type() == SymbolTable::map_indirect; }
00481 bool hasSolver(uint32 id) const { return id < solvers_.size(); }
00483 Solver* master() const { return solver(0); }
00485 Solver* solver(uint32 id) const { return solvers_[id]; }
00486
00488
00496 uint32 numVars() const { return static_cast<uint32>(varInfo_.size() - 1); }
00498 uint32 numEliminatedVars() const { return problem_.vars_eliminated; }
00500
00504 bool validVar(Var var) const { return var < static_cast<uint32>(varInfo_.size()); }
00506 VarInfo varInfo(Var v) const { assert(validVar(v)); return varInfo_[v]; }
00508 bool eliminated(Var v) const;
00509 bool marked(Literal p) const { return varInfo(p.var()).has(VarInfo::MARK_P + p.sign()); }
00510 Literal stepLiteral() const { return step_; }
00512 uint32 numConstraints() const;
00514 uint32 numBinary() const { return btig_.numBinary(); }
00516 uint32 numTernary() const { return btig_.numTernary(); }
00518 uint32 numUnary() const { return lastTopLevel_; }
00520 uint32 problemComplexity() const;
00521 StatsRef stats() const { return problem_; }
00522 SymbolsRef symbolTable() const { return symTabPtr_->symTab; }
00524
00543
00544
00550 bool unfreeze();
00552 void cloneVars(const SharedContext& other, InitMode m = init_copy_symbols);
00554 void resizeVars(uint32 maxVar) { varInfo_.resize(std::max(Var(1), maxVar)); problem_.vars = numVars(); }
00556
00563 Var addVar(VarType t, bool eq = false);
00565 void requestStepVar();
00567 void requestData(Var v);
00569 void setFrozen(Var v, bool b);
00571 void setNant(Var v, bool b) { if (b != varInfo(v).has(VarInfo::NANT)) varInfo_[v].toggle(VarInfo::NANT); }
00573 void setInDisj(Var v, bool b) { if (b != varInfo(v).has(VarInfo::DISJ)) varInfo_[v].toggle(VarInfo::DISJ); }
00575 void setProject(Var v, bool b) { if (b != varInfo(v).has(VarInfo::PROJECT)) varInfo_[v].toggle(VarInfo::PROJECT); }
00576 void setVarEq(Var v, bool b) { if (b != varInfo(v).has(VarInfo::EQ)) varInfo_[v].toggle(VarInfo::EQ); }
00577 void mark(Literal p) { assert(validVar(p.var())); varInfo_[p.var()].rep |= (VarInfo::MARK_P + p.sign()); }
00578 void unmark(Var v) { assert(validVar(v)); varInfo_[v].rep &= ~(VarInfo::MARK_P|VarInfo::MARK_N); }
00580
00583 void eliminate(Var v);
00584
00586
00591 Solver& startAddConstraints(uint32 constraintGuess = 100);
00592
00594 bool addUnary(Literal x);
00596 bool addBinary(Literal x, Literal y);
00598 bool addTernary(Literal x, Literal y, Literal z);
00600 void add(Constraint* c);
00601
00603
00614 bool endInit(bool attachAll = false);
00616
00625
00626
00632 bool attach(uint32 id) { return attach(*solver(id)); }
00633 bool attach(Solver& s);
00634
00635
00637
00644 void detach(uint32 id, bool reset = false) { return detach(*solver(id), reset); }
00645 void detach(Solver& s, bool reset = false);
00646
00647 DistrPtr distributor;
00649 uint32 winner() const { return share_.winner; }
00650 void setWinner(uint32 sId) { share_.winner = std::min(sId, concurrency()); }
00651
00653 void simplify(bool shuffle);
00655 void removeConstraint(uint32 idx, bool detach);
00656
00658
00664 int addImp(ImpGraph::ImpType t, const Literal* lits, ConstraintType ct);
00666 uint32 numLearntShort() const { return btig_.numLearnt(); }
00667 ImpGraphRef shortImplications() const { return btig_; }
00668 void simplifyShort(const Solver& s, Literal p);
00669 void report(const Event& ev) const { if (progress_) progress_->dispatch(ev); }
00670 bool report(const Solver& s, const Model& m) const { return !progress_ || progress_->onModel(s, m); }
00671 void initStats(Solver& s) const;
00672 const SolverStats& stats(const Solver& s, bool accu) const;
00674 private:
00675 SharedContext(const SharedContext&);
00676 SharedContext& operator=(const SharedContext&);
00677 void init();
00678 bool unfreezeStep();
00679 Literal addAuxLit();
00680 typedef SingleOwnerPtr<Configuration> Config;
00681 typedef PodVector<VarInfo>::type VarVec;
00682 typedef PodVector<SolverStats*>::type StatsVec;
00683 struct SharedSymTab {
00684 SharedSymTab() : refs(1) {}
00685 SymbolTable symTab;
00686 uint32 refs;
00687 }* symTabPtr_;
00688 ProblemStats problem_;
00689 VarVec varInfo_;
00690 ImpGraph btig_;
00691 Config config_;
00692 SolverVec solvers_;
00693 LogPtr progress_;
00694 Literal step_;
00695 uint32 lastTopLevel_;
00696 struct Share {
00697 uint32 count :12;
00698 uint32 winner :12;
00699 uint32 shareM : 3;
00700 uint32 shortM : 1;
00701 uint32 frozen : 1;
00702 uint32 seed : 1;
00703 uint32 satPreM : 1;
00704 Share() : count(1), winner(0), shareM((uint32)ContextParams::share_auto), shortM(0), frozen(0), seed(0), satPreM(0) {}
00705 } share_;
00706 StatsVec accu_;
00707 };
00709 }
00710 #endif