dlvhex
2.5.0
|
00001 /* dlvhex -- Answer-Set Programming with external interfaces. 00002 * Copyright (C) 2005-2007 Roman Schindlauer 00003 * Copyright (C) 2006-2015 Thomas Krennwallner 00004 * Copyright (C) 2009-2016 Peter Schüller 00005 * Copyright (C) 2011-2016 Christoph Redl 00006 * Copyright (C) 2015-2016 Tobias Kaminski 00007 * Copyright (C) 2015-2016 Antonius Weinzierl 00008 * 00009 * This file is part of dlvhex. 00010 * 00011 * dlvhex is free software; you can redistribute it and/or modify it 00012 * under the terms of the GNU Lesser General Public License as 00013 * published by the Free Software Foundation; either version 2.1 of 00014 * the License, or (at your option) any later version. 00015 * 00016 * dlvhex is distributed in the hope that it will be useful, but 00017 * WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00019 * Lesser General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU Lesser General Public 00022 * License along with dlvhex; if not, write to the Free Software 00023 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 00024 * 02110-1301 USA. 00025 */ 00026 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: