model.h
Go to the documentation of this file.00001 /*************************************************************************** 00002 file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/trunk/include/frepple/model.h $ 00003 version : $LastChangedRevision: 1355 $ $LastChangedBy: jdetaeye $ 00004 date : $LastChangedDate: 2010-09-12 16:28:25 +0200 (Sun, 12 Sep 2010) $ 00005 ***************************************************************************/ 00006 00007 /*************************************************************************** 00008 * * 00009 * Copyright (C) 2007-2010 by Johan De Taeye * 00010 * * 00011 * This library is free software; you can redistribute it and/or modify it * 00012 * under the terms of the GNU Lesser General Public License as published * 00013 * by the Free Software Foundation; either version 2.1 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 * This library is distributed in the hope that it will be useful, * 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 00019 * General Public License for more details. * 00020 * * 00021 * You should have received a copy of the GNU Lesser General Public * 00022 * License along with this library; if not, write to the Free Software * 00023 * Foundation Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * 00024 * USA * 00025 * * 00026 ***************************************************************************/ 00027 00028 #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) : nm(name), 00150 startdate(start), enddate(end), nextBucket(NULL), prevBucket(NULL), 00151 priority(0), 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 double 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) 00376 {return new Bucket(this, start,end,name);} 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) 00404 : Bucket(c,start,end,name), 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) 00542 {return new BucketValue(this,start,end,name);} 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) 00579 : Bucket(c,start,end,name), 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) 00743 {return new BucketPointer(this,start,end,name);} 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 lsit 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 algoritms 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 flows. */ 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 instantiate() 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() || op->getHidden())); 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 operation is a delivery. 02066 * If the operationplan isn't a delivery operation, 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. */ 02074 DECLARE_EXPORT double getPenalty() const; 02075 02076 /** Calculate the unavailable time during the operationplan. The regular 02077 * duration is extended with this amount. 02078 */ 02079 DECLARE_EXPORT TimePeriod getUnavailable() const; 02080 02081 /** Returns whether the operationplan is locked. A locked operationplan 02082 * is never changed. 02083 */ 02084 bool getLocked() const {return flags & IS_LOCKED;} 02085 02086 /** Deletes all operationplans of a certain operation. A boolean flag 02087 * allows to specify whether locked operationplans are to be deleted too. 02088 */ 02089 static DECLARE_EXPORT void deleteOperationPlans(Operation* o, bool deleteLocked=false); 02090 02091 /** Locks/unlocks an operationplan. A locked operationplan is never 02092 * changed. 02093 */ 02094 virtual DECLARE_EXPORT void setLocked(bool b = true); 02095 02096 /** Returns a pointer to the operation being instantiated. */ 02097 Operation* getOperation() const {return oper;} 02098 02099 /** Fixes the start and end date of an operationplan. Note that this 02100 * overrules the standard duration given on the operation, i.e. no logic 02101 * kicks in to verify the data makes sense. This is up to the user to 02102 * take care of.<br> 02103 * The methods setStart(Date) and setEnd(Date) are therefore preferred 02104 * since they properly apply all appropriate logic. 02105 */ 02106 void setStartAndEnd(Date st, Date nd) 02107 { 02108 dates.setStartAndEnd(st,nd); 02109 update(); 02110 } 02111 02112 /** A method to restore a previous state of an operationplan.<br> 02113 * NO validity checks are done on the parameters. 02114 */ 02115 void restore(const OperationPlanState& x); 02116 02117 /** Updates the operationplan owning this operationplan. In case of 02118 * a OperationRouting steps this will be the operationplan representing the 02119 * complete routing. */ 02120 void DECLARE_EXPORT setOwner(OperationPlan* o); 02121 02122 /** Returns a pointer to the operationplan for which this operationplan 02123 * a sub-operationplan.<br> 02124 * The method returns NULL if there is no owner defined.<br> 02125 * E.g. Sub-operationplans of a routing refer to the overall routing 02126 * operationplan.<br> 02127 * E.g. An alternate sub-operationplan refers to its parent. 02128 * @see getTopOwner 02129 */ 02130 OperationPlan* getOwner() const {return owner;} 02131 02132 /** Returns a pointer to the operationplan owning a set of 02133 * sub-operationplans. There can be multiple levels of suboperations.<br> 02134 * If no owner exists the method returns the current operationplan. 02135 * @see getOwner 02136 */ 02137 const OperationPlan* getTopOwner() const 02138 { 02139 if (owner) 02140 { 02141 // There is an owner indeed 02142 OperationPlan* o(owner); 02143 while (o->owner) o = o->owner; 02144 return o; 02145 } 02146 else 02147 // This operationplan is itself the top of a hierarchy 02148 return this; 02149 } 02150 02151 /** Returns the start and end date of this operationplan. */ 02152 const DateRange & getDates() const {return dates;} 02153 02154 /** Return true if the operationplan is redundant, ie all material 02155 * it produces is not used at all.<br> 02156 * If the optional argument is false (which is the default value), we 02157 * check with the minimum stock level of the buffers. If the argument 02158 * is true, we check with 0. 02159 */ 02160 DECLARE_EXPORT bool isExcess(bool = false) const; 02161 02162 /** Returns a unique identifier of the operationplan.<br> 02163 * The identifier can be specified in the data input (in which case 02164 * we check for the uniqueness during the read operation).<br> 02165 * For operationplans created during a solver run, the identifier is 02166 * assigned in the instantiate() function. The numbering starts with the 02167 * highest identifier read in from the input and is then incremented 02168 * for every operationplan that is registered. 02169 */ 02170 unsigned long getIdentifier() const {return id;} 02171 02172 /** Updates the end date of the operationplan and compute the start 02173 * date.<br> 02174 * Locked operationplans are not updated by this function.<br> 02175 * Slack can be introduced between sub operationaplans by this method, 02176 * i.e. the sub operationplans are only moved if required to meet the 02177 * end date. 02178 */ 02179 virtual DECLARE_EXPORT void setEnd(Date); 02180 02181 /** Updates the start date of the operationplan and compute the end 02182 * date.<br> 02183 * Locked operation_plans are not updated by this function.<br> 02184 * Slack can be introduced between sub operationaplans by this method, 02185 * i.e. the sub operationplans are only moved if required to meet the 02186 * start date. 02187 */ 02188 virtual DECLARE_EXPORT void setStart(Date); 02189 02190 virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 02191 DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&); 02192 DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&); 02193 virtual DECLARE_EXPORT PyObject* getattro(const Attribute&); 02194 virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&); 02195 static int initialize(); 02196 02197 PyObject* str() const 02198 { 02199 ostringstream ch; 02200 ch << id; 02201 return PythonObject(ch.str()); 02202 } 02203 02204 static PyObject* create(PyTypeObject*, PyObject*, PyObject*); 02205 02206 /** Initialize the operationplan. The initialization function should be 02207 * called when the operationplan is ready to be 'officially' added. The 02208 * initialization performs the following actions: 02209 * <ol> 02210 * <li> assign an identifier</li> 02211 * <li> create the flow and loadplans if these hadn't been created 02212 * before</li> 02213 * <li> add the operationplan to the global list of operationplans</li> 02214 * <li> create a link with a demand object if this is a delivery 02215 * operationplan</li> 02216 * </ol> 02217 * Every operationplan subclass that has sub-operations will normally 02218 * need to create an override of this function.<br> 02219 * 02220 * The return value indicates whether the initialization was successfull. 02221 * If the operationplan is invalid, it will be DELETED and the return value 02222 * is 'false'. 02223 */ 02224 virtual DECLARE_EXPORT bool instantiate(bool useMinCounter = true); 02225 02226 /** This method links the operationplan in the list of all operationplans 02227 * maintained on the operation.<br> 02228 * In most cases calling this method is not required since it included 02229 * in the instantiate method. In exceptional cases the solver already 02230 * needs to see uncommitted operationplans in the list - eg for the 02231 * procurement buffer. 02232 * @see instantiate 02233 */ 02234 DECLARE_EXPORT void insertInOperationplanList(); 02235 02236 /** Add a sub-operationplan to the list. */ 02237 virtual DECLARE_EXPORT void addSubOperationPlan(OperationPlan*); 02238 02239 /** Remove a sub-operation_plan from the list. */ 02240 virtual DECLARE_EXPORT void eraseSubOperationPlan(OperationPlan*); 02241 02242 /** This function is used to create the proper loadplan and flowplan 02243 * objects associated with the operation. */ 02244 DECLARE_EXPORT void createFlowLoads(); 02245 02246 bool getHidden() const {return getOperation()->getHidden();} 02247 02248 /** Searches for an OperationPlan with a given identifier.<br> 02249 * Returns a NULL pointer if no such OperationPlan can be found.<br> 02250 * The method is of complexity O(n), i.e. involves a LINEAR search through 02251 * the existing operationplans, and can thus be quite slow in big models.<br> 02252 * The method is O(1), i.e. constant time regardless of the model size, 02253 * when the parameter passed is bigger than the operationplan counter. 02254 */ 02255 static DECLARE_EXPORT OperationPlan* findId(unsigned long l); 02256 02257 /** Problem detection is actually done by the Operation class. That class 02258 * actually "delegates" the responsability to this class, for efficiency. 02259 */ 02260 virtual void updateProblems(); 02261 02262 /** Implement the pure virtual function from the HasProblem class. */ 02263 Plannable* getEntity() const {return oper;} 02264 02265 /** Return the metadata. We return the metadata of the operation class, 02266 * not the one of the operationplan class! 02267 */ 02268 const MetaClass& getType() const {return *metadata;} 02269 02270 static DECLARE_EXPORT const MetaClass* metadata; 02271 02272 static DECLARE_EXPORT const MetaCategory* metacategory; 02273 02274 virtual size_t getSize() const 02275 {return sizeof(OperationPlan);} 02276 02277 /** Handles the persistence of operationplan objects. */ 02278 static DECLARE_EXPORT void writer(const MetaCategory*, XMLOutput*); 02279 02280 /** Comparison of 2 OperationPlans. 02281 * To garantuee that the problems are sorted in a consistent and stable 02282 * way, the following sorting criteria are used (in order of priority): 02283 * <ol><li>Operation</li> 02284 * <li>Start date (earliest dates first)</li> 02285 * <li>Quantity (biggest quantities first)</li></ol> 02286 * Multiple operationplans for the same values of the above keys can exist. 02287 */ 02288 DECLARE_EXPORT bool operator < (const OperationPlan& a) const; 02289 02290 private: 02291 /** Updates the operationplan based on the latest information of quantity, 02292 * date and locked flag.<br> 02293 * This method will also update parent and child operationplans. 02294 * @see resizeFlowLoadPlans 02295 */ 02296 virtual DECLARE_EXPORT void update(); 02297 02298 /** Update the loadplans and flowplans of the operationplan based on the 02299 * latest information of quantity, date and locked flag.<br> 02300 * This method will NOT update parent or child operationplans. 02301 * @see update 02302 */ 02303 DECLARE_EXPORT void resizeFlowLoadPlans(); 02304 02305 /** Pointer to a higher level OperationPlan. */ 02306 OperationPlan *owner; 02307 02308 /** Quantity. */ 02309 double quantity; 02310 02311 /** Default constructor.<br> 02312 * This way of creating operationplan objects is not intended for use by 02313 * any client applications. Client applications should use the factory 02314 * method on the operation class instead.<br> 02315 * Subclasses of the Operation class may use this constructor in their 02316 * own override of the createOperationPlan method. 02317 * @see Operation::createOperationPlan 02318 */ 02319 OperationPlan() : owner(NULL), quantity(0.0), flags(0), dmd(NULL), 02320 id(0), oper(NULL), firstflowplan(NULL), firstloadplan(NULL), 02321 prev(NULL), next(NULL), firstsubopplan(NULL), lastsubopplan(NULL), 02322 nextsubopplan(NULL), prevsubopplan(NULL) 02323 {initType(metadata);} 02324 02325 private: 02326 static const short IS_LOCKED = 1; 02327 static const short IS_SETUP = 2; 02328 static const short HAS_SETUP = 4; 02329 02330 /** Is this operationplan locked? A locked operationplan doesn't accept 02331 * any changes. This field is only relevant for top-operationplans. */ 02332 short flags; 02333 02334 /** Counter of OperationPlans, which is used to automatically assign a 02335 * unique identifier for each operationplan.<br> 02336 * The value of the counter is the first available identifier value that 02337 * can be used for a new operationplan.<br> 02338 * The first value is 1, and each operationplan increases it by 1. 02339 * @see counterMax 02340 * @see getIdentifier() 02341 */ 02342 static DECLARE_EXPORT unsigned long counterMin; 02343 02344 /** Counter of OperationPlans, which is used to automatically assign a 02345 * unique identifier for each operationplan.<br> 02346 * The first value is a very high number, and each operationplan 02347 * decreases it by 1. 02348 * @see counterMin 02349 * @see getIdentifier() 02350 */ 02351 static DECLARE_EXPORT unsigned long counterMax; 02352 02353 /** Pointer to the demand.<br> 02354 * Only delivery operationplans have this field set. The field is NULL 02355 * for all other operationplans. 02356 */ 02357 Demand *dmd; 02358 02359 /** Unique identifier.<br> 02360 * The field is 0 while the operationplan is not fully registered yet. 02361 */ 02362 unsigned long id; 02363 02364 /** Start and end date. */ 02365 DateRange dates; 02366 02367 /** Pointer to the operation. */ 02368 Operation *oper; 02369 02370 /** Root of a single linked list of flowplans. */ 02371 FlowPlan* firstflowplan; 02372 02373 /** Single linked list of loadplans. */ 02374 LoadPlan* firstloadplan; 02375 02376 /** Pointer to the previous operationplan.<br> 02377 * Operationplans are chained in a doubly linked list for each operation. 02378 * @see next 02379 */ 02380 OperationPlan* prev; 02381 02382 /** Pointer to the next operationplan.<br> 02383 * Operationplans are chained in a doubly linked list for each operation. 02384 * @see prev 02385 */ 02386 OperationPlan* next; 02387 02388 /** Pointer to the first suboperationplan of this operationplan. */ 02389 OperationPlan* firstsubopplan; 02390 02391 /** Pointer to the last suboperationplan of this operationplan. */ 02392 OperationPlan* lastsubopplan; 02393 02394 /** Pointer to the next suboperationplan of the parent operationplan. */ 02395 OperationPlan* nextsubopplan; 02396 02397 /** Pointer to the previous suboperationplan of the parent operationplan. */ 02398 OperationPlan* prevsubopplan; 02399 }; 02400 02401 02402 /** @brief A simple class to easily remember the date and quantity of 02403 * an operationplan. */ 02404 class OperationPlanState // @todo should also restore suboperationplans!!! replace by move command??? 02405 { 02406 public: 02407 Date start; 02408 Date end; 02409 double quantity; 02410 02411 /** Default constructor. */ 02412 OperationPlanState() : quantity(0.0) {} 02413 02414 /** Constructor. */ 02415 OperationPlanState(const OperationPlan* x) 02416 { 02417 if (!x) 02418 { 02419 quantity = 0.0; 02420 return; 02421 } 02422 else 02423 { 02424 start = x->getDates().getStart(); 02425 end = x->getDates().getEnd(); 02426 quantity = x->getQuantity(); 02427 } 02428 } 02429 02430 /** Constructor. */ 02431 OperationPlanState(const Date x, const Date y, double q) 02432 : start(x), end(y), quantity(q) {} 02433 02434 /** Constructor. */ 02435 OperationPlanState(const DateRange& x, double q) 02436 : start(x.getStart()), end(x.getEnd()), quantity(q) {} 02437 }; 02438 02439 02440 /** @brief Models an operation that takes a fixed amount of time, independent 02441 * of the quantity. */ 02442 class OperationFixedTime : public Operation 02443 { 02444 public: 02445 /** Constructor. */ 02446 explicit OperationFixedTime(const string& s) : Operation(s) {initType(metadata);} 02447 02448 /** Returns the length of the operation. */ 02449 const TimePeriod getDuration() const {return duration;} 02450 02451 /** Updates the duration of the operation. Existing operation plans of this 02452 * operation are not automatically refreshed to reflect the change. */ 02453 void setDuration(TimePeriod t) 02454 { 02455 if (t<0L) 02456 throw DataException("FixedTime operation can't have a negative duration"); 02457 duration = t; 02458 } 02459 02460 DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 02461 DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&); 02462 virtual DECLARE_EXPORT PyObject* getattro(const Attribute&); 02463 virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&); 02464 static int initialize(); 02465 02466 virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);} 02467 02468 virtual const MetaClass& getType() const {return *metadata;} 02469 static DECLARE_EXPORT const MetaClass* metadata; 02470 virtual size_t getSize() const 02471 {return sizeof(OperationFixedTime) + Operation::extrasize();} 02472 02473 /** A operation of this type enforces the following rules on its 02474 * operationplans: 02475 * - The duration is always constant. 02476 * - If the end date is specified, we use that and ignore the start 02477 * date that could have been passed. 02478 * - If no end date but only a start date are specified, we'll use 02479 * that date. 02480 * - If no dates are specified, we don't update the dates of the 02481 * operationplan. 02482 * - The quantity can be any positive number. 02483 * - Locked operationplans can't be updated. 02484 * @see Operation::setOperationPlanParameters 02485 */ 02486 DECLARE_EXPORT OperationPlanState setOperationPlanParameters 02487 (OperationPlan*, double, Date, Date, bool=true, bool=true) const; 02488 02489 protected: 02490 DECLARE_EXPORT virtual bool extraInstantiate(OperationPlan* o); 02491 02492 private: 02493 /** Stores the lengh of the Operation. */ 02494 TimePeriod duration; 02495 }; 02496 02497 02498 /** @brief Models an operation to convert a setup on a resource. */ 02499 class OperationSetup : public Operation 02500 { 02501 friend class CommandErase; 02502 public: 02503 /** Constructor. */ 02504 explicit OperationSetup(const string& s) : Operation(s) {initType(metadata);} 02505 02506 // Never write the setup operation 02507 DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const {} 02508 static int initialize(); 02509 02510 virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);} 02511 02512 virtual const MetaClass& getType() const {return *metadata;} 02513 static DECLARE_EXPORT const MetaClass* metadata; 02514 virtual size_t getSize() const 02515 {return sizeof(OperationSetup) + Operation::extrasize();} 02516 02517 /** A operation of this type enforces the following rules on its 02518 * operationplans: 02519 * - The duration is calculated based on the conversion type. 02520 */ 02521 DECLARE_EXPORT OperationPlanState setOperationPlanParameters 02522 (OperationPlan*, double, Date, Date, bool=true, bool=true) const; 02523 02524 /** A pointer to the operation that is instantiated for all conversions. */ 02525 static DECLARE_EXPORT const Operation* setupoperation; 02526 }; 02527 02528 02529 /** @brief Models an operation whose duration is the sum of a constant time, 02530 * plus a cetain time per unit. 02531 */ 02532 class OperationTimePer : public Operation 02533 { 02534 public: 02535 /** Constructor. */ 02536 explicit OperationTimePer(const string& s) : Operation(s) {initType(metadata);} 02537 02538 /** Returns the constant part of the operation time. */ 02539 TimePeriod getDuration() const {return duration;} 02540 02541 /** Sets the constant part of the operation time. */ 02542 void setDuration(TimePeriod t) 02543 { 02544 if(t<0L) 02545 throw DataException("TimePer operation can't have a negative duration"); 02546 duration = t; 02547 } 02548 02549 /** Returns the time per unit of the operation time. */ 02550 TimePeriod getDurationPer() const {return duration_per;} 02551 02552 /** Sets the time per unit of the operation time. */ 02553 void setDurationPer(TimePeriod t) 02554 { 02555 if(t<0L) 02556 throw DataException("TimePer operation can't have a negative duration-per"); 02557 duration_per = t; 02558 } 02559 02560 /** A operation of this type enforces the following rules on its 02561 * operationplans: 02562 * - If both the start and end date are specified, the quantity is 02563 * computed to match these dates. 02564 * If the time difference between the start and end date is too 02565 * small to fit the fixed duration, the quantity is set to 0. 02566 * - If only an end date is specified, it will be respected and we 02567 * compute a start date based on the quantity. 02568 * - If only a start date is specified, it will be respected and we 02569 * compute an end date based on the quantity. 02570 * - If no date is specified, we respect the quantity and the end 02571 * date of the operation. A new start date is being computed. 02572 * @see Operation::setOperationPlanParameters 02573 */ 02574 DECLARE_EXPORT OperationPlanState setOperationPlanParameters 02575 (OperationPlan*, double, Date, Date, bool=true, bool=true) const; 02576 02577 DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 02578 DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&); 02579 virtual DECLARE_EXPORT PyObject* getattro(const Attribute&); 02580 virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&); 02581 static int initialize(); 02582 02583 virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);} 02584 02585 virtual const MetaClass& getType() const {return *metadata;} 02586 static DECLARE_EXPORT const MetaClass* metadata; 02587 virtual size_t getSize() const 02588 {return sizeof(OperationTimePer) + Operation::extrasize();} 02589 02590 private: 02591 /** Constant part of the operation time. */ 02592 TimePeriod duration; 02593 02594 /** Variable part of the operation time. */ 02595 TimePeriod duration_per; 02596 }; 02597 02598 02599 /** @brief Represents a routing operation, i.e. an operation consisting of 02600 * multiple, sequential sub-operations. 02601 */ 02602 class OperationRouting : public Operation 02603 { 02604 public: 02605 /** Constructor. */ 02606 explicit OperationRouting(const string& c) : Operation(c) {initType(metadata);} 02607 02608 /** Destructor. */ 02609 DECLARE_EXPORT ~OperationRouting(); 02610 02611 /** Adds a new steps to routing at the start of the routing. */ 02612 void addStepFront(Operation *o) 02613 { 02614 if (!o) throw DataException("Adding NULL operation to routing"); 02615 steps.push_front(o); 02616 o->addSuperOperation(this); 02617 } 02618 02619 /** Adds a new steps to routing at the end of the routing. */ 02620 void addStepBack(Operation *o) 02621 { 02622 if (!o) throw DataException("Adding NULL operation to routing"); 02623 steps.push_back(o); 02624 o->addSuperOperation(this); 02625 } 02626 02627 /** Add one or more steps to a routing. */ 02628 static DECLARE_EXPORT PyObject* addStep(PyObject*, PyObject*); 02629 02630 /** Remove a step from a routing. */ 02631 void removeSubOperation(Operation *o) 02632 {steps.remove(o); o->superoplist.remove(this);} 02633 02634 /** A operation of this type enforces the following rules on its 02635 * operationplans: 02636 * - If an end date is given, sequentially use this method on the 02637 * different steps. The steps are stepped through starting from the 02638 * last step, and each step will adjust to meet the requested end date. 02639 * If there is slack between the routings' step operationplans, it can 02640 * be used to "absorb" the change. 02641 * - When a start date is given, the behavior is similar to the previous 02642 * case, except that we step through the operationplans from the 02643 * first step this time. 02644 * - If both a start and an end date are given, we use only the end date. 02645 * - If there are no sub operationplans yet, apply the requested changes 02646 * blindly. 02647 * @see Operation::setOperationPlanParameters 02648 */ 02649 DECLARE_EXPORT OperationPlanState setOperationPlanParameters 02650 (OperationPlan*, double, Date, Date, bool=true, bool=true) const; 02651 02652 DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&); 02653 virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 02654 DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&); 02655 virtual DECLARE_EXPORT PyObject* getattro(const Attribute&); 02656 static int initialize(); 02657 02658 virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);} 02659 02660 /** Return a list of all sub-operationplans. */ 02661 virtual const Operationlist& getSubOperations() const {return steps;} 02662 02663 virtual const MetaClass& getType() const {return *metadata;} 02664 static DECLARE_EXPORT const MetaClass* metadata; 02665 virtual size_t getSize() const 02666 { 02667 return sizeof(OperationRouting) + Operation::extrasize() 02668 + steps.size() * 2 * sizeof(Operation*); 02669 } 02670 02671 protected: 02672 /** Extra logic to be used when instantiating an operationplan. */ 02673 virtual DECLARE_EXPORT bool extraInstantiate(OperationPlan* o); 02674 02675 private: 02676 /** Stores a double linked list of all step operations. */ 02677 Operationlist steps; 02678 }; 02679 02680 02681 inline void OperationPlan::restore(const OperationPlanState& x) 02682 { 02683 getOperation()->setOperationPlanParameters(this, x.quantity, x.start, x.end, true); 02684 assert(quantity == x.quantity); 02685 assert(dates.getStart() == x.start || x.start!=x.end); 02686 assert(dates.getEnd() == x.end || x.start!=x.end); 02687 } 02688 02689 02690 /** This type defines what mode used to search the alternates. */ 02691 enum SearchMode 02692 { 02693 /** Select the alternate with the lowest priority number.<br> 02694 * This is the default. 02695 */ 02696 PRIORITY = 0, 02697 /** Select the alternate which gives the lowest cost. */ 02698 MINCOST = 1, 02699 /** Select the alternate which gives the lowest penalty. */ 02700 MINPENALTY = 2, 02701 /** Select the alternate which gives the lowest sum of the cost and 02702 * penalty. */ 02703 MINCOSTPENALTY = 3 02704 }; 02705 02706 02707 /** Writes a search mode to an output stream. */ 02708 inline ostream & operator << (ostream & os, const SearchMode & d) 02709 { 02710 switch (d) 02711 { 02712 case PRIORITY: os << "PRIORITY"; return os; 02713 case MINCOST: os << "MINCOST"; return os; 02714 case MINPENALTY: os << "MINPENALTY"; return os; 02715 case MINCOSTPENALTY: os << "MINCOSTPENALTY"; return os; 02716 default: assert(false); return os; 02717 } 02718 } 02719 02720 02721 /** Translate a string to a search mode value. */ 02722 DECLARE_EXPORT SearchMode decodeSearchMode(const string& c); 02723 02724 02725 /** @brief This class represents a choice between multiple operations. The 02726 * alternates are sorted in order of priority. 02727 */ 02728 class OperationAlternate : public Operation 02729 { 02730 public: 02731 typedef pair<int,DateRange> alternateProperty; 02732 02733 /** Constructor. */ 02734 explicit OperationAlternate(const string& c) 02735 : Operation(c), search(PRIORITY) {initType(metadata);} 02736 02737 /** Destructor. */ 02738 DECLARE_EXPORT ~OperationAlternate(); 02739 02740 /** Add a new alternate operation.<br> 02741 * The lower the priority value, the more important this alternate 02742 * operation is. */ 02743 DECLARE_EXPORT void addAlternate 02744 (Operation*, int = 1, DateRange = DateRange()); 02745 02746 /** Removes an alternate from the list. */ 02747 DECLARE_EXPORT void removeSubOperation(Operation *); 02748 02749 /** Returns the properties of a certain suboperation. 02750 * @exception LogicException Generated when the argument operation is 02751 * null or when it is not a sub-operation of this alternate. 02752 */ 02753 DECLARE_EXPORT const alternateProperty& getProperties(Operation* o) const; 02754 02755 /** Updates the priority of a certain suboperation. 02756 * @exception DataException Generated when the argument operation is 02757 * not null and not a sub-operation of this alternate. 02758 */ 02759 DECLARE_EXPORT void setPriority(Operation*, int); 02760 02761 /** Updates the effective daterange of a certain suboperation. 02762 * @exception DataException Generated when the argument operation is 02763 * not null and not a sub-operation of this alternate. 02764 */ 02765 DECLARE_EXPORT void setEffective(Operation*, DateRange); 02766 02767 /** Return the search mode. */ 02768 SearchMode getSearch() const {return search;} 02769 02770 /** Update the search mode. */ 02771 void setSearch(const string a) {search = decodeSearchMode(a);} 02772 02773 /** A operation of this type enforces the following rules on its 02774 * operationplans: 02775 * - Very simple, call the method with the same name on the alternate 02776 * suboperationplan. 02777 * @see Operation::setOperationPlanParameters 02778 */ 02779 DECLARE_EXPORT OperationPlanState setOperationPlanParameters 02780 (OperationPlan*, double, Date, Date, bool=true, bool=true) const; 02781 02782 DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&); 02783 DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 02784 DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&); 02785 virtual DECLARE_EXPORT PyObject* getattro(const Attribute&); 02786 virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&); 02787 virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);} 02788 virtual const Operationlist& getSubOperations() const {return alternates;} 02789 static int initialize(); 02790 02791 /** Add an alternate to the operation.<br> 02792 * The keyword arguments are "operation", "priority", "effective_start" 02793 * and "effective_end" 02794 */ 02795 static DECLARE_EXPORT PyObject* addAlternate(PyObject*, PyObject*, PyObject*); 02796 02797 virtual const MetaClass& getType() const {return *metadata;} 02798 static DECLARE_EXPORT const MetaClass* metadata; 02799 virtual size_t getSize() const 02800 { 02801 return sizeof(OperationAlternate) + Operation::extrasize() 02802 + alternates.size() * (5*sizeof(Operation*)+sizeof(alternateProperty)); 02803 } 02804 02805 protected: 02806 /** Extra logic to be used when instantiating an operationplan. */ 02807 virtual DECLARE_EXPORT bool extraInstantiate(OperationPlan* o); 02808 02809 private: 02810 typedef list<alternateProperty> alternatePropertyList; 02811 02812 /** List of the priorities of the different alternate operations. The list 02813 * is maintained such that it is sorted in ascending order of priority. */ 02814 alternatePropertyList alternateProperties; 02815 02816 /** List of all alternate operations. The list is sorted with the operation 02817 * with the highest priority at the start of the list.<br> 02818 * Note that the list of operations and the list of priorities go hand in 02819 * hand: they have an equal number of elements and the order of the 02820 * elements is matching in both lists. 02821 */ 02822 Operationlist alternates; 02823 02824 /** Mode to select the preferred alternates. */ 02825 SearchMode search; 02826 }; 02827 02828 02829 /** @brief An item defines the products being planned, sold, stored and/or 02830 * manufactured. Buffers and demands have a reference an item. 02831 * 02832 * This is an abstract class. 02833 */ 02834 class Item : public HasHierarchy<Item>, public HasDescription 02835 { 02836 public: 02837 /** Constructor. Don't use this directly! */ 02838 explicit Item(const string& str) : HasHierarchy<Item>(str), 02839 deliveryOperation(NULL), price(0.0) {} 02840 02841 /** Returns the delivery operation.<br> 02842 * This field is inherited from a parent item, if it hasn't been 02843 * specified. 02844 */ 02845 Operation* getOperation() const 02846 { 02847 // Current item has a non-empty deliveryOperation field 02848 if (deliveryOperation) return deliveryOperation; 02849 02850 // Look for a non-empty deliveryOperation field on owners 02851 for (Item* i = getOwner(); i; i=i->getOwner()) 02852 if (i->deliveryOperation) return i->deliveryOperation; 02853 02854 // The field is not specified on the item or any of its parents. 02855 return NULL; 02856 } 02857 02858 /** Updates the delivery operation.<br> 02859 * If some demands have already been planned using the old delivery 02860 * operation they are left untouched and won't be replanned. 02861 */ 02862 void setOperation(Operation* o) {deliveryOperation = o;} 02863 02864 /** Return the selling price of the item.<br> 02865 * The default value is 0.0. 02866 */ 02867 double getPrice() const {return price;} 02868 02869 /** Update the selling price of the item. */ 02870 void setPrice(const double c) 02871 { 02872 if (c >= 0) price = c; 02873 else throw DataException("Item price must be positive"); 02874 } 02875 02876 virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 02877 DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&); 02878 DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&); 02879 virtual DECLARE_EXPORT PyObject* getattro(const Attribute&); 02880 virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&); 02881 static int initialize(); 02882 02883 /** Destructor. */ 02884 virtual DECLARE_EXPORT ~Item(); 02885 02886 virtual const MetaClass& getType() const {return *metadata;} 02887 static DECLARE_EXPORT const MetaCategory* metadata; 02888 02889 private: 02890 /** This is the operation used to satisfy a demand for this item. 02891 * @see Demand 02892 */ 02893 Operation* deliveryOperation; 02894 02895 /** Selling price of the item. */ 02896 double price; 02897 }; 02898 02899 02900 /** @brief This class is the default implementation of the abstract Item 02901 * class. */ 02902 class ItemDefault : public Item 02903 { 02904 public: 02905 explicit ItemDefault(const string& str) : Item(str) {initType(metadata);} 02906 virtual const MetaClass& getType() const {return *metadata;} 02907 static DECLARE_EXPORT const MetaClass* metadata; 02908 virtual size_t getSize() const 02909 { 02910 return sizeof(ItemDefault) + getName().size() 02911 + HasDescription::extrasize(); 02912 } 02913 static int initialize(); 02914 }; 02915 02916 02917 /** @brief A buffer represents a combination of a item and location.<br> 02918 * It is the entity for keeping modeling inventory. 02919 */ 02920 class Buffer : public HasHierarchy<Buffer>, public HasLevel, 02921 public Plannable, public HasDescription 02922 { 02923 friend class Flow; 02924 friend class FlowPlan; 02925 02926 public: 02927 typedef TimeLine<FlowPlan> flowplanlist; 02928 typedef Association<Operation,Buffer,Flow>::ListB flowlist; 02929 02930 /** Constructor. Implicit creation of instances is disallowed. */ 02931 explicit Buffer(const string& str) : HasHierarchy<Buffer>(str), 02932 hidden(false), producing_operation(NULL), loc(NULL), it(NULL), 02933 min_cal(NULL), max_cal(NULL), carrying_cost(0.0) {} 02934 02935 /** Returns the operation that is used to supply extra supply into this 02936 * buffer. */ 02937 Operation* getProducingOperation() const {return producing_operation;} 02938 02939 /** Updates the operation that is used to supply extra supply into this 02940 * buffer. */ 02941 void setProducingOperation(Operation* o) 02942 {producing_operation = o; setChanged();} 02943 02944 /** Returns the item stored in this buffer. */ 02945 Item* getItem() const {return it;} 02946 02947 /** Updates the Item stored in this buffer. */ 02948 void setItem(Item* i) {it = i; setChanged();} 02949 02950 /** Returns the Location of this buffer. */ 02951 Location* getLocation() const {return loc;} 02952 02953 /** Updates the location of this buffer. */ 02954 void setLocation(Location* i) {loc = i;} 02955 02956 /** Returns a pointer to a calendar for storing the minimum inventory 02957 * level. */ 02958 CalendarDouble* getMinimum() const {return min_cal;} 02959 02960 /** Returns a pointer to a calendar for storing the maximum inventory 02961 * level. */ 02962 CalendarDouble* getMaximum() const {return max_cal;} 02963 02964 /** Updates the minimum inventory target for the buffer. */ 02965 DECLARE_EXPORT void setMinimum(CalendarDouble *); 02966 02967 /** Updates the minimum inventory target for the buffer. */ 02968 DECLARE_EXPORT void setMaximum(CalendarDouble *); 02969 02970 /** Return the carrying cost.<br> 02971 * The cost of carrying inventory in this buffer. The value is a 02972 * percentage of the item sales price, per year and per unit. 02973 */ 02974 double getCarryingCost() const {return carrying_cost;} 02975 02976 /** Return the carrying cost.<br> 02977 * The cost of carrying inventory in this buffer. The value is a 02978 * percentage of the item sales price, per year and per unit.<br> 02979 * The default value is 0.0. 02980 */ 02981 void setCarryingCost(const double c) 02982 { 02983 if (c >= 0) carrying_cost = c; 02984 else throw DataException("Buffer carrying_cost must be positive"); 02985 } 02986 02987 DECLARE_EXPORT virtual void beginElement(XMLInput&, const Attribute&); 02988 DECLARE_EXPORT virtual void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 02989 DECLARE_EXPORT virtual void endElement(XMLInput&, const Attribute&, const DataElement&); 02990 virtual DECLARE_EXPORT PyObject* getattro(const Attribute&); 02991 virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&); 02992 02993 size_t extrasize() const 02994 {return getName().size() + HasDescription::extrasize();} 02995 02996 /** Initialize the class. */ 02997 static int initialize(); 02998 02999 /** Destructor. */ 03000 virtual DECLARE_EXPORT ~Buffer(); 03001 03002 /** Returns the available material on hand immediately after the 03003 * given date. 03004 */ 03005 DECLARE_EXPORT double getOnHand(Date d = Date::infinitePast) const; 03006 03007 /** Update the on-hand inventory at the start of the planning horizon. */ 03008 DECLARE_EXPORT void setOnHand(double f); 03009 03010 /** Returns minimum or maximum available material on hand in the given 03011 * daterange. The third parameter specifies whether we return the 03012 * minimum (which is the default) or the maximum value. 03013 * The computation is INclusive the start and end dates. 03014 */ 03015 DECLARE_EXPORT double getOnHand(Date, Date, bool min = true) const; 03016 03017 /** Returns a reference to the list of all flows of this buffer. */ 03018 const flowlist& getFlows() const {return flows;} 03019 03020 virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);} 03021 03022 /** Returns a reference to the list of all flow plans of this buffer. */ 03023 const flowplanlist& getFlowPlans() const {return flowplans;} 03024 03025 /** Returns a reference to the list of all flow plans of this buffer. */ 03026 flowplanlist& getFlowPlans() {return flowplans;} 03027 03028 /** Return the flow that is associates a given operation with this 03029 * buffer.<br>Returns NULL is no such flow exists. */ 03030 Flow* findFlow(const Operation* o, Date d) const 03031 {return flows.find(o,d);} 03032 03033 /** Deletes all operationplans consuming from or producing from this 03034 * buffer. The boolean parameter controls whether we delete also locked 03035 * operationplans or not. 03036 */ 03037 DECLARE_EXPORT void deleteOperationPlans(bool deleteLockedOpplans = false); 03038 03039 virtual DECLARE_EXPORT void updateProblems(); 03040 03041 void setHidden(bool b) {if (hidden!=b) setChanged(); hidden = b;} 03042 bool getHidden() const {return hidden;} 03043 03044 virtual const MetaClass& getType() const {return *metadata;} 03045 static DECLARE_EXPORT const MetaCategory* metadata; 03046 03047 /** This function matches producing and consuming operationplans 03048 * with each other, and updates the pegging iterator accordingly. 03049 */ 03050 virtual DECLARE_EXPORT void followPegging 03051 (PeggingIterator&, FlowPlan*, short, double, double); 03052 03053 private: 03054 /** This models the dynamic part of the plan, representing all planned 03055 * material flows on this buffer. */ 03056 flowplanlist flowplans; 03057 03058 /** This models the defined material flows on this buffer. */ 03059 flowlist flows; 03060 03061 /** Hide this entity from serialization or not. */ 03062 bool hidden; 03063 03064 /** This is the operation used to create extra material in this buffer. */ 03065 Operation *producing_operation; 03066 03067 /** Location of this buffer.<br> 03068 * This field is only used as information.<br> 03069 * The default is NULL. 03070 */ 03071 Location* loc; 03072 03073 /** Item being stored in this buffer.<br> 03074 * The default value is NULL. 03075 */ 03076 Item* it; 03077 03078 /** Points to a calendar to store the minimum inventory level.<br> 03079 * The default value is NULL, resulting in a constant minimum level 03080 * of 0. 03081 */ 03082 CalendarDouble *min_cal; 03083 03084 /** Points to a calendar to store the maximum inventory level.<br> 03085 * The default value is NULL, resulting in a buffer without excess 03086 * inventory problems. 03087 */ 03088 CalendarDouble *max_cal; 03089 03090 /** Carrying cost.<br> 03091 * The cost of carrying inventory in this buffer. The value is a 03092 * percentage of the item sales price, per year and per unit. 03093 */ 03094 double carrying_cost; 03095 }; 03096 03097 03098 03099 /** @brief This class is the default implementation of the abstract Buffer class. */ 03100 class BufferDefault : public Buffer 03101 { 03102 public: 03103 explicit BufferDefault(const string& str) : Buffer(str) {initType(metadata);} 03104 virtual const MetaClass& getType() const {return *metadata;} 03105 virtual size_t getSize() const 03106 {return sizeof(BufferDefault) + Buffer::extrasize();} 03107 static DECLARE_EXPORT const MetaClass* metadata; 03108 static int initialize(); 03109 }; 03110 03111 03112 /** @brief This class represents a material buffer with an infinite supply of extra 03113 * material. 03114 * 03115 * In other words, it never constrains the plan and it doesn't propagate any 03116 * requirements upstream. 03117 */ 03118 class BufferInfinite : public Buffer 03119 { 03120 public: 03121 virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);} 03122 virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 03123 virtual const MetaClass& getType() const {return *metadata;} 03124 virtual size_t getSize() const 03125 {return sizeof(BufferInfinite) + Buffer::extrasize();} 03126 explicit BufferInfinite(const string& c) : Buffer(c) 03127 {setDetectProblems(false); initType(metadata);} 03128 static DECLARE_EXPORT const MetaClass* metadata; 03129 static int initialize(); 03130 }; 03131 03132 03133 /** @brief This class models a buffer that is replenish by an external supplier 03134 * using a reorder-point policy. 03135 * 03136 * It represents a material buffer where a replenishment is triggered 03137 * whenever the inventory drops below the minimum level. The buffer is then 03138 * replenished to the maximum inventory level.<br> 03139 * A leadtime is taken into account for the replenishments.<br> 03140 * The following parameters control this replenishment: 03141 * - <b>MinimumInventory</b>:<br> 03142 * Inventory level triggering a new replenishment.<br> 03143 * The actual inventory can drop below this value. 03144 * - <b>MaximumInventory</b>:<br> 03145 * Inventory level to which we try to replenish.<br> 03146 * The actual inventory can exceed this value. 03147 * - <b>Leadtime</b>:<br> 03148 * Time taken between placing the purchase order with the supplier and the 03149 * delivery of the material. 03150 * 03151 * Using the additional parameters described below the replenishments can be 03152 * controlled in more detail. The resulting inventory profile can end up 03153 * to be completely different from the classical saw-tooth pattern! 03154 * 03155 * The timing of the replenishments can be constrained by the following 03156 * parameters: 03157 * - <b>MinimumInterval</b>:<br> 03158 * Minimum time between replenishments.<br> 03159 * The order quantity will be increased such that it covers at least 03160 * the demand in the minimum interval period. The actual inventory can 03161 * exceed the target set by the MinimumInventory parameter. 03162 * - <b>MaximumInterval</b>:<br> 03163 * Maximum time between replenishments.<br> 03164 * The order quantity will replenish to an inventory value less than the 03165 * maximum when this maximum interval is reached. 03166 * When the minimum and maximum interval are equal we basically define a fixed 03167 * schedule replenishment policy. 03168 * 03169 * The quantity of the replenishments can be constrained by the following 03170 * parameters: 03171 * - <b>MinimumQuantity</b>:<br> 03172 * Minimum quantity for a replenishment.<br> 03173 * This parameter can cause the actual inventory to exceed the target set 03174 * by the MinimumInventory parameter. 03175 * - <b>MaximumQuantity</b>:<br> 03176 * Maximum quantity for a replenishment.<br> 03177 * This parameter can cause the maximum inventory target never to be 03178 * reached. 03179 * - <b>MultipleQuantity</b>:<br> 03180 * All replenishments are rounded up to a multiple of this value. 03181 * When the minimum and maximum quantity are equal we basically define a fixed 03182 * quantity replenishment policy. 03183 */ 03184 class BufferProcure : public Buffer 03185 { 03186 public: 03187 virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);} 03188 virtual DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&); 03189 virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 03190 virtual const MetaClass& getType() const {return *metadata;} 03191 virtual size_t getSize() const 03192 {return sizeof(BufferProcure) + Buffer::extrasize();} 03193 virtual DECLARE_EXPORT PyObject* getattro(const Attribute&); 03194 virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&); 03195 static int initialize(); 03196 03197 /** Constructor. */ 03198 explicit BufferProcure(const string& c) : Buffer(c), 03199 size_minimum(0), size_maximum(DBL_MAX), size_multiple(0), 03200 oper(NULL) {initType(metadata);} 03201 static DECLARE_EXPORT const MetaClass* metadata; 03202 03203 /** Return the purchasing leadtime. */ 03204 TimePeriod getLeadtime() const {return leadtime;} 03205 03206 /** Update the procurement leadtime. */ 03207 void setLeadtime(TimePeriod p) 03208 { 03209 if (p<0L) 03210 throw DataException("Procurement buffer can't have a negative lead time"); 03211 leadtime = p; 03212 } 03213 03214 /** Return the release time fence. */ 03215 TimePeriod getFence() const {return fence;} 03216 03217 /** Update the release time fence. */ 03218 void setFence(TimePeriod p) {fence = p;} 03219 03220 /** Return the inventory level that will trigger creation of a 03221 * purchasing. 03222 */ 03223 double getMinimumInventory() const 03224 {return getFlowPlans().getMin(Date::infiniteFuture);} 03225 03226 /** Update the inventory level that will trigger the creation of a 03227 * replenishment.<br> 03228 * Because of the replenishment leadtime, the actual inventory will drop 03229 * below this value. It is up to the user to set an appropriate minimum 03230 * value. 03231 */ 03232 void setMinimumInventory(double f) 03233 { 03234 if (f<0) 03235 throw DataException("Procurement buffer can't have a negative minimum inventory"); 03236 flowplanlist::EventMinQuantity* min = getFlowPlans().getMinEvent(Date::infiniteFuture); 03237 if (min) 03238 min->setMin(f); 03239 else 03240 { 03241 // Create and insert a new minimum event 03242 min = new flowplanlist::EventMinQuantity(Date::infinitePast, f); 03243 getFlowPlans().insert(min); 03244 } 03245 // The minimum is increased over the maximum: auto-increase the maximum. 03246 if (getFlowPlans().getMax(Date::infiniteFuture) < f) 03247 setMaximumInventory(f); 03248 } 03249 03250 /** Return the maximum inventory level to which we wish to replenish. */ 03251 double getMaximumInventory() const 03252 {return getFlowPlans().getMax(Date::infiniteFuture);} 03253 03254 /** Update the maximum inventory level to which we plan to replenish.<br> 03255 * This is not a hard limit - other parameters can make that the actual 03256 * inventory either never reaches this value or always exceeds it. 03257 */ 03258 void setMaximumInventory(double f) 03259 { 03260 if (f<0) 03261 throw DataException("Procurement buffer can't have a negative maximum inventory"); 03262 flowplanlist::EventMaxQuantity* max = getFlowPlans().getMaxEvent(Date::infiniteFuture); 03263 if (max) 03264 max->setMax(f); 03265 else 03266 { 03267 // Create and insert a new maximum event 03268 max = new flowplanlist::EventMaxQuantity(Date::infinitePast, f); 03269 getFlowPlans().insert(max); 03270 } 03271 // The maximum is lowered below the minimum: auto-decrease the minimum 03272 if (f < getFlowPlans().getMin(Date::infiniteFuture)) 03273 setMinimumInventory(f); 03274 } 03275 03276 /** Return the minimum interval between purchasing operations.<br> 03277 * This parameter doesn't control the timing of the first purchasing 03278 * operation, but only to the subsequent ones. 03279 */ 03280 TimePeriod getMinimumInterval() const {return min_interval;} 03281 03282 /** Update the minimum time between replenishments. */ 03283 void setMinimumInterval(TimePeriod p) 03284 { 03285 if (p<0L) 03286 throw DataException("Procurement buffer can't have a negative minimum interval"); 03287 min_interval = p; 03288 // minimum is increased over the maximum: auto-increase the maximum 03289 if (max_interval < min_interval) max_interval = min_interval; 03290 } 03291 03292 /** Return the maximum time interval between sytem-generated replenishment 03293 * operations. 03294 */ 03295 TimePeriod getMaximumInterval() const {return max_interval;} 03296 03297 /** Update the minimum time between replenishments. */ 03298 void setMaximumInterval(TimePeriod p) 03299 { 03300 if (p<0L) 03301 throw DataException("Procurement buffer can't have a negative maximum interval"); 03302 max_interval = p; 03303 // maximum is lowered below the minimum: auto-decrease the minimum 03304 if (max_interval < min_interval) min_interval = max_interval; 03305 } 03306 03307 /** Return the minimum quantity of a purchasing operation. */ 03308 double getSizeMinimum() const {return size_minimum;} 03309 03310 /** Update the minimum replenishment quantity. */ 03311 void setSizeMinimum(double f) 03312 { 03313 if (f<0) 03314 throw DataException("Procurement buffer can't have a negative minimum size"); 03315 size_minimum = f; 03316 // minimum is increased over the maximum: auto-increase the maximum 03317 if (size_maximum < size_minimum) size_maximum = size_minimum; 03318 } 03319 03320 /** Return the maximum quantity of a purchasing operation. */ 03321 double getSizeMaximum() const {return size_maximum;} 03322 03323 /** Update the maximum replenishment quantity. */ 03324 void setSizeMaximum(double f) 03325 { 03326 if (f<0) 03327 throw DataException("Procurement buffer can't have a negative maximum size"); 03328 size_maximum = f; 03329 // maximum is lowered below the minimum: auto-decrease the minimum 03330 if (size_maximum < size_minimum) size_minimum = size_maximum; 03331 } 03332 03333 /** Return the multiple quantity of a purchasing operation. */ 03334 double getSizeMultiple() const {return size_multiple;} 03335 03336 /** Update the multiple quantity. */ 03337 void setSizeMultiple(double f) 03338 { 03339 if (f<0) 03340 throw DataException("Procurement buffer can't have a negative multiple size"); 03341 size_multiple = f; 03342 } 03343 03344 /** Returns the operation that is automatically created to represent the 03345 * procurements. 03346 */ 03347 DECLARE_EXPORT Operation* getOperation() const; 03348 03349 private: 03350 /** Purchasing leadtime.<br> 03351 * Within this leadtime fence no additional purchase orders can be generated. 03352 */ 03353 TimePeriod leadtime; 03354 03355 /** Time window from the current date in which all procurements are expected 03356 * to be released. 03357 */ 03358 TimePeriod fence; 03359 03360 /** Minimum time interval between purchasing operations. */ 03361 TimePeriod min_interval; 03362 03363 /** Maximum time interval between purchasing operations. */ 03364 TimePeriod max_interval; 03365 03366 /** Minimum purchasing quantity.<br> 03367 * The default value is 0, meaning no minimum. 03368 */ 03369 double size_minimum; 03370 03371 /** Maximum purchasing quantity.<br> 03372 * The default value is 0, meaning no maximum limit. 03373 */ 03374 double size_maximum; 03375 03376 /** Purchases are always rounded up to a multiple of this quantity.<br> 03377 * The default value is 0, meaning no multiple needs to be applied. 03378 */ 03379 double size_multiple; 03380 03381 /** A pointer to the procurement operation. */ 03382 Operation* oper; 03383 }; 03384 03385 03386 /** @brief This class defines a material flow to/from a buffer, linked with an 03387 * operation. This default implementation plans the material flow at the 03388 * start of the operation. 03389 */ 03390 class Flow : public Object, public Association<Operation,Buffer,Flow>::Node, 03391 public Solvable 03392 { 03393 public: 03394 /** Destructor. */ 03395 virtual DECLARE_EXPORT ~Flow(); 03396 03397 /** Constructor. */ 03398 explicit Flow(Operation* o, Buffer* b, double q) 03399 : quantity(q), priority(1), hasAlts(false), altFlow(NULL), search(PRIORITY) 03400 { 03401 setOperation(o); 03402 setBuffer(b); 03403 validate(ADD); 03404 initType(metadata); 03405 } 03406 03407 /** Returns the operation. */ 03408 Operation* getOperation() const {return getPtrA();} 03409 03410 /** Updates the operation of this flow. This method can be called only ONCE 03411 * for each flow. In case that doesn't suit you, delete the existing flow 03412 * and create a new one. 03413 */ 03414 void setOperation(Operation* o) {if (o) setPtrA(o,o->getFlows());} 03415 03416 /** Returns true if this flow consumes material from the buffer. */ 03417 bool isConsumer() const {return quantity < 0;} 03418 03419 /** Returns true if this flow produces material into the buffer. */ 03420 bool isProducer() const {return quantity >= 0;} 03421 03422 /** Returns the material flow PER UNIT of the operationplan. */ 03423 double getQuantity() const {return quantity;} 03424 03425 /** Updates the material flow PER UNIT of the operationplan. Existing 03426 * flowplans are NOT updated to take the new quantity in effect. Only new 03427 * operationplans and updates to existing ones will use the new quantity 03428 * value. 03429 */ 03430 void setQuantity(double f) {quantity = f;} 03431 03432 /** Returns the buffer. */ 03433 Buffer* getBuffer() const {return getPtrB();} 03434 03435 /** Updates the buffer of this flow. This method can be called only ONCE 03436 * for each flow. In case that doesn't suit you, delete the existing flow 03437 * and create a new one. 03438 */ 03439 void setBuffer(Buffer* b) {if (b) setPtrB(b,b->getFlows());} 03440 03441 /** Update the priority of a flow. */ 03442 void setPriority(int i) {priority = i;} 03443 03444 /** Return the priority of a flow. */ 03445 int getPriority() const {return priority;} 03446 03447 /** Returns true if there are alternates for this flow. */ 03448 bool hasAlternates() const {return hasAlts;} 03449 03450 /** Returns the flow of which this one is an alternate.<br> 03451 * NULL is return where there is none. 03452 */ 03453 Flow* getAlternate() const {return altFlow;} 03454 03455 /** Define the flow of which this one is an alternate. */ 03456 DECLARE_EXPORT void setAlternate(Flow *); 03457 03458 /** Define the flow of which this one is an alternate. */ 03459 DECLARE_EXPORT void setAlternate(const string& n); 03460 03461 /** Return the search mode. */ 03462 SearchMode getSearch() const {return search;} 03463 03464 /** Update the search mode. */ 03465 void setSearch(const string a) {search = decodeSearchMode(a);} 03466 03467 /** A flow is considered hidden when either its buffer or operation 03468 * are hidden. */ 03469 virtual bool getHidden() const 03470 { 03471 return (getBuffer() && getBuffer()->getHidden()) 03472 || (getOperation() && getOperation()->getHidden()); 03473 } 03474 03475 /** This method holds the logic the compute the date of a flowplan. */ 03476 virtual Date getFlowplanDate(const FlowPlan*) const; 03477 03478 /** This method holds the logic the compute the quantity of a flowplan. */ 03479 virtual double getFlowplanQuantity(const FlowPlan*) const; 03480 03481 virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 03482 DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&); 03483 DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&); 03484 static int initialize(); 03485 static void writer(const MetaCategory*, XMLOutput*); 03486 03487 virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);} 03488 03489 virtual const MetaClass& getType() const {return *metadata;} 03490 static DECLARE_EXPORT const MetaCategory* metadata; 03491 virtual size_t getSize() const {return sizeof(Flow) + getName().size();} 03492 03493 protected: 03494 /** Default constructor. */ 03495 explicit Flow() : quantity(0.0), priority(1), hasAlts(false), 03496 altFlow(NULL), search(PRIORITY) {initType(metadata);} 03497 03498 private: 03499 /** Verifies whether a flow meets all requirements to be valid. */ 03500 DECLARE_EXPORT void validate(Action action); 03501 03502 /** Quantity of the flow. */ 03503 double quantity; 03504 03505 /** Priority of the flow - used in case of alternate flows. */ 03506 int priority; 03507 03508 /** Flag that is set to true when a flow has alternates. */ 03509 bool hasAlts; 03510 03511 /** A flow representing the main flow of a set of alternate flows. */ 03512 Flow* altFlow; 03513 03514 /** Mode to select the preferred alternates. */ 03515 SearchMode search; 03516 03517 static PyObject* create(PyTypeObject* pytype, PyObject* args, PyObject* kwds); 03518 DECLARE_EXPORT PyObject* getattro(const Attribute&); 03519 DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&); 03520 }; 03521 03522 03523 /** @brief This class defines a material flow to/from a buffer, linked with an 03524 * operation. This subclass represents a flow that is at the start date of 03525 * the operation. 03526 */ 03527 class FlowStart : public Flow 03528 { 03529 public: 03530 /** Constructor. */ 03531 explicit FlowStart(Operation* o, Buffer* b, double q) : Flow(o,b,q) {} 03532 03533 /** This constructor is called from the plan begin_element function. */ 03534 explicit FlowStart() {} 03535 03536 virtual const MetaClass& getType() const {return *metadata;} 03537 static DECLARE_EXPORT const MetaClass* metadata; 03538 virtual size_t getSize() const {return sizeof(FlowStart);} 03539 virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);} 03540 }; 03541 03542 03543 /** @brief This class defines a material flow to/from a buffer, linked with an 03544 * operation. This subclass represents a flow that is at end date of the 03545 * operation. 03546 */ 03547 class FlowEnd : public Flow 03548 { 03549 public: 03550 /** Constructor. */ 03551 explicit FlowEnd(Operation* o, Buffer* b, double q) : Flow(o,b,q) {} 03552 03553 /** This constructor is called from the plan begin_element function. */ 03554 explicit FlowEnd() {} 03555 03556 /** This method holds the logic the compute the date of a flowplan. */ 03557 virtual Date getFlowplanDate(const FlowPlan* fl) const; 03558 03559 virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 03560 03561 virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);} 03562 03563 virtual const MetaClass& getType() const {return *metadata;} 03564 static DECLARE_EXPORT const MetaClass* metadata; 03565 virtual size_t getSize() const {return sizeof(FlowEnd);} 03566 }; 03567 03568 03569 /** @brief A flowplan represents a planned material flow in or out of a buffer. 03570 * 03571 * Flowplans are owned by operationplans, which manage a container to store 03572 * them. 03573 */ 03574 class FlowPlan : public TimeLine<FlowPlan>::EventChangeOnhand, public PythonExtensionBase 03575 { 03576 friend class OperationPlan::FlowPlanIterator; 03577 private: 03578 /** Points to the flow instantiated by this flowplan. */ 03579 const Flow *fl; 03580 03581 /** Python interface method. */ 03582 PyObject* getattro(const Attribute&); 03583 03584 /** Points to the operationplan owning this flowplan. */ 03585 OperationPlan *oper; 03586 03587 /** Points to the next flowplan owned by the same operationplan. */ 03588 FlowPlan *nextFlowPlan; 03589 03590 public: 03591 03592 static DECLARE_EXPORT const MetaCategory* metadata; 03593 static int initialize(); 03594 03595 /** Constructor. */ 03596 explicit DECLARE_EXPORT FlowPlan(OperationPlan*, const Flow*); 03597 03598 /** Returns the flow of which this is an plan instance. */ 03599 const Flow* getFlow() const {return fl;} 03600 03601 /** Returns the buffer. */ 03602 const Buffer* getBuffer() const {return fl->getBuffer();} 03603 03604 /** Update the flow of an already existing flowplan.<br> 03605 * The new flow must belong to the same operation. 03606 */ 03607 DECLARE_EXPORT void setFlow(const Flow*); 03608 03609 /** Returns the operationplan owning this flowplan. */ 03610 OperationPlan* getOperationPlan() const {return oper;} 03611 03612 /** Destructor. */ 03613 virtual ~FlowPlan() 03614 { 03615 Buffer* b = getFlow()->getBuffer(); 03616 b->setChanged(); 03617 b->flowplans.erase(this); 03618 } 03619 03620 /** Writing the element. 03621 * This method has the same prototype as a usual instance of the Object 03622 * class, but this is only superficial: FlowPlan isn't a subclass of 03623 * Object at all. 03624 */ 03625 void DECLARE_EXPORT writeElement 03626 (XMLOutput*, const Keyword&, mode=DEFAULT) const; 03627 03628 /** Updates the quantity of the flowplan by changing the quantity of the 03629 * operationplan owning this flowplan.<br> 03630 * The boolean parameter is used to control whether to round up (false) 03631 * or down (true) in case the operation quantity must be a multiple. 03632 */ 03633 void setQuantity(double qty, bool b=false, bool u = true) 03634 { 03635 if (getFlow()->getEffective().within(getDate())) 03636 oper->setQuantity(qty / getFlow()->getQuantity(), b, u); 03637 } 03638 03639 /** This function needs to be called whenever the flowplan date or 03640 * quantity are changed. 03641 */ 03642 DECLARE_EXPORT void update(); 03643 03644 /** Return a pointer to the timeline data structure owning this flowplan. */ 03645 TimeLine<FlowPlan>* getTimeLine() const 03646 {return &(getFlow()->getBuffer()->flowplans);} 03647 03648 /** Returns true when the flowplan is hidden.<br> 03649 * This is determined by looking at whether the flow is hidden or not. 03650 */ 03651 bool getHidden() const {return fl->getHidden();} 03652 }; 03653 03654 03655 inline double Flow::getFlowplanQuantity(const FlowPlan* fl) const 03656 { 03657 return getEffective().within(fl->getDate()) ? 03658 fl->getOperationPlan()->getQuantity() * getQuantity() : 03659 0.0; 03660 } 03661 03662 03663 inline Date Flow::getFlowplanDate(const FlowPlan* fl) const 03664 { 03665 return fl->getOperationPlan()->getDates().getStart(); 03666 } 03667 03668 03669 inline Date FlowEnd::getFlowplanDate(const FlowPlan* fl) const 03670 { 03671 return fl->getOperationPlan()->getDates().getEnd(); 03672 } 03673 03674 03675 /** @brief This class is used to represent a matrix defining the changeover 03676 * times between setups. 03677 */ 03678 class SetupMatrix : public HasName<SetupMatrix> 03679 { 03680 public: 03681 class RuleIterator; // Forward declaration 03682 /** @brief An specific changeover rule in a setup matrix. */ 03683 class Rule : public Object 03684 { 03685 friend class RuleIterator; 03686 friend class SetupMatrix; 03687 public: 03688 /** Constructor. */ 03689 DECLARE_EXPORT Rule(SetupMatrix *s, int p = 0); 03690 03691 /** Destructor. */ 03692 DECLARE_EXPORT ~Rule(); 03693 03694 virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 03695 DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&); 03696 virtual DECLARE_EXPORT PyObject* getattro(const Attribute&); 03697 virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&); 03698 static int initialize(); 03699 03700 virtual const MetaClass& getType() const {return *metadata;} 03701 static DECLARE_EXPORT const MetaCategory* metadata; 03702 03703 size_t getSize() const 03704 {return sizeof(Rule) + from.size() + to.size();} 03705 03706 /** Update the priority.<br> 03707 * The priority value is a key field. If multiple rules have the 03708 * same priority a data exception is thrown. 03709 */ 03710 DECLARE_EXPORT void setPriority(const int); 03711 03712 /** Return the priority. */ 03713 double getPriority() const {return priority;} 03714 03715 /** Update the from setup. */ 03716 void setFromSetup(const string f) {from = f;} 03717 03718 /** Return the from setup. */ 03719 const string& getFromSetup() const {return from;} 03720 03721 /** Update the from setup. */ 03722 void setToSetup(const string f) {to = f;} 03723 03724 /** Return the from setup. */ 03725 const string& getToSetup() const {return to;} 03726 03727 /** Update the conversion duration. */ 03728 void setDuration(const TimePeriod p) {duration = p;} 03729 03730 /** Return the conversion duration. */ 03731 TimePeriod getDuration() const {return duration;} 03732 03733 /** Update the conversion cost. */ 03734 void setCost(const double p) {cost = p;} 03735 03736 /** Return the conversion cost. */ 03737 double getCost() const {return cost;} 03738 03739 private: 03740 /** Original setup. */ 03741 string from; 03742 03743 /** New setup. */ 03744 string to; 03745 03746 /** Changeover time. */ 03747 TimePeriod duration; 03748 03749 /** Changeover cost. */ 03750 double cost; 03751 03752 /** Priority of the rule.<br> 03753 * This field is the key field, i.e. within a setup matrix all rules 03754 * need to have different priorities. 03755 */ 03756 int priority; 03757 03758 /** Pointer to the owning matrix. */ 03759 SetupMatrix *matrix; 03760 03761 /** Pointer to the next rule in this matrix. */ 03762 Rule *nextRule; 03763 03764 /** Pointer to the previous rule in this matrix. */ 03765 Rule *prevRule; 03766 }; 03767 03768 /** @brief An iterator class to go through all rules of a setup matrix. */ 03769 class RuleIterator 03770 { 03771 private: 03772 Rule* curRule; 03773 public: 03774 /** Constructor. */ 03775 RuleIterator(Rule* c = NULL) : curRule(c) {} 03776 bool operator != (const RuleIterator &b) const 03777 {return b.curRule != curRule;} 03778 bool operator == (const RuleIterator &b) const 03779 {return b.curRule == curRule;} 03780 RuleIterator& operator++() 03781 {if (curRule) curRule = curRule->nextRule; return *this;} 03782 RuleIterator operator++(int) 03783 {RuleIterator tmp = *this; ++*this; return tmp;} 03784 RuleIterator& operator--() 03785 {if(curRule) curRule = curRule->prevRule; return *this;} 03786 RuleIterator operator--(int) 03787 {RuleIterator tmp = *this; --*this; return tmp;} 03788 Rule* operator ->() const {return curRule;} 03789 Rule& operator *() const {return *curRule;} 03790 }; 03791 03792 public: 03793 /** Default constructor. */ 03794 SetupMatrix(const string& n) : HasName<SetupMatrix>(n), firstRule(NULL) {} 03795 03796 /** Destructor. */ 03797 DECLARE_EXPORT ~SetupMatrix(); 03798 03799 /** This is a factory method that creates a new rule<br> 03800 * This method is intended to be used to create objects when reading 03801 * XML input data. 03802 */ 03803 DECLARE_EXPORT Rule* createRule(const AttributeList&); 03804 03805 virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 03806 DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&); 03807 DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&); 03808 virtual DECLARE_EXPORT PyObject* getattro(const Attribute&); 03809 virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&); 03810 static int initialize(); 03811 03812 virtual const MetaClass& getType() const {return *metadata;} 03813 static DECLARE_EXPORT const MetaCategory* metadata; 03814 03815 virtual size_t getSize() const 03816 { 03817 size_t i = sizeof(SetupMatrix) + getName().size(); 03818 for (RuleIterator j = beginRules(); j!= endRules(); ++j) 03819 i += j->getSize(); 03820 return i; 03821 } 03822 03823 size_t extrasize() const {return getName().size();} 03824 03825 /** Returns an iterator to go through the list of buckets. */ 03826 RuleIterator beginRules() const {return RuleIterator(firstRule);} 03827 03828 /** Returns an iterator to go through the list of buckets. */ 03829 RuleIterator endRules() const {return RuleIterator(NULL);} 03830 03831 /** Python interface to add a new rule. */ 03832 static DECLARE_EXPORT PyObject* addPythonRule(PyObject*, PyObject*, PyObject*); 03833 03834 /** Computes the changeover time and cost between 2 setup values. 03835 * 03836 * To compute the time of a changeover the algorithm will evaluate all 03837 * rules in sequence (in order of priority).<br> 03838 * For a rule to match the changeover between the original setup X to 03839 * a new setup Y, two conditions need to be fulfilled: 03840 * - The original setup X must match with the fromsetup of the rule.<br> 03841 * If the fromsetup field is empty, it is considered a match. 03842 * - The new setup Y must match with the tosetup of the rule.<br> 03843 * If the tosetup field is empty, it is considered a match. 03844 * The wildcard characters * and ? can be used in the fromsetup and 03845 * tosetup fields.<br> 03846 * As soon as a matching rule is found, it is applied and subsequent 03847 * rules are not evaluated.<br> 03848 * If no matching rule is found, the changeover is not allowed: a NULL 03849 * pointer is returned. 03850 */ 03851 DECLARE_EXPORT Rule* calculateSetup(const string, const string) const; 03852 03853 private: 03854 /** Head of the list of rules. */ 03855 Rule *firstRule; 03856 }; 03857 03858 03859 /** @brief This class is the default implementation of the abstract 03860 * SetupMatrix class. 03861 */ 03862 class SetupMatrixDefault : public SetupMatrix 03863 { 03864 public: 03865 explicit SetupMatrixDefault(const string& str) : SetupMatrix(str) {initType(metadata);} 03866 virtual const MetaClass& getType() const {return *metadata;} 03867 static DECLARE_EXPORT const MetaClass* metadata; 03868 virtual size_t getSize() const 03869 {return sizeof(SetupMatrixDefault) + SetupMatrix::extrasize();} 03870 static int initialize(); 03871 }; 03872 03873 03874 /** @brief This class represents a workcentre, a physical or logical 03875 * representation of capacity. 03876 */ 03877 class Resource : public HasHierarchy<Resource>, 03878 public HasLevel, public Plannable, public HasDescription 03879 { 03880 friend class Load; 03881 friend class LoadPlan; 03882 03883 public: 03884 /** The default time window before the ask date where we look for 03885 * available capacity. */ 03886 static const long defaultMaxEarly = 100*86400L; 03887 03888 /** Constructor. */ 03889 explicit Resource(const string& str) : HasHierarchy<Resource>(str), 03890 max_cal(NULL), loc(NULL), cost(0.0), hidden(false), maxearly(defaultMaxEarly), 03891 setupmatrix(NULL) {}; 03892 03893 /** Destructor. */ 03894 virtual DECLARE_EXPORT ~Resource(); 03895 03896 /** Updates the size of a resource. */ 03897 DECLARE_EXPORT void setMaximum(CalendarDouble* c); 03898 03899 /** Return a pointer to the maximum capacity profile. */ 03900 CalendarDouble* getMaximum() const {return max_cal;} 03901 03902 /** Returns the cost of using 1 unit of this resource for 1 hour.<br> 03903 * The default value is 0.0. 03904 */ 03905 double getCost() const {return cost;} 03906 03907 /** Update the cost of using 1 unit of this resource for 1 hour. */ 03908 void setCost(const double c) 03909 { 03910 if (c >= 0) cost = c; 03911 else throw DataException("Resource cost must be positive"); 03912 } 03913 03914 typedef Association<Operation,Resource,Load>::ListB loadlist; 03915 typedef TimeLine<LoadPlan> loadplanlist; 03916 03917 /** Returns a reference to the list of loadplans. */ 03918 const loadplanlist& getLoadPlans() const {return loadplans;} 03919 03920 /** Returns a reference to the list of loadplans. */ 03921 loadplanlist& getLoadPlans() {return loadplans;} 03922 03923 /** Returns a constant reference to the list of loads. It defines 03924 * which operations are using the resource. 03925 */ 03926 const loadlist& getLoads() const {return loads;} 03927 03928 /** Return the load that is associates a given operation with this 03929 * resource. Returns NULL is no such load exists. */ 03930 Load* findLoad(const Operation* o, Date d) const 03931 {return loads.find(o,d);} 03932 03933 virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 03934 DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&); 03935 DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&); 03936 virtual DECLARE_EXPORT PyObject* getattro(const Attribute&); 03937 virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&); 03938 03939 /** Initialize the class. */ 03940 static int initialize(); 03941 03942 size_t extrasize() const 03943 {return getName().size() + HasDescription::extrasize() + setup.size();} 03944 03945 /** Returns the location of this resource. */ 03946 Location* getLocation() const {return loc;} 03947 03948 /** Updates the location of this resource. */ 03949 void setLocation(Location* i) {loc = i;} 03950 03951 virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);} 03952 03953 /** Deletes all operationplans loading this resource. The boolean parameter 03954 * controls whether we delete also locked operationplans or not. 03955 */ 03956 DECLARE_EXPORT void deleteOperationPlans(bool = false); 03957 03958 /** Recompute the problems of this resource. */ 03959 virtual DECLARE_EXPORT void updateProblems(); 03960 03961 /** Scan the setups of this resource. */ 03962 virtual DECLARE_EXPORT void updateSetups(const LoadPlan* = NULL); 03963 03964 void setHidden(bool b) {if (hidden!=b) setChanged(); hidden = b;} 03965 bool getHidden() const {return hidden;} 03966 03967 virtual const MetaClass& getType() const {return *metadata;} 03968 static DECLARE_EXPORT const MetaCategory* metadata; 03969 03970 /** Returns the maximum inventory buildup allowed in case of capacity 03971 * shortages. */ 03972 TimePeriod getMaxEarly() const {return maxearly;} 03973 03974 /** Updates the maximum inventory buildup allowed in case of capacity 03975 * shortages. */ 03976 void setMaxEarly(TimePeriod c) 03977 { 03978 if (c >= 0L) maxearly = c; 03979 else throw DataException("MaxEarly must be positive"); 03980 } 03981 03982 /** Return a pointer to the setup matrix. */ 03983 SetupMatrix* getSetupMatrix() const {return setupmatrix;} 03984 03985 /** Update the reference to the setup matrix. */ 03986 void setSetupMatrix(SetupMatrix *s) {setupmatrix = s;} 03987 03988 /** Return the current setup. */ 03989 const string& getSetup() const {return setup;} 03990 03991 /** Update the current setup. */ 03992 void setSetup(const string s) {setup = s;} 03993 03994 private: 03995 /** This calendar is used to updates to the resource size. */ 03996 CalendarDouble* max_cal; 03997 03998 /** Stores the collection of all loadplans of this resource. */ 03999 loadplanlist loadplans; 04000 04001 /** This is a list of all load models that are linking this resource with 04002 * operations. */ 04003 loadlist loads; 04004 04005 /** A pointer to the location of the resource. */ 04006 Location* loc; 04007 04008 /** The cost of using 1 unit of this resource for 1 hour. */ 04009 double cost; 04010 04011 /** Specifies whether this resource is hidden for serialization. */ 04012 bool hidden; 04013 04014 /** Maximum inventory buildup allowed in case of capacity shortages. */ 04015 TimePeriod maxearly; 04016 04017 /** Reference to the setup matrix. */ 04018 SetupMatrix *setupmatrix; 04019 04020 /** Current setup. */ 04021 string setup; 04022 }; 04023 04024 04025 /** @brief This class is the default implementation of the abstract 04026 * Resource class. 04027 */ 04028 class ResourceDefault : public Resource 04029 { 04030 public: 04031 explicit ResourceDefault(const string& str) : Resource(str) {initType(metadata);} 04032 virtual const MetaClass& getType() const {return *metadata;} 04033 static DECLARE_EXPORT const MetaClass* metadata; 04034 virtual size_t getSize() const 04035 {return sizeof(ResourceDefault) + Resource::extrasize();} 04036 static int initialize(); 04037 }; 04038 04039 04040 /** @brief This class represents a resource that'll never have any 04041 * capacity shortage. */ 04042 class ResourceInfinite : public Resource 04043 { 04044 public: 04045 virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);} 04046 virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 04047 virtual const MetaClass& getType() const {return *metadata;} 04048 explicit ResourceInfinite(const string& c) : Resource(c) 04049 {setDetectProblems(false); initType(metadata);} 04050 static DECLARE_EXPORT const MetaClass* metadata; 04051 virtual size_t getSize() const 04052 {return sizeof(ResourceInfinite) + Resource::extrasize();} 04053 static int initialize(); 04054 }; 04055 04056 04057 /** @brief This class links a resource to a certain operation. */ 04058 class Load 04059 : public Object, public Association<Operation,Resource,Load>::Node, 04060 public Solvable 04061 { 04062 friend class Resource; 04063 friend class Operation; 04064 04065 public: 04066 /** Constructor. */ 04067 explicit Load(Operation* o, Resource* r, double u) 04068 : priority(1), hasAlts(false), altLoad(NULL), search(PRIORITY) 04069 { 04070 setOperation(o); 04071 setResource(r); 04072 setQuantity(u); 04073 validate(ADD); 04074 initType(metadata); 04075 } 04076 04077 /** Destructor. */ 04078 DECLARE_EXPORT ~Load(); 04079 04080 /** Returns the operation consuming the resource capacity. */ 04081 Operation* getOperation() const {return getPtrA();} 04082 04083 /** Updates the operation being loaded. This method can only be called 04084 * once for a load. */ 04085 void setOperation(Operation* o) {if (o) setPtrA(o,o->getLoads());} 04086 04087 /** Returns the capacity resource being consumed. */ 04088 Resource* getResource() const {return getPtrB();} 04089 04090 /** Updates the capacity being consumed. This method can only be called 04091 * once on a resource. */ 04092 void setResource(Resource* r) {if (r) setPtrB(r,r->getLoads());} 04093 04094 /** Returns how much capacity is consumed during the duration of the 04095 * operationplan. */ 04096 double getQuantity() const {return qty;} 04097 04098 /** Updates the quantity of the load. 04099 * @exception DataException When a negative number is passed. 04100 */ 04101 void setQuantity(double f) 04102 { 04103 if (f < 0) throw DataException("Load quantity can't be negative"); 04104 qty = f; 04105 } 04106 04107 /** Update the priority of a load. */ 04108 void setPriority(int i) {priority = i;} 04109 04110 /** Return the priority of a load. */ 04111 int getPriority() const {return priority;} 04112 04113 /** Returns true if there are alternates for this load. */ 04114 bool hasAlternates() const {return hasAlts;} 04115 04116 /** Returns the load of which this one is an alternate.<br> 04117 * NULL is return where there is none. 04118 */ 04119 Load* getAlternate() const {return altLoad;} 04120 04121 /** Define the load of which this one is an alternate. */ 04122 DECLARE_EXPORT void setAlternate(Load *); 04123 04124 /** Define the load of which this one is an alternate. */ 04125 DECLARE_EXPORT void setAlternate(const string& n); 04126 04127 /** Update the required resource setup. */ 04128 DECLARE_EXPORT void setSetup(const string); 04129 04130 /** Return the required resource setup. */ 04131 const string& getSetup() const {return setup;} 04132 04133 /** This method holds the logic the compute the date of a loadplan. */ 04134 virtual Date getLoadplanDate(const LoadPlan*) const; 04135 04136 /** This method holds the logic the compute the quantity of a loadplan. */ 04137 virtual double getLoadplanQuantity(const LoadPlan*) const; 04138 04139 virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 04140 DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&); 04141 DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&); 04142 DECLARE_EXPORT PyObject* getattro(const Attribute&); 04143 DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&); 04144 static int initialize(); 04145 static void writer(const MetaCategory*, XMLOutput*); 04146 04147 bool getHidden() const 04148 { 04149 return (getResource() && getResource()->getHidden()) 04150 || (getOperation() && getOperation()->getHidden()); 04151 } 04152 virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);} 04153 04154 virtual const MetaClass& getType() const {return *metadata;} 04155 static DECLARE_EXPORT const MetaCategory* metadata; 04156 virtual size_t getSize() const 04157 {return sizeof(Load) + getName().size() + getSetup().size();} 04158 04159 /** Default constructor. */ 04160 Load() : qty(1.0), priority(1), hasAlts(false), altLoad(NULL), search(PRIORITY) 04161 {initType(metadata);} 04162 04163 /** Return the search mode. */ 04164 SearchMode getSearch() const {return search;} 04165 04166 /** Update the search mode. */ 04167 void setSearch(const string a) {search = decodeSearchMode(a);} 04168 04169 private: 04170 /** This method is called to check the validity of the object. It will 04171 * delete the invalid loads: be careful with the 'this' pointer after 04172 * calling this method! 04173 */ 04174 DECLARE_EXPORT void validate(Action action); 04175 04176 /** Stores how much capacity is consumed during the duration of an 04177 * operationplan. */ 04178 double qty; 04179 04180 /** Priority of the load - used in case of alternate loads. */ 04181 int priority; 04182 04183 /** Flag that is set to true when a load has alternates. */ 04184 bool hasAlts; 04185 04186 /** A load representing the main load of a set of alternates. */ 04187 Load* altLoad; 04188 04189 /** Required setup. */ 04190 string setup; 04191 04192 /** Mode to select the preferred alternates. */ 04193 SearchMode search; 04194 04195 /** Factory method. */ 04196 static PyObject* create(PyTypeObject*, PyObject*, PyObject*); 04197 }; 04198 04199 04200 04201 /** @brief This is the (logical) top class of the complete model. 04202 * 04203 * This is a singleton class: only a single instance can be created. 04204 * The data model has other limitations that make it not obvious to support 04205 * building multiple models/plans in memory of the same application: e.g. 04206 * the operations, resources, problems, operationplans... etc are all 04207 * implemented in static, global lists. An entity can't be simply linked with 04208 * a particular plan if multiple ones would exist. 04209 */ 04210 class Plan : public Plannable, public Object 04211 { 04212 private: 04213 /** Current Date of this plan. */ 04214 Date cur_Date; 04215 04216 /** A name for this plan. */ 04217 string name; 04218 04219 /** A getDescription of this plan. */ 04220 string descr; 04221 04222 /** Pointer to the singleton plan object. */ 04223 static DECLARE_EXPORT Plan* thePlan; 04224 04225 /** The only constructor of this class is made private. An object of this 04226 * class is created by the instance() member function. 04227 */ 04228 Plan() : cur_Date(Date::now()) {initType(metadata);} 04229 04230 public: 04231 /** Return a pointer to the singleton plan object. 04232 * The singleton object is created during the initialization of the 04233 * library. 04234 */ 04235 static Plan& instance() {return *thePlan;} 04236 04237 /** Destructor. 04238 * @warning In multi threaded applications, the destructor is never called 04239 * and the plan object leaks when we exit the application. 04240 * In single-threaded applications this function is called properly, when 04241 * the static plan variable is deleted. 04242 */ 04243 DECLARE_EXPORT ~Plan(); 04244 04245 /** Returns the plan name. */ 04246 const string& getName() const {return name;} 04247 04248 /** Updates the plan name. */ 04249 void setName(const string& s) {name = s;} 04250 04251 /** Returns the current Date of the plan. */ 04252 const Date & getCurrent() const {return cur_Date;} 04253 04254 /** Updates the current date of the plan. This method can be relatively 04255 * heavy in a plan where operationplans already exist, since the 04256 * detection for BeforeCurrent problems needs to be rerun. 04257 */ 04258 DECLARE_EXPORT void setCurrent(Date); 04259 04260 /** Returns the description of the plan. */ 04261 const string& getDescription() const {return descr;} 04262 04263 /** Updates the description of the plan. */ 04264 void setDescription(const string& str) {descr = str;} 04265 04266 /** This method writes out the model information. Depending on a flag in 04267 * the XMLOutput object a complete model is written, or only the 04268 * dynamic plan information. 04269 * @see CommandSave, CommandSavePlan 04270 */ 04271 virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 04272 DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&); 04273 DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&); 04274 DECLARE_EXPORT PyObject* getattro(const Attribute&); 04275 DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&); 04276 04277 /** Initialize the class. */ 04278 static int initialize(); 04279 04280 virtual void updateProblems() {}; 04281 04282 /** This method basically solves the whole planning problem. */ 04283 virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);} 04284 04285 const MetaClass& getType() const {return *metadata;} 04286 static DECLARE_EXPORT const MetaCategory* metadata; 04287 virtual size_t getSize() const 04288 {return sizeof(Plan) + name.size() + descr.size();} 04289 }; 04290 04291 04292 /** @brief This command is used for reading XML input. The input comes either 04293 * from a flatfile, or from the standard input. 04294 * 04295 * The command is not thread-safe: multiple threads can simultaneously access 04296 * the same objects. 04297 */ 04298 class CommandReadXMLFile : public Command 04299 { 04300 public: 04301 /** Constructor. If no file or directory name is passed or specified later 04302 * the standard input will be read during execution of the command. */ 04303 CommandReadXMLFile(const char* s = NULL, bool v = true, bool o = false) 04304 : validate(v), validate_only(o) {if (s) filename = s;} 04305 04306 /** Constructor. */ 04307 CommandReadXMLFile(const string& s, bool v = true, bool o = false) 04308 : filename(s), validate(v), validate_only(o) {} 04309 04310 /** Update the name of the input file. */ 04311 void setFileName(const string& v) {filename = v;} 04312 04313 /** Returns the name of the input file. */ 04314 string getFileName() {return filename;} 04315 04316 /** Enables or disables the validation. */ 04317 void setValidate(bool b) {validate = b;} 04318 04319 /** Returns true if the schema validation has been enabled. */ 04320 bool getValidate() {return validate;} 04321 04322 /** Only validate the input, do not really execute it. */ 04323 void setValidateOnly(bool b) {validate_only = b;} 04324 04325 /** Returns whether we only need to validate to data, or really execute 04326 * them too. */ 04327 bool getValidateOnly() {return validate_only;} 04328 04329 /** The commit action reads the input. If a filename is specified (either 04330 * in the constructor or with the setFileName function), a flat file is 04331 * read. Otherwise, the standard input is read. */ 04332 DECLARE_EXPORT void execute(); 04333 04334 /** Python interface for this command. */ 04335 static DECLARE_EXPORT PyObject* executePython(PyObject*, PyObject*); 04336 04337 private: 04338 /** Name of the input to be read. An empty string means that we want to 04339 * read from standard input rather than a file. */ 04340 string filename; 04341 04342 /** Specifies whether or not the input file needs to be validated against 04343 * the schema definition. The validation is switched ON by default. 04344 * Switching it ON is recommended in situations where there is not 04345 * 100% garantuee on the validity of the input data. 04346 */ 04347 bool validate; 04348 04349 /** If set to true the input data are validated against the schema, but the 04350 * contents isn't executed. The default value is false. */ 04351 bool validate_only; 04352 }; 04353 04354 04355 /** @brief This command is used for reading XML input from a certain string. 04356 * 04357 * The command is not thread-safe: multiple threads can simultaneously access 04358 * the same objects. 04359 */ 04360 class CommandReadXMLString : public Command 04361 { 04362 public: 04363 /** Constructor. */ 04364 CommandReadXMLString(const string& s, const bool v=true, const bool o=false) 04365 : data(s), validate(v), validate_only(o) {}; 04366 04367 /** Default constructor. */ 04368 CommandReadXMLString(const bool v=true, const bool o=false) 04369 : validate(v), validate_only(o) {}; 04370 04371 /** Updates the data string. */ 04372 void setData(const string& v) {data = v;} 04373 04374 /** Returns the data string. */ 04375 string getData() {return data;} 04376 04377 /** Enables or disables the validation. */ 04378 void setValidate(bool b) {validate = b;} 04379 04380 /** Returns true if the schema validation has been enabled. */ 04381 bool getValidate() {return validate;} 04382 04383 /** Only validate the input, do not really execute it. */ 04384 void setValidateOnly(bool b) {validate_only = b;} 04385 04386 /** Returns whether we only need to validate to data, or really execute 04387 * them too. */ 04388 bool getValidateOnly() {return validate_only;} 04389 04390 /** The commit action reads the input. */ 04391 DECLARE_EXPORT void execute(); 04392 04393 /** Python interface for this command. */ 04394 static DECLARE_EXPORT PyObject* executePython(PyObject *, PyObject *); 04395 04396 DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&); 04397 04398 private: 04399 /** Name of the input to be read. An empty string means that we want to 04400 * read from standard input rather than a file. */ 04401 string data; 04402 04403 /** Specifies whether or not the input file needs to be validated against 04404 * the schema definition. The validation is switched ON by default. 04405 * Switching it ON is recommended in situations where there is not 04406 * 100% garantuee on the validity of the input data. 04407 */ 04408 bool validate; 04409 04410 /** If set to true the input data are validated against the schema, but the 04411 * contents isn't executed. The default value is false. */ 04412 bool validate_only; 04413 }; 04414 04415 04416 /** @brief This command writes the complete model to an XML-file. 04417 * 04418 * Both the static model (i.e. items, locations, buffers, resources, 04419 * calendars, etc...) and the dynamic data (i.e. the actual plan including 04420 * the operationplans, demand, problems, etc...).<br> 04421 * The format is such that the output file can be re-read to restore the 04422 * very same model.<br> 04423 * The data is written by the execute() function. 04424 * @see CommandSavePlan 04425 */ 04426 class CommandSave : public Command 04427 { 04428 public: 04429 /** Constructor. */ 04430 CommandSave(const string& v = "plan.out") 04431 : filename(v), content(XMLOutput::STANDARD) {}; 04432 04433 /** Destructor. */ 04434 virtual ~CommandSave() {}; 04435 04436 /** Return the name of the output file. */ 04437 string getFileName() const {return filename;} 04438 04439 /** Update the name of the output file. */ 04440 void setFileName(const string& v) {filename = v;} 04441 04442 /** Execute the command, ie write the data into XML format. */ 04443 DECLARE_EXPORT void execute(); 04444 04445 /** Python interface to this command. */ 04446 static DECLARE_EXPORT PyObject* executePython(PyObject*, PyObject*); 04447 04448 /** Return the type of output. */ 04449 XMLOutput::content_type getContent() const {return content;} 04450 04451 /** Update the type of output. 04452 * @see XMLOutput::content_type 04453 */ 04454 void setContent(XMLOutput::content_type t) {content = t;} 04455 04456 /** Updates the string that is printed as the first line of each XML 04457 * document.<br> 04458 * The default value is: 04459 * <?xml version="1.0" encoding="UTF-8"?> 04460 */ 04461 void setHeaderStart(const string& s) {headerstart = s;} 04462 04463 /** Returns the string that is printed as the first line of each XML 04464 * document. */ 04465 string getHeaderStart() const {return headerstart;} 04466 04467 /** Updates the attributes that are written for the root element of each 04468 * XML document.<br> 04469 * The default value is an empty string. 04470 */ 04471 void setHeaderAtts(const string& s) {headeratts = s;} 04472 04473 /** Returns the attributes that are written for the root element of each 04474 * XML document. */ 04475 string getHeaderAtts() const {return headeratts;} 04476 04477 private: 04478 string filename; 04479 string headerstart; 04480 string headeratts; 04481 XMLOutput::content_type content; 04482 }; 04483 04484 04485 /** @brief This command writes the dynamic part of the plan to an text file. 04486 * 04487 * This saved information covers the buffer flowplans, operationplans, 04488 * resource loading, demand, problems, etc...<br> 04489 * The main use of this function is in the test suite: a simple text file 04490 * comparison allows us to identify changes quickly. The output format is 04491 * only to be seen in this context of testing, and is not intended to be used 04492 * as an official method for publishing plans to other systems.<br> 04493 * The data file is written by the execute() function. 04494 * @see CommandSave 04495 */ 04496 class CommandSavePlan : public Command 04497 { 04498 public: 04499 CommandSavePlan(const string& v = "plan.out") : filename(v) {}; 04500 string getFileName() const {return filename;} 04501 void setFileName(const string& v) {filename = v;} 04502 DECLARE_EXPORT void execute(); 04503 04504 /** Python interface to this command. */ 04505 static DECLARE_EXPORT PyObject* executePython(PyObject*, PyObject*); 04506 04507 private: 04508 string filename; 04509 }; 04510 04511 04512 /** @brief This command prints a summary of the dynamically allocated memory 04513 * to the standard output. This is useful for understanding better the size 04514 * of your model. 04515 * 04516 * The numbers reported by this function won't match the memory size as 04517 * reported by the operating system, since the dynamically allocated memory 04518 * is only a part of the total memory used by a program. 04519 */ 04520 class CommandPlanSize : public Command 04521 { 04522 public: 04523 CommandPlanSize() {}; 04524 DECLARE_EXPORT void execute(); 04525 static PyObject* executePython(PyObject* self, PyObject* args) 04526 {CommandPlanSize x;x.execute(); return Py_BuildValue("");} 04527 void undo() {} 04528 bool undoable() const {return true;} 04529 }; 04530 04531 04532 /** @brief This command deletes part of the model or the plan from memory. 04533 * 04534 * The class allows the following modes to control what to delete: 04535 * - plan:<br> 04536 * Deletes the dynamic modelling constructs, such as operationplans, 04537 * loadplans and flowplans only. Locked operationplans are not 04538 * deleted.<br> 04539 * The static model is left intact.<br> 04540 * This is the default mode. 04541 * - model:<br> 04542 * The dynamic as well as the static objects are removed. You'll end 04543 * up with a completely empty model. 04544 * Due to the logic required in the object destructors this mode doesn't 04545 * scale linear with the model size. 04546 */ 04547 class CommandErase : public Command 04548 { 04549 public: 04550 CommandErase(bool staticAlso = false) : deleteStaticModel(staticAlso) {}; 04551 04552 DECLARE_EXPORT void execute(); 04553 04554 /** Python interface to this command. */ 04555 static DECLARE_EXPORT PyObject* executePython(PyObject*, PyObject*); 04556 04557 bool getDeleteStaticModel() const {return deleteStaticModel;} 04558 void setDeleteStaticModel(bool b) {deleteStaticModel = b;} 04559 private: 04560 /** Flags whether to delete the complete static model or only the 04561 * dynamic plan information. */ 04562 bool deleteStaticModel; 04563 }; 04564 04565 04566 /** @brief Represents the (independent) demand in the system. It can represent a 04567 * customer order or a forecast. 04568 * 04569 * This is an abstract class. 04570 */ 04571 class Demand 04572 : public HasHierarchy<Demand>, public Plannable, public HasDescription 04573 { 04574 public: 04575 typedef slist<OperationPlan*> OperationPlan_list; 04576 04577 /** Constructor. */ 04578 explicit Demand(const string& str) : HasHierarchy<Demand>(str), 04579 it(NULL), oper(NULL), cust(NULL), qty(0.0), prio(0), 04580 maxLateness(TimePeriod::MAX), minShipment(0), hidden(false) {} 04581 04582 /** Destructor. Deleting the demand will also delete all delivery operation 04583 * plans (including locked ones). */ 04584 virtual ~Demand() 04585 { 04586 deleteOperationPlans(true); 04587 } 04588 04589 /** Returns the quantity of the demand. */ 04590 double getQuantity() const {return qty;} 04591 04592 /** Updates the quantity of the demand. The quantity must be be greater 04593 * than or equal to 0. */ 04594 virtual DECLARE_EXPORT void setQuantity(double); 04595 04596 /** Returns the priority of the demand.<br> 04597 * Lower numbers indicate a higher priority level. 04598 */ 04599 int getPriority() const {return prio;} 04600 04601 /** Updates the due date of the demand.<br> 04602 * Lower numbers indicate a higher priority level. 04603 */ 04604 virtual void setPriority(int i) {prio=i; setChanged();} 04605 04606 /** Returns the item/product being requested. */ 04607 Item* getItem() const {return it;} 04608 04609 /** Updates the item/product being requested. */ 04610 virtual void setItem(Item *i) {it=i; setChanged();} 04611 04612 /** This fields points to an operation that is to be used to plan the 04613 * demand. By default, the field is left to NULL and the demand will then 04614 * be planned using the delivery operation of its item. 04615 * @see Item::getDelivery() 04616 */ 04617 Operation* getOperation() const {return oper;} 04618 04619 /** This function returns the operation that is to be used to satisfy this 04620 * demand. In sequence of priority this goes as follows: 04621 * 1) If the "operation" field on the demand is set, use it. 04622 * 2) Otherwise, use the "delivery" field of the requested item. 04623 * 3) Else, return NULL. This demand can't be satisfied! 04624 */ 04625 DECLARE_EXPORT Operation* getDeliveryOperation() const; 04626 04627 /** Returns the cluster which this demand belongs to. */ 04628 int getCluster() const 04629 { 04630 Operation* o = getDeliveryOperation(); 04631 return o ? o->getCluster() : 0; 04632 } 04633 04634 /** Updates the operation being used to plan the demand. */ 04635 virtual void setOperation(Operation* o) {oper=o; setChanged();} 04636 04637 /** Returns the delivery operationplan list. */ 04638 DECLARE_EXPORT const OperationPlan_list& getDelivery() const; 04639 04640 /** Returns the latest delivery operationplan. */ 04641 DECLARE_EXPORT OperationPlan* getLatestDelivery() const; 04642 04643 /** Returns the earliest delivery operationplan. */ 04644 DECLARE_EXPORT OperationPlan* getEarliestDelivery() const; 04645 04646 /** Adds a delivery operationplan for this demand. */ 04647 DECLARE_EXPORT void addDelivery(OperationPlan *o); 04648 04649 /** Removes a delivery operationplan for this demand. */ 04650 DECLARE_EXPORT void removeDelivery(OperationPlan *o); 04651 04652 /** Deletes all delivery operationplans of this demand.<br> 04653 * The (optional) boolean parameter controls whether we delete also locked 04654 * operationplans or not.<br> 04655 * The second (optional) argument is a command list that can be used to 04656 * remove the operationplans in an undo-able way. 04657 */ 04658 DECLARE_EXPORT void deleteOperationPlans 04659 (bool deleteLockedOpplans = false, CommandList* = NULL); 04660 04661 /** Returns the due date of the demand. */ 04662 const Date& getDue() const {return dueDate;} 04663 04664 /** Updates the due date of the demand. */ 04665 virtual void setDue(Date d) {dueDate = d; setChanged();} 04666 04667 /** Returns the customer. */ 04668 Customer* getCustomer() const {return cust;} 04669 04670 /** Updates the customer. */ 04671 virtual void setCustomer(Customer* c) {cust = c; setChanged();} 04672 04673 /** Return a reference to the constraint list. */ 04674 const Problem::List& getConstraints() const {return constraints;} 04675 04676 /** Return a reference to the constraint list. */ 04677 Problem::List& getConstraints() {return constraints;} 04678 04679 /** Returns the total amount that has been planned. */ 04680 DECLARE_EXPORT double getPlannedQuantity() const; 04681 04682 virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const; 04683 virtual DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&); 04684 virtual DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&); 04685 virtual DECLARE_EXPORT PyObject* getattro(const Attribute&); 04686 virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&); 04687 static int initialize(); 04688 04689 size_t extrasize() const 04690 { 04691 return getName().size() + HasDescription::extrasize() 04692 + sizeof(void*) * 2 * deli.size(); 04693 } 04694 04695 virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);} 04696 04697 /** Return the maximum delay allowed in satisfying this demand.<br> 04698 * The default value is infinite. 04699 */ 04700 TimePeriod getMaxLateness() const {return maxLateness;} 04701 04702 /** Updates the maximum allowed lateness for this demand.<br> 04703 * The default value is infinite.<br> 04704 * The argument must be a positive time period. 04705 */ 04706 virtual void setMaxLateness(TimePeriod m) 04707 { 04708 if (m < 0L) 04709 throw DataException("The maximum demand lateness must be positive"); 04710 maxLateness = m; 04711 } 04712 04713 /** Return the minimum shipment quantity allowed in satisfying this 04714 * demand.<br> 04715 * The default value is 0, which allows deliveries of any size. 04716 */ 04717 double getMinShipment() const {return minShipment;} 04718 04719 /** Updates the maximum allowed lateness for this demand.<br> 04720 * The default value is infinite.<br> 04721 * The argument must be a positive time period. 04722 */ 04723 virtual void setMinShipment(double m) 04724 { 04725 if (m < 0.0) 04726 throw DataException("The minumum demand shipment quantity must be positive"); 04727 minShipment = m; 04728 } 04729 04730 /** Recompute the problems. */ 04731 virtual DECLARE_EXPORT void updateProblems(); 04732 04733 /** Specifies whether of not this demand is to be hidden from 04734 * serialization. The default value is false. */ 04735 void setHidden(bool b) {hidden = b;} 04736 04737 /** Returns true if this demand is to be hidden from serialization. */ 04738 bool getHidden() const {return hidden;} 04739 04740 virtual const MetaClass& getType() const {return *metadata;} 04741 static DECLARE_EXPORT const MetaCategory* metadata; 04742 04743 private: 04744 /** Requested item. */ 04745 Item *it; 04746 04747 /** Delivery Operation. Can be left NULL, in which case the delivery 04748 * operation can be specified on the requested item. */ 04749 Operation *oper; 04750 04751 /** Customer creating this demand. */ 04752 Customer *cust; 04753 04754 /** Requested quantity. Only positive numbers are allowed. */ 04755 double qty; 04756 04757 /** Priority. Lower numbers indicate a higher priority level.*/ 04758 int prio; 04759 04760 /** Due date. */ 04761 Date dueDate; 04762 04763 /** Maximum lateness allowed when planning this demand.<br> 04764 * The default value is TimePeriod::MAX. 04765 */ 04766 TimePeriod maxLateness; 04767 04768 /** Minimum size for a delivery operation plan satisfying this demand. */ 04769 double minShipment; 04770 04771 /** Hide this demand or not. */ 04772 bool hidden; 04773 04774 /** A list of operation plans to deliver this demand. */ 04775 OperationPlan_list deli; 04776 04777 /** A list of constraints preventing this demand from being planned in 04778 * full and on time. */ 04779 Problem::List constraints; 04780 }; 04781 04782 04783 /** @brief This class is the default implementation of the abstract 04784 * Demand class. */ 04785 class DemandDefault : public Demand 04786 { 04787 public: 04788 explicit DemandDefault(const string& str) : Demand(str) {initType(metadata);} 04789 virtual const MetaClass& getType() const {return *metadata;} 04790 static DECLARE_EXPORT const MetaClass* metadata; 04791 virtual size_t getSize() const 04792 {return sizeof(DemandDefault) + Demand::extrasize();} 04793 static int initialize(); 04794 }; 04795 04796 04797 /** @brief This class represents the resource capacity of an operationplan. 04798 * 04799 * For both the start and the end date of the operationplan, a loadplan 04800 * object is created. These are then inserted in the timeline structure 04801 * associated with a resource. 04802 */ 04803 class LoadPlan : public TimeLine<LoadPlan>::EventChangeOnhand, public PythonExtensionBase 04804 { 04805 friend class OperationPlan::LoadPlanIterator; 04806 public: 04807 /** Public constructor.<br> 04808 * This constructor constructs the starting loadplan and will 04809 * also call a private constructor to creates the ending loadplan. 04810 * In other words, a single call to the constructor will create 04811 * two loadplan objects. 04812 */ 04813 explicit DECLARE_EXPORT LoadPlan(OperationPlan*, const Load*); 04814 04815 /** Return the operationplan owning this loadplan. */ 04816 OperationPlan* getOperationPlan() const {return oper;} 04817 04818 /** Return the load of which this is a plan instance. */ 04819 const Load* getLoad() const {return ld;} 04820 04821 /** Return the resource. */ 04822 const Resource* getResource() const {return ld->getResource();} 04823 04824 /** Update the load of an already existing flowplan.<br> 04825 * The new load must belong to the same operation. 04826 */ 04827 DECLARE_EXPORT void setLoad(const Load*); 04828 04829 /** Return true when this loadplan marks the start of an operationplan. */ 04830 bool isStart() const {return start_or_end == START;} 04831 04832 /** Destructor. */ 04833 DECLARE_EXPORT virtual ~LoadPlan(); 04834 04835 /** This function needs to be called whenever the loadplan date or 04836 * quantity are changed. 04837 */ 04838 DECLARE_EXPORT void update(); 04839 04840 /** Return a pointer to the timeline data structure owning this loadplan. */ 04841 TimeLine<LoadPlan>* getTimeLine() const 04842 {return &(ld->getResource()->loadplans);} 04843 04844 /** Returns the current setup of the resource.<br> 04845 * When the argument is true (= default) the current setup is returned.<br> 04846 * When the argument is false the setup just before the loadplan is returned. 04847 */ 04848 DECLARE_EXPORT const string& getSetup(bool = true) const; 04849 04850 /** Returns true when the loadplan is hidden.<br> 04851 * This is determined by looking at whether the load is hidden or not. 04852 */ 04853 bool getHidden() const {return ld->getHidden();} 04854 04855 /** Each operationplan has 2 loadplans per load: one at the start, 04856 * when the capacity consumption starts, and one at the end, when the 04857 * capacity consumption ends.<br> 04858 * This method returns the "companion" loadplan. It is not very 04859 * scalable: the performance is linear with the number of loadplans 04860 * on the resource. 04861 */ 04862 DECLARE_EXPORT LoadPlan* getOtherLoadPlan() const; 04863 04864 static int initialize(); 04865 static DECLARE_EXPORT const MetaCategory* metadata; 04866 PyObject* getattro(const Attribute&); 04867 04868 private: 04869 /** Private constructor. It is called from the public constructor.<br> 04870 * The public constructor constructs the starting loadplan, while this 04871 * constructor creates the ending loadplan. 04872 */ 04873 DECLARE_EXPORT LoadPlan(OperationPlan*, const Load*, LoadPlan*); 04874 04875 /** This type is used to differentiate loadplans aligned with the START date 04876 * or the END date of operationplan. */ 04877 enum type {START, END}; 04878 04879 /** Is this loadplan a starting one or an ending one. */ 04880 type start_or_end; 04881 04882 /** A pointer to the load model. */ 04883 const Load *ld; 04884 04885 /** A pointer to the operationplan owning this loadplan. */ 04886 OperationPlan *oper; 04887 04888 /** Points to the next loadplan owned by the same operationplan. */ 04889 LoadPlan *nextLoadPlan; 04890 }; 04891 04892 04893 inline Date Load::getLoadplanDate(const LoadPlan* lp) const 04894 { 04895 const DateRange & dr = lp->getOperationPlan()->getDates(); 04896 if (lp->isStart()) 04897 return dr.getStart() > getEffective().getStart() ? 04898 dr.getStart() : 04899 getEffective().getStart(); 04900 else 04901 return dr.getEnd() < getEffective().getEnd() ? 04902 dr.getEnd() : 04903 getEffective().getEnd(); 04904 } 04905 04906 04907 inline double Load::getLoadplanQuantity(const LoadPlan* lp) const 04908 { 04909 if (!lp->getOperationPlan()->getDates().overlap(getEffective()) 04910 && (lp->getOperationPlan()->getDates().getDuration() 04911 || !getEffective().within(lp->getOperationPlan()->getDates().getStart()))) 04912 // Load is not effective during this time. 04913 // The extra check is required to make sure that zero duration operationplans 04914 // operationplans don't get resized to 0 04915 return 0.0; 04916 return lp->isStart() ? getQuantity() : -getQuantity(); 04917 } 04918 04919 04920 04921 /** @brief A problem of this class is created when an operationplan is being 04922 * planned in the past, i.e. it starts before the "current" date of 04923 * the plan. 04924 */ 04925 class ProblemBeforeCurrent : public Problem 04926 { 04927 public: 04928 string getDescription() const 04929 { 04930 ostringstream ch; 04931 ch << "Operation '" 04932 << (oper ? oper : static_cast<OperationPlan*>(getOwner())->getOperation()) 04933 << "' planned in the past"; 04934 return ch.str(); 04935 } 04936 bool isFeasible() const {return false;} 04937 double getWeight() const 04938 {return oper ? state.quantity : dynamic_cast<OperationPlan*>(getOwner())->getQuantity();} 04939 explicit ProblemBeforeCurrent(OperationPlan* o, bool add = true) : Problem(o), oper(NULL) 04940 {if (add) addProblem();} 04941 explicit ProblemBeforeCurrent(Operation* o, Date st, Date nd, double q) 04942 : oper(o), state(st, nd, q) {} 04943 ~ProblemBeforeCurrent() {removeProblem();} 04944 string getEntity() const {return "operation";} 04945 Object* getOwner() const 04946 {return oper ? static_cast<Object*>(oper) : dynamic_cast<OperationPlan*>(owner);} 04947 const DateRange getDates() const 04948 { 04949 if (oper) return DateRange(state.start, state.end); 04950 OperationPlan *o = dynamic_cast<OperationPlan*>(getOwner()); 04951 if (o->getDates().getEnd() > Plan::instance().getCurrent()) 04952 return DateRange(o->getDates().getStart(), 04953 Plan::instance().getCurrent()); 04954 else 04955 return DateRange(o->getDates().getStart(), 04956 o->getDates().getEnd()); 04957 } 04958 size_t getSize() const {return sizeof(ProblemBeforeCurrent);} 04959 04960 /** Return a reference to the metadata structure. */ 04961 const MetaClass& getType() const {return *metadata;} 04962 04963 /** Storing metadata on this class. */ 04964 static DECLARE_EXPORT const MetaClass* metadata; 04965 04966 private: 04967 Operation* oper; // @todo not clean and consitents to have 'extra' owner here 04968 OperationPlanState state; 04969 }; 04970 04971 04972 /** @brief A problem of this class is created when an operationplan is being 04973 * planned before its fence date, i.e. it starts 1) before the "current" 04974 * date of the plan plus the release fence of the operation and 2) after the 04975 * current date of the plan. 04976 */ 04977 class ProblemBeforeFence : public Problem 04978 { 04979 public: 04980 string getDescription() const 04981 { 04982 ostringstream ch; 04983 ch << "Operation '" 04984 << (oper ? oper : static_cast<OperationPlan*>(getOwner())->getOperation()) 04985 << "' planned before fence"; 04986 return ch.str(); 04987 } 04988 bool isFeasible() const {return true;} 04989 double getWeight() const 04990 {return oper ? state.quantity : static_cast<OperationPlan*>(getOwner())->getQuantity();} 04991 explicit ProblemBeforeFence(OperationPlan* o, bool add = true) 04992 : Problem(o), oper(NULL) 04993 {if (add) addProblem();} 04994 explicit ProblemBeforeFence(Operation* o, Date st, Date nd, double q) 04995 : oper(o), state(st, nd, q) {} 04996 ~ProblemBeforeFence() {removeProblem();} 04997 string getEntity() const {return "operation";} 04998 Object* getOwner() const 04999 {return oper ? static_cast<Object*>(oper) : dynamic_cast<OperationPlan*>(owner);} 05000 const DateRange getDates() const 05001 { 05002 if (oper) return DateRange(state.start, state.end); 05003 OperationPlan *o = dynamic_cast<OperationPlan*>(owner); 05004 if (o->getDates().getEnd() > Plan::instance().getCurrent() 05005 + o->getOperation()->getFence()) 05006 return DateRange(o->getDates().getStart(), 05007 Plan::instance().getCurrent() + o->getOperation()->getFence()); 05008 else 05009 return DateRange(o->getDates().getStart(), 05010 o->getDates().getEnd()); 05011 } 05012 size_t getSize() const {return sizeof(ProblemBeforeFence);} 05013 05014 /** Return a reference to the metadata structure. */ 05015 const MetaClass& getType() const {return *metadata;} 05016 05017 /** Storing metadata on this class. */ 05018 static DECLARE_EXPORT const MetaClass* metadata; 05019 05020 private: 05021 Operation* oper; // @todo not clean and consitents to have 'extra' owner here 05022 OperationPlanState state; 05023 }; 05024 05025 05026 /** @brief A problem of this class is created when the sequence of two 05027 * operationplans in a routing isn't respected. 05028 */ 05029 class ProblemPrecedence : public Problem 05030 { 05031 public: 05032 string getDescription() const 05033 { 05034 OperationPlan *o = static_cast<OperationPlan*>(getOwner()); 05035 if (!o->nextsubopplan) 05036 return string("Bogus precendence problem on '") 05037 + o->getOperation()->getName() + "'"; 05038 else 05039 return string("Operation '") + o->getOperation()->getName() 05040 + "' starts before operation '" 05041 + o->nextsubopplan->getOperation()->getName() +"' ends"; 05042 } 05043 bool isFeasible() const {return false;} 05044 /** The weight of the problem is equal to the duration in days. */ 05045 double getWeight() const 05046 { 05047 return static_cast<double>(getDates().getDuration()) / 86400; 05048 } 05049 explicit ProblemPrecedence(OperationPlan* o, bool add = true) : Problem(o) 05050 {if (add) addProblem();} 05051 ~ProblemPrecedence() {removeProblem();} 05052 string getEntity() const {return "operation";} 05053 Object* getOwner() const {return dynamic_cast<OperationPlan*>(owner);} 05054 const DateRange getDates() const 05055 { 05056 OperationPlan *o = static_cast<OperationPlan*>(getOwner()); 05057 return DateRange(o->nextsubopplan->getDates().getStart(), 05058 o->getDates().getEnd()); 05059 } 05060 05061 /** Return a reference to the metadata structure. */ 05062 const MetaClass& getType() const {return *metadata;} 05063 05064 /** Storing metadata on this class. */ 05065 static DECLARE_EXPORT const MetaClass* metadata; 05066 size_t getSize() const {return sizeof(ProblemPrecedence);} 05067 }; 05068 05069 05070 /** @brief A Problem of this class is created in the model when a new demand is 05071 * brought in the system, but it hasn't been planned yet. 05072 * 05073 * As a special case, a demand with a requested quantity of 0.0 doesn't create 05074 * this type of problem. 05075 */ 05076 class ProblemDemandNotPlanned : public Problem 05077 { 05078 public: 05079 string getDescription() const 05080 {return string("Demand '") + getDemand()->getName() + "' is not planned";} 05081 bool isFeasible() const {return false;} 05082 double getWeight() const {return getDemand()->getQuantity();} 05083 explicit ProblemDemandNotPlanned(Demand* d, bool add = true) : Problem(d) 05084 {if (add) addProblem();} 05085 ~ProblemDemandNotPlanned() {removeProblem();} 05086 string getEntity() const {return "demand";} 05087 const DateRange getDates() const 05088 {return DateRange(getDemand()->getDue(),getDemand()->getDue());} 05089 Object* getOwner() const {return dynamic_cast<Demand*>(owner);} 05090 Demand* getDemand() const {return dynamic_cast<Demand*>(owner);} 05091 size_t getSize() const {return sizeof(ProblemDemandNotPlanned);} 05092 05093 /** Return a reference to the metadata structure. */ 05094 const MetaClass& getType() const {return *metadata;} 05095 05096 /** Storing metadata on this class. */ 05097 static DECLARE_EXPORT const MetaClass* metadata; 05098 }; 05099 05100 05101 /** @brief A problem of this class is created when a demand is satisfied later 05102 * than the accepted tolerance after its due date. 05103 */ 05104 class ProblemLate : public Problem 05105 { 05106 public: 05107 DECLARE_EXPORT string getDescription() const; 05108 bool isFeasible() const {return true;} 05109 05110 /** The weight is equal to the delay, expressed in days.<br> 05111 * The quantity being delayed is not included. 05112 */ 05113 double getWeight() const 05114 { 05115 assert(getDemand() && !getDemand()->getDelivery().empty()); 05116 return static_cast<double>(DateRange( 05117 getDemand()->getDue(), 05118 getDemand()->getLatestDelivery()->getDates().getEnd() 05119 ).getDuration()) / 86400; 05120 } 05121 05122 /** Constructor. */ 05123 explicit ProblemLate(Demand* d, bool add = true) : Problem(d) 05124 {if (add) addProblem();} 05125 05126 /** Destructor. */ 05127 ~ProblemLate() {removeProblem();} 05128 05129 const DateRange getDates() const 05130 { 05131 assert(getDemand() && !getDemand()->getDelivery().empty()); 05132 return DateRange(getDemand()->getDue(), 05133 getDemand()->getLatestDelivery()->getDates().getEnd()); 05134 } 05135 Demand* getDemand() const {return dynamic_cast<Demand*>(getOwner());} 05136 size_t getSize() const {return sizeof(ProblemLate);} 05137 string getEntity() const {return "demand";} 05138 Object* getOwner() const {return dynamic_cast<Demand*>(owner);} 05139 05140 /** Return a reference to the metadata structure. */ 05141 const MetaClass& getType() const {return *metadata;} 05142 05143 /** Storing metadata on this class. */ 05144 static DECLARE_EXPORT const MetaClass* metadata; 05145 }; 05146 05147 05148 /** @brief A problem of this class is created when a demand is planned earlier 05149 * than the accepted tolerance before its due date. 05150 */ 05151 class ProblemEarly : public Problem 05152 { 05153 public: 05154 DECLARE_EXPORT string getDescription() const; 05155 bool isFeasible() const {return true;} 05156 double getWeight() const 05157 { 05158 assert(getDemand() && !getDemand()->getDelivery().empty()); 05159 return static_cast<double>(DateRange( 05160 getDemand()->getDue(), 05161 getDemand()->getEarliestDelivery()->getDates().getEnd() 05162 ).getDuration()) / 86400; 05163 } 05164 explicit ProblemEarly(Demand* d, bool add = true) : Problem(d) 05165 {if (add) addProblem();} 05166 ~ProblemEarly() {removeProblem();} 05167 string getEntity() const {return "demand";} 05168 Object* getOwner() const {return dynamic_cast<Demand*>(owner);} 05169 const DateRange getDates() const 05170 { 05171 assert(getDemand() && !getDemand()->getDelivery().empty()); 05172 return DateRange(getDemand()->getDue(), 05173 getDemand()->getEarliestDelivery()->getDates().getEnd()); 05174 } 05175 Demand* getDemand() const {return dynamic_cast<Demand*>(getOwner());} 05176 size_t getSize() const {return sizeof(ProblemEarly);} 05177 05178 /** Return a reference to the metadata structure. */ 05179 const MetaClass& getType() const {return *metadata;} 05180 05181 /** Storing metadata on this class. */ 05182 static DECLARE_EXPORT const MetaClass* metadata; 05183 }; 05184 05185 05186 /** @brief A Problem of this class is created in the model when a data exception 05187 * prevents planning of certain objects 05188 */ 05189 class ProblemInvalidData : public Problem 05190 { 05191 public: 05192 string getDescription() const {return description;} 05193 bool isFeasible() const {return false;} 05194 double getWeight() const {return qty;} 05195 explicit ProblemInvalidData(HasProblems* o, string d, string e, 05196 Date st, Date nd, double q, bool add = true) 05197 : Problem(o), description(d), entity(e), dates(st,nd), qty(q) 05198 {if (add) addProblem();} 05199 ~ProblemInvalidData() {removeProblem();} 05200 string getEntity() const {return entity;} 05201 const DateRange getDates() const {return dates;} 05202 Object* getOwner() const 05203 { 05204 if (entity == "demand") return dynamic_cast<Demand*>(owner); 05205 if (entity == "buffer") return dynamic_cast<Buffer*>(owner); 05206 if (entity == "resource") return dynamic_cast<Resource*>(owner); 05207 if (entity == "operation") return dynamic_cast<Operation*>(owner); 05208 throw LogicException("Unknown problem entity type"); 05209 } 05210 size_t getSize() const 05211 {return sizeof(ProblemInvalidData) + description.size() + entity.size();} 05212 05213 /** Return a reference to the metadata structure. */ 05214 const MetaClass& getType() const {return *metadata;} 05215 05216 /** Storing metadata on this class. */ 05217 static DECLARE_EXPORT const MetaClass* metadata; 05218 05219 private: 05220 /** Description of the data issue. */ 05221 string description; 05222 string entity; 05223 DateRange dates; 05224 double qty; 05225 }; 05226 05227 05228 /** @brief A problem of this class is created when a demand is planned for less than 05229 * the requested quantity. 05230 */ 05231 class ProblemShort : public Problem 05232 { 05233 public: 05234 string getDescription() const 05235 { 05236 ostringstream ch; 05237 ch << "Demand '" << getDemand()->getName() << "' planned " 05238 << (getDemand()->getQuantity() - getDemand()->getPlannedQuantity()) 05239 << " units short"; 05240 return ch.str(); 05241 } 05242 bool isFeasible() const {return true;} 05243 double getWeight() const 05244 {return getDemand()->getQuantity() - getDemand()->getPlannedQuantity();} 05245 explicit ProblemShort(Demand* d, bool add = true) : Problem(d) 05246 {if (add) addProblem();} 05247 ~ProblemShort() {removeProblem();} 05248 string getEntity() const {return "demand";} 05249 const DateRange getDates() const 05250 {return DateRange(getDemand()->getDue(), getDemand()->getDue());} 05251 Object* getOwner() const {return dynamic_cast<Demand*>(owner);} 05252 Demand* getDemand() const {return dynamic_cast<Demand*>(owner);} 05253 size_t getSize() const {return sizeof(ProblemShort);} 05254 05255 /** Return a reference to the metadata structure. */ 05256 const MetaClass& getType() const {return *metadata;} 05257 05258 /** Storing metadata on this class. */ 05259 static DECLARE_EXPORT const MetaClass* metadata; 05260 }; 05261 05262 05263 /** @brief A problem of this class is created when a demand is planned for more 05264 * than the requested quantity. 05265 */ 05266 class ProblemExcess : public Problem 05267 { 05268 public: 05269 string getDescription() const 05270 { 05271 ostringstream ch; 05272 ch << "Demand '" << getDemand()->getName() << "' planned " 05273 << (getDemand()->getPlannedQuantity() - getDemand()->getQuantity()) 05274 << " units excess"; 05275 return ch.str(); 05276 } 05277 bool isFeasible() const {return true;} 05278 double getWeight() const 05279 {return getDemand()->getPlannedQuantity() - getDemand()->getQuantity();} 05280 explicit ProblemExcess(Demand* d, bool add = true) : Problem(d) 05281 {if (add) addProblem();} 05282 string getEntity() const {return "demand";} 05283 Object* getOwner() const {return dynamic_cast<Demand*>(owner);} 05284 ~ProblemExcess() {removeProblem();} 05285 const DateRange getDates() const 05286 {return DateRange(getDemand()->getDue(), getDemand()->getDue());} 05287 Demand* getDemand() const {return dynamic_cast<Demand*>(getOwner());} 05288 size_t getSize() const {return sizeof(ProblemExcess);} 05289 05290 /** Return a reference to the metadata structure. */ 05291 const MetaClass& getType() const {return *metadata;} 05292 05293 /** Storing metadata on this class. */ 05294 static DECLARE_EXPORT const MetaClass* metadata; 05295 }; 05296 05297 05298 /** @brief A problem of this class is created when a resource is being 05299 * overloaded during a certain period of time. 05300 */ 05301 class ProblemCapacityOverload : public Problem 05302 { 05303 public: 05304 DECLARE_EXPORT string getDescription() const; 05305 bool isFeasible() const {return false;} 05306 double getWeight() const {return qty;} 05307 ProblemCapacityOverload(Resource* r, Date st, Date nd, double q, bool add = true) 05308 : Problem(r), qty(q), dr(st,nd) {if (add) addProblem();} 05309 ~ProblemCapacityOverload() {removeProblem();} 05310 string getEntity() const {return "capacity";} 05311 Object* getOwner() const {return dynamic_cast<Resource*>(owner);} 05312 const DateRange getDates() const {return dr;} 05313 Resource* getResource() const {return dynamic_cast<Resource*>(getOwner());} 05314 size_t getSize() const {return sizeof(ProblemCapacityOverload);} 05315 05316 /** Return a reference to the metadata structure. */ 05317 const MetaClass& getType() const {return *metadata;} 05318 05319 /** Storing metadata on this class. */ 05320 static DECLARE_EXPORT const MetaClass* metadata; 05321 05322 private: 05323 /** Overload quantity. */ 05324 double qty; 05325 05326 /** The daterange of the problem. */ 05327 DateRange dr; 05328 }; 05329 05330 05331 /** @brief A problem of this class is created when a resource is loaded below 05332 * its minimum during a certain period of time. 05333 */ 05334 class ProblemCapacityUnderload : public Problem 05335 { 05336 public: 05337 DECLARE_EXPORT string getDescription() const; 05338 bool isFeasible() const {return true;} 05339 double getWeight() const {return qty;} 05340 ProblemCapacityUnderload(Resource* r, DateRange d, double q, bool add = true) 05341 : Problem(r), qty(q), dr(d) {if (add) addProblem();} 05342 ~ProblemCapacityUnderload() {removeProblem();} 05343 string getEntity() const {return "capacity";} 05344 Object* getOwner() const {return dynamic_cast<Resource*>(owner);} 05345 const DateRange getDates() const {return dr;} 05346 Resource* getResource() const {return dynamic_cast<Resource*>(getOwner());} 05347 size_t getSize() const {return sizeof(ProblemCapacityUnderload);} 05348 05349 /** Return a reference to the metadata structure. */ 05350 const MetaClass& getType() const {return *metadata;} 05351 05352 /** Storing metadata on this class. */ 05353 static DECLARE_EXPORT const MetaClass* metadata; 05354 05355 private: 05356 /** Underload quantity. */ 05357 double qty; 05358 05359 /** The daterange of the problem. */ 05360 DateRange dr; 05361 }; 05362 05363 05364 /** @brief A problem of this class is created when a buffer is having a 05365 * material shortage during a certain period of time. 05366 */ 05367 class ProblemMaterialShortage : public Problem 05368 { 05369 public: 05370 DECLARE_EXPORT string getDescription() const; 05371 bool isFeasible() const {return false;} 05372 double getWeight() const {return qty;} 05373 ProblemMaterialShortage(Buffer* b, Date st, Date nd, double q, bool add = true) 05374 : Problem(b), qty(q), dr(st,nd) {if (add) addProblem();} 05375 string getEntity() const {return "material";} 05376 Object* getOwner() const {return dynamic_cast<Buffer*>(owner);} 05377 ~ProblemMaterialShortage() {removeProblem();} 05378 const DateRange getDates() const {return dr;} 05379 Buffer* getBuffer() const {return dynamic_cast<Buffer*>(getOwner());} 05380 size_t getSize() const {return sizeof(ProblemMaterialShortage);} 05381 05382 /** Return a reference to the metadata structure. */ 05383 const MetaClass& getType() const {return *metadata;} 05384 05385 /** Storing metadata on this class. */ 05386 static DECLARE_EXPORT const MetaClass* metadata; 05387 05388 private: 05389 /** Shortage quantity. */ 05390 double qty; 05391 05392 /** The daterange of the problem. */ 05393 DateRange dr; 05394 }; 05395 05396 05397 /** @brief A problem of this class is created when a buffer is carrying too 05398 * much material during a certain period of time. 05399 */ 05400 class ProblemMaterialExcess : public Problem 05401 { 05402 public: 05403 DECLARE_EXPORT string getDescription() const; 05404 bool isFeasible() const {return true;} 05405 double getWeight() const {return qty;} 05406 ProblemMaterialExcess(Buffer* b, Date st, Date nd, double q, bool add = true) 05407 : Problem(b), qty(q), dr(st,nd) {if (add) addProblem();} 05408 string getEntity() const {return "material";} 05409 ~ProblemMaterialExcess() {removeProblem();} 05410 const DateRange getDates() const {return dr;} 05411 Object* getOwner() const {return dynamic_cast<Buffer*>(owner);} 05412 Buffer* getBuffer() const {return dynamic_cast<Buffer*>(owner);} 05413 size_t getSize() const {return sizeof(ProblemMaterialExcess);} 05414 05415 /** Return a reference to the metadata structure. */ 05416 const MetaClass& getType() const {return *metadata;} 05417 05418 /** Storing metadata on this class. */ 05419 static DECLARE_EXPORT const MetaClass* metadata; 05420 05421 private: 05422 /** Excess quantity. */ 05423 double qty; 05424 05425 /** The daterange of the problem. */ 05426 DateRange dr; 05427 }; 05428 05429 05430 /** @brief This command is used to create an operationplan. 05431 * 05432 * The operationplan will have its load and loadplans created when the 05433 * command is created. It is assigned an id and added to the list of all 05434 * operationplans when the command is committed. 05435 */ 05436 class CommandCreateOperationPlan : public Command 05437 { 05438 public: 05439 /** Constructor. */ 05440 CommandCreateOperationPlan 05441 (const Operation* o, double q, Date d1, Date d2, Demand* l, 05442 OperationPlan* ow=NULL, bool makeflowsloads=true) 05443 { 05444 opplan = o ? 05445 o->createOperationPlan(q, d1, d2, l, ow, 0, makeflowsloads) 05446 : NULL; 05447 } 05448 void execute() 05449 { 05450 if (opplan) 05451 { 05452 opplan->instantiate(); 05453 opplan = NULL; // Avoid executing / initializing more than once 05454 } 05455 } 05456 void undo() {delete opplan; opplan = NULL;} 05457 bool undoable() const {return true;} 05458 ~CommandCreateOperationPlan() {if (opplan) delete opplan;} 05459 OperationPlan *getOperationPlan() const {return opplan;} 05460 05461 private: 05462 /** Pointer to the newly created operationplan. */ 05463 OperationPlan *opplan; 05464 }; 05465 05466 05467 /** @brief This command is used to delete an operationplan. 05468 * 05469 * The operationplan will be deleted when the command is created. 05470 */ 05471 class CommandDeleteOperationPlan : public Command 05472 { 05473 public: 05474 /** Constructor.<br> 05475 * Unlike most other commands the constructor already executes the deletion. 05476 */ 05477 DECLARE_EXPORT CommandDeleteOperationPlan(OperationPlan* o); 05478 void execute() {oper = NULL;} 05479 DECLARE_EXPORT void undo(); 05480 bool undoable() const {return true;} 05481 ~CommandDeleteOperationPlan() {if (oper) undo();} 05482 05483 private: 05484 /** Operation pointer of the original operationplan. */ 05485 Operation *oper; 05486 05487 /** Daterange of the original operationplan. */ 05488 DateRange dates; 05489 05490 /** Quantity of the original operationplan. */ 05491 double qty; 05492 05493 /** Identifier of the original operationplan. */ 05494 long unsigned id; 05495 05496 /** Demand pointer of the original operationplan. */ 05497 Demand *dmd; 05498 05499 /** Owner of the original operationplan. */ 05500 OperationPlan *ow; 05501 }; 05502 05503 05504 /** @brief This class represents the command of moving an operationplan to a 05505 * new date and/or resizing it. 05506 * @todo Moving in a routing operation can't be undone with the current 05507 * implementation! The command will need to store all original dates of 05508 * the suboperationplans... 05509 */ 05510 class CommandMoveOperationPlan : public Command 05511 { 05512 public: 05513 /** Constructor.<br> 05514 * Unlike most other commands the constructor already executes the change. 05515 * @param opplanptr Pointer to the operationplan being moved. 05516 * @param newStart New start date of the operationplan. 05517 * @param newEnd New end date of the operationplan. 05518 * @param newQty New quantity of the operationplan.The default is -1, 05519 * which indicates to leave the quantity unchanged. 05520 */ 05521 DECLARE_EXPORT CommandMoveOperationPlan(OperationPlan* opplanptr, 05522 Date newStart, Date newEnd, double newQty = -1.0); 05523 05524 /** Default constructor. */ 05525 DECLARE_EXPORT CommandMoveOperationPlan(OperationPlan*); 05526 05527 /** Commit the changes. */ 05528 void execute() {opplan=NULL;} 05529 05530 /** Undo the changes. */ 05531 void undo() {restore(true); opplan = NULL;} 05532 05533 /** Undo the changes. */ 05534 DECLARE_EXPORT void restore(bool = false); 05535 05536 bool undoable() const {return true;} 05537 05538 /** Destructor. */ 05539 ~CommandMoveOperationPlan() {if (opplan) undo();} 05540 05541 /** Returns the operationplan being manipulated. */ 05542 OperationPlan* getOperationPlan() const {return opplan;} 05543 05544 /** Set another start date for the operationplan. */ 05545 void setStart(Date d) {if (opplan) opplan->setStart(d);} 05546 05547 /** Set another start date, end date and quantity for the operationplan. */ 05548 void setParameters(Date s, Date e, double q, bool b) 05549 { 05550 assert(opplan->getOperation()); 05551 if (opplan) 05552 opplan->getOperation()->setOperationPlanParameters(opplan, q, s, e, b); 05553 } 05554 05555 /** Set another start date for the operationplan. */ 05556 void setEnd(Date d) {if (opplan) opplan->setEnd(d);} 05557 05558 /** Set another quantity for the operationplan. */ 05559 void setQuantity(double q) {if (opplan) opplan->setQuantity(q);} 05560 05561 /** Return the quantity of the original operationplan. */ 05562 double getQuantity() const {return originalqty; } 05563 05564 /** Return the dates of the original operationplan. */ 05565 DateRange getDates() const {return originaldates;} 05566 05567 private: 05568 /** This is a pointer to the operationplan being moved. */ 05569 OperationPlan *opplan; 05570 05571 /** These are the original dates of the operationplan before its move. */ 05572 DateRange originaldates; 05573 05574 /** This is the quantity of the operationplan before the command. */ 05575 double originalqty; 05576 05577 /** A pointer to a list of suboperationplan commands. */ 05578 Command* firstCommand; 05579 }; 05580 05581 05582 /** @brief This class models a iterator that walks over all available 05583 * HasProblem entities. 05584 * 05585 * This list is containing hard-coding the classes that are implementing 05586 * this class. It's not ideal, but we don't have an explicit container 05587 * of the objects (and we don't want one either) and this allows us also 05588 * to re-use the sorting used for the container classes. 05589 */ 05590 class HasProblems::EntityIterator 05591 { 05592 private: 05593 /** This union contains iterators through the different entity types. 05594 * Only one of the different iterators will be active at a time, and 05595 * can thus save memory by collapsing the iterators into a single 05596 * union. */ 05597 union 05598 { 05599 Buffer::iterator *bufIter; 05600 Resource::iterator *resIter; 05601 OperationPlan::iterator *operIter; 05602 Demand::iterator *demIter; 05603 }; 05604 05605 /** This type indicates which type of entity we are currently recursing 05606 * through. 05607 * - 0: buffers 05608 * - 1: resources 05609 * - 2: operationplans 05610 * - 3: demands 05611 */ 05612 unsigned short type; 05613 05614 public: 05615 /** Default constructor, which creates an iterator to the first 05616 * HasProblems object. */ 05617 explicit DECLARE_EXPORT EntityIterator(); 05618 05619 /** Used to create an iterator pointing beyond the last HasProblems 05620 * object. */ 05621 explicit EntityIterator(unsigned short i) : type(i) {} 05622 05623 /** Copy constructor. */ 05624 DECLARE_EXPORT EntityIterator(const EntityIterator& o); 05625 05626 /** Assignment operator. */ 05627 DECLARE_EXPORT EntityIterator& operator=(const EntityIterator& o); 05628 05629 /** Destructor. */ 05630 DECLARE_EXPORT ~EntityIterator(); 05631 05632 /** Pre-increment operator. */ 05633 DECLARE_EXPORT EntityIterator& operator++(); 05634 05635 /** Inequality operator.<br> 05636 * Two iterators are different when they point to different objects. 05637 */ 05638 DECLARE_EXPORT bool operator != (const EntityIterator& t) const; 05639 05640 /** Equality operator.<br> 05641 * Two iterators are equal when they point to the same object. 05642 */ 05643 bool operator == (const EntityIterator& t) const {return !(*this != t);} 05644 05645 /** Dereference operator. */ 05646 DECLARE_EXPORT HasProblems& operator*() const; 05647 05648 /** Dereference operator. */ 05649 DECLARE_EXPORT HasProblems* operator->() const; 05650 }; 05651 05652 05653 /** @brief This class models an STL-like iterator that allows us to iterate 05654 * over the named entities in a simple and safe way. 05655 * 05656 * Objects of this class are returned by the begin() and end() functions. 05657 * @see Problem::begin() 05658 * @see Problem::begin(HasProblem*) 05659 * @see Problem::end() 05660 */ 05661 class Problem::const_iterator 05662 { 05663 friend class Problem; 05664 private: 05665 /** A pointer to the current problem. If this pointer is NULL, we are 05666 * at the end of the list. */ 05667 Problem* iter; 05668 HasProblems* owner; 05669 HasProblems::EntityIterator eiter; 05670 05671 public: 05672 /** Creates an iterator that will loop through the problems of a 05673 * single entity only. <BR> 05674 * This constructor is also used to create a end-iterator, when passed 05675 * a NULL pointer as argument. 05676 */ 05677 explicit const_iterator(HasProblems* o) : iter(o ? o->firstProblem : NULL), 05678 owner(o), eiter(4) {} 05679 05680 /** Creates an iterator that will loop through the constraints of 05681 * a demand. 05682 */ 05683 explicit const_iterator(Problem* o) : iter(o), 05684 owner(NULL), eiter(4) {} 05685 05686 /** Creates an iterator that will loop through the problems of all 05687 * entities. */ 05688 explicit const_iterator() : owner(NULL) 05689 { 05690 // Loop till we find an entity with a problem 05691 while (eiter!=HasProblems::endEntity() && !(eiter->firstProblem)) 05692 ++eiter; 05693 // Found a first problem, or no problem at all 05694 iter = (eiter!=HasProblems::endEntity()) ? eiter->firstProblem : NULL; 05695 } 05696 05697 /** Pre-increment operator. */ 05698 DECLARE_EXPORT const_iterator& operator++(); 05699 05700 /** Inequality operator. */ 05701 bool operator != (const const_iterator& t) const {return iter!=t.iter;} 05702 05703 /** Equality operator. */ 05704 bool operator == (const const_iterator& t) const {return iter==t.iter;} 05705 05706 Problem& operator*() const {return *iter;} 05707 Problem* operator->() const {return iter;} 05708 }; 05709 05710 05711 /** Retrieve an iterator for the list. */ 05712 inline Problem::const_iterator Problem::List::begin() const 05713 {return Problem::const_iterator(first);} 05714 05715 05716 /** Stop iterator. */ 05717 inline Problem::const_iterator Problem::List::end() const 05718 {return Problem::const_iterator(static_cast<Problem*>(NULL));} 05719 05720 05721 /** @brief This class allows upstream and downstream navigation through 05722 * the plan. 05723 * 05724 * Downstream navigation follows the material flow from raw materials 05725 * towards the produced end item.<br> 05726 * Upstream navigation traces back the material flow from the end item up to 05727 * the consumed raw materials.<br> 05728 * The class is implemented as an STL-like iterator. 05729 * 05730 * @todo operationplans without flowplans are skipped by the iterator - not correct! 05731 */ 05732 class PeggingIterator : public Object 05733 { 05734 public: 05735 /** Constructor. */ 05736 DECLARE_EXPORT PeggingIterator(const Demand* e); 05737 05738 /** Constructor. */ 05739 PeggingIterator(const FlowPlan* e, bool b = true) 05740 : downstream(b), firstIteration(true) 05741 { 05742 if (!e) return; 05743 if (downstream) 05744 states.push(state(0,abs(e->getQuantity()),1.0,e,NULL)); 05745 else 05746 states.push(state(0,abs(e->getQuantity()),1.0,NULL,e)); 05747 initType(metadata); 05748 } 05749 05750 /** Return the operationplan consuming the material. */ 05751 OperationPlan* getConsumingOperationplan() const 05752 { 05753 const FlowPlan* x = states.top().cons_flowplan; 05754 return x ? x->getOperationPlan() : NULL; 05755 } 05756 05757 /** Return the material buffer through which we are pegging. */ 05758 Buffer *getBuffer() const 05759 { 05760 const FlowPlan* x = states.top().prod_flowplan; 05761 if (!x) x = states.top().cons_flowplan; 05762 return x ? x->getFlow()->getBuffer() : NULL; 05763 } 05764 05765 /** Return the operationplan producing the material. */ 05766 OperationPlan* getProducingOperationplan() const 05767 { 05768 const FlowPlan* x = states.top().prod_flowplan; 05769 return x ? x->getOperationPlan() : NULL; 05770 } 05771 05772 /** Return the date when the material is consumed. */ 05773 Date getConsumingDate() const 05774 { 05775 const FlowPlan* x = states.top().cons_flowplan; 05776 return x ? x->getDate() : Date::infinitePast; 05777 } 05778 05779 /** Return the date when the material is produced. */ 05780 Date getProducingDate() const 05781 { 05782 const FlowPlan* x = states.top().prod_flowplan; 05783 return x ? x->getDate() : Date::infinitePast; 05784 } 05785 05786 /** Returns the recursion depth of the iterator.<br> 05787 * The original flowplan is at level 0, and each level (either upstream 05788 * or downstream) increments the value by 1. 05789 */ 05790 short getLevel() const {return states.top().level;} 05791 05792 /** Returns the quantity of the demand that is linked to this pegging 05793 * record. 05794 */ 05795 double getQuantityDemand() const {return states.top().qty;} 05796 05797 /** Returns the quantity of the buffer flowplans that is linked to this 05798 * pegging record. 05799 */ 05800 double getQuantityBuffer() const 05801 { 05802 const state& t = states.top(); 05803 return t.prod_flowplan 05804 ? t.factor * t.prod_flowplan->getOperationPlan()->getQuantity() 05805 : 0; 05806 } 05807 05808 /** Returns which portion of the current flowplan is fed/supplied by the 05809 * original flowplan. */ 05810 double getFactor() const {return states.top().factor;} 05811 05812 /** Returns false if the flowplan remained unpegged, i.e. it wasn't 05813 * -either completely or paritally- unconsumed at the next level. 05814 */ 05815 bool getPegged() const {return states.top().pegged;} 05816 05817 /** Move the iterator foward to the next downstream flowplan. */ 05818 DECLARE_EXPORT PeggingIterator& operator++(); 05819 05820 /** Move the iterator foward to the next downstream flowplan.<br> 05821 * This post-increment operator is less efficient than the pre-increment 05822 * operator. 05823 */ 05824 PeggingIterator operator++(int) 05825 {PeggingIterator tmp = *this; ++*this; return tmp;} 05826 05827 /** Move the iterator foward to the next upstream flowplan. */ 05828 DECLARE_EXPORT PeggingIterator& operator--(); 05829 05830 /** Move the iterator foward to the next upstream flowplan.<br> 05831 * This post-increment operator is less efficient than the pre-decrement 05832 * operator. 05833 */ 05834 PeggingIterator operator--(int) 05835 {PeggingIterator tmp = *this; --*this; return tmp;} 05836 05837 /** Comparison operator. */ 05838 bool operator==(const PeggingIterator& x) const {return states == x.states;} 05839 05840 /** Inequality operator. */ 05841 bool operator!=(const PeggingIterator& x) const {return states != x.states;} 05842 05843 /** Conversion operator to a boolean value. 05844 * The return value is true when the iterator still has next elements to 05845 * explore. Returns false when the iteration is finished. 05846 */ 05847 operator bool () const {return !states.empty();} 05848 05849 /** Update the stack. */ 05850 DECLARE_EXPORT void updateStack(short, double, double, const FlowPlan*, const FlowPlan*, bool = true); 05851 05852 /** Returns true if this is a downstream iterator. */ 05853 bool isDownstream() {return downstream;} 05854 05855 /** Initialize the class. */ 05856 static int initialize(); 05857 05858 virtual void endElement(XMLInput& i, const Attribute& a, const DataElement& d) 05859 { 05860 throw LogicException("Pegging can't be read"); 05861 } 05862 virtual const MetaClass& getType() const {return *metadata;} 05863 static DECLARE_EXPORT const MetaCategory* metadata; 05864 size_t getSize() const {return sizeof(PeggingIterator);} 05865 05866 private: 05867 /** This structure is used to keep track of the iterator states during the 05868 * iteration. */ 05869 struct state 05870 { 05871 /** Stores the quantity of this flowplan that is involved. */ 05872 double qty; 05873 05874 /** Stores what portion of the flowplan is involved with the root flowplan 05875 * where the recursion started. 05876 */ 05877 double factor; 05878 05879 /** Keeps track of the number of levels we're removed from the root 05880 * flowplan where the recursion started. 05881 */ 05882 short level; 05883 05884 /** The current flowplan. */ 05885 const FlowPlan* cons_flowplan; 05886 05887 /** The current flowplan. */ 05888 const FlowPlan* prod_flowplan; 05889 05890 /** Set to false when unpegged quantities are involved. */ 05891 bool pegged; 05892 05893 /** Constructor. */ 05894 state(unsigned int l, double d, double f, 05895 const FlowPlan* fc, const FlowPlan* fp, bool p = true) 05896 : qty(d), factor(f), level(l), 05897 cons_flowplan(fc), prod_flowplan(fp), pegged(p) {}; 05898 05899 /** Inequality operator. */ 05900 bool operator != (const state& s) const 05901 { 05902 return cons_flowplan != s.cons_flowplan 05903 || prod_flowplan != s.prod_flowplan 05904 || level != s.level; 05905 } 05906 05907 /** Equality operator. */ 05908 bool operator == (const state& s) const 05909 { 05910 return cons_flowplan == s.cons_flowplan 05911 && prod_flowplan == s.prod_flowplan 05912 && level == s.level; 05913 } 05914 }; 05915 05916 /** A type to hold the iterator state. */ 05917 typedef stack < state > statestack; 05918 05919 /** A stack is used to store the iterator state. */ 05920 statestack states; 05921 05922 /** Iterate over the pegging in Python. */ 05923 DECLARE_EXPORT PyObject *iternext(); 05924 05925 DECLARE_EXPORT PyObject* getattro(const Attribute&); 05926 05927 /* Auxilary function to make recursive code possible. */ 05928 DECLARE_EXPORT void followPegging(const OperationPlan*, short, double, double); 05929 05930 /** Convenience variable during stack updates. 05931 * Depending on the value of this field, either the top element in the 05932 * stack is updated or a new state is pushed on the stack. 05933 */ 05934 bool first; 05935 05936 /** Downstream or upstream iterator. */ 05937 bool downstream; 05938 05939 /** A flag used by the Python iterators. 05940 * @see iternext() 05941 */ 05942 bool firstIteration; 05943 }; 05944 05945 05946 /** @brief An iterator class to go through all flowplans of an operationplan. 05947 * @see OperationPlan::beginFlowPlans 05948 * @see OperationPlan::endFlowPlans 05949 */ 05950 class OperationPlan::FlowPlanIterator 05951 { 05952 friend class OperationPlan; 05953 private: 05954 FlowPlan* curflowplan; 05955 FlowPlan* prevflowplan; 05956 FlowPlanIterator(FlowPlan* b) : curflowplan(b), prevflowplan(NULL) {} 05957 public: 05958 FlowPlanIterator(const FlowPlanIterator& b) 05959 { 05960 curflowplan = b.curflowplan; 05961 prevflowplan = b.prevflowplan; 05962 } 05963 bool operator != (const FlowPlanIterator &b) const 05964 {return b.curflowplan != curflowplan;} 05965 bool operator == (const FlowPlanIterator &b) const 05966 {return b.curflowplan == curflowplan;} 05967 FlowPlanIterator& operator++() 05968 { 05969 prevflowplan = curflowplan; 05970 if (curflowplan) curflowplan = curflowplan->nextFlowPlan; 05971 return *this; 05972 } 05973 FlowPlanIterator operator++(int) 05974 {FlowPlanIterator tmp = *this; ++*this; return tmp;} 05975 FlowPlan* operator ->() const {return curflowplan;} 05976 FlowPlan& operator *() const {return *curflowplan;} 05977 void deleteFlowPlan() 05978 { 05979 if (!curflowplan) return; 05980 if (prevflowplan) prevflowplan->nextFlowPlan = curflowplan->nextFlowPlan; 05981 else curflowplan->oper->firstflowplan = curflowplan->nextFlowPlan; 05982 FlowPlan* tmp = curflowplan; 05983 // Move the iterator to the next element 05984 curflowplan = curflowplan->nextFlowPlan; 05985 delete tmp; 05986 } 05987 }; 05988 05989 inline OperationPlan::FlowPlanIterator OperationPlan::beginFlowPlans() const 05990 {return OperationPlan::FlowPlanIterator(firstflowplan);} 05991 05992 inline OperationPlan::FlowPlanIterator OperationPlan::endFlowPlans() const 05993 {return OperationPlan::FlowPlanIterator(NULL);} 05994 05995 inline int OperationPlan::sizeFlowPlans() const 05996 { 05997 int c = 0; 05998 for (FlowPlanIterator i = beginFlowPlans(); i != endFlowPlans(); ++i) ++c; 05999 return c; 06000 } 06001 06002 06003 /** @brief An iterator class to go through all loadplans of an operationplan. 06004 * @see OperationPlan::beginLoadPlans 06005 * @see OperationPlan::endLoadPlans 06006 */ 06007 class OperationPlan::LoadPlanIterator 06008 { 06009 friend class OperationPlan; 06010 private: 06011 LoadPlan* curloadplan; 06012 LoadPlan* prevloadplan; 06013 LoadPlanIterator(LoadPlan* b) : curloadplan(b), prevloadplan(NULL) {} 06014 public: 06015 LoadPlanIterator(const LoadPlanIterator& b) 06016 { 06017 curloadplan = b.curloadplan; 06018 prevloadplan = b.prevloadplan; 06019 } 06020 bool operator != (const LoadPlanIterator &b) const 06021 {return b.curloadplan != curloadplan;} 06022 bool operator == (const LoadPlanIterator &b) const 06023 {return b.curloadplan == curloadplan;} 06024 LoadPlanIterator& operator++() 06025 { 06026 prevloadplan = curloadplan; 06027 if (curloadplan) curloadplan = curloadplan->nextLoadPlan; 06028 return *this; 06029 } 06030 LoadPlanIterator operator++(int) 06031 {LoadPlanIterator tmp = *this; ++*this; return tmp;} 06032 LoadPlan* operator ->() const {return curloadplan;} 06033 LoadPlan& operator *() const {return *curloadplan;} 06034 void deleteLoadPlan() 06035 { 06036 if (!curloadplan) return; 06037 if (prevloadplan) prevloadplan->nextLoadPlan = curloadplan->nextLoadPlan; 06038 else curloadplan->oper->firstloadplan = curloadplan->nextLoadPlan; 06039 LoadPlan* tmp = curloadplan; 06040 // Move the iterator to the next element 06041 curloadplan = curloadplan->nextLoadPlan; 06042 delete tmp; 06043 } 06044 }; 06045 06046 06047 inline OperationPlan::LoadPlanIterator OperationPlan::beginLoadPlans() const 06048 {return OperationPlan::LoadPlanIterator(firstloadplan);} 06049 06050 06051 inline OperationPlan::LoadPlanIterator OperationPlan::endLoadPlans() const 06052 {return OperationPlan::LoadPlanIterator(NULL);} 06053 06054 06055 inline int OperationPlan::sizeLoadPlans() const 06056 { 06057 int c = 0; 06058 for (LoadPlanIterator i = beginLoadPlans(); i != endLoadPlans(); ++i) ++c; 06059 return c; 06060 } 06061 06062 06063 class ProblemIterator 06064 : public FreppleIterator<ProblemIterator,Problem::const_iterator,Problem> 06065 { 06066 public: 06067 /** Constructor starting the iteration from a certain problem. */ 06068 ProblemIterator(Problem *x) : 06069 FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>(x) {} 06070 06071 /** Constructor starting the iteration from a certain problem. */ 06072 ProblemIterator(Problem &x) : 06073 FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>(&x) {} 06074 06075 /** Default constructor. */ 06076 ProblemIterator() : 06077 FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>() {} 06078 }; 06079 06080 06081 class BufferIterator 06082 : public FreppleIterator<BufferIterator,Buffer::iterator,Buffer> 06083 { 06084 }; 06085 06086 06087 class LocationIterator 06088 : public FreppleIterator<LocationIterator,Location::iterator,Location> 06089 { 06090 }; 06091 06092 06093 class CustomerIterator 06094 : public FreppleIterator<CustomerIterator,Customer::iterator,Customer> 06095 { 06096 }; 06097 06098 06099 class ItemIterator 06100 : public FreppleIterator<ItemIterator,Item::iterator,Item> 06101 { 06102 }; 06103 06104 class DemandIterator 06105 : public FreppleIterator<DemandIterator,Demand::iterator,Demand> 06106 { 06107 }; 06108 06109 06110 class ResourceIterator 06111 : public FreppleIterator<ResourceIterator,Resource::iterator,Resource> 06112 { 06113 }; 06114 06115 06116 class SolverIterator 06117 : public FreppleIterator<SolverIterator,Solver::iterator,Solver> 06118 { 06119 }; 06120 06121 06122 class OperationIterator 06123 : public FreppleIterator<OperationIterator,Operation::iterator,Operation> 06124 { 06125 }; 06126 06127 06128 class CalendarIterator 06129 : public FreppleIterator<CalendarIterator,Calendar::iterator,Calendar> 06130 { 06131 }; 06132 06133 06134 class SetupMatrixIterator 06135 : public FreppleIterator<SetupMatrixIterator,SetupMatrix::iterator,SetupMatrix> 06136 { 06137 }; 06138 06139 06140 // 06141 // SETUP MATRIX RULES 06142 // 06143 06144 06145 class SetupMatrixRuleIterator : public PythonExtension<SetupMatrixRuleIterator> 06146 { 06147 public: 06148 static int initialize(); 06149 06150 SetupMatrixRuleIterator(SetupMatrix* c) : matrix(c) 06151 { 06152 if (!c) 06153 throw LogicException("Creating rule iterator for NULL matrix"); 06154 currule = c->beginRules(); 06155 } 06156 06157 private: 06158 SetupMatrix* matrix; 06159 SetupMatrix::RuleIterator currule; 06160 PyObject *iternext(); 06161 }; 06162 06163 06164 // 06165 // CALENDARS 06166 // 06167 06168 06169 class CalendarBucketIterator : public PythonExtension<CalendarBucketIterator> 06170 { 06171 public: 06172 static int initialize(); 06173 06174 CalendarBucketIterator(Calendar* c) : cal(c) 06175 { 06176 if (!c) 06177 throw LogicException("Creating bucket iterator for NULL calendar"); 06178 i = c->beginBuckets(); 06179 } 06180 06181 private: 06182 Calendar* cal; 06183 Calendar::BucketIterator i; 06184 PyObject *iternext(); 06185 }; 06186 06187 06188 class CalendarEventIterator 06189 : public PythonExtension<CalendarEventIterator> 06190 { 06191 public: 06192 static int initialize(); 06193 06194 CalendarEventIterator(Calendar* c, Date d=Date::infinitePast, bool f=true) 06195 : cal(c), eventiter(c,d,f), forward(f) {} 06196 06197 private: 06198 Calendar* cal; 06199 Calendar::EventIterator eventiter; 06200 bool forward; 06201 PyObject *iternext(); 06202 }; 06203 06204 06205 // 06206 // OPERATIONPLANS 06207 // 06208 06209 06210 class OperationPlanIterator 06211 : public FreppleIterator<OperationPlanIterator,OperationPlan::iterator,OperationPlan> 06212 { 06213 public: 06214 /** Constructor to iterate over all operationplans. */ 06215 OperationPlanIterator() {} 06216 06217 /** Constructor to iterate over the operationplans of a single operation. */ 06218 OperationPlanIterator(Operation* o) 06219 : FreppleIterator<OperationPlanIterator,OperationPlan::iterator,OperationPlan>(o) 06220 {} 06221 06222 /** Constructor to iterate over the suboperationplans of an operationplans. */ 06223 OperationPlanIterator(OperationPlan* opplan) 06224 : FreppleIterator<OperationPlanIterator,OperationPlan::iterator,OperationPlan>(opplan) 06225 {} 06226 }; 06227 06228 06229 // 06230 // FLOWPLANS 06231 // 06232 06233 06234 class FlowPlanIterator : public PythonExtension<FlowPlanIterator> 06235 { 06236 public: 06237 static int initialize(); 06238 06239 FlowPlanIterator(Buffer* b) : buf(b), buffer_or_opplan(true) 06240 { 06241 if (!b) 06242 throw LogicException("Creating flowplan iterator for NULL buffer"); 06243 bufiter = new Buffer::flowplanlist::const_iterator(b->getFlowPlans().begin()); 06244 } 06245 06246 FlowPlanIterator(OperationPlan* o) : opplan(o), buffer_or_opplan(false) 06247 { 06248 if (!o) 06249 throw LogicException("Creating flowplan iterator for NULL operationplan"); 06250 opplaniter = new OperationPlan::FlowPlanIterator(o->beginFlowPlans()); 06251 } 06252 06253 ~FlowPlanIterator() 06254 { 06255 if (buffer_or_opplan) delete bufiter; 06256 else delete opplaniter; 06257 } 06258 06259 private: 06260 union 06261 { 06262 Buffer* buf; 06263 OperationPlan* opplan; 06264 }; 06265 06266 union 06267 { 06268 Buffer::flowplanlist::const_iterator *bufiter; 06269 OperationPlan::FlowPlanIterator *opplaniter; 06270 }; 06271 06272 /** Flags whether we are browsing over the flowplans in a buffer or in an 06273 * operationplan. */ 06274 bool buffer_or_opplan; 06275 06276 PyObject *iternext(); 06277 }; 06278 06279 06280 // 06281 // LOADPLANS 06282 // 06283 06284 06285 class LoadPlanIterator : public PythonExtension<LoadPlanIterator> 06286 { 06287 public: 06288 static int initialize(); 06289 06290 LoadPlanIterator(Resource* r) : res(r), resource_or_opplan(true) 06291 { 06292 if (!r) 06293 throw LogicException("Creating loadplan iterator for NULL resource"); 06294 resiter = new Resource::loadplanlist::const_iterator(r->getLoadPlans().begin()); 06295 } 06296 06297 LoadPlanIterator(OperationPlan* o) : opplan(o), resource_or_opplan(false) 06298 { 06299 if (!opplan) 06300 throw LogicException("Creating loadplan iterator for NULL operationplan"); 06301 opplaniter = new OperationPlan::LoadPlanIterator(o->beginLoadPlans()); 06302 } 06303 06304 ~LoadPlanIterator() 06305 { 06306 if (resource_or_opplan) delete resiter; 06307 else delete opplaniter; 06308 } 06309 06310 private: 06311 union 06312 { 06313 Resource* res; 06314 OperationPlan* opplan; 06315 }; 06316 06317 union 06318 { 06319 Resource::loadplanlist::const_iterator *resiter; 06320 OperationPlan::LoadPlanIterator *opplaniter; 06321 }; 06322 06323 /** Flags whether we are browsing over the flowplans in a buffer or in an 06324 * operationplan. */ 06325 bool resource_or_opplan; 06326 06327 PyObject *iternext(); 06328 }; 06329 06330 06331 // 06332 // DEMAND DELIVERY OPERATIONPLANS 06333 // 06334 06335 06336 class DemandPlanIterator : public PythonExtension<DemandPlanIterator> 06337 { 06338 public: 06339 static int initialize(); 06340 06341 DemandPlanIterator(Demand* r) : dem(r) 06342 { 06343 if (!r) 06344 throw LogicException("Creating demandplan iterator for NULL demand"); 06345 i = r->getDelivery().begin(); 06346 } 06347 06348 private: 06349 Demand* dem; 06350 Demand::OperationPlan_list::const_iterator i; 06351 PyObject *iternext(); 06352 }; 06353 06354 06355 // 06356 // LOADS 06357 // 06358 06359 06360 class LoadIterator : public PythonExtension<LoadIterator> 06361 { 06362 public: 06363 static int initialize(); 06364 06365 LoadIterator(Resource* r) 06366 : res(r), ir(r ? r->getLoads().begin() : NULL), oper(NULL), io(NULL) 06367 { 06368 if (!r) 06369 throw LogicException("Creating loadplan iterator for NULL resource"); 06370 } 06371 06372 LoadIterator(Operation* o) 06373 : res(NULL), ir(NULL), oper(o), io(o ? o->getLoads().begin() : NULL) 06374 { 06375 if (!o) 06376 throw LogicException("Creating loadplan iterator for NULL operation"); 06377 } 06378 06379 private: 06380 Resource* res; 06381 Resource::loadlist::const_iterator ir; 06382 Operation* oper; 06383 Operation::loadlist::const_iterator io; 06384 PyObject *iternext(); 06385 }; 06386 06387 06388 // 06389 // FLOW 06390 // 06391 06392 06393 class FlowIterator : public PythonExtension<FlowIterator> 06394 { 06395 public: 06396 static int initialize(); 06397 06398 FlowIterator(Buffer* b) 06399 : buf(b), ib(b ? b->getFlows().begin() : NULL), oper(NULL), io(NULL) 06400 { 06401 if (!b) 06402 throw LogicException("Creating flowplan iterator for NULL buffer"); 06403 } 06404 06405 FlowIterator(Operation* o) 06406 : buf(NULL), ib(NULL), oper(o), io(o ? o->getFlows().begin() : NULL) 06407 { 06408 if (!o) 06409 throw LogicException("Creating flowplan iterator for NULL operation"); 06410 } 06411 06412 private: 06413 Buffer* buf; 06414 Buffer::flowlist::const_iterator ib; 06415 Operation* oper; 06416 Operation::flowlist::const_iterator io; 06417 PyObject *iternext(); 06418 }; 06419 06420 06421 } // End namespace 06422 06423 #endif
Documentation generated for frePPLe by
