dlvhex  2.5.0
src/ClaspSolver.cpp
Go to the documentation of this file.
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: