this repo has no description
at develop 13 kB view raw
1/* Python Interface for MiniZinc constraint modelling 2 * Author: 3 * Tai Tran <tai.tran@student.adelaide.edu.au> 4 * Supervisor: 5 * Guido Tack <guido.tack@monash.edu> 6 */ 7 8#include "pyinterface.h" 9 10using namespace MiniZinc; 11using namespace std; 12 13static PyObject* Mzn_Call(PyObject* self, PyObject* args) { 14 const char* name; 15 PyObject* variableTuple; 16 PyTypeObject* returnType; 17 if (!PyArg_ParseTuple(args, "sO|O", &name, &variableTuple, &returnType)) { 18 PyErr_SetString(PyExc_TypeError, 19 "MiniZinc: Mzn_Call: Accepts 2 values: a string, a list of minizinc variable"); 20 PyErr_Print(); 21 return NULL; 22 } 23 24 if (!PyList_Check(variableTuple)) { 25 PyErr_SetString(PyExc_TypeError, "MiniZinc: Mzn_Call: Second argument must be a list"); 26 return NULL; 27 } 28 29 long len = PyList_GET_SIZE(variableTuple); 30 vector<Expression*> expressionList(len); 31 for (long i = 0; i != len; ++i) { 32 PyObject* pyval = PyList_GET_ITEM(variableTuple, i); 33 if (PyObject_TypeCheck(pyval, &MznObject_Type)) { 34 expressionList[i] = MznObject_get_e(reinterpret_cast<MznObject*>(pyval)); 35 } else { 36 Type type; 37 vector<pair<int, int> > dimList; 38 expressionList[i] = python_to_minizinc(pyval, type, dimList); 39 if (expressionList[i] == NULL) { 40 MZN_PYERR_SET_STRING(PyExc_RuntimeError, 41 "MiniZinc: MznCall: Second argument, item at position %li must be a " 42 "MiniZinc Object or Python int/float/string/list/tuple", 43 i); 44 return NULL; 45 } 46 } 47 } 48 49 PyObject* ret = MznExpression_new(&MznExpression_Type, NULL, NULL); 50 51 reinterpret_cast<MznExpression*>(ret)->e = new Call(Location(), string(name), expressionList); 52 53 return ret; 54} 55 56static PyObject* Mzn_Id(PyObject* self, PyObject* args) { 57 const char* name; 58 if (!PyArg_ParseTuple(args, "s", &name)) { 59 PyErr_SetString(PyExc_TypeError, "MiniZinc: Mzn_Id: Argument must be a string"); 60 return NULL; 61 } 62 PyObject* ret = MznExpression_new(&MznExpression_Type, NULL, NULL); 63 reinterpret_cast<MznExpression*>(ret)->e = new Id(Location(), name, NULL); 64 return ret; 65} 66 67static PyObject* Mzn_at(PyObject* self, PyObject* args) { 68 PyObject* Py_array; 69 PyObject* Py_idx; 70 if (!PyArg_ParseTuple(args, "OO", &Py_array, &Py_idx)) { 71 PyErr_SetString(PyExc_TypeError, "MiniZinc: at: Parsing error"); 72 return NULL; 73 } 74 75 if (!PyObject_TypeCheck(Py_array, &MznExpression_Type)) { 76 PyErr_SetString(PyExc_TypeError, "MiniZinc: at: First argument must be a MiniZinc Expression"); 77 return NULL; 78 } 79 80 if (!PyList_Check(Py_idx)) { 81 PyErr_SetString(PyExc_TypeError, "MiniZinc: at: Second argument must be a list of indices"); 82 return NULL; 83 } 84 85 Py_ssize_t n = PyList_GET_SIZE(Py_idx); 86 87 vector<Expression*> idx(n); 88 for (Py_ssize_t i = 0; i != n; ++i) { 89 PyObject* obj = PyList_GetItem(Py_idx, i); 90#if PY_MAJOR_VERSION < 3 91 if (PyInt_Check(obj)) { 92 long index = PyInt_AS_LONG(obj); 93 idx[i] = IntLit::a(IntVal(index)); 94 } else 95#endif 96 if (PyLong_Check(obj)) { 97 int overflow; 98 long long index = PyLong_AsLongLongAndOverflow(obj, &overflow); 99 if (overflow) { 100 MZN_PYERR_SET_STRING(PyExc_OverflowError, "MiniZinc: at: Index at pos %li overflowed", i); 101 return NULL; 102 } 103 idx[i] = IntLit::a(IntVal(index)); 104 } else if (PyObject_TypeCheck(obj, &MznExpression_Type)) { 105 idx[i] = reinterpret_cast<MznExpression*>(obj)->e; 106 } else { 107 PyErr_SetString(PyExc_TypeError, 108 "MiniZinc: ArrayAccess: Indices must be integers or MiniZinc Expression"); 109 return NULL; 110 } 111 } 112 113 MznExpression* ret = 114 reinterpret_cast<MznExpression*>(MznExpression_new(&MznExpression_Type, NULL, NULL)); 115 ret->e = new ArrayAccess(Location(), reinterpret_cast<MznExpression*>(Py_array)->e, idx); 116 return reinterpret_cast<PyObject*>(ret); 117} 118 119static PyObject* Mzn_UnOp(PyObject* self, PyObject* args) { 120 /* 121 enum UnOpType { 122 UOT_NOT, // 0 123 UOT_PLUS, // 1 124 UOT_MINUS // 2 125 };*/ 126 PyObject* r; 127 unsigned int op; 128 if (!PyArg_ParseTuple(args, "IO", &op, &r)) { 129 PyErr_SetString(PyExc_TypeError, 130 "MiniZinc: Mzn_UnOp: Requires a MiniZinc object and an integer"); 131 return NULL; 132 } 133 Expression* rhs; 134 135 if (PyObject_TypeCheck(r, &MznExpression_Type)) { 136 rhs = reinterpret_cast<MznExpression*>(r)->e; 137 } else if (PyBool_Check(r)) { 138 rhs = new BoolLit(Location(), PyObject_IsTrue(r)); 139 } else 140#if PY_MAJOR_VERSION < 3 141 if (PyInt_Check(r)) { 142 rhs = IntLit::a(IntVal(PyInt_AS_LONG(r))); 143 } else 144#endif 145 if (PyLong_Check(r)) { 146 int overflow; 147 long long c_val = PyLong_AsLongLongAndOverflow(r, &overflow); 148 if (overflow) { 149 PyErr_SetString(PyExc_OverflowError, "MiniZinc: Mzn_UnOp: Object is overflowed"); 150 return NULL; 151 } 152 rhs = IntLit::a(IntVal(c_val)); 153 } else if (PyFloat_Check(r)) { 154 rhs = new FloatLit(Location(), PyFloat_AS_DOUBLE(r)); 155 } else if (PyUnicode_Check(r)) { 156 rhs = new StringLit(Location(), string(PyUnicode_AsUTF8(r))); 157 } else { 158 PyErr_SetString(PyExc_TypeError, 159 "MiniZinc: Mzn_UnOp: Object must be a Python value or a MiniZinc object"); 160 return NULL; 161 } 162 163 GCLock Lock; 164 165 PyObject* ret = MznExpression_new(&MznExpression_Type, NULL, NULL); 166 reinterpret_cast<MznExpression*>(ret)->e = new UnOp(Location(), static_cast<UnOpType>(op), rhs); 167 return ret; 168} 169 170/* 171 * Description: Creates a minizinc BinOp expression 172 * Note: Need an outer GCLock for this to work 173 */ 174static PyObject* Mzn_BinOp(PyObject* self, PyObject* args) { 175 /* 176 enum BinOpType { 177 BOT_PLUS, // 0 178 BOT_MINUS, // 1 179 BOT_MULT, // 2 180 BOT_DIV, // 3 181 BOT_IDIV, // 4 182 BOT_MOD, // 5 183 BOT_LE, // 6 184 BOT_LQ, // 7 185 BOT_GR, // 8 186 BOT_GQ, // 9 187 BOT_EQ, //10 188 BOT_NQ, //11 189 BOT_IN, //12 190 BOT_SUBSET, //13 191 BOT_SUPERSET, //14 192 BOT_UNION, //15 193 BOT_DIFF, //16 194 BOT_SYMDIFF, //17 195 BOT_INTERSECT, //18 196 BOT_PLUSPLUS, //19 197 BOT_EQUIV, //20 198 BOT_IMPL, //21 199 BOT_RIMPL, //22 200 BOT_OR, //23 201 BOT_AND, //24 202 BOT_XOR, //25 203 BOT_DOTDOT //26 204 };*/ 205 PyObject* PyPre[2]; 206 unsigned int op; 207 if (!PyArg_ParseTuple(args, "OIO", &PyPre[0], &op, &PyPre[1])) { 208 PyErr_SetString(PyExc_TypeError, 209 "MiniZinc: Mzn_BinOp: Requires two MiniZinc objects and an integer"); 210 return NULL; 211 } 212 Expression* pre[2]; 213 // pre[0]: lhs; 214 // pre[1]: rhs; 215 for (int i = 0; i != 2; ++i) { 216 if (PyObject_TypeCheck(PyPre[i], &MznExpression_Type)) { 217 pre[i] = reinterpret_cast<MznExpression*>(PyPre[i])->e; 218 } else if (PyBool_Check(PyPre[i])) { 219 pre[i] = new BoolLit(Location(), PyObject_IsTrue(PyPre[i])); 220 } else 221#if PY_MAJOR_VERSION < 3 222 if (PyInt_Check(PyPre[i])) { 223 pre[i] = IntLit::a(IntVal(PyInt_AS_LONG(PyPre[i]))); 224 } else 225#endif 226 227 if (PyLong_Check(PyPre[i])) { 228 int overflow; 229 long long c_val = PyLong_AsLongLongAndOverflow(PyPre[i], &overflow); 230 if (overflow) { 231 PyErr_SetString(PyExc_OverflowError, "MiniZinc: Mzn_UnOp: Object is overflowed"); 232 return NULL; 233 } 234 pre[i] = IntLit::a(IntVal(c_val)); 235 } else if (PyFloat_Check(PyPre[i])) { 236 pre[i] = new FloatLit(Location(), PyFloat_AS_DOUBLE(PyPre[i])); 237 } else if (PyUnicode_Check(PyPre[i])) { 238 pre[i] = new StringLit(Location(), string(PyUnicode_AsUTF8(PyPre[i]))); 239 } else { 240 if (i == 0) 241 PyErr_SetString( 242 PyExc_TypeError, 243 "MiniZinc: Mzn_BinOp: Left hand side object must be a Python value or MiniZinc object"); 244 else 245 PyErr_SetString(PyExc_TypeError, 246 "MiniZinc: Mzn_BinOp: Right hand side object must be a Python value or " 247 "MiniZinc object"); 248 return NULL; 249 } 250 } 251 252 GCLock Lock; 253 254 PyObject* ret = MznExpression_new(&MznExpression_Type, NULL, NULL); 255 reinterpret_cast<MznExpression*>(ret)->e = 256 (new BinOp(Location(), pre[0], static_cast<BinOpType>(op), pre[1])); 257 return ret; 258} 259 260static PyObject* Mzn_load(PyObject* self, PyObject* args, PyObject* keywds) { 261 PyObject* model = MznModel_new(&MznModel_Type, NULL, NULL); 262 if (MznModel_init(reinterpret_cast<MznModel*>(model), NULL) < 0) return NULL; 263 if (MznModel_load(reinterpret_cast<MznModel*>(model), args, keywds) == NULL) return NULL; 264 return model; 265} 266 267static PyObject* Mzn_load_from_string(PyObject* self, PyObject* args, PyObject* keywds) { 268 PyObject* model = MznModel_new(&MznModel_Type, NULL, NULL); 269 if (model == NULL) return NULL; 270 if (MznModel_init(reinterpret_cast<MznModel*>(model), NULL) < 0) return NULL; 271 if (MznModel_load_from_string(reinterpret_cast<MznModel*>(model), args, keywds) == NULL) 272 return NULL; 273 return model; 274} 275 276static PyObject* Mzn_retrieveNames(PyObject* self, PyObject* args) { 277 PyObject* boolfuncs = PyDict_New(); 278 PyObject* annfuncs = PyDict_New(); 279 PyObject* annvars = PyList_New(0); 280 PyObject* libName = NULL; 281 282 { 283 Py_ssize_t n = PyTuple_GET_SIZE(args); 284 if (n > 1) { 285 PyErr_SetString(PyExc_TypeError, "MiniZinc: Mzn_retrieveNames: accepts at most 1 argument"); 286 return NULL; 287 } else if (n == 1) { 288 libName = PyTuple_GET_ITEM(args, 0); 289 if (PyObject_IsTrue(libName)) { 290 if (!PyUnicode_Check(libName)) { 291 PyErr_SetString(PyExc_TypeError, 292 "MiniZinc: Mzn_retrieveNames: first argument must be a string"); 293 return NULL; 294 } 295 } else 296 libName = NULL; 297 } 298 } 299 300 // If a library name is specified here, it means that this function is called at least once 301 // already. If that's the case, functions in globals.mzn and stdlib.mzn will be already defined, 302 // so we dont want to reinclude it 303 bool include_global_mzn = (libName == NULL); 304 305 MznModel* tempModel = reinterpret_cast<MznModel*>(MznModel_new(&MznModel_Type, NULL, NULL)); 306 307 if (MznModel_init(tempModel, libName) != 0) { 308 return NULL; 309 } 310 CollectBoolFuncNames bool_fv(boolfuncs, include_global_mzn); 311 CollectAnnNames ann_fv(annfuncs, annvars, include_global_mzn); 312 iterItems(bool_fv, tempModel->_m); 313 iterItems(ann_fv, tempModel->_m); 314 MznModel_dealloc(tempModel); 315 316 PyObject* dict = PyDict_New(); 317 PyDict_SetItemString(dict, "boolfuncs", boolfuncs); 318 PyDict_SetItemString(dict, "annfuncs", annfuncs); 319 PyDict_SetItemString(dict, "annvars", annvars); 320 321 Py_DECREF(boolfuncs); 322 Py_DECREF(annfuncs); 323 Py_DECREF(annvars); 324 return dict; 325} 326 327#if PY_MAJOR_VERSION >= 3 328 329#define INITERROR return NULL 330 331// PyObject* 332PyMODINIT_FUNC PyInit_minizinc_internal(void) 333#else 334#define INITERROR return 335 336PyMODINIT_FUNC initminizinc_internal(void) 337 338#endif 339 340{ 341#if PY_MAJOR_VERSION >= 3 342 PyObject* module = PyModule_Create(&moduledef); 343#else 344 PyObject* module = Py_InitModule3("minizinc_internal", Mzn_methods, 345 "A python interface for MiniZinc constraint modeling"); 346#endif 347 348 if (module == NULL) INITERROR; 349 350 if (PyType_Ready(&MznObject_Type) < 0) INITERROR; 351 Py_INCREF(&MznObject_Type); 352 PyModule_AddObject(module, "Object", reinterpret_cast<PyObject*>(&MznObject_Type)); 353 354 if (PyType_Ready(&MznSetIter_Type) < 0) INITERROR; 355 Py_INCREF(&MznSetIter_Type); 356 PyModule_AddObject(module, "Set_Iter", reinterpret_cast<PyObject*>(&MznSetIter_Type)); 357 358 if (PyType_Ready(&MznExpression_Type) < 0) INITERROR; 359 Py_INCREF(&MznExpression_Type); 360 PyModule_AddObject(module, "Expression", reinterpret_cast<PyObject*>(&MznExpression_Type)); 361 362 if (PyType_Ready(&MznAnnotation_Type) < 0) INITERROR; 363 Py_INCREF(&MznAnnotation_Type); 364 PyModule_AddObject(module, "Annotation", reinterpret_cast<PyObject*>(&MznAnnotation_Type)); 365 366 if (PyType_Ready(&MznSet_Type) < 0) INITERROR; 367 Py_INCREF(&MznSet_Type); 368 PyModule_AddObject(module, "Set", reinterpret_cast<PyObject*>(&MznSet_Type)); 369 370 if (PyType_Ready(&MznVarSet_Type) < 0) INITERROR; 371 Py_INCREF(&MznVarSet_Type); 372 PyModule_AddObject(module, "VarSet", reinterpret_cast<PyObject*>(&MznVarSet_Type)); 373 374 if (PyType_Ready(&MznModel_Type) < 0) INITERROR; 375 Py_INCREF(&MznModel_Type); 376 PyModule_AddObject(module, "Model", reinterpret_cast<PyObject*>(&MznModel_Type)); 377 378 if (PyType_Ready(&PyMznSolver_Type) < 0) INITERROR; 379 Py_INCREF(&PyMznSolver_Type); 380 PyModule_AddObject(module, "Solver", reinterpret_cast<PyObject*>(&PyMznSolver_Type)); 381 382#if PY_MAJOR_VERSION >= 3 383 return module; 384#endif 385}