setupmatrix.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002   file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/tags/0.9.1/src/model/setupmatrix.cpp $
00003   version : $LastChangedRevision: 1656 $  $LastChangedBy: jdetaeye $
00004   date : $LastChangedDate: 2012-03-27 19:05:34 +0200 (Tue, 27 Mar 2012) $
00005  ***************************************************************************/
00006 
00007 /***************************************************************************
00008  *                                                                         *
00009  * Copyright (C) 2009 by Johan De Taeye, frePPLe bvba                                    *
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   else
00212     return -1;  // Error
00213   return 0;
00214 }
00215 
00216 
00217 DECLARE_EXPORT PyObject* SetupMatrix::addPythonRule(PyObject* self, PyObject* args, PyObject* kwdict)
00218 {
00219   try
00220   {
00221     // Pick up the setup matrix
00222     SetupMatrix *matrix = static_cast<SetupMatrix*>(self);
00223     if (!matrix) throw LogicException("Can't add a rule to a NULL setupmatrix");
00224 
00225     // Parse the arguments
00226     int prio = 0;
00227     PyObject *pyfrom = NULL;
00228     PyObject *pyto = NULL;
00229     long duration = 0;
00230     double cost = 0;
00231     static const char *kwlist[] = {"priority", "fromsetup", "tosetup", "duration", "cost", NULL};
00232     if (!PyArg_ParseTupleAndKeywords(args, kwdict,
00233         "i|ssld:addRule",
00234         const_cast<char**>(kwlist), &prio, &pyfrom, &pyto, &duration, &cost))
00235       return NULL;
00236 
00237     // Add the new rule
00238     Rule * r = new Rule(matrix, prio);
00239     if (pyfrom) r->setFromSetup(PythonObject(pyfrom).getString());
00240     if (pyto) r->setToSetup(PythonObject(pyfrom).getString());
00241     r->setDuration(duration);
00242     r->setCost(cost);
00243     return PythonObject(r);
00244   }
00245   catch(...)
00246   {
00247     PythonType::evalException();
00248     return NULL;
00249   }
00250 }
00251 
00252 
00253 DECLARE_EXPORT SetupMatrix::Rule::Rule(SetupMatrix *s, int p)
00254   : cost(0), priority(p), matrix(s), nextRule(NULL), prevRule(NULL)
00255 {
00256   // Validate the arguments
00257   if (!matrix) throw DataException("Can't add a rule to NULL setup matrix");
00258 
00259   // Find the right place in the list
00260   Rule *next = matrix->firstRule, *prev = NULL;
00261   while (next && p > next->priority)
00262   {
00263     prev = next;
00264     next = next->nextRule;
00265   }
00266 
00267   // Duplicate priority
00268   if (next && next->priority == p)
00269     throw DataException("Multiple rules with identical priority in setup matrix");
00270 
00271   // Maintain linked list
00272   nextRule = next;
00273   prevRule = prev;
00274   if (prev) prev->nextRule = this;
00275   else matrix->firstRule = this;
00276   if (next) next->prevRule = this;
00277 
00278   // Initialize the Python type
00279   initType(metadata);
00280 }
00281 
00282 
00283 DECLARE_EXPORT SetupMatrix::Rule::~Rule()
00284 {
00285   // Maintain linked list
00286   if (nextRule) nextRule->prevRule = prevRule;
00287   if (prevRule) prevRule->nextRule = nextRule;
00288   else matrix->firstRule = nextRule;
00289 }
00290 
00291 
00292 DECLARE_EXPORT void SetupMatrix::Rule::writeElement
00293 (XMLOutput *o, const Keyword& tag, mode m) const
00294 {
00295   o->BeginObject(tag, Tags::tag_priority, priority);
00296   if (!from.empty()) o->writeElement(Tags::tag_fromsetup, from);
00297   if (!to.empty()) o->writeElement(Tags::tag_tosetup, to);
00298   if (duration) o->writeElement(Tags::tag_duration, duration);
00299   if (cost) o->writeElement(Tags::tag_cost, cost);
00300   o->EndObject(tag);
00301 }
00302 
00303 
00304 DECLARE_EXPORT void SetupMatrix::Rule::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00305 {
00306   if (pAttr.isA(Tags::tag_priority))
00307     setPriority(pElement.getInt());
00308   else if (pAttr.isA(Tags::tag_fromsetup))
00309     setFromSetup(pElement.getString());
00310   else if (pAttr.isA(Tags::tag_tosetup))
00311     setToSetup(pElement.getString());
00312   else if (pAttr.isA(Tags::tag_duration))
00313     setDuration(pElement.getTimeperiod());
00314   else if (pAttr.isA(Tags::tag_cost))
00315     setCost(pElement.getDouble());
00316 }
00317 
00318 
00319 DECLARE_EXPORT PyObject* SetupMatrix::Rule::getattro(const Attribute& attr)
00320 {
00321   if (attr.isA(Tags::tag_priority))
00322     return PythonObject(priority);
00323   if (attr.isA(Tags::tag_setupmatrix))
00324     return PythonObject(matrix);
00325   if (attr.isA(Tags::tag_fromsetup))
00326     return PythonObject(from);
00327   if (attr.isA(Tags::tag_tosetup))
00328     return PythonObject(to);
00329   if (attr.isA(Tags::tag_duration))
00330     return PythonObject(duration);
00331   if (attr.isA(Tags::tag_cost))
00332     return PythonObject(cost);
00333   return NULL;
00334 }
00335 
00336 
00337 DECLARE_EXPORT int SetupMatrix::Rule::setattro(const Attribute& attr, const PythonObject& field)
00338 {
00339   if (attr.isA(Tags::tag_priority))
00340     setPriority(field.getInt());
00341   else if (attr.isA(Tags::tag_fromsetup))
00342     setFromSetup(field.getString());
00343   else if (attr.isA(Tags::tag_tosetup))
00344     setToSetup(field.getString());
00345   else if (attr.isA(Tags::tag_duration))
00346     setDuration(field.getTimeperiod());
00347   else if (attr.isA(Tags::tag_cost))
00348     setCost(field.getDouble());
00349   else
00350     return -1;  // Error
00351   return 0;  // OK
00352 }
00353 
00354 
00355 DECLARE_EXPORT void SetupMatrix::Rule::setPriority(const int n)
00356 {
00357   // Update the field
00358   priority = n;
00359 
00360   // Check ordering on the left
00361   while (prevRule && priority < prevRule->priority)
00362   {
00363     Rule* next = nextRule;
00364     Rule* prev = prevRule;
00365     if (prev && prev->prevRule) prev->prevRule->nextRule = this;
00366     else matrix->firstRule = this;
00367     if (prev) prev->nextRule = nextRule;
00368     nextRule = prev;
00369     prevRule = prev ? prev->prevRule : NULL;
00370     if (next && next->nextRule) next->nextRule->prevRule = prev;
00371     if (next) next->prevRule = prev;
00372     if (prev) prev->prevRule = this;
00373   }
00374 
00375   // Check ordering on the right
00376   while (nextRule && priority > nextRule->priority)
00377   {
00378     Rule* next = nextRule;
00379     Rule* prev = prevRule;
00380     nextRule = next->nextRule;
00381     if (next && next->nextRule) next->nextRule->prevRule = this;
00382     if (prev) prev->nextRule = next;
00383     if (next) next->nextRule = this;
00384     if (next) next->prevRule = prev;
00385     prevRule = next;
00386   }
00387 
00388   // Check for duplicate priorities
00389   if ((prevRule && prevRule->priority == priority)
00390       || (nextRule && nextRule->priority == priority))
00391   {
00392     ostringstream o;
00393     o << "Duplicate priority " << priority << " in setup matrix '"
00394       << matrix->getName() << "'";
00395     throw DataException(o.str());
00396   }
00397 }
00398 
00399 
00400 int SetupMatrixRuleIterator::initialize()
00401 {
00402   // Initialize the type
00403   PythonType& x = PythonExtension<SetupMatrixRuleIterator>::getType();
00404   x.setName("setupmatrixRuleIterator");
00405   x.setDoc("frePPLe iterator for setupmatrix rules");
00406   x.supportiter();
00407   return x.typeReady();
00408 }
00409 
00410 
00411 PyObject* SetupMatrixRuleIterator::iternext()
00412 {
00413   if (currule == matrix->endRules()) return NULL;
00414   PyObject *result = &*(currule++);
00415   Py_INCREF(result);
00416   return result;
00417 }
00418 
00419 
00420 DECLARE_EXPORT SetupMatrix::Rule* SetupMatrix::calculateSetup
00421 (const string oldsetup, const string newsetup) const
00422 {
00423   // No need to look
00424   if (oldsetup == newsetup) return NULL;
00425 
00426   // Loop through all rules
00427   for (Rule *curRule = firstRule; curRule; curRule = curRule->nextRule)
00428   {
00429     // Need a match on the fromsetup
00430     if (!curRule->getFromSetup().empty()
00431         && !matchWildcard(curRule->getFromSetup().c_str(), oldsetup.c_str()))
00432       continue;
00433     // Need a match on the tosetup
00434     if (!curRule->getToSetup().empty()
00435         && !matchWildcard(curRule->getToSetup().c_str(), newsetup.c_str()))
00436       continue;
00437     // Found a match
00438     return curRule;
00439   }
00440 
00441   // No matching rule was found
00442   logger << "Warning: Conversion from '" << oldsetup << "' to '" << newsetup
00443       << "' undefined in setup matrix '" << getName() << endl;
00444   return NULL;
00445 }
00446 
00447 } // end namespace

Documentation generated for frePPLe by  doxygen