model.h
Go to the documentation of this file.
1 /***************************************************************************
2  * *
3  * Copyright (C) 2007-2013 by Johan De Taeye, frePPLe bvba *
4  * *
5  * This library is free software; you can redistribute it and/or modify it *
6  * under the terms of the GNU Affero General Public License as published *
7  * by the Free Software Foundation; either version 3 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This library is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU Affero General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU Affero General Public *
16  * License along with this program. *
17  * If not, see <http://www.gnu.org/licenses/>. *
18  * *
19  ***************************************************************************/
20 
21 #ifndef MODEL_H
22 #define MODEL_H
23 
24 /** @mainpage
25  * FrePPLe provides a framework for modeling a manufacturing environment
26  * and generating production plans.<br>
27  * This document describes its C++ API.<P>
28  *
29  * @namespace frepple
30  * @brief Core namespace
31  */
32 
33 #include "frepple/utils.h"
34 #include "frepple/timeline.h"
35 using namespace frepple::utils;
36 
37 namespace frepple
38 {
39 
40 class Flow;
41 class FlowEnd;
42 class FlowPlan;
43 class LoadPlan;
44 class Resource;
45 class ResourceInfinite;
46 class Problem;
47 class Demand;
48 class OperationPlan;
49 class Item;
50 class Operation;
51 class OperationPlanState;
52 class OperationFixedTime;
53 class OperationTimePer;
54 class OperationRouting;
55 class OperationAlternate;
56 class Buffer;
57 class BufferInfinite;
58 class BufferProcure;
59 class Plan;
60 class Plannable;
61 class Calendar;
62 class Load;
63 class Location;
64 class Customer;
65 class HasProblems;
66 class Solvable;
67 class PeggingIterator;
68 class Skill;
69 class ResourceSkill;
70 
71 
72 /** @brief This class is used for initialization. */
74 {
75  public:
76  static void initialize();
77 };
78 
79 
80 /** @brief This is the class used to represent variables that are
81  * varying over time.
82  *
83  * Some example usages for calendars:
84  * - A calendar defining the available capacity of a resource
85  * week by week.
86  * - The minimum inventory desired in a buffer week by week.
87  * - The working hours and holidays at a certain location.
88  */
89 class Calendar : public HasName<Calendar>
90 {
91  public:
92  class BucketIterator; // Forward declaration
93  class EventIterator; // Forward declaration
94 
95  /** @brief This class represents a time bucket as a part of a calendar.
96  *
97  * Manipulation of instances of this class need to be handled with the
98  * methods on the friend class Calendar.
99  * @see Calendar
100  */
101  class Bucket : public Object, public NonCopyable
102  {
103  friend class Calendar;
104  friend class BucketIterator;
105  friend class EventIterator;
106  private:
107  /** Unique identifier of the bucket within the calendar. */
108  int id;
109 
110  /** Start date of the bucket. */
111  Date startdate;
112 
113  /** End Date of the bucket. */
114  Date enddate;
115 
116  /** A pointer to the next bucket. */
117  Bucket* nextBucket;
118 
119  /** A pointer to the previous bucket. */
120  Bucket* prevBucket;
121 
122  /** Priority of this bucket, compared to other buckets effective
123  * at a certain time.
124  */
125  int priority;
126 
127  /** Weekdays on which the entry is effective.
128  * - Bit 0: Sunday
129  * - Bit 1: Monday
130  * - Bit 2: Tueday
131  * - Bit 3: Wednesday
132  * - Bit 4: Thursday
133  * - Bit 5: Friday
134  * - Bit 6: Saturday
135  */
136  short days;
137 
138  /** Starting time on the effective days. */
139  TimePeriod starttime;
140 
141  /** Ending time on the effective days. */
142  TimePeriod endtime;
143 
144  /** A pointer to the owning calendar. */
145  Calendar *cal;
146 
147  /** An internally managed data structure to keep the offsets
148  * inside the week where the entry changes effectivity. */
149  long offsets[14];
150 
151  /** An internal counter for the number of indices used in the
152  * offset array. */
153  short offsetcounter;
154 
155  /** Updates the offsets data structure. */
156  DECLARE_EXPORT void updateOffsets();
157 
158  /** Increments an iterator to the next change event.<br>
159  * A bucket will evaluate the current state of the iterator, and
160  * update it if a valid next event can be generated.
161  */
162  DECLARE_EXPORT void nextEvent(EventIterator*, Date) const;
163 
164  /** Increments an iterator to the previous change event.<br>
165  * A bucket will evaluate the current state of the iterator, and
166  * update it if a valid previous event can be generated.
167  */
168  DECLARE_EXPORT void prevEvent(EventIterator*, Date) const;
169 
170  /** Keep all calendar buckets sorted in ascending order of start date
171  * and use the priority as a tie breaker.
172  */
173  DECLARE_EXPORT void updateSort();
174 
175  protected:
176  /** Constructor. */
177  Bucket(Calendar *c, Date start, Date end, int ident=INT_MIN, int priority=0) :
178  startdate(start), enddate(end), nextBucket(NULL),
179  prevBucket(NULL), priority(priority), days(127), starttime(0L),
180  endtime(86400L), cal(c)
181  {
182  setId(ident);
183  if (c->firstBucket) c->firstBucket->prevBucket = this;
184  nextBucket = c->firstBucket;
185  c->firstBucket = this;
186  updateOffsets();
187  updateSort();
188  }
189 
190  /** Auxilary function to write out the start of the XML. */
191  DECLARE_EXPORT void writeHeader(XMLOutput *, const Keyword&) const;
192 
193  public:
194  /** Return the calendar to whom the bucket belongs. */
195  Calendar* getCalendar() const {return cal;}
196 
197  /** Get the identifier. */
198  int getId() const {return id;}
199 
200  /** Generate the identfier.<br>
201  * If a bucket with the given identifier already exists a unique
202  * number is generated instead. This is done by incrementing the
203  * value passed until it is unique.
204  */
205  DECLARE_EXPORT void setId(int ident=INT_MIN);
206 
207  /** Returns the end date of the bucket. */
208  Date getEnd() const {return enddate;}
209 
210  /** Updates the end date of the bucket. */
211  DECLARE_EXPORT void setEnd(const Date d);
212 
213  /** Returns the start date of the bucket. */
214  Date getStart() const {return startdate;}
215 
216  /** Updates the start date of the bucket. */
217  DECLARE_EXPORT void setStart(const Date d);
218 
219  /** Returns the priority of this bucket, compared to other buckets
220  * effective at a certain time.<br>
221  * Lower numbers indicate a higher priority level.<br>
222  * The default value is 0.
223  */
224  int getPriority() const {return priority;}
225 
226  /** Updates the priority of this bucket, compared to other buckets
227  * effective at a certain time.<br>
228  * Lower numbers indicate a higher priority level.<br>
229  * The default value is 0.
230  */
231  void setPriority(int f) {priority = f; updateSort();}
232 
233  /** Get the days on which the entry is valid.<br>
234  * The value is a bit pattern with bit 0 representing sunday, bit 1
235  * monday, ... and bit 6 representing saturday.<br>
236  * The default value is 127.
237  */
238  short getDays() const {return days;}
239 
240  /** Update the days on which the entry is valid. */
241  void setDays(short p)
242  {
243  if (p<0 || p>127)
244  throw DataException("Calendar bucket days must be between 0 and 127");
245  days = p;
246  updateOffsets();
247  }
248 
249  /** Return the time of the day when the entry becomes valid.<br>
250  * The default value is 0 or midnight.
251  */
252  TimePeriod getStartTime() const {return starttime;}
253 
254  /** Update the time of the day when the entry becomes valid. */
255  void setStartTime(TimePeriod t)
256  {
257  if (t > 86399L || t < 0L)
258  throw DataException("Calendar bucket start time must be between 0 and 86399 seconds");
259  starttime = t;
260  updateOffsets();
261  }
262 
263  /** Return the time of the day when the entry becomes invalid.<br>
264  * The default value is 23h59m59s.
265  */
266  TimePeriod getEndTime() const {return endtime;}
267 
268  /** Update the time of the day when the entry becomes invalid. */
269  void setEndTime(TimePeriod t)
270  {
271  if (t > 86400L || t < 0L)
272  throw DataException("Calendar bucket end time must be between 0 and 86400 seconds");
273  endtime = t;
274  updateOffsets();
275  }
276 
277  /** Convert the value of the bucket to a boolean value. */
278  virtual bool getBool() const {return true;}
279 
280  virtual DECLARE_EXPORT void writeElement
281  (XMLOutput*, const Keyword&, mode=DEFAULT) const;
282 
283  /** Reads the bucket information from the input. Only the fields "name"
284  * and "start" are read in. Other fields as also written out but these
285  * are information-only fields.
286  */
287  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
288 
289  virtual const MetaClass& getType() const {return *metadata;}
290  virtual size_t getSize() const {return sizeof(Bucket);}
292  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
293  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
294  static int initialize();
295  };
296 
297  /** Default constructor. */
298  Calendar(const string& n) : HasName<Calendar>(n), firstBucket(NULL) {}
299 
300  /** Destructor, which cleans up the buckets too and all references to the
301  * calendar from the core model.
302  */
304 
305  /** Convert the value of the calendar to a boolean value. */
306  virtual bool getBool() const {return false;}
307 
308  /** This is a factory method that creates a new bucket using the start
309  * date as the key field. The fields are passed as an array of character
310  * pointers.<br>
311  * This method is intended to be used to create objects when reading
312  * XML input data.
313  */
314  DECLARE_EXPORT Bucket* createBucket(const AttributeList&);
315 
316  /** Adds a new bucket to the list. */
317  DECLARE_EXPORT Bucket* addBucket(Date, Date, int = 1);
318 
319  /** Removes a bucket from the list. */
320  DECLARE_EXPORT void removeBucket(Bucket* bkt);
321 
322  /** Returns the bucket where a certain date belongs to.
323  * A NULL pointer is returned when no bucket is effective.
324  */
325  DECLARE_EXPORT Bucket* findBucket(Date d, bool fwd = true) const;
326 
327  /** Returns the bucket with a certain identifier.
328  * A NULL pointer is returned in case no bucket can be found with the
329  * given identifier.
330  */
331  DECLARE_EXPORT Bucket* findBucket(int ident) const;
332 
333  /** Find an existing bucket with a given identifier, or create a new one.
334  * If no identifier is passed, we always create a new bucket and automatically
335  * generate a unique identifier for it.
336  */
337  static DECLARE_EXPORT PyObject* addPythonBucket(PyObject*, PyObject*, PyObject*);
338 
339  /** @brief An iterator class to go through all dates where the calendar
340  * value changes.*/
342  {
343  friend class Calendar::Bucket;
344  protected:
351  public:
352  const Date& getDate() const {return curDate;}
353  const Bucket* getBucket() const {return curBucket;}
354  const Calendar* getCalendar() const {return theCalendar;}
356  bool forward = true) : theCalendar(c), curDate(d)
357  {
358  curBucket = lastBucket = c ? c->findBucket(d,forward) : NULL;
359  curPriority = lastPriority = curBucket ? curBucket->priority : INT_MAX;
360  };
361  DECLARE_EXPORT EventIterator& operator++();
362  DECLARE_EXPORT EventIterator& operator--();
363  EventIterator operator++(int)
364  {
365  EventIterator tmp = *this; ++*this; return tmp;
366  }
367  EventIterator operator--(int)
368  {
369  EventIterator tmp = *this; --*this; return tmp;
370  }
371  };
372 
373  /** @brief An iterator class to go through all buckets of the calendar. */
375  {
376  private:
377  Bucket* curBucket;
378  public:
379  BucketIterator(Bucket* b = NULL) : curBucket(b) {}
380  bool operator != (const BucketIterator &b) const
381  {return b.curBucket != curBucket;}
382  bool operator == (const BucketIterator &b) const
383  {return b.curBucket == curBucket;}
384  BucketIterator& operator++()
385  {if (curBucket) curBucket = curBucket->nextBucket; return *this;}
386  BucketIterator operator++(int)
387  {BucketIterator tmp = *this; ++*this; return tmp;}
388  BucketIterator& operator--()
389  {if(curBucket) curBucket = curBucket->prevBucket; return *this;}
390  BucketIterator operator--(int)
391  {BucketIterator tmp = *this; --*this; return tmp;}
392  Bucket* operator ->() const {return curBucket;}
393  Bucket& operator *() const {return *curBucket;}
394  };
395 
396  /** Returns an iterator to go through the list of buckets. */
397  BucketIterator beginBuckets() const {return BucketIterator(firstBucket);}
398 
399  /** Returns an iterator to go through the list of buckets. */
400  BucketIterator endBuckets() const {return BucketIterator(NULL);}
401 
402  DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
403  void endElement(XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement) {}
404  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
405  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
406  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
407  static int initialize();
408 
409  static DECLARE_EXPORT PyObject* getEvents(PyObject*, PyObject*);
410 
411  virtual const MetaClass& getType() const {return *metadata;}
413 
414  virtual size_t getSize() const
415  {
416  size_t i = sizeof(Calendar) + getName().size();
417  for (BucketIterator j = beginBuckets(); j!= endBuckets(); ++j)
418  i += j->getSize();
419  return i;
420  }
421 
422  protected:
423  /** Find the lowest priority of any bucket. */
424  int lowestPriority() const
425  {
426  int min = 0;
427  for (BucketIterator i = beginBuckets(); i != endBuckets(); ++i)
428  if (i->getPriority() < min) min = i->getPriority();
429  return min;
430  }
431 
432  private:
433  /** A pointer to the first bucket. The buckets are stored in a doubly
434  * linked list. */
435  Bucket* firstBucket;
436 
437  /** This is the factory method used to generate new buckets. Each subclass
438  * should provide an override for this function. */
439  virtual Bucket* createNewBucket(Date start, Date end, int id=1, int priority=0)
440  {return new Bucket(this, start, end, id, priority);}
441 };
442 
443 
444 /** @brief A calendar storing double values in its buckets. */
445 class CalendarDouble : public Calendar
446 {
447  public:
448  /** @brief A special type of calendar bucket, designed to hold a
449  * a value.
450  * @see Calendar::Bucket
451  */
453  {
454  friend class CalendarDouble;
455  private:
456  /** This is the value stored in this bucket. */
457  double val;
458 
459  /** Constructor. */
460  BucketDouble(CalendarDouble *c, Date start, Date end, int id=INT_MIN, int priority=0)
461  : Bucket(c, start, end, id, priority), val(0) {initType(metadata);}
462 
463  public:
464  /** Returns the value of this bucket. */
465  double getValue() const {return val;}
466 
467  /** Convert the value of the bucket to a boolean value. */
468  bool getBool() const {return val != 0;}
469 
470  /** Updates the value of this bucket. */
471  void setValue(const double v) {val = v;}
472 
473  void writeElement
474  (XMLOutput *o, const Keyword& tag, mode m = DEFAULT) const
475  {
476  assert(m == DEFAULT || m == FULL);
477  writeHeader(o, tag);
478  if (getPriority()) o->writeElement(Tags::tag_priority, getPriority());
479  if (val) o->writeElement(Tags::tag_value, val);
480  o->EndObject(tag);
481  }
482 
483  void endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
484  {
485  if (pAttr.isA(Tags::tag_value))
486  pElement >> val;
487  else
488  Bucket::endElement(pIn, pAttr, pElement);
489  }
490 
491 
492  virtual size_t getSize() const
493  {return sizeof(CalendarDouble::BucketDouble);}
494 
496  virtual const MetaClass& getType() const {return *metadata;}
497  static int initialize();
498  };
499 
500  /** @brief A special event iterator, providing also access to the
501  * current value. */
503  {
504  public:
505  /** Constructor. */
507  bool f = true) : Calendar::EventIterator(c,d,f) {}
508 
509  /** Return the current value of the iterator at this date. */
510  double getValue()
511  {
512  return curBucket ?
513  static_cast<const CalendarDouble::BucketDouble*>(curBucket)->getValue() :
514  static_cast<const CalendarDouble*>(theCalendar)->getDefault();
515  }
516  };
517 
518  public:
519  /** Default constructor. */
520  CalendarDouble(const string& n) : Calendar(n)
521  {setDefault(0.0); initType(metadata);}
522 
523  /** Destructor. */
525 
526  virtual const MetaClass& getType() const {return *metadata;}
528  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
529  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
530  static int initialize();
531 
532  static DECLARE_EXPORT PyObject* setPythonValue(PyObject*, PyObject*, PyObject*);
533 
534  void endElement(XMLInput&, const Attribute&, const DataElement&);
535  void writeElement(XMLOutput*, const Keyword&, mode m=DEFAULT) const;
536 
537  /** Returns the value on the specified date. */
538  double getValue(const Date d) const
539  {
540  BucketDouble* x = static_cast<BucketDouble*>(findBucket(d));
541  return x ? x->getValue() : defaultValue;
542  }
543 
544  /** Updates the value in a certain date range.<br>
545  * This will create a new bucket if required.
546  */
547  void setValue(Date start, Date end, const double v);
548 
549  double getValue(Calendar::BucketIterator& i) const
550  {
551  return reinterpret_cast<BucketDouble&>(*i).getValue();
552  }
553 
554  /** Returns the default calendar value when no entry is matching. */
555  double getDefault() const {return defaultValue;}
556 
557  /** Convert the value of the calendar to a boolean value. */
558  virtual bool getBool() const {return defaultValue != 0;}
559 
560  /** Update the default calendar value when no entry is matching. */
561  virtual void setDefault(const double v) {defaultValue = v;}
562 
563  private:
564  /** Factory method to add new buckets to the calendar.
565  * @see Calendar::addBucket()
566  */
567  Bucket* createNewBucket(Date start, Date end, int id, int priority=0)
568  {return new BucketDouble(this, start, end, id, priority);}
569 
570  /** Value when no bucket is matching a certain date. */
571  double defaultValue;
572 };
573 
574 
575 /** @brief A problem represents infeasibilities, alerts and warnings in
576  * the plan.
577  *
578  * Problems are maintained internally by the system. They are thus only
579  * exported, meaning that you can't directly import or create problems.<br>
580  * This class is the pure virtual base class for all problem types.<br>
581  * The usage of the problem objects is based on the following principles:
582  * - Problems objects are passive. They don't actively change the model
583  * state.
584  * - Objects of the HasProblems class actively create and destroy Problem
585  * objects.
586  * - Problem objects are managed in a 'lazy' way, meaning they only are
587  * getting created when the list of problems is requested by the user.<br>
588  * During normal planning activities we merely mark the planning entities
589  * that have changed, so we can easily pick up which entities to recompute
590  * the problems for. In this way we can avoid the cpu and memory overhead
591  * of keeping the problem list up to date at all times, while still
592  * providing the user with the correct list of problems when required.
593  * - Given the above, Problems are lightweight objects that consume
594  * limited memory.
595  */
596 class Problem : public NonCopyable, public Object
597 {
598  public:
600  friend class const_iterator;
601  class List;
602  friend class List;
603 
604  /** Constructor.<br>
605  * Note that this method can't manipulate the problem container, since
606  * the problem objects aren't fully constructed yet.
607  * @see addProblem
608  */
609  explicit Problem(HasProblems *p = NULL) : owner(p), nextProblem(NULL)
610  {initType(metadata);}
611 
612  /** Initialize the class. */
613  static int initialize();
614 
615  /** Destructor.
616  * @see removeProblem
617  */
618  virtual ~Problem() {}
619 
620  /** Returns the duration of this problem. */
621  virtual const DateRange getDates() const = 0;
622 
623  /** Returns a text description of this problem. */
624  virtual string getDescription() const = 0;
625 
626  /** Returns the object type having this problem. */
627  virtual string getEntity() const = 0;
628 
629  /** Returns true if the plan remains feasible even if it contains this
630  * problem, i.e. if the problems flags only a warning.
631  * Returns false if a certain problem points at an infeasibility of the
632  * plan.
633  */
634  virtual bool isFeasible() const = 0;
635 
636  /** Returns a double number reflecting the magnitude of the problem. This
637  * allows us to focus on the significant problems and filter out the
638  * small ones.
639  */
640  virtual double getWeight() const = 0;
641 
642  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
643  void endElement(XMLInput&, const Attribute&, const DataElement&) {}
644  static DECLARE_EXPORT void writer(const MetaCategory*, XMLOutput*);
645 
646  PyObject* getattro(const Attribute&);
647 
648  PyObject* str() const
649  {
650  return PythonObject(getDescription());
651  }
652 
653  /** Returns an iterator to the very first problem. The iterator can be
654  * incremented till it points past the very last problem. */
655  static DECLARE_EXPORT const_iterator begin();
656 
657  /** Return an iterator to the first problem of this entity. The iterator
658  * can be incremented till it points past the last problem of this
659  * plannable entity.<br>
660  * The boolean argument specifies whether the problems need to be
661  * recomputed as part of this method.
662  */
663  static DECLARE_EXPORT const_iterator begin(HasProblems*, bool = true);
664 
665  /** Return an iterator pointing beyond the last problem. */
666  static DECLARE_EXPORT const const_iterator end();
667 
668  /** Erases the list of all problems. This methods can be used reduce the
669  * memory consumption at critical points. The list of problems will be
670  * recreated when the problem detection is triggered again.
671  */
672  static DECLARE_EXPORT void clearProblems();
673 
674  /** Erases the list of problems linked with a certain plannable object.<br>
675  * If the second parameter is set to true, the problems will be
676  * recreated when the next problem detection round is triggered.
677  */
678  static DECLARE_EXPORT void clearProblems(HasProblems& p, bool setchanged = true);
679 
680  /** Returns a pointer to the object that owns this problem. */
681  virtual Object* getOwner() const = 0;
682 
683  /** Return a reference to the metadata structure. */
684  virtual const MetaClass& getType() const {return *metadata;}
685 
686  /** Storing metadata on this class. */
688 
689  protected:
690  /** Each Problem object references a HasProblem object as its owner. */
692 
693  /** Each Problem contains a pointer to the next pointer for the same
694  * owner. This class implements thus an intrusive single linked list
695  * of Problem objects. */
697 
698  /** Adds a newly created problem to the problem container.
699  * This method needs to be called in the constructor of a problem
700  * subclass. It can't be called from the constructor of the base
701  * Problem class, since the object isn't fully created yet and thus
702  * misses the proper information used by the compare method.
703  * @see removeProblem
704  */
705  DECLARE_EXPORT void addProblem();
706 
707  /** Removes a problem from the problem container.
708  * This method needs to be called from the destructor of a problem
709  * subclass.<br>
710  * Due to the single linked list data structure, this methods'
711  * performance is linear with the number of problems of an entity.
712  * This is acceptable since we don't expect entities with a huge amount
713  * of problems.
714  * @see addproblem
715  */
716  DECLARE_EXPORT void removeProblem();
717 
718  /** Comparison of 2 problems.<br>
719  * To garantuee that the problems are sorted in a consistent and stable
720  * way, the following sorting criteria are used (in order of priority):
721  * <ol><li>Entity<br>
722  * This sort is to be ensured by the client. This method can't
723  * compare problems of different entities!</li>
724  * <li>Type<br>
725  * Each problem type has a hashcode used for sorting.</li>
726  * <li>Start date</li></ol>
727  * The sorting is expected such that it can be used as a key, i.e. no
728  * two problems of will ever evaluate to be identical.
729  */
730  DECLARE_EXPORT bool operator < (const Problem& a) const;
731 };
732 
733 
734 /** @brief Classes that keep track of problem conditions need to implement
735  * this class.
736  *
737  * This class is closely related to the Problem class.
738  * @see Problem
739  */
741 {
743  friend class Problem;
744  public:
745  class EntityIterator;
746 
747  /** Returns an iterator pointing to the first HasProblem object. */
748  static DECLARE_EXPORT EntityIterator beginEntity();
749 
750  /** Returns an iterator pointing beyond the last HasProblem object. */
751  static DECLARE_EXPORT EntityIterator endEntity();
752 
753  /** Constructor. */
754  HasProblems() : firstProblem(NULL) {}
755 
756  /** Destructor. It needs to take care of making sure all problems objects
757  * are being deleted as well. */
758  virtual ~HasProblems() {Problem::clearProblems(*this, false);}
759 
760  /** Returns the plannable entity relating to this problem container. */
761  virtual Plannable* getEntity() const = 0;
762 
763  /** Called to update the list of problems. The function will only be
764  * called when:
765  * - the list of problems is being recomputed
766  * - AND, problem detection is enabled for this object
767  * - AND, the object has changed since the last problem computation
768  */
769  virtual void updateProblems() = 0;
770 
771  private:
772  /** A pointer to the first problem of this object. Problems are maintained
773  * in a single linked list. */
774  Problem* firstProblem;
775 };
776 
777 
778 /** @brief This auxilary class is used to maintain a list of problem models. */
780 {
781  public:
782  /** Constructor. */
783  List() : first(NULL) {};
784 
785  /** Destructor. */
786  ~List() {clear();}
787 
788  /** Empty the list.<br>
789  * If a problem is passed as argument, that problem and all problems
790  * following it in the list are deleted.<br>
791  * If no argument is passed, the complete list is erased.
792  */
793  DECLARE_EXPORT void clear(Problem * = NULL);
794 
795  /** Add a problem to the list. */
796  DECLARE_EXPORT Problem* push
797  (const MetaClass*, const Object*, Date, Date, double);
798 
799  /** Remove all problems from the list that appear AFTER the one
800  * passed as argument. */
801  DECLARE_EXPORT void pop(Problem *);
802 
803  /** Get the last problem on the list. */
804  DECLARE_EXPORT Problem* top() const;
805 
806  /** Cur the list in two parts . */
808  {
809  Problem *tmp = p->nextProblem;
810  p->nextProblem = NULL;
811  return tmp;
812  }
813 
814  /** Returns true if the list is empty. */
815  bool empty() const {return first == NULL;}
816 
817  /** Return an iterator to the start of the list. */
818  Problem::const_iterator begin() const;
819 
820  /** End iterator. */
821  Problem::const_iterator end() const;
822 
823  private:
824  /** Pointer to the head of the list. */
825  Problem* first;
826 };
827 
828 
829 /** @brief This class is an implementation of the "visitor" design pattern.
830  * It is intended as a basis for different algorithms processing the frePPLe
831  * data.
832  *
833  * The goal is to decouple the solver/algorithms from the model/data
834  * representation. Different solvers can be easily be plugged in to work on
835  * the same data.
836  */
837 class Solver : public HasName<Solver>
838 {
839  public:
840  explicit Solver(const string& n) : HasName<Solver>(n), loglevel(0) {}
841  virtual ~Solver() {}
842 
843  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
844  virtual DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
845  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
846  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
847  static int initialize();
848 
849  static DECLARE_EXPORT PyObject* solve(PyObject*, PyObject*);
850 
851  virtual void solve(void* = NULL) = 0;
852  virtual void solve(const Demand*,void* = NULL)
853  {throw LogicException("Called undefined solve(Demand*) method");}
854  virtual void solve(const Operation*,void* = NULL)
855  {throw LogicException("Called undefined solve(Operation*) method");}
856  virtual void solve(const OperationFixedTime* o, void* v = NULL)
857  {solve(reinterpret_cast<const Operation*>(o),v);}
858  virtual void solve(const OperationTimePer* o, void* v = NULL)
859  {solve(reinterpret_cast<const Operation*>(o),v);}
860  virtual void solve(const OperationRouting* o, void* v = NULL)
861  {solve(reinterpret_cast<const Operation*>(o),v);}
862  virtual void solve(const OperationAlternate* o, void* v = NULL)
863  {solve(reinterpret_cast<const Operation*>(o),v);}
864  virtual void solve(const Resource*,void* = NULL)
865  {throw LogicException("Called undefined solve(Resource*) method");}
866  virtual void solve(const ResourceInfinite* r, void* v = NULL)
867  {solve(reinterpret_cast<const Resource*>(r),v);}
868  virtual void solve(const Buffer*,void* = NULL)
869  {throw LogicException("Called undefined solve(Buffer*) method");}
870  virtual void solve(const BufferInfinite* b, void* v = NULL)
871  {solve(reinterpret_cast<const Buffer*>(b),v);}
872  virtual void solve(const BufferProcure* b, void* v = NULL)
873  {solve(reinterpret_cast<const Buffer*>(b),v);}
874  virtual void solve(const Load* b, void* v = NULL)
875  {throw LogicException("Called undefined solve(Load*) method");}
876  virtual void solve(const Flow* b, void* v = NULL)
877  {throw LogicException("Called undefined solve(Flow*) method");}
878  virtual void solve(const FlowEnd* b, void* v = NULL)
879  {solve(reinterpret_cast<const Flow*>(b),v);}
880  virtual void solve(const Solvable*,void* = NULL)
881  {throw LogicException("Called undefined solve(Solvable*) method");}
882 
883  /** Returns how elaborate and verbose output is requested.<br>
884  * As a guideline solvers should respect the following guidelines:
885  * - 0:<br>
886  * Completely silent.<br>
887  * This is the default value.
888  * - 1:<br>
889  * Minimal and high-level messages on the progress that are sufficient
890  * for logging normal operation.<br>
891  * - 2:<br>
892  * Higher numbers are solver dependent. These levels are typically
893  * used for debugging and tracing, and provide more detail on the
894  * solver's progress.
895  */
896  unsigned short getLogLevel() const {return loglevel;}
897 
898  /** Controls whether verbose output will be generated. */
899  void setLogLevel(unsigned short v) {loglevel = v;}
900 
901  virtual const MetaClass& getType() const {return *metadata;}
903 
904  private:
905  /** Controls the amount of tracing and debugging messages. */
906  unsigned short loglevel;
907 };
908 
909 
910 /** @brief This class needs to be implemented by all classes that implement
911  * dynamic behavior, and which can be called by a solver.
912  */
913 class Solvable
914 {
915  public:
916  /** This method is called by solver classes. The implementation of this
917  * class simply calls the solve method on the solver class. Using the
918  * polymorphism the solver can implement seperate methods for different
919  * plannable subclasses.
920  */
921  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
922 
923  /** Destructor. */
924  virtual ~Solvable() {}
925 };
926 
927 
928 /** @brief This class needs to be implemented by all classes that implement
929  * dynamic behavior in the plan.
930  *
931  * The problem detection logic is implemented in the detectProblems() method.
932  * For performance reasons, problem detection is "lazy", i.e. problems are
933  * computed only when somebody really needs the access to the list of
934  * problems.
935  */
936 class Plannable : public HasProblems, public Solvable
937 {
938  public:
939  /** Constructor. */
940  Plannable() : useProblemDetection(true), changed(true)
941  {anyChange = true;}
942 
943  /** Specify whether this entity reports problems. */
944  DECLARE_EXPORT void setDetectProblems(bool b);
945 
946  /** Returns whether or not this object needs to detect problems. */
947  bool getDetectProblems() const {return useProblemDetection;}
948 
949  /** Loops through all plannable objects and updates their problems if
950  * required. */
951  static DECLARE_EXPORT void computeProblems();
952 
953  /** See if this entity has changed since the last problem
954  * problem detection run. */
955  bool getChanged() const {return changed;}
956 
957  /** Mark that this entity has been updated and that the problem
958  * detection needs to be redone. */
959  void setChanged(bool b = true) {changed=b; if (b) anyChange=true;}
960 
961  /** Implement the pure virtual function from the HasProblem class. */
962  Plannable* getEntity() const {return const_cast<Plannable*>(this);}
963 
964  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
965  virtual DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
966 
967  private:
968  /** Stores whether this entity should be skip problem detection, or not. */
969  bool useProblemDetection;
970 
971  /** Stores whether this entity has been updated since the last problem
972  * detection run. */
973  bool changed;
974 
975  /** Marks whether any entity at all has changed its status since the last
976  * problem detection round.
977  */
978  static DECLARE_EXPORT bool anyChange;
979 
980  /** This flag is set to true during the problem recomputation. It is
981  * required to garantuee safe access to the problems in a multi-threaded
982  * environment.
983  */
984  static DECLARE_EXPORT bool computationBusy;
985 };
986 
987 
988 /** @brief The purpose of this class is to compute the levels of all buffers,
989  * operations and resources in the model, and to categorize them in clusters.
990  *
991  * Resources and buffers linked to the delivery operations of
992  * the demand are assigned level 1. buffers one level upstream have
993  * level 2, and so on...
994  *
995  * A cluster is group of planning entities (buffers, resources and operations)
996  * that are linked together using loads and/or flows. Each cluster can be seen
997  * as a completely independent part of the model and the planning problem.
998  * There is no interaction possible between clusters.
999  * Clusters are helpful is multi-threading the planning problem, partial
1000  * replanning of the model, etc...
1001  */
1003 {
1004  private:
1005  /** Flags whether the current computation is still up to date or not.
1006  * The flag is set when new objects of this are created or updated.
1007  * Running the computeLevels function clears the flag.
1008  */
1009  static DECLARE_EXPORT bool recomputeLevels;
1010 
1011  /** This flag is set to true during the computation of the levels. It is
1012  * required to ensure safe access to the level information in a
1013  * multi-threaded environment.
1014  */
1015  static DECLARE_EXPORT bool computationBusy;
1016 
1017  /** Stores the total number of clusters in the model. */
1018  static DECLARE_EXPORT unsigned short numberOfClusters;
1019 
1020  /** Stores the total number of hanging clusters in the model. */
1021  static DECLARE_EXPORT unsigned short numberOfHangingClusters;
1022 
1023  /** Stores the level of this entity. Higher numbers indicate more
1024  * upstream entities.
1025  * A value of -1 indicates an unused entity.
1026  */
1027  short lvl;
1028 
1029  /** Stores the cluster number of the current entity. */
1030  unsigned short cluster;
1031 
1032  protected:
1033  /** Default constructor. The initial level is -1 and basically indicates
1034  * that this HasHierarchy (either Operation, Buffer or Resource) is not
1035  * being used at all...
1036  */
1037  HasLevel() : lvl(0), cluster(0) {}
1038 
1039  /** Copy constructor. Since the characterictics of the new object are the
1040  * same as the original, the level and cluster are also the same.
1041  * No recomputation is required.
1042  */
1043  HasLevel(const HasLevel& o) : lvl(o.lvl), cluster(o.cluster) {}
1044 
1045  /** Destructor. Deleting a HasLevel object triggers recomputation of the
1046  * level and cluster computation, since the network now has changed.
1047  */
1048  ~HasLevel() {recomputeLevels = true;}
1049 
1050  /** This function recomputes all levels in the model.
1051  * It is called automatically when the getLevel or getCluster() function
1052  * on a Buffer, Resource or Operation are called while the
1053  * "recomputeLevels" flag is set.
1054  * Right, this is an example of a 'lazy' algorithm: only compute the
1055  * information when it is required. Note however that the computation
1056  * is triggered over the complete model, not a subset...
1057  * The runtime of the algorithm is pretty much linear with the total
1058  * number of operations in the model. The cluster size also has some
1059  * (limited) impact on the performance: a network with larger cluster
1060  * size will take longer to analyze.
1061  * @exception LogicException Generated when there are too many clusters in
1062  * your model. The maximum limit is USHRT_MAX, i.e. the greatest
1063  * number that can be stored in a variable of type "unsigned short".
1064  * The limit is platform dependent. On 32-bit platforms it will
1065  * typically be 65535.
1066  */
1067  static DECLARE_EXPORT void computeLevels();
1068 
1069  public:
1070  /** Returns the total number of clusters.<br>
1071  * If not up to date the recomputation will be triggered.
1072  */
1073  static unsigned short getNumberOfClusters()
1074  {
1075  if (recomputeLevels || computationBusy) computeLevels();
1076  return numberOfClusters;
1077  }
1078 
1079  /** Returns the total number of hanging clusters. A hanging cluster
1080  * is a cluster that consists of a single entity that isn't connected
1081  * to any other entity.<br>
1082  * If not up to date the recomputation will be triggered.
1083  */
1084  static unsigned short getNumberOfHangingClusters()
1085  {
1086  if (recomputeLevels || computationBusy) computeLevels();
1087  return numberOfHangingClusters;
1088  }
1089 
1090  /** Return the level (and recompute first if required). */
1091  short getLevel() const
1092  {
1093  if (recomputeLevels || computationBusy) computeLevels();
1094  return lvl;
1095  }
1096 
1097  /** Return the cluster number (and recompute first if required). */
1098  unsigned short getCluster() const
1099  {
1100  if (recomputeLevels || computationBusy) computeLevels();
1101  return cluster;
1102  }
1103 
1104  /** This function should be called when something is changed in the network
1105  * structure. The notification sets a flag, but does not immediately
1106  * trigger the recomputation.
1107  * @see computeLevels
1108  */
1109  static void triggerLazyRecomputation() {recomputeLevels = true;}
1110 };
1111 
1112 
1113 /** @brief This abstract class is used to associate buffers and resources with
1114  * a physical or logical location.
1115  *
1116  * The 'available' calendar is used to model the working hours and holidays
1117  * of resources, buffers and operations.
1118  */
1119 class Location : public HasHierarchy<Location>, public HasDescription
1120 {
1121  public:
1122  /** Constructor. */
1123  explicit Location(const string& n) : HasHierarchy<Location>(n), available(NULL) {}
1124 
1125  /** Destructor. */
1126  virtual DECLARE_EXPORT ~Location();
1127 
1128  /** Returns the availability calendar of the location.<br>
1129  * The availability calendar models the working hours and holidays. It
1130  * applies to all operations, resources and buffers using this location.
1131  */
1132  CalendarDouble *getAvailable() const {return available;}
1133 
1134  /** Updates the availability calendar of the location. */
1135  void setAvailable(CalendarDouble* b) {available = b;}
1136 
1137  DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
1138  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
1139  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
1140  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
1141  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
1142  size_t extrasize() const
1143  {return getName().size() + HasDescription::extrasize();}
1144  virtual const MetaClass& getType() const {return *metadata;}
1146  static int initialize();
1147 
1148  private:
1149  /** The availability calendar models the working hours and holidays. It
1150  * applies to all operations, resources and buffers using this location.
1151  */
1152  CalendarDouble* available;
1153 };
1154 
1155 
1156 /** @brief This class implements the abstract Location class. */
1158 {
1159  public:
1160  explicit LocationDefault(const string& str) : Location(str) {initType(metadata);}
1161  virtual const MetaClass& getType() const {return *metadata;}
1163  virtual size_t getSize() const
1164  {return sizeof(LocationDefault) + Location::extrasize();}
1165  static int initialize();
1166 };
1167 
1168 
1169 /** @brief This abstracts class represents customers.
1170  *
1171  * Demands can be associated with a customer, but there is no planning
1172  * behavior directly linked to customers.
1173  */
1174 class Customer : public HasHierarchy<Customer>, public HasDescription
1175 {
1176  public:
1177  DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
1178  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
1179  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
1180  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
1181  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
1182  size_t extrasize() const
1183  {return getName().size() + HasDescription::extrasize();}
1184  Customer(const string& n) : HasHierarchy<Customer>(n) {}
1185  virtual DECLARE_EXPORT ~Customer();
1186  virtual const MetaClass& getType() const {return *metadata;}
1188  static int initialize();
1189 };
1190 
1191 
1192 /** @brief This class implements the abstract Customer class. */
1194 {
1195  public:
1196  explicit CustomerDefault(const string& str) : Customer(str) {initType(metadata);}
1197  virtual const MetaClass& getType() const {return *metadata;}
1199  virtual size_t getSize() const
1200  {return sizeof(CustomerDefault) + Customer::extrasize();}
1201  static int initialize();
1202 };
1203 
1204 
1205 /** @brief An operation represents an activity: these consume and produce material,
1206  * take time and also require capacity.
1207  *
1208  * An operation consumes and produces material, modeled through flows.<br>
1209  * An operation requires capacity, modeled through loads.
1210  *
1211  * This is an abstract base class for all different operation types.
1212  */
1213 class Operation : public HasName<Operation>,
1214  public HasLevel, public Plannable, public HasDescription
1215 {
1216  friend class Flow;
1217  friend class Load;
1218  friend class OperationPlan;
1219  friend class OperationRouting;
1220  friend class OperationAlternate;
1221 
1222  protected:
1223  /** Constructor. Don't use it directly. */
1224  explicit Operation(const string& str) : HasName<Operation>(str),
1225  loc(NULL), size_minimum(1.0), size_multiple(0.0), size_maximum(DBL_MAX),
1226  cost(0.0), hidden(false), first_opplan(NULL), last_opplan(NULL) {}
1227 
1228  /** Extra logic called when instantiating an operationplan.<br>
1229  * When the function returns false the creation of the operationplan
1230  * is denied and it is deleted.
1231  */
1232  virtual bool extraInstantiate(OperationPlan* o) {return true;}
1233 
1234  public:
1235  /** Destructor. */
1236  virtual DECLARE_EXPORT ~Operation();
1237 
1238  /** Returns a pointer to the operationplan being instantiated. */
1239  OperationPlan* getFirstOpPlan() const {return first_opplan;}
1240 
1241  /** Returns the delay before this operation. TODO CURRENTLY NOT USED!
1242  * @see setPreTime
1243  */
1244  TimePeriod getPreTime() const {return pre_time;}
1245 
1246  /** Updates the delay before this operation.<br>
1247  * This delay is a soft constraint. This means that solvers should try to
1248  * respect this waiting time but can choose to leave a shorter time delay
1249  * if required.<br>
1250  * @see setPostTime
1251  */
1252  void setPreTime(TimePeriod t)
1253  {
1254  if (t<TimePeriod(0L))
1255  throw DataException("No negative pre-operation time allowed");
1256  pre_time=t;
1257  setChanged();
1258  }
1259 
1260  /** Returns the delay after this operation.
1261  * @see setPostTime
1262  */
1263  TimePeriod getPostTime() const {return post_time;}
1264 
1265  /** Updates the delay after this operation.<br>
1266  * This delay is a soft constraint. This means that solvers should try to
1267  * respect this waiting time but can choose to leave a shorter time delay
1268  * if required.
1269  * @see setPreTime
1270  */
1271  void setPostTime(TimePeriod t)
1272  {
1273  if (t<TimePeriod(0L))
1274  throw DataException("No negative post-operation time allowed");
1275  post_time=t;
1276  setChanged();
1277  }
1278 
1279  /** Return the operation cost.<br>
1280  * The cost of executing this operation, per unit of the
1281  * operation_plan.<br>
1282  * The default value is 0.0.
1283  */
1284  double getCost() const {return cost;}
1285 
1286  /** Update the operation cost.<br>
1287  * The cost of executing this operation, per unit of the operation_plan.
1288  */
1289  void setCost(const double c)
1290  {
1291  if (c >= 0) cost = c;
1292  else throw DataException("Operation cost must be positive");
1293  }
1294 
1297 
1298  /** This is the factory method which creates all operationplans of the
1299  * operation. */
1300  DECLARE_EXPORT OperationPlan* createOperationPlan(double, Date,
1301  Date, Demand* = NULL, OperationPlan* = NULL, unsigned long = 0,
1302  bool makeflowsloads=true) const;
1303 
1304  /** Calculates the daterange starting from (or ending at) a certain date
1305  * and using a certain amount of effective available time on the
1306  * operation.
1307  *
1308  * This calculation considers the availability calendars of:
1309  * - the availability calendar of the operation's location
1310  * - the availability calendar of all resources loaded by the operation @todo not implemented yet
1311  * - the availability calendar of the locations of all resources loaded @todo not implemented yet
1312  * by the operation
1313  *
1314  * @param[in] thedate The date from which to start searching.
1315  * @param[in] duration The amount of available time we are looking for.
1316  * @param[in] forward The search direction
1317  * @param[out] actualduration This variable is updated with the actual
1318  * amount of available time found.
1319  */
1320  DECLARE_EXPORT DateRange calculateOperationTime
1321  (Date thedate, TimePeriod duration, bool forward,
1322  TimePeriod* actualduration = NULL) const;
1323 
1324  /** Calculates the effective, available time between two dates.
1325  *
1326  * This calculation considers the availability calendars of:
1327  * - the availability calendar of the operation's location
1328  * - the availability calendar of all resources loaded by the operation @todo not implemented yet
1329  * - the availability calendar of the locations of all resources loaded @todo not implemented yet
1330  * by the operation
1331  *
1332  * @param[in] start The date from which to start searching.
1333  * @param[in] end The date where to stop searching.
1334  * @param[out] actualduration This variable is updated with the actual
1335  * amount of available time found.
1336  */
1337  DECLARE_EXPORT DateRange calculateOperationTime
1338  (Date start, Date end, TimePeriod* actualduration = NULL) const;
1339 
1340  /** This method stores ALL logic the operation needs to compute the
1341  * correct relationship between the quantity, startdate and enddate
1342  * of an operationplan.
1343  *
1344  * The parameters "startdate", "enddate" and "quantity" can be
1345  * conflicting if all are specified together.
1346  * Typically, one would use one of the following combinations:
1347  * - specify quantity and start date, and let the operation compute the
1348  * end date.
1349  * - specify quantity and end date, and let the operation compute the
1350  * start date.
1351  * - specify both the start and end date, and let the operation compute
1352  * the quantity.
1353  * - specify quantity, start and end date. In this case, you need to
1354  * be aware that the operationplan that is created can be different
1355  * from the parameters you requested.
1356  *
1357  * The following priority rules apply upon conflicts.
1358  * - respecting the end date has the first priority.
1359  * - respecting the start date has second priority.
1360  * - respecting the quantity should be done if the specified dates can
1361  * be respected.
1362  * - if the quantity is being computed to meet the specified dates, the
1363  * quantity being passed as argument is to be treated as a maximum
1364  * limit. The created operationplan can have a smaller quantity, but
1365  * not bigger...
1366  * - at all times, we expect to have an operationplan that is respecting
1367  * the constraints set by the operation. If required, some of the
1368  * specified parameters may need to be violated. In case of such a
1369  * violation we expect the operationplan quantity to be 0.
1370  *
1371  * The pre- and post-operation times are NOT considered in this method.
1372  * This method only enforces "hard" constraints. "Soft" constraints are
1373  * considered as 'hints' by the solver.
1374  *
1375  * Subclasses need to override this method to implement the correct
1376  * logic.
1377  */
1378  virtual OperationPlanState setOperationPlanParameters
1379  (OperationPlan*, double, Date, Date, bool=true, bool=true) const = 0;
1380 
1381  /** Returns the location of the operation, which is used to model the
1382  * working hours and holidays. */
1383  Location* getLocation() const {return loc;}
1384 
1385  /** Updates the location of the operation, which is used to model the
1386  * working hours and holidays. */
1387  void setLocation(Location* l) {loc = l;}
1388 
1389  /** Returns an reference to the list of flows. */
1390  const flowlist& getFlows() const {return flowdata;}
1391 
1392  /** Returns an reference to the list of loads. */
1393  const loadlist& getLoads() const {return loaddata;}
1394 
1395  /** Return the flow that is associates a given buffer with this
1396  * operation. Returns NULL is no such flow exists. */
1397  Flow* findFlow(const Buffer* b, Date d) const
1398  {return flowdata.find(b,d);}
1399 
1400  /** Return the load that is associates a given resource with this
1401  * operation. Returns NULL is no such load exists. */
1402  Load* findLoad(const Resource* r, Date d) const
1403  {return loaddata.find(r,d);}
1404 
1405  /** Deletes all operationplans of this operation. The boolean parameter
1406  * controls whether we delete also locked operationplans or not.
1407  */
1408  DECLARE_EXPORT void deleteOperationPlans(bool deleteLockedOpplans = false);
1409 
1410  /** Sets the minimum size of operationplans.<br>
1411  * The default value is 1.0
1412  */
1413  void setSizeMinimum(double f)
1414  {
1415  if (f<0)
1416  throw DataException("Operation can't have a negative minimum size");
1417  size_minimum = f;
1418  setChanged();
1419  }
1420 
1421  /** Returns the minimum size for operationplans. */
1422  double getSizeMinimum() const {return size_minimum;}
1423 
1424  /** Sets the multiple size of operationplans. */
1425  void setSizeMultiple(double f)
1426  {
1427  if (f<0)
1428  throw DataException("Operation can't have a negative multiple size");
1429  size_multiple = f;
1430  setChanged();
1431  }
1432 
1433  /** Returns the mutiple size for operationplans. */
1434  double getSizeMultiple() const {return size_multiple;}
1435 
1436  /** Sets the maximum size of operationplans. */
1437  void setSizeMaximum(double f)
1438  {
1439  if (f < size_minimum)
1440  throw DataException("Operation maximum size must be higher than the minimum size");
1441  if (f <= 0)
1442  throw DataException("Operation maximum size must be greater than 0");
1443  size_maximum = f;
1444  setChanged();
1445  }
1446 
1447  /** Returns the maximum size for operationplans. */
1448  double getSizeMaximum() const {return size_maximum;}
1449 
1450  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
1451  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
1452  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
1453  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
1454  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
1455  static int initialize();
1456 
1457  size_t extrasize() const
1458  {return getName().size() + HasDescription::extrasize();}
1459 
1460  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
1461 
1462  typedef list<Operation*> Operationlist;
1463 
1464  /** Returns a reference to the list of sub operations of this operation. */
1465  virtual const Operationlist& getSubOperations() const {return nosubOperations;}
1466 
1467  /** Returns a reference to the list of super-operations, i.e. operations
1468  * using the current Operation as a sub-Operation.
1469  */
1470  const Operationlist& getSuperOperations() const {return superoplist;}
1471 
1472  /** Register a super-operation, i.e. an operation having this one as a
1473  * sub-operation. */
1474  void addSuperOperation(Operation * o) {superoplist.push_front(o);}
1475 
1476  /** Removes a sub-operation from the list. This method will need to be
1477  * overridden by all operation types that acts as a super-operation. */
1478  virtual void removeSubOperation(Operation *o) {}
1479 
1480  /** Removes a super-operation from the list. */
1481  void removeSuperOperation(Operation *o)
1482  {superoplist.remove(o); o->removeSubOperation(this);}
1483 
1484  /** Return the release fence of this operation. */
1485  TimePeriod getFence() const {return fence;}
1486 
1487  /** Update the release fence of this operation. */
1488  void setFence(TimePeriod t) {if (fence!=t) setChanged(); fence=t;}
1489 
1490  virtual DECLARE_EXPORT void updateProblems();
1491 
1492  void setHidden(bool b) {if (hidden!=b) setChanged(); hidden = b;}
1493  bool getHidden() const {return hidden;}
1494 
1496 
1497  protected:
1498  DECLARE_EXPORT void initOperationPlan(OperationPlan*, double,
1499  const Date&, const Date&, Demand*, OperationPlan*, unsigned long,
1500  bool = true) const;
1501 
1502  private:
1503  /** List of operations using this operation as a sub-operation */
1504  Operationlist superoplist;
1505 
1506  /** Empty list of operations.<br>
1507  * For operation types which have no suboperations this list is
1508  * used as the list of suboperations.
1509  */
1510  static DECLARE_EXPORT Operationlist nosubOperations;
1511 
1512  /** Location of the operation.<br>
1513  * The location is used to model the working hours and holidays.
1514  */
1515  Location* loc;
1516 
1517  /** Represents the time between this operation and a next one. */
1518  TimePeriod post_time;
1519 
1520  /** Represents the time between this operation and a previous one. */
1521  TimePeriod pre_time;
1522 
1523  /** Represents the release fence of this operation, i.e. a period of time
1524  * (relative to the current date of the plan) in which normally no
1525  * operationplan is allowed to be created.
1526  */
1527  TimePeriod fence;
1528 
1529  /** Singly linked list of all flows of this operation. */
1530  flowlist flowdata;
1531 
1532  /** Singly linked list of all resources Loaded by this operation. */
1533  loadlist loaddata;
1534 
1535  /** Minimum size for operationplans.<br>
1536  * The default value is 1.0
1537  */
1538  double size_minimum;
1539 
1540  /** Multiple size for operationplans. */
1541  double size_multiple;
1542 
1543  /** Maximum size for operationplans. */
1544  double size_maximum;
1545 
1546  /** Cost of the operation.<br>
1547  * The default value is 0.0.
1548  */
1549  double cost;
1550 
1551  /** Does the operation require serialization or not. */
1552  bool hidden;
1553 
1554  /** A pointer to the first operationplan of this operation.<br>
1555  * All operationplans of this operation are stored in a sorted
1556  * doubly linked list.
1557  */
1558  OperationPlan* first_opplan;
1559 
1560  /** A pointer to the last operationplan of this operation.<br>
1561  * All operationplans of this operation are stored in a sorted
1562  * doubly linked list.
1563  */
1564  OperationPlan* last_opplan;
1565 };
1566 
1567 
1568 /** @brief An operationplan is the key dynamic element of a plan. It
1569  * represents a certain quantity being planned along a certain operation
1570  * during a certain date range.
1571  *
1572  * From a coding perspective:
1573  * - Operationplans are created by the factory method createOperationPlan()
1574  * on the matching Operation class.
1575  * - The createLoadAndFlowplans() can optionally be called to also create
1576  * the loadplans and flowplans, to take care of the material and
1577  * capacity consumption.
1578  * - Once you're sure about creating the operationplan, the activate()
1579  * method should be called. It will assign the operationplan a unique
1580  * numeric identifier, register the operationplan in a container owned
1581  * by the operation instance, and also create loadplans and flowplans
1582  * if this hasn't been done yet.<br>
1583  * - Operationplans can be organized in hierarchical structure, matching
1584  * the operation hierarchies they belong to.
1585  *
1586  * @todo reading suboperationplans can be improved
1587  */
1589  : public Object, public HasProblems, public NonCopyable
1590 {
1591  friend class FlowPlan;
1592  friend class LoadPlan;
1593  friend class Demand;
1594  friend class Operation;
1595  friend class OperationAlternate;
1596  friend class OperationRouting;
1597  friend class ProblemPrecedence;
1598 
1599  public:
1600  class FlowPlanIterator;
1601 
1602  /** Returns an iterator pointing to the first flowplan. */
1603  FlowPlanIterator beginFlowPlans() const;
1604 
1605  /** Returns an iterator pointing beyond the last flowplan. */
1606  FlowPlanIterator endFlowPlans() const;
1607 
1608  /** Returns how many flowplans are created on an operationplan. */
1609  int sizeFlowPlans() const;
1610 
1611  class LoadPlanIterator;
1612 
1613  /** Returns an iterator pointing to the first loadplan. */
1614  LoadPlanIterator beginLoadPlans() const;
1615 
1616  /** Returns an iterator pointing beyond the last loadplan. */
1617  LoadPlanIterator endLoadPlans() const;
1618 
1619  /** Returns how many loadplans are created on an operationplan. */
1620  int sizeLoadPlans() const;
1621 
1622  /** @brief This class models an STL-like iterator that allows us to iterate over
1623  * the operationplans in a simple and safe way.
1624  *
1625  * Objects of this class are created by the begin() and end() functions.
1626  */
1627  class iterator
1628  {
1629  public:
1630  /** Constructor. The iterator will loop only over the operationplans
1631  * of the operation passed. */
1632  iterator(const Operation* x) : op(Operation::end()), mode(1)
1633  {
1634  opplan = x ? x->getFirstOpPlan() : NULL;
1635  }
1636 
1637  /** Constructor. The iterator will loop only over the suboperationplans
1638  * of the operationplan passed. */
1639  iterator(const OperationPlan* x) : op(Operation::end()), mode(2)
1640  {
1641  opplan = x ? x->firstsubopplan : NULL;
1642  }
1643 
1644  /** Constructor. The iterator will loop over all operationplans. */
1645  iterator() : op(Operation::begin()), mode(3)
1646  {
1647  // The while loop is required since the first operation might not
1648  // have any operationplans at all
1649  while (op!=Operation::end() && !op->getFirstOpPlan()) ++op;
1650  if (op!=Operation::end())
1651  opplan = op->getFirstOpPlan();
1652  else
1653  opplan = NULL;
1654  }
1655 
1656  /** Copy constructor. */
1657  iterator(const iterator& it) : opplan(it.opplan), op(it.op), mode(it.mode) {}
1658 
1659  /** Return the content of the current node. */
1660  OperationPlan& operator*() const {return *opplan;}
1661 
1662  /** Return the content of the current node. */
1663  OperationPlan* operator->() const {return opplan;}
1664 
1665  /** Pre-increment operator which moves the pointer to the next
1666  * element. */
1667  iterator& operator++()
1668  {
1669  if (mode == 2)
1670  opplan = opplan->nextsubopplan;
1671  else
1672  opplan = opplan->next;
1673  // Move to a new operation
1674  if (!opplan && mode == 3)
1675  {
1676  do ++op;
1677  while (op!=Operation::end() && (!op->getFirstOpPlan()));
1678  if (op!=Operation::end())
1679  opplan = op->getFirstOpPlan();
1680  else
1681  opplan = NULL;
1682  }
1683  return *this;
1684  }
1685 
1686  /** Post-increment operator which moves the pointer to the next
1687  * element. */
1688  iterator operator++(int)
1689  {
1690  iterator tmp(*this);
1691  if (mode == 2)
1692  opplan = opplan->nextsubopplan;
1693  else
1694  opplan = opplan->next;
1695  // Move to a new operation
1696  if (!opplan && mode==3)
1697  {
1698  do ++op; while (op!=Operation::end() && !op->getFirstOpPlan());
1699  if (op!=Operation::end())
1700  opplan = op->getFirstOpPlan();
1701  else
1702  opplan = NULL;
1703  }
1704  return tmp;
1705  }
1706 
1707  /** Comparison operator. */
1708  bool operator==(const iterator& y) const {return opplan == y.opplan;}
1709 
1710  /** Inequality operator. */
1711  bool operator!=(const iterator& y) const {return opplan != y.opplan;}
1712 
1713  private:
1714  /** A pointer to current operationplan. */
1715  OperationPlan* opplan;
1716 
1717  /** An iterator over the operations. */
1718  Operation::iterator op;
1719 
1720  /** Describes the type of iterator.<br>
1721  * 1) iterate over operationplan instances of operation
1722  * 2) iterate over suboperationplans of an operationplan
1723  * 3) iterate over all operationplans
1724  */
1725  short mode;
1726  };
1727 
1728  friend class iterator;
1729 
1730  static iterator end() {return iterator(static_cast<Operation*>(NULL));}
1731 
1732  static iterator begin() {return iterator();}
1733 
1734  /** Returns true when not a single operationplan object exists. */
1735  static bool empty() {return begin()==end();}
1736 
1737  /** Returns the number of operationplans in the system. This method
1738  * is linear with the number of operationplans in the model, and should
1739  * therefore be used only with care.
1740  */
1741  static unsigned long size()
1742  {
1743  unsigned long cnt = 0;
1744  for (OperationPlan::iterator i = begin(); i != end(); ++i) ++cnt;
1745  return cnt;
1746  }
1747 
1748  /** This is a factory method that creates an operationplan pointer based
1749  * on the name and id, which are passed as an array of character pointers.
1750  * This method is intended to be used to create objects when reading
1751  * XML input data.
1752  */
1753  static DECLARE_EXPORT Object* createOperationPlan(const MetaClass*, const AttributeList&);
1754 
1755  /** Destructor. */
1756  virtual DECLARE_EXPORT ~OperationPlan();
1757 
1758  virtual DECLARE_EXPORT void setChanged(bool b = true);
1759 
1760  /** Returns the quantity. */
1761  double getQuantity() const {return quantity;}
1762 
1763  /** Updates the quantity.<br>
1764  * The operationplan quantity is subject to the following rules:
1765  * - The quantity must be greater than or equal to the minimum size.<br>
1766  * The value is rounded up to the smallest multiple above the minimum
1767  * size if required, or rounded down to 0.
1768  * - The quantity must be a multiple of the multiple_size field.<br>
1769  * The value is rounded up or down to meet this constraint.
1770  * - The quantity must be smaller than or equal to the maximum size.<br>
1771  * The value is limited to the smallest multiple below this limit.
1772  * - Setting the quantity of an operationplan to 0 is always possible,
1773  * regardless of the minimum, multiple and maximum values.
1774  * This method can only be called on top operationplans. Sub operation
1775  * plans should pass on a call to the parent operationplan.
1776  */
1777  virtual DECLARE_EXPORT double setQuantity(double f,
1778  bool roundDown = false, bool update = true, bool execute = true);
1779 
1780  /** Returns a pointer to the demand for which this operationplan is a delivery.
1781  * If the operationplan isn't a delivery, this is a NULL pointer.
1782  */
1783  Demand* getDemand() const {return dmd;}
1784 
1785  /** Updates the demand to which this operationplan is a solution. */
1786  DECLARE_EXPORT void setDemand(Demand* l);
1787 
1788  /** Calculate the penalty of an operationplan.<br>
1789  * It is the sum of all setup penalties of the resources it loads. */
1790  DECLARE_EXPORT double getPenalty() const;
1791 
1792  /** Calculate the unavailable time during the operationplan. The regular
1793  * duration is extended with this amount.
1794  */
1795  DECLARE_EXPORT TimePeriod getUnavailable() const;
1796 
1797  /** Returns whether the operationplan is locked. A locked operationplan
1798  * is never changed.
1799  */
1800  bool getLocked() const {return flags & IS_LOCKED;}
1801 
1802  /** Deletes all operationplans of a certain operation. A boolean flag
1803  * allows to specify whether locked operationplans are to be deleted too.
1804  */
1805  static DECLARE_EXPORT void deleteOperationPlans(Operation* o, bool deleteLocked=false);
1806 
1807  /** Locks/unlocks an operationplan. A locked operationplan is never
1808  * changed.
1809  */
1810  virtual DECLARE_EXPORT void setLocked(bool b = true);
1811 
1812  /** Returns a pointer to the operation being instantiated. */
1813  Operation* getOperation() const {return oper;}
1814 
1815  /** Fixes the start and end date of an operationplan. Note that this
1816  * overrules the standard duration given on the operation, i.e. no logic
1817  * kicks in to verify the data makes sense. This is up to the user to
1818  * take care of.<br>
1819  * The methods setStart(Date) and setEnd(Date) are therefore preferred
1820  * since they properly apply all appropriate logic.
1821  */
1822  void setStartAndEnd(Date st, Date nd)
1823  {
1824  dates.setStartAndEnd(st,nd);
1825  update();
1826  }
1827 
1828  /** A method to restore a previous state of an operationplan.<br>
1829  * NO validity checks are done on the parameters.
1830  */
1831  void restore(const OperationPlanState& x);
1832 
1833  /** Updates the operationplan owning this operationplan. In case of
1834  * a OperationRouting steps this will be the operationplan representing the
1835  * complete routing. */
1836  void DECLARE_EXPORT setOwner(OperationPlan* o);
1837 
1838  /** Returns a pointer to the operationplan for which this operationplan
1839  * a sub-operationplan.<br>
1840  * The method returns NULL if there is no owner defined.<br>
1841  * E.g. Sub-operationplans of a routing refer to the overall routing
1842  * operationplan.<br>
1843  * E.g. An alternate sub-operationplan refers to its parent.
1844  * @see getTopOwner
1845  */
1846  OperationPlan* getOwner() const {return owner;}
1847 
1848  /** Returns a pointer to the operationplan owning a set of
1849  * sub-operationplans. There can be multiple levels of suboperations.<br>
1850  * If no owner exists the method returns the current operationplan.
1851  * @see getOwner
1852  */
1853  const OperationPlan* getTopOwner() const
1854  {
1855  if (owner)
1856  {
1857  // There is an owner indeed
1858  OperationPlan* o(owner);
1859  while (o->owner) o = o->owner;
1860  return o;
1861  }
1862  else
1863  // This operationplan is itself the top of a hierarchy
1864  return this;
1865  }
1866 
1867  /** Returns the start and end date of this operationplan. */
1868  const DateRange & getDates() const {return dates;}
1869 
1870  /** Return true if the operationplan is redundant, ie all material
1871  * it produces is not used at all.<br>
1872  * If the optional argument is false (which is the default value), we
1873  * check with the minimum stock level of the buffers. If the argument
1874  * is true, we check with 0.
1875  */
1876  DECLARE_EXPORT bool isExcess(bool = false) const;
1877 
1878  /** Returns a unique identifier of the operationplan.<br>
1879  * The identifier can be specified in the data input (in which case
1880  * we check for the uniqueness during the read operation).<br>
1881  * For operationplans created during a solver run, the identifier is
1882  * assigned in the instantiate() function. The numbering starts with the
1883  * highest identifier read in from the input and is then incremented
1884  * for every operationplan that is registered.
1885  */
1886  unsigned long getIdentifier() const {return id;}
1887 
1888  /** Updates the end date of the operationplan and compute the start
1889  * date.<br>
1890  * Locked operationplans are not updated by this function.<br>
1891  * Slack can be introduced between sub operationaplans by this method,
1892  * i.e. the sub operationplans are only moved if required to meet the
1893  * end date.
1894  */
1895  virtual DECLARE_EXPORT void setEnd(Date);
1896 
1897  /** Updates the start date of the operationplan and compute the end
1898  * date.<br>
1899  * Locked operation_plans are not updated by this function.<br>
1900  * Slack can be introduced between sub operationaplans by this method,
1901  * i.e. the sub operationplans are only moved if required to meet the
1902  * start date.
1903  */
1904  virtual DECLARE_EXPORT void setStart(Date);
1905 
1906  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
1907  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
1908  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
1909  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
1910  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
1911  static int initialize();
1912 
1913  PyObject* str() const
1914  {
1915  ostringstream ch;
1916  ch << id;
1917  return PythonObject(ch.str());
1918  }
1919 
1920  /** Python factory method. */
1921  static PyObject* create(PyTypeObject*, PyObject*, PyObject*);
1922 
1923  /** Initialize the operationplan. The initialization function should be
1924  * called when the operationplan is ready to be 'officially' added. The
1925  * initialization performs the following actions:
1926  * <ol>
1927  * <li> assign an identifier</li>
1928  * <li> create the flow and loadplans if these hadn't been created
1929  * before</li>
1930  * <li> add the operationplan to the global list of operationplans</li>
1931  * <li> create a link with a demand object if this is a delivery
1932  * operationplan</li>
1933  * </ol>
1934  * Every operationplan subclass that has sub-operations will normally
1935  * need to create an override of this function.<br>
1936  *
1937  * The return value indicates whether the initialization was successfull.
1938  * If the operationplan is invalid, it will be DELETED and the return value
1939  * is 'false'.
1940  */
1941  DECLARE_EXPORT bool activate(bool useMinCounter = true);
1942 
1943  /** Remove an operationplan from the list of officially registered ones.<br>
1944  * The operationplan will keep its loadplans and flowplans after unregistration.
1945  */
1946  DECLARE_EXPORT void deactivate();
1947 
1948  /** This method links the operationplan in the list of all operationplans
1949  * maintained on the operation.<br>
1950  * In most cases calling this method is not required since it included
1951  * in the activate method. In exceptional cases the solver already
1952  * needs to see uncommitted operationplans in the list - eg for the
1953  * procurement buffer.
1954  * @see activate
1955  */
1956  DECLARE_EXPORT void insertInOperationplanList();
1957 
1958  /** This method remove the operationplan from the list of all operationplans
1959  * maintained on the operation.<br>
1960  * @see deactivate
1961  */
1962  DECLARE_EXPORT void removeFromOperationplanList();
1963 
1964  /** Add a sub-operationplan to the list. */
1965  virtual DECLARE_EXPORT void addSubOperationPlan(OperationPlan*);
1966 
1967  /** Remove a sub-operation_plan from the list. */
1968  virtual DECLARE_EXPORT void eraseSubOperationPlan(OperationPlan*);
1969 
1970  /** This function is used to create the loadplans, flowplans and
1971  * setup operationplans.
1972  */
1973  DECLARE_EXPORT void createFlowLoads();
1974 
1975  /** This function is used to delete the loadplans, flowplans and
1976  * setup operationplans.
1977  */
1978  DECLARE_EXPORT void deleteFlowLoads();
1979 
1980  bool getHidden() const {return getOperation()->getHidden();}
1981 
1982  /** Searches for an OperationPlan with a given identifier.<br>
1983  * Returns a NULL pointer if no such OperationPlan can be found.<br>
1984  * The method is of complexity O(n), i.e. involves a LINEAR search through
1985  * the existing operationplans, and can thus be quite slow in big models.<br>
1986  * The method is O(1), i.e. constant time regardless of the model size,
1987  * when the parameter passed is bigger than the operationplan counter.
1988  */
1989  static DECLARE_EXPORT OperationPlan* findId(unsigned long l);
1990 
1991  /** Problem detection is actually done by the Operation class. That class
1992  * actually "delegates" the responsability to this class, for efficiency.
1993  */
1994  virtual void updateProblems();
1995 
1996  /** Implement the pure virtual function from the HasProblem class. */
1997  Plannable* getEntity() const {return oper;}
1998 
1999  /** Return the metadata. We return the metadata of the operation class,
2000  * not the one of the operationplan class!
2001  */
2002  const MetaClass& getType() const {return *metadata;}
2003 
2005 
2007 
2008  virtual size_t getSize() const
2009  {return sizeof(OperationPlan);}
2010 
2011  /** Handles the persistence of operationplan objects. */
2012  static DECLARE_EXPORT void writer(const MetaCategory*, XMLOutput*);
2013 
2014  /** Comparison of 2 OperationPlans.
2015  * To garantuee that the problems are sorted in a consistent and stable
2016  * way, the following sorting criteria are used (in order of priority):
2017  * <ol><li>Operation</li>
2018  * <li>Start date (earliest dates first)</li>
2019  * <li>Quantity (biggest quantities first)</li></ol>
2020  * Multiple operationplans for the same values of the above keys can exist.
2021  */
2022  DECLARE_EXPORT bool operator < (const OperationPlan& a) const;
2023 
2024  /** Copy constructor.<br>
2025  * If the optional argument is false, the new copy is not initialized
2026  * and won't have flowplans and loadplans.
2027  */
2028  DECLARE_EXPORT OperationPlan(const OperationPlan&, bool = true);
2029 
2030  /** Return the plannable object that caused the creation of this
2031  * operationplan. Usage of this field can vary by solver.
2032  * The information is normally not relevant for end users.
2033  */
2034  DECLARE_EXPORT Plannable* getMotive() const {return motive;}
2035 
2036  /** Update the plannable object that created this operationplan. */
2037  DECLARE_EXPORT void setMotive(Plannable* v) {motive = v;}
2038 
2039  private:
2040  /** Private copy constructor.<br>
2041  * It is used in the public copy constructor to make a deep clone of suboperationplans.
2042  * @see OperationPlan(const OperationPlan&, bool = true)
2043  */
2045 
2046  /** Updates the operationplan based on the latest information of quantity,
2047  * date and locked flag.<br>
2048  * This method will also update parent and child operationplans.
2049  * @see resizeFlowLoadPlans
2050  */
2051  virtual DECLARE_EXPORT void update();
2052 
2053  /** Update the loadplans and flowplans of the operationplan based on the
2054  * latest information of quantity, date and locked flag.<br>
2055  * This method will NOT update parent or child operationplans.
2056  * @see update
2057  */
2058  DECLARE_EXPORT void resizeFlowLoadPlans();
2059 
2060  /** Default constructor.<br>
2061  * This way of creating operationplan objects is not intended for use by
2062  * any client applications. Client applications should use the factory
2063  * method on the operation class instead.<br>
2064  * Subclasses of the Operation class may use this constructor in their
2065  * own override of the createOperationPlan method.
2066  * @see Operation::createOperationPlan
2067  */
2068  OperationPlan() : owner(NULL), quantity(0.0), flags(0), dmd(NULL),
2069  id(0), oper(NULL), firstflowplan(NULL), firstloadplan(NULL),
2070  prev(NULL), next(NULL), firstsubopplan(NULL), lastsubopplan(NULL),
2071  nextsubopplan(NULL), prevsubopplan(NULL), motive(NULL)
2072  {initType(metadata);}
2073 
2074  private:
2075  static const short IS_LOCKED = 1;
2076  static const short IS_SETUP = 2;
2077  static const short HAS_SETUP = 4;
2078 
2079  /** Pointer to a higher level OperationPlan. */
2080  OperationPlan *owner;
2081 
2082  /** Quantity. */
2083  double quantity;
2084 
2085  /** Is this operationplan locked? A locked operationplan doesn't accept
2086  * any changes. This field is only relevant for top-operationplans. */
2087  short flags;
2088 
2089  /** Counter of OperationPlans, which is used to automatically assign a
2090  * unique identifier for each operationplan.<br>
2091  * The value of the counter is the first available identifier value that
2092  * can be used for a new operationplan.<br>
2093  * The first value is 1, and each operationplan increases it by 1.
2094  * @see counterMax
2095  * @see getIdentifier()
2096  */
2097  static DECLARE_EXPORT unsigned long counterMin;
2098 
2099  /** Counter of OperationPlans, which is used to automatically assign a
2100  * unique identifier for each operationplan.<br>
2101  * The first value is a very high number, and each operationplan
2102  * decreases it by 1.
2103  * @see counterMin
2104  * @see getIdentifier()
2105  */
2106  static DECLARE_EXPORT unsigned long counterMax;
2107 
2108  /** Pointer to the demand.<br>
2109  * Only delivery operationplans have this field set. The field is NULL
2110  * for all other operationplans.
2111  */
2112  Demand *dmd;
2113 
2114  /** Unique identifier.<br>
2115  * The field is 0 while the operationplan is not fully registered yet.
2116  */
2117  unsigned long id;
2118 
2119  /** Start and end date. */
2120  DateRange dates;
2121 
2122  /** Pointer to the operation. */
2123  Operation *oper;
2124 
2125  /** Root of a single linked list of flowplans. */
2126  FlowPlan* firstflowplan;
2127 
2128  /** Single linked list of loadplans. */
2129  LoadPlan* firstloadplan;
2130 
2131  /** Pointer to the previous operationplan.<br>
2132  * Operationplans are chained in a doubly linked list for each operation.
2133  * @see next
2134  */
2135  OperationPlan* prev;
2136 
2137  /** Pointer to the next operationplan.<br>
2138  * Operationplans are chained in a doubly linked list for each operation.
2139  * @see prev
2140  */
2141  OperationPlan* next;
2142 
2143  /** Pointer to the first suboperationplan of this operationplan. */
2144  OperationPlan* firstsubopplan;
2145 
2146  /** Pointer to the last suboperationplan of this operationplan. */
2147  OperationPlan* lastsubopplan;
2148 
2149  /** Pointer to the next suboperationplan of the parent operationplan. */
2150  OperationPlan* nextsubopplan;
2151 
2152  /** Pointer to the previous suboperationplan of the parent operationplan. */
2153  OperationPlan* prevsubopplan;
2154 
2155  /** Pointer to the demand that caused the creation of this operationplan. */
2156  Plannable* motive;
2157 };
2158 
2159 
2160 /** @brief A simple class to easily remember the date, quantity and owner of
2161  * an operationplan. */
2162 class OperationPlanState // @todo should also be able to remember and restore suboperationplans!!!
2163 {
2164  public:
2167  double quantity;
2168 
2169  /** Default constructor. */
2170  OperationPlanState() : quantity(0.0) {}
2171 
2172  /** Constructor. */
2174  {
2175  if (!x)
2176  {
2177  quantity = 0.0;
2178  return;
2179  }
2180  else
2181  {
2182  start = x->getDates().getStart();
2183  end = x->getDates().getEnd();
2184  quantity = x->getQuantity();
2185  }
2186  }
2187 
2188  /** Constructor. */
2189  OperationPlanState(const Date x, const Date y, double q)
2190  : start(x), end(y), quantity(q) {}
2191 
2192  /** Constructor. */
2193  OperationPlanState(const DateRange& x, double q)
2194  : start(x.getStart()), end(x.getEnd()), quantity(q) {}
2195 };
2196 
2197 
2198 /** @brief Models an operation that takes a fixed amount of time, independent
2199  * of the quantity. */
2201 {
2202  public:
2203  /** Constructor. */
2204  explicit OperationFixedTime(const string& s) : Operation(s) {initType(metadata);}
2205 
2206  /** Returns the length of the operation. */
2207  const TimePeriod getDuration() const {return duration;}
2208 
2209  /** Updates the duration of the operation. Existing operation plans of this
2210  * operation are not automatically refreshed to reflect the change. */
2211  void setDuration(TimePeriod t)
2212  {
2213  if (t<0L)
2214  throw DataException("FixedTime operation can't have a negative duration");
2215  duration = t;
2216  }
2217 
2218  DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
2219  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
2220  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
2221  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
2222  static int initialize();
2223 
2224  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
2225 
2226  virtual const MetaClass& getType() const {return *metadata;}
2228  virtual size_t getSize() const
2229  {return sizeof(OperationFixedTime) + Operation::extrasize();}
2230 
2231  /** A operation of this type enforces the following rules on its
2232  * operationplans:
2233  * - The duration is always constant.
2234  * - If the end date is specified, we use that and ignore the start
2235  * date that could have been passed.
2236  * - If no end date but only a start date are specified, we'll use
2237  * that date.
2238  * - If no dates are specified, we don't update the dates of the
2239  * operationplan.
2240  * - The quantity can be any positive number.
2241  * - Locked operationplans can't be updated.
2242  * @see Operation::setOperationPlanParameters
2243  */
2244  DECLARE_EXPORT OperationPlanState setOperationPlanParameters
2245  (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
2246 
2247  protected:
2248  DECLARE_EXPORT virtual bool extraInstantiate(OperationPlan* o);
2249 
2250  private:
2251  /** Stores the lengh of the Operation. */
2252  TimePeriod duration;
2253 };
2254 
2255 
2256 /** @brief Models an operation to convert a setup on a resource. */
2258 {
2259  public:
2260  /** Constructor. */
2261  explicit OperationSetup(const string& s) : Operation(s) {initType(metadata);}
2262 
2263  // Never write the setup operation
2265  static int initialize();
2266 
2267  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
2268 
2269  virtual const MetaClass& getType() const {return *metadata;}
2271  virtual size_t getSize() const
2272  {return sizeof(OperationSetup) + Operation::extrasize();}
2273 
2274  /** A operation of this type enforces the following rules on its
2275  * operationplans:
2276  * - The duration is calculated based on the conversion type.
2277  */
2278  DECLARE_EXPORT OperationPlanState setOperationPlanParameters
2279  (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
2280 
2281  /** A pointer to the operation that is instantiated for all conversions. */
2283 };
2284 
2285 
2286 /** @brief Models an operation whose duration is the sum of a constant time,
2287  * plus a cetain time per unit.
2288  */
2290 {
2291  public:
2292  /** Constructor. */
2293  explicit OperationTimePer(const string& s) : Operation(s) {initType(metadata);}
2294 
2295  /** Returns the constant part of the operation time. */
2296  TimePeriod getDuration() const {return duration;}
2297 
2298  /** Sets the constant part of the operation time. */
2299  void setDuration(TimePeriod t)
2300  {
2301  if(t<0L)
2302  throw DataException("TimePer operation can't have a negative duration");
2303  duration = t;
2304  }
2305 
2306  /** Returns the time per unit of the operation time. */
2307  TimePeriod getDurationPer() const {return duration_per;}
2308 
2309  /** Sets the time per unit of the operation time. */
2310  void setDurationPer(TimePeriod t)
2311  {
2312  if(t<0L)
2313  throw DataException("TimePer operation can't have a negative duration-per");
2314  duration_per = t;
2315  }
2316 
2317  /** A operation of this type enforces the following rules on its
2318  * operationplans:
2319  * - If both the start and end date are specified, the quantity is
2320  * computed to match these dates.
2321  * If the time difference between the start and end date is too
2322  * small to fit the fixed duration, the quantity is set to 0.
2323  * - If only an end date is specified, it will be respected and we
2324  * compute a start date based on the quantity.
2325  * - If only a start date is specified, it will be respected and we
2326  * compute an end date based on the quantity.
2327  * - If no date is specified, we respect the quantity and the end
2328  * date of the operation. A new start date is being computed.
2329  * @see Operation::setOperationPlanParameters
2330  */
2331  DECLARE_EXPORT OperationPlanState setOperationPlanParameters
2332  (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
2333 
2334  DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
2335  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
2336  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
2337  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
2338  static int initialize();
2339 
2340  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
2341 
2342  virtual const MetaClass& getType() const {return *metadata;}
2344  virtual size_t getSize() const
2345  {return sizeof(OperationTimePer) + Operation::extrasize();}
2346 
2347  private:
2348  /** Constant part of the operation time. */
2349  TimePeriod duration;
2350 
2351  /** Variable part of the operation time. */
2352  TimePeriod duration_per;
2353 };
2354 
2355 
2356 /** @brief Represents a routing operation, i.e. an operation consisting of
2357  * multiple, sequential sub-operations.
2358  */
2360 {
2361  public:
2362  /** Constructor. */
2363  explicit OperationRouting(const string& c) : Operation(c) {initType(metadata);}
2364 
2365  /** Destructor. */
2367 
2368  /** Adds a new steps to routing at the start of the routing. */
2369  void addStepFront(Operation *o)
2370  {
2371  if (!o) throw DataException("Adding NULL operation to routing");
2372  steps.push_front(o);
2373  o->addSuperOperation(this);
2374  }
2375 
2376  /** Adds a new steps to routing at the end of the routing. */
2377  void addStepBack(Operation *o)
2378  {
2379  if (!o) throw DataException("Adding NULL operation to routing");
2380  steps.push_back(o);
2381  o->addSuperOperation(this);
2382  }
2383 
2384  /** Add one or more steps to a routing. */
2385  static DECLARE_EXPORT PyObject* addStep(PyObject*, PyObject*);
2386 
2387  /** Remove a step from a routing. */
2388  void removeSubOperation(Operation *o)
2389  {steps.remove(o); o->superoplist.remove(this);}
2390 
2391  /** A operation of this type enforces the following rules on its
2392  * operationplans:
2393  * - If an end date is given, sequentially use this method on the
2394  * different steps. The steps are stepped through starting from the
2395  * last step, and each step will adjust to meet the requested end date.
2396  * If there is slack between the routings' step operationplans, it can
2397  * be used to "absorb" the change.
2398  * - When a start date is given, the behavior is similar to the previous
2399  * case, except that we step through the operationplans from the
2400  * first step this time.
2401  * - If both a start and an end date are given, we use only the end date.
2402  * - If there are no sub operationplans yet, apply the requested changes
2403  * blindly.
2404  * @see Operation::setOperationPlanParameters
2405  */
2406  DECLARE_EXPORT OperationPlanState setOperationPlanParameters
2407  (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
2408 
2409  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
2410  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
2411  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
2412  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
2413  static int initialize();
2414 
2415  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
2416 
2417  /** Return a list of all sub-operationplans. */
2418  virtual const Operationlist& getSubOperations() const {return steps;}
2419 
2420  virtual const MetaClass& getType() const {return *metadata;}
2422  virtual size_t getSize() const
2423  {
2424  return sizeof(OperationRouting) + Operation::extrasize()
2425  + steps.size() * 2 * sizeof(Operation*);
2426  }
2427 
2428  protected:
2429  /** Extra logic to be used when instantiating an operationplan. */
2430  virtual DECLARE_EXPORT bool extraInstantiate(OperationPlan* o);
2431 
2432  private:
2433  /** Stores a double linked list of all step operations. */
2434  Operationlist steps;
2435 };
2436 
2437 
2439 {
2440  getOperation()->setOperationPlanParameters(this, x.quantity, x.start, x.end, true);
2441  if (quantity != x.quantity) quantity = x.quantity;
2442  assert(dates.getStart() == x.start || x.start!=x.end);
2443  assert(dates.getEnd() == x.end || x.start!=x.end);
2444 }
2445 
2446 
2447 /** This type defines what mode used to search the alternates. */
2449 {
2450  /** Select the alternate with the lowest priority number.<br>
2451  * This is the default.
2452  */
2454  /** Select the alternate which gives the lowest cost. */
2455  MINCOST = 1,
2456  /** Select the alternate which gives the lowest penalty. */
2458  /** Select the alternate which gives the lowest sum of the cost and
2459  * penalty. */
2461 };
2462 
2463 
2464 /** Writes a search mode to an output stream. */
2465 inline ostream & operator << (ostream & os, const SearchMode & d)
2466 {
2467  switch (d)
2468  {
2469  case PRIORITY: os << "PRIORITY"; return os;
2470  case MINCOST: os << "MINCOST"; return os;
2471  case MINPENALTY: os << "MINPENALTY"; return os;
2472  case MINCOSTPENALTY: os << "MINCOSTPENALTY"; return os;
2473  default: assert(false); return os;
2474  }
2475 }
2476 
2477 
2478 /** Translate a string to a search mode value. */
2479 DECLARE_EXPORT SearchMode decodeSearchMode(const string& c);
2480 
2481 
2482 /** @brief This class represents a choice between multiple operations. The
2483  * alternates are sorted in order of priority.
2484  */
2486 {
2487  public:
2488  typedef pair<int,DateRange> alternateProperty;
2489 
2490  /** Constructor. */
2491  explicit OperationAlternate(const string& c)
2492  : Operation(c), search(PRIORITY) {initType(metadata);}
2493 
2494  /** Destructor. */
2496 
2497  /** Add a new alternate operation.<br>
2498  * The lower the priority value, the more important this alternate
2499  * operation is. */
2500  DECLARE_EXPORT void addAlternate
2501  (Operation*, int = 1, DateRange = DateRange());
2502 
2503  /** Removes an alternate from the list. */
2504  DECLARE_EXPORT void removeSubOperation(Operation *);
2505 
2506  /** Returns the properties of a certain suboperation.
2507  * @exception LogicException Generated when the argument operation is
2508  * null or when it is not a sub-operation of this alternate.
2509  */
2510  DECLARE_EXPORT const alternateProperty& getProperties(Operation* o) const;
2511 
2512  /** Updates the priority of a certain suboperation.
2513  * @exception DataException Generated when the argument operation is
2514  * not null and not a sub-operation of this alternate.
2515  */
2516  DECLARE_EXPORT void setPriority(Operation*, int);
2517 
2518  /** Updates the effective daterange of a certain suboperation.
2519  * @exception DataException Generated when the argument operation is
2520  * not null and not a sub-operation of this alternate.
2521  */
2522  DECLARE_EXPORT void setEffective(Operation*, DateRange);
2523 
2524  /** Return the search mode. */
2525  SearchMode getSearch() const {return search;}
2526 
2527  /** Update the search mode. */
2528  void setSearch(const string a) {search = decodeSearchMode(a);}
2529 
2530  /** A operation of this type enforces the following rules on its
2531  * operationplans:
2532  * - Very simple, call the method with the same name on the alternate
2533  * suboperationplan.
2534  * @see Operation::setOperationPlanParameters
2535  */
2536  DECLARE_EXPORT OperationPlanState setOperationPlanParameters
2537  (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
2538 
2539  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
2540  DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
2541  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
2542  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
2543  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
2544  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
2545  virtual const Operationlist& getSubOperations() const {return alternates;}
2546  static int initialize();
2547 
2548  /** Add an alternate to the operation.<br>
2549  * The keyword arguments are "operation", "priority", "effective_start"
2550  * and "effective_end"
2551  */
2552  static DECLARE_EXPORT PyObject* addAlternate(PyObject*, PyObject*, PyObject*);
2553 
2554  virtual const MetaClass& getType() const {return *metadata;}
2556  virtual size_t getSize() const
2557  {
2558  return sizeof(OperationAlternate) + Operation::extrasize()
2559  + alternates.size() * (5*sizeof(Operation*)+sizeof(alternateProperty));
2560  }
2561 
2562  protected:
2563  /** Extra logic to be used when instantiating an operationplan. */
2564  virtual DECLARE_EXPORT bool extraInstantiate(OperationPlan* o);
2565 
2566  private:
2567  typedef list<alternateProperty> alternatePropertyList;
2568 
2569  /** List of the priorities of the different alternate operations. The list
2570  * is maintained such that it is sorted in ascending order of priority. */
2571  alternatePropertyList alternateProperties;
2572 
2573  /** List of all alternate operations. The list is sorted with the operation
2574  * with the highest priority at the start of the list.<br>
2575  * Note that the list of operations and the list of priorities go hand in
2576  * hand: they have an equal number of elements and the order of the
2577  * elements is matching in both lists.
2578  */
2579  Operationlist alternates;
2580 
2581  /** Mode to select the preferred alternates. */
2582  SearchMode search;
2583 };
2584 
2585 
2586 /** @brief An item defines the products being planned, sold, stored and/or
2587  * manufactured. Buffers and demands have a reference an item.
2588  *
2589  * This is an abstract class.
2590  */
2591 class Item : public HasHierarchy<Item>, public HasDescription
2592 {
2593  public:
2594  /** Constructor. Don't use this directly! */
2595  explicit Item(const string& str) : HasHierarchy<Item>(str),
2596  deliveryOperation(NULL), price(0.0) {}
2597 
2598  /** Returns the delivery operation.<br>
2599  * This field is inherited from a parent item, if it hasn't been
2600  * specified.
2601  */
2602  Operation* getOperation() const
2603  {
2604  // Current item has a non-empty deliveryOperation field
2605  if (deliveryOperation) return deliveryOperation;
2606 
2607  // Look for a non-empty deliveryOperation field on owners
2608  for (Item* i = getOwner(); i; i=i->getOwner())
2609  if (i->deliveryOperation) return i->deliveryOperation;
2610 
2611  // The field is not specified on the item or any of its parents.
2612  return NULL;
2613  }
2614 
2615  /** Updates the delivery operation.<br>
2616  * If some demands have already been planned using the old delivery
2617  * operation they are left untouched and won't be replanned.
2618  */
2619  void setOperation(Operation* o) {deliveryOperation = o;}
2620 
2621  /** Return the selling price of the item.<br>
2622  * The default value is 0.0.
2623  */
2624  double getPrice() const {return price;}
2625 
2626  /** Update the selling price of the item. */
2627  void setPrice(const double c)
2628  {
2629  if (c >= 0) price = c;
2630  else throw DataException("Item price must be positive");
2631  }
2632 
2633  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
2634  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
2635  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
2636  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
2637  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
2638  static int initialize();
2639 
2640  /** Destructor. */
2641  virtual DECLARE_EXPORT ~Item();
2642 
2643  virtual const MetaClass& getType() const {return *metadata;}
2645 
2646  private:
2647  /** This is the operation used to satisfy a demand for this item.
2648  * @see Demand
2649  */
2650  Operation* deliveryOperation;
2651 
2652  /** Selling price of the item. */
2653  double price;
2654 };
2655 
2656 
2657 /** @brief This class is the default implementation of the abstract Item
2658  * class. */
2659 class ItemDefault : public Item
2660 {
2661  public:
2662  explicit ItemDefault(const string& str) : Item(str) {initType(metadata);}
2663  virtual const MetaClass& getType() const {return *metadata;}
2665  virtual size_t getSize() const
2666  {
2667  return sizeof(ItemDefault) + getName().size()
2669  }
2670  static int initialize();
2671 };
2672 
2673 
2674 /** @brief A buffer represents a combination of a item and location.<br>
2675  * It is the entity for keeping modeling inventory.
2676  */
2677 class Buffer : public HasHierarchy<Buffer>, public HasLevel,
2678  public Plannable, public HasDescription
2679 {
2680  friend class Flow;
2681  friend class FlowPlan;
2682 
2683  public:
2686 
2687  /** Constructor. Implicit creation of instances is disallowed. */
2688  explicit Buffer(const string& str) : HasHierarchy<Buffer>(str),
2689  hidden(false), producing_operation(NULL), loc(NULL), it(NULL),
2690  min_val(0), max_val(default_max), min_cal(NULL), max_cal(NULL),
2691  carrying_cost(0.0) {}
2692 
2693  /** Returns the operation that is used to supply extra supply into this
2694  * buffer. */
2695  Operation* getProducingOperation() const {return producing_operation;}
2696 
2697  /** Updates the operation that is used to supply extra supply into this
2698  * buffer. */
2699  void setProducingOperation(Operation* o)
2700  {producing_operation = o; setChanged();}
2701 
2702  /** Returns the item stored in this buffer. */
2703  Item* getItem() const {return it;}
2704 
2705  /** Updates the Item stored in this buffer. */
2706  void setItem(Item* i) {it = i; setChanged();}
2707 
2708  /** Returns the Location of this buffer. */
2709  Location* getLocation() const {return loc;}
2710 
2711  /** Updates the location of this buffer. */
2712  void setLocation(Location* i) {loc = i;}
2713 
2714  /** Returns the minimum inventory level. */
2715  double getMinimum() const {return min_val;}
2716 
2717  /** Returns a pointer to a calendar for storing the minimum inventory
2718  * level. */
2719  CalendarDouble* getMinimumCalendar() const {return min_cal;}
2720 
2721  /** Returns the maximum inventory level. */
2722  double getMaximum() const {return max_val;}
2723 
2724  /** Returns a pointer to a calendar for storing the maximum inventory
2725  * level. */
2726  CalendarDouble* getMaximumCalendar() const {return max_cal;}
2727 
2728  /** Updates the minimum inventory target for the buffer. */
2729  DECLARE_EXPORT void setMinimum(double);
2730 
2731  /** Updates the minimum inventory target for the buffer. */
2732  DECLARE_EXPORT void setMinimumCalendar(CalendarDouble *);
2733 
2734  /** Updates the minimum inventory target for the buffer. */
2735  DECLARE_EXPORT void setMaximum(double);
2736 
2737  /** Updates the minimum inventory target for the buffer. */
2738  DECLARE_EXPORT void setMaximumCalendar(CalendarDouble *);
2739 
2740  /** Return the carrying cost.<br>
2741  * The cost of carrying inventory in this buffer. The value is a
2742  * percentage of the item sales price, per year and per unit.
2743  */
2744  double getCarryingCost() const {return carrying_cost;}
2745 
2746  /** Return the carrying cost.<br>
2747  * The cost of carrying inventory in this buffer. The value is a
2748  * percentage of the item sales price, per year and per unit.<br>
2749  * The default value is 0.0.
2750  */
2751  void setCarryingCost(const double c)
2752  {
2753  if (c >= 0) carrying_cost = c;
2754  else throw DataException("Buffer carrying_cost must be positive");
2755  }
2756 
2757  DECLARE_EXPORT virtual void beginElement(XMLInput&, const Attribute&);
2758  DECLARE_EXPORT virtual void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
2759  DECLARE_EXPORT virtual void endElement(XMLInput&, const Attribute&, const DataElement&);
2760  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
2761  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
2762 
2763  size_t extrasize() const
2764  {return getName().size() + HasDescription::extrasize();}
2765 
2766  /** Initialize the class. */
2767  static int initialize();
2768 
2769  /** Destructor. */
2770  virtual DECLARE_EXPORT ~Buffer();
2771 
2772  /** Returns the available material on hand immediately after the
2773  * given date.
2774  */
2775  DECLARE_EXPORT double getOnHand(Date d = Date::infinitePast) const;
2776 
2777  /** Update the on-hand inventory at the start of the planning horizon. */
2778  DECLARE_EXPORT void setOnHand(double f);
2779 
2780  /** Returns minimum or maximum available material on hand in the given
2781  * daterange. The third parameter specifies whether we return the
2782  * minimum (which is the default) or the maximum value.
2783  * The computation is INclusive the start and end dates.
2784  */
2785  DECLARE_EXPORT double getOnHand(Date, Date, bool min = true) const;
2786 
2787  /** Returns a reference to the list of all flows of this buffer. */
2788  const flowlist& getFlows() const {return flows;}
2789 
2790  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
2791 
2792  /** Returns a reference to the list of all flow plans of this buffer. */
2793  const flowplanlist& getFlowPlans() const {return flowplans;}
2794 
2795  /** Returns a reference to the list of all flow plans of this buffer. */
2796  flowplanlist& getFlowPlans() {return flowplans;}
2797 
2798  /** Return the flow that is associates a given operation with this
2799  * buffer.<br>Returns NULL is no such flow exists. */
2800  Flow* findFlow(const Operation* o, Date d) const
2801  {return flows.find(o,d);}
2802 
2803  /** Deletes all operationplans consuming from or producing from this
2804  * buffer. The boolean parameter controls whether we delete also locked
2805  * operationplans or not.
2806  */
2807  DECLARE_EXPORT void deleteOperationPlans(bool deleteLockedOpplans = false);
2808 
2809  virtual DECLARE_EXPORT void updateProblems();
2810 
2811  void setHidden(bool b) {if (hidden!=b) setChanged(); hidden = b;}
2812  bool getHidden() const {return hidden;}
2813 
2814  virtual const MetaClass& getType() const {return *metadata;}
2816 
2817  /** This function matches producing and consuming operationplans
2818  * with each other, and updates the pegging iterator accordingly.
2819  */
2820  virtual DECLARE_EXPORT void followPegging
2821  (PeggingIterator&, FlowPlan*, short, double, double);
2822 
2823  private:
2824  /** A constant defining the default max inventory target.\\
2825  * Theoretically we should set this to DBL_MAX, but then the results
2826  * are not portable across platforms.
2827  */
2828  static DECLARE_EXPORT const double default_max;
2829 
2830  /** This models the dynamic part of the plan, representing all planned
2831  * material flows on this buffer. */
2832  flowplanlist flowplans;
2833 
2834  /** This models the defined material flows on this buffer. */
2835  flowlist flows;
2836 
2837  /** Hide this entity from serialization or not. */
2838  bool hidden;
2839 
2840  /** This is the operation used to create extra material in this buffer. */
2841  Operation *producing_operation;
2842 
2843  /** Location of this buffer.<br>
2844  * This field is only used as information.<br>
2845  * The default is NULL.
2846  */
2847  Location* loc;
2848 
2849  /** Item being stored in this buffer.<br>
2850  * The default value is NULL.
2851  */
2852  Item* it;
2853 
2854  /** Minimum inventory target.<br>
2855  * If a minimum calendar is specified this field is ignored.
2856  * @see min_cal
2857  */
2858  double min_val;
2859 
2860  /** Maximum inventory target. <br>
2861  * If a maximum calendar is specified this field is ignored.
2862  * @see max_cal
2863  */
2864  double max_val;
2865 
2866  /** Points to a calendar to store the minimum inventory level.<br>
2867  * The default value is NULL, resulting in a constant minimum level
2868  * of 0.
2869  */
2870  CalendarDouble *min_cal;
2871 
2872  /** Points to a calendar to store the maximum inventory level.<br>
2873  * The default value is NULL, resulting in a buffer without excess
2874  * inventory problems.
2875  */
2876  CalendarDouble *max_cal;
2877 
2878  /** Carrying cost.<br>
2879  * The cost of carrying inventory in this buffer. The value is a
2880  * percentage of the item sales price, per year and per unit.
2881  */
2882  double carrying_cost;
2883 };
2884 
2885 
2886 
2887 /** @brief This class is the default implementation of the abstract Buffer class. */
2888 class BufferDefault : public Buffer
2889 {
2890  public:
2891  explicit BufferDefault(const string& str) : Buffer(str) {initType(metadata);}
2892  virtual const MetaClass& getType() const {return *metadata;}
2893  virtual size_t getSize() const
2894  {return sizeof(BufferDefault) + Buffer::extrasize();}
2896  static int initialize();
2897 };
2898 
2899 
2900 /** @brief This class represents a material buffer with an infinite supply of extra
2901  * material.
2902  *
2903  * In other words, it never constrains the plan and it doesn't propagate any
2904  * requirements upstream.
2905  */
2906 class BufferInfinite : public Buffer
2907 {
2908  public:
2909  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
2910  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
2911  virtual const MetaClass& getType() const {return *metadata;}
2912  virtual size_t getSize() const
2913  {return sizeof(BufferInfinite) + Buffer::extrasize();}
2914  explicit BufferInfinite(const string& c) : Buffer(c)
2915  {setDetectProblems(false); initType(metadata);}
2917  static int initialize();
2918 };
2919 
2920 
2921 /** @brief This class models a buffer that is replenish by an external supplier
2922  * using a reorder-point policy.
2923  *
2924  * It represents a material buffer where a replenishment is triggered
2925  * whenever the inventory drops below the minimum level. The buffer is then
2926  * replenished to the maximum inventory level.<br>
2927  * A leadtime is taken into account for the replenishments.<br>
2928  * The following parameters control this replenishment:
2929  * - <b>MinimumInventory</b>:<br>
2930  * Inventory level triggering a new replenishment.<br>
2931  * The actual inventory can drop below this value.
2932  * - <b>MaximumInventory</b>:<br>
2933  * Inventory level to which we try to replenish.<br>
2934  * The actual inventory can exceed this value.
2935  * - <b>Leadtime</b>:<br>
2936  * Time taken between placing the purchase order with the supplier and the
2937  * delivery of the material.
2938  *
2939  * Using the additional parameters described below the replenishments can be
2940  * controlled in more detail. The resulting inventory profile can end up
2941  * to be completely different from the classical saw-tooth pattern!
2942  *
2943  * The timing of the replenishments can be constrained by the following
2944  * parameters:
2945  * - <b>MinimumInterval</b>:<br>
2946  * Minimum time between replenishments.<br>
2947  * The order quantity will be increased such that it covers at least
2948  * the demand in the minimum interval period. The actual inventory can
2949  * exceed the target set by the MinimumInventory parameter.
2950  * - <b>MaximumInterval</b>:<br>
2951  * Maximum time between replenishments.<br>
2952  * The order quantity will replenish to an inventory value less than the
2953  * maximum when this maximum interval is reached.
2954  * When the minimum and maximum interval are equal we basically define a fixed
2955  * schedule replenishment policy.
2956  *
2957  * The quantity of the replenishments can be constrained by the following
2958  * parameters:
2959  * - <b>MinimumQuantity</b>:<br>
2960  * Minimum quantity for a replenishment.<br>
2961  * This parameter can cause the actual inventory to exceed the target set
2962  * by the MinimumInventory parameter.
2963  * - <b>MaximumQuantity</b>:<br>
2964  * Maximum quantity for a replenishment.<br>
2965  * This parameter can cause the maximum inventory target never to be
2966  * reached.
2967  * - <b>MultipleQuantity</b>:<br>
2968  * All replenishments are rounded up to a multiple of this value.
2969  * When the minimum and maximum quantity are equal we basically define a fixed
2970  * quantity replenishment policy.
2971  */
2972 class BufferProcure : public Buffer
2973 {
2974  public:
2975  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
2976  virtual DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
2977  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
2978  virtual const MetaClass& getType() const {return *metadata;}
2979  virtual size_t getSize() const
2980  {return sizeof(BufferProcure) + Buffer::extrasize();}
2981  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
2982  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
2983  static int initialize();
2984 
2985  /** Constructor. */
2986  explicit BufferProcure(const string& c) : Buffer(c),
2987  size_minimum(0), size_maximum(DBL_MAX), size_multiple(0),
2988  oper(NULL) {initType(metadata);}
2990 
2991  /** Return the purchasing leadtime. */
2992  TimePeriod getLeadtime() const {return leadtime;}
2993 
2994  /** Update the procurement leadtime. */
2995  void setLeadtime(TimePeriod p)
2996  {
2997  if (p<0L)
2998  throw DataException("Procurement buffer can't have a negative lead time");
2999  leadtime = p;
3000  static_cast<OperationFixedTime*>(getOperation())->setDuration(leadtime);
3001  }
3002 
3003  /** Return the release time fence. */
3004  TimePeriod getFence() const {return fence;}
3005 
3006  /** Update the release time fence. */
3007  void setFence(TimePeriod p)
3008  {
3009  fence = p;
3010  getOperation()->setFence(p);
3011  }
3012 
3013  /** Return the inventory level that will trigger creation of a
3014  * purchasing.
3015  */
3016  double getMinimumInventory() const
3017  {return getFlowPlans().getMin(Date::infiniteFuture);}
3018 
3019  /** Update the inventory level that will trigger the creation of a
3020  * replenishment.<br>
3021  * Because of the replenishment leadtime, the actual inventory will drop
3022  * below this value. It is up to the user to set an appropriate minimum
3023  * value.
3024  */
3025  void setMinimumInventory(double f)
3026  {
3027  if (f<0)
3028  throw DataException("Procurement buffer can't have a negative minimum inventory");
3029  flowplanlist::EventMinQuantity* min = getFlowPlans().getMinEvent(Date::infiniteFuture);
3030  if (min)
3031  min->setMin(f);
3032  else
3033  {
3034  // Create and insert a new minimum event
3035  min = new flowplanlist::EventMinQuantity(Date::infinitePast, f);
3036  getFlowPlans().insert(min);
3037  }
3038  // The minimum is increased over the maximum: auto-increase the maximum.
3039  if (getFlowPlans().getMax(Date::infiniteFuture) < f)
3040  setMaximumInventory(f);
3041  }
3042 
3043  /** Return the maximum inventory level to which we wish to replenish. */
3044  double getMaximumInventory() const
3045  {return getFlowPlans().getMax(Date::infiniteFuture);}
3046 
3047  /** Update the maximum inventory level to which we plan to replenish.<br>
3048  * This is not a hard limit - other parameters can make that the actual
3049  * inventory either never reaches this value or always exceeds it.
3050  */
3051  void setMaximumInventory(double f)
3052  {
3053  if (f<0)
3054  throw DataException("Procurement buffer can't have a negative maximum inventory");
3055  flowplanlist::EventMaxQuantity* max = getFlowPlans().getMaxEvent(Date::infiniteFuture);
3056  if (max)
3057  max->setMax(f);
3058  else
3059  {
3060  // Create and insert a new maximum event
3061  max = new flowplanlist::EventMaxQuantity(Date::infinitePast, f);
3062  getFlowPlans().insert(max);
3063  }
3064  // The maximum is lowered below the minimum: auto-decrease the minimum
3065  if (f < getFlowPlans().getMin(Date::infiniteFuture))
3066  setMinimumInventory(f);
3067  }
3068 
3069  /** Return the minimum interval between purchasing operations.<br>
3070  * This parameter doesn't control the timing of the first purchasing
3071  * operation, but only to the subsequent ones.
3072  */
3073  TimePeriod getMinimumInterval() const {return min_interval;}
3074 
3075  /** Update the minimum time between replenishments. */
3076  void setMinimumInterval(TimePeriod p)
3077  {
3078  if (p<0L)
3079  throw DataException("Procurement buffer can't have a negative minimum interval");
3080  min_interval = p;
3081  // minimum is increased over the maximum: auto-increase the maximum
3082  if (max_interval < min_interval) max_interval = min_interval;
3083  }
3084 
3085  /** Return the maximum time interval between sytem-generated replenishment
3086  * operations.
3087  */
3088  TimePeriod getMaximumInterval() const {return max_interval;}
3089 
3090  /** Update the minimum time between replenishments. */
3091  void setMaximumInterval(TimePeriod p)
3092  {
3093  if (p<0L)
3094  throw DataException("Procurement buffer can't have a negative maximum interval");
3095  max_interval = p;
3096  // maximum is lowered below the minimum: auto-decrease the minimum
3097  if (max_interval < min_interval) min_interval = max_interval;
3098  }
3099 
3100  /** Return the minimum quantity of a purchasing operation. */
3101  double getSizeMinimum() const {return size_minimum;}
3102 
3103  /** Update the minimum replenishment quantity. */
3104  void setSizeMinimum(double f)
3105  {
3106  if (f<0)
3107  throw DataException("Procurement buffer can't have a negative minimum size");
3108  size_minimum = f;
3109  getOperation()->setSizeMinimum(f);
3110  // minimum is increased over the maximum: auto-increase the maximum
3111  if (size_maximum < size_minimum) size_maximum = size_minimum;
3112  }
3113 
3114  /** Return the maximum quantity of a purchasing operation. */
3115  double getSizeMaximum() const {return size_maximum;}
3116 
3117  /** Update the maximum replenishment quantity. */
3118  void setSizeMaximum(double f)
3119  {
3120  if (f<0)
3121  throw DataException("Procurement buffer can't have a negative maximum size");
3122  size_maximum = f;
3123  getOperation()->setSizeMaximum(f);
3124  // maximum is lowered below the minimum: auto-decrease the minimum
3125  if (size_maximum < size_minimum) size_minimum = size_maximum;
3126  }
3127 
3128  /** Return the multiple quantity of a purchasing operation. */
3129  double getSizeMultiple() const {return size_multiple;}
3130 
3131  /** Update the multiple quantity. */
3132  void setSizeMultiple(double f)
3133  {
3134  if (f<0)
3135  throw DataException("Procurement buffer can't have a negative multiple size");
3136  size_multiple = f;
3137  getOperation()->setSizeMultiple(f);
3138  }
3139 
3140  /** Returns the operation that is automatically created to represent the
3141  * procurements.
3142  */
3143  DECLARE_EXPORT Operation* getOperation() const;
3144 
3145  private:
3146  /** Purchasing leadtime.<br>
3147  * Within this leadtime fence no additional purchase orders can be generated.
3148  */
3149  TimePeriod leadtime;
3150 
3151  /** Time window from the current date in which all procurements are expected
3152  * to be released.
3153  */
3154  TimePeriod fence;
3155 
3156  /** Minimum time interval between purchasing operations. */
3157  TimePeriod min_interval;
3158 
3159  /** Maximum time interval between purchasing operations. */
3160  TimePeriod max_interval;
3161 
3162  /** Minimum purchasing quantity.<br>
3163  * The default value is 0, meaning no minimum.
3164  */
3165  double size_minimum;
3166 
3167  /** Maximum purchasing quantity.<br>
3168  * The default value is 0, meaning no maximum limit.
3169  */
3170  double size_maximum;
3171 
3172  /** Purchases are always rounded up to a multiple of this quantity.<br>
3173  * The default value is 0, meaning no multiple needs to be applied.
3174  */
3175  double size_multiple;
3176 
3177  /** A pointer to the procurement operation. */
3178  Operation* oper;
3179 };
3180 
3181 
3182 /** @brief This class defines a material flow to/from a buffer, linked with an
3183  * operation. This default implementation plans the material flow at the
3184  * start of the operation.
3185  */
3186 class Flow : public Object, public Association<Operation,Buffer,Flow>::Node,
3187  public Solvable
3188 {
3189  public:
3190  /** Destructor. */
3191  virtual DECLARE_EXPORT ~Flow();
3192 
3193  /** Constructor. */
3194  explicit Flow(Operation* o, Buffer* b, double q)
3195  : quantity(q), hasAlts(false), altFlow(NULL), search(PRIORITY)
3196  {
3197  setOperation(o);
3198  setBuffer(b);
3199  initType(metadata);
3200  try { validate(ADD); }
3201  catch (...)
3202  {
3203  if (getOperation()) getOperation()->flowdata.erase(this);
3204  if (getBuffer()) getBuffer()->flows.erase(this);
3205  resetReferenceCount();
3206  throw;
3207  }
3208  }
3209 
3210  /** Constructor. */
3211  explicit Flow(Operation* o, Buffer* b, double q, DateRange e)
3212  : quantity(q), hasAlts(false), altFlow(NULL), search(PRIORITY)
3213  {
3214  setOperation(o);
3215  setBuffer(b);
3216  setEffective(e);
3217  initType(metadata);
3218  try { validate(ADD); }
3219  catch (...)
3220  {
3221  if (getOperation()) getOperation()->flowdata.erase(this);
3222  if (getBuffer()) getBuffer()->flows.erase(this);
3223  resetReferenceCount();
3224  throw;
3225  }
3226  }
3227 
3228  /** Returns the operation. */
3229  Operation* getOperation() const {return getPtrA();}
3230 
3231  /** Updates the operation of this flow. This method can be called only ONCE
3232  * for each flow. In case that doesn't suit you, delete the existing flow
3233  * and create a new one.
3234  */
3235  void setOperation(Operation* o) {if (o) setPtrA(o,o->getFlows());}
3236 
3237  /** Returns true if this flow consumes material from the buffer. */
3238  bool isConsumer() const {return quantity < 0;}
3239 
3240  /** Returns true if this flow produces material into the buffer. */
3241  bool isProducer() const {return quantity >= 0;}
3242 
3243  /** Returns the material flow PER UNIT of the operationplan. */
3244  double getQuantity() const {return quantity;}
3245 
3246  /** Updates the material flow PER UNIT of the operationplan. Existing
3247  * flowplans are NOT updated to take the new quantity in effect. Only new
3248  * operationplans and updates to existing ones will use the new quantity
3249  * value.
3250  */
3251  void setQuantity(double f) {quantity = f;}
3252 
3253  /** Returns the buffer. */
3254  Buffer* getBuffer() const {return getPtrB();}
3255 
3256  /** Updates the buffer of this flow. This method can be called only ONCE
3257  * for each flow. In case that doesn't suit you, delete the existing flow
3258  * and create a new one.
3259  */
3260  void setBuffer(Buffer* b) {if (b) setPtrB(b,b->getFlows());}
3261 
3262  /** Returns true if there are alternates for this flow. */
3263  bool hasAlternates() const {return hasAlts;}
3264 
3265  /** Returns the flow of which this one is an alternate.<br>
3266  * NULL is return where there is none.
3267  */
3268  Flow* getAlternate() const {return altFlow;}
3269 
3270  /** Define the flow of which this one is an alternate. */
3271  DECLARE_EXPORT void setAlternate(Flow *);
3272 
3273  /** Define the flow of which this one is an alternate. */
3274  DECLARE_EXPORT void setAlternate(const string& n);
3275 
3276  /** Return the search mode. */
3277  SearchMode getSearch() const {return search;}
3278 
3279  /** Update the search mode. */
3280  void setSearch(const string a) {search = decodeSearchMode(a);}
3281 
3282  /** A flow is considered hidden when either its buffer or operation
3283  * are hidden. */
3284  virtual bool getHidden() const
3285  {
3286  return (getBuffer() && getBuffer()->getHidden())
3287  || (getOperation() && getOperation()->getHidden());
3288  }
3289 
3290  /** This method holds the logic the compute the date of a flowplan. */
3291  virtual Date getFlowplanDate(const FlowPlan*) const;
3292 
3293  /** This method holds the logic the compute the quantity of a flowplan. */
3294  virtual double getFlowplanQuantity(const FlowPlan*) const;
3295 
3296  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
3297  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
3298  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
3299  static int initialize();
3300  static void writer(const MetaCategory*, XMLOutput*);
3301 
3302  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
3303 
3304  virtual const MetaClass& getType() const {return *metadata;}
3306  virtual size_t getSize() const {return sizeof(Flow) + getName().size();}
3307 
3308  protected:
3309  /** Default constructor. */
3310  explicit Flow() : quantity(0.0), hasAlts(false),
3311  altFlow(NULL), search(PRIORITY) {initType(metadata);}
3312 
3313  private:
3314  /** Verifies whether a flow meets all requirements to be valid. <br>
3315  * An exception is thrown if the flow is invalid.
3316  */
3317  DECLARE_EXPORT void validate(Action action);
3318 
3319  /** Quantity of the flow. */
3320  double quantity;
3321 
3322  /** Flag that is set to true when a flow has alternates. */
3323  bool hasAlts;
3324 
3325  /** A flow representing the main flow of a set of alternate flows. */
3326  Flow* altFlow;
3327 
3328  /** Mode to select the preferred alternates. */
3329  SearchMode search;
3330 
3331  static PyObject* create(PyTypeObject* pytype, PyObject* args, PyObject* kwds);
3332  DECLARE_EXPORT PyObject* getattro(const Attribute&);
3333  DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
3334 };
3335 
3336 
3337 /** @brief This class defines a material flow to/from a buffer, linked with an
3338  * operation. This subclass represents a flow that is at the start date of
3339  * the operation.
3340  */
3341 class FlowStart : public Flow
3342 {
3343  public:
3344  /** Constructor. */
3345  explicit FlowStart(Operation* o, Buffer* b, double q) : Flow(o,b,q) {}
3346 
3347  /** Constructor. */
3348  explicit FlowStart(Operation* o, Buffer* b, double q, DateRange e) : Flow(o,b,q,e) {}
3349 
3350  /** This constructor is called from the plan begin_element function. */
3351  explicit FlowStart() {}
3352 
3353  virtual const MetaClass& getType() const {return *metadata;}
3355  virtual size_t getSize() const {return sizeof(FlowStart);}
3356  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
3357 };
3358 
3359 
3360 /** @brief This class defines a material flow to/from a buffer, linked with an
3361  * operation. This subclass represents a flow that is at end date of the
3362  * operation.
3363  */
3364 class FlowEnd : public Flow
3365 {
3366  public:
3367  /** Constructor. */
3368  explicit FlowEnd(Operation* o, Buffer* b, double q) : Flow(o,b,q) {}
3369 
3370  /** Constructor. */
3371  explicit FlowEnd(Operation* o, Buffer* b, double q, DateRange e) : Flow(o,b,q,e) {}
3372 
3373  /** This constructor is called from the plan begin_element function. */
3374  explicit FlowEnd() {}
3375 
3376  /** This method holds the logic the compute the date of a flowplan. */
3377  virtual Date getFlowplanDate(const FlowPlan* fl) const;
3378 
3379  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
3380 
3381  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
3382 
3383  virtual const MetaClass& getType() const {return *metadata;}
3385  virtual size_t getSize() const {return sizeof(FlowEnd);}
3386 };
3387 
3388 
3389 /** @brief This class represents a flow at end date of the
3390  * operation and with a fiwed quantity.
3391  */
3392 class FlowFixedEnd : public FlowEnd
3393 {
3394  public:
3395  /** Constructor. */
3396  explicit FlowFixedEnd(Operation* o, Buffer* b, double q) : FlowEnd(o,b,q) {}
3397 
3398  /** Constructor. */
3399  explicit FlowFixedEnd(Operation* o, Buffer* b, double q, DateRange e) : FlowEnd(o,b,q,e) {}
3400 
3401  /** This constructor is called from the plan begin_element function. */
3402  explicit FlowFixedEnd() {}
3403 
3404  /** This method holds the logic the compute the quantity of a flowplan. */
3405  virtual double getFlowplanQuantity(const FlowPlan*) const;
3406 
3407  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
3408 
3409  virtual const MetaClass& getType() const {return *metadata;}
3411  virtual size_t getSize() const {return sizeof(FlowFixedEnd);}
3412 };
3413 
3414 
3415 /** @brief This class represents a flow at start date of the
3416  * operation and with a fiwed quantity.
3417  */
3419 {
3420  public:
3421  /** Constructor. */
3422  explicit FlowFixedStart(Operation* o, Buffer* b, double q) : FlowStart(o,b,q) {}
3423 
3424  /** Constructor. */
3425  explicit FlowFixedStart(Operation* o, Buffer* b, double q, DateRange e) : FlowStart(o,b,q,e) {}
3426 
3427  /** This constructor is called from the plan begin_element function. */
3428  explicit FlowFixedStart() {}
3429 
3430  /** This method holds the logic the compute the quantity of a flowplan. */
3431  virtual double getFlowplanQuantity(const FlowPlan*) const;
3432 
3433  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
3434 
3435  virtual const MetaClass& getType() const {return *metadata;}
3437  virtual size_t getSize() const {return sizeof(FlowFixedStart);}
3438 };
3439 
3440 
3441 /** @brief A flowplan represents a planned material flow in or out of a buffer.
3442  *
3443  * Flowplans are owned by operationplans, which manage a container to store
3444  * them.
3445  */
3446 class FlowPlan : public TimeLine<FlowPlan>::EventChangeOnhand, public PythonExtensionBase
3447 {
3449  private:
3450  /** Points to the flow instantiated by this flowplan. */
3451  const Flow *fl;
3452 
3453  /** Python interface method. */
3454  PyObject* getattro(const Attribute&);
3455 
3456  /** Points to the operationplan owning this flowplan. */
3457  OperationPlan *oper;
3458 
3459  /** Points to the next flowplan owned by the same operationplan. */
3460  FlowPlan *nextFlowPlan;
3461 
3462  public:
3463 
3465  static int initialize();
3466 
3467  /** Constructor. */
3468  explicit DECLARE_EXPORT FlowPlan(OperationPlan*, const Flow*);
3469 
3470  /** Returns the flow of which this is an plan instance. */
3471  const Flow* getFlow() const {return fl;}
3472 
3473  /** Returns the buffer. */
3474  const Buffer* getBuffer() const {return fl->getBuffer();}
3475 
3476  /** Update the flow of an already existing flowplan.<br>
3477  * The new flow must belong to the same operation.
3478  */
3479  DECLARE_EXPORT void setFlow(const Flow*);
3480 
3481  /** Returns the operationplan owning this flowplan. */
3482  OperationPlan* getOperationPlan() const {return oper;}
3483 
3484  /** Destructor. */
3485  virtual ~FlowPlan()
3486  {
3487  Buffer* b = getFlow()->getBuffer();
3488  b->setChanged();
3489  b->flowplans.erase(this);
3490  }
3491 
3492  /** Writing the element.
3493  * This method has the same prototype as a usual instance of the Object
3494  * class, but this is only superficial: FlowPlan isn't a subclass of
3495  * Object at all.
3496  */
3497  void DECLARE_EXPORT writeElement
3498  (XMLOutput*, const Keyword&, mode=DEFAULT) const;
3499 
3500  /** Updates the quantity of the flowplan by changing the quantity of the
3501  * operationplan owning this flowplan.<br>
3502  * The boolean parameter is used to control whether to round up (false)
3503  * or down (true) in case the operation quantity must be a multiple.<br>
3504  * The second parameter is to flag whether we want to actually perform
3505  * the resizing, or only to simulate it.
3506  */
3507  double setQuantity(double qty, bool b=false, bool u = true)
3508  {
3509  if (!getFlow()->getEffective().within(getDate())) return 0.0;
3510  if (getFlow()->getType() == *FlowFixedEnd::metadata
3511  || getFlow()->getType() == *FlowFixedStart::metadata)
3512  {
3513  // Fixed quantity flows only allow resizing to 0
3514  if (qty == 0.0 && oper->getQuantity()!= 0.0)
3515  return oper->setQuantity(0.0, b, u) ? getFlow()->getQuantity() : 0.0;
3516  else if (qty != 0.0 && oper->getQuantity()== 0.0)
3517  return oper->setQuantity(
3518  (oper->getOperation()->getSizeMinimum()<=0) ? 0.001
3519  : oper->getOperation()->getSizeMinimum(),
3520  b, u) ? getFlow()->getQuantity() : 0.0;
3521  }
3522  else
3523  // Normal, proportional flows
3524  return oper->setQuantity(qty / getFlow()->getQuantity(), b, u) * getFlow()->getQuantity();
3525  throw LogicException("Unreachable code reached");
3526  }
3527 
3528  /** This function needs to be called whenever the flowplan date or
3529  * quantity are changed.
3530  */
3531  DECLARE_EXPORT void update();
3532 
3533  /** Return a pointer to the timeline data structure owning this flowplan. */
3534  TimeLine<FlowPlan>* getTimeLine() const
3535  {return &(getFlow()->getBuffer()->flowplans);}
3536 
3537  /** Returns true when the flowplan is hidden.<br>
3538  * This is determined by looking at whether the flow is hidden or not.
3539  */
3540  bool getHidden() const {return fl->getHidden();}
3541 };
3542 
3543 
3544 inline double Flow::getFlowplanQuantity(const FlowPlan* fl) const
3545 {
3546  return getEffective().within(fl->getDate()) ?
3547  fl->getOperationPlan()->getQuantity() * getQuantity() :
3548  0.0;
3549 }
3550 
3551 
3552 inline double FlowFixedStart::getFlowplanQuantity(const FlowPlan* fl) const
3553 {
3554  return getEffective().within(fl->getDate()) ?
3555  getQuantity() :
3556  0.0;
3557 }
3558 
3559 
3560 inline double FlowFixedEnd::getFlowplanQuantity(const FlowPlan* fl) const
3561 {
3562  return getEffective().within(fl->getDate()) ?
3563  getQuantity() :
3564  0.0;
3565 }
3566 
3567 
3568 inline Date Flow::getFlowplanDate(const FlowPlan* fl) const
3569 {
3570  return fl->getOperationPlan()->getDates().getStart();
3571 }
3572 
3573 
3574 inline Date FlowEnd::getFlowplanDate(const FlowPlan* fl) const
3575 {
3576  return fl->getOperationPlan()->getDates().getEnd();
3577 }
3578 
3579 
3580 /** @brief This class is used to represent a matrix defining the changeover
3581  * times between setups.
3582  */
3583 class SetupMatrix : public HasName<SetupMatrix>
3584 {
3585  public:
3586  class RuleIterator; // Forward declaration
3587  /** @brief An specific changeover rule in a setup matrix. */
3588  class Rule : public Object
3589  {
3590  friend class RuleIterator;
3591  friend class SetupMatrix;
3592  public:
3593  /** Constructor. */
3594  DECLARE_EXPORT Rule(SetupMatrix *s, int p = 0);
3595 
3596  /** Destructor. */
3597  DECLARE_EXPORT ~Rule();
3598 
3599  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
3600  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
3601  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
3602  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
3603  static int initialize();
3604 
3605  virtual const MetaClass& getType() const {return *metadata;}
3607 
3608  size_t getSize() const
3609  {return sizeof(Rule) + from.size() + to.size();}
3610 
3611  /** Update the priority.<br>
3612  * The priority value is a key field. If multiple rules have the
3613  * same priority a data exception is thrown.
3614  */
3615  DECLARE_EXPORT void setPriority(const int);
3616 
3617  /** Return the matrix owning this rule. */
3618  SetupMatrix* getSetupMatrix() const {return matrix;}
3619 
3620  /** Return the priority. */
3621  double getPriority() const {return priority;}
3622 
3623  /** Update the from setup. */
3624  void setFromSetup(const string f) {from = f;}
3625 
3626  /** Return the from setup. */
3627  const string& getFromSetup() const {return from;}
3628 
3629  /** Update the from setup. */
3630  void setToSetup(const string f) {to = f;}
3631 
3632  /** Return the from setup. */
3633  const string& getToSetup() const {return to;}
3634 
3635  /** Update the conversion duration. */
3636  void setDuration(const TimePeriod p) {duration = p;}
3637 
3638  /** Return the conversion duration. */
3639  TimePeriod getDuration() const {return duration;}
3640 
3641  /** Update the conversion cost. */
3642  void setCost(const double p) {cost = p;}
3643 
3644  /** Return the conversion cost. */
3645  double getCost() const {return cost;}
3646 
3647  private:
3648  /** Original setup. */
3649  string from;
3650 
3651  /** New setup. */
3652  string to;
3653 
3654  /** Changeover time. */
3655  TimePeriod duration;
3656 
3657  /** Changeover cost. */
3658  double cost;
3659 
3660  /** Priority of the rule.<br>
3661  * This field is the key field, i.e. within a setup matrix all rules
3662  * need to have different priorities.
3663  */
3664  int priority;
3665 
3666  /** Pointer to the owning matrix. */
3667  SetupMatrix *matrix;
3668 
3669  /** Pointer to the next rule in this matrix. */
3670  Rule *nextRule;
3671 
3672  /** Pointer to the previous rule in this matrix. */
3673  Rule *prevRule;
3674  };
3675 
3676  /** @brief An iterator class to go through all rules of a setup matrix. */
3678  {
3679  private:
3680  Rule* curRule;
3681  public:
3682  /** Constructor. */
3683  RuleIterator(Rule* c = NULL) : curRule(c) {}
3684  bool operator != (const RuleIterator &b) const
3685  {return b.curRule != curRule;}
3686  bool operator == (const RuleIterator &b) const
3687  {return b.curRule == curRule;}
3688  RuleIterator& operator++()
3689  {if (curRule) curRule = curRule->nextRule; return *this;}
3690  RuleIterator operator++(int)
3691  {RuleIterator tmp = *this; ++*this; return tmp;}
3692  RuleIterator& operator--()
3693  {if(curRule) curRule = curRule->prevRule; return *this;}
3694  RuleIterator operator--(int)
3695  {RuleIterator tmp = *this; --*this; return tmp;}
3696  Rule* operator ->() const {return curRule;}
3697  Rule& operator *() const {return *curRule;}
3698  };
3699 
3700  public:
3701  /** Default constructor. */
3702  SetupMatrix(const string& n) : HasName<SetupMatrix>(n), firstRule(NULL) {}
3703 
3704  /** Destructor. */
3706 
3707  /** This is a factory method that creates a new rule<br>
3708  * This method is intended to be used to create objects when reading
3709  * XML input data.
3710  */
3711  DECLARE_EXPORT Rule* createRule(const AttributeList&);
3712 
3713  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
3714  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
3715  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
3716  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
3717  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
3718  static int initialize();
3719 
3720  virtual const MetaClass& getType() const {return *metadata;}
3722 
3723  virtual size_t getSize() const
3724  {
3725  size_t i = sizeof(SetupMatrix) + getName().size();
3726  for (RuleIterator j = beginRules(); j!= endRules(); ++j)
3727  i += j->getSize();
3728  return i;
3729  }
3730 
3731  size_t extrasize() const
3732  {
3733  size_t i = getName().size();
3734  for (RuleIterator j = beginRules(); j!= endRules(); ++j)
3735  i += j->getSize();
3736  return i;
3737  }
3738 
3739  /** Returns an iterator to go through the list of rules. */
3740  RuleIterator beginRules() const {return RuleIterator(firstRule);}
3741 
3742  /** Returns an iterator to go through the list of rules. */
3743  RuleIterator endRules() const {return RuleIterator(NULL);}
3744 
3745  /** Python interface to add a new rule. */
3746  static DECLARE_EXPORT PyObject* addPythonRule(PyObject*, PyObject*, PyObject*);
3747 
3748  /** Computes the changeover time and cost between 2 setup values.
3749  *
3750  * To compute the time of a changeover the algorithm will evaluate all
3751  * rules in sequence (in order of priority).<br>
3752  * For a rule to match the changeover between the original setup X to
3753  * a new setup Y, two conditions need to be fulfilled:
3754  * - The original setup X must match with the fromsetup of the rule.<br>
3755  * If the fromsetup field is empty, it is considered a match.
3756  * - The new setup Y must match with the tosetup of the rule.<br>
3757  * If the tosetup field is empty, it is considered a match.
3758  * The wildcard characters * and ? can be used in the fromsetup and
3759  * tosetup fields.<br>
3760  * As soon as a matching rule is found, it is applied and subsequent
3761  * rules are not evaluated.<br>
3762  * If no matching rule is found, the changeover is not allowed: a NULL
3763  * pointer is returned.
3764  */
3765  DECLARE_EXPORT Rule* calculateSetup(const string, const string) const;
3766 
3767  private:
3768  /** Head of the list of rules. */
3769  Rule *firstRule;
3770 };
3771 
3772 
3773 /** @brief This class is the default implementation of the abstract
3774  * SetupMatrix class.
3775  */
3777 {
3778  public:
3779  explicit SetupMatrixDefault(const string& str) : SetupMatrix(str) {initType(metadata);}
3780  virtual const MetaClass& getType() const {return *metadata;}
3782  virtual size_t getSize() const
3783  {return sizeof(SetupMatrixDefault) + SetupMatrix::extrasize();}
3784  static int initialize();
3785 };
3786 
3787 
3788 /** @brief This class models skills that can be assigned to resources. */
3789 class Skill : public HasName<Skill>
3790 {
3791  friend class ResourceSkill;
3792 
3793  public:
3794  /** Default constructor. */
3795  Skill(const string& n) : HasName<Skill>(n) {}
3796 
3797  /** Destructor. */
3798  DECLARE_EXPORT ~Skill();
3799 
3801 
3802  /** Returns an reference to the list of resources having this skill. */
3803  const resourcelist& getResources() const {return resources;}
3804 
3805  /** Python interface to add a new resource. */
3806  static DECLARE_EXPORT PyObject* addPythonResource(PyObject*, PyObject*);
3807 
3808  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
3809  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
3810  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
3811  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
3812  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
3813  static int initialize();
3814 
3815  virtual const MetaClass& getType() const {return *metadata;}
3817 
3818  virtual size_t getSize() const
3819  {
3820  size_t i = sizeof(Skill) + getName().size() + resources.size() * 3 * sizeof(Resource*);
3821  return i;
3822  }
3823 
3824  size_t extrasize() const
3825  {
3826  return getName().size() + resources.size() * 3 * sizeof(Resource*);
3827  }
3828 
3829  private:
3830  /** This is a list of resources having this skill. */
3831  resourcelist resources;
3832 };
3833 
3834 
3835 /** @brief this class is the default implementation of the abstract
3836  * Skill class.
3837  */
3838 class SkillDefault : public Skill
3839 {
3840  public:
3841  explicit SkillDefault(const string& str) : Skill(str) {initType(metadata);}
3842  virtual const MetaClass& getType() const {return *metadata;}
3844  virtual size_t getSize() const
3845  {return sizeof(SkillDefault) + Skill::extrasize();}
3846  static int initialize();
3847 };
3848 
3849 
3850 /** @brief This class represents a workcentre, a physical or logical
3851  * representation of capacity.
3852  */
3853 class Resource : public HasHierarchy<Resource>,
3854  public HasLevel, public Plannable, public HasDescription
3855 {
3856  friend class Load;
3857  friend class LoadPlan;
3858  friend class ResourceSkill;
3859 
3860  public:
3861  class PlanIterator;
3862 
3863  /** The default time window before the ask date where we look for
3864  * available capacity. */
3865  static const long defaultMaxEarly = 100*86400L;
3866 
3867  /** Constructor. */
3868  explicit Resource(const string& str) : HasHierarchy<Resource>(str),
3869  size_max_cal(NULL), size_max(0), loc(NULL), cost(0.0), hidden(false), maxearly(defaultMaxEarly),
3870  setupmatrix(NULL) { setMaximum(1); };
3871 
3872  /** Destructor. */
3873  virtual DECLARE_EXPORT ~Resource();
3874 
3875  /** Updates the size of a resource, when it is time-dependent. */
3876  DECLARE_EXPORT void setMaximumCalendar(CalendarDouble*);
3877 
3878  /** Updates the size of a resource. */
3879  DECLARE_EXPORT void setMaximum(double);
3880 
3881  /** Return a pointer to the maximum capacity profile. */
3882  CalendarDouble* getMaximumCalendar() const {return size_max_cal;}
3883 
3884  /** Return a pointer to the maximum capacity. */
3885  double getMaximum() const {return size_max;}
3886 
3887  /** Returns the cost of using 1 unit of this resource for 1 hour.<br>
3888  * The default value is 0.0.
3889  */
3890  double getCost() const {return cost;}
3891 
3892  /** Update the cost of using 1 unit of this resource for 1 hour. */
3893  void setCost(const double c)
3894  {
3895  if (c >= 0) cost = c;
3896  else throw DataException("Resource cost must be positive");
3897  }
3898 
3902 
3903  /** Returns a reference to the list of loadplans. */
3904  const loadplanlist& getLoadPlans() const {return loadplans;}
3905 
3906  /** Returns a reference to the list of loadplans. */
3907  loadplanlist& getLoadPlans() {return loadplans;}
3908 
3909  /** Returns a constant reference to the list of loads. It defines
3910  * which operations are using the resource.
3911  */
3912  const loadlist& getLoads() const {return loads;}
3913 
3914  /** Returns a constant reference to the list of skills. */
3915  const skilllist& getSkills() const {return skills;}
3916 
3917  /** Return the load that is associates a given operation with this
3918  * resource. Returns NULL is no such load exists. */
3919  Load* findLoad(const Operation* o, Date d) const
3920  {return loads.find(o,d);}
3921 
3922  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
3923  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
3924  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
3925  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
3926  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
3927 
3928  /** Initialize the class. */
3929  static int initialize();
3930 
3931  size_t extrasize() const
3932  {
3933  return getName().size() + HasDescription::extrasize()
3934  + setup.size() + skills.size() * 3 * sizeof(Skill*);
3935  }
3936 
3937  /** Returns the location of this resource. */
3938  Location* getLocation() const {return loc;}
3939 
3940  /** Updates the location of this resource. */
3941  void setLocation(Location* i) {loc = i;}
3942 
3943  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
3944 
3945  /** Deletes all operationplans loading this resource. The boolean parameter
3946  * controls whether we delete also locked operationplans or not.
3947  */
3948  DECLARE_EXPORT void deleteOperationPlans(bool = false);
3949 
3950  /** Recompute the problems of this resource. */
3951  virtual DECLARE_EXPORT void updateProblems();
3952 
3953  /** Scan the setups of this resource. */
3954  virtual DECLARE_EXPORT void updateSetups(const LoadPlan* = NULL);
3955 
3956  void setHidden(bool b) {if (hidden!=b) setChanged(); hidden = b;}
3957  bool getHidden() const {return hidden;}
3958 
3959  virtual const MetaClass& getType() const {return *metadata;}
3961 
3962  /** Returns the maximum inventory buildup allowed in case of capacity
3963  * shortages. */
3964  TimePeriod getMaxEarly() const {return maxearly;}
3965 
3966  /** Updates the maximum inventory buildup allowed in case of capacity
3967  * shortages. */
3968  void setMaxEarly(TimePeriod c)
3969  {
3970  if (c >= 0L) maxearly = c;
3971  else throw DataException("MaxEarly must be positive");
3972  }
3973 
3974  /** Return a pointer to the setup matrix. */
3975  SetupMatrix* getSetupMatrix() const {return setupmatrix;}
3976 
3977  /** Update the reference to the setup matrix. */
3978  void setSetupMatrix(SetupMatrix *s) {setupmatrix = s;}
3979 
3980  /** Return the current setup. */
3981  const string& getSetup() const {return setup;}
3982 
3983  /** Update the current setup. */
3984  void setSetup(const string s) {setup = s;}
3985 
3986  private:
3987  /** This calendar is used to updates to the resource size. */
3988  CalendarDouble* size_max_cal;
3989 
3990  /** The maximum resource size.<br>
3991  * If a calendar is specified, this field is ignored.
3992  */
3993  double size_max;
3994 
3995  /** Stores the collection of all loadplans of this resource. */
3996  loadplanlist loadplans;
3997 
3998  /** This is a list of all load models that are linking this resource with
3999  * operations. */
4000  loadlist loads;
4001 
4002  /** This is a list of skills this resource has. */
4003  skilllist skills;
4004 
4005  /** A pointer to the location of the resource. */
4006  Location* loc;
4007 
4008  /** The cost of using 1 unit of this resource for 1 hour. */
4009  double cost;
4010 
4011  /** Specifies whether this resource is hidden for serialization. */
4012  bool hidden;
4013 
4014  /** Maximum inventory buildup allowed in case of capacity shortages. */
4015  TimePeriod maxearly;
4016 
4017  /** Reference to the setup matrix. */
4018  SetupMatrix *setupmatrix;
4019 
4020  /** Current setup. */
4021  string setup;
4022 
4023  /** Python method that returns an iterator over the resource plan. */
4024  static PyObject* plan(PyObject*, PyObject*);
4025 };
4026 
4027 
4028 /** @brief This class provides an efficient way to iterate over
4029  * the plan of a resource aggregated in time buckets.
4030  */
4031 class Resource::PlanIterator : public PythonExtension<Resource::PlanIterator>
4032 {
4033  public:
4034  static int initialize();
4035 
4036  /** Constructor.
4037  * The first argument is the resource whose plan we're looking at.
4038  * The second argument is a Python iterator over a list of dates. These
4039  * dates define the buckets at which we aggregate the resource plan.
4040  */
4041  PlanIterator(Resource*, PyObject*);
4042 
4043  /** Destructor. */
4044  ~PlanIterator();
4045 
4046  private:
4047  /** Pointer to the resource we're investigating. */
4048  Resource* res;
4049 
4050  /** A Python object pointing to a list of start dates of buckets. */
4051  PyObject* bucketiterator;
4052 
4053  /** An iterator over all events in the resource timeline. */
4054  Resource::loadplanlist::iterator ldplaniter;
4055 
4056  /** Python function to iterate over the periods. */
4057  PyObject* iternext();
4058 
4059  double cur_setup;
4060  double cur_load;
4061  double cur_size;
4062  Date cur_date;
4063  Date prev_date;
4064  bool prev_value;
4065  Calendar::EventIterator unavailableIterator;
4066  bool hasUnavailability;
4067  double bucket_available;
4068  double bucket_load;
4069  double bucket_setup;
4070  double bucket_unavailable;
4071 
4072  void update(Date till);
4073 
4074  /** Python object pointing to the start date of the plan bucket. */
4075  PyObject* start_date;
4076 
4077  /** Python object pointing to the start date of the plan bucket. */
4078  PyObject* end_date;
4079 };
4080 
4081 
4082 /** @brief This class is the default implementation of the abstract
4083  * Resource class.
4084  */
4086 {
4087  public:
4088  explicit ResourceDefault(const string& str) : Resource(str) {initType(metadata);}
4089  virtual const MetaClass& getType() const {return *metadata;}
4091  virtual size_t getSize() const
4092  {return sizeof(ResourceDefault) + Resource::extrasize();}
4093  static int initialize();
4094 };
4095 
4096 
4097 /** @brief This class represents a resource that'll never have any
4098  * capacity shortage. */
4100 {
4101  public:
4102  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
4103  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
4104  virtual const MetaClass& getType() const {return *metadata;}
4105  explicit ResourceInfinite(const string& c) : Resource(c)
4106  {setDetectProblems(false); initType(metadata);}
4108  virtual size_t getSize() const
4109  {return sizeof(ResourceInfinite) + Resource::extrasize();}
4110  static int initialize();
4111 };
4112 
4113 
4114 /** @brief This class associates a resource with its skills. */
4115 class ResourceSkill : public Object, public Association<Resource,Skill,ResourceSkill>::Node
4116 {
4117  public:
4118  /** Default constructor. */
4119  explicit ResourceSkill() {initType(metadata);}
4120 
4121  /** Constructor. */
4122  explicit DECLARE_EXPORT ResourceSkill(Skill*, Resource*, int);
4123 
4124  /** Constructor. */
4126 
4127  /** Initialize the class. */
4128  static int initialize();
4129  static void writer(const MetaCategory*, XMLOutput*);
4130  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
4131  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
4132  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
4133  DECLARE_EXPORT PyObject* getattro(const Attribute&);
4134  DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
4135 
4136  /** Returns the resource. */
4137  Resource* getResource() const {return getPtrA();}
4138 
4139  /** Updates the resource. This method can only be called on an instance. */
4140  void setResource(Resource* r) {if (r) setPtrA(r,r->getSkills());}
4141 
4142  /** Returns the skill. */
4143  Skill* getSkill() const {return getPtrB();}
4144 
4145  virtual const MetaClass& getType() const {return *metadata;}
4147  virtual size_t getSize() const {return sizeof(ResourceSkill);}
4148 
4149  /** Updates the skill. This method can only be called on an instance. */
4150  void setSkill(Skill* s) {if (s) setPtrB(s,s->getResources());}
4151 
4152  private:
4153  /** Factory method. */
4154  static PyObject* create(PyTypeObject*, PyObject*, PyObject*);
4155 
4156  /** This method is called to check the validity of the object.<br>
4157  * An exception is thrown if the resourceskill is invalid.
4158  */
4159  DECLARE_EXPORT void validate(Action action);
4160 };
4161 
4162 
4163 /** @brief This class links a resource to a certain operation. */
4164 class Load
4165  : public Object, public Association<Operation,Resource,Load>::Node,
4166  public Solvable
4167 {
4168  friend class Resource;
4169  friend class Operation;
4170 
4171  public:
4172  /** Constructor. */
4173  explicit Load(Operation* o, Resource* r, double u)
4174  : hasAlts(false), altLoad(NULL), search(PRIORITY), skill(NULL)
4175  {
4176  setOperation(o);
4177  setResource(r);
4178  setQuantity(u);
4179  initType(metadata);
4180  try { validate(ADD); }
4181  catch (...)
4182  {
4183  if (getOperation()) getOperation()->loaddata.erase(this);
4184  if (getResource()) getResource()->loads.erase(this);
4185  resetReferenceCount();
4186  throw;
4187  }
4188  }
4189 
4190  /** Constructor. */
4191  explicit Load(Operation* o, Resource* r, double u, DateRange e)
4192  : hasAlts(false), altLoad(NULL), search(PRIORITY), skill(NULL)
4193  {
4194  setOperation(o);
4195  setResource(r);
4196  setQuantity(u);
4197  setEffective(e);
4198  initType(metadata);
4199  try { validate(ADD); }
4200  catch (...)
4201  {
4202  if (getOperation()) getOperation()->loaddata.erase(this);
4203  if (getResource()) getResource()->loads.erase(this);
4204  resetReferenceCount();
4205  throw;
4206  }
4207  }
4208 
4209  /** Destructor. */
4210  DECLARE_EXPORT ~Load();
4211 
4212  /** Returns the operation consuming the resource capacity. */
4213  Operation* getOperation() const {return getPtrA();}
4214 
4215  /** Updates the operation being loaded. This method can only be called
4216  * once for a load. */
4217  void setOperation(Operation* o) {if (o) setPtrA(o,o->getLoads());}
4218 
4219  /** Returns the capacity resource being consumed. */
4220  Resource* getResource() const {return getPtrB();}
4221 
4222  /** Updates the capacity being consumed. This method can only be called
4223  * once on a resource. */
4224  void setResource(Resource* r) {if (r) setPtrB(r,r->getLoads());}
4225 
4226  /** Returns how much capacity is consumed during the duration of the
4227  * operationplan. */
4228  double getQuantity() const {return qty;}
4229 
4230  /** Updates the quantity of the load.
4231  * @exception DataException When a negative number is passed.
4232  */
4233  void setQuantity(double f)
4234  {
4235  if (f < 0) throw DataException("Load quantity can't be negative");
4236  qty = f;
4237  }
4238 
4239  /** Returns true if there are alternates for this load. */
4240  bool hasAlternates() const {return hasAlts;}
4241 
4242  /** Returns the load of which this one is an alternate.<br>
4243  * NULL is return where there is none.
4244  */
4245  Load* getAlternate() const {return altLoad;}
4246 
4247  /** Define the load of which this one is an alternate. */
4248  DECLARE_EXPORT void setAlternate(Load *);
4249 
4250  /** Define the load of which this one is an alternate. */
4251  DECLARE_EXPORT void setAlternate(const string& n);
4252 
4253  /** Update the required resource setup. */
4254  DECLARE_EXPORT void setSetup(const string);
4255 
4256  /** Return the required resource setup. */
4257  const string& getSetup() const {return setup;}
4258 
4259  /** Update the required skill. */
4260  void setSkill(Skill* s) {skill = s;}
4261 
4262  /** Return the required skill. */
4263  Skill* getSkill() const {return skill;}
4264 
4265  /** This method holds the logic the compute the date of a loadplan. */
4266  virtual Date getLoadplanDate(const LoadPlan*) const;
4267 
4268  /** This method holds the logic the compute the quantity of a loadplan. */
4269  virtual double getLoadplanQuantity(const LoadPlan*) const;
4270 
4271  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
4272  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
4273  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
4274  DECLARE_EXPORT PyObject* getattro(const Attribute&);
4275  DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
4276  static int initialize();
4277  static void writer(const MetaCategory*, XMLOutput*);
4278 
4279  bool getHidden() const
4280  {
4281  return (getResource() && getResource()->getHidden())
4282  || (getOperation() && getOperation()->getHidden());
4283  }
4284  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
4285 
4286  virtual const MetaClass& getType() const {return *metadata;}
4288  virtual size_t getSize() const
4289  {return sizeof(Load) + getName().size() + getSetup().size();}
4290 
4291  /** Default constructor. */
4292  Load() : qty(1.0), hasAlts(false), altLoad(NULL),
4293  search(PRIORITY), skill(NULL) {initType(metadata);}
4294 
4295  /** Return the search mode. */
4296  SearchMode getSearch() const {return search;}
4297 
4298  /** Update the search mode. */
4299  void setSearch(const string a) {search = decodeSearchMode(a);}
4300 
4301  private:
4302  /** This method is called to check the validity of the object.<br>
4303  * An exception is thrown if the load is invalid.
4304  */
4305  DECLARE_EXPORT void validate(Action action);
4306 
4307  /** Stores how much capacity is consumed during the duration of an
4308  * operationplan. */
4309  double qty;
4310 
4311  /** Flag that is set to true when a load has alternates. */
4312  bool hasAlts;
4313 
4314  /** A load representing the main load of a set of alternates. */
4315  Load* altLoad;
4316 
4317  /** Required setup. */
4318  string setup;
4319 
4320  /** Mode to select the preferred alternates. */
4321  SearchMode search;
4322 
4323  /** Required skill. */
4324  Skill* skill;
4325 
4326  /** Factory method. */
4327  static PyObject* create(PyTypeObject*, PyObject*, PyObject*);
4328 };
4329 
4330 
4331 
4332 /** @brief This is the (logical) top class of the complete model.
4333  *
4334  * This is a singleton class: only a single instance can be created.
4335  * The data model has other limitations that make it not obvious to support
4336  * building multiple models/plans in memory of the same application: e.g.
4337  * the operations, resources, problems, operationplans... etc are all
4338  * implemented in static, global lists. An entity can't be simply linked with
4339  * a particular plan if multiple ones would exist.
4340  */
4341 class Plan : public Plannable, public Object
4342 {
4343  private:
4344  /** Current Date of this plan. */
4345  Date cur_Date;
4346 
4347  /** A name for this plan. */
4348  string name;
4349 
4350  /** A getDescription of this plan. */
4351  string descr;
4352 
4353  /** Pointer to the singleton plan object. */
4354  static DECLARE_EXPORT Plan* thePlan;
4355 
4356  /** The only constructor of this class is made private. An object of this
4357  * class is created by the instance() member function.
4358  */
4359  Plan() : cur_Date(Date::now()) {initType(metadata);}
4360 
4361  public:
4362  /** Return a pointer to the singleton plan object.
4363  * The singleton object is created during the initialization of the
4364  * library.
4365  */
4366  static Plan& instance() {return *thePlan;}
4367 
4368  /** Destructor.
4369  * @warning In multi threaded applications, the destructor is never called
4370  * and the plan object leaks when we exit the application.
4371  * In single-threaded applications this function is called properly, when
4372  * the static plan variable is deleted.
4373  */
4374  DECLARE_EXPORT ~Plan();
4375 
4376  /** Returns the plan name. */
4377  const string& getName() const {return name;}
4378 
4379  /** Updates the plan name. */
4380  void setName(const string& s) {name = s;}
4381 
4382  /** Returns the current Date of the plan. */
4383  const Date & getCurrent() const {return cur_Date;}
4384 
4385  /** Updates the current date of the plan. This method can be relatively
4386  * heavy in a plan where operationplans already exist, since the
4387  * detection for BeforeCurrent problems needs to be rerun.
4388  */
4389  DECLARE_EXPORT void setCurrent(Date);
4390 
4391  /** Returns the description of the plan. */
4392  const string& getDescription() const {return descr;}
4393 
4394  /** Updates the description of the plan. */
4395  void setDescription(const string& str) {descr = str;}
4396 
4397  /** This method writes out the model information. Depending on a flag in
4398  * the XMLOutput object a complete model is written, or only the
4399  * dynamic plan information.
4400  */
4401  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
4402  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
4403  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
4404  DECLARE_EXPORT PyObject* getattro(const Attribute&);
4405  DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
4406 
4407  /** Initialize the class. */
4408  static int initialize();
4409 
4410  virtual void updateProblems() {};
4411 
4412  /** This method basically solves the whole planning problem. */
4413  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
4414 
4415  const MetaClass& getType() const {return *metadata;}
4417  virtual size_t getSize() const
4418  {return sizeof(Plan) + name.size() + descr.size();}
4419 };
4420 
4421 
4422 /** @brief Represents the (independent) demand in the system. It can represent a
4423  * customer order or a forecast.
4424  *
4425  * This is an abstract class.
4426  */
4427 class Demand
4428  : public HasHierarchy<Demand>, public Plannable, public HasDescription
4429 {
4430  public:
4431  typedef slist<OperationPlan*> OperationPlan_list;
4432 
4433  /** Constructor. */
4434  explicit Demand(const string& str) : HasHierarchy<Demand>(str),
4435  it(NULL), oper(NULL), cust(NULL), qty(0.0), prio(0),
4436  maxLateness(TimePeriod::MAX), minShipment(1), hidden(false) {}
4437 
4438  /** Destructor.
4439  * Deleting the demand will also delete all delivery operation
4440  * plans (including locked ones) and reset the motive on any
4441  * operationplans. */
4442  virtual DECLARE_EXPORT ~Demand();
4443 
4444  /** Returns the quantity of the demand. */
4445  double getQuantity() const {return qty;}
4446 
4447  /** Updates the quantity of the demand. The quantity must be be greater
4448  * than or equal to 0. */
4449  virtual DECLARE_EXPORT void setQuantity(double);
4450 
4451  /** Returns the priority of the demand.<br>
4452  * Lower numbers indicate a higher priority level.
4453  */
4454  int getPriority() const {return prio;}
4455 
4456  /** Updates the due date of the demand.<br>
4457  * Lower numbers indicate a higher priority level.
4458  */
4459  virtual void setPriority(int i) {prio=i; setChanged();}
4460 
4461  /** Returns the item/product being requested. */
4462  Item* getItem() const {return it;}
4463 
4464  /** Updates the item/product being requested. */
4465  virtual void setItem(Item *i) {it=i; setChanged();}
4466 
4467  /** This fields points to an operation that is to be used to plan the
4468  * demand. By default, the field is left to NULL and the demand will then
4469  * be planned using the delivery operation of its item.
4470  * @see Item::getDelivery()
4471  */
4472  Operation* getOperation() const {return oper;}
4473 
4474  /** This function returns the operation that is to be used to satisfy this
4475  * demand. In sequence of priority this goes as follows:
4476  * 1) If the "operation" field on the demand is set, use it.
4477  * 2) Otherwise, use the "delivery" field of the requested item.
4478  * 3) Else, return NULL. This demand can't be satisfied!
4479  */
4480  DECLARE_EXPORT Operation* getDeliveryOperation() const;
4481 
4482  /** Returns the cluster which this demand belongs to. */
4483  int getCluster() const
4484  {
4485  Operation* o = getDeliveryOperation();
4486  return o ? o->getCluster() : 0;
4487  }
4488 
4489  /** Updates the operation being used to plan the demand. */
4490  virtual void setOperation(Operation* o) {oper=o; setChanged();}
4491 
4492  /** Returns the delivery operationplan list. */
4493  DECLARE_EXPORT const OperationPlan_list& getDelivery() const;
4494 
4495  /** Returns the latest delivery operationplan. */
4496  DECLARE_EXPORT OperationPlan* getLatestDelivery() const;
4497 
4498  /** Returns the earliest delivery operationplan. */
4499  DECLARE_EXPORT OperationPlan* getEarliestDelivery() const;
4500 
4501  /** Adds a delivery operationplan for this demand. */
4502  DECLARE_EXPORT void addDelivery(OperationPlan *o);
4503 
4504  /** Removes a delivery operationplan for this demand. */
4505  DECLARE_EXPORT void removeDelivery(OperationPlan *o);
4506 
4507  /** Deletes all delivery operationplans of this demand.<br>
4508  * The (optional) boolean parameter controls whether we delete also locked
4509  * operationplans or not.<br>
4510  * The second (optional) argument is a command list that can be used to
4511  * remove the operationplans in an undo-able way.
4512  */
4513  DECLARE_EXPORT void deleteOperationPlans
4514  (bool deleteLockedOpplans = false, CommandManager* = NULL);
4515 
4516  /** Returns the due date of the demand. */
4517  const Date& getDue() const {return dueDate;}
4518 
4519  /** Updates the due date of the demand. */
4520  virtual void setDue(Date d) {dueDate = d; setChanged();}
4521 
4522  /** Returns the customer. */
4523  Customer* getCustomer() const {return cust;}
4524 
4525  /** Updates the customer. */
4526  virtual void setCustomer(Customer* c) {cust = c; setChanged();}
4527 
4528  /** Return a reference to the constraint list. */
4529  const Problem::List& getConstraints() const {return constraints;}
4530 
4531  /** Return a reference to the constraint list. */
4532  Problem::List& getConstraints() {return constraints;}
4533 
4534  /** Returns the total amount that has been planned. */
4535  DECLARE_EXPORT double getPlannedQuantity() const;
4536 
4537  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
4538  virtual DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
4539  virtual DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
4540  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
4541  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
4542  static int initialize();
4543 
4544  size_t extrasize() const
4545  {
4546  return getName().size() + HasDescription::extrasize()
4547  + sizeof(void*) * 2 * deli.size();
4548  }
4549 
4550  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
4551 
4552  /** Return the maximum delay allowed in satisfying this demand.<br>
4553  * The default value is infinite.
4554  */
4555  TimePeriod getMaxLateness() const {return maxLateness;}
4556 
4557  /** Updates the maximum allowed lateness for this demand.<br>
4558  * The default value is infinite.<br>
4559  * The argument must be a positive time period.
4560  */
4561  virtual void setMaxLateness(TimePeriod m)
4562  {
4563  if (m < 0L)
4564  throw DataException("The maximum demand lateness must be positive");
4565  maxLateness = m;
4566  }
4567 
4568  /** Return the minimum shipment quantity allowed in satisfying this
4569  * demand.<br>
4570  * The default value is 1.
4571  */
4572  double getMinShipment() const {return minShipment;}
4573 
4574  /** Updates the maximum allowed lateness for this demand.<br>
4575  * The default value is infinite.<br>
4576  * The argument must be a positive time period.
4577  */
4578  virtual void setMinShipment(double m)
4579  {
4580  if (m < 0.0)
4581  throw DataException("The minumum demand shipment quantity must be positive");
4582  minShipment = m;
4583  }
4584 
4585  /** Recompute the problems. */
4586  virtual DECLARE_EXPORT void updateProblems();
4587 
4588  /** Specifies whether of not this demand is to be hidden from
4589  * serialization. The default value is false. */
4590  void setHidden(bool b) {hidden = b;}
4591 
4592  /** Returns true if this demand is to be hidden from serialization. */
4593  bool getHidden() const {return hidden;}
4594 
4595  virtual const MetaClass& getType() const {return *metadata;}
4597 
4598  private:
4599  /** Requested item. */
4600  Item *it;
4601 
4602  /** Delivery Operation. Can be left NULL, in which case the delivery
4603  * operation can be specified on the requested item. */
4604  Operation *oper;
4605 
4606  /** Customer creating this demand. */
4607  Customer *cust;
4608 
4609  /** Requested quantity. Only positive numbers are allowed. */
4610  double qty;
4611 
4612  /** Priority. Lower numbers indicate a higher priority level.*/
4613  int prio;
4614 
4615  /** Due date. */
4616  Date dueDate;
4617 
4618  /** Maximum lateness allowed when planning this demand.<br>
4619  * The default value is TimePeriod::MAX.
4620  */
4621  TimePeriod maxLateness;
4622 
4623  /** Minimum size for a delivery operation plan satisfying this demand. */
4624  double minShipment;
4625 
4626  /** Hide this demand or not. */
4627  bool hidden;
4628 
4629  /** A list of operation plans to deliver this demand. */
4630  OperationPlan_list deli;
4631 
4632  /** A list of constraints preventing this demand from being planned in
4633  * full and on time. */
4634  Problem::List constraints;
4635 };
4636 
4637 
4638 /** @brief This class is the default implementation of the abstract
4639  * Demand class. */
4640 class DemandDefault : public Demand
4641 {
4642  public:
4643  explicit DemandDefault(const string& str) : Demand(str) {initType(metadata);}
4644  virtual const MetaClass& getType() const {return *metadata;}
4646  virtual size_t getSize() const
4647  {return sizeof(DemandDefault) + Demand::extrasize();}
4648  static int initialize();
4649 };
4650 
4651 
4652 /** @brief This class represents the resource capacity of an operationplan.
4653  *
4654  * For both the start and the end date of the operationplan, a loadplan
4655  * object is created. These are then inserted in the timeline structure
4656  * associated with a resource.
4657  */
4658 class LoadPlan : public TimeLine<LoadPlan>::EventChangeOnhand, public PythonExtensionBase
4659 {
4661  public:
4662  /** Public constructor.<br>
4663  * This constructor constructs the starting loadplan and will
4664  * also call a private constructor to creates the ending loadplan.
4665  * In other words, a single call to the constructor will create
4666  * two loadplan objects.
4667  */
4668  explicit DECLARE_EXPORT LoadPlan(OperationPlan*, const Load*);
4669 
4670  /** Return the operationplan owning this loadplan. */
4671  OperationPlan* getOperationPlan() const {return oper;}
4672 
4673  /** Return the load of which this is a plan instance. */
4674  const Load* getLoad() const {return ld;}
4675 
4676  /** Update the resource.<br>
4677  * The optional second argument specifies whether or not we need to verify
4678  * if the assigned resource is valid. A valid resource must a) be a
4679  * subresource of the resource specified on the load, and b) must also
4680  * have the skill specified on the resource.
4681  */
4682  DECLARE_EXPORT void setResource(Resource*, bool = false);
4683 
4684  /** Return the resource. */
4685  Resource* getResource() const {return res;}
4686 
4687  /** Update the load of an already existing flowplan.<br>
4688  * The new load must belong to the same operation.
4689  */
4690  DECLARE_EXPORT void setLoad(const Load*);
4691 
4692  /** Return true when this loadplan marks the start of an operationplan. */
4693  bool isStart() const {return start_or_end == START;}
4694 
4695  /** Destructor. */
4696  DECLARE_EXPORT virtual ~LoadPlan();
4697 
4698  /** This function needs to be called whenever the loadplan date or
4699  * quantity are changed.
4700  */
4701  DECLARE_EXPORT void update();
4702 
4703  /** Return a pointer to the timeline data structure owning this loadplan. */
4704  TimeLine<LoadPlan>* getTimeLine() const
4705  {return &(res->loadplans);}
4706 
4707  /** Returns the current setup of the resource.<br>
4708  * When the argument is true (= default) the current setup is returned.<br>
4709  * When the argument is false the setup just before the loadplan is returned.
4710  */
4711  DECLARE_EXPORT const string& getSetup(bool = true) const;
4712 
4713  /** Returns true when the loadplan is hidden.<br>
4714  * This is determined by looking at whether the load is hidden or not.
4715  */
4716  bool getHidden() const {return ld->getHidden();}
4717 
4718  /** Each operationplan has 2 loadplans per load: one at the start,
4719  * when the capacity consumption starts, and one at the end, when the
4720  * capacity consumption ends.<br>
4721  * This method returns the "companion" loadplan. It is not very
4722  * scalable: the performance is linear with the number of loadplans
4723  * on the resource.
4724  */
4725  DECLARE_EXPORT LoadPlan* getOtherLoadPlan() const;
4726 
4727  static int initialize();
4729  PyObject* getattro(const Attribute&);
4730  DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
4731 
4732  private:
4733  /** Private constructor. It is called from the public constructor.<br>
4734  * The public constructor constructs the starting loadplan, while this
4735  * constructor creates the ending loadplan.
4736  */
4738 
4739  /** This type is used to differentiate loadplans aligned with the START date
4740  * or the END date of operationplan. */
4741  enum type {START, END};
4742 
4743  /** Is this loadplan a starting one or an ending one. */
4744  type start_or_end;
4745 
4746  /** A pointer to the load model. */
4747  const Load *ld;
4748 
4749  /** A pointer to the selected resource.<br>
4750  * In case we use skills, the resource of the loadplan can be different
4751  * than the resource on the load.
4752  */
4753  Resource *res;
4754 
4755  /** A pointer to the operationplan owning this loadplan. */
4756  OperationPlan *oper;
4757 
4758  /** Points to the next loadplan owned by the same operationplan. */
4759  LoadPlan *nextLoadPlan;
4760 };
4761 
4762 
4763 inline Date Load::getLoadplanDate(const LoadPlan* lp) const
4764 {
4765  const DateRange & dr = lp->getOperationPlan()->getDates();
4766  if (lp->isStart())
4767  return dr.getStart() > getEffective().getStart() ?
4768  dr.getStart() :
4769  getEffective().getStart();
4770  else
4771  return dr.getEnd() < getEffective().getEnd() ?
4772  dr.getEnd() :
4773  getEffective().getEnd();
4774 }
4775 
4776 
4777 inline double Load::getLoadplanQuantity(const LoadPlan* lp) const
4778 {
4779  if (!lp->getOperationPlan()->getDates().overlap(getEffective())
4780  && (lp->getOperationPlan()->getDates().getDuration()
4781  || !getEffective().within(lp->getOperationPlan()->getDates().getStart())))
4782  // Load is not effective during this time.
4783  // The extra check is required to make sure that zero duration operationplans
4784  // operationplans don't get resized to 0
4785  return 0.0;
4786  return lp->isStart() ? getQuantity() : -getQuantity();
4787 }
4788 
4789 
4790 
4791 /** @brief A problem of this class is created when an operationplan is being
4792  * planned in the past, i.e. it starts before the "current" date of
4793  * the plan.
4794  */
4796 {
4797  public:
4798  string getDescription() const
4799  {
4800  ostringstream ch;
4801  ch << "Operation '"
4802  << (oper ? oper : static_cast<OperationPlan*>(getOwner())->getOperation())
4803  << "' planned in the past";
4804  return ch.str();
4805  }
4806  bool isFeasible() const {return false;}
4807  double getWeight() const
4808  {return oper ? state.quantity : dynamic_cast<OperationPlan*>(getOwner())->getQuantity();}
4809  explicit ProblemBeforeCurrent(OperationPlan* o, bool add = true) : Problem(o), oper(NULL)
4810  {if (add) addProblem();}
4811  explicit ProblemBeforeCurrent(Operation* o, Date st, Date nd, double q)
4812  : oper(o), state(st, nd, q) {}
4813  ~ProblemBeforeCurrent() {removeProblem();}
4814  string getEntity() const {return "operation";}
4815  Object* getOwner() const
4816  {return oper ? static_cast<Object*>(oper) : dynamic_cast<OperationPlan*>(owner);}
4817  const DateRange getDates() const
4818  {
4819  if (oper) return DateRange(state.start, state.end);
4820  OperationPlan *o = dynamic_cast<OperationPlan*>(getOwner());
4821  if (o->getDates().getEnd() > Plan::instance().getCurrent())
4822  return DateRange(o->getDates().getStart(),
4824  else
4825  return DateRange(o->getDates().getStart(),
4826  o->getDates().getEnd());
4827  }
4828  size_t getSize() const {return sizeof(ProblemBeforeCurrent);}
4829 
4830  /** Return a reference to the metadata structure. */
4831  const MetaClass& getType() const {return *metadata;}
4832 
4833  /** Storing metadata on this class. */
4835 
4836  private:
4837  Operation* oper;
4838  OperationPlanState state;
4839 };
4840 
4841 
4842 /** @brief A problem of this class is created when an operationplan is being
4843  * planned before its fence date, i.e. it starts 1) before the "current"
4844  * date of the plan plus the release fence of the operation and 2) after the
4845  * current date of the plan.
4846  */
4848 {
4849  public:
4850  string getDescription() const
4851  {
4852  ostringstream ch;
4853  ch << "Operation '"
4854  << (oper ? oper : static_cast<OperationPlan*>(getOwner())->getOperation())
4855  << "' planned before fence";
4856  return ch.str();
4857  }
4858  bool isFeasible() const {return true;}
4859  double getWeight() const
4860  {return oper ? state.quantity : static_cast<OperationPlan*>(getOwner())->getQuantity();}
4861  explicit ProblemBeforeFence(OperationPlan* o, bool add = true)
4862  : Problem(o), oper(NULL)
4863  {if (add) addProblem();}
4864  explicit ProblemBeforeFence(Operation* o, Date st, Date nd, double q)
4865  : oper(o), state(st, nd, q) {}
4866  ~ProblemBeforeFence() {removeProblem();}
4867  string getEntity() const {return "operation";}
4868  Object* getOwner() const
4869  {return oper ? static_cast<Object*>(oper) : dynamic_cast<OperationPlan*>(owner);}
4870  const DateRange getDates() const
4871  {
4872  if (oper) return DateRange(state.start, state.end);
4873  OperationPlan *o = dynamic_cast<OperationPlan*>(owner);
4874  if (o->getDates().getEnd() > Plan::instance().getCurrent()
4875  + o->getOperation()->getFence())
4876  return DateRange(o->getDates().getStart(),
4878  else
4879  return DateRange(o->getDates().getStart(),
4880  o->getDates().getEnd());
4881  }
4882  size_t getSize() const {return sizeof(ProblemBeforeFence);}
4883 
4884  /** Return a reference to the metadata structure. */
4885  const MetaClass& getType() const {return *metadata;}
4886 
4887  /** Storing metadata on this class. */
4889 
4890  private:
4891  Operation* oper;
4892  OperationPlanState state;
4893 };
4894 
4895 
4896 /** @brief A problem of this class is created when the sequence of two
4897  * operationplans in a routing isn't respected.
4898  */
4900 {
4901  public:
4902  string getDescription() const
4903  {
4904  OperationPlan *o = static_cast<OperationPlan*>(getOwner());
4905  if (!o->nextsubopplan)
4906  return string("Bogus precedence problem on '")
4907  + o->getOperation()->getName() + "'";
4908  else
4909  return string("Operation '") + o->getOperation()->getName()
4910  + "' starts before operation '"
4911  + o->nextsubopplan->getOperation()->getName() +"' ends";
4912  }
4913  bool isFeasible() const {return false;}
4914  /** The weight of the problem is equal to the duration in days. */
4915  double getWeight() const
4916  {
4917  return static_cast<double>(getDates().getDuration()) / 86400;
4918  }
4919  explicit ProblemPrecedence(OperationPlan* o, bool add = true) : Problem(o)
4920  {if (add) addProblem();}
4921  ~ProblemPrecedence() {removeProblem();}
4922  string getEntity() const {return "operation";}
4923  Object* getOwner() const {return dynamic_cast<OperationPlan*>(owner);}
4924  const DateRange getDates() const
4925  {
4926  OperationPlan *o = static_cast<OperationPlan*>(getOwner());
4927  return DateRange(o->nextsubopplan->getDates().getStart(),
4928  o->getDates().getEnd());
4929  }
4930 
4931  /** Return a reference to the metadata structure. */
4932  const MetaClass& getType() const {return *metadata;}
4933 
4934  /** Storing metadata on this class. */
4936  size_t getSize() const {return sizeof(ProblemPrecedence);}
4937 };
4938 
4939 
4940 /** @brief A Problem of this class is created in the model when a new demand is
4941  * brought in the system, but it hasn't been planned yet.
4942  *
4943  * As a special case, a demand with a requested quantity of 0.0 doesn't create
4944  * this type of problem.
4945  */
4947 {
4948  public:
4949  string getDescription() const
4950  {return string("Demand '") + getDemand()->getName() + "' is not planned";}
4951  bool isFeasible() const {return false;}
4952  double getWeight() const {return getDemand()->getQuantity();}
4953  explicit ProblemDemandNotPlanned(Demand* d, bool add = true) : Problem(d)
4954  {if (add) addProblem();}
4955  ~ProblemDemandNotPlanned() {removeProblem();}
4956  string getEntity() const {return "demand";}
4957  const DateRange getDates() const
4958  {return DateRange(getDemand()->getDue(),getDemand()->getDue());}
4959  Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
4960  Demand* getDemand() const {return dynamic_cast<Demand*>(owner);}
4961  size_t getSize() const {return sizeof(ProblemDemandNotPlanned);}
4962 
4963  /** Return a reference to the metadata structure. */
4964  const MetaClass& getType() const {return *metadata;}
4965 
4966  /** Storing metadata on this class. */
4968 };
4969 
4970 
4971 /** @brief A problem of this class is created when a demand is satisfied later
4972  * than the accepted tolerance after its due date.
4973  */
4974 class ProblemLate : public Problem
4975 {
4976  public:
4977  DECLARE_EXPORT string getDescription() const;
4978  bool isFeasible() const {return true;}
4979 
4980  /** The weight is equal to the delay, expressed in days.<br>
4981  * The quantity being delayed is not included.
4982  */
4983  double getWeight() const
4984  {
4985  assert(getDemand() && !getDemand()->getDelivery().empty());
4986  return static_cast<double>(DateRange(
4987  getDemand()->getDue(),
4988  getDemand()->getLatestDelivery()->getDates().getEnd()
4989  ).getDuration()) / 86400;
4990  }
4991 
4992  /** Constructor. */
4993  explicit ProblemLate(Demand* d, bool add = true) : Problem(d)
4994  {if (add) addProblem();}
4995 
4996  /** Destructor. */
4997  ~ProblemLate() {removeProblem();}
4998 
4999  const DateRange getDates() const
5000  {
5001  assert(getDemand() && !getDemand()->getDelivery().empty());
5002  return DateRange(getDemand()->getDue(),
5003  getDemand()->getLatestDelivery()->getDates().getEnd());
5004  }
5005  Demand* getDemand() const {return dynamic_cast<Demand*>(getOwner());}
5006  size_t getSize() const {return sizeof(ProblemLate);}
5007  string getEntity() const {return "demand";}
5008  Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
5009 
5010  /** Return a reference to the metadata structure. */
5011  const MetaClass& getType() const {return *metadata;}
5012 
5013  /** Storing metadata on this class. */
5015 };
5016 
5017 
5018 /** @brief A problem of this class is created when a demand is planned earlier
5019  * than the accepted tolerance before its due date.
5020  */
5021 class ProblemEarly : public Problem
5022 {
5023  public:
5024  DECLARE_EXPORT string getDescription() const;
5025  bool isFeasible() const {return true;}
5026  double getWeight() const
5027  {
5028  assert(getDemand() && !getDemand()->getDelivery().empty());
5029  return static_cast<double>(DateRange(
5030  getDemand()->getDue(),
5031  getDemand()->getEarliestDelivery()->getDates().getEnd()
5032  ).getDuration()) / 86400;
5033  }
5034  explicit ProblemEarly(Demand* d, bool add = true) : Problem(d)
5035  {if (add) addProblem();}
5036  ~ProblemEarly() {removeProblem();}
5037  string getEntity() const {return "demand";}
5038  Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
5039  const DateRange getDates() const
5040  {
5041  assert(getDemand() && !getDemand()->getDelivery().empty());
5042  return DateRange(getDemand()->getDue(),
5043  getDemand()->getEarliestDelivery()->getDates().getEnd());
5044  }
5045  Demand* getDemand() const {return dynamic_cast<Demand*>(getOwner());}
5046  size_t getSize() const {return sizeof(ProblemEarly);}
5047 
5048  /** Return a reference to the metadata structure. */
5049  const MetaClass& getType() const {return *metadata;}
5050 
5051  /** Storing metadata on this class. */
5053 };
5054 
5055 
5056 /** @brief A Problem of this class is created in the model when a data exception
5057  * prevents planning of certain objects
5058  */
5060 {
5061  public:
5062  string getDescription() const {return description;}
5063  bool isFeasible() const {return false;}
5064  double getWeight() const {return qty;}
5065  explicit ProblemInvalidData(HasProblems* o, string d, string e,
5066  Date st, Date nd, double q, bool add = true)
5067  : Problem(o), description(d), entity(e), dates(st,nd), qty(q)
5068  {if (add) addProblem();}
5069  ~ProblemInvalidData() {removeProblem();}
5070  string getEntity() const {return entity;}
5071  const DateRange getDates() const {return dates;}
5072  Object* getOwner() const
5073  {
5074  if (entity == "demand") return dynamic_cast<Demand*>(owner);
5075  if (entity == "buffer") return dynamic_cast<Buffer*>(owner);
5076  if (entity == "resource") return dynamic_cast<Resource*>(owner);
5077  if (entity == "operation") return dynamic_cast<Operation*>(owner);
5078  throw LogicException("Unknown problem entity type");
5079  }
5080  size_t getSize() const
5081  {return sizeof(ProblemInvalidData) + description.size() + entity.size();}
5082 
5083  /** Return a reference to the metadata structure. */
5084  const MetaClass& getType() const {return *metadata;}
5085 
5086  /** Storing metadata on this class. */
5088 
5089  private:
5090  /** Description of the data issue. */
5091  string description;
5092  string entity;
5093  DateRange dates;
5094  double qty;
5095 };
5096 
5097 
5098 /** @brief A problem of this class is created when a demand is planned for less than
5099  * the requested quantity.
5100  */
5101 class ProblemShort : public Problem
5102 {
5103  public:
5104  string getDescription() const
5105  {
5106  ostringstream ch;
5107  ch << "Demand '" << getDemand()->getName() << "' planned "
5108  << (getDemand()->getQuantity() - getDemand()->getPlannedQuantity())
5109  << " units short";
5110  return ch.str();
5111  }
5112  bool isFeasible() const {return true;}
5113  double getWeight() const
5114  {return getDemand()->getQuantity() - getDemand()->getPlannedQuantity();}
5115  explicit ProblemShort(Demand* d, bool add = true) : Problem(d)
5116  {if (add) addProblem();}
5117  ~ProblemShort() {removeProblem();}
5118  string getEntity() const {return "demand";}
5119  const DateRange getDates() const
5120  {return DateRange(getDemand()->getDue(), getDemand()->getDue());}
5121  Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
5122  Demand* getDemand() const {return dynamic_cast<Demand*>(owner);}
5123  size_t getSize() const {return sizeof(ProblemShort);}
5124 
5125  /** Return a reference to the metadata structure. */
5126  const MetaClass& getType() const {return *metadata;}
5127 
5128  /** Storing metadata on this class. */
5130 };
5131 
5132 
5133 /** @brief A problem of this class is created when a demand is planned for more
5134  * than the requested quantity.
5135  */
5136 class ProblemExcess : public Problem
5137 {
5138  public:
5139  string getDescription() const
5140  {
5141  ostringstream ch;
5142  ch << "Demand '" << getDemand()->getName() << "' planned "
5143  << (getDemand()->getPlannedQuantity() - getDemand()->getQuantity())
5144  << " units excess";
5145  return ch.str();
5146  }
5147  bool isFeasible() const {return true;}
5148  double getWeight() const
5149  {return getDemand()->getPlannedQuantity() - getDemand()->getQuantity();}
5150  explicit ProblemExcess(Demand* d, bool add = true) : Problem(d)
5151  {if (add) addProblem();}
5152  string getEntity() const {return "demand";}
5153  Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
5154  ~ProblemExcess() {removeProblem();}
5155  const DateRange getDates() const
5156  {return DateRange(getDemand()->getDue(), getDemand()->getDue());}
5157  Demand* getDemand() const {return dynamic_cast<Demand*>(getOwner());}
5158  size_t getSize() const {return sizeof(ProblemExcess);}
5159 
5160  /** Return a reference to the metadata structure. */
5161  const MetaClass& getType() const {return *metadata;}
5162 
5163  /** Storing metadata on this class. */
5165 };
5166 
5167 
5168 /** @brief A problem of this class is created when a resource is being
5169  * overloaded during a certain period of time.
5170  */
5172 {
5173  public:
5174  DECLARE_EXPORT string getDescription() const;
5175  bool isFeasible() const {return false;}
5176  double getWeight() const {return qty;}
5177  ProblemCapacityOverload(Resource* r, Date st, Date nd, double q, bool add = true)
5178  : Problem(r), qty(q), dr(st,nd) {if (add) addProblem();}
5179  ~ProblemCapacityOverload() {removeProblem();}
5180  string getEntity() const {return "capacity";}
5181  Object* getOwner() const {return dynamic_cast<Resource*>(owner);}
5182  const DateRange getDates() const {return dr;}
5183  Resource* getResource() const {return dynamic_cast<Resource*>(getOwner());}
5184  size_t getSize() const {return sizeof(ProblemCapacityOverload);}
5185 
5186  /** Return a reference to the metadata structure. */
5187  const MetaClass& getType() const {return *metadata;}
5188 
5189  /** Storing metadata on this class. */
5191 
5192  private:
5193  /** Overload quantity. */
5194  double qty;
5195 
5196  /** The daterange of the problem. */
5197  DateRange dr;
5198 };
5199 
5200 
5201 /** @brief A problem of this class is created when a resource is loaded below
5202  * its minimum during a certain period of time.
5203  */
5205 {
5206  public:
5207  DECLARE_EXPORT string getDescription() const;
5208  bool isFeasible() const {return true;}
5209  double getWeight() const {return qty;}
5210  ProblemCapacityUnderload(Resource* r, DateRange d, double q, bool add = true)
5211  : Problem(r), qty(q), dr(d) {if (add) addProblem();}
5212  ~ProblemCapacityUnderload() {removeProblem();}
5213  string getEntity() const {return "capacity";}
5214  Object* getOwner() const {return dynamic_cast<Resource*>(owner);}
5215  const DateRange getDates() const {return dr;}
5216  Resource* getResource() const {return dynamic_cast<Resource*>(getOwner());}
5217  size_t getSize() const {return sizeof(ProblemCapacityUnderload);}
5218 
5219  /** Return a reference to the metadata structure. */
5220  const MetaClass& getType() const {return *metadata;}
5221 
5222  /** Storing metadata on this class. */
5224 
5225  private:
5226  /** Underload quantity. */
5227  double qty;
5228 
5229  /** The daterange of the problem. */
5230  DateRange dr;
5231 };
5232 
5233 
5234 /** @brief A problem of this class is created when a buffer is having a
5235  * material shortage during a certain period of time.
5236  */
5238 {
5239  public:
5240  DECLARE_EXPORT string getDescription() const;
5241  bool isFeasible() const {return false;}
5242  double getWeight() const {return qty;}
5243  ProblemMaterialShortage(Buffer* b, Date st, Date nd, double q, bool add = true)
5244  : Problem(b), qty(q), dr(st,nd) {if (add) addProblem();}
5245  string getEntity() const {return "material";}
5246  Object* getOwner() const {return dynamic_cast<Buffer*>(owner);}
5247  ~ProblemMaterialShortage() {removeProblem();}
5248  const DateRange getDates() const {return dr;}
5249  Buffer* getBuffer() const {return dynamic_cast<Buffer*>(getOwner());}
5250  size_t getSize() const {return sizeof(ProblemMaterialShortage);}
5251 
5252  /** Return a reference to the metadata structure. */
5253  const MetaClass& getType() const {return *metadata;}
5254 
5255  /** Storing metadata on this class. */
5257 
5258  private:
5259  /** Shortage quantity. */
5260  double qty;
5261 
5262  /** The daterange of the problem. */
5263  DateRange dr;
5264 };
5265 
5266 
5267 /** @brief A problem of this class is created when a buffer is carrying too
5268  * much material during a certain period of time.
5269  */
5271 {
5272  public:
5273  DECLARE_EXPORT string getDescription() const;
5274  bool isFeasible() const {return true;}
5275  double getWeight() const {return qty;}
5276  ProblemMaterialExcess(Buffer* b, Date st, Date nd, double q, bool add = true)
5277  : Problem(b), qty(q), dr(st,nd) {if (add) addProblem();}
5278  string getEntity() const {return "material";}
5279  ~ProblemMaterialExcess() {removeProblem();}
5280  const DateRange getDates() const {return dr;}
5281  Object* getOwner() const {return dynamic_cast<Buffer*>(owner);}
5282  Buffer* getBuffer() const {return dynamic_cast<Buffer*>(owner);}
5283  size_t getSize() const {return sizeof(ProblemMaterialExcess);}
5284 
5285  /** Return a reference to the metadata structure. */
5286  const MetaClass& getType() const {return *metadata;}
5287 
5288  /** Storing metadata on this class. */
5290 
5291  private:
5292  /** Excess quantity. */
5293  double qty;
5294 
5295  /** The daterange of the problem. */
5296  DateRange dr;
5297 };
5298 
5299 
5300 /** @brief This command is used to create an operationplan.
5301  *
5302  * The operationplan will have its loadplans and flowplans created when the
5303  * command is created. It is assigned an id and added to the list of all
5304  * operationplans when the command is committed.
5305  */
5307 {
5308  public:
5309  /** Constructor. */
5311  (const Operation* o, double q, Date d1, Date d2, Demand* l,
5312  OperationPlan* ow=NULL, bool makeflowsloads=true)
5313  {
5314  opplan = o ?
5315  o->createOperationPlan(q, d1, d2, l, ow, 0, makeflowsloads)
5316  : NULL;
5317  }
5318  void commit()
5319  {
5320  if (opplan)
5321  {
5322  opplan->activate();
5323  opplan = NULL; // Avoid executing / initializing more than once
5324  }
5325  }
5326  virtual void rollback() {delete opplan; opplan = NULL;}
5327  virtual void undo() {if (opplan) opplan->deleteFlowLoads();}
5328  virtual void redo() {if (opplan) opplan->createFlowLoads();}
5329  virtual ~CommandCreateOperationPlan() {if (opplan) delete opplan;}
5330  OperationPlan *getOperationPlan() const {return opplan;}
5331 
5332  private:
5333  /** Pointer to the newly created operationplan. */
5334  OperationPlan *opplan;
5335 };
5336 
5337 
5338 /** @brief This command is used to delete an operationplan. */
5340 {
5341  public:
5342  /** Constructor. */
5344  virtual void commit()
5345  {
5346  if (opplan) delete opplan;
5347  opplan = NULL;
5348  }
5349  virtual void undo()
5350  {
5351  if (!opplan) return;
5352  opplan->createFlowLoads();
5353  opplan->insertInOperationplanList();
5354  if (opplan->getDemand())
5355  opplan->getDemand()->addDelivery(opplan);
5356  for (OperationPlan::iterator x(opplan); x != OperationPlan::end(); x++)
5357  {
5358  x->createFlowLoads();
5359  x->insertInOperationplanList();
5360  }
5361  }
5362  virtual void redo()
5363  {
5364  if (!opplan) return;
5365  opplan->deleteFlowLoads();
5366  opplan->removeFromOperationplanList();
5367  if (opplan->getDemand())
5368  opplan->getDemand()->removeDelivery(opplan);
5369  for (OperationPlan::iterator x(opplan); x != OperationPlan::end(); x++)
5370  {
5371  x->deleteFlowLoads();
5372  x->removeFromOperationplanList();
5373  }
5374  }
5375  virtual void rollback()
5376  {
5377  undo();
5378  opplan = NULL;
5379  }
5380  virtual ~CommandDeleteOperationPlan() {undo();}
5381 
5382  private:
5383  /** Pointer to the operationplan being deleted.<br>
5384  * Until the command is committed we don't deallocate the memory for the
5385  * operationplan, but only remove all pointers to it from various places.
5386  */
5387  OperationPlan *opplan;
5388 };
5389 
5390 
5391 /** @brief This class represents the command of moving an operationplan to a
5392  * new date and/or resizing it.
5393  * @todo Moving in a routing operation can't be undone with the current
5394  * implementation! The command will need to store all original dates of
5395  * the suboperationplans...
5396  */
5398 {
5399  public:
5400  /** Constructor.<br>
5401  * Unlike most other commands the constructor already executes the change.
5402  * @param opplanptr Pointer to the operationplan being moved.
5403  * @param newStart New start date of the operationplan.
5404  * @param newEnd New end date of the operationplan.
5405  * @param newQty New quantity of the operationplan.The default is -1,
5406  * which indicates to leave the quantity unchanged.
5407  */
5409  Date newStart, Date newEnd, double newQty = -1.0);
5410 
5411  /** Default constructor. */
5412  DECLARE_EXPORT CommandMoveOperationPlan(OperationPlan*);
5413 
5414  /** Commit the changes. */
5415  virtual void commit() {opplan=NULL;}
5416 
5417  /** Undo the changes. */
5418  virtual void rollback() {restore(true); opplan = NULL;}
5419 
5420  virtual void undo() {restore(false);}
5421  virtual DECLARE_EXPORT void redo();
5422 
5423  /** Undo the changes.<br>
5424  * When the argument is true, subcommands for suboperationplans are deleted. */
5425  DECLARE_EXPORT void restore(bool = false);
5426 
5427  /** Destructor. */
5428  virtual ~CommandMoveOperationPlan() {if (opplan) rollback();}
5429 
5430  /** Returns the operationplan being manipulated. */
5431  OperationPlan* getOperationPlan() const {return opplan;}
5432 
5433  /** Set another start date for the operationplan. */
5434  void setStart(Date d) {if (opplan) opplan->setStart(d);}
5435 
5436  /** Set another start date, end date and quantity for the operationplan. */
5437  void setParameters(Date s, Date e, double q, bool b)
5438  {
5439  assert(opplan->getOperation());
5440  if (opplan)
5441  opplan->getOperation()->setOperationPlanParameters(opplan, q, s, e, b);
5442  }
5443 
5444  /** Set another start date for the operationplan. */
5445  void setEnd(Date d) {if (opplan) opplan->setEnd(d);}
5446 
5447  /** Set another quantity for the operationplan. */
5448  void setQuantity(double q) {if (opplan) opplan->setQuantity(q);}
5449 
5450  /** Return the quantity of the original operationplan. */
5451  double getQuantity() const {return originalqty; }
5452 
5453  /** Return the dates of the original operationplan. */
5454  DateRange getDates() const {return originaldates;}
5455 
5456  private:
5457  /** This is a pointer to the operationplan being moved. */
5458  OperationPlan *opplan;
5459 
5460  /** These are the original dates of the operationplan before its move. */
5461  DateRange originaldates;
5462 
5463  /** This is the quantity of the operationplan before the command. */
5464  double originalqty;
5465 
5466  /** A pointer to a list of suboperationplan commands. */
5467  Command* firstCommand;
5468 };
5469 
5470 
5471 /** @brief This class models a iterator that walks over all available
5472  * HasProblem entities.
5473  *
5474  * This list is containing hard-coding the classes that are implementing
5475  * this class. It's not ideal, but we don't have an explicit container
5476  * of the objects (and we don't want one either) and this allows us also
5477  * to re-use the sorting used for the container classes.
5478  */
5480 {
5481  private:
5482  /** This union contains iterators through the different entity types.
5483  * Only one of the different iterators will be active at a time, and
5484  * can thus save memory by collapsing the iterators into a single
5485  * union. */
5486  union
5487  {
5488  Buffer::iterator *bufIter;
5489  Resource::iterator *resIter;
5491  Demand::iterator *demIter;
5492  };
5493 
5494  /** This type indicates which type of entity we are currently recursing
5495  * through.
5496  * - 0: buffers
5497  * - 1: resources
5498  * - 2: operationplans
5499  * - 3: demands
5500  */
5501  unsigned short type;
5502 
5503  public:
5504  /** Default constructor, which creates an iterator to the first
5505  * HasProblems object. */
5506  explicit DECLARE_EXPORT EntityIterator();
5507 
5508  /** Used to create an iterator pointing beyond the last HasProblems
5509  * object. */
5510  explicit EntityIterator(unsigned short i) : type(i) {}
5511 
5512  /** Copy constructor. */
5514 
5515  /** Assignment operator. */
5516  DECLARE_EXPORT EntityIterator& operator=(const EntityIterator& o);
5517 
5518  /** Destructor. */
5520 
5521  /** Pre-increment operator. */
5522  DECLARE_EXPORT EntityIterator& operator++();
5523 
5524  /** Inequality operator.<br>
5525  * Two iterators are different when they point to different objects.
5526  */
5527  DECLARE_EXPORT bool operator != (const EntityIterator& t) const;
5528 
5529  /** Equality operator.<br>
5530  * Two iterators are equal when they point to the same object.
5531  */
5532  bool operator == (const EntityIterator& t) const {return !(*this != t);}
5533 
5534  /** Dereference operator. */
5535  DECLARE_EXPORT HasProblems& operator*() const;
5536 
5537  /** Dereference operator. */
5538  DECLARE_EXPORT HasProblems* operator->() const;
5539 };
5540 
5541 
5542 /** @brief This class models an STL-like iterator that allows us to iterate
5543  * over the named entities in a simple and safe way.
5544  *
5545  * Objects of this class are returned by the begin() and end() functions.
5546  * @see Problem::begin()
5547  * @see Problem::begin(HasProblem*)
5548  * @see Problem::end()
5549  */
5551 {
5552  friend class Problem;
5553  private:
5554  /** A pointer to the current problem. If this pointer is NULL, we are
5555  * at the end of the list. */
5556  Problem* iter;
5557  HasProblems* owner;
5559 
5560  public:
5561  /** Creates an iterator that will loop through the problems of a
5562  * single entity only. <BR>
5563  * This constructor is also used to create a end-iterator, when passed
5564  * a NULL pointer as argument.
5565  */
5566  explicit const_iterator(HasProblems* o) : iter(o ? o->firstProblem : NULL),
5567  owner(o), eiter(4) {}
5568 
5569  /** Creates an iterator that will loop through the constraints of
5570  * a demand.
5571  */
5572  explicit const_iterator(Problem* o) : iter(o),
5573  owner(NULL), eiter(4) {}
5574 
5575  /** Creates an iterator that will loop through the problems of all
5576  * entities. */
5577  explicit const_iterator() : owner(NULL)
5578  {
5579  // Loop till we find an entity with a problem
5580  while (eiter!=HasProblems::endEntity() && !(eiter->firstProblem))
5581  ++eiter;
5582  // Found a first problem, or no problem at all
5583  iter = (eiter!=HasProblems::endEntity()) ? eiter->firstProblem : NULL;
5584  }
5585 
5586  /** Pre-increment operator. */
5587  DECLARE_EXPORT const_iterator& operator++();
5588 
5589  /** Inequality operator. */
5590  bool operator != (const const_iterator& t) const {return iter!=t.iter;}
5591 
5592  /** Equality operator. */
5593  bool operator == (const const_iterator& t) const {return iter==t.iter;}
5594 
5595  Problem& operator*() const {return *iter;}
5596  Problem* operator->() const {return iter;}
5597 };
5598 
5599 
5600 /** Retrieve an iterator for the list. */
5602 {return Problem::const_iterator(first);}
5603 
5604 
5605 /** Stop iterator. */
5607 {return Problem::const_iterator(static_cast<Problem*>(NULL));}
5608 
5609 
5610 /** @brief This class allows upstream and downstream navigation through
5611  * the plan.
5612  *
5613  * Downstream navigation follows the material flow from raw materials
5614  * towards the produced end item.<br>
5615  * Upstream navigation traces back the material flow from the end item up to
5616  * the consumed raw materials.<br>
5617  * The class is implemented as an STL-like iterator.
5618  *
5619  * @todo operationplans without flowplans are skipped by the iterator - not correct!
5620  */
5621 class PeggingIterator : public Object
5622 {
5623  public:
5624  /** Constructor. */
5626 
5627  /** Constructor. */
5628  DECLARE_EXPORT PeggingIterator(const OperationPlan*, bool = true);
5629 
5630  /** Constructor. */
5631  PeggingIterator(const FlowPlan* e, bool b = true)
5632  : downstream(b), firstIteration(true)
5633  {
5634  if (!e) return;
5635  if (downstream)
5636  states.push(state(0,abs(e->getQuantity()),1.0,e,NULL));
5637  else
5638  states.push(state(0,abs(e->getQuantity()),1.0,NULL,e));
5639  initType(metadata);
5640  }
5641 
5642  /** Return the operationplan consuming the material. */
5643  OperationPlan* getConsumingOperationplan() const
5644  {
5645  const FlowPlan* x = states.top().cons_flowplan;
5646  return x ? x->getOperationPlan() : NULL;
5647  }
5648 
5649  /** Return the material buffer through which we are pegging. */
5650  Buffer *getBuffer() const
5651  {
5652  const FlowPlan* x = states.top().prod_flowplan;
5653  if (!x) x = states.top().cons_flowplan;
5654  return x ? x->getFlow()->getBuffer() : NULL;
5655  }
5656 
5657  /** Return the operationplan producing the material. */
5658  OperationPlan* getProducingOperationplan() const
5659  {
5660  const FlowPlan* x = states.top().prod_flowplan;
5661  return x ? x->getOperationPlan() : NULL;
5662  }
5663 
5664  /** Return the date when the material is consumed. */
5665  Date getConsumingDate() const
5666  {
5667  const FlowPlan* x = states.top().cons_flowplan;
5668  return x ? x->getDate() : Date::infinitePast;
5669  }
5670 
5671  /** Return the date when the material is produced. */
5672  Date getProducingDate() const
5673  {
5674  const FlowPlan* x = states.top().prod_flowplan;
5675  return x ? x->getDate() : Date::infinitePast;
5676  }
5677 
5678  /** Returns the recursion depth of the iterator.<br>
5679  * The original flowplan is at level 0, and each level (either upstream
5680  * or downstream) increments the value by 1.
5681  */
5682  short getLevel() const {return states.top().level;}
5683 
5684  /** Returns the quantity of the demand that is linked to this pegging
5685  * record.
5686  */
5687  double getQuantityDemand() const {return states.top().qty;}
5688 
5689  /** Returns the quantity of the buffer flowplans that is linked to this
5690  * pegging record.
5691  */
5692  double getQuantityBuffer() const
5693  {
5694  const state& t = states.top();
5695  return t.prod_flowplan
5696  ? t.factor * t.prod_flowplan->getOperationPlan()->getQuantity()
5697  : 0;
5698  }
5699 
5700  /** Returns which portion of the current flowplan is fed/supplied by the
5701  * original flowplan. */
5702  double getFactor() const {return states.top().factor;}
5703 
5704  /** Returns false if the flowplan remained unpegged, i.e. it wasn't
5705  * -either completely or paritally- unconsumed at the next level.
5706  */
5707  bool getPegged() const {return states.top().pegged;}
5708 
5709  /** Move the iterator foward to the next downstream flowplan. */
5710  DECLARE_EXPORT PeggingIterator& operator++();
5711 
5712  /** Move the iterator foward to the next downstream flowplan.<br>
5713  * This post-increment operator is less efficient than the pre-increment
5714  * operator.
5715  */
5716  PeggingIterator operator++(int)
5717  {PeggingIterator tmp = *this; ++*this; return tmp;}
5718 
5719  /** Move the iterator foward to the next upstream flowplan. */
5720  DECLARE_EXPORT PeggingIterator& operator--();
5721 
5722  /** Move the iterator foward to the next upstream flowplan.<br>
5723  * This post-increment operator is less efficient than the pre-decrement
5724  * operator.
5725  */
5726  PeggingIterator operator--(int)
5727  {PeggingIterator tmp = *this; --*this; return tmp;}
5728 
5729  /** Comparison operator. */
5730  bool operator==(const PeggingIterator& x) const {return states == x.states;}
5731 
5732  /** Inequality operator. */
5733  bool operator!=(const PeggingIterator& x) const {return states != x.states;}
5734 
5735  /** Conversion operator to a boolean value.
5736  * The return value is true when the iterator still has next elements to
5737  * explore. Returns false when the iteration is finished.
5738  */
5739  operator bool () const {return !states.empty();}
5740 
5741  /** Update the stack. */
5742  DECLARE_EXPORT void updateStack(short, double, double, const FlowPlan*, const FlowPlan*, bool = true);
5743 
5744  /** Returns true if this is a downstream iterator. */
5745  bool isDownstream() {return downstream;}
5746 
5747  /** Initialize the class. */
5748  static int initialize();
5749 
5750  virtual void endElement(XMLInput& i, const Attribute& a, const DataElement& d)
5751  {
5752  throw LogicException("Pegging can't be read");
5753  }
5754  virtual const MetaClass& getType() const {return *metadata;}
5756  size_t getSize() const {return sizeof(PeggingIterator);}
5757 
5758  private:
5759  /** This structure is used to keep track of the iterator states during the
5760  * iteration. */
5761  struct state
5762  {
5763  /** Stores the quantity of this flowplan that is involved. */
5764  double qty;
5765 
5766  /** Stores what portion of the flowplan is involved with the root flowplan
5767  * where the recursion started.
5768  */
5769  double factor;
5770 
5771  /** Keeps track of the number of levels we're removed from the root
5772  * flowplan where the recursion started.
5773  */
5774  short level;
5775 
5776  /** The current flowplan. */
5777  const FlowPlan* cons_flowplan;
5778 
5779  /** The current flowplan. */
5780  const FlowPlan* prod_flowplan;
5781 
5782  /** Set to false when unpegged quantities are involved. */
5783  bool pegged;
5784 
5785  /** Constructor. */
5786  state(unsigned int l, double d, double f,
5787  const FlowPlan* fc, const FlowPlan* fp, bool p = true)
5788  : qty(d), factor(f), level(l),
5789  cons_flowplan(fc), prod_flowplan(fp), pegged(p) {};
5790 
5791  /** Inequality operator. */
5792  bool operator != (const state& s) const
5793  {
5794  return cons_flowplan != s.cons_flowplan
5795  || prod_flowplan != s.prod_flowplan
5796  || level != s.level;
5797  }
5798 
5799  /** Equality operator. */
5800  bool operator == (const state& s) const
5801  {
5802  return cons_flowplan == s.cons_flowplan
5803  && prod_flowplan == s.prod_flowplan
5804  && level == s.level;
5805  }
5806  };
5807 
5808  /** A type to hold the iterator state. */
5809  typedef stack < state > statestack;
5810 
5811  /** A stack is used to store the iterator state. */
5812  statestack states;
5813 
5814  /** Iterate over the pegging in Python. */
5815  DECLARE_EXPORT PyObject *iternext();
5816 
5817  DECLARE_EXPORT PyObject* getattro(const Attribute&);
5818 
5819  /* Auxilary function to make recursive code possible. */
5820  DECLARE_EXPORT void followPegging(const OperationPlan*, short, double, double);
5821 
5822  /** Convenience variable during stack updates.
5823  * Depending on the value of this field, either the top element in the
5824  * stack is updated or a new state is pushed on the stack.
5825  */
5826  bool first;
5827 
5828  /** Downstream or upstream iterator. */
5829  bool downstream;
5830 
5831  /** A flag used by the Python iterators.
5832  * @see iternext()
5833  */
5834  bool firstIteration;
5835 };
5836 
5837 
5838 /** @brief An iterator class to go through all flowplans of an operationplan.
5839  * @see OperationPlan::beginFlowPlans
5840  * @see OperationPlan::endFlowPlans
5841  */
5843 {
5844  friend class OperationPlan;
5845  private:
5846  FlowPlan* curflowplan;
5847  FlowPlan* prevflowplan;
5848  FlowPlanIterator(FlowPlan* b) : curflowplan(b), prevflowplan(NULL) {}
5849  public:
5851  {
5852  curflowplan = b.curflowplan;
5853  prevflowplan = b.prevflowplan;
5854  }
5855  bool operator != (const FlowPlanIterator &b) const
5856  {return b.curflowplan != curflowplan;}
5857  bool operator == (const FlowPlanIterator &b) const
5858  {return b.curflowplan == curflowplan;}
5859  FlowPlanIterator& operator++()
5860  {
5861  prevflowplan = curflowplan;
5862  if (curflowplan) curflowplan = curflowplan->nextFlowPlan;
5863  return *this;
5864  }
5865  FlowPlanIterator operator++(int)
5866  {FlowPlanIterator tmp = *this; ++*this; return tmp;}
5867  FlowPlan* operator ->() const {return curflowplan;}
5868  FlowPlan& operator *() const {return *curflowplan;}
5869  void deleteFlowPlan()
5870  {
5871  if (!curflowplan) return;
5872  if (prevflowplan) prevflowplan->nextFlowPlan = curflowplan->nextFlowPlan;
5873  else curflowplan->oper->firstflowplan = curflowplan->nextFlowPlan;
5874  FlowPlan* tmp = curflowplan;
5875  // Move the iterator to the next element
5876  curflowplan = curflowplan->nextFlowPlan;
5877  delete tmp;
5878  }
5879 };
5880 
5882 {return OperationPlan::FlowPlanIterator(firstflowplan);}
5883 
5885 {return OperationPlan::FlowPlanIterator(NULL);}
5886 
5888 {
5889  int c = 0;
5890  for (FlowPlanIterator i = beginFlowPlans(); i != endFlowPlans(); ++i) ++c;
5891  return c;
5892 }
5893 
5894 
5895 /** @brief An iterator class to go through all loadplans of an operationplan.
5896  * @see OperationPlan::beginLoadPlans
5897  * @see OperationPlan::endLoadPlans
5898  */
5900 {
5901  friend class OperationPlan;
5902  private:
5903  LoadPlan* curloadplan;
5904  LoadPlan* prevloadplan;
5905  LoadPlanIterator(LoadPlan* b) : curloadplan(b), prevloadplan(NULL) {}
5906  public:
5908  {
5909  curloadplan = b.curloadplan;
5910  prevloadplan = b.prevloadplan;
5911  }
5912  bool operator != (const LoadPlanIterator &b) const
5913  {return b.curloadplan != curloadplan;}
5914  bool operator == (const LoadPlanIterator &b) const
5915  {return b.curloadplan == curloadplan;}
5916  LoadPlanIterator& operator++()
5917  {
5918  prevloadplan = curloadplan;
5919  if (curloadplan) curloadplan = curloadplan->nextLoadPlan;
5920  return *this;
5921  }
5922  LoadPlanIterator operator++(int)
5923  {LoadPlanIterator tmp = *this; ++*this; return tmp;}
5924  LoadPlan* operator ->() const {return curloadplan;}
5925  LoadPlan& operator *() const {return *curloadplan;}
5926  void deleteLoadPlan()
5927  {
5928  if (!curloadplan) return;
5929  if (prevloadplan) prevloadplan->nextLoadPlan = curloadplan->nextLoadPlan;
5930  else curloadplan->oper->firstloadplan = curloadplan->nextLoadPlan;
5931  LoadPlan* tmp = curloadplan;
5932  // Move the iterator to the next element
5933  curloadplan = curloadplan->nextLoadPlan;
5934  delete tmp;
5935  }
5936 };
5937 
5938 
5940 {return OperationPlan::LoadPlanIterator(firstloadplan);}
5941 
5942 
5944 {return OperationPlan::LoadPlanIterator(NULL);}
5945 
5946 
5948 {
5949  int c = 0;
5950  for (LoadPlanIterator i = beginLoadPlans(); i != endLoadPlans(); ++i) ++c;
5951  return c;
5952 }
5953 
5954 
5956  : public FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>
5957 {
5958  public:
5959  /** Constructor starting the iteration from a certain problem. */
5961  FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>(x) {}
5962 
5963  /** Constructor starting the iteration from a certain problem. */
5965  FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>(&x) {}
5966 
5967  /** Default constructor. */
5969  FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>() {}
5970 };
5971 
5972 
5974  : public FreppleIterator<BufferIterator,Buffer::memberIterator,Buffer>
5975 {
5976  public:
5979 };
5980 
5981 
5983  : public FreppleIterator<LocationIterator,Location::memberIterator,Location>
5984 {
5985  public:
5988 };
5989 
5990 
5992  : public FreppleIterator<CustomerIterator,Customer::memberIterator,Customer>
5993 {
5994  public:
5997 };
5998 
5999 
6001  : public FreppleIterator<ItemIterator,Item::memberIterator,Item>
6002 {
6003  public:
6006 };
6007 
6008 
6010  : public FreppleIterator<DemandIterator,Demand::memberIterator,Demand>
6011 {
6012  public:
6015 };
6016 
6017 
6019  : public FreppleIterator<ResourceIterator,Resource::memberIterator,Resource>
6020 {
6021  public:
6024 };
6025 
6026 
6028  : public FreppleIterator<SolverIterator,Solver::iterator,Solver>
6029 {
6030 };
6031 
6032 
6034  : public FreppleIterator<OperationIterator,Operation::iterator,Operation>
6035 {
6036 };
6037 
6038 
6040  : public FreppleIterator<CalendarIterator,Calendar::iterator,Calendar>
6041 {
6042 };
6043 
6044 
6046  : public FreppleIterator<SetupMatrixIterator,SetupMatrix::iterator,SetupMatrix>
6047 {
6048 };
6049 
6050 
6052  : public FreppleIterator<SkillIterator,Skill::iterator,Skill>
6053 {
6054 };
6055 
6056 
6057 //
6058 // SETUP MATRIX RULES
6059 //
6060 
6061 
6062 class SetupMatrixRuleIterator : public PythonExtension<SetupMatrixRuleIterator>
6063 {
6064  public:
6065  static int initialize();
6066 
6068  {
6069  if (!c)
6070  throw LogicException("Creating rule iterator for NULL matrix");
6071  currule = c->beginRules();
6072  }
6073 
6074  private:
6075  SetupMatrix* matrix;
6076  SetupMatrix::RuleIterator currule;
6077  PyObject *iternext();
6078 };
6079 
6080 
6081 //
6082 // RESOURCE SKILLS
6083 //
6084 
6085 class ResourceSkillIterator : public PythonExtension<ResourceSkillIterator>
6086 {
6087  public:
6088  static int initialize();
6089 
6091  : res(r), ir(r ? r->getSkills().begin() : NULL), skill(NULL), is(NULL)
6092  {
6093  if (!r)
6094  throw LogicException("Creating resourceskill iterator for NULL resource");
6095  }
6096 
6098  : res(NULL), ir(NULL), skill(s), is(s ? s->getResources().begin() : NULL)
6099  {
6100  if (!s)
6101  throw LogicException("Creating resourceskill iterator for NULL skill");
6102  }
6103 
6104  private:
6105  Resource* res;
6106  Resource::skilllist::const_iterator ir;
6107  Skill* skill;
6108  Skill::resourcelist::const_iterator is;
6109  PyObject *iternext();
6110 };
6111 
6112 
6113 //
6114 // CALENDARS
6115 //
6116 
6117 
6118 class CalendarBucketIterator : public PythonExtension<CalendarBucketIterator>
6119 {
6120  public:
6121  static int initialize();
6122 
6124  {
6125  if (!c)
6126  throw LogicException("Creating bucket iterator for NULL calendar");
6127  i = c->beginBuckets();
6128  }
6129 
6130  private:
6131  Calendar* cal;
6133  PyObject *iternext();
6134 };
6135 
6136 
6138  : public PythonExtension<CalendarEventIterator>
6139 {
6140  public:
6141  static int initialize();
6142 
6144  : cal(c), eventiter(c,d,f), forward(f) {}
6145 
6146  private:
6147  Calendar* cal;
6148  Calendar::EventIterator eventiter;
6149  bool forward;
6150  PyObject *iternext();
6151 };
6152 
6153 
6154 //
6155 // OPERATIONPLANS
6156 //
6157 
6158 
6160  : public FreppleIterator<OperationPlanIterator,OperationPlan::iterator,OperationPlan>
6161 {
6162  public:
6163  /** Constructor to iterate over all operationplans. */
6165 
6166  /** Constructor to iterate over the operationplans of a single operation. */
6169  {}
6170 
6171  /** Constructor to iterate over the suboperationplans of an operationplans. */
6174  {}
6175 };
6176 
6177 
6178 //
6179 // FLOWPLANS
6180 //
6181 
6182 
6183 class FlowPlanIterator : public PythonExtension<FlowPlanIterator>
6184 {
6185  public:
6186  /** Registration of the Python class and its metadata. */
6187  static int initialize();
6188 
6189  /** Constructor to iterate over the flowplans of a buffer. */
6190  FlowPlanIterator(Buffer* b) : buf(b), buffer_or_opplan(true)
6191  {
6192  if (!b)
6193  throw LogicException("Creating flowplan iterator for NULL buffer");
6194  bufiter = new Buffer::flowplanlist::const_iterator(b->getFlowPlans().begin());
6195  }
6196 
6197  /** Constructor to iterate over the flowplans of an operationplan. */
6198  FlowPlanIterator(OperationPlan* o) : opplan(o), buffer_or_opplan(false)
6199  {
6200  if (!o)
6201  throw LogicException("Creating flowplan iterator for NULL operationplan");
6202  opplaniter = new OperationPlan::FlowPlanIterator(o->beginFlowPlans());
6203  }
6204 
6206  {
6207  if (buffer_or_opplan) delete bufiter;
6208  else delete opplaniter;
6209  }
6210 
6211  private:
6212  union
6213  {
6216  };
6217 
6218  union
6219  {
6220  Buffer::flowplanlist::const_iterator *bufiter;
6222  };
6223 
6224  /** Flags whether we are browsing over the flowplans in a buffer or in an
6225  * operationplan. */
6226  bool buffer_or_opplan;
6227 
6228  PyObject *iternext();
6229 };
6230 
6231 
6232 //
6233 // LOADPLANS
6234 //
6235 
6236 
6237 class LoadPlanIterator : public PythonExtension<LoadPlanIterator>
6238 {
6239  public:
6240  static int initialize();
6241 
6242  LoadPlanIterator(Resource* r) : res(r), resource_or_opplan(true)
6243  {
6244  if (!r)
6245  throw LogicException("Creating loadplan iterator for NULL resource");
6246  resiter = new Resource::loadplanlist::const_iterator(r->getLoadPlans().begin());
6247  }
6248 
6249  LoadPlanIterator(OperationPlan* o) : opplan(o), resource_or_opplan(false)
6250  {
6251  if (!opplan)
6252  throw LogicException("Creating loadplan iterator for NULL operationplan");
6253  opplaniter = new OperationPlan::LoadPlanIterator(o->beginLoadPlans());
6254  }
6255 
6257  {
6258  if (resource_or_opplan) delete resiter;
6259  else delete opplaniter;
6260  }
6261 
6262  private:
6263  union
6264  {
6267  };
6268 
6269  union
6270  {
6271  Resource::loadplanlist::const_iterator *resiter;
6273  };
6274 
6275  /** Flags whether we are browsing over the flowplans in a buffer or in an
6276  * operationplan. */
6277  bool resource_or_opplan;
6278 
6279  PyObject *iternext();
6280 };
6281 
6282 
6283 //
6284 // DEMAND DELIVERY OPERATIONPLANS
6285 //
6286 
6287 
6288 class DemandPlanIterator : public PythonExtension<DemandPlanIterator>
6289 {
6290  public:
6291  static int initialize();
6292 
6294  {
6295  if (!r)
6296  throw LogicException("Creating demandplan iterator for NULL demand");
6297  i = r->getDelivery().begin();
6298  }
6299 
6300  private:
6301  Demand* dem;
6302  Demand::OperationPlan_list::const_iterator i;
6303  PyObject *iternext();
6304 };
6305 
6306 
6307 //
6308 // LOADS
6309 //
6310 
6311 
6312 class LoadIterator : public PythonExtension<LoadIterator>
6313 {
6314  public:
6315  static int initialize();
6316 
6318  : res(r), ir(r ? r->getLoads().begin() : NULL), oper(NULL), io(NULL)
6319  {
6320  if (!r)
6321  throw LogicException("Creating loadplan iterator for NULL resource");
6322  }
6323 
6325  : res(NULL), ir(NULL), oper(o), io(o ? o->getLoads().begin() : NULL)
6326  {
6327  if (!o)
6328  throw LogicException("Creating loadplan iterator for NULL operation");
6329  }
6330 
6331  private:
6332  Resource* res;
6333  Resource::loadlist::const_iterator ir;
6334  Operation* oper;
6335  Operation::loadlist::const_iterator io;
6336  PyObject *iternext();
6337 };
6338 
6339 
6340 //
6341 // FLOW
6342 //
6343 
6344 
6345 class FlowIterator : public PythonExtension<FlowIterator>
6346 {
6347  public:
6348  static int initialize();
6349 
6351  : buf(b), ib(b ? b->getFlows().begin() : NULL), oper(NULL), io(NULL)
6352  {
6353  if (!b)
6354  throw LogicException("Creating flowplan iterator for NULL buffer");
6355  }
6356 
6358  : buf(NULL), ib(NULL), oper(o), io(o ? o->getFlows().begin() : NULL)
6359  {
6360  if (!o)
6361  throw LogicException("Creating flowplan iterator for NULL operation");
6362  }
6363 
6364  private:
6365  Buffer* buf;
6367  Operation* oper;
6369  PyObject *iternext();
6370 };
6371 
6372 
6373 /** @brief This Python function is used for reading XML input.
6374  *
6375  * The function takes up to three arguments:
6376  * - XML data file to be processed.
6377  * If this argument is omitted or None, the standard input is read.
6378  * - Optional validate flag, defining whether or not the input data needs to be
6379  * validated against the XML schema definition.
6380  * The validation is switched ON by default.
6381  * Switching it ON is recommended in situations where there is no 100% guarantee
6382  * on the validity of the input data.
6383  * - Optional validate_only flag, which allows us to validate the data but
6384  * skip any processing.
6385  */
6386 DECLARE_EXPORT PyObject* readXMLfile(PyObject*, PyObject*);
6387 
6388 
6389 /** @brief This Python function is used for processing XML input data from a string.
6390  *
6391  * The function takes up to three arguments:
6392  * - XML data string to be processed
6393  * - Optional validate flag, defining whether or not the input data needs to be
6394  * validated against the XML schema definition.
6395  * The validation is switched ON by default.
6396  * Switching it ON is recommended in situations where there is no 100% guarantee
6397  * on the validity of the input data.
6398  * - Optional validate_only flag, which allows us to validate the data but
6399  * skip any processing.
6400  */
6401 DECLARE_EXPORT PyObject* readXMLdata(PyObject *, PyObject *);
6402 
6403 
6404 /** @brief This Python function writes the dynamic part of the plan to an text file.
6405  *
6406  * This saved information covers the buffer flowplans, operationplans,
6407  * resource loading, demand, problems, etc...<br>
6408  * The main use of this function is in the test suite: a simple text file
6409  * comparison allows us to identify changes quickly. The output format is
6410  * only to be seen in this context of testing, and is not intended to be used
6411  * as an official method for publishing plans to other systems.
6412  */
6413 DECLARE_EXPORT PyObject* savePlan(PyObject*, PyObject*);
6414 
6415 
6416 /** @brief This Python function prints a summary of the dynamically allocated
6417  * memory to the standard output. This is useful for understanding better the
6418  * size of your model.
6419  *
6420  * The numbers reported by this function won't match the memory size as
6421  * reported by the operating system, since the dynamically allocated memory
6422  * is only a part of the total memory used by a program.
6423  */
6424 DECLARE_EXPORT PyObject* printModelSize(PyObject* self, PyObject* args);
6425 
6426 
6427 /** @brief This python function writes the complete model to an XML-file.
6428  *
6429  * Both the static model (i.e. items, locations, buffers, resources,
6430  * calendars, etc...) and the dynamic data (i.e. the actual plan including
6431  * the operationplans, demand, problems, etc...).<br>
6432  * The format is such that the output file can be re-read to restore the
6433  * very same model.<br>
6434  * The function takes the following arguments:
6435  * - Name of the output file
6436  * - Type of output desired: STANDARD, PLAN or PLANDETAIL.
6437  * The default value is STANDARD.
6438  */
6439 DECLARE_EXPORT PyObject* saveXMLfile(PyObject*, PyObject*);
6440 
6441 
6442 /** @brief This Python function erases the model or the plan from memory.
6443  *
6444  * The function allows the following modes to control what to delete:
6445  * - plan:<br>
6446  * Deletes the dynamic modelling constructs, such as operationplans,
6447  * loadplans and flowplans only. Locked operationplans are not
6448  * deleted.<br>
6449  * The static model is left intact.<br>
6450  * This is the default mode.
6451  * - model:<br>
6452  * The dynamic as well as the static objects are removed. You'll end
6453  * up with a completely empty model.
6454  * Due to the logic required in the object destructors this mode doesn't
6455  * scale linear with the model size.
6456  */
6457 DECLARE_EXPORT PyObject* eraseModel(PyObject* self, PyObject* args);
6458 
6459 
6460 } // End namespace
6461 
6462 #endif