diff --git a/contribution/trunk/combinatorial/routing/vrptw/AUTHORS b/contribution/trunk/combinatorial/routing/vrptw/AUTHORS new file mode 100644 index 000000000..64d8614c4 --- /dev/null +++ b/contribution/trunk/combinatorial/routing/vrptw/AUTHORS @@ -0,0 +1,3 @@ + +Antonio LaTorre atorre[at]fi.upm.es +Thomas Legrand paradiseo-help[at]lists.gforge.inria.fr diff --git a/contribution/trunk/combinatorial/routing/vrptw/src/eoVRP.h b/contribution/trunk/combinatorial/routing/vrptw/src/eoVRP.h new file mode 100644 index 000000000..96b139e5e --- /dev/null +++ b/contribution/trunk/combinatorial/routing/vrptw/src/eoVRP.h @@ -0,0 +1,455 @@ +/* + * Copyright (C) DOLPHIN Project-Team, INRIA Futurs, 2006-2007 + * (C) OPAC Team, LIFL, 2002-2007 + * + * (c) Antonio LaTorre , 2007 + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + * + * ParadisEO WebSite : http://paradiseo.gforge.inria.fr + * Contact: paradiseo-help@lists.gforge.inria.fr + * + */ + +#ifndef _eoVRP_h +#define _eoVRP_h + +// The base definition of eoVector +#include + +// Utilities for the VRP-TW problem +#include "eoVRPUtils.h" + +/** + * \class eoVRP eoVRP.h + * \brief Defines the getoype used to solve the VRP-TW problem. + */ + +class eoVRP: public eoVector { + +public: + + /** + * \brief Default constructor: initializes variables to safe values. + */ + + eoVRP () : mLength (0.0) { + + } + + + /** + * \brief Copy contructor: creates a new individual from a given one. + * \param _orig The individual used to create the new one. + */ + + eoVRP (const eoVRP& _orig) { + + operator= (_orig); + + } + + + /** + * \brief Default destructor: nothing to do here. + */ + + virtual ~eoVRP () { + + } + + + /** + * \brief Performs a copy from the invidual passed as argument. + * \param _orig The individual to copy from. + * \return A reference to this. + */ + + eoVRP& operator= (const eoVRP& _orig) { + + // Sanity check + if (&_orig != this) { + + // Cleans both individual and decoding information + clean (); + + // We call the assignment operator from the base class + eoVector::operator= (_orig); + + // And then copy all our attributes + mRoutes = _orig.mRoutes; + mLength = _orig.mLength; + + } + + return *this; + + } + + + /** + * \brief Returns a string containing the name of the class. + * \return The string containing the name of the class. + */ + + virtual std::string className () const { + + return "eoVRP"; + + } + + + /** + * \brief Prints the individual to a given stream. + * \param _os The stream to print to. + */ + + void printOn (std::ostream& _os) const { + + // First write the fitness + _os << std::endl; + + // Then the individual itself using the base printing method + eoVector::printOn (_os); + _os << std::endl << std::endl; + + } + + + /** + * \brief Prints a detailed version of the individual (decoding information, unsatisfied contraints, etc.) to a given stream. + * \param _os The stream to print to. + */ + + void printAllOn (std::ostream& _os) const { + + // Print the individual itself using the base printing method + eoVector::printOn (_os); + _os << std::endl << std::endl; + + // Check if we have decoding information to print + if (decoded ()) { + + // First, we print the decoded routes (stored in mRoutes) + _os << " => Routes: " << std::endl << std::endl; + printRoutes (_os); + _os << std::endl << std::endl; + + if (this->invalid ()) + _os << " => Fitness: INVALID." << std::endl << std::endl; + else + _os << " => Fitness: " << this->fitness () << std::endl << std::endl; + + } + else + std::cerr << "Warning: 'printAllOn' called but the individual was not already decoded." << std::endl; + + } + + + /** + * \brief Reads an individual from a given stream. + * \param _is The stream to read from. + */ + + void readFrom (std::istream& _is) { + + // Read the individual using the method from the base class + eoVector::readFrom (_is); + + } + + + /** + * \brief Returns a reference to the decoded individual. + * \return A reference to the decoded individual. + */ + + const Routes& routes () { + + if (mRoutes.size () == 0) + std::cerr << "Warning: This individual has not been already decoded." << std::endl; + + return mRoutes; + + } + + + /** + * \brief Returns the total cost (length) of traveling all the routes. + * \return The total cost (length) of traveling all the routes. + */ + + double length () { + + return mLength; + + } + + + /** + * \brief Aux. method to print a structure of routes. + * \param _os The stream to print to. + */ + + void printRoutes (std::ostream& _os) const { + + _os << "["; + + for (unsigned i = 0; i < mRoutes.size (); i++) { + + _os << "["; + + printRoute (_os, i); + + if (i == mRoutes.size () - 1) + _os << "]"; + else + _os << "]," << std::endl; + } + + _os << "]"; + + } + + + /** + * \brief Aux. method to print only one route. + * \param _os The stream to print to. + * \param _p The route to print. + */ + + void printRoute (std::ostream& _os, unsigned _p) const { + + _os << "["; + + for (unsigned i = 0; i < mRoutes [_p].size (); i++) { + + _os << mRoutes [_p][i]; + + if (i != mRoutes [_p].size () - 1) + _os << ", "; + + } + + _os << "]"; + + } + + + /** + * \brief Cleans the individual (the vector of clients and also the decoding information). + * \return True if the operation finishes correctly. False otherwise. + */ + + bool clean () { + + this->clear (); + mRoutes.clear (); + mLength = 0.0; + + return true; + + } + + + /** + * \brief Invalidates the decoding information (usually after crossover or mutation). + * \return True if the operation finishes correctly. False otherwise. + */ + + bool cleanRoutes () { + + mRoutes.clear (); + mLength = 0.0; + + return true; + + } + + + /** + * \brief Has this individual been decoded? + * \return True if has decoding information. False otherwise. + */ + + bool decoded () const { + + if (mRoutes.size () == 0) + return false; + + return true; + + } + + + /** + * \brief Encodes an individual from a set of routes (usually used within crossover). + * \return True if the operation finishes correctly. False otherwise. + */ + + bool encode (Routes& _routes) { + + clean (); + + for (unsigned i = 0; i < _routes.size (); i++) { + + for (unsigned j = 0; j < _routes [i].size (); j++) + this->push_back (_routes [i][j]); + + } + + return true; + + } + + + /** + * \brief Decodes an individual in a set of routes and calculates its cost (length) of traveling. + * \return The cost (length) of traveling the set of routes. + */ + + double decode () { + + bool routeStart = true; + + double demand = 0.0, route_len = 0.0, time = 0.0; + double readyTime, dueTime, serviceTime; + double depotReadyTime, depotDueTime, depotServiceTime; + + cleanRoutes (); + + Route route; + + eoVRPUtils::getTimeWindow (0, depotReadyTime, depotDueTime, depotServiceTime); + + for (unsigned i = 0; i < this->size (); i++) { + + if (routeStart) { + + demand = eoVRPUtils::clients [this->operator[] (i)].demand; + route_len = eoVRPUtils::distance (0, this->operator[] (i)); + time = eoVRPUtils::distance (0, this->operator[] (i)); + + // The capacity of the vehicle must NEVER be exceeded by the first client + // (it would be an instance impossible to solve in that case) + if (demand > VEHICLE_CAPACITY) { + + std::cerr << "This should never happen: " << std::endl; + abort (); + + } + + // Check that its TW is not exceeded + eoVRPUtils::getTimeWindow (this->operator[] (i), readyTime, dueTime, serviceTime); + + // Same thing as with capacity and first client, but now with the TW + if (time > dueTime) { + + std::cerr << "This should never happen: " << std::endl; + abort (); + + } + else if (time < readyTime) + time = readyTime; + + time += serviceTime; + + route.push_back (this->operator[] (i)); + + routeStart = false; + + } + else { + + time += eoVRPUtils::distance (this->operator[] (i - 1), this->operator[] (i)); + + // Check that its TW is not exceeded + eoVRPUtils::getTimeWindow (this->operator[] (i), readyTime, dueTime, serviceTime); + + if ((time > dueTime) || (time + serviceTime + eoVRPUtils::distance (this->operator[] (i), 0) > depotDueTime) || + (demand + eoVRPUtils::clients [this->operator[] (i)].demand > VEHICLE_CAPACITY) ) { + + route_len += eoVRPUtils::distance (this->operator[] (i - 1), 0); + + mLength += route_len; + + i--; + routeStart = true; + + // A route should contain, at least, one client. This should never happen, anyway... + if (route.size () == 0) { + + std::cerr << "Error: empty route detected while decoding. The wrong genome follows..." << std::endl; + this->printOn (std::cerr); + abort (); + + } + + mRoutes.push_back (route); + route.clear (); + + } + else { + + if (time < readyTime) + time = readyTime; + + time += serviceTime; + + route_len += eoVRPUtils::distance (this->operator[] (i - 1), this->operator[] (i)); + demand += eoVRPUtils::clients [this->operator[] (i)].demand; + + route.push_back (this->operator[] (i)); + + } + + } + + } + + if (route.size () > 0) { + + route_len += eoVRPUtils::distance (route [route.size () - 1], 0); + + mLength += route_len; + mRoutes.push_back (route); + route.clear (); + + } + + return mLength; + + } + + +private: + + Routes mRoutes; /**< A set of routes containing the decoding information of the individual. */ + double mLength; /**< Cached cost (length) of traveling the set of routes defined by the individual. */ + +}; + +#endif diff --git a/contribution/trunk/combinatorial/routing/vrptw/src/eoVRPEvalFunc.h b/contribution/trunk/combinatorial/routing/vrptw/src/eoVRPEvalFunc.h new file mode 100644 index 000000000..df836b210 --- /dev/null +++ b/contribution/trunk/combinatorial/routing/vrptw/src/eoVRPEvalFunc.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) DOLPHIN Project-Team, INRIA Futurs, 2006-2007 + * (C) OPAC Team, LIFL, 2002-2007 + * + * (c) Antonio LaTorre , 2007 + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + * + * ParadisEO WebSite : http://paradiseo.gforge.inria.fr + * Contact: paradiseo-help@lists.gforge.inria.fr + * + */ + +#ifndef _eoVRPEvalFunc_h +#define _eoVRPEvalFunc_h + +// General includes +#include +#include + +// The base definition of eoEvalFunc +#include "eoEvalFunc.h" + +// Utilities for the VRP-TW problem +#include "eoVRPUtils.h" + +/** + * \class eoVRPEvalFunc eoVRPEvalFunc.h + * \brief Evaluates an individual of type eoVRP. + */ + +class eoVRPEvalFunc : public eoEvalFunc { + +public: + + /** + * \brief Constructor: nothing to do here. + */ + + eoVRPEvalFunc () { + + } + + + /** + * \brief Computes the (penalized) fitness + * \param _eo The individual to be evaluated. + */ + + void operator () (eoVRP& _eo) { + + double fit = 0.0; + + if (_eo.decoded ()) { + + if (_eo.invalid ()) { + + std::cerr << "Warning: invalid individual presents decoding information." << std::endl; + fit = _eo.decode (); + + } + else + fit = _eo.length (); + + } + else { + + if (!_eo.invalid ()) { + + std::cerr << "Warning: valid individual does not present decoding information." << std::endl; + std::cerr << " Proceeding to decode..." << std::endl; + + } + + fit = _eo.decode (); + + } + + _eo.fitness (fit); + + } + + +private: + + +}; + +#endif diff --git a/contribution/trunk/combinatorial/routing/vrptw/src/eoVRPInit.h b/contribution/trunk/combinatorial/routing/vrptw/src/eoVRPInit.h new file mode 100644 index 000000000..0c4f027df --- /dev/null +++ b/contribution/trunk/combinatorial/routing/vrptw/src/eoVRPInit.h @@ -0,0 +1,606 @@ +/* + * Copyright (C) DOLPHIN Project-Team, INRIA Futurs, 2006-2007 + * (C) OPAC Team, LIFL, 2002-2007 + * + * (c) Antonio LaTorre , 2007 + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + * + * ParadisEO WebSite : http://paradiseo.gforge.inria.fr + * Contact: paradiseo-help@lists.gforge.inria.fr + * + */ + +#ifndef _eoVRPInit_h +#define _eoVRPInit_h + +// The base definition of eoInit +#include + +// Utilities for the VRP-TW problem +#include "eoVRPUtils.h" + +/** + * \def ALFA + * Constant used by "selectCheapestClient" method. + * \def BETA + * Constant used by "selectCheapestClient" method. + * \def GAMMA + * Constant used by "selectCheapestClient" method. + */ + +#define ALFA 0.7 +#define BETA 0.1 +#define GAMMA 0.2 + +/** + * \class eoVRPInit eoVRPInit.h + * \brief Class defining the initializer functor. + * This class initializes an individual of the VRP problem using + * an heuristic initializer. + */ + +class eoVRPInit: public eoInit { + +public: + + /** + * \brief Default constructor: nothing to do here. + */ + + eoVRPInit () { + + unsigned sz = eoVRPUtils::clients.size (); + + if (sz <= 0) { + + std::cerr << "Error: the dataset MUST be read before creating the initializer object." << std::endl; + abort (); + + } + + mSeedsUsedCount = 0; + + for (unsigned i = 0; i < sz; i++) + mSeedsUsed.push_back (false); + + } + + + /** + * \brief Functor member. + * Initializes a genotype using an heuristic initializer. + * \param _gen Generally a genotype that has been default-constructed. + * Whatever it contains will be lost. + */ + + void operator () (eoVRP& _gen) { + + HeuristicInitialization (_gen); + + } + + +private: + + unsigned mSeedsUsedCount; /**< Number of clients already used as seeds. */ + std::vector mSeedsUsed; /**< Vector storing if a client has been used as a seed or not. */ + + + /** + * \brief Heuristic initializer. + * This initializer constructs and individual from routes. Each route is built + * in a constructive way. The first client of each route is selected trying to + * maximize a function depending on its time window and how far it is from the depot. + * We always try to select the hardest clients as seeds. Used seeds are stored + * so that different seeds are selected for different individuals and thus guarantee + * the diversity of the initial population. + * \param _gen The individual to be initialized. + */ + + void HeuristicInitialization (eoVRP& _gen) { + + // Aux var to override seed used checking + bool seedCheckingOverride = false; + + // Erase any previous contents + _gen.clear (); + + // Aux vector to store unvisited clients + std::vector unvisited; + + // And an index to point to the last unvisited cutomer + int unvisitedIdx = eoVRPUtils::clients.size () - 2; + + // Initialization of the unvisited vector with all the clients + for (unsigned i = 1; i < eoVRPUtils::clients.size (); i++) + unvisited.push_back (i); + + // Main loop: keep iterating until all clients are visited + while (unvisitedIdx >= 0) { + + // Aux var to store the new route + Route route; + + createNewRoute (unvisited, unvisitedIdx, seedCheckingOverride, route); + seedCheckingOverride = true; + + for (unsigned i = 0; i < route.size (); i++) + _gen.push_back (route [i]); + + } + + // Invalidates the genotype forcing its re-evaluation + _gen.invalidate (); + + } + + + /** + * \brief Creates a new route. + * Creates a new route selecting the best (hardest) client as seed and then adding + * the cheapest clients until one of the constraints (time window or vehicle's capacity) + * is broken. + * \param _unvisited Vector of unvisited and thus available clients for constructing the new route. + * \param _unvisitedIdx Position of the last univisted client in _unvisited vector. + * \param _seedCheckingOverride If true, it overrides the seed checking mecanism. It must be + * always false for the first route and then true for the following ones. + * This way we will preserve diversity in our initial population as every individual + * will be initialized from a different initial route. + * \param _route The brand new route we have constructed. + * \return True if everything went ok. + */ + + bool createNewRoute (std::vector& _unvisited, int& _unvisitedIdx, + bool _seedCheckingOverride, Route& _route ) { + + // Selection of seed client for current route + unsigned seed = selectBestClientAsSeed (_unvisited, _unvisitedIdx, _seedCheckingOverride); + + // Add the seed client to the route + _route.push_back (_unvisited [seed]); + + // Mark the client as already selected as a main seed + // (i.e., as a seed for the first subroute of an individual) + if (!_seedCheckingOverride) { + + mSeedsUsed [_unvisited [seed]] = true; + mSeedsUsedCount++; + + if (mSeedsUsedCount == mSeedsUsed.size () - 1) { + + mSeedsUsedCount = 0; + + for (unsigned i = 0; i < mSeedsUsed.size (); i++) + mSeedsUsed [i] = false; + + } + + } + + // Delete the selected client from the unvisited vector + _unvisited [seed] = _unvisited [_unvisitedIdx]; + _unvisitedIdx--; + + bool feasibleInsert = true; + + while (feasibleInsert && _unvisitedIdx >= 0) { + + // Aux var to store the position to insert new clients in the route + Route::iterator it; + + unsigned next; + + if (selectBestInsertion (_unvisited, _unvisitedIdx, _route, next, it)) { + + if (it == _route.end ()) + _route.insert (_route.begin (), _unvisited [next]); + else + _route.insert (it + 1, _unvisited [next]); + + _unvisited [next] = _unvisited [_unvisitedIdx]; + _unvisitedIdx--; + + } + else + feasibleInsert = false; + + } + + return true; + + } + + + /** + * \brief Selects the best client and the best position for its insertion in a given route. + * Given a subroute, this method tries to find the best client and the best position for it + * among all the univisited clients. + * \param _unvisited Vector of unvisited and thus available clients for constructing the new route. + * \param _unvisitedIdx Position of the last univisted client in _unvisited vector. + * \param _route The route where we are trying to insert a new client. + * \param _nextClient A return value. The selected client to be inserted. + * \param _it A return value. The position for selected client to be inserted. + * \return True if a new insertion is possible. False otherwise. + */ + + bool selectBestInsertion (std::vector& _unvisited, unsigned _unvisitedIdx, Route& _route, + unsigned& _nextClient, Route::iterator& _it ) { + + double minCost = 999999999; + bool found = false; + + bool insertionPossible = false; + double cost = 0.0; + + for (unsigned i = 0; i < _unvisitedIdx; i++) { + + insertionPossible = evaluateInsertion (_route, _unvisited [i], -1, cost); + + if (insertionPossible && cost < minCost) { + + _it = _route.end (); + _nextClient = i; + minCost = cost; + found = true; + + } + + } + + for (Route::iterator it = _route.begin (); it != _route.end (); it++) { + + for (unsigned i = 0; i < _unvisitedIdx; i++) { + + insertionPossible = evaluateInsertion (_route, _unvisited [i], *it, cost); + + if (insertionPossible && cost < minCost) { + + _it = it; + _nextClient = i; + minCost = cost; + found = true; + + } + + } + + } + + return found; + + } + + + /** + * \brief Evaluates the feasibility and the cost of inserting a new client in a given subroute. + * Given a subroute, this method tries evaluates if it is possible to insert a client in a position. + * It will return the cost of the resulting route if this insertion is possible. + * \param _route The route where we are trying to insert a new client. + * \param _newClient The client we are trying to insert. + * \param _afterClient The position of insertion. + * \param _cost A return value. The cost of inserting the given client at the given position. + * \return True if the new insertion is possible. False otherwise. + */ + + bool evaluateInsertion (Route& _route, unsigned _newClient, int _afterClient, double& _cost) { + + // First of all, we check for capacity constraint to be satisfied + // before trying to insert the new client in the route + double demand = 0.0; + + // Cummulate the demand of all the clients in the current route + for (unsigned i = 0; i < _route.size (); i++) + demand += eoVRPUtils::clients [i].demand; + + // And then the demand of the new client + demand += eoVRPUtils::clients [_newClient].demand; + + // And finally, check if the cummulated demand exceeds vehicle's capacity + if (demand > VEHICLE_CAPACITY) + return false; + + // Now check for insertion position and TW constraints + double readyTime, dueTime, serviceTime; + + // If the client must be inserted after client "-1" that means that it + // has to be inserted at the very beginning of the route + if (_afterClient == - 1) { + + // We calculate the distante from the depot to the inserted client + _cost = eoVRPUtils::distance (0, _newClient); + + // And check that its TW is not exceeded + eoVRPUtils::getTimeWindow (_newClient, readyTime, dueTime, serviceTime); + + if (_cost > dueTime) + return false; + + // If the vehicle arrives before client's ready time, it has + // to wait until the client is ready + if (_cost < readyTime) + _cost = readyTime; + + // Add the service time for the newly inserted client + _cost += serviceTime; + + // And the cost of traveling to the next one (the first one in the old route) + _cost = _cost + eoVRPUtils::distance (_newClient, _route [0]); + + } + else + // We just need to add the cost of traveling from the depot to the first client + _cost = eoVRPUtils::distance (0, _route [0]); + + // Main loop to evaluate the rest of the route (except the last position) + for (unsigned i = 0; i < _route.size () - 1; i++) { + + // Check that the TW is not exceeded for the current client + eoVRPUtils::getTimeWindow (_route [i], readyTime, dueTime, serviceTime); + + if (_cost > dueTime) + return false; + + // If it is not exceeded, we check wether the vehicle arrives before + // the client is ready. If that's the case, it has to wait + if (_cost < readyTime) + _cost = readyTime; + + // We add the service time for this client + _cost += serviceTime; + + // And now check if we have to insert the new client after the current one + if (_route [i] == _afterClient) { + + // If that's the case, we add the cost of traveling from current client + // to the new one + _cost = _cost + eoVRPUtils::distance (_route [i], _newClient); + + // And check for its TW to be not exceeded + eoVRPUtils::getTimeWindow (_newClient, readyTime, dueTime, serviceTime); + + if (_cost > dueTime) + return false; + + // If the vehicle arrives before client's ready time, it has + // to wait until the client is ready + if (_cost < readyTime) + _cost = readyTime; + + // Add the service time for the newly inserted client + _cost += serviceTime; + + // And the cost of traveling to the next one + _cost = _cost + eoVRPUtils::distance (_newClient, _route [i + 1]); + + } + else + // We simply add the cost of traveling to the next client + _cost = _cost + eoVRPUtils::distance (_route [i], _route [i + 1]); + + } + + // Consider the special case where the new client has + // to be inserted at the end of the route + unsigned last =_route [_route.size () - 1]; + + // We first check that the TW of the last client in the old route + // has not been exedeed + eoVRPUtils::getTimeWindow (last, readyTime, dueTime, serviceTime); + + if (_cost > dueTime) + return false; + + // If the vehicle arrives before the client is ready, it waits + if (_cost < readyTime) + _cost = readyTime; + + // Now we add its service time + _cost += serviceTime; + + // And check if the new client has to be inserted at the end + // of the old route + if (_afterClient == last) { + + // In that case, we add the cost of traveling from the last client + // to the one being inserted + _cost = _cost + eoVRPUtils::distance (last, _newClient); + + // Check for its TW not being exceeded + eoVRPUtils::getTimeWindow (_newClient, readyTime, dueTime, serviceTime); + + if (_cost > dueTime) + return false; + + // If the vehicle arrives before the new client is ready, it waits + if (_cost < readyTime) + _cost = readyTime; + + // Now we add its service time + _cost += serviceTime; + + // And, finally, the time to travel back to the depot + _cost = _cost + eoVRPUtils::distance (_newClient, 0); + + } + else + // In this case we just add the cost of traveling back to the depot + _cost = _cost + eoVRPUtils::distance (last, 0); + + // Last thing to check is that the vehicle is back on time to the depot + eoVRPUtils::getTimeWindow (0, readyTime, dueTime, serviceTime); + + if (_cost > dueTime) + return false; + + // If all constraints are satisfied, we return true, and the cost of the + // insertion in the variable "_cost" + return true; + + } + + + /** + * \brief Selects the farthest client as seed for a new route. + * \param _unvisited Vector of unvisited and thus available clients for constructing the new route. + * \param _unvisitedIdx Position of the last univisted client in _unvisited vector. + * \return The position of the client farthest from the depot. + */ + + unsigned selectFarthestClientAsSeed (const std::vector& _unvisited, int _unvisitedIdx) { + + unsigned maxPos = 0; + double maxDist = eoVRPUtils::distance (0, _unvisited [0]); + + for (unsigned i = 1; i <= _unvisitedIdx; i++) + if (eoVRPUtils::distance (0, _unvisited [i]) > maxDist) { + + maxPos = i; + maxDist = eoVRPUtils::distance (0, _unvisited [i]); + + } + + return maxPos; + + } + + + /** + * \brief Selects the cheapest client as seed for a new route. + * \param _unvisited Vector of unvisited and thus available clients for constructing the new route. + * \param _unvisitedIdx Position of the last univisted client in _unvisited vector. + * \param _seedCheckingOverride If true, it overrides the seed checking mecanism. + * \return The position of the cheapest client. + */ + + unsigned selectCheapestClient (const std::vector& _unvisited, int _unvisitedIdx, bool _seedCheckingOverride) { + + int cheapestPos = -1; + double cheapestCost = 999999999; + + for (unsigned i = 0; i <= _unvisitedIdx; i++) { + + double cost = (-ALFA * eoVRPUtils::distance (0, _unvisited [i]) ) + + ( BETA * eoVRPUtils::clients [_unvisited [i]].dueTime) + + (GAMMA * eoVRPUtils::polarAngle (0, _unvisited [i]) / 360 * eoVRPUtils::distance (0, _unvisited [i])); + + if ((cost < cheapestCost || (cost == cheapestCost && rng.flip ())) && + (!mSeedsUsed [_unvisited [i]] || _seedCheckingOverride ) ) { + + cheapestPos = i; + cheapestCost = cost; + + } + + } + + return cheapestPos; + + } + + + /** + * \brief Selects the best (the "hardest" one) client as seed for a new route. + * \param _unvisited Vector of unvisited and thus available clients for constructing the new route. + * \param _unvisitedIdx Position of the last univisted client in _unvisited vector. + * \param _seedCheckingOverride If true, it overrides the seed checking mecanism. + * \return The position of the best client. + */ + + unsigned selectBestClientAsSeed (const std::vector& _unvisited, int _unvisitedIdx, bool _seedCheckingOverride) { + + int cheapestPos = -1; + double cheapestCost = 999999999; + double alfa, beta; + + alfa = rng.uniform (); + beta = rng.uniform (); + + for (unsigned i = 0; i <= _unvisitedIdx; i++) { + + double cost = (alfa * eoVRPUtils::distance (0, _unvisited [i])) + + (beta * (eoVRPUtils::clients [_unvisited [i]].dueTime - eoVRPUtils::clients [_unvisited [i]].readyTime)); + + + if ((cost < cheapestCost || (cost == cheapestCost && rng.flip ())) && + (!mSeedsUsed [_unvisited [i]] || _seedCheckingOverride ) ) { + + cheapestPos = i; + cheapestCost = cost; + + } + + } + + return cheapestPos; + + } + + + /** + * \brief Random initializer. + * Initializes a genotype using a random initializer. + * @param _gen Generally a genotype that has been default-constructed. + * Whatever it contains will be lost. + */ + + void RandomInitializationNoCheck (eoVRP& _gen) { + + // Erase any previous contents + _gen.clear (); + + // Aux vector to store unvisited clients + std::vector unvisited; + + // And an index to point to the last unvisited cutomer + int unvisitedIdx = eoVRPUtils::clients.size () - 2; + + // Initialization of the unvisited vector with all the clients + for (unsigned i = 1; i < eoVRPUtils::clients.size (); i++) + unvisited.push_back (i); + + while (unvisitedIdx >= 0) { + + unsigned n = rng.random (unvisitedIdx); + + for (unsigned i = 0; i <= n; i++) { + + unsigned pos = rng.random (unvisitedIdx); + + _gen.push_back (unvisited [pos]); + + unvisited [pos] = unvisited [unvisitedIdx]; + unvisitedIdx--; + + } + + } + + } + + +}; + +#endif diff --git a/contribution/trunk/combinatorial/routing/vrptw/src/eoVRPMutation.h b/contribution/trunk/combinatorial/routing/vrptw/src/eoVRPMutation.h new file mode 100644 index 000000000..b65fc3dfa --- /dev/null +++ b/contribution/trunk/combinatorial/routing/vrptw/src/eoVRPMutation.h @@ -0,0 +1,229 @@ +/* + * Copyright (C) DOLPHIN Project-Team, INRIA Futurs, 2006-2007 + * (C) OPAC Team, LIFL, 2002-2007 + * + * (c) Antonio LaTorre , 2007 + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + * + * ParadisEO WebSite : http://paradiseo.gforge.inria.fr + * Contact: paradiseo-help@lists.gforge.inria.fr + * + */ + +#ifndef eoVRPMutation_H +#define eoVRPMutation_H + +// General includes +#include + +// The base definition of eoMonOp +#include + +/** + * \class eoVRPMutation eoVRPMutation.h + * \brief Implementation of variations of the four mutation operators for the VRP-TW defined by Tavares et al. + * These four operators should be separated in different classes and their probabilities + * made parameterizable. + */ + +class eoVRPMutation: public eoMonOp { + +public: + + /** + * \brief Default constructor: nothing to do here. + */ + + eoVRPMutation () { + + } + + + /** + * \brief Returns a string containing the name of the class. Used to display statistics. + * \return The string containing the name of the class. + */ + + std::string className () const { + + return "eoVRPMutation"; + + } + + + /** + * \brief Functor operator. + * Applies one of the four mutation operators available, each of them with a predefined + * (hard-coded) probability. These operators should be separated in different classes + * and their probabilities made parameterizable to do it in a more "paradisEO" way. + * \param _genotype The genotype being mutated (it will be probably modified). + * \return True if the individual has been modified. False otherwise. + */ + + bool operator () (eoVRP& _genotype) { + + bool res = false; + double op = rng.uniform (); + + + if (op <= 0.05) + res = swapMutation (_genotype); + else if ((op > 0.05) && (op <= 0.20)) + res = inversionMutation (_genotype); + else if ((op > 0.20) && (op <= 0.25)) + res = insertionMutation (_genotype); + else if ((op > 0.25) && (op <= 0.45)) + res = DisplacementMutation (_genotype); + + if (res) + _genotype.cleanRoutes (); + + return res; + + } + + +private: + + + /** + * \brief It exhanges the positions of two clients within the individual. + * Clients may or may not be in the same route. + * \param _genotype The genotype being mutated (it will be probably modified). + * \return True if the individual has been modified. False otherwise. + */ + + bool swapMutation (eoVRP& _genotype) { + + int p1 = rng.random (_genotype.size ()); + int p2 = -1; + + do { + p2 = rng.random (_genotype.size ()); + } while (_genotype [p2] == _genotype [p1]); + + std::swap (_genotype [p1], _genotype [p2]); + + return true; + + } + + + /** + * \brief It selects two positions in the genotype and inverts the clients between them. + * Clients may or may not be in the same route. + * \param _genotype The genotype being mutated (it will be probably modified). + * \return True if the individual has been modified. False otherwise. + */ + + bool inversionMutation (eoVRP& _genotype) { + + int p1 = rng.random (_genotype.size ()); + int p2 = -1; + + do { + p2 = rng.random (_genotype.size ()); + } while (_genotype [p2] == _genotype [p1]); + + if (p1 > p2) + std::swap (p1, p2); + + // Reverse the subroute + reverse (_genotype.begin () + p1, _genotype.begin () + p2 + 1); + + + return false; + + } + + + /** + * \brief It selects and individual, erases it from its original position and inserts it somewhere else. + * The insertion may or may not be within the same route. + * \param _genotype The genotype being mutated (it will be probably modified). + * \return True if the individual has been modified. False otherwise. + */ + + bool insertionMutation (eoVRP& _genotype) { + + int p = -1; + + // Selection of the client to be moved + do { + p = rng.random (_genotype.size ()); + } while (_genotype [p] == -1); + + // Temporary copy of the client + unsigned client = _genotype [p]; + + _genotype.erase (_genotype.begin () + p); + + p = rng.random (_genotype.size () - 1); + _genotype.insert (_genotype.begin () + p, client); + + return true; + + } + + + /** + * \brief It selects a set of clients, erases them from their original position and inserts them somewhere else. + * The selected set of clients may cover different routes. + * \param _genotype The genotype being mutated (it will be probably modified). + * \return True if the individual has been modified. False otherwise. + */ + + bool DisplacementMutation (eoVRP& _genotype) { + + int p1 = rng.random (_genotype.size ()); + int p2 = -1; + + do { + p2 = rng.random (_genotype.size ()); + } while (_genotype [p2] == _genotype [p1]); + + if (p1 > p2) + std::swap (p1, p2); + + // Temporary copy of the fragment being moved + Route route; + + for (unsigned i = p1; i <= p2; i++) + route.push_back (_genotype [i]); + + _genotype.erase (_genotype.begin () + p1, _genotype.begin () + p2 + 1); + + unsigned p = rng.random ((_genotype.size () > 0) ? _genotype.size () - 1 : 0); + _genotype.insert (_genotype.begin () + p, route.begin (), route.end ()); + + return true; + + } + + +}; + +#endif diff --git a/contribution/trunk/combinatorial/routing/vrptw/src/eoVRPQuadCrossover.h b/contribution/trunk/combinatorial/routing/vrptw/src/eoVRPQuadCrossover.h new file mode 100644 index 000000000..bf5f4df64 --- /dev/null +++ b/contribution/trunk/combinatorial/routing/vrptw/src/eoVRPQuadCrossover.h @@ -0,0 +1,408 @@ +/* + * Copyright (C) DOLPHIN Project-Team, INRIA Futurs, 2006-2007 + * (C) OPAC Team, LIFL, 2002-2007 + * + * (c) Antonio LaTorre , 2007 + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + * + * ParadisEO WebSite : http://paradiseo.gforge.inria.fr + * Contact: paradiseo-help@lists.gforge.inria.fr + * + */ + +#ifndef eoVRPQuadCrossover_H +#define eoVRPQuadCrossover_H + +// General includes +#include +#include +#include +#include + +// The base definition of eoQuadOp +#include + +/** + * \class eoVRPGenericCrossover eoVRPQuadCrossover.h + * \brief Implementation of the generic crossover for the VRP-TW by Tavares et al. + */ + +class eoVRPGenericCrossover: public eoQuadOp { + +public: + + /** + * \brief Deafult constructor. + */ + + eoVRPGenericCrossover () { + + } + + + /** + * \brief Returns a string containing the name of the class. Used to display statistics. + * \return The string containing the name of the class. + */ + + std::string className () const { + + return "eoVRPGenericCrossover"; + + } + + + /** + * \brief Both parameters are the parents and the (future) children of the crossover. + * \param _genotype1 The first parent. + * \param _genotype2 The second parent. + * \return True if any of the parents was modified. False otherwise. + */ + + bool operator () (eoVRP& _genotype1, eoVRP& _genotype2) { + + Routes c1 = _genotype1.routes (); + Routes c2 = _genotype2.routes (); + + GenericCrossover (_genotype1.routes (), c2); + GenericCrossover (_genotype2.routes (), c1); + + _genotype1.encode (c1); + _genotype2.encode (c2); + + return true; + + } + + +private: + + /** + * \brief Actually performs the generic crossover. + * \param _donor Set of routes from the first parent. + * \param _receiver Set of routes from the second parent + * \return True if the second parent was modified. False otherwise. + */ + + bool GenericCrossover (const Routes& _donor, Routes& _receiver) const { + + unsigned srcRoute = rng.random (_donor.size ()); + unsigned srcPos1 = rng.random (_donor [srcRoute].size ()); + unsigned srcPos2 = rng.random (_donor [srcRoute].size ()); + + if (srcPos1 > srcPos2) + std::swap (srcPos1, srcPos2); + + Route::iterator it; + + for (unsigned i = srcPos1; i <= srcPos2; i++) + for (unsigned j = 0; j < _receiver.size (); j++) { + + it = find (_receiver [j].begin (), _receiver [j].end (), _donor [srcRoute][i]); + + if (it != _receiver [j].end ()) { + + // Deletion of the repeated client + _receiver [j].erase (it); + + // Deletion of empty route, if necessary + if (_receiver [j].size () == 0) + _receiver.erase (_receiver.begin () + j); + + break; + + } + + } + + unsigned dstRoute = rng.random (_receiver.size ()); + + it = _receiver [dstRoute].begin () + rng.random (_receiver [dstRoute].size ()); + + _receiver [dstRoute].insert (it + 1, _donor [srcRoute].begin () + srcPos1, _donor [srcRoute].begin () + srcPos2 + 1); + + return true; + + } + +}; + + +/** + * \class eoVRPOnePointCrossover eoVRPQuadCrossover.h + * \brief Implementation of the simple One Point Crossover. + */ + +class eoVRPOnePointCrossover: public eoQuadOp { + +public: + + /** + * \brief Deafult constructor. + */ + + eoVRPOnePointCrossover () { + + } + + + /** + * \brief Returns a string containing the name of the class. Used to display statistics. + * \return The string containing the name of the class. + */ + + std::string className () const { + + return "eoVRPOnePointCrossover"; + + } + + + /** + * \brief Performs a one point crossover. Both parameters are the parents and the (future) children of the crossover. + * \param _genotype1 The first parent. + * \param _genotype2 The second parent. + * \return True if any of the parents was modified. False otherwise. + */ + + bool operator () (eoVRP& _genotype1, eoVRP& _genotype2) { + + eoVRP& _gen = _genotype1; + + unsigned orig1, orig2, dest; + + // First child + orig1 = rng.random (_genotype2.size ()); + orig2 = rng.random (_genotype2.size ()); + + if (orig1 > orig2) + std::swap (orig1, orig2); + + for (unsigned i = orig1; i <= orig2; i++) + _genotype1.erase (find (_genotype1.begin (), _genotype1.end (), _genotype2 [i])); + + dest = rng.random (_genotype1.size ()); + + _genotype1.insert (_genotype1.begin () + dest, _genotype2.begin () + orig1, _genotype2.begin () + orig2 + 1); + + // Second child + orig1 = rng.random (_gen.size ()); + orig2 = rng.random (_gen.size ()); + + if (orig1 > orig2) + std::swap (orig1, orig2); + + for (unsigned i = orig1; i <= orig2; i++) + _genotype2.erase (find (_genotype2.begin (), _genotype2.end (), _gen [i])); + + dest = rng.random (_genotype2.size ()); + + _genotype2.insert (_genotype2.begin () + dest, _gen.begin () + orig1, _gen.begin () + orig2 + 1); + + _genotype1.cleanRoutes (); + _genotype2.cleanRoutes (); + + return true; + + } + +}; + + +/** + * \class eoVRPEdgeCrossover eoVRPQuadCrossover.h + * \brief Implementation of the classic Edge Crossover from the TSP. + */ + +class eoVRPEdgeCrossover: public eoQuadOp { + +public: + + /** + * \brief Deafult constructor. + */ + + eoVRPEdgeCrossover () { + + } + + + /** + * \brief Returns a string containing the name of the class. Used to display statistics. + * \return The string containing the name of the class. + */ + + std::string className () const { + + return "eoVRPEdgeCrossover"; + + } + + + /** + * \brief Both parameters are the parents and the (future) children of the crossover. + * \param _genotype1 The first parent. + * \param _genotype2 The second parent. + * \return True if any of the parents was modified. False otherwise. + */ + + bool operator () (eoVRP& _genotype1, eoVRP& _genotype2) { + + eoVRP par [2]; + + // Backup of the parents + par [0] = _genotype1; + par [1] = _genotype2; + + _genotype1.clean (); + _genotype2.clean (); + + EdgeCrossover (par [0], par [1], _genotype1); + EdgeCrossover (par [0], par [1], _genotype2); + + return true; + + } + + +private: + + /** + * \brief Actually performs the edge crossover. + * \param _genotype1 First parent. + * \param _genotype2 Second parent. + * \param _child Child. + * \return True if the second parent was modified. False otherwise. + */ + + bool EdgeCrossover (eoVRP& _genotype1, eoVRP& _genotype2, eoVRP& _child) { + + std::vector > _map; + std::vector visited; + + // Build map + unsigned len = _genotype1.size () ; + + _map.resize (len+1) ; + + for (unsigned i = 0 ; i < len ; i ++) { + + _map [_genotype1 [i]].insert (_genotype1 [(i + 1) % len]) ; + _map [_genotype2 [i]].insert (_genotype2 [(i + 1) % len]) ; + _map [_genotype1 [i]].insert (_genotype1 [(i - 1 + len) % len]) ; + _map [_genotype2 [i]].insert (_genotype2 [(i - 1 + len) % len]) ; + + } + + visited.clear () ; + visited.resize (len+1, false) ; + + + _child.clear () ; + + unsigned cur_vertex = rng.random (len)+1; + + add_vertex (cur_vertex, visited, _map, _child); + + for (unsigned i = 1; i < len; i ++) { + + unsigned len_min_entry = MAXINT; + + std::set & neigh = _map [cur_vertex]; + + for (std::set ::iterator it = neigh.begin (); it != neigh.end (); it ++) { + + unsigned l = _map [*it].size (); + + if (len_min_entry > l) + len_min_entry = l; + + } + + std::vector cand; /* Candidates */ + + for (std::set ::iterator it = neigh.begin (); it != neigh.end (); it ++) { + + unsigned l = _map [*it].size (); + + if (len_min_entry == l) + cand.push_back (*it); + + } + + if (!cand.size ()) { + + /* Oh no ! Implicit mutation */ + for (unsigned j = 1; j <= len; j ++) + if (!visited [j]) + cand.push_back (j); + + } + + cur_vertex = cand [rng.random (cand.size ())] ; + + add_vertex (cur_vertex, visited, _map, _child); + + } + + } + + + /** + * \brief Removes a vertex from all his neighbours. + * \param _vertex The vertex being erased. + * \param _map The structure containing the neighbourhood relationship. + */ + + void remove_entry (unsigned _vertex, std::vector >& _map) { + + std::set & neigh = _map [_vertex]; + + for (std::set ::iterator it = neigh.begin (); it != neigh.end (); it++) + _map [*it].erase (_vertex); + + } + + + /** + * \brief Adds a vertex to a child and erases it from the list of available vertices. + * \param _vertex The vertex being added to the child. + * \param _visited The vector of visited vertices. + * \param _map The structure containing the neighbourhood relationship. + * \param _child The child where we add the vertex. + */ + + void add_vertex (unsigned _vertex, std::vector & _visited, std::vector >& _map, eoVRP& _child) { + + _visited [_vertex] = true; + _child.push_back (_vertex); + remove_entry (_vertex, _map); + + } + +}; + +#endif diff --git a/contribution/trunk/combinatorial/routing/vrptw/src/eoVRPStat.h b/contribution/trunk/combinatorial/routing/vrptw/src/eoVRPStat.h new file mode 100644 index 000000000..10f92c4c1 --- /dev/null +++ b/contribution/trunk/combinatorial/routing/vrptw/src/eoVRPStat.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) DOLPHIN Project-Team, INRIA Futurs, 2006-2007 + * (C) OPAC Team, LIFL, 2002-2007 + * + * (c) Antonio LaTorre , 2007 + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + * + * ParadisEO WebSite : http://paradiseo.gforge.inria.fr + * Contact: paradiseo-help@lists.gforge.inria.fr + * + */ + +#ifndef _eoVRPStat_h +#define _eoVRPStat_h + +// The base definition of eoInit +#include + +/** + * \class eoVRPStat eoVRPStat.h + * \brief Manages the statistics of the VRP problem. + */ + +class eoVRPStat : public eoStat { + +public: + + /** + * \brief Constructor: initializes variables properly. + * \param _description A string identifying the class. + */ + + eoVRPStat (std::string _description = "eoVRPStat ") : eoStat (0.0, _description) { + + } + + + /** + * \brief Gets statistics from a population. + * \param _pop The population that will be analyzed. + */ + + void operator() (const eoPop& _pop) { + + double tmpStat (0.); + eoStat::value () = tmpStat; + + } + + + /** + * \brief Returns a string containing the name of the class. Used to display statistics. + * \return The string containing the name of the class. + */ + + virtual std::string className (void) const { + + return "eoVRPStat"; + + } + + +private: + +}; + +#endif diff --git a/contribution/trunk/combinatorial/routing/vrptw/src/eoVRPUtils.h b/contribution/trunk/combinatorial/routing/vrptw/src/eoVRPUtils.h new file mode 100644 index 000000000..e6c723d6c --- /dev/null +++ b/contribution/trunk/combinatorial/routing/vrptw/src/eoVRPUtils.h @@ -0,0 +1,294 @@ +/* + * Copyright (C) DOLPHIN Project-Team, INRIA Futurs, 2006-2007 + * (C) OPAC Team, LIFL, 2002-2007 + * + * (c) Antonio LaTorre , 2007 + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + * + * ParadisEO WebSite : http://paradiseo.gforge.inria.fr + * Contact: paradiseo-help@lists.gforge.inria.fr + * + */ + +#ifndef eoVRPUtils_h +#define eoVRPUtils_h + +// General includes +#include +#include +#include +#include +#include +#include + +/** + * \def PI + * Guess you know what this constant represents. + */ + +#define PI 3.14159265 + +/** + * \def VEHICLE_CAPACITY + * Hard-coded parameter for the capacity of the vehicles. This + * should be parametrized in a config file in a future version. + */ + +#define VEHICLE_CAPACITY 200 + + +typedef std::vector Route; +typedef std::vector< Route > Routes; + + +/** + * \namespace eoVRPUtils + * \brief A set of structures and utility functions for the VRP-TW problem. + */ + +namespace eoVRPUtils { + +/** +* \var typedef struct ClientData ClientDataT. +* \brief Renaming of struct ClientData. +*/ + +/** +* \struct ClientData +* \brief Information regarding each client in the dataset. +* This structure is intended to be used to store the information of each +* client read from the data file. +*/ + +typedef struct ClientData { + + unsigned id; /**< Client ID number. */ + double x; /**< Client's 'x' position in the map. */ + double y; /**< Client's 'y' position in the map. */ + double demand; /**< Client's demand of delivered product. */ + double readyTime; /**< Client's beginning of the time window. */ + double dueTime; /**< Client's end of the time window. */ + double serviceTime; /**< Client's service time (time needed to serve the product). */ + +} ClientDataT; + + +static std::vector clients; /**< Vector to store clients's information. */ +static std::vector > dist; /**< Distance matrix. */ + + +/** + * \brief Computes the distance between two clients. + * The computed distances will be stored in dist. + */ + +void computeDistances () { + + unsigned numClients = clients.size (); + + dist.resize (numClients) ; + + for (unsigned i = 0; i < dist.size (); i ++) + dist [i].resize (numClients); + + // Distances computation + for (unsigned i = 0; i < dist.size (); i ++) + for (unsigned j = i + 1 ; j < dist.size (); j ++) { + + double distX = clients [i].x - clients [j].x; + double distY = clients [i].y - clients [j].y; + + dist [i][j] = dist [j][i] = sqrt (distX * distX + distY * distY); + + } + +} + + +/** + * \brief Returns the time window information of a given client. + * \param _client The client whose information we want to know. + * \param _readyTime Return value. The beginning of the client's time window. + * \param _dueTime Return value. The end of the client's time window. + * \param _serviceTime Return value. The client's service time. + */ + +void getTimeWindow (unsigned _client, double& _readyTime, double& _dueTime, double& _serviceTime) { + + assert (_client >= 0 && _client < clients.size ()); + + _readyTime = clients [_client].readyTime; + _dueTime = clients [_client].dueTime; + _serviceTime = clients [_client].serviceTime; + +} + + +/** + * \brief A function to get the distance between two clients. + * \param _from The first client. + * \param _to The second client. + * \return The distance between _from and _to. + */ + +float distance (unsigned _from, unsigned _to) { + + assert (_from >= 0 && _from < clients.size ()); + assert (_to >= 0 && _to < clients.size ()); + + return dist [_from][_to]; + +} + + +/** + * \brief Computes de polar angle between clients. + * \param _from The first client. + * \param _to The second client. + * \return The polar angle between _from and _to. + */ + +float polarAngle (unsigned _from, unsigned _to) { + + assert (_from >= 0 && _from < clients.size ()); + assert (_to >= 0 && _to < clients.size ()); + + double angle = atan2 (clients [_from].y - clients [_to].y, + clients [_from].x - clients [_to].x); + + // To convert it from radians to degrees + angle *= 180 / PI; + + if (angle < 0) + angle *= -1; + + return angle; + +} + + +/** + * \brief Loads the problem data from a given file. + * \param _fileName The file to load data from. + * \warning No error check is performed! + */ + +void load (const char* _fileName) { + + std::ifstream f (_fileName); + + if (f) { + + while (!f.eof ()) { + + ClientDataT client; + + f >> client.id; + f >> client.x; + f >> client.y; + f >> client.demand; + f >> client.readyTime; + f >> client.dueTime; + f >> client.serviceTime; + + clients.push_back (client); + + } + + f.close (); + + computeDistances (); + + } + else { + + std::cerr << "Error: the file: " << _fileName << " doesn't exist !!!" << std::endl ; + exit (1); + + } + +} + + +/** + * \brief Prints a route to the standard output. + * \param _route The route to print. + */ + +void printRoute (const Route& _route) { + + std::cout << "["; + + for (unsigned i = 0; i < _route.size (); i++) { + + std::cout << _route [i]; + + if (i != _route.size () -1) + std::cout << ", "; + + } + + std::cout << "]"; + +} + + +/** + * \brief Prints a set of routes to the standard output. + * \param _routes The set of routes to print. + */ + +void printRoutes (Routes& _routes) { + + std::cout << "["; + + for (unsigned i = 0; i < _routes.size (); i++) { + + std::cout << "["; + + for (unsigned j = 0; j < _routes [i].size (); j++) { + + std::cout << _routes [i][j]; + + if (j != _routes [i].size () -1) + std::cout << ", "; + + } + + if (i == _routes.size () -1) + std::cout << "]"; + else + std::cout << "]," << std::endl; + } + + std::cout << "]"; + +} + + +}; + +#endif diff --git a/contribution/trunk/combinatorial/routing/vrptw/src/index.h b/contribution/trunk/combinatorial/routing/vrptw/src/index.h new file mode 100644 index 000000000..3e8ea6fa0 --- /dev/null +++ b/contribution/trunk/combinatorial/routing/vrptw/src/index.h @@ -0,0 +1,59 @@ +/** @mainpage Welcome to PARADISEO - CVRP-TW contribution + +@section Introduction + +The capacitated vehicle routing problem with time windows or CVRP-TW is a combinatorial +optimization problem seeking to service a number of customers with a fleet of vehicles +where the vehicles have a mimited capacity and the delivery locations have time windows +within which the deliveries (or visits) must be made. Often the context is that of +delivering goods located at a central depot to customers who have placed orders for such +goods. Implicit is the goal of minimizing the cost of distributing the goods. Finding the +global minimum for the cost function, except for the smallest instances, is +computationally complex. + +@section authors AUTHORS + + + + + + + +
Dolphin project-team INRIA Futurs, 2007.Antonio LaTorre atorre[at]fi.upm.esThomas Legrand paradiseo-help[at]lists.gforge.inria.fr
+ + +@section LICENSE + + This software is governed by the CeCILL license under French law and + abiding by the rules of distribution of free software. You can use, + modify and/ or redistribute the software under the terms of the CeCILL + license as circulated by CEA, CNRS and INRIA at the following URL + "http://www.cecill.info". + + As a counterpart to the access to the source code and rights to copy, + modify and redistribute granted by the license, users are provided only + with a limited warranty and the software's author, the holder of the + economic rights, and the successive licensors have only limited liability. + + In this respect, the user's attention is drawn to the risks associated + with loading, using, modifying and/or developing or reproducing the + software by the user in light of its specific status of free software, + that may mean that it is complicated to manipulate, and that also + therefore means that it is reserved for developers and experienced + professionals having in-depth computer knowledge. Users are therefore + encouraged to load and test the software's suitability as regards their + requirements in conditions enabling the security of their systems and/or + data to be ensured and, more generally, to use and operate it in the + same conditions as regards security. + The fact that you are presently reading this means that you have had + knowledge of the CeCILL license and that you accept its terms. + + ParadisEO WebSite : http://paradiseo.gforge.inria.fr + Contact: paradiseo-help@lists.gforge.inria.fr + + +@section Paradiseo Home Page + +http://paradiseo.gforge.inria.fr + +*/