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