From e497baabd078e1016d3accab15a1544d7dffa872 Mon Sep 17 00:00:00 2001 From: awenjb <126257927+awenjb@users.noreply.github.com> Date: Thu, 13 Mar 2025 16:26:17 +0100 Subject: [PATCH] Add selector --- CMakeLists.txt | 3 +- .../operator_selection.cpp => lns.cpp} | 0 src/lns/lns.h | 0 .../operators/selector/operator_selector.cpp | 33 ++++++ .../operators/selector/operator_selector.h | 104 ++++++++++++++++++ .../selector/small_large_selector.cpp | 38 +++++++ .../operators/selector/small_large_selector.h | 33 ++++++ src/mains/main.cpp | 55 ++++----- src/mains/main_interface.cpp | 2 +- 9 files changed, 234 insertions(+), 34 deletions(-) rename src/lns/{operators/selector/operator_selection.cpp => lns.cpp} (100%) create mode 100644 src/lns/lns.h create mode 100644 src/lns/operators/selector/operator_selector.cpp create mode 100644 src/lns/operators/selector/small_large_selector.cpp create mode 100644 src/lns/operators/selector/small_large_selector.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 96feadf..357cd49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,8 @@ add_executable(pdptw src/mains/main.cpp src/lns/operators/reconstruction/enumerate.cpp 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/lns/operators/selector/operator_selector.cpp + src/lns/operators/selector/small_large_selector.cpp src/utils.cpp ) diff --git a/src/lns/operators/selector/operator_selection.cpp b/src/lns/lns.cpp similarity index 100% rename from src/lns/operators/selector/operator_selection.cpp rename to src/lns/lns.cpp diff --git a/src/lns/lns.h b/src/lns/lns.h new file mode 100644 index 0000000..e69de29 diff --git a/src/lns/operators/selector/operator_selector.cpp b/src/lns/operators/selector/operator_selector.cpp new file mode 100644 index 0000000..e187ed1 --- /dev/null +++ b/src/lns/operators/selector/operator_selector.cpp @@ -0,0 +1,33 @@ +#include "operator_selector.h" + +#include "utils.h" + +ReconstructionOperator &OperatorPair::reconstructor() +{ + return reconstruct; +} + +DestructionOperator &OperatorPair::destructor() +{ + return destruct; +} + +bool OperatorPair::forceTakeSolution() const +{ + return forceAcceptance; +} + +OperatorPair::OperatorPair(DestructionOperator &destruct, ReconstructionOperator &reconstruct, bool forceAcceptance) + : destruct(destruct), reconstruct(reconstruct), forceAcceptance(forceAcceptance) +{} + +void OperatorPair::setForceAcceptance() +{ + forceAcceptance = true; +} + +OperatorPair SimpleOperatorSelector::getOperatorPair() +{ + return {*destructOperators.at(destructDistribution(util::getRawRandom())), + *reconstructOperators.at(reconstructDistribution(util::getRawRandom()))}; +} diff --git a/src/lns/operators/selector/operator_selector.h b/src/lns/operators/selector/operator_selector.h index e69de29..1dd7213 100644 --- a/src/lns/operators/selector/operator_selector.h +++ b/src/lns/operators/selector/operator_selector.h @@ -0,0 +1,104 @@ +#pragma once + +#include "lns/operators/abstract_operator.h" +#include <algorithm> +#include <memory> +#include <random> +#include <utility> +#include <vector> + +/** + * Represent a pair (destruction and reconstruction) of operators. + */ +class OperatorPair +{ + DestructionOperator &destruct; + ReconstructionOperator &reconstruct; + /** + * Allow the operator pair to force to accept the solution that will be created with the last getOperatorPair(); + * @return true to force the acceptance of the solution after the operators calls. + */ + bool forceAcceptance; + +public: + OperatorPair(DestructionOperator &destruct, ReconstructionOperator &reconstruct, bool forceAcceptance = false); + DestructionOperator &destructor(); + ReconstructionOperator &reconstructor(); + // the solution obtained with this operator pair will be accepted by the lns + void setForceAcceptance(); + bool forceTakeSolution() const; +}; + + +/** + * Abstract class which defines an interface for an operator selector + */ +class OperatorSelector +{ +public: + /** + * Called once per iteration, defines which destruction reconstruction pair is going to be used. + */ + virtual OperatorPair getOperatorPair() = 0; + /** + * Callback if a better solution has been found by the algorithm + */ + virtual void betterSolutionFound() = 0; + virtual ~OperatorSelector() = default; +}; + +/** + * Simple operator selector with weighted random distribution + */ +class SimpleOperatorSelector : public OperatorSelector +{ + std::vector<std::unique_ptr<DestructionOperator>> destructOperators; + std::vector<std::unique_ptr<ReconstructionOperator>> reconstructOperators; + std::discrete_distribution<> destructDistribution; + std::discrete_distribution<> reconstructDistribution; + +public: + SimpleOperatorSelector() = default; + SimpleOperatorSelector(SimpleOperatorSelector &rhs) = delete; + SimpleOperatorSelector &operator=(SimpleOperatorSelector &rhs) = delete; + SimpleOperatorSelector(SimpleOperatorSelector &&rhs) = default; + SimpleOperatorSelector &operator=(SimpleOperatorSelector &&rhs) noexcept = default; + + template<std::derived_from<DestructionOperator> T> + void addDestructor(T destructor, int weight = 1); + + template<std::derived_from<ReconstructionOperator> T> + void addReconstructor(T reconstructor, int weight = 1); + + OperatorPair getOperatorPair() override; + + void betterSolutionFound() override {} +}; + + + +template<std::derived_from<DestructionOperator> T> +void SimpleOperatorSelector::addDestructor(T destructor, int weight) +{ + auto newDistribution = std::vector<double>(destructDistribution.probabilities()); + int deconstructCount = destructOperators.size(); + newDistribution.resize(deconstructCount); + std::ranges::transform( + newDistribution, newDistribution.begin(), [&](double elmt) { return elmt * deconstructCount; }); + newDistribution.push_back(weight); + destructDistribution = std::discrete_distribution<>(newDistribution.begin(), newDistribution.end()); + destructOperators.push_back(std::make_unique<T>(std::move(destructor))); +} + +template<std::derived_from<ReconstructionOperator> T> +void SimpleOperatorSelector::addReconstructor(T reconstructor, int weight) +{ + auto newDistribution = std::vector<double>(reconstructDistribution.probabilities()); + int reconstructCount = reconstructOperators.size(); + newDistribution.resize(reconstructCount); + std::ranges::transform( + newDistribution, newDistribution.begin(), [&](double elmt) { return elmt * reconstructCount; }); + newDistribution.push_back(weight); + reconstructDistribution = std::discrete_distribution<>(newDistribution.begin(), newDistribution.end()); + reconstructOperators.push_back(std::make_unique<T>(std::move(reconstructor))); +} \ No newline at end of file diff --git a/src/lns/operators/selector/small_large_selector.cpp b/src/lns/operators/selector/small_large_selector.cpp new file mode 100644 index 0000000..eaebf5d --- /dev/null +++ b/src/lns/operators/selector/small_large_selector.cpp @@ -0,0 +1,38 @@ +#include "small_large_selector.h" + +#include <algorithm> +#include <spdlog/spdlog.h> + +SmallLargeOperatorSelector::SmallLargeOperatorSelector(std::vector<StepSelector> selectorsList) + : iterationAtCurrentStep(0), selectorStep(0), selectorPerSize(std::move(selectorsList)) +{ + iterationForNextStep = selectorPerSize.at(0).first; +} + +OperatorPair SmallLargeOperatorSelector::getOperatorPair() +{ + if (iterationAtCurrentStep > iterationForNextStep) [[unlikely]] + { + ++selectorStep; + if (selectorStep == selectorPerSize.size()) + { + betterSolutionFound(); + } + 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]] + { + pair.setForceAcceptance(); + } + ++iterationAtCurrentStep; + return pair; +} + +void SmallLargeOperatorSelector::betterSolutionFound() +{ + iterationAtCurrentStep = 0; + selectorStep = 0; +} diff --git a/src/lns/operators/selector/small_large_selector.h b/src/lns/operators/selector/small_large_selector.h new file mode 100644 index 0000000..247326b --- /dev/null +++ b/src/lns/operators/selector/small_large_selector.h @@ -0,0 +1,33 @@ +#pragma once + +#include "lns/operators/selector/operator_selector.h" + +/** + * + */ +class SmallLargeOperatorSelector : public OperatorSelector +{ +public: + using StepSelector = std::pair<unsigned int, SimpleOperatorSelector>; + +private: + // the number of call to getOperatorPair (ie. lns iteration) done with the current step + unsigned int iterationAtCurrentStep; + // the index of the selector used, called step + unsigned int selectorStep; + // number of iterations needed to use the next selector + unsigned int iterationForNextStep; + // vector of all the selector and the number of iterations for each + std::vector<StepSelector> selectorPerSize; + +public: + /** + * @param selectorPerSize each pair is the maximum of iterations for a given selector. + * ie. {{300,A},{700,B}} means that the A will be used for 300 iterations, + * then B is used for 700. Then cycle on A again. + */ + explicit SmallLargeOperatorSelector(std::vector<StepSelector> selectorPerSize); + OperatorPair getOperatorPair() override; + void betterSolutionFound() override; +}; + diff --git a/src/mains/main.cpp b/src/mains/main.cpp index 3d63ca6..41d5485 100644 --- a/src/mains/main.cpp +++ b/src/mains/main.cpp @@ -55,49 +55,40 @@ int main(int argc, char const *argv[]) 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"; - - PDPTWData data = parsing::parseJson(filepath); - data.checkData(); - - data.print(); - std::cout << " \n"; - /* - * test - */ - Solution solution = Solution::emptySolution(data); - - std::cout << "--- Empty Solution --- \n"; - solution.print(); - double blinkRate = 0; - SortingStrategyType strategy = SortingStrategyType::SHUFFLE; - EnumerationType enumeration = EnumerationType::ALL_INSERT_PAIR; - std::cout << "\n --- Operator - SHUFFLE - ALL_INSERTPAIR -> reconstruction (NO COST UPDATE)\n"; + ///////////////////////////////////////////////////////////////////////:: - //ListHeuristicInsertion heuristicInsertion; - //heuristicInsertion.reconstructSolution(solution, blinkRate, strategy, enumeration); + // std::cout << filepath << "\n"; - ListHeuristicCostOriented heuristic; - heuristic.reconstructSolution(solution, blinkRate, strategy, enumeration); + // PDPTWData data = parsing::parseJson(filepath); + // data.checkData(); - solution.print(); + // data.print(); - solution.print(); + // std::cout << " \n"; + // /* + // * test + // */ + // Solution solution = Solution::emptySolution(data); + + // std::cout << "--- Empty Solution --- \n"; + // solution.print(); + + // double blinkRate = 0; + // SortingStrategyType strategy = SortingStrategyType::SHUFFLE; + // EnumerationType enumeration = EnumerationType::ALL_INSERT_PAIR; + // std::cout << "\n --- Operator - SHUFFLE - ALL_INSERTPAIR -> reconstruction (NO COST UPDATE)\n"; - std::cout << " --- supr !!! --- \n "; + // ListHeuristicCostOriented heuristic; + // heuristic.reconstructSolution(solution, blinkRate, strategy, enumeration); - RandomDestroy randomdestroy = RandomDestroy(5); - randomdestroy.destroySolution(solution); + // RandomDestroy randomdestroy = RandomDestroy(4); + // randomdestroy.destroySolution(solution); - //Index index = std::make_tuple(0,7,9); - //RemovePair remPair = RemovePair(index, solution.getData().getPair(2)); - //solution.applyDestructSolution(remPair); - //solution.print(); - //output::exportToJson(solution); + //output::exportToJson(solution); return 0; } diff --git a/src/mains/main_interface.cpp b/src/mains/main_interface.cpp index 58ad8a7..aeb283a 100644 --- a/src/mains/main_interface.cpp +++ b/src/mains/main_interface.cpp @@ -36,6 +36,6 @@ int mainInterface(int argc, char **argv, std::function<void(PDPTWData &, Solutio return 1; } - spdlog::info("Fin"); + spdlog::info("End"); return 0; } -- GitLab