setupmatrix.cpp
Go to the documentation of this file.00001 /*************************************************************************** 00002 file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/trunk/src/model/setupmatrix.cpp $ 00003 version : $LastChangedRevision: 1171 $ $LastChangedBy: jdetaeye $ 00004 date : $LastChangedDate: 2010-01-31 22:52:44 +0100 (Sun, 31 Jan 2010) $ 00005 ***************************************************************************/ 00006 00007 /*************************************************************************** 00008 * * 00009 * Copyright (C) 2009 by Johan De Taeye * 00010 * * 00011 * This library is free software; you can redistribute it and/or modify it * 00012 * under the terms of the GNU Lesser General Public License as published * 00013 * by the Free Software Foundation; either version 2.1 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 * This library is distributed in the hope that it will be useful, * 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 00019 * General Public License for more details. * 00020 * * 00021 * You should have received a copy of the GNU Lesser General Public * 00022 * License along with this library; if not, write to the Free Software * 00023 * Foundation Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,* 00024 * USA * 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 // Initialize the metadata 00043 metadata = new MetaCategory("setupmatrix", "setupmatrices", reader, writer); 00044 00045 // Initialize the Python class 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 // Initialize the metadata 00056 metadata = new MetaCategory("setupmatrixrule", "setupmatrixrules"); 00057 00058 // Initialize the Python class 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 // Initialize the metadata 00072 SetupMatrixDefault::metadata = new MetaClass( 00073 "setupmatrix", 00074 "setupmatrix_default", 00075 Object::createString<SetupMatrixDefault>, true); 00076 00077 // Initialize the Python class 00078 return FreppleClass<SetupMatrixDefault,SetupMatrix>::initialize(); 00079 } 00080 00081 00082 DECLARE_EXPORT SetupMatrix::~SetupMatrix() 00083 { 00084 // Destroy the rules. 00085 // Note that the rule destructor updates the firstRule field. 00086 while (firstRule) delete firstRule; 00087 00088 // Remove all references to this setup matrix from resources 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 // Writing a reference 00097 if (m == REFERENCE) 00098 { 00099 o->writeElement 00100 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type); 00101 return; 00102 } 00103 00104 // Write the complete object 00105 if (m != NOHEADER) o->BeginObject 00106 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type); 00107 00108 // Write all rules 00109 o->BeginObject (Tags::tag_rules); 00110 for (RuleIterator i = beginRules(); i != endRules(); ++i) 00111 // We use the FULL mode, to force the rules being written regardless 00112 // of the depth in the XML tree. 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 // A new rule 00125 pIn.readto(createRule(pIn.getAttributes())); 00126 } 00127 00128 00129 DECLARE_EXPORT SetupMatrix::Rule* SetupMatrix::createRule(const AttributeList& atts) 00130 { 00131 // Pick up the start, end and name attributes 00132 int priority = atts.get(Tags::tag_priority)->getInt(); 00133 00134 // Check for existence of a rule with the same priority 00135 Rule* result = firstRule; 00136 while (result && priority > result->priority) 00137 result = result->nextRule; 00138 if (result && result->priority != priority) result = NULL; 00139 00140 // Pick up the action attribute and update the rule accordingly 00141 switch (MetaClass::decodeAction(atts)) 00142 { 00143 case ADD: 00144 // Only additions are allowed 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 // Only changes are allowed 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 // Delete the entity 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 // Delete it 00176 delete result; 00177 return NULL; 00178 } 00179 case ADD_CHANGE: 00180 if (!result) 00181 // Adding a new rule 00182 result = new Rule(this, priority); 00183 return result; 00184 } 00185 00186 // This part of the code isn't expected not be reached 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 // Pick up the setup matrix 00220 SetupMatrix *matrix = static_cast<SetupMatrix*>(self); 00221 if (!matrix) throw LogicException("Can't add a rule to a NULL setupmatrix"); 00222 00223 // Parse the arguments 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 // Add the new rule 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 // Validate the arguments 00255 if (!matrix) throw DataException("Can't add a rule to NULL setup matrix"); 00256 00257 // Find the right place in the list 00258 Rule *next = matrix->firstRule, *prev = NULL; 00259 while (next && p > next->priority) 00260 { 00261 prev = next; 00262 next = next->nextRule; 00263 } 00264 00265 // Duplicate priority 00266 if (next && next->priority == p) 00267 throw DataException("Multiple rules with identical priority in setup matrix"); 00268 00269 // Maintain linked list 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 // Initialize the Python type 00277 initType(metadata); 00278 } 00279 00280 00281 DECLARE_EXPORT SetupMatrix::Rule::~Rule() 00282 { 00283 // Maintain linked list 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; // Error 00347 return 0; // OK 00348 } 00349 00350 00351 DECLARE_EXPORT void SetupMatrix::Rule::setPriority(const int n) 00352 { 00353 // Update the field 00354 priority = n; 00355 00356 // Check ordering on the left 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 // Check ordering on the right 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 // Check for duplicate priorities 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 // Initialize the type 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 // No need to look 00420 if (oldsetup == newsetup) return NULL; 00421 00422 // Loop through all rules 00423 for (Rule *curRule = firstRule; curRule; curRule = curRule->nextRule) 00424 { 00425 // Need a match on the fromsetup 00426 if (!curRule->getFromSetup().empty() 00427 && !matchWildcard(curRule->getFromSetup().c_str(), oldsetup.c_str())) 00428 continue; 00429 // Need a match on the tosetup 00430 if (!curRule->getToSetup().empty() 00431 && !matchWildcard(curRule->getToSetup().c_str(), newsetup.c_str())) 00432 continue; 00433 // Found a match 00434 return curRule; 00435 } 00436 00437 // No matching rule was found 00438 logger << "Warning: Conversion from '" << oldsetup << "' to '" << newsetup 00439 << "' undefined in setup matrix '" << getName() << endl; 00440 return NULL; 00441 } 00442 00443 } // end namespace
Documentation generated for frePPLe by
