solver.h
Go to the documentation of this file.
00001 /***************************************************************************
00002   file : $URL: http://svn.code.sf.net/p/frepple/code/trunk/include/frepple/solver.h $
00003   version : $LastChangedRevision: 1715 $  $LastChangedBy: jdetaeye $
00004   date : $LastChangedDate: 2012-07-19 21:37:46 +0200 (Thu, 19 Jul 2012) $
00005  ***************************************************************************/
00006 
00007 /***************************************************************************
00008  *                                                                         *
00009  * Copyright (C) 2007-2012 by Johan De Taeye, frePPLe bvba                 *
00010  *                                                                         *
00011  * This library is free software; you can redistribute it and/or modify it *
00012  * under the terms of the GNU Affero General Public License as published   *
00013  * by the Free Software Foundation; either version 3 of the License, or    *
00014  * (at your option) any later version.                                     *
00015  *                                                                         *
00016  * This library is distributed in the hope that it will be useful,         *
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
00019  * GNU Affero General Public License for more details.                     *
00020  *                                                                         *
00021  * You should have received a copy of the GNU Affero General Public        *
00022  * License along with this program.                                        *
00023  * If not, see <http://www.gnu.org/licenses/>.                             *
00024  *                                                                         *
00025  ***************************************************************************/
00026 
00027 #ifndef SOLVER_H
00028 #define SOLVER_H
00029 
00030 #include "frepple/model.h"
00031 #ifndef DOXYGEN
00032 #include <deque>
00033 #include <cmath>
00034 #endif
00035 
00036 namespace frepple
00037 {
00038 
00039 /** @brief This solver implements a heuristic algorithm for planning demands.
00040   *
00041   * One by one the demands are processed. The demand will consume step by step
00042   * any upstream materials, respecting all constraints on its path.<br>
00043   * The solver supports all planning constraints as defined in Solver
00044   * class.<br>
00045   * See the documentation of the different solve methods to understand the
00046   * functionality in more detail.
00047   *
00048   * The logging levels have the following meaning:
00049   * - 0: Silent operation. Default logging level.
00050   * - 1: Show solver progress for each demand.
00051   * - 2: Show the complete ask&reply communication of the solver.
00052   * - 3: Trace the status of all entities.
00053   */
00054 class SolverMRP : public Solver
00055 {
00056   protected:
00057     /** This variable stores the constraint which the solver should respect.
00058       * By default no constraints are enabled. */
00059     short constrts;
00060 
00061     /** Behavior of this solver method is:
00062       *  - It will ask the consuming flows for the required quantity.
00063       *  - The quantity asked for takes into account the quantity_per of the
00064       *    producing flow.
00065       *  - The date asked for takes into account the post-operation time
00066       *    of the operation.
00067       */
00068     DECLARE_EXPORT void solve(const Operation*, void* = NULL);
00069 
00070     /** Behavior of this solver method is:
00071       *  - Asks each of the routing steps for the requested quantity, starting
00072       *    with the last routing step.<br>
00073       *    The time requested for the operation is based on the start date of
00074       *    the next routing step.
00075       */
00076     DECLARE_EXPORT void solve(const OperationRouting*, void* = NULL);
00077 
00078     /** Behavior of this solver method is:
00079       *  - The solver loops through each alternate operation in order of
00080       *    priority. On each alternate operation, the solver will try to plan
00081       *    the quantity that hasn't been planned on higher priority alternates.
00082       *  - As a special case, operations with zero priority are skipped in the
00083       *    loop. These operations are considered to be temporarily unavailable.
00084       *  - The requested operation can be planned over multiple alternates.
00085       *    We don't garantuee that a request is planned using a single alternate
00086       *    operation.
00087       *  - The solver properly considers the quantity_per of all flows producing
00088       *    into the requested buffer, if such a buffer is specified.
00089       */
00090     DECLARE_EXPORT void solve(const OperationAlternate*,void* = NULL);
00091 
00092     /** Behavior of this solver method:
00093       *  - No propagation to upstream buffers at all, even if a producing
00094       *    operation has been specified.
00095       *  - Always give an answer for the full quantity on the requested date.
00096       */
00097     DECLARE_EXPORT void solve(const BufferInfinite*,void* = NULL);
00098 
00099     /** Behavior of this solver method:
00100       *  - Consider 0 as the hard minimum limit. It is not possible
00101       *    to plan with a 'hard' safety stock reservation.
00102       *  - Minimum inventory is treated as a 'wish' inventory. When replenishing
00103       *    a buffer we try to satisfy the minimum target. If that turns out
00104       *    not to be possible we use whatever available supply for satisfying
00105       *    the demand first.
00106       *  - Planning for the minimum target is part of planning a demand. There
00107       *    is no planning run independent of demand to satisfy the minimum
00108       *    target.<br>
00109       *    E.g. If a buffer has no demand on it, the solver won't try to
00110       *    replenish to the minimum target.<br>
00111       *    E.g. If the minimum target increases after the latest date required
00112       *    for satisfying a certain demand that change will not be considered.
00113       *  - The solver completely ignores the maximum target.
00114       */
00115     DECLARE_EXPORT void solve(const Buffer*, void* = NULL);
00116 
00117     /** Behavior of this solver method:
00118       *  - When the inventory drops below the minimum inventory level, a new
00119       *    replenishment is triggered.
00120       *    The replenishment brings the inventory to the maximum level again.
00121       *  - The minimum and maximum inventory are soft-constraints. The actual
00122       *    inventory can go lower than the minimum or exceed the maximum.
00123       *  - The minimum, maximum and multiple size of the replenishment are
00124       *    hard constraints, and will always be respected.
00125       *  - A minimum and maximum interval between replenishment is also
00126       *    respected as a hard constraint.
00127       *  - No propagation to upstream buffers at all, even if a producing
00128       *    operation has been specified.
00129       *  - The minimum calendar isn't used by the solver.
00130       *
00131       * @todo Optimize the solver method as follows for the common case of infinite
00132       * buying capability (ie no max quantity + min time):
00133       *  - beyond lead time: always reply OK, without rearranging the operation plans
00134       *  - at the end of the solver loop, we revisit the procurement buffers to establish
00135       *    the final purchasing profile
00136       */
00137     DECLARE_EXPORT void solve(const BufferProcure*, void* = NULL);
00138 
00139     /** Behavior of this solver method:
00140       *  - This method simply passes on the request to the referenced buffer.
00141       *    It is called from a solve(Operation*) method and passes on the
00142       *    control to a solve(Buffer*) method.
00143       * @see checkOperationMaterial
00144       */
00145     DECLARE_EXPORT void solve(const Flow*, void* = NULL);
00146 
00147     /** Behavior of this solver method:
00148       *  - The operationplan is checked for a capacity overload. When detected
00149       *    it is moved to an earlier date.
00150       *  - This move can be repeated until no capacity is found till a suitable
00151       *    time slot is found. If the fence and/or leadtime constraints are
00152       *    enabled they can restrict the feasible moving time.<br>
00153       *    If a feasible timeslot is found, the method exits here.
00154       *  - If no suitable time slot can be found at all, the operation plan is
00155       *    put on its original date and we now try to move it to a feasible
00156       *    later date. Again, successive moves are possible till a suitable
00157       *    slot is found or till we reach the end of the horizon.
00158       *    The result of the search is returned as the answer-date to the
00159       *    solver.
00160       */
00161     DECLARE_EXPORT void solve(const Resource*, void* = NULL);
00162 
00163     /** Behavior of this solver method:
00164       *  - Always return OK.
00165       */
00166     DECLARE_EXPORT void solve(const ResourceInfinite*,void* = NULL);
00167 
00168     /** Behavior of this solver method:
00169       *  - This method simply passes on the request to the referenced resource.
00170       *    With the current model structure it could easily be avoided (and
00171       *    thus gain a bit in performance), but we wanted to include it anyway
00172       *    to make the solver as generic and future-proof as possible.
00173       * @see checkOperationCapacity
00174       */
00175     DECLARE_EXPORT void solve(const Load*, void* = NULL);
00176 
00177     /** Behavior of this solver method:
00178       *  - Respects the following demand planning policies:<br>
00179       *     1) Maximum allowed lateness
00180       *     2) Minimum shipment quantity
00181       * This method is normally called from within the main solve method, but
00182       * it can also be called independently to plan a certain demand.
00183       * @see solve
00184       */
00185     DECLARE_EXPORT void solve(const Demand*, void* = NULL);
00186 
00187   public:
00188     /** This is the main solver method that will appropriately call the other
00189       * solve methods.<br>
00190       * The demands in the model will all be sorted with the criteria defined in
00191       * the demand_comparison() method. For each of demand the solve(Demand*)
00192       * method is called to plan it.
00193       */
00194     DECLARE_EXPORT void solve(void *v = NULL);
00195 
00196     /** Constructor. */
00197     SolverMRP(const string& n) : Solver(n), constrts(15), plantype(1),
00198       lazydelay(86400L), iteration_threshold(1), iteration_accuracy(0.01),
00199       autocommit(true)
00200     { initType(metadata); }
00201 
00202     /** Destructor. */
00203     virtual ~SolverMRP() {}
00204 
00205     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
00206     DECLARE_EXPORT void endElement(XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement);
00207     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
00208     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
00209     static int initialize();
00210 
00211     virtual const MetaClass& getType() const {return *metadata;}
00212     static DECLARE_EXPORT const MetaClass* metadata;
00213     virtual size_t getSize() const {return sizeof(SolverMRP);}
00214 
00215     /** Static constant for the LEADTIME constraint type.<br>
00216       * The numeric value is 1.
00217       * @see MATERIAL
00218       * @see CAPACITY
00219       * @see FENCE
00220       */
00221     static const short LEADTIME = 1;
00222 
00223     /** Static constant for the MATERIAL constraint type.<br>
00224       * The numeric value is 2.
00225       * @see LEADTIME
00226       * @see CAPACITY
00227       * @see FENCE
00228       */
00229     static const short MATERIAL = 2;
00230 
00231     /** Static constant for the CAPACITY constraint type.<br>
00232       * The numeric value is 4.
00233       * @see MATERIAL
00234       * @see LEADTIME
00235       * @see FENCE
00236       */
00237     static const short CAPACITY = 4;
00238 
00239     /** Static constant for the FENCE constraint type.<br>
00240       * The numeric value is 8.
00241       * @see MATERIAL
00242       * @see CAPACITY
00243       * @see LEADTIME
00244       */
00245     static const short FENCE = 8;
00246 
00247     /** Update the constraints to be considered by this solver. This field may
00248       * not be applicable for all solvers. */
00249     void setConstraints(short i) {constrts = i;}
00250 
00251     /** Returns the constraints considered by the solve. */
00252     short getConstraints() const {return constrts;}
00253 
00254     /** Returns true if this solver respects the operation release fences.
00255       * The solver isn't allowed to create any operation plans within the
00256       * release fence.
00257       */
00258     bool isFenceConstrained() const {return (constrts & FENCE)>0;}
00259 
00260     /** Returns true if the solver respects the current time of the plan.
00261       * The solver isn't allowed to create any operation plans in the past.
00262       */
00263     bool isLeadtimeConstrained() const {return (constrts & LEADTIME)>0;}
00264 
00265     /** Returns true if the solver respects the material procurement
00266       * constraints on procurement buffers.
00267       */
00268     bool isMaterialConstrained() const {return (constrts & MATERIAL)>0;}
00269 
00270     /** Returns true if the solver respects capacity constraints. */
00271     bool isCapacityConstrained() const {return (constrts & CAPACITY)>0;}
00272 
00273     /** Returns true if any constraint is relevant for the solver. */
00274     bool isConstrained() const {return constrts>0;}
00275 
00276     /** Returns the plan type:
00277       *  - 1: Constrained plan.<br>
00278       *       This plan doesn't not violate any constraints.<br>
00279       *       In case of material or capacity shortages the demand is delayed
00280       *       or planned short.
00281       *  - 2: Unconstrained plan with alternate search.<br>
00282       *       This unconstrained plan leaves material, capacity and operation
00283       *       problems when shortages are found. Availability is searched across
00284       *       alternates and the remaining shortage is shown on the primary
00285       *       alternate.<br>
00286       *       The demand is always fully met on time.
00287       *  - 3: Unconstrained plan without alternate search.<br>
00288       *       This unconstrained plan leaves material, capacity and operation
00289       *       problems when shortages are found. It doesn't evaluate availability
00290       *       on alternates.<br>
00291       *       The demand is always fully met on time.
00292       * The default is 1.
00293       */
00294     short getPlanType() const {return plantype;}
00295 
00296     void setPlanType(short b)
00297     {
00298       if (b < 1 || b > 3)
00299         throw DataException("Invalid plan type");
00300       plantype = b;
00301     }
00302 
00303     /** This function defines the order in which the demands are being
00304       * planned.<br>
00305       * The following sorting criteria are appplied in order:
00306       *  - demand priority: smaller priorities first
00307       *  - demand due date: earlier due dates first
00308       *  - demand quantity: smaller quantities first
00309       */
00310     static DECLARE_EXPORT bool demand_comparison(const Demand*, const Demand*);
00311 
00312     /** Return the time increment between requests when the answered reply
00313       * date isn't usable. */
00314     TimePeriod getLazyDelay() const {return lazydelay;}
00315 
00316     /** Update the time increment between requests when the answered reply
00317       * date isn't usable. */
00318     void setLazyDelay(TimePeriod l)
00319     {
00320       if (l <= 0L)
00321         throw DataException("Invalid lazy delay");
00322       lazydelay = l;
00323     }
00324 
00325     /** Get the threshold to stop iterating when the delta between iterations
00326       * is less than this absolute threshold.
00327       */
00328     double getIterationThreshold() const {return iteration_threshold;}
00329 
00330     /** Set the threshold to stop iterating when the delta between iterations
00331       * is less than this absolute threshold.<br>
00332       * The value must be greater than or equal to zero and the default is 1.
00333       */
00334     void setIterationThreshold(double d)
00335     {
00336       if (d<0.0)
00337         throw DataException("Invalid iteration threshold: must be >= 0");
00338       iteration_threshold = d;
00339     }
00340 
00341     /** Get the threshold to stop iterating when the delta between iterations
00342       * is less than this percentage threshold.
00343       */
00344     double getIterationAccuracy() const {return iteration_accuracy;}
00345 
00346     /** Set the threshold to stop iterating when the delta between iterations
00347       * is less than this percentage threshold.<br>
00348       * The value must be between 0 and 100 and the default is 1%.
00349       */
00350     void setIterationAccuracy(double d)
00351     {
00352       if (d<0.0 || d>100.0)
00353         throw DataException("Invalid iteration accuracy: must be >=0 and <= 100");
00354       iteration_accuracy = d;
00355     }
00356 
00357     /** Return whether or not we automatically commit the changes after
00358       * planning a demand. */
00359     bool getAutocommit() const {return autocommit;}
00360 
00361     /** Update whether or not we automatically commit the changes after
00362       * planning a demand. */
00363     void setAutocommit(const bool b) {autocommit = b;}
00364 
00365     /** Specify a Python function that is called before solving a flow. */
00366     DECLARE_EXPORT void setUserExitFlow(const string& n) {userexit_flow = n;}
00367 
00368     /** Specify a Python function that is called before solving a flow. */
00369     DECLARE_EXPORT void setUserExitFlow(PyObject* p) {userexit_flow = p;}
00370 
00371     /** Return the Python function that is called before solving a flow. */
00372     PythonFunction getUserExitFlow() const {return userexit_flow;}
00373 
00374     /** Specify a Python function that is called before solving a demand. */
00375     DECLARE_EXPORT void setUserExitDemand(const string& n) {userexit_demand = n;}
00376 
00377     /** Specify a Python function that is called before solving a demand. */
00378     DECLARE_EXPORT void setUserExitDemand(PyObject* p) {userexit_demand = p;}
00379 
00380     /** Return the Python function that is called before solving a demand. */
00381     PythonFunction getUserExitDemand() const {return userexit_demand;}
00382 
00383     /** Specify a Python function that is called before solving a buffer. */
00384     DECLARE_EXPORT void setUserExitBuffer(const string& n) {userexit_buffer = n;}
00385 
00386     /** Specify a Python function that is called before solving a buffer. */
00387     DECLARE_EXPORT void setUserExitBuffer(PyObject* p) {userexit_buffer = p;}
00388 
00389     /** Return the Python function that is called before solving a buffer. */
00390     PythonFunction getUserExitBuffer() const {return userexit_buffer;}
00391 
00392     /** Specify a Python function that is called before solving a resource. */
00393     DECLARE_EXPORT void setUserExitResource(const string& n) {userexit_resource = n;}
00394 
00395     /** Specify a Python function that is called before solving a resource. */
00396     DECLARE_EXPORT void setUserExitResource(PyObject* p) {userexit_resource = p;}
00397 
00398     /** Return the Python function that is called before solving a resource. */
00399     PythonFunction getUserExitResource() const {return userexit_resource;}
00400 
00401     /** Specify a Python function that is called before solving a operation. */
00402     DECLARE_EXPORT void setUserExitOperation(const string& n) {userexit_operation = n;}
00403 
00404     /** Specify a Python function that is called before solving a operation. */
00405     DECLARE_EXPORT void setUserExitOperation(PyObject* p) {userexit_operation = p;}
00406 
00407     /** Return the Python function that is called before solving a operation. */
00408     PythonFunction getUserExitOperation() const {return userexit_operation;}
00409 
00410     /** Python method for running the solver. */
00411     static DECLARE_EXPORT PyObject* solve(PyObject*, PyObject*);
00412 
00413     /** Python method for commiting the plan changes. */
00414     static DECLARE_EXPORT PyObject* commit(PyObject*, PyObject*);
00415 
00416     /** Python method for undoing the plan changes. */
00417     static DECLARE_EXPORT PyObject* rollback(PyObject*, PyObject*);
00418 
00419   private:
00420     typedef map < int, deque<Demand*>, less<int> > classified_demand;
00421     typedef classified_demand::iterator cluster_iterator;
00422     classified_demand demands_per_cluster;
00423 
00424     /** Type of plan to be created. */
00425     short plantype;
00426 
00427     /** Time increments for a lazy replan.<br>
00428       * The solver is expected to return always a next-feasible date when the
00429       * request can't be met. The solver can then retry the request with an
00430       * updated request date. In some corner cases and in case of a bug it is
00431       * possible that no valid date is returned. The solver will then try the
00432       * request with a request date incremented by this value.<br>
00433       * The default value is 1 day.
00434       */
00435     TimePeriod lazydelay;
00436 
00437     /** Threshold to stop iterating when the delta between iterations is
00438       * less than this absolute limit.
00439       */
00440     double iteration_threshold;
00441 
00442     /** Threshold to stop iterating when the delta between iterations is
00443       * less than this percentage limit.
00444       */
00445     double iteration_accuracy;
00446 
00447     /** Enable or disable automatically committing the changes in the plan
00448       * after planning each demand.<br>
00449       * The flag is only respected when planning incremental changes, and
00450       * is ignored when doing a complete replan.
00451       */
00452     bool autocommit;
00453 
00454     /** A Python callback function that is called for each alternate
00455       * flow. If the callback function returns false, that alternate
00456       * flow is an invalid choice.
00457       */
00458     PythonFunction userexit_flow;
00459 
00460     /** A Python callback function that is called for each demand. The return
00461       * value is not used.
00462       */
00463     PythonFunction userexit_demand;
00464 
00465     /** A Python callback function that is called for each buffer. The return
00466       * value is not used.
00467       */
00468     PythonFunction userexit_buffer;
00469 
00470     /** A Python callback function that is called for each resource. The return
00471       * value is not used.
00472       */
00473     PythonFunction userexit_resource;
00474 
00475     /** A Python callback function that is called for each operation. The return
00476       * value is not used.
00477       */
00478     PythonFunction userexit_operation;
00479 
00480   protected:
00481     /** @brief This class is used to store the solver status during the
00482       * ask-reply calls of the solver.
00483       */
00484     struct State
00485     {
00486       /** Points to the demand being planned.<br>
00487         * This field is only non-null when planning the delivery operation.
00488         */
00489       Demand* curDemand;
00490 
00491       /** Points to the current owner operationplan. This is used when
00492         * operations are nested. */
00493       OperationPlan* curOwnerOpplan;
00494 
00495       /** Points to the current buffer. */
00496       Buffer* curBuffer;
00497 
00498       /** A flag to force the resource solver to move the operationplan to
00499         * a later date where it is feasible.
00500         */
00501       bool forceLate;
00502 
00503       /** This is the quantity we are asking for. */
00504       double q_qty;
00505 
00506       /** This is the date we are asking for. */
00507       Date q_date;
00508 
00509       /** This is the maximum date we are asking for.<br>
00510         * In case of a post-operation time there is a difference between
00511         * q_date and q_date_max.
00512         */
00513       Date q_date_max;
00514 
00515       /** This is the quantity we can get by the requested Date. */
00516       double a_qty;
00517 
00518       /** This is the Date when we can get extra availability. */
00519       Date a_date;
00520 
00521       /** This is a pointer to a LoadPlan. It is used for communication
00522         * between the Operation-Solver and the Resource-Solver. */
00523       LoadPlan* q_loadplan;
00524 
00525       /** This is a pointer to a FlowPlan. It is used for communication
00526         * between the Operation-Solver and the Buffer-Solver. */
00527       FlowPlan* q_flowplan;
00528 
00529       /** A pointer to an operationplan currently being solved. */
00530       OperationPlan* q_operationplan;
00531 
00532       /** Cost of the reply.<br>
00533         * Only the direct cost should be returned in this field.
00534         */
00535       double a_cost;
00536 
00537       /** Penalty associated with the reply.<br>
00538         * This field contains indirect costs and other penalties that are
00539         * not strictly related to the request. Examples are setup costs,
00540         * inventory carrying costs, ...
00541         */
00542       double a_penalty;
00543 
00544       /** Motive of the current solver. */
00545       Plannable* motive;
00546     };
00547 
00548     /** @brief This class is a helper class of the SolverMRP class.
00549       *
00550       * It stores the solver state maintained by each solver thread.
00551       * @see SolverMRP
00552       */
00553     class SolverMRPdata : public CommandManager
00554     {
00555         friend class SolverMRP;
00556       public:
00557         static void runme(void *args)
00558         {
00559           SolverMRP::SolverMRPdata* x = static_cast<SolverMRP::SolverMRPdata*>(args);
00560           x->commit();
00561           delete x;
00562         }
00563 
00564         /** Return the solver. */
00565         SolverMRP* getSolver() const {return sol;}
00566 
00567         /** Constructor. */
00568         SolverMRPdata(SolverMRP* s = NULL, int c = 0, deque<Demand*>* d = NULL)
00569           : sol(s), cluster(c), demands(d), constrainedPlanning(true),
00570             state(statestack), prevstate(statestack-1) {}
00571 
00572         /** Verbose mode is inherited from the solver. */
00573         unsigned short getLogLevel() const {return sol ? sol->getLogLevel() : 0;}
00574 
00575         /** This function runs a single planning thread. Such a thread will loop
00576           * through the following steps:
00577           *    - Use the method next_cluster() to find another unplanned cluster.
00578           *    - Exit the thread if no more cluster is found.
00579           *    - Sort all demands in the cluster, using the demand_comparison()
00580           *      method.
00581           *    - Loop through the sorted list of demands and plan each of them.
00582           *      During planning the demands exceptions are caught, and the
00583           *      planning loop will simply move on to the next demand.
00584           *      In this way, an error in a part of the model doesn't ruin the
00585           *      complete plan.
00586           * @see demand_comparison
00587           * @see next_cluster
00588           */
00589         virtual DECLARE_EXPORT void commit();
00590 
00591         virtual const MetaClass& getType() const {return *SolverMRP::metadata;}
00592         virtual size_t getSize() const {return sizeof(SolverMRPdata);}
00593 
00594         bool getVerbose() const
00595         {
00596           throw LogicException("Use the method SolverMRPdata::getLogLevel() instead of SolverMRPdata::getVerbose()");
00597         }
00598 
00599         /** Add a new state to the status stack. */
00600         inline void push(double q = 0.0, Date d = Date::infiniteFuture)
00601         {
00602           if (state >= statestack + MAXSTATES)
00603             throw RuntimeException("Maximum recursion depth exceeded");
00604           ++state;
00605           ++prevstate;
00606           state->q_qty = q;
00607           state->q_date = d;
00608           state->curOwnerOpplan = NULL;
00609           state->q_loadplan = NULL;
00610           state->q_flowplan = NULL;
00611           state->q_operationplan = NULL;
00612           state->curDemand = NULL;
00613           state->a_cost = 0.0;
00614           state->a_penalty = 0.0;
00615         }
00616 
00617         /** Removes a state from the status stack. */
00618         inline void pop()
00619         {
00620           if (--state < statestack)
00621             throw LogicException("State stack empty");
00622           --prevstate;
00623         }
00624 
00625       private:
00626         static const int MAXSTATES = 256;
00627 
00628         /** Points to the solver. */
00629         SolverMRP* sol;
00630 
00631         /** An identifier of the cluster being replanned. Note that it isn't
00632           * always the complete cluster that is being planned.
00633           */
00634         int cluster;
00635 
00636         /** A deque containing all demands to be (re-)planned. */
00637         deque<Demand*>* demands;
00638 
00639         /** Stack of solver status information. */
00640         State statestack[MAXSTATES];
00641 
00642         /** True when planning in constrained mode. */
00643         bool constrainedPlanning;
00644 
00645         /** Flags whether or not constraints are being tracked. */
00646         bool logConstraints;
00647 
00648         /** Points to the demand being planned. */
00649         Demand* planningDemand;
00650 
00651       public:
00652         /** Pointer to the current solver status. */
00653         State* state;
00654 
00655         /** Pointer to the solver status one level higher on the stack. */
00656         State* prevstate;
00657     };
00658 
00659     /** When autocommit is switched off, this command structure will contain
00660       * all plan changes.
00661       */
00662     SolverMRPdata commands;
00663 
00664     /** This function will check all constraints for an operationplan
00665       * and propagate it upstream. The check does NOT check eventual
00666       * sub operationplans.<br>
00667       * The return value is a flag whether the operationplan is
00668       * acceptable (sometimes in reduced quantity) or not.
00669       */
00670     DECLARE_EXPORT bool checkOperation(OperationPlan*, SolverMRPdata& data);
00671 
00672     /** Verifies whether this operationplan violates the leadtime
00673       * constraints. */
00674     DECLARE_EXPORT bool checkOperationLeadtime(OperationPlan*, SolverMRPdata&, bool);
00675 
00676     /** Verifies whether this operationplan violates the capacity constraint.<br>
00677       * In case it does the operationplan is moved to an earlier or later
00678       * feasible date.
00679       */
00680     DECLARE_EXPORT void checkOperationCapacity(OperationPlan*, SolverMRPdata&);
00681 
00682     /** Scan the operationplans that are about to be committed to verify that
00683       * they are not creating any excess.
00684       */
00685     DECLARE_EXPORT void scanExcess(CommandManager*);
00686 
00687     /** Scan the operationplans that are about to be committed to verify that
00688       * they are not creating any excess.
00689       */
00690     DECLARE_EXPORT void scanExcess(CommandList*);
00691 };
00692 
00693 
00694 /** @brief This class holds functions that used for maintenance of the solver
00695   * code.
00696   */
00697 class LibrarySolver
00698 {
00699   public:
00700     static void initialize();
00701 };
00702 
00703 
00704 } // end namespace
00705 
00706 
00707 #endif

Documentation generated for frePPLe by  doxygen