/* * Author: * Tai Tran * Supervisor: * Guido Tack */ #ifndef __PYINTERFACE_H #define __PYINTERFACE_H #include "Annotation.h" #include "Expression.h" #include "Model.cpp" #include "Model.h" #include "Object.h" #include "Set.cpp" #include "Set.h" #include "Solver.cpp" #include "Solver.h" #include "VarSet.h" #include "global.cpp" #include "global.h" /* Helper functions that load data into a new model * For example: instead of import minizinc_internal model = minizinc_internal.Model() model.load(...) we can do this: import minizinc_internal model = minizinc_internal.load(...) */ static PyObject* Mzn_load(PyObject* self, PyObject* args, PyObject* keywds); static PyObject* Mzn_load_from_string(PyObject* self, PyObject* args, PyObject* keywds); // GC::lock() and GC::unlock() static PyObject* Mzn_lock(PyObject* self) { GC::lock(); Py_RETURN_NONE; } static PyObject* Mzn_unlock(PyObject* self) { GC::unlock(); Py_RETURN_NONE; } /************************************************************ Groups of function that need an outer GCLock to work ************************************************************/ // Note: Please see Note 1 of the first python_to_minizinc declaration in global.h first // Requires: // - An UnOpType integer opcode // - A MiniZinc expression or Python value static PyObject* Mzn_UnOp(PyObject* self, PyObject* args); // Requires: // - A left hand sided MiniZinc expression or Python value // - A BinOpType integer opcode // - A right hand sided MiniZinc expression or Python value static PyObject* Mzn_BinOp(PyObject* self, PyObject* args); // Requires: // - Name of the MiniZinc function to be called (string) // - List of MiniZinc object or Python value // - (Optional, deprecated) Return type of Mzn_Call static PyObject* Mzn_Call(PyObject* self, PyObject* args); // Requires a name(string) static PyObject* Mzn_Id(PyObject* self, PyObject* args); // Requires: // - A MiniZinc expression of array type // - A list of integer indices (can be MiniZinc expression as well) static PyObject* Mzn_at(PyObject* self, PyObject* args); // ***************** END OF GROUPS ***************** /* Definition: Returns a dictionary of keys: "boolfuncs", "annfuncs" and "annvars" (currently) For each '*funcs': Itself is another dictionary: key: name of function value: a list of all possible combination of parsing argument types and return type: for each item in that list: item[0] is a tuple argument types: if a function accepts (int, int), it should be (, ) if a function accepts (array of [int, int]), it should be ( [, ], ) (notice the appearance of a list here) item[1] is the return type: MiniZinc Type - Python Type int - long float - float bool - bool string - str VarSet - minizinc.VarSet Ann - minizinc.Annotation Top - NoneType (accepts everything) others - minizinc.Object (means an error) For 'annvars': Just a list of ann names */ static PyObject* Mzn_retrieveNames(PyObject* self, PyObject* args); /********************* SKIP ******************************* */ PyObject* eval_type(TypeInst* ti) { ASTExprVec ranges = ti->ranges(); PyObject* v; switch (ti->type().bt()) { case Type::BT_BOOL: v = reinterpret_cast(&PyBool_Type); break; case Type::BT_INT: if (ti->type().st() == Type::ST_SET) v = reinterpret_cast(&MznVarSet_Type); else v = reinterpret_cast(&PyLong_Type); break; case Type::BT_FLOAT: v = reinterpret_cast(&PyFloat_Type); break; case Type::BT_STRING: v = reinterpret_cast(&PyUnicode_Type); break; case Type::BT_ANN: v = reinterpret_cast(&MznAnnotation_Type); break; case Type::BT_TOP: v = Py_None; break; default: // v = reinterpret_cast(&MznVariable_Type); // cout << ti->type().bt() << endl; v = reinterpret_cast(&MznObject_Type); break; throw runtime_error("CollectBoolFunctionNames: unexpected type"); } if (ranges.size() == 0) { Py_INCREF(v); return v; } else { PyObject* args_tuple = PyList_New(ranges.size()); for (int i = 0; i != ranges.size(); ++i) { Py_INCREF(v); PyList_SET_ITEM(args_tuple, i, v); } return args_tuple; } } void add_to_dictionary(FunctionI* fi, PyObject* toAdd) { ASTExprVec params = fi->params(); const char* str = fi->id().str().c_str(); PyObject* key = PyUnicode_FromString(str); PyObject* args_and_return_type_tuple = PyTuple_New(2); PyObject* args_tuple = PyTuple_New(params.size()); for (unsigned int i = 0; i < params.size(); ++i) { PyTuple_SET_ITEM(args_tuple, i, eval_type(params[i]->ti())); } PyObject* return_type = eval_type(fi->ti()); PyTuple_SET_ITEM(args_and_return_type_tuple, 0, args_tuple); PyTuple_SET_ITEM(args_and_return_type_tuple, 1, return_type); PyObject* toAdd_item = PyDict_GetItem(toAdd, key); if (toAdd_item == NULL) { toAdd_item = PyList_New(1); PyList_SET_ITEM(toAdd_item, 0, args_and_return_type_tuple); if (PyDict_SetItem(toAdd, key, toAdd_item) != 0) throw runtime_error("CollectBoolFunctionNames: cannot set new key to the dictionary"); Py_DECREF(toAdd_item); } else { if (PyList_Append(toAdd_item, args_and_return_type_tuple) != 0) throw runtime_error("CollectBoolFunctionNames: cannot append item to the list"); } } class CollectBoolFuncNames : public ItemVisitor { protected: bool include_global_mzn; PyObject* _boolfuncs; public: CollectBoolFuncNames(PyObject* boolfuncs, bool include_global_mzn0) : _boolfuncs(boolfuncs), include_global_mzn(include_global_mzn0) {} bool enterModel(Model* m) { return m->filename() != "stdlib.mzn" && (include_global_mzn || m->filename() != "globals.mzn"); } void vFunctionI(FunctionI* fi) { if (fi->ti()->type().isvarbool() == false) return; add_to_dictionary(fi, _boolfuncs); } }; class CollectAnnNames : public ItemVisitor { protected: PyObject* _annfuncs; PyObject* _annvars; bool include_global_mzn; public: CollectAnnNames(PyObject* annfuncs, PyObject* annvars, bool include_global_mzn0) : _annfuncs(annfuncs), _annvars(annvars), include_global_mzn(include_global_mzn0) {} bool enterModel(Model* m) { return include_global_mzn || (m->filename() != "globals.mzn" && m->filename() != "stdlib.mzn"); } void vFunctionI(FunctionI* fi) { if (fi->ti()->type().isann() == false) return; add_to_dictionary(fi, _annfuncs); } void vVarDeclI(VarDeclI* vdi) { if (vdi->e()->ti()->type().isann()) { PyList_Append(_annvars, PyUnicode_FromString(vdi->e()->id()->str().c_str())); } } }; /********************* END OF SKIP ******************************* */ static PyMethodDef Mzn_methods[] = { {"load", (PyCFunction)Mzn_load, METH_KEYWORDS, "Load MiniZinc model from MiniZinc file"}, {"load_from_string", (PyCFunction)Mzn_load_from_string, METH_KEYWORDS, "Load MiniZinc model from stdin"}, {"BinOp", (PyCFunction)Mzn_BinOp, METH_VARARGS, "Add a binary expression into the model"}, {"UnOp", (PyCFunction)Mzn_UnOp, METH_VARARGS, "Add a unary expression into the model"}, {"Id", (PyCFunction)Mzn_Id, METH_VARARGS, "Return a MiniZinc Variable containing the given name"}, {"Call", (PyCFunction)Mzn_Call, METH_VARARGS, "MiniZinc Call"}, {"at", (PyCFunction)Mzn_at, METH_VARARGS, "Array Access"}, {"retrieveNames", (PyCFunction)Mzn_retrieveNames, METH_VARARGS, "Returns names of MiniZinc functions and variables"}, {"lock", (PyCFunction)Mzn_lock, METH_NOARGS, "Internal: Create a lock for garbage collection"}, {"unlock", (PyCFunction)Mzn_lock, METH_NOARGS, "Internal: Unlock a lock for garbage collection"}, {NULL}}; #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, "minizinc", "A python interface for MiniZinc constraint modeling", -1, Mzn_methods, NULL, NULL, NULL, NULL}; #endif #endif