solver.h
Go to the documentation of this file.
00001 /***************************************************************************
00002   file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/trunk/include/frepple/solver.h $
00003   version : $LastChangedRevision: 1490 $  $LastChangedBy: jdetaeye $
00004   date : $LastChangedDate: 2011-07-24 12:11:13 +0200 (Sun, 24 Jul 2011) $
00005  ***************************************************************************/
00006 
00007 /***************************************************************************
00008  *                                                                         *
00009  * Copyright (C) 2007-2011 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.<br>
00501         * Admittedly this is an ugly hack...
00502         */
00503       bool forceLate;
00504 
00505       /** This is the quantity we are asking for. */
00506       double q_qty;
00507 
00508       /** This is the date we are asking for. */
00509       Date q_date;
00510 
00511       /** This is the maximum date we are asking for.<br>
00512         * In case of a post-operation time there is a difference between
00513         * q_date and q_date_max.
00514         */
00515       Date q_date_max;
00516 
00517       /** This is the quantity we can get by the requested Date. */
00518       double a_qty;
00519 
00520       /** This is the Date when we can get extra availability. */
00521       Date a_date;
00522 
00523       /** This is a pointer to a LoadPlan. It is used for communication
00524         * between the Operation-Solver and the Resource-Solver. */
00525       LoadPlan* q_loadplan;
00526 
00527       /** This is a pointer to a FlowPlan. It is used for communication
00528         * between the Operation-Solver and the Buffer-Solver. */
00529       FlowPlan* q_flowplan;
00530 
00531       /** A pointer to an operationplan currently being solved. */
00532       OperationPlan* q_operationplan;
00533 
00534       /** Cost of the reply.<br>
00535         * Only the direct cost should be returned in this field.
00536         */
00537       double a_cost;
00538 
00539       /** Penalty associated with the reply.<br>
00540         * This field contains indirect costs and other penalties that are
00541         * not strictly related to the request. Examples are setup costs,
00542         * inventory carrying costs, ...
00543         */
00544       double a_penalty;
00545     };
00546 
00547     /** @brief This class is a helper class of the SolverMRP class.
00548       *
00549       * It stores the solver state maintained by each solver thread.
00550       * @see SolverMRP
00551       */
00552     class SolverMRPdata : public CommandManager
00553     {
00554         friend class SolverMRP;
00555       public:
00556         static void runme(void *args)
00557         {
00558           SolverMRP::SolverMRPdata* x = static_cast<SolverMRP::SolverMRPdata*>(args);
00559           x->commit();
00560           delete x;
00561         }
00562 
00563         /** Return the solver. */
00564         SolverMRP* getSolver() const {return sol;}
00565 
00566         /** Constructor. */
00567         SolverMRPdata(SolverMRP* s = NULL, int c = 0, deque<Demand*>* d = NULL)
00568           : sol(s), cluster(c), demands(d), constrainedPlanning(true), 
00569             state(statestack), prevstate(statestack-1) {}
00570 
00571         /** Verbose mode is inherited from the solver. */
00572         unsigned short getLogLevel() const {return sol ? sol->getLogLevel() : 0;}
00573 
00574         /** This function runs a single planning thread. Such a thread will loop
00575           * through the following steps:
00576           *    - Use the method next_cluster() to find another unplanned cluster.
00577           *    - Exit the thread if no more cluster is found.
00578           *    - Sort all demands in the cluster, using the demand_comparison()
00579           *      method.
00580           *    - Loop through the sorted list of demands and plan each of them.
00581           *      During planning the demands exceptions are caught, and the
00582           *      planning loop will simply move on to the next demand.
00583           *      In this way, an error in a part of the model doesn't ruin the
00584           *      complete plan.
00585           * @see demand_comparison
00586           * @see next_cluster
00587           */
00588         virtual DECLARE_EXPORT void commit();
00589 
00590         virtual const MetaClass& getType() const {return *SolverMRP::metadata;}
00591         virtual size_t getSize() const {return sizeof(SolverMRPdata);}
00592 
00593         bool getVerbose() const
00594         {
00595           throw LogicException("Use the method SolverMRPdata::getLogLevel() instead of SolverMRPdata::getVerbose()");
00596         }
00597 
00598         /** Add a new state to the status stack. */
00599         inline void push(double q = 0.0, Date d = Date::infiniteFuture)
00600         {
00601           if (state >= statestack + MAXSTATES)
00602             throw RuntimeException("Maximum recursion depth exceeded");
00603           ++state;
00604           ++prevstate;
00605           state->q_qty = q;
00606           state->q_date = d;
00607           state->curOwnerOpplan = NULL;
00608           state->q_loadplan = NULL;
00609           state->q_flowplan = NULL;
00610           state->q_operationplan = NULL;
00611           state->curDemand = NULL;
00612           state->a_cost = 0.0;
00613           state->a_penalty = 0.0;
00614         }
00615 
00616         /** Removes a state from the status stack. */
00617         inline void pop()
00618         {
00619           if (--state < statestack)
00620             throw LogicException("State stack empty");
00621           --prevstate;
00622         }
00623 
00624       private:
00625         static const int MAXSTATES = 256;
00626 
00627         /** Points to the solver. */
00628         SolverMRP* sol;
00629 
00630         /** An identifier of the cluster being replanned. Note that it isn't
00631           * always the complete cluster that is being planned.
00632           */
00633         int cluster;
00634 
00635         /** A deque containing all demands to be (re-)planned. */
00636         deque<Demand*>* demands;
00637 
00638         /** Stack of solver status information. */
00639         State statestack[MAXSTATES];
00640         
00641         /** True when planning in constrained mode. */
00642         bool constrainedPlanning;
00643 
00644         /** Flags whether or not constraints are being tracked. */
00645         bool logConstraints;
00646 
00647         /** Points to the demand being planned. */
00648         Demand* planningDemand;
00649 
00650       public:
00651         /** Pointer to the current solver status. */
00652         State* state;
00653 
00654         /** Pointer to the solver status one level higher on the stack. */
00655         State* prevstate;
00656     };
00657  
00658     /** When autocommit is switched off, this command structure will contain
00659       * all plan changes.
00660       */
00661     SolverMRPdata commands;
00662 
00663     /** This function will check all constraints for an operationplan
00664       * and propagate it upstream. The check does NOT check eventual
00665       * sub operationplans.<br>
00666       * The return value is a flag whether the operationplan is
00667       * acceptable (sometimes in reduced quantity) or not.
00668       */
00669     DECLARE_EXPORT bool checkOperation(OperationPlan*, SolverMRPdata& data);
00670 
00671     /** Verifies whether this operationplan violates the leadtime
00672       * constraints. */
00673     DECLARE_EXPORT bool checkOperationLeadtime(OperationPlan*, SolverMRPdata&, bool);
00674 
00675     /** Verifies whether this operationplan violates the capacity constraint.<br>
00676       * In case it does the operationplan is moved to an earlier or later
00677       * feasible date.
00678       */
00679     DECLARE_EXPORT void checkOperationCapacity(OperationPlan*, SolverMRPdata&);
00680 
00681     /** Scan the operationplans that are about to be committed to verify that
00682       * they are not creating any excess. 
00683       */
00684     DECLARE_EXPORT void scanExcess(CommandManager*);  
00685 
00686     /** Scan the operationplans that are about to be committed to verify that
00687       * they are not creating any excess. 
00688       */
00689     DECLARE_EXPORT void scanExcess(CommandList*);  
00690 };
00691 
00692 
00693 /** @brief This class holds functions that used for maintenance of the solver
00694   * code.
00695   */
00696 class LibrarySolver
00697 {
00698   public:
00699     static void initialize();
00700 };
00701 
00702 
00703 } // end namespace
00704 
00705 
00706 #endif

Documentation generated for frePPLe by  doxygen