diff --git a/CMakeLists.txt b/CMakeLists.txt index c5466067ab2e3eea943fb63174ab2da7056338bc..96feadf83e7a405968380ac25da9ba5a57283f6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,8 @@ add_executable(pdptw src/mains/main.cpp src/lns/operators/sorting_strategy.cpp src/lns/operators/destruction/random_destroy.cpp src/lns/operators/reconstruction/enumerate.cpp - src/lns/operators/reconstruction/list_heuristic_insertion.hpp + src/lns/operators/reconstruction/list_heuristic_insertion.cpp + src/lns/operators/reconstruction/list_heuristic_cost_oriented.cpp src/lns/operators/selector/operator_selection.cpp src/utils.cpp ) diff --git a/src/lns/operators/reconstruction/enumerate.cpp b/src/lns/operators/reconstruction/enumerate.cpp index 24fabb6eb39e9bd05a5b5d78d9dc4b2d57a8419e..5a060def9c8faf37be68fe748dc790e39447cbde 100644 --- a/src/lns/operators/reconstruction/enumerate.cpp +++ b/src/lns/operators/reconstruction/enumerate.cpp @@ -2,17 +2,6 @@ namespace enumeration { - - template<std::derived_from<AtomicRecreation> ModificationType> - void addToListIfValidTemplate(Solution const &solution, ModificationType const &modification, ModificationContainer &list) - { - if (solution.checkModification(modification)) - { - std::cout << " => Insert Modification" << "\n"; - list.push_front(std::make_unique<ModificationType>(modification)); - } - } - /** * Enumerate InsertPair modifications. * Does some checks to cut some loops. (TO DO) @@ -20,19 +9,28 @@ namespace enumeration * @param pair * @param ModificationContainer */ - void enumerateAllInsertPair(Solution const &solution, Pair const &pair, ModificationContainer &list) + void enumerateAllInsertPair(Solution const &solution, Pair const &pair, std::function<void(InsertPair &&)> const &consumeModification) { int routeIndex = 0; // Insert into existing routes for (Route const &route: solution.getRoutes()) { - for (int p = 0; p <= route.getSize(); p++) + int routeSize = route.getSize(); + for (int p = 0; p <= routeSize; ++p) { - for (int d = p; d <= route.getSize(); d++) + for (int d = p; d <= routeSize; ++d) { Index index = std::make_tuple(routeIndex, p, d); - // add to list if valid modification - enumeration::addToListIfValidTemplate(solution, InsertPair(index, pair), list); + + consumeModification(InsertPair(index,pair)); + + // std::unique_ptr<InsertPair> modification = std::make_unique<InsertPair>(index, pair); + // // add to list if valid modification + // if (solution.checkModification(*modification)) + // { + // std::cout << " => Insert Modification\n"; + // list.push_front(std::move(modification)); + // } } } ++routeIndex; diff --git a/src/lns/operators/reconstruction/enumerate.h b/src/lns/operators/reconstruction/enumerate.h index 22cd2e29dca75f2ba6a0942c3fbd29eaf7252d0c..47ba175ba4d22be88ecea7490e549ddaf7bb1017 100644 --- a/src/lns/operators/reconstruction/enumerate.h +++ b/src/lns/operators/reconstruction/enumerate.h @@ -24,7 +24,7 @@ namespace enumeration * @param Pair * @param list */ - void enumerateAllInsertPair(Solution const &solution, Pair const &Pair, ModificationContainer &list); + void enumerateAllInsertPair(Solution const &solution, Pair const &pair, std::function<void(InsertPair &&)> const &consumeModification); }// namespace enumeration diff --git a/src/lns/operators/reconstruction/list_heuristic_cost_oriented.cpp b/src/lns/operators/reconstruction/list_heuristic_cost_oriented.cpp new file mode 100644 index 0000000000000000000000000000000000000000..47896e8c53b2db1b75a65a724f4be1d9fdf82fb1 --- /dev/null +++ b/src/lns/operators/reconstruction/list_heuristic_cost_oriented.cpp @@ -0,0 +1,53 @@ +#include "list_heuristic_cost_oriented.h" + +void ListHeuristicCostOriented::reconstructSolution(Solution &solution, double blinkRate, SortingStrategyType strategy, + EnumerationType enumeration) const +{ + std::vector<int> sortedPairs; + // selection strategy + switch (strategy) + { + case SortingStrategyType::SHUFFLE: { + std::cout << " \n(Shuffle)\n"; + // copy + sortedPairs = sorting_strategy::Shuffle(solution).sortPairs(); + break; + } + default: + spdlog::error("Error, invalid strategy selected."); + throw std::invalid_argument("Invalid sorting strategy selected."); + break; + } + + for (int pairID: sortedPairs) + { + Pair const &pair = solution.getData().getPair(pairID); + + AtomicRecreationPtr bestRecreation; + double bestRecreationCost = std::numeric_limits<double>::max(); + + // Enumeration strategy + switch (enumeration) + { + case EnumerationType::ALL_INSERT_PAIR: { + std::cout << " \n(All insert pair) \n"; + enumeration::enumerateAllInsertPair( + solution, + pair, + keepBestSolution<InsertPair>(solution, bestRecreation, bestRecreationCost, blinkRate)); + + break; + } + default: + spdlog::error("Error, invalid enumeration selected."); + throw std::invalid_argument("Invalid enumeration strategy selected."); + break; + } + + if (bestRecreation) + { + std::cout << "\n --- Apply recreation --- \n"; + solution.applyRecreateSolution(*bestRecreation); + } + } +} \ No newline at end of file diff --git a/src/lns/operators/reconstruction/list_heuristic_cost_oriented.h b/src/lns/operators/reconstruction/list_heuristic_cost_oriented.h new file mode 100644 index 0000000000000000000000000000000000000000..24c633f9f92e0a0272349470b72ff2f00276e089 --- /dev/null +++ b/src/lns/operators/reconstruction/list_heuristic_cost_oriented.h @@ -0,0 +1,46 @@ +#pragma once + +#include "input/data.h" +#include "input/pdptw_data.h" +#include "lns/operators/abstract_operator.h" +#include "lns/operators/sorting_strategy.h" +#include "utils.h" + +/** + * List heuristic operator but evaluates costs before trying to know if the modification is feasible + */ +class ListHeuristicCostOriented : public ReconstructionOperator +{ +public: + using AtomicRecreationPtr = std::unique_ptr<AtomicRecreation>; + void reconstructSolution(Solution &solution, double blinkRate, SortingStrategyType strategy, + EnumerationType enumeration) const override; +}; + +/** + * Create a function that will consume all the enumerated modifications + * @tparam ModificationType The type of modification enumerated + * @param bestModificationPtr the pointer to the actual best modification found yet + * @param bestCost the cost of the best modification + * @param blinkRate blinking rate + */ +template<std::derived_from<AtomicRecreation> ModificationType> +std::function<void(ModificationType &&)> keepBestSolution(Solution const &solution, + std::unique_ptr<AtomicRecreation> &bestModificationPtr, + double &bestCost, double blinkRate) +{ + return [&](ModificationType &&modification) { + double cost = modification.evaluate(solution); + // first test the cost + // if the modification is better, then blink, + // then check the modification + // 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.hpp b/src/lns/operators/reconstruction/list_heuristic_insertion.cpp similarity index 75% rename from src/lns/operators/reconstruction/list_heuristic_insertion.hpp rename to src/lns/operators/reconstruction/list_heuristic_insertion.cpp index fa241231917fc9494d1265b7501fa0d7b67d520d..bbe4dedecc7b2af810ed6a6318bcde342ea448fe 100644 --- a/src/lns/operators/reconstruction/list_heuristic_insertion.hpp +++ b/src/lns/operators/reconstruction/list_heuristic_insertion.cpp @@ -1,10 +1,7 @@ -#pragma once #include "list_heuristic_insertion.h" #include "lns/operators/sorting_strategy.h" #include "enumerate.h" -// This is a header, but it does define templates, so we can't put them in .cpp file -// for forward declaration you can use the .h file, but if you need to use the class, you must include this one instead #include <concepts> @@ -20,11 +17,13 @@ void ListHeuristicInsertion::reconstructSolution(Solution &solution, double blin case SortingStrategyType::SHUFFLE: { std::cout << " \n(Shuffle)\n"; + // copy sortedPairs = sorting_strategy::Shuffle(solution).sortPairs(); break; } default: - spdlog::error("Error, strategy selected."); + spdlog::error("Error, invalid strategy selected."); + throw std::invalid_argument("Invalid sorting strategy selected."); break; } @@ -32,7 +31,7 @@ void ListHeuristicInsertion::reconstructSolution(Solution &solution, double blin for (int pairID: sortedPairs) { Pair const &pair = solution.getData().getPair(pairID); - recreation = ListHeuristicInsertion::choosingStrategy(solution, pair, blinkRate, enumeration); + recreation = ListHeuristicInsertion::selectRecreation(solution, pair, blinkRate, enumeration); if (recreation) { std::cout << "\n --- Apply recreation --- \n"; @@ -41,27 +40,26 @@ void ListHeuristicInsertion::reconstructSolution(Solution &solution, double blin } } -std::unique_ptr<AtomicRecreation> ListHeuristicInsertion::choosingStrategy(Solution &solution, Pair const &pair, +std::unique_ptr<AtomicRecreation> ListHeuristicInsertion::selectRecreation(Solution &solution, Pair const &pair, double blinkRate, EnumerationType enumeration) { AtomicRecreationPtr bestInsertion; double bestKnownInsertionCost = std::numeric_limits<double>::max(); enumeration::ModificationContainer modifications; - //Generator().populate(solution, pair, modifications); - // // Enumeration strategy switch (enumeration) { case EnumerationType::ALL_INSERT_PAIR: { std::cout << " \n(All insert pair) \n"; - //enumerateAllInsertPair(Solution const &solution, Pair const &pair, ModificationContainer &list) - enumeration::enumerateAllInsertPair(solution, pair, modifications); + enumeration::enumerateAllInsertPair(solution, pair, addToListIfValidTemplate<InsertPair>(solution, modifications)); + break; } default: - spdlog::error("Error, enumeration selected."); + spdlog::error("Error, invalid enumeration selected."); + throw std::invalid_argument("Invalid enumeration strategy selected."); break; } diff --git a/src/lns/operators/reconstruction/list_heuristic_insertion.h b/src/lns/operators/reconstruction/list_heuristic_insertion.h index 895a47cdc6d2490781726f0b93af93dbd63580c9..395f88e29ea1a1b7dd1611b2ff68369d3ed29ff2 100644 --- a/src/lns/operators/reconstruction/list_heuristic_insertion.h +++ b/src/lns/operators/reconstruction/list_heuristic_insertion.h @@ -24,13 +24,36 @@ private: public: explicit ListHeuristicInsertion(); - void reconstructSolution(Solution &solution, double blinkRate, SortingStrategyType strategy, EnumerationType enumeration) const override; + void reconstructSolution(Solution &solution, double blinkRate, SortingStrategyType strategy, + EnumerationType enumeration) const override; private: /** * @param blinkRate probability to ignore the request insertion * @return the best insertion found */ - static std::unique_ptr<AtomicRecreation> choosingStrategy(Solution &solution, Pair const &pair, - double blinkRate, EnumerationType enumeration); + static std::unique_ptr<AtomicRecreation> selectRecreation(Solution &solution, Pair const &pair, double blinkRate, + EnumerationType enumeration); }; + +/** + * Used in enumerate.cpp functions to evaluate modification + * Do not evaluate cost (see list_heuristic_cost_oriented that evaluate cost before feasability) + * @tparam ModificationType the type of modification to be checked + * @param solution the solution to check the modification validity + * @param list the modification will be added to this list if valid + * @return a function that takes a ModificationType and add it to list iff it is valid + */ +template<std::derived_from<AtomicRecreation> ModificationType> +std::function<void(ModificationType &&)> addToListIfValidTemplate(Solution const &solution, + enumeration::ModificationContainer &list) +{ + return [&](ModificationType &&modification) { + if (solution.checkModification(modification)) + { + std::cout << " => Insert Modification" + << "\n"; + list.push_front(std::make_unique<ModificationType>(modification)); + } + }; +} \ No newline at end of file diff --git a/src/mains/main.cpp b/src/mains/main.cpp index 654c5c9c6997d93a002bf07e59cbe1b28190a8f7..c3ed313e0f985dd797044b2a8f55842e32e779d2 100644 --- a/src/mains/main.cpp +++ b/src/mains/main.cpp @@ -14,6 +14,7 @@ #include "input/data.h" #include "lns/constraints/capacity/capacity_constraint.h" #include "lns/constraints/time_window/time_window_constraint.h" +#include "lns/operators/reconstruction/list_heuristic_cost_oriented.h" #include "lns/solution/solution.h" #include "lns/modification/pair/insert_pair.h" #include "lns/modification/route/insert_route.h" @@ -21,7 +22,6 @@ #include "lns/modification/route/remove_route.h" #include "lns/operators/reconstruction/list_heuristic_insertion.h" -#include "lns/operators/reconstruction/list_heuristic_insertion.hpp" #include "lns/operators/sorting_strategy.h" #include "lns/operators/reconstruction/enumerate.h" @@ -76,8 +76,11 @@ int main(int argc, char const *argv[]) std::cout << "\n --- Operator - SHUFFLE - ALL_INSERTPAIR -> reconstruction (NO COST UPDATE)\n"; - ListHeuristicInsertion heuristicInsertion; - heuristicInsertion.reconstructSolution(solution, blinkRate, strategy, enumeration); + //ListHeuristicInsertion heuristicInsertion; + //heuristicInsertion.reconstructSolution(solution, blinkRate, strategy, enumeration); + + ListHeuristicCostOriented heuristic; + heuristic.reconstructSolution(solution, blinkRate, strategy, enumeration); solution.print();