/* Python Interface for MiniZinc constraint modelling * Author: * Tai Tran * Supervisor: * Guido Tack */ #ifndef __MZNSET_H #define __MZNSET_H #include "Object.h" #include #include #include #if PY_MAJOR_VERSION >= 3 #define Py_TPFLAGS_HAVE_ITER 0 #endif using namespace std; using namespace MiniZinc; struct MznRange { long long min; long long max; MznRange(long long min, long long max) : min(min), max(max) {} }; /* * My custom defined Set * * MznSet_init and MznSet_push take a variable list of arguments: * (item1, item2, ..., itemn) * For each item, it can be either a value or a list/tuple of min and max values: * item? = 1,4 or 5 .... * or item? = [1,10] or [5,6] * or item? = (1,10) or (5,6) * For example, a Set of 1..5, 7, 10..15 can be defined like this: * minizinc_internal.Set( [1,5], 7, [10,15] ) * * The set will automatically merge ranges if it can. * * XXX: should a Set of {1,2,6,35} be written as 1..2, 6, 35 * or 1, 2, 6, 35? */ struct MznSet : MznObject { list* ranges; void clear() { ranges->clear(); } void push(long long min, long long max); void push(long long v); long long min(); long long max(); long long size() { return ranges->size(); } bool continuous(); bool contains(long long val); // Requires an outer GC Lock Expression* e() { vector setRanges; for (list::const_iterator it = ranges->begin(); it != ranges->end(); ++it) { setRanges.push_back(IntSetVal::Range(IntVal(it->min), IntVal(it->max))); } Expression* rhs = new SetLit(Location(), IntSetVal::a(setRanges)); return rhs; } }; enum Mzn_PyContainer_Type { MZN_T_LIST, MZN_T_TUPLE, MZN_T_OTHER }; inline Mzn_PyContainer_Type Mzn_PyContainer_Check(PyObject* o) { if (PyList_Check(o)) return MZN_T_LIST; else if (PyTuple_Check(o)) return MZN_T_TUPLE; else return MZN_T_OTHER; } inline Py_ssize_t Mzn_PyContainer_Size(PyObject* o, Mzn_PyContainer_Type t) { switch (t) { case MZN_T_LIST: return PyList_Size(o); case MZN_T_TUPLE: return PyTuple_Size(o); default: return -1; } } inline PyObject* Mzn_PyContainer_GetItem(PyObject* o, Py_ssize_t i, Mzn_PyContainer_Type t) { switch (t) { case MZN_T_LIST: return PyList_GetItem(o, i); case MZN_T_TUPLE: return PyTuple_GetItem(o, i); default: return NULL; } } // Set representation on terminal command // XXX: should be redefined as MznSet_str static PyObject* MznSet_repr(PyObject* self); // Push accepts 1 argument, which is exactly like the Set initialization static PyObject* MznSet_push(MznSet* self, PyObject* args); static PyObject* MznSet_output(MznSet* self); static PyObject* MznSet_min(MznSet* self); static PyObject* MznSet_max(MznSet* self); static PyObject* MznSet_continuous(MznSet* self); static PyObject* MznSet_contains(MznSet* self, PyObject* args); static PyObject* MznSet_clear(MznSet* self); static int MznSet_init(MznSet* self, PyObject* args); static PyObject* MznSet_new(PyTypeObject* type, PyObject* args, PyObject* kwds); static void MznSet_dealloc(MznSet* self); static PyObject* MznSet_iter(PyObject* self); static PyMethodDef MznSet_methods[] = { {"output", (PyCFunction)MznSet_output, METH_NOARGS, "Return all values in the set"}, {"push", (PyCFunction)MznSet_push, METH_VARARGS, "Expand the set"}, {"min", (PyCFunction)MznSet_min, METH_NOARGS, "Lower bound of the set"}, {"max", (PyCFunction)MznSet_max, METH_NOARGS, "Upper bound of the set"}, {"continuous", (PyCFunction)MznSet_continuous, METH_NOARGS, "Check whether the set is continous"}, {"contains", (PyCFunction)MznSet_contains, METH_VARARGS, "Check whether a python value is in the Set"}, {"clear", (PyCFunction)MznSet_clear, METH_NOARGS, "Clear the set"}, {NULL} /* Sentinel */ }; static PyMemberDef MznSet_members[] = { {NULL} /* Sentinel */ }; static PyTypeObject MznSet_Type = { PyVarObject_HEAD_INIT(NULL, 0) "minizinc.Set", /* tp_name */ sizeof(MznSet), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)MznSet_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ MznSet_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /* tp_flags */ "Minizinc Set Object", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ MznSet_iter, /* tp_iter */ 0, /* tp_iternext */ MznSet_methods, /* tp_methods */ MznSet_members, /* tp_members */ 0, /* tp_getset */ &MznObject_Type, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)MznSet_init, /* tp_init */ 0, /* tp_alloc */ MznSet_new, /* tp_new */ }; struct MznSetIter { // To support python iteration PyObject_HEAD list::const_iterator listIndex; list::const_iterator listBegin; list::const_iterator listEnd; long long currentValue; }; static PyObject* MznSetIter_new(PyTypeObject* type, PyObject* args, PyObject* kwds); static void MznSetIter_dealloc(MznSetIter* self); static PyObject* MznSetIter_iternext(PyObject* self); static PyTypeObject MznSetIter_Type = { PyVarObject_HEAD_INIT(NULL, 0) "minizinc.SetIterator", /* tp_name */ sizeof(MznSetIter), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)MznSetIter_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /* tp_flags */ "Minizinc Set Iterator", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)MznSetIter_iternext, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ 0, /*MznModel_getseters, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ }; #endif