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

Documentation generated for frePPLe by  doxygen