/* * Copyright (C) DOLPHIN Project-Team, INRIA Lille Nord-Europe, 2007-2008 * (C) OPAC Team, LIFL, 2002-2008 * * (c) Mostepha Redouane Khouadjia , 2008 * * 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 * */ #include "eoPsoDVRPutils.h" // The computed distances will be stored in dist. setCustumers clients; std::vector newCustomers; lengthMatrix dist; template std::string to_string( const T & Value ) { // utiliser un flux de sortie pour créer la chaîne std::ostringstream oss; // écrire la valeur dans le flux oss << Value; // renvoyer une string return oss.str(); } void computeDistances() { dist.resize (clients.size ()) ; for (unsigned i = 0; i < dist.size (); i ++) dist [i].resize (clients.size ()); // Distances computation for (unsigned i = 0; i < dist.size (); i ++) for (unsigned j = i ; 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 _availTime Return value. The time xhen client will be available in system. * \param _durationService Return value. The client's service time. */ void getInformation (unsigned _custumer, double& _availTime, double& _durationService) { assert (_custumer >= 0 && _custumer < clients.size ()); _availTime = clients [_custumer].availTime; _durationService = clients [_custumer].durationService; } /** * \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. */ void PrintCustumersMatrix (){ for (int i =0 ; i < clients.size(); ++i) cout<< clients[i].id<<'\t'<= 0 && _from < clients.size ()); assert (_to >= 0 && _to < clients.size ()); return _dist [_from][_to]; } const lengthMatrix distanceMatrix() {return dist;} /** * \brief Loads the problem data from a given file. * \param _fileName The file to load data from. * \warning No error check is performed! */ double computTourLength(Route _route) { double RouteLength =0.0; for (unsigned i = 0, size = _route.size()-1; i < size; ++i ) RouteLength+=distance(dist,_route[i], _route[i+1]); RouteLength+= distance(dist, _route.back(),0); return RouteLength; } double computTourLength( Routes _mRoute) { double MatrixLength =0.0; for(unsigned tr = 0, tsize = _mRoute.size(); tr < tsize; ++tr ) MatrixLength += computTourLength(_mRoute[tr]); return MatrixLength; } bool findClient (unsigned id) // Look for one customers in the table Clients { for ( size_t i = 0, size = clients.size(); i < size; ++i ) { if (id == (clients.at(i)).id) return true; } return false; } void loadNewCustomers(double _timeStep, double _timeSlice){ unsigned id_customer; newCustomers.clear(); unsigned i = 1; while (i < clients.size()) { if(clients[i].availTime > (_timeStep - _timeSlice) && clients[i].availTime <=_timeStep) newCustomers.push_back(clients[i].id); i++; } } void loadMatrixCustomers (const string _fileName) { string line; istringstream iss; std::ifstream file (_fileName.c_str()); ClientDataT depot, custumer; unsigned int id; if (file) { depot.id= 0; depot.availTime = depot.demand=depot.durationService = 0.0; clients.push_back (depot); do getline(file,line); while (line.find("DEMAND_SECTION")== string::npos); getline(file,line); do{ iss.str(line); iss>> custumer.id>>custumer.demand; clients.push_back (custumer); iss.clear(); getline(file,line); }while(line.find("LOCATION_COORD_SECTION")== string::npos); getline(file,line); do{ iss.str(line); iss>>id; iss>>clients[id].x; iss>>clients[id].y; iss.clear(); getline(file,line); } while(line.find("DEPOT_LOCATION_SECTION")== string::npos); do getline(file,line); while (line.find("DURATION_SECTION")== string::npos); getline(file,line); do{ iss.str(line); iss>>id; iss>>clients[id].durationService; iss.clear(); getline(file,line); } while(line.find("DEPOT_TIME_WINDOW_SECTION")== string::npos); getline(file,line); iss.str(line); iss>>id; iss>>clients[id].availTime>>clients[id].durationService; iss.clear(); do getline(file,line); while(line.find("TIME_AVAIL_SECTION")== string::npos); getline(file,line); do{ iss.str(line); iss>>id; iss>>clients[id].availTime; iss.clear(); getline(file,line); } while(line.find("EOF")== string::npos); file.close (); computeDistances(); } else { std::cerr << "Error: the file: " << _fileName << " doesn't exist !!!" << std::endl ; abort(); } } /** * \brief Prints a route to the standard output. * \param _route The route to print. */ void printRoute (const Route& _route, std::ostream &_os) { _os<< "["; for (unsigned i = 0; i < _route.size (); i++) { _os << _route [i]; if (i != _route.size () -1) _os << ", "; } _os << "]"< _dispoTime) return _nextTimeStep ; else return _dispoTime; } double getCapacityUsed (Route _route) { double charge =0.0; unsigned id_custumer; for (size_t i=1, size = _route.size(); i uGen(0,maxTour); return uGen(); } int randVelocity(int sizetr) { eoUniformGenerator uGen(-sizetr,sizetr); return uGen(); } unsigned randPosition (unsigned _lastPosition, unsigned _sizeTour) { eoUniformGenerator uGen(_lastPosition ,_sizeTour); return uGen(); } void checkDistances(const Routes _matrix) { double longeurTotal = 0.0 ; for(size_t tr = 0, tsize =_matrix.size(); tr < tsize; ++tr ) { double longeur = 0.0 ; for (size_t i = 0, size = _matrix[tr].size()-1; i < size; ++i ) longeur +=distance(dist,_matrix[tr][i], _matrix[tr][i+1]); cout << endl<<"distance route "<< tr+1 << " "<< longeur < i) positionTour = i; else positionTour = i + 1; double dueTime = getTimeOfService(_route, _startTime, customer_id, positionTour) + distance (dist,_route.back(),0) ; double demandTour = getCapacityUsed(_route) + clients[customer_id].demand; if( dueTime <= depotTimeWindow && demandTour <= VEHICULE_CAPACITY ) { nearestCostInsertion = costInsertion ; nearestPosition = positionTour; feasibleInsertion = true; } } } } if(!commitCustomer && feasibleInsertion) { commitCustomer = true; nearestTourCost = nearestCostInsertion; positionNearestTour = nearestPosition; nearestTour = indexTour; } else { if(feasibleInsertion) if( nearestTourCost < nearestCostInsertion ) { nearestTourCost = nearestCostInsertion; positionNearestTour = nearestPosition; nearestTour = indexTour; } } } void nearestInsertionAlgorithm (Route _route, unsigned indexTour, unsigned lastServedCustomer_id, unsigned lastServedCustomerPosition, double serviceTime, unsigned customer_id, unsigned & nearestTour, double & nearestTourCost, unsigned & positionNearestTour, bool & commitCustomer) { double costInsertion, nearestCostInsertion, nearestCheapCostInsertion , costLeftInsertion , costRightInsertion; unsigned leftCustomer_id, rightCustomer_id, nearestPosition, positionTour; bool feasibleInsertion = false ; double depotTimeWindow = clients[0].durationService; for( size_t i = lastServedCustomerPosition, sizetr = _route.size() ; i < sizetr ; i ++) { unsigned nearestCustomer_id = _route [i]; costInsertion = distance (dist, nearestCustomer_id, customer_id); if (((!feasibleInsertion) ) || ( costInsertion < nearestCostInsertion)) { if( nearestCustomer_id != lastServedCustomer_id ) { leftCustomer_id = _route[i-1]; if(i == _route.size()-1) rightCustomer_id = 0; else rightCustomer_id = _route[i+1]; costLeftInsertion = distance (dist , leftCustomer_id , customer_id) + distance (dist, customer_id, nearestCustomer_id ) - distance (dist, leftCustomer_id, nearestCustomer_id ) ; costRightInsertion = distance(dist, nearestCustomer_id, customer_id) + distance(dist, customer_id , rightCustomer_id) - distance (dist , nearestCustomer_id , rightCustomer_id); if (costLeftInsertion < costRightInsertion) positionTour = i ; else positionTour = i + 1 ; } else positionTour = i + 1 ; double dueTime = getTimeOfService(_route, lastServedCustomer_id, serviceTime, customer_id, positionTour) + distance (dist, _route.back(),0); double demandTour = getCapacityUsed(_route) + clients[customer_id].demand; if( dueTime <= depotTimeWindow && demandTour <= VEHICULE_CAPACITY ) { nearestCostInsertion =costInsertion ; nearestPosition = positionTour; feasibleInsertion = true; } else if( nearestCustomer_id !=lastServedCustomer_id) { if( positionTour > i) positionTour = i; else positionTour = i + 1; double dueTime = getTimeOfService(_route, lastServedCustomer_id, serviceTime, customer_id, positionTour) + distance (dist, _route.back(),0); double demandTour = getCapacityUsed(_route) + clients[customer_id].demand; if( dueTime <= depotTimeWindow && demandTour <= VEHICULE_CAPACITY ) { nearestCostInsertion = costInsertion ; nearestPosition = positionTour; feasibleInsertion = true; } } } } if(!commitCustomer && feasibleInsertion) { commitCustomer = true; nearestTourCost = nearestCostInsertion; positionNearestTour = nearestPosition; nearestTour = indexTour; } else { if(feasibleInsertion) if(nearestTourCost < nearestCostInsertion ) { nearestTourCost = nearestCostInsertion; positionNearestTour = nearestPosition; nearestTour = indexTour; } } } void generalizedInsertionTypeOneAlgorithm (Route _route, Route & _GenRoute, unsigned indexTour, double _startTime, unsigned customer_id, unsigned & generalizedTour, unsigned & positionGeneralizedTour, double & generalizedTourCost, bool & commitCustomer) { double costInsertion, lowCostInsertion; unsigned positionTour, lowPosition; std::vector tempNodes; bool feasibleInsertion = false ; double depotTimeWindow = clients[0].durationService; Route _tempRoute, _GenTempRoute ; if(_route.size() >= 3) { for( size_t i = 1, sizetri = _route.size()-1; i < sizetri; i ++) { for( size_t j = i, sizetrj = _route.size()-1 ; j < sizetrj; j ++) for( size_t k = j+1, sizetrk = _route.size(); k < sizetrk ; k++) { costInsertion = distance(dist,_route[i] , customer_id) + distance (dist, customer_id, _route[j]) + distance (dist, _route[i+1],_route[k]) + distance(dist,_route[j+1],_route[k+1]) - distance (dist, _route[i],_route[i+1]) + distance (dist, _route[j], _route[j+1]) + distance(dist,_route[k],_route[k+1]); positionTour = i+1; _tempRoute = _route ; tempNodes.clear() ; tempNodes.push_back(j); tempNodes.push_back(k); InsertionTypeOne(_tempRoute,positionTour,customer_id,tempNodes); double dueTime = getTimeOfService(_tempRoute, 0, _startTime ) + distance (dist,_tempRoute.back() , 0); double demandTour = getCapacityUsed(_tempRoute); if (dueTime <= depotTimeWindow && demandTour <= VEHICULE_CAPACITY ) { if ((!feasibleInsertion) || (costInsertion < lowCostInsertion)) { lowCostInsertion= costInsertion; lowPosition = positionTour; _GenTempRoute = _tempRoute; feasibleInsertion = true; } } } } } else { _tempRoute = _route ; positionTour = _tempRoute.size(); _tempRoute.push_back(customer_id); costInsertion = distance(dist,_tempRoute.back(), customer_id) + distance(dist,customer_id, 0) - distance(dist,_tempRoute.back(),0) ; double dueTime = getTimeOfService(_tempRoute, 0, _startTime ) + distance (dist,_tempRoute.back() , 0); double demandTour = getCapacityUsed(_tempRoute) + clients[customer_id].demand; if (dueTime <= depotTimeWindow && demandTour <= VEHICULE_CAPACITY ) { if ((!feasibleInsertion) || (costInsertion < lowCostInsertion)) { lowCostInsertion= costInsertion; lowPosition = positionTour; _GenTempRoute = _tempRoute; feasibleInsertion = true; } } } if(feasibleInsertion) if( !commitCustomer || lowCostInsertion < generalizedTourCost ) { generalizedTourCost = lowCostInsertion; positionGeneralizedTour = lowPosition; _GenRoute = _GenTempRoute; generalizedTour = indexTour; commitCustomer = true; } } void generalizedInsertionTypeOneAlgorithm (Route _route, Route& _Genroute, unsigned indexTour, unsigned lastServedCustomer_id, unsigned lastServedCustomerPosition, double serviceTime, unsigned customer_id, unsigned & generalizedTour, unsigned & positionGeneralizedTour, double & generalizedTourCost, bool & commitCustomer) { double costInsertion, lowCostInsertion; unsigned positionTour, lowPosition; std::vector tempNodes; bool feasibleInsertion = false ; double depotTimeWindow = clients[0].durationService; Route _tempRoute, _GenTempRoute; if(_route.size() >= 3) { for( size_t i = lastServedCustomer_id + 1, sizetri = _route.size() -1; i < sizetri; i ++) { for( size_t j = i, sizetrj = _route.size() -1 ; j < sizetrj; j ++) for( size_t k = j+1, sizetrk = _route.size(); k < sizetrk ; k++) { costInsertion = distance(dist,_route[i] , customer_id) + distance (dist, customer_id, _route[j]) + distance (dist, _route[i+1],_route[k]) + distance(dist,_route[j+1],_route[k+1]) - distance (dist, _route[i],_route[i+1]) + distance (dist, _route[j], _route[j+1]) + distance(dist,_route[k],_route[k+1]); positionTour = i+1; _tempRoute = _route ; tempNodes.clear() ; tempNodes.push_back(j); tempNodes.push_back(k); InsertionTypeOne(_tempRoute,positionTour,customer_id,tempNodes); double dueTime = getTimeOfService(_tempRoute, lastServedCustomer_id, serviceTime) + distance (dist,_tempRoute.back() , 0); double demandTour = getCapacityUsed(_tempRoute); if (dueTime <= depotTimeWindow && demandTour <= VEHICULE_CAPACITY ) { if ((!feasibleInsertion) || (costInsertion < lowCostInsertion)) { lowCostInsertion= costInsertion; lowPosition = positionTour; _GenTempRoute = _tempRoute; feasibleInsertion = true; } } } } }else { _tempRoute = _route ; positionTour = _tempRoute.size(); _tempRoute.push_back(customer_id); costInsertion = distance(dist,_tempRoute.back(), customer_id) + distance(dist,customer_id, 0) - distance(dist,_tempRoute.back(),0) ; double dueTime = getTimeOfService(_tempRoute, lastServedCustomer_id, serviceTime) + distance (dist,_tempRoute.back() , 0); double demandTour = getCapacityUsed(_tempRoute) + clients[customer_id].demand; if (dueTime <= depotTimeWindow && demandTour <= VEHICULE_CAPACITY ) { if ((!feasibleInsertion) || (costInsertion < lowCostInsertion)) { lowCostInsertion= costInsertion; lowPosition = positionTour; _GenTempRoute = _tempRoute; feasibleInsertion = true; } } } if(feasibleInsertion) if( !commitCustomer || lowCostInsertion < generalizedTourCost ) { generalizedTourCost = lowCostInsertion; positionGeneralizedTour = lowPosition; generalizedTour = indexTour; _Genroute = _GenTempRoute; commitCustomer = true; } } /* double computTourLength(const Routes _routes) { double Length = 0.0 ; for(size_t tr = 0, tsize = _routes.size(); tr < tsize; ++tr ) { for (size_t i = 0, size = _routes[tr].size()-1; i < size; ++i ) Length+= distance(dist,_routes[tr][i], _routes[tr][i+1]); Length+= distance(dist,_routes[tr].back(),0); } return Length ; } */ unsigned bestNeighborhoodRoutes ( const std::vector _neighborhoodRoutes, unsigned _bestNeighborIndex, double _bestNeighbor_fitness) { double minFitness, fitnessRoute ; unsigned minRoute ; minFitness = computTourLength(_neighborhoodRoutes[0]); minRoute = 0; for (size_t i =1, size = _neighborhoodRoutes.size(); i < size ; i++ ) { fitnessRoute = computTourLength(_neighborhoodRoutes[i]) ; if(fitnessRoute < minFitness) { minFitness = fitnessRoute; minRoute = i ; } } _bestNeighborIndex = minRoute; _bestNeighbor_fitness = minFitness ; } void swapCustomers(Route &_route, unsigned _lastCustomerPosition) { unsigned customer1 = randPosition(_lastCustomerPosition + 1 , _route.size()); unsigned customer2 = randPosition(_lastCustomerPosition +1 , _route.size()); swap(_route[customer1],_route[customer2]); } bool twoOptOnRoute( Route & _route , unsigned _lastServedCustomerPosition) { bool twoOptFeasible = false ; for (unsigned from = _lastServedCustomerPosition , size1 = _route.size() ; from < size1 -1 ; from ++) for(unsigned to = from +1 , size2 = _route.size(); to < size2 ; to ++) if( GainCost(_route,from,to) > 0 ) { int idx =(to-from)/2; for(unsigned k = 1; k <= idx ;k++) std::swap(_route[from+k],_route[to-k]); twoOptFeasible = true; } return twoOptFeasible; } void InsertionTypeOne(Route & _route, unsigned positionGeneralizedTour, unsigned customer_id, std::vector vertices) { _route.insert(_route.begin() + positionGeneralizedTour, customer_id ); unsigned j = vertices[0]; unsigned k = vertices[1]; _route.insert(_route.begin() + positionGeneralizedTour + 1, _route[j+1]); _route.erase(_route.begin() + j + 2); unsigned to = k + 1; unsigned from = positionGeneralizedTour + 2; int idx =( to - from )/2; for(unsigned q = 1; q <= idx ;q++) std::swap(_route[from+q],_route[to-q]); } void threeMoveRoute(Route & _route, unsigned _from, unsigned _to, unsigned _end) { Route tempRoute; for(size_t i=0; i<= _from; i++) tempRoute.push_back(_route[i]); tempRoute.push_back( _route[_to + 1]); tempRoute.push_back(_route[_end]); for(size_t i=_from +1; i<= _to; i++) tempRoute.push_back(_route[i]); tempRoute.push_back(_route[_end+1]); for(size_t i=_to +2; i<_end; i++) tempRoute.push_back(_route[i]); for(size_t i=_end + 2; i<_route.size(); i++) tempRoute.push_back(_route[i]); _route = tempRoute; } bool threeOptOnRoute( Route & _route , unsigned _lastServedCustomerPosition) { bool threeOptFeasible = false ; for (unsigned from = _lastServedCustomerPosition , size1 = _route.size()-3 ; from < size1 ; from ++) for(unsigned to = from +1 , size2 = _route.size()-2; to < size2; to ++) for(unsigned end= to + 1, size3 = _route.size()-1 ; end < size3; end++) if( GainCost(_route,from,to,end) > 0 ) { //threeMoveRoute(_route,from,to,end); if (!threeOptFeasible) threeOptFeasible = true; } return threeOptFeasible; } double GainCost(Route _route, unsigned _from, unsigned _to) { double Gain ; Gain= (distance (dist, _route[_from], _route[(_from +1) % _route.size()]) + distance(dist, _route[_to - 1], _route[_to % _route.size()])) - (distance (dist, _route[_from],_route[_to - 1]) + distance(dist, _route[(_from+1)%_route.size()],_route[_to% _route.size()])); return Gain; } double GainCost(Route _route, unsigned _from, unsigned _to, unsigned _end) { double Gain; Gain = distance (dist, _route[_from],_route[(_from +1) % _route.size()]) + distance(dist, _route[_to], _route[(_to + 1) % _route.size()]) + distance (dist,_route[_end],_route[(_end + 1) % _route.size()]) - distance (dist, _route[_from],_route[(_to + 1) % _route.size()]) + distance(dist, _route[_to], _route[(_end + 1) % _route.size()]) + distance (dist,_route[_end],_route[(_from + 1) % _route.size()]); return Gain; }