solverflow.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002   file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/tags/0.8.0/src/solver/solverflow.cpp $
00003   version : $LastChangedRevision: 1187 $  $LastChangedBy: jdetaeye $
00004   date : $LastChangedDate: 2010-02-21 12:45:06 +0100 (Sun, 21 Feb 2010) $
00005  ***************************************************************************/
00006 
00007 /***************************************************************************
00008  *                                                                         *
00009  * Copyright (C) 2007 by Johan De Taeye                                    *
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 #define FREPPLE_CORE
00029 #include "frepple/solver.h"
00030 
00031 namespace frepple
00032 {
00033 
00034 bool sortFlow(const Flow* lhs, const Flow* rhs)
00035 {
00036   return lhs->getPriority() < rhs->getPriority();
00037 }
00038 
00039 
00040 DECLARE_EXPORT void SolverMRP::solve(const Flow* fl, void* v)  // @todo implement search mode
00041 {
00042   // Note: This method is only called for consuming flows and for the leading
00043   // flow of an alternate group. See SolverMRP::checkOperation
00044 
00045   SolverMRPdata* data = static_cast<SolverMRPdata*>(v);
00046   if (fl->hasAlternates())
00047   {
00048     // CASE I: It is an alternate flow.
00049     // We ask each alternate flow in order of priority till we find a flow
00050     // that has a non-zero reply.
00051 
00052     // 1) collect a list of alternates
00053     list<const Flow*> thealternates;
00054     const Flow *x = fl->hasAlternates() ? fl : fl->getAlternate();
00055     for (Operation::flowlist::const_iterator i = fl->getOperation()->getFlows().begin();
00056       i != fl->getOperation()->getFlows().end(); ++i)
00057       if ((i->getAlternate() == x || &*i == x)
00058         && i->getEffective().within(data->state->q_flowplan->getDate()))
00059         thealternates.push_front(&*i);
00060 
00061     // 2) Sort the list
00062     thealternates.sort(sortFlow);
00063 
00064     // 3) Control the planning mode
00065     bool originalPlanningMode = data->constrainedPlanning;
00066     data->constrainedPlanning = true;
00067     const Flow *firstAlternate = NULL;
00068     double firstQuantity;
00069 
00070     // 4) Loop through the alternates till we find a non-zero reply
00071     Date min_next_date(Date::infiniteFuture);
00072     double ask_qty;
00073     FlowPlan *flplan = data->state->q_flowplan;
00074     for (list<const Flow*>::const_iterator i = thealternates.begin();
00075       i != thealternates.end();)
00076     {
00077       const Flow *curflow = *i;
00078       data->state->q_flowplan = flplan; // because q_flowplan can change
00079 
00080       // 4a) Switch to this flow
00081       if (data->state->q_flowplan->getFlow() != curflow)
00082         data->state->q_flowplan->setFlow(curflow);
00083 
00084       // 4b) Call the Python user exit if there is one
00085       if (userexit_flow)
00086       {
00087         PythonObject result = userexit_flow.call(data->state->q_flowplan, PythonObject(data->constrainedPlanning));
00088         if (!result.getBool())
00089         {
00090           // Return value is false, alternate rejected
00091           if (data->getSolver()->getLogLevel()>1)
00092             logger << indent(curflow->getOperation()->getLevel())
00093               << "   User exit disallows consumption from '"
00094               << (*i)->getBuffer()->getName() << "'" << endl;
00095           // Move to the next alternate
00096           if (++i != thealternates.end() && data->getSolver()->getLogLevel()>1)
00097             logger << indent(curflow->getOperation()->getLevel()) << "   Alternate flow switches from '"
00098                   << curflow->getBuffer()->getName() << "' to '"
00099                   << (*i)->getBuffer()->getName() << "'" << endl;
00100           continue;
00101         }
00102       }
00103 
00104       // Remember the first alternate
00105       if (!firstAlternate)
00106       {
00107         firstAlternate = *i;
00108         firstQuantity = data->state->q_flowplan->getQuantity();
00109       }
00110 
00111       // 4c) Ask the buffer
00112       data->state->q_qty = ask_qty = - data->state->q_flowplan->getQuantity();
00113       data->state->q_date = data->state->q_flowplan->getDate();
00114       Command* topcommand = data->getLastCommand();
00115       curflow->getBuffer()->solve(*this,data);
00116 
00117       // 4d) A positive reply: exit the loop
00118       if (data->state->a_qty > ROUNDING_ERROR) 
00119       {
00120         // Update the opplan, which is required to (1) update the flowplans
00121         // and to (2) take care of lot sizing constraints of this operation.
00122         if (data->state->a_qty < ask_qty - ROUNDING_ERROR)
00123         {
00124           flplan->setQuantity(-data->state->a_qty, true);
00125           data->state->a_qty = -flplan->getQuantity();
00126         }
00127         if (data->state->a_qty > ROUNDING_ERROR)
00128         {
00129           data->constrainedPlanning = originalPlanningMode;
00130           return;
00131         }
00132       }
00133 
00134       // 4e) Undo the plan on the alternate
00135       data->undo(topcommand);
00136 
00137       // 4f) Prepare for the next alternate
00138       if (data->state->a_date < min_next_date)
00139         min_next_date = data->state->a_date;
00140       if (++i != thealternates.end() && data->getSolver()->getLogLevel()>1)
00141         logger << indent(curflow->getOperation()->getLevel()) << "   Alternate flow switches from '"
00142               << curflow->getBuffer()->getName() << "' to '"
00143               << (*i)->getBuffer()->getName() << "'" << endl;
00144     }
00145 
00146     // 5) No reply found, all alternates are infeasible
00147     if (!originalPlanningMode)
00148     {
00149       assert(firstAlternate);
00150       // Unconstrained plan: Plan on the primary alternate
00151       // Switch to this flow
00152       if (flplan->getFlow() != firstAlternate)
00153         flplan->setFlow(firstAlternate);
00154       // Message
00155       if (data->getSolver()->getLogLevel()>1)
00156         logger << indent(fl->getOperation()->getLevel()) 
00157           << "   Alternate flow plans unconstrained on alternate '"
00158           << firstAlternate->getBuffer()->getName() << "'" << endl;
00159       // Plan unconstrained
00160       data->constrainedPlanning = false;
00161       data->state->q_flowplan = flplan; // because q_flowplan can change
00162       flplan->setQuantity(firstQuantity, true);
00163       data->state->q_qty = ask_qty = - flplan->getQuantity();
00164       data->state->q_date = flplan->getDate();
00165       Command* topcommand = data->getLastCommand();
00166       firstAlternate->getBuffer()->solve(*this,data);
00167       data->state->a_qty = -flplan->getQuantity();
00168       // Restore original planning mode
00169       data->constrainedPlanning = originalPlanningMode;
00170     }
00171     else
00172     {
00173       // Constrained plan: Return 0
00174       data->state->a_date = min_next_date;
00175       data->state->a_qty = 0;
00176       if (data->getSolver()->getLogLevel()>1)
00177         logger << indent(fl->getOperation()->getLevel()) <<
00178           "   Alternate flow doesn't find supply on any alternate : "
00179           << data->state->a_qty << "  " << data->state->a_date << endl;
00180     }
00181   }
00182   else
00183   {
00184     // CASE II: Not an alternate flow.
00185     // In this case, this method is passing control on to the buffer.
00186     data->state->q_qty = - data->state->q_flowplan->getQuantity();
00187     data->state->q_date = data->state->q_flowplan->getDate();
00188     if (data->state->q_qty != 0.0)
00189     {
00190       fl->getBuffer()->solve(*this,data);
00191       if (data->state->a_date > fl->getEffective().getEnd())
00192       {
00193         // The reply date must be less than the effectivity end date: after
00194         // that date the flow in question won't consume any material any more.
00195         if (data->getSolver()->getLogLevel()>1
00196           && data->state->a_qty < ROUNDING_ERROR)
00197           logger << indent(fl->getBuffer()->getLevel()) << "  Buffer '"
00198             << fl->getBuffer()->getName() << "' answer date is adjusted to "
00199             << fl->getEffective().getEnd()
00200             << " because of a date effective flow" << endl;
00201         data->state->a_date = fl->getEffective().getEnd();
00202       }
00203     }
00204     else
00205     {
00206       // It's a zero quantity flowplan.
00207       // E.g. because it is not effective.
00208       data->state->a_date = data->state->q_date;
00209       data->state->a_qty = 0.0;
00210     }
00211   }
00212 }
00213 
00214 
00215 }

Generated on 21 Mar 2010 for frePPLe by  doxygen 1.6.1