dlvhex  2.5.0
src/PythonPlugin.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                           // HAVE_CONFIG_H
00037 
00038 #ifdef HAVE_PYTHON
00039 
00040 #include <boost/python.hpp>
00041 
00042 #include "dlvhex2/PythonPlugin.h"
00043 #include "dlvhex2/PlatformDefinitions.h"
00044 #include "dlvhex2/ProgramCtx.h"
00045 #include "dlvhex2/State.h"
00046 #include "dlvhex2/Registry.h"
00047 #include "dlvhex2/Printer.h"
00048 #include "dlvhex2/Printhelpers.h"
00049 #include "dlvhex2/PredicateMask.h"
00050 #include "dlvhex2/Logger.h"
00051 #include "dlvhex2/HexParser.h"
00052 #include "dlvhex2/HexParserModule.h"
00053 #include "dlvhex2/HexGrammar.h"
00054 #include "dlvhex2/ExternalLearningHelper.h"
00055 
00056 #include <boost/algorithm/string/predicate.hpp>
00057 #include <boost/lexical_cast.hpp>
00058 
00059 #include <cstring>
00060 
00061 DLVHEX_NAMESPACE_BEGIN
00062 
00063 PythonPlugin::CtxData::CtxData()
00064 {
00065 }
00066 
00067 
00068 PythonPlugin::PythonPlugin():
00069 PluginInterface()
00070 {
00071     setNameVersion("dlvhex-pythonplugin[internal]", 2, 0, 0);
00072 }
00073 
00074 
00075 PythonPlugin::~PythonPlugin()
00076 {
00077 }
00078 
00079 
00080 // output help message for this plugin
00081 void PythonPlugin::printUsage(std::ostream& o) const
00082 {
00083     //    123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-
00084     o << "     --python-plugin=[PATH]" << std::endl
00085         << "                      Add Python script \"PATH\" as new plugin." << std::endl;
00086     o << "     --python-main=PATH" << std::endl
00087         << "                      Call method \"main\" in the specified Python script (with dlvhex support) instead of evaluating a program." << std::endl;
00088     o << "     --python-arg=ARG  Passes arguments to Python (sys.argv) (can be used multiple times)." << std::endl;
00089 }
00090 
00091 
00092 // accepted options: --pythonplugin=[PATH]
00093 //
00094 // processes options for this plugin, and removes recognized options from pluginOptions
00095 // (do not free the pointers, the const char* directly come from argv)
00096 void PythonPlugin::processOptions(
00097 std::list<const char*>& pluginOptions,
00098 ProgramCtx& ctx)
00099 {
00100     PythonPlugin::CtxData& ctxdata = ctx.getPluginData<PythonPlugin>();
00101 
00102     typedef std::list<const char*>::iterator Iterator;
00103     Iterator it;
00104     WARNING("create (or reuse, maybe from potassco?) cmdline option processing facility")
00105         it = pluginOptions.begin();
00106 
00107     ctx.config.setOption("HavePythonMain", 0);
00108     while( it != pluginOptions.end() ) {
00109         bool processed = false;
00110         const std::string str(*it);
00111         if( boost::starts_with(str, "--python-plugin=") ) {
00112             ctxdata.pythonScripts.push_back(str.substr(std::string("--python-plugin=").length()));
00113             processed = true;
00114         }
00115                                  // option renamed in order to have a consistent naming schema, keep for backwards compatibility
00116         else if( boost::starts_with(str, "--pythonplugin=") ) {
00117             ctxdata.pythonScripts.push_back(str.substr(std::string("--pythonplugin=").length()));
00118             processed = true;
00119         }
00120         else if( boost::starts_with(str, "--python-main=") ) {
00121             ctx.config.setStringOption("PythonMain", str.substr(std::string("--python-main=").length()));
00122             ctx.config.setOption("HavePythonMain", 1);
00123             processed = true;
00124         }
00125                                  // option renamed in order to have a consistent naming schema, keep for backwards compatibility
00126         else if( boost::starts_with(str, "--pythonmain=") ) {
00127             ctx.config.setStringOption("PythonMain", str.substr(std::string("--pythonmain=").length()));
00128             ctx.config.setOption("HavePythonMain", 1);
00129             processed = true;
00130         }
00131         else if( boost::starts_with(str, "--python-arg=") ) {
00132             ctxdata.commandlineArguments.push_back(str.substr(std::string("--python-arg=").length()));
00133             processed = true;
00134         }
00135                                  // option renamed in order to have a consistent naming schema, keep for backwards compatibility
00136         else if( boost::starts_with(str, "--pythonarg=") ) {
00137             ctxdata.commandlineArguments.push_back(str.substr(std::string("--pythonarg=").length()));
00138             processed = true;
00139         }
00140 
00141         if( processed ) {
00142             // return value of erase: element after it, maybe end()
00143             DBGLOG(DBG,"PythonPlugin successfully processed option " << str);
00144             it = pluginOptions.erase(it);
00145         }
00146         else {
00147             it++;
00148         }
00149     }
00150 }
00151 
00152 
00153 namespace
00154 {
00155 
00156     typedef PythonPlugin::CtxData CtxData;
00157 
00158     class PythonRewriter:
00159     public PluginRewriter
00160     {
00161         private:
00162             PythonPlugin::CtxData& ctxdata;
00163         public:
00164             PythonRewriter(PythonPlugin::CtxData& ctxdata) : ctxdata(ctxdata) {}
00165             virtual ~PythonRewriter() {}
00166 
00167             virtual void rewrite(ProgramCtx& ctx);
00168     };
00169 
00170     void PythonRewriter::rewrite(ProgramCtx& ctx) {
00171     }
00172 
00173 }                                // anonymous namespace
00174 
00175 
00176 // rewrite program
00177 PluginRewriterPtr PythonPlugin::createRewriter(ProgramCtx& ctx)
00178 {
00179     PythonPlugin::CtxData& ctxdata = ctx.getPluginData<PythonPlugin>();
00180     return PluginRewriterPtr(new PythonRewriter(ctxdata));
00181 }
00182 
00183 
00184 // register context data
00185 void PythonPlugin::setupProgramCtx(ProgramCtx& ctx)
00186 {
00187     PythonPlugin::CtxData& ctxdata = ctx.getPluginData<PythonPlugin>();
00188     RegistryPtr reg = ctx.registry();
00189 }
00190 
00191 
00192 namespace
00193 {
00194 
00195     inline long IDToLong(ID id) {
00196         long l = ((long)id.kind << 32 ) | ((long)id.address);
00197         DBGLOG(DBG, "Stored ID " << id << " as " << l);
00198         return l;
00199     }
00200 
00201     inline ID longToID(long l) {
00202         ID id;
00203         id.kind = (l >> 32) & 0xFFFFFFFF;
00204         id.address = l & 0xFFFFFFFF;
00205         return id;
00206     }
00207 
00208 }
00209 
00210 
00211 namespace PythonAPI
00212 {
00213     ProgramCtx* emb_ctx;
00214     const PluginAtom::Query* emb_query;
00215     PluginAtom::Answer* emb_answer;
00216     NogoodContainerPtr emb_nogoods;
00217     bool emb_learnsupportsets;
00218     PredicateMaskPtr emb_eareplacements;
00219     std::vector<PluginAtomPtr> *emb_pluginAtoms;
00220     boost::python::object main;
00221     boost::python::object dict;
00222 }
00223 
00224 
00225 class PythonAtom : public PluginAtom
00226 {
00227     public:
00228         PythonAtom(ProgramCtx& ctx, std::string module, std::string functionName, std::vector<InputType> inputParameters, int outputArity, dlvhex::ExtSourceProperties prop)
00229         : PluginAtom(functionName.c_str(), false) {
00230             BOOST_FOREACH (InputType type, inputParameters) {
00231                 switch (type) {
00232                     case CONSTANT: addInputConstant(); break;
00233                     case PREDICATE: addInputPredicate(); break;
00234                     case TUPLE: addInputTuple(); break;
00235                 }
00236             }
00237             setOutputArity(outputArity);
00238 
00239             // update properties
00240             this->prop = prop;
00241         }
00242 
00243         virtual void
00244         retrieve(const Query& query, Answer& answer) throw (PluginError) {
00245             assert (false);
00246         }
00247 
00248         virtual void
00249         retrieve(const Query& query, Answer& answer, NogoodContainerPtr nogoods) throw (PluginError) {
00250             try
00251             {
00252                 DBGLOG(DBG, "Preparing Python for query");
00253                 PythonAPI::emb_query = &query;
00254                 PythonAPI::emb_answer = &answer;
00255                 PythonAPI::emb_nogoods = nogoods;
00256                 PythonAPI::emb_learnsupportsets = false;
00257                 if (query.eatomID != ID_FAIL) {
00258                     PythonAPI::emb_eareplacements = query.ctx->registry()->eatoms.getByID(query.eatomID).pluginAtom->getReplacements();
00259                 }
00260 
00261                 boost::python::tuple t;
00262                 DBGLOG(DBG, "Constructing input tuple");
00263                 for (int i = 0; i < getInputArity(); ++i) {
00264                     if (getInputType(i) != TUPLE) t += boost::python::make_tuple(query.input[i]);
00265                     else {
00266                         boost::python::tuple tupleparameters;
00267                         for (int var = i; var < query.input.size(); ++var) tupleparameters += boost::python::make_tuple(query.input[var]);
00268                         t += boost::python::make_tuple(tupleparameters);
00269                     }
00270                 }
00271 
00272                 DBGLOG(DBG, "Calling " << getPredicate() << "_caller helper function");
00273                 PythonAPI::main.attr((getPredicate() + "_caller").c_str())(t);
00274 
00275                 DBGLOG(DBG, "Resetting Python");
00276                 PythonAPI::emb_query = NULL;
00277                 PythonAPI::emb_answer = NULL;
00278                 PythonAPI::emb_nogoods.reset();
00279                 PythonAPI::emb_learnsupportsets = false;
00280                 PythonAPI::emb_eareplacements.reset();
00281             }
00282             catch(boost::python::error_already_set& e) {
00283                 PyErr_Print();
00284             }
00285         }
00286 
00287         virtual void learnSupportSets(const Query& query, NogoodContainerPtr nogoods)
00288         {
00289             try
00290             {
00291                 Answer answer;
00292                 DBGLOG(DBG, "Preparing Python for supportset learning");
00293                 PythonAPI::emb_query = &query;
00294                 PythonAPI::emb_answer = &answer;
00295                 PythonAPI::emb_nogoods = nogoods;
00296                 PythonAPI::emb_learnsupportsets = true;
00297                 if (query.eatomID != ID_FAIL) {
00298                     PythonAPI::emb_eareplacements = query.ctx->registry()->eatoms.getByID(query.eatomID).pluginAtom->getReplacements();
00299                 }
00300 
00301                 boost::python::tuple t;
00302                 DBGLOG(DBG, "Constructing input tuple");
00303                 for (int i = 0; i < getInputArity(); ++i) {
00304                     if (getInputType(i) != TUPLE) t += boost::python::make_tuple(query.input[i]);
00305                     else {
00306                         boost::python::tuple tupleparameters;
00307                         for (int var = i; var < query.input.size(); ++var) tupleparameters += boost::python::make_tuple(query.input[var]);
00308                         t += boost::python::make_tuple(tupleparameters);
00309                     }
00310                 }
00311 
00312                 DBGLOG(DBG, "Calling " << getPredicate() << "_caller helper function");
00313                 PythonAPI::main.attr((getPredicate() + "_caller").c_str())(t);
00314 
00315                 DBGLOG(DBG, "Resetting Python");
00316                 PythonAPI::emb_query = NULL;
00317                 PythonAPI::emb_answer = NULL;
00318                 PythonAPI::emb_nogoods.reset();
00319                 PythonAPI::emb_learnsupportsets = false;
00320                 PythonAPI::emb_eareplacements.reset();
00321             }
00322             catch(boost::python::error_already_set& e) {
00323                 PyErr_Print();
00324             }
00325         }
00326 };
00327 
00328 namespace PythonAPI
00329 {
00330 
00331     void addAtomWithProperties(std::string name, boost::python::tuple args, int outputArity, dlvhex::ExtSourceProperties prop) {
00332         if (!emb_pluginAtoms) throw PluginError("Cannot create external atoms at this point");
00333         std::vector<PluginAtom::InputType> inputParameters;
00334         for (int p = 0; p < boost::python::len(args); ++p) {
00335             int arg = boost::python::extract<int>(args[p]);
00336             if (arg == PluginAtom::CONSTANT || arg == PluginAtom::PREDICATE || arg == PluginAtom::TUPLE) inputParameters.push_back((PluginAtom::InputType)arg);
00337             else throw PluginError("dlvhex.addAtom: Unknown external atom parameter type");
00338         }
00339         std::stringstream passargs;
00340         DBGLOG(DBG, "Defining helper function " << name << "_caller(input)");
00341         for (int i = 0; i < boost::python::len(args); ++i) passargs << (i > 0 ? ", " : "") << "input[" << i << "]";
00342         boost::python::exec(("def " + name + "_caller(input):\n " + name + "(" + passargs.str() + ")").c_str(), dict, dict);
00343 
00344         // return smart pointer with deleter (i.e., delete code compiled into this plugin)
00345         emb_pluginAtoms->push_back(dlvhex::PluginAtomPtr(new PythonAtom(*emb_ctx, "unknown", name, inputParameters, outputArity, prop), PluginPtrDeleter<PluginAtom>()));
00346     }
00347 
00348     void addAtom(std::string name, boost::python::tuple args, int outputArity) {
00349         addAtomWithProperties(name, args, outputArity, dlvhex::ExtSourceProperties());
00350     }
00351 
00352     boost::python::tuple getTuple(ID id) {
00353         if (!id.isAtom() && !id.isLiteral()) throw PluginError("dlvhex.getTuple: Parameter must an atom or literal ID");
00354         const OrdinaryAtom& ogatom = emb_ctx->registry()->lookupOrdinaryAtom(id);
00355         boost::python::tuple t;
00356         BOOST_FOREACH (ID term, ogatom.tuple) t += boost::python::make_tuple(term);
00357         return t;
00358     }
00359 
00360     boost::python::tuple ID_tuple(ID* this_) {
00361         return getTuple(*this_);
00362     }
00363 
00364     std::string getValue(ID id) {
00365         std::stringstream ss;
00366         RawPrinter printer(ss, emb_ctx->registry());
00367         if (id.kind & ID::NAF_MASK) ss << "-";
00368         ID id_ = id;
00369         id_.kind &= (ID::ALL_ONES ^ ID::NAF_MASK);
00370         printer.print(id_);
00371         std::string str = ss.str();
00372         return ss.str();
00373     }
00374 
00375     std::string ID_value(ID* this_) {
00376         return getValue(*this_);
00377     }
00378 
00379     boost::python::tuple getExtension(ID id) {
00380 
00381         bm::bvector<>::enumerator en = emb_query->interpretation->getStorage().first();
00382         bm::bvector<>::enumerator en_end = emb_query->interpretation->getStorage().end();
00383         boost::python::tuple t;
00384         while (en < en_end) {
00385             const OrdinaryAtom& atom = emb_query->interpretation->getRegistry()->ogatoms.getByAddress(*en);
00386             if (atom.tuple[0] == id) {
00387                 boost::python::tuple currentTup;
00388                 for (int i = 1; i < atom.tuple.size(); ++i) {
00389                     currentTup += boost::python::make_tuple(atom.tuple[i]);
00390                 }
00391                 t += boost::python::make_tuple(currentTup);
00392             }
00393             en++;
00394         }
00395         return t;
00396     }
00397 
00398     boost::python::tuple ID_extension(ID* this_) {
00399         return getExtension(*this_);
00400     }
00401 
00402     int getIntValue(ID id) {
00403         if (!id.isTerm() || !id.isIntegerTerm()) throw PluginError("dlvhex.getIntValue: given value does not represent an integer");
00404         return id.address;
00405     }
00406 
00407     std::string getValueOfTuple(boost::python::tuple tup) {
00408 
00409         std::stringstream ret;
00410         ret << "{";
00411         std::string delim = " ";
00412         for (int i = 0; i < boost::python::len(tup); ++i) {
00413             boost::python::extract<boost::python::tuple> get_tuple(tup[i]);
00414             if (get_tuple.check()) {
00415                 ret << delim << getValueOfTuple(get_tuple());
00416             }
00417             else {
00418                 boost::python::extract<dlvhex::ID> get_ID(tup[i]);
00419                 if (!get_ID.check()) {
00420                     throw PluginError("dlvhex.getValue: parameter must be an ID or a tuple");
00421                 }
00422                 ret << delim << getValue(get_ID());
00423             }
00424             delim = ", ";
00425         }
00426         ret << " }";
00427         return ret.str();
00428     }
00429 
00430     int ID_intValue(ID* this_) {
00431         return getIntValue(*this_);
00432     }
00433 
00434     boost::python::tuple getTupleValues(ID id) {
00435         if (!id.isAtom() && !id.isLiteral()) throw PluginError("dlvhex.getTuple: Parameter must an atom or literal ID");
00436         const OrdinaryAtom& ogatom = emb_ctx->registry()->lookupOrdinaryAtom(id);
00437         boost::python::tuple t;
00438         BOOST_FOREACH(ID term, ogatom.tuple) {
00439             if (term.isIntegerTerm()) {
00440                 t += boost::python::make_tuple(getIntValue(term));
00441             }
00442             else {
00443                 t += boost::python::make_tuple(getValue(term));
00444             }
00445         }
00446         return t;
00447     }
00448 
00449     boost::python::tuple ID_tupleValues(ID* this_) {
00450         return getTupleValues(*this_);
00451     }
00452 
00453     ID storeInteger(int i) {
00454         return ID::termFromInteger(i);
00455     }
00456 
00457     ID storeString(std::string str) {
00458         return emb_ctx->registry()->storeConstantTerm(str);
00459     }
00460 
00461     ID storeAtom(boost::python::tuple args) {
00462         OrdinaryAtom atom(dlvhex::ID::MAINKIND_ATOM);
00463         bool nonground = false;
00464         DBGLOG(DBG,"PythonPlugin::storeAtom with " << boost::python::len(args) << " elements");
00465         for (int i = 0; i < boost::python::len(args); ++i) {
00466             boost::python::extract<int> get_int(args[i]);
00467             if (get_int.check()) {
00468                 // store as int
00469                 DBGLOG(DBG," arg " << i << " is integer " << get_int());
00470                 atom.tuple.push_back(dlvhex::ID::termFromInteger(get_int()));
00471             }
00472             else {
00473                 boost::python::extract<std::string> get_string(args[i]);
00474                 if (get_string.check()) {
00475                     // store as string
00476                     std::string str = boost::python::extract<std::string>(args[i]);
00477                     DBGLOG(DBG," arg " << i << " is string (=var/const) " << str);
00478                     if (str[0] == '_' || (str[0] >= 'A' && str[0] <= 'Z')) {
00479                         atom.tuple.push_back(emb_ctx->registry()->storeVariableTerm(str));
00480                         nonground = true;
00481                     }
00482                     else {
00483                         atom.tuple.push_back(emb_ctx->registry()->storeConstantTerm(str));
00484                     }
00485                 }
00486                 else {
00487                     boost::python::extract<ID> get_ID(args[i]);
00488                     if (get_ID.check()) {
00489                         DBGLOG(DBG," arg " << i << " is ID " << get_ID() << " which is " << printToString<RawPrinter>(get_ID(), emb_ctx->registry()));
00490                         if (!get_ID().isTerm()) throw PluginError("dlvhex.output/dlvhex.outputUnknown: Parameters must be term IDs");
00491                         atom.tuple.push_back(get_ID());
00492                     }
00493                     else {
00494                         PluginError("dlvhex.output/dlvhex.outputUnknown: unknown parameter type");
00495                     }
00496                 }
00497             }
00498         }
00499         if (nonground) {
00500             atom.kind |= dlvhex::ID::SUBKIND_ATOM_ORDINARYN;
00501             DBGLOG(DBG,"storing nonground atom " << atom);
00502             return emb_ctx->registry()->storeOrdinaryNAtom(atom);
00503         }
00504         else {
00505             atom.kind |= dlvhex::ID::SUBKIND_ATOM_ORDINARYG;
00506             DBGLOG(DBG,"storing ground atom " << atom);
00507             return emb_ctx->registry()->storeOrdinaryGAtom(atom);
00508         }
00509     }
00510 
00511     ID storeExternalAtom(std::string pred, boost::python::tuple iargs, boost::python::tuple oargs) {
00512         ExternalAtom eatom(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_EXTERNAL);
00513         eatom.predicate = emb_ctx->registry()->storeConstantTerm(pred);
00514         for (int i = 0; i < boost::python::len(iargs); ++i) {
00515             boost::python::extract<int> get_int(iargs[i]);
00516             if (get_int.check()) {
00517                 // store as int
00518                 eatom.inputs.push_back(dlvhex::ID::termFromInteger(get_int()));
00519             }
00520             else {
00521                 boost::python::extract<std::string> get_string(iargs[i]);
00522                 if (get_string.check()) {
00523                     // store as string
00524                     std::string str = boost::python::extract<std::string>(iargs[i]);
00525                     if (str[0] == '_' || (str[0] >= 'A' && str[0] <= 'Z')) {
00526                         eatom.inputs.push_back(emb_ctx->registry()->storeVariableTerm(str));
00527                     }
00528                     else {
00529                         eatom.inputs.push_back(emb_ctx->registry()->storeConstantTerm(str));
00530                     }
00531                 }
00532                 else {
00533                     boost::python::extract<ID> get_ID(iargs[i]);
00534                     if (get_ID.check()) {
00535                         if (!get_ID().isTerm()) throw PluginError("dlvhex.storeExternalAtom: Parameters must be term IDs");
00536                         eatom.inputs.push_back(get_ID());
00537                     }
00538                     else {
00539                         PluginError("dlvhex.storeExternalAtom: unknown parameter type");
00540                     }
00541                 }
00542             }
00543         }
00544         for (int i = 0; i < boost::python::len(oargs); ++i) {
00545             boost::python::extract<int> get_int(oargs[i]);
00546             if (get_int.check()) {
00547                 // store as int
00548                 eatom.tuple.push_back(dlvhex::ID::termFromInteger(get_int()));
00549             }
00550             else {
00551                 boost::python::extract<std::string> get_string(oargs[i]);
00552                 if (get_string.check()) {
00553                     // store as string
00554                     std::string str = boost::python::extract<std::string>(oargs[i]);
00555                     if (str[0] == '_' || (str[0] >= 'A' && str[0] <= 'Z')) {
00556                         eatom.tuple.push_back(emb_ctx->registry()->storeVariableTerm(str));
00557                     }
00558                     else {
00559                         eatom.tuple.push_back(emb_ctx->registry()->storeConstantTerm(str));
00560                     }
00561                 }
00562                 else {
00563                     boost::python::extract<ID> get_ID(oargs[i]);
00564                     if (get_ID.check()) {
00565                         if (!get_ID().isTerm()) throw PluginError("dlvhex.storeExternalAtom: Parameters must be term IDs");
00566                         eatom.tuple.push_back(get_ID());
00567                     }
00568                     else {
00569                         PluginError("dlvhex.storeExternalAtom: unknown parameter type");
00570                     }
00571                 }
00572             }
00573         }
00574         return emb_ctx->registry()->eatoms.storeAndGetID(eatom);
00575     }
00576 
00577     ID storeRule(boost::python::tuple head, boost::python::tuple pbody, boost::python::tuple nbody) {
00578 
00579         Rule rule(ID::MAINKIND_RULE);
00580         if (boost::python::len(head) == 0) rule.kind |= ID::SUBKIND_RULE_CONSTRAINT;
00581         for (int i = 0; i < boost::python::len(head); ++i) {
00582             boost::python::extract<ID> get_ID(head[i]);
00583             if (!get_ID.check()) {
00584                 throw PluginError("dlvhex.storeRule: Parameters must be term IDs");
00585             }
00586             rule.head.push_back(get_ID());
00587             if (i > 0) rule.kind |= ID::PROPERTY_RULE_DISJ;
00588         }
00589         for (int i = 0; i < boost::python::len(pbody); ++i) {
00590             boost::python::extract<ID> get_ID(pbody[i]);
00591             if (!get_ID.check()) {
00592                 throw PluginError("dlvhex.storeRule: Parameters must be term IDs");
00593             }
00594             rule.body.push_back(ID::posLiteralFromAtom(get_ID()));
00595             if (get_ID().isExternalAtom()) rule.kind |= ID::PROPERTY_RULE_EXTATOMS;
00596         }
00597         for (int i = 0; i < boost::python::len(nbody); ++i) {
00598             boost::python::extract<ID> get_ID(nbody[i]);
00599             if (!get_ID.check()) {
00600                 throw PluginError("dlvhex.storeRule: Parameters must be term IDs");
00601             }
00602             rule.body.push_back(ID::nafLiteralFromAtom(get_ID()));
00603             if (get_ID().isExternalAtom()) rule.kind |= ID::PROPERTY_RULE_EXTATOMS;
00604         }
00605         return emb_ctx->registry()->storeRule(rule);
00606     }
00607 
00608     boost::python::tuple evaluateSubprogram(boost::python::tuple tup) {
00609 
00610         boost::python::extract<boost::python::tuple> facts(tup[0]);
00611         boost::python::extract<boost::python::tuple> rules(tup[1]);
00612 
00613         if (!facts.check() || !rules.check()) throw PluginError("dlvhex.evaluateSubprogram: Input must be a pair of facts and rules");
00614 
00615         InterpretationPtr edb(new Interpretation(emb_ctx->registry()));
00616         for (int i = 0; i < boost::python::len(facts()); ++i) {
00617             boost::python::extract<ID> get_ID(facts()[i]);
00618             if (!get_ID.check() || !get_ID().isAtom() || !get_ID().isOrdinaryGroundAtom()) {
00619                 throw PluginError("dlvhex.evaluateSubprogram: Facts must be a tuple of ground atom IDs");
00620             }
00621             edb->setFact(get_ID().address);
00622         }
00623         std::vector<ID> idb;
00624         for (int i = 0; i < boost::python::len(rules()); ++i) {
00625             boost::python::extract<ID> get_ID(rules()[i]);
00626             if (!get_ID.check() || !get_ID().isRule()) {
00627                 throw PluginError("dlvhex.evaluateSubprogram: Facts must be a tuple of ground atom IDs");
00628             }
00629             idb.push_back(get_ID());
00630         }
00631         std::vector<InterpretationPtr> answersets = emb_ctx->evaluateSubprogram(edb, idb);
00632         boost::python::tuple pythonResult;
00633         BOOST_FOREACH (InterpretationConstPtr answerset, answersets) {
00634             boost::python::tuple pythonAS;
00635             bm::bvector<>::enumerator en = answerset->getStorage().first();
00636             bm::bvector<>::enumerator en_end = answerset->getStorage().end();
00637             while (en < en_end) {
00638                 // TODO: use auxiliary mask to filter so that auxiliaries are not given to python
00639                 pythonAS += boost::python::make_tuple(emb_ctx->registry()->ogatoms.getIDByAddress(*en));
00640                 en++;
00641             }
00642             pythonResult += boost::python::make_tuple(pythonAS);
00643         }
00644         return pythonResult;
00645     }
00646 
00647     boost::python::tuple loadSubprogram(std::string filename) {
00648 
00649         ProgramCtx pc = *emb_ctx;
00650         pc.idb.clear();
00651         pc.edb = InterpretationPtr(new Interpretation(emb_ctx->registry()));
00652         pc.currentOptimum.clear();
00653         pc.config.setOption("NumberOfModels",0);
00654         InputProviderPtr ip(new InputProvider());
00655         ip->addFileInput(filename);
00656         pc.inputProvider = ip;
00657         ip.reset();
00658 
00659         DBGLOG(DBG, "Resetting context");
00660         pc.state.reset();
00661         pc.modelBuilder.reset();
00662         pc.parser.reset();
00663         pc.evalgraph.reset();
00664         pc.compgraph.reset();
00665         pc.depgraph.reset();
00666 
00667         pc.config.setOption("DumpDepGraph",0);
00668         pc.config.setOption("DumpCyclicPredicateInputAnalysisGraph",0);
00669         pc.config.setOption("DumpCompGraph",0);
00670         pc.config.setOption("DumpEvalGraph",0);
00671         pc.config.setOption("DumpModelGraph",0);
00672         pc.config.setOption("DumpIModelGraph",0);
00673         pc.config.setOption("DumpAttrGraph",0);
00674 
00675         if( !pc.evalHeuristic ) {
00676             assert(false);
00677             throw GeneralError("No evaluation heuristics found");
00678         }
00679 
00680         pc.changeState(StatePtr(new ConvertState()));
00681         pc.convert();
00682         pc.parse();
00683         if( pc.maxint > emb_ctx->maxint ) {
00684             DBGLOG(DBG, "updating maxint of emb_ctx from " << emb_ctx->maxint << " to " << pc.maxint);
00685             emb_ctx->maxint = pc.maxint;
00686         }
00687 
00688         bm::bvector<>::enumerator en = pc.edb->getStorage().first();
00689         bm::bvector<>::enumerator en_end = pc.edb->getStorage().end();
00690         boost::python::tuple pyedb, pyidb;
00691         while (en < en_end) {
00692             pyedb += boost::python::make_tuple(emb_ctx->registry()->ogatoms.getIDByAddress(*en));
00693             en++;
00694         }
00695         BOOST_FOREACH (ID ruleID, pc.idb) {
00696             pyidb += boost::python::make_tuple(ruleID);
00697         }
00698 
00699         return boost::python::make_tuple(pyedb, pyidb);
00700     }
00701 
00702     ID negate(ID id) {
00703         if (!id.isAtom() && !id.isLiteral()) throw PluginError("dlvhex.negate: Can only negate literal IDs");
00704         if (!!emb_nogoods && emb_ctx->registry()->ogatoms.getIDByAddress(id.address).isExternalAuxiliary()) {
00705             DBGLOG(DBG, "Negating external atom output atom " << id);
00706             return emb_ctx->registry()->swapExternalAtomAuxiliaryAtom(emb_ctx->registry()->ogatoms.getIDByAddress(id.address));
00707         }
00708         else {
00709             DBGLOG(DBG, "Negating ordinary literal " << id);
00710             id.kind ^= dlvhex::ID::NAF_MASK;
00711             return id;
00712         }
00713     }
00714 
00715     ID ID_negate(ID* this_) {
00716         return negate(*this_);
00717     }
00718 
00719     bool learn(boost::python::tuple args) {
00720 
00721         if (!!emb_nogoods && emb_ctx->config.getOption("ExternalLearningUser")) {
00722             Nogood ng;
00723             for (int i = 0; i < boost::python::len(args); ++i) {
00724                 dlvhex::ID id = boost::python::extract<ID>(args[i]);
00725                 if (!id.isAtom() && !id.isLiteral()) throw PluginError("dlvhex.learn: Parameters must be positive or negated atom IDs");
00726                 ng.insert(NogoodContainer::createLiteral(id));
00727             }
00728             DBGLOG(DBG, "Learning nogood " << ng.getStringRepresentation(emb_ctx->registry()) << " from python plugin");
00729             emb_nogoods->addNogood(ng);
00730 
00731             return true;
00732         }
00733         else {
00734             return false;
00735         }
00736     }
00737 
00738     bool learnSupportSets() {
00739         return emb_learnsupportsets;
00740     }
00741 
00742     ID storeOutputAtomWithSign(boost::python::tuple args, bool sign) {
00743 
00744         Tuple outputTuple;
00745         for (int i = 0; i < boost::python::len(args); ++i) {
00746             boost::python::extract<int> get_int(args[i]);
00747             if (get_int.check()) {
00748                 // store as int
00749                 outputTuple.push_back(dlvhex::ID::termFromInteger(get_int()));
00750             }
00751             else {
00752                 boost::python::extract<std::string> get_string(args[i]);
00753                 if (get_string.check()) {
00754                     // store as string
00755                     outputTuple.push_back(emb_ctx->registry()->storeConstantTerm(boost::python::extract<std::string>(args[i])));
00756                 }
00757                 else {
00758                     boost::python::extract<ID> get_ID(args[i]);
00759                     if (get_ID.check()) {
00760                         if (!get_ID().isTerm()) throw PluginError("dlvhex.output: Parameters must be term IDs");
00761                         outputTuple.push_back(get_ID());
00762                     }
00763                     else {
00764                         PluginError("dlvhex.output: unknown parameter type");
00765                     }
00766                 }
00767             }
00768         }
00769         return ExternalLearningHelper::getOutputAtom(*emb_query, outputTuple, sign);
00770     }
00771 
00772     ID storeOutputAtom(boost::python::tuple args) {
00773         return storeOutputAtomWithSign(args, true);
00774     }
00775 
00776     void output(boost::python::tuple args) {
00777 
00778         Tuple outputTuple;
00779         for (int i = 0; i < boost::python::len(args); ++i) {
00780 
00781             boost::python::extract<int> get_int(args[i]);
00782             if (get_int.check()) {
00783                 // store as int
00784                 outputTuple.push_back(dlvhex::ID::termFromInteger(get_int()));
00785             }
00786             else {
00787                 boost::python::extract<std::string> get_string(args[i]);
00788                 if (get_string.check()) {
00789                     // store as string
00790                     outputTuple.push_back(emb_ctx->registry()->storeConstantTerm(boost::python::extract<std::string>(args[i])));
00791                 }
00792                 else {
00793                     boost::python::extract<ID> get_ID(args[i]);
00794                     if (get_ID.check()) {
00795                         if (!get_ID().isTerm()) throw PluginError("dlvhex.output: Parameters must be term IDs");
00796                         outputTuple.push_back(get_ID());
00797                     }
00798                     else {
00799                         PluginError("dlvhex.output: unknown parameter type");
00800                     }
00801                 }
00802             }
00803         }
00804         emb_answer->get().push_back(outputTuple);
00805     }
00806 
00807     void outputUnknown(boost::python::tuple args) {
00808 
00809         Tuple outputTuple;
00810         for (int i = 0; i < boost::python::len(args); ++i) {
00811 
00812             boost::python::extract<int> get_int(args[i]);
00813             if (get_int.check()) {
00814                 // store as int
00815                 outputTuple.push_back(dlvhex::ID::termFromInteger(get_int()));
00816             }
00817             else {
00818                 boost::python::extract<std::string> get_string(args[i]);
00819                 if (get_string.check()) {
00820                     // store as string
00821                     outputTuple.push_back(emb_ctx->registry()->storeConstantTerm(boost::python::extract<std::string>(args[i])));
00822                 }
00823                 else {
00824                     boost::python::extract<ID> get_ID(args[i]);
00825                     if (get_ID.check()) {
00826                         if (!get_ID().isTerm()) throw PluginError("dlvhex.outputUnknown: Parameters must be term IDs");
00827                         outputTuple.push_back(get_ID());
00828                     }
00829                     else {
00830                         PluginError("dlvhex.outputUnknown: unknown parameter type");
00831                     }
00832                 }
00833             }
00834         }
00835         emb_answer->getUnknown().push_back(outputTuple);
00836     }
00837 
00838     ID getExternalAtomID() {
00839         return emb_query->eatomID;
00840     }
00841 
00842     boost::python::tuple getInputAtoms() {
00843 
00844         bm::bvector<>::enumerator en = emb_query->predicateInputMask->getStorage().first();
00845         bm::bvector<>::enumerator en_end = emb_query->predicateInputMask->getStorage().end();
00846         long i = 0;
00847         boost::python::tuple t;
00848         while (en < en_end) {
00849             t += boost::python::make_tuple(emb_query->interpretation->getRegistry()->ogatoms.getIDByAddress(*en));
00850             i++;
00851             en++;
00852         }
00853         return t;
00854     }
00855 
00856     boost::python::tuple getInputAtomsOfPredicate(ID pred) {
00857 
00858         bm::bvector<>::enumerator en = emb_query->predicateInputMask->getStorage().first();
00859         bm::bvector<>::enumerator en_end = emb_query->predicateInputMask->getStorage().end();
00860         boost::python::tuple t;
00861         while (en < en_end) {
00862             if (emb_query->interpretation->getRegistry()->ogatoms.getByAddress(*en).tuple[0] == pred) {
00863                 t += boost::python::make_tuple(emb_query->interpretation->getRegistry()->ogatoms.getIDByAddress(*en));
00864             }
00865             en++;
00866         }
00867         return t;
00868     }
00869 
00870     boost::python::tuple getTrueInputAtoms() {
00871 
00872         bm::bvector<>::enumerator en = emb_query->interpretation->getStorage().first();
00873         bm::bvector<>::enumerator en_end = emb_query->interpretation->getStorage().end();
00874         long i = 0;
00875         boost::python::tuple t;
00876         while (en < en_end) {
00877             t += boost::python::make_tuple(emb_query->interpretation->getRegistry()->ogatoms.getIDByAddress(*en));
00878             i++;
00879             en++;
00880         }
00881         return t;
00882     }
00883 
00884     boost::python::tuple getTrueInputAtomsOfPredicate(ID pred) {
00885 
00886         bm::bvector<>::enumerator en = emb_query->interpretation->getStorage().first();
00887         bm::bvector<>::enumerator en_end = emb_query->interpretation->getStorage().end();
00888         boost::python::tuple t;
00889         while (en < en_end) {
00890             if (emb_query->interpretation->getRegistry()->ogatoms.getByAddress(*en).tuple[0] == pred) {
00891                 t += boost::python::make_tuple(emb_query->interpretation->getRegistry()->ogatoms.getIDByAddress(*en));
00892             }
00893             en++;
00894         }
00895         return t;
00896     }
00897 
00898     int getInputAtomCount() {
00899         return emb_query->predicateInputMask->getStorage().count();
00900     }
00901 
00902     int getTrueInputAtomCount() {
00903         return emb_query->interpretation->getStorage().count();
00904     }
00905 
00906     bool isInputAtom(ID id) {
00907         return emb_query->predicateInputMask->getFact(id.address);
00908     }
00909 
00910     bool ID_isInputAtom(ID* this_) {
00911         return isInputAtom(*this_);
00912     }
00913 
00914     bool isAssignmentComplete() {
00915         return !emb_query->assigned;
00916     }
00917 
00918     bool isAssigned(ID id) {
00919         if (!emb_query->assigned || emb_query->assigned->getFact(id.address)) return true;
00920         else return false;
00921     }
00922 
00923     bool ID_isAssigned(ID* this_) {
00924         return isAssigned(*this_);
00925     }
00926 
00927     bool hasChanged(ID id) {
00928         if (!emb_query->changed || emb_query->changed->getFact(id.address)) return true;
00929         else return false;
00930     }
00931 
00932     bool ID_hasChanged(ID* this_) {
00933         return hasChanged(*this_);
00934     }
00935 
00936     bool isTrue(ID id) {
00937         if (isAssigned(id) && emb_query->interpretation->getFact(id.address)) return true;
00938         else return false;
00939     }
00940 
00941     bool ID_isTrue(ID* this_) {
00942         return isTrue(*this_);
00943     }
00944 
00945     bool isFalse(ID id) {
00946         if (isAssigned(id) && !emb_query->interpretation->getFact(id.address)) return true;
00947         else return false;
00948     }
00949 
00950     bool ID_isFalse(ID* this_) {
00951         return isFalse(*this_);
00952     }
00953 
00954     boost::python::tuple getRelevantOutputAtoms() {
00955 
00956         boost::python::tuple t;
00957         if (getExternalAtomID() != ID_FAIL && !!emb_eareplacements) {
00958             const ExternalAtom& eatom = emb_query->interpretation->getRegistry()->eatoms.getByID(getExternalAtomID());
00959             bm::bvector<>::enumerator en = emb_eareplacements->mask()->getStorage().first();
00960             bm::bvector<>::enumerator en_end = emb_eareplacements->mask()->getStorage().end();
00961             while (en < en_end) {
00962                 t += boost::python::make_tuple(emb_query->interpretation->getRegistry()->ogatoms.getIDByAddress(*en));
00963                 en++;
00964             }
00965         }else{
00966             throw PluginError("getRelevantOutputAtoms() was called during evaluation of an external source without known external atom");
00967         }
00968         return t;
00969     }
00970 
00971     void resetCacheOfPlugins() {
00972         if( PythonAPI::emb_ctx == NULL ) {
00973             LOG(ERROR,"cannot reset plugin cache - emb_ctx = NULL");
00974         }
00975         else {
00976                                  // false -> reset all caches
00977             PythonAPI::emb_ctx->resetCacheOfPlugins(false);
00978         }
00979     }
00980 };
00981 
00982 BOOST_PYTHON_MODULE(dlvhex)
00983 {
00984     boost::python::def("addAtom", PythonAPI::addAtomWithProperties);
00985     boost::python::def("addAtom", PythonAPI::addAtom);
00986     boost::python::def("getValue", PythonAPI::getValue);
00987     boost::python::def("getValue", PythonAPI::getValueOfTuple);
00988     boost::python::def("getExtension", PythonAPI::getExtension);
00989     boost::python::def("getIntValue", PythonAPI::getIntValue);
00990     boost::python::def("getTuple", PythonAPI::getTuple);
00991     boost::python::def("getTupleValues", PythonAPI::getTupleValues);
00992     boost::python::def("storeInteger", PythonAPI::storeInteger);
00993     boost::python::def("storeString", PythonAPI::storeString);
00994     boost::python::def("storeAtom", PythonAPI::storeAtom);
00995     boost::python::def("negate", PythonAPI::negate);
00996     boost::python::def("learn", PythonAPI::learn);
00997     boost::python::def("storeOutputAtom", PythonAPI::storeOutputAtomWithSign);
00998     boost::python::def("storeOutputAtom", PythonAPI::storeOutputAtom);
00999     boost::python::def("output", PythonAPI::output);
01000     boost::python::def("outputUnknown", PythonAPI::outputUnknown);
01001     boost::python::def("getExternalAtomID", PythonAPI::getExternalAtomID);
01002     boost::python::def("getInputAtoms", PythonAPI::getInputAtoms);
01003     boost::python::def("getInputAtoms", PythonAPI::getInputAtomsOfPredicate);
01004     boost::python::def("getTrueInputAtoms", PythonAPI::getTrueInputAtoms);
01005     boost::python::def("getTrueInputAtoms", PythonAPI::getTrueInputAtomsOfPredicate);
01006     boost::python::def("getInputAtomCount", PythonAPI::getInputAtomCount);
01007     boost::python::def("getTrueInputAtomCount", PythonAPI::getTrueInputAtomCount);
01008     boost::python::def("isInputAtom", PythonAPI::isInputAtom);
01009     boost::python::def("isAssignmentComplete", PythonAPI::isAssignmentComplete);
01010     boost::python::def("isAssigned", PythonAPI::isAssigned);
01011     boost::python::def("hasChanged", PythonAPI::hasChanged);
01012     boost::python::def("isTrue", PythonAPI::isTrue);
01013     boost::python::def("isFalse", PythonAPI::isFalse);
01014     boost::python::def("getRelevantOutputAtoms", PythonAPI::getRelevantOutputAtoms);
01015     boost::python::def("storeExternalAtom", PythonAPI::storeExternalAtom);
01016     boost::python::def("storeRule", PythonAPI::storeRule);
01017     boost::python::def("evaluateSubprogram", PythonAPI::evaluateSubprogram);
01018     boost::python::def("loadSubprogram", PythonAPI::loadSubprogram);
01019     boost::python::def("resetCacheOfPlugins", PythonAPI::resetCacheOfPlugins);
01020     boost::python::def("learnSupportSets", PythonAPI::learnSupportSets);
01021     boost::python::class_<dlvhex::ID>("ID")
01022         .def("value", &PythonAPI::ID_value)
01023         .def("extension", &PythonAPI::ID_extension)
01024         .def("intValue", &PythonAPI::ID_intValue)
01025         .def("tuple", &PythonAPI::ID_tuple)
01026         .def("tupleValues", &PythonAPI::ID_tupleValues)
01027         .def("negate", &PythonAPI::ID_negate)
01028         .def("isInputAtom", &PythonAPI::ID_isInputAtom)
01029         .def("isAssigned", &PythonAPI::ID_isAssigned)
01030         .def("hasChanged", &PythonAPI::ID_hasChanged)
01031         .def("isTrue", &PythonAPI::ID_isTrue)
01032         .def("isFalse", &PythonAPI::ID_isFalse)
01033         .def(boost::python::self == dlvhex::ID());
01034     boost::python::class_<dlvhex::ExtSourceProperties>("ExtSourceProperties")
01035         .def("addMonotonicInputPredicate", &dlvhex::ExtSourceProperties::addMonotonicInputPredicate)
01036         .def("addAntimonotonicInputPredicate", &dlvhex::ExtSourceProperties::addAntimonotonicInputPredicate)
01037         .def("addPredicateParameterNameIndependence", &dlvhex::ExtSourceProperties::addPredicateParameterNameIndependence)
01038         .def("addFiniteOutputDomain", &dlvhex::ExtSourceProperties::addFiniteOutputDomain)
01039         .def("addRelativeFiniteOutputDomain", &dlvhex::ExtSourceProperties::addRelativeFiniteOutputDomain)
01040         .def("setFunctional", &dlvhex::ExtSourceProperties::setFunctional)
01041         .def("setFunctionalStart", &dlvhex::ExtSourceProperties::setFunctionalStart)
01042         .def("setOnlySafeSupportSets", &dlvhex::ExtSourceProperties::setOnlySafeSupportSets)
01043         .def("setSupportSets", &dlvhex::ExtSourceProperties::setSupportSets)
01044         .def("setCompletePositiveSupportSets", &dlvhex::ExtSourceProperties::setCompletePositiveSupportSets)
01045         .def("setCompleteNegativeSupportSets", &dlvhex::ExtSourceProperties::setCompleteNegativeSupportSets)
01046         .def("setVariableOutputArity", &dlvhex::ExtSourceProperties::setVariableOutputArity)
01047         .def("setCaresAboutAssigned", &dlvhex::ExtSourceProperties::setCaresAboutAssigned)
01048         .def("setCaresAboutChanged", &dlvhex::ExtSourceProperties::setCaresAboutChanged)
01049         .def("setAtomlevellinear", &dlvhex::ExtSourceProperties::setAtomlevellinear)
01050         .def("setTuplelevellinear", &dlvhex::ExtSourceProperties::setTuplelevellinear)
01051         .def("setUsesEnvironment", &dlvhex::ExtSourceProperties::setUsesEnvironment)
01052         .def("setFiniteFiber", &dlvhex::ExtSourceProperties::setFiniteFiber)
01053         .def("addWellorderingStrlen", &dlvhex::ExtSourceProperties::addWellorderingStrlen)
01054         .def("addWellorderingNatural", &dlvhex::ExtSourceProperties::addWellorderingNatural)
01055         .def("setProvidesPartialAnswer", &dlvhex::ExtSourceProperties::setProvidesPartialAnswer);
01056 
01057     boost::python::scope().attr("CONSTANT") = (int)PluginAtom::CONSTANT;
01058     boost::python::scope().attr("PREDICATE") = (int)PluginAtom::PREDICATE;
01059     boost::python::scope().attr("TUPLE") = (int)PluginAtom::TUPLE;
01060 }
01061 
01062 
01063 std::vector<PluginAtomPtr> PythonPlugin::createAtoms(ProgramCtx& ctx) const
01064 {
01065 
01066     PythonAPI::emb_ctx = &ctx;
01067     std::vector<PluginAtomPtr> pluginAtoms;
01068 
01069     // we have to do the program rewriting already here because it creates some side information that we need
01070     PythonPlugin::CtxData& ctxdata = ctx.getPluginData<PythonPlugin>();
01071 
01072     // load Python plugins
01073     DBGLOG(DBG, "Initialize Python plugin");
01074 
01075     // prepare sys.argv for Python
01076     char** pargv;
01077     int iargv;
01078     {
01079         std::vector<char*> argv;
01080         // first argument = script or empty (should exist!)
01081         if( !ctxdata.pythonScripts.empty() ) {
01082             argv.push_back(strdup(ctxdata.pythonScripts[0].c_str()));
01083         }
01084         else argv.push_back(strdup(""));
01085         // other arguments = as obtained from commandline
01086         BOOST_FOREACH (std::string& arg, ctxdata.commandlineArguments) {
01087             LOG(DBG,"Handling Python Commandline Argument '" << arg << "'");
01088             argv.push_back(strdup(arg.c_str()));
01089         }
01090         // terminator
01091         argv.push_back(NULL);
01092         // now prepare char** which we will give to python (also to free it)
01093         iargv = argv.size();
01094         pargv = new char*[iargv];
01095         for(unsigned i = 0; i < iargv; ++i) pargv[i] = argv[i];
01096     }
01097 
01098     #if PY_MAJOR_VERSION <= 2
01099     Py_Initialize();
01100     PySys_SetArgvEx(iargv-1, pargv, 0);
01101     initdlvhex();
01102     PythonAPI::main = boost::python::import("__main__");
01103     PythonAPI::dict = PythonAPI::main.attr("__dict__");
01104     #else
01105     if (PyImport_AppendInittab("dlvhex", PyInit_dlvhex) == -1) {
01106         throw PluginError("Could not register dlvhex module in Python");
01107     }
01108     Py_Initialize();
01109     wchar_t** wpargv = new wchar_t*[iargv];
01110     for(int i = 0; i < iargv; ++i) {
01111         if( pargv[i] == NULL ) wpargv[i] = NULL;
01112         else {
01113             wpargv[i] = new wchar_t[strlen(pargv[i])+1];
01114             for(int c = 0; c < strlen(pargv[i])+1; c++) {
01115                 // do a brutal cast (this will work in all 7-bit ASCII cases which is
01116                 // enough for now)
01117                 wpargv[i][c] = wchar_t(pargv[i][c]);
01118                 if( wpargv[i][c] & 0x7F != wpargv[i][c] ) {
01119                     LOG(WARNING,"console input argument contains non-7-bit character in argument '" << pargv[i] << "' !");
01120                 }
01121             }
01122         }
01123     }
01124     PySys_SetArgvEx(iargv-1, wpargv, 0);
01125         PythonAPI::main = boost::python::import("__main__");
01126         PythonAPI::dict = PythonAPI::main.attr("__dict__");
01127         #endif
01128 
01129     BOOST_FOREACH (std::string script, ctxdata.pythonScripts) {
01130         DBGLOG(DBG, "Loading file \"" + script + "\"");
01131             try
01132         {
01133             boost::python::exec_file(script.c_str(), PythonAPI::dict, PythonAPI::dict);
01134                 PythonAPI::emb_pluginAtoms = &pluginAtoms;
01135                 PythonAPI::main.attr("register")();
01136                 PythonAPI::emb_pluginAtoms = NULL;
01137         }
01138         catch(boost::python::error_already_set& e) {
01139             PyErr_Print();
01140         }
01141     }
01142     DBGLOG(DBG, "Python plugin initialization done");
01143 
01144         return pluginAtoms;
01145 }
01146 
01147 
01148 void PythonPlugin::runPythonMain(std::string filename)
01149 {
01150     try
01151     {
01152         boost::python::exec_file(filename.c_str(), PythonAPI::dict, PythonAPI::dict);
01153             PythonAPI::main.attr("main")();
01154     }
01155     catch(boost::python::error_already_set& e) {
01156         PyErr_Print();
01157     }
01158 }
01159 
01160 
01161 DLVHEX_NAMESPACE_END
01162 #endif
01163 
01164 // this would be the code to use this plugin as a "real" plugin in a .so file
01165 // but we directly use it in dlvhex.cpp
01166 #if 0
01167 PythonPlugin thePythonPlugin;
01168 
01169 // return plain C type s.t. all compilers and linkers will like this code
01170 extern "C"
01171 void * PLUGINIMPORTFUNCTION()
01172 {
01173     return reinterpret_cast<void*>(& DLVHEX_NAMESPACE thePythonPlugin);
01174 }
01175 #endif
01176 
01177 
01178 // vim:expandtab:ts=4:sw=4:
01179 // mode: C++
01180 // End: