Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
23 kB · 694 lines
C++
at develop
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695#include "Model.h"
using namespace MiniZinc;using namespace std;
int MznModel::addData(const char* const name, PyObject* value) { GCLock Lock; if (value == NULL) { PyErr_SetString(PyExc_TypeError, "MiniZinc: Model.addData: Received a NULL value"); return -1; } for (unsigned int i = 0; i < _m->size(); i++) if (VarDeclI* vdi = (*_m)[i]->dyn_cast<VarDeclI>()) { if (strcmp(vdi->e()->id()->str().c_str(), name) == 0) { vector<pair<int, int> > dimList; Type type; Expression* rhs = python_to_minizinc(value, vdi->e()->ti()->ranges()); //, vdi->e()->type(), name); if (rhs == NULL) return -1; vdi->e()->e(rhs); return 0; } } MZN_PYERR_SET_STRING(PyExc_TypeError, "MiniZinc: Model.addData: Undefined name '%s'", name); return -1;}
int MznModel::load(PyObject* args, PyObject* keywds, bool fromFile) { GCLock Lock; Model* saveModel = _m; stringstream errorStream; vector<string> data;
PyObject* obj = Py_None; char* options = NULL; const char* py_string; char* errorFile = "./error.txt";
bool isDict = false;
if (fromFile) { char* kwlist[] = {"file", "data", "options"}; if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|Os", kwlist, &py_string, &obj, &options)) { PyErr_SetString(PyExc_TypeError, "MiniZinc: load: Parsing error"); return -1; } if (options != NULL) { char* pch; bool t_flag = false; pch = strtok(options, " "); while (pch != NULL) { if (strcmp(pch, "-t") == 0) t_flag = true; else { if (t_flag) { char* ptr; int t = strtol(pch, &ptr, 10); if (t == 0) { PyErr_SetString(PyExc_ValueError, "MiniZinc: Model.load: Time value must be a valid positive number"); return -1; } timeLimit = t; t_flag = false; } else { PyErr_SetString(PyExc_ValueError, "MiniZinc: Model.load: Unknown option"); return -1; } } pch = strtok(NULL, " "); } } if (obj != Py_None) { if (PyUnicode_Check(obj)) { data.push_back(string(PyUnicode_AsUTF8(obj))); } else if (PyList_Check(obj)) { Py_ssize_t n = PyList_GET_SIZE(obj); for (Py_ssize_t i = 0; i != n; ++i) { const char* name = PyUnicode_AsUTF8(PyList_GET_ITEM(obj, i)); if (name == NULL) { PyErr_SetString(PyExc_TypeError, "MiniZinc: Model.load: Element in the list must be a filename"); return -1; } data.push_back(string(name)); } } else if (PyDict_Check(obj)) { isDict = true; } else { PyErr_SetString(PyExc_TypeError, "MiniZinc: Model.load: The second argument must be either a filename, a " "list of filenames or a dictionary of data"); return -1; } } vector<string> models{py_string}; _m = parse(models, data, *includePaths, false, false, false, errorStream); _e = new Env(_m); } else { char* kwlist[] = {"string", "error", "options"}; if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|ss", kwlist, &py_string, &errorFile, &options)) { PyErr_SetString(PyExc_TypeError, "MiniZinc: Model.load: Keyword parsing error"); return -1; } _m = parseFromString(string(py_string), errorFile, *includePaths, false, false, false, errorStream); _e = new Env(_m); } if (_m) { delete saveModel; if (isDict) { stringstream assignments; Py_ssize_t pos = 0; PyObject* key; PyObject* value; GCLock lock; while (PyDict_Next(obj, &pos, &key, &value)) { const char* name = PyUnicode_AsUTF8(key); if (addData(name, value) == -1) { // addData handles the error message return -1; } } } loaded = true; return 0; } else { const std::string tmp = "MiniZinc: Model.load: " + errorStream.str(); PyErr_SetString(PyExc_RuntimeError, tmp.c_str()); return -1; }}
PyObject* MznModel::solve(PyObject* args, PyObject* kwds) { if (!loaded) { PyErr_SetString(PyExc_RuntimeError, "MiniZinc: Model.solve: No data has been loaded into the model"); return NULL; }
PyObject* dict = NULL;
static char* kwlist[] = {"dict", "solver", "time", NULL};
char* solverName = ""; unsigned long newTimeLimit = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Osk", kwlist, &dict, &solverName, &newTimeLimit)) { PyErr_SetString(PyExc_RuntimeError, "MiniZinc: Model.solve: Parsing error"); return NULL; }
Model* saveModel; { GCLock lock; saveModel = copy(_e->envi(), _m); Py_ssize_t pos = 0; PyObject* key; PyObject* value; if (dict) { while (PyDict_Next(dict, &pos, &key, &value)) { const char* name = PyUnicode_AsUTF8(key); if (addData(name, value) == -1) { // addData handled the error message goto SOLVE__ERROR_HANDLING; } } } if (newTimeLimit > 0) { timeLimit = newTimeLimit; } if (strlen(solverName)) { if (set_solver(solverName) == NULL) { // setSolver handled the error message goto SOLVE__ERROR_HANDLING; } } goto SOLVE__NO_ERROR; SOLVE__ERROR_HANDLING: delete _m; _m = saveModel; _e = new Env(_m); return NULL; }
SOLVE__NO_ERROR: vector<TypeError> typeErrors; try { MiniZinc::typecheck(*_e, _m, typeErrors, false); } catch (LocationException& e) { MZN_PYERR_SET_STRING(PyExc_RuntimeError, "MiniZinc: Model.solve: %s: %s", e.what(), e.msg().c_str()); return NULL; } if (typeErrors.size() > 0) { stringstream errorLog; for (unsigned int i = 0; i < typeErrors.size(); i++) { errorLog << typeErrors[i].loc() << ":" << endl; errorLog << typeErrors[i].what() << ": " << typeErrors[i].msg() << "\n"; } const std::string& tmp = errorLog.str(); const char* cstr = tmp.c_str(); PyErr_SetString(PyExc_TypeError, cstr); return NULL; } MiniZinc::registerBuiltins(*_e, _m);
Env* env = _e; try { FlatteningOptions fopts; flatten(*env, fopts); } catch (LocationException& e) { stringstream errorLog; errorLog << e.what() << ": " << std::endl; env->dumpErrorStack(errorLog); errorLog << " " << e.msg() << std::endl; const std::string& tmp = errorLog.str(); const char* cstr = tmp.c_str(); PyErr_SetString(PyExc_RuntimeError, cstr); return NULL; } if (env->warnings().size() != 0) { stringstream warningLog; warningLog << "MiniZinc: Model.solve: Warning:\n"; for (unsigned int i = 0; i < env->warnings().size(); i++) { warningLog << env->warnings()[i]; } const std::string& tmp = warningLog.str(); const char* cstr = tmp.c_str(); PyErr_WarnEx(PyExc_RuntimeWarning, cstr, 1); } optimize(*env); oldflatzinc(*env); GCLock lock; Options options; if (timeLimit != 0) options.setIntParam("time", timeLimit); delete _m; _m = saveModel; _e = new Env(_m); PyMznSolver* ret = reinterpret_cast<PyMznSolver*>(PyMznSolver_new(&PyMznSolver_Type, NULL, NULL)); switch (sc) { case SC_UNKNOWN: delete env; PyErr_SetString(PyExc_ValueError, "MiniZinc: Model.solve: Solver name is not set"); return NULL;
case SC_GECODE: ret->solver = new GecodeSolverInstance(*env, options); break; } ret->solver->processFlatZinc(); ret->env = env; return reinterpret_cast<PyObject*>(ret);}
/* * Description: Creates a minizinc constraint * Note: Need an outer GCLock for this to work */static PyObject* MznModel_Constraint(MznModel* self, PyObject* args) { PyObject* obj; if (!PyArg_ParseTuple(args, "O", &obj)) { PyErr_SetString(PyExc_TypeError, "MiniZinc: Model.Constraint: Requires an object of Minizinc Variable"); return NULL; }
GCLock Lock; ConstraintI* i; if (PyObject_ExactTypeCheck(obj, &MznExpression_Type)) { i = new ConstraintI(Location(), (reinterpret_cast<MznExpression*>(obj)->e)); } else if (PyBool_Check(obj)) { bool val = PyObject_IsTrue(obj); i = new ConstraintI(Location(), new BoolLit(Location(), val)); } else { PyErr_SetString( PyExc_TypeError, "MiniZinc: Model.Constraint: Object must be a MiniZinc Variable or Python Boolean value"); return NULL; } self->_m->addItem(i); Py_RETURN_NONE;}
/* * Description: Defines the type of solution of the model */// The responsibility to check if the parsed argument is annotation or not is of the Python// interface, not the C++ interfacestatic PyObject* MznModel_SolveItem(MznModel* self, PyObject* args) { unsigned int solveType; PyObject* PyExp = NULL; PyObject* PyAnn = NULL; Expression* e = NULL; Expression* ann = NULL;
if (!PyArg_ParseTuple(args, "I|OO", &solveType, &PyAnn, &PyExp)) { PyErr_SetString(PyExc_TypeError, "MiniZinc: Model.SolveItem: Requires a solver code, an annotation (can be " "NULL) and an optional expression (for optimisation)"); return NULL; }
if (solveType > 2) { PyErr_SetString( PyExc_ValueError, "MiniZinc: Model.SolveItem: Invalid solver code (Must be a positive less than 3 integer)"); return NULL; } if (solveType) { if (PyExp == NULL) { PyErr_SetString( PyExc_TypeError, "MiniZinc: Model.SolveItem: Optimisation solver requires an addition constraint object"); return NULL; } else if (PyObject_ExactTypeCheck(PyExp, &MznExpression_Type)) { e = reinterpret_cast<MznExpression*>(PyExp)->e; } else { PyErr_SetString(PyExc_TypeError, "MiniZinc: Model.SolveItem: Expression must be a Minizinc Variable Object"); return NULL; } }
GCLock Lock; SolveI* i; switch (solveType) { case 0: i = SolveI::sat(Location()); break; case 1: i = SolveI::min(Location(), (e)); break; case 2: i = SolveI::max(Location(), (e)); break; } if (PyObject_IsTrue(PyAnn)) { if (PyObject_TypeCheck(PyAnn, &MznExpression_Type)) { ann = reinterpret_cast<MznExpression*>(PyAnn)->e; i->ann().add(ann); } else if (PyList_Check(PyAnn)) { long n = PyList_GET_SIZE(PyAnn); for (long idx = 0; idx != n; ++idx) { PyObject* PyItem = PyList_GET_ITEM(PyAnn, idx); if (!PyObject_TypeCheck(PyItem, &MznExpression_Type)) { // XXX: CONSIDER REVIEW - should I delete i or it will be automatically deleted delete i; MZN_PYERR_SET_STRING( PyExc_TypeError, "MiniZinc: Model.SolveItem: Item at position %ld must be a MiniZinc Variable", idx); return NULL; } ann = reinterpret_cast<MznExpression*>(PyItem)->e; i->ann().add(ann); } } else if (PyTuple_Check(PyAnn)) { long n = PyTuple_GET_SIZE(PyAnn); for (long idx = 0; idx != n; ++idx) { PyObject* PyItem = PyTuple_GET_ITEM(PyAnn, idx); if (!PyObject_TypeCheck(PyItem, &MznExpression_Type)) { // XXX: CONSIDER REVIEW delete i; MZN_PYERR_SET_STRING( PyExc_TypeError, "MiniZinc: Model.SolveItem: Item at position %ld must be a MiniZinc Variable", idx); return NULL; } ann = reinterpret_cast<MznExpression*>(PyItem)->e; i->ann().add(ann); } } else { // XXX: CONSIDER REVIEW delete i; PyErr_SetString(PyExc_TypeError, "MiniZinc: Model.SolveItem: Annotation must be a single value of or a " "list/tuple of MiniZinc Variable Object"); return NULL; } } self->_m->addItem(i); Py_RETURN_NONE;}
static PyObject* MznModel_new(PyTypeObject* type, PyObject* args, PyObject* kwds) { MznModel* self = reinterpret_cast<MznModel*>(type->tp_alloc(type, 0)); if (self == NULL) { PyErr_SetString(PyExc_RuntimeError, "MiniZinc: Unable to create new model"); return NULL; } self->includePaths = NULL; self->_m = NULL; self->_e = NULL; return reinterpret_cast<PyObject*>(self);}
static int MznModel_init(MznModel* self, PyObject* args = NULL) { self->loaded = false; string std_lib_dir; if (char* MZNSTDLIBDIR = getenv("MZN_STDLIB_DIR")) { std_lib_dir = string(MZNSTDLIBDIR); } else { PyErr_SetString(PyExc_EnvironmentError, "MiniZinc: Model.init: No MiniZinc library directory MZN_STDLIB_DIR defined."); return -1; } stringstream libNames; libNames << "include \"globals.mzn\";"; if (args != NULL) { PyObject* PyLibNames = NULL; if (PyUnicode_Check(args)) { libNames << "\ninclude \"" << PyUnicode_AsUTF8(args) << "\";"; } else if (PyTuple_Check(args)) { Py_ssize_t n = PyTuple_GET_SIZE(args); if (n > 1) { PyErr_SetString(PyExc_TypeError, "MiniZinc: Model.init: Accept at most 1 argument"); return -1; } else if (n == 1) { PyLibNames = PyTuple_GET_ITEM(args, 0); if (PyObject_IsTrue(PyLibNames)) { if (PyUnicode_Check(PyLibNames)) { libNames << "\ninclude \"" << PyUnicode_AsUTF8(PyLibNames) << "\";"; } else if (PyList_Check(PyLibNames)) { Py_ssize_t n = PyList_GET_SIZE(PyLibNames); for (Py_ssize_t i = 0; i != n; ++i) { PyObject* temp = PyList_GET_ITEM(PyLibNames, i); if (!PyUnicode_Check(temp)) { PyErr_SetString(PyExc_TypeError, "MiniZinc: Model.init: Items in parsing list must be strings"); return -1; } libNames << "\ninclude \"" << PyUnicode_AsUTF8(temp) << "\";"; } } else if (PyTuple_Check(PyLibNames)) { Py_ssize_t n = PyTuple_GET_SIZE(PyLibNames); for (Py_ssize_t i = 0; i != n; ++i) { PyObject* temp = PyTuple_GET_ITEM(PyLibNames, i); if (!PyUnicode_Check(temp)) { PyErr_SetString(PyExc_TypeError, "MiniZinc: Model.init: Items in parsing tuples must be strings"); return -1; } libNames << "\ninclude \"" << PyUnicode_AsUTF8(temp) << "\";"; } } else { PyErr_SetString(PyExc_TypeError, "MiniZinc: Model.init: Parsing argument must be a string or " "list/tuple of strings"); return -1; } } } } } const std::string& libNamesStr = libNames.str(); self->timeLimit = 0; self->includePaths = new vector<string>; self->includePaths->push_back(std_lib_dir + "/gecode/"); self->includePaths->push_back(std_lib_dir + "/std/"); self->sc = MznModel::default_solver; stringstream errorStream; self->_m = parseFromString(libNamesStr, "error.txt", *(self->includePaths), false, false, false, errorStream); self->_e = new Env(self->_m); if (!(self->_m)) { const std::string& tmp = errorStream.str(); const char* cstr = tmp.c_str(); PyErr_SetString(PyExc_EnvironmentError, cstr); return -1; } return 0;}
static void MznModel_dealloc(MznModel* self) { if (self->_m) delete self->_m; if (self->_m) delete self->includePaths; Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));}
static PyObject* MznModel_addData(MznModel* self, PyObject* args) { PyObject* obj; const char* name; if (!PyArg_ParseTuple(args, "sO", &name, &obj)) { PyErr_SetString(PyExc_RuntimeError, "MiniZinc: Model.addData: Parsing error"); return NULL; } if (self->addData(name, obj) == -1) { // addData set error string already return NULL; } Py_RETURN_NONE;}
static PyObject* MznModel_copy(MznModel* self) { MznModel* ret = reinterpret_cast<MznModel*>(MznModel_new(&MznModel_Type, NULL, NULL)); GCLock lock; ret->_m = copy(self->_e->envi(), self->_m); ret->includePaths = new vector<string>(*(self->includePaths));
ret->timeLimit = self->timeLimit; ret->loaded = self->loaded; return reinterpret_cast<PyObject*>(ret);}
static PyObject* MznModel_debugprint(MznModel* self) { debugprint(self->_m); Py_RETURN_NONE;}
static PyObject* MznModel_load(MznModel* self, PyObject* args, PyObject* keywds) { if (self->load(args, keywds, true) < 0) return NULL; Py_RETURN_NONE;}
static PyObject* MznModel_load_from_string(MznModel* self, PyObject* args, PyObject* keywds) { if (self->load(args, keywds, false) < 0) return NULL; Py_RETURN_NONE;}
static PyObject* MznModel_solve(MznModel* self, PyObject* args, PyObject* kwds) { return self->solve(args, kwds);}
static PyObject* MznModel_set_time_limit(MznModel* self, PyObject* args) { unsigned long t; if (!PyArg_ParseTuple(args, "k", &t)) { PyErr_SetString(PyExc_TypeError, "MiniZinc: Model.set_time_limit: Time limit must be an integer"); return NULL; } self->timeLimit = t; return Py_None;}
PyObject* MznModel::set_solver(const char* s) { std::string name(s); // lower characters in name for (std::string::iterator i = name.begin(); i != name.end(); ++i) if (*i <= 'Z' && *i >= 'A') *i = *i - ('Z' - 'z'); if (name == "gecode") sc = SC_GECODE; else { MZN_PYERR_SET_STRING(PyExc_ValueError, "MiniZinc: Model.set_solver: Unexpected solver name: %s", name.c_str()); return NULL; } return Py_None;}
static PyObject* MznModel_set_solver(MznModel* self, PyObject* args) { const char* s; if (!PyArg_ParseTuple(args, "s", &s)) { PyErr_SetString(PyExc_TypeError, "MiniZinc: Model.set_solver: Solver name must be a string"); return NULL; } return (self->set_solver(s));}
static PyObject* MznModel_Declaration(MznModel* self, PyObject* args) { GCLock Lock; enum TypeId { PARINT, // 0 PARBOOL, // 1 PARFLOAT, // 2 PARSTRING, // 3 ANN, // 4 PARSETINT, // 5 PARSETBOOL, // 6 PARSETFLOAT, // 7 PARSETSTRING, // 8 VARINT, // 9 VARBOOL, // 10 VARFLOAT, // 11 VARSETINT, // 12 VARBOT, // 13 BOT, // 14 TOP, // 15 VARTOP, // 16 OPTVARTOP // 17 };
char* name; long tid; PyObject* pydim = NULL; PyObject* pylb = NULL; PyObject* pyub = NULL; PyObject* pyval = NULL; Type type; Expression* domain = NULL; Expression* initValue = NULL; Py_ssize_t dim;
vector<TypeInst*> ranges; Type::BaseType code = Type::BT_UNKNOWN;
if (!PyArg_ParseTuple(args, "sO|OOO", &name, &pyval, &pydim, &pylb, &pyub)) { MZN_PYERR_SET_STRING(PyExc_TypeError, "MiniZinc: MznModel.Declaration: Variable parsing error"); return NULL; } // if only 2 arguments, second value is the initial value if (pydim == NULL) { vector<pair<int, int> > dimList; initValue = python_to_minizinc(pyval, type, dimList); dim = dimList.size(); domain = NULL; } else // else if > 2 arguments, create a MiniZinc Variable {#if PY_MAJOR_VERSION < 3 if (PyInt_Check(pyval)) { tid = PyInt_AS_LONG(pyval); pyval = NULL; } else#endif if (PyLong_Check(pyval)) { tid = PyLong_AsLong(pyval); pyval = NULL; } else { PyErr_SetString(PyExc_TypeError, "MiniZinc: MznModel.Declaration: Type Id must be an integer"); return NULL; } if (tid > 17 || tid < 0) { PyErr_SetString(PyExc_ValueError, "MiniZinc: MznModel.Declaration: Type Id is from 0 to 17"); return NULL; }
int errorOccurred; ranges = pydim_to_minizinc_ranges(pydim, errorOccurred); if (errorOccurred) return NULL; dim = ranges.size();
// Process different types switch (static_cast<TypeId>(tid)) { case VARINT: type = Type::varint(dim); code = Type::BT_INT; if (pyub == NULL) { Type tempType; vector<pair<int, int> > tempDimList; domain = python_to_minizinc(pylb, tempType, tempDimList); if (tempType.st() != Type::ST_SET) { PyErr_SetString(PyExc_TypeError, "MiniZinc: MznModel.Declaration: If 5th argument does not exist, 4th " "argument must be a Minizinc Set"); return NULL; } } else domain = new BinOp(Location(), one_dim_python_to_minizinc(pylb, code), BOT_DOTDOT, one_dim_python_to_minizinc(pyub, code)); break; case VARBOOL: type = Type::varbool(dim); break; case VARFLOAT: type = Type::varfloat(dim); code = Type::BT_FLOAT; domain = new BinOp(Location(), one_dim_python_to_minizinc(pylb, code), BOT_DOTDOT, one_dim_python_to_minizinc(pyub, code)); break; case VARSETINT: type = Type::varsetint(dim); if (pyub == NULL) { Type tempType; vector<pair<int, int> > tempDimList; domain = python_to_minizinc(pylb, tempType, tempDimList); if (tempType.st() != Type::ST_SET) { PyErr_SetString(PyExc_TypeError, "MiniZinc: MznModel.Declaration: If 5th argument does not exist, 4th " "argument must be a Minizinc Set"); return NULL; } } else domain = new BinOp(Location(), one_dim_python_to_minizinc(pylb, code), BOT_DOTDOT, one_dim_python_to_minizinc(pyub, code)); break; default: MZN_PYERR_SET_STRING(PyExc_ValueError, "MiniZinc: MznModel.Declaration: Value code %li not supported", tid); return NULL; } }
VarDecl* vd = new VarDecl(Location(), new TypeInst(Location(), type, ranges, domain), string(name), initValue); self->_m->addItem(new VarDeclI(Location(), vd)); self->loaded = true;
PyObject* ret = MznExpression_new(&MznExpression_Type, NULL, NULL); reinterpret_cast<MznExpression*>(ret)->e = vd->id(); return ret;}