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