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