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