clasp_facade.cpp
Go to the documentation of this file.
00001 // 
00002 // Copyright (c) 2006-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/clasp_facade.h>
00021 #include <clasp/lookahead.h>
00022 #include <clasp/cb_enumerator.h>
00023 #include <clasp/dependency_graph.h>
00024 #include <clasp/minimize_constraint.h>
00025 #include <clasp/util/timer.h>
00026 #include <clasp/util/atomic.h>
00027 #include <cstdio>
00028 #include <cstdlib>
00029 #include <signal.h>
00030 #include <limits>
00031 #if WITH_THREADS
00032 #include <clasp/util/mutex.h>
00033 #endif
00034 namespace Clasp {
00036 // ClaspConfig
00038 ClaspConfig::ClaspConfig() : tester_(0) { }
00039 ClaspConfig::~ClaspConfig() {
00040         setSolvers(1);
00041         delete tester_;
00042 }
00043 void ClaspConfig::reset() {
00044         BasicSatConfig::reset();
00045         solve     = SolveOptions();
00046         enumerate = EnumOptions();
00047         asp       = AspOptions();
00048         if (tester_) { tester_->reset(); }
00049         setSolvers(1);
00050 }
00051 BasicSatConfig* ClaspConfig::addTesterConfig() {
00052         if (!tester_) { tester_ = new BasicSatConfig(); }
00053         return tester_;
00054 }
00055 void ClaspConfig::setSolvers(uint32 num) {
00056         if (!num) { num = 1; }
00057 #if WITH_THREADS
00058         solve.algorithm.threads = num;
00059 #endif
00060         if (num < numSolver()) { BasicSatConfig::resize(num, std::min(num, numSearch())); }
00061         if (testerConfig() && num < testerConfig()->numSolver()) { testerConfig()->resize(num, std::min(num, testerConfig()->numSearch())); }
00062 }
00063 void ClaspConfig::prepare(SharedContext& ctx) {
00064         uint32 numS = solve.numSolver();
00065         if (numS > solve.recommendedSolvers()) {
00066                 ctx.report(warning(Event::subsystem_facade, clasp_format_error("Oversubscription: #Threads=%u exceeds logical CPUs=%u.", numS, solve.recommendedSolvers())));
00067         }
00068         if (numS > solve.supportedSolvers()) {
00069                 ctx.report(warning(Event::subsystem_facade, "Too many solvers."));
00070                 numS = solve.supportedSolvers();
00071         }
00072         if (numS > 1 && !solve.defaultPortfolio()) {
00073                 for (uint32 i = 0, sWarn = 0; i != numS; ++i) {
00074                         if (solver(i).optStrat >= SolverStrategies::opt_unsat) {
00075                                 if (++sWarn == 1) { ctx.report(warning(Event::subsystem_facade, "Splitting: Disabling unsat-core based optimization!")); }
00076                                 addSolver(i).optStrat = SolverStrategies::opt_dec;
00077                         }
00078                 }
00079         }
00080         if (std::abs(enumerate.numModels) != 1) { satPre.mode = SatPreParams::prepro_preserve_models; }
00081         setSolvers(numS);
00082         ctx.setConcurrency(solve.numSolver());
00083         for (uint32 i = 1; i != ctx.concurrency(); ++i) {
00084                 if (!ctx.hasSolver(i)) { ctx.addSolver(); }
00085         }
00086         BasicSatConfig::prepare(ctx);
00087 }
00089 // ClaspFacade::SolveImpl/SolveStrategy/AsyncResult
00091 struct ClaspFacade::SolveStrategy {
00092 public:
00093         static const int SIGCANCEL = 9;
00094         enum State { state_start = 0, state_running = 1, state_result = 2, state_model = 3, state_done = 6 };
00095         SolveStrategy()         { state = signal = 0; algo = 0; handler = 0; }
00096         virtual ~SolveStrategy(){}
00097         bool running() const    { return (state & state_running) != 0; }
00098         bool interrupt(int sig) {
00099                 if (!running()) { return false; }
00100                 if (!signal || sig < signal) { signal = sig; } 
00101                 return cancel(sig);
00102         }
00103         void solve(ClaspFacade& f, SolveAlgorithm* algo, EventHandler* h) {
00104                 this->algo    = algo;
00105                 this->handler = h;
00106                 state = signal= 0;
00107                 doSolve(f);
00108         }
00109         virtual void release()  {}
00110         virtual bool cancel(int){ return algo->interrupt(); }
00111         Clasp::atomic<int> state;
00112         Clasp::atomic<int> signal;
00113         SolveAlgorithm*    algo;
00114         EventHandler*      handler;
00115 protected:
00116         void solveImpl(ClaspFacade& f, State end);
00117         virtual void doSolve(ClaspFacade& f) = 0;
00118 };
00119 struct ClaspFacade::SolveImpl {
00120         typedef SingleOwnerPtr<SolveAlgorithm> AlgoPtr;
00121         typedef SingleOwnerPtr<Enumerator>     EnumPtr;
00122         SolveImpl() : en(0), algo(0), active(0) { }
00123         ~SolveImpl() { reset(); }
00124         void init(SolveAlgorithm* algo, Enumerator* en) {
00125                 this->en   = en;
00126                 this->algo = algo;
00127                 this->algo->setEnumerator(*en);
00128         }
00129         void reset() {
00130                 if (active)    { interrupt(SolveStrategy::SIGCANCEL); active->release(); active = 0; }
00131                 if (algo.get()){ algo->resetSolve(); }
00132                 if (en.get())  { en->reset(); }
00133         }
00134         void prepare(SharedContext& ctx, SharedMinimizeData* min, int numM) {
00135                 CLASP_FAIL_IF(active, "Solve operation still active");
00136                 int limit = en->init(ctx, min, numM);
00137                 algo->setEnumLimit(limit ? static_cast<uint64>(limit) : UINT64_MAX);
00138         }
00139         bool update(const Solver& s, const Model& m) { return !active->handler || active->handler->onModel(s, m); }
00140         bool interrupt(int sig)                      { return active && active->interrupt(sig); }
00141         bool                      solving()   const  { return active && active->running();   }
00142         const Model*              lastModel() const  { return en.get() ? &en->lastModel() : 0; }
00143         const SharedMinimizeData* minimizer() const  { return en.get() ? en->minimizer() : 0; } 
00144         bool                      optimize()  const  { return en.get() && en->optimize(); }
00145         int                       modelType() const  { return en.get() ? en->modelType() : 0; }
00146         EnumPtr        en;
00147         AlgoPtr        algo;
00148         SolveStrategy* active;
00149 };
00150 void ClaspFacade::SolveStrategy::solveImpl(ClaspFacade& f, State done) {
00151         if (state != state_running){ state = state_running; }
00152         if (f.result().flags)      { state = done; signal = f.result().signal; return; }
00153         struct OnExit {
00154                 OnExit(SolveStrategy* s, ClaspFacade* x, int st) : self(s), facade(x), endState(st), more(true) {}
00155                 ~OnExit() { 
00156                         facade->stopStep(self->signal, !more);
00157                         if (self->handler) { self->handler->onEvent(StepReady(facade->summary())); }
00158                         self->state  = endState;
00159                 }
00160                 SolveStrategy* self;
00161                 ClaspFacade*   facade;
00162                 int            endState;
00163                 bool           more;
00164         } scope(this, &f, done);
00165         f.step_.solveTime = f.step_.unsatTime = RealTime::getTime();
00166         scope.more = algo->solve(f.ctx, f.assume_, &f);
00167 }
00168 
00169 #if WITH_THREADS
00170 struct ClaspFacade::AsyncSolve : public SolveStrategy, public EventHandler {
00171         static EventHandler* asyncModelHandler() { return reinterpret_cast<EventHandler*>(0x1); }
00172         AsyncSolve() { refs = 1; }
00173         virtual void doSolve(ClaspFacade& f) {
00174                 if (handler == AsyncSolve::asyncModelHandler()) { handler = this; }
00175                 algo->enableInterrupts();
00176                 state  = state_running;
00177                 result = f.result();
00178                 if (result.flags) { signal = result.signal; state = state_done; return; }
00179                 // start solve in worker thread
00180                 Clasp::thread(std::mem_fun(&AsyncSolve::threadMain), this, &f).swap(task);
00181         }
00182         virtual bool cancel(int sig) {
00183                 return SolveStrategy::cancel(sig) && (sig != SIGCANCEL || wait());
00184         }
00185         void threadMain(ClaspFacade* f) {
00186                 try         { solveImpl(*f, state_running); }
00187                 catch (...) { result.flags |= Result::EXT_ERROR; }
00188                 {
00189                         unique_lock<Clasp::mutex> lock(this->mqMutex);
00190                         result = f->result();
00191                         state  = state_done;
00192                 }
00193                 mqCond.notify_one();
00194         }
00195         virtual void release() {
00196                 if      (--refs == 1) { interrupt(SIGCANCEL); }
00197                 else if (refs   == 0) { join(); delete this; }
00198         }
00199         bool hasResult()const { return (state & state_result)  != 0; }
00200         bool next() {
00201                 if (state != state_model) { return false; }
00202                 unique_lock<Clasp::mutex> lock(mqMutex);
00203                 state = state_running;
00204                 mqCond.notify_one();
00205                 return true;
00206         }
00207         bool wait(double s = -1.0) {
00208                 if (state == state_start) { return false; }
00209                 if (signal != 0)          { next(); }
00210                 for (unique_lock<Clasp::mutex> lock(mqMutex); !hasResult(); ) {
00211                         if (s < 0.0) { mqCond.wait(lock); }
00212                         else {
00213                                 try { 
00214                                         mqCond.wait_for(lock, tbb::tick_count::interval_t(s));
00215                                         if (!hasResult()) { return false; }
00216                                 }
00217                                 catch (const std::runtime_error&) {
00218                                         // Due to a bug in the computation of the wait time in some tbb versions 
00219                                         // for linux wait_for might fail with eid_condvar_wait_failed.
00220                                         // See: http://software.intel.com/en-us/forums/topic/280012
00221                                         // Ignore the error and retry the wait - the computed wait time will be valid, eventually.
00222                                 }
00223                         }
00224                 }
00225                 if (state == state_done) { join(); }
00226                 return true;
00227         }
00228         bool onModel(const Solver&, const Model&) {
00229                 const Result sat = {Result::SAT, 0};
00230                 unique_lock<Clasp::mutex> lock(mqMutex);
00231                 state = state_model;
00232                 result= sat;
00233                 mqCond.notify_one();
00234                 while (state == state_model && signal == 0) { mqCond.wait(lock); }
00235                 return signal == 0;
00236         }
00237         void join() { if (task.joinable()) { task.join(); } }
00238         Clasp::thread             task;   // async solving thread
00239         Clasp::mutex              mqMutex;// protects mqCond
00240         Clasp::condition_variable mqCond; // for iterating over models one by one
00241         Clasp::atomic<int>        refs;   // 1 + #AsyncResult objects
00242         Result                    result; // result of async operation
00243 };
00244 ClaspFacade::AsyncResult::AsyncResult(SolveImpl& x) : state_(static_cast<AsyncSolve*>(x.active)) { ++state_->refs; }
00245 ClaspFacade::AsyncResult::~AsyncResult() { state_->release(); }
00246 ClaspFacade::AsyncResult::AsyncResult(const AsyncResult& x) : state_(x.state_) { ++state_->refs; }
00247 int  ClaspFacade::AsyncResult::interrupted()        const { return state_->signal; }
00248 bool ClaspFacade::AsyncResult::error()              const { return ready() && state_->result.error(); }
00249 bool ClaspFacade::AsyncResult::ready()              const { return state_->hasResult(); }
00250 bool ClaspFacade::AsyncResult::ready(Result& r)     const { if (ready()) { r = get(); return true; } return false; }
00251 bool ClaspFacade::AsyncResult::running()            const { return state_->running(); }
00252 void ClaspFacade::AsyncResult::wait()               const { state_->wait(-1.0); }
00253 bool ClaspFacade::AsyncResult::waitFor(double sec)  const { return state_->wait(sec); }
00254 void ClaspFacade::AsyncResult::next()               const { state_->next(); }
00255 bool ClaspFacade::AsyncResult::cancel()             const { return state_->interrupt(AsyncSolve::SIGCANCEL); }
00256 ClaspFacade::Result ClaspFacade::AsyncResult::get() const {
00257         state_->wait();
00258         if (!state_->result.error()) { return state_->result; }
00259         throw std::runtime_error("Async operation failed!");
00260 }
00261 bool ClaspFacade::AsyncResult::end() const { 
00262         // first running() handles case where iterator is outdated (state was reset to start)
00263         // second running() is used to distinguish models from final result (summary)
00264         return !running() || !get().sat() || !running();
00265 }
00266 const Model& ClaspFacade::AsyncResult::model() const { 
00267         CLASP_FAIL_IF(state_->state != AsyncSolve::state_model, "Invalid iterator access!");
00268         return const_cast<const SolveAlgorithm*>(state_->algo)->enumerator()->lastModel();
00269 }
00270 #endif
00271 
00272 // ClaspFacade
00274 ClaspFacade::ClaspFacade() : config_(0) {}
00275 ClaspFacade::~ClaspFacade() { }
00276 void ClaspFacade::discardProblem() {
00277         config_  = 0;
00278         builder_ = 0;
00279         lpStats_ = 0;
00280         solve_   = 0;
00281         accu_    = 0;
00282         step_.init(*this);
00283         if (ctx.numConstraints() || ctx.numVars()) { ctx.reset(); }
00284 }
00285 void ClaspFacade::init(ClaspConfig& config, bool discard) {
00286         if (discard) { discardProblem(); }
00287         ctx.setConfiguration(0, false); // force reload of configuration once done
00288         config_ = &config;
00289         SolveImpl::EnumPtr e(config.enumerate.createEnumerator());
00290         if (e.get() == 0) { e = EnumOptions::nullEnumerator(); }
00291         if (config.solve.numSolver() > 1 && !e->supportsParallel()) {
00292                 ctx.report(warning(Event::subsystem_facade, "Selected reasoning mode implies #Threads=1."));
00293                 config.setSolvers(1);
00294         }
00295         ctx.setConfiguration(&config, false); // prepare and apply config
00296         if (!solve_.get()) { solve_ = new SolveImpl(); }
00297         SolveImpl::AlgoPtr a(config.solve.createSolveObject());
00298         solve_->init(a.release(), e.release());
00299         if (discard) { startStep(0); }
00300 }
00301 
00302 void ClaspFacade::initBuilder(ProgramBuilder* in, bool incremental) {
00303         builder_ = in;
00304         assume_.clear();
00305         builder_->startProgram(ctx);
00306         if (incremental) { 
00307                 ctx.requestStepVar();
00308                 builder_->updateProgram();
00309                 solve_->algo->enableInterrupts();
00310                 accu_ = new Summary();
00311                 accu_->init(*this);
00312                 accu_->step = UINT32_MAX;
00313         }
00314 }
00315 
00316 ProgramBuilder& ClaspFacade::start(ClaspConfig& config, ProblemType t, bool allowUpdate) {
00317         if      (t == Problem_t::SAT) { return startSat(config, allowUpdate); }
00318         else if (t == Problem_t::PB)  { return startPB(config, allowUpdate);  }
00319         else if (t == Problem_t::ASP) { return startAsp(config, allowUpdate); }
00320         else                          { throw std::domain_error("Unknown problem type!"); }
00321 }
00322 
00323 SatBuilder& ClaspFacade::startSat(ClaspConfig& config, bool allowUpdate) {
00324         init(config, true);
00325         initBuilder(new SatBuilder(config.enumerate.maxSat), allowUpdate);
00326         return static_cast<SatBuilder&>(*builder_.get());
00327 }
00328 
00329 PBBuilder& ClaspFacade::startPB(ClaspConfig& config, bool allowUpdate) {
00330         init(config, true);
00331         initBuilder(new PBBuilder(), allowUpdate);
00332         return static_cast<PBBuilder&>(*builder_.get());
00333 }
00334 
00335 Asp::LogicProgram& ClaspFacade::startAsp(ClaspConfig& config, bool allowUpdate) {
00336         init(config, true);
00337         Asp::LogicProgram* p = new Asp::LogicProgram();
00338         lpStats_             = new Asp::LpStats;
00339         p->accu              = lpStats_.get();
00340         initBuilder(p, allowUpdate);
00341         p->setOptions(config.asp);
00342         p->setNonHcfConfiguration(config.testerConfig());
00343         return *p;
00344 }
00345 ProgramBuilder& ClaspFacade::update(bool reloadConfig) {
00346         CLASP_ASSERT_CONTRACT(builder_.get() && !solving());
00347         CLASP_ASSERT_CONTRACT_MSG(step_.result.signal != SIGINT, "Interrupt not handled!");
00348         solve_->reset();
00349         if (reloadConfig) { init(*config_, false); }
00350         if (builder_->frozen()) {
00351                 startStep(step()+1);
00352                 if (builder_->updateProgram()) { assume_.clear(); }
00353                 else                           { stopStep(0, true); }
00354         }
00355         return *builder_;
00356 }
00357 bool ClaspFacade::terminate(int signal) {
00358         if (solve_.get() && solve_->interrupt(signal)) {
00359                 return true;
00360         }
00361         // solving not active or not interruptible
00362         stopStep(signal, false);
00363         return false;
00364 }
00365 
00366 bool ClaspFacade::prepare(EnumMode enumMode) {
00367         CLASP_ASSERT_CONTRACT(config_ && !solving());
00368         bool ok = this->ok();
00369         SharedMinimizeData* m = 0;
00370         EnumOptions& en       = config_->enumerate;
00371         if (builder_.get() && (ok = builder_->endProgram()) == true) {
00372                 builder_->getAssumptions(assume_);
00373                 if ((m  = en.opt != MinimizeMode_t::ignore ? builder_->getMinimizeConstraint(&en.bound) : 0) != 0) {
00374                         ok = m->setMode(en.opt, en.bound);
00375                         if (en.opt == MinimizeMode_t::enumerate && en.bound.empty()) {
00376                                 ctx.report(warning(Event::subsystem_facade, "opt-mode=enum: no bound given, optimize statement ignored"));
00377                         }
00378                 }
00379         }
00380         if (ok && (!ctx.frozen() || (ok = ctx.unfreeze()) == true)) {
00381                 // Step literal only needed for volatile enumeration
00382                 ok = (enumMode == enum_volatile || ctx.addUnary(ctx.stepLiteral()));
00383                 if (ok) { solve_->prepare(ctx, m ? m->share() : 0, en.numModels); }
00384         }
00385         if (!accu_.get()) { builder_ = 0; }
00386         return (ok && ctx.endInit()) || (stopStep(0, true), false);
00387 }
00388 void ClaspFacade::assume(Literal p) {
00389         assume_.push_back(p);
00390 }
00391 void ClaspFacade::assume(const LitVec& ext) {
00392         assume_.insert(assume_.end(), ext.begin(), ext.end());
00393 }
00394 bool ClaspFacade::solving() const { return solve_.get() && solve_->solving(); }
00395 
00396 const ClaspFacade::Summary& ClaspFacade::shutdown() {
00397         if      (!config_) { step_.init(*this); }
00398         else if (solving()){ terminate(SIGINT); }
00399         else               { stopStep(0, false); }
00400         return accu_.get() && accu_->step ? *accu_ : step_;
00401 }
00402 
00403 ClaspFacade::Result ClaspFacade::solve(EventHandler* handler) {
00404         CLASP_ASSERT_CONTRACT(!solving());
00405         struct SyncSolve : public SolveStrategy {
00406                 SyncSolve(SolveImpl& s) : x(&s) { x->active = this; }
00407                 ~SyncSolve()                    { x->active = 0;    }
00408                 virtual void doSolve(ClaspFacade& f) { solveImpl(f, state_done); }
00409                 SolveImpl* x;
00410         } syncSolve(*solve_);
00411         syncSolve.solve(*this, solve_->algo.get(), handler);
00412         return result();
00413 }
00414 #if WITH_THREADS
00415 ClaspFacade::AsyncResult ClaspFacade::solveAsync(EventHandler* handler) {
00416         CLASP_ASSERT_CONTRACT(!solving());
00417         solve_->active = new AsyncSolve();
00418         solve_->active->solve(*this, solve_->algo.get(), handler);
00419         return AsyncResult(*solve_);
00420 }
00421 ClaspFacade::AsyncResult ClaspFacade::startSolveAsync() {
00422         return solveAsync(AsyncSolve::asyncModelHandler());
00423 }
00424 #endif
00425 
00426 void ClaspFacade::startStep(uint32 n) {
00427         step_.init(*this);
00428         step_.totalTime = -RealTime::getTime();
00429         step_.cpuTime   = -ProcessTime::getTime();
00430         step_.step      = n;
00431         ctx.report(StepStart(*this));
00432 }
00433 ClaspFacade::Result ClaspFacade::stopStep(int signal, bool complete) {
00434         if (step_.totalTime < 0) {
00435                 double t = RealTime::getTime();
00436                 step_.totalTime += t;
00437                 step_.cpuTime   += ProcessTime::getTime();
00438                 if (step_.solveTime) {
00439                         step_.solveTime = t - step_.solveTime;
00440                         step_.unsatTime = complete ? t - step_.unsatTime : 0;
00441                 }
00442                 Result res = {uint8(0), uint8(signal)};
00443                 if (complete) { res.flags = uint8(step_.enumerated() ? Result::SAT : Result::UNSAT) | Result::EXT_EXHAUST; }
00444                 else          { res.flags = uint8(step_.enumerated() ? Result::SAT : Result::UNKNOWN); }
00445                 if (signal)   { res.flags|= uint8(Result::EXT_INTERRUPT); }
00446                 step_.result = res;
00447                 accuStep();
00448                 ctx.report(StepReady(step_)); 
00449         }
00450         return result();
00451 }
00452 void ClaspFacade::accuStep() {
00453         if (accu_.get() && accu_->step != step_.step){
00454                 if (step_.stats()) { ctx.accuStats(); }
00455                 accu_->totalTime += step_.totalTime;
00456                 accu_->cpuTime   += step_.cpuTime;
00457                 accu_->solveTime += step_.solveTime;
00458                 accu_->unsatTime += step_.unsatTime;
00459                 accu_->numEnum   += step_.numEnum;
00460                 // no aggregation
00461                 if (step_.numEnum) { accu_->satTime = step_.satTime; }
00462                 accu_->step       = step_.step;
00463                 accu_->result     = step_.result;
00464         }
00465 }
00466 bool ClaspFacade::onModel(const Solver& s, const Model& m) {
00467         step_.unsatTime = RealTime::getTime();
00468         if (++step_.numEnum == 1) { step_.satTime = step_.unsatTime - step_.solveTime; }
00469         return solve_->update(s, m);
00470 }
00471 ExpectedQuantity::ExpectedQuantity(double d) : rep(d >= 0 ? d : -std::min(-d, 3.0)) {}
00472 ExpectedQuantity::Error ExpectedQuantity::error() const {
00473         if (rep >= 0.0) { return error_none; }
00474         return static_cast<ExpectedQuantity::Error>(std::min(3, int(-rep)));
00475 }
00476 ExpectedQuantity::ExpectedQuantity(Error e) : rep(-double(int(e))) {}
00477 ExpectedQuantity::operator double() const { return valid() ? rep : std::numeric_limits<double>::quiet_NaN(); }
00478 
00479 ExpectedQuantity ClaspFacade::getStatImpl(const char* path, bool keys) const {
00480 #define GET_KEYS(o, path) ( ExpectedQuantity((o).keys(path)) )
00481 #define GET_OBJ(o, path)  ( ExpectedQuantity((o)[path]) )
00482 #define COMMON_KEYS "ctx.\0solvers.\0solver.\0costs.\0totalTime\0cpuTime\0solveTime\0unsatTime\0satTime\0numEnum\0optimal\0step\0result\0"
00483         static const char* _keys[] = {"accu.\0hccs.\0hcc.\0lp.\0" COMMON_KEYS, 0, "accu.\0lp.\0" COMMON_KEYS, "accu.\0" COMMON_KEYS };
00484         enum ObjId { id_hccs, id_hcc, id_lp, id_ctx, id_solvers, id_solver, id_costs, id_total, id_cpu, id_solve, id_unsat, id_sat, id_num, id_opt, id_step, id_result };
00485         if (!path)  path = "";
00486         std::size_t kLen = 0;
00487         int         oId  = lpStats_.get() ? ((ctx.sccGraph.get() && ctx.sccGraph->numNonHcfs() != 0) ? id_hccs : id_lp) : id_ctx;
00488         const char* keyL = _keys[oId];
00489         bool        accu = matchStatPath(path, "accu");
00490         if (!*path) { 
00491                 if (accu) { keyL += 6; }
00492                 return keys ? ExpectedQuantity(keyL) : ExpectedQuantity::error_ambiguous_quantity;
00493         }
00494         accu = accu && step() != 0;
00495         for (const char* k = keyL + 6; (kLen = std::strlen(k)) != 0; k += kLen + 1, ++oId) {
00496                 bool match = k[kLen-1] == '.' ? matchStatPath(path, k, kLen-1) : std::strcmp(path, k) == 0;
00497                 if (match) {
00498                         if (!*path && !keys){ return ExpectedQuantity::error_ambiguous_quantity; }
00499                         switch(oId) {
00500                                 default: {
00501                                         const Summary* stats = accu && accu_.get() ? accu_.get() : &step_;
00502                                         if (oId == id_costs) {
00503                                                 char* x;
00504                                                 uint32 n = (uint32)std::strtoul(path, &x, 10);
00505                                                 uint32 N = stats->model() && stats->optimize() ? stats->costs()->numRules() : 0u;
00506                                                 if (x == path) {
00507                                                         if (!*path) { return keys ? ExpectedQuantity("__len\0") : ExpectedQuantity::error_ambiguous_quantity; }
00508                                                         if (!keys && std::strcmp(path, "__len") == 0) { return ExpectedQuantity(N); }
00509                                                         return ExpectedQuantity::error_unknown_quantity;
00510                                                 }
00511                                                 if (*(path = x) == '.') { ++path; }
00512                                                 if (*path)  { return ExpectedQuantity::error_unknown_quantity; }
00513                                                 if (n >= N) { return ExpectedQuantity::error_not_available;    }
00514                                                 if (!keys)  { return ExpectedQuantity((double)stats->costs()->optimum(n)); }
00515                                         }
00516                                         if (keys)            { return ExpectedQuantity(uint32(0)); }
00517                                         if (oId <= id_sat)   { return *((&stats->totalTime) + (oId - id_total)); }
00518                                         if (oId == id_num)   { return ExpectedQuantity(stats->numEnum); }
00519                                         if (oId == id_opt)   { return ExpectedQuantity(stats->optimal()); }
00520                                         if (oId == id_step)  { return ExpectedQuantity(stats->step);    }
00521                                         if (oId == id_result){ return ExpectedQuantity((double)stats->result); }
00522                                         return ExpectedQuantity::error_unknown_quantity; }
00523                                 case id_lp: if (!lpStats_.get()) { return ExpectedQuantity::error_not_available; }
00524                                         return keys ? GET_KEYS((*lpStats_), path) : GET_OBJ((*lpStats_), path);
00525                                 case id_ctx:     return keys ? GET_KEYS(ctx.stats(), path) : GET_OBJ(ctx.stats(), path);
00526                                 case id_solvers: return keys ? GET_KEYS(ctx.stats(*ctx.solver(0), accu), path) : getStat(ctx, path, accu, Range32(0, ctx.concurrency()));                       
00527                                 case id_hccs: if (!ctx.sccGraph.get() || ctx.sccGraph->numNonHcfs() == 0) { return ExpectedQuantity::error_not_available; } else {
00528                                         ExpectedQuantity res(0.0);
00529                                         for (SharedDependencyGraph::NonHcfIter it = ctx.sccGraph->nonHcfBegin(), end = ctx.sccGraph->nonHcfEnd(); it != end; ++it) {
00530                                                 const SharedContext& hCtx= it->second->ctx();
00531                                                 if (keys) { return GET_KEYS(hCtx.stats(*hCtx.solver(0), accu), path); }
00532                                                 ExpectedQuantity hccAccu = getStat(hCtx, path, accu, Range32(0, hCtx.concurrency()));
00533                                                 if (!hccAccu.valid()) { return hccAccu; }
00534                                                 res.rep += hccAccu.rep;
00535                                         }
00536                                         return res; }
00537                                 case id_solver:
00538                                 case id_hcc: 
00539                                         Range32 r(0, oId == id_solver ? ctx.concurrency() : ctx.sccGraph.get() ? ctx.sccGraph->numNonHcfs() : 0);
00540                                         char* x;
00541                                         r.lo = (uint32)std::strtoul(path, &x, 10);
00542                                         if (x == path) {
00543                                                 if (!*path) { return keys ? ExpectedQuantity("__len\0") : ExpectedQuantity::error_ambiguous_quantity; }
00544                                                 if (!keys && std::strcmp(path, "__len") == 0) { return ExpectedQuantity(r.hi); }
00545                                                 return ExpectedQuantity::error_unknown_quantity;
00546                                         }
00547                                         if (r.lo >= r.hi)  { return ExpectedQuantity::error_not_available;    }
00548                                         if (*(path = x) == '.') { ++path; }
00549                                         const SharedContext* active = &ctx; 
00550                                         if (oId == id_hcc) {
00551                                                 active = &(ctx.sccGraph->nonHcfBegin() + r.lo)->second->ctx();
00552                                                 r      = Range32(0, active->concurrency());
00553                                         }
00554                                         return keys ? GET_KEYS(active->stats(*active->solver(r.lo), accu), path) : getStat(*active, path, accu, r);
00555                         }
00556                 }
00557         }
00558         return ExpectedQuantity::error_unknown_quantity; 
00559 #undef GET_KEYS
00560 #undef GET_OBJ
00561 #undef COMMON_KEYS
00562 }
00563 
00564 ExpectedQuantity ClaspFacade::getStat(const char* path)const {
00565         return config_ && step_.totalTime >= 0.0 ? getStatImpl(path, false) : ExpectedQuantity::error_not_available;
00566 }
00567 const char*      ClaspFacade::getKeys(const char* path)const {
00568         ExpectedQuantity x =  config_ && step_.totalTime >= 0.0 ? getStatImpl(path, true) : ExpectedQuantity::error_not_available;
00569         if (x.valid()) { return (const char*)static_cast<uintp>(x.rep); }
00570         return x.error() == ExpectedQuantity::error_unknown_quantity ? 0 : "\0";
00571 }
00572 ExpectedQuantity ClaspFacade::getStat(const SharedContext& ctx, const char* key, bool accu, const Range<uint32>& r) const {
00573         if (!key || !*key) { return ExpectedQuantity::error_ambiguous_quantity; }
00574         ExpectedQuantity res(0.0);
00575         for (uint32 i = r.lo; i != r.hi && ctx.hasSolver(i); ++i) {
00576                 ExpectedQuantity x = ctx.stats(*ctx.solver(i), accu)[key];
00577                 if (!x.valid()) { return x; }
00578                 res.rep += x.rep;
00579         }
00580         return res;     
00581 }
00583 // ClaspFacade::Summary
00585 void ClaspFacade::Summary::init(ClaspFacade& f)  { std::memset(this, 0, sizeof(Summary)); facade = &f;}
00586 int ClaspFacade::Summary::stats()          const { return ctx().master()->stats.level(); }
00587 const Model* ClaspFacade::Summary::model() const { return facade->solve_.get() ? facade->solve_->lastModel() : 0; }
00588 const SharedMinimizeData* ClaspFacade::Summary::costs()const { return facade->solve_.get() ? facade->solve_->minimizer() : 0;  }
00589 const char* ClaspFacade::Summary::consequences() const {
00590         int mt = facade->solve_.get() ? facade->solve_->modelType() : 0;
00591         if ( (mt & CBConsequences::brave_consequences)    == CBConsequences::brave_consequences)   { return "Brave"; }
00592         if ( (mt & CBConsequences::cautious_consequences) == CBConsequences::cautious_consequences){ return "Cautious"; }
00593         return 0;
00594 }
00595 bool ClaspFacade::Summary::optimize()  const { return (facade->solve_.get() && facade->solve_->optimize()) || (model() && model()->opt); }
00596 bool ClaspFacade::Summary::optimum()   const { return (model() && model()->opt) || (costs() && complete()); }
00597 uint64 ClaspFacade::Summary::optimal() const { 
00598         const Model* m = model();
00599         if (m && m->opt) {
00600                 return !m->consequences() ? std::max(m->num, uint64(1)) : uint64(complete());
00601         }
00602         return 0;
00603 }
00604 }


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