00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
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
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
00219
00220
00221
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;
00239 Clasp::mutex mqMutex;
00240 Clasp::condition_variable mqCond;
00241 Clasp::atomic<int> refs;
00242 Result result;
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
00263
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
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);
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);
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
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
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
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
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 }