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 #ifndef GRINGO3 // GRINGO4 00039 00040 #ifdef HAVE_LIBGRINGO 00041 00042 #include "gringo/input/groundtermparser.hh" 00043 #include "dlvhex2/GringoGrounder.h" 00044 #include "dlvhex2/Rule.h" 00045 #include "dlvhex2/Benchmarking.h" 00046 00047 #include <boost/tokenizer.hpp> 00048 00049 #include <iostream> 00050 #include <sstream> 00051 #include <stdio.h> 00052 #include <algorithm> 00053 #include <utility> 00054 00055 using dlvhex::ID; 00056 00057 #define DEBUG_GRINGOPARSER 00058 00059 #ifdef DEBUG_GRINGOPARSER 00060 # define GPDBGLOG(a,b) DBGLOG(a,b) 00061 #else 00062 # define GPDBGLOG(a,b) do { } while(false); 00063 #endif 00064 00065 DLVHEX_NAMESPACE_BEGIN 00066 00067 void GringoGrounder::Printer::printRule(ID id) 00068 { 00069 00070 const Rule& r = registry->rules.getByID(id); 00071 00072 // check if there is an unsatisfied ground atom 00073 BOOST_FOREACH (ID b, r.body) { 00074 if (b.isBuiltinAtom()) { 00075 const BuiltinAtom& bi = registry->batoms.getByID(b); 00076 if (bi.tuple.size() == 3 && bi.tuple[0] == ID::termFromBuiltin(ID::TERM_BUILTIN_EQ)) { 00077 if ((bi.tuple[1].isConstantTerm() || bi.tuple[1].isIntegerTerm()) && (bi.tuple[2].isConstantTerm() || bi.tuple[2].isIntegerTerm())) { 00078 if (bi.tuple[1] != bi.tuple[2]) { 00079 // skip rule 00080 return; 00081 } 00082 } 00083 } 00084 } 00085 } 00086 00087 // disjunction in rule heads is | not v 00088 printmany(r.head, " | "); 00089 if(r.headGuard.size() > 0) { 00090 out << " : "; 00091 printmany(r.headGuard, ","); 00092 } 00093 if( !r.body.empty() ) { 00094 bool first = true; 00095 BOOST_FOREACH (ID b, r.body) { 00096 // gringo does not accept equalities of type constant=Variable, so reverse them 00097 // also remove equlities between equal ground terms 00098 if (b.isBuiltinAtom()) { 00099 const BuiltinAtom& bi = registry->batoms.getByID(b); 00100 if (bi.tuple.size() == 3 && (bi.tuple[1].isConstantTerm() || bi.tuple[1].isIntegerTerm()) && (bi.tuple[2].isConstantTerm() || bi.tuple[2].isIntegerTerm())) { 00101 if (bi.tuple[0].address == ID::TERM_BUILTIN_EQ && bi.tuple[1] == bi.tuple[2] || 00102 bi.tuple[0].address == ID::TERM_BUILTIN_NE && bi.tuple[1] != bi.tuple[2]) { 00103 // skip 00104 continue; 00105 } 00106 } 00107 else if (bi.tuple.size() == 3 && (bi.tuple[1].isConstantTerm() || bi.tuple[1].isIntegerTerm()) && bi.tuple[2].isVariableTerm()) { 00108 BuiltinAtom bi2 = bi; 00109 bi2.tuple[1] = bi.tuple[2]; 00110 bi2.tuple[2] = bi.tuple[1]; 00111 bi2.tuple[0].address = ID::reverseBinaryOperator(bi2.tuple[0].address); 00112 if (first) { 00113 out << " :- "; 00114 } 00115 else { 00116 out << ", "; 00117 } 00118 first = false; 00119 print(b.isNaf() ? ID::nafLiteralFromAtom(registry->batoms.storeAndGetID(bi2)) : ID::posLiteralFromAtom(registry->batoms.storeAndGetID(bi2))); 00120 continue; 00121 } 00122 } 00123 00124 if (first) { 00125 out << " :- "; 00126 } 00127 else { 00128 out << ", "; 00129 } 00130 first = false; 00131 00132 print(b); 00133 } 00134 } 00135 out << "."; 00136 } 00137 00138 00139 void GringoGrounder::Printer::printAggregate(ID id) 00140 { 00141 00142 // we support aggregates of one of the four kinds: 00143 // 1. l <= #agg{...} <= u 00144 // 2. v = #agg{...} 00145 // 3. l <= #agg{...} 00146 // 4. #agg{...} <= u 00147 const AggregateAtom& aatom = registry->aatoms.getByID(id); 00148 00149 // skipping the domain predicate is only possible when both bounds are specified and equal 00150 bool assignment = ( aatom.tuple[0] != ID_FAIL && aatom.tuple[1] == ID::termFromBuiltin(ID::TERM_BUILTIN_EQ) ) 00151 || ( aatom.tuple[4] != ID_FAIL && aatom.tuple[3] == ID::termFromBuiltin(ID::TERM_BUILTIN_EQ) ); 00152 00153 ID lowerbound, upperbound; 00154 // 1. l <= #agg{...} <= u 00155 if (aatom.tuple[0] != ID_FAIL && aatom.tuple[1] == ID::termFromBuiltin(ID::TERM_BUILTIN_LE) && 00156 aatom.tuple[4] != ID_FAIL && aatom.tuple[3] == ID::termFromBuiltin(ID::TERM_BUILTIN_LE)) { 00157 lowerbound = aatom.tuple[0]; 00158 upperbound = aatom.tuple[4]; 00159 // gringo expects a domain predicate: use #int 00160 if (!assignment && lowerbound.isVariableTerm()) { 00161 print(intPred); 00162 out << "("; 00163 print(lowerbound); 00164 out << "), "; 00165 } 00166 if (!assignment && upperbound.isVariableTerm()) { 00167 print(intPred); 00168 out << "("; 00169 print(upperbound); 00170 out << "), "; 00171 } 00172 // 2. v = #agg{...} 00173 }else if (aatom.tuple[0] != ID_FAIL && aatom.tuple[1] == ID::termFromBuiltin(ID::TERM_BUILTIN_EQ) && 00174 aatom.tuple[4] == ID_FAIL) { 00175 lowerbound = aatom.tuple[0]; 00176 upperbound = aatom.tuple[0]; 00177 // gringo expects a domain predicate: use #int 00178 if (!assignment && lowerbound.isVariableTerm()) { 00179 print(intPred); 00180 out << "("; 00181 print(lowerbound); 00182 out << "), "; 00183 } 00184 // 3. l <= #agg{...} 00185 }else if (aatom.tuple[0] != ID_FAIL && aatom.tuple[1] == ID::termFromBuiltin(ID::TERM_BUILTIN_LE) && 00186 aatom.tuple[4] == ID_FAIL) { 00187 lowerbound = aatom.tuple[0]; 00188 // gringo expects a domain predicate: use #int 00189 if (!assignment && lowerbound.isVariableTerm()) { 00190 print(intPred); 00191 out << "("; 00192 print(lowerbound); 00193 out << "), "; 00194 } 00195 // 4. #agg{...} <= u 00196 }else if (aatom.tuple[0] == ID_FAIL && aatom.tuple[3] == ID::termFromBuiltin(ID::TERM_BUILTIN_LE) && 00197 aatom.tuple[4] != ID_FAIL) { 00198 upperbound = aatom.tuple[4]; 00199 // gringo expects a domain predicate: use #int 00200 if (!assignment && upperbound.isVariableTerm()) { 00201 print(intPred); 00202 out << "("; 00203 print(upperbound); 00204 out << "), "; 00205 } 00206 } 00207 else { 00208 throw GeneralError("GringoGrounder can only handle aggregates of form: l <= #agg{...} <= u or v = #agg{...} or l <= #agg{...} or #agg{...} <= u with exactly one atom in the aggregate body"); 00209 } 00210 if (aatom.literals.size() > 1) throw GeneralError("GringoGrounder can only handle aggregates of form: l <= #agg{...} <= u or v = #agg{...} with exactly one atom in the aggregate body (use --aggregate-enable --aggregate-mode=simplify)"); 00211 00212 if (id.isLiteral() && id.isNaf()) out << "not "; 00213 00214 if (aatom.tuple[2] == ID::termFromBuiltin(ID::TERM_BUILTIN_AGGAVG)) { 00215 throw PluginError("Aggregate #avg is unsupported in Gringo backend"); 00216 } 00217 00218 if (assignment) { 00219 print(lowerbound); 00220 out << "="; 00221 print(aatom.tuple[2]); 00222 out << "{"; 00223 printmany(aatom.variables, ","); 00224 out << ":"; 00225 printmany(aatom.literals, ","); 00226 out << "}"; 00227 } 00228 else { 00229 if(lowerbound != ID_FAIL) print(lowerbound); 00230 print(aatom.tuple[2]); 00231 out << "{"; 00232 printmany(aatom.variables, ","); 00233 out << ":"; 00234 printmany(aatom.literals, ","); 00235 out << "}"; 00236 if(upperbound != ID_FAIL) print(upperbound); 00237 } 00238 } 00239 00240 00241 void GringoGrounder::Printer::printInt(ID id) 00242 { 00243 // replace #int by a standard but unique predicate 00244 print(intPred); 00245 } 00246 00247 00248 void GringoGrounder::Printer::print(ID id) 00249 { 00250 if(id.isRule()) { 00251 if (id.isWeakConstraint()) throw GeneralError("Gringo-based grounder does not support weak constraints"); 00252 printRule(id); 00253 } 00254 else if((id.isAtom() || id.isLiteral()) && id.isAggregateAtom()) { 00255 printAggregate(id); 00256 } 00257 else if(id.isTerm() && id.isBuiltinTerm() && id == ID::termFromBuiltin(ID::TERM_BUILTIN_INT)) { 00258 printInt(id); 00259 } 00260 else if(id.isNaf() && id.isLiteral() && id.isBuiltinAtom()) { 00261 const BuiltinAtom& bi = registry->batoms.getByID(id); 00262 print(bi.tuple[1]); 00263 print(ID::termFromBuiltin(static_cast<dlvhex::ID::TermBuiltinAddress>(ID::negateBinaryOperator(bi.tuple[0].address)))); 00264 print(bi.tuple[2]); 00265 } 00266 else { 00267 Base::print(id); 00268 } 00269 } 00270 00271 00272 GringoGrounder::GroundHexProgramBuilder::GroundHexProgramBuilder(ProgramCtx& ctx, OrdinaryASPProgram& groundProgram, ID intPred, ID anonymousPred, ID unsatPred, bool incAdd) 00273 : Gringo::Output::PlainLparseOutputter(emptyStream), ctx(ctx), groundProgram(groundProgram), symbols_(1), intPred(intPred), anonymousPred(anonymousPred), unsatPred(unsatPred) 00274 { 00275 00276 // Note: We do NOT use shifting but ground disjunctive rules as they are. 00277 // Shifting is instead done in ClaspSolver (as clasp does not support disjunctions) 00278 // This allows for using also other solver-backends which support disjunctive programs. 00279 00280 // take the mask passed with the input program; 00281 // it might be extended during grounding in case that intermediate symbols are introduced 00282 mask = InterpretationPtr(new Interpretation(ctx.registry())); 00283 if (groundProgram.mask != InterpretationConstPtr()) { 00284 mask->add(*groundProgram.mask); 00285 } 00286 groundProgram.mask = mask; 00287 this->incAdd = incAdd; 00288 } 00289 00290 00291 void GringoGrounder::GroundHexProgramBuilder::addSymbol(uint32_t symbol) 00292 { 00293 00294 // check if the symbol is in the list 00295 if (indexToGroundAtomID.find(symbol) != indexToGroundAtomID.end()) { 00296 // nothing to do 00297 } 00298 else { 00299 assert(anonymousPred != ID_FAIL); 00300 assert(!anonymousPred.isVariableTerm()); 00301 00302 // create a propositional atom with this name 00303 OrdinaryAtom ogatom(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG | ID::PROPERTY_ATOM_HIDDEN); 00304 std::stringstream name; 00305 name << ctx.registry()->terms.getByID(anonymousPred).symbol << "(" << symbol << ")"; 00306 ogatom.text = name.str(); 00307 if( anonymousPred.isAuxiliary() ) ogatom.kind |= ID::PROPERTY_AUX; 00308 if( anonymousPred.isExternalAuxiliary() ) ogatom.kind |= ID::PROPERTY_EXTERNALAUX; 00309 if( anonymousPred.isExternalInputAuxiliary() ) ogatom.kind |= ID::PROPERTY_EXTERNALINPUTAUX; 00310 ogatom.tuple.push_back(anonymousPred); 00311 ogatom.tuple.push_back(ID::termFromInteger(symbol)); 00312 ID aid = ctx.registry()->ogatoms.getIDByTuple(ogatom.tuple); 00313 if (aid == ID_FAIL) { 00314 aid = ctx.registry()->ogatoms.storeAndGetID(ogatom); 00315 } 00316 assert(aid != ID_FAIL); 00317 00318 // we have now a new ID: add it to the table 00319 indexToGroundAtomID[symbol] = aid; 00320 00321 // remove dummy atoms from models 00322 mask->setFact(aid.address); 00323 } 00324 } 00325 00326 00327 void GringoGrounder::GroundHexProgramBuilder::finishRules() 00328 { 00329 } 00330 00331 00332 void GringoGrounder::GroundHexProgramBuilder::transformRules() 00333 { 00334 00335 const int false_ = 1; // Gringo index 1 is constant "false" 00336 00337 DBGLOG(DBG, "Transforming " << rules.size() << " rules to DLVHEX"); 00338 InterpretationPtr edb = InterpretationPtr(new Interpretation(ctx.registry())); 00339 if (incAdd) edb->add(*groundProgram.edb); 00340 groundProgram.edb = edb; 00341 if (!incAdd) { 00342 groundProgram.idb.clear(); 00343 groundProgram.idb.reserve(rules.size()); 00344 } 00345 BOOST_FOREACH (const LParseRule& lpr, rules) { 00346 Rule r(ID::MAINKIND_RULE); 00347 switch (lpr.type) { 00348 case LParseRule::Weight: 00349 r.kind |= ID::SUBKIND_RULE_WEIGHT; 00350 BOOST_FOREACH (uint32_t w, lpr.weights) r.bodyWeightVector.push_back(ID::termFromInteger(w)); 00351 DBGLOG(DBG, "Converting a weight rule with bound " << lpr.bound); 00352 r.bound = ID::termFromInteger(lpr.bound); 00353 // do not break here! 00354 case LParseRule::Regular: 00355 if (lpr.head.size() == 1 && lpr.body.size() == 0) { 00356 // facts 00357 if (lpr.head[0] == false_) { 00358 // special case: unsatisfiable rule: F :- T 00359 // make a constraint :- not unsat, where unsat is not defined elsewhere 00360 00361 OrdinaryAtom ogatom(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG); 00362 ogatom.text = ctx.registry()->terms.getByID(unsatPred).symbol; 00363 ogatom.kind |= ID::PROPERTY_AUX; 00364 ogatom.tuple.push_back(unsatPred); 00365 ID aid = ctx.registry()->ogatoms.getIDByTuple(ogatom.tuple); 00366 if (aid == ID_FAIL) { 00367 aid = ctx.registry()->ogatoms.storeAndGetID(ogatom); 00368 } 00369 assert(aid != ID_FAIL); 00370 00371 r.kind |= ID::SUBKIND_RULE_CONSTRAINT; 00372 r.body.push_back(ID::nafLiteralFromAtom(aid)); 00373 ID rid = ctx.registry()->storeRule(r); 00374 GPDBGLOG(DBG, "Adding rule " << rid << " to enforce inconsistency"); 00375 groundProgram.idb.push_back(rid); 00376 } 00377 else { 00378 // make sure that the fact is in the symbol table 00379 addSymbol(lpr.head[0]); 00380 00381 // skip facts which are not in the symbol table 00382 GPDBGLOG(DBG, "Setting fact " << indexToGroundAtomID[lpr.head[0]].address << " (Gringo: " << lpr.head[0] << ")"); 00383 edb->setFact(indexToGroundAtomID[lpr.head[0]].address); 00384 00385 // project dummy integer facts 00386 if (ctx.registry()->ogatoms.getByAddress(indexToGroundAtomID[lpr.head[0]].address).tuple[0] == intPred) { 00387 mask->setFact(indexToGroundAtomID[lpr.head[0]].address); 00388 } 00389 } 00390 } 00391 else { 00392 // rules 00393 BOOST_FOREACH (uint32_t h, lpr.head) { 00394 if (h != false_) { 00395 addSymbol(h); 00396 00397 if (indexToGroundAtomID.find(h) == indexToGroundAtomID.end()) { 00398 std::stringstream ss; 00399 ss << "Grounding Error: Symbol '" << h << "' not found in symbol table"; 00400 throw GeneralError(ss.str()); 00401 } 00402 r.head.push_back(indexToGroundAtomID[h]); 00403 } 00404 } 00405 BOOST_FOREACH (int p, lpr.body) { 00406 int at = (p < 0 ? -p : p); 00407 addSymbol(at); 00408 00409 if (indexToGroundAtomID.find(at) == indexToGroundAtomID.end()) { 00410 std::stringstream ss; 00411 ss << "Grounding Error: Symbol '" << at << "' not found in symbol table"; 00412 throw GeneralError(ss.str()); 00413 00414 } 00415 r.body.push_back(ID::literalFromAtom(indexToGroundAtomID[at], p < 0)); 00416 } 00417 00418 if (r.head.size() == 0) r.kind |= ID::SUBKIND_RULE_CONSTRAINT; 00419 else { 00420 r.kind |= ID::SUBKIND_RULE_REGULAR; 00421 if (r.head.size() > 1) r.kind |= ID::PROPERTY_RULE_DISJ; 00422 } 00423 ID rid = ctx.registry()->storeRule(r); 00424 DBGLOG(DBG, "Adding rule " << rid << ": " << printToString<RawPrinter>(rid, ctx.registry())); 00425 groundProgram.idb.push_back(rid); 00426 } 00427 break; 00428 } 00429 } 00430 } 00431 00432 00433 void GringoGrounder::GroundHexProgramBuilder::printBasicRule(unsigned head, const LitVec &body) 00434 { 00435 rules.push_back(LParseRule(head, body)); 00436 } 00437 00438 00439 void GringoGrounder::GroundHexProgramBuilder::printChoiceRule(const AtomVec &head, const LitVec &body) 00440 { 00441 rules.push_back(LParseRule(head, body)); 00442 } 00443 00444 00445 void GringoGrounder::GroundHexProgramBuilder::printCardinalityRule(unsigned head, unsigned lower, const LitVec &body) 00446 { 00447 WeightVec weights; 00448 weights.resize(body.size(), 1); 00449 rules.push_back(LParseRule(head, body, weights, lower)); 00450 } 00451 00452 00453 void GringoGrounder::GroundHexProgramBuilder::printWeightRule(unsigned head, unsigned bound, const LitWeightVec &body) 00454 { 00455 LitVec vec; 00456 WeightVec weights; 00457 typedef std::pair<int, unsigned> WeightedLit; 00458 BOOST_FOREACH (WeightedLit wl, body) { 00459 vec.push_back(wl.first); 00460 weights.push_back(wl.second); 00461 } 00462 DBGLOG(DBG, "Found a weight rule with bound " << bound); 00463 rules.push_back(LParseRule(head, vec, weights, bound)); 00464 assert (rules.back().bound == bound && "storing the bound of a weight rule failed"); 00465 } 00466 00467 00468 void GringoGrounder::GroundHexProgramBuilder::printMinimizeRule(const LitWeightVec &body) 00469 { 00470 } 00471 00472 00473 void GringoGrounder::GroundHexProgramBuilder::printDisjunctiveRule(const AtomVec &head, const LitVec &body) 00474 { 00475 rules.push_back(LParseRule(head, body)); 00476 } 00477 00478 00479 void GringoGrounder::GroundHexProgramBuilder::printSymbol(unsigned atomUid, Gringo::Value v) 00480 { 00481 00482 std::stringstream ss; 00483 v.print(ss); 00484 std::string str = ss.str(); 00485 00486 ID dlvhexId = ctx.registry()->ogatoms.getIDByString(str); 00487 if( dlvhexId == ID_FAIL ) { 00488 OrdinaryAtom ogatom(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG, str); 00489 00490 // parse groundatom, register and store 00491 GPDBGLOG(DBG,"parsing gringo ground atom '" << ogatom.text << "'"); 00492 { 00493 // parse atom as nested term 00494 Term dummyTerm(ID::MAINKIND_TERM, ogatom.text); 00495 dummyTerm.analyzeTerm(ctx.registry()); 00496 00497 // extract the predicate 00498 ID id; 00499 if (dummyTerm.arguments.empty()) { 00500 // the predicate is exactly this term which is a constant 00501 // we need to get its ID and probably register it 00502 id = ctx.registry()->storeTerm(dummyTerm); 00503 ogatom.tuple.push_back(id); 00504 } 00505 else { 00506 // this term is hierarchical 00507 // we can just use the tuple of the hierarchical dummy term 00508 // then the predicate is the first argument 00509 ogatom.tuple = dummyTerm.arguments; 00510 id = ogatom.tuple[0]; 00511 } 00512 00513 assert(id != ID_FAIL); 00514 assert(!id.isVariableTerm()); 00515 if( id.isAuxiliary() ) ogatom.kind |= ID::PROPERTY_AUX; 00516 if( id.isExternalAuxiliary() ) ogatom.kind |= ID::PROPERTY_EXTERNALAUX; 00517 if( id.isExternalInputAuxiliary() ) ogatom.kind |= ID::PROPERTY_EXTERNALINPUTAUX; 00518 } 00519 assert (ogatom.tuple.size() > 0 && "Cannot store empty atom"); 00520 dlvhexId = ctx.registry()->ogatoms.storeAndGetID(ogatom); 00521 00522 GPDBGLOG(DBG, "Registered atom " << str << " (arity " << (ogatom.tuple.size() - 1) << ") with tuple " << printvector(ogatom.tuple) << " and Gringo-ID " << atomUid << " and dlvhex-ID " << dlvhexId); 00523 } 00524 else { 00525 GPDBGLOG(DBG, "Found atom " << str << " with Gringo-ID " << atomUid << " and dlvhex-ID " << dlvhexId); 00526 } 00527 00528 indexToGroundAtomID[atomUid] = dlvhexId; 00529 } 00530 00531 00532 void GringoGrounder::GroundHexProgramBuilder::printExternal(unsigned atomUid, Gringo::TruthValue e) 00533 { 00534 } 00535 00536 00537 uint32_t GringoGrounder::GroundHexProgramBuilder::symbol() 00538 { 00539 return symbols_++; 00540 } 00541 00542 00543 GringoGrounder::GringoGrounder(ProgramCtx& ctx, const OrdinaryASPProgram& p, InterpretationConstPtr frozen): 00544 ctx(ctx), nongroundProgram(p), groundProgram(ctx.registry()), frozen(frozen) 00545 { 00546 00547 // we need a unique integer, a unique anonymous and a unique unsat predicate 00548 unsatPred = ctx.registry()->getAuxiliaryConstantSymbol('o', ID::termFromInteger(0)); 00549 anonymousPred = ctx.registry()->getAuxiliaryConstantSymbol('o', ID::termFromInteger(1)); 00550 intPred = ctx.registry()->getAuxiliaryConstantSymbol('o', ID::termFromInteger(2)); 00551 00552 groundProgram.mask = nongroundProgram.mask; 00553 doRun(); 00554 } 00555 00556 00557 const OrdinaryASPProgram& GringoGrounder::getGroundProgram() 00558 { 00559 return groundProgram; 00560 } 00561 00562 namespace{ 00563 struct EmptyMod : public Gringo::GringoModule { 00564 Gringo::Input::GroundTermParser termParser; 00565 virtual Gringo::Value parseValue(std::string const &str) { return termParser.parse(str); } 00566 virtual Gringo::Control *newControl(int, char const **) { throw std::logic_error("creating new control instances not supported in gringo"); } 00567 virtual void freeControl(Gringo::Control *) { throw std::logic_error("creating new control instances not supported in gringo"); } 00568 ~EmptyMod() {} 00569 }; 00570 } 00571 00572 int GringoGrounder::doRun() 00573 { 00574 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidgroundertime, "Grounder time"); 00575 00576 try 00577 { 00578 std::stringstream* programStream = new std::stringstream(); 00579 Printer printer(*programStream, ctx.registry(), intPred); 00580 00581 // print nonground program 00582 if( nongroundProgram.edb != 0 ) { 00583 // print edb interpretation as facts 00584 nongroundProgram.edb->printAsFacts(*programStream); 00585 *programStream << "\n"; 00586 } 00587 00588 // define integer predicateMessagePrinter 00589 printer.printmany(nongroundProgram.idb, "\n"); 00590 *programStream << std::endl; 00591 printer.print(intPred); 00592 *programStream << "(0.." << ctx.maxint << ")."; 00593 00594 // don't spam stderr with warnings (note: Gringo prints to stderr, not to cerr!) 00595 Gringo::message_printer()->disable(Gringo::W_OPERATION_UNDEFINED); 00596 Gringo::message_printer()->disable(Gringo::W_ATOM_UNDEFINED); 00597 Gringo::message_printer()->disable(Gringo::W_FILE_INCLUDED); 00598 Gringo::message_printer()->disable(Gringo::W_VARIABLE_UNBOUNDED); 00599 Gringo::message_printer()->disable(Gringo::W_TOTAL); 00600 00601 // prepare 00602 Gringo::Output::OutputPredicates outPreds; 00603 GroundHexProgramBuilder outputter(ctx, groundProgram, intPred, anonymousPred, unsatPred); 00604 Gringo::Output::OutputBase out(std::move(outPreds), outputter); 00605 EmptyMod mod; 00606 Gringo::Scripts scripts(mod); 00607 Gringo::Defines defs; 00608 Gringo::Input::Program prg; 00609 Gringo::Input::NongroundProgramBuilder pb(scripts, prg, out, defs); 00610 Gringo::Input::NonGroundParser parser(pb); 00611 Gringo::Ground::Parameters params; 00612 Gringo::Input::ProgramVec parts; 00613 00614 if (!!frozen) { 00615 bm::bvector<>::enumerator en = frozen->getStorage().first(); 00616 bm::bvector<>::enumerator en_end = frozen->getStorage().end(); 00617 // declare frozen atoms as external 00618 while (en < en_end) { 00619 *programStream << "#external "; 00620 printer.print(ctx.registry()->ogatoms.getIDByAddress(*en)); 00621 *programStream << "."; 00622 en++; 00623 } 00624 } 00625 00626 LOG(DBG, "Sending the following input to Gringo: {{" << programStream->str() << "}}"); 00627 00628 // grounding 00629 //parser.pushStream("s1", std::unique_ptr<std::stringstream>(new std::stringstream("a | b."))); 00630 parser.pushStream("dlvhex", std::unique_ptr<std::stringstream>(programStream)); 00631 parser.parse(); 00632 prg.rewrite(defs); 00633 prg.check(); 00634 params.add("base", {} 00635 ); 00636 00637 Gringo::Ground::Program gPrg(prg.toGround(out.domains)); 00638 gPrg.ground(params, scripts, out, false); 00639 out.finish(); 00640 outputter.transformRules(); 00641 00642 #if 0 00643 // adding new modules incrementally can be done by repeating the above code as follows: 00644 // (previously defined atoms need to be defined as external in order to prevent them from being optimized away) 00645 { 00646 Gringo::Output::OutputPredicates outPreds; 00647 GroundHexProgramBuilder outputter(ctx, groundProgram, intPred, anonymousPred, true); 00648 Gringo::Output::OutputBase out(std::move(outPreds), outputter); 00649 Gringo::Scripts scripts; 00650 Gringo::Defines defs; 00651 Gringo::Input::Program prg; 00652 Gringo::Input::NongroundProgramBuilder pb(scripts, prg, out, defs); 00653 Gringo::Input::NonGroundParser parser(pb); 00654 Gringo::Ground::Parameters params; 00655 Gringo::Input::ProgramVec parts; 00656 // declare atoms as external: 00657 // *programStream << "#external a."; 00658 00659 // grounding 00660 parser.pushStream("s2", std::unique_ptr<std::stringstream>(new std::stringstream("#external b. c | d :- b."))); 00661 // parser.pushStream("dlvhex", std::unique_ptr<std::stringstream>(programStream)); 00662 parser.parse(); 00663 prg.rewrite(defs); 00664 prg.check(); 00665 params.add("base", {} 00666 ); 00667 00668 Gringo::Ground::Program gPrg(prg.toGround(out.domains)); 00669 gPrg.ground(params, scripts, out, false); 00670 out.finish(); 00671 outputter.transformRules(); 00672 } 00673 #endif 00674 00675 #ifdef DEBUG 00676 // print ground program 00677 std::stringstream groungprogString; 00678 RawPrinter rp(groungprogString, ctx.registry()); 00679 if( groundProgram.edb != 0 ) { 00680 // print edb interpretation as facts 00681 groundProgram.edb->printAsFacts(groungprogString); 00682 groungprogString << "\n"; 00683 } 00684 rp.printmany(groundProgram.idb, "\n"); 00685 groungprogString << std::endl; 00686 LOG(DBG, "Got the following ground program from Gringo: {" << groungprogString.str() << "}"); 00687 #endif 00688 00689 return EXIT_SUCCESS; 00690 } 00691 catch(...) { 00692 DBGLOG(DBG, "Gringo terminated with error"); 00693 throw; 00694 } 00695 } 00696 00697 00698 DLVHEX_NAMESPACE_END 00699 #endif 00700 00701 #else // GRINGO3 00702 00703 #ifdef HAVE_LIBGRINGO 00704 00705 #include "dlvhex2/GringoGrounder.h" 00706 #include <gringo/inclit.h> 00707 #include <gringo/parser.h> 00708 #include <gringo/converter.h> 00709 #include <gringo/grounder.h> 00710 #include <gringo/plainoutput.h> 00711 #include <gringo/lparseoutput.h> 00712 #include <gringo/reifiedoutput.h> 00713 #include "dlvhex2/Rule.h" 00714 #include "dlvhex2/Benchmarking.h" 00715 00716 #include <boost/tokenizer.hpp> 00717 00718 #include <iostream> 00719 #include <sstream> 00720 #include <algorithm> 00721 00722 using dlvhex::ID; 00723 00724 #undef DEBUG_GRINGOPARSER 00725 00726 #ifdef DEBUG_GRINGOPARSER 00727 # define GPDBGLOG(a,b) DBGLOG(a,b) 00728 #else 00729 # define GPDBGLOG(a,b) do { } while(false); 00730 #endif 00731 00732 namespace 00733 { 00734 bool parsePositional(const std::string&, std::string& out) { 00735 out = "file"; 00736 return true; 00737 } 00738 } 00739 00740 00741 DLVHEX_NAMESPACE_BEGIN 00742 00743 void GringoGrounder::Printer::printRule(ID id) 00744 { 00745 00746 const Rule& r = registry->rules.getByID(id); 00747 00748 // check if there is an unsatisfied ground atom 00749 BOOST_FOREACH (ID b, r.body) { 00750 if (b.isBuiltinAtom()) { 00751 const BuiltinAtom& bi = registry->batoms.getByID(b); 00752 if (bi.tuple.size() == 3 && bi.tuple[0] == ID::termFromBuiltin(ID::TERM_BUILTIN_EQ)) { 00753 if ((bi.tuple[1].isConstantTerm() || bi.tuple[1].isIntegerTerm()) && (bi.tuple[2].isConstantTerm() || bi.tuple[2].isIntegerTerm())) { 00754 if (bi.tuple[1] != bi.tuple[2]) { 00755 // skip rule 00756 return; 00757 } 00758 } 00759 } 00760 } 00761 } 00762 00763 // disjunction in rule heads is | not v 00764 printmany(r.head, " | "); 00765 if(r.headGuard.size() > 0) { 00766 out << " : "; 00767 printmany(r.headGuard, ","); 00768 } 00769 if( !r.body.empty() ) { 00770 bool first = true; 00771 BOOST_FOREACH (ID b, r.body) { 00772 // gringo does not accept equalities of type constant=Variable, so reverse them 00773 // also remove equlities between equal ground terms 00774 if (b.isBuiltinAtom()) { 00775 const BuiltinAtom& bi = registry->batoms.getByID(b); 00776 if (bi.tuple.size() == 3 && (bi.tuple[1].isConstantTerm() || bi.tuple[1].isIntegerTerm()) && (bi.tuple[2].isConstantTerm() || bi.tuple[2].isIntegerTerm())) { 00777 if (bi.tuple[0].address == ID::TERM_BUILTIN_EQ && bi.tuple[1] == bi.tuple[2] || 00778 bi.tuple[0].address == ID::TERM_BUILTIN_NE && bi.tuple[1] != bi.tuple[2]) { 00779 // skip 00780 continue; 00781 } 00782 } 00783 else if (bi.tuple.size() == 3 && (bi.tuple[1].isConstantTerm() || bi.tuple[1].isIntegerTerm()) && bi.tuple[2].isVariableTerm()) { 00784 BuiltinAtom bi2 = bi; 00785 bi2.tuple[1] = bi.tuple[2]; 00786 bi2.tuple[2] = bi.tuple[1]; 00787 bi2.tuple[0].address = ID::reverseBinaryOperator(bi2.tuple[0].address); 00788 if (first) { 00789 out << " :- "; 00790 } 00791 else { 00792 out << ", "; 00793 } 00794 first = false; 00795 print(b.isNaf() ? ID::nafLiteralFromAtom(registry->batoms.storeAndGetID(bi2)) : ID::posLiteralFromAtom(registry->batoms.storeAndGetID(bi2))); 00796 continue; 00797 } 00798 } 00799 00800 if (first) { 00801 out << " :- "; 00802 } 00803 else { 00804 out << ", "; 00805 } 00806 first = false; 00807 00808 // do not print the domain predicate for aggregates in constraints (this could be generalized to non-recursive aggregates!) 00809 if (r.head.empty() && b.isAggregateAtom()) { 00810 printAggregate(b); 00811 } 00812 00813 print(b); 00814 } 00815 } 00816 out << "."; 00817 } 00818 00819 00820 void GringoGrounder::Printer::printAggregate(ID id) 00821 { 00822 00823 // gringo 3 does not support ASP-Core-2 standard, thus we cannot do direct assignments and always need domain predicates! 00824 00825 // we support aggregates of one of the four kinds: 00826 // 1. l <= #agg{...} <= u 00827 // 2. v = #agg{...} 00828 // 3. l <= #agg{...} 00829 // 4. #agg{...} <= u 00830 const AggregateAtom& aatom = registry->aatoms.getByID(id); 00831 00832 ID lowerbound, upperbound; 00833 // 1. l <= #agg{...} <= u 00834 if (aatom.tuple[0] != ID_FAIL && aatom.tuple[1] == ID::termFromBuiltin(ID::TERM_BUILTIN_LE) && 00835 aatom.tuple[4] != ID_FAIL && aatom.tuple[3] == ID::termFromBuiltin(ID::TERM_BUILTIN_LE)) { 00836 lowerbound = aatom.tuple[0]; 00837 upperbound = aatom.tuple[4]; 00838 // gringo expects a domain predicate: use #int 00839 if (lowerbound.isVariableTerm()) { 00840 print(intPred); 00841 out << "("; 00842 print(lowerbound); 00843 out << "), "; 00844 } 00845 if (upperbound.isVariableTerm()) { 00846 print(intPred); 00847 out << "("; 00848 print(upperbound); 00849 out << "), "; 00850 } 00851 // 2. v = #agg{...} 00852 }else if (aatom.tuple[0] != ID_FAIL && aatom.tuple[1] == ID::termFromBuiltin(ID::TERM_BUILTIN_EQ) && 00853 aatom.tuple[4] == ID_FAIL) { 00854 lowerbound = aatom.tuple[0]; 00855 upperbound = aatom.tuple[0]; 00856 // gringo expects a domain predicate: use #int 00857 if (lowerbound.isVariableTerm()) { 00858 print(intPred); 00859 out << "("; 00860 print(lowerbound); 00861 out << "), "; 00862 } 00863 // 3. l <= #agg{...} 00864 }else if (aatom.tuple[0] != ID_FAIL && aatom.tuple[1] == ID::termFromBuiltin(ID::TERM_BUILTIN_LE) && 00865 aatom.tuple[4] == ID_FAIL) { 00866 lowerbound = aatom.tuple[0]; 00867 // gringo expects a domain predicate: use #int 00868 if (lowerbound.isVariableTerm()) { 00869 print(intPred); 00870 out << "("; 00871 print(lowerbound); 00872 out << "), "; 00873 } 00874 // 4. #agg{...} <= u 00875 }else if (aatom.tuple[0] == ID_FAIL && aatom.tuple[3] == ID::termFromBuiltin(ID::TERM_BUILTIN_LE) && 00876 aatom.tuple[4] != ID_FAIL) { 00877 upperbound = aatom.tuple[4]; 00878 // gringo expects a domain predicate: use #int 00879 if (upperbound.isVariableTerm()) { 00880 print(intPred); 00881 out << "("; 00882 print(upperbound); 00883 out << "), "; 00884 } 00885 } 00886 else { 00887 throw GeneralError("GringoGrounder can only handle aggregates of form: l <= #agg{...} <= u or v = #agg{...} or l <= #agg{...} or #agg{...} <= u with exactly one atom in the aggregate body"); 00888 } 00889 if (aatom.literals.size() > 1) throw GeneralError("GringoGrounder can only handle aggregates of form: l <= #agg{...} <= u or v = #agg{...} with exactly one atom in the aggregate body (use --aggregate-enable --aggregate-mode=simplify)"); 00890 00891 if (id.isLiteral() && id.isNaf()) out << "not "; 00892 if (lowerbound != ID_FAIL) print(lowerbound); 00893 print(aatom.tuple[2]); 00894 const OrdinaryAtom& oatom = registry->lookupOrdinaryAtom(aatom.literals[0]); 00895 if (aatom.tuple[2] == ID::termFromBuiltin(ID::TERM_BUILTIN_AGGCOUNT)) { 00896 out << "{"; 00897 print(aatom.literals[0]); 00898 out << "}"; 00899 } 00900 else { 00901 out << "["; 00902 print(aatom.literals[0]); 00903 out << "="; 00904 print(oatom.tuple[oatom.tuple.size() - 1]); 00905 00906 // make the value variable safe 00907 if (oatom.tuple[oatom.tuple.size() - 1].isVariableTerm()) { 00908 out << ":"; 00909 print(intPred); 00910 out << "("; 00911 print(oatom.tuple[oatom.tuple.size() - 1]); 00912 out << ")"; 00913 } 00914 00915 out << "]"; 00916 } 00917 if (upperbound != ID_FAIL) print(upperbound); 00918 } 00919 00920 00921 void GringoGrounder::Printer::printInt(ID id) 00922 { 00923 // replace #int by a standard but unique predicate 00924 print(intPred); 00925 } 00926 00927 00928 void GringoGrounder::Printer::print(ID id) 00929 { 00930 if(id.isRule()) { 00931 if (id.isWeakConstraint()) throw GeneralError("Gringo-based grounder does not support weak constraints"); 00932 printRule(id); 00933 } 00934 else if((id.isAtom() || id.isLiteral()) && id.isAggregateAtom()) { 00935 printAggregate(id); 00936 } 00937 else if(id.isTerm() && id.isBuiltinTerm() && id == ID::termFromBuiltin(ID::TERM_BUILTIN_INT)) { 00938 printInt(id); 00939 } 00940 else if(id.isNaf() && id.isLiteral() && id.isBuiltinAtom()) { 00941 const BuiltinAtom& bi = registry->batoms.getByID(id); 00942 print(bi.tuple[1]); 00943 print(ID::termFromBuiltin(static_cast<dlvhex::ID::TermBuiltinAddress>(ID::negateBinaryOperator(bi.tuple[0].address)))); 00944 print(bi.tuple[2]); 00945 } 00946 else { 00947 Base::print(id); 00948 } 00949 } 00950 00951 00952 GringoGrounder::GroundHexProgramBuilder::GroundHexProgramBuilder(ProgramCtx& ctx, OrdinaryASPProgram& groundProgram, ID intPred, ID unsatPred, ID anonymousPred) : LparseConverter(&emptyStream, false /* disjunction shifting */), ctx(ctx), groundProgram(groundProgram), symbols_(1), intPred(intPred), anonymousPred(anonymousPred), unsatPred(unsatPred){ 00953 // Note: We do NOT use shifting but ground disjunctive rules as they are. 00954 // Shifting is instead done in ClaspSolver (as clasp does not support disjunctions) 00955 // This allows for using also other solver-backends which support disjunctive programs. 00956 00957 // take the mask passed with the input program; 00958 // it might be extended during grounding in case that intermediate symbols are introduced 00959 mask = InterpretationPtr(new Interpretation(ctx.registry())); 00960 if (groundProgram.mask != InterpretationConstPtr()) { 00961 mask->add(*groundProgram.mask); 00962 } 00963 00964 00965 groundProgram.mask = mask; 00966 } 00967 00968 00969 void GringoGrounder::GroundHexProgramBuilder::addSymbol(uint32_t symbol) 00970 { 00971 00972 // check if the symbol is in the list 00973 if (indexToGroundAtomID.find(symbol) != indexToGroundAtomID.end()) { 00974 // nothing to do 00975 } 00976 else { 00977 // this is static because the name needs to be unique only wrt. the whole dlvhex instance (also if we have nested HEX programs) 00978 static ID tid = anonymousPred; 00979 assert(tid != ID_FAIL); 00980 assert(!tid.isVariableTerm()); 00981 00982 // create a propositional atom with this name 00983 OrdinaryAtom ogatom(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG | ID::PROPERTY_ATOM_HIDDEN); 00984 std::stringstream name; 00985 name << ctx.registry()->terms.getByID(tid).symbol << "(" << symbol << ")"; 00986 ogatom.text = name.str(); 00987 if( tid.isAuxiliary() ) ogatom.kind |= ID::PROPERTY_AUX; 00988 if( tid.isExternalAuxiliary() ) ogatom.kind |= ID::PROPERTY_EXTERNALAUX; 00989 if( tid.isExternalInputAuxiliary() ) ogatom.kind |= ID::PROPERTY_EXTERNALINPUTAUX; 00990 ogatom.tuple.push_back(tid); 00991 ogatom.tuple.push_back(ID::termFromInteger(symbol)); 00992 ID aid = ctx.registry()->ogatoms.getIDByTuple(ogatom.tuple); 00993 if (aid == ID_FAIL) { 00994 aid = ctx.registry()->ogatoms.storeAndGetID(ogatom); 00995 } 00996 assert(aid != ID_FAIL); 00997 00998 // we have now a new ID: add it to the table 00999 indexToGroundAtomID[symbol] = aid; 01000 01001 // remove dummy atoms from models 01002 // mask->setFact(aid.address); 01003 } 01004 } 01005 01006 01007 void GringoGrounder::GroundHexProgramBuilder::doFinalize() 01008 { 01009 01010 const int false_ = 1; // Gringo index 1 is constant "false" 01011 01012 DBGLOG(DBG, "Constructing symbol table"); 01013 printSymbolTable(); 01014 01015 DBGLOG(DBG, "Transforming rules to DLVHEX"); 01016 InterpretationPtr edb = InterpretationPtr(new Interpretation(ctx.registry())); 01017 groundProgram.edb = edb; 01018 groundProgram.idb.clear(); 01019 groundProgram.idb.reserve(rules.size()); 01020 BOOST_FOREACH (const LParseRule& lpr, rules) { 01021 Rule r(ID::MAINKIND_RULE); 01022 switch (lpr.type) { 01023 case LParseRule::Weight: 01024 r.kind |= ID::SUBKIND_RULE_WEIGHT; 01025 BOOST_FOREACH (uint32_t w, lpr.wpos) r.bodyWeightVector.push_back(ID::termFromInteger(w)); 01026 BOOST_FOREACH (uint32_t w, lpr.wneg) r.bodyWeightVector.push_back(ID::termFromInteger(w)); 01027 r.bound = ID::termFromInteger(lpr.bound); 01028 // do not break here! 01029 case LParseRule::Regular: 01030 if (lpr.head.size() == 1 && lpr.pos.size() == 0 && lpr.neg.size() == 0) { 01031 // facts 01032 if (lpr.head[0] == false_) { 01033 // special case: unsatisfiable rule: F :- T 01034 // make a constraint :- not unsat, where unsat is not defined elsewhere 01035 01036 OrdinaryAtom ogatom(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG); 01037 ogatom.text = ctx.registry()->terms.getByID(unsatPred).symbol; 01038 ogatom.kind |= ID::PROPERTY_AUX; 01039 ogatom.tuple.push_back(unsatPred); 01040 ID aid = ctx.registry()->ogatoms.getIDByTuple(ogatom.tuple); 01041 if (aid == ID_FAIL) { 01042 aid = ctx.registry()->ogatoms.storeAndGetID(ogatom); 01043 } 01044 assert(aid != ID_FAIL); 01045 01046 r.kind |= ID::SUBKIND_RULE_CONSTRAINT; 01047 r.body.push_back(ID::nafLiteralFromAtom(aid)); 01048 ID rid = ctx.registry()->storeRule(r); 01049 GPDBGLOG(DBG, "Adding rule " << rid << " to enforce inconsistency"); 01050 groundProgram.idb.push_back(rid); 01051 } 01052 else { 01053 // make sure that the fact is in the symbol table 01054 addSymbol(lpr.head[0]); 01055 01056 // skip facts which are not in the symbol table 01057 GPDBGLOG(DBG, "Setting fact " << indexToGroundAtomID[lpr.head[0]].address << " (Gringo: " << lpr.head[0] << ")"); 01058 edb->setFact(indexToGroundAtomID[lpr.head[0]].address); 01059 01060 // project dummy integer facts 01061 if (ctx.registry()->ogatoms.getByAddress(indexToGroundAtomID[lpr.head[0]].address).tuple[0] == intPred) { 01062 mask->setFact(indexToGroundAtomID[lpr.head[0]].address); 01063 } 01064 } 01065 } 01066 else { 01067 // rules 01068 BOOST_FOREACH (uint32_t h, lpr.head) { 01069 if (h != false_) { 01070 addSymbol(h); 01071 01072 if (indexToGroundAtomID.find(h) == indexToGroundAtomID.end()) { 01073 std::stringstream ss; 01074 ss << "Grounding Error: Symbol '" << h << "' not found in symbol table"; 01075 throw GeneralError(ss.str()); 01076 } 01077 r.head.push_back(indexToGroundAtomID[h]); 01078 } 01079 } 01080 BOOST_FOREACH (uint32_t p, lpr.pos) { 01081 addSymbol(p); 01082 01083 if (indexToGroundAtomID.find(p) == indexToGroundAtomID.end()) { 01084 std::stringstream ss; 01085 ss << "Grounding Error: Symbol '" << p << "' not found in symbol table"; 01086 throw GeneralError(ss.str()); 01087 01088 } 01089 r.body.push_back(ID::literalFromAtom(indexToGroundAtomID[p], false)); 01090 } 01091 BOOST_FOREACH (uint32_t n, lpr.neg) { 01092 addSymbol(n); 01093 01094 if (indexToGroundAtomID.find(n) == indexToGroundAtomID.end()) { 01095 std::stringstream ss; 01096 ss << "Grounding Error: Symbol '" << n << "' not found in symbol table"; 01097 throw GeneralError(ss.str()); 01098 01099 } 01100 r.body.push_back(ID::literalFromAtom(indexToGroundAtomID[n], true)); 01101 } 01102 01103 if (r.head.size() == 0) r.kind |= ID::SUBKIND_RULE_CONSTRAINT; 01104 else { 01105 r.kind |= ID::SUBKIND_RULE_REGULAR; 01106 if (r.head.size() > 1) r.kind |= ID::PROPERTY_RULE_DISJ; 01107 } 01108 ID rid = ctx.registry()->storeRule(r); 01109 GPDBGLOG(DBG, "Adding rule " << rid); 01110 groundProgram.idb.push_back(rid); 01111 } 01112 break; 01113 } 01114 } 01115 } 01116 01117 01118 void GringoGrounder::GroundHexProgramBuilder::printBasicRule(int head, const AtomVec &pos, const AtomVec &neg) 01119 { 01120 rules.push_back(LParseRule(head, pos, neg)); 01121 } 01122 01123 01124 void GringoGrounder::GroundHexProgramBuilder::printConstraintRule(int head, int bound, const AtomVec &pos, const AtomVec &neg) 01125 { 01126 WeightVec wpos, wneg; 01127 BOOST_FOREACH (uint32_t p, pos) wpos.push_back(1); 01128 BOOST_FOREACH (uint32_t n, neg) wneg.push_back(1); 01129 rules.push_back(LParseRule(head, pos, neg, wpos, wneg, bound)); 01130 } 01131 01132 01133 void GringoGrounder::GroundHexProgramBuilder::printChoiceRule(const AtomVec &head, const AtomVec &pos, const AtomVec &neg) 01134 { 01135 rules.push_back(LParseRule(head, pos, neg)); 01136 } 01137 01138 01139 void GringoGrounder::GroundHexProgramBuilder::printWeightRule(int head, int bound, const AtomVec &pos, const AtomVec &neg, const WeightVec &wPos, const WeightVec &wNeg) 01140 { 01141 rules.push_back(LParseRule(head, pos, neg, wPos, wNeg, bound)); 01142 } 01143 01144 01145 void GringoGrounder::GroundHexProgramBuilder::printMinimizeRule(const AtomVec &pos, const AtomVec &neg, const WeightVec &wPos, const WeightVec &wNeg) 01146 { 01147 // @TODO: weights 01148 // rules.push_back(LParseRule(head, pos, neg)); 01149 } 01150 01151 01152 void GringoGrounder::GroundHexProgramBuilder::printDisjunctiveRule(const AtomVec &head, const AtomVec &pos, const AtomVec &neg) 01153 { 01154 rules.push_back(LParseRule(head, pos, neg)); 01155 } 01156 01157 01158 void GringoGrounder::GroundHexProgramBuilder::printComputeRule(int models, const AtomVec &pos, const AtomVec &neg) 01159 { 01160 // @TODO 01161 } 01162 01163 01164 void GringoGrounder::GroundHexProgramBuilder::printSymbolTableEntry(const AtomRef &atom, uint32_t arity, const std::string &name) 01165 { 01166 // should be called symbolstarts,lastsymbolends-2,or endofstring-2 01167 std::vector<unsigned> symbolstarts; 01168 symbolstarts.reserve(arity+1); 01169 std::stringstream ss; 01170 ss << name; 01171 if(arity > 0) { 01172 ValVec::const_iterator k = vals_.begin() + atom.second; 01173 ValVec::const_iterator end = k + arity; 01174 ss << "("; 01175 symbolstarts.push_back((unsigned)ss.tellp()); 01176 k->print(s_, ss); 01177 for(++k; k != end; ++k) { 01178 ss << ","; 01179 symbolstarts.push_back((unsigned)ss.tellp()); 01180 k->print(s_, ss); 01181 } 01182 ss << ")"; 01183 symbolstarts.push_back((unsigned)ss.tellp()); 01184 } 01185 else { 01186 symbolstarts.push_back(1 + static_cast<unsigned>(ss.tellp())); 01187 } 01188 //std::cerr << arity << " " << ss.str() << " " << printrange(symbolstarts) << std::endl; 01189 assert(symbolstarts.size() == arity+1); 01190 OrdinaryAtom ogatom(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG, ss.str()); 01191 01192 ID dlvhexId = ctx.registry()->ogatoms.getIDByString(ogatom.text); 01193 01194 if( dlvhexId == ID_FAIL ) { 01195 // parse groundatom, register and store 01196 GPDBGLOG(DBG,"parsing gringo ground atom '" << ogatom.text << "'"); 01197 { 01198 // create ogatom.tuple 01199 unsigned lastsymbolstart = 0; 01200 for(unsigned symidx = 0; symidx < arity+1; symidx++) { 01201 Term term(ID::MAINKIND_TERM, ogatom.text.substr(lastsymbolstart, symbolstarts[symidx]-lastsymbolstart-1)); 01202 term.analyzeTerm(ctx.registry()); 01203 GPDBGLOG(DBG,"got token '" << term.symbol << "'"); 01204 01205 // the following takes care of int vs const/string 01206 ID id = ctx.registry()->storeTerm(term); 01207 assert(id != ID_FAIL); 01208 assert(!id.isVariableTerm()); 01209 if( symidx == 0 && id.isAuxiliary() ) ogatom.kind |= ID::PROPERTY_AUX; 01210 if( symidx == 0 && id.isExternalAuxiliary() ) ogatom.kind |= ID::PROPERTY_EXTERNALAUX; 01211 if( symidx == 0 && id.isExternalInputAuxiliary() ) ogatom.kind |= ID::PROPERTY_EXTERNALINPUTAUX; 01212 ogatom.tuple.push_back(id); 01213 01214 lastsymbolstart = symbolstarts[symidx]; 01215 } 01216 } 01217 dlvhexId = ctx.registry()->ogatoms.storeAndGetID(ogatom); 01218 } 01219 01220 indexToGroundAtomID[atom.first] = dlvhexId; 01221 GPDBGLOG(DBG, "Got atom " << ogatom.text << " (arity " << (ogatom.tuple.size() - 1) << ") with Gringo-ID " << atom.first << " and dlvhex-ID " << dlvhexId); 01222 } 01223 01224 01225 void GringoGrounder::GroundHexProgramBuilder::printExternalTableEntry(const AtomRef &atom, uint32_t arity, const std::string &name) 01226 { 01227 } 01228 01229 01230 uint32_t GringoGrounder::GroundHexProgramBuilder::symbol() 01231 { 01232 return symbols_++; 01233 } 01234 01235 01236 GringoGrounder::GringoGrounder(ProgramCtx& ctx, const OrdinaryASPProgram& p, InterpretationConstPtr frozen): 01237 ctx(ctx), nongroundProgram(p), groundProgram(ctx.registry()), frozen(frozen) 01238 { 01239 gringo.disjShift = false; 01240 01241 // we need a unique integer, a unique anonymous and a unique unsat predicate 01242 unsatPred = ctx.registry()->getAuxiliaryConstantSymbol('o', ID::termFromInteger(0)); 01243 anonymousPred = ctx.registry()->getAuxiliaryConstantSymbol('o', ID::termFromInteger(1)); 01244 intPred = ctx.registry()->getAuxiliaryConstantSymbol('o', ID::termFromInteger(2)); 01245 01246 groundProgram.mask = nongroundProgram.mask; 01247 doRun(); 01248 } 01249 01250 01251 Output *GringoGrounder::output() 01252 { 01253 return new GroundHexProgramBuilder(ctx, groundProgram, intPred, unsatPred, anonymousPred); 01254 } 01255 01256 01257 const OrdinaryASPProgram& GringoGrounder::getGroundProgram() 01258 { 01259 return groundProgram; 01260 } 01261 01262 01263 Streams::StreamPtr GringoGrounder::constStream() const 01264 { 01265 std::auto_ptr<std::stringstream> constants(new std::stringstream()); 01266 for(std::vector<std::string>::const_iterator i = gringo.consts.begin(); i != gringo.consts.end(); ++i) 01267 *constants << "#const " << *i << ".\n"; 01268 return Streams::StreamPtr(constants.release()); 01269 } 01270 01271 01272 int GringoGrounder::doRun() 01273 { 01274 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidgroundertime, "Grounder time"); 01275 01276 // redirect std::cerr output to temporary string because gringo spams std:cerr with lots of useless warnings 01277 std::stringstream errstr; 01278 std::streambuf* origcerr = NULL; 01279 if( !Logger::Instance().shallPrint(Logger::DBG) ) { 01280 // only do this if we are not debugging 01281 // (this origcerr procedure kills all logging in the following) 01282 origcerr = std::cerr.rdbuf(errstr.rdbuf()); 01283 } 01284 01285 try 01286 { 01287 std::ostringstream programStream; 01288 Printer printer(programStream, ctx.registry(), intPred); 01289 01290 // print nonground program 01291 if( nongroundProgram.edb != 0 ) { 01292 // print edb interpretation as facts 01293 nongroundProgram.edb->printAsFacts(programStream); 01294 programStream << "\n"; 01295 } 01296 01297 // define integer predicate 01298 printer.printmany(nongroundProgram.idb, "\n"); 01299 programStream << std::endl; 01300 printer.print(intPred); 01301 programStream << "(0.." << ctx.maxint << ")."; 01302 01303 if (!!frozen) { 01304 bm::bvector<>::enumerator en = frozen->getStorage().first(); 01305 bm::bvector<>::enumerator en_end = frozen->getStorage().end(); 01306 // declare frozen atoms as external 01307 while (en < en_end) { 01308 programStream << "#external "; 01309 printer.print(ctx.registry()->ogatoms.getIDByAddress(*en)); 01310 programStream << "."; 01311 en++; 01312 } 01313 } 01314 01315 LOG(DBG, "Sending the following input to Gringo: {{" << programStream.str() << "}}"); 01316 01317 // grounding 01318 std::auto_ptr<Output> o(output()); 01319 Streams inputStreams; 01320 inputStreams.appendStream(std::auto_ptr<std::istream>(new std::stringstream(programStream.str())), "program"); 01321 programStream.str(""); 01322 if(gringo.groundInput) { 01323 Storage s(o.get()); 01324 Converter c(o.get(), inputStreams); 01325 01326 (void)s; 01327 o->initialize(); 01328 c.parse(); 01329 o->finalize(); 01330 } 01331 else { 01332 IncConfig config; 01333 bool verbose = true; 01334 TermExpansionPtr expansion(new TermExpansion()); 01335 Grounder g(o.get(), verbose, expansion); 01336 Parser p(&g, config, inputStreams, gringo.compat); 01337 01338 config.incBegin = 1; 01339 config.incEnd = config.incBegin + gringo.ifixed; 01340 config.incBase = gringo.ibase; 01341 01342 o->initialize(); 01343 p.parse(); 01344 g.analyze(gringo.depGraph, gringo.stats); 01345 g.ground(); 01346 o->finalize(); 01347 } 01348 01349 // restore cerr output 01350 if( origcerr != NULL ) { 01351 std::cerr.rdbuf(origcerr); 01352 if( errstr.str().size() > 0 ) { 01353 LOG(INFO, "Gringo Output was {" << errstr.str() << "}"); 01354 } 01355 } 01356 01357 // print ground program 01358 #if 1 01359 if( Logger::Instance().shallPrint(Logger::DBG) ) { 01360 std::stringstream groungprogString; 01361 RawPrinter rp(groungprogString, ctx.registry()); 01362 if( groundProgram.edb != 0 ) { 01363 // print edb interpretation as facts 01364 groundProgram.edb->printAsFacts(groungprogString); 01365 groungprogString << "\n"; 01366 } 01367 rp.printmany(groundProgram.idb, "\n"); 01368 groungprogString << std::endl; 01369 LOG(DBG, "Got the following ground program from Gringo: {" << groungprogString.str() << "}"); 01370 } 01371 #endif 01372 01373 return EXIT_SUCCESS; 01374 } 01375 catch(...) { 01376 // restore cerr output 01377 if( origcerr != NULL ) 01378 std::cerr.rdbuf(origcerr); 01379 01380 throw; 01381 } 01382 } 01383 01384 01385 detail::GringoOptions::GringoOptions() 01386 : smodelsOut(false) 01387 , textOut(false) 01388 , metaOut(false) 01389 , groundOnly(false) 01390 , ifixed(1) 01391 , ibase(false) 01392 , groundInput(false) 01393 , disjShift(false) 01394 , compat(false) 01395 , stats(false) 01396 , iexpand(IEXPAND_ALL) 01397 { } 01398 01399 DLVHEX_NAMESPACE_END 01400 #endif 01401 #endif 01402 01403 // vim:expandtab:ts=4:sw=4: 01404 // mode: C++ 01405 // End: