complete vcrptw package with an AUTHORS file + the sources at least

git-svn-id: svn://scm.gforge.inria.fr/svnroot/paradiseo@835 331e1502-861f-0410-8da2-ba01fb791d7f
This commit is contained in:
legrand 2007-12-07 15:45:50 +00:00
commit 7d6038307e
9 changed files with 2255 additions and 0 deletions

View file

@ -0,0 +1,3 @@
Antonio LaTorre atorre[at]fi.upm.es
Thomas Legrand paradiseo-help[at]lists.gforge.inria.fr

View file

@ -0,0 +1,455 @@
/*
* Copyright (C) DOLPHIN Project-Team, INRIA Futurs, 2006-2007
* (C) OPAC Team, LIFL, 2002-2007
*
* (c) Antonio LaTorre <atorre@fi.upm.es>, 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 <eoVector.h>
// 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<eoMinimizingFitness, int> {
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<eoMinimizingFitness, int>::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<eoMinimizingFitness, int>::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<eoMinimizingFitness, int>::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<eoMinimizingFitness, int>::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

View file

@ -0,0 +1,111 @@
/*
* Copyright (C) DOLPHIN Project-Team, INRIA Futurs, 2006-2007
* (C) OPAC Team, LIFL, 2002-2007
*
* (c) Antonio LaTorre <atorre@fi.upm.es>, 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 <stdexcept>
#include <fstream>
// 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<eoVRP> {
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

View file

@ -0,0 +1,606 @@
/*
* Copyright (C) DOLPHIN Project-Team, INRIA Futurs, 2006-2007
* (C) OPAC Team, LIFL, 2002-2007
*
* (c) Antonio LaTorre <atorre@fi.upm.es>, 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 <eoInit.h>
// 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 <eoVRP> {
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<bool> 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<int> 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<int>& _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<int>& _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<int>& _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<int>& _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<int>& _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<int> 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

View file

@ -0,0 +1,229 @@
/*
* Copyright (C) DOLPHIN Project-Team, INRIA Futurs, 2006-2007
* (C) OPAC Team, LIFL, 2002-2007
*
* (c) Antonio LaTorre <atorre@fi.upm.es>, 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 <algorithm>
// The base definition of eoMonOp
#include <eoOp.h>
/**
* \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 <eoVRP> {
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

View file

@ -0,0 +1,408 @@
/*
* Copyright (C) DOLPHIN Project-Team, INRIA Futurs, 2006-2007
* (C) OPAC Team, LIFL, 2002-2007
*
* (c) Antonio LaTorre <atorre@fi.upm.es>, 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 <assert.h>
#include <values.h>
#include <utils/eoRNG.h>
#include <set>
// The base definition of eoQuadOp
#include <eoOp.h>
/**
* \class eoVRPGenericCrossover eoVRPQuadCrossover.h
* \brief Implementation of the generic crossover for the VRP-TW by Tavares et al.
*/
class eoVRPGenericCrossover: public eoQuadOp <eoVRP> {
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 <eoVRP> {
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 <eoVRP> {
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 <std::set <unsigned> > _map;
std::vector <bool> 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 <unsigned>& neigh = _map [cur_vertex];
for (std::set <unsigned>::iterator it = neigh.begin (); it != neigh.end (); it ++) {
unsigned l = _map [*it].size ();
if (len_min_entry > l)
len_min_entry = l;
}
std::vector <unsigned> cand; /* Candidates */
for (std::set <unsigned>::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 <std::set <unsigned> >& _map) {
std::set <unsigned>& neigh = _map [_vertex];
for (std::set <unsigned>::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 <bool>& _visited, std::vector <std::set <unsigned> >& _map, eoVRP& _child) {
_visited [_vertex] = true;
_child.push_back (_vertex);
remove_entry (_vertex, _map);
}
};
#endif

View file

@ -0,0 +1,90 @@
/*
* Copyright (C) DOLPHIN Project-Team, INRIA Futurs, 2006-2007
* (C) OPAC Team, LIFL, 2002-2007
*
* (c) Antonio LaTorre <atorre@fi.upm.es>, 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 <utils/eoStat.h>
/**
* \class eoVRPStat eoVRPStat.h
* \brief Manages the statistics of the VRP problem.
*/
class eoVRPStat : public eoStat<eoVRP, double> {
public:
/**
* \brief Constructor: initializes variables properly.
* \param _description A string identifying the class.
*/
eoVRPStat (std::string _description = "eoVRPStat ") : eoStat<eoVRP, double> (0.0, _description) {
}
/**
* \brief Gets statistics from a population.
* \param _pop The population that will be analyzed.
*/
void operator() (const eoPop<eoVRP>& _pop) {
double tmpStat (0.);
eoStat<eoVRP, double>::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

View file

@ -0,0 +1,294 @@
/*
* Copyright (C) DOLPHIN Project-Team, INRIA Futurs, 2006-2007
* (C) OPAC Team, LIFL, 2002-2007
*
* (c) Antonio LaTorre <atorre@fi.upm.es>, 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 <vector>
#include <utility>
#include <fstream>
#include <iostream>
#include <sstream>
#include <math.h>
/**
* \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<int> 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 <ClientDataT> clients; /**< Vector to store clients's information. */
static std::vector <std::vector <double> > 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

View file

@ -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
<TABLE>
<TR>
<TD>Dolphin project-team INRIA Futurs, 2007.</TD>
<TD>Antonio LaTorre atorre[at]fi.upm.es</TD>
<TD>Thomas Legrand paradiseo-help[at]lists.gforge.inria.fr</TD>
</TR>
</TABLE>
@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
<A href=http://paradiseo.gforge.inria.fr>http://paradiseo.gforge.inria.fr</A>
*/