00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #define FREPPLE_CORE
00029 #include "frepple/model.h"
00030
00031 namespace frepple
00032 {
00033
00034 template<class SetupMatrix> DECLARE_EXPORT Tree utils::HasName<SetupMatrix>::st;
00035 DECLARE_EXPORT const MetaCategory* SetupMatrix::metadata;
00036 DECLARE_EXPORT const MetaClass* SetupMatrixDefault::metadata;
00037 DECLARE_EXPORT const MetaCategory* SetupMatrix::Rule::metadata;
00038
00039
00040 int SetupMatrix::initialize()
00041 {
00042
00043 metadata = new MetaCategory("setupmatrix", "setupmatrices", reader, writer);
00044
00045
00046 FreppleCategory<SetupMatrix>::getType().addMethod("addRule", addPythonRule, METH_KEYWORDS, "add a new setup rule");
00047 return FreppleCategory<SetupMatrix>::initialize()
00048 + Rule::initialize()
00049 + SetupMatrixRuleIterator::initialize();
00050 }
00051
00052
00053 int SetupMatrix::Rule::initialize()
00054 {
00055
00056 metadata = new MetaCategory("setupmatrixrule", "setupmatrixrules");
00057
00058
00059 PythonType& x = PythonExtension<SetupMatrix::Rule>::getType();
00060 x.setName("setupmatrixrule");
00061 x.setDoc("frePPLe setupmatrixrule");
00062 x.supportgetattro();
00063 x.supportsetattro();
00064 const_cast<MetaCategory*>(metadata)->pythonClass = x.type_object();
00065 return x.typeReady();
00066 }
00067
00068
00069 int SetupMatrixDefault::initialize()
00070 {
00071
00072 SetupMatrixDefault::metadata = new MetaClass(
00073 "setupmatrix",
00074 "setupmatrix_default",
00075 Object::createString<SetupMatrixDefault>, true);
00076
00077
00078 return FreppleClass<SetupMatrixDefault,SetupMatrix>::initialize();
00079 }
00080
00081
00082 DECLARE_EXPORT SetupMatrix::~SetupMatrix()
00083 {
00084
00085
00086 while (firstRule) delete firstRule;
00087
00088
00089 for (Resource::iterator m = Resource::begin(); m != Resource::end(); ++m)
00090 if (m->getSetupMatrix() == this) m->setSetupMatrix(NULL);
00091 }
00092
00093
00094 DECLARE_EXPORT void SetupMatrix::writeElement(XMLOutput *o, const Keyword& tag, mode m) const
00095 {
00096
00097 if (m == REFERENCE)
00098 {
00099 o->writeElement
00100 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00101 return;
00102 }
00103
00104
00105 if (m != NOHEADER) o->BeginObject
00106 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00107
00108
00109 o->BeginObject (Tags::tag_rules);
00110 for (RuleIterator i = beginRules(); i != endRules(); ++i)
00111
00112
00113 o->writeElement(Tags::tag_rule, *i, FULL);
00114 o->EndObject(Tags::tag_rules);
00115
00116 o->EndObject(tag);
00117 }
00118
00119
00120 DECLARE_EXPORT void SetupMatrix::beginElement(XMLInput& pIn, const Attribute& pAttr)
00121 {
00122 if (pAttr.isA(Tags::tag_rule)
00123 && pIn.getParentElement().first.isA(Tags::tag_rules))
00124
00125 pIn.readto(createRule(pIn.getAttributes()));
00126 }
00127
00128
00129 DECLARE_EXPORT SetupMatrix::Rule* SetupMatrix::createRule(const AttributeList& atts)
00130 {
00131
00132 int priority = atts.get(Tags::tag_priority)->getInt();
00133
00134
00135 Rule* result = firstRule;
00136 while (result && priority > result->priority)
00137 result = result->nextRule;
00138 if (result && result->priority != priority) result = NULL;
00139
00140
00141 switch (MetaClass::decodeAction(atts))
00142 {
00143 case ADD:
00144
00145 if (result)
00146 {
00147 ostringstream o;
00148 o << "Rule with priority " << priority
00149 << " already exists in setup matrix '" << getName() << "'";
00150 throw DataException(o.str());
00151 }
00152 result = new Rule(this, priority);
00153 return result;
00154 case CHANGE:
00155
00156 if (!result)
00157 {
00158 ostringstream o;
00159 o << "No rule with priority " << priority
00160 << " exists in setup matrix '" << getName() << "'";
00161 throw DataException(o.str());
00162 }
00163 return result;
00164 case REMOVE:
00165
00166 if (!result)
00167 {
00168 ostringstream o;
00169 o << "No rule with priority " << priority
00170 << " exists in setup matrix '" << getName() << "'";
00171 throw DataException(o.str());
00172 }
00173 else
00174 {
00175
00176 delete result;
00177 return NULL;
00178 }
00179 case ADD_CHANGE:
00180 if (!result)
00181
00182 result = new Rule(this, priority);
00183 return result;
00184 }
00185
00186
00187 throw LogicException("Unreachable code reached");
00188 }
00189
00190
00191 DECLARE_EXPORT void SetupMatrix::endElement(XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00192 {
00193 HasName<SetupMatrix>::endElement(pIn, pAttr, pElement);
00194 }
00195
00196
00197 DECLARE_EXPORT PyObject* SetupMatrix::getattro(const Attribute& attr)
00198 {
00199 if (attr.isA(Tags::tag_name))
00200 return PythonObject(getName());
00201 if (attr.isA(Tags::tag_rules))
00202 return new SetupMatrixRuleIterator(this);
00203 return NULL;
00204 }
00205
00206
00207 DECLARE_EXPORT int SetupMatrix::setattro(const Attribute& attr, const PythonObject& field)
00208 {
00209 if (attr.isA(Tags::tag_name))
00210 setName(field.getString());
00211 return 0;
00212 }
00213
00214
00215 DECLARE_EXPORT PyObject* SetupMatrix::addPythonRule(PyObject* self, PyObject* args, PyObject* kwdict)
00216 {
00217 try
00218 {
00219
00220 SetupMatrix *matrix = static_cast<SetupMatrix*>(self);
00221 if (!matrix) throw LogicException("Can't add a rule to a NULL setupmatrix");
00222
00223
00224 int prio = 0;
00225 PyObject *pyfrom = NULL;
00226 PyObject *pyto = NULL;
00227 long duration = 0;
00228 double cost = 0;
00229 static const char *kwlist[] = {"priority", "fromsetup", "tosetup", "duration", "cost", NULL};
00230 if (!PyArg_ParseTupleAndKeywords(args, kwdict,
00231 "i|ssld:addRule",
00232 const_cast<char**>(kwlist), &prio, &pyfrom, &pyto, &duration, &cost))
00233 return NULL;
00234
00235
00236 Rule * r = new Rule(matrix, prio);
00237 if (pyfrom) r->setFromSetup(PythonObject(pyfrom).getString());
00238 if (pyto) r->setToSetup(PythonObject(pyfrom).getString());
00239 r->setDuration(duration);
00240 r->setCost(cost);
00241 return PythonObject(r);
00242 }
00243 catch(...)
00244 {
00245 PythonType::evalException();
00246 return NULL;
00247 }
00248 }
00249
00250
00251 DECLARE_EXPORT SetupMatrix::Rule::Rule(SetupMatrix *s, int p)
00252 : cost(0), priority(p), matrix(s), nextRule(NULL), prevRule(NULL)
00253 {
00254
00255 if (!matrix) throw DataException("Can't add a rule to NULL setup matrix");
00256
00257
00258 Rule *next = matrix->firstRule, *prev = NULL;
00259 while (next && p > next->priority)
00260 {
00261 prev = next;
00262 next = next->nextRule;
00263 }
00264
00265
00266 if (next && next->priority == p)
00267 throw DataException("Multiple rules with identical priority in setup matrix");
00268
00269
00270 nextRule = next;
00271 prevRule = prev;
00272 if (prev) prev->nextRule = this;
00273 else matrix->firstRule = this;
00274 if (next) next->prevRule = this;
00275
00276
00277 initType(metadata);
00278 }
00279
00280
00281 DECLARE_EXPORT SetupMatrix::Rule::~Rule()
00282 {
00283
00284 if (nextRule) nextRule->prevRule = prevRule;
00285 if (prevRule) prevRule->nextRule = nextRule;
00286 else matrix->firstRule = nextRule;
00287 }
00288
00289
00290 DECLARE_EXPORT void SetupMatrix::Rule::writeElement
00291 (XMLOutput *o, const Keyword& tag, mode m) const
00292 {
00293 o->BeginObject(tag, Tags::tag_priority, priority);
00294 if (!from.empty()) o->writeElement(Tags::tag_fromsetup, from);
00295 if (!to.empty()) o->writeElement(Tags::tag_tosetup, to);
00296 if (duration) o->writeElement(Tags::tag_duration, duration);
00297 if (cost) o->writeElement(Tags::tag_cost, cost);
00298 o->EndObject(tag);
00299 }
00300
00301
00302 DECLARE_EXPORT void SetupMatrix::Rule::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00303 {
00304 if (pAttr.isA(Tags::tag_priority))
00305 setPriority(pElement.getInt());
00306 else if (pAttr.isA(Tags::tag_fromsetup))
00307 setFromSetup(pElement.getString());
00308 else if (pAttr.isA(Tags::tag_tosetup))
00309 setToSetup(pElement.getString());
00310 else if (pAttr.isA(Tags::tag_duration))
00311 setDuration(pElement.getTimeperiod());
00312 else if (pAttr.isA(Tags::tag_cost))
00313 setCost(pElement.getDouble());
00314 }
00315
00316
00317 DECLARE_EXPORT PyObject* SetupMatrix::Rule::getattro(const Attribute& attr)
00318 {
00319 if (attr.isA(Tags::tag_priority))
00320 return PythonObject(priority);
00321 if (attr.isA(Tags::tag_fromsetup))
00322 return PythonObject(from);
00323 if (attr.isA(Tags::tag_tosetup))
00324 return PythonObject(to);
00325 if (attr.isA(Tags::tag_duration))
00326 return PythonObject(duration);
00327 if (attr.isA(Tags::tag_cost))
00328 return PythonObject(cost);
00329 return NULL;
00330 }
00331
00332
00333 DECLARE_EXPORT int SetupMatrix::Rule::setattro(const Attribute& attr, const PythonObject& field)
00334 {
00335 if (attr.isA(Tags::tag_priority))
00336 setPriority(field.getInt());
00337 else if (attr.isA(Tags::tag_fromsetup))
00338 setFromSetup(field.getString());
00339 else if (attr.isA(Tags::tag_tosetup))
00340 setToSetup(field.getString());
00341 else if (attr.isA(Tags::tag_duration))
00342 setDuration(field.getTimeperiod());
00343 else if (attr.isA(Tags::tag_cost))
00344 setCost(field.getDouble());
00345 else
00346 return -1;
00347 return 0;
00348 }
00349
00350
00351 DECLARE_EXPORT void SetupMatrix::Rule::setPriority(const int n)
00352 {
00353
00354 priority = n;
00355
00356
00357 while (prevRule && priority < prevRule->priority)
00358 {
00359 Rule* next = nextRule;
00360 Rule* prev = prevRule;
00361 if (prev && prev->prevRule) prev->prevRule->nextRule = this;
00362 else matrix->firstRule = this;
00363 if (prev) prev->nextRule = nextRule;
00364 nextRule = prev;
00365 prevRule = prev ? prev->prevRule : NULL;
00366 if (next && next->nextRule) next->nextRule->prevRule = prev;
00367 if (next) next->prevRule = prev;
00368 if (prev) prev->prevRule = this;
00369 }
00370
00371
00372 while (nextRule && priority > nextRule->priority)
00373 {
00374 Rule* next = nextRule;
00375 Rule* prev = prevRule;
00376 nextRule = next->nextRule;
00377 if (next && next->nextRule) next->nextRule->prevRule = this;
00378 if (prev) prev->nextRule = next;
00379 if (next) next->nextRule = this;
00380 if (next) next->prevRule = prev;
00381 prevRule = next;
00382 }
00383
00384
00385 if ((prevRule && prevRule->priority == priority)
00386 || (nextRule && nextRule->priority == priority))
00387 {
00388 ostringstream o;
00389 o << "Duplicate priority " << priority << " in setup matrix '"
00390 << matrix->getName() << "'";
00391 throw DataException(o.str());
00392 }
00393 }
00394
00395
00396 int SetupMatrixRuleIterator::initialize()
00397 {
00398
00399 PythonType& x = PythonExtension<SetupMatrixRuleIterator>::getType();
00400 x.setName("setupmatrixRuleIterator");
00401 x.setDoc("frePPLe iterator for setupmatrix rules");
00402 x.supportiter();
00403 return x.typeReady();
00404 }
00405
00406
00407 PyObject* SetupMatrixRuleIterator::iternext()
00408 {
00409 if (currule == matrix->endRules()) return NULL;
00410 PyObject *result = &*(currule++);
00411 Py_INCREF(result);
00412 return result;
00413 }
00414
00415
00416 DECLARE_EXPORT SetupMatrix::Rule* SetupMatrix::calculateSetup
00417 (const string oldsetup, const string newsetup) const
00418 {
00419
00420 if (oldsetup == newsetup) return NULL;
00421
00422
00423 for (Rule *curRule = firstRule; curRule; curRule = curRule->nextRule)
00424 {
00425
00426 if (!curRule->getFromSetup().empty()
00427 && !matchWildcard(curRule->getFromSetup().c_str(), oldsetup.c_str()))
00428 continue;
00429
00430 if (!curRule->getToSetup().empty()
00431 && !matchWildcard(curRule->getToSetup().c_str(), newsetup.c_str()))
00432 continue;
00433
00434 return curRule;
00435 }
00436
00437
00438 logger << "Warning: Conversion from '" << oldsetup << "' to '" << newsetup
00439 << "' undefined in setup matrix '" << getName() << endl;
00440 return NULL;
00441 }
00442
00443 }