dlvhex
2.5.0
|
00001 /* dlvhex -- Answer-Set Programming with external interfaces. 00002 * Copyright (C) 2005-2007 Roman Schindlauer 00003 * Copyright (C) 2006-2015 Thomas Krennwallner 00004 * Copyright (C) 2009-2016 Peter Schüller 00005 * Copyright (C) 2011-2016 Christoph Redl 00006 * Copyright (C) 2015-2016 Tobias Kaminski 00007 * Copyright (C) 2015-2016 Antonius Weinzierl 00008 * 00009 * This file is part of dlvhex. 00010 * 00011 * dlvhex is free software; you can redistribute it and/or modify it 00012 * under the terms of the GNU Lesser General Public License as 00013 * published by the Free Software Foundation; either version 2.1 of 00014 * the License, or (at your option) any later version. 00015 * 00016 * dlvhex is distributed in the hope that it will be useful, but 00017 * WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00019 * Lesser General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU Lesser General Public 00022 * License along with dlvhex; if not, write to the Free Software 00023 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 00024 * 02110-1301 USA. 00025 */ 00026 00035 #ifdef HAVE_CONFIG_H 00036 #include "config.h" 00037 #endif 00038 00039 #ifdef HAVE_LIBCLASP 00040 00041 #include "dlvhex2/ClaspSolver.h" 00042 00043 #include <iostream> 00044 #include <sstream> 00045 #include "dlvhex2/Logger.h" 00046 #include "dlvhex2/GenuineSolver.h" 00047 #include "dlvhex2/Printer.h" 00048 #include "dlvhex2/Printhelpers.h" 00049 #include "dlvhex2/Set.h" 00050 #include "dlvhex2/UnfoundedSetChecker.h" 00051 #include "dlvhex2/AnnotatedGroundProgram.h" 00052 #include "dlvhex2/Benchmarking.h" 00053 00054 #include <boost/foreach.hpp> 00055 #include <boost/graph/strong_components.hpp> 00056 #include <boost/interprocess/sync/scoped_lock.hpp> 00057 #include <boost/tokenizer.hpp> 00058 00059 #include "clasp/solver.h" 00060 #include "clasp/clause.h" 00061 #include "clasp/literal.h" 00062 #include "program_opts/program_options.h" 00063 #include "program_opts/application.h" 00064 00065 // activate this for detailed benchmarking in this file 00066 #undef DLVHEX_CLASPSOLVER_PROGRAMINIT_BENCHMARKING 00067 00068 // @clasp examples: Run the following command to use the Makefile in clasp/libclasp/examples: 00069 // export CXXFLAGS="-DWITH_THREADS=0 -I $PWD/../ -I $PWD/../../libprogram_opts/" 00070 00071 DLVHEX_NAMESPACE_BEGIN 00072 00073 // ============================== ExternalPropagator ============================== 00074 00075 ClaspSolver::ExternalPropagator::ExternalPropagator(ClaspSolver& cs) : cs(cs) 00076 { 00077 00078 cs.claspctx.master()->addPost(this); 00079 startAssignmentExtraction(); 00080 00081 // initialize propagation deferring 00082 lastPropagation = boost::posix_time::ptime(boost::posix_time::microsec_clock::local_time()); 00083 int deferMS = cs.ctx.config.getOption("ClaspDeferMaxTMilliseconds"); 00084 skipMaxDuration = boost::posix_time::microseconds(deferMS * 1000); 00085 00086 skipAmount = cs.ctx.config.getOption("ClaspDeferNPropagations"); 00087 skipCounter = 0; 00088 } 00089 00090 00091 ClaspSolver::ExternalPropagator::~ExternalPropagator() 00092 { 00093 stopAssignmentExtraction(); 00094 cs.claspctx.master()->removePost(this); 00095 } 00096 00097 00098 void ClaspSolver::ExternalPropagator::startAssignmentExtraction() 00099 { 00100 00101 DBGLOG(DBG, "Initializing assignment extraction"); 00102 currentIntr = InterpretationPtr(new Interpretation(cs.reg)); 00103 currentAssigned = InterpretationPtr(new Interpretation(cs.reg)); 00104 currentChanged = InterpretationPtr(new Interpretation(cs.reg)); 00105 00106 // we need to extract the full assignment (only this time), to make sure that we did not miss any updates before initialization of this extractor 00107 DBGLOG(DBG, "Extracting full interpretation from clasp"); 00108 cs.extractClaspInterpretation(*cs.claspctx.master(), currentIntr, currentAssigned, currentChanged); 00109 00110 // add watches for all literals and decision levels 00111 for (Clasp::SymbolTable::const_iterator it = cs.claspctx.master()->symbolTable().begin(); it != cs.claspctx.master()->symbolTable().end(); ++it) { 00112 // skip eliminated variables 00113 if (cs.claspctx.eliminated(it->second.lit.var())) continue; 00114 00115 uint32_t level = cs.claspctx.master()->level(it->second.lit.var()); 00116 if (cs.claspToHex.size() > it->second.lit.index()) { 00117 BOOST_FOREACH (IDAddress adr, *cs.convertClaspSolverLitToHex(it->second.lit.index())) { 00118 // add the variable to the undo watch for the decision level on which it was assigned 00119 while (assignmentsOnDecisionLevel.size() < level + 1) { 00120 assignmentsOnDecisionLevel.push_back(std::vector<IDAddress>()); 00121 DBGLOG(DBG, "Adding undo watch to level " << level); 00122 if (level > 0) cs.claspctx.master()->addUndoWatch(level, this); 00123 } 00124 } 00125 } 00126 00127 DBGLOG(DBG, "Adding watch for literal C:" << it->second.lit.index() << "/" << (it->second.lit.sign() ? "!" : "") << it->second.lit.var() << " and its negation"); 00128 cs.claspctx.master()->addWatch(it->second.lit, this); 00129 cs.claspctx.master()->addWatch(Clasp::Literal(it->second.lit.var(), !it->second.lit.sign()), this); 00130 } 00131 } 00132 00133 00134 void ClaspSolver::ExternalPropagator::stopAssignmentExtraction() 00135 { 00136 00137 // remove watches for all literals 00138 for (Clasp::SymbolTable::const_iterator it = cs.claspctx.master()->symbolTable().begin(); it != cs.claspctx.master()->symbolTable().end(); ++it) { 00139 // skip eliminated variables 00140 if (cs.claspctx.eliminated(it->second.lit.var())) continue; 00141 00142 DBGLOG(DBG, "Removing watch for literal C:" << it->second.lit.index() << "/" << (it->second.lit.sign() ? "!" : "") << it->second.lit.var() << " and its negation"); 00143 cs.claspctx.master()->removeWatch(it->second.lit, this); 00144 cs.claspctx.master()->removeWatch(Clasp::Literal(it->second.lit.var(), !it->second.lit.sign()), this); 00145 } 00146 00147 // remove watches for all decision levels 00148 for (uint32_t i = 1; i < assignmentsOnDecisionLevel.size(); i++) { 00149 //if (cs.claspctx.master()->validLevel(i)){ 00150 DBGLOG(DBG, "Removing watch for decision level " << i); 00151 cs.claspctx.master()->removeUndoWatch(i, this); 00152 //} 00153 } 00154 00155 currentIntr.reset(); 00156 currentAssigned.reset(); 00157 currentChanged.reset(); 00158 } 00159 00160 00161 void ClaspSolver::ExternalPropagator::callHexPropagators(Clasp::Solver& s) 00162 { 00163 00164 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid, "ClaspSlv::ExtProp:callHEXProps"); 00165 00166 DBGLOG(DBG, "ExternalPropagator: Calling HEX-Propagator"); 00167 00168 #ifndef NDEBUG 00169 // extract model and compare with the incrementally extracted one 00170 InterpretationPtr fullyExtractedCurrentIntr = InterpretationPtr(new Interpretation(cs.reg)); 00171 InterpretationPtr fullyExtractedCurrentAssigned = InterpretationPtr(new Interpretation(cs.reg)); 00172 cs.extractClaspInterpretation(s, fullyExtractedCurrentIntr, fullyExtractedCurrentAssigned, InterpretationPtr()); 00173 00174 std::stringstream ss; 00175 ss << "Partial assignment: " << *fullyExtractedCurrentIntr << " (assigned: " << *fullyExtractedCurrentAssigned << ")" << std::endl; 00176 ss << "Incrementally extracted partial assignment: " << *currentIntr << " (assigned: " << *currentAssigned << ")" << std::endl; 00177 ss << "Changed atoms: " << *currentChanged; 00178 DBGLOG(DBG, ss.str()); 00179 assert (fullyExtractedCurrentIntr->getStorage() == currentIntr->getStorage() && fullyExtractedCurrentAssigned->getStorage() == currentAssigned->getStorage()); 00180 00181 int propNr = 0; 00182 #endif 00183 00184 // call HEX propagators 00185 DBGLOG(DBG, "Need to call " << cs.propagators.size() << " propagators"); 00186 BOOST_FOREACH (PropagatorCallback* propagator, cs.propagators) { 00187 DBGLOG(DBG, "ExternalPropagator: Calling HEX-Propagator #" << (++propNr)); 00188 propagator->propagate(currentIntr, currentAssigned, currentChanged); 00189 } 00190 currentChanged->clear(); 00191 } 00192 00193 00194 bool ClaspSolver::ExternalPropagator::addNewNogoodsToClasp(Clasp::Solver& s) 00195 { 00196 00197 assert (!s.hasConflict() && "tried to add new nogoods while solver is in conflict"); 00198 00199 // add new clauses to clasp 00200 DBGLOG(DBG, "ExternalPropagator: Adding new clauses to clasp (" << cs.nogoods.size() << " were prepared)"); 00201 bool inconsistent = false; 00202 Clasp::ClauseCreator cc(cs.claspctx.master()); 00203 std::list<Nogood>::iterator ngIt = cs.nogoods.begin(); 00204 while (ngIt != cs.nogoods.end()) { 00205 const Nogood& ng = *ngIt; 00206 00207 TransformNogoodToClaspResult ngClasp = cs.nogoodToClaspClause(ng); 00208 if (!ngClasp.tautological && !ngClasp.outOfDomain) { 00209 DBGLOG(DBG, "Adding learned nogood " << ng.getStringRepresentation(cs.reg) << " to clasp"); 00210 cc.start(Clasp::Constraint_t::learnt_other); 00211 BOOST_FOREACH (Clasp::Literal lit, ngClasp.clause) { 00212 cc.add(lit); 00213 } 00214 00215 Clasp::ClauseInfo ci(Clasp::Constraint_t::learnt_other); 00216 assert (!s.hasConflict() && (s.decisionLevel() == 0 || ci.learnt())); 00217 Clasp::ClauseCreator::Result res = cc.create(s, cc.lits(), 0, ci); 00218 DBGLOG(DBG, "Assignment is " << (res.ok() ? "not " : "") << "conflicting, new clause is " << (res.unit() ? "" : "not ") << "unit"); 00219 00220 if (!res.ok()) { 00221 inconsistent = true; 00222 break; 00223 } 00224 } 00225 ngIt++; 00226 } 00227 00228 // remove all processed nogoods 00229 cs.nogoods.erase(cs.nogoods.begin(), ngIt); 00230 assert(!inconsistent || s.hasConflict()); 00231 return inconsistent; 00232 } 00233 00234 00235 bool ClaspSolver::ExternalPropagator::propagateFixpoint(Clasp::Solver& s, Clasp::PostPropagator* ctx) 00236 { 00237 00238 DBGLOG(DBG, "ExternalPropagator::propagateFixpoint"); 00239 00240 // check if we shall propagate 00241 bool hexPropagate = false; 00242 boost::posix_time::ptime now(boost::posix_time::microsec_clock::local_time()); 00243 if(now - lastPropagation > skipMaxDuration) { 00244 DBGLOG(DBG,"we shall propagate to HEX because skipMaxDuration=" << skipMaxDuration << 00245 " < time of last propgation, now=" << now << ", lastPropagation=" << lastPropagation); 00246 lastPropagation = now; 00247 skipCounter = 0; 00248 hexPropagate = true; 00249 } 00250 else { 00251 if(skipCounter >= skipAmount) { 00252 DBGLOG(DBG,"we shall propagate to HEX because skipCounter=" << skipCounter << 00253 " >= skipAmount=" << skipAmount); 00254 lastPropagation = now; 00255 skipCounter = 0; 00256 hexPropagate = true; 00257 } else { 00258 skipCounter++; 00259 } 00260 } 00261 DBGLOG(DBG, "Will " << (hexPropagate ? "" : "not ") << "propagate to HEX"); 00262 00263 for (;;) { 00264 if (hexPropagate) { 00265 callHexPropagators(s); 00266 } 00267 if (addNewNogoodsToClasp(s)) { 00268 DBGLOG(DBG, "Propagation led to conflict"); 00269 assert(s.queueSize() == 0 || s.hasConflict()); 00270 return false; 00271 } 00272 if (s.queueSize() == 0) { 00273 DBGLOG(DBG, "Nothing more to propagate"); 00274 assert(s.queueSize() == 0 || s.hasConflict()); 00275 return true; 00276 } 00277 if (!s.propagateUntil(this)) { 00278 DBGLOG(DBG, "Propagated something, rescheduling previous propagators"); 00279 assert(s.queueSize() == 0 || s.hasConflict()); 00280 return false; 00281 } 00282 } 00283 } 00284 00285 00286 bool ClaspSolver::ExternalPropagator::isModel(Clasp::Solver& s) 00287 { 00288 00289 DBGLOG(DBG, "ExternalPropagator::isModel"); 00290 00291 // here we must call the HEX propagators to make sure that the verification status of external atoms is correct 00292 // after this method returns 00293 DBGLOG(DBG, "Must propagate to HEX"); 00294 callHexPropagators(s); 00295 if (addNewNogoodsToClasp(s)) return false; 00296 return s.numFreeVars() == 0 && !s.hasConflict(); 00297 } 00298 00299 00300 uint32_t ClaspSolver::ExternalPropagator::priority() const 00301 { 00302 return Clasp::PostPropagator::priority_class_general; 00303 } 00304 00305 00306 Clasp::Constraint::PropResult ClaspSolver::ExternalPropagator::propagate(Clasp::Solver& s, Clasp::Literal p, uint32& data) 00307 { 00308 00309 DBGLOG(DBG, "ExternalPropagator::propagate"); 00310 Clasp::Literal pneg(p.var(), !p.sign()); 00311 00312 assert(s.isTrue(p) && s.isFalse(pneg)); 00313 00314 uint32_t level = s.level(p.var()); 00315 00316 DBGLOG(DBG, "Clasp notified about literal C:" << p.index() << "/" << (p.sign() ? "!" : "") << p.var() << " becoming true on dl " << level); 00317 if (cs.claspToHex.size() > p.index()) { 00318 BOOST_FOREACH (IDAddress adr, *cs.convertClaspSolverLitToHex(p.index())) { 00319 DBGLOG(DBG, "Assigning H:" << adr << " to true"); 00320 currentIntr->setFact(adr); 00321 currentAssigned->setFact(adr); 00322 currentChanged->setFact(adr); 00323 00324 // add the variable t o the undo watch for the decision level on which it was assigned 00325 while (assignmentsOnDecisionLevel.size() < level + 1) { 00326 if(assignmentsOnDecisionLevel.size() > 0) { 00327 DBGLOG(DBG, "Adding undo watch to level " << assignmentsOnDecisionLevel.size()); 00328 cs.claspctx.master()->addUndoWatch(assignmentsOnDecisionLevel.size(), this); 00329 } 00330 assignmentsOnDecisionLevel.push_back(std::vector<IDAddress>()); 00331 } 00332 assignmentsOnDecisionLevel[level].push_back(adr); 00333 } 00334 } 00335 00336 DBGLOG(DBG, "This implies that literal C:" << pneg.index() << "/" << (pneg.sign() ? "!" : "") << p.var() << " becomes false on dl " << level); 00337 if (cs.claspToHex.size() > pneg.index()) { 00338 BOOST_FOREACH (IDAddress adr, *cs.convertClaspSolverLitToHex(pneg.index())) { 00339 DBGLOG(DBG, "Assigning H:" << adr << " to false"); 00340 currentIntr->clearFact(adr); 00341 currentAssigned->setFact(adr); 00342 currentChanged->setFact(adr); 00343 00344 // add the variable to the undo watch for the decision level on which it was assigned 00345 while (assignmentsOnDecisionLevel.size() < level + 1) { 00346 if(assignmentsOnDecisionLevel.size() > 0) cs.claspctx.master()->addUndoWatch(assignmentsOnDecisionLevel.size(), this); 00347 assignmentsOnDecisionLevel.push_back(std::vector<IDAddress>()); 00348 } 00349 assignmentsOnDecisionLevel[level].push_back(adr); 00350 } 00351 } 00352 DBGLOG(DBG, "ExternalPropagator::propagate finished"); 00353 return PropResult(); 00354 } 00355 00356 00357 void ClaspSolver::ExternalPropagator::undoLevel(Clasp::Solver& s) 00358 { 00359 00360 DBGLOG(DBG, "Backtracking to decision level " << s.decisionLevel()); 00361 for (uint32_t i = s.decisionLevel(); i < assignmentsOnDecisionLevel.size(); i++) { 00362 DBGLOG(DBG, "Undoing decision level " << i); 00363 BOOST_FOREACH (IDAddress adr, assignmentsOnDecisionLevel[i]) { 00364 DBGLOG(DBG, "Unassigning H:" << adr); 00365 currentIntr->clearFact(adr); 00366 currentAssigned->clearFact(adr); 00367 currentChanged->setFact(adr); 00368 } 00369 } 00370 assignmentsOnDecisionLevel.erase(assignmentsOnDecisionLevel.begin() + s.decisionLevel(), assignmentsOnDecisionLevel.end()); 00371 } 00372 00373 00374 // ============================== ClaspSolver ============================== 00375 00376 std::string ClaspSolver::idAddressToString(IDAddress adr) 00377 { 00378 std::stringstream ss; 00379 ss << adr; 00380 return ss.str(); 00381 } 00382 00383 00384 IDAddress ClaspSolver::stringToIDAddress(std::string str) 00385 { 00386 #ifndef NDEBUG 00387 if (str.find(":") != std::string::npos) { 00388 str = str.substr(0, str.find(":")); 00389 } 00390 #endif 00391 return atoi(str.c_str()); 00392 } 00393 00394 00395 void ClaspSolver::extractClaspInterpretation(Clasp::Solver& solver, InterpretationPtr extractCurrentIntr, InterpretationPtr extractCurrentAssigned, InterpretationPtr extractCurrentChanged) 00396 { 00397 00398 DBGLOG(DBG, "Extracting clasp interpretation"); 00399 if (!!extractCurrentIntr) extractCurrentIntr->clear(); 00400 if (!!extractCurrentAssigned) extractCurrentAssigned->clear(); 00401 for (Clasp::SymbolTable::const_iterator it = solver.symbolTable().begin(); it != solver.symbolTable().end(); ++it) { 00402 // skip eliminated variables 00403 if (claspctx.eliminated(it->second.lit.var())) continue; 00404 00405 if (solver.isTrue(it->second.lit) && !it->second.name.empty()) { 00406 DBGLOG(DBG, "Literal C:" << it->second.lit.index() << "/" << (it->second.lit.sign() ? "!" : "") << it->second.lit.var() << "@" << 00407 solver.level(it->second.lit.var()) << (claspctx.eliminated(it->second.lit.var()) ? "(elim)" : "") << ",H:" << it->second.name.c_str() << " is true"); 00408 BOOST_FOREACH (IDAddress adr, *convertClaspSolverLitToHex(it->second.lit.index())) { 00409 if (!!extractCurrentIntr) extractCurrentIntr->setFact(adr); 00410 if (!!extractCurrentAssigned) extractCurrentAssigned->setFact(adr); 00411 if (!!extractCurrentChanged) extractCurrentChanged->setFact(adr); 00412 } 00413 } 00414 if (solver.isFalse(it->second.lit) && !it->second.name.empty()) { 00415 DBGLOG(DBG, "Literal C:" << it->second.lit.index() << "/" << (it->second.lit.sign() ? "!" : "") << it->second.lit.var() << "@" << 00416 solver.level(it->second.lit.var()) << (claspctx.eliminated(it->second.lit.var()) ? "(elim)" : "") << ",H:" << it->second.name.c_str() << " is false"); 00417 BOOST_FOREACH (IDAddress adr, *convertClaspSolverLitToHex(it->second.lit.index())) { 00418 if (!!extractCurrentAssigned) extractCurrentAssigned->setFact(adr); 00419 if (!!extractCurrentChanged) extractCurrentChanged->setFact(adr); 00420 } 00421 } 00422 } 00423 } 00424 00425 00426 // freezes all variables in "frozen"; if the pointer is 0, then all variables are frozen 00427 void ClaspSolver::freezeVariables(InterpretationConstPtr frozen, bool freezeByDefault) 00428 { 00429 00430 if (!!frozen) { 00431 DBGLOG(DBG, "Setting selected variables to frozen: " << *frozen); 00432 00433 #ifndef NDEBUG 00434 int cntFrozen = 0; 00435 std::set<int> alreadyFrozen; 00436 #endif 00437 bm::bvector<>::enumerator en = frozen->getStorage().first(); 00438 bm::bvector<>::enumerator en_end = frozen->getStorage().end(); 00439 while (en < en_end) { 00440 convertHexToClaspProgramLit(*en); // all frozen literals are always part of the instance to make sure that they are contained in the answer sets 00441 if (isMappedToClaspLiteral(*en)) { 00442 #ifndef NDEBUG 00443 if (alreadyFrozen.count(hexToClaspSolver[*en].var()) == 0) { 00444 cntFrozen++; 00445 alreadyFrozen.insert(hexToClaspSolver[*en].var()); 00446 } 00447 #endif 00448 switch (problemType) { 00449 case ASP: 00450 // Note: (1) asp.free() does more than (2) claspctx.setFrozen(). 00451 // (2) prevents the internal solver variable from being eliminated due to optimization 00452 // (1) does in addition prevent Clark's completion an loop clauses for these variables from being added (now), which 00453 // allows for defining them in later incremental steps 00454 asp.freeze(convertHexToClaspProgramLit(*en).var(), Clasp::value_false); 00455 break; 00456 case SAT: 00457 claspctx.setFrozen(convertHexToClaspSolverLit(*en).var(), true); 00458 break; 00459 default: 00460 assert(false && "unknown problem type"); 00461 } 00462 } 00463 en++; 00464 } 00465 #ifndef NDEBUG 00466 DBGLOG(DBG, "Setting " << cntFrozen << " out of " << claspctx.numVars() << " variables to frozen"); 00467 #endif 00468 } 00469 else { 00470 if (freezeByDefault) { 00471 DBGLOG(DBG, "Setting all " << claspctx.numVars() << " variables to frozen"); 00472 for (uint32_t i = 1; i <= claspctx.numVars(); i++) { 00473 00474 switch (problemType) { 00475 case ASP: 00476 asp.freeze(i, Clasp::value_false); 00477 break; 00478 case SAT: 00479 claspctx.setFrozen(i, true); 00480 break; 00481 default: 00482 assert(false && "unknown problem type"); 00483 } 00484 } 00485 } 00486 } 00487 } 00488 00489 00490 void ClaspSolver::sendWeightRuleToClasp(Clasp::Asp::LogicProgram& asp, ID ruleId) 00491 { 00492 #ifdef DLVHEX_CLASPSOLVER_PROGRAMINIT_BENCHMARKING 00493 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid, "ClaspSlv::sendWeightRuleTC"); 00494 #endif 00495 00496 DBGLOG(DBG, "Sending weight rule to clasp: " << printToString<RawPrinter>(ruleId, reg)); 00497 const Rule& rule = reg->rules.getByID(ruleId); 00498 asp.startRule(Clasp::Asp::WEIGHTRULE, rule.bound.address); 00499 assert(rule.head.size() != 0); 00500 BOOST_FOREACH (ID h, rule.head) { 00501 // add literal to head 00502 DBGLOG(DBG, "Adding to head: " << convertHexToClaspProgramLit(h.address).var()); 00503 asp.addHead(convertHexToClaspProgramLit(h.address).var()); 00504 } 00505 for (uint32_t i = 0; i < rule.body.size(); ++i) { 00506 // add literal to body 00507 DBGLOG(DBG, "Adding to body: " << (!(convertHexToClaspProgramLit(rule.body[i].address).sign() ^ rule.body[i].isNaf()) ? "" : "!") << convertHexToClaspProgramLit(rule.body[i].address).var()); 00508 asp.addToBody(convertHexToClaspProgramLit(rule.body[i].address).var(), !(convertHexToClaspProgramLit(rule.body[i].address).sign() ^ rule.body[i].isNaf()), rule.bodyWeightVector[i].address); 00509 } 00510 asp.endRule(); 00511 } 00512 00513 00514 void ClaspSolver::sendOrdinaryRuleToClasp(Clasp::Asp::LogicProgram& asp, ID ruleId) 00515 { 00516 #ifdef DLVHEX_CLASPSOLVER_PROGRAMINIT_BENCHMARKING 00517 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid, "ClaspSlv::sendOrdinaryRuleTC"); 00518 #endif 00519 00520 DBGLOG(DBG, "Sending ordinary rule to clasp: " << printToString<RawPrinter>(ruleId, reg)); 00521 const Rule& rule = reg->rules.getByID(ruleId); 00522 asp.startRule(rule.head.size() > 1 ? Clasp::Asp::DISJUNCTIVERULE : Clasp::Asp::BASICRULE); 00523 if (rule.head.size() == 0) { 00524 asp.addHead(false_); 00525 } 00526 BOOST_FOREACH (ID h, rule.head) { 00527 // add literal to head 00528 DBGLOG(DBG, "Adding to head: " << convertHexToClaspProgramLit(h.address).var()); 00529 asp.addHead(convertHexToClaspProgramLit(h.address).var()); 00530 } 00531 BOOST_FOREACH (ID b, rule.body) { 00532 // add literal to body 00533 DBGLOG(DBG, "Adding to body: " << (!(convertHexToClaspProgramLit(b.address).sign() ^ b.isNaf()) ? "" : "!") << convertHexToClaspProgramLit(b.address).var()); 00534 asp.addToBody(convertHexToClaspProgramLit(b.address).var(), !(convertHexToClaspProgramLit(b.address).sign() ^ b.isNaf())); 00535 } 00536 asp.endRule(); 00537 } 00538 00539 00540 void ClaspSolver::sendRuleToClasp(Clasp::Asp::LogicProgram& asp, ID ruleId) 00541 { 00542 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid, "ClaspSlv::sendRuleTC"); 00543 const Rule& rule = reg->rules.getByID(ruleId); 00544 00545 if (ID(rule.kind, 0).isWeakConstraint()) throw GeneralError("clasp-based solver does not support weak constraints"); 00546 00547 DBGLOG(DBG, "sendRuleToClasp " << printToString<RawPrinter>(ruleId, reg)); 00548 00549 // distinct by the type of the rule 00550 if (ID(rule.kind, 0).isWeightRule()) { 00551 sendWeightRuleToClasp(asp, ruleId); 00552 } 00553 else { 00554 sendOrdinaryRuleToClasp(asp, ruleId); 00555 } 00556 } 00557 00558 00559 void ClaspSolver::sendProgramToClasp(const AnnotatedGroundProgram& p, InterpretationConstPtr frozen) 00560 { 00561 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid, "ClaspSlv::sendProgramTC"); 00562 00563 asp.start(claspctx, config.asp); 00564 asp.setNonHcfConfiguration(config.testerConfig()); 00565 00566 // The following two lines allow for defining the program incrementally 00567 // Note: If the program is to be defined incrementally, then updateProgram() must be called before each extension, even for the first one 00568 asp.updateProgram(); 00569 00570 false_ = nextVar++; 00571 asp.setCompute(false_, false); 00572 00573 // transfer edb 00574 DBGLOG(DBG, "Sending EDB to clasp: " << *p.getGroundProgram().edb); 00575 bm::bvector<>::enumerator en = p.getGroundProgram().edb->getStorage().first(); 00576 bm::bvector<>::enumerator en_end = p.getGroundProgram().edb->getStorage().end(); 00577 while (en < en_end) { 00578 // add fact 00579 asp.startRule(Clasp::Asp::BASICRULE).addHead(convertHexToClaspProgramLit(*en).var()).endRule(); 00580 en++; 00581 } 00582 00583 // transfer idb 00584 DBGLOG(DBG, "Sending IDB to clasp"); 00585 BOOST_FOREACH (ID ruleId, p.getGroundProgram().idb) { 00586 00587 /* 00588 //Incremental Solving: 00589 00590 inconsistent = !asp.endProgram(); 00591 00592 DBGLOG(DBG, "SAT instance has " << claspctx.numVars() << " variables"); 00593 DBGLOG(DBG, "Instance is now " << (inconsistent ? "" : "not ") << "inconsistent"); 00594 00595 if (inconsistent){ 00596 DBGLOG(DBG, "Program is inconsistent, aborting initialization"); 00597 inconsistent = true; 00598 return; 00599 } 00600 00601 DBGLOG(DBG, "Prepare new model enumerator"); 00602 modelEnumerator.reset(config.solve.createEnumerator(config.solve)); 00603 modelEnumerator->init(claspctx, 0, config.solve.numModels); 00604 00605 DBGLOG(DBG, "Finalizing reinitialization"); 00606 if (!claspctx.endInit()){ 00607 DBGLOG(DBG, "Program is inconsistent, aborting initialization"); 00608 inconsistent = true; 00609 return; 00610 } 00611 00612 DBGLOG(DBG, "Resetting solver object"); 00613 solve.reset(new Clasp::BasicSolve(*claspctx.master())); 00614 enumerationStarted = false; 00615 00616 asp.update(); 00617 */ 00618 00619 sendRuleToClasp(asp, ruleId); 00620 } 00621 00622 freezeVariables(frozen, false /* do not freeze variables by default */); 00623 00624 inconsistent = !asp.endProgram(); 00625 00626 DBGLOG(DBG, "ASP instance has " << claspctx.numVars() << " variables"); 00627 00628 DBGLOG(DBG, "Instance is " << (inconsistent ? "" : "not ") << "inconsistent"); 00629 00630 #ifndef NDEBUG 00631 std::stringstream ss; 00632 asp.write(ss); 00633 DBGLOG(DBG, "Program in LParse format: " << ss.str()); 00634 #endif 00635 } 00636 00637 00638 void ClaspSolver::createMinimizeConstraints(const AnnotatedGroundProgram& p) 00639 { 00640 00641 // just do something if we need to optimize something 00642 if( ctx.config.getOption("Optimization") == 0 ) { 00643 LOG(DBG, "Do not need minimize constraint"); 00644 return; 00645 } 00646 00647 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid, "ClaspSlv::createMinimizeConstraints"); 00648 00649 DBGLOG(DBG, "Preparing minimize constraints"); 00650 00651 // one minimize statement for each level 00652 std::vector<Clasp::WeightLitVec> minimizeStatements; 00653 #ifndef NDEBUG 00654 std::vector<std::vector<IDAddress> > minimizeStatementsHex; 00655 #endif 00656 00657 // construct the minimize statements for each level 00658 bm::bvector<>::enumerator en = p.getGroundProgram().edb->getStorage().first(); 00659 bm::bvector<>::enumerator en_end = p.getGroundProgram().edb->getStorage().end(); 00660 while (en < en_end) { 00661 const OrdinaryAtom& weightAtom = reg->ogatoms.getByAddress(*en); 00662 if (weightAtom.tuple[0].isAuxiliary() && reg->getTypeByAuxiliaryConstantSymbol(weightAtom.tuple[0]) == 'w') { 00663 int level = weightAtom.tuple[2].address; 00664 while (minimizeStatements.size() < level) minimizeStatements.push_back(Clasp::WeightLitVec()); 00665 minimizeStatements[level - 1].push_back(Clasp::WeightLiteral(convertHexToClaspSolverLit(*en), weightAtom.tuple[1].address)); 00666 DBGLOG(DBG, "EDB Clasp::WeightLiteral on level " << (level-1) << " for atom " << 00667 printToString<RawPrinter>(weightAtom.tuple[1], reg) << "(IDAddress=" << *en << ")"); 00668 #ifndef NDEBUG 00669 while (minimizeStatementsHex.size() < level) minimizeStatementsHex.push_back(std::vector<IDAddress>()); 00670 minimizeStatementsHex[level - 1].push_back(*en); 00671 #endif 00672 } 00673 en++; 00674 } 00675 BOOST_FOREACH (ID ruleID, p.getGroundProgram().idb) { 00676 const Rule& rule = reg->rules.getByID(ruleID); 00677 00678 // check if this is a weight rule 00679 if (rule.head.size() == 1) { 00680 const OrdinaryAtom& weightAtom = reg->ogatoms.getByID(rule.head[0]); 00681 if (weightAtom.tuple[0].isAuxiliary() && reg->getTypeByAuxiliaryConstantSymbol(weightAtom.tuple[0]) == 'w') { 00682 int level = weightAtom.tuple[2].address; 00683 while (minimizeStatements.size() < level) minimizeStatements.push_back(Clasp::WeightLitVec()); 00684 minimizeStatements[level - 1].push_back(Clasp::WeightLiteral(convertHexToClaspSolverLit(rule.head[0].address), weightAtom.tuple[1].address)); 00685 DBGLOG(DBG, "IDB Clasp::WeightLiteral on level " << (level-1) << " for atom " << 00686 printToString<RawPrinter>(weightAtom.tuple[1], reg) << "(IDAddress=" << *en << ")"); 00687 #ifndef NDEBUG 00688 while (minimizeStatementsHex.size() < level) minimizeStatementsHex.push_back(std::vector<IDAddress>()); 00689 minimizeStatementsHex[level - 1].push_back(rule.head[0].address); 00690 #endif 00691 } 00692 } 00693 } 00694 00695 // add the minimize statements to clasp 00696 for (int level = minimizeStatements.size() - 1; level >= 0; --level) { 00697 DBGLOG(DBG, "Minimize statement at level " << level << ": " << printvector(minimizeStatementsHex[level])); 00698 minb.addRule(minimizeStatements[level]); 00699 } 00700 ctx.currentOptimumRelevantLevels = minimizeStatements.size(); 00701 00702 00703 LOG(DBG, "Constructing minimize constraint"); 00704 sharedMinimizeData = minb.build(claspctx); 00705 minc = 0; 00706 if (!!sharedMinimizeData) { 00707 DBGLOG(DBG, "Setting minimize mode"); 00708 00709 // start with the current global optimum as upper bound if available 00710 if (ctx.currentOptimum.size() > 0){ 00711 int optlen = ctx.currentOptimum.size() - 1; 00712 LOG(DBG, "Transforming optimum " << printvector(ctx.currentOptimum) << " (length: " << optlen << ") to clasp-internal representation"); 00713 Clasp::wsum_t* newopt = new Clasp::wsum_t[optlen]; 00714 for (int l = 0; l < optlen; ++l) 00715 newopt[l] = ctx.currentOptimum[optlen - l]; 00716 00717 sharedMinimizeData->setMode(Clasp::MinimizeMode_t::enumerate, newopt, optlen); 00718 00719 LOG(DBG, "Attaching minimize constraint to clasp"); 00720 minc = sharedMinimizeData->attach(*claspctx.master(), Clasp::MinimizeMode_t::opt_bb); 00721 00722 bool intres = minc->integrate(*claspctx.master()); 00723 LOG(DBG, "Integrating constraint gave result " << intres); 00724 delete []newopt; 00725 }else{ 00726 00727 // setting the upper bound works by enabling the following comments: 00728 // 00729 // int len = 1; 00730 //Clasp::wsum_t* newopt = new Clasp::wsum_t[len]; 00731 //newopt[0] = 3; 00732 00733 sharedMinimizeData->setMode(Clasp::MinimizeMode_t::enumerate /*, newopt, len*/); 00734 00735 LOG(DBG, "Attaching minimize constraint to clasp"); 00736 minc = sharedMinimizeData->attach(*claspctx.master(), Clasp::MinimizeMode_t::opt_bb); 00737 00738 //bool intres = minc->integrate(*claspctx.master()); 00739 //LOG(DBG, "Integrating constraint gave result " << intres); 00740 //delete []newopt; 00741 00742 } 00743 00744 assert(!!minc); 00745 } 00746 } 00747 00748 00749 void ClaspSolver::sendNogoodSetToClasp(const NogoodSet& ns, InterpretationConstPtr frozen) 00750 { 00751 00752 #ifdef DLVHEX_CLASPSOLVER_PROGRAMINIT_BENCHMARKING 00753 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid, "ClaspSlv::sendNogoodSetTC"); 00754 #endif 00755 00756 DBGLOG(DBG, "Sending NogoodSet to clasp: " << ns); 00757 00758 sat.startProgram(claspctx); 00759 00760 prepareProblem(sat, ns); 00761 updateSymbolTable(); 00762 00763 for (int i = 0; i < ns.getNogoodCount(); i++) { 00764 const Nogood& ng = ns.getNogood(i); 00765 TransformNogoodToClaspResult ngClasp = nogoodToClaspClause(ng, true); 00766 assert (!ngClasp.outOfDomain && "literals were not properly mapped to clasp"); 00767 if (!ngClasp.tautological) { 00768 DBGLOG(DBG, "Adding nogood " << ng << " as clasp-clause"); 00769 00770 sat.addClause(ngClasp.clause); 00771 } 00772 else { 00773 DBGLOG(DBG, "Skipping tautological nogood"); 00774 } 00775 } 00776 00777 inconsistent = !sat.endProgram(); 00778 DBGLOG(DBG, "SAT instance has " << claspctx.numVars() << " variables"); 00779 00780 DBGLOG(DBG, "Instance is " << (inconsistent ? "" : "not ") << "inconsistent"); 00781 00782 freezeVariables(frozen, true /* freeze variables by default */); 00783 } 00784 00785 00786 void ClaspSolver::interpretClaspCommandline(Clasp::Problem_t::Type type) 00787 { 00788 00789 DBGLOG(DBG, "Interpreting clasp command-line"); 00790 00791 std::string claspconfigstr = ctx.config.getStringOption("ClaspConfiguration"); 00792 if( claspconfigstr == "none" ) claspconfigstr = ""; 00793 if( claspconfigstr == "frumpy" 00794 || claspconfigstr == "jumpy" 00795 || claspconfigstr == "handy" 00796 || claspconfigstr == "crafty" 00797 || claspconfigstr == "trendy") claspconfigstr = "--configuration=" + claspconfigstr; 00798 // otherwise let the config string itself be parsed by clasp 00799 00800 DBGLOG(DBG, "Found configuration: " << claspconfigstr); 00801 try 00802 { 00803 // options found in command-line 00804 allOpts = std::auto_ptr<ProgramOptions::OptionContext>(new ProgramOptions::OptionContext("<clasp_dlvhex>")); 00805 DBGLOG(DBG, "Configuring options"); 00806 config.reset(); 00807 config.addOptions(*allOpts); 00808 DBGLOG(DBG, "Parsing command-line"); 00809 parsedValues = std::auto_ptr<ProgramOptions::ParsedValues>(new ProgramOptions::ParsedValues(*allOpts)); 00810 *parsedValues = ProgramOptions::parseCommandString(claspconfigstr, *allOpts); 00811 DBGLOG(DBG, "Assigning specified values"); 00812 parsedOptions.assign(*parsedValues); 00813 DBGLOG(DBG, "Assigning defaults"); 00814 allOpts->assignDefaults(parsedOptions); 00815 00816 DBGLOG(DBG, "Applying options"); 00817 config.finalize(parsedOptions, type, true); 00818 config.solve.numModels = 0; 00819 claspctx.setConfiguration(&config, false); 00820 00821 DBGLOG(DBG, "Finished option parsing"); 00822 } 00823 catch(...) { 00824 DBGLOG(DBG, "Could not parse clasp options: " + claspconfigstr); 00825 throw; 00826 } 00827 } 00828 00829 00830 void ClaspSolver::shutdownClasp() 00831 { 00832 if (!!ep.get()) ep.reset(); 00833 if (minc) { minc->destroy(claspctx.master(), true); } 00834 if (sharedMinimizeData) { sharedMinimizeData->release(); } 00835 resetAndResizeClaspToHex(0); 00836 } 00837 00838 00839 ClaspSolver::TransformNogoodToClaspResult ClaspSolver::nogoodToClaspClause(const Nogood& ng, bool extendDomainIfNecessary) 00840 { 00841 00842 #ifndef NDEBUG 00843 DBGLOG(DBG, "Translating nogood " << ng.getStringRepresentation(reg) << " to clasp"); 00844 std::stringstream ss; 00845 ss << "{ "; 00846 bool first = true; 00847 #endif 00848 00849 // translate dlvhex::Nogood to clasp clause 00850 Set<uint32> pos; 00851 Set<uint32> neg; 00852 Clasp::LitVec clause; 00853 bool taut = false; 00854 BOOST_FOREACH (ID lit, ng) { 00855 00856 // only nogoods are relevant where all variables occur in this clasp instance 00857 if (!isMappedToClaspLiteral(lit.address) && !extendDomainIfNecessary) { 00858 DBGLOG(DBG, "some literal was not properly mapped to clasp"); 00859 return TransformNogoodToClaspResult(Clasp::LitVec(), false, true); 00860 } 00861 00862 // mclit = mapped clasp literal 00863 const Clasp::Literal mclit = convertHexToClaspSolverLit(lit.address, extendDomainIfNecessary); 00864 if (claspctx.eliminated(mclit.var())) { 00865 DBGLOG(DBG, "some literal was eliminated"); 00866 return TransformNogoodToClaspResult(clause, false, true); 00867 } 00868 00869 // avoid duplicate literals 00870 // if the literal was already added with the same sign, skip it 00871 // if it was added with different sign, cancel adding the clause 00872 if (!(mclit.sign() ^ lit.isNaf())) { 00873 if (pos.contains(mclit.var())) { 00874 continue; 00875 } 00876 else if (neg.contains(mclit.var())) { 00877 taut = true; 00878 } 00879 pos.insert(mclit.var()); 00880 } 00881 else { 00882 if (neg.contains(mclit.var())) { 00883 continue; 00884 } 00885 else if (pos.contains(mclit.var())) { 00886 taut = true; 00887 } 00888 neg.insert(mclit.var()); 00889 } 00890 00891 // 1. cs.hexToClaspSolver maps hex-atoms to clasp-literals 00892 // 2. the sign must be changed if the hex-atom was default-negated (xor ^) 00893 // 3. the overall sign must be changed (negation !) because we work with nogoods and clasp works with clauses 00894 Clasp::Literal clit = Clasp::Literal(mclit.var(), !(mclit.sign() ^ lit.isNaf())); 00895 clause.push_back(clit); 00896 #ifndef NDEBUG 00897 if (!first) ss << ", "; 00898 first = false; 00899 ss << (clit.sign() ? "!" : "") << clit.var(); 00900 #endif 00901 } 00902 00903 #ifndef NDEBUG 00904 ss << " } (" << (taut ? "" : "not ") << "tautological)"; 00905 DBGLOG(DBG, "Clasp clause is: " << ss.str()); 00906 #endif 00907 00908 return TransformNogoodToClaspResult(clause, taut, false); 00909 } 00910 00911 00912 void ClaspSolver::prepareProblem(Clasp::Asp::LogicProgram& asp, const OrdinaryASPProgram& p) 00913 { 00914 00915 assert(false && "Deprecated. Due to use of Clasp::LogicProgram for initialization, this method does not need to be called anymore"); 00916 00917 #ifdef DLVHEX_CLASPSOLVER_PROGRAMINIT_BENCHMARKING 00918 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid, "ClaspSlv::prepareProblem P pb"); 00919 #endif 00920 00921 DBGLOG(DBG, "Building atom index"); 00922 00923 // edb 00924 bm::bvector<>::enumerator en = p.edb->getStorage().first(); 00925 bm::bvector<>::enumerator en_end = p.edb->getStorage().end(); 00926 while (en < en_end) { 00927 if (!isMappedToClaspLiteral(*en)) { 00928 uint32_t c = *en + 2; 00929 DBGLOG(DBG, "Clasp index of atom H:" << *en << " is " << c); 00930 00931 // create positive literal -> false 00932 storeHexToClasp(*en, Clasp::Literal(c, false)); 00933 00934 std::string str = idAddressToString(*en); 00935 asp.setAtomName(c, str.c_str()); 00936 } 00937 en++; 00938 } 00939 00940 // idb 00941 BOOST_FOREACH (ID ruleId, p.idb) { 00942 const Rule& rule = reg->rules.getByID(ruleId); 00943 BOOST_FOREACH (ID h, rule.head) { 00944 if (!isMappedToClaspLiteral(h.address)) { 00945 uint32_t c = h.address + 2; 00946 DBGLOG(DBG, "Clasp index of atom H:" << h.address << " is C:" << c); 00947 00948 // create positive literal -> false 00949 storeHexToClasp(h.address, Clasp::Literal(c, false)); 00950 00951 std::string str = idAddressToString(h.address); 00952 asp.setAtomName(c, str.c_str()); 00953 } 00954 } 00955 BOOST_FOREACH (ID b, rule.body) { 00956 if (!isMappedToClaspLiteral(b.address)) { 00957 uint32_t c = b.address + 2; 00958 DBGLOG(DBG, "Clasp index of atom H:" << b.address << " is C:" << c); 00959 00960 // create positive literal -> false 00961 storeHexToClasp(b.address, Clasp::Literal(c, false)); 00962 00963 std::string str = idAddressToString(b.address); 00964 asp.setAtomName(c, str.c_str()); 00965 } 00966 } 00967 } 00968 } 00969 00970 00971 void ClaspSolver::prepareProblem(Clasp::SatBuilder& sat, const NogoodSet& ns) 00972 { 00973 #ifdef DLVHEX_CLASPSOLVER_PROGRAMINIT_BENCHMARKING 00974 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid, "ClaspSlv::prepareProblem ns"); 00975 #endif 00976 00977 DBGLOG(DBG, "Building atom index"); 00978 DBGLOG(DBG, "symbol table has " << claspctx.symbolTable().size() << " entries"); 00979 00980 bool inverselits = (ctx.config.getOption("ClaspInverseLiterals") != 0); 00981 00982 assert(hexToClaspSolver.empty()); 00983 hexToClaspSolver.reserve(reg->ogatoms.getSize()); 00984 00985 // build symbol table and hexToClaspSolver 00986 claspctx.symbolTable().startInit(Clasp::SymbolTable::map_indirect); 00987 unsigned largestIdx = 0; 00988 unsigned varCnt = 0; 00989 for (int i = 0; i < ns.getNogoodCount(); i++) { 00990 const Nogood& ng = ns.getNogood(i); 00991 BOOST_FOREACH (ID lit, ng) { 00992 Clasp::Literal clasplit = convertHexToClaspSolverLit(lit.address, true, inverselits); 00993 if (clasplit.index() > largestIdx) largestIdx = clasplit.index(); 00994 } 00995 } 00996 claspctx.symbolTable().endInit(); 00997 sat.prepareProblem(claspctx.numVars()); 00998 updateSymbolTable(); 00999 } 01000 01001 01002 void ClaspSolver::updateSymbolTable() 01003 { 01004 01005 #ifdef DLVHEX_CLASPSOLVER_PROGRAMINIT_BENCHMARKING 01006 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid, "ClaspSlv::updateSymbolTable"); 01007 #endif 01008 01009 hexToClaspSolver.clear(); 01010 hexToClaspSolver.reserve(reg->ogatoms.getSize()); 01011 01012 // go through clasp symbol table 01013 const Clasp::SymbolTable& symTab = claspctx.symbolTable(); 01014 01015 // each variable can be a positive or negative literal, literals are (var << 1 | sign) 01016 // build empty set of NULL-pointers to vectors 01017 // (literals which are internal variables and have no HEX equivalent do not show up in symbol table) 01018 #ifndef NDEBUG 01019 if (problemType == ASP) { 01020 DBGLOG(DBG, "ASP problem has " << claspctx.numVars() << " variables"); 01021 } 01022 else if (problemType == SAT) { 01023 DBGLOG(DBG, "SAT problem has " << claspctx.numVars() << " variables"); 01024 } 01025 #endif 01026 // the largest possible index is "claspctx.numVars() * 2 + 1", thus we allocate one element more 01027 resetAndResizeClaspToHex(claspctx.numVars() * 2 + 1 + 1); 01028 01029 LOG(DBG, "Symbol table of optimized program:"); 01030 for (Clasp::SymbolTable::const_iterator it = symTab.begin(); it != symTab.end(); ++it) { 01031 std::string ss(it->second.name.c_str()); 01032 IDAddress hexAdr = stringToIDAddress(it->second.name.c_str()); 01033 storeHexToClasp(hexAdr, it->second.lit); 01034 DBGLOG(DBG, "H:" << hexAdr << " (" << reg->ogatoms.getByAddress(hexAdr).text << ") <--> " 01035 "C:" << it->second.lit.index() << "/" << (it->second.lit.sign() ? "!" : "") << it->second.lit.var()); 01036 assert(it->second.lit.index() < claspToHex.size()); 01037 AddressVector* &c2h = claspToHex[it->second.lit.index()]; 01038 c2h->push_back(hexAdr); 01039 } 01040 01041 DBGLOG(DBG, "hexToClaspSolver.size()=" << hexToClaspSolver.size() << ", symTab.size()=" << symTab.size()); 01042 } 01043 01044 01045 void ClaspSolver::storeHexToClasp(IDAddress addr, Clasp::Literal lit, bool alsoStoreNonoptimized) 01046 { 01047 01048 if(addr >= hexToClaspSolver.size()) { 01049 hexToClaspSolver.resize(addr + 1, noLiteral); 01050 } 01051 hexToClaspSolver[addr] = lit; 01052 01053 if (alsoStoreNonoptimized) { 01054 if(addr >= hexToClaspProgram.size()) { 01055 hexToClaspProgram.resize(addr + 1, noLiteral); 01056 } 01057 hexToClaspProgram[addr] = lit; 01058 } 01059 } 01060 01061 01062 void ClaspSolver::resetAndResizeClaspToHex(unsigned size) 01063 { 01064 DBGLOG(DBG, "resetAndResizeClaspToHex: current size is " << claspToHex.size()); 01065 for(unsigned u = 0; u < claspToHex.size(); ++u) { 01066 if(claspToHex[u]) { 01067 delete claspToHex[u]; 01068 claspToHex[u] = NULL; 01069 } 01070 } 01071 DBGLOG(DBG, "resetAndResizeClaspToHex: resizing to " << size); 01072 claspToHex.resize(size, NULL); 01073 for(unsigned u = 0; u < claspToHex.size(); ++u) { 01074 claspToHex[u] = new AddressVector; 01075 } 01076 } 01077 01078 01079 Clasp::Literal ClaspSolver::convertHexToClaspSolverLit(IDAddress addr, bool registerVar, bool inverseLits) 01080 { 01081 01082 if (!isMappedToClaspLiteral(addr)) { 01083 uint32_t c = (registerVar ? claspctx.addVar(Clasp::Var_t::atom_var) : nextVar++); 01084 Clasp::Literal clasplit(c, inverseLits); 01085 storeHexToClasp(addr, clasplit, true); 01086 std::string str = idAddressToString(addr); 01087 #ifndef NDEBUG 01088 str = str + ":" + RawPrinter::toString(reg, reg->ogatoms.getIDByAddress(addr)); 01089 #endif 01090 claspctx.symbolTable().addUnique(c, str.c_str()).lit = clasplit; 01091 } 01092 assert(addr < hexToClaspSolver.size()); 01093 assert(hexToClaspSolver[addr] != noLiteral); 01094 return hexToClaspSolver[addr]; 01095 } 01096 01097 01098 Clasp::Literal ClaspSolver::convertHexToClaspProgramLit(IDAddress addr, bool registerVar, bool inverseLits) 01099 { 01100 if (!isMappedToClaspLiteral(addr)) { 01101 uint32_t c = (registerVar ? claspctx.addVar(Clasp::Var_t::atom_var) : nextVar++); 01102 Clasp::Literal clasplit(c, inverseLits); 01103 storeHexToClasp(addr, clasplit, true); 01104 std::string str = idAddressToString(addr); 01105 #ifndef NDEBUG 01106 str = str + ":" + RawPrinter::toString(reg, reg->ogatoms.getIDByAddress(addr)); 01107 #endif 01108 claspctx.symbolTable().addUnique(c, str.c_str()).lit = clasplit; 01109 } 01110 assert(addr < hexToClaspSolver.size()); 01111 assert(hexToClaspSolver[addr] != noLiteral); 01112 return hexToClaspProgram[addr]; 01113 } 01114 01115 01116 const ClaspSolver::AddressVector* ClaspSolver::convertClaspSolverLitToHex(int index) 01117 { 01118 return claspToHex[index]; 01119 } 01120 01121 01122 void ClaspSolver::outputProject(InterpretationPtr intr) 01123 { 01124 if( !!intr && !!projectionMask ) { 01125 DBGLOG(DBG, "Projecting " << *intr); 01126 intr->getStorage() -= projectionMask->getStorage(); 01127 DBGLOG(DBG, "Projected to " << *intr); 01128 } 01129 } 01130 01131 01132 ClaspSolver::ClaspSolver(ProgramCtx& ctx, const AnnotatedGroundProgram& p, InterpretationConstPtr frozen) 01133 : ctx(ctx), solve(0), ep(0), modelCount(0), nextVar(2), projectionMask(p.getGroundProgram().mask), noLiteral(Clasp::Literal::fromRep(~0x0)), minc(0), sharedMinimizeData(0) 01134 { 01135 reg = ctx.registry(); 01136 01137 DBGLOG(DBG, "Configure clasp in ASP mode"); 01138 problemType = ASP; 01139 config.reset(); 01140 interpretClaspCommandline(Clasp::Problem_t::ASP); 01141 nextSolveStep = Restart; 01142 01143 claspctx.requestStepVar(); 01144 sendProgramToClasp(p, frozen); 01145 01146 if (inconsistent) { 01147 DBGLOG(DBG, "Program is inconsistent, aborting initialization"); 01148 inconsistent = true; 01149 return; 01150 } 01151 01152 DBGLOG(DBG, "Prepare model enumerator"); 01153 modelEnumerator.reset(config.solve.createEnumerator(config.solve)); 01154 modelEnumerator->init(claspctx, 0, config.solve.numModels); 01155 01156 DBGLOG(DBG, "Finalizing initialization"); 01157 if (!claspctx.endInit()) { 01158 DBGLOG(DBG, "Program is inconsistent, aborting initialization"); 01159 inconsistent = true; 01160 return; 01161 } 01162 01163 updateSymbolTable(); 01164 01165 createMinimizeConstraints(p); 01166 01167 DBGLOG(DBG, "Prepare solver object"); 01168 solve.reset(new Clasp::BasicSolve(*claspctx.master())); 01169 enumerationStarted = false; 01170 01171 DBGLOG(DBG, "Adding post propagator"); 01172 ep.reset(new ExternalPropagator(*this)); 01173 } 01174 01175 01176 ClaspSolver::ClaspSolver(ProgramCtx& ctx, const NogoodSet& ns, InterpretationConstPtr frozen) 01177 : ctx(ctx), solve(0), ep(0), modelCount(0), nextVar(2), noLiteral(Clasp::Literal::fromRep(~0x0)), minc(0), sharedMinimizeData(0) 01178 { 01179 reg = ctx.registry(); 01180 01181 DBGLOG(DBG, "Configure clasp in SAT mode"); 01182 problemType = SAT; 01183 config.reset(); 01184 interpretClaspCommandline(Clasp::Problem_t::SAT); 01185 nextSolveStep = Restart; 01186 01187 claspctx.requestStepVar(); 01188 sendNogoodSetToClasp(ns, frozen); 01189 01190 if (inconsistent) { 01191 DBGLOG(DBG, "Program is inconsistent, aborting initialization"); 01192 inconsistent = true; 01193 return; 01194 } 01195 01196 DBGLOG(DBG, "Prepare model enumerator"); 01197 modelEnumerator.reset(config.solve.createEnumerator(config.solve)); 01198 modelEnumerator->init(claspctx, 0, config.solve.numModels); 01199 01200 DBGLOG(DBG, "Finalizing initialization"); 01201 if (!claspctx.endInit()) { 01202 DBGLOG(DBG, "SAT instance is unsatisfiable"); 01203 inconsistent = true; 01204 return; 01205 } 01206 01207 updateSymbolTable(); 01208 01209 #ifndef NDEBUG 01210 std::stringstream ss; 01211 InterpretationPtr vars = InterpretationPtr(new Interpretation(reg)); 01212 for (int ngi = 0; ngi < ns.getNogoodCount(); ++ngi) { 01213 const Nogood& ng = ns.getNogood(ngi); 01214 TransformNogoodToClaspResult ngClasp = nogoodToClaspClause(ng); 01215 bool first = true; 01216 ss << ":- "; 01217 for (uint32_t i = 0; i < ngClasp.clause.size(); ++i) { 01218 Clasp::Literal lit = ngClasp.clause[i]; 01219 if (!first) ss << ", "; 01220 first = false; 01221 ss << (lit.sign() ? "-" : "") << "a" << lit.var(); 01222 vars->setFact(lit.var()); 01223 } 01224 if (!first) ss << "." << std::endl; 01225 } 01226 bm::bvector<>::enumerator en = vars->getStorage().first(); 01227 bm::bvector<>::enumerator en_end = vars->getStorage().end(); 01228 while (en < en_end) { 01229 ss << "a" << *en << " v -a" << *en << "." << std::endl; 01230 en++; 01231 } 01232 01233 DBGLOG(DBG, "SAT instance in ASP format:" << std::endl << ss.str()); 01234 #endif 01235 01236 DBGLOG(DBG, "Prepare solver object"); 01237 solve.reset(new Clasp::BasicSolve(*claspctx.master())); 01238 enumerationStarted = false; 01239 01240 DBGLOG(DBG, "Adding post propagator"); 01241 ep.reset(new ExternalPropagator(*this)); 01242 } 01243 01244 01245 ClaspSolver::~ClaspSolver() 01246 { 01247 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid, "ClaspSlv::~ClaspSolver"); 01248 shutdownClasp(); 01249 } 01250 01251 01252 void ClaspSolver::addProgram(const AnnotatedGroundProgram& p, InterpretationConstPtr frozen) 01253 { 01254 01255 assert(problemType == ASP && "programs can only be added in ASP mode"); 01256 DBGLOG(DBG, "Adding program component incrementally"); 01257 nextSolveStep = Restart; 01258 01259 // remove post propagator to avoid that it tries the extract the assignment before the symbol table is updated 01260 if (!!ep.get()) ep.reset(); 01261 01262 // Update program 01263 asp.updateProgram(); 01264 01265 // transfer added edb 01266 DBGLOG(DBG, "Sending added EDB to clasp: " << *p.getGroundProgram().edb); 01267 bm::bvector<>::enumerator en = p.getGroundProgram().edb->getStorage().first(); 01268 bm::bvector<>::enumerator en_end = p.getGroundProgram().edb->getStorage().end(); 01269 while (en < en_end) { 01270 #ifndef NDEBUG 01271 assert ((!reg->ogatoms.getIDByAddress(*en).isAuxiliary() || reg->getTypeByAuxiliaryConstantSymbol(reg->ogatoms.getIDByAddress(*en)) != 'w') && "weak constraints cannot be added incrementally"); 01272 #endif 01273 // redundancy check 01274 if (convertHexToClaspSolverLit(*en).var() > 0) { 01275 // add fact 01276 asp.startRule(Clasp::Asp::BASICRULE).addHead(convertHexToClaspSolverLit(*en).var()).endRule(); 01277 } 01278 en++; 01279 } 01280 01281 // transfer added idb 01282 DBGLOG(DBG, "Sending added IDB to clasp"); 01283 BOOST_FOREACH (ID ruleId, p.getGroundProgram().idb) { 01284 // redundancy check 01285 bool redundant = false; 01286 BOOST_FOREACH (ID h, reg->rules.getByID(ruleId).head) { 01287 #ifndef NDEBUG 01288 assert ((!h.isAuxiliary() || reg->getTypeByAuxiliaryConstantSymbol(h) != 'w') && "weak constraints cannot be added incrementally"); 01289 #endif 01290 01291 if (convertHexToClaspSolverLit(h.address).var() == 0) { 01292 redundant = true; 01293 break; 01294 } 01295 } 01296 01297 if (!redundant) sendRuleToClasp(asp, ruleId); 01298 } 01299 01300 // finalize update 01301 freezeVariables(frozen, false /* do not freeze variables by default */); 01302 inconsistent = !asp.endProgram(); 01303 DBGLOG(DBG, "ASP instance has " << claspctx.numVars() << " variables"); 01304 DBGLOG(DBG, "Instance is now " << (inconsistent ? "" : "not ") << "inconsistent"); 01305 01306 // update projection 01307 if (!!p.getGroundProgram().mask) { 01308 InterpretationPtr pm = InterpretationPtr(new Interpretation(reg)); 01309 if (!!projectionMask) pm->add(*projectionMask); 01310 DBGLOG(DBG, "Adding to program mask:" << *p.getGroundProgram().mask); 01311 pm->add(*p.getGroundProgram().mask); 01312 projectionMask = pm; 01313 } 01314 01315 if (inconsistent) { 01316 DBGLOG(DBG, "Program is inconsistent, aborting initialization"); 01317 inconsistent = true; 01318 return; 01319 } 01320 01321 DBGLOG(DBG, "Prepare new model enumerator"); 01322 modelEnumerator.reset(config.solve.createEnumerator(config.solve)); 01323 modelEnumerator->init(claspctx, 0, config.solve.numModels); 01324 01325 DBGLOG(DBG, "Finalizing reinitialization"); 01326 if (!claspctx.endInit()) { 01327 DBGLOG(DBG, "Program is inconsistent, aborting initialization"); 01328 inconsistent = true; 01329 return; 01330 } 01331 01332 updateSymbolTable(); 01333 01334 DBGLOG(DBG, "Resetting solver object"); 01335 solve.reset(new Clasp::BasicSolve(*claspctx.master())); 01336 nextSolveStep = Restart; 01337 01338 DBGLOG(DBG, "Resetting post propagator"); 01339 ep.reset(new ExternalPropagator(*this)); 01340 01341 #ifndef NDEBUG 01342 std::stringstream ss; 01343 asp.write(ss); 01344 DBGLOG(DBG, "Updated program in LParse format: " << ss.str()); 01345 #endif 01346 } 01347 01348 01349 void ClaspSolver::addNogoodSet(const NogoodSet& ns, InterpretationConstPtr frozen) 01350 { 01351 01352 assert(problemType == SAT && "programs can only be added in SAT mode"); 01353 DBGLOG(DBG, "Adding set of nogoods incrementally"); 01354 01355 // remove post propagator to avoid that it tries the extract the assignment before the symbol table is updated 01356 if (!!ep.get()) ep.reset(); 01357 01358 claspctx.unfreeze(); 01359 01360 // add new variables 01361 claspctx.symbolTable().startInit(Clasp::SymbolTable::map_indirect); 01362 for (int i = 0; i < ns.getNogoodCount(); ++i) { 01363 const Nogood ng = ns.getNogood(i); 01364 BOOST_FOREACH (ID id, ng) { 01365 // this will register the variable if not already available 01366 convertHexToClaspProgramLit(id.address, true); 01367 assert(isMappedToClaspLiteral(id.address) && "new variable was not properly mapped to clasp"); 01368 } 01369 } 01370 claspctx.symbolTable().endInit(); 01371 01372 // add the new constraints 01373 // (SATBuilder does not currently not support this, so we need to do it my hand!) 01374 claspctx.startAddConstraints(); 01375 Clasp::ClauseCreator cc(claspctx.master()); 01376 for (int i = 0; i < ns.getNogoodCount(); i++) { 01377 const Nogood& ng = ns.getNogood(i); 01378 TransformNogoodToClaspResult ngClasp = nogoodToClaspClause(ng, true); 01379 assert (!ngClasp.outOfDomain && "literals were not properly mapped to clasp"); 01380 if (!ngClasp.tautological) { 01381 DBGLOG(DBG, "Adding nogood " << ng << " as clasp-clause"); 01382 cc.start(Clasp::Constraint_t::learnt_other); 01383 BOOST_FOREACH (Clasp::Literal lit, ngClasp.clause) { 01384 cc.add(lit); 01385 } 01386 01387 Clasp::ClauseInfo ci(Clasp::Constraint_t::static_constraint); 01388 assert (!claspctx.master()->hasConflict() && (claspctx.master()->decisionLevel() == 0 || ci.learnt())); 01389 Clasp::ClauseCreator::Result res = cc.create(*claspctx.master(), cc.lits(), 0, ci); 01390 DBGLOG(DBG, "Assignment is " << (res.ok() ? "not " : "") << "conflicting, new clause is " << (res.unit() ? "" : "not ") << "unit"); 01391 01392 if (!res.ok()) { 01393 inconsistent = true; 01394 break; 01395 } 01396 } 01397 else { 01398 DBGLOG(DBG, "Skipping tautological nogood"); 01399 } 01400 } 01401 01402 DBGLOG(DBG, "SAT instance has " << claspctx.numVars() << " variables"); 01403 01404 freezeVariables(frozen, true /* freeze variables by default */); 01405 01406 DBGLOG(DBG, "Prepare new model enumerator"); 01407 modelEnumerator.reset(config.solve.createEnumerator(config.solve)); 01408 modelEnumerator->init(claspctx, 0, config.solve.numModels); 01409 01410 DBGLOG(DBG, "Finalizing reinitialization"); 01411 if (!claspctx.endInit()) { 01412 DBGLOG(DBG, "Program is inconsistent, aborting initialization"); 01413 inconsistent = true; 01414 return; 01415 } 01416 01417 updateSymbolTable(); 01418 01419 DBGLOG(DBG, "Resetting solver object"); 01420 solve.reset(new Clasp::BasicSolve(*claspctx.master())); 01421 nextSolveStep = Restart; 01422 01423 DBGLOG(DBG, "Resetting post propagator"); 01424 ep.reset(new ExternalPropagator(*this)); 01425 } 01426 01427 01428 void ClaspSolver::restartWithAssumptions(const std::vector<ID>& assumptions) 01429 { 01430 01431 DBGLOG(DBG, "Restarting search"); 01432 01433 if (inconsistent) { 01434 DBGLOG(DBG, "Program is unconditionally inconsistent, ignoring assumptions"); 01435 return; 01436 } 01437 01438 DBGLOG(DBG, "Setting new assumptions"); 01439 this->assumptions.clear(); 01440 BOOST_FOREACH (ID a, assumptions) { 01441 if (isMappedToClaspLiteral(a.address)) { 01442 DBGLOG(DBG, "Setting assumption H:" << RawPrinter::toString(reg, a) << " (clasp: C:" << convertHexToClaspSolverLit(a.address).index() << "/" << (convertHexToClaspSolverLit(a.address).sign() ^ a.isNaf() ? "!" : "") << convertHexToClaspSolverLit(a.address).var() << ")"); 01443 Clasp::Literal al = Clasp::Literal(convertHexToClaspSolverLit(a.address).var(), convertHexToClaspSolverLit(a.address).sign() ^ a.isNaf()); 01444 this->assumptions.push_back(al); 01445 } 01446 else { 01447 DBGLOG(DBG, "Ignoring assumption H:" << RawPrinter::toString(reg, a)); 01448 } 01449 } 01450 nextSolveStep = Restart; 01451 } 01452 01453 01454 void ClaspSolver::addPropagator(PropagatorCallback* pb) 01455 { 01456 propagators.insert(pb); 01457 } 01458 01459 01460 void ClaspSolver::removePropagator(PropagatorCallback* pb) 01461 { 01462 propagators.erase(pb); 01463 } 01464 01465 01466 void ClaspSolver::addNogood(Nogood ng) 01467 { 01468 Nogood ng2; 01469 BOOST_FOREACH (ID lit, ng) { 01470 // do not add nogoods which expand the domain (this is the case if they contain positive atoms which are not in the domain) 01471 if (!lit.isNaf() && !isMappedToClaspLiteral(lit.address)) { return; } 01472 // keep positive atoms and negated atoms which are in the domain 01473 else if (!lit.isNaf() || isMappedToClaspLiteral(lit.address)) { ng2.insert(lit); } 01474 // the only remaining case should be that the literal is negated and the atom is not contained in the domain 01475 else { assert(lit.isNaf() && !isMappedToClaspLiteral(lit.address) && "conditions are logically incomplete"); } 01476 } 01477 01478 nogoods.push_back(ng2); 01479 } 01480 01481 01482 // this method is called before asking for the next model 01483 // therefore it can be called with the same optimum multiple times 01484 void ClaspSolver::setOptimum(std::vector<int>& optimum) 01485 { 01486 LOG(DBG, "Setting optimum " << printvector(optimum) << " in clasp"); 01487 if (!minc || !sharedMinimizeData) return; 01488 01489 // This method helps the reasoner to eliminate non-optimal partial models in advance 01490 // by setting the internal upper bound to a given value. 01491 // 01492 // Warning: A call of this method is just a hint for the reasoner, i.e., 01493 // it is not guaranteed that the solver will no longer create models with higher cost. 01494 // 01495 // This is because clasp does not allow to decrease the upper bound if the new bound is violated 01496 // by the current assignment. Therefore, the new optimum is only integrated into the clasp instance 01497 // if it is compatible with the assignment. 01498 // 01499 // PS: I am not sure if the above is true. 01500 01501 Clasp::MinimizeMode newMode; 01502 bool markAsOptimal = false; 01503 bool increaseLeastSignificant = false; 01504 01505 switch( ctx.config.getOption("OptimizationTwoStep") ) { 01506 case 0: 01507 // enumeration shall find models of same quality or better (the safe option) 01508 // clasp MinimizeMode_t::Mode::optimize and pctx.currentOptimum is increased by 1 on the least significant level 01509 newMode = Clasp::MinimizeMode_t::enumerate; 01510 increaseLeastSignificant = true; 01511 break; 01512 case 1: 01513 // enumeration must find a better model (works only if this solver solves the single monolithic evaluation unit) 01514 // clasp MinimizeMode_t::Mode::optimize and pctx.currentOptimum is used as it is 01515 newMode = Clasp::MinimizeMode_t::optimize; 01516 break; 01517 case 2: 01518 // enumeration finds all models of equal quality 01519 // clasp MinimizeMode_t::Mode::enumOpt and pctx.currentOptimum is used as it is and we mark it as optimum 01520 newMode = Clasp::MinimizeMode_t::enumOpt; 01521 markAsOptimal = true; 01522 break; 01523 default: 01524 throw std::runtime_error("OptimizationTwoStep: unexpected value"); 01525 break; 01526 } 01527 01528 if (markAsOptimal) { 01529 // for marking optimal: if we have no weight vector we must extend the optimum 01530 // to ctx.currentOptimumRelevantLevels by the best possible value (cost 0) 01531 while (optimum.size() < (ctx.currentOptimumRelevantLevels+1)) 01532 optimum.push_back(0); 01533 } 01534 else { 01535 // in all other cases we can abort if we have no weights stored (optimum[0] is unused) 01536 if (optimum.size() <= 1) return; 01537 // but if we have at least one weight we need to complete the vector 01538 // in order to obtain bounds for all levels 01539 while (optimum.size() < (ctx.currentOptimumRelevantLevels+1)) 01540 optimum.push_back(0); 01541 } 01542 01543 // transform optimum vector to clasp-internal representation 01544 // optimum[0] is unused, but in clasp levels start with 0 01545 int optlen = optimum.size() - 1; 01546 assert(optlen == ctx.currentOptimumRelevantLevels); 01547 01548 LOG(DBG, "Transforming optimum " << printvector(optimum) << " (length: " << optlen << ") to clasp-internal representation"); 01549 Clasp::wsum_t* newopt = new Clasp::wsum_t[optlen]; 01550 for (int l = 0; l < optlen; ++l) 01551 newopt[l] = optimum[optlen - l]; 01552 01553 01554 if( increaseLeastSignificant ) 01555 // add one on the least significant level to make sure that more solutions of the same quality are found 01556 newopt[optlen - 1]++; 01557 01558 LOG(DBG, "Setting sharedMinimizeData mode to " << static_cast<int>(newMode)); 01559 Clasp::MinimizeMode oldMode = sharedMinimizeData->mode(); 01560 if( oldMode != newMode ) { 01561 LOG(DBG, "Changing sharedMinimizeData mode from " << static_cast<int>(oldMode) << " to " << static_cast<int>(newMode)); 01562 sharedMinimizeData->setMode(newMode); 01563 // TODO do we need to call resetBounds if we go from optimize to enumOpt? 01564 if( oldMode == Clasp::MinimizeMode_t::optimize && newMode == Clasp::MinimizeMode_t::enumOpt ) { 01565 LOG(DBG, "also calling resetBounds()"); 01566 sharedMinimizeData->resetBounds(); 01567 } 01568 } 01569 LOG(DBG, "Setting optimum to " << printvector(std::vector<int>(&newopt[0], &newopt[optlen]))); 01570 sharedMinimizeData->setOptimum(newopt); 01571 if( markAsOptimal ) { 01572 LOG(DBG, "Marking this optimum as optimal"); 01573 sharedMinimizeData->markOptimal(); 01574 } 01575 bool intres = minc->integrate(*claspctx.master()); 01576 LOG(DBG, "Integrating constraint gave result " << intres); 01577 delete []newopt; 01578 } 01579 01580 Nogood ClaspSolver::getInconsistencyCause(InterpretationConstPtr explanationAtoms){ 01581 throw GeneralError("Not implemented"); 01582 } 01583 01584 InterpretationPtr ClaspSolver::getNextModel() 01585 { 01586 01587 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid, "ClaspSlv::gNM (getNextModel)"); 01588 01589 #define ENUMALGODBG(msg) { DBGLOG(DBG, "Model enumeration algorithm: (" << msg << ")"); } 01590 01591 /* 01592 This method essentially implements the following algorithm: 01593 01594 [Restart] 01595 while (solve.solve() == Clasp::value_true) { [Solve] 01596 if (e->commitModel(solve.solver())) { [CommitModel] 01597 do { 01598 onModel(e->lastModel()); [ExtractModel] & [ReturnModel] 01599 } while (e->commitSymmetric(solve.solver())); [CommitSymmetricModel] 01600 } 01601 e->update(solve.solver()); [Update] 01602 } 01603 01604 However, the onModel-call is actually a return. 01605 The algorithm is then continued with the next call of the method. 01606 The enum type NextSolveStep is used to keep track of the current state of the algorithm. 01607 */ 01608 01609 DBGLOG(DBG, "ClaspSolver::getNextModel"); 01610 01611 // ReturnModel is the only step which allows for interrupting the algorithm, i.e., leaving this loop 01612 while (nextSolveStep != ReturnModel) { 01613 switch (nextSolveStep) { 01614 case Restart: 01615 ENUMALGODBG("ini"); 01616 DBGLOG(DBG, "Starting new search"); 01617 01618 if (inconsistent) { 01619 model = InterpretationPtr(); 01620 nextSolveStep = ReturnModel; 01621 } 01622 else { 01623 DBGLOG(DBG, "Adding step literal to assumptions"); 01624 assumptions.push_back(claspctx.stepLiteral()); 01625 01626 DBGLOG(DBG, "Starting enumerator with " << assumptions.size() << " assumptions (including step literal)"); 01627 assert(!!modelEnumerator.get() && !!solve.get()); 01628 if (enumerationStarted) { 01629 modelEnumerator->end(solve->solver()); 01630 } 01631 enumerationStarted = true; 01632 01633 if (modelEnumerator->start(solve->solver(), assumptions)) { 01634 ENUMALGODBG("sat"); 01635 DBGLOG(DBG, "Instance is satisfiable wrt. assumptions"); 01636 nextSolveStep = Solve; 01637 } 01638 else { 01639 ENUMALGODBG("ust"); 01640 DBGLOG(DBG, "Instance is unsatisfiable wrt. assumptions"); 01641 model = InterpretationPtr(); 01642 nextSolveStep = ReturnModel; 01643 } 01644 } 01645 break; 01646 01647 case Solve: 01648 ENUMALGODBG("sol"); 01649 DBGLOG(DBG, "Solve for next model"); 01650 { 01651 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid, "ClaspSlv::gNM sol"); 01652 01653 if (solve->solve() == Clasp::value_true) { 01654 nextSolveStep = CommitModel; 01655 } 01656 else { 01657 model = InterpretationPtr(); 01658 nextSolveStep = ReturnModel; 01659 } 01660 } 01661 break; 01662 01663 case CommitModel: 01664 ENUMALGODBG("com"); 01665 DBGLOG(DBG, "Committing model"); 01666 01667 if (modelEnumerator->commitModel(solve->solver())) { 01668 nextSolveStep = ExtractModel; 01669 } 01670 else { 01671 nextSolveStep = Update; 01672 } 01673 break; 01674 01675 case ExtractModel: 01676 ENUMALGODBG("ext"); 01677 DBGLOG(DBG, "Extract model model"); 01678 01679 { 01680 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid, "ClaspSlv::gNM ext"); 01681 // Note: currentIntr does not necessarily coincide with the last model because clasp 01682 // possibly has already continued the search at this point 01683 model = InterpretationPtr(new Interpretation(reg)); 01684 // go over all clasp variables 01685 for(unsigned claspIndex = 0; claspIndex < claspToHex.size(); ++claspIndex) { 01686 // check if they are true 01687 if( modelEnumerator->lastModel().isTrue(Clasp::Literal::fromIndex(claspIndex)) ) { 01688 // set all corresponding bits 01689 BOOST_FOREACH(IDAddress adr, *convertClaspSolverLitToHex(claspIndex)) { 01690 model->setFact(adr); 01691 } 01692 } 01693 } 01694 } 01695 01696 outputProject(model); 01697 01698 modelCount++; 01699 01700 #ifndef NDEBUG 01701 if (!!model) { 01702 BOOST_FOREACH (Clasp::Literal lit, assumptions) { 01703 if (lit != claspctx.stepLiteral() && !modelEnumerator->lastModel().isTrue(lit)) { 01704 assert(false && "Model contradicts assumptions"); 01705 } 01706 } 01707 } 01708 #endif 01709 01710 nextSolveStep = ReturnModel; 01711 break; 01712 01713 case CommitSymmetricModel: 01714 ENUMALGODBG("cos"); 01715 DBGLOG(DBG, "Committing symmetric model"); 01716 if (modelEnumerator->commitSymmetric(solve->solver())) { 01717 DBGLOG(DBG, "Found more symmetric models, going back to extraction"); 01718 nextSolveStep = ExtractModel; 01719 } 01720 else { 01721 DBGLOG(DBG, "No more symmetric models, going to update"); 01722 nextSolveStep = Update; 01723 } 01724 break; 01725 01726 case Update: 01727 ENUMALGODBG("upd"); 01728 01729 bool optContinue; 01730 if (modelEnumerator->optimize()) { 01731 DBGLOG(DBG, "Committing unsat (for optimization problems)"); 01732 optContinue = modelEnumerator->commitUnsat(solve->solver()); 01733 } 01734 01735 DBGLOG(DBG, "Updating enumerator"); 01736 modelEnumerator->update(solve->solver()); 01737 01738 if (modelEnumerator->optimize()) { 01739 DBGLOG(DBG, "Committing complete (for optimization problems)"); 01740 if (optContinue) optContinue = modelEnumerator->commitComplete(); 01741 } 01742 01743 nextSolveStep = Solve; 01744 break; 01745 default: 01746 assert (false && "invalid state"); 01747 } 01748 } 01749 01750 assert (nextSolveStep == ReturnModel); 01751 01752 assert (!(inconsistent && !!model) && "algorithm produced a model although instance is inconsistent"); 01753 // Note: !(!inconsistent && model) can *not* be asserted since an instance can be consistent but still 01754 // produce an empty model because if 01755 // (1) end of models; or 01756 // (2) because the instance is inconsistent wrt. the *current* assumptions 01757 // (variable "inconsistent" means that the instance is inconsistent wrt. *any* assumptions). 01758 01759 ENUMALGODBG("ret"); 01760 DBGLOG(DBG, "Returning " << (!model ? "empty " :"") << "model"); 01761 if (!!model) { 01762 // committing symmetric models is only necessary if some variables are frozen 01763 // but we still want to get all models 01764 nextSolveStep = CommitSymmetricModel; 01765 } 01766 else { 01767 // we stay in this state until restart 01768 nextSolveStep = ReturnModel; 01769 } 01770 return model; 01771 } 01772 01773 01774 int ClaspSolver::getModelCount() 01775 { 01776 return modelCount; 01777 } 01778 01779 01780 std::string ClaspSolver::getStatistics() 01781 { 01782 std::stringstream ss; 01783 ss << "Guesses: " << claspctx.master()->stats.choices << std::endl << 01784 "Conflicts: " << claspctx.master()->stats.conflicts << std::endl << 01785 "Models: " << modelCount; 01786 return ss.str(); 01787 } 01788 01789 01790 DLVHEX_NAMESPACE_END 01791 #endif 01792 01793 01794 // vim:expandtab:ts=4:sw=4: 01795 // mode: C++ 01796 // End: