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