- Main Page
- Namespaces
- Classes
- Files

- Search for |

# 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