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}