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 00037 #ifdef HAVE_CONFIG_H 00038 #include "config.h" 00039 #endif 00040 00041 #include "dlvhex2/AnnotatedGroundProgram.h" 00042 #include "dlvhex2/Printer.h" 00043 #include "dlvhex2/ProgramCtx.h" 00044 #include "dlvhex2/Benchmarking.h" 00045 #include "dlvhex2/ExtSourceProperties.h" 00046 00047 #include <boost/graph/breadth_first_search.hpp> 00048 #include <boost/graph/visitors.hpp> 00049 #include <boost/graph/strong_components.hpp> 00050 #include <boost/graph/filtered_graph.hpp> 00051 00052 #include <boost/foreach.hpp> 00053 00054 DLVHEX_NAMESPACE_BEGIN 00055 00056 AnnotatedGroundProgram::AnnotatedGroundProgram() : ctx(0), groundProgram(OrdinaryASPProgram(RegistryPtr(), std::vector<ID>(), InterpretationConstPtr())), haveGrounding(false) 00057 { 00058 } 00059 00060 00061 AnnotatedGroundProgram::AnnotatedGroundProgram(ProgramCtx& ctx, const OrdinaryASPProgram& groundProgram, std::vector<ID> indexedEatoms, std::vector<ID> dependencyIDB) : 00062 ctx(&ctx), reg(ctx.registry()), groundProgram(groundProgram), indexedEatoms(indexedEatoms), haveGrounding(true), dependencyIDB(dependencyIDB) 00063 { 00064 00065 initialize(); 00066 } 00067 00068 00069 AnnotatedGroundProgram::AnnotatedGroundProgram(ProgramCtx& ctx, std::vector<ID> indexedEatoms) : 00070 ctx(&ctx), reg(ctx.registry()), groundProgram(OrdinaryASPProgram(RegistryPtr(), std::vector<ID>(), InterpretationConstPtr())), indexedEatoms(indexedEatoms), haveGrounding(false) 00071 { 00072 00073 initialize(); 00074 } 00075 00076 00077 // Incremental extension 00078 // Note: program "other" MUST NOT cyclically depend on the current program (this condition is not checked but violation harms validity of the state of this object!) 00079 void AnnotatedGroundProgram::addProgram(const AnnotatedGroundProgram& other) 00080 { 00081 00082 DBGLOG(DBG, "Adding program to AnnotatedGroundProgram"); 00083 if (haveGrounding && other.haveGrounding) { 00084 std::vector<ID> newGroundIdb = groundProgram.idb; 00085 newGroundIdb.insert(newGroundIdb.end(), other.groundProgram.idb.begin(), other.groundProgram.idb.end()); 00086 00087 InterpretationPtr newGroundEdb(new Interpretation(reg)); 00088 if (!!groundProgram.edb) newGroundEdb->add(*groundProgram.edb); 00089 if (!!other.groundProgram.edb) newGroundEdb->add(*other.groundProgram.edb); 00090 00091 InterpretationPtr newGroundMask(new Interpretation(reg)); 00092 if (!!groundProgram.mask) newGroundMask->add(*groundProgram.mask); 00093 if (!!other.groundProgram.mask) newGroundMask->add(*other.groundProgram.mask); 00094 00095 groundProgram = OrdinaryASPProgram(groundProgram.registry, newGroundIdb, newGroundEdb, groundProgram.maxint, newGroundMask); 00096 haveGrounding = true; 00097 } 00098 else { 00099 haveGrounding = false; 00100 } 00101 00102 // build a mapping of SCCs of the other program to SCCs of this program 00103 std::map<int, int> otherCompToThisComp; 00104 bm::bvector<>::enumerator en = other.programMask->getStorage().first(); 00105 bm::bvector<>::enumerator en_end = other.programMask->getStorage().end(); 00106 int thisComp; 00107 int prevCompCount = depSCC.size(); 00108 while (en < en_end) { 00109 assert(other.componentOfAtom.find(*en) != other.componentOfAtom.end() && "atom has no \"other\" component assigned"); 00110 int otherComp = other.componentOfAtom.at(*en); 00111 DBGLOG(DBG, "Mapping atom " << *en << " (" << printToString<RawPrinter>(reg->ogatoms.getIDByAddress(*en), reg) << ") in \"other\" component " << otherComp); 00112 00113 // check if the atom already occurs in this program 00114 if (componentOfAtom.find(*en) != componentOfAtom.end()) { 00115 int thisComp = componentOfAtom[*en]; 00116 // if we already mapped the atom previously, then the "this" component must be the same 00117 if (otherCompToThisComp.find(otherComp) != otherCompToThisComp.end()) { 00118 if (thisComp == otherCompToThisComp[otherComp]) { 00119 DBGLOG(DBG, "The \"other\" component was already previsouly mapped to the same \"this\" component" << (thisComp >= prevCompCount ? " (the \"this\" component was newly generated)" : " (the \"this\" component did already exist)")); 00120 } 00121 else { 00122 DBGLOG(DBG, "The \"other\" component was previsouly mapped to \"this\" component " << otherCompToThisComp[otherComp] << " but shall now be mapped to \"this\" component " << thisComp << "; violation of the criterion"); 00123 assert(false && "violation of the criterion, see description of AnnotatedGroundProgram::addProgram"); 00124 } 00125 } 00126 else { 00127 DBGLOG(DBG, "The atom occurs in component " << thisComp << "; will map \"other\" component " << otherComp << " to \"this\" component " << thisComp); 00128 otherCompToThisComp[otherComp] = thisComp; 00129 } 00130 } 00131 else { 00132 DBGLOG(DBG, "The atom does not occur in \"this\" program, will map it to a new \"this\" component " << depSCC.size()); 00133 otherCompToThisComp[otherComp] = depSCC.size(); 00134 depSCC.push_back(other.depSCC[otherComp]); 00135 headCycles.push_back(other.headCycles[otherComp]); 00136 eCycles.push_back(other.eCycles[otherComp]); 00137 programComponents.push_back(other.programComponents[otherComp]); 00138 } 00139 00140 en++; 00141 } 00142 00143 // extend mapped SCCs 00144 DBGLOG(DBG, "Extending pre-existing \"this\" components by corresponding \"other\" components"); 00145 typedef std::pair<int, int> CompMapping; 00146 BOOST_FOREACH (CompMapping m, otherCompToThisComp) { 00147 if (m.second >= prevCompCount) { 00148 DBGLOG(DBG, "Adding \"other\" component " << m.first << " to \"this\" component " << m.second); 00149 DBGLOG(DBG, "\"other\" component info:"); 00150 #ifndef NDEBUG 00151 { 00152 std::stringstream ss; 00153 BOOST_FOREACH (IDAddress adr, other.depSCC[m.first]) ss << printToString<RawPrinter>(reg->ogatoms.getIDByAddress(adr), reg); 00154 DBGLOG(DBG, other.depSCC[m.first].size() << " atoms in component vector: " << ss.str() << " (" << other.programComponents[m.first]->componentAtoms->getStorage().count() << " in bitvector: " << *other.programComponents[m.first]->componentAtoms << ")"); 00155 } 00156 #endif 00157 DBGLOG(DBG, "head cycles=" << other.headCycles[m.first]); 00158 DBGLOG(DBG, "e-cycles=" << other.eCycles[m.first]); 00159 DBGLOG(DBG, other.programComponents[m.first]->program.edb->getStorage().count() << " atoms in EDB"); 00160 if (!!other.programComponents[m.first]->program.mask) { 00161 DBGLOG(DBG, other.programComponents[m.first]->program.mask->getStorage().count() << " atoms in program mask"); 00162 } 00163 DBGLOG(DBG, "maxint=" << other.programComponents[m.first]->program.maxint); 00164 DBGLOG(DBG, "Previous \"this\" component info:"); 00165 #ifndef NDEBUG 00166 { 00167 std::stringstream ss; 00168 BOOST_FOREACH (IDAddress adr, depSCC[m.second]) ss << printToString<RawPrinter>(reg->ogatoms.getIDByAddress(adr), reg); 00169 DBGLOG(DBG, depSCC[m.second].size() << " atoms in component vector: " << ss.str() << " (" << programComponents[m.second]->componentAtoms->getStorage().count() << " in bitvector: " << *programComponents[m.second]->componentAtoms << ")"); 00170 } 00171 #endif 00172 DBGLOG(DBG, "head cycles=" << headCycles[m.second]); 00173 DBGLOG(DBG, "e-cycles=" << eCycles[m.second]); 00174 DBGLOG(DBG, programComponents[m.second]->program.edb->getStorage().count() << " atoms in EDB"); 00175 if (!!programComponents[m.second]->program.mask) { 00176 DBGLOG(DBG, programComponents[m.second]->program.mask->getStorage().count() << " atoms in program mask"); 00177 } 00178 DBGLOG(DBG, "maxint=" << programComponents[m.second]->program.maxint); 00179 depSCC[m.second].insert(other.depSCC[m.first].begin(), other.depSCC[m.first].end()); 00180 if (other.headCycles[m.first]) headCycles[m.second] = true; 00181 if (other.eCycles[m.first]) eCycles[m.second]; 00182 00183 InterpretationPtr intr(new Interpretation(reg)); 00184 intr->add(*other.programComponents[m.first]->componentAtoms); 00185 intr->add(*programComponents[m.second]->componentAtoms); 00186 programComponents[m.second]->componentAtoms = intr; 00187 00188 intr.reset(new Interpretation(reg)); 00189 intr->add(*other.programComponents[m.first]->program.edb); 00190 intr->add(*programComponents[m.second]->program.edb); 00191 programComponents[m.second]->program.edb = intr; 00192 00193 intr.reset(new Interpretation(reg)); 00194 if (!!other.programComponents[m.first]->program.mask) intr->add(*other.programComponents[m.first]->program.mask); 00195 if (!!programComponents[m.second]->program.mask) intr->add(*programComponents[m.second]->program.mask); 00196 programComponents[m.second]->program.mask= intr; 00197 00198 programComponents[m.second]->program.idb.insert(programComponents[m.second]->program.idb.begin(), other.programComponents[m.first]->program.idb.begin(), other.programComponents[m.first]->program.idb.end()); 00199 00200 if (programComponents[m.second]->program.maxint > other.programComponents[m.first]->program.maxint) other.programComponents[m.first]->program.maxint = programComponents[m.second]->program.maxint; 00201 DBGLOG(DBG, "New \"this\" component info:"); 00202 #ifndef NDEBUG 00203 { 00204 std::stringstream ss; 00205 BOOST_FOREACH (IDAddress adr, depSCC[m.second]) ss << printToString<RawPrinter>(reg->ogatoms.getIDByAddress(adr), reg); 00206 DBGLOG(DBG, depSCC[m.second].size() << " atoms in component vector: " << ss.str() << " (" << programComponents[m.second]->componentAtoms->getStorage().count() << " in bitvector: " << *programComponents[m.second]->componentAtoms << ")"); 00207 } 00208 #endif 00209 DBGLOG(DBG, "head cycles=" << headCycles[m.second]); 00210 DBGLOG(DBG, "e-cycles=" << eCycles[m.second]); 00211 DBGLOG(DBG, programComponents[m.second]->program.edb->getStorage().count() << " atoms in EDB"); 00212 if (!!programComponents[m.second]->program.mask) { 00213 DBGLOG(DBG, programComponents[m.second]->program.mask->getStorage().count() << " atoms in program mask"); 00214 } 00215 DBGLOG(DBG, "maxint=" << programComponents[m.second]->program.maxint); 00216 } 00217 } 00218 DBGLOG(DBG, "Indexing atoms from new program part"); 00219 typedef const boost::unordered_map<IDAddress, int>::value_type ComponentOfAtomPair; 00220 BOOST_FOREACH (ComponentOfAtomPair pair, other.componentOfAtom) { 00221 componentOfAtom[pair.first] = otherCompToThisComp[pair.second]; 00222 } 00223 00224 // copy all indexed external atom (duplications do not matter) including EA-masks 00225 indexedEatoms.insert(indexedEatoms.end(), other.indexedEatoms.begin(), other.indexedEatoms.end()); 00226 eaMasks.insert(eaMasks.end(), other.eaMasks.begin(), other.eaMasks.end()); 00227 00228 // extend aux mapping 00229 typedef const boost::unordered_map<IDAddress, std::vector<ID> >::value_type AuxToEAPair; 00230 BOOST_FOREACH (AuxToEAPair pair, other.auxToEA) { 00231 DBGLOG(DBG, "Copying " << pair.second.size() << " auxToEA mapping infos of auxiliary " << pair.first); 00232 auxToEA[pair.first].insert(auxToEA[pair.first].end(), pair.second.begin(), pair.second.end()); 00233 } 00234 00235 // copy support sets 00236 if (!!other.supportSets) { 00237 if (!supportSets) supportSets = SimpleNogoodContainerPtr(new SimpleNogoodContainer()); 00238 for (int i = 0; i < other.supportSets->getNogoodCount(); ++i) { 00239 supportSets->addNogood(other.supportSets->getNogood(i)); 00240 } 00241 } 00242 00243 // extend indices of cyclic rules 00244 InterpretationPtr newHeadCyclicRules(new Interpretation(reg)); 00245 newHeadCyclicRules->add(*headCyclicRules); 00246 newHeadCyclicRules->add(*other.headCyclicRules); 00247 headCyclicRules = newHeadCyclicRules; 00248 00249 eaMasks.insert(eaMasks.end(), other.eaMasks.begin(), other.eaMasks.end()); 00250 headCyclesTotal |= other.headCyclesTotal; 00251 eCyclesTotal |= other.eCyclesTotal; 00252 if (!!programMask && !! other.programMask) programMask->add(*other.programMask); 00253 00254 createEAMasks(); 00255 } 00256 00257 00258 const AnnotatedGroundProgram& 00259 AnnotatedGroundProgram::operator=( 00260 const AnnotatedGroundProgram& other) 00261 { 00262 reg = other.reg; 00263 groundProgram = other.groundProgram; 00264 haveGrounding = other.haveGrounding; 00265 indexedEatoms = other.indexedEatoms; 00266 eaMasks = other.eaMasks; 00267 auxToEA = other.auxToEA; 00268 programMask = other.programMask; 00269 depNodes = other.depNodes; 00270 depGraph = other.depGraph; 00271 depSCC = other.depSCC; 00272 componentOfAtom = other.componentOfAtom; 00273 externalEdges = other.externalEdges; 00274 headCycles = other.headCycles; 00275 headCyclicRules = other.headCyclicRules; 00276 eCycles = other.eCycles; 00277 programComponents = other.programComponents; 00278 headCyclesTotal = other.headCyclesTotal; 00279 eCyclesTotal = other.eCyclesTotal; 00280 supportSets = other.supportSets; 00281 return *this; 00282 } 00283 00284 00285 void AnnotatedGroundProgram::createProgramMask() 00286 { 00287 00288 // create mask of all atoms in the program 00289 programMask = InterpretationPtr(new Interpretation(reg)); 00290 programMask->add(*groundProgram.edb); 00291 BOOST_FOREACH (ID ruleID, groundProgram.idb) { 00292 const Rule& rule = reg->rules.getByID(ruleID); 00293 BOOST_FOREACH (ID h, rule.head) programMask->setFact(h.address); 00294 BOOST_FOREACH (ID b, rule.body) if (!b.isExternalAuxiliary()) programMask->setFact(b.address); 00295 } 00296 } 00297 00298 00299 void AnnotatedGroundProgram::createEAMasks() 00300 { 00301 eaMasks.resize(indexedEatoms.size()); 00302 int eaIndex = 0; 00303 BOOST_FOREACH (ID eatom, indexedEatoms) { 00304 // create an EAMask for each inner external atom 00305 eaMasks[eaIndex] = boost::shared_ptr<ExternalAtomMask>(new ExternalAtomMask); 00306 ExternalAtomMask& eaMask = *eaMasks[eaIndex]; 00307 eaMask.setEAtom(*ctx, reg->eatoms.getByID(eatom), groundProgram.idb); 00308 eaMask.updateMask(); 00309 eaIndex++; 00310 } 00311 } 00312 00313 00314 void AnnotatedGroundProgram::mapAuxToEAtoms() 00315 { 00316 00317 int eaIndex = 0; 00318 BOOST_FOREACH (ID eatom, indexedEatoms) { 00319 // create an EAMask for each inner external atom 00320 ExternalAtomMask& eaMask = *eaMasks[eaIndex]; 00321 // we already did this in createEAMasks 00322 //eaMask.setEAtom(*ctx, reg->eatoms.getByID(eatom), groundProgram.idb); 00323 //eaMask.updateMask(); 00324 00325 // map external auxiliaries back to their external atoms 00326 bm::bvector<>::enumerator en = eaMask.mask()->getStorage().first(); 00327 bm::bvector<>::enumerator en_end = eaMask.mask()->getStorage().end(); 00328 while (en < en_end) { 00329 if (reg->ogatoms.getIDByAddress(*en).isExternalAuxiliary()) { 00330 DBGLOG(DBG, "Auxiliary " << *en << " maps to " << indexedEatoms[eaIndex]); 00331 auxToEA[*en].push_back(indexedEatoms[eaIndex]); 00332 } 00333 en++; 00334 } 00335 eaIndex++; 00336 } 00337 } 00338 00339 00340 void AnnotatedGroundProgram::setIndexEAtoms(std::vector<ID> indexedEatoms) 00341 { 00342 this->indexedEatoms = indexedEatoms; 00343 00344 initialize(); 00345 } 00346 00347 00348 void AnnotatedGroundProgram::initialize() 00349 { 00350 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"AnnotatedGroundProg init"); 00351 00352 headCyclicRules = InterpretationPtr(new Interpretation(reg)); 00353 00354 eaMasks.resize(0); 00355 if (haveGrounding) createProgramMask(); 00356 createEAMasks(); 00357 mapAuxToEAtoms(); 00358 if (haveGrounding) computeAtomDependencyGraph(); 00359 if (haveGrounding) computeAdditionalDependencies(); 00360 if (haveGrounding) computeStronglyConnectedComponents(); 00361 if (haveGrounding) computeHeadCycles(); 00362 if (haveGrounding) computeECycles(); 00363 00364 #ifndef NDEBUG 00365 if (haveGrounding) { 00366 std::stringstream programstring; 00367 { 00368 RawPrinter printer(programstring, reg); 00369 if (groundProgram.edb) programstring << "EDB: " << *groundProgram.edb << std::endl; 00370 programstring << "IDB:" << std::endl; 00371 BOOST_FOREACH (ID ruleId, groundProgram.idb) { 00372 printer.print(ruleId); 00373 programstring << std::endl; 00374 } 00375 } 00376 00377 std::stringstream sccstring; 00378 { 00379 RawPrinter printer(sccstring, reg); 00380 int sai = 0; 00381 BOOST_FOREACH (std::set<IDAddress> sa, depSCC) { 00382 sccstring << "{ "; 00383 bool first = true; 00384 BOOST_FOREACH (IDAddress ida, sa) { 00385 if (!first) sccstring << ", "; 00386 first = false; 00387 printer.print(reg->ogatoms.getIDByAddress(ida)); 00388 } 00389 sccstring << " } (HC: " << headCycles[sai] << ", EC: " << eCycles[sai] << ") "; 00390 sai++; 00391 } 00392 } 00393 00394 DBGLOG(DBG, "Program:" << std::endl << programstring.str() << std::endl << "has SCC-decomposition: " << sccstring.str()); 00395 } 00396 #endif 00397 } 00398 00399 00400 void AnnotatedGroundProgram::computeAtomDependencyGraph() 00401 { 00402 00403 // construct atom dependency graph 00404 DBGLOG(DBG, "Constructing atom dependency graph for " << groundProgram.idb.size() << " rules"); 00405 bm::bvector<>::enumerator en = groundProgram.edb->getStorage().first(); 00406 bm::bvector<>::enumerator en_end = groundProgram.edb->getStorage().end(); 00407 while (en < en_end) { 00408 if (depNodes.find(*en) == depNodes.end()) depNodes[*en] = boost::add_vertex(*en, depGraph); 00409 en++; 00410 } 00411 BOOST_FOREACH (ID ruleID, groundProgram.idb) { 00412 const Rule& rule = reg->rules.getByID(ruleID); 00413 00414 BOOST_FOREACH (ID h, rule.head) { 00415 if (depNodes.find(h.address) == depNodes.end()) depNodes[h.address] = boost::add_vertex(h.address, depGraph); 00416 } 00417 BOOST_FOREACH (ID b, rule.body) { 00418 if (depNodes.find(b.address) == depNodes.end() && !b.isExternalAuxiliary()) depNodes[b.address] = boost::add_vertex(b.address, depGraph); 00419 } 00420 00421 // add an arc from all head atoms to all positive body literals 00422 // literals in weight rules always count as positive body atoms, even if they are default negated (because the weighted body as a whole is positive) 00423 DBGLOG(DBG, "Adding ordinary edges"); 00424 BOOST_FOREACH (ID h, rule.head) { 00425 BOOST_FOREACH (ID b, rule.body) { 00426 if ((!b.isNaf() || ruleID.isWeightRule()) && !b.isExternalAuxiliary()) { 00427 DBGLOG(DBG, "Adding dependency from " << h.address << " to " << b.address); 00428 boost::add_edge(depNodes[h.address], depNodes[b.address], depGraph); 00429 } 00430 } 00431 } 00432 00433 // add an arc from all head atoms to atoms which are input to some external atom in the rule body 00434 DBGLOG(DBG, "Adding e-edges"); 00435 BOOST_FOREACH (ID b, rule.body) { 00436 if (b.isExternalAuxiliary()) { 00437 BOOST_FOREACH (ID eaID, auxToEA[b.address]) { 00438 const ExternalAtom& ea = reg->eatoms.getByID(eaID); 00439 const ExtSourceProperties& prop = ea.getExtSourceProperties(); 00440 00441 ea.updatePredicateInputMask(); 00442 bm::bvector<>::enumerator en = ea.getPredicateInputMask()->getStorage().first(); 00443 bm::bvector<>::enumerator en_end = ea.getPredicateInputMask()->getStorage().end(); 00444 while (en < en_end) { 00445 if (depNodes.find(*en) == depNodes.end()) depNodes[*en] = boost::add_vertex(*en, depGraph); 00446 00447 if (ctx->config.getOption("FLPDecisionCriterionEM")) { 00448 const OrdinaryAtom& oatom = ctx->registry()->ogatoms.getByAddress(*en); 00449 bool relevant = true; 00450 for (int i = 0; i < ea.inputs.size(); ++i) { 00451 if (oatom.tuple[0] == ea.inputs[i] && (!b.isNaf() && prop.isAntimonotonic(i) || b.isNaf() && prop.isMonotonic(i))) { 00452 relevant = false; 00453 break; 00454 } 00455 } 00456 if (!relevant) { 00457 DLVHEX_BENCHMARK_REGISTER_AND_COUNT(siddc, "UFS dec. c. for mon./antim.", 1); 00458 en++; 00459 continue; 00460 } 00461 } 00462 00463 BOOST_FOREACH (ID h, rule.head) { 00464 if (!h.isExternalAuxiliary()) { 00465 DBGLOG(DBG, "Adding dependency from " << h.address << " to " << *en); 00466 boost::add_edge(depNodes[h.address], depNodes[*en], depGraph); 00467 externalEdges.push_back(std::pair<IDAddress, IDAddress>(h.address, *en)); 00468 } 00469 } 00470 en++; 00471 } 00472 } 00473 } 00474 } 00475 } 00476 } 00477 00478 00479 void AnnotatedGroundProgram::computeAdditionalDependencies() 00480 { 00481 00482 if (dependencyIDB.size() == 0) return; 00483 00484 // Construct a nonground atom dependency graph 00485 // Note: This graph is of a different kind from the one used in the very first HEX algorithm (which is still somewhere in the code) as it uses only positive and a different kind of external dependencies 00486 DBGLOG(DBG, "Constructing nonground atom dependency graph for " << dependencyIDB.size() << " rules and EDB " << *groundProgram.edb); 00487 typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, ID> NongroundGraph; 00488 typedef std::pair<ID, Node> Pair; 00489 NongroundGraph nongroundDepGraph; 00490 std::map<ID, Node> nongroundDepNodes; 00491 bm::bvector<>::enumerator en = groundProgram.edb->getStorage().first(); 00492 bm::bvector<>::enumerator en_end = groundProgram.edb->getStorage().end(); 00493 while (en < en_end) { 00494 DBGLOG(DBG, "Retrieving ground atom " << *en); 00495 ID id = reg->ogatoms.getIDByAddress(*en); 00496 if (nongroundDepNodes.find(id) == nongroundDepNodes.end()) nongroundDepNodes[id] = boost::add_vertex(id, nongroundDepGraph); 00497 en++; 00498 } 00499 DBGLOG(DBG, "Analyzing IDB"); 00500 std::vector<std::pair<ID, ID> > nongroundExternalEdges; 00501 BOOST_FOREACH (ID ruleID, dependencyIDB) { 00502 const Rule& rule = reg->rules.getByID(ruleID); 00503 BOOST_FOREACH (ID h, rule.head) { 00504 if (nongroundDepNodes.find(h) == nongroundDepNodes.end()) nongroundDepNodes[h] = boost::add_vertex(h, nongroundDepGraph); 00505 } 00506 BOOST_FOREACH (ID b, rule.body) { 00507 if (nongroundDepNodes.find(ID::atomFromLiteral(b)) == nongroundDepNodes.end() && b.isOrdinaryAtom()) nongroundDepNodes[ID::atomFromLiteral(b)] = boost::add_vertex(ID::atomFromLiteral(b), nongroundDepGraph); 00508 } 00509 00510 // add an arc from all head atoms to all positive body literals 00511 // literals in weight rules always count as positive body atoms, even if they are default negated (because the weighted body as a whole is positive) 00512 DBGLOG(DBG, "Adding ordinary edges"); 00513 BOOST_FOREACH (ID h, rule.head) { 00514 BOOST_FOREACH (ID b, rule.body) { 00515 if ((!b.isNaf() || ruleID.isWeightRule()) && b.isOrdinaryAtom()) { 00516 DBGLOG(DBG, "Adding dependency from " << h << " to " << b); 00517 boost::add_edge(nongroundDepNodes[h], nongroundDepNodes[ID::atomFromLiteral(b)], nongroundDepGraph); 00518 } 00519 } 00520 } 00521 00522 // add an arc from all head atoms to atoms which are input to some external atom in the rule body 00523 DBGLOG(DBG, "Adding e-edges"); 00524 BOOST_FOREACH (ID b, rule.body) { 00525 if (b.isExternalAtom()) { 00526 const ExternalAtom& ea = reg->eatoms.getByID(b); 00527 const ExtSourceProperties& prop = ea.getExtSourceProperties(); 00528 ea.updatePredicateInputMask(); 00529 // for all (nonground) atoms over a predicate parameter 00530 for (int i = 0; i < ea.inputs.size(); ++i) { 00531 if (ea.pluginAtom->getInputType(i) == PluginAtom::PREDICATE) { 00532 // polarity check 00533 if (ctx->config.getOption("FLPDecisionCriterionEM") && (!b.isNaf() && prop.isAntimonotonic(i) || b.isNaf() && prop.isMonotonic(i))) { 00534 DLVHEX_BENCHMARK_REGISTER_AND_COUNT(siddc, "UFS decision c. for mon./antim. applies", 1); 00535 continue; 00536 } 00537 00538 BOOST_FOREACH (Pair p, nongroundDepNodes) { 00539 const OrdinaryAtom& at = reg->lookupOrdinaryAtom(p.first); 00540 // check if this nonground atom specifies input to the external atom 00541 if (at.tuple[0] == ea.inputs[i]) { 00542 // add dependency from all head atoms of this rule to the input atom 00543 BOOST_FOREACH (ID h, rule.head) { 00544 DBGLOG(DBG, "Adding dependency from " << h << " to " << p.first); 00545 boost::add_edge(nongroundDepNodes[h], nongroundDepNodes[p.first], nongroundDepGraph); 00546 nongroundExternalEdges.push_back(std::pair<ID, ID>(h, p.first)); 00547 } 00548 } 00549 } 00550 } 00551 } 00552 } 00553 } 00554 } 00555 00556 // for all pairs of distinct nonground atoms we also need unification dependencies! (this is different from the ground case) 00557 DBGLOG(DBG, "Adding unification edges"); 00558 BOOST_FOREACH (Pair p1, nongroundDepNodes) { 00559 BOOST_FOREACH (Pair p2, nongroundDepNodes) { 00560 if (p1.first != p2.first && p1.first.isOrdinaryNongroundAtom() && p2.first.isOrdinaryNongroundAtom()) { 00561 const OrdinaryAtom& at1 = reg->lookupOrdinaryAtom(p1.first); 00562 const OrdinaryAtom& at2 = reg->lookupOrdinaryAtom(p2.first); 00563 if (at1.unifiesWith(at2)) { 00564 DBGLOG(DBG, "Adding unification dependency from " << p1.first << " to " << p2.first); 00565 boost::add_edge(nongroundDepNodes[p1.first], nongroundDepNodes[p2.first], nongroundDepGraph); 00566 } 00567 } 00568 } 00569 } 00570 00571 // compute SCC decomposition of the nonground graph 00572 DBGLOG(DBG, "Computing SCC decomposition"); 00573 std::vector<int> nongroundComponentMap(nongroundDepNodes.size()); 00574 int num = boost::strong_components(nongroundDepGraph, boost::make_iterator_property_map(nongroundComponentMap.begin(), get(boost::vertex_index, nongroundDepGraph))); 00575 00576 // create for each SCC an interpretation of its nonground atoms 00577 std::vector<InterpretationPtr> nongroundDepSCC(num, InterpretationPtr()); 00578 Node nodeNr = 0; 00579 BOOST_FOREACH (int componentOfNode, nongroundComponentMap) { 00580 if (!nongroundDepSCC[componentOfNode]) nongroundDepSCC[componentOfNode] = InterpretationPtr(new Interpretation(reg)); 00581 00582 // since "nonground atoms" can actually be strictly nonground or ground, taking only the address part would cause confusion; by convention we add the number of ground atoms in the registry to nonground addresses 00583 if (nongroundDepGraph[nodeNr].isOrdinaryGroundAtom()) { 00584 nongroundDepSCC[componentOfNode]->setFact(nongroundDepGraph[nodeNr].address + reg->ogatoms.getSize()); 00585 } 00586 else { 00587 assert (nongroundDepGraph[nodeNr].isOrdinaryNongroundAtom() && "atom is not ordinary"); 00588 nongroundDepSCC[componentOfNode]->setFact(nongroundDepGraph[nodeNr].address); 00589 } 00590 nodeNr++; 00591 } 00592 00593 // determine for each nonground SCC if it contains e-cycles 00594 std::vector<bool> nongroundDepSCCECycle(nongroundDepSCC.size(), false); 00595 for (uint32_t comp = 0; comp < nongroundDepSCC.size(); ++comp) { 00596 00597 // check for each e-edge x -> y nonground atoms x and y are both this component; if yes, then there is a cycle 00598 typedef std::pair<ID, ID> Edge; 00599 BOOST_FOREACH (Edge e, nongroundExternalEdges) { 00600 assert(e.first.isOrdinaryAtom() && "atom is not ordinary"); 00601 assert(e.second.isOrdinaryAtom() && "atom is not ordinary"); 00602 int n1 = (e.first.isOrdinaryGroundAtom() ? e.first.address + reg->ogatoms.getSize(): e.first.address); 00603 int n2 = (e.second.isOrdinaryGroundAtom() ? e.second.address + reg->ogatoms.getSize(): e.second.address); 00604 if (nongroundDepSCC[comp]->getFact(n1) && nongroundDepSCC[comp]->getFact(n2)) { 00605 // yes, there is a cycle 00606 nongroundDepSCCECycle[comp] = true; 00607 break; 00608 } 00609 } 00610 } 00611 00612 DBGLOG(DBG, "Nonground atoms in SCCs:"); 00613 for (int i = 0; i < nongroundDepSCC.size(); ++i) { 00614 DBGLOG(DBG, "SCC " << i << ": component " << (nongroundDepSCCECycle[i] ? "contains" : "does not contain") << " an e-cycle and consists of " << nongroundDepSCC[i]->getStorage().count() << " atoms"); 00615 } 00616 00617 // Now enrich the ground graph using the information from the nonground graph. 00618 // For this, check for each pair of ground atoms if they unify with atoms from the same SCC of the nonground graph s.t. the two atoms are either different or the same with a reflexive connection. 00619 // Step 1: Build for each atom a in the ground graph the set of nonground atoms N(a) it unifies with 00620 typedef std::pair<IDAddress, Node> GPair; 00621 std::vector<InterpretationPtr> unifiesWith; 00622 DBGLOG(DBG, "depNodes.size()=" << depNodes.size() << ", size of programMask=" << programMask->getStorage().count()); 00623 BOOST_FOREACH (GPair gp, depNodes) { 00624 DBGLOG(DBG, "Building set of nonground atoms for ground atom " << gp.first); 00625 BOOST_FOREACH (Pair p, nongroundDepNodes) { 00626 const OrdinaryAtom& gAt = reg->ogatoms.getByAddress(gp.first); 00627 const OrdinaryAtom& nAt = reg->lookupOrdinaryAtom(p.first); 00628 if (gAt.unifiesWith(nAt)) { 00629 if (unifiesWith.size() <= gp.first) { 00630 unifiesWith.resize(gp.first + 1, InterpretationPtr()); 00631 } 00632 if (!unifiesWith[gp.first]) unifiesWith[gp.first] = InterpretationPtr(new Interpretation(reg)); 00633 00634 // as above, if p.first is actually ground we add the number of nonground atoms in the registry 00635 if (p.first.isOrdinaryGroundAtom()) { 00636 unifiesWith[gp.first]->setFact(p.first.address + reg->ogatoms.getSize()); 00637 } 00638 else { 00639 assert (p.first.isOrdinaryNongroundAtom() && "atom is not ordinary"); 00640 unifiesWith[gp.first]->setFact(p.first.address); 00641 } 00642 } 00643 } 00644 } 00645 00646 // Step 2: For each pair of ground atoms (a1,a2) and SCC S of the nonground graph: check if S intersects both with N(a1) and N(a2) 00647 bm::bvector<>::enumerator en1 = programMask->getStorage().first(); 00648 bm::bvector<>::enumerator en_end1 = programMask->getStorage().end(); 00649 while (en1 < en_end1) { 00650 bm::bvector<>::enumerator en2 = programMask->getStorage().first(); 00651 bm::bvector<>::enumerator en_end2 = programMask->getStorage().end(); 00652 IDAddress at1adr = *en1; 00653 while (en2 < en_end2) { 00654 IDAddress at2adr = *en2; 00655 if (at1adr != at2adr) { 00656 // if they are already dependent then there is no need for another check 00657 if (boost::edge(depNodes[at1adr], depNodes[at2adr], depGraph).second) { 00658 DBGLOG(DBG, "Ground atoms " << at1adr << " and " << at2adr << " are already dependent, skipping check"); 00659 } 00660 else { 00661 DBGLOG(DBG, "Checking if ground atoms " << at1adr << " and " << at2adr << " are dependent using nonground information"); 00662 for (int i = 0; i < num; ++i) { 00663 DBGLOG(DBG, "SCC " << i << " contains " << nongroundDepSCC[i]->getStorage().count() << " nonground atoms, ptr=" << nongroundDepSCC[i]); 00664 if (!!nongroundDepSCC[i] && at1adr < unifiesWith.size() && at2adr < unifiesWith.size() && !!unifiesWith[at1adr] && !!unifiesWith[at2adr]) { 00665 DBGLOG(DBG, "Ground atom 1 unifies with " << (nongroundDepSCC[i]->getStorage() & unifiesWith[at1adr]->getStorage()).count() << " atoms in this SCC"); 00666 DBGLOG(DBG, "Ground atom 2 unifies with " << (nongroundDepSCC[i]->getStorage() & unifiesWith[at2adr]->getStorage()).count() << " atoms in this SCC"); 00667 if ((nongroundDepSCC[i]->getStorage() & unifiesWith[at1adr]->getStorage()).count() > 0 && 00668 (nongroundDepSCC[i]->getStorage() & unifiesWith[at2adr]->getStorage()).count() > 0) { 00669 bool dep = false; 00670 DBGLOG(DBG, "Checking if the atoms of the intersection of the SCC with N(a1) and the intersection with N(a2) differ in at least one atom"); 00671 if ((nongroundDepSCC[i]->getStorage() & (unifiesWith[at1adr]->getStorage() - unifiesWith[at2adr]->getStorage())).count() > 0 && 00672 (nongroundDepSCC[i]->getStorage() & (unifiesWith[at2adr]->getStorage() - unifiesWith[at1adr]->getStorage())).count() > 0) { 00673 DBGLOG(DBG, "Yes"); 00674 dep = true; 00675 } 00676 else { 00677 DBGLOG(DBG, "No: Checking if one of the SCC's atoms which unified both with a1 and a2 is reflexive"); 00678 Interpretation::Storage st = (nongroundDepSCC[i]->getStorage() & unifiesWith[at1adr]->getStorage() & unifiesWith[at2adr]->getStorage()); 00679 bm::bvector<>::enumerator en = st.first(); 00680 bm::bvector<>::enumerator en_end = st.end(); 00681 while (en < en_end) { 00682 Node cn = nongroundDepNodes[*en < reg->ogatoms.getSize() ? reg->ogatoms.getIDByAddress(*en) : reg->onatoms.getIDByAddress(*en - reg->ogatoms.getSize())]; 00683 if (boost::edge(cn, cn, nongroundDepGraph).second) { 00684 DBGLOG(DBG, "Yes"); 00685 dep = true; 00686 break; 00687 } 00688 en++; 00689 } 00690 } 00691 if (dep) { 00692 DBGLOG(DBG, "Ground atoms " << at1adr << " and " << at2adr << " are dependent using nonground information"); 00693 DBGLOG(DBG, "Adding dependency from " << at1adr << " to " << at2adr << (nongroundDepSCCECycle[i] ? " (this is an e-edge)" : " (this is an ordinary edge)")); 00694 boost::add_edge(depNodes[at1adr], depNodes[at2adr], depGraph); 00695 if (nongroundDepSCCECycle[i]) { 00696 externalEdges.push_back(std::pair<IDAddress, IDAddress>(at1adr, at2adr)); 00697 } 00698 break; 00699 } 00700 else { 00701 DBGLOG(DBG, "Ground atoms " << at1adr << " and " << at2adr << " do not depend on each other because they unify only with the same non-reflexive atom in the SCC"); 00702 } 00703 } 00704 } 00705 } 00706 } 00707 } 00708 en2++; 00709 } 00710 en1++; 00711 } 00712 } 00713 00714 00715 void AnnotatedGroundProgram::computeStronglyConnectedComponents() 00716 { 00717 00718 // find strongly connected components in the dependency graph 00719 DBGLOG(DBG, "Computing strongly connected components"); 00720 std::vector<int> componentMap(depNodes.size()); 00721 int num = boost::strong_components(depGraph, boost::make_iterator_property_map(componentMap.begin(), get(boost::vertex_index, depGraph))); 00722 00723 // translate into real map 00724 depSCC = std::vector<std::set<IDAddress> >(num); 00725 Node nodeNr = 0; 00726 00727 BOOST_FOREACH (int componentOfNode, componentMap) { 00728 depSCC[componentOfNode].insert(depGraph[nodeNr]); 00729 componentOfAtom[depGraph[nodeNr]] = componentOfNode; 00730 nodeNr++; 00731 } 00732 #ifndef NDEBUG 00733 for (uint32_t comp = 0; comp < depSCC.size(); ++comp) { 00734 std::stringstream ss; 00735 bool first = true; 00736 BOOST_FOREACH (IDAddress ida, depSCC[comp]) { 00737 if (!first) ss << ", "; 00738 first = false; 00739 ss << ida; 00740 } 00741 DBGLOG(DBG, "Component " << comp << ": " << ss.str()); 00742 } 00743 #endif 00744 00745 // partition the program according to the strongly connected components 00746 DBGLOG(DBG, "Partitioning program"); 00747 std::map<IDAddress, std::vector<ID> > rulesWithHeadAtom; 00748 BOOST_FOREACH (ID ruleID, groundProgram.idb) { 00749 const Rule& rule = reg->rules.getByID(ruleID); 00750 BOOST_FOREACH (ID h, rule.head) { 00751 rulesWithHeadAtom[h.address].push_back(ruleID); 00752 } 00753 } 00754 for (uint32_t comp = 0; comp < depSCC.size(); ++comp) { 00755 OrdinaryASPProgram componentProgram(reg, std::vector<ID>(), groundProgram.edb); 00756 InterpretationPtr componentAtoms = InterpretationPtr(new Interpretation(reg)); 00757 ProgramComponentPtr currentComp(new ProgramComponent(componentAtoms, componentProgram)); 00758 00759 // set all atoms of this component 00760 BOOST_FOREACH (IDAddress ida, depSCC[comp]) { 00761 componentAtoms->setFact(ida); 00762 } 00763 DBGLOG(DBG, "Partition " << comp << ": " << *componentAtoms); 00764 00765 // compute the program partition 00766 bm::bvector<>::enumerator en = componentAtoms->getStorage().first(); 00767 bm::bvector<>::enumerator en_end = componentAtoms->getStorage().end(); 00768 while (en < en_end) { 00769 BOOST_FOREACH (ID ruleID, rulesWithHeadAtom[*en]) { 00770 #ifndef NDEBUG 00771 std::stringstream programstring; 00772 RawPrinter printer(programstring, reg); 00773 printer.print(ruleID); 00774 DBGLOG(DBG, programstring.str()); 00775 #endif 00776 00777 currentComp->program.idb.push_back(ruleID); 00778 } 00779 en++; 00780 } 00781 00782 programComponents.push_back(currentComp); 00783 } 00784 } 00785 00786 00787 void AnnotatedGroundProgram::computeHeadCycles() 00788 { 00789 00790 // check if the components contain head-cycles 00791 DBGLOG(DBG, "Computing head-cycles of components"); 00792 headCyclesTotal = false; 00793 for (uint32_t comp = 0; comp < depSCC.size(); ++comp) { 00794 int hcf = true; 00795 BOOST_FOREACH (ID ruleID, programComponents[comp]->program.idb) { 00796 const Rule& rule = reg->rules.getByID(ruleID); 00797 int intersectionCount = 0; 00798 BOOST_FOREACH (ID h, rule.head) { 00799 // if (std::find(depSCC[comp].begin(), depSCC[comp].end(), h.address) != depSCC[comp].end()){ 00800 if (programComponents[comp]->componentAtoms->getFact(h.address)) { 00801 intersectionCount++; 00802 } 00803 if (intersectionCount >= 2) break; 00804 } 00805 if (intersectionCount >= 2) { 00806 hcf = false; 00807 break; 00808 } 00809 } 00810 headCycles.push_back(!hcf); 00811 headCyclesTotal |= headCycles[headCycles.size() - 1]; 00812 DBGLOG(DBG, "Component " << comp << ": " << !hcf); 00813 00814 if (!hcf) { 00815 // all rules in the component are head-cyclic 00816 BOOST_FOREACH (ID ruleID, programComponents[comp]->program.idb) { 00817 headCyclicRules->setFact(ruleID.address); 00818 } 00819 } 00820 } 00821 } 00822 00823 00824 void AnnotatedGroundProgram::computeECycles() 00825 { 00826 00827 DBGLOG(DBG, "Computing e-cycles of components"); 00828 00829 if (ctx->config.getOption("LegacyECycleDetection")) { 00830 eCyclesTotal = false; 00831 for (uint32_t comp = 0; comp < depSCC.size(); ++comp) { 00832 00833 // check for each e-edge x -> y if there is a path from y to x 00834 // if yes, then y is a cyclic predicate input 00835 InterpretationPtr cyclicInputAtoms = InterpretationPtr(new Interpretation(reg)); 00836 typedef std::pair<IDAddress, IDAddress> Edge; 00837 BOOST_FOREACH (Edge e, externalEdges) { 00838 if (!programComponents[comp]->componentAtoms->getFact(e.first)) continue; 00839 if (!programComponents[comp]->componentAtoms->getFact(e.second)) continue; 00840 00841 std::vector<Graph::vertex_descriptor> reachable; 00842 boost::breadth_first_search(depGraph, depNodes[e.second], 00843 boost::visitor( 00844 boost::make_bfs_visitor( 00845 boost::write_property( 00846 boost::identity_property_map(), 00847 std::back_inserter(reachable), 00848 boost::on_discover_vertex())))); 00849 00850 if (std::find(reachable.begin(), reachable.end(), depNodes[e.first]) != reachable.end()) { 00851 // yes, there is a cycle 00852 cyclicInputAtoms->setFact(e.second); 00853 } 00854 } 00855 eCycles.push_back(cyclicInputAtoms->getStorage().count() > 0); 00856 eCyclesTotal |= eCycles[eCycles.size() - 1]; 00857 00858 #ifndef NDEBUG 00859 std::stringstream ss; 00860 bool first = true; 00861 bm::bvector<>::enumerator en = cyclicInputAtoms->getStorage().first(); 00862 bm::bvector<>::enumerator en_end = cyclicInputAtoms->getStorage().end(); 00863 while (en < en_end) { 00864 if (!first) ss << ", "; 00865 first = false; 00866 ss << *en; 00867 en++; 00868 } 00869 if (cyclicInputAtoms->getStorage().count() > 0) { 00870 DBGLOG(DBG, "Component " << comp << ": 1 with cyclic input atoms " << ss.str()); 00871 } 00872 else { 00873 DBGLOG(DBG, "Component " << comp << ": 0"); 00874 } 00875 #endif 00876 } 00877 } 00878 else { 00879 for (uint32_t comp = 0; comp < depSCC.size(); ++comp) { 00880 eCycles.push_back(false); 00881 } 00882 00883 // for each e-edge x -> y: if x and y are in the same component, then y is cyclic 00884 typedef std::pair<IDAddress, IDAddress> Edge; 00885 BOOST_FOREACH (Edge e, externalEdges) { 00886 if (componentOfAtom[e.first] == componentOfAtom[e.second]) { 00887 eCycles[componentOfAtom[e.second]] = true; 00888 } 00889 } 00890 00891 eCyclesTotal = false; 00892 for (uint32_t comp = 0; comp < depSCC.size(); ++comp) { 00893 eCyclesTotal |= eCycles[comp]; 00894 } 00895 } 00896 } 00897 00898 00899 bool AnnotatedGroundProgram::containsHeadCycles(ID ruleID) const 00900 { 00901 return headCyclicRules->getFact(ruleID.address); 00902 } 00903 00904 00905 int AnnotatedGroundProgram::getComponentCount() const 00906 { 00907 return programComponents.size(); 00908 } 00909 00910 00911 const OrdinaryASPProgram& AnnotatedGroundProgram::getProgramOfComponent(int compNr) const 00912 { 00913 assert((uint32_t)compNr >= 0 && (uint32_t)compNr < depSCC.size()); 00914 return programComponents[compNr]->program; 00915 } 00916 00917 00918 InterpretationConstPtr AnnotatedGroundProgram::getAtomsOfComponent(int compNr) const 00919 { 00920 assert((uint32_t)compNr >= 0 && (uint32_t)compNr < depSCC.size()); 00921 return programComponents[compNr]->componentAtoms; 00922 } 00923 00924 00925 bool AnnotatedGroundProgram::hasHeadCycles(int compNr) const 00926 { 00927 assert((uint32_t)compNr >= 0 && (uint32_t)compNr < depSCC.size()); 00928 return headCycles[compNr]; 00929 } 00930 00931 00932 bool AnnotatedGroundProgram::hasECycles(int compNr) const 00933 { 00934 assert((uint32_t)compNr >= 0 && (uint32_t)compNr < depSCC.size()); 00935 return eCycles[compNr]; 00936 } 00937 00938 00939 namespace 00940 { 00941 00942 typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, IDAddress> Graph; 00943 typedef Graph::vertex_descriptor Node; 00944 00945 struct edge_filter 00946 { 00947 const std::set<Node>& skipnodes; 00948 00949 edge_filter(std::set<Node>& skipnodes) : skipnodes(skipnodes) { } 00950 00951 template <typename Edge> 00952 bool operator()(const Edge& e) const 00953 { 00954 return true; 00955 } 00956 }; 00957 00958 struct vertex_filter 00959 { 00960 const std::set<Node>& skipnodes; 00961 00962 vertex_filter(std::set<Node>& skipnodes) : skipnodes(skipnodes) { } 00963 00964 template <typename Vertex> 00965 bool operator()(const Vertex& v) const 00966 { 00967 return std::find(skipnodes.begin(), skipnodes.end(), v) == skipnodes.end(); 00968 } 00969 }; 00970 00971 } 00972 00973 bool AnnotatedGroundProgram::hasECycles(int compNr, InterpretationConstPtr intr) const 00974 { 00975 00976 DBGLOG(DBG, "Computing e-cycles wrt. interpretation " << *intr); 00977 00978 #ifdef WIN32 00979 // make a copy of the dependency graph 00980 Graph depGraph2; 00981 boost::copy_graph(depGraph, depGraph2); 00982 00983 // remove atoms which are not in intr and corresponding edges 00984 std::set<Node> skipnodes; 00985 BOOST_FOREACH (IDAddress adr, depSCC[compNr]) { 00986 if (!intr->getFact(adr)) skipnodes.insert(depNodes.at(adr)); 00987 } 00988 00989 boost::graph_traits<Graph>::edge_iterator vi, vi_end; 00990 std::vector<Graph::edge_descriptor> delEdges; 00991 for (boost::tuples::tie(vi, vi_end) = edges(depGraph2); vi != vi_end; vi++) { 00992 if (std::find(skipnodes.begin(), skipnodes.end(), source(*vi, depGraph2)) != skipnodes.end() || 00993 std::find(skipnodes.begin(), skipnodes.end(), target(*vi, depGraph2)) != skipnodes.end()) { 00994 delEdges.push_back(*vi); 00995 } 00996 } 00997 BOOST_FOREACH (Graph::edge_descriptor e, delEdges) { 00998 remove_edge(e, depGraph2); 00999 } 01000 BOOST_FOREACH (Node n, skipnodes) { 01001 remove_vertex(n, depGraph2); 01002 } 01003 #else 01004 // filter the graph: eliminate vertices which are not in intr 01005 struct edge_filter { 01006 InterpretationConstPtr intr; 01007 edge_filter() {} 01008 edge_filter(InterpretationConstPtr intr) : intr(intr) { } 01009 bool operator()(const boost::detail::edge_desc_impl<boost::bidirectional_tag, long unsigned int>& e) const { 01010 return intr->getFact(e.m_source) && intr->getFact(e.m_target); 01011 } 01012 }; 01013 struct node_filter { 01014 InterpretationConstPtr intr; 01015 node_filter() {} 01016 node_filter(InterpretationConstPtr intr) : intr(intr) { } 01017 bool operator()(const Node& n) const { 01018 return intr->getFact(n); 01019 } 01020 }; 01021 edge_filter efilter(intr); 01022 node_filter nfilter(intr); 01023 boost::filtered_graph<Graph, edge_filter, node_filter> depGraph2(depGraph, efilter, nfilter); 01024 #endif 01025 01026 // make a BFS in the reduced graph 01027 typedef std::pair<IDAddress, IDAddress> Edge; 01028 BOOST_FOREACH (Edge e, externalEdges) { 01029 DBGLOG(DBG, "Checking e-edge " << printToString<RawPrinter>(ctx->registry()->ogatoms.getIDByAddress(e.first), ctx->registry()) << " --> " << printToString<RawPrinter>(ctx->registry()->ogatoms.getIDByAddress(e.second), ctx->registry())); 01030 if (!intr->getFact(e.first)) continue; 01031 if (!intr->getFact(e.second)) continue; 01032 if (std::find(depSCC[compNr].begin(), depSCC[compNr].end(), e.first) == depSCC[compNr].end()) continue; 01033 if (std::find(depSCC[compNr].begin(), depSCC[compNr].end(), e.second) == depSCC[compNr].end()) continue; 01034 01035 std::vector<Graph::vertex_descriptor> reachable; 01036 boost::breadth_first_search(depGraph2, depNodes.at(e.second), 01037 boost::visitor( 01038 boost::make_bfs_visitor( 01039 boost::write_property( 01040 boost::identity_property_map(), 01041 std::back_inserter(reachable), 01042 boost::on_discover_vertex())))); 01043 01044 if (std::find(reachable.begin(), reachable.end(), depNodes.at(e.first)) != reachable.end()) { 01045 // yes, there is a cycle 01046 return true; 01047 } 01048 } 01049 01050 if (hasECycles(compNr)) { 01051 DBGLOG(DBG, "Component " << compNr << " has no e-cycle wrt. interpretation, although it has e-cycles in general"); 01052 DLVHEX_BENCHMARK_REGISTER_AND_COUNT(sidecycintskip, "E-cycles broken by interpretation", 1); 01053 } 01054 01055 return false; 01056 } 01057 01058 01059 bool AnnotatedGroundProgram::hasHeadCycles() const 01060 { 01061 return headCyclesTotal; 01062 } 01063 01064 01065 bool AnnotatedGroundProgram::hasECycles(InterpretationConstPtr intr) const 01066 { 01067 for (uint32_t i = 0; i < depSCC.size(); ++i) { 01068 if (hasECycles(i, intr)) return true; 01069 } 01070 #ifndef NDEBUG 01071 if (hasECycles()) { 01072 DBGLOG(DBG, "Program has no e-cycle wrt. interpretation, although it has e-cycles in general"); 01073 } 01074 #endif 01075 return false; 01076 } 01077 01078 01079 bool AnnotatedGroundProgram::hasECycles() const 01080 { 01081 return eCyclesTotal; 01082 } 01083 01084 01085 bool AnnotatedGroundProgram::mapsAux(IDAddress ida) const 01086 { 01087 return auxToEA.find(ida) != auxToEA.end(); 01088 } 01089 01090 01091 const boost::unordered_map<IDAddress, std::vector<ID> >& AnnotatedGroundProgram::getAuxToEA() const 01092 { 01093 return auxToEA; 01094 } 01095 01096 01097 const std::vector<ID>& AnnotatedGroundProgram::getAuxToEA(IDAddress ida) const 01098 { 01099 assert(auxToEA.find(ida) != auxToEA.end() && "could not find auxiliary mapping"); 01100 return auxToEA.at(ida); 01101 } 01102 01103 01104 const boost::shared_ptr<ExternalAtomMask> AnnotatedGroundProgram::getEAMask(int eaIndex) const 01105 { 01106 assert((uint32_t)eaIndex >= 0 && (uint32_t)eaIndex < indexedEatoms.size()); 01107 eaMasks[eaIndex]->updateMask(); 01108 return eaMasks[eaIndex]; 01109 } 01110 01111 01112 const OrdinaryASPProgram& AnnotatedGroundProgram::getGroundProgram() const 01113 { 01114 return groundProgram; 01115 } 01116 01117 01118 const std::vector<ID>& AnnotatedGroundProgram::getIndexedEAtoms() const 01119 { 01120 return indexedEatoms; 01121 } 01122 01123 01124 ID AnnotatedGroundProgram::getIndexedEAtom(int index) const 01125 { 01126 assert((uint32_t)index >= 0 && (uint32_t)index < indexedEatoms.size()); 01127 return indexedEatoms[index]; 01128 } 01129 01130 int AnnotatedGroundProgram::getIndexOfEAtom(ID eatomID) const 01131 { 01132 for (int i = 0; i < indexedEatoms.size(); ++i) 01133 if (indexedEatoms[i] == eatomID) return i; 01134 return -1; 01135 } 01136 01137 InterpretationConstPtr AnnotatedGroundProgram::getProgramMask() const 01138 { 01139 assert(!!programMask); 01140 return programMask; 01141 } 01142 01143 01144 void AnnotatedGroundProgram::setCompleteSupportSetsForVerification(SimpleNogoodContainerPtr supportSets) 01145 { 01146 this->supportSets = supportSets; 01147 } 01148 01149 01150 bool AnnotatedGroundProgram::allowsForVerificationUsingCompleteSupportSets() const 01151 { 01152 return !!supportSets; 01153 } 01154 01155 01156 SimpleNogoodContainerPtr AnnotatedGroundProgram::getCompleteSupportSetsForVerification() 01157 { 01158 return supportSets; 01159 } 01160 01161 01162 bool AnnotatedGroundProgram::verifyExternalAtomsUsingCompleteSupportSets(int eaIndex, InterpretationConstPtr interpretation, InterpretationConstPtr auxiliariesToVerify) const 01163 { 01164 01165 const ExternalAtom& eatom = reg->eatoms.getByID(indexedEatoms[eaIndex]); 01166 01167 bool supportSetPolarity = eatom.getExtSourceProperties().providesCompletePositiveSupportSets(); 01168 01169 DBGLOG(DBG, "Verifying external atom " << indexedEatoms[eaIndex] << " using " << supportSets->getNogoodCount() << " complete support sets"); 01170 01171 // The external atom is verified wrt. interpretation I iff 01172 // (i) it provides complete positive (negative) support sets 01173 // and (ii) for each ground instance which is true (false) in I, there is a support set which contains this ground instance negatively (positively) 01174 // and such that the remaining atoms are true in I. 01175 // This is checked as follows: 01176 // 1. Identify all support sets (Inp \cup { EA }) s.t. Inp \subseteq I is a set of ordinary literals and EA is an external atom replacement 01177 // 2. Keep the set S of all positive EAs that must be true (false) 01178 // 3. All positive ground instances which are true (false) in I must occur in S 01179 01180 #ifdef DEBUG 01181 Nogood impl_ng; 01182 #endif 01183 // this is set S 01184 InterpretationPtr implications(new Interpretation(reg)); 01185 for (int i = 0; i < supportSets->getNogoodCount(); i++) { 01186 ID mismatch = ID_FAIL; 01187 ID ea = ID_FAIL; 01188 const Nogood& ng = supportSets->getNogood(i); 01189 if (ng.isGround()) { 01190 BOOST_FOREACH (ID id, ng) { 01191 // because nogoods eliminate unnecessary flags from IDs in order to store them in a uniform way, 01192 // we need to lookup the atom here to get its attributes 01193 IDKind kind = reg->ogatoms.getIDByAddress(id.address).kind | (id.isNaf() ? ID::NAF_MASK : 0); 01194 if ((kind & ID::PROPERTY_EXTERNALAUX) == ID::PROPERTY_EXTERNALAUX) { 01195 if (ea != ID_FAIL) throw GeneralError("Support set " + ng.getStringRepresentation(reg) + " is invalid becaues it contains multiple external atom replacement literals"); 01196 ea = ID(kind, id.address); 01197 } 01198 else if (!id.isNaf() != interpretation->getFact(id.address)) { 01199 #ifdef DEBUG 01200 std::stringstream ss; 01201 RawPrinter printer(ss, reg); 01202 printer.print(id); 01203 ss << " is false in " << *interpretation; 01204 DBGLOG(DBG, "Mismatch: " << ss.str()); 01205 #endif 01206 mismatch = id; 01207 break; 01208 } 01209 } 01210 DBGLOG(DBG, "Analyzing support set " << ng.getStringRepresentation(reg) << " yielded " << (mismatch != ID_FAIL ? "mis" : "") << "match"); 01211 if (mismatch == ID_FAIL) { 01212 if (ea == ID_FAIL) throw GeneralError("Support set " + ng.getStringRepresentation(reg) + " is invalid becaues it contains no external atom replacement literal"); 01213 01214 if (supportSetPolarity == true) { 01215 // store all and only the positive replacement atoms which must be true 01216 if (reg->isPositiveExternalAtomAuxiliaryAtom(ea) && ea.isNaf()) { 01217 #ifdef DEBUG 01218 impl_ng.insert(ea); 01219 #endif 01220 implications->setFact(ea.address); 01221 } 01222 else if(reg->isNegativeExternalAtomAuxiliaryAtom(ea) && !ea.isNaf()) { 01223 #ifdef DEBUG 01224 impl_ng.insert(reg->swapExternalAtomAuxiliaryAtom(ea)); 01225 #endif 01226 implications->setFact(reg->swapExternalAtomAuxiliaryAtom(ea).address); 01227 } 01228 else { 01229 throw GeneralError("Set " + ng.getStringRepresentation(reg) + " is an invalid positive support set"); 01230 } 01231 } 01232 else { 01233 // store all and only the positive replacement atoms which must be false 01234 if (reg->isPositiveExternalAtomAuxiliaryAtom(ea) && !ea.isNaf()) { 01235 #ifdef DEBUG 01236 impl_ng.insert(reg->swapExternalAtomAuxiliaryAtom(ea)); 01237 #endif 01238 implications->setFact(reg->swapExternalAtomAuxiliaryAtom(ea).address); 01239 } 01240 else if(reg->isNegativeExternalAtomAuxiliaryAtom(ea) && ea.isNaf()) { 01241 #ifdef DEBUG 01242 impl_ng.insert(ea); 01243 #endif 01244 implications->setFact(ea.address); 01245 } 01246 else { 01247 throw GeneralError("Set " + ng.getStringRepresentation(reg) + " is an invalid negative support set"); 01248 } 01249 } 01250 } 01251 } 01252 } 01253 01254 // if auxiliariesToVerify is not set, then verify all true atoms 01255 if (!auxiliariesToVerify) auxiliariesToVerify = interpretation; 01256 #ifdef DEBUG 01257 DBGLOG(DBG, "Interpretation: " << *interpretation); 01258 DBGLOG(DBG, "Implications: " << *implications); 01259 DBGLOG(DBG, "Aux to verify: " << *auxiliariesToVerify); 01260 std::stringstream eamss; 01261 eamss << *getEAMask(eaIndex)->mask(); 01262 DBGLOG(DBG, "EA-Mask: " << eamss.str()); 01263 #endif 01264 01265 bool verify = true; 01266 bm::bvector<>::enumerator en = getEAMask(eaIndex)->mask()->getStorage().first(); 01267 bm::bvector<>::enumerator en_end = getEAMask(eaIndex)->mask()->getStorage().end(); 01268 while (en < en_end) { 01269 if (auxiliariesToVerify->getFact(*en)) { 01270 ID id = reg->ogatoms.getIDByAddress(*en); 01271 if (id.isExternalAuxiliary() && !id.isExternalInputAuxiliary()) { 01272 01273 // determine the guessed truth value of the external atom 01274 bool eaGuessedTruthValue; 01275 ID posId, negId; 01276 if (reg->isPositiveExternalAtomAuxiliaryAtom(id)) { 01277 eaGuessedTruthValue = interpretation->getFact(id.address); 01278 posId = id; 01279 negId = reg->swapExternalAtomAuxiliaryAtom(id); 01280 } 01281 else { 01282 eaGuessedTruthValue = !interpretation->getFact(id.address); 01283 posId = reg->swapExternalAtomAuxiliaryAtom(id); 01284 negId = id; 01285 } 01286 01287 #ifdef DEBUG 01288 std::stringstream ss; 01289 RawPrinter printer(ss, reg); 01290 printer.print(posId); 01291 DBGLOG(DBG, "Verifying auxiliary " << ss.str() << "=" << eaGuessedTruthValue); 01292 #endif 01293 01294 // check it against the support sets 01295 if (eaGuessedTruthValue == true) { 01296 if ( supportSetPolarity == true && !implications->getFact(posId.address) ) { 01297 DBGLOG(DBG, "Failed because " << implications->getFact(id.address) << " == false"); 01298 verify = false; 01299 break; 01300 } 01301 if ( supportSetPolarity == false && implications->getFact(negId.address) ) { 01302 DBGLOG(DBG, "Failed because " << implications->getFact(negId.address) << " == true"); 01303 verify = false; 01304 break; 01305 } 01306 } 01307 else { 01308 if ( supportSetPolarity == false && !implications->getFact(negId.address) ) { 01309 DBGLOG(DBG, "Failed because " << implications->getFact(id.address) << " == false"); 01310 verify = false; 01311 break; 01312 } 01313 if ( supportSetPolarity == true && implications->getFact(posId.address) ) { 01314 DBGLOG(DBG, "Failed because " << implications->getFact(posId.address) << " == true"); 01315 verify = false; 01316 break; 01317 } 01318 } 01319 DBGLOG(DBG, "Verified auxiliary " << ss.str() << "=" << eaGuessedTruthValue << " in " << *interpretation << " wrt. implications " << *implications); 01320 } 01321 } 01322 en++; 01323 } 01324 01325 DBGLOG(DBG, "Verification done"); 01326 return verify; 01327 } 01328 01329 01330 DLVHEX_NAMESPACE_END 01331 01332 // vim:expandtab:ts=4:sw=4: 01333 // mode: C++ 01334 // End: