model.h
Go to the documentation of this file.
00001 /***************************************************************************
00002   file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/tags/0.9.1/include/frepple/model.h $
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) 2007-2012 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 #ifndef MODEL_H
00029 #define MODEL_H
00030 
00031 /** @mainpage frePPLe API
00032   * FrePPLe provides a framework for modeling a manufacturing environment and
00033   * computing production plans.<br>
00034   * This document describes its C++ API.<P>
00035   *
00036   * @namespace frepple
00037   * @brief Core namespace
00038   */
00039 
00040 #include "frepple/utils.h"
00041 #include "frepple/timeline.h"
00042 using namespace frepple::utils;
00043 
00044 namespace frepple
00045 {
00046 
00047 class Flow;
00048 class FlowEnd;
00049 class FlowPlan;
00050 class LoadPlan;
00051 class Resource;
00052 class ResourceInfinite;
00053 class Problem;
00054 class Demand;
00055 class OperationPlan;
00056 class Item;
00057 class Operation;
00058 class OperationPlanState;
00059 class OperationFixedTime;
00060 class OperationTimePer;
00061 class OperationRouting;
00062 class OperationAlternate;
00063 class Buffer;
00064 class BufferInfinite;
00065 class BufferProcure;
00066 class Plan;
00067 class Plannable;
00068 class Calendar;
00069 class Load;
00070 class Location;
00071 class Customer;
00072 class HasProblems;
00073 class Solvable;
00074 class PeggingIterator;
00075 
00076 
00077 /** @brief This class is used for initialization. */
00078 class LibraryModel
00079 {
00080   public:
00081     static void initialize();
00082 };
00083 
00084 
00085 /** @brief This is the class used to represent variables that are
00086   * varying over time.
00087   *
00088   * Some example usages for calendars:
00089   *  - A calendar defining the available capacity of a resource
00090   *    week by week.
00091   *  - The minimum inventory desired in a buffer week by week.
00092   *  - The working hours and holidays at a certain location.
00093   */
00094 class Calendar : public HasName<Calendar>
00095 {
00096   public:
00097     class BucketIterator; // Forward declaration
00098     class EventIterator; // Forward declaration
00099 
00100     /** @brief This class represents a time bucket as a part of a calendar.
00101       *
00102       * Manipulation of instances of this class need to be handled with the
00103       * methods on the friend class Calendar.
00104       * @see Calendar
00105       */
00106     class Bucket : public Object, public NonCopyable
00107     {
00108         friend class Calendar;
00109         friend class BucketIterator;
00110         friend class EventIterator;
00111       private:
00112         /** Name of the bucket. */
00113         string nm;
00114 
00115         /** Start date of the bucket. */
00116         Date startdate;
00117 
00118         /** End Date of the bucket. */
00119         Date enddate;
00120 
00121         /** A pointer to the next bucket. */
00122         Bucket* nextBucket;
00123 
00124         /** A pointer to the previous bucket. */
00125         Bucket* prevBucket;
00126 
00127         /** Priority of this bucket, compared to other buckets effective
00128           * at a certain time.
00129           */
00130         int priority;
00131 
00132         /** A pointer to the owning calendar. */
00133         Calendar *cal;
00134 
00135         /** Increments an iterator to the next change event.<br>
00136           * A bucket will evaluate the current state of the iterator, and
00137           * update it if a valid next event can be generated.
00138           */
00139         DECLARE_EXPORT void nextEvent(EventIterator*, Date) const;
00140 
00141         /** Increments an iterator to the previous change event.<br>
00142           * A bucket will evaluate the current state of the iterator, and
00143           * update it if a valid previous event can be generated.
00144           */
00145         DECLARE_EXPORT void prevEvent(EventIterator*, Date) const;
00146 
00147       protected:
00148         /** Constructor. */
00149         Bucket(Calendar *c, Date start, Date end, string name, int priority=0) :
00150           nm(name), startdate(start), enddate(end), nextBucket(NULL),
00151           prevBucket(NULL), priority(priority), cal(c) {initType(metadata);}
00152 
00153         /** Auxilary function to write out the start of the XML. */
00154         DECLARE_EXPORT void writeHeader(XMLOutput *, const Keyword&) const;
00155 
00156       public:
00157         /** Return the calendar to whom the bucket belongs. */
00158         Calendar* getCalendar() const {return cal;}
00159 
00160         /** This method is here only to keep the API of all calendar classes
00161           * consistent.<br>
00162           * Note that this isn't exactly a virtual method, since the return
00163           * value is different for different calendar types.
00164           */
00165         void getValue() const {}
00166 
00167         /** This method is here only to keep the API of all calendar classes
00168           * consistent.
00169           */
00170         void setValue() {}
00171 
00172         /** Returns the name of the bucket. If no name was ever explicitly
00173           * specified with the setName() method, a default name is generated
00174           * by converting the start date into a string.<br>
00175           * To reduce the memory needs, this default string is computed with
00176           * every call to the getName() method and never stored internally.
00177           * Only explicitly specified names are kept in memory.
00178           */
00179         string getName() const {return nm.empty() ? string(startdate) : nm;}
00180 
00181         /** Returns true if the name of the bucket has not been explicitly
00182           * specified. */
00183         bool useDefaultName() const {return nm.empty();}
00184 
00185         /** Updates the name of a bucket. */
00186         void setName(const string& s) {nm=s;}
00187 
00188         /** Returns the end date of the bucket. */
00189         Date getEnd() const {return enddate;}
00190 
00191         /** Updates the end date of the bucket. */
00192         void setEnd(const Date& d) {enddate = d;}
00193 
00194         /** Returns the start date of the bucket. */
00195         Date getStart() const {return startdate;}
00196 
00197         /** Updates the end date of the bucket. */
00198         void setStart(const Date& d) {startdate = d;}
00199 
00200         /** Returns the priority of this bucket, compared to other buckets
00201           * effective at a certain time.<br>
00202           * Lower numbers indicate a higher priority level.<br>
00203           * The default value is 0.
00204           */
00205         int getPriority() const {return priority;}
00206 
00207         /** Updates the priority of this bucket, compared to other buckets
00208           * effective at a certain time.<br>
00209           * Lower numbers indicate a higher priority level.<br>
00210           * The default value is 0.
00211           */
00212         void setPriority(int f) {priority = f;}
00213 
00214         /** Verifies whether this entry is effective on a given date. */
00215         bool checkValid(Date d) const
00216         {
00217           return true;
00218         }
00219 
00220         /** Convert the value of the bucket to a boolean value. */
00221         virtual bool getBool() const {return true;}
00222 
00223         virtual DECLARE_EXPORT void writeElement
00224         (XMLOutput*, const Keyword&, mode=DEFAULT) const;
00225 
00226         /** Reads the bucket information from the input. Only the fields "name"
00227           * and "start" are read in. Other fields as also written out but these
00228           * are information-only fields.
00229           */
00230         DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
00231 
00232         virtual const MetaClass& getType() const
00233         {return *metadata;}
00234         virtual size_t getSize() const
00235         {return sizeof(Bucket) + nm.size();}
00236         static DECLARE_EXPORT const MetaCategory* metadata;
00237         virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
00238         virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
00239         static int initialize();
00240     };
00241 
00242     /** Default constructor. */
00243     Calendar(const string& n) : HasName<Calendar>(n), firstBucket(NULL) {}
00244 
00245     /** Destructor, which cleans up the buckets too and all references to the
00246       * calendar from the core model.
00247       */
00248     DECLARE_EXPORT ~Calendar();
00249 
00250     /** Convert the value of the calendar to a boolean value. */
00251     virtual bool getBool() const {return false;}
00252 
00253     /** This is a factory method that creates a new bucket using the start
00254       * date as the key field. The fields are passed as an array of character
00255       * pointers.<br>
00256       * This method is intended to be used to create objects when reading
00257       * XML input data.
00258       */
00259     DECLARE_EXPORT Bucket* createBucket(const AttributeList&);
00260 
00261     /** Adds a new bucket to the list. */
00262     DECLARE_EXPORT Bucket* addBucket(Date, Date, string);
00263 
00264     /** Removes a bucket from the list. */
00265     DECLARE_EXPORT void removeBucket(Bucket* bkt);
00266 
00267     /** Returns the bucket where a certain date belongs to.
00268       * A bucket will always be returned, i.e. the data structure is such
00269       * that we all dates between infinitePast and infiniteFuture match
00270       * with one (and only one) bucket.
00271       */
00272     DECLARE_EXPORT Bucket* findBucket(Date d, bool fwd = true) const;
00273 
00274     /** Returns the bucket with a certain name.
00275       * A NULL pointer is returned in case no bucket can be found with the
00276       * given name.
00277       */
00278     DECLARE_EXPORT Bucket* findBucket(const string&) const;
00279 
00280     /** @brief An iterator class to go through all dates where the calendar
00281       * value changes.*/
00282     class EventIterator
00283     {
00284         friend class Calendar::Bucket;
00285       protected:
00286         const Calendar* theCalendar;
00287         const Bucket* curBucket;
00288         Date curDate;
00289         int curPriority;
00290       public:
00291         const Date& getDate() const {return curDate;}
00292         const Bucket* getBucket() const {return curBucket;}
00293         const Calendar* getCalendar() const {return theCalendar;}
00294         EventIterator(const Calendar* c, Date d = Date::infinitePast,
00295             bool forward = true) : theCalendar(c), curDate(d)
00296         {
00297           if (!c)
00298             throw LogicException("Creating iterator for NULL calendar");
00299           curBucket = c->findBucket(d,forward);
00300         };
00301         DECLARE_EXPORT EventIterator& operator++();
00302         DECLARE_EXPORT EventIterator& operator--();
00303         EventIterator operator++(int)
00304         {EventIterator tmp = *this; ++*this; return tmp;}
00305         EventIterator operator--(int)
00306         {EventIterator tmp = *this; --*this; return tmp;}
00307     };
00308 
00309     /** @brief An iterator class to go through all buckets of the calendar. */
00310     class BucketIterator
00311     {
00312       private:
00313         Bucket* curBucket;
00314       public:
00315         BucketIterator(Bucket* b = NULL) : curBucket(b) {}
00316         bool operator != (const BucketIterator &b) const
00317         {return b.curBucket != curBucket;}
00318         bool operator == (const BucketIterator &b) const
00319         {return b.curBucket == curBucket;}
00320         BucketIterator& operator++()
00321         {if (curBucket) curBucket = curBucket->nextBucket; return *this;}
00322         BucketIterator operator++(int)
00323         {BucketIterator tmp = *this; ++*this; return tmp;}
00324         BucketIterator& operator--()
00325         {if(curBucket) curBucket = curBucket->prevBucket; return *this;}
00326         BucketIterator operator--(int)
00327         {BucketIterator tmp = *this; --*this; return tmp;}
00328         Bucket* operator ->() const {return curBucket;}
00329         Bucket& operator *() const {return *curBucket;}
00330     };
00331 
00332     /** Returns an iterator to go through the list of buckets. */
00333     BucketIterator beginBuckets() const {return BucketIterator(firstBucket);}
00334 
00335     /** Returns an iterator to go through the list of buckets. */
00336     BucketIterator endBuckets() const {return BucketIterator(NULL);}
00337 
00338     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
00339     void endElement(XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement) {}
00340     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
00341     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
00342     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
00343     static int initialize();
00344 
00345     static DECLARE_EXPORT PyObject* getEvents(PyObject*, PyObject*, PyObject*);
00346 
00347     virtual const MetaClass& getType() const {return *metadata;}
00348     static DECLARE_EXPORT const MetaCategory* metadata;
00349 
00350     virtual size_t getSize() const
00351     {
00352       size_t i = sizeof(Calendar) + getName().size();
00353       for (BucketIterator j = beginBuckets(); j!= endBuckets(); ++j)
00354         i += j->getSize();
00355       return i;
00356     }
00357 
00358   protected:
00359     /** Find the lowest priority of any bucket. */
00360     int lowestPriority() const
00361     {
00362       int min = 0;
00363       for (BucketIterator i = beginBuckets(); i != endBuckets(); ++i)
00364         if (i->getPriority() < min) min = i->getPriority();
00365       return min;
00366     }
00367 
00368   private:
00369     /** A pointer to the first bucket. The buckets are stored in a doubly
00370       * linked list. */
00371     Bucket* firstBucket;
00372 
00373     /** This is the factory method used to generate new buckets. Each subclass
00374       * should provide an override for this function. */
00375     virtual Bucket* createNewBucket(Date start, Date end, string name, int priority=0)
00376     {return new Bucket(this, start, end, name, priority);}
00377 };
00378 
00379 
00380 /** @brief This calendar type is used to store values in its buckets.
00381   *
00382   * The template type must statisfy the following requirements:
00383   *   - XML import supported by the operator >> of the class DataElement.
00384   *   - XML export supported by the method writeElement of the class XMLOutput.
00385   * Subclasses will need to implement the getType() method.
00386   * @see CalendarPointer
00387   */
00388 template <typename T> class CalendarValue : public Calendar
00389 {
00390   public:
00391     /** @brief A special type of calendar bucket, designed to hold a
00392       * a value.
00393       * @see Calendar::Bucket
00394       */
00395     class BucketValue : public Calendar::Bucket
00396     {
00397         friend class CalendarValue<T>;
00398       private:
00399         /** This is the value stored in this bucket. */
00400         T val;
00401 
00402         /** Constructor. */
00403         BucketValue(CalendarValue<T> *c, Date start, Date end, string name, int priority=0)
00404           : Bucket(c,start,end,name,priority), val(c->getDefault()) {}
00405 
00406       public:
00407         /** Returns the value of this bucket. */
00408         const T& getValue() const {return val;}
00409 
00410         /** Convert the value of the bucket to a boolean value. */
00411         bool getBool() const {return val != 0;}
00412 
00413         /** Updates the value of this bucket. */
00414         void setValue(const T& v) {val = v;}
00415 
00416         void writeElement
00417         (XMLOutput *o, const Keyword& tag, mode m = DEFAULT) const
00418         {
00419           assert(m == DEFAULT || m == FULL);
00420           writeHeader(o, tag);
00421           if (getPriority()) o->writeElement(Tags::tag_priority, getPriority());
00422           o->writeElement(Tags::tag_value, val);
00423           o->EndObject(tag);
00424         }
00425 
00426         void endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00427         {
00428           if (pAttr.isA(Tags::tag_value))
00429             pElement >> val;
00430           else
00431             Bucket::endElement(pIn, pAttr, pElement);
00432         }
00433 
00434         virtual const MetaClass& getType() const
00435         {return *Calendar::Bucket::metadata;}
00436 
00437         virtual size_t getSize() const
00438         {return sizeof(typename CalendarValue<T>::BucketValue) + getName().size();}
00439     };
00440 
00441     /** @brief A special event iterator, providing also access to the
00442       * current value. */
00443     class EventIterator : public Calendar::EventIterator
00444     {
00445       public:
00446         /** Constructor. */
00447         EventIterator(const Calendar* c, Date d = Date::infinitePast,
00448             bool f = true) : Calendar::EventIterator(c,d,f) {}
00449 
00450         /** Return the current value of the iterator at this date. */
00451         T getValue()
00452         {
00453           typedef CalendarValue<T> calendarvaluetype;
00454           typedef typename CalendarValue<T>::BucketValue bucketvaluetype;
00455           return curBucket ?
00456               static_cast<const bucketvaluetype*>(curBucket)->getValue() :
00457               static_cast<const calendarvaluetype*>(theCalendar)->getDefault();
00458         }
00459     };
00460 
00461     /** Default constructor. */
00462     CalendarValue(const string& n) : Calendar(n) {}
00463 
00464     /** Returns the value on the specified date. */
00465     const T& getValue(const Date d) const
00466     {
00467       BucketValue* x = static_cast<BucketValue*>(findBucket(d));
00468       return x ? x->getValue() : defaultValue;
00469     }
00470 
00471     /** Updates the value in a certain date range.<br>
00472       * This will create a new bucket if required. */
00473     void setValue(Date start, Date end, const T& v)
00474     {
00475       BucketValue* x = static_cast<BucketValue*>(findBucket(start));
00476       if (x && x->getStart() == start && x->getEnd() <= end)
00477         // We can update an existing bucket: it has the same start date
00478         // and ends before the new effective period ends.
00479         x->setEnd(end);
00480       else
00481         // Creating a new bucket
00482         x = static_cast<BucketValue*>(addBucket(start,end,""));
00483       x->setValue(v);
00484       x->setPriority(lowestPriority()-1);
00485     }
00486 
00487     virtual const MetaClass& getType() const = 0;
00488 
00489     const T& getValue(Calendar::BucketIterator& i) const
00490     {return reinterpret_cast<BucketValue&>(*i).getValue();}
00491 
00492     /** Returns the default calendar value when no entry is matching. */
00493     virtual T getDefault() const {return defaultValue;}
00494 
00495     /** Convert the value of the calendar to a boolean value. */
00496     virtual bool getBool() const {return defaultValue != 0;}
00497 
00498     /** Update the default calendar value when no entry is matching. */
00499     virtual void setDefault(const T v) {defaultValue = v;}
00500 
00501     void writeElement(XMLOutput *o, const Keyword& tag, mode m=DEFAULT) const
00502     {
00503       // Writing a reference
00504       if (m == REFERENCE)
00505       {
00506         o->writeElement
00507         (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00508         return;
00509       }
00510 
00511       // Write the complete object
00512       if (m != NOHEADER) o->BeginObject
00513         (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00514 
00515       // Write my own fields
00516       o->writeElement(Tags::tag_default, getDefault());
00517 
00518       // Write all buckets
00519       o->BeginObject (Tags::tag_buckets);
00520       for (BucketIterator i = beginBuckets(); i != endBuckets(); ++i)
00521         // We use the FULL mode, to force the buckets being written regardless
00522         // of the depth in the XML tree.
00523         o->writeElement(Tags::tag_bucket, *i, FULL);
00524       o->EndObject(Tags::tag_buckets);
00525 
00526       o->EndObject(tag);
00527     }
00528 
00529     void endElement(XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00530     {
00531       if (pAttr.isA(Tags::tag_default))
00532         pElement >> defaultValue;
00533       else
00534         Calendar::endElement(pIn, pAttr, pElement);
00535     }
00536 
00537   private:
00538     /** Factory method to add new buckets to the calendar.
00539       * @see Calendar::addBucket()
00540       */
00541     Bucket* createNewBucket(Date start, Date end, string name, int priority=0)
00542     {return new BucketValue(this, start, end, name, priority);}
00543 
00544     /** Value when no bucket is matching a certain date. */
00545     T defaultValue;
00546 };
00547 
00548 
00549 /* Declaration of specialized template functions. */
00550 template <> DECLARE_EXPORT bool CalendarValue<string>::getBool() const;
00551 template <> DECLARE_EXPORT bool CalendarValue<string>::BucketValue::getBool() const;
00552 
00553 
00554 /** @brief This calendar type is used to store object pointers in its buckets.
00555   *
00556   * The template type must statisfy the following requirements:
00557   *   - It must be a subclass of the Object class and implement the
00558   *     beginElement(), writeElement() and endElement() as appropriate.
00559   *   - Implement a metadata data element
00560   * Subclasses will need to implement the getType() method.
00561   * @see CalendarValue
00562   */
00563 template <typename T> class CalendarPointer : public Calendar
00564 {
00565   public:
00566     /** @brief A special type of calendar bucket, designed to hold a pointer
00567       * to an object.
00568       * @see Calendar::Bucket
00569       */
00570     class BucketPointer : public Calendar::Bucket
00571     {
00572         friend class CalendarPointer<T>;
00573       private:
00574         /** The object stored in this bucket. */
00575         T* val;
00576 
00577         /** Constructor. */
00578         BucketPointer(CalendarPointer<T> *c, Date start, Date end, string name, int priority=0)
00579           : Bucket(c,start,end,name,priority), val(c->getDefault()) {};
00580 
00581       public:
00582         /** Returns the value stored in this bucket. */
00583         T* getValue() const {return val;}
00584 
00585         /** Convert the value of the bucket to a boolean value. */
00586         bool getBool() const {return val != NULL;}
00587 
00588         /** Updates the value of this bucket. */
00589         void setValue(T* v) {val = v;}
00590 
00591         void writeElement
00592         (XMLOutput *o, const Keyword& tag, mode m = DEFAULT) const
00593         {
00594           assert(m == DEFAULT || m == FULL);
00595           writeHeader(o, tag);
00596           if (getPriority()) o->writeElement(Tags::tag_priority, getPriority());
00597           if (val) o->writeElement(Tags::tag_value, val);
00598           o->EndObject(tag);
00599         }
00600 
00601         void beginElement(XMLInput& pIn, const Attribute& pAttr)
00602         {
00603           if (pAttr.isA(Tags::tag_value))
00604             pIn.readto(
00605               MetaCategory::ControllerDefault(T::metadata,pIn.getAttributes())
00606             );
00607           else
00608             Bucket::beginElement(pIn, pAttr);
00609         }
00610 
00611         void endElement(XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00612         {
00613           if (pAttr.isA(Tags::tag_value))
00614           {
00615             T *o = dynamic_cast<T*>(pIn.getPreviousObject());
00616             if (!o)
00617               throw LogicException
00618               ("Incorrect object type during read operation");
00619             val = o;
00620           }
00621           else
00622             Bucket::endElement(pIn, pAttr, pElement);
00623         }
00624 
00625         virtual const MetaClass& getType() const
00626         {return *Calendar::Bucket::metadata;}
00627 
00628         virtual size_t getSize() const
00629         {return sizeof(typename CalendarPointer<T>::BucketPointer) + getName().size();}
00630     };
00631 
00632     /** @brief A special event iterator, providing also access to the
00633       * current value. */
00634     class EventIterator : public Calendar::EventIterator
00635     {
00636       public:
00637         /** Constructor. */
00638         EventIterator(const Calendar* c, Date d = Date::infinitePast,
00639             bool f = true) : Calendar::EventIterator(c,d,f) {}
00640 
00641         /** Return the current value of the iterator at this date. */
00642         const T* getValue()
00643         {
00644           typedef CalendarPointer<T> calendarpointertype;
00645           typedef typename CalendarPointer<T>::BucketPointer bucketpointertype;
00646           return curBucket ?
00647               static_cast<const bucketpointertype*>(curBucket)->getValue() :
00648               static_cast<const calendarpointertype*>(theCalendar)->getDefault();
00649         }
00650     };
00651 
00652     /** Default constructor. */
00653     CalendarPointer(const string& n) : Calendar(n), defaultValue(NULL) {}
00654 
00655     /** Returns the value on the specified date. */
00656     T* getValue(const Date d) const
00657     {
00658       BucketPointer* x = static_cast<BucketPointer*>(findBucket(d));
00659       return x ? x->getValue() : defaultValue;
00660     }
00661 
00662     /** Convert the value of the calendar to a boolean value. */
00663     virtual bool getBool() const {return defaultValue != NULL;}
00664 
00665     /** Updates the value in a certain date range.<br>
00666       * This will create a new bucket if required. */
00667     void setValue(Date start, Date end, T* v)
00668     {
00669       BucketPointer* x = static_cast<BucketPointer*>(findBucket(start));
00670       if (x && x->getStart() == start && x->getEnd() <= end)
00671         // We can update an existing bucket: it has the same start date
00672         // and ends before the new effective period ends.
00673         x->setEnd(end);
00674       else
00675         // Creating a new bucket
00676         x = static_cast<BucketPointer*>(addBucket(start,end,""));
00677       x->setValue(v);
00678       x->setPriority(lowestPriority()-1);
00679     }
00680 
00681     /** Returns the default calendar value when no entry is matching. */
00682     virtual T* getDefault() const {return defaultValue;}
00683 
00684     /** Update the default calendar value when no entry is matching. */
00685     virtual void setDefault(T* v) {defaultValue = v;}
00686 
00687     virtual const MetaClass& getType() const = 0;
00688 
00689     void writeElement(XMLOutput *o, const Keyword& tag, mode m=DEFAULT) const
00690     {
00691       // Writing a reference
00692       if (m == REFERENCE)
00693       {
00694         o->writeElement
00695         (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00696         return;
00697       }
00698 
00699       // Write the complete object
00700       if (m != NOHEADER) o->BeginObject
00701         (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00702 
00703       // Write my own fields
00704       if (defaultValue) o->writeElement(Tags::tag_default, defaultValue);
00705 
00706       // Write all buckets
00707       o->BeginObject (Tags::tag_buckets);
00708       for (BucketIterator i = beginBuckets(); i != endBuckets(); ++i)
00709         // We use the FULL mode, to force the buckets being written regardless
00710         // of the depth in the XML tree.
00711         o->writeElement(Tags::tag_bucket, *i, FULL);
00712       o->EndObject(Tags::tag_buckets);
00713 
00714       o->EndObject(tag);
00715     }
00716 
00717     void beginElement(XMLInput& pIn, const Attribute& pAttr)
00718     {
00719       if (pAttr.isA (Tags::tag_default))
00720         pIn.readto(T::reader(T::metadata,pIn.getAttributes()));
00721       else
00722         Calendar::beginElement(pIn, pAttr);
00723     }
00724 
00725     void endElement(XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00726     {
00727       if (pAttr.isA(Tags::tag_default))
00728       {
00729         T *o = dynamic_cast<T*>(pIn.getPreviousObject());
00730         if (!o)
00731           throw LogicException("Incorrect object type during read operation");
00732         defaultValue = o;
00733       }
00734       else
00735         Calendar::endElement(pIn, pAttr, pElement);
00736     }
00737 
00738   private:
00739     /** Factory method to add new buckets to the calendar.
00740       * @see Calendar::addBucket()
00741       */
00742     Bucket* createNewBucket(Date start, Date end, string name, int priority=0)
00743     {return new BucketPointer(this,start,end,name,priority);}
00744 
00745     /** Value when no bucket is matching a certain date. */
00746     T* defaultValue;
00747 };
00748 
00749 
00750 /** @brief A calendar only defining time buckets and not storing any data
00751   * fields. */
00752 class CalendarVoid : public Calendar
00753 {
00754   public:
00755     CalendarVoid(const string& n) : Calendar(n) {initType(metadata);}
00756     virtual const MetaClass& getType() const {return *metadata;}
00757     static DECLARE_EXPORT const MetaClass* metadata;
00758     static DECLARE_EXPORT PyObject* setPythonValue(PyObject*, PyObject*, PyObject*);
00759     static int initialize();
00760 };
00761 
00762 
00763 /** @brief A calendar storing double values in its buckets. */
00764 class CalendarDouble : public CalendarValue<double>
00765 {
00766   public:
00767     CalendarDouble(const string& n) : CalendarValue<double>(n)
00768     {setDefault(0.0); initType(metadata);}
00769     DECLARE_EXPORT ~CalendarDouble();
00770     virtual const MetaClass& getType() const {return *metadata;}
00771     static DECLARE_EXPORT const MetaClass* metadata;
00772     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
00773     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
00774     static int initialize();
00775 
00776     static DECLARE_EXPORT PyObject* setPythonValue(PyObject*, PyObject*, PyObject*);
00777 };
00778 
00779 
00780 /** @brief A calendar storing integer values in its buckets. */
00781 class CalendarInt : public CalendarValue<int>
00782 {
00783   public:
00784     CalendarInt(const string& n) : CalendarValue<int>(n)
00785     {setDefault(0); initType(metadata);}
00786     virtual const MetaClass& getType() const {return *metadata;}
00787     static DECLARE_EXPORT const MetaClass* metadata;
00788     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
00789     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
00790     static int initialize();
00791 
00792     static DECLARE_EXPORT PyObject* setPythonValue(PyObject*, PyObject*, PyObject*);
00793 };
00794 
00795 
00796 /** @brief A calendar storing boolean values in its buckets. */
00797 class CalendarBool : public CalendarValue<bool>
00798 {
00799   public:
00800     CalendarBool(const string& n) : CalendarValue<bool>(n)
00801     {setDefault(false); initType(metadata);}
00802     DECLARE_EXPORT ~CalendarBool();
00803     virtual const MetaClass& getType() const {return *metadata;}
00804     static DECLARE_EXPORT const MetaClass* metadata;
00805     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
00806     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
00807     static int initialize();
00808 
00809     static DECLARE_EXPORT PyObject* setPythonValue(PyObject*, PyObject*, PyObject*);
00810 };
00811 
00812 
00813 /** @brief A calendar storing strings in its buckets. */
00814 class CalendarString : public CalendarValue<string>
00815 {
00816   public:
00817     CalendarString(const string& n) : CalendarValue<string>(n) {initType(metadata);}
00818     virtual const MetaClass& getType() const {return *metadata;}
00819     bool getBool() const {return getDefault().empty();}
00820     static DECLARE_EXPORT const MetaClass* metadata;
00821     virtual size_t getSize() const
00822     {
00823       size_t i = sizeof(CalendarString);
00824       for (BucketIterator j = beginBuckets(); j!= endBuckets(); ++j)
00825         i += j->getSize()
00826             + static_cast<CalendarValue<string>::BucketValue&>(*j).getValue().size();
00827       return i;
00828     }
00829     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
00830     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
00831     static int initialize();
00832 
00833     static DECLARE_EXPORT PyObject* setPythonValue(PyObject*, PyObject*, PyObject*);
00834 };
00835 
00836 
00837 /** @brief A calendar storing pointers to operations in its buckets. */
00838 class CalendarOperation : public CalendarPointer<Operation>
00839 {
00840   public:
00841     CalendarOperation(const string& n) : CalendarPointer<Operation>(n)
00842     {initType(metadata);}
00843     virtual const MetaClass& getType() const {return *metadata;}
00844     static DECLARE_EXPORT const MetaClass* metadata;
00845     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
00846     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
00847     static int initialize();
00848 
00849     static DECLARE_EXPORT PyObject* setPythonValue(PyObject*, PyObject*, PyObject*);
00850 };
00851 
00852 
00853 /** @brief A problem represents infeasibilities, alerts and warnings in
00854   * the plan.
00855   *
00856   * Problems are maintained internally by the system. They are thus only
00857   * exported, meaning that you can't directly import or create problems.<br>
00858   * This class is the pure virtual base class for all problem types.<br>
00859   * The usage of the problem objects is based on the following principles:
00860   *  - Problems objects are passive. They don't actively change the model
00861   *    state.
00862   *  - Objects of the HasProblems class actively create and destroy Problem
00863   *    objects.
00864   *  - Problem objects are managed in a 'lazy' way, meaning they only are
00865   *    getting created when the list of problems is requested by the user.<br>
00866   *    During normal planning activities we merely mark the planning entities
00867   *    that have changed, so we can easily pick up which entities to recompute
00868   *    the problems for. In this way we can avoid the cpu and memory overhead
00869   *    of keeping the problem list up to date at all times, while still
00870   *    providing the user with the correct list of problems when required.
00871   *  - Given the above, Problems are lightweight objects that consume
00872   *    limited memory.
00873   */
00874 class Problem : public NonCopyable, public Object
00875 {
00876   public:
00877     class const_iterator;
00878     friend class const_iterator;
00879     class List;
00880     friend class List;
00881 
00882     /** Constructor.<br>
00883       * Note that this method can't manipulate the problem container, since
00884       * the problem objects aren't fully constructed yet.
00885       * @see addProblem
00886       */
00887     explicit Problem(HasProblems *p = NULL) : owner(p), nextProblem(NULL)
00888     {initType(metadata);}
00889 
00890     /** Initialize the class. */
00891     static int initialize();
00892 
00893     /** Destructor.
00894       * @see removeProblem
00895       */
00896     virtual ~Problem() {}
00897 
00898     /** Returns the duration of this problem. */
00899     virtual const DateRange getDates() const = 0;
00900 
00901     /** Returns a text description of this problem. */
00902     virtual string getDescription() const = 0;
00903 
00904     /** Returns the object type having this problem. */
00905     virtual string getEntity() const = 0;
00906 
00907     /** Returns true if the plan remains feasible even if it contains this
00908       * problem, i.e. if the problems flags only a warning.
00909       * Returns false if a certain problem points at an infeasibility of the
00910       * plan.
00911       */
00912     virtual bool isFeasible() const = 0;
00913 
00914     /** Returns a double number reflecting the magnitude of the problem. This
00915       * allows us to focus on the significant problems and filter out the
00916       * small ones.
00917       */
00918     virtual double getWeight() const = 0;
00919 
00920     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
00921     void endElement(XMLInput&, const Attribute&, const DataElement&) {}
00922     static DECLARE_EXPORT void writer(const MetaCategory*, XMLOutput*);
00923 
00924     PyObject* getattro(const Attribute&);
00925 
00926     PyObject* str() const
00927     {
00928       return PythonObject(getDescription());
00929     }
00930 
00931     /** Returns an iterator to the very first problem. The iterator can be
00932       * incremented till it points past the very last problem. */
00933     static DECLARE_EXPORT const_iterator begin();
00934 
00935     /** Return an iterator to the first problem of this entity. The iterator
00936       * can be incremented till it points past the last problem of this
00937       * plannable entity.<br>
00938       * The boolean argument specifies whether the problems need to be
00939       * recomputed as part of this method.
00940       */
00941     static DECLARE_EXPORT const_iterator begin(HasProblems*, bool = true);
00942 
00943     /** Return an iterator pointing beyond the last problem. */
00944     static DECLARE_EXPORT const const_iterator end();
00945 
00946     /** Erases the list of all problems. This methods can be used reduce the
00947       * memory consumption at critical points. The list of problems will be
00948       * recreated when the problem detection is triggered again.
00949       */
00950     static DECLARE_EXPORT void clearProblems();
00951 
00952     /** Erases the list of problems linked with a certain plannable object.<br>
00953       * If the second parameter is set to true, the problems will be
00954       * recreated when the next problem detection round is triggered.
00955       */
00956     static DECLARE_EXPORT void clearProblems(HasProblems& p, bool setchanged = true);
00957 
00958     /** Returns a pointer to the object that owns this problem. */
00959     virtual Object* getOwner() const = 0;
00960 
00961     /** Return a reference to the metadata structure. */
00962     virtual const MetaClass& getType() const {return *metadata;}
00963 
00964     /** Storing metadata on this class. */
00965     static DECLARE_EXPORT const MetaCategory* metadata;
00966 
00967   protected:
00968     /** Each Problem object references a HasProblem object as its owner. */
00969     HasProblems *owner;
00970 
00971     /** Each Problem contains a pointer to the next pointer for the same
00972       * owner. This class implements thus an intrusive single linked list
00973       * of Problem objects. */
00974     Problem *nextProblem;
00975 
00976     /** Adds a newly created problem to the problem container.
00977       * This method needs to be called in the constructor of a problem
00978       * subclass. It can't be called from the constructor of the base
00979       * Problem class, since the object isn't fully created yet and thus
00980       * misses the proper information used by the compare method.
00981       * @see removeProblem
00982       */
00983     DECLARE_EXPORT void addProblem();
00984 
00985     /** Removes a problem from the problem container.
00986       * This method needs to be called from the destructor of a problem
00987       * subclass.<br>
00988       * Due to the single linked list data structure, this methods'
00989       * performance is linear with the number of problems of an entity.
00990       * This is acceptable since we don't expect entities with a huge amount
00991       * of problems.
00992       * @see addproblem
00993       */
00994     DECLARE_EXPORT void removeProblem();
00995 
00996     /** Comparison of 2 problems.<br>
00997       * To garantuee that the problems are sorted in a consistent and stable
00998       * way, the following sorting criteria are used (in order of priority):
00999       * <ol><li>Entity<br>
01000       *    This sort is to be ensured by the client. This method can't
01001       *    compare problems of different entities!</li>
01002       * <li>Type<br>
01003       *    Each problem type has a hashcode used for sorting.</li>
01004       * <li>Start date</li></ol>
01005       * The sorting is expected such that it can be used as a key, i.e. no
01006       * two problems of will ever evaluate to be identical.
01007       */
01008     DECLARE_EXPORT bool operator < (const Problem& a) const;
01009 };
01010 
01011 
01012 /** @brief Classes that keep track of problem conditions need to implement
01013   * this class.
01014   *
01015   * This class is closely related to the Problem class.
01016   * @see Problem
01017   */
01018 class HasProblems
01019 {
01020     friend class Problem::const_iterator;
01021     friend class Problem;
01022   public:
01023     class EntityIterator;
01024 
01025     /** Returns an iterator pointing to the first HasProblem object. */
01026     static DECLARE_EXPORT EntityIterator beginEntity();
01027 
01028     /** Returns an iterator pointing beyond the last HasProblem object. */
01029     static DECLARE_EXPORT EntityIterator endEntity();
01030 
01031     /** Constructor. */
01032     HasProblems() : firstProblem(NULL) {}
01033 
01034     /** Destructor. It needs to take care of making sure all problems objects
01035       * are being deleted as well. */
01036     virtual ~HasProblems() {Problem::clearProblems(*this, false);}
01037 
01038     /** Returns the plannable entity relating to this problem container. */
01039     virtual Plannable* getEntity() const = 0;
01040 
01041     /** Called to update the list of problems. The function will only be
01042       * called when:
01043       *  - the list of problems is being recomputed
01044       *  - AND, problem detection is enabled for this object
01045       *  - AND, the object has changed since the last problem computation
01046       */
01047     virtual void updateProblems() = 0;
01048 
01049   private:
01050     /** A pointer to the first problem of this object. Problems are maintained
01051       * in a single linked list. */
01052     Problem* firstProblem;
01053 };
01054 
01055 
01056 /** @brief This auxilary class is used to maintain a list of problem models. */
01057 class Problem::List
01058 {
01059   public:
01060     /** Constructor. */
01061     List() : first(NULL) {};
01062 
01063     /** Destructor. */
01064     ~List() {clear();}
01065 
01066     /** Empty the list.<br>
01067       * If a problem is passed as argument, that problem and all problems
01068       * following it in the list are deleted.<br>
01069       * If no argument is passed, the complete list is erased.
01070       */
01071     DECLARE_EXPORT void clear(Problem * = NULL);
01072 
01073     /** Add a problem to the list. */
01074     DECLARE_EXPORT Problem* push
01075     (const MetaClass*, const Object*, Date, Date, double);
01076 
01077     /** Remove all problems from the list that appear AFTER the one
01078       * passed as argument. */
01079     DECLARE_EXPORT void pop(Problem *);
01080 
01081     /** Get the last problem on the list. */
01082     DECLARE_EXPORT Problem* top() const;
01083 
01084     /** Cur the list in two parts . */
01085     DECLARE_EXPORT Problem* unlink(Problem* p)
01086     {
01087       Problem *tmp = p->nextProblem;
01088       p->nextProblem = NULL;
01089       return tmp;
01090     }
01091 
01092     /** Returns true if the list is empty. */
01093     bool empty() const {return first == NULL;}
01094 
01095     /** Return an iterator to the start of the list. */
01096     Problem::const_iterator begin() const;
01097 
01098     /** End iterator. */
01099     Problem::const_iterator end() const;
01100 
01101   private:
01102     /** Pointer to the head of the list. */
01103     Problem* first;
01104 };
01105 
01106 
01107 /** @brief This class is an implementation of the "visitor" design pattern.
01108   * It is intended as a basis for different algorithms processing the frePPLe
01109   * data.
01110   *
01111   * The goal is to decouple the solver/algorithms from the model/data
01112   * representation. Different solvers can be easily be plugged in to work on
01113   * the same data.
01114   */
01115 class Solver : public HasName<Solver>
01116 {
01117   public:
01118     explicit Solver(const string& n) : HasName<Solver>(n), loglevel(0) {}
01119     virtual ~Solver() {}
01120 
01121     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
01122     virtual DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
01123     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
01124     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
01125     static int initialize();
01126 
01127     static DECLARE_EXPORT PyObject* solve(PyObject*, PyObject*);
01128 
01129     virtual void solve(void* = NULL) = 0;
01130     virtual void solve(const Demand*,void* = NULL)
01131     {throw LogicException("Called undefined solve(Demand*) method");}
01132     virtual void solve(const Operation*,void* = NULL)
01133     {throw LogicException("Called undefined solve(Operation*) method");}
01134     virtual void solve(const OperationFixedTime* o, void* v = NULL)
01135     {solve(reinterpret_cast<const Operation*>(o),v);}
01136     virtual void solve(const OperationTimePer* o, void* v = NULL)
01137     {solve(reinterpret_cast<const Operation*>(o),v);}
01138     virtual void solve(const OperationRouting* o, void* v = NULL)
01139     {solve(reinterpret_cast<const Operation*>(o),v);}
01140     virtual void solve(const OperationAlternate* o, void* v = NULL)
01141     {solve(reinterpret_cast<const Operation*>(o),v);}
01142     virtual void solve(const Resource*,void* = NULL)
01143     {throw LogicException("Called undefined solve(Resource*) method");}
01144     virtual void solve(const ResourceInfinite* r, void* v = NULL)
01145     {solve(reinterpret_cast<const Resource*>(r),v);}
01146     virtual void solve(const Buffer*,void* = NULL)
01147     {throw LogicException("Called undefined solve(Buffer*) method");}
01148     virtual void solve(const BufferInfinite* b, void* v = NULL)
01149     {solve(reinterpret_cast<const Buffer*>(b),v);}
01150     virtual void solve(const BufferProcure* b, void* v = NULL)
01151     {solve(reinterpret_cast<const Buffer*>(b),v);}
01152     virtual void solve(const Load* b, void* v = NULL)
01153     {throw LogicException("Called undefined solve(Load*) method");}
01154     virtual void solve(const Flow* b, void* v = NULL)
01155     {throw LogicException("Called undefined solve(Flow*) method");}
01156     virtual void solve(const FlowEnd* b, void* v = NULL)
01157     {solve(reinterpret_cast<const Flow*>(b),v);}
01158     virtual void solve(const Solvable*,void* = NULL)
01159     {throw LogicException("Called undefined solve(Solvable*) method");}
01160 
01161     /** Returns how elaborate and verbose output is requested.<br>
01162       * As a guideline solvers should respect the following guidelines:
01163       * - 0:<br>
01164       *   Completely silent.<br>
01165       *   This is the default value.
01166       * - 1:<br>
01167       *   Minimal and high-level messages on the progress that are sufficient
01168       *   for logging normal operation.<br>
01169       * - 2:<br>
01170       *   Higher numbers are solver dependent. These levels are typically
01171       *   used for debugging and tracing, and provide more detail on the
01172       *   solver's progress.
01173       */
01174     unsigned short getLogLevel() const {return loglevel;}
01175 
01176     /** Controls whether verbose output will be generated. */
01177     void setLogLevel(unsigned short v) {loglevel = v;}
01178 
01179     virtual const MetaClass& getType() const {return *metadata;}
01180     static DECLARE_EXPORT const MetaCategory* metadata;
01181 
01182   private:
01183     /** Controls the amount of tracing and debugging messages. */
01184     unsigned short loglevel;
01185 };
01186 
01187 
01188 /** @brief This class needs to be implemented by all classes that implement
01189   * dynamic behavior, and which can be called by a solver.
01190   */
01191 class Solvable
01192 {
01193   public:
01194     /** This method is called by solver classes. The implementation of this
01195       * class simply calls the solve method on the solver class. Using the
01196       * polymorphism the solver can implement seperate methods for different
01197       * plannable subclasses.
01198       */
01199     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
01200 
01201     /** Destructor. */
01202     virtual ~Solvable() {}
01203 };
01204 
01205 
01206 /** @brief This class needs to be implemented by all classes that implement
01207   * dynamic behavior in the plan.
01208   *
01209   * The problem detection logic is implemented in the detectProblems() method.
01210   * For performance reasons, problem detection is "lazy", i.e. problems are
01211   * computed only when somebody really needs the access to the list of
01212   * problems.
01213   */
01214 class Plannable : public HasProblems, public Solvable
01215 {
01216   public:
01217     /** Constructor. */
01218     Plannable() : useProblemDetection(true), changed(true)
01219     {anyChange = true;}
01220 
01221     /** Specify whether this entity reports problems. */
01222     DECLARE_EXPORT void setDetectProblems(bool b);
01223 
01224     /** Returns whether or not this object needs to detect problems. */
01225     bool getDetectProblems() const {return useProblemDetection;}
01226 
01227     /** Loops through all plannable objects and updates their problems if
01228       * required. */
01229     static DECLARE_EXPORT void computeProblems();
01230 
01231     /** See if this entity has changed since the last problem
01232       * problem detection run. */
01233     bool getChanged() const {return changed;}
01234 
01235     /** Mark that this entity has been updated and that the problem
01236       * detection needs to be redone. */
01237     void setChanged(bool b = true) {changed=b; if (b) anyChange=true;}
01238 
01239     /** Implement the pure virtual function from the HasProblem class. */
01240     Plannable* getEntity() const {return const_cast<Plannable*>(this);}
01241 
01242     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
01243     virtual DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
01244 
01245   private:
01246     /** Stores whether this entity should be skip problem detection, or not. */
01247     bool useProblemDetection;
01248 
01249     /** Stores whether this entity has been updated since the last problem
01250       * detection run. */
01251     bool changed;
01252 
01253     /** Marks whether any entity at all has changed its status since the last
01254       * problem detection round.
01255       */
01256     static DECLARE_EXPORT bool anyChange;
01257 
01258     /** This flag is set to true during the problem recomputation. It is
01259       * required to garantuee safe access to the problems in a multi-threaded
01260       * environment.
01261       */
01262     static DECLARE_EXPORT bool computationBusy;
01263 };
01264 
01265 
01266 /** @brief The purpose of this class is to compute the levels of all buffers,
01267   * operations and resources in the model, and to categorize them in clusters.
01268   *
01269   * Resources and buffers linked to the delivery operations of
01270   * the demand are assigned level 1. buffers one level upstream have
01271   * level 2, and so on...
01272   *
01273   * A cluster is group of planning entities (buffers, resources and operations)
01274   * that are linked together using loads and/or flows. Each cluster can be seen
01275   * as a completely independent part of the model and the planning problem.
01276   * There is no interaction possible between clusters.
01277   * Clusters are helpful is multi-threading the planning problem, partial
01278   * replanning of the model, etc...
01279   */
01280 class HasLevel
01281 {
01282 
01283 #if defined(_MSC_VER) || defined(__BORLANDC__)
01284     // Visual C++ 6.0 and Borland C++ 5.5. seem to get confused. Static
01285     // functions can't access private members.
01286     friend class HasLevel;
01287 #endif
01288 
01289   private:
01290     /** Flags whether the current computation is still up to date or not.
01291       * The flag is set when new objects of this are created or updated.
01292       * Running the computeLevels function clears the flag.
01293       */
01294     static DECLARE_EXPORT bool recomputeLevels;
01295 
01296     /** This flag is set to true during the computation of the levels. It is
01297       * required to ensure safe access to the level information in a
01298       * multi-threaded environment.
01299       */
01300     static DECLARE_EXPORT bool computationBusy;
01301 
01302     /** Stores the total number of clusters in the model. */
01303     static DECLARE_EXPORT unsigned short numberOfClusters;
01304 
01305     /** Stores the total number of hanging clusters in the model. */
01306     static DECLARE_EXPORT unsigned short numberOfHangingClusters;
01307 
01308     /** Stores the level of this entity. Higher numbers indicate more
01309       * upstream entities.
01310       * A value of -1 indicates an unused entity.
01311       */
01312     short lvl;
01313 
01314     /** Stores the cluster number of the current entity. */
01315     unsigned short cluster;
01316 
01317   protected:
01318     /** Default constructor. The initial level is -1 and basically indicates
01319       * that this HasHierarchy (either Operation, Buffer or Resource) is not
01320       * being used at all...
01321       */
01322     HasLevel() : lvl(0), cluster(0) {}
01323 
01324     /** Copy constructor. Since the characterictics of the new object are the
01325       * same as the original, the level and cluster are also the same.
01326       * No recomputation is required.
01327       */
01328     HasLevel(const HasLevel& o) : lvl(o.lvl), cluster(o.cluster) {}
01329 
01330     /** Destructor. Deleting a HasLevel object triggers recomputation of the
01331       * level and cluster computation, since the network now has changed.
01332       */
01333     ~HasLevel() {recomputeLevels = true;}
01334 
01335     /** This function recomputes all levels in the model.
01336       * It is called automatically when the getLevel or getCluster() function
01337       * on a Buffer, Resource or Operation are called while the
01338       * "recomputeLevels" flag is set.
01339       * Right, this is an example of a 'lazy' algorithm: only compute the
01340       * information when it is required. Note however that the computation
01341       * is triggered over the complete model, not a subset...
01342       * The runtime of the algorithm is pretty much linear with the total
01343       * number of operations in the model. The cluster size also has some
01344       * (limited) impact on the performance: a network with larger cluster
01345       * size will take longer to analyze.
01346       * @exception LogicException Generated when there are too many clusters in
01347       *     your model. The maximum limit is USHRT_MAX, i.e. the greatest
01348       *     number that can be stored in a variable of type "unsigned short".
01349       *     The limit is platform dependent. On 32-bit platforms it will
01350       *     typically be 65535.
01351       */
01352     static DECLARE_EXPORT void computeLevels();
01353 
01354   public:
01355     /** Returns the total number of clusters.<br>
01356       * If not up to date the recomputation will be triggered.
01357       */
01358     static unsigned short getNumberOfClusters()
01359     {
01360       if (recomputeLevels || computationBusy) computeLevels();
01361       return numberOfClusters;
01362     }
01363 
01364     /** Returns the total number of hanging clusters. A hanging cluster
01365       * is a cluster that consists of a single entity that isn't connected
01366       * to any other entity.<br>
01367       * If not up to date the recomputation will be triggered.
01368       */
01369     static unsigned short getNumberOfHangingClusters()
01370     {
01371       if (recomputeLevels || computationBusy) computeLevels();
01372       return numberOfHangingClusters;
01373     }
01374 
01375     /** Return the level (and recompute first if required). */
01376     short getLevel() const
01377     {
01378       if (recomputeLevels || computationBusy) computeLevels();
01379       return lvl;
01380     }
01381 
01382     /** Return the cluster number (and recompute first if required). */
01383     unsigned short getCluster() const
01384     {
01385       if (recomputeLevels || computationBusy) computeLevels();
01386       return cluster;
01387     }
01388 
01389     /** This function should be called when something is changed in the network
01390       * structure. The notification sets a flag, but does not immediately
01391       * trigger the recomputation.
01392       * @see computeLevels
01393       */
01394     static void triggerLazyRecomputation() {recomputeLevels = true;}
01395 };
01396 
01397 
01398 /** @brief This abstract class is used to associate buffers and resources with
01399   * a physical or logical location.
01400   *
01401   * The 'available' calendar is used to model the working hours and holidays
01402   * of resources, buffers and operations.
01403   */
01404 class Location : public HasHierarchy<Location>, public HasDescription
01405 {
01406   public:
01407     /** Constructor. */
01408     explicit Location(const string& n) : HasHierarchy<Location>(n), available(NULL) {}
01409 
01410     /** Destructor. */
01411     virtual DECLARE_EXPORT ~Location();
01412 
01413     /** Returns the availability calendar of the location.<br>
01414       * The availability calendar models the working hours and holidays. It
01415       * applies to all operations, resources and buffers using this location.
01416       */
01417     CalendarBool *getAvailable() const {return available;}
01418 
01419     /** Updates the availability calend of the location. */
01420     void setAvailable(CalendarBool* b) {available = b;}
01421 
01422     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
01423     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
01424     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
01425     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
01426     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
01427     size_t extrasize() const
01428     {return getName().size() + HasDescription::extrasize();}
01429     virtual const MetaClass& getType() const {return *metadata;}
01430     static DECLARE_EXPORT const MetaCategory* metadata;
01431     static int initialize();
01432 
01433   private:
01434     /** The availability calendar models the working hours and holidays. It
01435       * applies to all operations, resources and buffers using this location.
01436       */
01437     CalendarBool* available;
01438 };
01439 
01440 
01441 /** @brief This class implements the abstract Location class. */
01442 class LocationDefault : public Location
01443 {
01444   public:
01445     explicit LocationDefault(const string& str) : Location(str) {initType(metadata);}
01446     virtual const MetaClass& getType() const {return *metadata;}
01447     static DECLARE_EXPORT const MetaClass* metadata;
01448     virtual size_t getSize() const
01449     {return sizeof(LocationDefault) + Location::extrasize();}
01450     static int initialize();
01451 };
01452 
01453 
01454 /** @brief This abstracts class represents customers.
01455   *
01456   * Demands can be associated with a customer, but there is no planning
01457   * behavior directly linked to customers.
01458   */
01459 class Customer : public HasHierarchy<Customer>, public HasDescription
01460 {
01461   public:
01462     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
01463     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
01464     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
01465     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
01466     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
01467     size_t extrasize() const
01468     {return getName().size() + HasDescription::extrasize();}
01469     Customer(const string& n) : HasHierarchy<Customer>(n) {}
01470     virtual DECLARE_EXPORT ~Customer();
01471     virtual const MetaClass& getType() const {return *metadata;}
01472     static DECLARE_EXPORT const MetaCategory* metadata;
01473     static int initialize();
01474 };
01475 
01476 
01477 /** @brief This class implements the abstract Customer class. */
01478 class CustomerDefault : public Customer
01479 {
01480   public:
01481     explicit CustomerDefault(const string& str) : Customer(str) {initType(metadata);}
01482     virtual const MetaClass& getType() const {return *metadata;}
01483     static DECLARE_EXPORT const MetaClass* metadata;
01484     virtual size_t getSize() const
01485     {return sizeof(CustomerDefault) + Customer::extrasize();}
01486     static int initialize();
01487 };
01488 
01489 
01490 /** @brief An operation represents an activity: these consume and produce material,
01491   * take time and also require capacity.
01492   *
01493   * An operation consumes and produces material, modeled through flows.<br>
01494   * An operation requires capacity, modeled through loads.
01495   *
01496   * This is an abstract base class for all different operation types.
01497   */
01498 class Operation : public HasName<Operation>,
01499   public HasLevel, public Plannable, public HasDescription
01500 {
01501     friend class Flow;
01502     friend class Load;
01503     friend class OperationPlan;
01504     friend class OperationRouting;
01505     friend class OperationAlternate;
01506 
01507   protected:
01508     /** Constructor. Don't use it directly. */
01509     explicit Operation(const string& str) : HasName<Operation>(str),
01510       loc(NULL), size_minimum(1.0), size_multiple(0.0), size_maximum(DBL_MAX),
01511       cost(0.0), hidden(false), first_opplan(NULL), last_opplan(NULL) {}
01512 
01513     /** Extra logic called when instantiating an operationplan.<br>
01514       * When the function returns false the creation of the operationplan
01515       * is denied and it is deleted.
01516       */
01517     virtual bool extraInstantiate(OperationPlan* o) {return true;}
01518 
01519   public:
01520     /** Destructor. */
01521     virtual DECLARE_EXPORT ~Operation();
01522 
01523     /** Returns a pointer to the operationplan being instantiated. */
01524     OperationPlan* getFirstOpPlan() const {return first_opplan;}
01525 
01526     /** Returns the delay before this operation.
01527       * @see setPreTime
01528       */
01529     TimePeriod getPreTime() const {return pre_time;}
01530 
01531     /** Updates the delay before this operation.<br>
01532       * This delay is a soft constraint. This means that solvers should try to
01533       * respect this waiting time but can choose to leave a shorter time delay
01534       * if required.<br>
01535       * @see setPostTime
01536       */
01537     void setPreTime(TimePeriod t)
01538     {
01539       if (t<TimePeriod(0L))
01540         throw DataException("No negative pre-operation time allowed");
01541       pre_time=t;
01542       setChanged();
01543     }
01544 
01545     /** Returns the delay after this operation.
01546       * @see setPostTime
01547       */
01548     TimePeriod getPostTime() const {return post_time;}
01549 
01550     /** Updates the delay after this operation.<br>
01551       * This delay is a soft constraint. This means that solvers should try to
01552       * respect this waiting time but can choose to leave a shorter time delay
01553       * if required.
01554       * @see setPreTime
01555       */
01556     void setPostTime(TimePeriod t)
01557     {
01558       if (t<TimePeriod(0L))
01559         throw DataException("No negative post-operation time allowed");
01560       post_time=t;
01561       setChanged();
01562     }
01563 
01564     /** Return the operation cost.<br>
01565       * The cost of executing this operation, per unit of the
01566       * operation_plan.<br>
01567       * The default value is 0.0.
01568       */
01569     double getCost() const {return cost;}
01570 
01571     /** Update the operation cost.<br>
01572       * The cost of executing this operation, per unit of the operation_plan.
01573       */
01574     void setCost(const double c)
01575     {
01576       if (c >= 0) cost = c;
01577       else throw DataException("Operation cost must be positive");
01578     }
01579 
01580     typedef Association<Operation,Buffer,Flow>::ListA flowlist;
01581     typedef Association<Operation,Resource,Load>::ListA  loadlist;
01582 
01583     /** This is the factory method which creates all operationplans of the
01584       * operation. */
01585     DECLARE_EXPORT OperationPlan* createOperationPlan(double, Date,
01586         Date, Demand* = NULL, OperationPlan* = NULL, unsigned long = 0,
01587         bool makeflowsloads=true) const;
01588 
01589     /** Calculates the daterange starting from (or ending at) a certain date
01590       * and using a certain amount of effective available time on the
01591       * operation.
01592       *
01593       * This calculation considers the availability calendars of:
01594       * - the availability calendar of the operation's location
01595       * - the availability calendar of all resources loaded by the operation @todo not implemented yet
01596       * - the availability calendar of the locations of all resources loaded @todo not implemented yet
01597       *   by the operation
01598       *
01599       * @param[in] thedate  The date from which to start searching.
01600       * @param[in] duration The amount of available time we are looking for.
01601       * @param[in] forward  The search direction
01602       * @param[out] actualduration This variable is updated with the actual
01603       *             amount of available time found.
01604       */
01605     DECLARE_EXPORT DateRange calculateOperationTime
01606     (Date thedate, TimePeriod duration, bool forward,
01607      TimePeriod* actualduration = NULL) const;
01608 
01609     /** Calculates the effective, available time between two dates.
01610       *
01611       * This calculation considers the availability calendars of:
01612       * - the availability calendar of the operation's location
01613       * - the availability calendar of all resources loaded by the operation @todo not implemented yet
01614       * - the availability calendar of the locations of all resources loaded @todo not implemented yet
01615       *   by the operation
01616       *
01617       * @param[in] start  The date from which to start searching.
01618       * @param[in] end    The date where to stop searching.
01619       * @param[out] actualduration This variable is updated with the actual
01620       *             amount of available time found.
01621       */
01622     DECLARE_EXPORT DateRange calculateOperationTime
01623     (Date start, Date end, TimePeriod* actualduration = NULL) const;
01624 
01625     /** This method stores ALL logic the operation needs to compute the
01626       * correct relationship between the quantity, startdate and enddate
01627       * of an operationplan.
01628       *
01629       * The parameters "startdate", "enddate" and "quantity" can be
01630       * conflicting if all are specified together.
01631       * Typically, one would use one of the following combinations:
01632       *  - specify quantity and start date, and let the operation compute the
01633       *    end date.
01634       *  - specify quantity and end date, and let the operation compute the
01635       *    start date.
01636       *  - specify both the start and end date, and let the operation compute
01637       *    the quantity.
01638       *  - specify quantity, start and end date. In this case, you need to
01639       *    be aware that the operationplan that is created can be different
01640       *    from the parameters you requested.
01641       *
01642       * The following priority rules apply upon conflicts.
01643       *  - respecting the end date has the first priority.
01644       *  - respecting the start date has second priority.
01645       *  - respecting the quantity should be done if the specified dates can
01646       *    be respected.
01647       *  - if the quantity is being computed to meet the specified dates, the
01648       *    quantity being passed as argument is to be treated as a maximum
01649       *    limit. The created operationplan can have a smaller quantity, but
01650       *    not bigger...
01651       *  - at all times, we expect to have an operationplan that is respecting
01652       *    the constraints set by the operation. If required, some of the
01653       *    specified parameters may need to be violated. In case of such a
01654       *    violation we expect the operationplan quantity to be 0.
01655       *
01656       * The pre- and post-operation times are NOT considered in this method.
01657       * This method only enforces "hard" constraints. "Soft" constraints are
01658       * considered as 'hints' by the solver.
01659       *
01660       * Subclasses need to override this method to implement the correct
01661       * logic.
01662       */
01663     virtual OperationPlanState setOperationPlanParameters
01664     (OperationPlan*, double, Date, Date, bool=true, bool=true) const = 0;
01665 
01666     /** Returns the location of the operation, which is used to model the
01667       * working hours and holidays. */
01668     Location* getLocation() const {return loc;}
01669 
01670     /** Updates the location of the operation, which is used to model the
01671       * working hours and holidays. */
01672     void setLocation(Location* l) {loc = l;}
01673 
01674     /** Returns an reference to the list of flows. */
01675     const flowlist& getFlows() const {return flowdata;}
01676 
01677     /** Returns an reference to the list of loads. */
01678     const loadlist& getLoads() const {return loaddata;}
01679 
01680     /** Return the flow that is associates a given buffer with this
01681       * operation. Returns NULL is no such flow exists. */
01682     Flow* findFlow(const Buffer* b, Date d) const
01683     {return flowdata.find(b,d);}
01684 
01685     /** Return the load that is associates a given resource with this
01686       * operation. Returns NULL is no such load exists. */
01687     Load* findLoad(const Resource* r, Date d) const
01688     {return loaddata.find(r,d);}
01689 
01690     /** Deletes all operationplans of this operation. The boolean parameter
01691       * controls whether we delete also locked operationplans or not.
01692       */
01693     DECLARE_EXPORT void deleteOperationPlans(bool deleteLockedOpplans = false);
01694 
01695     /** Sets the minimum size of operationplans.<br>
01696       * The default value is 1.0
01697       */
01698     void setSizeMinimum(double f)
01699     {
01700       if (f<0)
01701         throw DataException("Operation can't have a negative minimum size");
01702       size_minimum = f;
01703       setChanged();
01704     }
01705 
01706     /** Returns the minimum size for operationplans. */
01707     double getSizeMinimum() const {return size_minimum;}
01708 
01709     /** Sets the multiple size of operationplans. */
01710     void setSizeMultiple(double f)
01711     {
01712       if (f<0)
01713         throw DataException("Operation can't have a negative multiple size");
01714       size_multiple = f;
01715       setChanged();
01716     }
01717 
01718     /** Returns the mutiple size for operationplans. */
01719     double getSizeMultiple() const {return size_multiple;}
01720 
01721     /** Sets the maximum size of operationplans. */
01722     void setSizeMaximum(double f)
01723     {
01724       if (f < size_minimum)
01725         throw DataException("Operation maximum size must be higher than the minimum size");
01726       if (f <= 0)
01727         throw DataException("Operation maximum size must be greater than 0");
01728       size_maximum = f;
01729       setChanged();
01730     }
01731 
01732     /** Returns the maximum size for operationplans. */
01733     double getSizeMaximum() const {return size_maximum;}
01734 
01735     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
01736     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
01737     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
01738     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
01739     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
01740     static int initialize();
01741 
01742     size_t extrasize() const
01743     {return getName().size() + HasDescription::extrasize();}
01744 
01745     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
01746 
01747     typedef list<Operation*> Operationlist;
01748 
01749     /** Returns a reference to the list of sub operations of this operation. */
01750     virtual const Operationlist& getSubOperations() const {return nosubOperations;}
01751 
01752     /** Returns a reference to the list of super-operations, i.e. operations
01753       * using the current Operation as a sub-Operation.
01754       */
01755     const Operationlist& getSuperOperations() const {return superoplist;}
01756 
01757     /** Register a super-operation, i.e. an operation having this one as a
01758       * sub-operation. */
01759     void addSuperOperation(Operation * o) {superoplist.push_front(o);}
01760 
01761     /** Removes a sub-operation from the list. This method will need to be
01762       * overridden by all operation types that acts as a super-operation. */
01763     virtual void removeSubOperation(Operation *o) {}
01764 
01765     /** Removes a super-operation from the list. */
01766     void removeSuperOperation(Operation *o)
01767     {superoplist.remove(o); o->removeSubOperation(this);}
01768 
01769     /** Return the release fence of this operation. */
01770     TimePeriod getFence() const {return fence;}
01771 
01772     /** Update the release fence of this operation. */
01773     void setFence(TimePeriod t) {if (fence!=t) setChanged(); fence=t;}
01774 
01775     virtual DECLARE_EXPORT void updateProblems();
01776 
01777     void setHidden(bool b) {if (hidden!=b) setChanged(); hidden = b;}
01778     bool getHidden() const {return hidden;}
01779 
01780     static DECLARE_EXPORT const MetaCategory* metadata;
01781 
01782   protected:
01783     DECLARE_EXPORT void initOperationPlan(OperationPlan*, double,
01784         const Date&, const Date&, Demand*, OperationPlan*, unsigned long,
01785         bool = true) const;
01786 
01787   private:
01788     /** List of operations using this operation as a sub-operation */
01789     Operationlist superoplist;
01790 
01791     /** Empty list of operations.<br>
01792       * For operation types which have no suboperations this list is
01793       * used as the list of suboperations.
01794       */
01795     static DECLARE_EXPORT Operationlist nosubOperations;
01796 
01797     /** Location of the operation.<br>
01798       * The location is used to model the working hours and holidays.
01799       */
01800     Location* loc;
01801 
01802     /** Represents the time between this operation and a next one. */
01803     TimePeriod post_time;
01804 
01805     /** Represents the time between this operation and a previous one. */
01806     TimePeriod pre_time;
01807 
01808     /** Represents the release fence of this operation, i.e. a period of time
01809       * (relative to the current date of the plan) in which normally no
01810       * operationplan is allowed to be created.
01811       */
01812     TimePeriod fence;
01813 
01814     /** Singly linked list of all flows of this operation. */
01815     flowlist flowdata;
01816 
01817     /** Singly linked list of all resources Loaded by this operation. */
01818     loadlist loaddata;
01819 
01820     /** Minimum size for operationplans.<br>
01821       * The default value is 1.0
01822       */
01823     double size_minimum;
01824 
01825     /** Multiple size for operationplans. */
01826     double size_multiple;
01827 
01828     /** Maximum size for operationplans. */
01829     double size_maximum;
01830 
01831     /** Cost of the operation.<br>
01832       * The default value is 0.0.
01833       */
01834     double cost;
01835 
01836     /** Does the operation require serialization or not. */
01837     bool hidden;
01838 
01839     /** A pointer to the first operationplan of this operation.<br>
01840       * All operationplans of this operation are stored in a sorted
01841       * doubly linked list.
01842       */
01843     OperationPlan* first_opplan;
01844 
01845     /** A pointer to the last operationplan of this operation.<br>
01846       * All operationplans of this operation are stored in a sorted
01847       * doubly linked list.
01848       */
01849     OperationPlan* last_opplan;
01850 };
01851 
01852 
01853 /** @brief An operationplan is the key dynamic element of a plan. It
01854   * represents a certain quantity being planned along a certain operation
01855   * during a certain date range.
01856   *
01857   * From a coding perspective:
01858   *  - Operationplans are created by the factory method createOperationPlan()
01859   *    on the matching Operation class.
01860   *  - The createLoadAndFlowplans() can optionally be called to also create
01861   *    the loadplans and flowplans, to take care of the material and
01862   *    capacity consumption.
01863   *  - Once you're sure about creating the operationplan, the activate()
01864   *    method should be called. It will assign the operationplan a unique
01865   *    numeric identifier, register the operationplan in a container owned
01866   *    by the operation instance, and also create loadplans and flowplans
01867   *    if this hasn't been done yet.<br>
01868   *  - Operationplans can be organized in hierarchical structure, matching
01869   *    the operation hierarchies they belong to.
01870   *
01871   * @todo reading suboperationplans can be improved
01872   */
01873 class OperationPlan
01874   : public Object, public HasProblems, public NonCopyable
01875 {
01876     friend class FlowPlan;
01877     friend class LoadPlan;
01878     friend class Demand;
01879     friend class Operation;
01880     friend class OperationAlternate;
01881     friend class OperationRouting;
01882     friend class ProblemPrecedence;
01883 
01884   public:
01885     class FlowPlanIterator;
01886 
01887     /** Returns an iterator pointing to the first flowplan. */
01888     FlowPlanIterator beginFlowPlans() const;
01889 
01890     /** Returns an iterator pointing beyond the last flowplan. */
01891     FlowPlanIterator endFlowPlans() const;
01892 
01893     /** Returns how many flowplans are created on an operationplan. */
01894     int sizeFlowPlans() const;
01895 
01896     class LoadPlanIterator;
01897 
01898     /** Returns an iterator pointing to the first loadplan. */
01899     LoadPlanIterator beginLoadPlans() const;
01900 
01901     /** Returns an iterator pointing beyond the last loadplan. */
01902     LoadPlanIterator endLoadPlans() const;
01903 
01904     /** Returns how many loadplans are created on an operationplan. */
01905     int sizeLoadPlans() const;
01906 
01907     /** @brief This class models an STL-like iterator that allows us to iterate over
01908       * the operationplans in a simple and safe way.
01909       *
01910       * Objects of this class are created by the begin() and end() functions.
01911       */
01912     class iterator
01913     {
01914       public:
01915         /** Constructor. The iterator will loop only over the operationplans
01916           * of the operation passed. */
01917         iterator(const Operation* x) : op(Operation::end()), mode(1)
01918         {
01919           opplan = x ? x->getFirstOpPlan() : NULL;
01920         }
01921 
01922         /** Constructor. The iterator will loop only over the suboperationplans
01923           * of the operationplan passed. */
01924         iterator(const OperationPlan* x) : op(Operation::end()), mode(2)
01925         {
01926           opplan = x ? x->firstsubopplan : NULL;
01927         }
01928 
01929         /** Constructor. The iterator will loop over all operationplans. */
01930         iterator() : op(Operation::begin()), mode(3)
01931         {
01932           // The while loop is required since the first operation might not
01933           // have any operationplans at all
01934           while (op!=Operation::end() && !op->getFirstOpPlan()) ++op;
01935           if (op!=Operation::end())
01936             opplan = op->getFirstOpPlan();
01937           else
01938             opplan = NULL;
01939         }
01940 
01941         /** Copy constructor. */
01942         iterator(const iterator& it) : opplan(it.opplan), op(it.op), mode(it.mode) {}
01943 
01944         /** Return the content of the current node. */
01945         OperationPlan& operator*() const {return *opplan;}
01946 
01947         /** Return the content of the current node. */
01948         OperationPlan* operator->() const {return opplan;}
01949 
01950         /** Pre-increment operator which moves the pointer to the next
01951           * element. */
01952         iterator& operator++()
01953         {
01954           if (mode == 2)
01955             opplan = opplan->nextsubopplan;
01956           else
01957             opplan = opplan->next;
01958           // Move to a new operation
01959           if (!opplan && mode == 3)
01960           {
01961             do ++op;
01962             while (op!=Operation::end() && (!op->getFirstOpPlan()));
01963             if (op!=Operation::end())
01964               opplan = op->getFirstOpPlan();
01965             else
01966               opplan = NULL;
01967           }
01968           return *this;
01969         }
01970 
01971         /** Post-increment operator which moves the pointer to the next
01972           * element. */
01973         iterator operator++(int)
01974         {
01975           iterator tmp(*this);
01976           if (mode == 2)
01977             opplan = opplan->nextsubopplan;
01978           else
01979             opplan = opplan->next;
01980           // Move to a new operation
01981           if (!opplan && mode==3)
01982           {
01983             do ++op; while (op!=Operation::end() && !op->getFirstOpPlan());
01984             if (op!=Operation::end())
01985               opplan = op->getFirstOpPlan();
01986             else
01987               opplan = NULL;
01988           }
01989           return tmp;
01990         }
01991 
01992         /** Comparison operator. */
01993         bool operator==(const iterator& y) const {return opplan == y.opplan;}
01994 
01995         /** Inequality operator. */
01996         bool operator!=(const iterator& y) const {return opplan != y.opplan;}
01997 
01998       private:
01999         /** A pointer to current operationplan. */
02000         OperationPlan* opplan;
02001 
02002         /** An iterator over the operations. */
02003         Operation::iterator op;
02004 
02005         /** Describes the type of iterator.<br>
02006           * 1) iterate over operationplan instances of operation
02007           * 2) iterate over suboperationplans of an operationplan
02008           * 3) iterate over all operationplans
02009           */
02010         short mode;
02011     };
02012 
02013     friend class iterator;
02014 
02015     static iterator end() {return iterator(static_cast<Operation*>(NULL));}
02016 
02017     static iterator begin() {return iterator();}
02018 
02019     /** Returns true when not a single operationplan object exists. */
02020     static bool empty() {return begin()==end();}
02021 
02022     /** Returns the number of operationplans in the system. This method
02023       * is linear with the number of operationplans in the model, and should
02024       * therefore be used only with care.
02025       */
02026     static unsigned long size()
02027     {
02028       unsigned long cnt = 0;
02029       for (OperationPlan::iterator i = begin(); i != end(); ++i) ++cnt;
02030       return cnt;
02031     }
02032 
02033     /** This is a factory method that creates an operationplan pointer based
02034       * on the name and id, which are passed as an array of character pointers.
02035       * This method is intended to be used to create objects when reading
02036       * XML input data.
02037       */
02038     static DECLARE_EXPORT Object* createOperationPlan(const MetaClass*, const AttributeList&);
02039 
02040     /** Destructor. */
02041     virtual DECLARE_EXPORT ~OperationPlan();
02042 
02043     virtual DECLARE_EXPORT void setChanged(bool b = true);
02044 
02045     /** Returns the quantity. */
02046     double getQuantity() const {return quantity;}
02047 
02048     /** Updates the quantity.<br>
02049       * The operationplan quantity is subject to the following rules:
02050       *  - The quantity must be greater than or equal to the minimum size.<br>
02051       *    The value is rounded up to the smallest multiple above the minimum
02052       *    size if required, or rounded down to 0.
02053       *  - The quantity must be a multiple of the multiple_size field.<br>
02054       *    The value is rounded up or down to meet this constraint.
02055       *  - The quantity must be smaller than or equal to the maximum size.<br>
02056       *    The value is limited to the smallest multiple below this limit.
02057       *  - Setting the quantity of an operationplan to 0 is always possible,
02058       *    regardless of the minimum, multiple and maximum values.
02059       * This method can only be called on top operationplans. Sub operation
02060       * plans should pass on a call to the parent operationplan.
02061       */
02062     virtual DECLARE_EXPORT double setQuantity(double f,
02063         bool roundDown = false, bool update = true, bool execute = true);
02064 
02065     /** Returns a pointer to the demand for which this operationplan is a delivery.
02066       * If the operationplan isn't a delivery, this is a NULL pointer.
02067       */
02068     Demand* getDemand() const {return dmd;}
02069 
02070     /** Updates the demand to which this operationplan is a solution. */
02071     DECLARE_EXPORT void setDemand(Demand* l);
02072 
02073     /** Calculate the penalty of an operationplan.<br>
02074       * It is the sum of all setup penalties of the resources it loads. */
02075     DECLARE_EXPORT double getPenalty() const;
02076 
02077     /** Calculate the unavailable time during the operationplan. The regular
02078       * duration is extended with this amount.
02079       */
02080     DECLARE_EXPORT TimePeriod getUnavailable() const;
02081 
02082     /** Returns whether the operationplan is locked. A locked operationplan
02083       * is never changed.
02084       */
02085     bool getLocked() const {return flags & IS_LOCKED;}
02086 
02087     /** Deletes all operationplans of a certain operation. A boolean flag
02088       * allows to specify whether locked operationplans are to be deleted too.
02089       */
02090     static DECLARE_EXPORT void deleteOperationPlans(Operation* o, bool deleteLocked=false);
02091 
02092     /** Locks/unlocks an operationplan. A locked operationplan is never
02093       * changed.
02094       */
02095     virtual DECLARE_EXPORT void setLocked(bool b = true);
02096 
02097     /** Returns a pointer to the operation being instantiated. */
02098     Operation* getOperation() const {return oper;}
02099 
02100     /** Fixes the start and end date of an operationplan. Note that this
02101       * overrules the standard duration given on the operation, i.e. no logic
02102       * kicks in to verify the data makes sense. This is up to the user to
02103       * take care of.<br>
02104       * The methods setStart(Date) and setEnd(Date) are therefore preferred
02105       * since they properly apply all appropriate logic.
02106       */
02107     void setStartAndEnd(Date st, Date nd)
02108     {
02109       dates.setStartAndEnd(st,nd);
02110       update();
02111     }
02112 
02113     /** A method to restore a previous state of an operationplan.<br>
02114       * NO validity checks are done on the parameters.
02115       */
02116     void restore(const OperationPlanState& x);
02117 
02118     /** Updates the operationplan owning this operationplan. In case of
02119       * a OperationRouting steps this will be the operationplan representing the
02120       * complete routing. */
02121     void DECLARE_EXPORT setOwner(OperationPlan* o);
02122 
02123     /** Returns a pointer to the operationplan for which this operationplan
02124       * a sub-operationplan.<br>
02125       * The method returns NULL if there is no owner defined.<br>
02126       * E.g. Sub-operationplans of a routing refer to the overall routing
02127       * operationplan.<br>
02128       * E.g. An alternate sub-operationplan refers to its parent.
02129       * @see getTopOwner
02130       */
02131     OperationPlan* getOwner() const {return owner;}
02132 
02133     /** Returns a pointer to the operationplan owning a set of
02134       * sub-operationplans. There can be multiple levels of suboperations.<br>
02135       * If no owner exists the method returns the current operationplan.
02136       * @see getOwner
02137       */
02138     const OperationPlan* getTopOwner() const
02139     {
02140       if (owner)
02141       {
02142         // There is an owner indeed
02143         OperationPlan* o(owner);
02144         while (o->owner) o = o->owner;
02145         return o;
02146       }
02147       else
02148         // This operationplan is itself the top of a hierarchy
02149         return this;
02150     }
02151 
02152     /** Returns the start and end date of this operationplan. */
02153     const DateRange & getDates() const {return dates;}
02154 
02155     /** Return true if the operationplan is redundant, ie all material
02156       * it produces is not used at all.<br>
02157       * If the optional argument is false (which is the default value), we
02158       * check with the minimum stock level of the buffers. If the argument
02159       * is true, we check with 0.
02160       */
02161     DECLARE_EXPORT bool isExcess(bool = false) const;
02162 
02163     /** Returns a unique identifier of the operationplan.<br>
02164       * The identifier can be specified in the data input (in which case
02165       * we check for the uniqueness during the read operation).<br>
02166       * For operationplans created during a solver run, the identifier is
02167       * assigned in the instantiate() function. The numbering starts with the
02168       * highest identifier read in from the input and is then incremented
02169       * for every operationplan that is registered.
02170       */
02171     unsigned long getIdentifier() const {return id;}
02172 
02173     /** Updates the end date of the operationplan and compute the start
02174       * date.<br>
02175       * Locked operationplans are not updated by this function.<br>
02176       * Slack can be introduced between sub operationaplans by this method,
02177       * i.e. the sub operationplans are only moved if required to meet the
02178       * end date.
02179       */
02180     virtual DECLARE_EXPORT void setEnd(Date);
02181 
02182     /** Updates the start date of the operationplan and compute the end
02183       * date.<br>
02184       * Locked operation_plans are not updated by this function.<br>
02185       * Slack can be introduced between sub operationaplans by this method,
02186       * i.e. the sub operationplans are only moved if required to meet the
02187       * start date.
02188       */
02189     virtual DECLARE_EXPORT void setStart(Date);
02190 
02191     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02192     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
02193     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
02194     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02195     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
02196     static int initialize();
02197 
02198     PyObject* str() const
02199     {
02200       ostringstream ch;
02201       ch << id;
02202       return PythonObject(ch.str());
02203     }
02204 
02205     static PyObject* create(PyTypeObject*, PyObject*, PyObject*);
02206 
02207     /** Initialize the operationplan. The initialization function should be
02208       * called when the operationplan is ready to be 'officially' added. The
02209       * initialization performs the following actions:
02210       * <ol>
02211       * <li> assign an identifier</li>
02212       * <li> create the flow and loadplans if these hadn't been created
02213       * before</li>
02214       * <li> add the operationplan to the global list of operationplans</li>
02215       * <li> create a link with a demand object if this is a delivery
02216       * operationplan</li>
02217       * </ol>
02218       * Every operationplan subclass that has sub-operations will normally
02219       * need to create an override of this function.<br>
02220       *
02221       * The return value indicates whether the initialization was successfull.
02222       * If the operationplan is invalid, it will be DELETED and the return value
02223       * is 'false'.
02224       */
02225     DECLARE_EXPORT bool activate(bool useMinCounter = true);
02226 
02227     /** Remove an operationplan from the list of officially registered ones.<br>
02228       * The operationplan will keep its loadplans and flowplans after unregistration.
02229       */
02230     DECLARE_EXPORT void deactivate();
02231 
02232     /** This method links the operationplan in the list of all operationplans
02233       * maintained on the operation.<br>
02234       * In most cases calling this method is not required since it included
02235       * in the activate method. In exceptional cases the solver already
02236       * needs to see uncommitted operationplans in the list - eg for the
02237       * procurement buffer.
02238       * @see activate
02239       */
02240     DECLARE_EXPORT void insertInOperationplanList();
02241 
02242     /** This method remove the operationplan from the list of all operationplans
02243       * maintained on the operation.<br>
02244       * @see deactivate
02245       */
02246     DECLARE_EXPORT void removeFromOperationplanList();
02247 
02248     /** Add a sub-operationplan to the list. */
02249     virtual DECLARE_EXPORT void addSubOperationPlan(OperationPlan*);
02250 
02251     /** Remove a sub-operation_plan from the list. */
02252     virtual DECLARE_EXPORT void eraseSubOperationPlan(OperationPlan*);
02253 
02254     /** This function is used to create the loadplans, flowplans and
02255       * setup operationplans.
02256       */
02257     DECLARE_EXPORT void createFlowLoads();
02258 
02259     /** This function is used to delete the loadplans, flowplans and
02260       * setup operationplans.
02261       */
02262     DECLARE_EXPORT void deleteFlowLoads();
02263 
02264     bool getHidden() const {return getOperation()->getHidden();}
02265 
02266     /** Searches for an OperationPlan with a given identifier.<br>
02267       * Returns a NULL pointer if no such OperationPlan can be found.<br>
02268       * The method is of complexity O(n), i.e. involves a LINEAR search through
02269       * the existing operationplans, and can thus be quite slow in big models.<br>
02270       * The method is O(1), i.e. constant time regardless of the model size,
02271       * when the parameter passed is bigger than the operationplan counter.
02272       */
02273     static DECLARE_EXPORT OperationPlan* findId(unsigned long l);
02274 
02275     /** Problem detection is actually done by the Operation class. That class
02276       * actually "delegates" the responsability to this class, for efficiency.
02277       */
02278     virtual void updateProblems();
02279 
02280     /** Implement the pure virtual function from the HasProblem class. */
02281     Plannable* getEntity() const {return oper;}
02282 
02283     /** Return the metadata. We return the metadata of the operation class,
02284       * not the one of the operationplan class!
02285       */
02286     const MetaClass& getType() const {return *metadata;}
02287 
02288     static DECLARE_EXPORT const MetaClass* metadata;
02289 
02290     static DECLARE_EXPORT const MetaCategory* metacategory;
02291 
02292     virtual size_t getSize() const
02293     {return sizeof(OperationPlan);}
02294 
02295     /** Handles the persistence of operationplan objects. */
02296     static DECLARE_EXPORT void writer(const MetaCategory*, XMLOutput*);
02297 
02298     /** Comparison of 2 OperationPlans.
02299       * To garantuee that the problems are sorted in a consistent and stable
02300       * way, the following sorting criteria are used (in order of priority):
02301       * <ol><li>Operation</li>
02302       * <li>Start date (earliest dates first)</li>
02303       * <li>Quantity (biggest quantities first)</li></ol>
02304       * Multiple operationplans for the same values of the above keys can exist.
02305       */
02306     DECLARE_EXPORT bool operator < (const OperationPlan& a) const;
02307 
02308     /** Copy constructor.<br>
02309       * If the optional argument is false, the new copy is not initialized
02310       * and won't have flowplans and loadplans.
02311       */
02312     DECLARE_EXPORT OperationPlan(const OperationPlan&, bool = true);
02313 
02314     /** Return the plannable object that caused the creation of this
02315       * operationplan. Usage of this field can vary by solver.
02316       * The information is normally not relevant for end users.
02317       */
02318     DECLARE_EXPORT Plannable* getMotive() const {return motive;}
02319 
02320     /** Update the plannable object that created this operationplan. */
02321     DECLARE_EXPORT void setMotive(Plannable* v) {motive = v;}
02322 
02323   private:
02324     /** Private copy constructor.<br>
02325       * It is used in the public copy constructor to make a deep clone of suboperationplans.
02326       * @see OperationPlan(const OperationPlan&, bool = true)
02327       */
02328     DECLARE_EXPORT OperationPlan(const OperationPlan&, OperationPlan*);
02329 
02330     /** Updates the operationplan based on the latest information of quantity,
02331       * date and locked flag.<br>
02332       * This method will also update parent and child operationplans.
02333       * @see resizeFlowLoadPlans
02334       */
02335     virtual DECLARE_EXPORT void update();
02336 
02337     /** Update the loadplans and flowplans of the operationplan based on the
02338       * latest information of quantity, date and locked flag.<br>
02339       * This method will NOT update parent or child operationplans.
02340       * @see update
02341       */
02342     DECLARE_EXPORT void resizeFlowLoadPlans();
02343 
02344     /** Default constructor.<br>
02345       * This way of creating operationplan objects is not intended for use by
02346       * any client applications. Client applications should use the factory
02347       * method on the operation class instead.<br>
02348       * Subclasses of the Operation class may use this constructor in their
02349       * own override of the createOperationPlan method.
02350       * @see Operation::createOperationPlan
02351       */
02352     OperationPlan() : owner(NULL), quantity(0.0), flags(0), dmd(NULL),
02353       id(0), oper(NULL), firstflowplan(NULL), firstloadplan(NULL),
02354       prev(NULL), next(NULL), firstsubopplan(NULL), lastsubopplan(NULL),
02355       nextsubopplan(NULL), prevsubopplan(NULL), motive(NULL)
02356     {initType(metadata);}
02357 
02358   private:
02359     static const short IS_LOCKED = 1;
02360     static const short IS_SETUP = 2;
02361     static const short HAS_SETUP = 4;
02362 
02363     /** Pointer to a higher level OperationPlan. */
02364     OperationPlan *owner;
02365 
02366     /** Quantity. */
02367     double quantity;
02368 
02369     /** Is this operationplan locked? A locked operationplan doesn't accept
02370       * any changes. This field is only relevant for top-operationplans. */
02371     short flags;
02372 
02373     /** Counter of OperationPlans, which is used to automatically assign a
02374       * unique identifier for each operationplan.<br>
02375       * The value of the counter is the first available identifier value that
02376       * can be used for a new operationplan.<br>
02377       * The first value is 1, and each operationplan increases it by 1.
02378       * @see counterMax
02379       * @see getIdentifier()
02380       */
02381     static DECLARE_EXPORT unsigned long counterMin;
02382 
02383     /** Counter of OperationPlans, which is used to automatically assign a
02384       * unique identifier for each operationplan.<br>
02385       * The first value is a very high number, and each operationplan
02386       * decreases it by 1.
02387       * @see counterMin
02388       * @see getIdentifier()
02389       */
02390     static DECLARE_EXPORT unsigned long counterMax;
02391 
02392     /** Pointer to the demand.<br>
02393       * Only delivery operationplans have this field set. The field is NULL
02394       * for all other operationplans.
02395       */
02396     Demand *dmd;
02397 
02398     /** Unique identifier.<br>
02399       * The field is 0 while the operationplan is not fully registered yet.
02400       */
02401     unsigned long id;
02402 
02403     /** Start and end date. */
02404     DateRange dates;
02405 
02406     /** Pointer to the operation. */
02407     Operation *oper;
02408 
02409     /** Root of a single linked list of flowplans. */
02410     FlowPlan* firstflowplan;
02411 
02412     /** Single linked list of loadplans. */
02413     LoadPlan* firstloadplan;
02414 
02415     /** Pointer to the previous operationplan.<br>
02416       * Operationplans are chained in a doubly linked list for each operation.
02417       * @see next
02418       */
02419     OperationPlan* prev;
02420 
02421     /** Pointer to the next operationplan.<br>
02422       * Operationplans are chained in a doubly linked list for each operation.
02423       * @see prev
02424       */
02425     OperationPlan* next;
02426 
02427     /** Pointer to the first suboperationplan of this operationplan. */
02428     OperationPlan* firstsubopplan;
02429 
02430     /** Pointer to the last suboperationplan of this operationplan. */
02431     OperationPlan* lastsubopplan;
02432 
02433     /** Pointer to the next suboperationplan of the parent operationplan. */
02434     OperationPlan* nextsubopplan;
02435 
02436     /** Pointer to the previous suboperationplan of the parent operationplan. */
02437     OperationPlan* prevsubopplan;
02438 
02439     /** Pointer to the demand that caused the creation of this operationplan. */
02440     Plannable* motive;
02441 };
02442 
02443 
02444 /** @brief A simple class to easily remember the date, quantity and owner of
02445   * an operationplan. */
02446 class OperationPlanState  // @todo should also be able to remember and restore suboperationplans!!!
02447 {
02448   public:
02449     Date start;
02450     Date end;
02451     double quantity;
02452 
02453     /** Default constructor. */
02454     OperationPlanState() : quantity(0.0) {}
02455 
02456     /** Constructor. */
02457     OperationPlanState(const OperationPlan* x)
02458     {
02459       if (!x)
02460       {
02461         quantity = 0.0;
02462         return;
02463       }
02464       else
02465       {
02466         start = x->getDates().getStart();
02467         end = x->getDates().getEnd();
02468         quantity = x->getQuantity();
02469       }
02470     }
02471 
02472     /** Constructor. */
02473     OperationPlanState(const Date x, const Date y, double q)
02474       : start(x), end(y), quantity(q) {}
02475 
02476     /** Constructor. */
02477     OperationPlanState(const DateRange& x, double q)
02478       : start(x.getStart()), end(x.getEnd()), quantity(q) {}
02479 };
02480 
02481 
02482 /** @brief Models an operation that takes a fixed amount of time, independent
02483   * of the quantity. */
02484 class OperationFixedTime : public Operation
02485 {
02486   public:
02487     /** Constructor. */
02488     explicit OperationFixedTime(const string& s) : Operation(s) {initType(metadata);}
02489 
02490     /** Returns the length of the operation. */
02491     const TimePeriod getDuration() const {return duration;}
02492 
02493     /** Updates the duration of the operation. Existing operation plans of this
02494       * operation are not automatically refreshed to reflect the change. */
02495     void setDuration(TimePeriod t)
02496     {
02497       if (t<0L)
02498         throw DataException("FixedTime operation can't have a negative duration");
02499       duration = t;
02500     }
02501 
02502     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02503     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
02504     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02505     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
02506     static int initialize();
02507 
02508     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
02509 
02510     virtual const MetaClass& getType() const {return *metadata;}
02511     static DECLARE_EXPORT const MetaClass* metadata;
02512     virtual size_t getSize() const
02513     {return sizeof(OperationFixedTime) + Operation::extrasize();}
02514 
02515     /** A operation of this type enforces the following rules on its
02516       * operationplans:
02517       *  - The duration is always constant.
02518       *  - If the end date is specified, we use that and ignore the start
02519       *    date that could have been passed.
02520       *  - If no end date but only a start date are specified, we'll use
02521       *    that date.
02522       *  - If no dates are specified, we don't update the dates of the
02523       *    operationplan.
02524       *  - The quantity can be any positive number.
02525       *  - Locked operationplans can't be updated.
02526       * @see Operation::setOperationPlanParameters
02527       */
02528     DECLARE_EXPORT OperationPlanState setOperationPlanParameters
02529     (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
02530 
02531   protected:
02532     DECLARE_EXPORT virtual bool extraInstantiate(OperationPlan* o);
02533 
02534   private:
02535     /** Stores the lengh of the Operation. */
02536     TimePeriod duration;
02537 };
02538 
02539 
02540 /** @brief Models an operation to convert a setup on a resource. */
02541 class OperationSetup : public Operation
02542 {
02543   public:
02544     /** Constructor. */
02545     explicit OperationSetup(const string& s) : Operation(s) {initType(metadata);}
02546 
02547     // Never write the setup operation
02548     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const {}
02549     static int initialize();
02550 
02551     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
02552 
02553     virtual const MetaClass& getType() const {return *metadata;}
02554     static DECLARE_EXPORT const MetaClass* metadata;
02555     virtual size_t getSize() const
02556     {return sizeof(OperationSetup) + Operation::extrasize();}
02557 
02558     /** A operation of this type enforces the following rules on its
02559       * operationplans:
02560       *  - The duration is calculated based on the conversion type.
02561       */
02562     DECLARE_EXPORT OperationPlanState setOperationPlanParameters
02563     (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
02564 
02565     /** A pointer to the operation that is instantiated for all conversions. */
02566     static DECLARE_EXPORT const Operation* setupoperation;
02567 };
02568 
02569 
02570 /** @brief Models an operation whose duration is the sum of a constant time,
02571   * plus a cetain time per unit.
02572   */
02573 class OperationTimePer : public Operation
02574 {
02575   public:
02576     /** Constructor. */
02577     explicit OperationTimePer(const string& s) : Operation(s) {initType(metadata);}
02578 
02579     /** Returns the constant part of the operation time. */
02580     TimePeriod getDuration() const {return duration;}
02581 
02582     /** Sets the constant part of the operation time. */
02583     void setDuration(TimePeriod t)
02584     {
02585       if(t<0L)
02586         throw DataException("TimePer operation can't have a negative duration");
02587       duration = t;
02588     }
02589 
02590     /** Returns the time per unit of the operation time. */
02591     TimePeriod getDurationPer() const {return duration_per;}
02592 
02593     /** Sets the time per unit of the operation time. */
02594     void setDurationPer(TimePeriod t)
02595     {
02596       if(t<0L)
02597         throw DataException("TimePer operation can't have a negative duration-per");
02598       duration_per = t;
02599     }
02600 
02601     /** A operation of this type enforces the following rules on its
02602       * operationplans:
02603       *   - If both the start and end date are specified, the quantity is
02604       *     computed to match these dates.
02605       *     If the time difference between the start and end date is too
02606       *     small to fit the fixed duration, the quantity is set to 0.
02607       *   - If only an end date is specified, it will be respected and we
02608       *     compute a start date based on the quantity.
02609       *   - If only a start date is specified, it will be respected and we
02610       *     compute an end date based on the quantity.
02611       *   - If no date is specified, we respect the quantity and the end
02612       *     date of the operation. A new start date is being computed.
02613       * @see Operation::setOperationPlanParameters
02614       */
02615     DECLARE_EXPORT OperationPlanState setOperationPlanParameters
02616     (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
02617 
02618     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02619     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
02620     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02621     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
02622     static int initialize();
02623 
02624     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
02625 
02626     virtual const MetaClass& getType() const {return *metadata;}
02627     static DECLARE_EXPORT const MetaClass* metadata;
02628     virtual size_t getSize() const
02629     {return sizeof(OperationTimePer) + Operation::extrasize();}
02630 
02631   private:
02632     /** Constant part of the operation time. */
02633     TimePeriod duration;
02634 
02635     /** Variable part of the operation time. */
02636     TimePeriod duration_per;
02637 };
02638 
02639 
02640 /** @brief Represents a routing operation, i.e. an operation consisting of
02641   * multiple, sequential sub-operations.
02642   */
02643 class OperationRouting : public Operation
02644 {
02645   public:
02646     /** Constructor. */
02647     explicit OperationRouting(const string& c) : Operation(c) {initType(metadata);}
02648 
02649     /** Destructor. */
02650     DECLARE_EXPORT ~OperationRouting();
02651 
02652     /** Adds a new steps to routing at the start of the routing. */
02653     void addStepFront(Operation *o)
02654     {
02655       if (!o) throw DataException("Adding NULL operation to routing");
02656       steps.push_front(o);
02657       o->addSuperOperation(this);
02658     }
02659 
02660     /** Adds a new steps to routing at the end of the routing. */
02661     void addStepBack(Operation *o)
02662     {
02663       if (!o) throw DataException("Adding NULL operation to routing");
02664       steps.push_back(o);
02665       o->addSuperOperation(this);
02666     }
02667 
02668     /** Add one or more steps to a routing. */
02669     static DECLARE_EXPORT PyObject* addStep(PyObject*, PyObject*);
02670 
02671     /** Remove a step from a routing. */
02672     void removeSubOperation(Operation *o)
02673     {steps.remove(o); o->superoplist.remove(this);}
02674 
02675     /** A operation of this type enforces the following rules on its
02676       * operationplans:
02677       *  - If an end date is given, sequentially use this method on the
02678       *    different steps. The steps are stepped through starting from the
02679       *    last step, and each step will adjust to meet the requested end date.
02680       *    If there is slack between the routings' step operationplans, it can
02681       *    be used to "absorb" the change.
02682       *  - When a start date is given, the behavior is similar to the previous
02683       *    case, except that we step through the operationplans from the
02684       *    first step this time.
02685       *  - If both a start and an end date are given, we use only the end date.
02686       *  - If there are no sub operationplans yet, apply the requested changes
02687       *    blindly.
02688       * @see Operation::setOperationPlanParameters
02689       */
02690     DECLARE_EXPORT OperationPlanState setOperationPlanParameters
02691     (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
02692 
02693     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
02694     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02695     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
02696     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02697     static int initialize();
02698 
02699     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
02700 
02701     /** Return a list of all sub-operationplans. */
02702     virtual const Operationlist& getSubOperations() const {return steps;}
02703 
02704     virtual const MetaClass& getType() const {return *metadata;}
02705     static DECLARE_EXPORT const MetaClass* metadata;
02706     virtual size_t getSize() const
02707     {
02708       return sizeof(OperationRouting) + Operation::extrasize()
02709           + steps.size() * 2 * sizeof(Operation*);
02710     }
02711 
02712   protected:
02713     /** Extra logic to be used when instantiating an operationplan. */
02714     virtual DECLARE_EXPORT bool extraInstantiate(OperationPlan* o);
02715 
02716   private:
02717     /** Stores a double linked list of all step operations. */
02718     Operationlist steps;
02719 };
02720 
02721 
02722 inline void OperationPlan::restore(const OperationPlanState& x)
02723 {
02724   getOperation()->setOperationPlanParameters(this, x.quantity, x.start, x.end, true);
02725   assert(quantity == x.quantity);
02726   assert(dates.getStart() == x.start || x.start!=x.end);
02727   assert(dates.getEnd() == x.end || x.start!=x.end);
02728 }
02729 
02730 
02731 /** This type defines what mode used to search the alternates. */
02732 enum SearchMode
02733 {
02734   /** Select the alternate with the lowest priority number.<br>
02735     * This is the default.
02736     */
02737   PRIORITY = 0,
02738   /** Select the alternate which gives the lowest cost. */
02739   MINCOST = 1,
02740   /** Select the alternate which gives the lowest penalty. */
02741   MINPENALTY = 2,
02742   /** Select the alternate which gives the lowest sum of the cost and
02743     * penalty. */
02744   MINCOSTPENALTY = 3
02745 };
02746 
02747 
02748 /** Writes a search mode to an output stream. */
02749 inline ostream & operator << (ostream & os, const SearchMode & d)
02750 {
02751   switch (d)
02752   {
02753     case PRIORITY: os << "PRIORITY"; return os;
02754     case MINCOST: os << "MINCOST"; return os;
02755     case MINPENALTY: os << "MINPENALTY"; return os;
02756     case MINCOSTPENALTY: os << "MINCOSTPENALTY"; return os;
02757     default: assert(false); return os;
02758   }
02759 }
02760 
02761 
02762 /** Translate a string to a search mode value. */
02763 DECLARE_EXPORT SearchMode decodeSearchMode(const string& c);
02764 
02765 
02766 /** @brief This class represents a choice between multiple operations. The
02767   * alternates are sorted in order of priority.
02768   */
02769 class OperationAlternate : public Operation
02770 {
02771   public:
02772     typedef pair<int,DateRange> alternateProperty;
02773 
02774     /** Constructor. */
02775     explicit OperationAlternate(const string& c)
02776       : Operation(c), search(PRIORITY) {initType(metadata);}
02777 
02778     /** Destructor. */
02779     DECLARE_EXPORT ~OperationAlternate();
02780 
02781     /** Add a new alternate operation.<br>
02782       * The lower the priority value, the more important this alternate
02783       * operation is. */
02784     DECLARE_EXPORT void addAlternate
02785     (Operation*, int = 1, DateRange = DateRange());
02786 
02787     /** Removes an alternate from the list. */
02788     DECLARE_EXPORT void removeSubOperation(Operation *);
02789 
02790     /** Returns the properties of a certain suboperation.
02791       * @exception LogicException Generated when the argument operation is
02792       *     null or when it is not a sub-operation of this alternate.
02793       */
02794     DECLARE_EXPORT const alternateProperty& getProperties(Operation* o) const;
02795 
02796     /** Updates the priority of a certain suboperation.
02797       * @exception DataException Generated when the argument operation is
02798       *     not null and not a sub-operation of this alternate.
02799       */
02800     DECLARE_EXPORT void setPriority(Operation*, int);
02801 
02802     /** Updates the effective daterange of a certain suboperation.
02803       * @exception DataException Generated when the argument operation is
02804       *     not null and not a sub-operation of this alternate.
02805       */
02806     DECLARE_EXPORT void setEffective(Operation*, DateRange);
02807 
02808     /** Return the search mode. */
02809     SearchMode getSearch() const {return search;}
02810 
02811     /** Update the search mode. */
02812     void setSearch(const string a) {search = decodeSearchMode(a);}
02813 
02814     /** A operation of this type enforces the following rules on its
02815       * operationplans:
02816       *  - Very simple, call the method with the same name on the alternate
02817       *    suboperationplan.
02818       * @see Operation::setOperationPlanParameters
02819       */
02820     DECLARE_EXPORT OperationPlanState setOperationPlanParameters
02821     (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
02822 
02823     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
02824     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02825     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
02826     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02827     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
02828     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
02829     virtual const Operationlist& getSubOperations() const {return alternates;}
02830     static int initialize();
02831 
02832     /** Add an alternate to the operation.<br>
02833       * The keyword arguments are "operation", "priority", "effective_start"
02834       * and "effective_end"
02835       */
02836     static DECLARE_EXPORT PyObject* addAlternate(PyObject*, PyObject*, PyObject*);
02837 
02838     virtual const MetaClass& getType() const {return *metadata;}
02839     static DECLARE_EXPORT const MetaClass* metadata;
02840     virtual size_t getSize() const
02841     {
02842       return sizeof(OperationAlternate) + Operation::extrasize()
02843           + alternates.size() * (5*sizeof(Operation*)+sizeof(alternateProperty));
02844     }
02845 
02846   protected:
02847     /** Extra logic to be used when instantiating an operationplan. */
02848     virtual DECLARE_EXPORT bool extraInstantiate(OperationPlan* o);
02849 
02850   private:
02851     typedef list<alternateProperty> alternatePropertyList;
02852 
02853     /** List of the priorities of the different alternate operations. The list
02854       * is maintained such that it is sorted in ascending order of priority. */
02855     alternatePropertyList alternateProperties;
02856 
02857     /** List of all alternate operations. The list is sorted with the operation
02858       * with the highest priority at the start of the list.<br>
02859       * Note that the list of operations and the list of priorities go hand in
02860       * hand: they have an equal number of elements and the order of the
02861       * elements is matching in both lists.
02862       */
02863     Operationlist alternates;
02864 
02865     /** Mode to select the preferred alternates. */
02866     SearchMode search;
02867 };
02868 
02869 
02870 /** @brief An item defines the products being planned, sold, stored and/or
02871   * manufactured. Buffers and demands have a reference an item.
02872   *
02873   * This is an abstract class.
02874   */
02875 class Item : public HasHierarchy<Item>, public HasDescription
02876 {
02877   public:
02878     /** Constructor. Don't use this directly! */
02879     explicit Item(const string& str) : HasHierarchy<Item>(str),
02880       deliveryOperation(NULL), price(0.0) {}
02881 
02882     /** Returns the delivery operation.<br>
02883       * This field is inherited from a parent item, if it hasn't been
02884       * specified.
02885       */
02886     Operation* getOperation() const
02887     {
02888       // Current item has a non-empty deliveryOperation field
02889       if (deliveryOperation) return deliveryOperation;
02890 
02891       // Look for a non-empty deliveryOperation field on owners
02892       for (Item* i = getOwner(); i; i=i->getOwner())
02893         if (i->deliveryOperation) return i->deliveryOperation;
02894 
02895       // The field is not specified on the item or any of its parents.
02896       return NULL;
02897     }
02898 
02899     /** Updates the delivery operation.<br>
02900       * If some demands have already been planned using the old delivery
02901       * operation they are left untouched and won't be replanned.
02902       */
02903     void setOperation(Operation* o) {deliveryOperation = o;}
02904 
02905     /** Return the selling price of the item.<br>
02906       * The default value is 0.0.
02907       */
02908     double getPrice() const {return price;}
02909 
02910     /** Update the selling price of the item. */
02911     void setPrice(const double c)
02912     {
02913       if (c >= 0) price = c;
02914       else throw DataException("Item price must be positive");
02915     }
02916 
02917     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02918     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
02919     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
02920     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02921     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
02922     static int initialize();
02923 
02924     /** Destructor. */
02925     virtual DECLARE_EXPORT ~Item();
02926 
02927     virtual const MetaClass& getType() const {return *metadata;}
02928     static DECLARE_EXPORT const MetaCategory* metadata;
02929 
02930   private:
02931     /** This is the operation used to satisfy a demand for this item.
02932       * @see Demand
02933       */
02934     Operation* deliveryOperation;
02935 
02936     /** Selling price of the item. */
02937     double price;
02938 };
02939 
02940 
02941 /** @brief This class is the default implementation of the abstract Item
02942   * class. */
02943 class ItemDefault : public Item
02944 {
02945   public:
02946     explicit ItemDefault(const string& str) : Item(str) {initType(metadata);}
02947     virtual const MetaClass& getType() const {return *metadata;}
02948     static DECLARE_EXPORT const MetaClass* metadata;
02949     virtual size_t getSize() const
02950     {
02951       return sizeof(ItemDefault) + getName().size()
02952           + HasDescription::extrasize();
02953     }
02954     static int initialize();
02955 };
02956 
02957 
02958 /** @brief A buffer represents a combination of a item and location.<br>
02959   * It is the entity for keeping modeling inventory.
02960   */
02961 class Buffer : public HasHierarchy<Buffer>, public HasLevel,
02962   public Plannable, public HasDescription
02963 {
02964     friend class Flow;
02965     friend class FlowPlan;
02966 
02967   public:
02968     typedef TimeLine<FlowPlan> flowplanlist;
02969     typedef Association<Operation,Buffer,Flow>::ListB flowlist;
02970 
02971     /** Constructor. Implicit creation of instances is disallowed. */
02972     explicit Buffer(const string& str) : HasHierarchy<Buffer>(str),
02973       hidden(false), producing_operation(NULL), loc(NULL), it(NULL),
02974       min_val(0), max_val(default_max), min_cal(NULL), max_cal(NULL),
02975       carrying_cost(0.0) {}
02976 
02977     /** Returns the operation that is used to supply extra supply into this
02978       * buffer. */
02979     Operation* getProducingOperation() const {return producing_operation;}
02980 
02981     /** Updates the operation that is used to supply extra supply into this
02982       * buffer. */
02983     void setProducingOperation(Operation* o)
02984     {producing_operation = o; setChanged();}
02985 
02986     /** Returns the item stored in this buffer. */
02987     Item* getItem() const {return it;}
02988 
02989     /** Updates the Item stored in this buffer. */
02990     void setItem(Item* i) {it = i; setChanged();}
02991 
02992     /** Returns the Location of this buffer. */
02993     Location* getLocation() const {return loc;}
02994 
02995     /** Updates the location of this buffer. */
02996     void setLocation(Location* i) {loc = i;}
02997 
02998     /** Returns the minimum inventory level. */
02999     double getMinimum() const {return min_val;}
03000 
03001     /** Returns a pointer to a calendar for storing the minimum inventory
03002       * level. */
03003     CalendarDouble* getMinimumCalendar() const {return min_cal;}
03004 
03005     /** Returns the maximum inventory level. */
03006     double getMaximum() const {return max_val;}
03007 
03008     /** Returns a pointer to a calendar for storing the maximum inventory
03009       * level. */
03010     CalendarDouble* getMaximumCalendar() const {return max_cal;}
03011 
03012     /** Updates the minimum inventory target for the buffer. */
03013     DECLARE_EXPORT void setMinimum(double);
03014 
03015     /** Updates the minimum inventory target for the buffer. */
03016     DECLARE_EXPORT void setMinimumCalendar(CalendarDouble *);
03017 
03018     /** Updates the minimum inventory target for the buffer. */
03019     DECLARE_EXPORT void setMaximum(double);
03020 
03021     /** Updates the minimum inventory target for the buffer. */
03022     DECLARE_EXPORT void setMaximumCalendar(CalendarDouble *);
03023 
03024     /** Return the carrying cost.<br>
03025       * The cost of carrying inventory in this buffer. The value is a
03026       * percentage of the item sales price, per year and per unit.
03027       */
03028     double getCarryingCost() const {return carrying_cost;}
03029 
03030     /** Return the carrying cost.<br>
03031       * The cost of carrying inventory in this buffer. The value is a
03032       * percentage of the item sales price, per year and per unit.<br>
03033       * The default value is 0.0.
03034       */
03035     void setCarryingCost(const double c)
03036     {
03037       if (c >= 0) carrying_cost = c;
03038       else throw DataException("Buffer carrying_cost must be positive");
03039     }
03040 
03041     DECLARE_EXPORT virtual void beginElement(XMLInput&, const Attribute&);
03042     DECLARE_EXPORT virtual void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03043     DECLARE_EXPORT virtual void endElement(XMLInput&, const Attribute&, const DataElement&);
03044     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
03045     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
03046 
03047     size_t extrasize() const
03048     {return getName().size() + HasDescription::extrasize();}
03049 
03050     /** Initialize the class. */
03051     static int initialize();
03052 
03053     /** Destructor. */
03054     virtual DECLARE_EXPORT ~Buffer();
03055 
03056     /** Returns the available material on hand immediately after the
03057       * given date.
03058       */
03059     DECLARE_EXPORT double getOnHand(Date d = Date::infinitePast) const;
03060 
03061     /** Update the on-hand inventory at the start of the planning horizon. */
03062     DECLARE_EXPORT void setOnHand(double f);
03063 
03064     /** Returns minimum or maximum available material on hand in the given
03065       * daterange. The third parameter specifies whether we return the
03066       * minimum (which is the default) or the maximum value.
03067       * The computation is INclusive the start and end dates.
03068       */
03069     DECLARE_EXPORT double getOnHand(Date, Date, bool min = true) const;
03070 
03071     /** Returns a reference to the list of all flows of this buffer. */
03072     const flowlist& getFlows() const {return flows;}
03073 
03074     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03075 
03076     /** Returns a reference to the list of all flow plans of this buffer. */
03077     const flowplanlist& getFlowPlans() const {return flowplans;}
03078 
03079     /** Returns a reference to the list of all flow plans of this buffer. */
03080     flowplanlist& getFlowPlans() {return flowplans;}
03081 
03082     /** Return the flow that is associates a given operation with this
03083       * buffer.<br>Returns NULL is no such flow exists. */
03084     Flow* findFlow(const Operation* o, Date d) const
03085     {return flows.find(o,d);}
03086 
03087     /** Deletes all operationplans consuming from or producing from this
03088       * buffer. The boolean parameter controls whether we delete also locked
03089       * operationplans or not.
03090       */
03091     DECLARE_EXPORT void deleteOperationPlans(bool deleteLockedOpplans = false);
03092 
03093     virtual DECLARE_EXPORT void updateProblems();
03094 
03095     void setHidden(bool b) {if (hidden!=b) setChanged(); hidden = b;}
03096     bool getHidden() const {return hidden;}
03097 
03098     virtual const MetaClass& getType() const {return *metadata;}
03099     static DECLARE_EXPORT const MetaCategory* metadata;
03100 
03101     /** This function matches producing and consuming operationplans
03102       * with each other, and updates the pegging iterator accordingly.
03103       */
03104     virtual DECLARE_EXPORT void followPegging
03105     (PeggingIterator&, FlowPlan*, short, double, double);
03106 
03107   private:
03108     /** A constant defining the default max inventory target.\\
03109       * Theoretically we should set this to DBL_MAX, but then the results
03110       * are not portable across platforms.
03111       */
03112     static DECLARE_EXPORT const double default_max;
03113 
03114     /** This models the dynamic part of the plan, representing all planned
03115       * material flows on this buffer. */
03116     flowplanlist flowplans;
03117 
03118     /** This models the defined material flows on this buffer. */
03119     flowlist flows;
03120 
03121     /** Hide this entity from serialization or not. */
03122     bool hidden;
03123 
03124     /** This is the operation used to create extra material in this buffer. */
03125     Operation *producing_operation;
03126 
03127     /** Location of this buffer.<br>
03128       * This field is only used as information.<br>
03129       * The default is NULL.
03130       */
03131     Location* loc;
03132 
03133     /** Item being stored in this buffer.<br>
03134       * The default value is NULL.
03135       */
03136     Item* it;
03137 
03138     /** Minimum inventory target.<br>
03139       * If a minimum calendar is specified this field is ignored.
03140       * @see min_cal
03141       */
03142     double min_val;
03143 
03144     /** Maximum inventory target. <br>
03145       * If a maximum calendar is specified this field is ignored.
03146       * @see max_cal
03147       */
03148     double max_val;
03149 
03150     /** Points to a calendar to store the minimum inventory level.<br>
03151       * The default value is NULL, resulting in a constant minimum level
03152       * of 0.
03153       */
03154     CalendarDouble *min_cal;
03155 
03156     /** Points to a calendar to store the maximum inventory level.<br>
03157       * The default value is NULL, resulting in a buffer without excess
03158       * inventory problems.
03159       */
03160     CalendarDouble *max_cal;
03161 
03162     /** Carrying cost.<br>
03163       * The cost of carrying inventory in this buffer. The value is a
03164       * percentage of the item sales price, per year and per unit.
03165       */
03166     double carrying_cost;
03167 };
03168 
03169 
03170 
03171 /** @brief This class is the default implementation of the abstract Buffer class. */
03172 class BufferDefault : public Buffer
03173 {
03174   public:
03175     explicit BufferDefault(const string& str) : Buffer(str) {initType(metadata);}
03176     virtual const MetaClass& getType() const {return *metadata;}
03177     virtual size_t getSize() const
03178     {return sizeof(BufferDefault) + Buffer::extrasize();}
03179     static DECLARE_EXPORT const MetaClass* metadata;
03180     static int initialize();
03181 };
03182 
03183 
03184 /** @brief  This class represents a material buffer with an infinite supply of extra
03185   * material.
03186   *
03187   * In other words, it never constrains the plan and it doesn't propagate any
03188   * requirements upstream.
03189   */
03190 class BufferInfinite : public Buffer
03191 {
03192   public:
03193     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03194     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03195     virtual const MetaClass& getType() const {return *metadata;}
03196     virtual size_t getSize() const
03197     {return sizeof(BufferInfinite) + Buffer::extrasize();}
03198     explicit BufferInfinite(const string& c) : Buffer(c)
03199     {setDetectProblems(false); initType(metadata);}
03200     static DECLARE_EXPORT const MetaClass* metadata;
03201     static int initialize();
03202 };
03203 
03204 
03205 /** @brief This class models a buffer that is replenish by an external supplier
03206   * using a reorder-point policy.
03207   *
03208   * It represents a material buffer where a replenishment is triggered
03209   * whenever the inventory drops below the minimum level. The buffer is then
03210   * replenished to the maximum inventory level.<br>
03211   * A leadtime is taken into account for the replenishments.<br>
03212   * The following parameters control this replenishment:
03213   *  - <b>MinimumInventory</b>:<br>
03214   *    Inventory level triggering a new replenishment.<br>
03215   *    The actual inventory can drop below this value.
03216   *  - <b>MaximumInventory</b>:<br>
03217   *    Inventory level to which we try to replenish.<br>
03218   *    The actual inventory can exceed this value.
03219   *  - <b>Leadtime</b>:<br>
03220   *    Time taken between placing the purchase order with the supplier and the
03221   *    delivery of the material.
03222   *
03223   * Using the additional parameters described below the replenishments can be
03224   * controlled in more detail. The resulting inventory profile can end up
03225   * to be completely different from the classical saw-tooth pattern!
03226   *
03227   * The timing of the replenishments can be constrained by the following
03228   * parameters:
03229   *  - <b>MinimumInterval</b>:<br>
03230   *    Minimum time between replenishments.<br>
03231   *    The order quantity will be increased such that it covers at least
03232   *    the demand in the minimum interval period. The actual inventory can
03233   *    exceed the target set by the MinimumInventory parameter.
03234   *  - <b>MaximumInterval</b>:<br>
03235   *    Maximum time between replenishments.<br>
03236   *    The order quantity will replenish to an inventory value less than the
03237   *    maximum when this maximum interval is reached.
03238   * When the minimum and maximum interval are equal we basically define a fixed
03239   * schedule replenishment policy.
03240   *
03241   * The quantity of the replenishments can be constrained by the following
03242   * parameters:
03243   *  - <b>MinimumQuantity</b>:<br>
03244   *    Minimum quantity for a replenishment.<br>
03245   *    This parameter can cause the actual inventory to exceed the target set
03246   *    by the MinimumInventory parameter.
03247   *  - <b>MaximumQuantity</b>:<br>
03248   *    Maximum quantity for a replenishment.<br>
03249   *    This parameter can cause the maximum inventory target never to be
03250   *    reached.
03251   *  - <b>MultipleQuantity</b>:<br>
03252   *    All replenishments are rounded up to a multiple of this value.
03253   * When the minimum and maximum quantity are equal we basically define a fixed
03254   * quantity replenishment policy.
03255   */
03256 class BufferProcure : public Buffer
03257 {
03258   public:
03259     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03260     virtual DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
03261     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03262     virtual const MetaClass& getType() const {return *metadata;}
03263     virtual size_t getSize() const
03264     {return sizeof(BufferProcure) + Buffer::extrasize();}
03265     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
03266     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
03267     static int initialize();
03268 
03269     /** Constructor. */
03270     explicit BufferProcure(const string& c) : Buffer(c),
03271       size_minimum(0), size_maximum(DBL_MAX), size_multiple(0),
03272       oper(NULL) {initType(metadata);}
03273     static DECLARE_EXPORT const MetaClass* metadata;
03274 
03275     /** Return the purchasing leadtime. */
03276     TimePeriod getLeadtime() const {return leadtime;}
03277 
03278     /** Update the procurement leadtime. */
03279     void setLeadtime(TimePeriod p)
03280     {
03281       if (p<0L)
03282         throw DataException("Procurement buffer can't have a negative lead time");
03283       leadtime = p;
03284     }
03285 
03286     /** Return the release time fence. */
03287     TimePeriod getFence() const {return fence;}
03288 
03289     /** Update the release time fence. */
03290     void setFence(TimePeriod p) {fence = p;}
03291 
03292     /** Return the inventory level that will trigger creation of a
03293       * purchasing.
03294       */
03295     double getMinimumInventory() const
03296     {return getFlowPlans().getMin(Date::infiniteFuture);}
03297 
03298     /** Update the inventory level that will trigger the creation of a
03299       * replenishment.<br>
03300       * Because of the replenishment leadtime, the actual inventory will drop
03301       * below this value. It is up to the user to set an appropriate minimum
03302       * value.
03303       */
03304     void setMinimumInventory(double f)
03305     {
03306       if (f<0)
03307         throw DataException("Procurement buffer can't have a negative minimum inventory");
03308       flowplanlist::EventMinQuantity* min = getFlowPlans().getMinEvent(Date::infiniteFuture);
03309       if (min)
03310         min->setMin(f);
03311       else
03312       {
03313         // Create and insert a new minimum event
03314         min = new flowplanlist::EventMinQuantity(Date::infinitePast, f);
03315         getFlowPlans().insert(min);
03316       }
03317       // The minimum is increased over the maximum: auto-increase the maximum.
03318       if (getFlowPlans().getMax(Date::infiniteFuture) < f)
03319         setMaximumInventory(f);
03320     }
03321 
03322     /** Return the maximum inventory level to which we wish to replenish. */
03323     double getMaximumInventory() const
03324     {return getFlowPlans().getMax(Date::infiniteFuture);}
03325 
03326     /** Update the maximum inventory level to which we plan to replenish.<br>
03327       * This is not a hard limit - other parameters can make that the actual
03328       * inventory either never reaches this value or always exceeds it.
03329       */
03330     void setMaximumInventory(double f)
03331     {
03332       if (f<0)
03333         throw DataException("Procurement buffer can't have a negative maximum inventory");
03334       flowplanlist::EventMaxQuantity* max = getFlowPlans().getMaxEvent(Date::infiniteFuture);
03335       if (max)
03336         max->setMax(f);
03337       else
03338       {
03339         // Create and insert a new maximum event
03340         max = new flowplanlist::EventMaxQuantity(Date::infinitePast, f);
03341         getFlowPlans().insert(max);
03342       }
03343       // The maximum is lowered below the minimum: auto-decrease the minimum
03344       if (f < getFlowPlans().getMin(Date::infiniteFuture))
03345         setMinimumInventory(f);
03346     }
03347 
03348     /** Return the minimum interval between purchasing operations.<br>
03349       * This parameter doesn't control the timing of the first purchasing
03350       * operation, but only to the subsequent ones.
03351       */
03352     TimePeriod getMinimumInterval() const {return min_interval;}
03353 
03354     /** Update the minimum time between replenishments. */
03355     void setMinimumInterval(TimePeriod p)
03356     {
03357       if (p<0L)
03358         throw DataException("Procurement buffer can't have a negative minimum interval");
03359       min_interval = p;
03360       // minimum is increased over the maximum: auto-increase the maximum
03361       if (max_interval < min_interval) max_interval = min_interval;
03362     }
03363 
03364     /** Return the maximum time interval between sytem-generated replenishment
03365       * operations.
03366       */
03367     TimePeriod getMaximumInterval() const {return max_interval;}
03368 
03369     /** Update the minimum time between replenishments. */
03370     void setMaximumInterval(TimePeriod p)
03371     {
03372       if (p<0L)
03373         throw DataException("Procurement buffer can't have a negative maximum interval");
03374       max_interval = p;
03375       // maximum is lowered below the minimum: auto-decrease the minimum
03376       if (max_interval < min_interval) min_interval = max_interval;
03377     }
03378 
03379     /** Return the minimum quantity of a purchasing operation. */
03380     double getSizeMinimum() const {return size_minimum;}
03381 
03382     /** Update the minimum replenishment quantity. */
03383     void setSizeMinimum(double f)
03384     {
03385       if (f<0)
03386         throw DataException("Procurement buffer can't have a negative minimum size");
03387       size_minimum = f;
03388       // minimum is increased over the maximum: auto-increase the maximum
03389       if (size_maximum < size_minimum) size_maximum = size_minimum;
03390     }
03391 
03392     /** Return the maximum quantity of a purchasing operation. */
03393     double getSizeMaximum() const {return size_maximum;}
03394 
03395     /** Update the maximum replenishment quantity. */
03396     void setSizeMaximum(double f)
03397     {
03398       if (f<0)
03399         throw DataException("Procurement buffer can't have a negative maximum size");
03400       size_maximum = f;
03401       // maximum is lowered below the minimum: auto-decrease the minimum
03402       if (size_maximum < size_minimum) size_minimum = size_maximum;
03403     }
03404 
03405     /** Return the multiple quantity of a purchasing operation. */
03406     double getSizeMultiple() const {return size_multiple;}
03407 
03408     /** Update the multiple quantity. */
03409     void setSizeMultiple(double f)
03410     {
03411       if (f<0)
03412         throw DataException("Procurement buffer can't have a negative multiple size");
03413       size_multiple = f;
03414     }
03415 
03416     /** Returns the operation that is automatically created to represent the
03417       * procurements.
03418       */
03419     DECLARE_EXPORT Operation* getOperation() const;
03420 
03421   private:
03422     /** Purchasing leadtime.<br>
03423       * Within this leadtime fence no additional purchase orders can be generated.
03424       */
03425     TimePeriod leadtime;
03426 
03427     /** Time window from the current date in which all procurements are expected
03428       * to be released.
03429       */
03430     TimePeriod fence;
03431 
03432     /** Minimum time interval between purchasing operations. */
03433     TimePeriod min_interval;
03434 
03435     /** Maximum time interval between purchasing operations. */
03436     TimePeriod max_interval;
03437 
03438     /** Minimum purchasing quantity.<br>
03439       * The default value is 0, meaning no minimum.
03440       */
03441     double size_minimum;
03442 
03443     /** Maximum purchasing quantity.<br>
03444       * The default value is 0, meaning no maximum limit.
03445       */
03446     double size_maximum;
03447 
03448     /** Purchases are always rounded up to a multiple of this quantity.<br>
03449       * The default value is 0, meaning no multiple needs to be applied.
03450       */
03451     double size_multiple;
03452 
03453     /** A pointer to the procurement operation. */
03454     Operation* oper;
03455 };
03456 
03457 
03458 /** @brief This class defines a material flow to/from a buffer, linked with an
03459   * operation. This default implementation plans the material flow at the
03460   * start of the operation.
03461   */
03462 class Flow : public Object, public Association<Operation,Buffer,Flow>::Node,
03463   public Solvable
03464 {
03465   public:
03466     /** Destructor. */
03467     virtual DECLARE_EXPORT ~Flow();
03468 
03469     /** Constructor. */
03470     explicit Flow(Operation* o, Buffer* b, double q)
03471       : quantity(q), priority(1), hasAlts(false), altFlow(NULL), search(PRIORITY)
03472     {
03473       setOperation(o);
03474       setBuffer(b);
03475       initType(metadata);
03476       try { validate(ADD); }
03477       catch (...)
03478       {
03479         if (getOperation()) getOperation()->flowdata.erase(this);
03480         if (getBuffer()) getBuffer()->flows.erase(this);
03481         resetReferenceCount();
03482         throw;
03483       }
03484     }
03485 
03486     /** Constructor. */
03487     explicit Flow(Operation* o, Buffer* b, double q, DateRange e)
03488       : quantity(q), priority(1), hasAlts(false), altFlow(NULL), search(PRIORITY)
03489     {
03490       setOperation(o);
03491       setBuffer(b);
03492       setEffective(e);
03493       initType(metadata);
03494       try { validate(ADD); }
03495       catch (...)
03496       {
03497         if (getOperation()) getOperation()->flowdata.erase(this);
03498         if (getBuffer()) getBuffer()->flows.erase(this);
03499         resetReferenceCount();
03500         throw;
03501       }
03502     }
03503 
03504     /** Returns the operation. */
03505     Operation* getOperation() const {return getPtrA();}
03506 
03507     /** Updates the operation of this flow. This method can be called only ONCE
03508       * for each flow. In case that doesn't suit you, delete the existing flow
03509       * and create a new one.
03510       */
03511     void setOperation(Operation* o) {if (o) setPtrA(o,o->getFlows());}
03512 
03513     /** Returns true if this flow consumes material from the buffer. */
03514     bool isConsumer() const {return quantity < 0;}
03515 
03516     /** Returns true if this flow produces material into the buffer. */
03517     bool isProducer() const {return quantity >= 0;}
03518 
03519     /** Returns the material flow PER UNIT of the operationplan. */
03520     double getQuantity() const {return quantity;}
03521 
03522     /** Updates the material flow PER UNIT of the operationplan. Existing
03523       * flowplans are NOT updated to take the new quantity in effect. Only new
03524       * operationplans and updates to existing ones will use the new quantity
03525       * value.
03526       */
03527     void setQuantity(double f) {quantity = f;}
03528 
03529     /** Returns the buffer. */
03530     Buffer* getBuffer() const {return getPtrB();}
03531 
03532     /** Updates the buffer of this flow. This method can be called only ONCE
03533       * for each flow. In case that doesn't suit you, delete the existing flow
03534       * and create a new one.
03535       */
03536     void setBuffer(Buffer* b) {if (b) setPtrB(b,b->getFlows());}
03537 
03538     /** Update the priority of a flow. */
03539     void setPriority(int i) {priority = i;}
03540 
03541     /** Return the priority of a flow. */
03542     int getPriority() const {return priority;}
03543 
03544     /** Returns true if there are alternates for this flow. */
03545     bool hasAlternates() const {return hasAlts;}
03546 
03547     /** Returns the flow of which this one is an alternate.<br>
03548       * NULL is return where there is none.
03549       */
03550     Flow* getAlternate() const {return altFlow;}
03551 
03552     /** Define the flow of which this one is an alternate. */
03553     DECLARE_EXPORT void setAlternate(Flow *);
03554 
03555     /** Define the flow of which this one is an alternate. */
03556     DECLARE_EXPORT void setAlternate(const string& n);
03557 
03558     /** Return the search mode. */
03559     SearchMode getSearch() const {return search;}
03560 
03561     /** Update the search mode. */
03562     void setSearch(const string a) {search = decodeSearchMode(a);}
03563 
03564     /** A flow is considered hidden when either its buffer or operation
03565       * are hidden. */
03566     virtual bool getHidden() const
03567     {
03568       return (getBuffer() && getBuffer()->getHidden())
03569           || (getOperation() && getOperation()->getHidden());
03570     }
03571 
03572     /** This method holds the logic the compute the date of a flowplan. */
03573     virtual Date getFlowplanDate(const FlowPlan*) const;
03574 
03575     /** This method holds the logic the compute the quantity of a flowplan. */
03576     virtual double getFlowplanQuantity(const FlowPlan*) const;
03577 
03578     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03579     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
03580     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
03581     static int initialize();
03582     static void writer(const MetaCategory*, XMLOutput*);
03583 
03584     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03585 
03586     virtual const MetaClass& getType() const {return *metadata;}
03587     static DECLARE_EXPORT const MetaCategory* metadata;
03588     virtual size_t getSize() const {return sizeof(Flow) + getName().size();}
03589 
03590   protected:
03591     /** Default constructor. */
03592     explicit Flow() : quantity(0.0), priority(1), hasAlts(false),
03593       altFlow(NULL), search(PRIORITY) {initType(metadata);}
03594 
03595   private:
03596     /** Verifies whether a flow meets all requirements to be valid. <br>
03597       * An exception is thrown if the flow is invalid.
03598       */
03599     DECLARE_EXPORT void validate(Action action);
03600 
03601     /** Quantity of the flow. */
03602     double quantity;
03603 
03604     /** Priority of the flow - used in case of alternate flows. */
03605     int priority;
03606 
03607     /** Flag that is set to true when a flow has alternates. */
03608     bool hasAlts;
03609 
03610     /** A flow representing the main flow of a set of alternate flows. */
03611     Flow* altFlow;
03612 
03613     /** Mode to select the preferred alternates. */
03614     SearchMode search;
03615 
03616     static PyObject* create(PyTypeObject* pytype, PyObject* args, PyObject* kwds);
03617     DECLARE_EXPORT PyObject* getattro(const Attribute&);
03618     DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
03619 };
03620 
03621 
03622 /** @brief This class defines a material flow to/from a buffer, linked with an
03623   * operation. This subclass represents a flow that is at the start date of
03624   * the operation.
03625   */
03626 class FlowStart : public Flow
03627 {
03628   public:
03629     /** Constructor. */
03630     explicit FlowStart(Operation* o, Buffer* b, double q) : Flow(o,b,q) {}
03631 
03632     /** Constructor. */
03633     explicit FlowStart(Operation* o, Buffer* b, double q, DateRange e) : Flow(o,b,q,e) {}
03634 
03635     /** This constructor is called from the plan begin_element function. */
03636     explicit FlowStart() {}
03637 
03638     virtual const MetaClass& getType() const {return *metadata;}
03639     static DECLARE_EXPORT const MetaClass* metadata;
03640     virtual size_t getSize() const {return sizeof(FlowStart);}
03641     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03642 };
03643 
03644 
03645 /** @brief This class defines a material flow to/from a buffer, linked with an
03646   * operation. This subclass represents a flow that is at end date of the
03647   * operation.
03648   */
03649 class FlowEnd : public Flow
03650 {
03651   public:
03652     /** Constructor. */
03653     explicit FlowEnd(Operation* o, Buffer* b, double q) : Flow(o,b,q) {}
03654 
03655     /** Constructor. */
03656     explicit FlowEnd(Operation* o, Buffer* b, double q, DateRange e) : Flow(o,b,q,e) {}
03657 
03658     /** This constructor is called from the plan begin_element function. */
03659     explicit FlowEnd() {}
03660 
03661     /** This method holds the logic the compute the date of a flowplan. */
03662     virtual Date getFlowplanDate(const FlowPlan* fl) const;
03663 
03664     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03665 
03666     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03667 
03668     virtual const MetaClass& getType() const {return *metadata;}
03669     static DECLARE_EXPORT const MetaClass* metadata;
03670     virtual size_t getSize() const {return sizeof(FlowEnd);}
03671 };
03672 
03673 
03674 /** @brief A flowplan represents a planned material flow in or out of a buffer.
03675   *
03676   * Flowplans are owned by operationplans, which manage a container to store
03677   * them.
03678   */
03679 class FlowPlan : public TimeLine<FlowPlan>::EventChangeOnhand, public PythonExtensionBase
03680 {
03681     friend class OperationPlan::FlowPlanIterator;
03682   private:
03683     /** Points to the flow instantiated by this flowplan. */
03684     const Flow *fl;
03685 
03686     /** Python interface method. */
03687     PyObject* getattro(const Attribute&);
03688 
03689     /** Points to the operationplan owning this flowplan. */
03690     OperationPlan *oper;
03691 
03692     /** Points to the next flowplan owned by the same operationplan. */
03693     FlowPlan *nextFlowPlan;
03694 
03695   public:
03696 
03697     static DECLARE_EXPORT const MetaCategory* metadata;
03698     static int initialize();
03699 
03700     /** Constructor. */
03701     explicit DECLARE_EXPORT FlowPlan(OperationPlan*, const Flow*);
03702 
03703     /** Returns the flow of which this is an plan instance. */
03704     const Flow* getFlow() const {return fl;}
03705 
03706     /** Returns the buffer. */
03707     const Buffer* getBuffer() const {return fl->getBuffer();}
03708 
03709     /** Update the flow of an already existing flowplan.<br>
03710       * The new flow must belong to the same operation.
03711       */
03712     DECLARE_EXPORT void setFlow(const Flow*);
03713 
03714     /** Returns the operationplan owning this flowplan. */
03715     OperationPlan* getOperationPlan() const {return oper;}
03716 
03717     /** Destructor. */
03718     virtual ~FlowPlan()
03719     {
03720       Buffer* b = getFlow()->getBuffer();
03721       b->setChanged();
03722       b->flowplans.erase(this);
03723     }
03724 
03725     /** Writing the element.
03726       * This method has the same prototype as a usual instance of the Object
03727       * class, but this is only superficial: FlowPlan isn't a subclass of
03728       * Object at all.
03729       */
03730     void DECLARE_EXPORT writeElement
03731     (XMLOutput*, const Keyword&, mode=DEFAULT) const;
03732 
03733     /** Updates the quantity of the flowplan by changing the quantity of the
03734       * operationplan owning this flowplan.<br>
03735       * The boolean parameter is used to control whether to round up (false)
03736       * or down (true) in case the operation quantity must be a multiple.
03737       */
03738     void setQuantity(double qty, bool b=false, bool u = true)
03739     {
03740       if (getFlow()->getEffective().within(getDate()))
03741         oper->setQuantity(qty / getFlow()->getQuantity(), b, u);
03742     }
03743 
03744     /** This function needs to be called whenever the flowplan date or
03745       * quantity are changed.
03746       */
03747     DECLARE_EXPORT void update();
03748 
03749     /** Return a pointer to the timeline data structure owning this flowplan. */
03750     TimeLine<FlowPlan>* getTimeLine() const
03751     {return &(getFlow()->getBuffer()->flowplans);}
03752 
03753     /** Returns true when the flowplan is hidden.<br>
03754       * This is determined by looking at whether the flow is hidden or not.
03755       */
03756     bool getHidden() const {return fl->getHidden();}
03757 };
03758 
03759 
03760 inline double Flow::getFlowplanQuantity(const FlowPlan* fl) const
03761 {
03762   return getEffective().within(fl->getDate()) ?
03763       fl->getOperationPlan()->getQuantity() * getQuantity() :
03764       0.0;
03765 }
03766 
03767 
03768 inline Date Flow::getFlowplanDate(const FlowPlan* fl) const
03769 {
03770   return fl->getOperationPlan()->getDates().getStart();
03771 }
03772 
03773 
03774 inline Date FlowEnd::getFlowplanDate(const FlowPlan* fl) const
03775 {
03776   return fl->getOperationPlan()->getDates().getEnd();
03777 }
03778 
03779 
03780 /** @brief This class is used to represent a matrix defining the changeover
03781   * times between setups.
03782   */
03783 class SetupMatrix : public HasName<SetupMatrix>
03784 {
03785   public:
03786     class RuleIterator; // Forward declaration
03787     /** @brief An specific changeover rule in a setup matrix. */
03788     class Rule : public Object
03789     {
03790         friend class RuleIterator;
03791         friend class SetupMatrix;
03792       public:
03793         /** Constructor. */
03794         DECLARE_EXPORT Rule(SetupMatrix *s, int p = 0);
03795 
03796         /** Destructor. */
03797         DECLARE_EXPORT ~Rule();
03798 
03799         virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03800         DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
03801         virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
03802         virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
03803         static int initialize();
03804 
03805         virtual const MetaClass& getType() const {return *metadata;}
03806         static DECLARE_EXPORT const MetaCategory* metadata;
03807 
03808         size_t getSize() const
03809         {return sizeof(Rule) + from.size() + to.size();}
03810 
03811         /** Update the priority.<br>
03812           * The priority value is a key field. If multiple rules have the
03813           * same priority a data exception is thrown.
03814           */
03815         DECLARE_EXPORT void setPriority(const int);
03816 
03817         /** Return the matrix owning this rule. */
03818         SetupMatrix* getSetupMatrix() const {return matrix;}
03819 
03820         /** Return the priority. */
03821         double getPriority() const {return priority;}
03822 
03823         /** Update the from setup. */
03824         void setFromSetup(const string f) {from = f;}
03825 
03826         /** Return the from setup. */
03827         const string& getFromSetup() const {return from;}
03828 
03829         /** Update the from setup. */
03830         void setToSetup(const string f) {to = f;}
03831 
03832         /** Return the from setup. */
03833         const string& getToSetup() const {return to;}
03834 
03835         /** Update the conversion duration. */
03836         void setDuration(const TimePeriod p) {duration = p;}
03837 
03838         /** Return the conversion duration. */
03839         TimePeriod getDuration() const {return duration;}
03840 
03841         /** Update the conversion cost. */
03842         void setCost(const double p) {cost = p;}
03843 
03844         /** Return the conversion cost. */
03845         double getCost() const {return cost;}
03846 
03847       private:
03848         /** Original setup. */
03849         string from;
03850 
03851         /** New setup. */
03852         string to;
03853 
03854         /** Changeover time. */
03855         TimePeriod duration;
03856 
03857         /** Changeover cost. */
03858         double cost;
03859 
03860         /** Priority of the rule.<br>
03861           * This field is the key field, i.e. within a setup matrix all rules
03862           * need to have different priorities.
03863           */
03864         int priority;
03865 
03866         /** Pointer to the owning matrix. */
03867         SetupMatrix *matrix;
03868 
03869         /** Pointer to the next rule in this matrix. */
03870         Rule *nextRule;
03871 
03872         /** Pointer to the previous rule in this matrix. */
03873         Rule *prevRule;
03874     };
03875 
03876     /** @brief An iterator class to go through all rules of a setup matrix. */
03877     class RuleIterator
03878     {
03879       private:
03880         Rule* curRule;
03881       public:
03882         /** Constructor. */
03883         RuleIterator(Rule* c = NULL) : curRule(c) {}
03884         bool operator != (const RuleIterator &b) const
03885         {return b.curRule != curRule;}
03886         bool operator == (const RuleIterator &b) const
03887         {return b.curRule == curRule;}
03888         RuleIterator& operator++()
03889         {if (curRule) curRule = curRule->nextRule; return *this;}
03890         RuleIterator operator++(int)
03891         {RuleIterator tmp = *this; ++*this; return tmp;}
03892         RuleIterator& operator--()
03893         {if(curRule) curRule = curRule->prevRule; return *this;}
03894         RuleIterator operator--(int)
03895         {RuleIterator tmp = *this; --*this; return tmp;}
03896         Rule* operator ->() const {return curRule;}
03897         Rule& operator *() const {return *curRule;}
03898     };
03899 
03900   public:
03901     /** Default constructor. */
03902     SetupMatrix(const string& n) : HasName<SetupMatrix>(n), firstRule(NULL) {}
03903 
03904     /** Destructor. */
03905     DECLARE_EXPORT ~SetupMatrix();
03906 
03907     /** This is a factory method that creates a new rule<br>
03908       * This method is intended to be used to create objects when reading
03909       * XML input data.
03910       */
03911     DECLARE_EXPORT Rule* createRule(const AttributeList&);
03912 
03913     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03914     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
03915     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
03916     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
03917     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
03918     static int initialize();
03919 
03920     virtual const MetaClass& getType() const {return *metadata;}
03921     static DECLARE_EXPORT const MetaCategory* metadata;
03922 
03923     virtual size_t getSize() const
03924     {
03925       size_t i = sizeof(SetupMatrix) + getName().size();
03926       for (RuleIterator j = beginRules(); j!= endRules(); ++j)
03927         i += j->getSize();
03928       return i;
03929     }
03930 
03931     size_t extrasize() const {return getName().size();}
03932 
03933     /** Returns an iterator to go through the list of buckets. */
03934     RuleIterator beginRules() const {return RuleIterator(firstRule);}
03935 
03936     /** Returns an iterator to go through the list of buckets. */
03937     RuleIterator endRules() const {return RuleIterator(NULL);}
03938 
03939     /** Python interface to add a new rule. */
03940     static DECLARE_EXPORT PyObject* addPythonRule(PyObject*, PyObject*, PyObject*);
03941 
03942     /** Computes the changeover time and cost between 2 setup values.
03943       *
03944       * To compute the time of a changeover the algorithm will evaluate all
03945       * rules in sequence (in order of priority).<br>
03946       * For a rule to match the changeover between the original setup X to
03947       * a new setup Y, two conditions need to be fulfilled:
03948       *  - The original setup X must match with the fromsetup of the rule.<br>
03949       *    If the fromsetup field is empty, it is considered a match.
03950       *  - The new setup Y must match with the tosetup of the rule.<br>
03951       *    If the tosetup field is empty, it is considered a match.
03952       * The wildcard characters * and ? can be used in the fromsetup and
03953       * tosetup fields.<br>
03954       * As soon as a matching rule is found, it is applied and subsequent
03955       * rules are not evaluated.<br>
03956       * If no matching rule is found, the changeover is not allowed: a NULL
03957       * pointer is returned.
03958       */
03959     DECLARE_EXPORT Rule* calculateSetup(const string, const string) const;
03960 
03961   private:
03962     /** Head of the list of rules. */
03963     Rule *firstRule;
03964 };
03965 
03966 
03967 /** @brief This class is the default implementation of the abstract
03968   * SetupMatrix class.
03969   */
03970 class SetupMatrixDefault : public SetupMatrix
03971 {
03972   public:
03973     explicit SetupMatrixDefault(const string& str) : SetupMatrix(str) {initType(metadata);}
03974     virtual const MetaClass& getType() const {return *metadata;}
03975     static DECLARE_EXPORT const MetaClass* metadata;
03976     virtual size_t getSize() const
03977     {return sizeof(SetupMatrixDefault) + SetupMatrix::extrasize();}
03978     static int initialize();
03979 };
03980 
03981 
03982 /** @brief This class represents a workcentre, a physical or logical
03983   * representation of capacity.
03984   */
03985 class Resource : public HasHierarchy<Resource>,
03986   public HasLevel, public Plannable, public HasDescription
03987 {
03988     friend class Load;
03989     friend class LoadPlan;
03990 
03991   public:
03992     /** The default time window before the ask date where we look for
03993       * available capacity. */
03994     static const long defaultMaxEarly = 100*86400L;
03995 
03996     /** Constructor. */
03997     explicit Resource(const string& str) : HasHierarchy<Resource>(str),
03998       size_max_cal(NULL), size_max(0), loc(NULL), cost(0.0), hidden(false), maxearly(defaultMaxEarly),
03999       setupmatrix(NULL) { setMaximum(1); };
04000 
04001     /** Destructor. */
04002     virtual DECLARE_EXPORT ~Resource();
04003 
04004     /** Updates the size of a resource, when it is time-dependent. */
04005     DECLARE_EXPORT void setMaximumCalendar(CalendarDouble*);
04006 
04007     /** Updates the size of a resource. */
04008     DECLARE_EXPORT void setMaximum(double);
04009 
04010     /** Return a pointer to the maximum capacity profile. */
04011     CalendarDouble* getMaximumCalendar() const {return size_max_cal;}
04012 
04013     /** Return a pointer to the maximum capacity. */
04014     double getMaximum() const {return size_max;}
04015 
04016     /** Returns the cost of using 1 unit of this resource for 1 hour.<br>
04017       * The default value is 0.0.
04018       */
04019     double getCost() const {return cost;}
04020 
04021     /** Update the cost of using 1 unit of this resource for 1 hour. */
04022     void setCost(const double c)
04023     {
04024       if (c >= 0) cost = c;
04025       else throw DataException("Resource cost must be positive");
04026     }
04027 
04028     typedef Association<Operation,Resource,Load>::ListB loadlist;
04029     typedef TimeLine<LoadPlan> loadplanlist;
04030 
04031     /** Returns a reference to the list of loadplans. */
04032     const loadplanlist& getLoadPlans() const {return loadplans;}
04033 
04034     /** Returns a reference to the list of loadplans. */
04035     loadplanlist& getLoadPlans() {return loadplans;}
04036 
04037     /** Returns a constant reference to the list of loads. It defines
04038       * which operations are using the resource.
04039       */
04040     const loadlist& getLoads() const {return loads;}
04041 
04042     /** Return the load that is associates a given operation with this
04043       * resource. Returns NULL is no such load exists. */
04044     Load* findLoad(const Operation* o, Date d) const
04045     {return loads.find(o,d);}
04046 
04047     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
04048     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
04049     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
04050     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
04051     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
04052 
04053     /** Initialize the class. */
04054     static int initialize();
04055 
04056     size_t extrasize() const
04057     {return getName().size() + HasDescription::extrasize() + setup.size();}
04058 
04059     /** Returns the location of this resource. */
04060     Location* getLocation() const {return loc;}
04061 
04062     /** Updates the location of this resource. */
04063     void setLocation(Location* i) {loc = i;}
04064 
04065     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
04066 
04067     /** Deletes all operationplans loading this resource. The boolean parameter
04068       * controls whether we delete also locked operationplans or not.
04069       */
04070     DECLARE_EXPORT void deleteOperationPlans(bool = false);
04071 
04072     /** Recompute the problems of this resource. */
04073     virtual DECLARE_EXPORT void updateProblems();
04074 
04075     /** Scan the setups of this resource. */
04076     virtual DECLARE_EXPORT void updateSetups(const LoadPlan* = NULL);
04077 
04078     void setHidden(bool b) {if (hidden!=b) setChanged(); hidden = b;}
04079     bool getHidden() const {return hidden;}
04080 
04081     virtual const MetaClass& getType() const {return *metadata;}
04082     static DECLARE_EXPORT const MetaCategory* metadata;
04083 
04084     /** Returns the maximum inventory buildup allowed in case of capacity
04085       * shortages. */
04086     TimePeriod getMaxEarly() const {return maxearly;}
04087 
04088     /** Updates the maximum inventory buildup allowed in case of capacity
04089       * shortages. */
04090     void setMaxEarly(TimePeriod c)
04091     {
04092       if (c >= 0L) maxearly = c;
04093       else throw DataException("MaxEarly must be positive");
04094     }
04095 
04096     /** Return a pointer to the setup matrix. */
04097     SetupMatrix* getSetupMatrix() const {return setupmatrix;}
04098 
04099     /** Update the reference to the setup matrix. */
04100     void setSetupMatrix(SetupMatrix *s) {setupmatrix = s;}
04101 
04102     /** Return the current setup. */
04103     const string& getSetup() const {return setup;}
04104 
04105     /** Update the current setup. */
04106     void setSetup(const string s) {setup = s;}
04107 
04108   private:
04109     /** This calendar is used to updates to the resource size. */
04110     CalendarDouble* size_max_cal;
04111 
04112     /** The maximum resource size.<br>
04113       * If a calendar is specified, this field is ignored.
04114       */
04115     double size_max;
04116 
04117     /** Stores the collection of all loadplans of this resource. */
04118     loadplanlist loadplans;
04119 
04120     /** This is a list of all load models that are linking this resource with
04121       * operations. */
04122     loadlist loads;
04123 
04124     /** A pointer to the location of the resource. */
04125     Location* loc;
04126 
04127     /** The cost of using 1 unit of this resource for 1 hour. */
04128     double cost;
04129 
04130     /** Specifies whether this resource is hidden for serialization. */
04131     bool hidden;
04132 
04133     /** Maximum inventory buildup allowed in case of capacity shortages. */
04134     TimePeriod maxearly;
04135 
04136     /** Reference to the setup matrix. */
04137     SetupMatrix *setupmatrix;
04138 
04139     /** Current setup. */
04140     string setup;
04141 };
04142 
04143 
04144 /** @brief This class is the default implementation of the abstract
04145   * Resource class.
04146   */
04147 class ResourceDefault : public Resource
04148 {
04149   public:
04150     explicit ResourceDefault(const string& str) : Resource(str) {initType(metadata);}
04151     virtual const MetaClass& getType() const {return *metadata;}
04152     static DECLARE_EXPORT const MetaClass* metadata;
04153     virtual size_t getSize() const
04154     {return sizeof(ResourceDefault) + Resource::extrasize();}
04155     static int initialize();
04156 };
04157 
04158 
04159 /** @brief This class represents a resource that'll never have any
04160   * capacity shortage. */
04161 class ResourceInfinite : public Resource
04162 {
04163   public:
04164     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
04165     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
04166     virtual const MetaClass& getType() const {return *metadata;}
04167     explicit ResourceInfinite(const string& c) : Resource(c)
04168     {setDetectProblems(false); initType(metadata);}
04169     static DECLARE_EXPORT const MetaClass* metadata;
04170     virtual size_t getSize() const
04171     {return sizeof(ResourceInfinite) + Resource::extrasize();}
04172     static int initialize();
04173 };
04174 
04175 
04176 /** @brief This class links a resource to a certain operation. */
04177 class Load
04178   : public Object, public Association<Operation,Resource,Load>::Node,
04179   public Solvable
04180 {
04181     friend class Resource;
04182     friend class Operation;
04183 
04184   public:
04185     /** Constructor. */
04186     explicit Load(Operation* o, Resource* r, double u)
04187       : priority(1), hasAlts(false), altLoad(NULL), search(PRIORITY)
04188     {
04189       setOperation(o);
04190       setResource(r);
04191       setQuantity(u);
04192       initType(metadata);
04193       try { validate(ADD); }
04194       catch (...)
04195       {
04196         if (getOperation()) getOperation()->loaddata.erase(this);
04197         if (getResource()) getResource()->loads.erase(this);
04198         resetReferenceCount();
04199         throw;
04200       }
04201     }
04202 
04203     /** Constructor. */
04204     explicit Load(Operation* o, Resource* r, double u, DateRange e)
04205       : priority(1), hasAlts(false), altLoad(NULL), search(PRIORITY)
04206     {
04207       setOperation(o);
04208       setResource(r);
04209       setQuantity(u);
04210       setEffective(e);
04211       initType(metadata);
04212       try { validate(ADD); }
04213       catch (...)
04214       {
04215         if (getOperation()) getOperation()->loaddata.erase(this);
04216         if (getResource()) getResource()->loads.erase(this);
04217         resetReferenceCount();
04218         throw;
04219       }
04220     }
04221 
04222     /** Destructor. */
04223     DECLARE_EXPORT ~Load();
04224 
04225     /** Returns the operation consuming the resource capacity. */
04226     Operation* getOperation() const {return getPtrA();}
04227 
04228     /** Updates the operation being loaded. This method can only be called
04229       * once for a load. */
04230     void setOperation(Operation* o) {if (o) setPtrA(o,o->getLoads());}
04231 
04232     /** Returns the capacity resource being consumed. */
04233     Resource* getResource() const {return getPtrB();}
04234 
04235     /** Updates the capacity being consumed. This method can only be called
04236       * once on a resource. */
04237     void setResource(Resource* r) {if (r) setPtrB(r,r->getLoads());}
04238 
04239     /** Returns how much capacity is consumed during the duration of the
04240       * operationplan. */
04241     double getQuantity() const {return qty;}
04242 
04243     /** Updates the quantity of the load.
04244       * @exception DataException When a negative number is passed.
04245       */
04246     void setQuantity(double f)
04247     {
04248       if (f < 0) throw DataException("Load quantity can't be negative");
04249       qty = f;
04250     }
04251 
04252     /** Update the priority of a load. */
04253     void setPriority(int i) {priority = i;}
04254 
04255     /** Return the priority of a load. */
04256     int getPriority() const {return priority;}
04257 
04258     /** Returns true if there are alternates for this load. */
04259     bool hasAlternates() const {return hasAlts;}
04260 
04261     /** Returns the load of which this one is an alternate.<br>
04262       * NULL is return where there is none.
04263       */
04264     Load* getAlternate() const {return altLoad;}
04265 
04266     /** Define the load of which this one is an alternate. */
04267     DECLARE_EXPORT void setAlternate(Load *);
04268 
04269     /** Define the load of which this one is an alternate. */
04270     DECLARE_EXPORT void setAlternate(const string& n);
04271 
04272     /** Update the required resource setup. */
04273     DECLARE_EXPORT void setSetup(const string);
04274 
04275     /** Return the required resource setup. */
04276     const string& getSetup() const {return setup;}
04277 
04278     /** This method holds the logic the compute the date of a loadplan. */
04279     virtual Date getLoadplanDate(const LoadPlan*) const;
04280 
04281     /** This method holds the logic the compute the quantity of a loadplan. */
04282     virtual double getLoadplanQuantity(const LoadPlan*) const;
04283 
04284     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
04285     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
04286     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
04287     DECLARE_EXPORT PyObject* getattro(const Attribute&);
04288     DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
04289     static int initialize();
04290     static void writer(const MetaCategory*, XMLOutput*);
04291 
04292     bool getHidden() const
04293     {
04294       return (getResource() && getResource()->getHidden())
04295           || (getOperation() && getOperation()->getHidden());
04296     }
04297     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
04298 
04299     virtual const MetaClass& getType() const {return *metadata;}
04300     static DECLARE_EXPORT const MetaCategory* metadata;
04301     virtual size_t getSize() const
04302     {return sizeof(Load) + getName().size() + getSetup().size();}
04303 
04304     /** Default constructor. */
04305     Load() : qty(1.0), priority(1), hasAlts(false), altLoad(NULL), search(PRIORITY)
04306     {initType(metadata);}
04307 
04308     /** Return the search mode. */
04309     SearchMode getSearch() const {return search;}
04310 
04311     /** Update the search mode. */
04312     void setSearch(const string a) {search = decodeSearchMode(a);}
04313 
04314   private:
04315     /** This method is called to check the validity of the object.<br>
04316       * An exception is thrown if the load is invalid.
04317       */
04318     DECLARE_EXPORT void validate(Action action);
04319 
04320     /** Stores how much capacity is consumed during the duration of an
04321       * operationplan. */
04322     double qty;
04323 
04324     /** Priority of the load - used in case of alternate loads. */
04325     int priority;
04326 
04327     /** Flag that is set to true when a load has alternates. */
04328     bool hasAlts;
04329 
04330     /** A load representing the main load of a set of alternates. */
04331     Load* altLoad;
04332 
04333     /** Required setup. */
04334     string setup;
04335 
04336     /** Mode to select the preferred alternates. */
04337     SearchMode search;
04338 
04339     /** Factory method. */
04340     static PyObject* create(PyTypeObject*, PyObject*, PyObject*);
04341 };
04342 
04343 
04344 
04345 /** @brief This is the (logical) top class of the complete model.
04346   *
04347   * This is a singleton class: only a single instance can be created.
04348   * The data model has other limitations that make it not obvious to support
04349   * building multiple models/plans in memory of the same application: e.g.
04350   * the operations, resources, problems, operationplans... etc are all
04351   * implemented in static, global lists. An entity can't be simply linked with
04352   * a particular plan if multiple ones would exist.
04353   */
04354 class Plan : public Plannable, public Object
04355 {
04356   private:
04357     /** Current Date of this plan. */
04358     Date cur_Date;
04359 
04360     /** A name for this plan. */
04361     string name;
04362 
04363     /** A getDescription of this plan. */
04364     string descr;
04365 
04366     /** Pointer to the singleton plan object. */
04367     static DECLARE_EXPORT Plan* thePlan;
04368 
04369     /** The only constructor of this class is made private. An object of this
04370       * class is created by the instance() member function.
04371       */
04372     Plan() : cur_Date(Date::now()) {initType(metadata);}
04373 
04374   public:
04375     /** Return a pointer to the singleton plan object.
04376       * The singleton object is created during the initialization of the
04377       * library.
04378       */
04379     static Plan& instance() {return *thePlan;}
04380 
04381     /** Destructor.
04382       * @warning In multi threaded applications, the destructor is never called
04383       * and the plan object leaks when we exit the application.
04384       * In single-threaded applications this function is called properly, when
04385       * the static plan variable is deleted.
04386       */
04387     DECLARE_EXPORT ~Plan();
04388 
04389     /** Returns the plan name. */
04390     const string& getName() const {return name;}
04391 
04392     /** Updates the plan name. */
04393     void setName(const string& s) {name = s;}
04394 
04395     /** Returns the current Date of the plan. */
04396     const Date & getCurrent() const {return cur_Date;}
04397 
04398     /** Updates the current date of the plan. This method can be relatively
04399       * heavy in a plan where operationplans already exist, since the
04400       * detection for BeforeCurrent problems needs to be rerun.
04401       */
04402     DECLARE_EXPORT void setCurrent(Date);
04403 
04404     /** Returns the description of the plan. */
04405     const string& getDescription() const {return descr;}
04406 
04407     /** Updates the description of the plan. */
04408     void setDescription(const string& str) {descr = str;}
04409 
04410     /** This method writes out the model information. Depending on a flag in
04411       * the XMLOutput object a complete model is written, or only the
04412       * dynamic plan information.
04413       * @see CommandSave, CommandSavePlan
04414       */
04415     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
04416     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
04417     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
04418     DECLARE_EXPORT PyObject* getattro(const Attribute&);
04419     DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
04420 
04421     /** Initialize the class. */
04422     static int initialize();
04423 
04424     virtual void updateProblems() {};
04425 
04426     /** This method basically solves the whole planning problem. */
04427     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
04428 
04429     const MetaClass& getType() const {return *metadata;}
04430     static DECLARE_EXPORT const MetaCategory* metadata;
04431     virtual size_t getSize() const
04432     {return sizeof(Plan) + name.size() + descr.size();}
04433 };
04434 
04435 
04436 /** @brief Represents the (independent) demand in the system. It can represent a
04437   * customer order or a forecast.
04438   *
04439   * This is an abstract class.
04440   */
04441 class Demand
04442   : public HasHierarchy<Demand>, public Plannable, public HasDescription
04443 {
04444   public:
04445     typedef slist<OperationPlan*> OperationPlan_list;
04446 
04447     /** Constructor. */
04448     explicit Demand(const string& str) : HasHierarchy<Demand>(str),
04449       it(NULL), oper(NULL), cust(NULL), qty(0.0), prio(0),
04450       maxLateness(TimePeriod::MAX), minShipment(1), hidden(false) {}
04451 
04452     /** Destructor. Deleting the demand will also delete all delivery operation
04453       * plans (including locked ones). */
04454     virtual ~Demand()
04455     {
04456       deleteOperationPlans(true);
04457     }
04458 
04459     /** Returns the quantity of the demand. */
04460     double getQuantity() const {return qty;}
04461 
04462     /** Updates the quantity of the demand. The quantity must be be greater
04463       * than or equal to 0. */
04464     virtual DECLARE_EXPORT void setQuantity(double);
04465 
04466     /** Returns the priority of the demand.<br>
04467       * Lower numbers indicate a higher priority level.
04468       */
04469     int getPriority() const {return prio;}
04470 
04471     /** Updates the due date of the demand.<br>
04472       * Lower numbers indicate a higher priority level.
04473       */
04474     virtual void setPriority(int i) {prio=i; setChanged();}
04475 
04476     /** Returns the item/product being requested. */
04477     Item* getItem() const {return it;}
04478 
04479     /** Updates the item/product being requested. */
04480     virtual void setItem(Item *i) {it=i; setChanged();}
04481 
04482     /** This fields points to an operation that is to be used to plan the
04483       * demand. By default, the field is left to NULL and the demand will then
04484       * be planned using the delivery operation of its item.
04485       * @see Item::getDelivery()
04486       */
04487     Operation* getOperation() const {return oper;}
04488 
04489     /** This function returns the operation that is to be used to satisfy this
04490       * demand. In sequence of priority this goes as follows:
04491       *   1) If the "operation" field on the demand is set, use it.
04492       *   2) Otherwise, use the "delivery" field of the requested item.
04493       *   3) Else, return NULL. This demand can't be satisfied!
04494       */
04495     DECLARE_EXPORT Operation* getDeliveryOperation() const;
04496 
04497     /** Returns the cluster which this demand belongs to. */
04498     int getCluster() const
04499     {
04500       Operation* o = getDeliveryOperation();
04501       return o ? o->getCluster() : 0;
04502     }
04503 
04504     /** Updates the operation being used to plan the demand. */
04505     virtual void setOperation(Operation* o) {oper=o; setChanged();}
04506 
04507     /** Returns the delivery operationplan list. */
04508     DECLARE_EXPORT const OperationPlan_list& getDelivery() const;
04509 
04510     /** Returns the latest delivery operationplan. */
04511     DECLARE_EXPORT OperationPlan* getLatestDelivery() const;
04512 
04513     /** Returns the earliest delivery operationplan. */
04514     DECLARE_EXPORT OperationPlan* getEarliestDelivery() const;
04515 
04516     /** Adds a delivery operationplan for this demand. */
04517     DECLARE_EXPORT void addDelivery(OperationPlan *o);
04518 
04519     /** Removes a delivery operationplan for this demand. */
04520     DECLARE_EXPORT void removeDelivery(OperationPlan *o);
04521 
04522     /** Deletes all delivery operationplans of this demand.<br>
04523       * The (optional) boolean parameter controls whether we delete also locked
04524       * operationplans or not.<br>
04525       * The second (optional) argument is a command list that can be used to
04526       * remove the operationplans in an undo-able way.
04527       */
04528     DECLARE_EXPORT void deleteOperationPlans
04529     (bool deleteLockedOpplans = false, CommandManager* = NULL);
04530 
04531     /** Returns the due date of the demand. */
04532     const Date& getDue() const {return dueDate;}
04533 
04534     /** Updates the due date of the demand. */
04535     virtual void setDue(Date d) {dueDate = d; setChanged();}
04536 
04537     /** Returns the customer. */
04538     Customer* getCustomer() const {return cust;}
04539 
04540     /** Updates the customer. */
04541     virtual void setCustomer(Customer* c) {cust = c; setChanged();}
04542 
04543     /** Return a reference to the constraint list. */
04544     const Problem::List& getConstraints() const {return constraints;}
04545 
04546     /** Return a reference to the constraint list. */
04547     Problem::List& getConstraints() {return constraints;}
04548 
04549     /** Returns the total amount that has been planned. */
04550     DECLARE_EXPORT double getPlannedQuantity() const;
04551 
04552     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
04553     virtual DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
04554     virtual DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
04555     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
04556     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
04557     static int initialize();
04558 
04559     size_t extrasize() const
04560     {
04561       return getName().size() + HasDescription::extrasize()
04562           + sizeof(void*) * 2 * deli.size();
04563     }
04564 
04565     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
04566 
04567     /** Return the maximum delay allowed in satisfying this demand.<br>
04568       * The default value is infinite.
04569       */
04570     TimePeriod getMaxLateness() const {return maxLateness;}
04571 
04572     /** Updates the maximum allowed lateness for this demand.<br>
04573       * The default value is infinite.<br>
04574       * The argument must be a positive time period.
04575       */
04576     virtual void setMaxLateness(TimePeriod m)
04577     {
04578       if (m < 0L)
04579         throw DataException("The maximum demand lateness must be positive");
04580       maxLateness = m;
04581     }
04582 
04583     /** Return the minimum shipment quantity allowed in satisfying this
04584       * demand.<br>
04585       * The default value is 1.
04586       */
04587     double getMinShipment() const {return minShipment;}
04588 
04589     /** Updates the maximum allowed lateness for this demand.<br>
04590       * The default value is infinite.<br>
04591       * The argument must be a positive time period.
04592       */
04593     virtual void setMinShipment(double m)
04594     {
04595       if (m < 0.0)
04596         throw DataException("The minumum demand shipment quantity must be positive");
04597       minShipment = m;
04598     }
04599 
04600     /** Recompute the problems. */
04601     virtual DECLARE_EXPORT void updateProblems();
04602 
04603     /** Specifies whether of not this demand is to be hidden from
04604       * serialization. The default value is false. */
04605     void setHidden(bool b) {hidden = b;}
04606 
04607     /** Returns true if this demand is to be hidden from serialization. */
04608     bool getHidden() const {return hidden;}
04609 
04610     virtual const MetaClass& getType() const {return *metadata;}
04611     static DECLARE_EXPORT const MetaCategory* metadata;
04612 
04613   private:
04614     /** Requested item. */
04615     Item *it;
04616 
04617     /** Delivery Operation. Can be left NULL, in which case the delivery
04618       * operation can be specified on the requested item. */
04619     Operation *oper;
04620 
04621     /** Customer creating this demand. */
04622     Customer *cust;
04623 
04624     /** Requested quantity. Only positive numbers are allowed. */
04625     double qty;
04626 
04627     /** Priority. Lower numbers indicate a higher priority level.*/
04628     int prio;
04629 
04630     /** Due date. */
04631     Date dueDate;
04632 
04633     /** Maximum lateness allowed when planning this demand.<br>
04634       * The default value is TimePeriod::MAX.
04635       */
04636     TimePeriod maxLateness;
04637 
04638     /** Minimum size for a delivery operation plan satisfying this demand. */
04639     double minShipment;
04640 
04641     /** Hide this demand or not. */
04642     bool hidden;
04643 
04644     /** A list of operation plans to deliver this demand. */
04645     OperationPlan_list deli;
04646 
04647     /** A list of constraints preventing this demand from being planned in
04648       * full and on time. */
04649     Problem::List constraints;
04650 };
04651 
04652 
04653 /** @brief This class is the default implementation of the abstract
04654   * Demand class. */
04655 class DemandDefault : public Demand
04656 {
04657   public:
04658     explicit DemandDefault(const string& str) : Demand(str) {initType(metadata);}
04659     virtual const MetaClass& getType() const {return *metadata;}
04660     static DECLARE_EXPORT const MetaClass* metadata;
04661     virtual size_t getSize() const
04662     {return sizeof(DemandDefault) + Demand::extrasize();}
04663     static int initialize();
04664 };
04665 
04666 
04667 /** @brief This class represents the resource capacity of an operationplan.
04668   *
04669   * For both the start and the end date of the operationplan, a loadplan
04670   * object is created. These are then inserted in the timeline structure
04671   * associated with a resource.
04672   */
04673 class LoadPlan : public TimeLine<LoadPlan>::EventChangeOnhand, public PythonExtensionBase
04674 {
04675     friend class OperationPlan::LoadPlanIterator;
04676   public:
04677     /** Public constructor.<br>
04678       * This constructor constructs the starting loadplan and will
04679       * also call a private constructor to creates the ending loadplan.
04680       * In other words, a single call to the constructor will create
04681       * two loadplan objects.
04682       */
04683     explicit DECLARE_EXPORT LoadPlan(OperationPlan*, const Load*);
04684 
04685     /** Return the operationplan owning this loadplan. */
04686     OperationPlan* getOperationPlan() const {return oper;}
04687 
04688     /** Return the load of which this is a plan instance. */
04689     const Load* getLoad() const {return ld;}
04690 
04691     /** Return the resource. */
04692     const Resource* getResource() const {return ld->getResource();}
04693 
04694     /** Update the load of an already existing flowplan.<br>
04695       * The new load must belong to the same operation.
04696       */
04697     DECLARE_EXPORT void setLoad(const Load*);
04698 
04699     /** Return true when this loadplan marks the start of an operationplan. */
04700     bool isStart() const {return start_or_end == START;}
04701 
04702     /** Destructor. */
04703     DECLARE_EXPORT virtual ~LoadPlan();
04704 
04705     /** This function needs to be called whenever the loadplan date or
04706       * quantity are changed.
04707       */
04708     DECLARE_EXPORT void update();
04709 
04710     /** Return a pointer to the timeline data structure owning this loadplan. */
04711     TimeLine<LoadPlan>* getTimeLine() const
04712     {return &(ld->getResource()->loadplans);}
04713 
04714     /** Returns the current setup of the resource.<br>
04715       * When the argument is true (= default) the current setup is returned.<br>
04716       * When the argument is false the setup just before the loadplan is returned.
04717       */
04718     DECLARE_EXPORT const string& getSetup(bool = true) const;
04719 
04720     /** Returns true when the loadplan is hidden.<br>
04721       * This is determined by looking at whether the load is hidden or not.
04722       */
04723     bool getHidden() const {return ld->getHidden();}
04724 
04725     /** Each operationplan has 2 loadplans per load: one at the start,
04726       * when the capacity consumption starts, and one at the end, when the
04727       * capacity consumption ends.<br>
04728       * This method returns the "companion" loadplan. It is not very
04729       * scalable: the performance is linear with the number of loadplans
04730       * on the resource.
04731       */
04732     DECLARE_EXPORT LoadPlan* getOtherLoadPlan() const;
04733 
04734     static int initialize();
04735     static DECLARE_EXPORT const MetaCategory* metadata;
04736     PyObject* getattro(const Attribute&);
04737 
04738   private:
04739     /** Private constructor. It is called from the public constructor.<br>
04740       * The public constructor constructs the starting loadplan, while this
04741       * constructor creates the ending loadplan.
04742       */
04743     DECLARE_EXPORT LoadPlan(OperationPlan*, const Load*, LoadPlan*);
04744 
04745     /** This type is used to differentiate loadplans aligned with the START date
04746       * or the END date of operationplan. */
04747     enum type {START, END};
04748 
04749     /** Is this loadplan a starting one or an ending one. */
04750     type start_or_end;
04751 
04752     /** A pointer to the load model. */
04753     const Load *ld;
04754 
04755     /** A pointer to the operationplan owning this loadplan. */
04756     OperationPlan *oper;
04757 
04758     /** Points to the next loadplan owned by the same operationplan. */
04759     LoadPlan *nextLoadPlan;
04760 };
04761 
04762 
04763 inline Date Load::getLoadplanDate(const LoadPlan* lp) const
04764 {
04765   const DateRange & dr = lp->getOperationPlan()->getDates();
04766   if (lp->isStart())
04767     return dr.getStart() > getEffective().getStart() ?
04768         dr.getStart() :
04769         getEffective().getStart();
04770   else
04771     return dr.getEnd() < getEffective().getEnd() ?
04772         dr.getEnd() :
04773         getEffective().getEnd();
04774 }
04775 
04776 
04777 inline double Load::getLoadplanQuantity(const LoadPlan* lp) const
04778 {
04779   if (!lp->getOperationPlan()->getDates().overlap(getEffective())
04780       && (lp->getOperationPlan()->getDates().getDuration()
04781           || !getEffective().within(lp->getOperationPlan()->getDates().getStart())))
04782     // Load is not effective during this time.
04783     // The extra check is required to make sure that zero duration operationplans
04784     // operationplans don't get resized to 0
04785     return 0.0;
04786   return lp->isStart() ? getQuantity() : -getQuantity();
04787 }
04788 
04789 
04790 
04791 /** @brief A problem of this class is created when an operationplan is being
04792   * planned in the past, i.e. it starts before the "current" date of
04793   * the plan.
04794   */
04795 class ProblemBeforeCurrent : public Problem
04796 {
04797   public:
04798     string getDescription() const
04799     {
04800       ostringstream ch;
04801       ch << "Operation '"
04802           << (oper ? oper : static_cast<OperationPlan*>(getOwner())->getOperation())
04803           << "' planned in the past";
04804       return ch.str();
04805     }
04806     bool isFeasible() const {return false;}
04807     double getWeight() const
04808     {return oper ? state.quantity : dynamic_cast<OperationPlan*>(getOwner())->getQuantity();}
04809     explicit ProblemBeforeCurrent(OperationPlan* o, bool add = true) : Problem(o), oper(NULL)
04810     {if (add) addProblem();}
04811     explicit ProblemBeforeCurrent(Operation* o, Date st, Date nd, double q)
04812       : oper(o), state(st, nd, q) {}
04813     ~ProblemBeforeCurrent() {removeProblem();}
04814     string getEntity() const {return "operation";}
04815     Object* getOwner() const
04816     {return oper ? static_cast<Object*>(oper) : dynamic_cast<OperationPlan*>(owner);}
04817     const DateRange getDates() const
04818     {
04819       if (oper) return DateRange(state.start, state.end);
04820       OperationPlan *o = dynamic_cast<OperationPlan*>(getOwner());
04821       if (o->getDates().getEnd() > Plan::instance().getCurrent())
04822         return DateRange(o->getDates().getStart(),
04823             Plan::instance().getCurrent());
04824       else
04825         return DateRange(o->getDates().getStart(),
04826             o->getDates().getEnd());
04827     }
04828     size_t getSize() const {return sizeof(ProblemBeforeCurrent);}
04829 
04830     /** Return a reference to the metadata structure. */
04831     const MetaClass& getType() const {return *metadata;}
04832 
04833     /** Storing metadata on this class. */
04834     static DECLARE_EXPORT const MetaClass* metadata;
04835 
04836   private:
04837     Operation* oper;
04838     OperationPlanState state;
04839 };
04840 
04841 
04842 /** @brief A problem of this class is created when an operationplan is being
04843   * planned before its fence date, i.e. it starts 1) before the "current"
04844   * date of the plan plus the release fence of the operation and 2) after the
04845   * current date of the plan.
04846   */
04847 class ProblemBeforeFence : public Problem
04848 {
04849   public:
04850     string getDescription() const
04851     {
04852       ostringstream ch;
04853       ch << "Operation '"
04854           << (oper ? oper : static_cast<OperationPlan*>(getOwner())->getOperation())
04855           << "' planned before fence";
04856       return ch.str();
04857     }
04858     bool isFeasible() const {return true;}
04859     double getWeight() const
04860     {return oper ? state.quantity : static_cast<OperationPlan*>(getOwner())->getQuantity();}
04861     explicit ProblemBeforeFence(OperationPlan* o, bool add = true)
04862       : Problem(o), oper(NULL)
04863     {if (add) addProblem();}
04864     explicit ProblemBeforeFence(Operation* o, Date st, Date nd, double q)
04865       : oper(o), state(st, nd, q) {}
04866     ~ProblemBeforeFence() {removeProblem();}
04867     string getEntity() const {return "operation";}
04868     Object* getOwner() const
04869     {return oper ? static_cast<Object*>(oper) : dynamic_cast<OperationPlan*>(owner);}
04870     const DateRange getDates() const
04871     {
04872       if (oper) return DateRange(state.start, state.end);
04873       OperationPlan *o = dynamic_cast<OperationPlan*>(owner);
04874       if (o->getDates().getEnd() > Plan::instance().getCurrent()
04875           + o->getOperation()->getFence())
04876         return DateRange(o->getDates().getStart(),
04877             Plan::instance().getCurrent() + o->getOperation()->getFence());
04878       else
04879         return DateRange(o->getDates().getStart(),
04880             o->getDates().getEnd());
04881     }
04882     size_t getSize() const {return sizeof(ProblemBeforeFence);}
04883 
04884     /** Return a reference to the metadata structure. */
04885     const MetaClass& getType() const {return *metadata;}
04886 
04887     /** Storing metadata on this class. */
04888     static DECLARE_EXPORT const MetaClass* metadata;
04889 
04890   private:
04891     Operation* oper;
04892     OperationPlanState state;
04893 };
04894 
04895 
04896 /** @brief A problem of this class is created when the sequence of two
04897   * operationplans in a routing isn't respected.
04898   */
04899 class ProblemPrecedence : public Problem
04900 {
04901   public:
04902     string getDescription() const
04903     {
04904       OperationPlan *o = static_cast<OperationPlan*>(getOwner());
04905       if (!o->nextsubopplan)
04906         return string("Bogus precedence problem on '")
04907             + o->getOperation()->getName() + "'";
04908       else
04909         return string("Operation '") + o->getOperation()->getName()
04910             + "' starts before operation '"
04911             + o->nextsubopplan->getOperation()->getName() +"' ends";
04912     }
04913     bool isFeasible() const {return false;}
04914     /** The weight of the problem is equal to the duration in days. */
04915     double getWeight() const
04916     {
04917       return static_cast<double>(getDates().getDuration()) / 86400;
04918     }
04919     explicit ProblemPrecedence(OperationPlan* o, bool add = true) : Problem(o)
04920     {if (add) addProblem();}
04921     ~ProblemPrecedence() {removeProblem();}
04922     string getEntity() const {return "operation";}
04923     Object* getOwner() const {return dynamic_cast<OperationPlan*>(owner);}
04924     const DateRange getDates() const
04925     {
04926       OperationPlan *o = static_cast<OperationPlan*>(getOwner());
04927       return DateRange(o->nextsubopplan->getDates().getStart(),
04928           o->getDates().getEnd());
04929     }
04930 
04931     /** Return a reference to the metadata structure. */
04932     const MetaClass& getType() const {return *metadata;}
04933 
04934     /** Storing metadata on this class. */
04935     static DECLARE_EXPORT const MetaClass* metadata;
04936     size_t getSize() const {return sizeof(ProblemPrecedence);}
04937 };
04938 
04939 
04940 /** @brief A Problem of this class is created in the model when a new demand is
04941   * brought in the system, but it hasn't been planned yet.
04942   *
04943   * As a special case, a demand with a requested quantity of 0.0 doesn't create
04944   * this type of problem.
04945   */
04946 class ProblemDemandNotPlanned : public Problem
04947 {
04948   public:
04949     string getDescription() const
04950     {return string("Demand '") + getDemand()->getName() + "' is not planned";}
04951     bool isFeasible() const {return false;}
04952     double getWeight() const {return getDemand()->getQuantity();}
04953     explicit ProblemDemandNotPlanned(Demand* d, bool add = true) : Problem(d)
04954     {if (add) addProblem();}
04955     ~ProblemDemandNotPlanned() {removeProblem();}
04956     string getEntity() const {return "demand";}
04957     const DateRange getDates() const
04958     {return DateRange(getDemand()->getDue(),getDemand()->getDue());}
04959     Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
04960     Demand* getDemand() const {return dynamic_cast<Demand*>(owner);}
04961     size_t getSize() const {return sizeof(ProblemDemandNotPlanned);}
04962 
04963     /** Return a reference to the metadata structure. */
04964     const MetaClass& getType() const {return *metadata;}
04965 
04966     /** Storing metadata on this class. */
04967     static DECLARE_EXPORT const MetaClass* metadata;
04968 };
04969 
04970 
04971 /** @brief A problem of this class is created when a demand is satisfied later
04972   * than the accepted tolerance after its due date.
04973   */
04974 class ProblemLate : public Problem
04975 {
04976   public:
04977     DECLARE_EXPORT string getDescription() const;
04978     bool isFeasible() const {return true;}
04979 
04980     /** The weight is equal to the delay, expressed in days.<br>
04981       * The quantity being delayed is not included.
04982       */
04983     double getWeight() const
04984     {
04985       assert(getDemand() && !getDemand()->getDelivery().empty());
04986       return static_cast<double>(DateRange(
04987           getDemand()->getDue(),
04988           getDemand()->getLatestDelivery()->getDates().getEnd()
04989           ).getDuration()) / 86400;
04990     }
04991 
04992     /** Constructor. */
04993     explicit ProblemLate(Demand* d, bool add = true) : Problem(d)
04994     {if (add) addProblem();}
04995 
04996     /** Destructor. */
04997     ~ProblemLate() {removeProblem();}
04998 
04999     const DateRange getDates() const
05000     {
05001       assert(getDemand() && !getDemand()->getDelivery().empty());
05002       return DateRange(getDemand()->getDue(),
05003           getDemand()->getLatestDelivery()->getDates().getEnd());
05004     }
05005     Demand* getDemand() const {return dynamic_cast<Demand*>(getOwner());}
05006     size_t getSize() const {return sizeof(ProblemLate);}
05007     string getEntity() const {return "demand";}
05008     Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
05009 
05010     /** Return a reference to the metadata structure. */
05011     const MetaClass& getType() const {return *metadata;}
05012 
05013     /** Storing metadata on this class. */
05014     static DECLARE_EXPORT const MetaClass* metadata;
05015 };
05016 
05017 
05018 /** @brief A problem of this class is created when a demand is planned earlier
05019   * than the accepted tolerance before its due date.
05020   */
05021 class ProblemEarly : public Problem
05022 {
05023   public:
05024     DECLARE_EXPORT string getDescription() const;
05025     bool isFeasible() const {return true;}
05026     double getWeight() const
05027     {
05028       assert(getDemand() && !getDemand()->getDelivery().empty());
05029       return static_cast<double>(DateRange(
05030           getDemand()->getDue(),
05031           getDemand()->getEarliestDelivery()->getDates().getEnd()
05032           ).getDuration()) / 86400;
05033     }
05034     explicit ProblemEarly(Demand* d, bool add = true) : Problem(d)
05035     {if (add) addProblem();}
05036     ~ProblemEarly() {removeProblem();}
05037     string getEntity() const {return "demand";}
05038     Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
05039     const DateRange getDates() const
05040     {
05041       assert(getDemand() && !getDemand()->getDelivery().empty());
05042       return DateRange(getDemand()->getDue(),
05043           getDemand()->getEarliestDelivery()->getDates().getEnd());
05044     }
05045     Demand* getDemand() const {return dynamic_cast<Demand*>(getOwner());}
05046     size_t getSize() const {return sizeof(ProblemEarly);}
05047 
05048     /** Return a reference to the metadata structure. */
05049     const MetaClass& getType() const {return *metadata;}
05050 
05051     /** Storing metadata on this class. */
05052     static DECLARE_EXPORT const MetaClass* metadata;
05053 };
05054 
05055 
05056 /** @brief A Problem of this class is created in the model when a data exception
05057   * prevents planning of certain objects
05058   */
05059 class ProblemInvalidData : public Problem
05060 {
05061   public:
05062     string getDescription() const {return description;}
05063     bool isFeasible() const {return false;}
05064     double getWeight() const {return qty;}
05065     explicit ProblemInvalidData(HasProblems* o, string d, string e,
05066         Date st, Date nd, double q, bool add = true)
05067       : Problem(o), description(d), entity(e), dates(st,nd), qty(q)
05068     {if (add) addProblem();}
05069     ~ProblemInvalidData() {removeProblem();}
05070     string getEntity() const {return entity;}
05071     const DateRange getDates() const {return dates;}
05072     Object* getOwner() const
05073     {
05074       if (entity == "demand") return dynamic_cast<Demand*>(owner);
05075       if (entity == "buffer") return dynamic_cast<Buffer*>(owner);
05076       if (entity == "resource") return dynamic_cast<Resource*>(owner);
05077       if (entity == "operation") return dynamic_cast<Operation*>(owner);
05078       throw LogicException("Unknown problem entity type");
05079     }
05080     size_t getSize() const
05081     {return sizeof(ProblemInvalidData) + description.size() + entity.size();}
05082 
05083     /** Return a reference to the metadata structure. */
05084     const MetaClass& getType() const {return *metadata;}
05085 
05086     /** Storing metadata on this class. */
05087     static DECLARE_EXPORT const MetaClass* metadata;
05088 
05089   private:
05090     /** Description of the data issue. */
05091     string description;
05092     string entity;
05093     DateRange dates;
05094     double qty;
05095 };
05096 
05097 
05098 /** @brief A problem of this class is created when a demand is planned for less than
05099   * the requested quantity.
05100   */
05101 class ProblemShort : public Problem
05102 {
05103   public:
05104     string getDescription() const
05105     {
05106       ostringstream ch;
05107       ch << "Demand '" << getDemand()->getName() << "' planned "
05108           << (getDemand()->getQuantity() - getDemand()->getPlannedQuantity())
05109           << " units short";
05110       return ch.str();
05111     }
05112     bool isFeasible() const {return true;}
05113     double getWeight() const
05114     {return getDemand()->getQuantity() - getDemand()->getPlannedQuantity();}
05115     explicit ProblemShort(Demand* d, bool add = true) : Problem(d)
05116     {if (add) addProblem();}
05117     ~ProblemShort() {removeProblem();}
05118     string getEntity() const {return "demand";}
05119     const DateRange getDates() const
05120     {return DateRange(getDemand()->getDue(), getDemand()->getDue());}
05121     Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
05122     Demand* getDemand() const {return dynamic_cast<Demand*>(owner);}
05123     size_t getSize() const {return sizeof(ProblemShort);}
05124 
05125     /** Return a reference to the metadata structure. */
05126     const MetaClass& getType() const {return *metadata;}
05127 
05128     /** Storing metadata on this class. */
05129     static DECLARE_EXPORT const MetaClass* metadata;
05130 };
05131 
05132 
05133 /** @brief A problem of this class is created when a demand is planned for more
05134   * than the requested quantity.
05135   */
05136 class ProblemExcess : public Problem
05137 {
05138   public:
05139     string getDescription() const
05140     {
05141       ostringstream ch;
05142       ch << "Demand '" << getDemand()->getName() << "' planned "
05143           << (getDemand()->getPlannedQuantity() - getDemand()->getQuantity())
05144           << " units excess";
05145       return ch.str();
05146     }
05147     bool isFeasible() const {return true;}
05148     double getWeight() const
05149     {return getDemand()->getPlannedQuantity() - getDemand()->getQuantity();}
05150     explicit ProblemExcess(Demand* d, bool add = true) : Problem(d)
05151     {if (add) addProblem();}
05152     string getEntity() const {return "demand";}
05153     Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
05154     ~ProblemExcess() {removeProblem();}
05155     const DateRange getDates() const
05156     {return DateRange(getDemand()->getDue(), getDemand()->getDue());}
05157     Demand* getDemand() const {return dynamic_cast<Demand*>(getOwner());}
05158     size_t getSize() const {return sizeof(ProblemExcess);}
05159 
05160     /** Return a reference to the metadata structure. */
05161     const MetaClass& getType() const {return *metadata;}
05162 
05163     /** Storing metadata on this class. */
05164     static DECLARE_EXPORT const MetaClass* metadata;
05165 };
05166 
05167 
05168 /** @brief A problem of this class is created when a resource is being
05169   * overloaded during a certain period of time.
05170   */
05171 class ProblemCapacityOverload : public Problem
05172 {
05173   public:
05174     DECLARE_EXPORT string getDescription() const;
05175     bool isFeasible() const {return false;}
05176     double getWeight() const {return qty;}
05177     ProblemCapacityOverload(Resource* r, Date st, Date nd, double q, bool add = true)
05178       : Problem(r), qty(q), dr(st,nd) {if (add) addProblem();}
05179     ~ProblemCapacityOverload() {removeProblem();}
05180     string getEntity() const {return "capacity";}
05181     Object* getOwner() const {return dynamic_cast<Resource*>(owner);}
05182     const DateRange getDates() const {return dr;}
05183     Resource* getResource() const {return dynamic_cast<Resource*>(getOwner());}
05184     size_t getSize() const {return sizeof(ProblemCapacityOverload);}
05185 
05186     /** Return a reference to the metadata structure. */
05187     const MetaClass& getType() const {return *metadata;}
05188 
05189     /** Storing metadata on this class. */
05190     static DECLARE_EXPORT const MetaClass* metadata;
05191 
05192   private:
05193     /** Overload quantity. */
05194     double qty;
05195 
05196     /** The daterange of the problem. */
05197     DateRange dr;
05198 };
05199 
05200 
05201 /** @brief A problem of this class is created when a resource is loaded below
05202   * its minimum during a certain period of time.
05203   */
05204 class ProblemCapacityUnderload : public Problem
05205 {
05206   public:
05207     DECLARE_EXPORT string getDescription() const;
05208     bool isFeasible() const {return true;}
05209     double getWeight() const {return qty;}
05210     ProblemCapacityUnderload(Resource* r, DateRange d, double q, bool add = true)
05211       : Problem(r), qty(q), dr(d) {if (add) addProblem();}
05212     ~ProblemCapacityUnderload() {removeProblem();}
05213     string getEntity() const {return "capacity";}
05214     Object* getOwner() const {return dynamic_cast<Resource*>(owner);}
05215     const DateRange getDates() const {return dr;}
05216     Resource* getResource() const {return dynamic_cast<Resource*>(getOwner());}
05217     size_t getSize() const {return sizeof(ProblemCapacityUnderload);}
05218 
05219     /** Return a reference to the metadata structure. */
05220     const MetaClass& getType() const {return *metadata;}
05221 
05222     /** Storing metadata on this class. */
05223     static DECLARE_EXPORT const MetaClass* metadata;
05224 
05225   private:
05226     /** Underload quantity. */
05227     double qty;
05228 
05229     /** The daterange of the problem. */
05230     DateRange dr;
05231 };
05232 
05233 
05234 /** @brief A problem of this class is created when a buffer is having a
05235   * material shortage during a certain period of time.
05236   */
05237 class ProblemMaterialShortage : public Problem
05238 {
05239   public:
05240     DECLARE_EXPORT string getDescription() const;
05241     bool isFeasible() const {return false;}
05242     double getWeight() const {return qty;}
05243     ProblemMaterialShortage(Buffer* b, Date st, Date nd, double q, bool add = true)
05244       : Problem(b), qty(q), dr(st,nd) {if (add) addProblem();}
05245     string getEntity() const {return "material";}
05246     Object* getOwner() const {return dynamic_cast<Buffer*>(owner);}
05247     ~ProblemMaterialShortage() {removeProblem();}
05248     const DateRange getDates() const {return dr;}
05249     Buffer* getBuffer() const {return dynamic_cast<Buffer*>(getOwner());}
05250     size_t getSize() const {return sizeof(ProblemMaterialShortage);}
05251 
05252     /** Return a reference to the metadata structure. */
05253     const MetaClass& getType() const {return *metadata;}
05254 
05255     /** Storing metadata on this class. */
05256     static DECLARE_EXPORT const MetaClass* metadata;
05257 
05258   private:
05259     /** Shortage quantity. */
05260     double qty;
05261 
05262     /** The daterange of the problem. */
05263     DateRange dr;
05264 };
05265 
05266 
05267 /** @brief A problem of this class is created when a buffer is carrying too
05268   * much material during a certain period of time.
05269   */
05270 class ProblemMaterialExcess : public Problem
05271 {
05272   public:
05273     DECLARE_EXPORT string getDescription() const;
05274     bool isFeasible() const {return true;}
05275     double getWeight() const {return qty;}
05276     ProblemMaterialExcess(Buffer* b, Date st, Date nd, double q, bool add = true)
05277       : Problem(b), qty(q), dr(st,nd) {if (add) addProblem();}
05278     string getEntity() const {return "material";}
05279     ~ProblemMaterialExcess() {removeProblem();}
05280     const DateRange getDates() const {return dr;}
05281     Object* getOwner() const {return dynamic_cast<Buffer*>(owner);}
05282     Buffer* getBuffer() const {return dynamic_cast<Buffer*>(owner);}
05283     size_t getSize() const {return sizeof(ProblemMaterialExcess);}
05284 
05285     /** Return a reference to the metadata structure. */
05286     const MetaClass& getType() const {return *metadata;}
05287 
05288     /** Storing metadata on this class. */
05289     static DECLARE_EXPORT const MetaClass* metadata;
05290 
05291   private:
05292     /** Excess quantity. */
05293     double qty;
05294 
05295     /** The daterange of the problem. */
05296     DateRange dr;
05297 };
05298 
05299 
05300 /** @brief This command is used to create an operationplan.
05301   *
05302   * The operationplan will have its loadplans and flowplans created when the
05303   * command is created. It is assigned an id and added to the list of all
05304   * operationplans when the command is committed.
05305   */
05306 class CommandCreateOperationPlan : public Command
05307 {
05308   public:
05309     /** Constructor. */
05310     CommandCreateOperationPlan
05311     (const Operation* o, double q, Date d1, Date d2, Demand* l,
05312      OperationPlan* ow=NULL, bool makeflowsloads=true)
05313     {
05314       opplan = o ?
05315           o->createOperationPlan(q, d1, d2, l, ow, 0, makeflowsloads)
05316           : NULL;
05317     }
05318     void commit()
05319     {
05320       if (opplan)
05321       {
05322         opplan->activate();
05323         opplan = NULL; // Avoid executing / initializing more than once
05324       }
05325     }
05326     virtual void rollback() {delete opplan; opplan = NULL;}
05327     virtual void undo() {if (opplan) opplan->deleteFlowLoads();}
05328     virtual void redo() {if (opplan) opplan->createFlowLoads();}
05329     virtual ~CommandCreateOperationPlan() {if (opplan) delete opplan;}
05330     OperationPlan *getOperationPlan() const {return opplan;}
05331 
05332   private:
05333     /** Pointer to the newly created operationplan. */
05334     OperationPlan *opplan;
05335 };
05336 
05337 
05338 /** @brief This command is used to delete an operationplan. */
05339 class CommandDeleteOperationPlan : public Command
05340 {
05341   public:
05342     /** Constructor. */
05343     DECLARE_EXPORT CommandDeleteOperationPlan(OperationPlan* o);
05344     virtual void commit()
05345     {
05346       if (opplan) delete opplan;
05347       opplan = NULL;
05348     }
05349     virtual void undo()
05350     {
05351       if (!opplan) return;
05352       opplan->createFlowLoads();
05353       if (opplan->getIdentifier())
05354       {
05355         opplan->insertInOperationplanList();
05356         if (opplan->getDemand())
05357           opplan->getDemand()->addDelivery(opplan);
05358       }
05359     }
05360     virtual void redo()
05361     {
05362       if (!opplan) return;
05363       opplan->deleteFlowLoads();
05364       if (opplan->getIdentifier())
05365       {
05366         opplan->removeFromOperationplanList();
05367         if (opplan->getDemand())
05368           opplan->getDemand()->removeDelivery(opplan);
05369       }
05370     }
05371     virtual void rollback()
05372     {
05373       undo();
05374       opplan = NULL;
05375     }
05376     virtual ~CommandDeleteOperationPlan() {undo();}
05377 
05378   private:
05379     /** Pointer to the operationplan being deleted.<br>
05380       * Until the command is committed we don't deallocate the memory for the
05381       * operationplan, but only remove all pointers to it from various places.
05382       */
05383     OperationPlan *opplan;
05384 };
05385 
05386 
05387 /** @brief This class represents the command of moving an operationplan to a
05388   * new date and/or resizing it.
05389   * @todo Moving in a routing operation can't be undone with the current
05390   * implementation! The command will need to store all original dates of
05391   * the suboperationplans...
05392   */
05393 class CommandMoveOperationPlan : public Command
05394 {
05395   public:
05396     /** Constructor.<br>
05397       * Unlike most other commands the constructor already executes the change.
05398       * @param opplanptr Pointer to the operationplan being moved.
05399       * @param newStart New start date of the operationplan.
05400       * @param newEnd New end date of the operationplan.
05401       * @param newQty New quantity of the operationplan.The default is -1,
05402       * which indicates to leave the quantity unchanged.
05403       */
05404     DECLARE_EXPORT CommandMoveOperationPlan(OperationPlan* opplanptr,
05405         Date newStart, Date newEnd, double newQty = -1.0);
05406 
05407     /** Default constructor. */
05408     DECLARE_EXPORT CommandMoveOperationPlan(OperationPlan*);
05409 
05410     /** Commit the changes. */
05411     virtual void commit() {opplan=NULL;}
05412 
05413     /** Undo the changes. */
05414     virtual void rollback() {restore(true); opplan = NULL;}
05415 
05416     virtual void undo() {restore(false);}
05417     virtual DECLARE_EXPORT void redo();
05418 
05419     /** Undo the changes.<br>
05420       * When the argument is true, subcommands for suboperationplans are deleted. */
05421     DECLARE_EXPORT void restore(bool = false);
05422 
05423     /** Destructor. */
05424     virtual ~CommandMoveOperationPlan() {if (opplan) rollback();}
05425 
05426     /** Returns the operationplan being manipulated. */
05427     OperationPlan* getOperationPlan() const {return opplan;}
05428 
05429     /** Set another start date for the operationplan. */
05430     void setStart(Date d) {if (opplan) opplan->setStart(d);}
05431 
05432     /** Set another start date, end date and quantity for the operationplan. */
05433     void setParameters(Date s, Date e, double q, bool b)
05434     {
05435       assert(opplan->getOperation());
05436       if (opplan)
05437         opplan->getOperation()->setOperationPlanParameters(opplan, q, s, e, b);
05438     }
05439 
05440     /** Set another start date for the operationplan. */
05441     void setEnd(Date d) {if (opplan) opplan->setEnd(d);}
05442 
05443     /** Set another quantity for the operationplan. */
05444     void setQuantity(double q) {if (opplan) opplan->setQuantity(q);}
05445 
05446     /** Return the quantity of the original operationplan. */
05447     double getQuantity() const {return originalqty; }
05448 
05449     /** Return the dates of the original operationplan. */
05450     DateRange getDates() const {return originaldates;}
05451 
05452   private:
05453     /** This is a pointer to the operationplan being moved. */
05454     OperationPlan *opplan;
05455 
05456     /** These are the original dates of the operationplan before its move. */
05457     DateRange originaldates;
05458 
05459     /** This is the quantity of the operationplan before the command. */
05460     double originalqty;
05461 
05462     /** A pointer to a list of suboperationplan commands. */
05463     Command* firstCommand;
05464 };
05465 
05466 
05467 /** @brief This class models a iterator that walks over all available
05468   * HasProblem entities.
05469   *
05470   * This list is containing hard-coding the classes that are implementing
05471   * this class. It's not ideal, but we don't have an explicit container
05472   * of the objects (and we don't want one either) and this allows us also
05473   * to re-use the sorting used for the container classes.
05474   */
05475 class HasProblems::EntityIterator
05476 {
05477   private:
05478     /** This union contains iterators through the different entity types.
05479       * Only one of the different iterators will be active at a time, and
05480       * can thus save memory by collapsing the iterators into a single
05481       * union. */
05482     union
05483     {
05484       Buffer::iterator *bufIter;
05485       Resource::iterator *resIter;
05486       OperationPlan::iterator *operIter;
05487       Demand::iterator *demIter;
05488     };
05489 
05490     /** This type indicates which type of entity we are currently recursing
05491       * through.
05492       *  - 0: buffers
05493       *  - 1: resources
05494       *  - 2: operationplans
05495       *  - 3: demands
05496       */
05497     unsigned short type;
05498 
05499   public:
05500     /** Default constructor, which creates an iterator to the first
05501       * HasProblems object. */
05502     explicit DECLARE_EXPORT EntityIterator();
05503 
05504     /** Used to create an iterator pointing beyond the last HasProblems
05505       * object. */
05506     explicit EntityIterator(unsigned short i) : type(i) {}
05507 
05508     /** Copy constructor. */
05509     DECLARE_EXPORT EntityIterator(const EntityIterator& o);
05510 
05511     /** Assignment operator. */
05512     DECLARE_EXPORT EntityIterator& operator=(const EntityIterator& o);
05513 
05514     /** Destructor. */
05515     DECLARE_EXPORT ~EntityIterator();
05516 
05517     /** Pre-increment operator. */
05518     DECLARE_EXPORT EntityIterator& operator++();
05519 
05520     /** Inequality operator.<br>
05521       * Two iterators are different when they point to different objects.
05522       */
05523     DECLARE_EXPORT bool operator != (const EntityIterator& t) const;
05524 
05525     /** Equality operator.<br>
05526       * Two iterators are equal when they point to the same object.
05527       */
05528     bool operator == (const EntityIterator& t) const {return !(*this != t);}
05529 
05530     /** Dereference operator. */
05531     DECLARE_EXPORT HasProblems& operator*() const;
05532 
05533     /** Dereference operator. */
05534     DECLARE_EXPORT HasProblems* operator->() const;
05535 };
05536 
05537 
05538 /** @brief This class models an STL-like iterator that allows us to iterate
05539   * over the named entities in a simple and safe way.
05540   *
05541   * Objects of this class are returned by the begin() and end() functions.
05542   * @see Problem::begin()
05543   * @see Problem::begin(HasProblem*)
05544   * @see Problem::end()
05545   */
05546 class Problem::const_iterator
05547 {
05548     friend class Problem;
05549   private:
05550     /** A pointer to the current problem. If this pointer is NULL, we are
05551       * at the end of the list. */
05552     Problem* iter;
05553     HasProblems* owner;
05554     HasProblems::EntityIterator eiter;
05555 
05556   public:
05557     /** Creates an iterator that will loop through the problems of a
05558       * single entity only. <BR>
05559       * This constructor is also used to create a end-iterator, when passed
05560       * a NULL pointer as argument.
05561       */
05562     explicit const_iterator(HasProblems* o) : iter(o ? o->firstProblem : NULL),
05563       owner(o), eiter(4) {}
05564 
05565     /** Creates an iterator that will loop through the constraints of
05566       * a demand.
05567       */
05568     explicit const_iterator(Problem* o) : iter(o),
05569       owner(NULL), eiter(4) {}
05570 
05571     /** Creates an iterator that will loop through the problems of all
05572       * entities. */
05573     explicit const_iterator() : owner(NULL)
05574     {
05575       // Loop till we find an entity with a problem
05576       while (eiter!=HasProblems::endEntity() && !(eiter->firstProblem))
05577         ++eiter;
05578       // Found a first problem, or no problem at all
05579       iter = (eiter!=HasProblems::endEntity()) ? eiter->firstProblem : NULL;
05580     }
05581 
05582     /** Pre-increment operator. */
05583     DECLARE_EXPORT const_iterator& operator++();
05584 
05585     /** Inequality operator. */
05586     bool operator != (const const_iterator& t) const {return iter!=t.iter;}
05587 
05588     /** Equality operator. */
05589     bool operator == (const const_iterator& t) const {return iter==t.iter;}
05590 
05591     Problem& operator*() const {return *iter;}
05592     Problem* operator->() const {return iter;}
05593 };
05594 
05595 
05596 /** Retrieve an iterator for the list. */
05597 inline Problem::const_iterator Problem::List::begin() const
05598 {return Problem::const_iterator(first);}
05599 
05600 
05601 /** Stop iterator. */
05602 inline Problem::const_iterator Problem::List::end() const
05603 {return Problem::const_iterator(static_cast<Problem*>(NULL));}
05604 
05605 
05606 /** @brief This class allows upstream and downstream navigation through
05607   * the plan.
05608   *
05609   * Downstream navigation follows the material flow from raw materials
05610   * towards the produced end item.<br>
05611   * Upstream navigation traces back the material flow from the end item up to
05612   * the consumed raw materials.<br>
05613   * The class is implemented as an STL-like iterator.
05614   *
05615   * @todo operationplans without flowplans are skipped by the iterator - not correct!
05616   */
05617 class PeggingIterator : public Object
05618 {
05619   public:
05620     /** Constructor. */
05621     DECLARE_EXPORT PeggingIterator(const Demand* e);
05622 
05623     /** Constructor. */
05624     PeggingIterator(const FlowPlan* e, bool b = true)
05625       : downstream(b), firstIteration(true)
05626     {
05627       if (!e) return;
05628       if (downstream)
05629         states.push(state(0,abs(e->getQuantity()),1.0,e,NULL));
05630       else
05631         states.push(state(0,abs(e->getQuantity()),1.0,NULL,e));
05632       initType(metadata);
05633     }
05634 
05635     /** Return the operationplan consuming the material. */
05636     OperationPlan* getConsumingOperationplan() const
05637     {
05638       const FlowPlan* x = states.top().cons_flowplan;
05639       return x ? x->getOperationPlan() : NULL;
05640     }
05641 
05642     /** Return the material buffer through which we are pegging. */
05643     Buffer *getBuffer() const
05644     {
05645       const FlowPlan* x = states.top().prod_flowplan;
05646       if (!x) x = states.top().cons_flowplan;
05647       return x ? x->getFlow()->getBuffer() : NULL;
05648     }
05649 
05650     /** Return the operationplan producing the material. */
05651     OperationPlan* getProducingOperationplan() const
05652     {
05653       const FlowPlan* x = states.top().prod_flowplan;
05654       return x ? x->getOperationPlan() : NULL;
05655     }
05656 
05657     /** Return the date when the material is consumed. */
05658     Date getConsumingDate() const
05659     {
05660       const FlowPlan* x = states.top().cons_flowplan;
05661       return x ? x->getDate() : Date::infinitePast;
05662     }
05663 
05664     /** Return the date when the material is produced. */
05665     Date getProducingDate() const
05666     {
05667       const FlowPlan* x = states.top().prod_flowplan;
05668       return x ? x->getDate() : Date::infinitePast;
05669     }
05670 
05671     /** Returns the recursion depth of the iterator.<br>
05672       * The original flowplan is at level 0, and each level (either upstream
05673       * or downstream) increments the value by 1.
05674       */
05675     short getLevel() const {return states.top().level;}
05676 
05677     /** Returns the quantity of the demand that is linked to this pegging
05678       * record.
05679       */
05680     double getQuantityDemand() const {return states.top().qty;}
05681 
05682     /** Returns the quantity of the buffer flowplans that is linked to this
05683       * pegging record.
05684       */
05685     double getQuantityBuffer() const
05686     {
05687       const state& t = states.top();
05688       return t.prod_flowplan
05689           ? t.factor * t.prod_flowplan->getOperationPlan()->getQuantity()
05690           : 0;
05691     }
05692 
05693     /** Returns which portion of the current flowplan is fed/supplied by the
05694       * original flowplan. */
05695     double getFactor() const {return states.top().factor;}
05696 
05697     /** Returns false if the flowplan remained unpegged, i.e. it wasn't
05698       * -either completely or paritally- unconsumed at the next level.
05699       */
05700     bool getPegged() const {return states.top().pegged;}
05701 
05702     /** Move the iterator foward to the next downstream flowplan. */
05703     DECLARE_EXPORT PeggingIterator& operator++();
05704 
05705     /** Move the iterator foward to the next downstream flowplan.<br>
05706       * This post-increment operator is less efficient than the pre-increment
05707       * operator.
05708       */
05709     PeggingIterator operator++(int)
05710     {PeggingIterator tmp = *this; ++*this; return tmp;}
05711 
05712     /** Move the iterator foward to the next upstream flowplan. */
05713     DECLARE_EXPORT PeggingIterator& operator--();
05714 
05715     /** Move the iterator foward to the next upstream flowplan.<br>
05716       * This post-increment operator is less efficient than the pre-decrement
05717       * operator.
05718       */
05719     PeggingIterator operator--(int)
05720     {PeggingIterator tmp = *this; --*this; return tmp;}
05721 
05722     /** Comparison operator. */
05723     bool operator==(const PeggingIterator& x) const {return states == x.states;}
05724 
05725     /** Inequality operator. */
05726     bool operator!=(const PeggingIterator& x) const {return states != x.states;}
05727 
05728     /** Conversion operator to a boolean value.
05729       * The return value is true when the iterator still has next elements to
05730       * explore. Returns false when the iteration is finished.
05731       */
05732     operator bool () const {return !states.empty();}
05733 
05734     /** Update the stack. */
05735     DECLARE_EXPORT void updateStack(short, double, double, const FlowPlan*, const FlowPlan*, bool = true);
05736 
05737     /** Returns true if this is a downstream iterator. */
05738     bool isDownstream() {return downstream;}
05739 
05740     /** Initialize the class. */
05741     static int initialize();
05742 
05743     virtual void endElement(XMLInput& i, const Attribute& a, const DataElement& d)
05744     {
05745       throw LogicException("Pegging can't be read");
05746     }
05747     virtual const MetaClass& getType() const {return *metadata;}
05748     static DECLARE_EXPORT const MetaCategory* metadata;
05749     size_t getSize() const {return sizeof(PeggingIterator);}
05750 
05751   private:
05752     /** This structure is used to keep track of the iterator states during the
05753       * iteration. */
05754     struct state
05755     {
05756       /** Stores the quantity of this flowplan that is involved. */
05757       double qty;
05758 
05759       /** Stores what portion of the flowplan is involved with the root flowplan
05760         * where the recursion started.
05761         */
05762       double factor;
05763 
05764       /** Keeps track of the number of levels we're removed from the root
05765         * flowplan where the recursion started.
05766         */
05767       short level;
05768 
05769       /** The current flowplan. */
05770       const FlowPlan* cons_flowplan;
05771 
05772       /** The current flowplan. */
05773       const FlowPlan* prod_flowplan;
05774 
05775       /** Set to false when unpegged quantities are involved. */
05776       bool pegged;
05777 
05778       /** Constructor. */
05779       state(unsigned int l, double d, double f,
05780           const FlowPlan* fc, const FlowPlan* fp, bool p = true)
05781         : qty(d), factor(f), level(l),
05782           cons_flowplan(fc), prod_flowplan(fp), pegged(p) {};
05783 
05784       /** Inequality operator. */
05785       bool operator != (const state& s) const
05786       {
05787         return cons_flowplan != s.cons_flowplan
05788             || prod_flowplan != s.prod_flowplan
05789             || level != s.level;
05790       }
05791 
05792       /** Equality operator. */
05793       bool operator == (const state& s) const
05794       {
05795         return cons_flowplan == s.cons_flowplan
05796             && prod_flowplan == s.prod_flowplan
05797             && level == s.level;
05798       }
05799     };
05800 
05801     /** A type to hold the iterator state. */
05802     typedef stack < state > statestack;
05803 
05804     /** A stack is used to store the iterator state. */
05805     statestack states;
05806 
05807     /** Iterate over the pegging in Python. */
05808     DECLARE_EXPORT PyObject *iternext();
05809 
05810     DECLARE_EXPORT PyObject* getattro(const Attribute&);
05811 
05812     /* Auxilary function to make recursive code possible. */
05813     DECLARE_EXPORT void followPegging(const OperationPlan*, short, double, double);
05814 
05815     /** Convenience variable during stack updates.
05816       * Depending on the value of this field, either the top element in the
05817       * stack is updated or a new state is pushed on the stack.
05818       */
05819     bool first;
05820 
05821     /** Downstream or upstream iterator. */
05822     bool downstream;
05823 
05824     /** A flag used by the Python iterators.
05825       * @see iternext()
05826       */
05827     bool firstIteration;
05828 };
05829 
05830 
05831 /** @brief An iterator class to go through all flowplans of an operationplan.
05832   * @see OperationPlan::beginFlowPlans
05833   * @see OperationPlan::endFlowPlans
05834   */
05835 class OperationPlan::FlowPlanIterator
05836 {
05837     friend class OperationPlan;
05838   private:
05839     FlowPlan* curflowplan;
05840     FlowPlan* prevflowplan;
05841     FlowPlanIterator(FlowPlan* b) : curflowplan(b), prevflowplan(NULL) {}
05842   public:
05843     FlowPlanIterator(const FlowPlanIterator& b)
05844     {
05845       curflowplan = b.curflowplan;
05846       prevflowplan = b.prevflowplan;
05847     }
05848     bool operator != (const FlowPlanIterator &b) const
05849     {return b.curflowplan != curflowplan;}
05850     bool operator == (const FlowPlanIterator &b) const
05851     {return b.curflowplan == curflowplan;}
05852     FlowPlanIterator& operator++()
05853     {
05854       prevflowplan = curflowplan;
05855       if (curflowplan) curflowplan = curflowplan->nextFlowPlan;
05856       return *this;
05857     }
05858     FlowPlanIterator operator++(int)
05859     {FlowPlanIterator tmp = *this; ++*this; return tmp;}
05860     FlowPlan* operator ->() const {return curflowplan;}
05861     FlowPlan& operator *() const {return *curflowplan;}
05862     void deleteFlowPlan()
05863     {
05864       if (!curflowplan) return;
05865       if (prevflowplan) prevflowplan->nextFlowPlan = curflowplan->nextFlowPlan;
05866       else curflowplan->oper->firstflowplan = curflowplan->nextFlowPlan;
05867       FlowPlan* tmp = curflowplan;
05868       // Move the iterator to the next element
05869       curflowplan = curflowplan->nextFlowPlan;
05870       delete tmp;
05871     }
05872 };
05873 
05874 inline OperationPlan::FlowPlanIterator OperationPlan::beginFlowPlans() const
05875 {return OperationPlan::FlowPlanIterator(firstflowplan);}
05876 
05877 inline OperationPlan::FlowPlanIterator OperationPlan::endFlowPlans() const
05878 {return OperationPlan::FlowPlanIterator(NULL);}
05879 
05880 inline int OperationPlan::sizeFlowPlans() const
05881 {
05882   int c = 0;
05883   for (FlowPlanIterator i = beginFlowPlans(); i != endFlowPlans(); ++i) ++c;
05884   return c;
05885 }
05886 
05887 
05888 /** @brief An iterator class to go through all loadplans of an operationplan.
05889   * @see OperationPlan::beginLoadPlans
05890   * @see OperationPlan::endLoadPlans
05891   */
05892 class OperationPlan::LoadPlanIterator
05893 {
05894     friend class OperationPlan;
05895   private:
05896     LoadPlan* curloadplan;
05897     LoadPlan* prevloadplan;
05898     LoadPlanIterator(LoadPlan* b) : curloadplan(b), prevloadplan(NULL) {}
05899   public:
05900     LoadPlanIterator(const LoadPlanIterator& b)
05901     {
05902       curloadplan = b.curloadplan;
05903       prevloadplan = b.prevloadplan;
05904     }
05905     bool operator != (const LoadPlanIterator &b) const
05906     {return b.curloadplan != curloadplan;}
05907     bool operator == (const LoadPlanIterator &b) const
05908     {return b.curloadplan == curloadplan;}
05909     LoadPlanIterator& operator++()
05910     {
05911       prevloadplan = curloadplan;
05912       if (curloadplan) curloadplan = curloadplan->nextLoadPlan;
05913       return *this;
05914     }
05915     LoadPlanIterator operator++(int)
05916     {LoadPlanIterator tmp = *this; ++*this; return tmp;}
05917     LoadPlan* operator ->() const {return curloadplan;}
05918     LoadPlan& operator *() const {return *curloadplan;}
05919     void deleteLoadPlan()
05920     {
05921       if (!curloadplan) return;
05922       if (prevloadplan) prevloadplan->nextLoadPlan = curloadplan->nextLoadPlan;
05923       else curloadplan->oper->firstloadplan = curloadplan->nextLoadPlan;
05924       LoadPlan* tmp = curloadplan;
05925       // Move the iterator to the next element
05926       curloadplan = curloadplan->nextLoadPlan;
05927       delete tmp;
05928     }
05929 };
05930 
05931 
05932 inline OperationPlan::LoadPlanIterator OperationPlan::beginLoadPlans() const
05933 {return OperationPlan::LoadPlanIterator(firstloadplan);}
05934 
05935 
05936 inline OperationPlan::LoadPlanIterator OperationPlan::endLoadPlans() const
05937 {return OperationPlan::LoadPlanIterator(NULL);}
05938 
05939 
05940 inline int OperationPlan::sizeLoadPlans() const
05941 {
05942   int c = 0;
05943   for (LoadPlanIterator i = beginLoadPlans(); i != endLoadPlans(); ++i) ++c;
05944   return c;
05945 }
05946 
05947 
05948 class ProblemIterator
05949   : public FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>
05950 {
05951   public:
05952     /** Constructor starting the iteration from a certain problem. */
05953     ProblemIterator(Problem *x) :
05954       FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>(x) {}
05955 
05956     /** Constructor starting the iteration from a certain problem. */
05957     ProblemIterator(Problem &x) :
05958       FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>(&x) {}
05959 
05960     /** Default constructor. */
05961     ProblemIterator() :
05962       FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>() {}
05963 };
05964 
05965 
05966 class BufferIterator
05967   : public FreppleIterator<BufferIterator,Buffer::memberIterator,Buffer>
05968 {
05969   public:
05970     BufferIterator(Buffer* b) : FreppleIterator<BufferIterator,Buffer::memberIterator,Buffer>(b) {}
05971     BufferIterator() {}
05972 };
05973 
05974 
05975 class LocationIterator
05976   : public FreppleIterator<LocationIterator,Location::memberIterator,Location>
05977 {
05978   public:
05979     LocationIterator(Location* b) : FreppleIterator<LocationIterator,Location::memberIterator,Location>(b) {}
05980     LocationIterator() {}
05981 };
05982 
05983 
05984 class CustomerIterator
05985   : public FreppleIterator<CustomerIterator,Customer::memberIterator,Customer>
05986 {
05987   public:
05988     CustomerIterator(Customer* b) : FreppleIterator<CustomerIterator,Customer::memberIterator,Customer>(b) {}
05989     CustomerIterator() {}
05990 };
05991 
05992 
05993 class ItemIterator
05994   : public FreppleIterator<ItemIterator,Item::memberIterator,Item>
05995 {
05996   public:
05997     ItemIterator(Item* b) : FreppleIterator<ItemIterator,Item::memberIterator,Item>(b) {}
05998     ItemIterator() {}
05999 };
06000 
06001 
06002 class DemandIterator
06003   : public FreppleIterator<DemandIterator,Demand::memberIterator,Demand>
06004 {
06005   public:
06006     DemandIterator(Demand* b) : FreppleIterator<DemandIterator,Demand::memberIterator,Demand>(b) {}
06007     DemandIterator() {}
06008 };
06009 
06010 
06011 class ResourceIterator
06012   : public FreppleIterator<ResourceIterator,Resource::memberIterator,Resource>
06013 {
06014   public:
06015     ResourceIterator(Resource* b) : FreppleIterator<ResourceIterator,Resource::memberIterator,Resource>(b) {}
06016     ResourceIterator() {}
06017 };
06018 
06019 
06020 class SolverIterator
06021   : public FreppleIterator<SolverIterator,Solver::iterator,Solver>
06022 {
06023 };
06024 
06025 
06026 class OperationIterator
06027   : public FreppleIterator<OperationIterator,Operation::iterator,Operation>
06028 {
06029 };
06030 
06031 
06032 class CalendarIterator
06033   : public FreppleIterator<CalendarIterator,Calendar::iterator,Calendar>
06034 {
06035 };
06036 
06037 
06038 class SetupMatrixIterator
06039   : public FreppleIterator<SetupMatrixIterator,SetupMatrix::iterator,SetupMatrix>
06040 {
06041 };
06042 
06043 
06044 //
06045 // SETUP MATRIX RULES
06046 //
06047 
06048 
06049 class SetupMatrixRuleIterator : public PythonExtension<SetupMatrixRuleIterator>
06050 {
06051   public:
06052     static int initialize();
06053 
06054     SetupMatrixRuleIterator(SetupMatrix* c) : matrix(c)
06055     {
06056       if (!c)
06057         throw LogicException("Creating rule iterator for NULL matrix");
06058       currule = c->beginRules();
06059     }
06060 
06061   private:
06062     SetupMatrix* matrix;
06063     SetupMatrix::RuleIterator currule;
06064     PyObject *iternext();
06065 };
06066 
06067 
06068 //
06069 // CALENDARS
06070 //
06071 
06072 
06073 class CalendarBucketIterator : public PythonExtension<CalendarBucketIterator>
06074 {
06075   public:
06076     static int initialize();
06077 
06078     CalendarBucketIterator(Calendar* c) : cal(c)
06079     {
06080       if (!c)
06081         throw LogicException("Creating bucket iterator for NULL calendar");
06082       i = c->beginBuckets();
06083     }
06084 
06085   private:
06086     Calendar* cal;
06087     Calendar::BucketIterator i;
06088     PyObject *iternext();
06089 };
06090 
06091 
06092 class CalendarEventIterator
06093   : public PythonExtension<CalendarEventIterator>
06094 {
06095   public:
06096     static int initialize();
06097 
06098     CalendarEventIterator(Calendar* c, Date d=Date::infinitePast, bool f=true)
06099       : cal(c), eventiter(c,d,f), forward(f) {}
06100 
06101   private:
06102     Calendar* cal;
06103     Calendar::EventIterator eventiter;
06104     bool forward;
06105     PyObject *iternext();
06106 };
06107 
06108 
06109 //
06110 // OPERATIONPLANS
06111 //
06112 
06113 
06114 class OperationPlanIterator
06115   : public FreppleIterator<OperationPlanIterator,OperationPlan::iterator,OperationPlan>
06116 {
06117   public:
06118     /** Constructor to iterate over all operationplans. */
06119     OperationPlanIterator() {}
06120 
06121     /** Constructor to iterate over the operationplans of a single operation. */
06122     OperationPlanIterator(Operation* o)
06123       : FreppleIterator<OperationPlanIterator,OperationPlan::iterator,OperationPlan>(o)
06124     {}
06125 
06126     /** Constructor to iterate over the suboperationplans of an operationplans. */
06127     OperationPlanIterator(OperationPlan* opplan)
06128       : FreppleIterator<OperationPlanIterator,OperationPlan::iterator,OperationPlan>(opplan)
06129     {}
06130 };
06131 
06132 
06133 //
06134 // FLOWPLANS
06135 //
06136 
06137 
06138 class FlowPlanIterator : public PythonExtension<FlowPlanIterator>
06139 {
06140   public:
06141     static int initialize();
06142 
06143     FlowPlanIterator(Buffer* b) : buf(b), buffer_or_opplan(true)
06144     {
06145       if (!b)
06146         throw LogicException("Creating flowplan iterator for NULL buffer");
06147       bufiter = new Buffer::flowplanlist::const_iterator(b->getFlowPlans().begin());
06148     }
06149 
06150     FlowPlanIterator(OperationPlan* o) : opplan(o), buffer_or_opplan(false)
06151     {
06152       if (!o)
06153         throw LogicException("Creating flowplan iterator for NULL operationplan");
06154       opplaniter = new OperationPlan::FlowPlanIterator(o->beginFlowPlans());
06155     }
06156 
06157     ~FlowPlanIterator()
06158     {
06159       if (buffer_or_opplan) delete bufiter;
06160       else delete opplaniter;
06161     }
06162 
06163   private:
06164     union
06165     {
06166       Buffer* buf;
06167       OperationPlan* opplan;
06168     };
06169 
06170     union
06171     {
06172       Buffer::flowplanlist::const_iterator *bufiter;
06173       OperationPlan::FlowPlanIterator *opplaniter;
06174     };
06175 
06176     /** Flags whether we are browsing over the flowplans in a buffer or in an
06177       * operationplan. */
06178     bool buffer_or_opplan;
06179 
06180     PyObject *iternext();
06181 };
06182 
06183 
06184 //
06185 // LOADPLANS
06186 //
06187 
06188 
06189 class LoadPlanIterator : public PythonExtension<LoadPlanIterator>
06190 {
06191   public:
06192     static int initialize();
06193 
06194     LoadPlanIterator(Resource* r) : res(r), resource_or_opplan(true)
06195     {
06196       if (!r)
06197         throw LogicException("Creating loadplan iterator for NULL resource");
06198       resiter = new Resource::loadplanlist::const_iterator(r->getLoadPlans().begin());
06199     }
06200 
06201     LoadPlanIterator(OperationPlan* o) : opplan(o), resource_or_opplan(false)
06202     {
06203       if (!opplan)
06204         throw LogicException("Creating loadplan iterator for NULL operationplan");
06205       opplaniter = new OperationPlan::LoadPlanIterator(o->beginLoadPlans());
06206     }
06207 
06208     ~LoadPlanIterator()
06209     {
06210       if (resource_or_opplan) delete resiter;
06211       else delete opplaniter;
06212     }
06213 
06214   private:
06215     union
06216     {
06217       Resource* res;
06218       OperationPlan* opplan;
06219     };
06220 
06221     union
06222     {
06223       Resource::loadplanlist::const_iterator *resiter;
06224       OperationPlan::LoadPlanIterator *opplaniter;
06225     };
06226 
06227     /** Flags whether we are browsing over the flowplans in a buffer or in an
06228       * operationplan. */
06229     bool resource_or_opplan;
06230 
06231     PyObject *iternext();
06232 };
06233 
06234 
06235 //
06236 // DEMAND DELIVERY OPERATIONPLANS
06237 //
06238 
06239 
06240 class DemandPlanIterator : public PythonExtension<DemandPlanIterator>
06241 {
06242   public:
06243     static int initialize();
06244 
06245     DemandPlanIterator(Demand* r) : dem(r)
06246     {
06247       if (!r)
06248         throw LogicException("Creating demandplan iterator for NULL demand");
06249       i = r->getDelivery().begin();
06250     }
06251 
06252   private:
06253     Demand* dem;
06254     Demand::OperationPlan_list::const_iterator i;
06255     PyObject *iternext();
06256 };
06257 
06258 
06259 //
06260 // LOADS
06261 //
06262 
06263 
06264 class LoadIterator : public PythonExtension<LoadIterator>
06265 {
06266   public:
06267     static int initialize();
06268 
06269     LoadIterator(Resource* r)
06270       : res(r), ir(r ? r->getLoads().begin() : NULL), oper(NULL), io(NULL)
06271     {
06272       if (!r)
06273         throw LogicException("Creating loadplan iterator for NULL resource");
06274     }
06275 
06276     LoadIterator(Operation* o)
06277       : res(NULL), ir(NULL), oper(o), io(o ? o->getLoads().begin() : NULL)
06278     {
06279       if (!o)
06280         throw LogicException("Creating loadplan iterator for NULL operation");
06281     }
06282 
06283   private:
06284     Resource* res;
06285     Resource::loadlist::const_iterator ir;
06286     Operation* oper;
06287     Operation::loadlist::const_iterator io;
06288     PyObject *iternext();
06289 };
06290 
06291 
06292 //
06293 // FLOW
06294 //
06295 
06296 
06297 class FlowIterator : public PythonExtension<FlowIterator>
06298 {
06299   public:
06300     static int initialize();
06301 
06302     FlowIterator(Buffer* b)
06303       : buf(b), ib(b ? b->getFlows().begin() : NULL), oper(NULL), io(NULL)
06304     {
06305       if (!b)
06306         throw LogicException("Creating flowplan iterator for NULL buffer");
06307     }
06308 
06309     FlowIterator(Operation* o)
06310       : buf(NULL), ib(NULL), oper(o), io(o ? o->getFlows().begin() : NULL)
06311     {
06312       if (!o)
06313         throw LogicException("Creating flowplan iterator for NULL operation");
06314     }
06315 
06316   private:
06317     Buffer* buf;
06318     Buffer::flowlist::const_iterator ib;
06319     Operation* oper;
06320     Operation::flowlist::const_iterator io;
06321     PyObject *iternext();
06322 };
06323 
06324 
06325 /** @brief This Python function is used for reading XML input.
06326   *
06327   * The function takes up to three arguments:
06328   *   - XML data file to be processed.
06329   *     If this argument is omitted or None, the standard input is read.
06330   *   - Optional validate flag, defining whether or not the input data needs to be
06331   *     validated against the XML schema definition.
06332   *     The validation is switched ON by default.
06333   *     Switching it ON is recommended in situations where there is no 100% guarantee
06334   *     on the validity of the input data.
06335   *   - Optional validate_only flag, which allows us to validate the data but
06336   *     skip any processing.
06337   */
06338 DECLARE_EXPORT PyObject* readXMLfile(PyObject*, PyObject*);
06339 
06340 
06341 /** @brief This Python function is used for processing XML input data from a string.
06342   *
06343   * The function takes up to three arguments:
06344   *   - XML data string to be processed
06345   *   - Optional validate flag, defining whether or not the input data needs to be
06346   *     validated against the XML schema definition.
06347   *     The validation is switched ON by default.
06348   *     Switching it ON is recommended in situations where there is no 100% guarantee
06349   *     on the validity of the input data.
06350   *   - Optional validate_only flag, which allows us to validate the data but
06351   *     skip any processing.
06352   */
06353 DECLARE_EXPORT PyObject* readXMLdata(PyObject *, PyObject *);
06354 
06355 
06356 /** @brief This Python function writes the dynamic part of the plan to an text file.
06357   *
06358   * This saved information covers the buffer flowplans, operationplans,
06359   * resource loading, demand, problems, etc...<br>
06360   * The main use of this function is in the test suite: a simple text file
06361   * comparison allows us to identify changes quickly. The output format is
06362   * only to be seen in this context of testing, and is not intended to be used
06363   * as an official method for publishing plans to other systems.
06364   */
06365 DECLARE_EXPORT PyObject* savePlan(PyObject*, PyObject*);
06366 
06367 
06368 /** @brief This Python function prints a summary of the dynamically allocated
06369   * memory to the standard output. This is useful for understanding better the
06370   * size of your model.
06371   *
06372   * The numbers reported by this function won't match the memory size as
06373   * reported by the operating system, since the dynamically allocated memory
06374   * is only a part of the total memory used by a program.
06375   */
06376 DECLARE_EXPORT PyObject* printModelSize(PyObject* self, PyObject* args);
06377 
06378 
06379 /** @brief This python function writes the complete model to an XML-file.
06380   *
06381   * Both the static model (i.e. items, locations, buffers, resources,
06382   * calendars, etc...) and the dynamic data (i.e. the actual plan including
06383   * the operationplans, demand, problems, etc...).<br>
06384   * The format is such that the output file can be re-read to restore the
06385   * very same model.<br>
06386   * The function takes the following arguments:
06387   *   - Name of the output file
06388   *   - Type of output desired: STANDARD, PLAN or PLANDETAIL.
06389   *     The default value is STANDARD.
06390   */
06391 DECLARE_EXPORT PyObject* saveXMLfile(PyObject*, PyObject*);
06392 
06393 
06394 /** @brief This Python function erases the model or the plan from memory.
06395   *
06396   * The function allows the following modes to control what to delete:
06397   *  - plan:<br>
06398   *    Deletes the dynamic modelling constructs, such as operationplans,
06399   *    loadplans and flowplans only. Locked operationplans are not
06400   *    deleted.<br>
06401   *    The static model is left intact.<br>
06402   *    This is the default mode.
06403   *  - model:<br>
06404   *    The dynamic as well as the static objects are removed. You'll end
06405   *    up with a completely empty model.
06406   *    Due to the logic required in the object destructors this mode doesn't
06407   *    scale linear with the model size.
06408   */
06409 DECLARE_EXPORT PyObject* eraseModel(PyObject* self, PyObject* args);
06410 
06411 
06412 }   // End namespace
06413 
06414 #endif

Documentation generated for frePPLe by  doxygen