dlvhex  2.5.0
src/InternalGrounder.cpp
Go to the documentation of this file.
00001 /* dlvhex -- Answer-Set Programming with external interfaces.
00002  * Copyright (C) 2005-2007 Roman Schindlauer
00003  * Copyright (C) 2006-2015 Thomas Krennwallner
00004  * Copyright (C) 2009-2016 Peter Schüller
00005  * Copyright (C) 2011-2016 Christoph Redl
00006  * Copyright (C) 2015-2016 Tobias Kaminski
00007  * Copyright (C) 2015-2016 Antonius Weinzierl
00008  *
00009  * This file is part of dlvhex.
00010  *
00011  * dlvhex is free software; you can redistribute it and/or modify it
00012  * under the terms of the GNU Lesser General Public License as
00013  * published by the Free Software Foundation; either version 2.1 of
00014  * the License, or (at your option) any later version.
00015  *
00016  * dlvhex is distributed in the hope that it will be useful, but
00017  * WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  * Lesser General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Lesser General Public
00022  * License along with dlvhex; if not, write to the Free Software
00023  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00024  * 02110-1301 USA.
00025  */
00026 
00034 #ifdef HAVE_CONFIG_H
00035 #include "config.h"
00036 #endif
00037 
00038 #include "dlvhex2/Logger.h"
00039 #include "dlvhex2/Registry.h"
00040 #include "dlvhex2/Printer.h"
00041 #include "dlvhex2/ASPSolver.h"
00042 #include "dlvhex2/ProgramCtx.h"
00043 #include "dlvhex2/PluginInterface.h"
00044 #include "dlvhex2/Benchmarking.h"
00045 #include "dlvhex2/InternalGrounder.h"
00046 
00047 #include <boost/foreach.hpp>
00048 #include <boost/algorithm/string/predicate.hpp>
00049 #include <boost/graph/strong_components.hpp>
00050 #include <boost/graph/topological_sort.hpp>
00051 
00052 DLVHEX_NAMESPACE_BEGIN
00053 
00054 void InternalGrounder::computeDepGraph()
00055 {
00056 
00057     // add edb
00058     bm::bvector<>::enumerator en = inputprogram.edb->getStorage().first();
00059     bm::bvector<>::enumerator en_end = inputprogram.edb->getStorage().end();
00060 
00061     while (en < en_end) {
00062         ID pred = getPredicateOfAtom(ID(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG, *en));
00063         if (depNodes.find(pred) == depNodes.end()) {
00064             depNodes[pred] = boost::add_vertex(pred, depGraph);
00065         }
00066         en++;
00067     }
00068 
00069     // go through all rules
00070     BOOST_FOREACH (ID ruleID, inputprogram.idb) {
00071         const Rule& rule = reg->rules.getByID(ruleID);
00072 
00073         DBGLOG(DBG, "Analyzing rule " << ruleToString(ruleID));
00074 
00075         // all predicates are nodes
00076         BOOST_FOREACH (ID headLiteralID, rule.head) {
00077             ID pred = getPredicateOfAtom(headLiteralID);
00078             if (depNodes.find(pred) == depNodes.end()) {
00079                 depNodes[pred] = boost::add_vertex(pred, depGraph);
00080             }
00081         }
00082         BOOST_FOREACH (ID bodyLiteralID, rule.body) {
00083             ID pred = getPredicateOfAtom(bodyLiteralID);
00084             if (depNodes.find(pred) == depNodes.end()) {
00085                 depNodes[pred] = boost::add_vertex(pred, depGraph);
00086             }
00087         }
00088 
00089         // add an arc from all predicates in head literals to all predicates in body literals
00090         BOOST_FOREACH (ID headLiteralID, rule.head) {
00091             BOOST_FOREACH (ID bodyLiteralID, rule.body) {
00092                 boost::add_edge(depNodes[getPredicateOfAtom(headLiteralID)], depNodes[getPredicateOfAtom(bodyLiteralID)], depGraph);
00093                 DBGLOG(DBG, "Predicate " << getPredicateOfAtom(headLiteralID) << " depends on " << getPredicateOfAtom(bodyLiteralID));
00094             }
00095         }
00096 
00097         // head predicates cyclically depend on each other
00098         BOOST_FOREACH (ID headLiteralID1, rule.head) {
00099             BOOST_FOREACH (ID headLiteralID2, rule.head) {
00100                 if (headLiteralID1 != headLiteralID2) {
00101                     boost::add_edge(depNodes[getPredicateOfAtom(headLiteralID1)], depNodes[getPredicateOfAtom(headLiteralID2)], depGraph);
00102                     DBGLOG(DBG, "Predicate " << getPredicateOfAtom(headLiteralID1) << " depends on " << getPredicateOfAtom(headLiteralID2));
00103                 }
00104             }
00105         }
00106     }
00107 }
00108 
00109 
00110 ID InternalGrounder::preprocessRule(ID ruleID)
00111 {
00112 
00113     DBGLOG(DBG, "Preprocessing rule " << printToString<RawPrinter>(ruleID, reg));
00114     const Rule& rule = reg->rules.getByID(ruleID);
00115     Rule newrule = rule;
00116     newrule.body.clear();
00117 
00118     if (ruleID.hasRuleHeadGuard()) {
00119         throw GeneralError("Internal grounder cannot handle guards in rule heads");
00120     }
00121 
00122     // find length of the longest variable name
00123     std::set<ID> vars;
00124     BOOST_FOREACH (ID a, rule.body) {
00125         reg->getVariablesInID(a, vars, true);
00126     }
00127     int vlen = 0;
00128     std::stringstream prefix;
00129     BOOST_FOREACH (ID v, vars) {
00130         int s = reg->terms.getByID(v).symbol.size();
00131         vlen = s > vlen ? s : vlen;
00132     }
00133     prefix << "Anonymous";
00134     for (int i = 0; i < vlen - 8; i++) prefix << "_";
00135 
00136     // check for nested terms in rule head
00137     BOOST_FOREACH (ID a, rule.head) {
00138         OrdinaryAtom oa = reg->lookupOrdinaryAtom(a);
00139         for (uint32_t i = 1; i < oa.tuple.size(); ++i) {
00140             if (oa.tuple[i].isNestedTerm()) {
00141                 throw GeneralError("Internal grounder cannot handle function symbols and ranges");
00142             }
00143         }
00144     }
00145     BOOST_FOREACH (ID a, rule.body) {
00146         if (a.isOrdinaryAtom()) {
00147             OrdinaryAtom oa = reg->lookupOrdinaryAtom(a);
00148             for (uint32_t i = 1; i < oa.tuple.size(); ++i) {
00149                 if (oa.tuple[i].isNestedTerm()) {
00150                     throw GeneralError("Internal grounder cannot handle function symbols and ranges");
00151                 }
00152             }
00153         }
00154         else if (a.isExternalAtom()) {
00155             ExternalAtom ea = reg->eatoms.getByID(a);
00156             for (uint32_t i = 0; i < ea.inputs.size(); ++i) {
00157                 if (ea.inputs[i].isNestedTerm()) {
00158                     throw GeneralError("Internal grounder cannot handle function symbols and ranges");
00159                 }
00160             }
00161             for (uint32_t i = 0; i < ea.tuple.size(); ++i) {
00162                 if (ea.tuple[i].isNestedTerm()) {
00163                     throw GeneralError("Internal grounder cannot handle function symbols and ranges");
00164                 }
00165             }
00166         }
00167         else if (a.isNaf() && a.isBuiltinAtom()) {
00168             throw GeneralError("Internal grounder cannot default negated builtins");
00169         }
00170     }
00171 
00172     // replace anonymous variables by unique variable symbols and check for nested terms
00173     int varIndex = 1;
00174     BOOST_FOREACH (ID a, rule.body) {
00175         // check if the literals contains an anonamous variable
00176         vars.clear();
00177         reg->getVariablesInID(a, vars, true);
00178         bool av = false;
00179         BOOST_FOREACH (ID v, vars) {
00180             if (v.isAnonymousVariable()) {
00181                 av = true;
00182                 break;
00183             }
00184         }
00185         if (av) {
00186             // replace all anonamous variables by ordinary ones ("_N" with N>=0)
00187             if (a.isOrdinaryAtom()) {
00188                 OrdinaryAtom oa = reg->lookupOrdinaryAtom(a);
00189                 for (uint32_t i = 1; i < oa.tuple.size(); ++i) {
00190                     if (oa.tuple[i].isAnonymousVariable()) {
00191                         std::stringstream newVar;
00192                         newVar << prefix.str() << varIndex++;
00193                         oa.tuple[i] = reg->storeVariableTerm(newVar.str());
00194                     }
00195                 }
00196                 newrule.body.push_back(ID::literalFromAtom(reg->storeOrdinaryAtom(oa), a.isNaf()));
00197             }
00198             else if (a.isExternalAtom()) {
00199                 ExternalAtom ea = reg->eatoms.getByID(a);
00200                 for (uint32_t i = 0; i < ea.inputs.size(); ++i) {
00201                     if (ea.inputs[i].isAnonymousVariable()) {
00202                         std::stringstream newVar;
00203                         newVar << prefix.str() << varIndex++;
00204                         ea.inputs[i] = reg->storeVariableTerm(newVar.str());
00205                     }
00206                 }
00207                 for (uint32_t i = 0; i < ea.tuple.size(); ++i) {
00208                     if (ea.tuple[i].isAnonymousVariable()) {
00209                         std::stringstream newVar;
00210                         newVar << prefix.str() << varIndex++;
00211                         ea.tuple[i] = reg->storeVariableTerm(newVar.str());
00212                     }
00213                 }
00214                 newrule.body.push_back(ID::literalFromAtom(reg->eatoms.storeAndGetID(ea), a.isNaf()));
00215             }
00216             else {
00217                 assert(false && "Unknown literal type");
00218             }
00219         }
00220         else {
00221             newrule.body.push_back(a);
00222         }
00223     }
00224 
00225     ID newRuleID = reg->storeRule(newrule);
00226     DBGLOG(DBG, "Preprocessed rule " << printToString<RawPrinter>(newRuleID, reg));
00227     return newRuleID;
00228 }
00229 
00230 
00231 void InternalGrounder::computeStrata()
00232 {
00233 
00234     // find strongly connected components in the dependency graph using boost
00235     std::vector<int> componentMap(depNodes.size());
00236     int num = boost::strong_components(depGraph, boost::make_iterator_property_map(componentMap.begin(), get(boost::vertex_index, depGraph)));
00237 
00238     // translate into real map
00239     depSCC = std::vector<Set<ID> >(num);
00240     Node nodeNr = 0;
00241     BOOST_FOREACH (int componentOfNode, componentMap) {
00242         depSCC[componentOfNode].insert(depGraph[nodeNr]);
00243         nodeNr++;
00244     }
00245 
00246     #ifndef NDEBUG
00247     std::stringstream compStr;
00248     bool firstC = true;
00249     BOOST_FOREACH (Set<ID> component, depSCC) {
00250         if (!firstC) compStr << ", ";
00251         firstC = false;
00252         compStr << "{";
00253         bool firstL = true;
00254         BOOST_FOREACH (ID predID, component) {
00255             if (!firstL) compStr << ", ";
00256             firstL = false;
00257             compStr << predID;
00258         }
00259         compStr << "}";
00260     }
00261     DBGLOG(DBG, "Predicate components: " << compStr.str());
00262     #endif
00263 
00264     // create a graph modeling the dependencies between the strongly-connected predicate components
00265     // one node for each component
00266     std::map<int, SCCDepGraph::vertex_descriptor> compToVertex;
00267     std::map<SCCDepGraph::vertex_descriptor, int> vertexToComp;
00268     for (uint32_t compNr = 0; compNr < depSCC.size(); ++compNr) {
00269         compToVertex[compNr] = boost::add_vertex(compNr, compDependencies);
00270         vertexToComp[compToVertex[compNr]] = compNr;
00271     }
00272     // go through all edges of the dep graph
00273     std::pair<DepGraph::edge_iterator, DepGraph::edge_iterator> edgeIteratorRange = boost::edges(depGraph);
00274     for(DepGraph::edge_iterator edgeIterator = edgeIteratorRange.first; edgeIterator != edgeIteratorRange.second; ++edgeIterator) {
00275         // connect the according strongly connected components
00276         int sourceIdx = componentMap[boost::source(*edgeIterator, depGraph)];
00277         int targetIdx = componentMap[boost::target(*edgeIterator, depGraph)];
00278         if (sourceIdx != targetIdx) {
00279             DBGLOG(DBG, "Component " << sourceIdx << " depends on " << targetIdx);
00280             boost::add_edge(compToVertex[sourceIdx], compToVertex[targetIdx], compDependencies);
00281         }
00282     }
00283 
00284     // compute topological ordering of components
00285     std::vector<SCCDepGraph::vertex_descriptor> compOrdering;
00286     topological_sort(compDependencies, std::back_inserter(compOrdering));
00287     DBGLOG(DBG, "Processing components in the following ordering:");
00288     BOOST_FOREACH (SCCDepGraph::vertex_descriptor compVertex, compOrdering) {
00289         int comp = vertexToComp[compVertex];
00290         DBGLOG(DBG, "Component " << comp << ", predicates are: ");
00291         std::set<ID> stratum;
00292         BOOST_FOREACH (ID pred, depSCC[comp]) {
00293             DBGLOG(DBG, "" << pred);
00294             stratum.insert(pred);
00295             stratumOfPredicate[pred] = predicatesOfStratum.size();
00296         }
00297         predicatesOfStratum.push_back(stratum);
00298     }
00299 
00300     // arrange the rules accordingly
00301     rulesOfStratum = std::vector<std::set<ID> >(compOrdering.size());
00302     BOOST_FOREACH (ID ruleID, inputprogram.idb) {
00303         rulesOfStratum[getStratumOfRule(ruleID)].insert(preprocessRule(ruleID));
00304     }
00305 }
00306 
00307 
00308 void InternalGrounder::buildPredicateIndex()
00309 {
00310 
00311     positionsOfPredicate.clear();
00312 
00313     int ruleNr = 0;
00314     BOOST_FOREACH (ID nonGroundRuleID, nonGroundRules) {
00315         const Rule& rule = reg->rules.getByID(nonGroundRuleID);
00316         DBGLOG(DBG, "Processing rule " << rule);
00317         int bodyAtomNr = 0;
00318         BOOST_FOREACH (ID bodyAtomID, rule.body) {
00319             DBGLOG(DBG, "Atom " << bodyAtomID << " has predicate " << getPredicateOfAtom(bodyAtomID));
00320             positionsOfPredicate[getPredicateOfAtom(bodyAtomID)].insert(std::pair<int, int>(ruleNr, bodyAtomNr));
00321             bodyAtomNr++;
00322         }
00323         ruleNr++;
00324     }
00325 }
00326 
00327 
00328 void InternalGrounder::loadStratum(int index)
00329 {
00330 
00331     DBGLOG(DBG, "Loading stratum " << index);
00332     nonGroundRules.clear();
00333     nonGroundRules.insert(nonGroundRules.begin(), rulesOfStratum[index].begin(), rulesOfStratum[index].end());
00334     buildPredicateIndex();
00335 }
00336 
00337 
00338 void InternalGrounder::groundStratum(int stratumNr)
00339 {
00340 
00341     loadStratum(stratumNr);
00342 
00343     DBGLOG(DBG, "Grounding stratum " << stratumNr);
00344     Set<ID> newDerivableAtoms;
00345 
00346     // all facts are immediately derivable and true
00347     if (stratumNr == 0) {
00348         DBGLOG(DBG, "Deriving all facts");
00349 
00350         bm::bvector<>::enumerator en = inputprogram.edb->getStorage().first();
00351         bm::bvector<>::enumerator en_end = inputprogram.edb->getStorage().end();
00352 
00353         Set<ID> newGroundRules;
00354         while (en < en_end) {
00355             ID atom(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG, *en);
00356             setToTrue(atom);
00357             addDerivableAtom(atom, groundRules, newDerivableAtoms);
00358             en++;
00359         }
00360     }
00361 
00362     // ground all rules
00363     DBGLOG(DBG, "Processing rules");
00364     for (uint32_t ruleIndex = 0; ruleIndex < nonGroundRules.size(); ++ruleIndex) {
00365         Substitution s;
00366         groundRule(nonGroundRules[ruleIndex], s, groundRules, newDerivableAtoms);
00367     }
00368 
00369     // as long as there were new rules generated, add their heads to the list of derivable atoms
00370     DBGLOG(DBG, "Processing cyclically depending rules");
00371     while (newDerivableAtoms.size() > 0) {
00372 
00373         // generate further rules for the new derivable atoms
00374         Set<ID> newDerivableAtoms2;
00375         BOOST_FOREACH (ID atom, newDerivableAtoms) {
00376             addDerivableAtom(atom, groundRules, newDerivableAtoms2);
00377         }
00378         newDerivableAtoms = newDerivableAtoms2;
00379     }
00380     DBGLOG(DBG, "Produced " << groundRules.size() << " ground rules");
00381 
00382     groundedPredicates.insert(predicatesOfStratum[stratumNr].begin(), predicatesOfStratum[stratumNr].end());
00383     BOOST_FOREACH (ID pred, predicatesOfStratum[stratumNr]) {
00384         // check if the predicate is completely solved; this is, there does not exist a derivable atom which is not known to be true
00385         bool solved = true;
00386         BOOST_FOREACH (ID atom, derivableAtomsOfPredicate[pred]) {
00387             if (!trueAtoms->getFact(atom.address)) {
00388                 solved = false;
00389                 break;
00390             }
00391         }
00392         if (solved) solvedPredicates.insert(pred);
00393     }
00394 
00395     #ifndef NDEBUG
00396     DBGLOG(DBG, "Set of grounded predicates is now: ");
00397     BOOST_FOREACH (ID pred, groundedPredicates) {
00398         DBGLOG(DBG, pred);
00399     }
00400 
00401     DBGLOG(DBG, "Set of solved predicates is now: ");
00402     BOOST_FOREACH (ID pred, solvedPredicates) {
00403         DBGLOG(DBG, pred);
00404     }
00405     #endif
00406 }
00407 
00408 
00409 void InternalGrounder::groundRule(ID ruleID, Substitution& s, std::vector<ID>& groundedRules, Set<ID>& newDerivableAtoms)
00410 {
00411     #define OPTIMIZED
00412     Substitution currentSubstitution = s;
00413     const Rule& rule = reg->rules.getByID(ruleID);
00414 
00415     DBGLOG(DBG, "Grounding rule " << ruleToString(ruleID));
00416 
00417     std::vector<ID> body = reorderRuleBody(ruleID);
00418 
00419     // compute binders of the variables in the rule
00420     Binder binders = getBinderOfRule(body);
00421     std::set<ID> outputVars = getOutputVariables(ruleID);
00422     std::vector<std::set<ID> > freeVars;
00423     for (uint32_t i = 0; i < body.size(); ++i) {
00424         freeVars.push_back(getFreeVars(body, i));
00425     }
00426     std::set<ID> failureVars;
00427 
00428     int csb = -1;                // barrier for backjumping
00429     if (body.size() == 0) {
00430         // grounding of choice rules
00431         buildGroundInstance(ruleID, currentSubstitution, groundedRules, newDerivableAtoms);
00432     }
00433     else {
00434         // start search at position 0 in the extension of all predicates
00435         std::vector<int> searchPos;
00436         for (uint32_t i = 0; i < body.size(); ++i) searchPos.push_back(0);
00437 
00438         // go through all (positive) body atoms
00439         for (std::vector<ID>::const_iterator it = body.begin(); it != body.end(); ) {
00440             if (it->isAggregateAtom()) throw GeneralError("Error: Internal grounder does not support aggregate atoms");
00441 
00442             int bodyLitIndex = it - body.begin();
00443             ID bodyLiteralID = *it;
00444 
00445             // remove assignments to all variables which do not occur between body.begin() and it - 1
00446             DBGLOG(DBG, "Undoing variable assignments before position " << bodyLitIndex);
00447             std::set<ID> keepVars;
00448             for (std::vector<ID>::const_iterator itVarCheck = body.begin(); itVarCheck != it; ++itVarCheck) {
00449                 reg->getVariablesInID(*itVarCheck, keepVars);
00450             }
00451             Substitution newSubst = s;
00452             BOOST_FOREACH (ID var, keepVars) {
00453                 newSubst[var] = currentSubstitution[var];
00454             }
00455             currentSubstitution = newSubst;
00456 
00457             DBGLOG(DBG, "Finding next match at position " << bodyLitIndex << " in extension after index " << searchPos[bodyLitIndex]);
00458             int startSearchPos = searchPos[bodyLitIndex];
00459             searchPos[bodyLitIndex] = matchNextFromExtension(applySubstitutionToAtom(currentSubstitution, bodyLiteralID), currentSubstitution, searchPos[bodyLitIndex]);
00460             DBGLOG(DBG, "Search result: " << searchPos[bodyLitIndex]);
00461 
00462             // match?
00463             if (searchPos[bodyLitIndex] == -1) {
00464 
00465                 #ifdef OPTIMIZED
00466                 // the conflict in this literal is due to any of the variables occurring in it
00467                 reg->getVariablesInID(*it, failureVars);
00468 
00469                 int btIndex = -1;
00470                 if (startSearchPos == 0) {
00471                     // failure on first match
00472                     DBGLOG(DBG, "Failure on first match at position " << bodyLitIndex);
00473                     std::set<ID> vars;
00474                     reg->getVariablesInID(*it, vars);
00475                     btIndex = getClosestBinder(body, bodyLitIndex, vars);
00476                 }
00477                 else {
00478                     // failure on next match
00479                     DBGLOG(DBG, "Failure on next match at position " << bodyLitIndex);
00480 
00481                     btIndex = getClosestBinder(body, bodyLitIndex, failureVars);
00482                     btIndex = csb > btIndex ? csb : btIndex;
00483 
00484                     if (btIndex == csb) {
00485                         csb = getClosestBinder(body, btIndex, outputVars);
00486                     }
00487                 }
00488                 if (btIndex == -1) {
00489                     DBGLOG(DBG, "No more matches");
00490                     return;
00491                 }
00492                 else {
00493                     DBGLOG(DBG, "Backtracking to literal " << btIndex);
00494                     it = body.begin() + btIndex;
00495                 }
00496                 #else
00497                 // backtrack
00498                 int btIndex = backtrack(ruleID, binders, bodyLitIndex);
00499                 if (btIndex == -1) {
00500                     DBGLOG(DBG, "No more matches");
00501                     return;
00502                 }
00503                 else {
00504                     DBGLOG(DBG, "Backtracking to literal " << btIndex);
00505                     it = body.begin() + btIndex;
00506                 }
00507                 #endif
00508 
00509                 continue;
00510             }
00511             else {
00512                 // variables which occur in the current literals are now no failure variables anymore
00513                 BOOST_FOREACH (ID v, freeVars[bodyLitIndex]) {
00514                     failureVars.erase(v);
00515                 }
00516             }
00517 
00518             // match
00519             // if we are at the end of the body list we have found a valid substitution
00520             if (it == body.end() - 1) {
00521                 DBGLOG(DBG, "Substitution complete");
00522                 buildGroundInstance(ruleID, currentSubstitution, groundedRules, newDerivableAtoms);
00523                 #ifdef OPTIMIZED
00524                 int btIndex = getClosestBinder(body, bodyLitIndex + 1, outputVars);
00525                 if (btIndex == -1) {
00526                     DBGLOG(DBG, "No more matches after solution found");
00527                     return;
00528                 }
00529                 else {
00530                     DBGLOG(DBG, "Backtracking to literal " << btIndex << " after solution found");
00531                     csb = getClosestBinder(body, btIndex, outputVars);
00532                     it = body.begin() + btIndex;
00533                 }
00534                 #else
00535 
00536                 // go back to last non-naf body literal
00537                 while(bodyLiteralID.isNaf()) {
00538                     if (it == body.begin()) return;
00539                     --it;
00540                     bodyLiteralID = *it;
00541                 }
00542                 #endif
00543             }
00544             else {
00545                 // go to next atom in rule body
00546                 ++it;
00547                                  // start from scratch
00548                 searchPos[bodyLitIndex + 1] = 0;
00549             }
00550         }
00551     }
00552 }
00553 
00554 
00555 void InternalGrounder::buildGroundInstance(ID ruleID, Substitution s, std::vector<ID>& groundedRules, Set<ID>& newDerivableAtoms)
00556 {
00557 
00558     const Rule& rule = reg->rules.getByID(ruleID);
00559 
00560     Tuple groundedHead, groundedBody;
00561 
00562     // ground head
00563     BOOST_FOREACH (ID headAtom, rule.head) {
00564         ID groundHeadAtom = applySubstitutionToAtom(s, headAtom);
00565         groundedHead.push_back(groundHeadAtom);
00566         newDerivableAtoms.insert(groundHeadAtom);
00567     }
00568 
00569     // ground body
00570     BOOST_FOREACH (ID bodyLitID, rule.body) {
00571         ID groundBodyLiteralID = applySubstitutionToAtom(s, bodyLitID);
00572 
00573         if (groundBodyLiteralID.isBuiltinAtom() && optlevel != none) {
00574             // at this point, built-in atoms are always true, otherwise the grounding terminates even earlier
00575             continue;
00576         }
00577 
00578         if (groundBodyLiteralID.isOrdinaryAtom() && optlevel == full) {
00579             const OrdinaryAtom& groundBodyLiteral = reg->ogatoms.getByID(groundBodyLiteralID);
00580 
00581             // h :- a, not b         where a is known to be true
00582             // optimization: skip satisfied literals
00583             if (!groundBodyLiteralID.isNaf() && trueAtoms->getFact(groundBodyLiteralID.address)) {
00584                 DBGLOG(DBG, "Skipping true " << groundBodyLiteralID);
00585                 continue;
00586             }
00587 
00588             // h :- a, not b         where b is known to be not derivable
00589             // optimization for stratified negation: skip naf-body literals over known predicates which are not derivable
00590             if (groundBodyLiteralID.isNaf() && isPredicateGrounded(groundBodyLiteral.front()) && !isAtomDerivable(groundBodyLiteralID)) {
00591                 DBGLOG(DBG, "Skipping underivable " << groundBodyLiteralID);
00592                 continue;
00593             }
00594 
00595             // h :- a, not b         where b is known to be true
00596             // optimization: skip rules which contain a naf-literal which in known to be true
00597             if (groundBodyLiteralID.isNaf() && trueAtoms->getFact(groundBodyLiteralID.address)) {
00598                 DBGLOG(DBG, "Skipping rule " << ruleToString(ruleID) << " due to true " << groundBodyLiteralID);
00599                 return;
00600             }
00601 
00602             // h :- a, not b         where a is known to be not derivable
00603             // optimization for stratified negation: skip naf-body literals over known predicates which are not derivable
00604             if (!groundBodyLiteralID.isNaf() && isPredicateGrounded(groundBodyLiteral.front()) && !isAtomDerivable(groundBodyLiteralID)) {
00605                 DBGLOG(DBG, "Skipping rule " << ruleToString(ruleID) << " due to " << groundBodyLiteralID);
00606                 return;
00607             }
00608         }
00609 
00610         groundedBody.push_back(groundBodyLiteralID);
00611     }
00612 
00613     // determine type of rule
00614     IDKind kind = ID::MAINKIND_RULE;
00615     if (groundedHead.size() == 0) kind |= ID::SUBKIND_RULE_CONSTRAINT;
00616     if (groundedHead.size() > 0) kind |= ID::SUBKIND_RULE_REGULAR;
00617     if (groundedHead.size() > 1) kind |= ID::PROPERTY_RULE_DISJ;
00618 
00619     // avoid empty rules:
00620     // in case that both the head and the body are empty, add default-negated atom which does not occur elsewhere
00621     if (groundedHead.size() == 0 && groundedBody.size() == 0) {
00622         DBGLOG(DBG, "Adding globally new naf-literal " << globallyNewAtom.address << " to body");
00623         groundedBody.push_back(ID(ID::MAINKIND_LITERAL | ID::SUBKIND_ATOM_ORDINARYG | ID::NAF_MASK, globallyNewAtom.address));
00624     }
00625 
00626     // new facts are set immediately
00627     if (groundedHead.size() == 1 && groundedBody.size() == 0) {
00628         // derive new fact
00629         DBGLOG(DBG, "Adding fact " << groundedHead[0]);
00630         setToTrue(groundedHead[0]);
00631     }
00632     else {
00633         // build rule
00634         Rule groundedRule(kind, groundedHead, groundedBody, rule.weight, rule.level, Tuple());
00635 
00636         // avoid duplicate entries (they cause the registry to crash)
00637         ID id = reg->rules.getIDByElement(groundedRule);
00638         if (id == ID_FAIL) {
00639             DBGLOG(DBG, "Adding ground rule");
00640             id = reg->rules.storeAndGetID(groundedRule);
00641             DBGLOG(DBG, "Added ground rule " << ruleToString(id));
00642         }
00643         else {
00644             DBGLOG(DBG, "Ground rule " << ruleToString(id) << " was already present");
00645         }
00646         groundedRules.push_back(id);
00647     }
00648 }
00649 
00650 
00651 bool InternalGrounder::match(ID literalID, ID patternLiteralID, Substitution& s)
00652 {
00653 
00654     // sign must be equal
00655     if (literalID.isNaf() != patternLiteralID.isNaf()) return false;
00656 
00657     if (literalID.isOrdinaryAtom()) {
00658         return matchOrdinary(literalID, patternLiteralID, s);
00659     }
00660     else if(literalID.isBuiltinAtom()) {
00661         return matchBuiltin(literalID, patternLiteralID, s);
00662     }
00663     else {
00664         // other types of atoms are currently not implemented (e.g. aggregate atoms)
00665         assert(false);
00666         return false;
00667     }
00668 }
00669 
00670 
00671 bool InternalGrounder::matchOrdinary(ID literalID, ID patternLiteralID, Substitution& s)
00672 {
00673 
00674     const OrdinaryAtom& atom = literalID.isOrdinaryGroundAtom() ? reg->ogatoms.getByID(literalID) : reg->onatoms.getByID(literalID);
00675     const OrdinaryAtom& patternAtom = reg->ogatoms.getByID(patternLiteralID);
00676 
00677     if (!atom.unifiesWith(patternAtom)) return false;
00678 
00679     // compute the unifying substitution
00680     for (uint32_t termIndex = 0; termIndex < atom.tuple.size(); ++termIndex) {
00681         if (atom.tuple[termIndex].isVariableTerm()) {
00682             s[atom.tuple[termIndex]] = patternAtom.tuple[termIndex];
00683         }
00684     }
00685     return true;
00686 }
00687 
00688 
00689 bool InternalGrounder::matchBuiltin(ID literalID, ID patternLiteralID, Substitution& s)
00690 {
00691 
00692     // builtin-atoms must not be default-negated
00693     assert(!literalID.isNaf());
00694     assert(!patternLiteralID.isNaf());
00695 
00696     const BuiltinAtom& atom = reg->batoms.getByID(literalID);
00697     const BuiltinAtom& patternAtom = reg->batoms.getByID(patternLiteralID);
00698 
00699     // compute the unifying substitution
00700     Substitution s2 = s;
00701     for (uint32_t termIndex = 0; termIndex < atom.tuple.size(); ++termIndex) {
00702         if (atom.tuple[termIndex].isVariableTerm()) {
00703             if (s.find(atom.tuple[termIndex]) != s.end() && s[atom.tuple[termIndex]] != patternAtom.tuple[termIndex]) return false;
00704             s[atom.tuple[termIndex]] = patternAtom.tuple[termIndex];
00705         }
00706         else {
00707             if (atom.tuple[termIndex] != patternAtom.tuple[termIndex]) return false;
00708         }
00709     }
00710     s = s2;
00711     return true;
00712 }
00713 
00714 
00715 int InternalGrounder::matchNextFromExtension(ID literalID, Substitution& s, int startSearchIndex)
00716 {
00717 
00718     if (literalID.isOrdinaryAtom()) {
00719         return matchNextFromExtensionOrdinary(literalID, s, startSearchIndex);
00720     }
00721     else if (literalID.isBuiltinAtom()) {
00722         return matchNextFromExtensionBuiltin(literalID, s, startSearchIndex);
00723     }
00724     else {
00725         // other types of atoms are currently not implemented (e.g. aggregate atoms)
00726         assert(false);
00727         return false;
00728     }
00729 }
00730 
00731 
00732 int InternalGrounder::matchNextFromExtensionOrdinary(ID literalID, Substitution& s, int startSearchIndex)
00733 {
00734 
00735     DBGLOG(DBG, "Matching ordinary atom");
00736     if (!literalID.isNaf()) {
00737         const OrdinaryAtom& atom = literalID.isOrdinaryGroundAtom() ? reg->ogatoms.getByID(literalID) : reg->onatoms.getByID(literalID);
00738         std::vector<ID>& extension = derivableAtomsOfPredicate[atom.front()];
00739 
00740         for (std::vector<ID>::const_iterator it = extension.begin() + startSearchIndex; it != extension.end(); ++it) {
00741 
00742             if (match(literalID, *it, s)) {
00743                 // yes
00744                 // return next start search index
00745                 return it - extension.begin() + 1;
00746             }
00747         }
00748         // no match
00749         return -1;
00750     }
00751     else {
00752                                  // matching of non-ground naf-literals is illegal
00753         assert(!literalID.isOrdinaryNongroundAtom());
00754 
00755                                  // only one match
00756         if (startSearchIndex > 0) return -1;
00757 
00758         // naf-literals will always match if the predicates is unsolved
00759         if (!isPredicateSolved(getPredicateOfAtom(literalID))) {
00760             return 1;
00761         }
00762         else {
00763             // check if the ground literal is NOT in the (complete) extension
00764             ID posID = ID(((literalID.kind & (ID::ALL_ONES ^ ID::MAINKIND_MASK)) | ID::MAINKIND_ATOM) ^ ID::NAF_MASK, literalID.address);
00765             const OrdinaryAtom& atom = reg->ogatoms.getByID(posID);
00766             std::vector<ID>& extension = derivableAtomsOfPredicate[atom.front()];
00767             if (isAtomDerivable(posID)) {
00768                 return -1;       // no match of naf-literal
00769             }
00770             else {
00771                 return 1;        // match of naf-literal
00772             }
00773         }
00774     }
00775 }
00776 
00777 
00778 int InternalGrounder::matchNextFromExtensionBuiltin(ID literalID, Substitution& s, int startSearchIndex)
00779 {
00780 
00781     // builtin-atoms must not be default-negated
00782     assert (!literalID.isNaf());
00783 
00784     DBGLOG(DBG, "Matching builtin atom");
00785     const BuiltinAtom& atom = reg->batoms.getByID(literalID);
00786 
00787     switch (atom.tuple[0].address) {
00788         case ID::TERM_BUILTIN_INT:
00789             return matchNextFromExtensionBuiltinUnary(literalID, s, startSearchIndex);
00790 
00791         case ID::TERM_BUILTIN_EQ:
00792         case ID::TERM_BUILTIN_NE:
00793         case ID::TERM_BUILTIN_LT:
00794         case ID::TERM_BUILTIN_LE:
00795         case ID::TERM_BUILTIN_GT:
00796         case ID::TERM_BUILTIN_GE:
00797         case ID::TERM_BUILTIN_SUCC:
00798             return matchNextFromExtensionBuiltinBinary(literalID, s, startSearchIndex);
00799 
00800         case ID::TERM_BUILTIN_ADD:
00801         case ID::TERM_BUILTIN_MUL:
00802         case ID::TERM_BUILTIN_SUB:
00803         case ID::TERM_BUILTIN_DIV:
00804         case ID::TERM_BUILTIN_MOD:
00805             return matchNextFromExtensionBuiltinTernary(literalID, s, startSearchIndex);
00806     }
00807     assert(false);
00808     return -1;
00809 }
00810 
00811 
00812 int InternalGrounder::matchNextFromExtensionBuiltinUnary(ID literalID, Substitution& s, int startSearchIndex)
00813 {
00814 
00815     const BuiltinAtom& atom = reg->batoms.getByID(literalID);
00816     switch (atom.tuple[0].address) {
00817         case ID::TERM_BUILTIN_INT:
00818             if (startSearchIndex > (int)ctx.maxint) {
00819                 return -1;
00820             }
00821             else {
00822                 if (atom.tuple[1].isVariableTerm()) {
00823                     s[atom.tuple[1]] = ID::termFromInteger(startSearchIndex);
00824                     return startSearchIndex + 1;
00825                 }
00826                 else if (atom.tuple[1].isConstantTerm()) {
00827                     return -1;
00828                 }
00829                 else {
00830                     assert(atom.tuple[1].isIntegerTerm());
00831 
00832                     if (startSearchIndex <= (int)atom.tuple[1].address) {
00833                         return atom.tuple[1].address + 1;
00834                     }
00835                 }
00836             }
00837     }
00838     assert(false);
00839     return 0;
00840 }
00841 
00842 
00843 int InternalGrounder::matchNextFromExtensionBuiltinBinary(ID literalID, Substitution& s, int startSearchIndex)
00844 {
00845 
00846     const BuiltinAtom& atom = reg->batoms.getByID(literalID);
00847 
00848     if (startSearchIndex > 0) return -1;
00849 
00850     if (atom.tuple[1].isVariableTerm() && atom.tuple[2].isVariableTerm()) {
00851         return -1;
00852     }
00853     else if ((atom.tuple[1].isConstantTerm() || atom.tuple[1].isIntegerTerm()) && atom.tuple[2].isVariableTerm() && atom.tuple[0].address == ID::TERM_BUILTIN_EQ) {
00854         s[atom.tuple[2]] = atom.tuple[1];
00855         return 1;
00856     }
00857     else if ((atom.tuple[2].isConstantTerm() || atom.tuple[2].isIntegerTerm()) && atom.tuple[1].isVariableTerm() && atom.tuple[0].address == ID::TERM_BUILTIN_EQ) {
00858         s[atom.tuple[1]] = atom.tuple[2];
00859         return 1;
00860     }
00861     else if (atom.tuple[1].isIntegerTerm() && atom.tuple[2].isVariableTerm() && atom.tuple[0].address == ID::TERM_BUILTIN_SUCC) {
00862         s[atom.tuple[2]] = ID::termFromInteger(atom.tuple[1].address + 1);
00863         return 1;
00864     }
00865     else if (atom.tuple[1].isVariableTerm() && atom.tuple[2].isIntegerTerm() && atom.tuple[0].address == ID::TERM_BUILTIN_SUCC) {
00866         if (atom.tuple[2].address == 0) return -1;
00867         s[atom.tuple[1]] = ID::termFromInteger(atom.tuple[2].address - 1);
00868         return 1;
00869     }
00870     else {
00871         // all values are fixed
00872         bool cmp;
00873         switch (atom.tuple[0].address) {
00874             case ID::TERM_BUILTIN_EQ: cmp = (atom.tuple[1].address == atom.tuple[2].address); break;
00875             case ID::TERM_BUILTIN_NE: cmp = (atom.tuple[1].address != atom.tuple[2].address); break;
00876             case ID::TERM_BUILTIN_LT: cmp = (atom.tuple[1].address < atom.tuple[2].address); break;
00877             case ID::TERM_BUILTIN_LE: cmp = (atom.tuple[1].address <= atom.tuple[2].address); break;
00878             case ID::TERM_BUILTIN_GT: cmp = (atom.tuple[1].address > atom.tuple[2].address); break;
00879             case ID::TERM_BUILTIN_GE: cmp = (atom.tuple[1].address >= atom.tuple[2].address); break;
00880         }
00881         if (cmp) return 1;
00882         else return -1;
00883     }
00884 }
00885 
00886 
00887 int InternalGrounder::matchNextFromExtensionBuiltinTernary(ID literalID, Substitution& s, int startSearchIndex)
00888 {
00889 
00890     if (startSearchIndex > (int)((ctx.maxint + 1) * (ctx.maxint + 1))) {
00891         return -1;
00892     }
00893     else {
00894         const BuiltinAtom& atom = reg->batoms.getByID(literalID);
00895 
00896         uint32_t x = startSearchIndex / (ctx.maxint + 1);
00897         uint32_t y = startSearchIndex % (ctx.maxint + 1);
00898 
00899         if (atom.tuple[1].isConstantTerm() || atom.tuple[2].isConstantTerm() || atom.tuple[3].isConstantTerm()) return -1;
00900 
00901         if (atom.tuple[1].isIntegerTerm() && atom.tuple[2].isIntegerTerm()) {
00902             if (x <= atom.tuple[1].address && y <= atom.tuple[2].address) {
00903                 x = atom.tuple[1].address;
00904                 y = atom.tuple[2].address;
00905                 int z = applyIntFunction(x_op_y_eq_ret, atom.tuple[0], x, y);
00906                 if (atom.tuple[3].isIntegerTerm()) {
00907                     if (atom.tuple[3].address != z) return -1;
00908                     else return x * (ctx.maxint + 1) + y + 1;
00909                 }
00910                 else {
00911                     s[atom.tuple[3]] = ID::termFromInteger(z);
00912                     return x * (ctx.maxint + 1) + y + 1;
00913                 }
00914             }
00915             else {
00916                 return -1;
00917             }
00918         }
00919 
00920         return -1;
00921     }
00922 }
00923 
00924 
00925 int InternalGrounder::backtrack(ID ruleID, Binder& binders, int currentIndex)
00926 {
00927 
00928     // backtrack to the last positive literal
00929     const Rule& rule = reg->rules.getByID(ruleID);
00930 
00931     int bt = currentIndex - 1;
00932     while (bt > -1 && rule.body[bt].isNaf()) bt--;
00933     return bt;
00934 }
00935 
00936 
00937 void InternalGrounder::setToTrue(ID atom)
00938 {
00939 
00940     DBGLOG(DBG, "Setting " << atom << " to true");
00941     trueAtoms->setFact(atom.address);
00942 }
00943 
00944 
00945 void InternalGrounder::addDerivableAtom(ID atomID, std::vector<ID>& groundRules, Set<ID>& newDerivableAtoms)
00946 {
00947 
00948     DBGLOG(DBG, "" << atomID << " becomes derivable");
00949 
00950     const OrdinaryAtom& ogatom = reg->ogatoms.getByID(atomID);
00951     if (isAtomDerivable(atomID)) {
00952         // is already marked as derivable: nothing to do
00953         return;
00954     }
00955     else {
00956         derivableAtomsOfPredicate[ogatom.front()].push_back(atomID);
00957     }
00958 
00959     // go through all rules which contain this predicate positively in their body
00960     typedef std::pair<int, int> Pair;
00961     BOOST_FOREACH (Pair location, positionsOfPredicate[ogatom.front()]) {
00962         // extract the atom from the body
00963         // if it unifies with atomID, ground the rule with this substitution being predetermined
00964         const Rule& rule = reg->rules.getByID(nonGroundRules[location.first]);
00965         if (!rule.body[location.second].isNaf()) {
00966             DBGLOG(DBG, "Atom occurs in rule " << location.first << " at position " << location.second);
00967             Substitution s;
00968             match(rule.body[location.second], atomID, s);
00969 
00970             groundRule(nonGroundRules[location.first], s, groundRules, newDerivableAtoms);
00971         }
00972     }
00973 }
00974 
00975 
00976 ID InternalGrounder::applySubstitutionToAtom(Substitution s, ID atomID)
00977 {
00978 
00979     if (atomID.isOrdinaryAtom()) {
00980         return applySubstitutionToOrdinaryAtom(s, atomID);
00981     }
00982 
00983     if (atomID.isBuiltinAtom()) {
00984         return applySubstitutionToBuiltinAtom(s, atomID);
00985     }
00986 
00987     assert(false && "unsupported atom type");
00988     return ID_FAIL;
00989 }
00990 
00991 
00992 ID InternalGrounder::applySubstitutionToOrdinaryAtom(Substitution s, ID atomID)
00993 {
00994 
00995     if (atomID.isOrdinaryGroundAtom()) return atomID;
00996 
00997     // apply substitution to tuple of atom
00998     const OrdinaryAtom& onatom = reg->onatoms.getByID(atomID);
00999     Tuple t = onatom.tuple;
01000     bool isGround = true;
01001     for (uint32_t termIndex = 0; termIndex < t.size(); ++termIndex) {
01002         if (s.find(t[termIndex]) != s.end()) {
01003             t[termIndex] = s[t[termIndex]];
01004         }
01005         if (t[termIndex].isVariableTerm()) isGround = false;
01006     }
01007 
01008     // replace mainkind by ATOM and subkind according to groundness
01009     IDKind kind = atomID.kind;
01010     kind &= (ID::ALL_ONES ^ ID::MAINKIND_MASK);
01011     kind &= (ID::ALL_ONES ^ ID::SUBKIND_MASK);
01012     kind |= ID::MAINKIND_ATOM;
01013     if (isGround) {
01014         kind |= ID::SUBKIND_ATOM_ORDINARYG;
01015     }
01016     else {
01017         kind |= ID::SUBKIND_ATOM_ORDINARYN;
01018     }
01019     OrdinaryAtom atom(kind);
01020     atom.tuple = t;
01021     ID id;
01022     if (isGround) {
01023         id = reg->storeOrdinaryGAtom(atom);
01024     }
01025     else {
01026         id = reg->storeOrdinaryNAtom(atom);
01027     }
01028 
01029     // output: use kind of input, except for the subtype, which is according to groundness
01030     kind &= (ID::ALL_ONES ^ ID::MAINKIND_MASK);
01031     kind |= (atomID.kind & ID::MAINKIND_MASK);
01032     return ID(kind, id.address);
01033 }
01034 
01035 
01036 ID InternalGrounder::applySubstitutionToBuiltinAtom(Substitution s, ID atomID)
01037 {
01038 
01039     const BuiltinAtom& batom = reg->batoms.getByID(atomID);
01040     Tuple t = batom.tuple;
01041     bool isGround = true;
01042     for (uint32_t termIndex = 1; termIndex < t.size(); ++termIndex) {
01043         if (s.find(t[termIndex]) != s.end()) {
01044             t[termIndex] = s[t[termIndex]];
01045         }
01046         if (t[termIndex].isVariableTerm()) isGround = false;
01047     }
01048 
01049     BuiltinAtom sbatom(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_BUILTIN, t);
01050     // TODO: We have to check if sbatom is already present, otherwise the registry crashes!
01051     return reg->batoms.storeAndGetID(sbatom);
01052 }
01053 
01054 
01055 std::string InternalGrounder::atomToString(ID atomID)
01056 {
01057     std::stringstream ss;
01058     RawPrinter p(ss, reg);
01059     p.print(atomID);
01060     return ss.str();
01061 }
01062 
01063 
01064 std::string InternalGrounder::ruleToString(ID ruleID)
01065 {
01066     std::stringstream ss;
01067     RawPrinter p(ss, reg);
01068     p.print(ruleID);
01069     return ss.str();
01070 }
01071 
01072 
01073 ID InternalGrounder::getPredicateOfAtom(ID atomID)
01074 {
01075 
01076     if (atomID.isOrdinaryAtom()) {
01077         const OrdinaryAtom& atom = (atomID.isOrdinaryGroundAtom() ? reg->ogatoms.getByID(atomID) : reg->onatoms.getByID(atomID));
01078         return atom.front();
01079     }
01080     if (atomID.isBuiltinAtom()) {
01081         const BuiltinAtom& atom = reg->batoms.getByID(atomID);
01082         return atom.front();
01083     }
01084     if (atomID.isAggregateAtom()) throw GeneralError("Error: Internal grounder does not support aggregate atoms");
01085 
01086     return ID_FAIL;
01087 }
01088 
01089 
01090 bool InternalGrounder::isGroundRule(ID ruleID)
01091 {
01092 
01093     const Rule& rule = reg->rules.getByID(ruleID);
01094     BOOST_FOREACH (ID bodyAtom, rule.body) {
01095         if (!bodyAtom.isOrdinaryGroundAtom()) return false;
01096     }
01097     return true;
01098 }
01099 
01100 
01101 bool InternalGrounder::isPredicateGrounded(ID pred)
01102 {
01103 
01104     return (std::find(groundedPredicates.begin(), groundedPredicates.end(), pred) != groundedPredicates.end());
01105 }
01106 
01107 
01108 bool InternalGrounder::isPredicateSolved(ID pred)
01109 {
01110 
01111     return (std::find(solvedPredicates.begin(), solvedPredicates.end(), pred) != solvedPredicates.end());
01112 }
01113 
01114 
01115 bool InternalGrounder::isAtomDerivable(ID atom)
01116 {
01117 
01118     ID pred = getPredicateOfAtom(atom);
01119     BOOST_FOREACH (ID derv, derivableAtomsOfPredicate[pred]) {
01120         if (atom.address == derv.address) return true;
01121     }
01122     return false;
01123 }
01124 
01125 
01126 int InternalGrounder::getStratumOfRule(ID ruleID)
01127 {
01128 
01129     const Rule& rule = reg->rules.getByID(ruleID);
01130     int stratum = 0;
01131 
01132     // compute the highest stratum of all head atoms
01133     BOOST_FOREACH (ID lit, rule.body) {
01134         int s;
01135         if (lit.isOrdinaryAtom()) {
01136             const OrdinaryAtom& atom = (lit.isOrdinaryGroundAtom() ? reg->ogatoms.getByID(lit) : reg->onatoms.getByID(lit));
01137             s = stratumOfPredicate[atom.front()];
01138         }
01139         else {
01140             s = 0;
01141         }
01142         stratum = (s > stratum ? s : stratum);
01143     }
01144 
01145     BOOST_FOREACH (ID headLit, rule.head) {
01146         const OrdinaryAtom& atom = (headLit.isOrdinaryGroundAtom() ? reg->ogatoms.getByID(headLit) : reg->onatoms.getByID(headLit));
01147         int s = stratumOfPredicate[atom.front()];
01148         stratum = (s > stratum ? s : stratum);
01149     }
01150     DBGLOG(DBG, "Stratum of rule " << ruleToString(ruleID) << " is " << stratum);
01151     return stratum;
01152 }
01153 
01154 
01155 void InternalGrounder::computeGloballyNewAtom()
01156 {
01157 
01158     // get new predicate name
01159     std::string newPredicateName("newPredName");
01160 
01161     // idb
01162     BOOST_FOREACH (ID ruleID, inputprogram.idb) {
01163         const Rule& rule = reg->rules.getByID(ruleID);
01164 
01165         BOOST_FOREACH (ID headLiteralID, rule.head) {
01166             ID pred = getPredicateOfAtom(headLiteralID);
01167             if (pred.isConstantTerm() || pred.isPredicateTerm()) {
01168                 while (boost::starts_with(reg->getTermStringByID(pred), newPredicateName)) {
01169                     newPredicateName += std::string("0");
01170                 }
01171             }
01172         }
01173         BOOST_FOREACH (ID bodyLiteralID, rule.body) {
01174             ID pred = getPredicateOfAtom(bodyLiteralID);
01175             if (pred.isConstantTerm() || pred.isPredicateTerm()) {
01176                 while (boost::starts_with(reg->getTermStringByID(pred), newPredicateName)) {
01177                     newPredicateName += std::string("0");
01178                 }
01179             }
01180         }
01181     }
01182 
01183     // edb
01184     bm::bvector<>::enumerator en = inputprogram.edb->getStorage().first();
01185     bm::bvector<>::enumerator en_end = inputprogram.edb->getStorage().end();
01186     while (en < en_end) {
01187         ID pred = getPredicateOfAtom(ID(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG, *en));
01188         while (boost::starts_with(reg->getTermStringByID(pred), newPredicateName)) {
01189             newPredicateName += std::string("0");
01190         }
01191         en++;
01192     }
01193 
01194     // create atom
01195     OrdinaryAtom atom(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG);
01196     Term predTerm(ID::MAINKIND_TERM | ID::SUBKIND_TERM_CONSTANT, newPredicateName);
01197     ID predID = reg->storeTerm(predTerm);
01198     atom.tuple.push_back(predID);
01199     globallyNewAtom = reg->storeOrdinaryGAtom(atom);
01200 }
01201 
01202 
01203 InternalGrounder::Binder InternalGrounder::getBinderOfRule(std::vector<ID>& body)
01204 {
01205 
01206     Binder binders;
01207     int litIdx = 0;
01208     BOOST_FOREACH (ID lit, body) {
01209         std::set<ID> varsInLit;
01210         reg->getVariablesInID(lit, varsInLit);
01211         BOOST_FOREACH (ID var, varsInLit) {
01212             if (binders.find(var) == binders.end()) {
01213                 DBGLOG(DBG, "Binder of variable " << var << " is literal " << litIdx);
01214                 binders[var] = litIdx;
01215             }
01216         }
01217         ++litIdx;
01218     }
01219     return binders;
01220 }
01221 
01222 
01223 int InternalGrounder::getClosestBinder(std::vector<ID>& body, int litIndex, std::set<ID> variables /*do not make this a reference because it is used as working copy!*/ ){
01224 
01225 int cb = -1;
01226 for (int i = 0; i < litIndex; ++i) {
01227     // is this literal a binder of some variable?
01228     if (!body[i].isNaf()) {
01229         std::set<ID> varsInLit;
01230         reg->getVariablesInID(body[i], varsInLit);
01231         BOOST_FOREACH(ID v, varsInLit) {
01232             if (variables.count(v) > 0) {
01233                 cb = i;
01234                                  // make sure that only the first literal with v is recognized as binder of v
01235                 variables.erase(v);
01236             }
01237         }
01238     }
01239 }
01240 
01241 
01242 return cb;
01243 }
01244 
01245 
01246 std::set<ID> InternalGrounder::getFreeVars(std::vector<ID>& body, int litIndex)
01247 {
01248 
01249     std::set<ID> vars;
01250     reg->getVariablesInID(body[litIndex], vars);
01251     for (int i = 0; i < litIndex; ++i) {
01252         std::set<ID> v2;
01253         reg->getVariablesInID(body[i], v2);
01254         // check if v2 contains some variable in vars
01255         BOOST_FOREACH (ID v, v2) {
01256             vars.erase(v);
01257         }
01258     }
01259     return vars;
01260 }
01261 
01262 
01263 std::set<ID> InternalGrounder::getOutputVariables(ID ruleID)
01264 {
01265 
01266     // compute output variables of this rule
01267     // this is the set of all variables which occur in literals over unsolved predicates
01268     const Rule& rule = reg->rules.getByID(ruleID);
01269     std::set<ID> outputVars;
01270     BOOST_FOREACH (ID headLitIndex, rule.head) {
01271         if (!isPredicateSolved(getPredicateOfAtom(headLitIndex))) {
01272             reg->getVariablesInID(headLitIndex, outputVars);
01273         }
01274     }
01275     BOOST_FOREACH (ID bodyLitIndex, rule.body) {
01276         // if the head does not contain variables, all body variables are output variables
01277         if (!isPredicateSolved(getPredicateOfAtom(bodyLitIndex))) {
01278             reg->getVariablesInID(bodyLitIndex, outputVars);
01279         }
01280     }
01281 
01282     #ifndef NDEBUG
01283     DBGLOG(DBG, "Output variables:");
01284     BOOST_FOREACH (ID var, outputVars) {
01285         DBGLOG(DBG, "" << var.address);
01286     }
01287     #endif
01288 
01289     return outputVars;
01290 }
01291 
01292 
01293 std::vector<ID> InternalGrounder::reorderRuleBody(ID ruleID)
01294 {
01295 
01296     const Rule& rule = reg->rules.getByID(ruleID);
01297 
01298     // reorder literals in rule body
01299     std::vector<ID> body;
01300 
01301     // 1. positive
01302     BOOST_FOREACH (ID lit, rule.body) {
01303         if (!(lit.isNaf() || lit.isBuiltinAtom())) body.push_back(lit);
01304     }
01305 
01306     // 2. builtin
01307 
01308     // dependency graph
01309     typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, ID> BIDepGraph;
01310     typedef BIDepGraph::vertex_descriptor BINode;
01311     std::map<ID, BINode> biDepNodes;
01312     std::map<BINode, ID> biDepNodesIndex;
01313     BIDepGraph biDepGraph;
01314 
01315     BOOST_FOREACH (ID lit, rule.body) {
01316         // all builtin-atoms are nodes in the dep graph
01317         if (lit.isBuiltinAtom()) {
01318 
01319             biDepNodes[lit] = boost::add_vertex(lit, biDepGraph);
01320             biDepNodesIndex[biDepNodes[lit]] = lit;
01321 
01322             // add edges between depending nodes
01323             BOOST_FOREACH (ID lit2, rule.body) {
01324                 if (lit2.isBuiltinAtom() && lit != lit2) {
01325                     if (biDependency(lit, lit2)) {
01326                         boost::add_edge(biDepNodes[lit], biDepNodes[lit2], biDepGraph);
01327                     }
01328                 }
01329             }
01330         }
01331     }
01332     // get topological ordering
01333 
01334     // compute topological ordering of components
01335     std::vector<BINode> biOrdering;
01336     topological_sort(biDepGraph, std::back_inserter(biOrdering));
01337     DBGLOG(DBG, "Processing BI-atoms in the following ordering:");
01338     BOOST_FOREACH (BINode biAtomNode, biOrdering) {
01339         ID biAtom = biDepNodesIndex[biAtomNode];
01340         DBGLOG(DBG, "" << biAtom.address);
01341         body.push_back(biAtom);
01342     }
01343 
01344     // 3. naf
01345     BOOST_FOREACH (ID lit, rule.body) {
01346         if (lit.isNaf()) body.push_back(lit);
01347     }
01348 
01349     return body;
01350 }
01351 
01352 
01353 bool InternalGrounder::biDependency(ID bi1, ID bi2)
01354 {
01355 
01356     const BuiltinAtom& biAtom1 = reg->batoms.getByID(bi1);
01357     const BuiltinAtom& biAtom2 = reg->batoms.getByID(bi2);
01358 
01359     std::set<ID> output1;
01360     std::set<ID> input2;
01361 
01362     switch(biAtom1.tuple.size()) {
01363         case 2:
01364             output1.insert(biAtom1.tuple[1]);
01365             break;
01366         case 3:
01367             output1.insert(biAtom1.tuple[2]);
01368             break;
01369         case 4:
01370             output1.insert(biAtom1.tuple[3]);
01371             break;
01372         default:
01373             assert(false);
01374     }
01375     switch(biAtom2.tuple.size()) {
01376         case 2:
01377             break;
01378         case 3:
01379             output1.insert(biAtom1.tuple[1]);
01380             break;
01381         case 4:
01382             output1.insert(biAtom1.tuple[1]);
01383             output1.insert(biAtom1.tuple[2]);
01384             break;
01385         default:
01386             assert(false);
01387     }
01388     BOOST_FOREACH (ID i2, input2) {
01389         if (output1.count(i2) > 0) return true;
01390     }
01391     return false;
01392 }
01393 
01394 
01395 int InternalGrounder::applyIntFunction(AppDir ad, ID op, int x, int y)
01396 {
01397 
01398     switch(ad) {
01399         case x_op_y_eq_ret:
01400             switch (op.address) {
01401                 case ID::TERM_BUILTIN_ADD: return x + y;
01402                 case ID::TERM_BUILTIN_MUL: return x * y;
01403                 case ID::TERM_BUILTIN_SUB: return x - y;
01404                 case ID::TERM_BUILTIN_DIV:
01405                     if (y == 0) return -1;
01406                     return x / y;
01407                 case ID::TERM_BUILTIN_MOD:
01408                     if (y == 0) return -1;
01409                     return x % y;
01410             }
01411             break;
01412         case x_op_ret_eq_y:
01413             switch (op.address) {
01414                 case ID::TERM_BUILTIN_ADD: return y - x;
01415                 case ID::TERM_BUILTIN_MUL:
01416                     if (x == 0) return -1;
01417                     if (y % x == 0) return y / x;
01418                 case ID::TERM_BUILTIN_SUB: return x - y;
01419                 case ID::TERM_BUILTIN_DIV:
01420                     if (y == 0) return -1;
01421                     if (x % y == 0) return x / y;
01422             }
01423             break;
01424         case ret_op_y_eq_x:
01425             switch (op.address) {
01426                 case ID::TERM_BUILTIN_ADD: return x - y;
01427                 case ID::TERM_BUILTIN_MUL:
01428                     if (y == 0) return -1;
01429                     if (x % y == 0) return x / y;
01430                 case ID::TERM_BUILTIN_SUB: return x + y;
01431                 case ID::TERM_BUILTIN_DIV: return x * y;
01432             }
01433             break;
01434     }
01435     return -1;
01436 }
01437 
01438 
01439 InternalGrounder::InternalGrounder(ProgramCtx& c, const OrdinaryASPProgram& p, OptLevel ol) : inputprogram(p), groundProgram(p), ctx(c), optlevel(ol)
01440 {
01441 
01442     DBGLOG(DBG, "Starting grounding");
01443     DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidgroundertime, "Grounder time");
01444 
01445     reg = ctx.registry();
01446 
01447     trueAtoms = InterpretationPtr(new Interpretation(reg));
01448 
01449     computeDepGraph();
01450     computeStrata();
01451     computeGloballyNewAtom();
01452 
01453     // now ground stratum by stratum
01454     for (uint32_t stratumNr = 0; stratumNr < predicatesOfStratum.size(); ++stratumNr) {
01455         groundStratum(stratumNr);
01456     }
01457 
01458     groundProgram = OrdinaryASPProgram(reg, groundRules, trueAtoms, inputprogram.maxint, inputprogram.mask);
01459 
01460     #ifndef NDEBUG
01461     const OrdinaryASPProgram& gp = getGroundProgram();
01462 
01463     std::stringstream ss;
01464     ss << *trueAtoms << " (" << trueAtoms->getStorage().count() << ")";
01465     ss << std::endl;
01466     BOOST_FOREACH (ID ruleID, groundRules) {
01467         ss << ruleToString(ruleID) << std::endl;
01468     }
01469     DBGLOG(DBG, "Grounded program: " << std::endl << ss.str());
01470     #endif
01471 }
01472 
01473 
01474 std::string InternalGrounder::getGroundProgramString()
01475 {
01476 
01477     std::stringstream ss;
01478 
01479     // add edb
01480     bm::bvector<>::enumerator en = trueAtoms->getStorage().first();
01481     bm::bvector<>::enumerator en_end = trueAtoms->getStorage().end();
01482 
01483     std::set<ID> newGroundRules;
01484     while (en < en_end) {
01485         ss << ruleToString(ID(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG, *en)) << "." << std::endl;
01486         en++;
01487     }
01488 
01489     // add idb
01490     ss << std::endl;
01491     BOOST_FOREACH (ID ruleID, groundRules) {
01492         ss << ruleToString(ruleID) << std::endl;
01493     }
01494     return ss.str();
01495 }
01496 
01497 
01498 std::string InternalGrounder::getNongroundProgramString()
01499 {
01500 
01501     std::stringstream ss;
01502 
01503     // add edb
01504     bm::bvector<>::enumerator en = inputprogram.edb->getStorage().first();
01505     bm::bvector<>::enumerator en_end = inputprogram.edb->getStorage().end();
01506 
01507     while (en < en_end) {
01508         ss << ruleToString(ID(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG, *en)) << "." << std::endl;
01509         en++;
01510     }
01511 
01512     // add idb
01513     ss << std::endl;
01514     BOOST_FOREACH (ID ruleID, inputprogram.idb) {
01515         ss << ruleToString(ruleID) << std::endl;
01516     }
01517     return ss.str();
01518 }
01519 
01520 
01521 const OrdinaryASPProgram& InternalGrounder::getGroundProgram()
01522 {
01523 
01524     return groundProgram;
01525 }
01526 
01527 
01528 const OrdinaryASPProgram& InternalGrounder::getNongroundProgram()
01529 {
01530 
01531     return inputprogram;
01532 }
01533 
01534 
01535 DLVHEX_NAMESPACE_END
01536 
01537 // vim:expandtab:ts=4:sw=4:
01538 // mode: C++
01539 // End: