diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ca5b977d0fadc09b3794075af46b16ba6383216..18c228b21659c5ea442e1904e9d4b1a1a959d6e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/src/input/data.cpp b/src/input/data.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3ace1f48c596759cbeb502fcbe0118a359713f25 --- /dev/null +++ b/src/input/data.cpp @@ -0,0 +1,53 @@ +#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 diff --git a/src/input/data.h b/src/input/data.h new file mode 100644 index 0000000000000000000000000000000000000000..0570d5ac808ef2834a3d11273382b2ed86ee1852 --- /dev/null +++ b/src/input/data.h @@ -0,0 +1,42 @@ +#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 diff --git a/src/input/pdptw_data.h b/src/input/pdptw_data.h index fd2d4463bb67387785c72dc67e56e7a48da79b97..d3f8510d028c980e551fe4e436d88e81e9e108f8 100644 --- a/src/input/pdptw_data.h +++ b/src/input/pdptw_data.h @@ -32,6 +32,7 @@ class PDPTWData public: + PDPTWData(); PDPTWData(PDPTWData const &rhs) = delete; PDPTWData(PDPTWData &&rhs) noexcept; PDPTWData &operator=(PDPTWData &&rhs) noexcept; diff --git a/src/lns/modification/atomic_destruction.h b/src/lns/modification/atomic_destruction.h new file mode 100644 index 0000000000000000000000000000000000000000..c396ca6af5e26881444a3b706d298683e81327be --- /dev/null +++ b/src/lns/modification/atomic_destruction.h @@ -0,0 +1,18 @@ +#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; +}; diff --git a/src/lns/modification/atomic_modification.h b/src/lns/modification/atomic_modification.h new file mode 100644 index 0000000000000000000000000000000000000000..835ef39fa387c768dec7e767e994b6bf4e21b319 --- /dev/null +++ b/src/lns/modification/atomic_modification.h @@ -0,0 +1,26 @@ +#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; +}; + + diff --git a/src/lns/modification/atomic_recreation.h b/src/lns/modification/atomic_recreation.h new file mode 100644 index 0000000000000000000000000000000000000000..f554a25a5a77d964c8715338d20f19e57f95cfa7 --- /dev/null +++ b/src/lns/modification/atomic_recreation.h @@ -0,0 +1,18 @@ +#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 diff --git a/src/lns/modification/insert_pair.cpp b/src/lns/modification/insert_pair.cpp deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/lns/modification/insert_pair.h b/src/lns/modification/insert_pair.h deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/lns/modification/insert_route.cpp b/src/lns/modification/insert_route.cpp deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/lns/modification/insert_route.h b/src/lns/modification/insert_route.h deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/lns/modification/insert_route_with_pair.cpp b/src/lns/modification/insert_route_with_pair.cpp deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/lns/modification/insert_route_with_pair.h b/src/lns/modification/insert_route_with_pair.h deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/lns/modification/pair/insert_pair.cpp b/src/lns/modification/pair/insert_pair.cpp new file mode 100644 index 0000000000000000000000000000000000000000..46160fd88bbe9a00b3ad9f7d5ce5a846f593e467 --- /dev/null +++ b/src/lns/modification/pair/insert_pair.cpp @@ -0,0 +1,81 @@ +#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; +} + diff --git a/src/lns/modification/pair/insert_pair.h b/src/lns/modification/pair/insert_pair.h new file mode 100644 index 0000000000000000000000000000000000000000..a2537b504a3dcd75c7eb374e8e58302edfd964e1 --- /dev/null +++ b/src/lns/modification/pair/insert_pair.h @@ -0,0 +1,54 @@ +#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 diff --git a/src/lns/modification/pair/remove_pair.cpp b/src/lns/modification/pair/remove_pair.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d279e85c89734ff69cb4ed725249a79378919cd9 --- /dev/null +++ b/src/lns/modification/pair/remove_pair.cpp @@ -0,0 +1,81 @@ +#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 diff --git a/src/lns/modification/pair/remove_pair.h b/src/lns/modification/pair/remove_pair.h new file mode 100644 index 0000000000000000000000000000000000000000..d71a9629b9aa39be849cdcfa46de70fdcf01dfff --- /dev/null +++ b/src/lns/modification/pair/remove_pair.h @@ -0,0 +1,62 @@ +#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; +}; + diff --git a/src/lns/modification/remove_pair.cpp b/src/lns/modification/remove_pair.cpp deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/lns/modification/remove_pair.h b/src/lns/modification/remove_pair.h deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/lns/modification/remove_route.cpp b/src/lns/modification/remove_route.cpp deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/lns/modification/remove_route.h b/src/lns/modification/remove_route.h deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/lns/modification/route/insert_route.cpp b/src/lns/modification/route/insert_route.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5b0b04ef5889d0a0ac96df0546a132cf3ee5fed0 --- /dev/null +++ b/src/lns/modification/route/insert_route.cpp @@ -0,0 +1,21 @@ +#include "insert_route.h" + + +InsertRoute::InsertRoute() {} + +void InsertRoute::modifySolution(Solution &solution) +{ + std::vector<Route> &routes = solution.getRoutes(); + routes.push_back(Route()); +} + +double InsertRoute::evaluate(Solution const &solution) const +{ + return 0; +} + +Location const *InsertRoute::getAddedLocation() const +{ + return nullptr; +} + diff --git a/src/lns/modification/route/insert_route.h b/src/lns/modification/route/insert_route.h new file mode 100644 index 0000000000000000000000000000000000000000..1196526f5899a6c9333324c9164e4fd8d1dfc56a --- /dev/null +++ b/src/lns/modification/route/insert_route.h @@ -0,0 +1,24 @@ +#pragma once + +#include "./../atomic_recreation.h" +#include "./../../solution/solution.h" +#include "./../../../input/location.h" +#include <functional> + +class Route; + +/** + * Insert a new empty route in the solution + * Do not cost anything + */ +class InsertRoute : public AtomicRecreation +{ + +public: + InsertRoute(); + + void modifySolution(Solution &solution) override; + double evaluate(Solution const &solution) const override; + Location const *getAddedLocation() const override; + +}; \ No newline at end of file diff --git a/src/lns/modification/route/insert_route_with_pair.cpp b/src/lns/modification/route/insert_route_with_pair.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4622a7804d2cce309c8918c08866dc515325261e --- /dev/null +++ b/src/lns/modification/route/insert_route_with_pair.cpp @@ -0,0 +1 @@ +// TO DO \ No newline at end of file diff --git a/src/lns/modification/route/insert_route_with_pair.h b/src/lns/modification/route/insert_route_with_pair.h new file mode 100644 index 0000000000000000000000000000000000000000..ba71dd70be5e7dd2cbb7260d84ed00c3491e224b --- /dev/null +++ b/src/lns/modification/route/insert_route_with_pair.h @@ -0,0 +1,2 @@ +// Insertion d'une route avec une ou plusieurs paires pickup / delivery +// TO DO \ No newline at end of file diff --git a/src/lns/modification/route/remove_route.cpp b/src/lns/modification/route/remove_route.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8dd22bd7bb2b7c9540aaa0372e74e84bce4fc2a4 --- /dev/null +++ b/src/lns/modification/route/remove_route.cpp @@ -0,0 +1,34 @@ +#include "remove_route.h" +#include "../../../input/data.h" + +RemoveRoute::RemoveRoute() : routeIndex(-1), removedLocationID({}) {} +RemoveRoute::RemoveRoute(int routeIndex) : routeIndex(routeIndex), removedLocationID({}) {} +RemoveRoute::RemoveRoute(int routeIndex, std::vector<int> removedLocationID) : routeIndex(routeIndex), removedLocationID(removedLocationID) {} + +void RemoveRoute::modifySolution(Solution &solution) +{ + std::vector<Route> &routes = solution.getRoutes(); + + // update removedLocationID + removedLocationID.insert(removedLocationID.end(), + std::make_move_iterator(routes[routeIndex].getRoute().begin()), + std::make_move_iterator(routes[routeIndex].getRoute().end())); + + routes.erase(routes.begin() + routeIndex); +} + +double RemoveRoute::evaluate(Solution const &solution) const +{ + return data::routeCost(solution.getData(), solution.getRoute(routeIndex)); +} + +int RemoveRoute::getRouteIndex() const +{ + return routeIndex; +} + + +std::vector<int> const &RemoveRoute::getDeletedRequests() const +{ + return removedLocationID; +} \ No newline at end of file diff --git a/src/lns/modification/route/remove_route.h b/src/lns/modification/route/remove_route.h new file mode 100644 index 0000000000000000000000000000000000000000..83f67c65d5dd1036d7471616574bec323d6ee68d --- /dev/null +++ b/src/lns/modification/route/remove_route.h @@ -0,0 +1,40 @@ +#pragma once + +#include "./../atomic_destruction.h" +#include "./../../solution/solution.h" +#include "./../../../input/location.h" +#include <functional> + + +/** + * A modification that will remove a route from the solution. + */ +class RemoveRoute : public AtomicDestruction +{ + + /** + * Index of the route to remove + */ + int routeIndex; + + /** + * Removed Location ID (empty before ModifySolution is called) + */ + std::vector<int> removedLocationID; + +public: + + RemoveRoute(); + RemoveRoute(int routeIndex); + RemoveRoute(int routeIndex, std::vector<int> removedLocationID); + + void modifySolution(Solution &solution) override; + double evaluate(Solution const &solution) const override; + + int getRouteIndex() const; + + /** + * Return the location ID of location that has been deleted + */ + std::vector<int> const &getDeletedRequests() const override; +}; \ No newline at end of file diff --git a/src/lns/solution/route.cpp b/src/lns/solution/route.cpp index b24be977a5d3dbab5115092cfc8d2ea64748e0bf..6ebee237600353e77282a210cdc68d3f4b50337d 100644 --- a/src/lns/solution/route.cpp +++ b/src/lns/solution/route.cpp @@ -1,6 +1,8 @@ #include "route.h" #include <iostream> +#include <spdlog/spdlog.h> +Route::Route() = default; Route::Route(std::vector<int> route, int cost) : route(route), cost(cost) {} @@ -21,4 +23,40 @@ void Route::print() const std::cout << id << ", "; } std::cout << "\n"; +} + +void Route::insertAt(int locationIndex, int position) +{ + if (position < 0 || position > route.size()) { + spdlog::error("Invalid position for the insertion : {}", position); + throw std::out_of_range("Invalid position for the insertion."); + } + + route.insert(route.begin() + position, locationIndex); +} + + +void Route::deleteAt(int position) { + // Vérification si la position est valide + if (position < 0 || position >= route.size()) { + spdlog::error("Invalid position for the suppression : {}", position); + throw std::out_of_range("Invalid position for the suppression"); + } + route.erase(route.begin() + position); +} + +int Route::getLocation(int index) const +{ + // Vérification si la position est valide + if (index < 0 || index >= route.size()) { + spdlog::error("Invalid index when reading route: {}", index); + throw std::out_of_range("Invalid index when reading route"); + } + return route[index]; +} + + +int Route::getSize() const +{ + return route.size(); } \ No newline at end of file diff --git a/src/lns/solution/route.h b/src/lns/solution/route.h index 5bcc7eaf055563c571c86eb7231865456f525baa..5f645698614e6fa64afe312234a0c0c938ffd19d 100644 --- a/src/lns/solution/route.h +++ b/src/lns/solution/route.h @@ -5,6 +5,7 @@ /** * Represent a route for the PDPTW + * A route does not include the depot at the begining and the end ! */ class Route { @@ -22,9 +23,25 @@ private: public: + Route(); Route(std::vector<int> route, int cost); int getCost() const; - const std::vector<int>& getRoute() const; + const std::vector<int> & getRoute() const; + + // get Location + int getLocation(int index) const; + void print() const; - + + /* + * Add a location index in the route (does not update the route cost) + */ + void insertAt(int locationIndex, int position); + + /* + * Remove the element at "position" + */ + void deleteAt(int position); + + int getSize() const; }; \ No newline at end of file diff --git a/src/lns/solution/solution.cpp b/src/lns/solution/solution.cpp index 7781d5679f479328ba8c82ca1c35ad8904743ede..03864d872855b48f9438417829cfb533df9b2471 100644 --- a/src/lns/solution/solution.cpp +++ b/src/lns/solution/solution.cpp @@ -1,29 +1,78 @@ #include "solution.h" #include <iostream> +#include <spdlog/spdlog.h> -Solution::Solution(RequestBank bank, std::vector<Route> routes, int totalCost) - : bank(bank), routes(routes), totalCost(totalCost) {} + +Solution::Solution(const PDPTWData &data) + : data(data), totalCost(0) { + + bank = RequestBank(); + routes = std::vector<Route>(); +} + + +Solution::Solution(const PDPTWData &data, RequestBank bank, std::vector<Route> routes, int totalCost) + : data(data), bank(bank), routes(routes), totalCost(totalCost) {} const std::vector<int> & Solution::getBank() const { return bank; } -const std::vector<Route> & Solution::getRoute() const +const std::vector<Route> & Solution::getRoutes() const +{ + return routes; +} + +std::vector<Route> & Solution::getRoutes() { return routes; } +Route & Solution::getRoute(int routeIndex) +{ + if (routeIndex < 0 || routeIndex >= routes.size()) + { + spdlog::error("Invalid route index: {}", routeIndex); + throw std::out_of_range("Invalid route index."); + } + return routes[routeIndex]; +} + +const Route & Solution::getRoute(int routeIndex) const +{ + if (routeIndex < 0 || routeIndex >= routes.size()) + { + spdlog::error("Invalid route index: {}", routeIndex); + throw std::out_of_range("Invalid route index."); + } + return routes[routeIndex]; +} + int Solution::getCost() { return totalCost; } +const PDPTWData & Solution::getData() const +{ + return data; +} + void Solution::print() const { - std::cout << "Cost :" << totalCost << "\n"; - for (const Route& id : getRoute()) + std::cout << "Cost :" << totalCost << "\n" << "Routes : \n"; + + for (const Route& id : getRoutes()) { id.print(); } + + std::cout << "Banques : \n"; + + for (const int id : getBank()) + { + std::cout << id << ", "; + } + std::cout << "\n"; } \ No newline at end of file diff --git a/src/lns/solution/solution.h b/src/lns/solution/solution.h index e4fa61d80e0b59034c88635625b5f708e124b448..453a4f8067bce8d28f9c81ab846396b6c8b762fc 100644 --- a/src/lns/solution/solution.h +++ b/src/lns/solution/solution.h @@ -2,6 +2,7 @@ #include <vector> #include "route.h" +#include "./../../input/pdptw_data.h" /** * Represent a solution of PDPTW @@ -12,14 +13,29 @@ public: using RequestBank = std::vector<int>; private: + PDPTWData const & data; RequestBank bank; std::vector<Route> routes; int totalCost; + static PDPTWData dummy; + public: - Solution(RequestBank bank, std::vector<Route> routes, int totalCost); - const RequestBank & getBank() const; - const std::vector<Route> & getRoute() const; + Solution(const PDPTWData &data); + Solution(const PDPTWData &data, RequestBank bank, std::vector<Route> routes, int totalCost); + + RequestBank const & getBank() const; + + std::vector<Route> const & getRoutes() const; + Route const & getRoute(int routeIndex) const; + + const PDPTWData & getData() const; + + // For route modification + std::vector<Route> & getRoutes(); + Route & getRoute(int routeIndex); + + int getCost(); void print() const; diff --git a/src/main.cpp b/src/main.cpp index ffe109d360ac1eda97222f2a25a991410a4a7edd..21ba0830faf30f4b9912421f7190cb30c02c511a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,6 +12,12 @@ #include "input/location.h" #include "input/time_window.h" #include "input/json_parser.h" +#include "input/data.h" +#include "lns/solution/solution.h" +#include "lns/modification/pair/insert_pair.h" +#include "lns/modification/route/insert_route.h" +#include "lns/modification/pair/remove_pair.h" +#include "lns/modification/route/remove_route.h" namespace fs = std::filesystem; using json = nlohmann::json; @@ -29,13 +35,61 @@ int main(int argc, char const *argv[]) PDPTWData data = parsing::parseJson(filepath); data.checkData(); - /* test */ - TimeWindow tw = TimeWindow(3,4); - Location pos = Location(1, 1, 20, 3, tw, 4, 5, LocType::DEPOT); + /* + * test + */ + // Empty Solution + Solution sol = Solution(data); + + InsertRoute op1 = InsertRoute(); + // Ajoute une route vide + op1.modifySolution(sol); + Location r1P = data.getLocations()[0]; + Location r1D = data.getLocations()[50]; + Location r2P = data.getLocations()[1]; + Location r2D = data.getLocations()[51]; + Location r3P = data.getLocations()[2]; + Location r3D = data.getLocations()[52]; + // Opération : Ajoute une paire pickup delivery à la route 0 en position 0 et 0 + InsertPair op2 = InsertPair(0, 0, 0, r1P, r1D); + op2.modifySolution(sol); + InsertPair op3 = InsertPair(0, 0, 2, r2P, r2D); + op3.modifySolution(sol); + std::cout << "--- \n"; + + data::routeCost(data, sol.getRoute(0)); + + InsertPair op4 = InsertPair(0, 3, 4, r3P, r3D); + std::cout << "cout d'insert : "<< op4.evaluate(sol) << "\n"; + op4.modifySolution(sol); + + std::cout << "--- \n"; + sol.print(); + data::routeCost(data, sol.getRoute(0)); + + // TO DO + // Test supr + std::cout << "--- \n"; + RemovePair op5 = RemovePair(0, 3, 5, r3P, r3D); + + std::cout << "cout de supr : "<< op5.evaluate(sol) << "\n"; + + op5.modifySolution(sol); + sol.print(); + + data::routeCost(data, sol.getRoute(0)); + + RemoveRoute op6 = RemoveRoute(0); + + std::cout << "cout de supr : "<< op6.evaluate(sol) << "\n"; + + op6.modifySolution(sol); + + sol.print(); return 0; }