Skip to content
Snippets Groups Projects
Commit caf73959 authored by awenjb's avatar awenjb
Browse files

Add acceptance function

parent 8c773c25
No related branches found
No related tags found
No related merge requests found
......@@ -23,6 +23,7 @@ add_executable(pdptw src/mains/main.cpp
src/input/pdptw_data.cpp
src/input/time_window.cpp
src/input/json_parser.cpp
src/lns/acceptance/threshold_acceptance.cpp
src/lns/solution/route.cpp
src/lns/solution/solution.cpp
src/lns/constraints/constraint.cpp
......
#pragma once
class Solution;
/**
* see AcceptanceFunction::operator()
*/
enum class AcceptationStatus
{
ACCEPT,
REFUSE
};
/**
* Function object that accept or not a solution as the new solution for the next LNS iteration.
*/
class AcceptanceFunction
{
public:
virtual ~AcceptanceFunction() = default;
/**
* Indicate which solution must be used for the next iteration.
* @param candidateSolution the solution that can be accepted
* @param actualSolution the solution used to create the candidate solution
* @param bestSolution the best known solution known to this point.
* @return ACCEPT to use \p candidateSolution for next iteration, REFUSE to continue to use \p actualSolution.
*/
virtual AcceptationStatus operator()(Solution const &candidateSolution, Solution const &actualSolution,
Solution const &bestSolution) const = 0;
};
\ No newline at end of file
#include "threshold_acceptance.h"
#include "lns/solution/solution.h"
AcceptationStatus ThresholdAcceptance::operator()(Solution const &candidateSolution, Solution const &actualSolution,
Solution const &bestSolution) const
{
// the threshold does not take into account the penalisation cost.
if (candidateSolution.getCost() < bestSolution.getRawCost() * thresholdValue + bestSolution.computePenalisation())
{
// accept because of threshold on best solution
return AcceptationStatus::ACCEPT;
}
if (candidateSolution.getCost() < actualSolution.getCost())
{
// accept because better than the actual solution
return AcceptationStatus::ACCEPT;
}
return AcceptationStatus::REFUSE;
}
ThresholdAcceptance::ThresholdAcceptance(double threshold) : thresholdValue(1 + threshold) {}
\ No newline at end of file
#pragma once
#include "acceptance_function.h"
/**
* Simple implementation of AcceptanceFunction.
* If the candidate is not better than the best solution, we accept it if the relative difference is under a threshold.
* ACCEPT If better than the actual solution.
*/
class ThresholdAcceptance : public AcceptanceFunction
{
double thresholdValue = 1.05;
public:
/**
* @param threshold 0.05 means that a solution with a ratio with a solution worse by less than 5% will be accepted
*/
explicit ThresholdAcceptance(double threshold = 0.05);
AcceptationStatus operator()(Solution const &candidateSolution, Solution const &actualSolution,
Solution const &bestSolution) const override;
};
\ No newline at end of file
#include "lns.h"
output::LnsOutput runLns(Solution const &initialSolution, OperatorSelector &opSelector, AcceptanceFunction const &acceptFunctor)
#include "lns/acceptance/acceptance_function.h"
#include "lns/operators/selector/operator_selector.h"
#include "output/solution_checker.h"
namespace
{
bool isBetterSolution(Solution const &candidateSolution, Solution const &bestKnownSol)
{
return candidateSolution.getCost() < bestKnownSol.getCost();
}
}// namespace
output::LnsOutput lns::runLns(Solution const &initialSolution, OperatorSelector &opSelector,
AcceptanceFunction const &acceptFunctor)
{
/**
* The solution is the base solution used to create the neighbor solution.
* It is constant unless we accept the candidate solution.
*/
Solution actualSolution = initialSolution;
Solution bestSolution = initialSolution;
int it = 10;
while (it > 0)
{
/**
* 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
destructReconstructPair.destructor().destroySolution(candidateSolution);
destructReconstructPair.reconstructor().reconstructSolution(candidateSolution, 0.01);
// TO DO
// Update best solution
if (isBetterSolution(candidateSolution, bestSolution))
{
checker::checkAll(candidateSolution, candidateSolution.getData(), false);
bestSolution = candidateSolution;
opSelector.betterSolutionFound();
}
//auto result = output::LnsOutput(std::move(runtime.bestSolution), runtime.numberOfIteration, getTimeSinceInSec(runtime.start));
//return result;
// Check if we use the candidate solution as the new actual solution
// operator can force to take the new solution
if (destructReconstructPair.forceTakeSolution() ||
acceptFunctor(candidateSolution, actualSolution, bestSolution) == AcceptationStatus::ACCEPT)
{
actualSolution = std::move(candidateSolution);
}
--it;
}
auto result = output::LnsOutput(std::move(bestSolution), it, it);
return result;
}
\ No newline at end of file
......@@ -8,6 +8,7 @@
#include "lns/solution/route.h"
#include "output/solution_checker.h"
#include <bits/ranges_algo.h>
#include <bits/ranges_util.h>
#include <utility>
......@@ -35,10 +36,10 @@ void Solution::initConstraints()
void Solution::computeAndStoreSolutionCost()
{
routeCost = computeSolutionCost();
rawCost = computeSolutionCost();
// add penalty for solution in the pairBank ?
totalCost = routeCost + computePenalization();
totalCost = rawCost + computePenalisation();
}
double Solution::computeSolutionCost() const
......@@ -51,7 +52,7 @@ double Solution::computeSolutionCost() const
return cost;
}
double Solution::computePenalization() const
double Solution::computePenalisation() const
{
return getBank().size() * EXCLUSION_PENALTY;
}
......@@ -64,9 +65,9 @@ void Solution::init()
computeAndStoreSolutionCost();
}
Solution::Solution(PDPTWData const &data, Solution::PairBank pairbank, std::vector<Route> routes, double routeCost,
Solution::Solution(PDPTWData const &data, Solution::PairBank pairbank, std::vector<Route> routes, double rawCost,
double totalCost)
: data(data), pairBank(std::move(pairbank)), routes(std::move(routes)), routeCost(routeCost), totalCost(totalCost)
: data(data), pairBank(std::move(pairbank)), routes(std::move(routes)), rawCost(rawCost), totalCost(totalCost)
{}
Solution::Solution(PDPTWData const &data) : data(data)
......@@ -80,6 +81,64 @@ Solution Solution::emptySolution(PDPTWData const &data)
return s;
}
Solution::~Solution() noexcept = default;
Solution::Solution(Solution const &rhs) : Solution(rhs.getData())
{
*this = rhs;
}
Solution &Solution::operator=(Solution const &rhs)
{
if (&rhs == this)
{
return *this;
}
data = rhs.data;
rawCost = rhs.rawCost;
totalCost = rhs.totalCost;
pairBank = rhs.pairBank;
routes.clear();
routes = rhs.routes;
constraints.clear();
std::ranges::transform(rhs.constraints, std::back_inserter(constraints), [this](auto const &constraintPtr) {
return constraintPtr->clone(*this);
});
return *this;
}
Solution::Solution(Solution &&sol) noexcept : data(sol.data)
{
*this = std::move(sol);
}
Solution &Solution::operator=(Solution &&sol) noexcept
{
if (&sol == this)
{
return *this;
}
data = sol.data;
rawCost = sol.rawCost;
totalCost = sol.totalCost;
pairBank = std::move(sol.pairBank);
routes = std::move(sol.routes);
constraints = std::move(sol.constraints);
for (auto &constraint: constraints)
{
constraint->setSolution(*this);
}
return *this;
}
Solution::PairBank const &Solution::getBank() const
{
return pairBank;
......@@ -127,7 +186,12 @@ Route const &Solution::getRoute(int routeIndex) const
double Solution::getCost() const
{
return totalCost;
return rawCost + computePenalisation();
}
double Solution::getRawCost() const
{
return rawCost;
}
PDPTWData const &Solution::getData() const
......@@ -145,7 +209,7 @@ int Solution::requestsFulFilledCount() const
return count;
}
bool Solution::checkModification(AtomicRecreation const &modification) const
bool Solution::checkModification(AtomicRecreation const &modification) const
{
std::cout << "--- Check Modification Validity : ";
ModificationCheckVariant const &checkVariant = modification.asCheckVariant();
......@@ -159,10 +223,9 @@ bool Solution::checkModification(AtomicRecreation const &modification) const
}
}
std::cout << "\n";
return true;
return true;
}
void Solution::beforeApplyModification(AtomicModification &modification)
{
// pre modification check
......@@ -201,8 +264,8 @@ void Solution::applyDestructSolution(AtomicDestruction &modification)
modification.modifySolution(*this);
// updating request bank
std::vector<int> const &deletedPair = modification.getDeletedPairs();
//pairBank.reserve(pairBank.size() + deletedPair.size());
//pairBank.reserve(pairBank.size() + deletedPair.size());
pairBank.insert(pairBank.end(), deletedPair.begin(), deletedPair.end());
afterApplyModification(modification);
......@@ -211,7 +274,7 @@ void Solution::applyDestructSolution(AtomicDestruction &modification)
void Solution::check() const
{
checker::checkSolutionCoherence(*this, getData());
checker::checkSolutionCoherence(*this, getData());
}
void Solution::print() const
......@@ -232,7 +295,7 @@ void Solution::print() const
}
std::cout << "\nConstraints : \n";
for (const std::unique_ptr<Constraint> &constraint: constraints)
for (std::unique_ptr<Constraint> const &constraint: constraints)
{
constraint->print();
}
......
......@@ -34,16 +34,29 @@ private:
* Vector of routes representing the solution
*/
std::vector<Route> routes;
double routeCost;
double rawCost;
double totalCost;
std::vector<std::unique_ptr<Constraint>> constraints;
public:
//========CONSTRUCTORS, COPY, MOVE, DESTRUCTORS===========
/**
* Expected way to construct a solution.
* Generate an empty solution with all pairs in the pairBank and one empty route.
*/
static Solution emptySolution(PDPTWData const &data);
/**
* In depth copy of the solution
*/
Solution(Solution const &);
/**
* In depth copy of the solution
*/
Solution &operator=(Solution const &);
Solution(Solution &&) noexcept;
Solution &operator=(Solution &&) noexcept;
~Solution() noexcept;
explicit Solution(PDPTWData const &data);
......@@ -61,6 +74,7 @@ public:
std::vector<Route> const &getRoutes() const;
Route const &getRoute(int routeIndex) const;
PDPTWData const &getData() const;
double getRawCost() const;
double getCost() const;
/**
......@@ -104,6 +118,7 @@ public:
*/
void applyDestructSolution(AtomicDestruction &modification);
double computePenalisation() const;
// For route modification
std::vector<Route> &getRoutes();
......@@ -131,6 +146,4 @@ private:
* Compute the cost of the solution (routes cost)
*/
double computeSolutionCost() const;
double computePenalization() const;
};
\ No newline at end of file
#include <nlohmann/json.hpp>
#include <vector>
#include <iostream>
#include <string>
#include <filesystem>
#include <fstream>
#include <spdlog/spdlog.h>
#include "input/data.h"
#include "input/json_parser.h"
#include "input/location.h"
#include "input/pdptw_data.h"
#include "input/time_window.h"
#include "input/json_parser.h"
#include "input/data.h"
#include "lns/acceptance/threshold_acceptance.h"
#include "lns/constraints/capacity/capacity_constraint.h"
#include "lns/constraints/time_window/time_window_constraint.h"
#include "lns/operators/destruction/random_destroy.h"
#include "lns/operators/reconstruction/list_heuristic_cost_oriented.h"
#include "lns/operators/selector/operator_selector.h"
#include "lns/operators/selector/small_large_selector.h"
#include "lns/solution/solution.h"
#include "lns/lns.h"
#include "lns/modification/pair/insert_pair.h"
#include "lns/modification/route/insert_route.h"
#include "lns/modification/pair/remove_pair.h"
#include "lns/modification/route/insert_route.h"
#include "lns/modification/route/remove_route.h"
#include "lns/operators/destruction/random_destroy.h"
#include "lns/operators/reconstruction/enumerate.h"
#include "lns/operators/reconstruction/list_heuristic_cost_oriented.h"
#include "lns/operators/reconstruction/list_heuristic_insertion.h"
#include "lns/operators/selector/operator_selector.h"
#include "lns/operators/selector/small_large_selector.h"
#include "lns/operators/sorting_strategy.h"
#include "lns/operators/reconstruction/enumerate.h"
#include "lns/solution/solution.h"
#include "mains/main_interface.h"
#include "output/solution_exporter.h"
#include <filesystem>
#include <fstream>
#include <iostream>
#include <nlohmann/json.hpp>
#include <spdlog/spdlog.h>
#include <string>
#include <vector>
using json = nlohmann::json;
void simpleLNS(PDPTWData const &data, Solution &startingSolution)
......@@ -43,7 +42,7 @@ void simpleLNS(PDPTWData const &data, Solution &startingSolution)
int manyPairs = requests * 40 / 100;
// threshold function to do
ThresholdAcceptance acceptor(0.05);
// lns operators
SimpleOperatorSelector smallSelector;
......@@ -54,67 +53,45 @@ void simpleLNS(PDPTWData const &data, Solution &startingSolution)
addAllReconstructor(largeSelector);
largeSelector.addDestructor(RandomDestroy(pairs));
SimpleOperatorSelector veryLargeSelector;
addAllReconstructor(veryLargeSelector);
veryLargeSelector.addDestructor(RandomDestroy(pairs));
// SimpleOperatorSelector veryLargeSelector;
// addAllReconstructor(veryLargeSelector);
// veryLargeSelector.addDestructor(RandomDestroy(pairs));
SimpleOperatorSelector hugeSelector;
addAllReconstructor(hugeSelector);
hugeSelector.addDestructor(RandomDestroy(pairs));
// SimpleOperatorSelector hugeSelector;
// addAllReconstructor(hugeSelector);
// hugeSelector.addDestructor(RandomDestroy(pairs));
SimpleOperatorSelector lastSelector;
addAllReconstructor(lastSelector);
lastSelector.addDestructor(RandomDestroy(manyPairs));
// SimpleOperatorSelector lastSelector;
// addAllReconstructor(lastSelector);
// lastSelector.addDestructor(RandomDestroy(manyPairs));
std::vector<SmallLargeOperatorSelector::StepSelector> selectors;
selectors.emplace_back(500, std::move(smallSelector));
selectors.emplace_back(1000, std::move(largeSelector));
selectors.emplace_back(1000, std::move(veryLargeSelector));
selectors.emplace_back(3000, std::move(hugeSelector));
selectors.emplace_back(1, std::move(lastSelector));
selectors.emplace_back(2, std::move(smallSelector));
selectors.emplace_back(2, 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);
lns::runLns(startingSolution, smallLargeSelector, acceptor);
}
int main(int argc, char const *argv[])
int main(int argc, char **argv)
{
//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";
//return mainInterface(argc, argv, &simpleLNS);
///////////////////////////////////////////////////////////////////////::
// std::cout << filepath << "\n";
// 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";
// ListHeuristicCostOriented heuristic;
// heuristic.reconstructSolution(solution, blinkRate, strategy, enumeration);
//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";
// RandomDestroy randomdestroy = RandomDestroy(4);
// randomdestroy.destroySolution(solution);
PDPTWData data = parsing::parseJson(filepath);
Solution startingSolution = Solution::emptySolution(data);
simpleLNS(data, startingSolution);
//output::exportToJson(solution);
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment