model.h
Go to the documentation of this file.
1 /***************************************************************************
2  * *
3  * Copyright (C) 2007-2012 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.
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  assert(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 A flowplan represents a planned material flow in or out of a buffer.
3390  *
3391  * Flowplans are owned by operationplans, which manage a container to store
3392  * them.
3393  */
3394 class FlowPlan : public TimeLine<FlowPlan>::EventChangeOnhand, public PythonExtensionBase
3395 {
3397  private:
3398  /** Points to the flow instantiated by this flowplan. */
3399  const Flow *fl;
3400 
3401  /** Python interface method. */
3402  PyObject* getattro(const Attribute&);
3403 
3404  /** Points to the operationplan owning this flowplan. */
3405  OperationPlan *oper;
3406 
3407  /** Points to the next flowplan owned by the same operationplan. */
3408  FlowPlan *nextFlowPlan;
3409 
3410  public:
3411 
3413  static int initialize();
3414 
3415  /** Constructor. */
3416  explicit DECLARE_EXPORT FlowPlan(OperationPlan*, const Flow*);
3417 
3418  /** Returns the flow of which this is an plan instance. */
3419  const Flow* getFlow() const {return fl;}
3420 
3421  /** Returns the buffer. */
3422  const Buffer* getBuffer() const {return fl->getBuffer();}
3423 
3424  /** Update the flow of an already existing flowplan.<br>
3425  * The new flow must belong to the same operation.
3426  */
3427  DECLARE_EXPORT void setFlow(const Flow*);
3428 
3429  /** Returns the operationplan owning this flowplan. */
3430  OperationPlan* getOperationPlan() const {return oper;}
3431 
3432  /** Destructor. */
3433  virtual ~FlowPlan()
3434  {
3435  Buffer* b = getFlow()->getBuffer();
3436  b->setChanged();
3437  b->flowplans.erase(this);
3438  }
3439 
3440  /** Writing the element.
3441  * This method has the same prototype as a usual instance of the Object
3442  * class, but this is only superficial: FlowPlan isn't a subclass of
3443  * Object at all.
3444  */
3445  void DECLARE_EXPORT writeElement
3446  (XMLOutput*, const Keyword&, mode=DEFAULT) const;
3447 
3448  /** Updates the quantity of the flowplan by changing the quantity of the
3449  * operationplan owning this flowplan.<br>
3450  * The boolean parameter is used to control whether to round up (false)
3451  * or down (true) in case the operation quantity must be a multiple.
3452  */
3453  void setQuantity(double qty, bool b=false, bool u = true)
3454  {
3455  if (getFlow()->getEffective().within(getDate()))
3456  oper->setQuantity(qty / getFlow()->getQuantity(), b, u);
3457  }
3458 
3459  /** This function needs to be called whenever the flowplan date or
3460  * quantity are changed.
3461  */
3462  DECLARE_EXPORT void update();
3463 
3464  /** Return a pointer to the timeline data structure owning this flowplan. */
3465  TimeLine<FlowPlan>* getTimeLine() const
3466  {return &(getFlow()->getBuffer()->flowplans);}
3467 
3468  /** Returns true when the flowplan is hidden.<br>
3469  * This is determined by looking at whether the flow is hidden or not.
3470  */
3471  bool getHidden() const {return fl->getHidden();}
3472 };
3473 
3474 
3475 inline double Flow::getFlowplanQuantity(const FlowPlan* fl) const
3476 {
3477  return getEffective().within(fl->getDate()) ?
3478  fl->getOperationPlan()->getQuantity() * getQuantity() :
3479  0.0;
3480 }
3481 
3482 
3483 inline Date Flow::getFlowplanDate(const FlowPlan* fl) const
3484 {
3485  return fl->getOperationPlan()->getDates().getStart();
3486 }
3487 
3488 
3489 inline Date FlowEnd::getFlowplanDate(const FlowPlan* fl) const
3490 {
3491  return fl->getOperationPlan()->getDates().getEnd();
3492 }
3493 
3494 
3495 /** @brief This class is used to represent a matrix defining the changeover
3496  * times between setups.
3497  */
3498 class SetupMatrix : public HasName<SetupMatrix>
3499 {
3500  public:
3501  class RuleIterator; // Forward declaration
3502  /** @brief An specific changeover rule in a setup matrix. */
3503  class Rule : public Object
3504  {
3505  friend class RuleIterator;
3506  friend class SetupMatrix;
3507  public:
3508  /** Constructor. */
3509  DECLARE_EXPORT Rule(SetupMatrix *s, int p = 0);
3510 
3511  /** Destructor. */
3512  DECLARE_EXPORT ~Rule();
3513 
3514  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
3515  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
3516  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
3517  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
3518  static int initialize();
3519 
3520  virtual const MetaClass& getType() const {return *metadata;}
3522 
3523  size_t getSize() const
3524  {return sizeof(Rule) + from.size() + to.size();}
3525 
3526  /** Update the priority.<br>
3527  * The priority value is a key field. If multiple rules have the
3528  * same priority a data exception is thrown.
3529  */
3530  DECLARE_EXPORT void setPriority(const int);
3531 
3532  /** Return the matrix owning this rule. */
3533  SetupMatrix* getSetupMatrix() const {return matrix;}
3534 
3535  /** Return the priority. */
3536  double getPriority() const {return priority;}
3537 
3538  /** Update the from setup. */
3539  void setFromSetup(const string f) {from = f;}
3540 
3541  /** Return the from setup. */
3542  const string& getFromSetup() const {return from;}
3543 
3544  /** Update the from setup. */
3545  void setToSetup(const string f) {to = f;}
3546 
3547  /** Return the from setup. */
3548  const string& getToSetup() const {return to;}
3549 
3550  /** Update the conversion duration. */
3551  void setDuration(const TimePeriod p) {duration = p;}
3552 
3553  /** Return the conversion duration. */
3554  TimePeriod getDuration() const {return duration;}
3555 
3556  /** Update the conversion cost. */
3557  void setCost(const double p) {cost = p;}
3558 
3559  /** Return the conversion cost. */
3560  double getCost() const {return cost;}
3561 
3562  private:
3563  /** Original setup. */
3564  string from;
3565 
3566  /** New setup. */
3567  string to;
3568 
3569  /** Changeover time. */
3570  TimePeriod duration;
3571 
3572  /** Changeover cost. */
3573  double cost;
3574 
3575  /** Priority of the rule.<br>
3576  * This field is the key field, i.e. within a setup matrix all rules
3577  * need to have different priorities.
3578  */
3579  int priority;
3580 
3581  /** Pointer to the owning matrix. */
3582  SetupMatrix *matrix;
3583 
3584  /** Pointer to the next rule in this matrix. */
3585  Rule *nextRule;
3586 
3587  /** Pointer to the previous rule in this matrix. */
3588  Rule *prevRule;
3589  };
3590 
3591  /** @brief An iterator class to go through all rules of a setup matrix. */
3593  {
3594  private:
3595  Rule* curRule;
3596  public:
3597  /** Constructor. */
3598  RuleIterator(Rule* c = NULL) : curRule(c) {}
3599  bool operator != (const RuleIterator &b) const
3600  {return b.curRule != curRule;}
3601  bool operator == (const RuleIterator &b) const
3602  {return b.curRule == curRule;}
3603  RuleIterator& operator++()
3604  {if (curRule) curRule = curRule->nextRule; return *this;}
3605  RuleIterator operator++(int)
3606  {RuleIterator tmp = *this; ++*this; return tmp;}
3607  RuleIterator& operator--()
3608  {if(curRule) curRule = curRule->prevRule; return *this;}
3609  RuleIterator operator--(int)
3610  {RuleIterator tmp = *this; --*this; return tmp;}
3611  Rule* operator ->() const {return curRule;}
3612  Rule& operator *() const {return *curRule;}
3613  };
3614 
3615  public:
3616  /** Default constructor. */
3617  SetupMatrix(const string& n) : HasName<SetupMatrix>(n), firstRule(NULL) {}
3618 
3619  /** Destructor. */
3621 
3622  /** This is a factory method that creates a new rule<br>
3623  * This method is intended to be used to create objects when reading
3624  * XML input data.
3625  */
3626  DECLARE_EXPORT Rule* createRule(const AttributeList&);
3627 
3628  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
3629  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
3630  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
3631  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
3632  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
3633  static int initialize();
3634 
3635  virtual const MetaClass& getType() const {return *metadata;}
3637 
3638  virtual size_t getSize() const
3639  {
3640  size_t i = sizeof(SetupMatrix) + getName().size();
3641  for (RuleIterator j = beginRules(); j!= endRules(); ++j)
3642  i += j->getSize();
3643  return i;
3644  }
3645 
3646  size_t extrasize() const
3647  {
3648  size_t i = getName().size();
3649  for (RuleIterator j = beginRules(); j!= endRules(); ++j)
3650  i += j->getSize();
3651  return i;
3652  }
3653 
3654  /** Returns an iterator to go through the list of rules. */
3655  RuleIterator beginRules() const {return RuleIterator(firstRule);}
3656 
3657  /** Returns an iterator to go through the list of rules. */
3658  RuleIterator endRules() const {return RuleIterator(NULL);}
3659 
3660  /** Python interface to add a new rule. */
3661  static DECLARE_EXPORT PyObject* addPythonRule(PyObject*, PyObject*, PyObject*);
3662 
3663  /** Computes the changeover time and cost between 2 setup values.
3664  *
3665  * To compute the time of a changeover the algorithm will evaluate all
3666  * rules in sequence (in order of priority).<br>
3667  * For a rule to match the changeover between the original setup X to
3668  * a new setup Y, two conditions need to be fulfilled:
3669  * - The original setup X must match with the fromsetup of the rule.<br>
3670  * If the fromsetup field is empty, it is considered a match.
3671  * - The new setup Y must match with the tosetup of the rule.<br>
3672  * If the tosetup field is empty, it is considered a match.
3673  * The wildcard characters * and ? can be used in the fromsetup and
3674  * tosetup fields.<br>
3675  * As soon as a matching rule is found, it is applied and subsequent
3676  * rules are not evaluated.<br>
3677  * If no matching rule is found, the changeover is not allowed: a NULL
3678  * pointer is returned.
3679  */
3680  DECLARE_EXPORT Rule* calculateSetup(const string, const string) const;
3681 
3682  private:
3683  /** Head of the list of rules. */
3684  Rule *firstRule;
3685 };
3686 
3687 
3688 /** @brief This class is the default implementation of the abstract
3689  * SetupMatrix class.
3690  */
3692 {
3693  public:
3694  explicit SetupMatrixDefault(const string& str) : SetupMatrix(str) {initType(metadata);}
3695  virtual const MetaClass& getType() const {return *metadata;}
3697  virtual size_t getSize() const
3698  {return sizeof(SetupMatrixDefault) + SetupMatrix::extrasize();}
3699  static int initialize();
3700 };
3701 
3702 
3703 /** @brief This class models skills that can be assigned to resources. */
3704 class Skill : public HasName<Skill>
3705 {
3706  friend class ResourceSkill;
3707 
3708  public:
3709  /** Default constructor. */
3710  Skill(const string& n) : HasName<Skill>(n) {}
3711 
3712  /** Destructor. */
3713  DECLARE_EXPORT ~Skill();
3714 
3716 
3717  /** Returns an reference to the list of resources having this skill. */
3718  const resourcelist& getResources() const {return resources;}
3719 
3720  /** Python interface to add a new resource. */
3721  static DECLARE_EXPORT PyObject* addPythonResource(PyObject*, PyObject*);
3722 
3723  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
3724  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
3725  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
3726  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
3727  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
3728  static int initialize();
3729 
3730  virtual const MetaClass& getType() const {return *metadata;}
3732 
3733  virtual size_t getSize() const
3734  {
3735  size_t i = sizeof(Skill) + getName().size() + resources.size() * 3 * sizeof(Resource*);
3736  return i;
3737  }
3738 
3739  size_t extrasize() const
3740  {
3741  return getName().size() + resources.size() * 3 * sizeof(Resource*);
3742  }
3743 
3744  private:
3745  /** This is a list of resources having this skill. */
3746  resourcelist resources;
3747 };
3748 
3749 
3750 /** @brief this class is the default implementation of the abstract
3751  * Skill class.
3752  */
3753 class SkillDefault : public Skill
3754 {
3755  public:
3756  explicit SkillDefault(const string& str) : Skill(str) {initType(metadata);}
3757  virtual const MetaClass& getType() const {return *metadata;}
3759  virtual size_t getSize() const
3760  {return sizeof(SkillDefault) + Skill::extrasize();}
3761  static int initialize();
3762 };
3763 
3764 
3765 /** @brief This class represents a workcentre, a physical or logical
3766  * representation of capacity.
3767  */
3768 class Resource : public HasHierarchy<Resource>,
3769  public HasLevel, public Plannable, public HasDescription
3770 {
3771  friend class Load;
3772  friend class LoadPlan;
3773  friend class ResourceSkill;
3774 
3775  public:
3776  class PlanIterator;
3777 
3778  /** The default time window before the ask date where we look for
3779  * available capacity. */
3780  static const long defaultMaxEarly = 100*86400L;
3781 
3782  /** Constructor. */
3783  explicit Resource(const string& str) : HasHierarchy<Resource>(str),
3784  size_max_cal(NULL), size_max(0), loc(NULL), cost(0.0), hidden(false), maxearly(defaultMaxEarly),
3785  setupmatrix(NULL) { setMaximum(1); };
3786 
3787  /** Destructor. */
3788  virtual DECLARE_EXPORT ~Resource();
3789 
3790  /** Updates the size of a resource, when it is time-dependent. */
3791  DECLARE_EXPORT void setMaximumCalendar(CalendarDouble*);
3792 
3793  /** Updates the size of a resource. */
3794  DECLARE_EXPORT void setMaximum(double);
3795 
3796  /** Return a pointer to the maximum capacity profile. */
3797  CalendarDouble* getMaximumCalendar() const {return size_max_cal;}
3798 
3799  /** Return a pointer to the maximum capacity. */
3800  double getMaximum() const {return size_max;}
3801 
3802  /** Returns the cost of using 1 unit of this resource for 1 hour.<br>
3803  * The default value is 0.0.
3804  */
3805  double getCost() const {return cost;}
3806 
3807  /** Update the cost of using 1 unit of this resource for 1 hour. */
3808  void setCost(const double c)
3809  {
3810  if (c >= 0) cost = c;
3811  else throw DataException("Resource cost must be positive");
3812  }
3813 
3817 
3818  /** Returns a reference to the list of loadplans. */
3819  const loadplanlist& getLoadPlans() const {return loadplans;}
3820 
3821  /** Returns a reference to the list of loadplans. */
3822  loadplanlist& getLoadPlans() {return loadplans;}
3823 
3824  /** Returns a constant reference to the list of loads. It defines
3825  * which operations are using the resource.
3826  */
3827  const loadlist& getLoads() const {return loads;}
3828 
3829  /** Returns a constant reference to the list of skills. */
3830  const skilllist& getSkills() const {return skills;}
3831 
3832  /** Return the load that is associates a given operation with this
3833  * resource. Returns NULL is no such load exists. */
3834  Load* findLoad(const Operation* o, Date d) const
3835  {return loads.find(o,d);}
3836 
3837  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
3838  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
3839  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
3840  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
3841  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
3842 
3843  /** Initialize the class. */
3844  static int initialize();
3845 
3846  size_t extrasize() const
3847  {
3848  return getName().size() + HasDescription::extrasize()
3849  + setup.size() + skills.size() * 3 * sizeof(Skill*);
3850  }
3851 
3852  /** Returns the location of this resource. */
3853  Location* getLocation() const {return loc;}
3854 
3855  /** Updates the location of this resource. */
3856  void setLocation(Location* i) {loc = i;}
3857 
3858  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
3859 
3860  /** Deletes all operationplans loading this resource. The boolean parameter
3861  * controls whether we delete also locked operationplans or not.
3862  */
3863  DECLARE_EXPORT void deleteOperationPlans(bool = false);
3864 
3865  /** Recompute the problems of this resource. */
3866  virtual DECLARE_EXPORT void updateProblems();
3867 
3868  /** Scan the setups of this resource. */
3869  virtual DECLARE_EXPORT void updateSetups(const LoadPlan* = NULL);
3870 
3871  void setHidden(bool b) {if (hidden!=b) setChanged(); hidden = b;}
3872  bool getHidden() const {return hidden;}
3873 
3874  virtual const MetaClass& getType() const {return *metadata;}
3876 
3877  /** Returns the maximum inventory buildup allowed in case of capacity
3878  * shortages. */
3879  TimePeriod getMaxEarly() const {return maxearly;}
3880 
3881  /** Updates the maximum inventory buildup allowed in case of capacity
3882  * shortages. */
3883  void setMaxEarly(TimePeriod c)
3884  {
3885  if (c >= 0L) maxearly = c;
3886  else throw DataException("MaxEarly must be positive");
3887  }
3888 
3889  /** Return a pointer to the setup matrix. */
3890  SetupMatrix* getSetupMatrix() const {return setupmatrix;}
3891 
3892  /** Update the reference to the setup matrix. */
3893  void setSetupMatrix(SetupMatrix *s) {setupmatrix = s;}
3894 
3895  /** Return the current setup. */
3896  const string& getSetup() const {return setup;}
3897 
3898  /** Update the current setup. */
3899  void setSetup(const string s) {setup = s;}
3900 
3901  private:
3902  /** This calendar is used to updates to the resource size. */
3903  CalendarDouble* size_max_cal;
3904 
3905  /** The maximum resource size.<br>
3906  * If a calendar is specified, this field is ignored.
3907  */
3908  double size_max;
3909 
3910  /** Stores the collection of all loadplans of this resource. */
3911  loadplanlist loadplans;
3912 
3913  /** This is a list of all load models that are linking this resource with
3914  * operations. */
3915  loadlist loads;
3916 
3917  /** This is a list of skills this resource has. */
3918  skilllist skills;
3919 
3920  /** A pointer to the location of the resource. */
3921  Location* loc;
3922 
3923  /** The cost of using 1 unit of this resource for 1 hour. */
3924  double cost;
3925 
3926  /** Specifies whether this resource is hidden for serialization. */
3927  bool hidden;
3928 
3929  /** Maximum inventory buildup allowed in case of capacity shortages. */
3930  TimePeriod maxearly;
3931 
3932  /** Reference to the setup matrix. */
3933  SetupMatrix *setupmatrix;
3934 
3935  /** Current setup. */
3936  string setup;
3937 
3938  /** Python method that returns an iterator over the resource plan. */
3939  static PyObject* plan(PyObject*, PyObject*);
3940 };
3941 
3942 
3943 /** @brief This class provides an efficient way to iterate over
3944  * the plan of a resource aggregated in time buckets.
3945  */
3946 class Resource::PlanIterator : public PythonExtension<Resource::PlanIterator>
3947 {
3948  public:
3949  static int initialize();
3950 
3951  /** Constructor.
3952  * The first argument is the resource whose plan we're looking at.
3953  * The second argument is a Python iterator over a list of dates. These
3954  * dates define the buckets at which we aggregate the resource plan.
3955  */
3956  PlanIterator(Resource*, PyObject*);
3957 
3958  /** Destructor. */
3959  ~PlanIterator();
3960 
3961  private:
3962  /** Pointer to the resource we're investigating. */
3963  Resource* res;
3964 
3965  /** A Python object pointing to a list of start dates of buckets. */
3966  PyObject* bucketiterator;
3967 
3968  /** An iterator over all events in the resource timeline. */
3969  Resource::loadplanlist::iterator ldplaniter;
3970 
3971  /** Python function to iterate over the periods. */
3972  PyObject* iternext();
3973 
3974  double cur_setup;
3975  double cur_load;
3976  double cur_size;
3977  Date cur_date;
3978  Date prev_date;
3979  bool prev_value;
3980  Calendar::EventIterator unavailableIterator;
3981  bool hasUnavailability;
3982  double bucket_available;
3983  double bucket_load;
3984  double bucket_setup;
3985  double bucket_unavailable;
3986 
3987  void update(Date till);
3988 
3989  /** Python object pointing to the start date of the plan bucket. */
3990  PyObject* start_date;
3991 
3992  /** Python object pointing to the start date of the plan bucket. */
3993  PyObject* end_date;
3994 };
3995 
3996 
3997 /** @brief This class is the default implementation of the abstract
3998  * Resource class.
3999  */
4001 {
4002  public:
4003  explicit ResourceDefault(const string& str) : Resource(str) {initType(metadata);}
4004  virtual const MetaClass& getType() const {return *metadata;}
4006  virtual size_t getSize() const
4007  {return sizeof(ResourceDefault) + Resource::extrasize();}
4008  static int initialize();
4009 };
4010 
4011 
4012 /** @brief This class represents a resource that'll never have any
4013  * capacity shortage. */
4015 {
4016  public:
4017  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
4018  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
4019  virtual const MetaClass& getType() const {return *metadata;}
4020  explicit ResourceInfinite(const string& c) : Resource(c)
4021  {setDetectProblems(false); initType(metadata);}
4023  virtual size_t getSize() const
4024  {return sizeof(ResourceInfinite) + Resource::extrasize();}
4025  static int initialize();
4026 };
4027 
4028 
4029 /** @brief This class associates a resource with its skills. */
4030 class ResourceSkill : public Object, public Association<Resource,Skill,ResourceSkill>::Node
4031 {
4032  public:
4033  /** Default constructor. */
4034  explicit ResourceSkill() {initType(metadata);}
4035 
4036  /** Constructor. */
4037  explicit DECLARE_EXPORT ResourceSkill(Skill*, Resource*, int);
4038 
4039  /** Constructor. */
4041 
4042  /** Initialize the class. */
4043  static int initialize();
4044  static void writer(const MetaCategory*, XMLOutput*);
4045  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
4046  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
4047  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
4048  DECLARE_EXPORT PyObject* getattro(const Attribute&);
4049  DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
4050 
4051  /** Returns the resource. */
4052  Resource* getResource() const {return getPtrA();}
4053 
4054  /** Updates the resource. This method can only be called on an instance. */
4055  void setResource(Resource* r) {if (r) setPtrA(r,r->getSkills());}
4056 
4057  /** Returns the skill. */
4058  Skill* getSkill() const {return getPtrB();}
4059 
4060  virtual const MetaClass& getType() const {return *metadata;}
4062  virtual size_t getSize() const {return sizeof(ResourceSkill);}
4063 
4064  /** Updates the skill. This method can only be called on an instance. */
4065  void setSkill(Skill* s) {if (s) setPtrB(s,s->getResources());}
4066 
4067  private:
4068  /** Factory method. */
4069  static PyObject* create(PyTypeObject*, PyObject*, PyObject*);
4070 
4071  /** This method is called to check the validity of the object.<br>
4072  * An exception is thrown if the resourceskill is invalid.
4073  */
4074  DECLARE_EXPORT void validate(Action action);
4075 };
4076 
4077 
4078 /** @brief This class links a resource to a certain operation. */
4079 class Load
4080  : public Object, public Association<Operation,Resource,Load>::Node,
4081  public Solvable
4082 {
4083  friend class Resource;
4084  friend class Operation;
4085 
4086  public:
4087  /** Constructor. */
4088  explicit Load(Operation* o, Resource* r, double u)
4089  : hasAlts(false), altLoad(NULL), search(PRIORITY), skill(NULL)
4090  {
4091  setOperation(o);
4092  setResource(r);
4093  setQuantity(u);
4094  initType(metadata);
4095  try { validate(ADD); }
4096  catch (...)
4097  {
4098  if (getOperation()) getOperation()->loaddata.erase(this);
4099  if (getResource()) getResource()->loads.erase(this);
4100  resetReferenceCount();
4101  throw;
4102  }
4103  }
4104 
4105  /** Constructor. */
4106  explicit Load(Operation* o, Resource* r, double u, DateRange e)
4107  : hasAlts(false), altLoad(NULL), search(PRIORITY), skill(NULL)
4108  {
4109  setOperation(o);
4110  setResource(r);
4111  setQuantity(u);
4112  setEffective(e);
4113  initType(metadata);
4114  try { validate(ADD); }
4115  catch (...)
4116  {
4117  if (getOperation()) getOperation()->loaddata.erase(this);
4118  if (getResource()) getResource()->loads.erase(this);
4119  resetReferenceCount();
4120  throw;
4121  }
4122  }
4123 
4124  /** Destructor. */
4125  DECLARE_EXPORT ~Load();
4126 
4127  /** Returns the operation consuming the resource capacity. */
4128  Operation* getOperation() const {return getPtrA();}
4129 
4130  /** Updates the operation being loaded. This method can only be called
4131  * once for a load. */
4132  void setOperation(Operation* o) {if (o) setPtrA(o,o->getLoads());}
4133 
4134  /** Returns the capacity resource being consumed. */
4135  Resource* getResource() const {return getPtrB();}
4136 
4137  /** Updates the capacity being consumed. This method can only be called
4138  * once on a resource. */
4139  void setResource(Resource* r) {if (r) setPtrB(r,r->getLoads());}
4140 
4141  /** Returns how much capacity is consumed during the duration of the
4142  * operationplan. */
4143  double getQuantity() const {return qty;}
4144 
4145  /** Updates the quantity of the load.
4146  * @exception DataException When a negative number is passed.
4147  */
4148  void setQuantity(double f)
4149  {
4150  if (f < 0) throw DataException("Load quantity can't be negative");
4151  qty = f;
4152  }
4153 
4154  /** Returns true if there are alternates for this load. */
4155  bool hasAlternates() const {return hasAlts;}
4156 
4157  /** Returns the load of which this one is an alternate.<br>
4158  * NULL is return where there is none.
4159  */
4160  Load* getAlternate() const {return altLoad;}
4161 
4162  /** Define the load of which this one is an alternate. */
4163  DECLARE_EXPORT void setAlternate(Load *);
4164 
4165  /** Define the load of which this one is an alternate. */
4166  DECLARE_EXPORT void setAlternate(const string& n);
4167 
4168  /** Update the required resource setup. */
4169  DECLARE_EXPORT void setSetup(const string);
4170 
4171  /** Return the required resource setup. */
4172  const string& getSetup() const {return setup;}
4173 
4174  /** Update the required skill. */
4175  void setSkill(Skill* s) {skill = s;}
4176 
4177  /** Return the required skill. */
4178  Skill* getSkill() const {return skill;}
4179 
4180  /** This method holds the logic the compute the date of a loadplan. */
4181  virtual Date getLoadplanDate(const LoadPlan*) const;
4182 
4183  /** This method holds the logic the compute the quantity of a loadplan. */
4184  virtual double getLoadplanQuantity(const LoadPlan*) const;
4185 
4186  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
4187  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
4188  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
4189  DECLARE_EXPORT PyObject* getattro(const Attribute&);
4190  DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
4191  static int initialize();
4192  static void writer(const MetaCategory*, XMLOutput*);
4193 
4194  bool getHidden() const
4195  {
4196  return (getResource() && getResource()->getHidden())
4197  || (getOperation() && getOperation()->getHidden());
4198  }
4199  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
4200 
4201  virtual const MetaClass& getType() const {return *metadata;}
4203  virtual size_t getSize() const
4204  {return sizeof(Load) + getName().size() + getSetup().size();}
4205 
4206  /** Default constructor. */
4207  Load() : qty(1.0), hasAlts(false), altLoad(NULL),
4208  search(PRIORITY), skill(NULL) {initType(metadata);}
4209 
4210  /** Return the search mode. */
4211  SearchMode getSearch() const {return search;}
4212 
4213  /** Update the search mode. */
4214  void setSearch(const string a) {search = decodeSearchMode(a);}
4215 
4216  private:
4217  /** This method is called to check the validity of the object.<br>
4218  * An exception is thrown if the load is invalid.
4219  */
4220  DECLARE_EXPORT void validate(Action action);
4221 
4222  /** Stores how much capacity is consumed during the duration of an
4223  * operationplan. */
4224  double qty;
4225 
4226  /** Flag that is set to true when a load has alternates. */
4227  bool hasAlts;
4228 
4229  /** A load representing the main load of a set of alternates. */
4230  Load* altLoad;
4231 
4232  /** Required setup. */
4233  string setup;
4234 
4235  /** Mode to select the preferred alternates. */
4236  SearchMode search;
4237 
4238  /** Required skill. */
4239  Skill* skill;
4240 
4241  /** Factory method. */
4242  static PyObject* create(PyTypeObject*, PyObject*, PyObject*);
4243 };
4244 
4245 
4246 
4247 /** @brief This is the (logical) top class of the complete model.
4248  *
4249  * This is a singleton class: only a single instance can be created.
4250  * The data model has other limitations that make it not obvious to support
4251  * building multiple models/plans in memory of the same application: e.g.
4252  * the operations, resources, problems, operationplans... etc are all
4253  * implemented in static, global lists. An entity can't be simply linked with
4254  * a particular plan if multiple ones would exist.
4255  */
4256 class Plan : public Plannable, public Object
4257 {
4258  private:
4259  /** Current Date of this plan. */
4260  Date cur_Date;
4261 
4262  /** A name for this plan. */
4263  string name;
4264 
4265  /** A getDescription of this plan. */
4266  string descr;
4267 
4268  /** Pointer to the singleton plan object. */
4269  static DECLARE_EXPORT Plan* thePlan;
4270 
4271  /** The only constructor of this class is made private. An object of this
4272  * class is created by the instance() member function.
4273  */
4274  Plan() : cur_Date(Date::now()) {initType(metadata);}
4275 
4276  public:
4277  /** Return a pointer to the singleton plan object.
4278  * The singleton object is created during the initialization of the
4279  * library.
4280  */
4281  static Plan& instance() {return *thePlan;}
4282 
4283  /** Destructor.
4284  * @warning In multi threaded applications, the destructor is never called
4285  * and the plan object leaks when we exit the application.
4286  * In single-threaded applications this function is called properly, when
4287  * the static plan variable is deleted.
4288  */
4289  DECLARE_EXPORT ~Plan();
4290 
4291  /** Returns the plan name. */
4292  const string& getName() const {return name;}
4293 
4294  /** Updates the plan name. */
4295  void setName(const string& s) {name = s;}
4296 
4297  /** Returns the current Date of the plan. */
4298  const Date & getCurrent() const {return cur_Date;}
4299 
4300  /** Updates the current date of the plan. This method can be relatively
4301  * heavy in a plan where operationplans already exist, since the
4302  * detection for BeforeCurrent problems needs to be rerun.
4303  */
4304  DECLARE_EXPORT void setCurrent(Date);
4305 
4306  /** Returns the description of the plan. */
4307  const string& getDescription() const {return descr;}
4308 
4309  /** Updates the description of the plan. */
4310  void setDescription(const string& str) {descr = str;}
4311 
4312  /** This method writes out the model information. Depending on a flag in
4313  * the XMLOutput object a complete model is written, or only the
4314  * dynamic plan information.
4315  */
4316  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
4317  DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
4318  DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
4319  DECLARE_EXPORT PyObject* getattro(const Attribute&);
4320  DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
4321 
4322  /** Initialize the class. */
4323  static int initialize();
4324 
4325  virtual void updateProblems() {};
4326 
4327  /** This method basically solves the whole planning problem. */
4328  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
4329 
4330  const MetaClass& getType() const {return *metadata;}
4332  virtual size_t getSize() const
4333  {return sizeof(Plan) + name.size() + descr.size();}
4334 };
4335 
4336 
4337 /** @brief Represents the (independent) demand in the system. It can represent a
4338  * customer order or a forecast.
4339  *
4340  * This is an abstract class.
4341  */
4342 class Demand
4343  : public HasHierarchy<Demand>, public Plannable, public HasDescription
4344 {
4345  public:
4346  typedef slist<OperationPlan*> OperationPlan_list;
4347 
4348  /** Constructor. */
4349  explicit Demand(const string& str) : HasHierarchy<Demand>(str),
4350  it(NULL), oper(NULL), cust(NULL), qty(0.0), prio(0),
4351  maxLateness(TimePeriod::MAX), minShipment(1), hidden(false) {}
4352 
4353  /** Destructor. Deleting the demand will also delete all delivery operation
4354  * plans (including locked ones). */
4355  virtual ~Demand()
4356  {
4357  deleteOperationPlans(true);
4358  }
4359 
4360  /** Returns the quantity of the demand. */
4361  double getQuantity() const {return qty;}
4362 
4363  /** Updates the quantity of the demand. The quantity must be be greater
4364  * than or equal to 0. */
4365  virtual DECLARE_EXPORT void setQuantity(double);
4366 
4367  /** Returns the priority of the demand.<br>
4368  * Lower numbers indicate a higher priority level.
4369  */
4370  int getPriority() const {return prio;}
4371 
4372  /** Updates the due date of the demand.<br>
4373  * Lower numbers indicate a higher priority level.
4374  */
4375  virtual void setPriority(int i) {prio=i; setChanged();}
4376 
4377  /** Returns the item/product being requested. */
4378  Item* getItem() const {return it;}
4379 
4380  /** Updates the item/product being requested. */
4381  virtual void setItem(Item *i) {it=i; setChanged();}
4382 
4383  /** This fields points to an operation that is to be used to plan the
4384  * demand. By default, the field is left to NULL and the demand will then
4385  * be planned using the delivery operation of its item.
4386  * @see Item::getDelivery()
4387  */
4388  Operation* getOperation() const {return oper;}
4389 
4390  /** This function returns the operation that is to be used to satisfy this
4391  * demand. In sequence of priority this goes as follows:
4392  * 1) If the "operation" field on the demand is set, use it.
4393  * 2) Otherwise, use the "delivery" field of the requested item.
4394  * 3) Else, return NULL. This demand can't be satisfied!
4395  */
4396  DECLARE_EXPORT Operation* getDeliveryOperation() const;
4397 
4398  /** Returns the cluster which this demand belongs to. */
4399  int getCluster() const
4400  {
4401  Operation* o = getDeliveryOperation();
4402  return o ? o->getCluster() : 0;
4403  }
4404 
4405  /** Updates the operation being used to plan the demand. */
4406  virtual void setOperation(Operation* o) {oper=o; setChanged();}
4407 
4408  /** Returns the delivery operationplan list. */
4409  DECLARE_EXPORT const OperationPlan_list& getDelivery() const;
4410 
4411  /** Returns the latest delivery operationplan. */
4412  DECLARE_EXPORT OperationPlan* getLatestDelivery() const;
4413 
4414  /** Returns the earliest delivery operationplan. */
4415  DECLARE_EXPORT OperationPlan* getEarliestDelivery() const;
4416 
4417  /** Adds a delivery operationplan for this demand. */
4418  DECLARE_EXPORT void addDelivery(OperationPlan *o);
4419 
4420  /** Removes a delivery operationplan for this demand. */
4421  DECLARE_EXPORT void removeDelivery(OperationPlan *o);
4422 
4423  /** Deletes all delivery operationplans of this demand.<br>
4424  * The (optional) boolean parameter controls whether we delete also locked
4425  * operationplans or not.<br>
4426  * The second (optional) argument is a command list that can be used to
4427  * remove the operationplans in an undo-able way.
4428  */
4429  DECLARE_EXPORT void deleteOperationPlans
4430  (bool deleteLockedOpplans = false, CommandManager* = NULL);
4431 
4432  /** Returns the due date of the demand. */
4433  const Date& getDue() const {return dueDate;}
4434 
4435  /** Updates the due date of the demand. */
4436  virtual void setDue(Date d) {dueDate = d; setChanged();}
4437 
4438  /** Returns the customer. */
4439  Customer* getCustomer() const {return cust;}
4440 
4441  /** Updates the customer. */
4442  virtual void setCustomer(Customer* c) {cust = c; setChanged();}
4443 
4444  /** Return a reference to the constraint list. */
4445  const Problem::List& getConstraints() const {return constraints;}
4446 
4447  /** Return a reference to the constraint list. */
4448  Problem::List& getConstraints() {return constraints;}
4449 
4450  /** Returns the total amount that has been planned. */
4451  DECLARE_EXPORT double getPlannedQuantity() const;
4452 
4453  virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
4454  virtual DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
4455  virtual DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
4456  virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
4457  virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
4458  static int initialize();
4459 
4460  size_t extrasize() const
4461  {
4462  return getName().size() + HasDescription::extrasize()
4463  + sizeof(void*) * 2 * deli.size();
4464  }
4465 
4466  virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
4467 
4468  /** Return the maximum delay allowed in satisfying this demand.<br>
4469  * The default value is infinite.
4470  */
4471  TimePeriod getMaxLateness() const {return maxLateness;}
4472 
4473  /** Updates the maximum allowed lateness for this demand.<br>
4474  * The default value is infinite.<br>
4475  * The argument must be a positive time period.
4476  */
4477  virtual void setMaxLateness(TimePeriod m)
4478  {
4479  if (m < 0L)
4480  throw DataException("The maximum demand lateness must be positive");
4481  maxLateness = m;
4482  }
4483 
4484  /** Return the minimum shipment quantity allowed in satisfying this
4485  * demand.<br>
4486  * The default value is 1.
4487  */
4488  double getMinShipment() const {return minShipment;}
4489 
4490  /** Updates the maximum allowed lateness for this demand.<br>
4491  * The default value is infinite.<br>
4492  * The argument must be a positive time period.
4493  */
4494  virtual void setMinShipment(double m)
4495  {
4496  if (m < 0.0)
4497  throw DataException("The minumum demand shipment quantity must be positive");
4498  minShipment = m;
4499  }
4500 
4501  /** Recompute the problems. */
4502  virtual DECLARE_EXPORT void updateProblems();
4503 
4504  /** Specifies whether of not this demand is to be hidden from
4505  * serialization. The default value is false. */
4506  void setHidden(bool b) {hidden = b;}
4507 
4508  /** Returns true if this demand is to be hidden from serialization. */
4509  bool getHidden() const {return hidden;}
4510 
4511  virtual const MetaClass& getType() const {return *metadata;}
4513 
4514  private:
4515  /** Requested item. */
4516  Item *it;
4517 
4518  /** Delivery Operation. Can be left NULL, in which case the delivery
4519  * operation can be specified on the requested item. */
4520  Operation *oper;
4521 
4522  /** Customer creating this demand. */
4523  Customer *cust;
4524 
4525  /** Requested quantity. Only positive numbers are allowed. */
4526  double qty;
4527 
4528  /** Priority. Lower numbers indicate a higher priority level.*/
4529  int prio;
4530 
4531  /** Due date. */
4532  Date dueDate;
4533 
4534  /** Maximum lateness allowed when planning this demand.<br>
4535  * The default value is TimePeriod::MAX.
4536  */
4537  TimePeriod maxLateness;
4538 
4539  /** Minimum size for a delivery operation plan satisfying this demand. */
4540  double minShipment;
4541 
4542  /** Hide this demand or not. */
4543  bool hidden;
4544 
4545  /** A list of operation plans to deliver this demand. */
4546  OperationPlan_list deli;
4547 
4548  /** A list of constraints preventing this demand from being planned in
4549  * full and on time. */
4550  Problem::List constraints;
4551 };
4552 
4553 
4554 /** @brief This class is the default implementation of the abstract
4555  * Demand class. */
4556 class DemandDefault : public Demand
4557 {
4558  public:
4559  explicit DemandDefault(const string& str) : Demand(str) {initType(metadata);}
4560  virtual const MetaClass& getType() const {return *metadata;}
4562  virtual size_t getSize() const
4563  {return sizeof(DemandDefault) + Demand::extrasize();}
4564  static int initialize();
4565 };
4566 
4567 
4568 /** @brief This class represents the resource capacity of an operationplan.
4569  *
4570  * For both the start and the end date of the operationplan, a loadplan
4571  * object is created. These are then inserted in the timeline structure
4572  * associated with a resource.
4573  */
4574 class LoadPlan : public TimeLine<LoadPlan>::EventChangeOnhand, public PythonExtensionBase
4575 {
4577  public:
4578  /** Public constructor.<br>
4579  * This constructor constructs the starting loadplan and will
4580  * also call a private constructor to creates the ending loadplan.
4581  * In other words, a single call to the constructor will create
4582  * two loadplan objects.
4583  */
4584  explicit DECLARE_EXPORT LoadPlan(OperationPlan*, const Load*);
4585 
4586  /** Return the operationplan owning this loadplan. */
4587  OperationPlan* getOperationPlan() const {return oper;}
4588 
4589  /** Return the load of which this is a plan instance. */
4590  const Load* getLoad() const {return ld;}
4591 
4592  /** Update the resource.<br>
4593  * The optional second argument specifies whether or not we need to verify
4594  * if the assigned resource is valid. A valid resource must a) be a
4595  * subresource of the resource specified on the load, and b) must also
4596  * have the skill specified on the resource.
4597  */
4598  DECLARE_EXPORT void setResource(Resource*, bool = false);
4599 
4600  /** Return the resource. */
4601  Resource* getResource() const {return res;}
4602 
4603  /** Update the load of an already existing flowplan.<br>
4604  * The new load must belong to the same operation.
4605  */
4606  DECLARE_EXPORT void setLoad(const Load*);
4607 
4608  /** Return true when this loadplan marks the start of an operationplan. */
4609  bool isStart() const {return start_or_end == START;}
4610 
4611  /** Destructor. */
4612  DECLARE_EXPORT virtual ~LoadPlan();
4613 
4614  /** This function needs to be called whenever the loadplan date or
4615  * quantity are changed.
4616  */
4617  DECLARE_EXPORT void update();
4618 
4619  /** Return a pointer to the timeline data structure owning this loadplan. */
4620  TimeLine<LoadPlan>* getTimeLine() const
4621  {return &(res->loadplans);}
4622 
4623  /** Returns the current setup of the resource.<br>
4624  * When the argument is true (= default) the current setup is returned.<br>
4625  * When the argument is false the setup just before the loadplan is returned.
4626  */
4627  DECLARE_EXPORT const string& getSetup(bool = true) const;
4628 
4629  /** Returns true when the loadplan is hidden.<br>
4630  * This is determined by looking at whether the load is hidden or not.
4631  */
4632  bool getHidden() const {return ld->getHidden();}
4633 
4634  /** Each operationplan has 2 loadplans per load: one at the start,
4635  * when the capacity consumption starts, and one at the end, when the
4636  * capacity consumption ends.<br>
4637  * This method returns the "companion" loadplan. It is not very
4638  * scalable: the performance is linear with the number of loadplans
4639  * on the resource.
4640  */
4641  DECLARE_EXPORT LoadPlan* getOtherLoadPlan() const;
4642 
4643  static int initialize();
4645  PyObject* getattro(const Attribute&);
4646  DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
4647 
4648  private:
4649  /** Private constructor. It is called from the public constructor.<br>
4650  * The public constructor constructs the starting loadplan, while this
4651  * constructor creates the ending loadplan.
4652  */
4654 
4655  /** This type is used to differentiate loadplans aligned with the START date
4656  * or the END date of operationplan. */
4657  enum type {START, END};
4658 
4659  /** Is this loadplan a starting one or an ending one. */
4660  type start_or_end;
4661 
4662  /** A pointer to the load model. */
4663  const Load *ld;
4664 
4665  /** A pointer to the selected resource.<br>
4666  * In case we use skills, the resource of the loadplan can be different
4667  * than the resource on the load.
4668  */
4669  Resource *res;
4670 
4671  /** A pointer to the operationplan owning this loadplan. */
4672  OperationPlan *oper;
4673 
4674  /** Points to the next loadplan owned by the same operationplan. */
4675  LoadPlan *nextLoadPlan;
4676 };
4677 
4678 
4679 inline Date Load::getLoadplanDate(const LoadPlan* lp) const
4680 {
4681  const DateRange & dr = lp->getOperationPlan()->getDates();
4682  if (lp->isStart())
4683  return dr.getStart() > getEffective().getStart() ?
4684  dr.getStart() :
4685  getEffective().getStart();
4686  else
4687  return dr.getEnd() < getEffective().getEnd() ?
4688  dr.getEnd() :
4689  getEffective().getEnd();
4690 }
4691 
4692 
4693 inline double Load::getLoadplanQuantity(const LoadPlan* lp) const
4694 {
4695  if (!lp->getOperationPlan()->getDates().overlap(getEffective())
4696  && (lp->getOperationPlan()->getDates().getDuration()
4697  || !getEffective().within(lp->getOperationPlan()->getDates().getStart())))
4698  // Load is not effective during this time.
4699  // The extra check is required to make sure that zero duration operationplans
4700  // operationplans don't get resized to 0
4701  return 0.0;
4702  return lp->isStart() ? getQuantity() : -getQuantity();
4703 }
4704 
4705 
4706 
4707 /** @brief A problem of this class is created when an operationplan is being
4708  * planned in the past, i.e. it starts before the "current" date of
4709  * the plan.
4710  */
4712 {
4713  public:
4714  string getDescription() const
4715  {
4716  ostringstream ch;
4717  ch << "Operation '"
4718  << (oper ? oper : static_cast<OperationPlan*>(getOwner())->getOperation())
4719  << "' planned in the past";
4720  return ch.str();
4721  }
4722  bool isFeasible() const {return false;}
4723  double getWeight() const
4724  {return oper ? state.quantity : dynamic_cast<OperationPlan*>(getOwner())->getQuantity();}
4725  explicit ProblemBeforeCurrent(OperationPlan* o, bool add = true) : Problem(o), oper(NULL)
4726  {if (add) addProblem();}
4727  explicit ProblemBeforeCurrent(Operation* o, Date st, Date nd, double q)
4728  : oper(o), state(st, nd, q) {}
4729  ~ProblemBeforeCurrent() {removeProblem();}
4730  string getEntity() const {return "operation";}
4731  Object* getOwner() const
4732  {return oper ? static_cast<Object*>(oper) : dynamic_cast<OperationPlan*>(owner);}
4733  const DateRange getDates() const
4734  {
4735  if (oper) return DateRange(state.start, state.end);
4736  OperationPlan *o = dynamic_cast<OperationPlan*>(getOwner());
4737  if (o->getDates().getEnd() > Plan::instance().getCurrent())
4738  return DateRange(o->getDates().getStart(),
4740  else
4741  return DateRange(o->getDates().getStart(),
4742  o->getDates().getEnd());
4743  }
4744  size_t getSize() const {return sizeof(ProblemBeforeCurrent);}
4745 
4746  /** Return a reference to the metadata structure. */
4747  const MetaClass& getType() const {return *metadata;}
4748 
4749  /** Storing metadata on this class. */
4751 
4752  private:
4753  Operation* oper;
4754  OperationPlanState state;
4755 };
4756 
4757 
4758 /** @brief A problem of this class is created when an operationplan is being
4759  * planned before its fence date, i.e. it starts 1) before the "current"
4760  * date of the plan plus the release fence of the operation and 2) after the
4761  * current date of the plan.
4762  */
4764 {
4765  public:
4766  string getDescription() const
4767  {
4768  ostringstream ch;
4769  ch << "Operation '"
4770  << (oper ? oper : static_cast<OperationPlan*>(getOwner())->getOperation())
4771  << "' planned before fence";
4772  return ch.str();
4773  }
4774  bool isFeasible() const {return true;}
4775  double getWeight() const
4776  {return oper ? state.quantity : static_cast<OperationPlan*>(getOwner())->getQuantity();}
4777  explicit ProblemBeforeFence(OperationPlan* o, bool add = true)
4778  : Problem(o), oper(NULL)
4779  {if (add) addProblem();}
4780  explicit ProblemBeforeFence(Operation* o, Date st, Date nd, double q)
4781  : oper(o), state(st, nd, q) {}
4782  ~ProblemBeforeFence() {removeProblem();}
4783  string getEntity() const {return "operation";}
4784  Object* getOwner() const
4785  {return oper ? static_cast<Object*>(oper) : dynamic_cast<OperationPlan*>(owner);}
4786  const DateRange getDates() const
4787  {
4788  if (oper) return DateRange(state.start, state.end);
4789  OperationPlan *o = dynamic_cast<OperationPlan*>(owner);
4790  if (o->getDates().getEnd() > Plan::instance().getCurrent()
4791  + o->getOperation()->getFence())
4792  return DateRange(o->getDates().getStart(),
4794  else
4795  return DateRange(o->getDates().getStart(),
4796  o->getDates().getEnd());
4797  }
4798  size_t getSize() const {return sizeof(ProblemBeforeFence);}
4799 
4800  /** Return a reference to the metadata structure. */
4801  const MetaClass& getType() const {return *metadata;}
4802 
4803  /** Storing metadata on this class. */
4805 
4806  private:
4807  Operation* oper;
4808  OperationPlanState state;
4809 };
4810 
4811 
4812 /** @brief A problem of this class is created when the sequence of two
4813  * operationplans in a routing isn't respected.
4814  */
4816 {
4817  public:
4818  string getDescription() const
4819  {
4820  OperationPlan *o = static_cast<OperationPlan*>(getOwner());
4821  if (!o->nextsubopplan)
4822  return string("Bogus precedence problem on '")
4823  + o->getOperation()->getName() + "'";
4824  else
4825  return string("Operation '") + o->getOperation()->getName()
4826  + "' starts before operation '"
4827  + o->nextsubopplan->getOperation()->getName() +"' ends";
4828  }
4829  bool isFeasible() const {return false;}
4830  /** The weight of the problem is equal to the duration in days. */
4831  double getWeight() const
4832  {
4833  return static_cast<double>(getDates().getDuration()) / 86400;
4834  }
4835  explicit ProblemPrecedence(OperationPlan* o, bool add = true) : Problem(o)
4836  {if (add) addProblem();}
4837  ~ProblemPrecedence() {removeProblem();}
4838  string getEntity() const {return "operation";}
4839  Object* getOwner() const {return dynamic_cast<OperationPlan*>(owner);}
4840  const DateRange getDates() const
4841  {
4842  OperationPlan *o = static_cast<OperationPlan*>(getOwner());
4843  return DateRange(o->nextsubopplan->getDates().getStart(),
4844  o->getDates().getEnd());
4845  }
4846 
4847  /** Return a reference to the metadata structure. */
4848  const MetaClass& getType() const {return *metadata;}
4849 
4850  /** Storing metadata on this class. */
4852  size_t getSize() const {return sizeof(ProblemPrecedence);}
4853 };
4854 
4855 
4856 /** @brief A Problem of this class is created in the model when a new demand is
4857  * brought in the system, but it hasn't been planned yet.
4858  *
4859  * As a special case, a demand with a requested quantity of 0.0 doesn't create
4860  * this type of problem.
4861  */
4863 {
4864  public:
4865  string getDescription() const
4866  {return string("Demand '") + getDemand()->getName() + "' is not planned";}
4867  bool isFeasible() const {return false;}
4868  double getWeight() const {return getDemand()->getQuantity();}
4869  explicit ProblemDemandNotPlanned(Demand* d, bool add = true) : Problem(d)
4870  {if (add) addProblem();}
4871  ~ProblemDemandNotPlanned() {removeProblem();}
4872  string getEntity() const {return "demand";}
4873  const DateRange getDates() const
4874  {return DateRange(getDemand()->getDue(),getDemand()->getDue());}
4875  Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
4876  Demand* getDemand() const {return dynamic_cast<Demand*>(owner);}
4877  size_t getSize() const {return sizeof(ProblemDemandNotPlanned);}
4878 
4879  /** Return a reference to the metadata structure. */
4880  const MetaClass& getType() const {return *metadata;}
4881 
4882  /** Storing metadata on this class. */
4884 };
4885 
4886 
4887 /** @brief A problem of this class is created when a demand is satisfied later
4888  * than the accepted tolerance after its due date.
4889  */
4890 class ProblemLate : public Problem
4891 {
4892  public:
4893  DECLARE_EXPORT string getDescription() const;
4894  bool isFeasible() const {return true;}
4895 
4896  /** The weight is equal to the delay, expressed in days.<br>
4897  * The quantity being delayed is not included.
4898  */
4899  double getWeight() const
4900  {
4901  assert(getDemand() && !getDemand()->getDelivery().empty());
4902  return static_cast<double>(DateRange(
4903  getDemand()->getDue(),
4904  getDemand()->getLatestDelivery()->getDates().getEnd()
4905  ).getDuration()) / 86400;
4906  }
4907 
4908  /** Constructor. */
4909  explicit ProblemLate(Demand* d, bool add = true) : Problem(d)
4910  {if (add) addProblem();}
4911 
4912  /** Destructor. */
4913  ~ProblemLate() {removeProblem();}
4914 
4915  const DateRange getDates() const
4916  {
4917  assert(getDemand() && !getDemand()->getDelivery().empty());
4918  return DateRange(getDemand()->getDue(),
4919  getDemand()->getLatestDelivery()->getDates().getEnd());
4920  }
4921  Demand* getDemand() const {return dynamic_cast<Demand*>(getOwner());}
4922  size_t getSize() const {return sizeof(ProblemLate);}
4923  string getEntity() const {return "demand";}
4924  Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
4925 
4926  /** Return a reference to the metadata structure. */
4927  const MetaClass& getType() const {return *metadata;}
4928 
4929  /** Storing metadata on this class. */
4931 };
4932 
4933 
4934 /** @brief A problem of this class is created when a demand is planned earlier
4935  * than the accepted tolerance before its due date.
4936  */
4937 class ProblemEarly : public Problem
4938 {
4939  public:
4940  DECLARE_EXPORT string getDescription() const;
4941  bool isFeasible() const {return true;}
4942  double getWeight() const
4943  {
4944  assert(getDemand() && !getDemand()->getDelivery().empty());
4945  return static_cast<double>(DateRange(
4946  getDemand()->getDue(),
4947  getDemand()->getEarliestDelivery()->getDates().getEnd()
4948  ).getDuration()) / 86400;
4949  }
4950  explicit ProblemEarly(Demand* d, bool add = true) : Problem(d)
4951  {if (add) addProblem();}
4952  ~ProblemEarly() {removeProblem();}
4953  string getEntity() const {return "demand";}
4954  Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
4955  const DateRange getDates() const
4956  {
4957  assert(getDemand() && !getDemand()->getDelivery().empty());
4958  return DateRange(getDemand()->getDue(),
4959  getDemand()->getEarliestDelivery()->getDates().getEnd());
4960  }
4961  Demand* getDemand() const {return dynamic_cast<Demand*>(getOwner());}
4962  size_t getSize() const {return sizeof(ProblemEarly);}
4963 
4964  /** Return a reference to the metadata structure. */
4965  const MetaClass& getType() const {return *metadata;}
4966 
4967  /** Storing metadata on this class. */
4969 };
4970 
4971 
4972 /** @brief A Problem of this class is created in the model when a data exception
4973  * prevents planning of certain objects
4974  */
4976 {
4977  public:
4978  string getDescription() const {return description;}
4979  bool isFeasible() const {return false;}
4980  double getWeight() const {return qty;}
4981  explicit ProblemInvalidData(HasProblems* o, string d, string e,
4982  Date st, Date nd, double q, bool add = true)
4983  : Problem(o), description(d), entity(e), dates(st,nd), qty(q)
4984  {if (add) addProblem();}
4985  ~ProblemInvalidData() {removeProblem();}
4986  string getEntity() const {return entity;}
4987  const DateRange getDates() const {return dates;}
4988  Object* getOwner() const
4989  {
4990  if (entity == "demand") return dynamic_cast<Demand*>(owner);
4991  if (entity == "buffer") return dynamic_cast<Buffer*>(owner);
4992  if (entity == "resource") return dynamic_cast<Resource*>(owner);
4993  if (entity == "operation") return dynamic_cast<Operation*>(owner);
4994  throw LogicException("Unknown problem entity type");
4995  }
4996  size_t getSize() const
4997  {return sizeof(ProblemInvalidData) + description.size() + entity.size();}
4998 
4999  /** Return a reference to the metadata structure. */
5000  const MetaClass& getType() const {return *metadata;}
5001 
5002  /** Storing metadata on this class. */
5004 
5005  private:
5006  /** Description of the data issue. */
5007  string description;
5008  string entity;
5009  DateRange dates;
5010  double qty;
5011 };
5012 
5013 
5014 /** @brief A problem of this class is created when a demand is planned for less than
5015  * the requested quantity.
5016  */
5017 class ProblemShort : public Problem
5018 {
5019  public:
5020  string getDescription() const
5021  {
5022  ostringstream ch;
5023  ch << "Demand '" << getDemand()->getName() << "' planned "
5024  << (getDemand()->getQuantity() - getDemand()->getPlannedQuantity())
5025  << " units short";
5026  return ch.str();
5027  }
5028  bool isFeasible() const {return true;}
5029  double getWeight() const
5030  {return getDemand()->getQuantity() - getDemand()->getPlannedQuantity();}
5031  explicit ProblemShort(Demand* d, bool add = true) : Problem(d)
5032  {if (add) addProblem();}
5033  ~ProblemShort() {removeProblem();}
5034  string getEntity() const {return "demand";}
5035  const DateRange getDates() const
5036  {return DateRange(getDemand()->getDue(), getDemand()->getDue());}
5037  Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
5038  Demand* getDemand() const {return dynamic_cast<Demand*>(owner);}
5039  size_t getSize() const {return sizeof(ProblemShort);}
5040 
5041  /** Return a reference to the metadata structure. */
5042  const MetaClass& getType() const {return *metadata;}
5043 
5044  /** Storing metadata on this class. */
5046 };
5047 
5048 
5049 /** @brief A problem of this class is created when a demand is planned for more
5050  * than the requested quantity.
5051  */
5052 class ProblemExcess : public Problem
5053 {
5054  public:
5055  string getDescription() const
5056  {
5057  ostringstream ch;
5058  ch << "Demand '" << getDemand()->getName() << "' planned "
5059  << (getDemand()->getPlannedQuantity() - getDemand()->getQuantity())
5060  << " units excess";
5061  return ch.str();
5062  }
5063  bool isFeasible() const {return true;}
5064  double getWeight() const
5065  {return getDemand()->getPlannedQuantity() - getDemand()->getQuantity();}
5066  explicit ProblemExcess(Demand* d, bool add = true) : Problem(d)
5067  {if (add) addProblem();}
5068  string getEntity() const {return "demand";}
5069  Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
5070  ~ProblemExcess() {removeProblem();}
5071  const DateRange getDates() const
5072  {return DateRange(getDemand()->getDue(), getDemand()->getDue());}
5073  Demand* getDemand() const {return dynamic_cast<Demand*>(getOwner());}
5074  size_t getSize() const {return sizeof(ProblemExcess);}
5075 
5076  /** Return a reference to the metadata structure. */
5077  const MetaClass& getType() const {return *metadata;}
5078 
5079  /** Storing metadata on this class. */
5081 };
5082 
5083 
5084 /** @brief A problem of this class is created when a resource is being
5085  * overloaded during a certain period of time.
5086  */
5088 {
5089  public:
5090  DECLARE_EXPORT string getDescription() const;
5091  bool isFeasible() const {return false;}
5092  double getWeight() const {return qty;}
5093  ProblemCapacityOverload(Resource* r, Date st, Date nd, double q, bool add = true)
5094  : Problem(r), qty(q), dr(st,nd) {if (add) addProblem();}
5095  ~ProblemCapacityOverload() {removeProblem();}
5096  string getEntity() const {return "capacity";}
5097  Object* getOwner() const {return dynamic_cast<Resource*>(owner);}
5098  const DateRange getDates() const {return dr;}
5099  Resource* getResource() const {return dynamic_cast<Resource*>(getOwner());}
5100  size_t getSize() const {return sizeof(ProblemCapacityOverload);}
5101 
5102  /** Return a reference to the metadata structure. */
5103  const MetaClass& getType() const {return *metadata;}
5104 
5105  /** Storing metadata on this class. */
5107 
5108  private:
5109  /** Overload quantity. */
5110  double qty;
5111 
5112  /** The daterange of the problem. */
5113  DateRange dr;
5114 };
5115 
5116 
5117 /** @brief A problem of this class is created when a resource is loaded below
5118  * its minimum during a certain period of time.
5119  */
5121 {
5122  public:
5123  DECLARE_EXPORT string getDescription() const;
5124  bool isFeasible() const {return true;}
5125  double getWeight() const {return qty;}
5126  ProblemCapacityUnderload(Resource* r, DateRange d, double q, bool add = true)
5127  : Problem(r), qty(q), dr(d) {if (add) addProblem();}
5128  ~ProblemCapacityUnderload() {removeProblem();}
5129  string getEntity() const {return "capacity";}
5130  Object* getOwner() const {return dynamic_cast<Resource*>(owner);}
5131  const DateRange getDates() const {return dr;}
5132  Resource* getResource() const {return dynamic_cast<Resource*>(getOwner());}
5133  size_t getSize() const {return sizeof(ProblemCapacityUnderload);}
5134 
5135  /** Return a reference to the metadata structure. */
5136  const MetaClass& getType() const {return *metadata;}
5137 
5138  /** Storing metadata on this class. */
5140 
5141  private:
5142  /** Underload quantity. */
5143  double qty;
5144 
5145  /** The daterange of the problem. */
5146  DateRange dr;
5147 };
5148 
5149 
5150 /** @brief A problem of this class is created when a buffer is having a
5151  * material shortage during a certain period of time.
5152  */
5154 {
5155  public:
5156  DECLARE_EXPORT string getDescription() const;
5157  bool isFeasible() const {return false;}
5158  double getWeight() const {return qty;}
5159  ProblemMaterialShortage(Buffer* b, Date st, Date nd, double q, bool add = true)
5160  : Problem(b), qty(q), dr(st,nd) {if (add) addProblem();}
5161  string getEntity() const {return "material";}
5162  Object* getOwner() const {return dynamic_cast<Buffer*>(owner);}
5163  ~ProblemMaterialShortage() {removeProblem();}
5164  const DateRange getDates() const {return dr;}
5165  Buffer* getBuffer() const {return dynamic_cast<Buffer*>(getOwner());}
5166  size_t getSize() const {return sizeof(ProblemMaterialShortage);}
5167 
5168  /** Return a reference to the metadata structure. */
5169  const MetaClass& getType() const {return *metadata;}
5170 
5171  /** Storing metadata on this class. */
5173 
5174  private:
5175  /** Shortage quantity. */
5176  double qty;
5177 
5178  /** The daterange of the problem. */
5179  DateRange dr;
5180 };
5181 
5182 
5183 /** @brief A problem of this class is created when a buffer is carrying too
5184  * much material during a certain period of time.
5185  */
5187 {
5188  public:
5189  DECLARE_EXPORT string getDescription() const;
5190  bool isFeasible() const {return true;}
5191  double getWeight() const {return qty;}
5192  ProblemMaterialExcess(Buffer* b, Date st, Date nd, double q, bool add = true)
5193  : Problem(b), qty(q), dr(st,nd) {if (add) addProblem();}
5194  string getEntity() const {return "material";}
5195  ~ProblemMaterialExcess() {removeProblem();}
5196  const DateRange getDates() const {return dr;}
5197  Object* getOwner() const {return dynamic_cast<Buffer*>(owner);}
5198  Buffer* getBuffer() const {return dynamic_cast<Buffer*>(owner);}
5199  size_t getSize() const {return sizeof(ProblemMaterialExcess);}
5200 
5201  /** Return a reference to the metadata structure. */
5202  const MetaClass& getType() const {return *metadata;}
5203 
5204  /** Storing metadata on this class. */
5206 
5207  private:
5208  /** Excess quantity. */
5209  double qty;
5210 
5211  /** The daterange of the problem. */
5212  DateRange dr;
5213 };
5214 
5215 
5216 /** @brief This command is used to create an operationplan.
5217  *
5218  * The operationplan will have its loadplans and flowplans created when the
5219  * command is created. It is assigned an id and added to the list of all
5220  * operationplans when the command is committed.
5221  */
5223 {
5224  public:
5225  /** Constructor. */
5227  (const Operation* o, double q, Date d1, Date d2, Demand* l,
5228  OperationPlan* ow=NULL, bool makeflowsloads=true)
5229  {
5230  opplan = o ?
5231  o->createOperationPlan(q, d1, d2, l, ow, 0, makeflowsloads)
5232  : NULL;
5233  }
5234  void commit()
5235  {
5236  if (opplan)
5237  {
5238  opplan->activate();
5239  opplan = NULL; // Avoid executing / initializing more than once
5240  }
5241  }
5242  virtual void rollback() {delete opplan; opplan = NULL;}
5243  virtual void undo() {if (opplan) opplan->deleteFlowLoads();}
5244  virtual void redo() {if (opplan) opplan->createFlowLoads();}
5245  virtual ~CommandCreateOperationPlan() {if (opplan) delete opplan;}
5246  OperationPlan *getOperationPlan() const {return opplan;}
5247 
5248  private:
5249  /** Pointer to the newly created operationplan. */
5250  OperationPlan *opplan;
5251 };
5252 
5253 
5254 /** @brief This command is used to delete an operationplan. */
5256 {
5257  public:
5258  /** Constructor. */
5260  virtual void commit()
5261  {
5262  if (opplan) delete opplan;
5263  opplan = NULL;
5264  }
5265  virtual void undo()
5266  {
5267  if (!opplan) return;
5268  opplan->createFlowLoads();
5269  if (opplan->getIdentifier())
5270  {
5271  opplan->insertInOperationplanList();
5272  if (opplan->getDemand())
5273  opplan->getDemand()->addDelivery(opplan);
5274  }
5275  }
5276  virtual void redo()
5277  {
5278  if (!opplan) return;
5279  opplan->deleteFlowLoads();
5280  if (opplan->getIdentifier())
5281  {
5282  opplan->removeFromOperationplanList();
5283  if (opplan->getDemand())
5284  opplan->getDemand()->removeDelivery(opplan);
5285  }
5286  }
5287  virtual void rollback()
5288  {
5289  undo();
5290  opplan = NULL;
5291  }
5292  virtual ~CommandDeleteOperationPlan() {undo();}
5293 
5294  private:
5295  /** Pointer to the operationplan being deleted.<br>
5296  * Until the command is committed we don't deallocate the memory for the
5297  * operationplan, but only remove all pointers to it from various places.
5298  */
5299  OperationPlan *opplan;
5300 };
5301 
5302 
5303 /** @brief This class represents the command of moving an operationplan to a
5304  * new date and/or resizing it.
5305  * @todo Moving in a routing operation can't be undone with the current
5306  * implementation! The command will need to store all original dates of
5307  * the suboperationplans...
5308  */
5310 {
5311  public:
5312  /** Constructor.<br>
5313  * Unlike most other commands the constructor already executes the change.
5314  * @param opplanptr Pointer to the operationplan being moved.
5315  * @param newStart New start date of the operationplan.
5316  * @param newEnd New end date of the operationplan.
5317  * @param newQty New quantity of the operationplan.The default is -1,
5318  * which indicates to leave the quantity unchanged.
5319  */
5321  Date newStart, Date newEnd, double newQty = -1.0);
5322 
5323  /** Default constructor. */
5324  DECLARE_EXPORT CommandMoveOperationPlan(OperationPlan*);
5325 
5326  /** Commit the changes. */
5327  virtual void commit() {opplan=NULL;}
5328 
5329  /** Undo the changes. */
5330  virtual void rollback() {restore(true); opplan = NULL;}
5331 
5332  virtual void undo() {restore(false);}
5333  virtual DECLARE_EXPORT void redo();
5334 
5335  /** Undo the changes.<br>
5336  * When the argument is true, subcommands for suboperationplans are deleted. */
5337  DECLARE_EXPORT void restore(bool = false);
5338 
5339  /** Destructor. */
5340  virtual ~CommandMoveOperationPlan() {if (opplan) rollback();}
5341 
5342  /** Returns the operationplan being manipulated. */
5343  OperationPlan* getOperationPlan() const {return opplan;}
5344 
5345  /** Set another start date for the operationplan. */
5346  void setStart(Date d) {if (opplan) opplan->setStart(d);}
5347 
5348  /** Set another start date, end date and quantity for the operationplan. */
5349  void setParameters(Date s, Date e, double q, bool b)
5350  {
5351  assert(opplan->getOperation());
5352  if (opplan)
5353  opplan->getOperation()->setOperationPlanParameters(opplan, q, s, e, b);
5354  }
5355 
5356  /** Set another start date for the operationplan. */
5357  void setEnd(Date d) {if (opplan) opplan->setEnd(d);}
5358 
5359  /** Set another quantity for the operationplan. */
5360  void setQuantity(double q) {if (opplan) opplan->setQuantity(q);}
5361 
5362  /** Return the quantity of the original operationplan. */
5363  double getQuantity() const {return originalqty; }
5364 
5365  /** Return the dates of the original operationplan. */
5366  DateRange getDates() const {return originaldates;}
5367 
5368  private:
5369  /** This is a pointer to the operationplan being moved. */
5370  OperationPlan *opplan;
5371 
5372  /** These are the original dates of the operationplan before its move. */
5373  DateRange originaldates;
5374 
5375  /** This is the quantity of the operationplan before the command. */
5376  double originalqty;
5377 
5378  /** A pointer to a list of suboperationplan commands. */
5379  Command* firstCommand;
5380 };
5381 
5382 
5383 /** @brief This class models a iterator that walks over all available
5384  * HasProblem entities.
5385  *
5386  * This list is containing hard-coding the classes that are implementing
5387  * this class. It's not ideal, but we don't have an explicit container
5388  * of the objects (and we don't want one either) and this allows us also
5389  * to re-use the sorting used for the container classes.
5390  */
5392 {
5393  private:
5394  /** This union contains iterators through the different entity types.
5395  * Only one of the different iterators will be active at a time, and
5396  * can thus save memory by collapsing the iterators into a single
5397  * union. */
5398  union
5399  {
5400  Buffer::iterator *bufIter;
5401  Resource::iterator *resIter;
5403  Demand::iterator *demIter;
5404  };
5405 
5406  /** This type indicates which type of entity we are currently recursing
5407  * through.
5408  * - 0: buffers
5409  * - 1: resources
5410  * - 2: operationplans
5411  * - 3: demands
5412  */
5413  unsigned short type;
5414 
5415  public:
5416  /** Default constructor, which creates an iterator to the first
5417  * HasProblems object. */
5418  explicit DECLARE_EXPORT EntityIterator();
5419 
5420  /** Used to create an iterator pointing beyond the last HasProblems
5421  * object. */
5422  explicit EntityIterator(unsigned short i) : type(i) {}
5423 
5424  /** Copy constructor. */
5426 
5427  /** Assignment operator. */
5428  DECLARE_EXPORT EntityIterator& operator=(const EntityIterator& o);
5429 
5430  /** Destructor. */
5432 
5433  /** Pre-increment operator. */
5434  DECLARE_EXPORT EntityIterator& operator++();
5435 
5436  /** Inequality operator.<br>
5437  * Two iterators are different when they point to different objects.
5438  */
5439  DECLARE_EXPORT bool operator != (const EntityIterator& t) const;
5440 
5441  /** Equality operator.<br>
5442  * Two iterators are equal when they point to the same object.
5443  */
5444  bool operator == (const EntityIterator& t) const {return !(*this != t);}
5445 
5446  /** Dereference operator. */
5447  DECLARE_EXPORT HasProblems& operator*() const;
5448 
5449  /** Dereference operator. */
5450  DECLARE_EXPORT HasProblems* operator->() const;
5451 };
5452 
5453 
5454 /** @brief This class models an STL-like iterator that allows us to iterate
5455  * over the named entities in a simple and safe way.
5456  *
5457  * Objects of this class are returned by the begin() and end() functions.
5458  * @see Problem::begin()
5459  * @see Problem::begin(HasProblem*)
5460  * @see Problem::end()
5461  */
5463 {
5464  friend class Problem;
5465  private:
5466  /** A pointer to the current problem. If this pointer is NULL, we are
5467  * at the end of the list. */
5468  Problem* iter;
5469  HasProblems* owner;
5471 
5472  public:
5473  /** Creates an iterator that will loop through the problems of a
5474  * single entity only. <BR>
5475  * This constructor is also used to create a end-iterator, when passed
5476  * a NULL pointer as argument.
5477  */
5478  explicit const_iterator(HasProblems* o) : iter(o ? o->firstProblem : NULL),
5479  owner(o), eiter(4) {}
5480 
5481  /** Creates an iterator that will loop through the constraints of
5482  * a demand.
5483  */
5484  explicit const_iterator(Problem* o) : iter(o),
5485  owner(NULL), eiter(4) {}
5486 
5487  /** Creates an iterator that will loop through the problems of all
5488  * entities. */
5489  explicit const_iterator() : owner(NULL)
5490  {
5491  // Loop till we find an entity with a problem
5492  while (eiter!=HasProblems::endEntity() && !(eiter->firstProblem))
5493  ++eiter;
5494  // Found a first problem, or no problem at all
5495  iter = (eiter!=HasProblems::endEntity()) ? eiter->firstProblem : NULL;
5496  }
5497 
5498  /** Pre-increment operator. */
5499  DECLARE_EXPORT const_iterator& operator++();
5500 
5501  /** Inequality operator. */
5502  bool operator != (const const_iterator& t) const {return iter!=t.iter;}
5503 
5504  /** Equality operator. */
5505  bool operator == (const const_iterator& t) const {return iter==t.iter;}
5506 
5507  Problem& operator*() const {return *iter;}
5508  Problem* operator->() const {return iter;}
5509 };
5510 
5511 
5512 /** Retrieve an iterator for the list. */
5514 {return Problem::const_iterator(first);}
5515 
5516 
5517 /** Stop iterator. */
5519 {return Problem::const_iterator(static_cast<Problem*>(NULL));}
5520 
5521 
5522 /** @brief This class allows upstream and downstream navigation through
5523  * the plan.
5524  *
5525  * Downstream navigation follows the material flow from raw materials
5526  * towards the produced end item.<br>
5527  * Upstream navigation traces back the material flow from the end item up to
5528  * the consumed raw materials.<br>
5529  * The class is implemented as an STL-like iterator.
5530  *
5531  * @todo operationplans without flowplans are skipped by the iterator - not correct!
5532  */
5533 class PeggingIterator : public Object
5534 {
5535  public:
5536  /** Constructor. */
5538 
5539  /** Constructor. */
5540  PeggingIterator(const FlowPlan* e, bool b = true)
5541  : downstream(b), firstIteration(true)
5542  {
5543  if (!e) return;
5544  if (downstream)
5545  states.push(state(0,abs(e->getQuantity()),1.0,e,NULL));
5546  else
5547  states.push(state(0,abs(e->getQuantity()),1.0,NULL,e));
5548  initType(metadata);
5549  }
5550 
5551  /** Return the operationplan consuming the material. */
5552  OperationPlan* getConsumingOperationplan() const
5553  {
5554  const FlowPlan* x = states.top().cons_flowplan;
5555  return x ? x->getOperationPlan() : NULL;
5556  }
5557 
5558  /** Return the material buffer through which we are pegging. */
5559  Buffer *getBuffer() const
5560  {
5561  const FlowPlan* x = states.top().prod_flowplan;
5562  if (!x) x = states.top().cons_flowplan;
5563  return x ? x->getFlow()->getBuffer() : NULL;
5564  }
5565 
5566  /** Return the operationplan producing the material. */
5567  OperationPlan* getProducingOperationplan() const
5568  {
5569  const FlowPlan* x = states.top().prod_flowplan;
5570  return x ? x->getOperationPlan() : NULL;
5571  }
5572 
5573  /** Return the date when the material is consumed. */
5574  Date getConsumingDate() const
5575  {
5576  const FlowPlan* x = states.top().cons_flowplan;
5577  return x ? x->getDate() : Date::infinitePast;
5578  }
5579 
5580  /** Return the date when the material is produced. */
5581  Date getProducingDate() const
5582  {
5583  const FlowPlan* x = states.top().prod_flowplan;
5584  return x ? x->getDate() : Date::infinitePast;
5585  }
5586 
5587  /** Returns the recursion depth of the iterator.<br>
5588  * The original flowplan is at level 0, and each level (either upstream
5589  * or downstream) increments the value by 1.
5590  */
5591  short getLevel() const {return states.top().level;}
5592 
5593  /** Returns the quantity of the demand that is linked to this pegging
5594  * record.
5595  */
5596  double getQuantityDemand() const {return states.top().qty;}
5597 
5598  /** Returns the quantity of the buffer flowplans that is linked to this
5599  * pegging record.
5600  */
5601  double getQuantityBuffer() const
5602  {
5603  const state& t = states.top();
5604  return t.prod_flowplan
5605  ? t.factor * t.prod_flowplan->getOperationPlan()->getQuantity()
5606  : 0;
5607  }
5608 
5609  /** Returns which portion of the current flowplan is fed/supplied by the
5610  * original flowplan. */
5611  double getFactor() const {return states.top().factor;}
5612 
5613  /** Returns false if the flowplan remained unpegged, i.e. it wasn't
5614  * -either completely or paritally- unconsumed at the next level.
5615  */
5616  bool getPegged() const {return states.top().pegged;}
5617 
5618  /** Move the iterator foward to the next downstream flowplan. */
5619  DECLARE_EXPORT PeggingIterator& operator++();
5620 
5621  /** Move the iterator foward to the next downstream flowplan.<br>
5622  * This post-increment operator is less efficient than the pre-increment
5623  * operator.
5624  */
5625  PeggingIterator operator++(int)
5626  {PeggingIterator tmp = *this; ++*this; return tmp;}
5627 
5628  /** Move the iterator foward to the next upstream flowplan. */
5629  DECLARE_EXPORT PeggingIterator& operator--();
5630 
5631  /** Move the iterator foward to the next upstream flowplan.<br>
5632  * This post-increment operator is less efficient than the pre-decrement
5633  * operator.
5634  */
5635  PeggingIterator operator--(int)
5636  {PeggingIterator tmp = *this; --*this; return tmp;}
5637 
5638  /** Comparison operator. */
5639  bool operator==(const PeggingIterator& x) const {return states == x.states;}
5640 
5641  /** Inequality operator. */
5642  bool operator!=(const PeggingIterator& x) const {return states != x.states;}
5643 
5644  /** Conversion operator to a boolean value.
5645  * The return value is true when the iterator still has next elements to
5646  * explore. Returns false when the iteration is finished.
5647  */
5648  operator bool () const {return !states.empty();}
5649 
5650  /** Update the stack. */
5651  DECLARE_EXPORT void updateStack(short, double, double, const FlowPlan*, const FlowPlan*, bool = true);
5652 
5653  /** Returns true if this is a downstream iterator. */
5654  bool isDownstream() {return downstream;}
5655 
5656  /** Initialize the class. */
5657  static int initialize();
5658 
5659  virtual void endElement(XMLInput& i, const Attribute& a, const DataElement& d)
5660  {
5661  throw LogicException("Pegging can't be read");
5662  }
5663  virtual const MetaClass& getType() const {return *metadata;}
5665  size_t getSize() const {return sizeof(PeggingIterator);}
5666 
5667  private:
5668  /** This structure is used to keep track of the iterator states during the
5669  * iteration. */
5670  struct state
5671  {
5672  /** Stores the quantity of this flowplan that is involved. */
5673  double qty;
5674 
5675  /** Stores what portion of the flowplan is involved with the root flowplan
5676  * where the recursion started.
5677  */
5678  double factor;
5679 
5680  /** Keeps track of the number of levels we're removed from the root
5681  * flowplan where the recursion started.
5682  */
5683  short level;
5684 
5685  /** The current flowplan. */
5686  const FlowPlan* cons_flowplan;
5687 
5688  /** The current flowplan. */
5689  const FlowPlan* prod_flowplan;
5690 
5691  /** Set to false when unpegged quantities are involved. */
5692  bool pegged;
5693 
5694  /** Constructor. */
5695  state(unsigned int l, double d, double f,
5696  const FlowPlan* fc, const FlowPlan* fp, bool p = true)
5697  : qty(d), factor(f), level(l),
5698  cons_flowplan(fc), prod_flowplan(fp), pegged(p) {};
5699 
5700  /** Inequality operator. */
5701  bool operator != (const state& s) const
5702  {
5703  return cons_flowplan != s.cons_flowplan
5704  || prod_flowplan != s.prod_flowplan
5705  || level != s.level;
5706  }
5707 
5708  /** Equality operator. */
5709  bool operator == (const state& s) const
5710  {
5711  return cons_flowplan == s.cons_flowplan
5712  && prod_flowplan == s.prod_flowplan
5713  && level == s.level;
5714  }
5715  };
5716 
5717  /** A type to hold the iterator state. */
5718  typedef stack < state > statestack;
5719 
5720  /** A stack is used to store the iterator state. */
5721  statestack states;
5722 
5723  /** Iterate over the pegging in Python. */
5724  DECLARE_EXPORT PyObject *iternext();
5725 
5726  DECLARE_EXPORT PyObject* getattro(const Attribute&);
5727 
5728  /* Auxilary function to make recursive code possible. */
5729  DECLARE_EXPORT void followPegging(const OperationPlan*, short, double, double);
5730 
5731  /** Convenience variable during stack updates.
5732  * Depending on the value of this field, either the top element in the
5733  * stack is updated or a new state is pushed on the stack.
5734  */
5735  bool first;
5736 
5737  /** Downstream or upstream iterator. */
5738  bool downstream;
5739 
5740  /** A flag used by the Python iterators.
5741  * @see iternext()
5742  */
5743  bool firstIteration;
5744 };
5745 
5746 
5747 /** @brief An iterator class to go through all flowplans of an operationplan.
5748  * @see OperationPlan::beginFlowPlans
5749  * @see OperationPlan::endFlowPlans
5750  */
5752 {
5753  friend class OperationPlan;
5754  private:
5755  FlowPlan* curflowplan;
5756  FlowPlan* prevflowplan;
5757  FlowPlanIterator(FlowPlan* b) : curflowplan(b), prevflowplan(NULL) {}
5758  public:
5760  {
5761  curflowplan = b.curflowplan;
5762  prevflowplan = b.prevflowplan;
5763  }
5764  bool operator != (const FlowPlanIterator &b) const
5765  {return b.curflowplan != curflowplan;}
5766  bool operator == (const FlowPlanIterator &b) const
5767  {return b.curflowplan == curflowplan;}
5768  FlowPlanIterator& operator++()
5769  {
5770  prevflowplan = curflowplan;
5771  if (curflowplan) curflowplan = curflowplan->nextFlowPlan;
5772  return *this;
5773  }
5774  FlowPlanIterator operator++(int)
5775  {FlowPlanIterator tmp = *this; ++*this; return tmp;}
5776  FlowPlan* operator ->() const {return curflowplan;}
5777  FlowPlan& operator *() const {return *curflowplan;}
5778  void deleteFlowPlan()
5779  {
5780  if (!curflowplan) return;
5781  if (prevflowplan) prevflowplan->nextFlowPlan = curflowplan->nextFlowPlan;
5782  else curflowplan->oper->firstflowplan = curflowplan->nextFlowPlan;
5783  FlowPlan* tmp = curflowplan;
5784  // Move the iterator to the next element
5785  curflowplan = curflowplan->nextFlowPlan;
5786  delete tmp;
5787  }
5788 };
5789 
5791 {return OperationPlan::FlowPlanIterator(firstflowplan);}
5792 
5794 {return OperationPlan::FlowPlanIterator(NULL);}
5795 
5797 {
5798  int c = 0;
5799  for (FlowPlanIterator i = beginFlowPlans(); i != endFlowPlans(); ++i) ++c;
5800  return c;
5801 }
5802 
5803 
5804 /** @brief An iterator class to go through all loadplans of an operationplan.
5805  * @see OperationPlan::beginLoadPlans
5806  * @see OperationPlan::endLoadPlans
5807  */
5809 {
5810  friend class OperationPlan;
5811  private:
5812  LoadPlan* curloadplan;
5813  LoadPlan* prevloadplan;
5814  LoadPlanIterator(LoadPlan* b) : curloadplan(b), prevloadplan(NULL) {}
5815  public:
5817  {
5818  curloadplan = b.curloadplan;
5819  prevloadplan = b.prevloadplan;
5820  }
5821  bool operator != (const LoadPlanIterator &b) const
5822  {return b.curloadplan != curloadplan;}
5823  bool operator == (const LoadPlanIterator &b) const
5824  {return b.curloadplan == curloadplan;}
5825  LoadPlanIterator& operator++()
5826  {
5827  prevloadplan = curloadplan;
5828  if (curloadplan) curloadplan = curloadplan->nextLoadPlan;
5829  return *this;
5830  }
5831  LoadPlanIterator operator++(int)
5832  {LoadPlanIterator tmp = *this; ++*this; return tmp;}
5833  LoadPlan* operator ->() const {return curloadplan;}
5834  LoadPlan& operator *() const {return *curloadplan;}
5835  void deleteLoadPlan()
5836  {
5837  if (!curloadplan) return;
5838  if (prevloadplan) prevloadplan->nextLoadPlan = curloadplan->nextLoadPlan;
5839  else curloadplan->oper->firstloadplan = curloadplan->nextLoadPlan;
5840  LoadPlan* tmp = curloadplan;
5841  // Move the iterator to the next element
5842  curloadplan = curloadplan->nextLoadPlan;
5843  delete tmp;
5844  }
5845 };
5846 
5847 
5849 {return OperationPlan::LoadPlanIterator(firstloadplan);}
5850 
5851 
5853 {return OperationPlan::LoadPlanIterator(NULL);}
5854 
5855 
5857 {
5858  int c = 0;
5859  for (LoadPlanIterator i = beginLoadPlans(); i != endLoadPlans(); ++i) ++c;
5860  return c;
5861 }
5862 
5863 
5865  : public FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>
5866 {
5867  public:
5868  /** Constructor starting the iteration from a certain problem. */
5870  FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>(x) {}
5871 
5872  /** Constructor starting the iteration from a certain problem. */
5874  FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>(&x) {}
5875 
5876  /** Default constructor. */
5878  FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>() {}
5879 };
5880 
5881 
5883  : public FreppleIterator<BufferIterator,Buffer::memberIterator,Buffer>
5884 {
5885  public:
5888 };
5889 
5890 
5892  : public FreppleIterator<LocationIterator,Location::memberIterator,Location>
5893 {
5894  public:
5897 };
5898 
5899 
5901  : public FreppleIterator<CustomerIterator,Customer::memberIterator,Customer>
5902 {
5903  public:
5906 };
5907 
5908 
5910  : public FreppleIterator<ItemIterator,Item::memberIterator,Item>
5911 {
5912  public:
5915 };
5916 
5917 
5919  : public FreppleIterator<DemandIterator,Demand::memberIterator,Demand>
5920 {
5921  public:
5924 };
5925 
5926 
5928  : public FreppleIterator<ResourceIterator,Resource::memberIterator,Resource>
5929 {
5930  public:
5933 };
5934 
5935 
5937  : public FreppleIterator<SolverIterator,Solver::iterator,Solver>
5938 {
5939 };
5940 
5941 
5943  : public FreppleIterator<OperationIterator,Operation::iterator,Operation>
5944 {
5945 };
5946 
5947 
5949  : public FreppleIterator<CalendarIterator,Calendar::iterator,Calendar>
5950 {
5951 };
5952 
5953 
5955  : public FreppleIterator<SetupMatrixIterator,SetupMatrix::iterator,SetupMatrix>
5956 {
5957 };
5958 
5959 
5961  : public FreppleIterator<SkillIterator,Skill::iterator,Skill>
5962 {
5963 };
5964 
5965 
5966 //
5967 // SETUP MATRIX RULES
5968 //
5969 
5970 
5971 class SetupMatrixRuleIterator : public PythonExtension<SetupMatrixRuleIterator>
5972 {
5973  public:
5974  static int initialize();
5975 
5977  {
5978  if (!c)
5979  throw LogicException("Creating rule iterator for NULL matrix");
5980  currule = c->beginRules();
5981  }
5982 
5983  private:
5984  SetupMatrix* matrix;
5985  SetupMatrix::RuleIterator currule;
5986  PyObject *iternext();
5987 };
5988 
5989 
5990 //
5991 // RESOURCE SKILLS
5992 //
5993 
5994 class ResourceSkillIterator : public PythonExtension<ResourceSkillIterator>
5995 {
5996  public:
5997  static int initialize();
5998 
6000  : res(r), ir(r ? r->getSkills().begin() : NULL), skill(NULL), is(NULL)
6001  {
6002  if (!r)
6003  throw LogicException("Creating resourceskill iterator for NULL resource");
6004  }
6005 
6007  : res(NULL), ir(NULL), skill(s), is(s ? s->getResources().begin() : NULL)
6008  {
6009  if (!s)
6010  throw LogicException("Creating resourceskill iterator for NULL skill");
6011  }
6012 
6013  private:
6014  Resource* res;
6015  Resource::skilllist::const_iterator ir;
6016  Skill* skill;
6017  Skill::resourcelist::const_iterator is;
6018  PyObject *iternext();
6019 };
6020 
6021 
6022 //
6023 // CALENDARS
6024 //
6025 
6026 
6027 class CalendarBucketIterator : public PythonExtension<CalendarBucketIterator>
6028 {
6029  public:
6030  static int initialize();
6031 
6033  {
6034  if (!c)
6035  throw LogicException("Creating bucket iterator for NULL calendar");
6036  i = c->beginBuckets();
6037  }
6038 
6039  private:
6040  Calendar* cal;
6042  PyObject *iternext();
6043 };
6044 
6045 
6047  : public PythonExtension<CalendarEventIterator>
6048 {
6049  public:
6050  static int initialize();
6051 
6053  : cal(c), eventiter(c,d,f), forward(f) {}
6054 
6055  private:
6056  Calendar* cal;
6057  Calendar::EventIterator eventiter;
6058  bool forward;
6059  PyObject *iternext();
6060 };
6061 
6062 
6063 //
6064 // OPERATIONPLANS
6065 //
6066 
6067 
6069  : public FreppleIterator<OperationPlanIterator,OperationPlan::iterator,OperationPlan>
6070 {
6071  public:
6072  /** Constructor to iterate over all operationplans. */
6074 
6075  /** Constructor to iterate over the operationplans of a single operation. */
6078  {}
6079 
6080  /** Constructor to iterate over the suboperationplans of an operationplans. */
6083  {}
6084 };
6085 
6086 
6087 //
6088 // FLOWPLANS
6089 //
6090 
6091 
6092 class FlowPlanIterator : public PythonExtension<FlowPlanIterator>
6093 {
6094  public:
6095  /** Registration of the Python class and its metadata. */
6096  static int initialize();
6097 
6098  /** Constructor to iterate over the flowplans of a buffer. */
6099  FlowPlanIterator(Buffer* b) : buf(b), buffer_or_opplan(true)
6100  {
6101  if (!b)
6102  throw LogicException("Creating flowplan iterator for NULL buffer");
6103  bufiter = new Buffer::flowplanlist::const_iterator(b->getFlowPlans().begin());
6104  }
6105 
6106  /** Constructor to iterate over the flowplans of an operationplan. */
6107  FlowPlanIterator(OperationPlan* o) : opplan(o), buffer_or_opplan(false)
6108  {
6109  if (!o)
6110  throw LogicException("Creating flowplan iterator for NULL operationplan");
6111  opplaniter = new OperationPlan::FlowPlanIterator(o->beginFlowPlans());
6112  }
6113 
6115  {
6116  if (buffer_or_opplan) delete bufiter;
6117  else delete opplaniter;
6118  }
6119 
6120  private:
6121  union
6122  {
6125  };
6126 
6127  union
6128  {
6129  Buffer::flowplanlist::const_iterator *bufiter;
6131  };
6132 
6133  /** Flags whether we are browsing over the flowplans in a buffer or in an
6134  * operationplan. */
6135  bool buffer_or_opplan;
6136 
6137  PyObject *iternext();
6138 };
6139 
6140 
6141 //
6142 // LOADPLANS
6143 //
6144 
6145 
6146 class LoadPlanIterator : public PythonExtension<LoadPlanIterator>
6147 {
6148  public:
6149  static int initialize();
6150 
6151  LoadPlanIterator(Resource* r) : res(r), resource_or_opplan(true)
6152  {
6153  if (!r)
6154  throw LogicException("Creating loadplan iterator for NULL resource");
6155  resiter = new Resource::loadplanlist::const_iterator(r->getLoadPlans().begin());
6156  }
6157 
6158  LoadPlanIterator(OperationPlan* o) : opplan(o), resource_or_opplan(false)
6159  {
6160  if (!opplan)
6161  throw LogicException("Creating loadplan iterator for NULL operationplan");
6162  opplaniter = new OperationPlan::LoadPlanIterator(o->beginLoadPlans());
6163  }
6164 
6166  {
6167  if (resource_or_opplan) delete resiter;
6168  else delete opplaniter;
6169  }
6170 
6171  private:
6172  union
6173  {
6176  };
6177 
6178  union
6179  {
6180  Resource::loadplanlist::const_iterator *resiter;
6182  };
6183 
6184  /** Flags whether we are browsing over the flowplans in a buffer or in an
6185  * operationplan. */
6186  bool resource_or_opplan;
6187 
6188  PyObject *iternext();
6189 };
6190 
6191 
6192 //
6193 // DEMAND DELIVERY OPERATIONPLANS
6194 //
6195 
6196 
6197 class DemandPlanIterator : public PythonExtension<DemandPlanIterator>
6198 {
6199  public:
6200  static int initialize();
6201 
6203  {
6204  if (!r)
6205  throw LogicException("Creating demandplan iterator for NULL demand");
6206  i = r->getDelivery().begin();
6207  }
6208 
6209  private:
6210  Demand* dem;
6211  Demand::OperationPlan_list::const_iterator i;
6212  PyObject *iternext();
6213 };
6214 
6215 
6216 //
6217 // LOADS
6218 //
6219 
6220 
6221 class LoadIterator : public PythonExtension<LoadIterator>
6222 {
6223  public:
6224  static int initialize();
6225 
6227  : res(r), ir(r ? r->getLoads().begin() : NULL), oper(NULL), io(NULL)
6228  {
6229  if (!r)
6230  throw LogicException("Creating loadplan iterator for NULL resource");
6231  }
6232 
6234  : res(NULL), ir(NULL), oper(o), io(o ? o->getLoads().begin() : NULL)
6235  {
6236  if (!o)
6237  throw LogicException("Creating loadplan iterator for NULL operation");
6238  }
6239 
6240  private:
6241  Resource* res;
6242  Resource::loadlist::const_iterator ir;
6243  Operation* oper;
6244  Operation::loadlist::const_iterator io;
6245  PyObject *iternext();
6246 };
6247 
6248 
6249 //
6250 // FLOW
6251 //
6252 
6253 
6254 class FlowIterator : public PythonExtension<FlowIterator>
6255 {
6256  public:
6257  static int initialize();
6258 
6260  : buf(b), ib(b ? b->getFlows().begin() : NULL), oper(NULL), io(NULL)
6261  {
6262  if (!b)
6263  throw LogicException("Creating flowplan iterator for NULL buffer");
6264  }
6265 
6267  : buf(NULL), ib(NULL), oper(o), io(o ? o->getFlows().begin() : NULL)
6268  {
6269  if (!o)
6270  throw LogicException("Creating flowplan iterator for NULL operation");
6271  }
6272 
6273  private:
6274  Buffer* buf;
6276  Operation* oper;
6278  PyObject *iternext();
6279 };
6280 
6281 
6282 /** @brief This Python function is used for reading XML input.
6283  *
6284  * The function takes up to three arguments:
6285  * - XML data file to be processed.
6286  * If this argument is omitted or None, the standard input is read.
6287  * - Optional validate flag, defining whether or not the input data needs to be
6288  * validated against the XML schema definition.
6289  * The validation is switched ON by default.
6290  * Switching it ON is recommended in situations where there is no 100% guarantee
6291  * on the validity of the input data.
6292  * - Optional validate_only flag, which allows us to validate the data but
6293  * skip any processing.
6294  */
6295 DECLARE_EXPORT PyObject* readXMLfile(PyObject*, PyObject*);
6296 
6297 
6298 /** @brief This Python function is used for processing XML input data from a string.
6299  *
6300  * The function takes up to three arguments:
6301  * - XML data string to be processed
6302  * - Optional validate flag, defining whether or not the input data needs to be
6303  * validated against the XML schema definition.
6304  * The validation is switched ON by default.
6305  * Switching it ON is recommended in situations where there is no 100% guarantee
6306  * on the validity of the input data.
6307  * - Optional validate_only flag, which allows us to validate the data but
6308  * skip any processing.
6309  */
6310 DECLARE_EXPORT PyObject* readXMLdata(PyObject *, PyObject *);
6311 
6312 
6313 /** @brief This Python function writes the dynamic part of the plan to an text file.
6314  *
6315  * This saved information covers the buffer flowplans, operationplans,
6316  * resource loading, demand, problems, etc...<br>
6317  * The main use of this function is in the test suite: a simple text file
6318  * comparison allows us to identify changes quickly. The output format is
6319  * only to be seen in this context of testing, and is not intended to be used
6320  * as an official method for publishing plans to other systems.
6321  */
6322 DECLARE_EXPORT PyObject* savePlan(PyObject*, PyObject*);
6323 
6324 
6325 /** @brief This Python function prints a summary of the dynamically allocated
6326  * memory to the standard output. This is useful for understanding better the
6327  * size of your model.
6328  *
6329  * The numbers reported by this function won't match the memory size as
6330  * reported by the operating system, since the dynamically allocated memory
6331  * is only a part of the total memory used by a program.
6332  */
6333 DECLARE_EXPORT PyObject* printModelSize(PyObject* self, PyObject* args);
6334 
6335 
6336 /** @brief This python function writes the complete model to an XML-file.
6337  *
6338  * Both the static model (i.e. items, locations, buffers, resources,
6339  * calendars, etc...) and the dynamic data (i.e. the actual plan including
6340  * the operationplans, demand, problems, etc...).<br>
6341  * The format is such that the output file can be re-read to restore the
6342  * very same model.<br>
6343  * The function takes the following arguments:
6344  * - Name of the output file
6345  * - Type of output desired: STANDARD, PLAN or PLANDETAIL.
6346  * The default value is STANDARD.
6347  */
6348 DECLARE_EXPORT PyObject* saveXMLfile(PyObject*, PyObject*);
6349 
6350 
6351 /** @brief This Python function erases the model or the plan from memory.
6352  *
6353  * The function allows the following modes to control what to delete:
6354  * - plan:<br>
6355  * Deletes the dynamic modelling constructs, such as operationplans,
6356  * loadplans and flowplans only. Locked operationplans are not
6357  * deleted.<br>
6358  * The static model is left intact.<br>
6359  * This is the default mode.
6360  * - model:<br>
6361  * The dynamic as well as the static objects are removed. You'll end
6362  * up with a completely empty model.
6363  * Due to the logic required in the object destructors this mode doesn't
6364  * scale linear with the model size.
6365  */
6366 DECLARE_EXPORT PyObject* eraseModel(PyObject* self, PyObject* args);
6367 
6368 
6369 } // End namespace
6370 
6371 #endif