eoVRPInit.h

00001 /*
00002  * Copyright (C) DOLPHIN Project-Team, INRIA Futurs, 2006-2007
00003  * (C) OPAC Team, LIFL, 2002-2007
00004  *
00005  * (c) Antonio LaTorre <atorre@fi.upm.es>, 2007
00006  *
00007  * This software is governed by the CeCILL license under French law and
00008  * abiding by the rules of distribution of free software.  You can  use,
00009  * modify and/ or redistribute the software under the terms of the CeCILL
00010  * license as circulated by CEA, CNRS and INRIA at the following URL
00011  * "http://www.cecill.info".
00012  *
00013  * As a counterpart to the access to the source code and  rights to copy,
00014  * modify and redistribute granted by the license, users are provided only
00015  * with a limited warranty  and the software's author,  the holder of the
00016  * economic rights,  and the successive licensors  have only  limited liability.
00017  *
00018  * In this respect, the user's attention is drawn to the risks associated
00019  * with loading,  using,  modifying and/or developing or reproducing the
00020  * software by the user in light of its specific status of free software,
00021  * that may mean  that it is complicated to manipulate,  and  that  also
00022  * therefore means  that it is reserved for developers  and  experienced
00023  * professionals having in-depth computer knowledge. Users are therefore
00024  * encouraged to load and test the software's suitability as regards their
00025  * requirements in conditions enabling the security of their systems and/or
00026  * data to be ensured and,  more generally, to use and operate it in the
00027  * same conditions as regards security.
00028  * The fact that you are presently reading this means that you have had
00029  * knowledge of the CeCILL license and that you accept its terms.
00030  *
00031  * ParadisEO WebSite : http://paradiseo.gforge.inria.fr
00032  * Contact: paradiseo-help@lists.gforge.inria.fr
00033  *
00034  */
00035 
00036 #ifndef _eoVRPInit_h
00037 #define _eoVRPInit_h
00038 
00039 // The base definition of eoInit
00040 #include <eoInit.h>
00041 
00042 // Utilities for the VRP-TW problem
00043 #include "eoVRPUtils.h"
00044 
00054 #define ALFA                 0.7
00055 #define BETA                 0.1
00056 #define GAMMA                0.2
00057 
00065 class eoVRPInit: public eoInit <eoVRP> {
00066 
00067 public:
00068 
00073     eoVRPInit () {
00074 
00075         unsigned sz = eoVRPUtils::clients.size ();
00076 
00077         if (sz <= 0) {
00078 
00079             std::cerr << "Error: the dataset MUST be read before creating the initializer object." << std::endl;
00080             abort ();
00081 
00082         }
00083 
00084         mSeedsUsedCount = 0;
00085 
00086         for (unsigned i = 0; i < sz; i++)
00087             mSeedsUsed.push_back (false);
00088 
00089     }
00090 
00091 
00099     void operator () (eoVRP& _gen) {
00100 
00101         HeuristicInitialization (_gen);
00102 
00103     }
00104 
00105 
00106 private:
00107 
00108     unsigned mSeedsUsedCount;        
00109     std::vector<bool> mSeedsUsed;    
00123     void HeuristicInitialization (eoVRP& _gen) {
00124 
00125         // Aux var to override seed used checking
00126         bool seedCheckingOverride = false;
00127 
00128         // Erase any previous contents
00129         _gen.clear ();
00130 
00131         // Aux vector to store unvisited clients
00132         std::vector<int> unvisited;
00133 
00134         // And an index to point to the last unvisited cutomer
00135         int unvisitedIdx = eoVRPUtils::clients.size () - 2;
00136 
00137         // Initialization of the unvisited vector with all the clients
00138         for (unsigned i = 1; i < eoVRPUtils::clients.size (); i++)
00139             unvisited.push_back (i);
00140 
00141         // Main loop: keep iterating until all clients are visited
00142         while (unvisitedIdx >= 0) {
00143 
00144             // Aux var to store the new route
00145             Route route;
00146 
00147             createNewRoute (unvisited, unvisitedIdx, seedCheckingOverride, route);
00148             seedCheckingOverride = true;
00149 
00150             for (unsigned i = 0; i < route.size (); i++)
00151                 _gen.push_back (route [i]);
00152 
00153         }
00154 
00155         // Invalidates the genotype forcing its re-evaluation
00156         _gen.invalidate ();
00157 
00158     }
00159 
00160 
00176     bool createNewRoute (std::vector<int>& _unvisited, int& _unvisitedIdx,
00177                          bool _seedCheckingOverride, Route& _route         ) {
00178 
00179         // Selection of seed client for current route
00180         unsigned seed = selectBestClientAsSeed (_unvisited, _unvisitedIdx, _seedCheckingOverride);
00181 
00182         // Add the seed client to the route
00183         _route.push_back (_unvisited [seed]);
00184 
00185         // Mark the client as already selected as a main seed
00186         // (i.e., as a seed for the first subroute of an individual)
00187         if (!_seedCheckingOverride) {
00188 
00189             mSeedsUsed [_unvisited [seed]] = true;
00190             mSeedsUsedCount++;
00191 
00192             if (mSeedsUsedCount == mSeedsUsed.size () - 1) {
00193 
00194                 mSeedsUsedCount = 0;
00195 
00196                 for (unsigned i = 0; i < mSeedsUsed.size (); i++)
00197                     mSeedsUsed [i] = false;
00198 
00199             }
00200 
00201         }
00202 
00203         // Delete the selected client from the unvisited vector
00204         _unvisited [seed] = _unvisited [_unvisitedIdx];
00205         _unvisitedIdx--;
00206 
00207         bool feasibleInsert = true;
00208 
00209         while (feasibleInsert && _unvisitedIdx >= 0) {
00210 
00211             // Aux var to store the position to insert new clients in the route
00212             Route::iterator it;
00213 
00214             unsigned next;
00215 
00216             if (selectBestInsertion (_unvisited, _unvisitedIdx, _route, next, it)) {
00217 
00218                 if (it == _route.end ())
00219                     _route.insert (_route.begin (), _unvisited [next]);
00220                 else
00221                     _route.insert (it + 1, _unvisited [next]);
00222 
00223                 _unvisited [next] = _unvisited [_unvisitedIdx];
00224                 _unvisitedIdx--;
00225 
00226             }
00227             else
00228                 feasibleInsert = false;
00229 
00230         }
00231 
00232         return true;
00233 
00234     }
00235 
00236 
00249     bool selectBestInsertion (std::vector<int>& _unvisited, unsigned _unvisitedIdx, Route& _route,
00250                               unsigned& _nextClient, Route::iterator& _it                          ) {
00251 
00252         double minCost = 999999999;
00253         bool found = false;
00254 
00255         bool insertionPossible = false;
00256         double cost = 0.0;
00257 
00258         for (unsigned i = 0; i < _unvisitedIdx; i++) {
00259 
00260             insertionPossible = evaluateInsertion (_route, _unvisited [i], -1, cost);
00261 
00262             if (insertionPossible && cost < minCost) {
00263 
00264                 _it = _route.end ();
00265                 _nextClient = i;
00266                 minCost = cost;
00267                 found = true;
00268 
00269             }
00270 
00271         }
00272 
00273         for (Route::iterator it = _route.begin (); it != _route.end (); it++) {
00274 
00275             for (unsigned i = 0; i < _unvisitedIdx; i++) {
00276 
00277                 insertionPossible = evaluateInsertion (_route, _unvisited [i], *it, cost);
00278 
00279                 if (insertionPossible && cost < minCost) {
00280 
00281                     _it = it;
00282                     _nextClient = i;
00283                     minCost = cost;
00284                     found = true;
00285 
00286                 }
00287 
00288             }
00289 
00290         }
00291 
00292         return found;
00293 
00294     }
00295 
00296 
00308     bool evaluateInsertion (Route& _route, unsigned _newClient, int _afterClient, double& _cost) {
00309 
00310         // First of all, we check for capacity constraint to be satisfied
00311         // before trying to insert the new client in the route
00312         double demand = 0.0;
00313 
00314         // Cummulate the demand of all the clients in the current route
00315         for (unsigned i = 0; i < _route.size (); i++)
00316             demand += eoVRPUtils::clients [i].demand;
00317 
00318         // And then the demand of the new client
00319         demand += eoVRPUtils::clients [_newClient].demand;
00320 
00321         // And finally, check if the cummulated demand exceeds vehicle's capacity
00322         if (demand > VEHICLE_CAPACITY)
00323             return false;
00324 
00325         // Now check for insertion position and TW constraints
00326         double readyTime, dueTime, serviceTime;
00327 
00328         // If the client must be inserted after client "-1" that means that it
00329         // has to be inserted at the very beginning of the route
00330         if (_afterClient == - 1) {
00331 
00332             // We calculate the distante from the depot to the inserted client
00333             _cost = eoVRPUtils::distance (0, _newClient);
00334 
00335             // And check that its TW is not exceeded
00336             eoVRPUtils::getTimeWindow (_newClient, readyTime, dueTime, serviceTime);
00337 
00338             if (_cost > dueTime)
00339                 return false;
00340 
00341             // If the vehicle arrives before client's ready time, it has
00342             // to wait until the client is ready
00343             if (_cost < readyTime)
00344                 _cost = readyTime;
00345 
00346             // Add the service time for the newly inserted client
00347             _cost += serviceTime;
00348 
00349             // And the cost of traveling to the next one (the first one in the old route)
00350             _cost = _cost + eoVRPUtils::distance (_newClient, _route [0]);
00351 
00352         }
00353         else
00354             // We just need to add the cost of traveling from the depot to the first client
00355             _cost = eoVRPUtils::distance (0, _route [0]);
00356 
00357         // Main loop to evaluate the rest of the route (except the last position)
00358         for (unsigned i = 0; i < _route.size () - 1; i++) {
00359 
00360             // Check that the TW is not exceeded for the current client
00361             eoVRPUtils::getTimeWindow (_route [i], readyTime, dueTime, serviceTime);
00362 
00363             if (_cost > dueTime)
00364                 return false;
00365 
00366             // If it is not exceeded, we check wether the vehicle arrives before
00367             // the client is ready. If that's the case, it has to wait
00368             if (_cost < readyTime)
00369                 _cost = readyTime;
00370 
00371             // We add the service time for this client
00372             _cost += serviceTime;
00373 
00374             // And now check if we have to insert the new client after the current one
00375             if (_route [i] == _afterClient) {
00376 
00377                 // If that's the case, we add the cost of traveling from current client
00378                 // to the new one
00379                 _cost = _cost + eoVRPUtils::distance (_route [i], _newClient);
00380 
00381                 // And check for its TW to be not exceeded
00382                 eoVRPUtils::getTimeWindow (_newClient, readyTime, dueTime, serviceTime);
00383 
00384                 if (_cost > dueTime)
00385                     return false;
00386 
00387                 // If the vehicle arrives before client's ready time, it has
00388                 // to wait until the client is ready
00389                 if (_cost < readyTime)
00390                     _cost = readyTime;
00391 
00392                 // Add the service time for the newly inserted client
00393                 _cost += serviceTime;
00394 
00395                 // And the cost of traveling to the next one
00396                 _cost = _cost + eoVRPUtils::distance (_newClient, _route [i + 1]);
00397 
00398             }
00399             else
00400                 // We simply add the cost of traveling to the next client
00401                 _cost = _cost + eoVRPUtils::distance (_route [i], _route [i + 1]);
00402 
00403         }
00404 
00405         // Consider the special case where the new client has
00406         // to be inserted at the end of the route
00407         unsigned last =_route [_route.size () - 1];
00408 
00409         // We first check that the TW of the last client in the old route
00410         // has not been exedeed
00411         eoVRPUtils::getTimeWindow (last, readyTime, dueTime, serviceTime);
00412 
00413         if (_cost > dueTime)
00414             return false;
00415 
00416         // If the vehicle arrives before the client is ready, it waits
00417         if (_cost < readyTime)
00418             _cost = readyTime;
00419 
00420         // Now we add its service time
00421         _cost += serviceTime;
00422 
00423         // And check if the new client has to be inserted at the end
00424         // of the old route
00425         if (_afterClient == last) {
00426 
00427             // In that case, we add the cost of traveling from the last client
00428             // to the one being inserted
00429             _cost = _cost + eoVRPUtils::distance (last, _newClient);
00430 
00431             // Check for its TW not being exceeded
00432             eoVRPUtils::getTimeWindow (_newClient, readyTime, dueTime, serviceTime);
00433 
00434             if (_cost > dueTime)
00435                 return false;
00436 
00437             // If the vehicle arrives before the new client is ready, it waits
00438             if (_cost < readyTime)
00439                 _cost = readyTime;
00440 
00441             // Now we add its service time
00442             _cost += serviceTime;
00443 
00444             // And, finally, the time to travel back to the depot
00445             _cost = _cost + eoVRPUtils::distance (_newClient, 0);
00446 
00447         }
00448         else
00449             // In this case we just add the cost of traveling back to the depot
00450             _cost = _cost + eoVRPUtils::distance (last, 0);
00451 
00452         // Last thing to check is that the vehicle is back on time to the depot
00453         eoVRPUtils::getTimeWindow (0, readyTime, dueTime, serviceTime);
00454 
00455         if (_cost > dueTime)
00456             return false;
00457 
00458         // If all constraints are satisfied, we return true, and the cost of the
00459         // insertion in the variable "_cost"
00460         return true;
00461 
00462     }
00463 
00464 
00472     unsigned selectFarthestClientAsSeed (const std::vector<int>& _unvisited, int _unvisitedIdx) {
00473 
00474         unsigned maxPos  = 0;
00475         double   maxDist = eoVRPUtils::distance (0, _unvisited [0]);
00476 
00477         for (unsigned i = 1; i <= _unvisitedIdx; i++)
00478             if (eoVRPUtils::distance (0, _unvisited [i]) > maxDist) {
00479 
00480                 maxPos  = i;
00481                 maxDist = eoVRPUtils::distance (0, _unvisited [i]);
00482 
00483             }
00484 
00485         return maxPos;
00486 
00487     }
00488 
00489 
00498     unsigned selectCheapestClient (const std::vector<int>& _unvisited, int _unvisitedIdx, bool _seedCheckingOverride) {
00499 
00500         int    cheapestPos  = -1;
00501         double cheapestCost = 999999999;
00502 
00503         for (unsigned i = 0; i <= _unvisitedIdx; i++) {
00504 
00505             double cost = (-ALFA * eoVRPUtils::distance (0, _unvisited [i])    ) +
00506                           ( BETA * eoVRPUtils::clients [_unvisited [i]].dueTime) +
00507                           (GAMMA * eoVRPUtils::polarAngle (0, _unvisited [i]) / 360 * eoVRPUtils::distance (0, _unvisited [i]));
00508 
00509             if ((cost <  cheapestCost        || (cost == cheapestCost && rng.flip ())) &&
00510                     (!mSeedsUsed [_unvisited [i]] ||  _seedCheckingOverride               )    ) {
00511 
00512                 cheapestPos  = i;
00513                 cheapestCost = cost;
00514 
00515             }
00516 
00517         }
00518 
00519         return cheapestPos;
00520 
00521     }
00522 
00523 
00532     unsigned selectBestClientAsSeed (const std::vector<int>& _unvisited, int _unvisitedIdx, bool _seedCheckingOverride) {
00533 
00534         int    cheapestPos  = -1;
00535         double cheapestCost = 999999999;
00536         double alfa, beta;
00537 
00538         alfa = rng.uniform ();
00539         beta = rng.uniform ();
00540 
00541         for (unsigned i = 0; i <= _unvisitedIdx; i++) {
00542 
00543             double cost = (alfa * eoVRPUtils::distance (0, _unvisited [i])) +
00544                           (beta * (eoVRPUtils::clients [_unvisited [i]].dueTime - eoVRPUtils::clients [_unvisited [i]].readyTime));
00545 
00546 
00547             if ((cost <  cheapestCost        || (cost == cheapestCost && rng.flip ())) &&
00548                     (!mSeedsUsed [_unvisited [i]] ||  _seedCheckingOverride               )    ) {
00549 
00550                 cheapestPos  = i;
00551                 cheapestCost = cost;
00552 
00553             }
00554 
00555         }
00556 
00557         return cheapestPos;
00558 
00559     }
00560 
00561 
00569     void RandomInitializationNoCheck (eoVRP& _gen) {
00570 
00571         // Erase any previous contents
00572         _gen.clear ();
00573 
00574         // Aux vector to store unvisited clients
00575         std::vector<int> unvisited;
00576 
00577         // And an index to point to the last unvisited cutomer
00578         int unvisitedIdx = eoVRPUtils::clients.size () - 2;
00579 
00580         // Initialization of the unvisited vector with all the clients
00581         for (unsigned i = 1; i < eoVRPUtils::clients.size (); i++)
00582             unvisited.push_back (i);
00583 
00584         while (unvisitedIdx >= 0) {
00585 
00586             unsigned n = rng.random (unvisitedIdx);
00587 
00588             for (unsigned i = 0; i <= n; i++) {
00589 
00590                 unsigned pos = rng.random (unvisitedIdx);
00591 
00592                 _gen.push_back (unvisited [pos]);
00593 
00594                 unvisited [pos] = unvisited [unvisitedIdx];
00595                 unvisitedIdx--;
00596 
00597             }
00598 
00599         }
00600 
00601     }
00602 
00603 
00604 };
00605 
00606 #endif

Generated on Fri Dec 7 16:57:19 2007 for CVRP-TW by  doxygen 1.4.7