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