From abc43935e5f543fc58f2d14190c0e885303af5eb Mon Sep 17 00:00:00 2001 From: awenjb <126257927+awenjb@users.noreply.github.com> Date: Fri, 14 Mar 2025 16:24:50 +0100 Subject: [PATCH] Add new sorting strategies - add sorting based on demand - add sorting based on nearest and furthest - add sorting based on time window --- .../capacity/capacity_constraint.cpp | 4 +- .../time_window/time_window_constraint.cpp | 4 +- src/lns/lns.cpp | 7 +- .../operators/destruction/random_destroy.cpp | 7 +- .../list_heuristic_cost_oriented.cpp | 17 ++++- .../list_heuristic_cost_oriented.h | 2 - .../list_heuristic_insertion.cpp | 2 - .../reconstruction/list_heuristic_insertion.h | 2 - .../selector/small_large_selector.cpp | 2 + src/lns/operators/sorting_strategy.cpp | 73 +++++++++++++++++++ src/lns/operators/sorting_strategy.h | 70 +++++++++++++++++- src/lns/solution/solution.cpp | 9 +-- src/mains/main.cpp | 31 ++++++-- src/output/solution_checker.cpp | 8 -- 14 files changed, 193 insertions(+), 45 deletions(-) diff --git a/src/lns/constraints/capacity/capacity_constraint.cpp b/src/lns/constraints/capacity/capacity_constraint.cpp index ccc8d97..34ad11f 100644 --- a/src/lns/constraints/capacity/capacity_constraint.cpp +++ b/src/lns/constraints/capacity/capacity_constraint.cpp @@ -102,12 +102,12 @@ void CapacityConstraint::applyModif(Pair const &pair, int routeIndex, int Pickup bool CapacityConstraint::check(InsertPair const &op) const { - std::cout << " #Capa Check"; + //std::cout << " #Capa Check"; return checkModif(op.getPair(), op.getRouteIndex(), op.getPickupInsertion(), op.getDeliveryInsertion()); } void CapacityConstraint::apply(InsertPair const &op) { - std::cout << "-> Apply Modification on Capacity \n"; + //std::cout << "-> Apply Modification on Capacity \n"; applyModif(op.getPair(), op.getRouteIndex(), op.getPickupInsertion(), op.getDeliveryInsertion(), true); } diff --git a/src/lns/constraints/time_window/time_window_constraint.cpp b/src/lns/constraints/time_window/time_window_constraint.cpp index 7421d50..ca0c629 100644 --- a/src/lns/constraints/time_window/time_window_constraint.cpp +++ b/src/lns/constraints/time_window/time_window_constraint.cpp @@ -179,7 +179,7 @@ void TimeWindowConstraint::ApplyModif(PDPTWData const &data, Pair const &pair, i bool TimeWindowConstraint::check(InsertPair const &op) const { - std::cout << " #TW Check"; + //std::cout << " #TW Check"; return checkInsertion(getSolution().getData(), op.getPair(), op.getRouteIndex(), @@ -189,7 +189,7 @@ bool TimeWindowConstraint::check(InsertPair const &op) const void TimeWindowConstraint::apply(InsertPair const &op) { - std::cout << "-> Apply Modification on Time Windows \n"; + //std::cout << "-> Apply Modification on Time Windows \n"; ApplyModif(getSolution().getData(), op.getPair(), op.getRouteIndex(), diff --git a/src/lns/lns.cpp b/src/lns/lns.cpp index aee47c9..e79bcb7 100644 --- a/src/lns/lns.cpp +++ b/src/lns/lns.cpp @@ -23,16 +23,16 @@ output::LnsOutput lns::runLns(Solution const &initialSolution, OperatorSelector Solution actualSolution = initialSolution; Solution bestSolution = initialSolution; - int it = 10; + int it = 100; while (it > 0) - { + { + std::cout << "\n" << 101-it << " : "; /** * The solution on which we apply the operators. * It is discarded at the end of each loop if it is not accepted by the Acceptance Function. */ Solution candidateSolution = actualSolution; - // Chose operator pair auto destructReconstructPair = opSelector.getOperatorPair(); // Apply operators @@ -42,6 +42,7 @@ output::LnsOutput lns::runLns(Solution const &initialSolution, OperatorSelector // Update best solution if (isBetterSolution(candidateSolution, bestSolution)) { + std::cout << "\n > new Best Solution \n"; checker::checkAll(candidateSolution, candidateSolution.getData(), false); bestSolution = candidateSolution; diff --git a/src/lns/operators/destruction/random_destroy.cpp b/src/lns/operators/destruction/random_destroy.cpp index fb3fdec..819029f 100644 --- a/src/lns/operators/destruction/random_destroy.cpp +++ b/src/lns/operators/destruction/random_destroy.cpp @@ -9,7 +9,7 @@ void RandomDestroy::destroySolution(Solution &solution) const { - std::cout << " --- Random Destroy --- \n"; + std::cout << "RD "; int nbRequests = solution.requestsFulFilledCount(); int actualNumberOfPairsToDestroy = std::min(nbRequests, numberOfPairsToDestroy); @@ -23,11 +23,6 @@ void RandomDestroy::destroySolution(Solution &solution) const // choose a random location int locationNumber = util::getRandomInt(0, remainingPairToDelete * 2 - 1); - // test - // locationNumber = nbRequests * 2 - 1; - // std::cout << " " << locationNumber << " \n"; - // - int pairID = 0; int routeID = 0; int position = 0; diff --git a/src/lns/operators/reconstruction/list_heuristic_cost_oriented.cpp b/src/lns/operators/reconstruction/list_heuristic_cost_oriented.cpp index 55d94f1..7a5b95d 100644 --- a/src/lns/operators/reconstruction/list_heuristic_cost_oriented.cpp +++ b/src/lns/operators/reconstruction/list_heuristic_cost_oriented.cpp @@ -11,8 +11,8 @@ void ListHeuristicCostOriented::reconstructSolution(Solution &solution, double b switch (strategy) { case SortingStrategyType::SHUFFLE: { - std::cout << " \n(Shuffle)\n"; // copy + std::cout << "S"; sortedPairs = sorting_strategy::Shuffle(solution).sortPairs(); break; } @@ -22,6 +22,19 @@ void ListHeuristicCostOriented::reconstructSolution(Solution &solution, double b break; } + // just for print (no use) + + switch (enumeration) + { + case EnumerationType::ALL_INSERT_PAIR: { + // copy + std::cout << "_AIP "; + } + default: + break; + } + + for (int pairID: sortedPairs) { Pair const &pair = solution.getData().getPair(pairID); @@ -33,7 +46,6 @@ void ListHeuristicCostOriented::reconstructSolution(Solution &solution, double b switch (enumeration) { case EnumerationType::ALL_INSERT_PAIR: { - std::cout << " \n(All insert pair) \n"; enumeration::enumerateAllInsertPair( solution, pair, @@ -49,7 +61,6 @@ void ListHeuristicCostOriented::reconstructSolution(Solution &solution, double b if (bestRecreation) { - std::cout << "\n --- Apply recreation --- \n"; solution.applyRecreateSolution(*bestRecreation); } } diff --git a/src/lns/operators/reconstruction/list_heuristic_cost_oriented.h b/src/lns/operators/reconstruction/list_heuristic_cost_oriented.h index 0833c84..36355e0 100644 --- a/src/lns/operators/reconstruction/list_heuristic_cost_oriented.h +++ b/src/lns/operators/reconstruction/list_heuristic_cost_oriented.h @@ -42,8 +42,6 @@ std::function<void(ModificationType &&)> keepBestSolution(Solution const &soluti // then store the best cost and the modification to the pointer if (cost < bestCost && util::getRandom() >= blinkRate && solution.checkModification(modification)) { - std::cout << " => Better Modification, update pointer" - << "\n"; bestModificationPtr = std::make_unique<ModificationType>(modification); bestCost = cost; } diff --git a/src/lns/operators/reconstruction/list_heuristic_insertion.cpp b/src/lns/operators/reconstruction/list_heuristic_insertion.cpp index e12eacb..9247078 100644 --- a/src/lns/operators/reconstruction/list_heuristic_insertion.cpp +++ b/src/lns/operators/reconstruction/list_heuristic_insertion.cpp @@ -18,7 +18,6 @@ void ListHeuristicInsertion::reconstructSolution(Solution &solution, double blin switch (strategy) { case SortingStrategyType::SHUFFLE: { - std::cout << " \n(Shuffle)\n"; // copy sortedPairs = sorting_strategy::Shuffle(solution).sortPairs(); break; @@ -54,7 +53,6 @@ std::unique_ptr<AtomicRecreation> ListHeuristicInsertion::selectRecreation(Solut switch (enumeration) { case EnumerationType::ALL_INSERT_PAIR: { - std::cout << " \n(All insert pair) \n"; enumeration::enumerateAllInsertPair(solution, pair, addToListIfValidTemplate<InsertPair>(solution, modifications)); break; diff --git a/src/lns/operators/reconstruction/list_heuristic_insertion.h b/src/lns/operators/reconstruction/list_heuristic_insertion.h index 66f1e98..142438f 100644 --- a/src/lns/operators/reconstruction/list_heuristic_insertion.h +++ b/src/lns/operators/reconstruction/list_heuristic_insertion.h @@ -52,8 +52,6 @@ std::function<void(ModificationType &&)> addToListIfValidTemplate(Solution const return [&](ModificationType &&modification) { if (solution.checkModification(modification)) { - std::cout << " => Insert Modification" - << "\n"; list.push_front(std::make_unique<ModificationType>(modification)); } }; diff --git a/src/lns/operators/selector/small_large_selector.cpp b/src/lns/operators/selector/small_large_selector.cpp index eaebf5d..e91912f 100644 --- a/src/lns/operators/selector/small_large_selector.cpp +++ b/src/lns/operators/selector/small_large_selector.cpp @@ -20,8 +20,10 @@ OperatorPair SmallLargeOperatorSelector::getOperatorPair() } iterationForNextStep = selectorPerSize.at(selectorStep).first; } + SimpleOperatorSelector &selector = selectorPerSize.at(selectorStep).second; OperatorPair pair = selector.getOperatorPair(); + // when we arrive at the last iteration of the last selector, we force the acceptance if (iterationAtCurrentStep == iterationForNextStep - 1 && selectorStep == selectorPerSize.size()) [[unlikely]] { diff --git a/src/lns/operators/sorting_strategy.cpp b/src/lns/operators/sorting_strategy.cpp index a639b8e..babc1a8 100644 --- a/src/lns/operators/sorting_strategy.cpp +++ b/src/lns/operators/sorting_strategy.cpp @@ -1,13 +1,86 @@ #include "sorting_strategy.h" +#include "input/pdptw_data.h" +#include "input/data.h" #include "utils.h" #include <algorithm> #include <ranges> + +double getDistanceToDepot(PDPTWData const &data, int pairID) +{ + return data::TravelTime(data, 0, pairID); +} + + std::vector<int> const &sorting_strategy::Shuffle::sortPairs() const { auto &bank = getSolution().getPairBank(); std::ranges::shuffle(bank, util::getRawRandom()); return bank; +} + +std::vector<int> const &sorting_strategy::Demand::sortPairs() const +{ + auto &bank = getSolution().getPairBank(); + + // Pair ID = Pickup ID + std::sort(bank.begin(), bank.end(), [&](int a, int b) { + return getSolution().getData().getLocation(a).getDemand() > getSolution().getData().getLocation(b).getDemand(); + }); + return bank; +} + +// Following sorting strategy are based on the pickup, TO DO, sort based on the pickup and the delivery + + +std::vector<int> const &sorting_strategy::Close::sortPairs() const +{ + auto &bank = getSolution().getPairBank(); + // Pair ID = Pickup ID + std::sort(bank.begin(), bank.end(), [&](int a, int b) { + return getDistanceToDepot(getSolution().getData(), a) < getDistanceToDepot(getSolution().getData(), b); + }); + return bank; +} + +std::vector<int> const &sorting_strategy::Far::sortPairs() const +{ + auto &bank = getSolution().getPairBank(); + // Pair ID = Pickup ID + std::sort(bank.begin(), bank.end(), [&](int a, int b) { + return getDistanceToDepot(getSolution().getData(), a) > getDistanceToDepot(getSolution().getData(), b); + }); + return bank; +} + +std::vector<int> const &sorting_strategy::TimeWindowWidth::sortPairs() const +{ + auto &bank = getSolution().getPairBank(); + // Pair ID = Pickup ID + std::sort(bank.begin(), bank.end(), [&](int a, int b) { + return getSolution().getData().getLocation(a).getTimeWindow().getWidth() < getSolution().getData().getLocation(b).getTimeWindow().getWidth(); + }); + return bank; +} + +std::vector<int> const &sorting_strategy::TimeWindowStart::sortPairs() const +{ + auto &bank = getSolution().getPairBank(); + // Pair ID = Pickup ID + std::sort(bank.begin(), bank.end(), [&](int a, int b) { + return getSolution().getData().getLocation(a).getTimeWindow().getStart() < getSolution().getData().getLocation(b).getTimeWindow().getStart(); + }); + return bank; +} + +std::vector<int> const &sorting_strategy::TimeWindowEnd::sortPairs() const +{ + auto &bank = getSolution().getPairBank(); + // Pair ID = Pickup ID + std::sort(bank.begin(), bank.end(), [&](int a, int b) { + return getSolution().getData().getLocation(a).getTimeWindow().getEnd() > getSolution().getData().getLocation(b).getTimeWindow().getEnd(); + }); + return bank; } \ No newline at end of file diff --git a/src/lns/operators/sorting_strategy.h b/src/lns/operators/sorting_strategy.h index 4b33762..6624619 100644 --- a/src/lns/operators/sorting_strategy.h +++ b/src/lns/operators/sorting_strategy.h @@ -1,12 +1,20 @@ #pragma once +#include "input/time_window.h" #include "lns/solution/solution.h" /** * A type of sorting strategy for the bank of pairs */ -enum class SortingStrategyType { - SHUFFLE +enum class SortingStrategyType +{ + SHUFFLE, + DEMAND, + CLOSE, + FAR, + TWWIDTH, + TWSTART, + TWEND, }; namespace sorting_strategy @@ -34,11 +42,69 @@ namespace sorting_strategy */ class Shuffle : public SortingStrategy { + public: + using SortingStrategy::SortingStrategy; + std::vector<int> const &sortPairs() const override; + }; + + /** + * Sort the bank by decreasing order of demand + */ + class Demand : public SortingStrategy + { + public: + using SortingStrategy::SortingStrategy; + std::vector<int> const &sortPairs() const override; + }; + + /** + * Sort the bank by increasing distance from the depot + */ + class Close : public SortingStrategy + { + public: using SortingStrategy::SortingStrategy; + std::vector<int> const &sortPairs() const override; + }; + /** + * Sort the bank by decreasing distance from the depot + */ + class Far : public SortingStrategy + { public: + using SortingStrategy::SortingStrategy; std::vector<int> const &sortPairs() const override; }; + /** + * Sort the bank by increasing time window width + */ + class TimeWindowWidth : public SortingStrategy + { + public: + using SortingStrategy::SortingStrategy; + std::vector<int> const &sortPairs() const override; + }; + + /** + * Sort the bank by inscreasing time window start + */ + class TimeWindowStart : public SortingStrategy + { + public: + using SortingStrategy::SortingStrategy; + std::vector<int> const &sortPairs() const override; + }; + + /** + * Sort the bank by decreasing time window end + */ + class TimeWindowEnd : public SortingStrategy + { + public: + using SortingStrategy::SortingStrategy; + std::vector<int> const &sortPairs() const override; + }; }// namespace sorting_strategy \ No newline at end of file diff --git a/src/lns/solution/solution.cpp b/src/lns/solution/solution.cpp index e563f6e..fae1ffe 100644 --- a/src/lns/solution/solution.cpp +++ b/src/lns/solution/solution.cpp @@ -211,18 +211,18 @@ int Solution::requestsFulFilledCount() const bool Solution::checkModification(AtomicRecreation const &modification) const { - std::cout << "--- Check Modification Validity : "; + //std::cout << "--- Check Modification Validity : "; ModificationCheckVariant const &checkVariant = modification.asCheckVariant(); // visitor pattern for (std::unique_ptr<Constraint> const &constraint: constraints) { if (!constraint->checkVariant(checkVariant)) { - std::cout << "\n"; + //std::cout << "\n"; return false; } } - std::cout << "\n"; + //std::cout << "\n"; return true; } @@ -253,8 +253,6 @@ void Solution::applyRecreateSolution(AtomicRecreation &modification) } afterApplyModification(modification); - std::cout << "\n --- \n"; - this->print(); } void Solution::applyDestructSolution(AtomicDestruction &modification) @@ -269,7 +267,6 @@ void Solution::applyDestructSolution(AtomicDestruction &modification) pairBank.insert(pairBank.end(), deletedPair.begin(), deletedPair.end()); afterApplyModification(modification); - this->print(); } void Solution::check() const diff --git a/src/mains/main.cpp b/src/mains/main.cpp index fc86864..948b5cf 100644 --- a/src/mains/main.cpp +++ b/src/mains/main.cpp @@ -12,6 +12,7 @@ #include "lns/modification/pair/remove_pair.h" #include "lns/modification/route/insert_route.h" #include "lns/modification/route/remove_route.h" +#include "lns/operators/abstract_operator.h" #include "lns/operators/destruction/random_destroy.h" #include "lns/operators/reconstruction/enumerate.h" #include "lns/operators/reconstruction/list_heuristic_cost_oriented.h" @@ -45,9 +46,9 @@ void simpleLNS(PDPTWData const &data, Solution &startingSolution) ThresholdAcceptance acceptor(0.05); // lns operators - SimpleOperatorSelector smallSelector; - addAllReconstructor(smallSelector); - smallSelector.addDestructor(RandomDestroy(pairs)); + SimpleOperatorSelector RandomDestroy_ShuffleBestInsert; + addAllReconstructor(RandomDestroy_ShuffleBestInsert); + RandomDestroy_ShuffleBestInsert.addDestructor(RandomDestroy(pairs)); SimpleOperatorSelector largeSelector; addAllReconstructor(largeSelector); @@ -66,15 +67,16 @@ void simpleLNS(PDPTWData const &data, Solution &startingSolution) // lastSelector.addDestructor(RandomDestroy(manyPairs)); std::vector<SmallLargeOperatorSelector::StepSelector> selectors; - selectors.emplace_back(2, std::move(smallSelector)); - selectors.emplace_back(2, std::move(largeSelector)); + selectors.emplace_back(10, std::move(RandomDestroy_ShuffleBestInsert)); + // selectors.emplace_back(100, std::move(largeSelector)); // selectors.emplace_back(2, std::move(veryLargeSelector)); // selectors.emplace_back(2, std::move(hugeSelector)); // selectors.emplace_back(2, std::move(lastSelector)); SmallLargeOperatorSelector smallLargeSelector(std::move(selectors)); // run lns - lns::runLns(startingSolution, smallLargeSelector, acceptor); + output::LnsOutput result = lns::runLns(startingSolution, smallLargeSelector, acceptor); + result.getBestSolution().print(); } int main(int argc, char **argv) @@ -91,7 +93,22 @@ int main(int argc, char **argv) PDPTWData data = parsing::parseJson(filepath); Solution startingSolution = Solution::emptySolution(data); - simpleLNS(data, startingSolution); + //simpleLNS(data, startingSolution); + + /// + std::cout << "===== TEST ===== \n"; + Solution testSolution = Solution::emptySolution(data); + //ListHeuristicCostOriented reconstruction = ListHeuristicCostOriented(SortingStrategyType::SHUFFLE, EnumerationType::ALL_INSERT_PAIR); + //reconstruction.reconstructSolution(testSolution, 0.01); + + testSolution.print(); + sorting_strategy::Shuffle(testSolution).sortPairs(); + + testSolution.print(); + + sorting_strategy::TimeWindowStart(testSolution).sortPairs(); + + testSolution.print(); return 0; } diff --git a/src/output/solution_checker.cpp b/src/output/solution_checker.cpp index 36ab18c..dbd7dcc 100644 --- a/src/output/solution_checker.cpp +++ b/src/output/solution_checker.cpp @@ -11,8 +11,6 @@ void checker::checkSolutionCoherence(Solution const &sol, PDPTWData const &data) { - std::cout << " --- Solution Coherence checker : "; - bool errorFlag = false; // Vector that will store the route ID serving the location, (-1 if no routes) @@ -23,7 +21,6 @@ void checker::checkSolutionCoherence(Solution const &sol, PDPTWData const &data) int routeID = 0; for (Route const &route: sol.getRoutes()) { - std::cout << "#"; // skip if it is an empty route if (!route.getRoute().empty()) { @@ -31,8 +28,6 @@ void checker::checkSolutionCoherence(Solution const &sol, PDPTWData const &data) { if (check.at(LocID -1) != -1) { - std::cout << "#"; - // Error the location is already attributed (doublon) spdlog::error("Location {} has already been visited.", LocID); errorFlag = true; @@ -54,7 +49,6 @@ void checker::checkSolutionCoherence(Solution const &sol, PDPTWData const &data) ++routeID; } - std::cout << "#"; // checking PairBank coherence (given the routes) for (int pairID: sol.getBank()) @@ -73,8 +67,6 @@ void checker::checkSolutionCoherence(Solution const &sol, PDPTWData const &data) sol.print(); throw SolutionConstraintError("Error in the consistency of the solution.", sol); } - - std::cout << " : checker end ---\n"; } void checker::checkCapacity(Solution const &sol, PDPTWData const &data) -- GitLab