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