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