this repo has no description
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 "Set.h" 9 10static void MznSet_dealloc(MznSet* self) { 11 delete self->ranges; 12 Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self)); 13} 14 15static PyObject* MznSet_new(PyTypeObject* type, PyObject* args, PyObject* kwds) { 16 MznSet* self = reinterpret_cast<MznSet*>(type->tp_alloc(type, 0)); 17 self->ranges = new list<MznRange>; 18 self->tid = MOC_SET; 19 return reinterpret_cast<PyObject*>(self); 20} 21 22static PyObject* MznSet_iter(PyObject* self) { 23 MznSetIter* iter = reinterpret_cast<MznSetIter*>(MznSetIter_new(&MznSetIter_Type, NULL, NULL)); 24 iter->listBegin = reinterpret_cast<MznSet*>(self)->ranges->begin(); 25 iter->listEnd = reinterpret_cast<MznSet*>(self)->ranges->end(); 26 iter->listIndex = iter->listBegin; 27 iter->currentValue = iter->listBegin->min; 28 return reinterpret_cast<PyObject*>(iter); 29} 30 31bool MznSet::contains(long long val) { 32 list<MznRange>::iterator it = ranges->begin(); 33 list<MznRange>::iterator end = ranges->end(); 34 assert(it != end); 35 for (; it++ != end;) 36 if (val < it->min) 37 return false; 38 else if (val <= it->max) 39 return true; 40 return false; 41} 42 43bool MznSet::continuous() { 44 if (ranges->empty()) 45 throw length_error("Ranges cannot be empty"); 46 else { 47 // returning ranges.size() == 1, with O(1) time complexity 48 list<MznRange>::iterator it = ranges->begin(); 49 return ++it == ranges->end(); 50 } 51} 52 53void MznSet::push(long long min, long long max) { 54 if (ranges->empty()) { 55 MznRange toAdd(min, max); 56 ranges->push_front(toAdd); 57 return; 58 } 59 list<MznRange>::iterator it, last; 60 for (it = ranges->begin(); it != ranges->end(); ++it) { 61 if (min <= it->max + 1) { 62 if (it->min < min) min = it->min; 63 if (max <= it->max) { 64 ranges->insert(it, MznRange(min, max)); 65 return; 66 } 67 goto FOUNDMIN; 68 } 69 continue; 70 FOUNDMIN: 71 last = it; 72 while (++it != ranges->end()) { 73 if (max < it->min - 1) { 74 break; 75 } else { 76 ranges->erase(last); 77 last = it; 78 if (max <= it->max) { 79 break; 80 } else 81 ++it; 82 } 83 } 84 last->min = min; 85 last->max = max; 86 return; 87 } 88 ranges->push_back(MznRange(min, max)); 89} 90 91void MznSet::push(long long v) { 92 list<MznRange>::iterator it, last; 93 last = ranges->begin(); 94 if (ranges->empty()) { 95 MznRange toAdd(v, v); 96 ranges->push_front(toAdd); 97 return; 98 } 99 for (it = last; it != ranges->end(); ++it) { 100 if (v < it->min) { 101 if (v == it->min - 1) { 102 it->min = v; 103 if (last->max == v) { 104 last->max = it->max; 105 ranges->erase(it); 106 return; 107 } 108 } else { 109 // 110 if (last->max < v) { 111 MznRange toAdd(v, v); 112 ranges->insert(it, toAdd); 113 } 114 return; 115 } 116 } else if (v > it->max) { 117 if (v == it->max + 1) { 118 it->max = v; 119 } 120 last = it; 121 continue; 122 } else { 123 return; 124 } 125 } 126 if (last->max < v) { 127 MznRange toAdd(v, v); 128 ranges->insert(it, toAdd); 129 } 130 return; 131} 132 133long long MznSet::min() { 134 assert(ranges->begin() != ranges->end()); 135 return ranges->front().min; 136} 137 138long long MznSet::max() { 139 assert(ranges->begin() != ranges->end()); 140 return ranges->back().max; 141} 142 143static PyObject* MznSet_min(MznSet* self) { return c_to_py_number(self->min()); } 144 145static PyObject* MznSet_max(MznSet* self) { return c_to_py_number(self->max()); } 146 147static PyObject* MznSet_continuous(MznSet* self) { return PyBool_FromLong(self->continuous()); } 148 149static PyObject* MznSet_contains(MznSet* self, PyObject* args) { 150 PyObject* py_val; 151 if (!PyArg_ParseTuple(args, "O", &py_val)) { 152 PyErr_SetString(PyExc_TypeError, "MiniZinc: Set.contains: Parsing error"); 153 return NULL; 154 } 155 long long c_val = py_to_c_number(py_val); 156 if (PyErr_Occurred()) { 157 PyObject *ptype, *pmessage, *ptraceback; 158 PyErr_Fetch(&ptype, &pmessage, &ptraceback); 159 const char* pStrErrorMessage = PyUnicode_AsUTF8(pmessage); 160 string error = "MiniZinc: Set.contains: " + string(pStrErrorMessage); 161 PyErr_SetString(ptype, error.c_str()); 162 return NULL; 163 } 164 165 return PyBool_FromLong(self->contains(c_val)); 166} 167 168static PyObject* MznSet_push(MznSet* self, PyObject* isv) { 169 /*PyObject* isv; 170 if (!PyArg_ParseTuple(args,"O",&isv)) { 171 PyErr_SetString(PyExc_TypeError, "MiniZinc: Set.push: Parsing error"); 172 return NULL; 173 }*/ 174 // if (isv == NULL) 175 // Py_RETURN_NONE; 176 177 Py_ssize_t size = PyTuple_Size(isv); 178 179 for (Py_ssize_t i = 0; i != size; ++i) { 180 PyObject* elem = PyTuple_GetItem(isv, i); 181 182 Mzn_PyContainer_Type elem_type = Mzn_PyContainer_Check(elem); 183 Py_ssize_t elem_size = Mzn_PyContainer_Size(elem, elem_type); 184 185 switch (elem_size) { 186 // elem_size == -1 means it is neither list nor tuple 187 case -1: { 188 int overflow; 189 long long c_val = py_to_c_number(elem, &overflow); 190 if (PyErr_Occurred()) { 191 if (overflow) { 192 MZN_PYERR_SET_STRING(PyExc_OverflowError, 193 "MiniZinc: Set.push: Overflow at tuple element at pos %li", i); 194 return NULL; 195 } else { 196 MZN_PYERR_SET_STRING(PyExc_TypeError, 197 "MiniZinc: Set.push: Type mismatched at tuple element pos %li: " 198 "expected an integer or list of integers", 199 i); 200 return NULL; 201 } 202 } 203 self->push(c_val); 204 break; 205 } 206 case 1: { 207 PyObject* py_val = Mzn_PyContainer_GetItem(elem, 0, elem_type); 208 long long c_val = py_to_c_number(py_val); 209 if (PyErr_Occurred()) { 210 PyObject *ptype, *pmessage, *ptraceback; 211 PyErr_Fetch(&ptype, &pmessage, &ptraceback); 212 const char* pStrErrorMessage = PyUnicode_AsUTF8(pmessage); 213 string error = "MiniZinc: Set.push: tuple item %li: " + string(pStrErrorMessage); 214 MZN_PYERR_SET_STRING(ptype, error.c_str(), i); 215 return NULL; 216 } 217 self->push(c_val); 218 break; 219 } 220 case 2: { 221 PyObject* p_min = Mzn_PyContainer_GetItem(elem, 0, elem_type); 222 PyObject* p_max = Mzn_PyContainer_GetItem(elem, 1, elem_type); 223 long long c_min = py_to_c_number(p_min); 224 if (PyErr_Occurred()) { 225 PyObject *ptype, *pmessage, *ptraceback; 226 PyErr_Fetch(&ptype, &pmessage, &ptraceback); 227 const char* pStrErrorMessage = PyUnicode_AsUTF8(pmessage); 228 string error = 229 "MiniZinc: Set.push: tuple item %li, first argument: " + string(pStrErrorMessage); 230 MZN_PYERR_SET_STRING(ptype, error.c_str(), i); 231 return NULL; 232 } 233 234 long long c_max = py_to_c_number(p_max); 235 if (PyErr_Occurred()) { 236 PyObject *ptype, *pmessage, *ptraceback; 237 PyErr_Fetch(&ptype, &pmessage, &ptraceback); 238 const char* pStrErrorMessage = PyUnicode_AsUTF8(pmessage); 239 string error = 240 "MiniZinc: Set.push: tuple item %li, second argument: " + string(pStrErrorMessage); 241 MZN_PYERR_SET_STRING(ptype, error.c_str(), i); 242 return NULL; 243 } 244 245 if (c_min < c_max) 246 self->push(c_min, c_max); 247 else if (c_min > c_max) 248 self->push(c_max, c_min); 249 else 250 self->push(c_min); 251 break; 252 } 253 default: 254 PyErr_SetString(PyExc_TypeError, 255 "MiniZinc: Set.push: The sublist size can only be 1 or 2"); 256 return NULL; 257 } 258 } 259 Py_RETURN_NONE; 260} 261 262static int MznSet_init(MznSet* self, PyObject* args) { 263 if (MznSet_push(self, args) == NULL) return -1; 264 return 0; 265} 266 267static PyObject* MznSet_clear(MznSet* self) { 268 self->clear(); 269 Py_RETURN_NONE; 270} 271 272static PyObject* MznSet_output(MznSet* self) { 273 stringstream s; 274 for (list<MznRange>::iterator it = self->ranges->begin(); it != self->ranges->end(); ++it) { 275 s << it->min << ".." << it->max << " "; 276 } 277 const std::string& tmp = s.str(); 278 const char* cstr = tmp.c_str(); 279 PyObject* result = PyUnicode_FromString(cstr); 280 return result; 281} 282 283static PyObject* MznSet_repr(PyObject* self) { 284 stringstream output; 285 list<MznRange>* r = (reinterpret_cast<MznSet*>(self))->ranges; 286 if (r->begin() == r->end()) 287 output << "Empty Set"; 288 else 289 for (list<MznRange>::iterator it = r->begin();;) { 290 if (it->min == it->max) 291 output << it->min; 292 else 293 output << it->min << ".." << it->max; 294 if (++it == r->end()) 295 break; 296 else 297 output << ", "; 298 } 299 const std::string& tmp = output.str(); 300 return PyUnicode_FromString(tmp.c_str()); 301} 302 303static void MznSetIter_dealloc(MznSetIter* self) { 304 Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self)); 305} 306 307static PyObject* MznSetIter_new(PyTypeObject* type, PyObject* args, PyObject* kwds) { 308 return type->tp_alloc(type, 0); 309} 310 311static PyObject* MznSetIter_iternext(PyObject* self) { 312 MznSetIter* iter = reinterpret_cast<MznSetIter*>(self); 313 if (iter->listIndex == iter->listEnd) { 314 iter->listIndex = iter->listBegin; 315 iter->currentValue = iter->listBegin->min; 316 PyErr_SetNone(PyExc_StopIteration); 317 return NULL; 318 } else { 319 PyObject* result = c_to_py_number(iter->currentValue); 320 iter->currentValue++; 321 if (iter->currentValue > iter->listIndex->max) { 322 iter->listIndex++; 323 if (iter->listIndex != iter->listEnd) iter->currentValue = iter->listIndex->min; 324 } 325 return result; 326 } 327}