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