diff --git a/CMakeLists.txt b/CMakeLists.txt index 18c228b21659c5ea442e1904e9d4b1a1a959d6e7..b53e89fd20e56f3d48a8000b1f08cc5638cb1c81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) # link time optimisation (LTO) for release and release with debug info builds set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON) set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON) - +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Finding dependencies find_package(CLI11 REQUIRED) @@ -22,11 +22,15 @@ find_package(spdlog REQUIRED) add_executable(pdptw src/main.cpp src/input/data.cpp src/input/location.cpp + src/input/pair.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/constraints/constraint.cpp + src/lns/constraints/capacity/capacity_constraint.cpp + src/lns/constraints/time_window/time_window_constraint.cpp src/lns/modification/pair/insert_pair.cpp src/lns/modification/pair/remove_pair.cpp src/lns/modification/route/insert_route_with_pair.cpp @@ -34,4 +38,6 @@ add_executable(pdptw src/main.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 +target_link_libraries(pdptw PRIVATE CLI11::CLI11 nlohmann_json::nlohmann_json spdlog::spdlog) + +target_include_directories(pdptw PUBLIC ${CMAKE_SOURCE_DIR}/src) diff --git a/src/input/data.cpp b/src/input/data.cpp index 3ace1f48c596759cbeb502fcbe0118a359713f25..ded751825e988bf1caa07d2415f15075532d8fa8 100644 --- a/src/input/data.cpp +++ b/src/input/data.cpp @@ -46,6 +46,12 @@ double data::TravelCost(PDPTWData const &data, int index1, int index2) return data.getMatrix()[index1][index2]; } +double data::TravelTime(PDPTWData const &data, int from, int to) +{ + return data.getMatrix()[from][to]; +} + + double data::SegmentCost(PDPTWData const &data, Route const &route, int start, int end) { // TO DO diff --git a/src/input/data.h b/src/input/data.h index 0570d5ac808ef2834a3d11273382b2ed86ee1852..72771500c65e344f7604f73660e8549731c3bea3 100644 --- a/src/input/data.h +++ b/src/input/data.h @@ -39,4 +39,10 @@ namespace data * (take location id in parameters) */ double TravelCost(PDPTWData const &data, int index1, int index2); + + /** + * Return the travel time between two location + * (take location id in parameters) + */ + double TravelTime(PDPTWData const &data, int from, int to); } \ No newline at end of file diff --git a/src/input/pair.cpp b/src/input/pair.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ccdccb07ba15c1385c410a2af0382fc7a1489fc7 --- /dev/null +++ b/src/input/pair.cpp @@ -0,0 +1,14 @@ +#include "pair.h" + +Pair::Pair(const Location& pickupLoc, const Location& deliveryLoc) +: pickup(pickupLoc), delivery(deliveryLoc) {} + +const Location& Pair::getPickup() const +{ + return pickup.get(); +} + +const Location& Pair::getDelivery() const +{ + return delivery.get(); +} \ No newline at end of file diff --git a/src/input/pair.h b/src/input/pair.h new file mode 100644 index 0000000000000000000000000000000000000000..4183a20293d914095f70d9c07ff5b1e61f2b6e35 --- /dev/null +++ b/src/input/pair.h @@ -0,0 +1,17 @@ +#pragma once + +#include "location.h" + +// Represent a pair pickup/delivery of location +class Pair +{ +private: + std::reference_wrapper<Location const> pickup; + std::reference_wrapper<Location const> delivery; + +public: + Pair(const Location& pickupLoc, const Location& deliveryLoc); + + const Location& getPickup() const; + const Location& getDelivery() const; +}; \ No newline at end of file diff --git a/src/input/pdptw_data.cpp b/src/input/pdptw_data.cpp index ee78a2b8ef0ffafdc25b475ed3068f3c01fc9ef5..6b819c615a70b00aeb010b95a5f0d25ebfedd692 100644 --- a/src/input/pdptw_data.cpp +++ b/src/input/pdptw_data.cpp @@ -12,7 +12,7 @@ unsigned int PDPTWData::getSize() return size; } -int PDPTWData::getCapacity() +int PDPTWData::getCapacity() const { return capacity; } diff --git a/src/input/pdptw_data.h b/src/input/pdptw_data.h index d3f8510d028c980e551fe4e436d88e81e9e108f8..b7a504ec783ccf480076fe0a1924f1c7089b1ac9 100644 --- a/src/input/pdptw_data.h +++ b/src/input/pdptw_data.h @@ -57,7 +57,7 @@ public: Matrix const &getMatrix() const; unsigned int getSize(); - int getCapacity(); + int getCapacity() const; void print() const; }; diff --git a/src/lns/constraints/capacity/capacity_constraint.cpp b/src/lns/constraints/capacity/capacity_constraint.cpp new file mode 100644 index 0000000000000000000000000000000000000000..44d3c775a4fce4c7df4709d6e71e7c460c98e8fe --- /dev/null +++ b/src/lns/constraints/capacity/capacity_constraint.cpp @@ -0,0 +1,163 @@ +#include "capacity_constraint.h" + + +CapacityConstraint::CapacityConstraint(Solution const &solution) : Constraint(solution) +{ + // Init an empty vector of reach time for all routes + //std::vector<CapacityVector> routeCapacities(getSolution().getRoutes().size(), CapacityVector()); + routeCapacities.resize(getSolution().getRoutes().size()); +} + +std::unique_ptr<Constraint> CapacityConstraint::clone(Solution const &newOwningSolution) const { + std::unique_ptr<CapacityConstraint> clonePtr = std::make_unique<CapacityConstraint>(newOwningSolution); + clonePtr->routeCapacities = routeCapacities; + return clonePtr; +} + + +void CapacityConstraint::initCapacities() +{ + routeCapacities = std::vector<CapacityVector>(); + for (const Route& route : getSolution().getRoutes()) + { + CapacityVector capacities; + int currentCapacity = 0; + + for (int locationID : route.getRoute()) + { + currentCapacity += getSolution().getData().getLocation(locationID).getDemand(); + capacities.push_back(currentCapacity); + } + + routeCapacities.push_back(capacities); + } +} + + +std::vector<int> const & CapacityConstraint::getRouteCapacities(int routeIndex) const +{ + return routeCapacities[routeIndex]; +} + +// check for every location between the pickupPosition and the deliveryPosition +// not ideal +bool CapacityConstraint::checkModif(Pair const &pair, int routeIndex, int PickupPosition, int DeliveryPosition) const +{ + std::cout << "\n"; + int max_capacity = getSolution().getData().getCapacity(); + + // guardrail + if (pair.getPickup().getDemand() > max_capacity) + { + return false; + } + + // check if the disponible capacity is enough are not + for (int i = PickupPosition; i <= DeliveryPosition; ++i) { + + if ((i!=0) && (getRouteCapacities(routeIndex).at(i-1) + pair.getPickup().getDemand() >= max_capacity)) + { + return false; + } + } + return true; +} + +// update the route and the weight +// not ideal +void CapacityConstraint::applyModif(Pair const &pair, int routeIndex, int PickupPosition, int DeliveryPosition, bool addPair) +{ + std::cout << "ok \n"; + if (addPair) + { + // Insert new values + routeCapacities[routeIndex].insert(routeCapacities[routeIndex].begin()+DeliveryPosition, 0); + if (DeliveryPosition != 0) + { + routeCapacities[routeIndex][DeliveryPosition] += routeCapacities[routeIndex][DeliveryPosition-1]; + } + routeCapacities[routeIndex].insert(routeCapacities[routeIndex].begin()+PickupPosition, pair.getPickup().getDemand()); + if (PickupPosition != 0) + { + routeCapacities[routeIndex][PickupPosition] += routeCapacities[routeIndex][PickupPosition-1]; + } + + // Update value + for (int i = PickupPosition + 1; i < DeliveryPosition + 1; ++i) + { + routeCapacities[routeIndex][i] += pair.getPickup().getDemand(); + } + } + else + { + for (int i = PickupPosition + 1; i < DeliveryPosition; ++i) + { + routeCapacities[routeIndex][i] += pair.getDelivery().getDemand(); + } + + // remove pair + routeCapacities[routeIndex].erase(routeCapacities[routeIndex].begin() + DeliveryPosition); + routeCapacities[routeIndex].erase(routeCapacities[routeIndex].begin() + PickupPosition); + } +} + + +bool CapacityConstraint::check(InsertPair const &op) const +{ + return checkModif(op.getPair(), op.getRouteIndex(), op.getPickupInsertion(), op.getDeliveryInsertion()); +} +void CapacityConstraint::apply(InsertPair const &op) +{ + applyModif(op.getPair(), op.getRouteIndex(), op.getPickupInsertion(), op.getDeliveryInsertion(), true); +} + + +bool CapacityConstraint::check(InsertRoute const &op) const +{ + return true; +} +void CapacityConstraint::apply(InsertRoute const &op) +{ + // add new empty route + routeCapacities.emplace_back(); +} + + +bool CapacityConstraint::check(RemovePair const &op) const +{ + // Remove a pair (always true) + return true; +} +void CapacityConstraint::apply(RemovePair const &op) +{ + applyModif(op.getPair(), op.getRouteIndex(), op.getPickupDeletion(), op.getDeliveryDeletion(), false); +} + + +bool CapacityConstraint::check(RemoveRoute const &op) const +{ + return true; +} +void CapacityConstraint::apply(RemoveRoute const &op) +{ + // add new empty route + routeCapacities.erase(routeCapacities.begin() + op.getRouteIndex()); +} + +void CapacityConstraint::print() const +{ + std::cout << "Used capacity : \n"; + int i = 0; + for (const auto& capaVector : routeCapacities) + { + std::cout << "#" << i << " : "; + for (const int capa : capaVector) + { + std::cout << capa << ", "; + } + std::cout << "\n "; + i++; + } + std::cout << "\n"; +} + diff --git a/src/lns/constraints/capacity/capacity_constraint.h b/src/lns/constraints/capacity/capacity_constraint.h new file mode 100644 index 0000000000000000000000000000000000000000..31149539a47361619559564bfcb73e4c060fda97 --- /dev/null +++ b/src/lns/constraints/capacity/capacity_constraint.h @@ -0,0 +1,62 @@ +#pragma once + +#include "./../constraint.h" +#include "./../../../input/pair.h" + +/** + * Capacity constraint. + * To check this, we keep track of the sum of all requests and check it against the max capacity. + * TO DO, verification in O(1) by storing a matrix ! + */ +class CapacityConstraint : public Constraint +{ +public: + using CapacityVector = std::vector<int>; +private: + + std::vector<CapacityVector> routeCapacities; + + void apply(InsertPair const &op) override; + void apply(InsertRoute const &op) override; + void apply(RemovePair const &op) override; + void apply(RemoveRoute const &op) override; + + bool check(InsertPair const &op) const override; + bool check(InsertRoute const &op) const override; + bool check(RemovePair const &op) const override; + bool check(RemoveRoute const &op) const override; +public: + + explicit CapacityConstraint(Solution const &); + CapacityConstraint(CapacityConstraint const &) = default; + + std::unique_ptr<Constraint> clone(Solution const &newOwningSolution) const override; + + /* + * Given the solution, calculate the capacities when leaving each location + * Modify the routeCapacities vector ! + */ + void initCapacities(); + + /* + * Return capacity vector of a route + */ + CapacityVector const &getRouteCapacities(int routeIndex) const; + + /* + * Check if a modification is valid or not + * (for now, check only the position of the pickup) + * TO DO (1 or 2) + * 1) check if every index on the path can take the new capacity + * 2) store a matrix / Segment Tree ?? to evaluate the maximum load between two part of the route + * -> a matrix but check in O(1) (update in O(n)) + */ + bool checkModif(Pair const &pair, int routeIndex, int position, int DeliveryPosition) const; + + /* + * Update the weight + */ + void applyModif(Pair const &pair, int routeIndex, int PickupPosition, int DeliveryPosition, bool addPair); + + void print() const; +}; \ No newline at end of file diff --git a/src/lns/constraints/constraint.cpp b/src/lns/constraints/constraint.cpp new file mode 100644 index 0000000000000000000000000000000000000000..51f375e42af71712c048049c594b2a9072e3a047 --- /dev/null +++ b/src/lns/constraints/constraint.cpp @@ -0,0 +1,36 @@ +#include "constraint.h" + + +Constraint::Constraint(Solution const &solution) : solution(solution) {} + +Solution const &Constraint::getSolution() const +{ + return solution.get(); +} + +PDPTWData const &Constraint::data() const +{ + return getSolution().getData(); +} + +void Constraint::setSolution(Solution const &newSolutionOwner) +{ + solution = newSolutionOwner; +} + + +void ModificationVisitor::applyVariant(ModificationApplyVariant const &applyModificationVariant) +{ + // lambda auto&& + std::visit combo + // allows to split the variant to each strongly typed function for each modification (see the protected pure virtual functions apply) + // If compilation breaks here, it is likely that a type T in the ModificationApplyVariant has no function ModificationVisitor::apply(T const &) associated + std::visit([this](auto &&op) { this->apply(op); }, applyModificationVariant); +} + +bool ConstraintVisitor::checkVariant(ModificationCheckVariant const &checkModificationVariant) +{ + // lambda auto&& + std::visit combo + // allows to split the variant to each strongly typed function for each modification (see the protected pure virtual functions apply) + // If compilation breaks here, it is likely that a type T in the ModificationCheckVariant has no function ConstraintVisitor::apply(T const &) associated + return std::visit([this](auto &&op) { return this->check(op); }, checkModificationVariant); +} diff --git a/src/lns/constraints/constraint.h b/src/lns/constraints/constraint.h new file mode 100644 index 0000000000000000000000000000000000000000..f41e778eab64f2a6c3869012dfbd34615667df7a --- /dev/null +++ b/src/lns/constraints/constraint.h @@ -0,0 +1,98 @@ +#pragma once +#include <variant> +#include "./../solution/solution.h" + +// all modifications +#include "./../modification/pair/insert_pair.h" +#include "./../modification/pair/remove_pair.h" +#include "./../modification/route/insert_route.h" +#include "./../modification/route/remove_route.h" + + +using ModificationApplyVariant = + std::variant<std::reference_wrapper<InsertPair const>, std::reference_wrapper<InsertRoute const>, + std::reference_wrapper<RemovePair const>, std::reference_wrapper<RemoveRoute const>>; + +// defines the variant that can store all the modifications that can be checked (recreation modifications) +using ModificationCheckVariant = + std::variant<std::reference_wrapper<InsertPair const>, std::reference_wrapper<InsertRoute const>, + std::reference_wrapper<RemovePair const>, std::reference_wrapper<RemoveRoute const>>; + + +/** + * Visitor pattern for the modifications. + * It splits the variant into separate apply functions for each Modification. + */ +class ModificationVisitor +{ +protected: + // A child class must handle all the modification types ie. implement all these functions + virtual void apply(InsertPair const &op) = 0; + virtual void apply(InsertRoute const &op) = 0; + virtual void apply(RemovePair const &op) = 0; + virtual void apply(RemoveRoute const &op) = 0; + +public: + /** + * A modification has been applied to the solution, + * the constraint can use information from the modification to update its state. + */ + void applyVariant(ModificationApplyVariant const &applyModificationVariant); +}; + + +/** + * Visitor pattern for the constraint. Adds the check part that constraints must implement + * It splits the variant into separate check/apply functions for each Modification. + */ +class ConstraintVisitor : public ModificationVisitor +{ +protected: + // A child class must handle all the modification types ie. implement all these functions + virtual bool check(InsertPair const &op) const = 0; + virtual bool check(InsertRoute const &op) const = 0; + virtual bool check(RemovePair const &op) const = 0; + virtual bool check(RemoveRoute const &op) const = 0; + + +public: +virtual ~ConstraintVisitor() = default; + /** + * Checks that a modification is valid for the solution + * If a check fails it must return false. + */ + bool checkVariant(ModificationCheckVariant const &checkModificationVariant); +}; + + +/** + * Base class for a constraint. + * It has to define all checks (from ConstraintVisitor), + * and can modify its state with the apply (from ModificationVisitor), it looks like a listener pattern + */ +class Constraint : public ConstraintVisitor +{ + std::reference_wrapper<Solution const> solution; + +protected: + explicit Constraint(Solution const &); + PDPTWData const &data() const; + +public: + /** + * It is expected that the new Solution is in valid state regarding precedence graph and times when cloning + */ + virtual std::unique_ptr<Constraint> clone(Solution const &newOwningSolution) const = 0; + + Solution const &getSolution() const; + + // used when a solution is moved, we must update the owner + void setSolution(Solution const &newSolutionOwner); + ~Constraint() override = default; + + /** + * Callback when many destruction are done. It is expected that checks work after a call to this. + * Defaults to no op + */ + virtual void endOfDestructionCallback() {} +}; \ No newline at end of file diff --git a/src/lns/constraints/time_window/time_window_constraint.cpp b/src/lns/constraints/time_window/time_window_constraint.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe4134e7e243056ab7e1fc05f85d2b140563def8 --- /dev/null +++ b/src/lns/constraints/time_window/time_window_constraint.cpp @@ -0,0 +1,137 @@ +#include "time_window_constraint.h" +#include "input/data.h" +#include "input/pdptw_data.h" +#include "input/time_window.h" +#include "lns/solution/solution.h" + + +TimeWindowConstraint::TimeWindowConstraint(Solution const &solution) : Constraint(solution) +{ + // Empty +} + +std::unique_ptr<Constraint> TimeWindowConstraint::clone(Solution const &newOwningSolution) const { + std::unique_ptr<TimeWindowConstraint> clonePtr = std::make_unique<TimeWindowConstraint>(newOwningSolution); + clonePtr->allRouteReachTimes = allRouteReachTimes; + return clonePtr; +} + + +// Copie le vecteur de reach time de la route concernée +// Insère les positions pickup/delivery +// refait l'ordo sur le nouveau vecteur +bool TimeWindowConstraint::checkInsertion(const PDPTWData& data, const Pair & pair, int routeIndex, int pickupPos, int deliveryPos) const +{ + ReachTimeVector const &reachTimes = allRouteReachTimes.at(routeIndex); + + // COPY route vector + std::vector<int> route(getSolution().getRoute(routeIndex).getRoute().begin(), getSolution().getRoute(routeIndex).getRoute().end()) ; + // COPY reachTimes vector + ReachTimeVector newReachTimes(reachTimes.begin(), reachTimes.end()); + + // Insert pickup and delivery + route.insert(route.begin() + pickupPos, pair.getPickup().getId()); + route.insert(route.begin() + deliveryPos, pair.getDelivery().getId()); + + // Compute new reach time + computeReachTimes(data, route, newReachTimes); + + // Check Time Windows + for (int i = 0; i < reachTimes.size(); ++i) + { + if (! data.getLocation(route[i]).getTimeWindow().isValid(newReachTimes.at(i)) ) + { + return false; + } + } + return true; +} + +void TimeWindowConstraint::computeReachTimes(const PDPTWData& data, const std::vector<int> & routeIDs, ReachTimeVector & reachTimes) const +{ + // Adjust the size of reachTimes vector + reachTimes.resize(routeIDs.size(), 0); + // Time to the first location + reachTimes[0] = data.getDepot().getTimeWindow().getStart() + data::TravelTime(data, 0, routeIDs.at(0)); + // Compute other reachTimes (max between arrival and start of the time window) + for (int i = 1; i < routeIDs.size(); ++i) { + TimeInteger travelTime = data::TravelTime(data, routeIDs[i - 1], routeIDs[i]); + TimeInteger serviceTime = data.getLocation(routeIDs[i - 1]).getServiceDuration(); + TimeInteger startTW = data.getLocation(routeIDs[i]).getTimeWindow().getStart(); + reachTimes[i] = std::max(reachTimes[i - 1] + serviceTime + travelTime, startTW); + } +} + + +void TimeWindowConstraint::ApplyModif(const PDPTWData& data, const Pair & pair, int routeIndex, int pickupPos, int deliveryPos, bool addPair) +{ + // COPY route vector + std::vector<int> routeIDs(getSolution().getRoute(routeIndex).getRoute().begin(), getSolution().getRoute(routeIndex).getRoute().end()); + + // Adjust pickup and delivery + if (addPair) + { + routeIDs.insert(routeIDs.begin() + pickupPos, pair.getPickup().getId()); + routeIDs.insert(routeIDs.begin() + deliveryPos, pair.getDelivery().getId()); + } + else + { + routeIDs.erase(routeIDs.begin() + deliveryPos); + routeIDs.erase(routeIDs.begin() + pickupPos); + } + + // Adjust the size of reachTimes vector + allRouteReachTimes[routeIndex].resize(routeIDs.size(), 0); + // Time to the first location + allRouteReachTimes[routeIndex][0] = data.getDepot().getTimeWindow().getStart() + data::TravelTime(data, 0, routeIDs.at(0)); + // Compute other reachTimes (max between arrival and start of the time window) + for (int i = 1; i < routeIDs.size(); ++i) { + TimeInteger travelTime = data::TravelTime(data, routeIDs[i - 1], routeIDs[i]); + TimeInteger serviceTime = data.getLocation(routeIDs[i - 1]).getServiceDuration(); + TimeInteger startTW = data.getLocation(routeIDs[i]).getTimeWindow().getStart(); + allRouteReachTimes[routeIndex][i] = std::max(allRouteReachTimes[routeIndex][i - 1] + serviceTime + travelTime, startTW); + } +} + + +bool TimeWindowConstraint::check(InsertPair const &op) const +{ + return checkInsertion(getSolution().getData(), op.getPair(), op.getRouteIndex(), op.getPickupInsertion(), op.getDeliveryInsertion()); +} +void TimeWindowConstraint::apply(InsertPair const &op) +{ + ApplyModif(getSolution().getData(), op.getPair(), op.getRouteIndex(), op.getPickupInsertion(), op.getDeliveryInsertion(), true); +} + +bool TimeWindowConstraint::check(InsertRoute const &op) const +{ + return true; +} +void TimeWindowConstraint::apply(InsertRoute const &op) +{ + allRouteReachTimes.emplace_back(); +} + + +bool TimeWindowConstraint::check(RemovePair const &op) const +{ + return true; +} +void TimeWindowConstraint::apply(RemovePair const &op) +{ + ApplyModif(getSolution().getData(), op.getPair(), op.getRouteIndex(), op.getPickupDeletion(), op.getDeliveryDeletion(), false); +} + + +bool TimeWindowConstraint::check(RemoveRoute const &op) const +{ + return true; +} +void TimeWindowConstraint::apply(RemoveRoute const &op) +{ + allRouteReachTimes.erase(allRouteReachTimes.begin() + op.getRouteIndex()); +} + + + + diff --git a/src/lns/constraints/time_window/time_window_constraint.h b/src/lns/constraints/time_window/time_window_constraint.h new file mode 100644 index 0000000000000000000000000000000000000000..89bc0554cb5788eeeda339aac70fca22191d6888 --- /dev/null +++ b/src/lns/constraints/time_window/time_window_constraint.h @@ -0,0 +1,67 @@ +#pragma once + +#include "lns/constraints/constraint.h" +#include "input/pair.h" +#include "input/time_window.h" +#include <vector> + +/** + * Time Window Constraint + * Check that the time windows are respected. + * For now, compute all time window in a route + * TO DO FTS + */ +class TimeWindowConstraint : public Constraint +{ +public: + explicit TimeWindowConstraint(Solution const &); + TimeWindowConstraint(TimeWindowConstraint const &) = default; + + std::unique_ptr<Constraint> clone(Solution const &newOwningSolution) const override; + +private: + using ReachTimeVector = std::vector<TimeInteger>; + + + + /** + * For each route, store the reach time of each location + */ + std::vector<ReachTimeVector> allRouteReachTimes; + + // Recalcul tous les reachTimes pour une route + ReachTimeVector computeReachTimes(const Route& route) const; + bool updateReachTimes(const PDPTWData& data, Pair & pair,int routeIndex, int pickupPos, int deliveryPos); + + /** + * Check if the insertion of a pair pickup/delivery is valid or not. + * COPY the route where we insert the pair ! + */ + bool checkInsertion(const PDPTWData& data, const Pair & pair, int routeIndex, int pickupPos, int deliveryPos) const; + + /** + * Given route IDs, compute the reachTimes of the route. + * If a vehicule is in advance, set the reach time to start of the timeWindow. + * Modify reachTimes vector ! + */ + void computeReachTimes(const PDPTWData& data, const std::vector<int> & routeIDs, ReachTimeVector & reachTimes) const; + + /** + * Given route IDs, modify the reachTimes + */ + void ApplyModif(const PDPTWData& data, const Pair & pair, int routeIndex, int pickupPos, int deliveryPos, bool addPair); + + + void apply(InsertPair const &op) override; + void apply(InsertRoute const &op) override; + void apply(RemovePair const &op) override; + void apply(RemoveRoute const &op) override; + + bool check(InsertPair const &op) const override; + bool check(InsertRoute const &op) const override; + bool check(RemovePair const &op) const override; + bool check(RemoveRoute const &op) const override; + +public: + +}; \ No newline at end of file diff --git a/src/lns/modification/pair/insert_pair.cpp b/src/lns/modification/pair/insert_pair.cpp index 46160fd88bbe9a00b3ad9f7d5ce5a846f593e467..206d66f81936e1b3f1dcafae56f2911c86b2ed89 100644 --- a/src/lns/modification/pair/insert_pair.cpp +++ b/src/lns/modification/pair/insert_pair.cpp @@ -8,7 +8,17 @@ InsertPair::InsertPair(int routeIndex, int pickupInsertion, int deliveryInsertio pickupInsertion(pickupInsertion), deliveryInsertion(deliveryInsertion), pickupLocation(pickupLocation), - deliveryLocation(deliveryLocation) {} + deliveryLocation(deliveryLocation), + pair(Pair(pickupLocation, deliveryLocation)) {} + +InsertPair::InsertPair(int routeIndex, int pickupInsertion, int deliveryInsertion, + Pair const &pair) + : routeIndex(routeIndex), + pickupInsertion(pickupInsertion), + deliveryInsertion(deliveryInsertion), + pickupLocation(pair.getPickup()), + deliveryLocation(pair.getDelivery()), + pair(pair) {} void InsertPair::modifySolution(Solution &solution) @@ -79,3 +89,9 @@ const Location *InsertPair::getAddedLocation() const return &pickupLocation; } +const Pair &InsertPair::getPair() const +{ + return pair; +} + + diff --git a/src/lns/modification/pair/insert_pair.h b/src/lns/modification/pair/insert_pair.h index a2537b504a3dcd75c7eb374e8e58302edfd964e1..ddeea7f9d389a828abe7fcb47e9ceb196f74fb28 100644 --- a/src/lns/modification/pair/insert_pair.h +++ b/src/lns/modification/pair/insert_pair.h @@ -3,6 +3,7 @@ #include "./../atomic_recreation.h" #include "./../../solution/solution.h" #include "./../../../input/location.h" +#include "./../../../input/pair.h" #include <functional> class Route; @@ -37,8 +38,11 @@ class InsertPair : public AtomicRecreation */ Location const & deliveryLocation; + Pair const & pair; + public: InsertPair(int routeIndex, int pickupInsertion, int deliveryInsertion, Location const &pickupLocation, Location const &deliveryLocation); + InsertPair(int routeIndex, int pickupInsertion, int deliveryInsertion, Pair const &pair); void modifySolution(Solution &solution) override; double evaluate(Solution const &solution) const override; @@ -48,6 +52,7 @@ public: int getRouteIndex() const; Location const &getPickupLocation() const; Location const &getDeliveryLocation() const; + Pair const &getPair() const; Location const *getAddedLocation() const override; diff --git a/src/lns/modification/pair/remove_pair.cpp b/src/lns/modification/pair/remove_pair.cpp index d279e85c89734ff69cb4ed725249a79378919cd9..fcb2fb40fa9b32fea860edffe311c2fcf85968d0 100644 --- a/src/lns/modification/pair/remove_pair.cpp +++ b/src/lns/modification/pair/remove_pair.cpp @@ -7,8 +7,18 @@ RemovePair::RemovePair(int routeIndex, int pickupDeletion, int deliveryDeletion, routeIndex(routeIndex), pickupDeletion(pickupDeletion), deliveryDeletion(deliveryDeletion), - pickupLocation(pickupLocation), - deliveryLocation(deliveryLocation) {} + pickupLocation(pickupLocation), + deliveryLocation(deliveryLocation), + pair(Pair(pickupLocation, deliveryLocation)) {} + +RemovePair::RemovePair(int routeIndex, int pickupDeletion, int deliveryDeletion, + Pair const &pair) : + routeIndex(routeIndex), + pickupDeletion(pickupDeletion), + deliveryDeletion(deliveryDeletion), + pickupLocation(pair.getPickup()), + deliveryLocation(pair.getDelivery()), + pair(pair) {} void RemovePair::modifySolution(Solution &solution) { @@ -78,4 +88,9 @@ Location const & RemovePair::getDeliveryLocation() const std::vector<int> const & RemovePair::getDeletedRequests() const { return removedLocationID; +} + +Pair const &RemovePair::getPair() const +{ + return pair; } \ No newline at end of file diff --git a/src/lns/modification/pair/remove_pair.h b/src/lns/modification/pair/remove_pair.h index d71a9629b9aa39be849cdcfa46de70fdcf01dfff..cb543e724c4cfb36c1a5f05f40420c012624b4e5 100644 --- a/src/lns/modification/pair/remove_pair.h +++ b/src/lns/modification/pair/remove_pair.h @@ -3,6 +3,7 @@ #include "./../atomic_destruction.h" #include "./../../solution/solution.h" #include "./../../../input/location.h" +#include "./../../../input/pair.h" #include <functional> class Route; @@ -35,6 +36,7 @@ class RemovePair : public AtomicDestruction */ Location const & deliveryLocation; + Pair const & pair; /** * Removed Location ID (empty before ModifySolution is called) @@ -44,6 +46,7 @@ class RemovePair : public AtomicDestruction public: RemovePair(int routeIndex, int pickupDeletion, int deliveryDeletion, Location const &pickupLocation, Location const &deliveryLocation); + RemovePair(int routeIndex, int pickupDeletion, int deliveryDeletion, Pair const &pair); void modifySolution(Solution &solution) override; double evaluate(Solution const &solution) const override; @@ -54,6 +57,8 @@ public: Location const &getPickupLocation() const; Location const &getDeliveryLocation() const; + Pair const &getPair() const; + /** * Return the location ID of location that has been deleted */ diff --git a/src/lns/solution/route.h b/src/lns/solution/route.h index 5f645698614e6fa64afe312234a0c0c938ffd19d..67686cfd8bbaba29dff91caadf984dcc3d785498 100644 --- a/src/lns/solution/route.h +++ b/src/lns/solution/route.h @@ -11,8 +11,9 @@ class Route { private: - int cost; std::vector<int> route; + int cost; + /* Stocké dans les contraintes diff --git a/src/main.cpp b/src/main.cpp index 21ba0830faf30f4b9912421f7190cb30c02c511a..7c736af9788670fc1a0bf7902534f0f5bfe223d7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,6 +13,8 @@ #include "input/time_window.h" #include "input/json_parser.h" #include "input/data.h" +#include "lns/constraints/capacity/capacity_constraint.h" +#include "lns/constraints/time_window/time_window_constraint.h" #include "lns/solution/solution.h" #include "lns/modification/pair/insert_pair.h" #include "lns/modification/route/insert_route.h" @@ -24,10 +26,9 @@ using json = nlohmann::json; int main(int argc, char const *argv[]) { - /* code */ - //std::string filepath = "/home/a24jacqb/Documents/Code/pdptw-main/data_in/test_inst.json"; - std::string filepath = "/home/a24jacqb/Documents/Code/pdptw-main/data_in/n100/bar-n100-1.json"; + //std::string filepath = "/home/a24jacqb/Documents/Code/pdptw-main/data_in/n100/bar-n100-1.json"; + std::string filepath = "/home/a24jacqb/Documents/Code/pdptw-main/data_in/Nantes_1.json"; //std::string filepath = "/home/a24jacqb/Documents/Code/pdptw-main/data_in/n5000/bar-n5000-1.json"; std::cout << filepath << "\n"; @@ -38,58 +39,58 @@ int main(int argc, char const *argv[]) /* * test */ + Solution emptySol = Solution(data); + + // SOLUTION 1-6-2-7 (time ; 104) + + Solution::RequestBank bank {3,4,5,8,9,10}; + + std::vector<int> path {1,2,6,7}; + Route route = Route(path, 0); + std::vector<Route> routes; + routes.push_back(route); - // Empty Solution - Solution sol = Solution(data); + int totalCost = 0; - InsertRoute op1 = InsertRoute(); + Solution sol = Solution(data, bank, routes, totalCost); + + sol.print(); - // Ajoute une route vide - op1.modifySolution(sol); - Location r1P = data.getLocations()[0]; - Location r1D = data.getLocations()[50]; + // Couple pickup/delivery Location r2P = data.getLocations()[1]; - Location r2D = data.getLocations()[51]; + Location r2D = data.getLocations()[6]; Location r3P = data.getLocations()[2]; - Location r3D = data.getLocations()[52]; + Location r3D = data.getLocations()[7]; - // 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"; + Pair pair2 = Pair(r2P, r2D); + Pair pair3 = Pair(r3P, r3D); + + // Modification + InsertPair opInsert = InsertPair(0, 2, 2, pair3); - 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); + CapacityConstraint cap_const = CapacityConstraint(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"; + cap_const.initCapacities(); + cap_const.print(); - op5.modifySolution(sol); - sol.print(); + std::cout << "Is Valid ? : " << cap_const.checkVariant(opInsert) << "\n"; - data::routeCost(data, sol.getRoute(0)); + cap_const.applyVariant(opInsert); - RemoveRoute op6 = RemoveRoute(0); + cap_const.print(); - std::cout << "cout de supr : "<< op6.evaluate(sol) << "\n"; + RemovePair opRemove = RemovePair(0, 2, 3, pair3); - op6.modifySolution(sol); + cap_const.applyVariant(opRemove); + + cap_const.print(); + */ - sol.print(); + TimeWindowConstraint twconst = TimeWindowConstraint(sol); return 0; }