this repo has no description
1#include "global.h" 2 3using namespace MiniZinc; 4using namespace std; 5 6inline PyObject* c_to_py_number(long long c_val) { 7#if PY_MAJOR_VERSION < 3 8 if (c_val > LONG_MIN || c_val < LONG_MAX) 9 return PyInt_FromLong(static_cast<long>(c_val)); 10 else 11#endif 12 return PyLong_FromLongLong(c_val); 13} 14 15inline long long py_to_c_number(PyObject* py_val) { 16#if PY_MAJOR_VERSION < 3 17 if (PyInt_Check(py_val)) { 18 return PyInt_AS_LONG(py_val); 19 } else 20#endif 21 if (PyLong_Check(py_val)) { 22 int overflow; 23 long long c_val = PyLong_AsLongLongAndOverflow(py_val, &overflow); 24 if (overflow) { 25 PyErr_SetString(PyExc_OverflowError, "Python value is overflown"); 26 return -1; 27 } 28 return c_val; 29 } else { 30 PyErr_SetString(PyExc_TypeError, "Python value must be an integer"); 31 return -1; 32 } 33} 34 35inline long long py_to_c_number(PyObject* py_val, int* overflow) { 36#if PY_MAJOR_VERSION < 3 37 if (PyInt_Check(py_val)) { 38 *overflow = 0; 39 return PyInt_AS_LONG(py_val); 40 } else 41#endif 42 if (PyLong_Check(py_val)) { 43 long long c_val = PyLong_AsLongLongAndOverflow(py_val, overflow); 44 if (*overflow) { 45 PyErr_SetString(PyExc_OverflowError, "Python value is overflown"); 46 return -1; 47 } 48 *overflow = 0; 49 return c_val; 50 } else { 51 *overflow = 0; 52 PyErr_SetString(PyExc_TypeError, "Python value must be an integer"); 53 return -1; 54 } 55} 56 57bool compareType(const Type& type1, const Type& type2) { 58 return (type1.bt() == type2.bt() && type1.st() == type2.st() && type1.dim() == type2.dim()); 59} 60 61string typePresentation(const Type& type) { 62 string baseTypeString; 63 switch (type.bt()) { 64 case Type::BT_BOOL: 65 baseTypeString = "bool"; 66 break; 67 case Type::BT_INT: 68 baseTypeString = "int"; 69 break; 70 case Type::BT_FLOAT: 71 baseTypeString = "float"; 72 break; 73 case Type::BT_STRING: 74 baseTypeString = "string"; 75 break; 76 default: 77 baseTypeString = "UNSET"; 78 } 79 if (type.st() == Type::ST_SET) 80 return "a set of " + baseTypeString; 81 else if (type.dim() == 0) { 82 if (type.bt() == Type::BT_INT) 83 return "an " + baseTypeString; 84 else 85 return "a " + baseTypeString; 86 } else { 87 string ret = "an array of ["; 88 for (int i = type.dim(); i--;) { 89 ret += baseTypeString; 90 if (i - 1 > 0) ret += ", "; 91 } 92 ret += ']'; 93 return ret; 94 } 95} 96 97inline PyObject* one_dim_minizinc_to_python(Expression* e, const Type& type) { 98 Env env(NULL); 99 100 if (type.st() == Type::ST_SET) { 101 IntSetVal* isv = eval_intset(env.envi(), e); 102 MznSet* newSet = reinterpret_cast<MznSet*>(MznSet_new(&MznSet_Type, NULL, NULL)); 103 for (IntSetRanges isr(isv); isr(); ++isr) { 104 newSet->push(isr.min().toInt(), isr.max().toInt()); 105 } 106 return reinterpret_cast<PyObject*>(newSet); 107 } else 108 switch (type.bt()) { 109 case Type::BT_BOOL: 110 return PyBool_FromLong(eval_bool(env.envi(), e)); 111 case Type::BT_INT: 112 return c_to_py_number(eval_int(env.envi(), e).toInt()); 113 case Type::BT_FLOAT: 114 return PyFloat_FromDouble(eval_float(env.envi(), e)); 115 case Type::BT_STRING: { 116 string temp(eval_string(env.envi(), e)); 117 return PyUnicode_FromString(temp.c_str()); 118 } 119 default: 120 throw logic_error("MiniZinc: one_dim_minizinc_to_python: Unexpected type code"); 121 } 122} 123 124/* 125 * Convert minizinc expression to python value 126 */ 127PyObject* minizinc_to_python(VarDecl* vd) { 128 GCLock Lock; 129 if (vd == NULL) { 130 PyErr_SetString(PyExc_ValueError, "MiniZinc_to_Python: Value is not set"); 131 return NULL; 132 } 133 Type type = vd->type(); 134 if (type.dim() == 0) { 135 return one_dim_minizinc_to_python(vd->e(), type); 136 } else { 137 Env env(NULL); 138 ArrayLit* al = eval_par(env.envi(), vd->e())->cast<ArrayLit>(); 139 int dim = vd->type().dim(); 140 141 // Maximum size of each dimension 142 vector<Py_ssize_t> dmax; 143 // Current size of each dimension 144 vector<Py_ssize_t> d; 145 // p[0] holds the final array, p[1+] builds up p[0] 146 vector<PyObject*> p(dim); 147 148 for (int i = 0; i < dim; ++i) { 149 d.push_back(0); 150 Py_ssize_t dtemp = al->max(i) - al->min(i) + 1; 151 dmax.push_back(dtemp); 152 p[i] = PyList_New(dtemp); 153 } 154 155 int i = dim - 1; 156 157 // next item to be put onto the final array 158 unsigned int currentPos = 0; 159 do { 160 PyList_SetItem(p[i], d[i], one_dim_minizinc_to_python(al->v()[currentPos], type)); 161 currentPos++; 162 d[i]++; 163 while (d[i] >= dmax[i] && i > 0) { 164 PyList_SetItem(p[i - 1], d[i - 1], p[i]); 165 Py_DECREF(p[i]); 166 d[i] = 0; 167 p[i] = PyList_New(dmax[i]); 168 i--; 169 d[i]++; 170 } 171 i = dim - 1; 172 } while (d[0] < dmax[0]); 173 for (int i = 1; i < dim; i++) Py_DECREF(p[i]); 174 return p[0]; 175 } 176} 177 178inline Expression* one_dim_python_to_minizinc(PyObject* pvalue, Type::BaseType& code) { 179 /*enum BaseType { BT_TOP, BT_BOOL, BT_INT, BT_FLOAT, BT_STRING, BT_ANN, 180 BT_BOT, BT_UNKNOWN };*/ 181 switch (code) { 182 case Type::BT_UNKNOWN: 183 if (PyObject_TypeCheck(pvalue, &MznObject_Type)) { 184 return MznObject_get_e(reinterpret_cast<MznObject*>(pvalue)); 185 // return reinterpret_cast<MznObject*>(pvalue)->e(); 186 } else if (PyBool_Check(pvalue)) { 187 BT_BOOLEAN_PROCESS: 188 Expression* rhs = new BoolLit(Location(), PyObject_IsTrue(pvalue)); 189 code = Type::BT_BOOL; 190 return rhs; 191 } else 192#if PY_MAJOR_VERSION < 3 193 if (PyInt_Check(pvalue)) { 194 BT_INTEGER_PROCESS_2X_VERSION: 195 Expression* rhs = IntLit::a(IntVal(PyInt_AS_LONG(pvalue))); 196 code = Type::BT_INT; 197 return rhs; 198 } else 199#endif 200 if (PyLong_Check(pvalue)) { 201 BT_INTEGER_PROCESS: 202 int overflow; 203 Expression* rhs = IntLit::a(IntVal(PyLong_AsLongLongAndOverflow(pvalue, &overflow))); 204 if (overflow) { 205 if (overflow > 0) 206 PyErr_SetString(PyExc_OverflowError, 207 "MiniZinc: Python integer value is larger than 2^63-1"); 208 else 209 PyErr_SetString(PyExc_OverflowError, 210 "MiniZinc: Python integer value is smaller than -2^63"); 211 return NULL; 212 } 213 code = Type::BT_INT; 214 return rhs; 215 } else if (PyFloat_Check(pvalue)) { 216 BT_FLOAT_PROCESS: 217 Expression* rhs = new FloatLit(Location(), PyFloat_AS_DOUBLE(pvalue)); 218 code = Type::BT_FLOAT; 219 return rhs; 220 } else if (PyUnicode_Check(pvalue)) { 221 BT_STRING_PROCESS: 222 Expression* rhs = new StringLit(Location(), PyUnicode_AsUTF8(pvalue)); 223 code = Type::BT_STRING; 224 return rhs; 225 } else { 226 PyErr_SetString(PyExc_TypeError, "MiniZinc: Unexpected python type"); 227 return NULL; 228 } 229 break; 230 231 case Type::BT_INT: 232#if PY_MAJOR_VERSION < 3 233 if (PyInt_Check(pvalue)) 234 goto BT_INTEGER_PROCESS_2X_VERSION; 235 else 236#endif 237 if (!PyLong_Check(pvalue)) { 238 PyErr_SetString( 239 PyExc_TypeError, 240 "MiniZinc: Object in an array must be of the same type: Expected an integer"); 241 return NULL; 242 } 243 goto BT_INTEGER_PROCESS; 244 245 case Type::BT_FLOAT: 246 if (!PyFloat_Check(pvalue)) { 247 PyErr_SetString(PyExc_TypeError, 248 "MiniZinc: Object in an array must be of the same type: Expected an float"); 249 return NULL; 250 } 251 goto BT_FLOAT_PROCESS; 252 253 case Type::BT_STRING: 254 if (!PyUnicode_Check(pvalue)) { 255 PyErr_SetString( 256 PyExc_TypeError, 257 "MiniZinc: Object in an array must be of the same type: Expected an string"); 258 return NULL; 259 } 260 goto BT_STRING_PROCESS; 261 262 case Type::BT_BOOL: 263 if (!PyBool_Check(pvalue)) { 264 PyErr_SetString( 265 PyExc_TypeError, 266 "MiniZinc: Object in an array must be of the same type: Expected an boolean"); 267 return NULL; 268 } 269 goto BT_BOOLEAN_PROCESS; 270 271 default: 272 throw std::invalid_argument("MiniZinc: Internal Error: Received unexpected base type code"); 273 } 274} 275 276Expression* python_to_minizinc(PyObject* pvalue, const ASTExprVec<TypeInst>& ranges) { 277 if (PyObject_TypeCheck(pvalue, &MznObject_Type)) { 278 return MznObject_get_e(reinterpret_cast<MznObject*>(pvalue)); 279 } else if (PyList_Check(pvalue)) { 280 vector<Py_ssize_t> dimensions; 281 vector<PyObject*> simpleArray; 282 if (getList(pvalue, dimensions, simpleArray, 0) == -1) 283 // getList should already set the error string 284 return NULL; 285 if (ranges.size() != dimensions.size()) { 286 PyErr_SetString( 287 PyExc_ValueError, 288 "MiniZinc: python_to_minizinc: size of declared array and actual array not matched"); 289 return NULL; 290 } 291 vector<Expression*> callArgument(dimensions.size() + 1); 292 vector<Expression*> onedArray(simpleArray.size()); 293 294 stringstream buffer; 295 buffer << "array" << dimensions.size() << "d"; 296 string callName(buffer.str()); 297 for (int i = 0; i != dimensions.size(); ++i) { 298 Expression* domain = ranges[i]->domain(); 299 if (domain == NULL) { 300 Expression* e0 = IntLit::a(IntVal(1)); 301 Expression* e1 = IntLit::a(IntVal(dimensions[i])); 302 callArgument[i] = new BinOp(Location(), e0, BOT_DOTDOT, e1); 303 } else { 304 callArgument[i] = domain; 305 } 306 } 307 Type::BaseType code = Type::BT_UNKNOWN; 308 for (int i = 0; i != simpleArray.size(); ++i) { 309 PyObject* temp = simpleArray[i]; 310 Expression* rhs = one_dim_python_to_minizinc(temp, code); 311 if (rhs == NULL) return NULL; 312 onedArray[i] = rhs; 313 } 314 callArgument[dimensions.size()] = new ArrayLit(Location(), onedArray); 315 Expression* rhs = new Call(Location(), callName, callArgument); 316 return rhs; 317 } else { 318 Type::BaseType code = Type::BT_UNKNOWN; 319 Expression* rhs = one_dim_python_to_minizinc(pvalue, code); 320 return rhs; 321 } 322} 323 324Expression* python_to_minizinc(PyObject* pvalue, Type& returnType, 325 vector<pair<int, int> >& dimList) { 326 Type::BaseType code = Type::BT_UNKNOWN; 327 if (PyObject_TypeCheck(pvalue, &MznObject_Type)) { 328 returnType = Type::parsetint(); 329 return MznObject_get_e(reinterpret_cast<MznObject*>(pvalue)); 330 } else if (PyList_Check(pvalue)) { 331 vector<Py_ssize_t> dimensions; 332 vector<PyObject*> simpleArray; 333 if (getList(pvalue, dimensions, simpleArray, 0) == -1) { 334 // getList should set error string already 335 return NULL; 336 } 337 if (dimList.empty()) 338 for (int i = 0; i != dimensions.size(); i++) 339 dimList.push_back(pair<Py_ssize_t, Py_ssize_t>(0, dimensions[i] - 1)); 340 else { 341 if (dimList.size() != dimensions.size()) { 342 PyErr_SetString( 343 PyExc_ValueError, 344 "MiniZinc: python_to_minizinc: size of declared and actual array not matched"); 345 return NULL; 346 } 347 for (int i = 0; i != dimensions.size(); i++) { 348 if ((dimList[i].second - (dimList[i].first) + 1) != dimensions[i]) { 349 PyErr_SetString( 350 PyExc_ValueError, 351 "MiniZinc: python_to_minizinc: size of each dimension of python array not matched"); 352 return NULL; 353 } 354 } 355 } 356 vector<Expression*> v; 357 for (int i = 0; i != simpleArray.size(); ++i) { 358 PyObject* temp = simpleArray[i]; 359 Expression* rhs = one_dim_python_to_minizinc(temp, code); 360 if (rhs == NULL) return NULL; 361 v.push_back(rhs); 362 } 363 returnType = Type(); 364 returnType.bt(code); 365 returnType.dim(dimList.size()); 366 Expression* rhs = new ArrayLit(Location(), v, dimList); 367 return rhs; 368 } else { 369 Expression* rhs = one_dim_python_to_minizinc(pvalue, code); 370 returnType = Type(); 371 returnType.bt(code); 372 return rhs; 373 } 374} 375 376vector<TypeInst*> pydim_to_minizinc_ranges(PyObject* pydim, int& errorOccurred) { 377 if (!PyList_Check(pydim)) { 378 errorOccurred = 1; 379 PyErr_SetString(PyExc_TypeError, "MiniZinc: python_to_dimList: argument must be a python list"); 380 return vector<TypeInst*>(); 381 } 382 Py_ssize_t dim = PyList_GET_SIZE(pydim); 383 vector<TypeInst*> ranges(dim); 384 for (Py_ssize_t i = 0; i != dim; ++i) { 385 PyObject* temp = PyList_GET_ITEM(pydim, i); 386 if (!PyList_Check(temp)) { 387 for (int j = 0; j != i; ++j) delete ranges[j]; 388 ranges.clear(); 389 errorOccurred = 1; 390 PyErr_SetString(PyExc_TypeError, 391 "MiniZinc: python_to_dimList: objects in the list must be range lists"); 392 return ranges; 393 } 394 PyObject* Py_bound[2]; 395 Py_bound[0] = PyList_GetItem(temp, 0); 396 Py_bound[1] = PyList_GetItem(temp, 1); 397 if (PyErr_Occurred()) { 398 for (int j = 0; j != i; ++j) delete ranges[j]; 399 ranges.clear(); 400 errorOccurred = 1; 401 PyErr_SetString(PyExc_TypeError, 402 "MiniZinc: python_to_dimList: a range must consist of 2 values"); 403 return ranges; 404 } 405 406 long long c_bound[2]; 407 for (int k = 0; k != 2; ++k) { 408#if PY_MAJOR_VERSION < 3 409 if (PyInt_Check(Py_bound[k])) 410 c_bound[k] = PyInt_AS_LONG(Py_bound[k]); 411 else 412#endif 413 if (PyLong_Check(Py_bound[k])) { 414 int overflow; 415 c_bound[k] = PyLong_AsLongLongAndOverflow(Py_bound[k], &overflow); 416 if (overflow) { 417 switch (k) { 418 case 0: 419 MZN_PYERR_SET_STRING( 420 PyExc_OverflowError, 421 "MiniZinc: python_to_dimList: Range at pos %i: First argument is overflown", i); 422 break; 423 case 1: 424 MZN_PYERR_SET_STRING( 425 PyExc_OverflowError, 426 "MiniZinc: python_to_dimList: Range at pos %i: Second argument is overflown", i); 427 break; 428 default: 429 throw logic_error("pydim_to_dimList: Unexpected iterator value"); 430 } 431 for (int j = 0; j != i; ++j) delete ranges[j]; 432 ranges.clear(); 433 errorOccurred = 1; 434 return ranges; 435 } 436 } else { 437 switch (k) { 438 case 0: 439 MZN_PYERR_SET_STRING(PyExc_OverflowError, 440 "MiniZinc: python_to_dimList: Range at pos %i: First argument " 441 "type is mismatched: expected a number", 442 i); 443 break; 444 case 1: 445 MZN_PYERR_SET_STRING(PyExc_OverflowError, 446 "MiniZinc: python_to_dimList: Range at pos %i: Second argument " 447 "type is mismatched: expected a number", 448 i); 449 break; 450 default: 451 throw logic_error("pydim_to_dimList: Unexpected iterator value"); 452 } 453 for (int j = 0; j != i; ++j) delete ranges[j]; 454 ranges.clear(); 455 errorOccurred = 1; 456 return ranges; 457 } 458 } 459 if (c_bound[0] > c_bound[1]) swap(c_bound[0], c_bound[1]); 460 Expression* e0 = IntLit::a(IntVal(c_bound[0])); 461 Expression* e1 = IntLit::a(IntVal(c_bound[1])); 462 Expression* domain = new BinOp(Location(), e0, BOT_DOTDOT, e1); 463 ranges[i] = new TypeInst(Location(), Type(), domain); 464 } 465 errorOccurred = 0; 466 return ranges; 467} 468 469int getList(PyObject* value, vector<Py_ssize_t>& dimensions, vector<PyObject*>& simpleArray, 470 const int layer) { 471 for (Py_ssize_t i = 0; i < PyList_Size(value); i++) { 472 if (dimensions.size() <= layer) { 473 dimensions.push_back(PyList_Size(value)); 474 } else if (dimensions[layer] != PyList_Size(value)) { 475 PyErr_SetString(PyExc_ValueError, 476 "MiniZinc: Inconsistency in size of multidimensional array"); 477 return -1; 478 } 479 PyObject* li = PyList_GetItem(value, i); 480 if (PyList_Check(li)) { 481 if (getList(li, dimensions, simpleArray, layer + 1) == -1) { 482 return -1; 483 } 484 } else { 485 simpleArray.push_back(li); 486 } 487 } 488 return 0; 489}