1 //
2 // Copyright (c) 2006-2017 Benjamin Kaufmann
3 //
4 // This file is part of Clasp. See http://www.cs.uni-potsdam.de/clasp/
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to
8 // deal in the Software without restriction, including without limitation the
9 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 // sell copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 // IN THE SOFTWARE.
23 //
24 #include <clasp/clasp_facade.h>
25 #include <clasp/lookahead.h>
26 #include <clasp/dependency_graph.h>
27 #include <clasp/minimize_constraint.h>
28 #include <clasp/unfounded_check.h>
29 #include <clasp/parser.h>
30 #include <clasp/clingo.h>
31 #include <clasp/util/timer.h>
32 #include <potassco/string_convert.h>
33 #include <cstdio>
34 #include <cstdlib>
35 #include <signal.h>
36 #include <climits>
37 #include <utility>
38 #if CLASP_HAS_THREADS
39 #include <clasp/mt/mutex.h>
40 #include <clasp/mt/thread.h>
41 #endif
42 namespace Clasp {
43 /////////////////////////////////////////////////////////////////////////////////////////
44 // ClaspConfig
45 /////////////////////////////////////////////////////////////////////////////////////////
46 struct ClaspConfig::Impl {
47 struct ConfiguratorProxy {
48 enum { OnceBit = 62, AcquireBit = 61 };
ConfiguratorProxyClasp::ClaspConfig::Impl::ConfiguratorProxy49 ConfiguratorProxy(Configurator* c, Ownership_t::Type own, bool once) : cfg(reinterpret_cast<uintp>(c)), set(0) {
50 if (once) { store_set_bit(cfg, OnceBit); }
51 if (own == Ownership_t::Acquire) { store_set_bit(cfg, AcquireBit); }
52 assert(ptr() == c);
53 }
applyConfigClasp::ClaspConfig::Impl::ConfiguratorProxy54 bool applyConfig(Solver& s) {
55 POTASSCO_ASSERT(s.id() < 64, "invalid solver id!");
56 if (test_bit(set, s.id())) { return true; }
57 if (test_bit(cfg, OnceBit)) { store_set_bit(set, s.id()); }
58 return this->ptr()->applyConfig(s);
59 }
prepareClasp::ClaspConfig::Impl::ConfiguratorProxy60 void prepare(SharedContext& ctx) {
61 if (ctx.concurrency() < 64) {
62 set &= (bit_mask<uint64>(ctx.concurrency()) - 1);
63 }
64 ptr()->prepare(ctx);
65 }
unfreezeClasp::ClaspConfig::Impl::ConfiguratorProxy66 void unfreeze(SharedContext& ctx) {
67 ptr()->unfreeze(ctx);
68 }
destroyClasp::ClaspConfig::Impl::ConfiguratorProxy69 void destroy() { if (test_bit(cfg, AcquireBit)) { delete ptr(); } }
ptrClasp::ClaspConfig::Impl::ConfiguratorProxy70 Configurator* ptr() const {
71 static const uint64 ptrMask = ~(bit_mask<uint64>(OnceBit) | bit_mask<uint64>(AcquireBit));
72 return reinterpret_cast<Configurator*>(static_cast<uintp>(cfg & ptrMask));
73 }
74 uint64 cfg;
75 uint64 set;
76 };
77 typedef PodVector<ConfiguratorProxy>::type PPVec;
ImplClasp::ClaspConfig::Impl78 Impl() { acycSet = 0; }
~ImplClasp::ClaspConfig::Impl79 ~Impl() { reset(); }
80 void reset();
81 void prepare(SharedContext& ctx);
82 bool addPost(Solver& s, const SolverParams& opts);
addClasp::ClaspConfig::Impl83 void add(Configurator* c, Ownership_t::Type t, bool once) { pp.push_back(ConfiguratorProxy(c, t, once)); }
84 void unfreeze(SharedContext& ctx);
85 PPVec pp;
86 uint64 acycSet;
87 #if CLASP_HAS_THREADS
88 Clasp::mt::mutex mutex;
89 #endif
90 };
reset()91 void ClaspConfig::Impl::reset() {
92 for (; !pp.empty(); pp.pop_back()) { pp.back().destroy(); }
93 }
94
prepare(SharedContext & ctx)95 void ClaspConfig::Impl::prepare(SharedContext& ctx) {
96 if (ctx.concurrency() < 64) {
97 acycSet &= (bit_mask<uint64>(ctx.concurrency()) - 1);
98 }
99 for (PPVec::iterator it = pp.begin(), end = pp.end(); it != end; ++it) {
100 it->prepare(ctx);
101 }
102 }
addPost(Solver & s,const SolverParams & opts)103 bool ClaspConfig::Impl::addPost(Solver& s, const SolverParams& opts) {
104 #if CLASP_HAS_THREADS
105 #define LOCKED() for (Clasp::mt::unique_lock<Clasp::mt::mutex> lock(mutex); lock.owns_lock(); lock.unlock())
106 #else
107 #define LOCKED()
108 #endif
109 POTASSCO_ASSERT(s.sharedContext() != 0, "Solver not attached!");
110 if (s.sharedContext()->sccGraph.get()) {
111 if (DefaultUnfoundedCheck* ufs = static_cast<DefaultUnfoundedCheck*>(s.getPost(PostPropagator::priority_reserved_ufs))) {
112 ufs->setReasonStrategy(static_cast<DefaultUnfoundedCheck::ReasonStrategy>(opts.loopRep));
113 }
114 else if (!s.addPost(new DefaultUnfoundedCheck(*s.sharedContext()->sccGraph, static_cast<DefaultUnfoundedCheck::ReasonStrategy>(opts.loopRep)))) {
115 return false;
116 }
117 }
118 if (s.sharedContext()->extGraph.get()) {
119 bool addAcyc = false;
120 // protect access to acycSet
121 LOCKED() { addAcyc = !test_bit(acycSet, s.id()) && store_set_bit(acycSet, s.id()); }
122 if (addAcyc && !s.addPost(new AcyclicityCheck(s.sharedContext()->extGraph.get()))) {
123 return false;
124 }
125 }
126 for (PPVec::iterator it = pp.begin(), end = pp.end(); it != end; ++it) {
127 // protect call to user code
128 LOCKED() { if (!it->applyConfig(s)) { return false; } }
129 }
130 return true;
131 #undef LOCKED
132 }
unfreeze(SharedContext & ctx)133 void ClaspConfig::Impl::unfreeze(SharedContext& ctx) {
134 for (PPVec::iterator it = pp.begin(), end = pp.end(); it != end; ++it) {
135 it->unfreeze(ctx);
136 }
137 }
138
ClaspConfig()139 ClaspConfig::ClaspConfig() : tester_(0), impl_(new Impl()) {}
~ClaspConfig()140 ClaspConfig::~ClaspConfig() {
141 delete impl_;
142 delete tester_;
143 }
144
reset()145 void ClaspConfig::reset() {
146 if (tester_) { tester_->reset(); }
147 impl_->reset();
148 BasicSatConfig::reset();
149 solve = SolveOptions();
150 asp = AspOptions();
151 }
152
addTesterConfig()153 BasicSatConfig* ClaspConfig::addTesterConfig() {
154 if (!tester_) { tester_ = new BasicSatConfig(); }
155 return tester_;
156 }
157
prepare(SharedContext & ctx)158 void ClaspConfig::prepare(SharedContext& ctx) {
159 BasicSatConfig::prepare(ctx);
160 uint32 numS = solve.numSolver();
161 if (numS > solve.supportedSolvers()) {
162 ctx.warn("Too many solvers.");
163 numS = solve.supportedSolvers();
164 }
165 if (numS > solve.recommendedSolvers()) {
166 ctx.warn(POTASSCO_FORMAT("Oversubscription: #Threads=%u exceeds logical CPUs=%u.", numS, solve.recommendedSolvers()));
167 }
168 for (uint32 i = 0; i != numS; ++i) {
169 if (solver(i).heuId == Heuristic_t::Domain) {
170 parse.enableHeuristic();
171 break;
172 }
173 }
174 solve.setSolvers(numS);
175 if (std::abs(static_cast<int>(solve.numModels)) != 1 || !solve.models()) {
176 ctx.setPreserveModels(true);
177 }
178 ctx.setConcurrency(solve.numSolver(), SharedContext::resize_resize);
179 impl_->prepare(ctx);
180 }
181
config(const char * n)182 Configuration* ClaspConfig::config(const char* n) {
183 return (n && std::strcmp(n, "tester") == 0) ? testerConfig() : BasicSatConfig::config(n);
184 }
185
addConfigurator(Configurator * c,Ownership_t::Type t,bool once)186 void ClaspConfig::addConfigurator(Configurator* c, Ownership_t::Type t, bool once) {
187 impl_->add(c, t, once);
188 }
189
addPost(Solver & s) const190 bool ClaspConfig::addPost(Solver& s) const {
191 return impl_->addPost(s, solver(s.id())) && BasicSatConfig::addPost(s);
192 }
193
unfreeze(SharedContext & ctx)194 void ClaspConfig::unfreeze(SharedContext& ctx) {
195 impl_->unfreeze(ctx);
196 }
197
~Configurator()198 ClaspConfig::Configurator::~Configurator() {}
prepare(SharedContext &)199 void ClaspConfig::Configurator::prepare(SharedContext&) {}
unfreeze(SharedContext &)200 void ClaspConfig::Configurator::unfreeze(SharedContext&){}
201 /////////////////////////////////////////////////////////////////////////////////////////
202 // ClaspFacade::SolveStrategy
203 /////////////////////////////////////////////////////////////////////////////////////////
204 struct ClaspFacade::SolveStrategy {
205 public:
206 enum { SIGCANCEL = 9, SIGERROR = 128};
207 enum State { state_run = 1u, state_model = 2u, state_done = 4u };
208 enum Event { event_attach, event_model, event_resume, event_detach };
~SolveStrategyClasp::ClaspFacade::SolveStrategy209 virtual ~SolveStrategy() {}
210 static SolveStrategy* create(SolveMode_t m, ClaspFacade& f, SolveAlgorithm& algo);
211 void start(EventHandler* h, const LitVec& a);
runningClasp::ClaspFacade::SolveStrategy212 bool running() const { return (state_ & uint32(state_done-1)) != 0u; }
errorClasp::ClaspFacade::SolveStrategy213 bool error() const { return signal_ == SIGERROR; }
readyClasp::ClaspFacade::SolveStrategy214 bool ready() const { return state_ != uint32(state_run); }
signalClasp::ClaspFacade::SolveStrategy215 int signal() const { return static_cast<int>(signal_); }
interruptClasp::ClaspFacade::SolveStrategy216 bool interrupt(int sig) {
217 bool stopped = running() && compare_and_swap(signal_, uint32(0), uint32(sig)) == 0u && algo_->interrupt();
218 if (sig == SIGCANCEL) { wait(-1.0); }
219 return stopped;
220 }
waitClasp::ClaspFacade::SolveStrategy221 bool wait(double s) { return doWait(s); }
resumeClasp::ClaspFacade::SolveStrategy222 void resume() { doNotify(event_resume); }
setModelClasp::ClaspFacade::SolveStrategy223 bool setModel(const Solver& s, const Model& m) {
224 result_.flags |= SolveResult::SAT;
225 bool ok = !handler_ || handler_->onModel(s, m);
226 if ((mode_ & SolveMode_t::Yield) != 0) { doNotify(event_model); }
227 return ok && !signal();
228 }
resultClasp::ClaspFacade::SolveStrategy229 Result result() {
230 wait(-1.0);
231 if (error()) { throw std::runtime_error(error_.c_str()); }
232 return result_;
233 }
modelClasp::ClaspFacade::SolveStrategy234 const Model* model() {
235 return state_ == state_model || (result().sat() && state_ == state_model)
236 ? &algo_->model()
237 : 0;
238 }
nextClasp::ClaspFacade::SolveStrategy239 bool next() {
240 return running() && (state_ != state_model || (resume(), true)) && model() != 0;
241 }
releaseClasp::ClaspFacade::SolveStrategy242 void release() {
243 if (--nrefs_ == 1) { interrupt(SIGCANCEL); }
244 else if (nrefs_ == 0) { delete this; }
245 }
shareClasp::ClaspFacade::SolveStrategy246 SolveStrategy* share() { ++nrefs_; return this; }
247 protected:
248 SolveStrategy(SolveMode_t m, ClaspFacade& f, SolveAlgorithm* algo);
249 ClaspFacade* facade_;
250 SolveAlgorithm* algo_;
251 void startAlgo(SolveMode_t m);
continueAlgoClasp::ClaspFacade::SolveStrategy252 void continueAlgo() {
253 bool detach = true;
254 try {
255 detach = (signal() && running()) || (state_ == state_run && !algo_->next());
256 if (detach) { detach = false; detachAlgo(algo_->more(), 0); }
257 }
258 catch (...) {
259 if (detach) { detachAlgo(algo_->more(), 1); }
260 else { throw; }
261 }
262 }
263 void detachAlgo(bool more, int nException, int state = 0);
264 private:
265 struct Async;
doStartClasp::ClaspFacade::SolveStrategy266 virtual void doStart() { startAlgo(mode_); }
doWaitClasp::ClaspFacade::SolveStrategy267 virtual bool doWait(double maxTime) {
268 POTASSCO_REQUIRE(maxTime < 0.0, "Timed wait not supported!");
269 if (mode_ == SolveMode_t::Yield) { continueAlgo(); }
270 return true;
271 }
doNotifyClasp::ClaspFacade::SolveStrategy272 virtual void doNotify(Event event) {
273 switch (event) {
274 case event_attach: state_ = state_run; break;
275 case event_model : state_ = state_model; break;
276 case event_resume: compare_and_swap(state_, uint32(state_model), uint32(state_run)); break;
277 case event_detach: state_ = state_done; break;
278 };
279 }
280 typedef Clasp::Atomic_t<uint32>::type SafeIntType;
281 std::string error_;
282 EventHandler* handler_;
283 SafeIntType nrefs_; // Facade + #Handle objects
284 SafeIntType state_;
285 SafeIntType signal_;
286 Result result_;
287 SolveMode_t mode_;
288 uint32 aTop_;
289 };
SolveStrategy(SolveMode_t m,ClaspFacade & f,SolveAlgorithm * algo)290 ClaspFacade::SolveStrategy::SolveStrategy(SolveMode_t m, ClaspFacade& f, SolveAlgorithm* algo)
291 : facade_(&f)
292 , algo_(algo)
293 , handler_(0)
294 , mode_(m) {
295 nrefs_ = 1;
296 state_ = signal_ = 0;
297 }
start(EventHandler * h,const LitVec & a)298 void ClaspFacade::SolveStrategy::start(EventHandler* h, const LitVec& a) {
299 ClaspFacade& f = *facade_;
300 aTop_ = (uint32)f.assume_.size();
301 f.assume_.insert(f.assume_.end(), a.begin(), a.end());
302 if (!isSentinel(f.ctx.stepLiteral())) {
303 f.assume_.push_back(f.ctx.stepLiteral());
304 }
305 handler_ = h;
306 std::memset(&result_, 0, sizeof(SolveResult));
307 doStart();
308 assert(running() || ready());
309 }
startAlgo(SolveMode_t m)310 void ClaspFacade::SolveStrategy::startAlgo(SolveMode_t m) {
311 bool more = true, detach = true;
312 doNotify(event_attach);
313 try {
314 facade_->interrupt(0); // handle pending interrupts
315 if (!signal_ && !facade_->ctx.master()->hasConflict()) {
316 facade_->step_.solveTime = facade_->step_.unsatTime = RealTime::getTime();
317 if ((m & SolveMode_t::Yield) == 0) {
318 more = algo_->solve(facade_->ctx, facade_->assume_, facade_);
319 }
320 else {
321 algo_->start(facade_->ctx, facade_->assume_, facade_);
322 detach = false;
323 }
324 }
325 else {
326 facade_->ctx.report(Clasp::Event::subsystem_solve);
327 more = facade_->ctx.ok();
328 }
329 if (detach) { detach = false; detachAlgo(more, 0); }
330 }
331 catch (...) {
332 if (detach) { detachAlgo(more, 1); }
333 else { throw; }
334 }
335 }
detachAlgo(bool more,int nException,int state)336 void ClaspFacade::SolveStrategy::detachAlgo(bool more, int nException, int state) {
337 #define PROTECT(ec, X) if ((ec)) try { X; } catch (...) {} else X
338 try {
339 if (nException == 1) { throw; }
340 switch (state) {
341 case 0: ++state; PROTECT(nException, algo_->stop()); // FALLTHRU
342 case 1: ++state; PROTECT(nException, facade_->stopStep(signal_, !more)); // FALLTHRU
343 case 2: ++state; if (handler_) { PROTECT(nException, handler_->onEvent(StepReady(facade_->summary()))); } // FALLTHRU
344 case 3: state = -1;
345 result_ = facade_->result();
346 facade_->assume_.resize(aTop_);
347 doNotify(event_detach);
348 default: break;
349 }
350 }
351 catch (...) {
352 error_ = "Operation failed: ";
353 if (!signal_) { signal_ = SIGERROR; }
354 if (state != -1) { detachAlgo(more, 2, state); }
355 if ((mode_ & SolveMode_t::Async) == 0) {
356 error_ += "exception thrown";
357 throw;
358 }
359 try { throw; }
360 catch (const std::exception& e) { error_ = e.what(); }
361 catch (...) { error_ = "unknown error"; }
362 }
363 }
364 #if CLASP_HAS_THREADS
365 struct ClaspFacade::SolveStrategy::Async : public ClaspFacade::SolveStrategy {
366 enum { state_async = (state_done << 1), state_next = state_model | state_async, state_join = state_done | state_async };
AsyncClasp::ClaspFacade::SolveStrategy::Async367 Async(SolveMode_t m, ClaspFacade& f, SolveAlgorithm* algo) : SolveStrategy(m, f, algo) {}
doStartClasp::ClaspFacade::SolveStrategy::Async368 virtual void doStart() {
369 algo_->enableInterrupts();
370 Clasp::mt::thread(std::mem_fun(&SolveStrategy::startAlgo), this, SolveMode_t::Async).swap(task_);
371 for (mt::unique_lock<Clasp::mt::mutex> lock(mqMutex_); state_ == 0u;) {
372 mqCond_.wait(lock);
373 }
374 }
doWaitClasp::ClaspFacade::SolveStrategy::Async375 virtual bool doWait(double t) {
376 for (mt::unique_lock<Clasp::mt::mutex> lock(mqMutex_);;) {
377 if (signal() && running()) { // propagate signal to async thread and force wait
378 mqCond_.notify_all();
379 mqCond_.wait(lock);
380 }
381 else if (ready()) { break; }
382 else if (t < 0.0) { mqCond_.wait(lock); }
383 else if (t > 0.0) { mqCond_.wait_for(lock, t); t = 0.0; }
384 else { return false; }
385 }
386 assert(ready());
387 // acknowledge current model or join if first to see done
388 if (compare_and_swap(state_, uint32(state_next), uint32(state_model)) == state_done
389 && compare_and_swap(state_, uint32(state_done), uint32(state_join)) == state_done) {
390 task_.join();
391 }
392 return true;
393 }
doNotifyClasp::ClaspFacade::SolveStrategy::Async394 virtual void doNotify(Event event) {
395 mt::unique_lock<Clasp::mt::mutex> lock(mqMutex_);
396 switch (event) {
397 case event_attach: state_ = state_run; break;
398 case event_model : state_ = state_next; break;
399 case event_resume: if (state_ == state_model) { state_ = state_run; break; } else { return; }
400 case event_detach: state_ = state_done; break;
401 };
402 lock.unlock(); // synchronize-with other threads but no need to notify under lock
403 mqCond_.notify_all();
404 if (event == event_model) {
405 for (lock.lock(); state_ != state_run && !signal();) {
406 mqCond_.wait(lock);
407 }
408 }
409 }
410 typedef Clasp::mt::condition_variable ConditionVar;
411 Clasp::mt::thread task_; // async solving thread
412 Clasp::mt::mutex mqMutex_;// protects mqCond
413 ConditionVar mqCond_; // for iterating over models one by one
414 };
415 #endif
create(SolveMode_t m,ClaspFacade & f,SolveAlgorithm & algo)416 ClaspFacade::SolveStrategy* ClaspFacade::SolveStrategy::create(SolveMode_t m, ClaspFacade& f, SolveAlgorithm& algo) {
417 if ((m & SolveMode_t::Async) == 0) { return new SolveStrategy(m, f, &algo); }
418 #if CLASP_HAS_THREADS
419 return new SolveStrategy::Async(m, f, &algo);
420 #else
421 throw std::logic_error("Solve mode not supported!");
422 #endif
423 }
424 /////////////////////////////////////////////////////////////////////////////////////////
425 // ClaspFacade::SolveData
426 /////////////////////////////////////////////////////////////////////////////////////////
427 struct ClaspFacade::SolveData {
428 struct CostArray {
CostArrayClasp::ClaspFacade::SolveData::CostArray429 CostArray() : data(0) {}
~CostArrayClasp::ClaspFacade::SolveData::CostArray430 ~CostArray() { while (!refs.empty()) { delete refs.back(); refs.pop_back(); } }
431 struct LevelRef {
LevelRefClasp::ClaspFacade::SolveData::CostArray::LevelRef432 LevelRef(const CostArray* a, uint32 l) : arr(a), at(l) {}
valueClasp::ClaspFacade::SolveData::CostArray::LevelRef433 static double value(const LevelRef* ref) {
434 POTASSCO_REQUIRE(ref->at < ref->arr->size(), "expired key");
435 return static_cast<double>(ref->arr->data->costs->at(ref->at));
436 }
437 const CostArray* arr;
438 uint32 at;
439 };
440 typedef PodVector<LevelRef*>::type ElemVec;
sizeClasp::ClaspFacade::SolveData::CostArray441 uint32 size() const {
442 return data && data->costs ? sizeVec(*data->costs) : 0;
443 }
atClasp::ClaspFacade::SolveData::CostArray444 StatisticObject at(uint32 i) const {
445 POTASSCO_REQUIRE(i < size(), "invalid key");
446 while (i >= refs.size()) { refs.push_back(new LevelRef(this, sizeVec(refs))); }
447 return StatisticObject::value<LevelRef, &LevelRef::value>(refs[i]);
448 }
449 const Model* data;
450 mutable ElemVec refs;
451 };
452 typedef SingleOwnerPtr<SolveAlgorithm> AlgoPtr;
453 typedef SingleOwnerPtr<Enumerator> EnumPtr;
454 typedef Clasp::Atomic_t<int>::type SafeIntType;
455 typedef const SharedMinimizeData* MinPtr;
SolveDataClasp::ClaspFacade::SolveData456 SolveData() : en(0), algo(0), active(0), prepared(false), solved(false), interruptible(false) { qSig = 0; }
~SolveDataClasp::ClaspFacade::SolveData457 ~SolveData() { reset(); }
458 void init(SolveAlgorithm* algo, Enumerator* en);
459 void reset();
460 void prepareEnum(SharedContext& ctx, int64 numM, EnumOptions::OptMode opt, EnumMode mode, ProjectMode prj);
interruptClasp::ClaspFacade::SolveData461 bool interrupt(int sig) {
462 if (solving()) { return active->interrupt(sig); }
463 if (!qSig && sig != SolveStrategy::SIGCANCEL) { qSig = sig; }
464 return false;
465 }
onModelClasp::ClaspFacade::SolveData466 bool onModel(const Solver& s, const Model& m) {
467 return !active || active->setModel(s, m);
468 }
solvingClasp::ClaspFacade::SolveData469 bool solving() const { return active && active->running(); }
lastModelClasp::ClaspFacade::SolveData470 const Model* lastModel() const { return en.get() ? &en->lastModel() : 0; }
minimizerClasp::ClaspFacade::SolveData471 MinPtr minimizer() const { return en.get() ? en->minimizer() : 0; }
enumeratorClasp::ClaspFacade::SolveData472 Enumerator* enumerator()const { return en.get(); }
modelTypeClasp::ClaspFacade::SolveData473 int modelType() const { return en.get() ? en->modelType() : 0; }
signalClasp::ClaspFacade::SolveData474 int signal() const { return solving() ? active->signal() : static_cast<int>(qSig); }
475 EnumPtr en;
476 AlgoPtr algo;
477 SolveStrategy* active;
478 CostArray costs;
479 SafeIntType qSig;
480 bool prepared;
481 bool solved;
482 bool interruptible;
483 };
init(SolveAlgorithm * a,Enumerator * e)484 void ClaspFacade::SolveData::init(SolveAlgorithm* a, Enumerator* e) {
485 en = e;
486 algo = a;
487 costs.data = 0;
488 algo->setEnumerator(*en);
489 if (interruptible) {
490 this->algo->enableInterrupts();
491 }
492 }
reset()493 void ClaspFacade::SolveData::reset() {
494 if (active) { active->interrupt(SolveStrategy::SIGCANCEL); active->release(); active = 0; }
495 if (algo.get()) { algo->resetSolve(); }
496 if (en.get()) { en->reset(); }
497 prepared = solved = false;
498 }
prepareEnum(SharedContext & ctx,int64 numM,EnumOptions::OptMode opt,EnumMode mode,ProjectMode proj)499 void ClaspFacade::SolveData::prepareEnum(SharedContext& ctx, int64 numM, EnumOptions::OptMode opt, EnumMode mode, ProjectMode proj) {
500 POTASSCO_REQUIRE(!active, "Solve operation still active");
501 if (ctx.ok() && !ctx.frozen() && !prepared) {
502 if (mode == enum_volatile && ctx.solveMode() == SharedContext::solve_multi) {
503 ctx.requestStepVar();
504 }
505 ctx.output.setProjectMode(proj);
506 int lim = en->init(ctx, opt, (int)Range<int64>(-1, INT_MAX).clamp(numM));
507 if (lim == 0 || numM < 0) {
508 numM = lim;
509 }
510 algo->setEnumLimit(numM ? static_cast<uint64>(numM) : UINT64_MAX);
511 costs.data = lastModel();
512 prepared = true;
513 }
514 }
SolveHandle(SolveStrategy * s)515 ClaspFacade::SolveHandle::SolveHandle(SolveStrategy* s) : strat_(s->share()) {}
~SolveHandle()516 ClaspFacade::SolveHandle::~SolveHandle() { strat_->release(); }
SolveHandle(const SolveHandle & o)517 ClaspFacade::SolveHandle::SolveHandle(const SolveHandle& o) : strat_(o.strat_->share()) {}
interrupted() const518 int ClaspFacade::SolveHandle::interrupted() const { return strat_->signal(); }
error() const519 bool ClaspFacade::SolveHandle::error() const { return ready() && strat_->error(); }
ready() const520 bool ClaspFacade::SolveHandle::ready() const { return strat_->ready(); }
running() const521 bool ClaspFacade::SolveHandle::running() const { return strat_->running(); }
cancel() const522 void ClaspFacade::SolveHandle::cancel() const { strat_->interrupt(SolveStrategy::SIGCANCEL); }
wait() const523 void ClaspFacade::SolveHandle::wait() const { strat_->wait(-1.0); }
waitFor(double s) const524 bool ClaspFacade::SolveHandle::waitFor(double s) const { return strat_->wait(s); }
resume() const525 void ClaspFacade::SolveHandle::resume() const { strat_->resume(); }
get() const526 SolveResult ClaspFacade::SolveHandle::get() const { return strat_->result(); }
model() const527 const Model* ClaspFacade::SolveHandle::model() const { return strat_->model(); }
next() const528 bool ClaspFacade::SolveHandle::next() const { return strat_->next(); }
529 /////////////////////////////////////////////////////////////////////////////////////////
530 // ClaspFacade::Statistics
531 /////////////////////////////////////////////////////////////////////////////////////////
532 namespace {
533 struct KV { const char* key; StatisticObject(*get)(const ClaspFacade::Summary*); };
534 template <double ClaspFacade::Summary::*time>
_getT(const ClaspFacade::Summary * x)535 StatisticObject _getT(const ClaspFacade::Summary* x) { return StatisticObject::value(&static_cast<const double&>((x->*time))); }
536 template <uint64 ClaspFacade::Summary::*model>
_getM(const ClaspFacade::Summary * x)537 StatisticObject _getM(const ClaspFacade::Summary* x) { return StatisticObject::value(&static_cast<const uint64&>((x->*model))); }
538 static const KV sumKeys_s[] = {
539 {"total" , _getT<&ClaspFacade::Summary::totalTime>},
540 {"cpu" , _getT<&ClaspFacade::Summary::cpuTime>},
541 {"solve" , _getT<&ClaspFacade::Summary::solveTime>},
542 {"unsat" , _getT<&ClaspFacade::Summary::unsatTime>},
543 {"sat" , _getT<&ClaspFacade::Summary::satTime>},
544 {"enumerated", _getM<&ClaspFacade::Summary::numEnum>},
545 {"optimal" , _getM<&ClaspFacade::Summary::numOptimal>},
546 };
547 struct SummaryStats {
SummaryStatsClasp::__anon3da370190411::SummaryStats548 SummaryStats() : stats_(0), range_(0,0) {}
bindClasp::__anon3da370190411::SummaryStats549 void bind(const ClaspFacade::Summary& x, Range32 r) {
550 stats_ = &x;
551 range_ = r;
552 }
sizeClasp::__anon3da370190411::SummaryStats553 uint32 size() const { return range_.hi - range_.lo; }
keyClasp::__anon3da370190411::SummaryStats554 const char* key(uint32 i) const { return i < size() ? sumKeys_s[i + range_.lo].key : throw std::out_of_range(POTASSCO_FUNC_NAME); }
atClasp::__anon3da370190411::SummaryStats555 StatisticObject at(const char* key) const {
556 for (const KV* x = sumKeys_s + range_.lo, *end = sumKeys_s + range_.hi; x != end; ++x) {
557 if (std::strcmp(x->key, key) == 0) { return x->get(stats_); }
558 }
559 throw std::out_of_range(POTASSCO_FUNC_NAME);
560 }
toStatsClasp::__anon3da370190411::SummaryStats561 StatisticObject toStats() const { return StatisticObject::map(this); }
562 const ClaspFacade::Summary* stats_;
563 Range32 range_;
564 };
565
_getConcurrency(const SharedContext * ctx)566 double _getConcurrency(const SharedContext* ctx) { return ctx->concurrency(); }
_getWinner(const SharedContext * ctx)567 double _getWinner(const SharedContext* ctx) { return ctx->winner(); }
_getResult(const SolveResult * r)568 double _getResult(const SolveResult* r) { return static_cast<double>(r->operator Clasp::SolveResult::Base()); }
_getSignal(const SolveResult * r)569 double _getSignal(const SolveResult* r) { return static_cast<double>(r->signal); }
_getExhausted(const SolveResult * r)570 double _getExhausted(const SolveResult* r) { return static_cast<double>(r->exhausted()); }
571 }
572
573 struct ClaspFacade::Statistics {
StatisticsClasp::ClaspFacade::Statistics574 Statistics(ClaspFacade& f) : self_(&f), tester_(0), level_(0), clingo_(0) {}
~StatisticsClasp::ClaspFacade::Statistics575 ~Statistics() { delete clingo_; delete solvers_.multi; }
576 void start(uint32 level);
577 void initLevel(uint32 level);
578 void end();
579 void addTo(StatsMap& solving, StatsMap* accu) const;
580 void accept(StatsVisitor& out, bool final) const;
incrementalClasp::ClaspFacade::Statistics581 bool incremental() const { return self_->incremental(); }
582 typedef StatsVec<SolverStats> SolverVec;
583 typedef SingleOwnerPtr<Asp::LpStats> LpStatsPtr;
584 typedef PrgDepGraph::NonHcfStats TesterStats;
585 ClaspFacade* self_;
586 LpStatsPtr lp_; // level 0 and asp
587 SolverStats solvers_; // level 0
588 SolverVec solver_; // level > 1
589 SolverVec accu_; // level > 1 and incremental
590 TesterStats* tester_; // level > 0 and nonhcfs
591 uint32 level_; // active stats level
592 // For clingo stats interface
593 class ClingoView : public ClaspStatistics {
594 public:
595 explicit ClingoView(const ClaspFacade& f);
596 void update(const Statistics& s);
597 Key_t user(bool final) const;
598 private:
599 struct StepStats {
600 SummaryStats times;
601 SummaryStats models;
bindClasp::ClaspFacade::Statistics::ClingoView::StepStats602 void bind(const ClaspFacade::Summary& x) {
603 times.bind(x, Range32(0, 5));
604 models.bind(x, Range32(5, 7));
605 }
addToClasp::ClaspFacade::Statistics::ClingoView::StepStats606 void addTo(StatsMap& summary) {
607 summary.add("times", times.toStats());
608 summary.add("models", models.toStats());
609 }
610 };
611 StatsMap* keys_;
612 StatsMap problem_;
613 StatsMap solving_;
614 struct Summary : StatsMap { StepStats step; } summary_;
615 struct Accu : StatsMap { StepStats step; StatsMap solving_; };
616 typedef SingleOwnerPtr<Accu> AccuPtr;
617 AccuPtr accu_;
618 }* clingo_; // new clingo stats interface
619 ClingoView* getClingo();
620 };
initLevel(uint32 level)621 void ClaspFacade::Statistics::initLevel(uint32 level) {
622 if (level_ < level) {
623 if (incremental() && !solvers_.multi) { solvers_.multi = new SolverStats(); }
624 level_ = level;
625 }
626 if (self_->ctx.sccGraph.get() && self_->ctx.sccGraph->numNonHcfs() && !tester_) {
627 tester_ = self_->ctx.sccGraph->nonHcfStats();
628 }
629 }
630
start(uint32 level)631 void ClaspFacade::Statistics::start(uint32 level) {
632 // cleanup previous state
633 solvers_.reset();
634 solver_.reset();
635 if (tester_) { tester_->startStep(self_->config()->testerConfig() ? self_->config()->testerConfig()->context().stats : 0); }
636 // init next step
637 initLevel(level);
638 if (lp_.get() && self_->step_.lpStep()) {
639 lp_->accu(*self_->step_.lpStep());
640 }
641 if (level > 1 && solver_.size() < self_->ctx.concurrency()) {
642 uint32 sz = sizeVec(solver_);
643 solver_.growTo(self_->ctx.concurrency());
644 for (const bool inc = incremental() && (accu_.growTo(sizeVec(solver_)), true); sz != sizeVec(solver_); ++sz) {
645 if (!inc) { solver_[sz] = &self_->ctx.solverStats(sz); }
646 else { (solver_[sz] = new SolverStats())->multi = (accu_[sz] = new SolverStats()); }
647 }
648 if (!incremental()) { solver_.release(); }
649 }
650 }
end()651 void ClaspFacade::Statistics::end() {
652 self_->ctx.accuStats(solvers_); // compute solvers = sum(solver[1], ... , solver[n])
653 solvers_.flush();
654 for (uint32 i = incremental() ? 0 : sizeVec(solver_), end = sizeVec(solver_); i != end && self_->ctx.hasSolver(i); ++i) {
655 solver_[i]->accu(self_->ctx.solverStats(i), true);
656 solver_[i]->flush();
657 }
658 if (tester_) { tester_->endStep(); }
659 if (clingo_) { clingo_->update(*this); }
660 }
addTo(StatsMap & solving,StatsMap * accu) const661 void ClaspFacade::Statistics::addTo(StatsMap& solving, StatsMap* accu) const {
662 solvers_.addTo("solvers", solving, accu);
663 if (solver_.size()) { solving.add("solver", solver_.toStats()); }
664 if (accu && accu_.size()) { accu->add("solver", accu_.toStats()); }
665 }
accept(StatsVisitor & out,bool final) const666 void ClaspFacade::Statistics::accept(StatsVisitor& out, bool final) const {
667 final = final && solvers_.multi;
668 if (out.visitGenerator(StatsVisitor::Enter)) {
669 out.visitSolverStats(final ? *solvers_.multi : solvers_);
670 if (lp_.get()) { out.visitLogicProgramStats(*lp_); }
671 out.visitProblemStats(self_->ctx.stats());
672 const SolverVec& solver = final ? accu_ : solver_;
673 const uint32 nThreads = final ? (uint32)accu_.size() : self_->ctx.concurrency();
674 const uint32 nSolver = (uint32)solver.size();
675 if (const AbstractStatistics::Key_t userKey = clingo_ ? clingo_->user(final) : 0) {
676 out.visitExternalStats(clingo_->getObject(userKey));
677 }
678 if (nThreads > 1 && nSolver > 1 && out.visitThreads(StatsVisitor::Enter)) {
679 for (uint32 i = 0, end = std::min(nSolver, nThreads); i != end; ++i) {
680 out.visitThread(i, *solver[i]);
681 }
682 out.visitThreads(StatsVisitor::Leave);
683 }
684 out.visitGenerator(StatsVisitor::Leave);
685 }
686 if (tester_ && out.visitTester(StatsVisitor::Enter)) {
687 tester_->accept(out, final);
688 out.visitTester(StatsVisitor::Leave);
689 }
690 }
getClingo()691 ClaspFacade::Statistics::ClingoView* ClaspFacade::Statistics::getClingo() {
692 if (!clingo_) {
693 clingo_ = new ClingoView(*this->self_);
694 clingo_->update(*this);
695 }
696 return clingo_;
697 }
ClingoView(const ClaspFacade & f)698 ClaspFacade::Statistics::ClingoView::ClingoView(const ClaspFacade& f) {
699 keys_ = makeRoot();
700 summary_.add("call" , StatisticObject::value(&f.step_.step));
701 summary_.add("result" , StatisticObject::value<SolveResult, _getResult>(&f.step_.result));
702 summary_.add("signal" , StatisticObject::value<SolveResult, _getSignal>(&f.step_.result));
703 summary_.add("exhausted" , StatisticObject::value<SolveResult, _getExhausted>(&f.step_.result));
704 summary_.add("costs" , StatisticObject::array(&f.solve_->costs));
705 summary_.add("concurrency", StatisticObject::value<SharedContext, _getConcurrency>(&f.ctx));
706 summary_.add("winner" , StatisticObject::value<SharedContext, _getWinner>(&f.ctx));
707 summary_.step.bind(f.step_);
708 summary_.step.addTo(summary_);
709 if (f.step_.lpStats()) {
710 problem_.add("lp", StatisticObject::map(f.step_.lpStats()));
711 if (f.incremental()) { problem_.add("lpStep", StatisticObject::map(f.step_.lpStep())); }
712 }
713 problem_.add("generator", StatisticObject::map(&f.ctx.stats()));
714 keys_->add("problem", problem_.toStats());
715 keys_->add("solving", solving_.toStats());
716 keys_->add("summary", summary_.toStats());
717
718 if (f.incremental()) {
719 accu_ = new Accu();
720 accu_->step.bind(*f.accu_.get());
721 }
722 }
user(bool final) const723 Potassco::AbstractStatistics::Key_t ClaspFacade::Statistics::ClingoView::user(bool final) const {
724 Key_t key = 0;
725 find(root(), final ? "user_accu" : "user_step", &key);
726 return key;
727 }
update(const ClaspFacade::Statistics & stats)728 void ClaspFacade::Statistics::ClingoView::update(const ClaspFacade::Statistics& stats) {
729 if (stats.level_ > 0 && accu_.get() && keys_->add("accu", accu_->toStats())) {
730 accu_->step.addTo(*accu_);
731 accu_->add("solving", accu_->solving_.toStats());
732 }
733 stats.addTo(solving_, stats.level_ > 0 && accu_.get() ? &accu_->solving_ : 0);
734 if (stats.tester_) {
735 stats.tester_->addTo(problem_, solving_, stats.level_ > 0 && accu_.get() ? &accu_->solving_ : 0);
736 }
737 }
738 /////////////////////////////////////////////////////////////////////////////////////////
739 // ClaspFacade
740 /////////////////////////////////////////////////////////////////////////////////////////
ClaspFacade()741 ClaspFacade::ClaspFacade() : config_(0) { step_.init(*this); }
~ClaspFacade()742 ClaspFacade::~ClaspFacade() {}
prepared() const743 bool ClaspFacade::prepared() const {
744 return solve_.get() && solve_->prepared;
745 }
solving() const746 bool ClaspFacade::solving() const {
747 return solve_.get() && solve_->solving();
748 }
solved() const749 bool ClaspFacade::solved() const {
750 return solve_.get() && solve_->solved;
751 }
interrupted() const752 bool ClaspFacade::interrupted() const {
753 return result().interrupted();
754 }
incremental() const755 bool ClaspFacade::incremental() const {
756 return accu_.get() != 0;
757 }
detectProblemType(std::istream & str)758 ProblemType ClaspFacade::detectProblemType(std::istream& str) {
759 return Clasp::detectProblemType(str);
760 }
summary(bool accu) const761 const ClaspFacade::Summary& ClaspFacade::summary(bool accu) const {
762 return accu && accu_.get() ? *accu_ : step_;
763 }
764
discardProblem()765 void ClaspFacade::discardProblem() {
766 config_ = 0;
767 builder_ = 0;
768 stats_ = 0;
769 solve_ = 0;
770 accu_ = 0;
771 step_.init(*this);
772 if (ctx.frozen() || ctx.numVars()) { ctx.reset(); }
773 }
init(ClaspConfig & config,bool discard)774 void ClaspFacade::init(ClaspConfig& config, bool discard) {
775 if (discard) { discardProblem(); }
776 ctx.setConfiguration(0, Ownership_t::Retain); // force reload of configuration once done
777 config_ = &config;
778 if (config_->solve.enumMode == EnumOptions::enum_dom_record && config_->solver(0).heuId != Heuristic_t::Domain) {
779 ctx.warn("Reasoning mode requires domain heuristic and is ignored.");
780 config_->solve.enumMode = EnumOptions::enum_auto;
781 }
782 SolveData::EnumPtr e(config.solve.createEnumerator(config.solve));
783 if (e.get() == 0) { e = EnumOptions::nullEnumerator(); }
784 if (config.solve.numSolver() > 1 && !e->supportsParallel()) {
785 ctx.warn("Selected reasoning mode implies #Threads=1.");
786 config.solve.setSolvers(1);
787 }
788 ctx.setConfiguration(&config, Ownership_t::Retain); // prepare and apply config
789 if (program() && type_ == Problem_t::Asp) {
790 Asp::LogicProgram* p = static_cast<Asp::LogicProgram*>(program());
791 p->setOptions(config.asp);
792 p->setNonHcfConfiguration(config.testerConfig());
793 }
794 if (!solve_.get()) { solve_ = new SolveData(); }
795 SolveData::AlgoPtr a(config.solve.createSolveObject());
796 solve_->init(a.release(), e.release());
797 if (discard) { startStep(0); }
798 }
799
initBuilder(ProgramBuilder * in)800 void ClaspFacade::initBuilder(ProgramBuilder* in) {
801 builder_ = in;
802 assume_.clear();
803 builder_->startProgram(ctx);
804 }
start(ClaspConfig & config,ProblemType t)805 ProgramBuilder& ClaspFacade::start(ClaspConfig& config, ProblemType t) {
806 if (t == Problem_t::Sat) { return startSat(config); }
807 else if (t == Problem_t::Pb) { return startPB(config); }
808 else if (t == Problem_t::Asp) { return startAsp(config); }
809 else { throw std::domain_error("Unknown problem type!"); }
810 }
811
start(ClaspConfig & config,std::istream & str)812 ProgramBuilder& ClaspFacade::start(ClaspConfig& config, std::istream& str) {
813 ProgramParser& p = start(config, detectProblemType(str)).parser();
814 POTASSCO_REQUIRE(p.accept(str, config_->parse), "Auto detection failed!");
815 if (p.incremental()) { enableProgramUpdates(); }
816 return *program();
817 }
818
startSat(ClaspConfig & config)819 SatBuilder& ClaspFacade::startSat(ClaspConfig& config) {
820 init(config, true);
821 initBuilder(new SatBuilder());
822 type_ = Problem_t::Sat;
823 return static_cast<SatBuilder&>(*builder_.get());
824 }
825
startPB(ClaspConfig & config)826 PBBuilder& ClaspFacade::startPB(ClaspConfig& config) {
827 init(config, true);
828 initBuilder(new PBBuilder());
829 type_ = Problem_t::Sat;
830 return static_cast<PBBuilder&>(*builder_.get());
831 }
832
startAsp(ClaspConfig & config,bool enableUpdates)833 Asp::LogicProgram& ClaspFacade::startAsp(ClaspConfig& config, bool enableUpdates) {
834 init(config, true);
835 Asp::LogicProgram* p = new Asp::LogicProgram();
836 initBuilder(p);
837 p->setOptions(config.asp);
838 p->setNonHcfConfiguration(config.testerConfig());
839 type_ = Problem_t::Asp;
840 stats_->lp_ = new Asp::LpStats();
841 if (enableUpdates) { enableProgramUpdates(); }
842 return *p;
843 }
844
enableProgramUpdates()845 bool ClaspFacade::enableProgramUpdates() {
846 POTASSCO_REQUIRE(program(), "Program was already released!");
847 POTASSCO_REQUIRE(!solving() && !program()->frozen());
848 if (!accu_.get()) {
849 builder_->updateProgram();
850 ctx.setSolveMode(SharedContext::solve_multi);
851 enableSolveInterrupts();
852 accu_ = new Summary();
853 accu_->init(*this);
854 accu_->step = UINT32_MAX;
855 }
856 return isAsp(); // currently only ASP supports program updates
857 }
enableSolveInterrupts()858 void ClaspFacade::enableSolveInterrupts() {
859 POTASSCO_REQUIRE(!solving(), "Solving is already active!");
860 POTASSCO_ASSERT(solve_.get(), "Active program required!");
861 if (!solve_->interruptible) {
862 solve_->interruptible = true;
863 solve_->algo->enableInterrupts();
864 }
865 }
866
startStep(uint32 n)867 void ClaspFacade::startStep(uint32 n) {
868 step_.init(*this);
869 step_.totalTime = RealTime::getTime();
870 step_.cpuTime = ProcessTime::getTime();
871 step_.step = n;
872 solve_->solved = false;
873 if (!stats_.get()) { stats_ = new Statistics(*this); }
874 ctx.report(StepStart(*this));
875 }
876
stopStep(int signal,bool complete)877 ClaspFacade::Result ClaspFacade::stopStep(int signal, bool complete) {
878 if (!solved()) {
879 double t = RealTime::getTime();
880 solve_->solved = true;
881 step_.totalTime = diffTime(t, step_.totalTime);
882 step_.cpuTime = diffTime(ProcessTime::getTime(), step_.cpuTime);
883 if (step_.solveTime) {
884 step_.solveTime = diffTime(t, step_.solveTime);
885 step_.unsatTime = complete ? diffTime(t, step_.unsatTime) : 0;
886 }
887 Result res = {uint8(0), uint8(signal)};
888 if (complete) { res.flags = uint8(step_.numEnum ? Result::SAT : Result::UNSAT) | Result::EXT_EXHAUST; }
889 else { res.flags = uint8(step_.numEnum ? Result::SAT : Result::UNKNOWN); }
890 if (signal) { res.flags|= uint8(Result::EXT_INTERRUPT); }
891 step_.result = res;
892 if (res.sat() && step_.model()->opt && !step_.numOptimal) {
893 step_.numOptimal = 1;
894 }
895 updateStats();
896 ctx.report(StepReady(step_));
897 ctx.report(Event::subsystem_facade);
898 }
899 return result();
900 }
901
updateStats()902 void ClaspFacade::updateStats() {
903 if (stats_.get()) {
904 stats_->end();
905 }
906 if (accu_.get() && accu_->step != step_.step) {
907 accu_->totalTime += step_.totalTime;
908 accu_->cpuTime += step_.cpuTime;
909 accu_->solveTime += step_.solveTime;
910 accu_->unsatTime += step_.unsatTime;
911 accu_->satTime += step_.satTime;
912 accu_->numEnum += step_.numEnum;
913 accu_->numOptimal += step_.numOptimal;
914 // no aggregation
915 accu_->step = step_.step;
916 accu_->result = step_.result;
917 }
918 }
919
interrupt(int signal)920 bool ClaspFacade::interrupt(int signal) {
921 return solve_.get() && (signal || (signal = solve_->qSig.exchange(0)) != 0) && solve_->interrupt(signal);
922 }
923
shutdown()924 const ClaspFacade::Summary& ClaspFacade::shutdown() {
925 if (solve_.get()) {
926 solve_->interrupt(SolveStrategy::SIGCANCEL);
927 stopStep(solve_->signal(), !ok());
928 }
929 return summary(true);
930 }
931
read()932 bool ClaspFacade::read() {
933 POTASSCO_REQUIRE(solve_.get());
934 if (!program() || interrupted()) { return false; }
935 ProgramParser& p = program()->parser();
936 if (!p.isOpen() || (solved() && !update().ok())) { return false; }
937 POTASSCO_REQUIRE(p.parse(), "Invalid input stream!");
938 if (!p.more()) { p.reset(); }
939 return true;
940 }
941
prepare(EnumMode enumMode)942 void ClaspFacade::prepare(EnumMode enumMode) {
943 POTASSCO_REQUIRE(solve_.get() && !solving());
944 EnumOptions& en = config_->solve;
945 if (solved()) {
946 doUpdate(0, false, SIG_DFL);
947 solve_->prepareEnum(ctx, en.numModels, en.optMode, enumMode, en.proMode);
948 ctx.endInit();
949 }
950 if (prepared()) { return; }
951 SharedMinimizeData* m = 0;
952 ProgramBuilder* prg = program();
953 if (prg && prg->endProgram()) {
954 assume_.clear();
955 prg->getAssumptions(assume_);
956 prg->getWeakBounds(en.optBound);
957 }
958 stats_->start(uint32(config_->context().stats));
959 if (ctx.ok() && en.optMode != MinimizeMode_t::ignore && (m = ctx.minimize()) != 0) {
960 if (!m->setMode(en.optMode, en.optBound)) {
961 assume_.push_back(lit_false());
962 }
963 if (en.optMode == MinimizeMode_t::enumerate && en.optBound.empty()) {
964 ctx.warn("opt-mode=enum: No bound given, optimize statement ignored.");
965 }
966 }
967 POTASSCO_REQUIRE(!ctx.ok() || !ctx.frozen());
968 solve_->prepareEnum(ctx, en.numModels, en.optMode, enumMode, en.proMode);
969 if (!accu_.get()) { builder_ = 0; }
970 else if (isAsp()) { static_cast<Asp::LogicProgram*>(builder_.get())->dispose(false); }
971 if (!builder_.get() && !ctx.heuristic.empty()) {
972 bool keepDom = false;
973 for (uint32 i = 0; i != config_->solve.numSolver() && !keepDom; ++i) {
974 keepDom = config_->solver(i).heuId == Heuristic_t::Domain;
975 }
976 if (!keepDom) { ctx.heuristic.reset(); }
977 }
978 if (ctx.ok()) { ctx.endInit(); }
979 }
980
solve(SolveMode_t p,const LitVec & a,EventHandler * eh)981 ClaspFacade::SolveHandle ClaspFacade::solve(SolveMode_t p, const LitVec& a, EventHandler* eh) {
982 prepare();
983 solve_->active = SolveStrategy::create(p, *this, *solve_->algo.get());
984 solve_->active->start(eh, a);
985 return SolveHandle(solve_->active);
986 }
solve(const LitVec & a,EventHandler * handler)987 ClaspFacade::Result ClaspFacade::solve(const LitVec& a, EventHandler* handler) {
988 return solve(SolveMode_t::Default, a, handler).get();
989 }
990
update(bool updateConfig,void (* sigAct)(int))991 ProgramBuilder& ClaspFacade::update(bool updateConfig, void (*sigAct)(int)) {
992 POTASSCO_REQUIRE(config_ && program() && !solving());
993 doUpdate(program(), updateConfig, sigAct);
994 return *program();
995 }
update(bool updateConfig)996 ProgramBuilder& ClaspFacade::update(bool updateConfig) {
997 return update(updateConfig, SIG_DFL);
998 }
999
doUpdate(ProgramBuilder * p,bool updateConfig,void (* sigAct)(int))1000 void ClaspFacade::doUpdate(ProgramBuilder* p, bool updateConfig, void(*sigAct)(int)) {
1001 if (updateConfig) {
1002 init(*config_, false);
1003 }
1004 if (solved()) {
1005 startStep(step() + 1);
1006 }
1007 if (p && p->frozen()) {
1008 p->updateProgram();
1009 }
1010 if (ctx.frozen()) {
1011 ctx.unfreeze();
1012 }
1013 solve_->reset();
1014 config_->unfreeze(ctx);
1015 int sig = sigAct == SIG_DFL ? 0 : solve_->qSig.exchange(0);
1016 if (sig && sigAct != SIG_IGN) { sigAct(sig); }
1017 }
1018
onModel(const Solver & s,const Model & m)1019 bool ClaspFacade::onModel(const Solver& s, const Model& m) {
1020 step_.unsatTime = RealTime::getTime();
1021 if (++step_.numEnum == 1) { step_.satTime = diffTime(step_.unsatTime, step_.solveTime); }
1022 if (m.opt) { ++step_.numOptimal; }
1023 return solve_->onModel(s, m);
1024 }
enumerator() const1025 Enumerator* ClaspFacade::enumerator() const { return solve_.get() ? solve_->enumerator() : 0; }
getStats() const1026 Potassco::AbstractStatistics* ClaspFacade::getStats() const {
1027 POTASSCO_REQUIRE(stats_.get() && !solving(), "statistics not (yet) available");
1028 return stats_->getClingo();
1029 }
1030 /////////////////////////////////////////////////////////////////////////////////////////
1031 // ClaspFacade::Summary
1032 /////////////////////////////////////////////////////////////////////////////////////////
init(ClaspFacade & f)1033 void ClaspFacade::Summary::init(ClaspFacade& f) { std::memset(this, 0, sizeof(Summary)); facade = &f;}
model() const1034 const Model* ClaspFacade::Summary::model() const { return facade->solve_.get() ? facade->solve_->lastModel() : 0; }
costs() const1035 const SumVec* ClaspFacade::Summary::costs()const { return model() ? model()->costs : 0; }
optimal() const1036 uint64 ClaspFacade::Summary::optimal() const { return facade->step_.numOptimal; }
optimize() const1037 bool ClaspFacade::Summary::optimize() const {
1038 if (const Enumerator* e = facade->enumerator()){
1039 return e->optimize() || e->lastModel().opt;
1040 }
1041 return false;
1042 }
lpStep() const1043 const Asp::LpStats* ClaspFacade::Summary::lpStep() const {
1044 return facade->isAsp() ? &static_cast<const Asp::LogicProgram*>(facade->program())->stats : 0;
1045 }
lpStats() const1046 const Asp::LpStats* ClaspFacade::Summary::lpStats() const {
1047 return facade->stats_.get() ? facade->stats_->lp_.get() : lpStep();
1048 }
consequences() const1049 const char* ClaspFacade::Summary::consequences() const {
1050 const Model* m = model();
1051 return m && m->consequences() ? modelType(*m) : 0;
1052 }
1053
hasLower() const1054 bool ClaspFacade::Summary::hasLower() const {
1055 const SharedMinimizeData* m = optimize() ? facade->enumerator()->minimizer() : 0;
1056 return m && m->lower(0) != 0;
1057 }
lower() const1058 SumVec ClaspFacade::Summary::lower() const {
1059 if (hasLower()) {
1060 const SharedMinimizeData* m = facade->enumerator()->minimizer();
1061 SumVec ret(m->numRules());
1062 for (uint32 i = 0; i != m->numRules(); ++i) {
1063 ret[i] = m->lower(i) + m->adjust(i);
1064 }
1065 return ret;
1066 }
1067 return SumVec();
1068 }
accept(StatsVisitor & out) const1069 void ClaspFacade::Summary::accept(StatsVisitor& out) const {
1070 if (facade->solved()) { facade->stats_->accept(out, this == facade->accu_.get()); }
1071 }
1072
1073 }
1074
1075