dlvhex  2.5.0
src/InternalGroundASPSolver.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 
00034 #ifdef HAVE_CONFIG_H
00035 #include "config.h"
00036 #endif
00037 
00038 #include "dlvhex2/InternalGroundASPSolver.h"
00039 
00040 #include <iostream>
00041 #include <sstream>
00042 
00043 #include "dlvhex2/Logger.h"
00044 #include "dlvhex2/GenuineSolver.h"
00045 #include "dlvhex2/Benchmarking.h"
00046 #include "dlvhex2/Printer.h"
00047 
00048 #include <boost/foreach.hpp>
00049 #include <boost/graph/strong_components.hpp>
00050 
00051 DLVHEX_NAMESPACE_BEGIN
00052 
00053 //#define DBGLOGD(X,Y) DBGLOG(X,Y)
00054 #define DBGLOGD(X,Y) do{}while(false);
00055 
00056 // 1. body must not be false if all literals are true
00057 // 2. body must not be true if a literal is false
00058 // 3. head must not be false if body is true
00059 void InternalGroundASPSolver::createNogoodsForRule(ID ruleBodyAtomID, ID ruleID)
00060 {
00061 
00062     if (ruleID.isWeightRule()) throw GeneralError("Internal solver does not support weight rules");
00063     const Rule& r = reg->rules.getByID(ruleID);
00064 
00065     // 1 and 2
00066     createNogoodsForRuleBody(ruleBodyAtomID, r.body);
00067 
00068     // 3. head must not be false if body is true
00069     Nogood bodyImpliesHead;
00070     bodyImpliesHead.insert(createLiteral(ruleBodyAtomID));
00071     BOOST_FOREACH(ID headLit, r.head) {
00072         bodyImpliesHead.insert(createLiteral(headLit.address, false));
00073     }
00074     nogoodset.addNogood(bodyImpliesHead);
00075 }
00076 
00077 
00078 // 1. body must not be false if all literals are true
00079 // 2. body must not be true if a literal is false
00080 void InternalGroundASPSolver::createNogoodsForRuleBody(ID ruleBodyAtomID, const Tuple& ruleBody)
00081 {
00082     BOOST_FOREACH(ID bodyLit, ruleBody) {
00083         if (bodyLit.isAggregateAtom()) throw GeneralError("Internal solver does not support aggregate atoms");
00084     }
00085 
00086     // 1. body must not be false if all literals are true
00087     Nogood bodySatIfLitSat;
00088     BOOST_FOREACH(ID bodyLit, ruleBody) {
00089         bodySatIfLitSat.insert(createLiteral(bodyLit));
00090     }
00091     bodySatIfLitSat.insert(negation(createLiteral(ruleBodyAtomID)));
00092     nogoodset.addNogood(bodySatIfLitSat);
00093 
00094     // 2. body must not be true if a literal is false
00095     BOOST_FOREACH(ID bodyLit, ruleBody) {
00096         Nogood bodyFalseIfLitFalse;
00097         bodyFalseIfLitFalse.insert(createLiteral(ruleBodyAtomID));
00098         bodyFalseIfLitFalse.insert(negation(createLiteral(bodyLit)));
00099         nogoodset.addNogood(bodyFalseIfLitFalse);
00100     }
00101 }
00102 
00103 
00104 Set<std::pair<ID, ID> > InternalGroundASPSolver::createShiftedProgram()
00105 {
00106 
00107     // create for each rule of kind
00108     //  a(1) v ... v a(m) :- B
00109     // all shifted rules of kind
00110     //  a(i) :- B, -a(1), ..., -a(i-1), -a(i+1), ..., a(m)
00111     // for all 1 <= i <= m
00112 
00113     DBGLOG(DBG, "Creating shifted program");
00114 
00115     Set<std::pair<ID, ID> > shiftedProg;
00116     BOOST_FOREACH (ID ruleID, program.getGroundProgram().idb) {
00117 
00118         const Rule& r = reg->rules.getByID(ruleID);
00119 
00120         // real shifted rule?
00121         if (r.head.size() > 1) {
00122             BOOST_FOREACH (ID headLit, r.head) {
00123                 // take body of r and current head literal
00124                 Tuple singularHead;
00125                 singularHead.push_back(createLiteral(headLit));
00126                 Rule shiftedRule(ID::MAINKIND_RULE | ID::SUBKIND_RULE_REGULAR, singularHead, r.body);
00127 
00128                 // add negations of all other head literals to body
00129                 BOOST_FOREACH (ID otherHeadLit, r.head) {
00130                     if (otherHeadLit != headLit) {
00131                         shiftedRule.body.push_back(negation(createLiteral(otherHeadLit)));
00132                     }
00133                 }
00134 
00135                 // create a new body atom
00136                 DBGLOG(DBG, "Creating real shifted rule: " << shiftedRule);
00137                 ID shiftedRuleID = reg->rules.getIDByElement(shiftedRule);
00138                 if (shiftedRuleID == ID_FAIL) {
00139                     shiftedRuleID = reg->rules.storeAndGetID(shiftedRule);
00140                 }
00141                 ID ruleBodyAtomID = createNewBodyAtom();
00142 
00143                 shiftedProg.insert(std::pair<ID, ID>(shiftedRuleID, ruleBodyAtomID));
00144             }
00145         }
00146         else {
00147             // rule was already present in original program and has already a body literal
00148             DBGLOG(DBG, "Creating shifted rule which was already present in original program: " << r);
00149 
00150             shiftedProg.insert(std::pair<ID, ID>(ruleID, createLiteral(bodyAtomOfRule[ruleID.address])));
00151         }
00152     }
00153 
00154     DBGLOG(DBG, "Creating shifted program finished");
00155 
00156     return shiftedProg;
00157 }
00158 
00159 
00160 void InternalGroundASPSolver::createSingularLoopNogoods(InterpretationConstPtr frozen)
00161 {
00162 
00163     DBGLOG(DBG, "Creating singular loop nogoods");
00164 
00165     typedef std::pair<ID, ID> RulePair;
00166     Set<RulePair> shiftedProgram = createShiftedProgram();
00167 
00168     // create for each real shifted rule the nogoods which associate the rule body with the body atom
00169     // (shifted rules which were already present in the original program were already handled before)
00170     BOOST_FOREACH (RulePair pair, shiftedProgram) {
00171         if (!contains(program.getGroundProgram().idb, pair.first)) {
00172             const Rule& r = reg->rules.getByID(pair.first);
00173             createNogoodsForRuleBody(pair.second, r.body);
00174         }
00175     }
00176 
00177     // an atom must not be true if the bodies of all supporting shifted rules are false
00178     BOOST_FOREACH (IDAddress litadr, ordinaryFacts) {
00179         // only for atoms which are no facts
00180         if (!program.getGroundProgram().edb->getFact(litadr) && (!frozen || !frozen->getFact(litadr))) {
00181             Nogood supNogood;
00182             supNogood.insert(createLiteral(litadr));
00183 
00184             // for all supporting rules
00185             BOOST_FOREACH(RulePair pair, shiftedProgram) {
00186                 const Rule& r = reg->rules.getByID(pair.first);
00187                 if (r.head.size() > 0 && (r.head[0].address == litadr)) {
00188                     supNogood.insert(negation(createLiteral(pair.second)));
00189                 }
00190             }
00191             nogoodset.addNogood(supNogood);
00192         }
00193     }
00194 
00195     DBGLOG(DBG, "Nogoods with singular loop nogoods: " << nogoodset);
00196 }
00197 
00198 
00199 void InternalGroundASPSolver::resizeVectors()
00200 {
00201 
00202     CDNLSolver::resizeVectors();
00203 
00204     unsigned atomNamespaceSize = reg->ogatoms.getSize();
00205 
00206     /*
00207       componentOfAtom.resize(atomNamespaceSize);
00208       bodyAtomOfRule.resize(atomNamespaceSize);
00209       rulesWithPosBodyLiteral.resize(atomNamespaceSize);
00210       rulesWithNegBodyLiteral.resize(atomNamespaceSize);
00211       rulesWithPosHeadLiteral.resize(atomNamespaceSize);
00212       foundedAtomsOfBodyAtom.resize(atomNamespaceSize);
00213     */
00214 }
00215 
00216 
00217 void InternalGroundASPSolver::computeClarkCompletion()
00218 {
00219 
00220     // compute completion
00221     BOOST_FOREACH (ID ruleID, program.getGroundProgram().idb) {
00222         if (ruleID.isWeakConstraint()) throw GeneralError("Internal solver does not support weak constraints");
00223 
00224         ID ruleBodyAtomID = createNewBodyAtom();
00225         bodyAtomOfRule[ruleID.address] = ruleBodyAtomID.address;
00226         createNogoodsForRule(ruleBodyAtomID, ruleID);
00227     }
00228 
00229     DBGLOG(DBG, "Created Clark's completion: " << nogoodset);
00230 }
00231 
00232 
00233 void InternalGroundASPSolver::setEDB()
00234 {
00235 
00236     DBGLOG(DBG, "Setting EDB");
00237 
00238     // set all facts at decision level 0 without cause
00239     bm::bvector<>::enumerator en = program.getGroundProgram().edb->getStorage().first();
00240     bm::bvector<>::enumerator en_end = program.getGroundProgram().edb->getStorage().end();
00241 
00242     while (en < en_end) {
00243         if (ordinaryFacts.count(*en) > 0) {
00244             setFact(createLiteral(*en), 0, -1);
00245         }
00246         ++en;
00247     }
00248 }
00249 
00250 
00251 void InternalGroundASPSolver::computeDepGraph()
00252 {
00253 
00254     // all literals are nodes
00255     BOOST_FOREACH (IDAddress litadr, ordinaryFacts) {
00256         depNodes[litadr] = boost::add_vertex(litadr, depGraph);
00257     }
00258 
00259     // go through all rules
00260     BOOST_FOREACH (ID ruleID, program.getGroundProgram().idb) {
00261         const Rule& rule = reg->rules.getByID(ruleID);
00262 
00263         // add an arc from all head literals to all positive body literals
00264         BOOST_FOREACH (ID headLiteral, rule.head) {
00265             BOOST_FOREACH (ID bodyLiteral, rule.body) {
00266                 if (!bodyLiteral.isNaf()) {
00267                     boost::add_edge(depNodes[headLiteral.address], depNodes[bodyLiteral.address], depGraph);
00268                 }
00269             }
00270         }
00271     }
00272 }
00273 
00274 
00275 void InternalGroundASPSolver::computeStronglyConnectedComponents()
00276 {
00277 
00278     // find strongly connected components in the dependency graph using boost
00279     std::vector<int> componentMap(depNodes.size());
00280     int num = boost::strong_components(depGraph, boost::make_iterator_property_map(componentMap.begin(), get(boost::vertex_index, depGraph)));
00281 
00282     // translate into real map
00283     depSCC = std::vector<Set<IDAddress> >(num);
00284     Node nodeNr = 0;
00285     BOOST_FOREACH (int componentOfNode, componentMap) {
00286         depSCC[componentOfNode].insert(depGraph[nodeNr]);
00287         componentOfAtom[depGraph[nodeNr]] = componentOfNode;
00288         nodeNr++;
00289     }
00290 
00291     // store which atoms occur in non-singular components
00292     BOOST_FOREACH (IDAddress litadr, ordinaryFacts) {
00293         if (depSCC[componentOfAtom[litadr]].size() > 1) {
00294             nonSingularFacts.insert(litadr);
00295         }
00296     }
00297 
00298     #ifndef NDEBUG
00299     std::stringstream compStr;
00300     bool firstC = true;
00301     BOOST_FOREACH (Set<IDAddress> component, depSCC) {
00302         if (!firstC) compStr << ", ";
00303         firstC = false;
00304         compStr << "{";
00305         bool firstL = true;
00306         BOOST_FOREACH (IDAddress litadr, component) {
00307             if (!firstL) compStr << ", ";
00308             firstL = false;
00309             compStr << litadr;
00310         }
00311         compStr << "}";
00312     }
00313     DBGLOG(DBG, "Program components: " << compStr.str());
00314     DBGLOG(DBG, "All atoms: " << toString(allAtoms));
00315     DBGLOG(DBG, "All ordinary atoms: " << toString(ordinaryFacts));
00316     DBGLOG(DBG, "Ordinary atoms in non-singular components: " << toString(nonSingularFacts));
00317     #endif
00318 }
00319 
00320 
00321 void InternalGroundASPSolver::initSourcePointers()
00322 {
00323 
00324     DBGLOG(DBG, "Initialize source pointers");
00325 
00326     // initially, all atoms in non-singular components, except facts, are unfounded
00327     BOOST_FOREACH (IDAddress litadr, ordinaryFacts) {
00328         if (program.getGroundProgram().edb->getFact(litadr)) {
00329             // store pseudo source rule ID_FAIL to mark that this is a fact and founded by itself
00330             sourceRule[litadr] = ID_FAIL;
00331         }
00332         else {
00333             // all non-facts in non-singular components are unfounded
00334             if (nonSingularFacts.count(litadr) > 0) {
00335                 unfoundedAtoms.insert(litadr);
00336             }
00337         }
00338     }
00339 
00340     DBGLOG(DBG, "Initially unfounded atoms: " << toString(unfoundedAtoms));
00341 }
00342 
00343 
00344 void InternalGroundASPSolver::initializeLists(InterpretationConstPtr frozen)
00345 {
00346 
00347     // determine the set of all facts and a literal index
00348     BOOST_FOREACH (ID ruleID, program.getGroundProgram().idb) {
00349         const Rule& r = reg->rules.getByID(ruleID);
00350 
00351         // remember this rule for each contained literal
00352         for (std::vector<ID>::const_iterator lIt = r.head.begin(); lIt != r.head.end(); ++lIt) {
00353             if (lIt->isOrdinaryNongroundAtom()) throw GeneralError("Got nonground program");
00354 
00355             rulesWithPosHeadLiteral[lIt->address].insert(ruleID);
00356             // collect all facts
00357             allAtoms.insert(lIt->address);
00358             ordinaryFacts.insert(lIt->address);
00359         }
00360         for (std::vector<ID>::const_iterator lIt = r.body.begin(); lIt != r.body.end(); ++lIt) {
00361             if (lIt->isOrdinaryNongroundAtom()) throw GeneralError("Got nonground program");
00362 
00363             if (!lIt->isNaf()) {
00364                 rulesWithPosBodyLiteral[lIt->address].insert(ruleID);
00365             }
00366             else {
00367                 rulesWithNegBodyLiteral[lIt->address].insert(ruleID);
00368             }
00369             // collect all facts
00370             allAtoms.insert(lIt->address);
00371             ordinaryFacts.insert(lIt->address);
00372         }
00373     }
00374 
00375     // include facts in the list of all atoms
00376     bm::bvector<>::enumerator en = program.getGroundProgram().edb->getStorage().first();
00377     bm::bvector<>::enumerator en_end = program.getGroundProgram().edb->getStorage().end();
00378     while (en < en_end) {
00379         allAtoms.insert(*en);
00380         ordinaryFacts.insert(*en);
00381         ++en;
00382     }
00383 
00384     // frozen atoms in the list of all atoms
00385     if (!!frozen) {
00386         en = frozen->getStorage().first();
00387         en_end = frozen->getStorage().end();
00388         while (en < en_end) {
00389             allAtoms.insert(*en);
00390             ordinaryFacts.insert(*en);
00391             en++;
00392         }
00393     }
00394 
00395     // built an interpretation of ordinary facts
00396     ordinaryFactsInt = InterpretationPtr(new Interpretation(reg));
00397     BOOST_FOREACH (IDAddress idadr, ordinaryFacts) {
00398         ordinaryFactsInt->setFact(idadr);
00399     }
00400 }
00401 
00402 
00403 void InternalGroundASPSolver::setFact(ID fact, int dl, int cause = -1)
00404 {
00405     CDNLSolver::setFact(fact, dl, cause);
00406     updateUnfoundedSetStructuresAfterSetFact(fact);
00407 }
00408 
00409 
00410 void InternalGroundASPSolver::clearFact(IDAddress litadr)
00411 {
00412     CDNLSolver::clearFact(litadr);
00413     updateUnfoundedSetStructuresAfterClearFact(litadr);
00414 }
00415 
00416 
00417 void InternalGroundASPSolver::removeSourceFromAtom(IDAddress litadr)
00418 {
00419 
00420     // check if the literal has currently a source rule
00421     if (sourceRule.find(litadr) != sourceRule.end()) {
00422         if (sourceRule[litadr] != ID_FAIL) {
00423             ID sourceRuleID = sourceRule[litadr];
00424             DBGLOG(DBG, "Literal " << litadr << " canceled its source pointer to rule " << sourceRuleID.address);
00425             foundedAtomsOfBodyAtom[bodyAtomOfRule[sourceRuleID.address]].erase(litadr);
00426             sourceRule.erase(litadr);
00427         }
00428     }
00429 }
00430 
00431 
00432 void InternalGroundASPSolver::addSourceToAtom(IDAddress litadr, ID rule)
00433 {
00434     DBGLOG(DBG, "Literal " << litadr << " sets a source pointer to " << rule.address);
00435     sourceRule[litadr] = rule;
00436     foundedAtomsOfBodyAtom[bodyAtomOfRule[rule.address]].insert(litadr);
00437 }
00438 
00439 
00440 Set<IDAddress> InternalGroundASPSolver::getDependingAtoms(IDAddress litadr)
00441 {
00442 
00443     // litadr became unfounded; now compute all atoms which depend on litadr and are
00444     // therefore become unfounded too
00445     Set<IDAddress> dependingAtoms;
00446 
00447     // go through all rules which contain litadr in their body
00448     BOOST_FOREACH (ID ruleID, rulesWithPosBodyLiteral[litadr]) {
00449 
00450         // go through all atoms which use this rule as source
00451         BOOST_FOREACH (IDAddress dependingAtom, foundedAtomsOfBodyAtom[bodyAtomOfRule[ruleID.address]]) {
00452             // this atom is depends on litadr
00453             dependingAtoms.insert(dependingAtom);
00454         }
00455     }
00456 
00457     return dependingAtoms;
00458 }
00459 
00460 
00461 void InternalGroundASPSolver::getInitialNewlyUnfoundedAtomsAfterSetFact(ID fact, Set<IDAddress>& newlyUnfoundedAtoms)
00462 {
00463 
00464     // if the fact is a falsified body literal, all atoms which depend on it become unfounded
00465     if (fact.isNaf()) {
00466         if (foundedAtomsOfBodyAtom.find(fact.address) != foundedAtomsOfBodyAtom.end()) {
00467             BOOST_FOREACH (IDAddress dependingAtom, foundedAtomsOfBodyAtom[fact.address]) {
00468                 DBGLOGD(DBG, "" << dependingAtom << " is initially unfounded because the body of its source rule became false");
00469                 newlyUnfoundedAtoms.insert(dependingAtom);
00470             }
00471         }
00472     }
00473 
00474     // if the fact is a satisfied head literal of a rule, all head literals which use it as source rule and
00475     // (i) which were set later; or
00476     // (ii) which are true in a different component
00477     // become unfounded
00478     else {
00479         // for all rules which contain the fact in their head
00480         if (rulesWithPosHeadLiteral.find(fact.address) != rulesWithPosHeadLiteral.end()) {
00481             BOOST_FOREACH (ID ruleID, rulesWithPosHeadLiteral[fact.address]) {
00482                 const Rule& r = reg->rules.getByID(ruleID);
00483 
00484                 // all other head literals cannot use this rule as source, if
00485                 BOOST_FOREACH (ID otherHeadLit, r.head) {
00486                     if (otherHeadLit.address != fact.address && sourceRule[otherHeadLit.address] == ruleID) {
00487                         // (i) they were set to true later
00488                         // TODO: maybe we have to compare the order of assignments instead of the decision levels
00489                         //       or we can use the decision level (would be much more efficient)
00490                         if (satisfied(createLiteral(otherHeadLit.address)) &&
00491                             getAssignmentOrderIndex(otherHeadLit.address) > getAssignmentOrderIndex(fact.address)
00492                         ) {
00493                             DBGLOGD(DBG, "" << otherHeadLit.address << " is initially unfounded because " << otherHeadLit.address <<
00494                                 " occurs in the head of its source rule and became true on a lower decision level");
00495                             newlyUnfoundedAtoms.insert(otherHeadLit.address);
00496                         }
00497 
00498                         // (ii) they belong to a different component
00499                         if (componentOfAtom[otherHeadLit.address] != componentOfAtom[fact.address]) {
00500                             DBGLOGD(DBG, "" << otherHeadLit.address << " is initially unfounded because " << fact.address <<
00501                                 " occurs in the head of its source rule and is true in a different component");
00502                             newlyUnfoundedAtoms.insert(otherHeadLit.address);
00503                         }
00504                     }
00505                 }
00506             }
00507         }
00508     }
00509 
00510     DBGLOGD(DBG, "Scope of unfounded set check is initially extended by " << toString(newlyUnfoundedAtoms));
00511 
00512 }
00513 
00514 
00515 void InternalGroundASPSolver::updateUnfoundedSetStructuresAfterSetFact(ID fact)
00516 {
00517 
00518     DBGLOGD(DBG, "Updating set of atoms without source pointers, currently: " << toString(unfoundedAtoms));
00519 
00520     #ifndef NDEBUG
00521     {
00522         std::stringstream ss;
00523         typedef std::pair<IDAddress, Set<IDAddress> > SourcePair;
00524         BOOST_FOREACH (SourcePair pair, foundedAtomsOfBodyAtom) {
00525             ss << "Body atom " << pair.first << " is source for " << toString(pair.second) << "; ";
00526         }
00527         DBGLOGD(DBG, "Source pointer: " << ss.str());
00528     }
00529     #endif
00530 
00531     // atom does not need a source pointer if it is assigned to false
00532     if (fact.isNaf()) {
00533         DBGLOGD(DBG, "Literal " << fact.address << " was assigned to false and is not unfounded anymore");
00534         removeSourceFromAtom(fact.address);
00535         unfoundedAtoms.erase(fact.address);
00536     }
00537 
00538     // update the unfounded data structures
00539     DBGLOGD(DBG, "Computing initially newly unfounded atoms");
00540     Set<IDAddress> newlyUnfoundedAtoms;
00541     getInitialNewlyUnfoundedAtomsAfterSetFact(fact, newlyUnfoundedAtoms);
00542 
00543     while (newlyUnfoundedAtoms.size() > 0) {
00544         Set<IDAddress> nextNewlyUnfoundedAtoms;
00545 
00546         DBGLOGD(DBG, "Collecting depending atoms of " << toString(newlyUnfoundedAtoms));
00547 
00548         BOOST_FOREACH (IDAddress newlyUnfoundedAtom, newlyUnfoundedAtoms) {
00549             // only atoms which occur in non-singular components
00550             // (singular atoms are already handled by static loop nogoods)
00551             if (nonSingularFacts.count(newlyUnfoundedAtom) > 0) {
00552                 // only atoms which are not already unfounded or false
00553                 if (!falsified(createLiteral(newlyUnfoundedAtom)) && (unfoundedAtoms.count(newlyUnfoundedAtom) == 0)) {
00554                     // only atoms which occur in a component that depends on unfounded atoms
00555                     if (intersect(depSCC[componentOfAtom[newlyUnfoundedAtom]], unfoundedAtoms).size() > 0 ||
00556                     intersect(depSCC[componentOfAtom[newlyUnfoundedAtom]], newlyUnfoundedAtoms).size() > 0) {
00557                         DBGLOGD(DBG, "Atom " << newlyUnfoundedAtom << " becomes unfounded");
00558                         removeSourceFromAtom(newlyUnfoundedAtom);
00559                         unfoundedAtoms.insert(newlyUnfoundedAtom);
00560 
00561                         // collect depending atoms
00562                         Set<IDAddress> dependingAtoms = getDependingAtoms(newlyUnfoundedAtom);
00563                         DBGLOGD(DBG, "Depending on " << newlyUnfoundedAtom << ": " << toString(dependingAtoms));
00564                         nextNewlyUnfoundedAtoms.insert(dependingAtoms.begin(), dependingAtoms.end());
00565                     }
00566                 }
00567             }
00568         }
00569         newlyUnfoundedAtoms = nextNewlyUnfoundedAtoms;
00570     }
00571 
00572     DBGLOG(DBG, "Updated set of unfounded atoms: " << toString(unfoundedAtoms));
00573 }
00574 
00575 
00576 void InternalGroundASPSolver::updateUnfoundedSetStructuresAfterClearFact(IDAddress litadr)
00577 {
00578 
00579     DBGLOGD(DBG, "Updating set of atoms without source pointers, currently: " << toString(unfoundedAtoms));
00580 
00581     // fact becomes unfounded if it has no source pointer
00582     // and if it is non-singular
00583     if (nonSingularFacts.count(litadr) > 0) {
00584         if (sourceRule.find(litadr) == sourceRule.end()) {
00585             unfoundedAtoms.insert(litadr);
00586         }
00587     }
00588 
00589     DBGLOGD(DBG, "Updated set of unfounded atoms: " << toString(unfoundedAtoms));
00590 }
00591 
00592 
00593 ID InternalGroundASPSolver::getPossibleSourceRule(const Set<ID>& ufs)
00594 {
00595 
00596     DBGLOG(DBG, "Computing externally supporting rules for " << toString(ufs));
00597 
00598     Set<ID> extSup = getExternalSupport(ufs);
00599 
00600     #ifndef NDEBUG
00601     {
00602         std::stringstream ss;
00603         ss << "Externally supporting rules of potential ufs: {";
00604         bool first = true;
00605         BOOST_FOREACH (ID ruleID, extSup) {
00606             if (!first) ss << ", ";
00607             first = false;
00608             ss << ruleID.address;
00609         }
00610         ss << "}";
00611         DBGLOG(DBG, ss.str());
00612     }
00613     #endif
00614 
00615     // from this set, remove all rules which are satisfied independently from ufs
00616     // and can therefore not be used as source rules
00617     BOOST_FOREACH (ID extRuleID, extSup) {
00618         Set<ID> satInd = satisfiesIndependently(extRuleID, ufs);
00619         bool skipRule = false;
00620         BOOST_FOREACH (ID indSatLit, satInd) {
00621             if (satisfied(indSatLit)) {
00622                 skipRule = true;
00623                 break;
00624             }
00625         }
00626         if (!skipRule) {
00627             DBGLOG(DBG, "Found possible source rule: " << extRuleID.address);
00628             return extRuleID;
00629         }
00630         else {
00631             DBGLOG(DBG, "Rule " << extRuleID.address << " is removed (independently satisfied)");
00632         }
00633     }
00634 
00635     return ID_FAIL;
00636 }
00637 
00638 
00639 // a head atom uses the rule as source, if
00640 // 1. the atom is currently unfounded
00641 // 2. no other head literal was set to true earlier
00642 bool InternalGroundASPSolver::useAsNewSourceForHeadAtom(IDAddress headAtom, ID sourceRuleID)
00643 {
00644 
00645     DBGLOG(DBG, "Checking if " << headAtom << " uses rule " << sourceRuleID.address << " as source");
00646     if (unfoundedAtoms.count(headAtom) == 0) {
00647         DBGLOG(DBG, "No: " << headAtom << " is currently not unfounded");
00648         return false;
00649     }
00650 
00651     const Rule& sourceRule = reg->rules.getByID(sourceRuleID);
00652 
00653     // only the literal which was set first can use a rule as source:
00654     //
00655     // if headLit is currently assigned, other head literals must not be set to true earlier
00656     // if headLit is currently unassigned, other head literals must not be true at all
00657     if (assigned(headAtom)) {
00658         int headLitDecisionLevel = decisionlevel[headAtom];
00659         BOOST_FOREACH (ID otherHeadLit, sourceRule.head) {
00660             if (otherHeadLit.address != headAtom) {
00661                 if (satisfied(otherHeadLit)) {
00662                     // TODO: maybe we have to compare the order of assignments instead of the decision levels
00663                     //       or we can use the decision level (would be much more efficient)
00664                     if (
00665                         getAssignmentOrderIndex(otherHeadLit.address) < getAssignmentOrderIndex(headAtom)
00666                     ) {
00667                         DBGLOG(DBG, "No: Head literal " << otherHeadLit.address << " was set to true on a lower decision level");
00668                         return false;
00669                     }
00670                 }
00671             }
00672         }
00673     }
00674     else {
00675         BOOST_FOREACH (ID otherHeadLit, sourceRule.head) {
00676             if (otherHeadLit.address != headAtom) {
00677                 if (satisfied(otherHeadLit)) {
00678                     DBGLOG(DBG, "No: Head literal " << otherHeadLit.address << " was already set to true, whereas " << headAtom << " is unassigned");
00679                     return false;
00680                 }
00681             }
00682         }
00683     }
00684     return true;
00685 }
00686 
00687 
00688 Set<ID> InternalGroundASPSolver::getUnfoundedSet()
00689 {
00690 
00691     DBGLOG(DBG, "Currently unfounded atoms: " << toString(unfoundedAtoms));
00692 
00693     Set<ID> ufs(5, 10);
00694     while (unfoundedAtoms.size() > 0) {
00695         IDAddress atom = *(unfoundedAtoms.begin());
00696         ufs.clear();
00697         ufs.insert(createLiteral(atom));
00698         do {
00699             DBGLOG(DBG, "Trying to build an unfounded set over " << toString(ufs));
00700 
00701             // find a rule which externally supports ufs and
00702             // which is not satisfied independently of ufs
00703             ID supportingRuleID = getPossibleSourceRule(ufs);
00704 
00705             // if no rule survives, ufs is indeed unfounded
00706             if (supportingRuleID == ID_FAIL) return ufs;
00707 
00708             // check if this rule depends on unfounded atoms from atom's component
00709             const Rule& supportingRule = reg->rules.getByID(supportingRuleID);
00710             bool dependsOnUnfoundedAtoms = false;
00711             BOOST_FOREACH (ID bodyLit, supportingRule.body) {
00712                 if (!bodyLit.isNaf() && (unfoundedAtoms.count(bodyLit.address) > 0) && (depSCC[componentOfAtom[atom]].count(bodyLit.address) > 0)) {
00713                     // extend the unfounded set by this atom
00714                     DBGLOG(DBG, "Rule depends on unfounded " << litToString(bodyLit) << " --> adding to ufs");
00715                     ufs.insert(createLiteral(bodyLit));
00716                     dependsOnUnfoundedAtoms = true;
00717                 }
00718             }
00719 
00720             // if the rule does not depend on unfounded atoms, it can be used as the new source for its head atom(s)
00721             if (!dependsOnUnfoundedAtoms) {
00722                 BOOST_FOREACH (ID headLit, supportingRule.head) {
00723 
00724                     if (useAsNewSourceForHeadAtom(headLit.address, supportingRuleID)) {
00725                         // use the rule as new source
00726                         DBGLOG(DBG, "Using rule " << supportingRuleID.address << " as new source for " << headLit.address);
00727                         addSourceToAtom(headLit.address, supportingRuleID);
00728 
00729                         // atom hIt->address is no longer unfounded
00730                         unfoundedAtoms.erase(headLit.address);
00731                         ufs.erase(createLiteral(headLit.address));
00732                     }
00733                 }
00734             }
00735         }while(ufs.size() > 0);
00736     }
00737 
00738     return Set<ID>();
00739 }
00740 
00741 
00742 bool InternalGroundASPSolver::doesRuleExternallySupportLiteral(ID ruleID, ID lit, const Set<ID>& s)
00743 {
00744 
00745     const Rule& rule = reg->rules.getByID(ruleID);
00746 
00747     // check if the rule supports the literal
00748     bool supportsLit = false;
00749     BOOST_FOREACH (ID headLit, rule.head) {
00750         if (headLit.address == lit.address) {
00751             supportsLit = true;
00752             break;
00753         }
00754     }
00755     if (!supportsLit) return false;
00756 
00757     // check if the support is external wrt s
00758     BOOST_FOREACH (ID sLit, s) {
00759         if (contains(rule.body, sLit)) {
00760             return false;
00761         }
00762     }
00763 
00764     return true;
00765 }
00766 
00767 
00768 Set<ID> InternalGroundASPSolver::getExternalSupport(const Set<ID>& s)
00769 {
00770 
00771     Set<ID> extRules;
00772     DBGLOG(DBG, "Computing externally supporting rules for set " << toString(s));
00773 
00774     // go through all rules which contain one of s in their head
00775     BOOST_FOREACH (ID lit, s) {
00776 
00777         const Set<ID>& containingRules = rulesWithPosHeadLiteral[lit.address];
00778 
00779         BOOST_FOREACH (ID ruleID, containingRules) {
00780 
00781             // check if none of the elements of s occurs in the body of r
00782             if (doesRuleExternallySupportLiteral(ruleID, lit, s)) {
00783                 DBGLOG(DBG, "Found external rule " << ruleID.address << " for set " << toString(s));
00784                 extRules.insert(ruleID);
00785             }
00786             else {
00787                 DBGLOGD(DBG, "Rule " << ruleID.address << " contains " << lit.address << " but does not externally support it wrt " << toString(s));
00788             }
00789         }
00790     }
00791     return extRules;
00792 }
00793 
00794 
00795 Set<ID> InternalGroundASPSolver::satisfiesIndependently(ID ruleID, const Set<ID>& y)
00796 {
00797 
00798     const Rule& rule = reg->rules.getByID(ruleID);
00799 
00800     // compute all literals which satisfy the rule independently of set y:
00801     // either (i) the body of rule is false; or
00802     //        (ii) some head literal, which is not in y, is true
00803     Set<ID> indSat;
00804                                  // (i)
00805     indSat.insert(createLiteral(bodyAtomOfRule[ruleID.address], false));
00806                                  // (ii)
00807     BOOST_FOREACH (ID headLiteral, rule.head) {
00808         if (y.count(createLiteral(headLiteral.address)) == 0) {
00809             indSat.insert(createLiteral(headLiteral.address));
00810         }
00811     }
00812     DBGLOG(DBG, "Rule " << ruleID.address << " is satisfied independently from " << toString(y) << " by " << toString(indSat));
00813     return indSat;
00814 }
00815 
00816 
00817 Nogood InternalGroundASPSolver::getLoopNogood(const Set<ID>& ufs)
00818 {
00819 
00820     Nogood loopNogood;
00821 
00822     // there are exponentially many loop nogoods for ufs;
00823     // choose one l from
00824     // lamba(ufs) = { Ta | a in ufs} x Prod_{r in extsup(ufs)} indsat(r, ufs)
00825     // such that l \ { Ta | a in ufs} is currently satisfied
00826     loopNogood.insert(createLiteral(*(ufs.begin())));
00827 
00828     // choose for each external rule one literal which
00829     // (i) satisfies it independently from ufs; and
00830     // (ii) is currently true
00831     Set<ID> extSup = getExternalSupport(ufs);
00832     BOOST_FOREACH (ID ruleID, extSup) {
00833                                  // (i)
00834         Set<ID> satInd = satisfiesIndependently(ruleID, ufs);
00835         BOOST_FOREACH (ID indLit, satInd) {
00836                                  // (ii)
00837             if (satisfied(indLit)) {
00838                 loopNogood.insert(createLiteral(indLit));
00839                 break;
00840             }
00841         }
00842     }
00843     DBGLOG(DBG, "Loop nogood for " << toString(ufs) << " is " << loopNogood);
00844 
00845     return loopNogood;
00846 }
00847 
00848 
00849 ID InternalGroundASPSolver::createNewAtom(ID predID)
00850 {
00851     OrdinaryAtom atom(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG);
00852     atom.tuple.push_back(predID);
00853     return createLiteral(reg->storeOrdinaryGAtom(atom).address);
00854 }
00855 
00856 
00857 ID InternalGroundASPSolver::createNewBodyAtom()
00858 {
00859     std::stringstream bodyPred;
00860     bodyPred << bodyAtomPrefix << bodyAtomNumber;
00861     DBGLOG(DBG, "Creating body atom " << bodyPred.str());
00862     bodyAtomNumber++;
00863     ID bodyAtom = createNewAtom(reg->getNewConstantTerm("body"));
00864     allAtoms.insert(bodyAtom.address);
00865     return bodyAtom;
00866 }
00867 
00868 
00869 std::string InternalGroundASPSolver::toString(const Set<ID>& lits)
00870 {
00871     std::stringstream ss;
00872     ss << "{";
00873     bool first = true;
00874     BOOST_FOREACH (ID lit, lits) {
00875         if (!first) ss << ", ";
00876         if ((lit.kind & ID::NAF_MASK) != 0) ss << "-";
00877         ss << lit.address;
00878         first = false;
00879     }
00880     ss << "}";
00881     return ss.str();
00882 }
00883 
00884 
00885 std::string InternalGroundASPSolver::toString(const Set<IDAddress>& lits)
00886 {
00887     std::stringstream ss;
00888     ss << "{";
00889     bool first = true;
00890     BOOST_FOREACH (IDAddress lit, lits) {
00891         if (!first) ss << ", ";
00892         ss << lit;
00893         first = false;
00894     }
00895     ss << "}";
00896     return ss.str();
00897 }
00898 
00899 
00900 std::string InternalGroundASPSolver::toString(const std::vector<IDAddress>& lits)
00901 {
00902     std::stringstream ss;
00903     ss << "{";
00904     for (std::vector<IDAddress>::const_iterator it = lits.begin(); it != lits.end(); ++it) {
00905         if (it != lits.begin()) ss << ", ";
00906         ss << *it;
00907     }
00908     ss << "}";
00909     return ss.str();
00910 }
00911 
00912 
00913 InterpretationPtr InternalGroundASPSolver::outputProjection(InterpretationConstPtr intr)
00914 {
00915 
00916     if (intr == InterpretationPtr()) {
00917         return InterpretationPtr();
00918     }
00919     else {
00920         InterpretationPtr answer = InterpretationPtr(new Interpretation(reg));
00921         answer->add(*intr);
00922         answer->bit_and(*ordinaryFactsInt);
00923         if (program.getGroundProgram().mask != InterpretationConstPtr()) {
00924             answer->getStorage() -= program.getGroundProgram().mask->getStorage();
00925         }
00926         return answer;
00927     }
00928 }
00929 
00930 
00931 InternalGroundASPSolver::InternalGroundASPSolver(ProgramCtx& c, const AnnotatedGroundProgram& p, InterpretationConstPtr frozen) : CDNLSolver(c, NogoodSet()), program(p), bodyAtomPrefix(std::string("body_")), bodyAtomNumber(0), firstmodel(true), cntDetectedUnfoundedSets(0), modelCount(0)
00932 {
00933     DBGLOG(DBG, "Internal Ground ASP Solver Init");
00934 
00935     DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidsolvertime, "Solver time");
00936     reg = ctx.registry();
00937 
00938     resizeVectors();
00939     initializeLists(frozen);
00940     computeClarkCompletion();
00941     createSingularLoopNogoods(frozen);
00942     resizeVectors();
00943     initWatchingStructures();
00944     computeDepGraph();
00945     computeStronglyConnectedComponents();
00946     initSourcePointers();
00947     setEDB();
00948 }
00949 
00950 
00951 void InternalGroundASPSolver::addProgram(const AnnotatedGroundProgram& p, InterpretationConstPtr frozen)
00952 {
00953     throw GeneralError("Internal grounder does not support incremental extension of the program");
00954 }
00955 
00961 Nogood InternalGroundASPSolver::getInconsistencyCause(InterpretationConstPtr explanationAtoms){
00962 
00963     loadAddedNogoods();
00964     if ((!getNextModel() && modelCount == 0) ||
00968         (!getNextModel() && contradictoryNogoods.size() > 0)) {
00969         if (!explanationAtoms) return Nogood(); // explanation is trivial in this case
00970 
00971         // start from the conflicting nogood
00972         int conflictNogoodIndex = *(contradictoryNogoods.begin());
00973         Nogood violatedNogood = nogoodset.getNogood(conflictNogoodIndex);
00974 
00975 #ifndef NDEBUG
00976         std::stringstream debugoutput;
00977         debugoutput << "getInconsistencyCause, current implication graph:" << std::endl << getImplicationGraphAsDotString() << std::endl;
00978         debugoutput << "getInconsistencyCause, explanation atoms: " << *explanationAtoms << std::endl;
00979         debugoutput << "getInconsistencyCause, starting from nogood: " << violatedNogood.getStringRepresentation(reg) << std::endl;
00980 #endif
00981 
00982         // resolve back to explanationAtoms
00983         std::vector<ID> removeLits;
00984         int resolveWithNogoodIndex = -1;
00985         ID resolvedLiteral = ID_FAIL;
00986         do {
00987             removeLits.clear();
00988             resolveWithNogoodIndex = -1;
00989             resolvedLiteral = ID_FAIL;
00990             // 1. check if the violated nogood contains implied literals; in this case mark for resolving
00991             // 2. check if the violated nogood contains not implied literals other than from explanationAtoms; in this case mark for removal
00992             BOOST_FOREACH (ID lit, violatedNogood) {
00993                 assert (decisionlevel[lit.address] == 0 && "found literal assigned on decisionlevel > 0");
00994                 // check if there are literals other than from explanationAtoms
00995                 if (!explanationAtoms->getFact(lit.address)) {
00996                     // if it is an implied literal, resolve with its reason, otherwise it is a fact and we remove it
00997                     if (cause[lit.address] != -1){
00998                         if (resolveWithNogoodIndex == -1){
00999                             resolveWithNogoodIndex = cause[lit.address];
01000                             resolvedLiteral = lit;
01001                         }
01002                     }else{
01003                         removeLits.push_back(lit);
01004                     }
01005                 }
01006             }
01007             // remove the literals marked for removal (actually, since removal from vectors is expensive, create a new vector but skip removed literals)
01008             Nogood newNogood;
01009             int nextRemovedLit = 0;
01010             BOOST_FOREACH (ID lit, violatedNogood){
01011                 if (nextRemovedLit < removeLits.size() && lit == removeLits[nextRemovedLit]){
01012                     nextRemovedLit++;
01013                 }else{
01014                     // keep
01015                     newNogood.insert(lit);
01016                 }
01017             }
01018             // possibly resolve
01019             if (resolveWithNogoodIndex != -1){
01020                 violatedNogood = resolve(newNogood, nogoodset.getNogood(resolveWithNogoodIndex), resolvedLiteral.address);
01021 #ifndef NDEBUG
01022                 debugoutput << "Removed facts other than explanation atoms: " << newNogood.getStringRepresentation(reg) << std::endl;
01023                 debugoutput << "Resolved with " << nogoodset.getNogood(resolveWithNogoodIndex).getStringRepresentation(reg) << ": " << violatedNogood.getStringRepresentation(reg) << std::endl;
01024 #endif
01025             }else{
01026                 violatedNogood = newNogood;
01027             }
01028         }while(removeLits.size() > 0 || resolveWithNogoodIndex != -1);
01029 
01030         // the nogood contains now only literals which have not been implied and which are from explanationAtoms
01031 #ifndef NDEBUG
01032         debugoutput << "Final explanation nogood: " << violatedNogood.getStringRepresentation(reg) << std::endl;
01033         DBGLOG(DBG, debugoutput.str());
01034 #endif
01035         return violatedNogood;
01036     }
01037     throw GeneralError("getInconsistencyCause can only be called for inconsistent instances (getNextModel() has to return NULL at first call)");
01038 }
01039 
01040 void InternalGroundASPSolver::addNogoodSet(const NogoodSet& ns, InterpretationConstPtr frozen)
01041 {
01042     throw GeneralError("Internal CDNL solver does not support incremental extension of the instance");
01043 }
01044 
01045 
01046 void InternalGroundASPSolver::restartWithAssumptions(const std::vector<ID>& assumptions)
01047 {
01048 
01049     // reset
01050     std::vector<IDAddress> toClear;
01051     bm::bvector<>::enumerator en = assignedAtoms->getStorage().first();
01052     bm::bvector<>::enumerator en_end = assignedAtoms->getStorage().end();
01053     while (en < en_end) {
01054         toClear.push_back(*en);
01055         en++;
01056     }
01057     BOOST_FOREACH (IDAddress adr, toClear) clearFact(adr);
01058     /*
01059 
01060       DBGLOG(DBG, "Resetting solver");
01061       interpretation.reset(new Interpretation(ctx.registry()));
01062       assigned.reset(new Interpretation(ctx.registry()));
01063       changed.reset(new Interpretation(ctx.registry()));
01064       currentDL = 0;
01065       exhaustedDL = 0;
01066 
01067       initWatchingStructures();
01068     */
01069     // set assumptions at DL=0
01070     DBGLOG(DBG, "Setting assumptions");
01071     BOOST_FOREACH (ID a, assumptions) {
01072         if (allAtoms.contains(a.address)) {
01073             setFact(a, 0);
01074         }
01075     }
01076 
01077     setEDB();
01078 }
01079 
01080 
01081 void InternalGroundASPSolver::addPropagator(PropagatorCallback* pb)
01082 {
01083     propagator.insert(pb);
01084 }
01085 
01086 
01087 void InternalGroundASPSolver::removePropagator(PropagatorCallback* pb)
01088 {
01089     propagator.erase(pb);
01090 }
01091 
01092 
01093 void InternalGroundASPSolver::setOptimum(std::vector<int>& optimum)
01094 {
01095     // not supported: ignore the call
01096     LOG(INFO,"InternalGroundASPSolver::setOptimum not supported!");
01097 }
01098 
01099 
01100 InterpretationPtr InternalGroundASPSolver::getNextModel()
01101 {
01102 #ifndef NDEBUG
01103     DBGLOG(DBG, "getNextModel, current implication graph:" << std::endl << getImplicationGraphAsDotString());
01104 #endif
01105 
01106     DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidsolvertime, "Solver time");
01107     Nogood violatedNogood;
01108 
01109     if (!firstmodel && complete()) {
01110         if (currentDL == 0) {
01111             return InterpretationPtr();
01112         }
01113         else {
01114             flipDecisionLiteral();
01115         }
01116     }
01117     firstmodel = false;
01118 
01119     // if set to true, the loop will run even if the interpretation is already complete
01120     bool anotherIterationEvenIfComplete = false;
01121     // (needed to check if newly added nogood (e.g. by external learners) are satisfied)
01122     while (!complete() || anotherIterationEvenIfComplete) {
01123         anotherIterationEvenIfComplete = false;
01124         if (!unitPropagation(violatedNogood)) {
01125             if (currentDL == 0) {
01126                 // no answer set
01127                 return InterpretationPtr();
01128             }
01129             else {
01130                 if (currentDL > exhaustedDL) {
01131                     DBGLOG(DBG, "Conflict analysis");
01132                     // backtrack
01133                     Nogood learnedNogood;
01134                     int k = currentDL;
01135                     analysis(violatedNogood, learnedNogood, k);
01136                     recentConflicts.push_back(addNogoodAndUpdateWatchingStructures(learnedNogood));
01137                                  // do not jump below exhausted level, this could lead to regeneration of models
01138                     currentDL = k > exhaustedDL ? k : exhaustedDL;
01139                     backtrack(currentDL);
01140                 }
01141                 else {
01142                     flipDecisionLiteral();
01143                 }
01144             }
01145         }
01146         else {
01147             Set<ID> ufs = getUnfoundedSet();
01148 
01149             if (ufs.size() > 0) {
01150                 DBGLOG(DBG, "Found UFS: " << toString(ufs));
01151                 #ifndef NDEBUG
01152                 ++cntDetectedUnfoundedSets;
01153                 #endif
01154 
01155                 Nogood loopNogood = getLoopNogood(ufs);
01156                 addNogoodAndUpdateWatchingStructures(loopNogood);
01157                 anotherIterationEvenIfComplete = true;
01158             }
01159             else {
01160                 // no ufs
01161                 DBGLOG(DBG, "No unfounded set exists");
01162 
01163                 DBGLOG(DBG, "Calling external learner");
01164                 int nogoodCount = nogoodset.getNogoodCount();
01165                 BOOST_FOREACH (PropagatorCallback* cb, propagator) {
01166                     DBGLOG(DBG, "Calling external learners with interpretation: " << *interpretation);
01167                     cb->propagate(interpretation, assignedAtoms, changedAtoms);
01168                 }
01169                 // add new nogoods
01170                 int ngc = nogoodset.getNogoodCount();
01171                 loadAddedNogoods();
01172                 if (ngc != nogoodset.getNogoodCount()) anotherIterationEvenIfComplete = true;
01173                 changedAtoms->clear();
01174 
01175                 if (nogoodset.getNogoodCount() != nogoodCount) {
01176                     DBGLOG(DBG, "Learned something");
01177                 }
01178                 else {
01179                     DBGLOG(DBG, "Did not learn anything");
01180 
01181                     if (assignedAtoms->getStorage().count() > allAtoms.size()){
01182                         std::cout << "All: ";
01183                         BOOST_FOREACH (IDAddress a, allAtoms) { std::cout << printToString<RawPrinter>(reg->ogatoms.getIDByAddress(a), reg) << " "; }
01184                         std::cout << " (" << allAtoms.size() << ")" << std::endl;
01185                     }
01186 
01187                     if (!complete()) {
01188                         // guess
01189                         currentDL++;
01190                         ID guess = getGuess();
01191                         DBGLOG(DBG, "Guess: " << litToString(guess));
01192                         decisionLiteralOfDecisionLevel[currentDL] = guess;
01193                         setFact(guess, currentDL);
01194                     }
01195                 }
01196             }
01197         }
01198     }
01199 
01200     InterpretationPtr icp = outputProjection(interpretation);
01201     modelCount++;
01202     return icp;
01203 }
01204 
01205 
01206 int InternalGroundASPSolver::getModelCount()
01207 {
01208     return modelCount;
01209 }
01210 
01211 
01212 std::string InternalGroundASPSolver::getStatistics()
01213 {
01214 
01215     #ifndef NDEBUG
01216     std::stringstream ss;
01217     ss  << CDNLSolver::getStatistics() << std::endl
01218         << "Detected unfounded sets: " << cntDetectedUnfoundedSets;
01219     return ss.str();
01220     #else
01221     std::stringstream ss;
01222     ss << "Only available in debug mode";
01223     return ss.str();
01224     #endif
01225 }
01226 
01227 
01228 std::string InternalGroundASPSolver::getImplicationGraphAsDotString(){
01229 
01230     // create debug output graph
01231     std::stringstream dot;
01232 
01233     // export implication graph
01234     dot << "digraph G { ";
01235     BOOST_FOREACH (IDAddress adr, this->allAtoms){
01236         if (!assignedAtoms->getFact(adr)) continue;
01237 
01238         dot << adr << " [label=\"" << (this->interpretation->getFact(adr) ? "" : "-") << printToString<RawPrinter>(reg->ogatoms.getIDByAddress(adr), reg) << "@" << this->decisionlevel[adr] << " ";
01239         // decision literal?
01240         if (cause[adr] == -1 && decisionlevel[adr] == 0){
01241             dot << "(fact)" << "\"]; ";
01242         }else if (cause[adr] == -1 && decisionlevel[adr] > 0){
01243             dot << "(" << (flipped[adr] ? "flipped " : "")  << "decision)" << "\"]; ";
01244         }else{
01245             const Nogood& implicant = nogoodset.getNogood(cause[adr]);
01246             dot << "(" << implicant.getStringRepresentation(reg) << ")" << "\"]; ";
01247             // add edges from implicants
01248             BOOST_FOREACH (ID id, implicant) {
01249                 if (id.address != adr){
01250                     dot << id.address << " -> " << adr << "; ";
01251                 }
01252             }
01253         }
01254     }
01255 
01256     // add conflict nogood and edges if present
01257     if (contradictoryNogoods.size() > 0) {
01258         // start from the conflicting nogood
01259         int conflictNogoodIndex = *(contradictoryNogoods.begin());
01260         Nogood violatedNogood = nogoodset.getNogood(conflictNogoodIndex);
01261         dot << "c [label=\"conflict (" << violatedNogood.getStringRepresentation(reg) << ")\"]; ";
01262         BOOST_FOREACH (ID id, violatedNogood) {
01263             dot << id.address << " -> c; ";
01264         }
01265     }
01266 
01267     dot << "}" << std::endl;
01268     return dot.str();
01269 }
01270 
01271 DLVHEX_NAMESPACE_END
01272 
01273 // vim:expandtab:ts=4:sw=4:
01274 // mode: C++
01275 // End: