Skip to content
Snippets Groups Projects
Commit 9829a4b0 authored by awenjb's avatar awenjb
Browse files

Atomic Modifications

- add basic modification for a solution
parent 9ef014fa
No related branches found
No related tags found
No related merge requests found
Showing
with 442 additions and 5 deletions
......@@ -20,17 +20,18 @@ find_package(spdlog REQUIRED)
add_executable(pdptw src/main.cpp
src/input/data.cpp
src/input/location.cpp
src/input/pdptw_data.cpp
src/input/time_window.cpp
src/input/json_parser.cpp
src/lns/solution/route.cpp
src/lns/solution/solution.cpp
src/lns/modification/insert_pair.cpp
src/lns/modification/insert_route_with_pair.cpp
src/lns/modification/insert_route.cpp
src/lns/modification/remove_pair.cpp
src/lns/modification/remove_route.cpp
src/lns/modification/pair/insert_pair.cpp
src/lns/modification/pair/remove_pair.cpp
src/lns/modification/route/insert_route_with_pair.cpp
src/lns/modification/route/insert_route.cpp
src/lns/modification/route/remove_route.cpp
)
target_link_libraries(pdptw PRIVATE CLI11::CLI11 nlohmann_json::nlohmann_json spdlog::spdlog)
\ No newline at end of file
#include "data.h"
double data::addedCostForInsertion(PDPTWData const &data, int before, int toInsert, int after)
{
const Matrix & matrix = data.getMatrix();
double cost = 0;
cost = matrix[before][toInsert] + matrix[toInsert][after] - matrix[before][after];
return cost;
}
double data::removedCostForSuppression(PDPTWData const &data, int before, int toRemove, int after)
{
const Matrix & matrix = data.getMatrix();
double cost = 0;
cost = matrix[before][after] - matrix[before][toRemove] - matrix[toRemove][after];
return cost;
}
double data::routeCost(PDPTWData const & data, Route const & route)
{
const Matrix & matrix = data.getMatrix();
const std::vector<int> & routeIDs = route.getRoute();
double cost = 0;
// cost from and to the depot
cost += matrix[0][routeIDs[0]];
//std::cout << "\n route cost : " << matrix[0][routeIDs[0]] << " ";
cost += matrix[routeIDs.back()][0];
// cost in the route
for (size_t i = 0; i < routeIDs.size() - 1; ++i) {
cost += matrix[routeIDs[i]][routeIDs[i+1]];
//std::cout << matrix[routeIDs[i]][routeIDs[i+1]] << " ";
}
//std::cout << matrix[routeIDs.back()][0] << " : " << cost << "\n";
return cost;
}
double data::TravelCost(PDPTWData const &data, int index1, int index2)
{
return data.getMatrix()[index1][index2];
}
double data::SegmentCost(PDPTWData const &data, Route const &route, int start, int end)
{
// TO DO
return 0;
}
\ No newline at end of file
#pragma once
#include "time_window.h"
#include "pdptw_data.h"
#include "location.h"
#include "../lns/solution/route.h"
/**
* Functions for PDPTWData
*/
namespace data
{
/**
* Compute the cost added by an insertion of one location.
* Index are the id of the location (the same as in the cost matrix)
*/
double addedCostForInsertion(PDPTWData const &data, int before, int toInsert, int after);
/**
* Compute the gain of removing an location.
* Index are the id of the location (the same as in the cost matrix)
*/
double removedCostForSuppression(PDPTWData const &data, int before, int toRemove, int after);
/**
* Compute the cost of a route
*/
double routeCost(PDPTWData const &data, Route const &route);
/**
* Compute the cost of a segment of location in a route
* (does not take into accout that pair of pickup/delivery must be removed together)
*/
double SegmentCost(PDPTWData const &data, Route const &route, int start, int end);
/**
* Return the travel cost between two location
* (take location id in parameters)
*/
double TravelCost(PDPTWData const &data, int index1, int index2);
}
\ No newline at end of file
......@@ -32,6 +32,7 @@ class PDPTWData
public:
PDPTWData();
PDPTWData(PDPTWData const &rhs) = delete;
PDPTWData(PDPTWData &&rhs) noexcept;
PDPTWData &operator=(PDPTWData &&rhs) noexcept;
......
#pragma once
#include "atomic_modification.h"
#include <vector>
class Location;
/**
* Abstract Modification that destruct the solution.
*/
class AtomicDestruction : public AtomicModification
{
public:
/**
* @return the location ID removed from the solution.
*/
virtual std::vector<int> const &getDeletedRequests() const = 0;
};
#pragma once
class Solution;
/**
* Represent a modification of the solution, it can recreate/destroy the solution.
*
* @see AtomicRecreation and AtomicDestruction
*/
class AtomicModification
{
public:
/**
* Return the cost of the operation.
* @return a positive number if the solution cost is bigger after the modification.
*/
virtual double evaluate(Solution const &solution) const = 0;
/**
* Apply of the modification to the solution.
* @note does not check the validity of the modification, does not update solution cost nor constraints
*/
virtual void modifySolution(Solution &solution) = 0;
};
#pragma once
#include "atomic_modification.h"
class Location;
/**
* Abstract specification of AtomicModification for modifications that recreate the solution.
*/
class AtomicRecreation : public AtomicModification
{
public:
/**
* @return the pickup location added to the solution, nullptr if none were added
*/
virtual Location const *getAddedLocation() const = 0;
};
\ No newline at end of file
#include "insert_pair.h"
#include "./../../../input/data.h"
InsertPair::InsertPair(int routeIndex, int pickupInsertion, int deliveryInsertion,
Location const &pickupLocation, Location const &deliveryLocation)
: routeIndex(routeIndex),
pickupInsertion(pickupInsertion),
deliveryInsertion(deliveryInsertion),
pickupLocation(pickupLocation),
deliveryLocation(deliveryLocation) {}
void InsertPair::modifySolution(Solution &solution)
{
Route &route = solution.getRoute(routeIndex);
route.insertAt(pickupLocation.getId(), pickupInsertion);
// + 1 because the pickup location was inserted earlier in the route
route.insertAt(deliveryLocation.getId(), deliveryInsertion+1);
}
double InsertPair::evaluate(Solution const &solution) const {
Route const &route = solution.getRoute(routeIndex);
const std::vector<int> & routeIDs = route.getRoute();
const PDPTWData &data = solution.getData();
int prevPickup = (pickupInsertion == 0) ? 0 : routeIDs[pickupInsertion - 1];
int nextPickup = (pickupInsertion >= routeIDs.size()) ? 0 : routeIDs[pickupInsertion];
double pickupCost = data::addedCostForInsertion(data, prevPickup, pickupLocation.getId(), nextPickup);
// if pickupInsertion == deliveryInsertion+1, then prevDelivery = pickupLocation.getId()
// the insertion of the delivery is done just after the pickup without intermediate location
// otherwise, the pickup and the delivery insertion are independant and the pickup insertion does not affect the delivery insertion cost
int prevDelivery = (deliveryInsertion == 0) ? 0 : routeIDs[deliveryInsertion - 1];
if (pickupInsertion == deliveryInsertion)
{
prevDelivery = pickupLocation.getId();
}
int nextDelivery = (deliveryInsertion >= routeIDs.size()) ? 0 : routeIDs[deliveryInsertion];
//std::cout << "insert " << prevDelivery << " + " << deliveryLocation.getId() << " + " << nextDelivery << "\n";
double deliveryCost = data::addedCostForInsertion(data, prevDelivery, deliveryLocation.getId(), nextDelivery);
//std::cout << "insert " << pickupCost << " + " << deliveryCost << "\n";
return pickupCost + deliveryCost;
}
int InsertPair::getPickupInsertion() const
{
return pickupInsertion;
}
int InsertPair::getDeliveryInsertion() const
{
return deliveryInsertion;
}
int InsertPair::getRouteIndex() const
{
return routeIndex;
}
Location const &InsertPair::getPickupLocation() const
{
return pickupLocation;
}
const Location &InsertPair::getDeliveryLocation() const
{
return deliveryLocation;
}
const Location *InsertPair::getAddedLocation() const
{
return &pickupLocation;
}
#pragma once
#include "./../atomic_recreation.h"
#include "./../../solution/solution.h"
#include "./../../../input/location.h"
#include <functional>
class Route;
/**
* A modification that will insert a pair (pickup/delivery) of location in a route at the given index.
* First index for the pickup location and second index for the delivery location.
* Insertion index are the index before modification !
*/
class InsertPair : public AtomicRecreation
{
/**
* The route index on which the insertion will be made
*/
int routeIndex;
/**
* Index at which the insertion must be made
*/
int pickupInsertion;
/**
* Index at which the insertion must be made
*/
int deliveryInsertion;
/**
* The pickup location to insert
*/
Location const & pickupLocation;
/**
* The delivery location to insert
*/
Location const & deliveryLocation;
public:
InsertPair(int routeIndex, int pickupInsertion, int deliveryInsertion, Location const &pickupLocation, Location const &deliveryLocation);
void modifySolution(Solution &solution) override;
double evaluate(Solution const &solution) const override;
int getPickupInsertion() const;
int getDeliveryInsertion() const;
int getRouteIndex() const;
Location const &getPickupLocation() const;
Location const &getDeliveryLocation() const;
Location const *getAddedLocation() const override;
};
\ No newline at end of file
#include "remove_pair.h"
#include "../../../input/data.h"
RemovePair::RemovePair(int routeIndex, int pickupDeletion, int deliveryDeletion,
Location const &pickupLocation, Location const &deliveryLocation) :
routeIndex(routeIndex),
pickupDeletion(pickupDeletion),
deliveryDeletion(deliveryDeletion),
pickupLocation(pickupLocation),
deliveryLocation(deliveryLocation) {}
void RemovePair::modifySolution(Solution &solution)
{
Route &route = solution.getRoute(routeIndex);
// update removedLocationID
removedLocationID.push_back(route.getRoute()[pickupDeletion]);
removedLocationID.push_back(route.getRoute()[deliveryDeletion]);
// remove the delivery before (to not have to update the index)
route.deleteAt(deliveryDeletion);
route.deleteAt(pickupDeletion);
}
double RemovePair::evaluate(Solution const &solution) const
{
Route const &route = solution.getRoute(routeIndex);
const std::vector<int> & routeIDs = route.getRoute();
const PDPTWData &data = solution.getData();
int prevPickup = (pickupDeletion == 0) ? 0 : routeIDs[pickupDeletion - 1];
// pickup location should not be at the end of a route anyway
int nextPickup = (pickupDeletion >= routeIDs.size()) ? 0 : routeIDs[pickupDeletion + 1];
double pickupCost = data::removedCostForSuppression(data, prevPickup, pickupLocation.getId(), nextPickup);
int prevDelivery = (deliveryDeletion == 0) ? 0 : routeIDs[deliveryDeletion - 1];
int nextDelivery = (deliveryDeletion >= routeIDs.size()) ? 0 : routeIDs[deliveryDeletion + 1];
if (deliveryDeletion == pickupDeletion+1)
{
prevDelivery = prevPickup;
}
double deliveryCost = data::removedCostForSuppression(data, prevDelivery, deliveryLocation.getId(), nextDelivery);
return pickupCost + deliveryCost;
}
int RemovePair::getPickupDeletion() const
{
return pickupDeletion;
}
int RemovePair::getDeliveryDeletion() const
{
return deliveryDeletion;
}
int RemovePair::getRouteIndex() const
{
return routeIndex;
}
Location const & RemovePair::getPickupLocation() const
{
return pickupLocation;
}
Location const & RemovePair::getDeliveryLocation() const
{
return deliveryLocation;
}
std::vector<int> const & RemovePair::getDeletedRequests() const
{
return removedLocationID;
}
\ No newline at end of file
#pragma once
#include "./../atomic_destruction.h"
#include "./../../solution/solution.h"
#include "./../../../input/location.h"
#include <functional>
class Route;
/**
* A modification that will remove a pair (pickup/delivery) of location from the solution.
*/
class RemovePair : public AtomicDestruction
{
/**
* The route index on which the deletion will be made
*/
int routeIndex;
/**
* Index at which the deletion must be made
*/
int pickupDeletion;
/**
* Index at which the deletion must be made
*/
int deliveryDeletion;
/**
* The pickup location to remove
*/
Location const & pickupLocation;
/**
* The delivery location to remove
*/
Location const & deliveryLocation;
/**
* Removed Location ID (empty before ModifySolution is called)
*/
std::vector<int> removedLocationID;
public:
RemovePair(int routeIndex, int pickupDeletion, int deliveryDeletion, Location const &pickupLocation, Location const &deliveryLocation);
void modifySolution(Solution &solution) override;
double evaluate(Solution const &solution) const override;
int getPickupDeletion() const;
int getDeliveryDeletion() const;
int getRouteIndex() const;
Location const &getPickupLocation() const;
Location const &getDeliveryLocation() const;
/**
* Return the location ID of location that has been deleted
*/
std::vector<int> const &getDeletedRequests() const override;
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment