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