Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • a24jacqb/pdptw-main
1 result
Show changes
Commits on Source (5)
Showing
with 345 additions and 95 deletions
...@@ -23,6 +23,7 @@ add_executable(pdptw src/mains/main.cpp ...@@ -23,6 +23,7 @@ add_executable(pdptw src/mains/main.cpp
src/input/pdptw_data.cpp src/input/pdptw_data.cpp
src/input/time_window.cpp src/input/time_window.cpp
src/input/json_parser.cpp src/input/json_parser.cpp
src/lns/acceptance/threshold_acceptance.cpp
src/lns/solution/route.cpp src/lns/solution/route.cpp
src/lns/solution/solution.cpp src/lns/solution/solution.cpp
src/lns/constraints/constraint.cpp src/lns/constraints/constraint.cpp
...@@ -33,6 +34,7 @@ add_executable(pdptw src/mains/main.cpp ...@@ -33,6 +34,7 @@ add_executable(pdptw src/mains/main.cpp
src/lns/modification/route/insert_route_with_pair.cpp src/lns/modification/route/insert_route_with_pair.cpp
src/lns/modification/route/insert_route.cpp src/lns/modification/route/insert_route.cpp
src/lns/modification/route/remove_route.cpp src/lns/modification/route/remove_route.cpp
src/output/lns_output.cpp
src/output/solution_checker.cpp src/output/solution_checker.cpp
src/output/solution_exporter.cpp src/output/solution_exporter.cpp
src/lns/operators/sorting_strategy.cpp src/lns/operators/sorting_strategy.cpp
...@@ -40,7 +42,9 @@ add_executable(pdptw src/mains/main.cpp ...@@ -40,7 +42,9 @@ add_executable(pdptw src/mains/main.cpp
src/lns/operators/reconstruction/enumerate.cpp src/lns/operators/reconstruction/enumerate.cpp
src/lns/operators/reconstruction/list_heuristic_insertion.cpp src/lns/operators/reconstruction/list_heuristic_insertion.cpp
src/lns/operators/reconstruction/list_heuristic_cost_oriented.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/lns/lns.cpp
src/utils.cpp src/utils.cpp
) )
......
...@@ -78,6 +78,12 @@ const Pair &PDPTWData::getPair(int id) const ...@@ -78,6 +78,12 @@ const Pair &PDPTWData::getPair(int id) const
throw std::runtime_error("Pair not found"); throw std::runtime_error("Pair not found");
} }
int PDPTWData::getPairCount() const
{
return getPairs().size();
}
void PDPTWData::print() const void PDPTWData::print() const
{ {
std::cout << "Instance name : " << dataName << "\n"; std::cout << "Instance name : " << dataName << "\n";
......
#pragma once #pragma once
#include <nlohmann/json_fwd.hpp>
#include <vector>
#include "pair.h"
#include "location.h" #include "location.h"
#include "pair.h"
#include "types.h" #include "types.h"
#include <nlohmann/json_fwd.hpp>
#include <vector>
using json = nlohmann::json; using json = nlohmann::json;
/** /**
...@@ -28,7 +28,7 @@ class PDPTWData ...@@ -28,7 +28,7 @@ class PDPTWData
int capacity; int capacity;
Location depot; Location depot;
std::vector<Location> locations; std::vector<Location> locations;
std::vector<Pair> pairs; // std::unordered_map<int, Pair> pair; if getPair(index) is needed ? std::vector<Pair> pairs;// std::unordered_map<int, Pair> pair; if getPair(index) is needed ?
Matrix distanceMatrix; Matrix distanceMatrix;
public: public:
...@@ -43,7 +43,8 @@ public: ...@@ -43,7 +43,8 @@ public:
* Constructs an empty PDPTWData. * Constructs an empty PDPTWData.
* @see parsing::parseJson * @see parsing::parseJson
*/ */
PDPTWData(std::string dataName, int size, int capacity, Location depot, std::vector<Location> locations, Matrix distanceMatrix); PDPTWData(std::string dataName, int size, int capacity, Location depot, std::vector<Location> locations,
Matrix distanceMatrix);
/** /**
* Checks some data coherence * Checks some data coherence
*/ */
...@@ -54,8 +55,8 @@ public: ...@@ -54,8 +55,8 @@ public:
std::vector<Location> const &getLocations() const; std::vector<Location> const &getLocations() const;
std::vector<Pair> const &getPairs() const; std::vector<Pair> const &getPairs() const;
int getPairCount() const;
const Pair &getPair(int id) const; Pair const &getPair(int id) const;
/** /**
* 0 return the depot. * 0 return the depot.
......
#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
...@@ -102,12 +102,12 @@ void CapacityConstraint::applyModif(Pair const &pair, int routeIndex, int Pickup ...@@ -102,12 +102,12 @@ void CapacityConstraint::applyModif(Pair const &pair, int routeIndex, int Pickup
bool CapacityConstraint::check(InsertPair const &op) const 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()); return checkModif(op.getPair(), op.getRouteIndex(), op.getPickupInsertion(), op.getDeliveryInsertion());
} }
void CapacityConstraint::apply(InsertPair const &op) 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); applyModif(op.getPair(), op.getRouteIndex(), op.getPickupInsertion(), op.getDeliveryInsertion(), true);
} }
......
...@@ -64,5 +64,5 @@ public: ...@@ -64,5 +64,5 @@ public:
*/ */
void applyModif(Pair const &pair, int routeIndex, int PickupPosition, int DeliveryPosition, bool addPair); void applyModif(Pair const &pair, int routeIndex, int PickupPosition, int DeliveryPosition, bool addPair);
void print() const; void print() const override;
}; };
\ No newline at end of file
...@@ -99,4 +99,6 @@ public: ...@@ -99,4 +99,6 @@ public:
* Defaults to no op * Defaults to no op
*/ */
virtual void endOfDestructionCallback() {} virtual void endOfDestructionCallback() {}
virtual void print() const = 0;
}; };
\ No newline at end of file
...@@ -8,32 +8,33 @@ ...@@ -8,32 +8,33 @@
#include "lns/modification/route/remove_route.h" #include "lns/modification/route/remove_route.h"
#include "lns/solution/solution.h" #include "lns/solution/solution.h"
TimeWindowConstraint::TimeWindowConstraint(Solution const &solution) : Constraint(solution)
TimeWindowConstraint::TimeWindowConstraint(const Solution& solution) : Constraint(solution)
{ {
allRouteReachTimes.resize(getSolution().getRoutes().size()); allRouteReachTimes.resize(getSolution().getRoutes().size());
} }
TimeWindowConstraint::~TimeWindowConstraint()
TimeWindowConstraint::~TimeWindowConstraint()
{ {
allRouteReachTimes.clear(); allRouteReachTimes.clear();
} }
std::unique_ptr<Constraint> TimeWindowConstraint::clone(Solution const &newOwningSolution) const { std::unique_ptr<Constraint> TimeWindowConstraint::clone(Solution const &newOwningSolution) const
{
std::unique_ptr<TimeWindowConstraint> clonePtr = std::make_unique<TimeWindowConstraint>(newOwningSolution); std::unique_ptr<TimeWindowConstraint> clonePtr = std::make_unique<TimeWindowConstraint>(newOwningSolution);
clonePtr->allRouteReachTimes = allRouteReachTimes; clonePtr->allRouteReachTimes = allRouteReachTimes;
return clonePtr; return clonePtr;
} }
void TimeWindowConstraint::computeReachTimes(const PDPTWData& data, const std::vector<int> & routeIDs, ReachTimeVector & reachTimes) const void TimeWindowConstraint::computeReachTimes(PDPTWData const &data, std::vector<int> const &routeIDs,
ReachTimeVector &reachTimes) const
{ {
// Adjust the size of reachTimes vector // Adjust the size of reachTimes vector
reachTimes.resize(routeIDs.size(), 0); reachTimes.resize(routeIDs.size(), 0);
// Time to the first location // Time to the first location
reachTimes.at(0) = data.getDepot().getTimeWindow().getStart() + data::TravelTime(data, 0, routeIDs.at(0)); reachTimes.at(0) = data.getDepot().getTimeWindow().getStart() + data::TravelTime(data, 0, routeIDs.at(0));
// Compute other reachTimes (max between arrival and start of the time window + previous service time + travel time) // Compute other reachTimes (max between arrival and start of the time window + previous service time + travel time)
for (int i = 1; i < routeIDs.size(); ++i) { for (int i = 1; i < routeIDs.size(); ++i)
{
TimeInteger travelTime = data::TravelTime(data, routeIDs.at(i - 1), routeIDs.at(i)); TimeInteger travelTime = data::TravelTime(data, routeIDs.at(i - 1), routeIDs.at(i));
// locations are indexed from 0 to n-1, // locations are indexed from 0 to n-1,
TimeInteger serviceTime = data.getLocation(routeIDs.at(i - 1)).getServiceDuration(); TimeInteger serviceTime = data.getLocation(routeIDs.at(i - 1)).getServiceDuration();
...@@ -47,7 +48,7 @@ void TimeWindowConstraint::initReachTimes() ...@@ -47,7 +48,7 @@ void TimeWindowConstraint::initReachTimes()
{ {
allRouteReachTimes = std::vector<ReachTimeVector>(); allRouteReachTimes = std::vector<ReachTimeVector>();
int i = 0; int i = 0;
for (const Route& route : getSolution().getRoutes()) for (Route const &route: getSolution().getRoutes())
{ {
// init and calculate reach time value // init and calculate reach time value
allRouteReachTimes.emplace_back(); allRouteReachTimes.emplace_back();
...@@ -56,25 +57,24 @@ void TimeWindowConstraint::initReachTimes() ...@@ -56,25 +57,24 @@ void TimeWindowConstraint::initReachTimes()
} }
} }
// Copie le vecteur de reach time de la route concernée // Copie le vecteur de reach time de la route concernée
// Insère les positions pickup/delivery // Insère les positions pickup/delivery
// refait l'ordo sur le nouveau vecteur // refait l'ordo sur le nouveau vecteur
bool TimeWindowConstraint::checkInsertion(const PDPTWData& data, const Pair & pair, int routeIndex, int pickupPos, int deliveryPos) const bool TimeWindowConstraint::checkInsertion(PDPTWData const &data, Pair const &pair, int routeIndex, int pickupPos,
int deliveryPos) const
{ {
ReachTimeVector const &reachTimes = allRouteReachTimes.at(routeIndex); ReachTimeVector const &reachTimes = allRouteReachTimes.at(routeIndex);
// COPY route vector // COPY route vector
std::vector<int> route(getSolution().getRoute(routeIndex).getRoute().begin(), getSolution().getRoute(routeIndex).getRoute().end()) ; std::vector<int> route(getSolution().getRoute(routeIndex).getRoute().begin(),
getSolution().getRoute(routeIndex).getRoute().end());
// COPY reachTimes vector // COPY reachTimes vector
ReachTimeVector newReachTimes(reachTimes.begin(), reachTimes.end()); ReachTimeVector newReachTimes(reachTimes.begin(), reachTimes.end());
// Insert pickup and delivery // Insert pickup and delivery
route.insert(route.begin() + deliveryPos, pair.getDelivery().getId()); route.insert(route.begin() + deliveryPos, pair.getDelivery().getId());
route.insert(route.begin() + pickupPos, pair.getPickup().getId()); route.insert(route.begin() + pickupPos, pair.getPickup().getId());
// std::cout << "\n"; // std::cout << "\n";
// for (auto pos : route) // for (auto pos : route)
...@@ -94,89 +94,147 @@ bool TimeWindowConstraint::checkInsertion(const PDPTWData& data, const Pair & pa ...@@ -94,89 +94,147 @@ bool TimeWindowConstraint::checkInsertion(const PDPTWData& data, const Pair & pa
// std::cout << "\n"; // std::cout << "\n";
// Check Time Windows // Check Time Windows
for (int i = 0; i < newReachTimes.size(); ++i) for (int i = 0; i < newReachTimes.size(); ++i)
{ {
if (! data.getLocation(route.at(i)).getTimeWindow().isValid(newReachTimes.at(i)) ) if (!data.getLocation(route.at(i)).getTimeWindow().isValid(newReachTimes.at(i)))
{ {
return false; return false;
} }
} }
return true; return true;
} }
// A lot of check here because i had problems with this function
void TimeWindowConstraint::ApplyModif(PDPTWData const &data, Pair const &pair, int routeIndex, int pickupPos,
int deliveryPos, bool addPair)
{
// Check the routeIndex validity
if (routeIndex < 0 || routeIndex >= getSolution().getRoutes().size())
{
spdlog::error("Error: routeIndex out of bounds ({})", routeIndex);
return;
}
// Copy of the route vector (problem that cause a duplication of the TW)
std::vector<int> routeIDs = getSolution().getRoute(routeIndex).getRoute();
void TimeWindowConstraint::ApplyModif(const PDPTWData& data, const Pair & pair, int routeIndex, int pickupPos, int deliveryPos, bool addPair) // // Check Position validity
{ // if (pickupPos < 0 || pickupPos > routeIDs.size() ||
// COPY route vector // deliveryPos < 0 || deliveryPos > routeIDs.size()) {
std::vector<int> routeIDs(getSolution().getRoute(routeIndex).getRoute().begin(), getSolution().getRoute(routeIndex).getRoute().end()); // spdlog::error("Error: Indices pickupPos ({}) or deliveryPos ({}) are invalid for a route size of {}.",
// pickupPos, deliveryPos, routeIDs.size());
// Adjust pickup and delivery // return;
if (addPair) // }
// if (addPair) {
// routeIDs.insert(routeIDs.begin() + deliveryPos, pair.getDelivery().getId());
// routeIDs.insert(routeIDs.begin() + pickupPos, pair.getPickup().getId());
// }
// else {
// if (deliveryPos < routeIDs.size() && pickupPos < routeIDs.size() && pickupPos != deliveryPos) {
// if (deliveryPos > pickupPos) {
// routeIDs.erase(routeIDs.begin() + deliveryPos);
// routeIDs.erase(routeIDs.begin() + pickupPos);
// } else {
// routeIDs.erase(routeIDs.begin() + pickupPos);
// routeIDs.erase(routeIDs.begin() + deliveryPos);
// }
// } else {
// spdlog::error("Error: Invalid indices for removal (pickupPos: {}, deliveryPos: {}).", pickupPos, deliveryPos);
// return;
// }
// }
// the route is empty !
if (routeIDs.empty())
{ {
routeIDs.insert(routeIDs.begin() + deliveryPos, pair.getDelivery().getId()); allRouteReachTimes.at(routeIndex).clear();
routeIDs.insert(routeIDs.begin() + pickupPos, pair.getPickup().getId());
} }
else else
{ {
routeIDs.erase(routeIDs.begin() + deliveryPos); allRouteReachTimes.at(routeIndex).resize(routeIDs.size(), 0);
routeIDs.erase(routeIDs.begin() + pickupPos);
}
// Adjust the size of reachTimes vector allRouteReachTimes.at(routeIndex).at(0) =
allRouteReachTimes.at(routeIndex).resize(routeIDs.size(), 0); data.getDepot().getTimeWindow().getStart() + data::TravelTime(data, 0, routeIDs.at(0));
// Time to the first location
allRouteReachTimes.at(routeIndex).at(0) = data.getDepot().getTimeWindow().getStart() + data::TravelTime(data, 0, routeIDs.at(0)); // Compute reach times
// Compute other reachTimes (max between arrival and start of the time window) for (size_t i = 1; i < routeIDs.size(); ++i)
for (int i = 1; i < routeIDs.size(); ++i) { {
TimeInteger travelTime = data::TravelTime(data, routeIDs.at(i - 1), routeIDs.at(i)); if (i - 1 >= routeIDs.size() || i >= routeIDs.size())
TimeInteger serviceTime = data.getLocation(routeIDs.at(i - 1)).getServiceDuration(); {
TimeInteger startTW = data.getLocation(routeIDs.at(i - 1)).getTimeWindow().getStart(); spdlog::error("Error: Out-of-bounds access to routeIDs in the computation loop.");
allRouteReachTimes.at(routeIndex).at(i) = std::max(allRouteReachTimes.at(routeIndex).at(i - 1), startTW) + serviceTime + travelTime; return;
}
TimeInteger travelTime = data::TravelTime(data, routeIDs.at(i - 1), routeIDs.at(i));
TimeInteger serviceTime = data.getLocation(routeIDs.at(i - 1)).getServiceDuration();
TimeInteger startTW = data.getLocation(routeIDs.at(i - 1)).getTimeWindow().getStart();
allRouteReachTimes.at(routeIndex).at(i) =
std::max(allRouteReachTimes.at(routeIndex).at(i - 1), startTW) + serviceTime + travelTime;
}
} }
} }
bool TimeWindowConstraint::check(InsertPair const &op) const bool TimeWindowConstraint::check(InsertPair const &op) const
{ {
std::cout << " #TW Check"; //std::cout << " #TW Check";
return checkInsertion(getSolution().getData(), op.getPair(), op.getRouteIndex(), op.getPickupInsertion(), op.getDeliveryInsertion()); return checkInsertion(getSolution().getData(),
op.getPair(),
op.getRouteIndex(),
op.getPickupInsertion(),
op.getDeliveryInsertion());
} }
void TimeWindowConstraint::apply(InsertPair const &op) 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(), op.getPickupInsertion(), op.getDeliveryInsertion(), true); ApplyModif(getSolution().getData(),
op.getPair(),
op.getRouteIndex(),
op.getPickupInsertion(),
op.getDeliveryInsertion(),
true);
} }
bool TimeWindowConstraint::check(InsertRoute const &op) const bool TimeWindowConstraint::check(InsertRoute const &op) const
{ {
return true; return true;
} }
void TimeWindowConstraint::apply(InsertRoute const &op) void TimeWindowConstraint::apply(InsertRoute const &op)
{ {
allRouteReachTimes.emplace_back(); allRouteReachTimes.emplace_back();
} }
bool TimeWindowConstraint::check(RemovePair const &op) const bool TimeWindowConstraint::check(RemovePair const &op) const
{ {
return true; return true;
} }
void TimeWindowConstraint::apply(RemovePair const &op) void TimeWindowConstraint::apply(RemovePair const &op)
{ {
ApplyModif(getSolution().getData(), op.getPair(), op.getRouteIndex(), op.getPickupDeletion(), op.getDeliveryDeletion(), false); ApplyModif(getSolution().getData(),
op.getPair(),
op.getRouteIndex(),
op.getPickupDeletion(),
op.getDeliveryDeletion(),
false);
} }
bool TimeWindowConstraint::check(RemoveRoute const &op) const bool TimeWindowConstraint::check(RemoveRoute const &op) const
{ {
return true; return true;
} }
void TimeWindowConstraint::apply(RemoveRoute const &op) void TimeWindowConstraint::apply(RemoveRoute const &op)
{ {
allRouteReachTimes.erase(allRouteReachTimes.begin() + op.getRouteIndex()); allRouteReachTimes.erase(allRouteReachTimes.begin() + op.getRouteIndex());
} }
const std::vector<TimeWindowConstraint::ReachTimeVector>& TimeWindowConstraint::getallRouteReachTimes() const { std::vector<TimeWindowConstraint::ReachTimeVector> const &TimeWindowConstraint::getallRouteReachTimes() const
{
return allRouteReachTimes; return allRouteReachTimes;
} }
...@@ -184,17 +242,22 @@ void TimeWindowConstraint::print() const ...@@ -184,17 +242,22 @@ void TimeWindowConstraint::print() const
{ {
std::cout << "Reach Times : \n"; std::cout << "Reach Times : \n";
int i = 0; int i = 0;
for (const auto& reachTimes : getallRouteReachTimes()) for (auto const &reachTimes: getallRouteReachTimes())
{ {
//std::cout << reachTimes.size() << ", "; //std::cout << reachTimes.size() << ", ";
std::cout << "#" << i << " : "; std::cout << "#" << i << " : ";
for (const TimeInteger reachTime : reachTimes) for (const TimeInteger reachTime: reachTimes)
{ {
std::cout << reachTime << ", "; std::cout << reachTime << ", ";
} }
std::cout << "\n";
std::cout << "#" << i << " : ";
for (int locID: getSolution().getRoute(i).getRoute())
{
std::cout << locID << ", ";
}
std::cout << "\n "; std::cout << "\n ";
i++; i++;
} }
std::cout << "\n"; std::cout << "\n";
} }
...@@ -29,7 +29,7 @@ public: ...@@ -29,7 +29,7 @@ public:
const std::vector<ReachTimeVector> & getallRouteReachTimes() const; const std::vector<ReachTimeVector> & getallRouteReachTimes() const;
void print() const; void print() const override;
private: private:
/** /**
......
#include "lns.h"
#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 = 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
destructReconstructPair.destructor().destroySolution(candidateSolution);
destructReconstructPair.reconstructor().reconstructSolution(candidateSolution, 0.01);
// Update best solution
if (isBetterSolution(candidateSolution, bestSolution))
{
std::cout << "\n > new Best Solution \n";
checker::checkAll(candidateSolution, candidateSolution.getData(), false);
bestSolution = candidateSolution;
opSelector.betterSolutionFound();
}
// 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
#pragma once
#include "output/lns_output.h"
class Solution;
class OperatorSelector;
class AcceptanceFunction;
namespace lns
{
/**
* @param initialSolution must be a valid solution !
*/
output::LnsOutput runLns(Solution const &initialSolution, OperatorSelector &opSelector, AcceptanceFunction const &acceptFunctor);
}// namespace lns
\ No newline at end of file
...@@ -105,5 +105,5 @@ Index InsertPair::getIndex() const ...@@ -105,5 +105,5 @@ Index InsertPair::getIndex() const
ModificationApplyVariant InsertPair::asApplyVariant() const ModificationApplyVariant InsertPair::asApplyVariant() const
{ {
return (*this); return *this;
} }
\ No newline at end of file
...@@ -91,5 +91,5 @@ Index RemovePair::getIndex() const ...@@ -91,5 +91,5 @@ Index RemovePair::getIndex() const
ModificationApplyVariant RemovePair::asApplyVariant() const ModificationApplyVariant RemovePair::asApplyVariant() const
{ {
return (*this); return *this;
} }
\ No newline at end of file
...@@ -15,6 +15,6 @@ public: ...@@ -15,6 +15,6 @@ public:
class ReconstructionOperator class ReconstructionOperator
{ {
public: public:
virtual void reconstructSolution(Solution &solution, double blinkRate, SortingStrategyType strategy, EnumerationType enumeration) const = 0; virtual void reconstructSolution(Solution &solution, double blinkRate) const = 0;
virtual ~ReconstructionOperator() = default; virtual ~ReconstructionOperator() = default;
}; };
...@@ -9,53 +9,60 @@ ...@@ -9,53 +9,60 @@
void RandomDestroy::destroySolution(Solution &solution) const void RandomDestroy::destroySolution(Solution &solution) const
{ {
std::cout << "RD ";
int nbRequests = solution.requestsFulFilledCount(); int nbRequests = solution.requestsFulFilledCount();
int actualNumberOfPairsToDestroy = std::min(nbRequests, numberOfPairsToDestroy); int actualNumberOfPairsToDestroy = std::min(nbRequests, numberOfPairsToDestroy);
int remainingPairToDelete = actualNumberOfPairsToDestroy; int remainingPairToDelete = actualNumberOfPairsToDestroy;
while (remainingPairToDelete < 0) while (remainingPairToDelete > 0)
{ {
// too complicated // too complicated
// Other (simpler) option -> choose random route then choose random pair ? // Other (simpler) option -> choose random route then choose random pair ?
// choose a random pair // choose a random location
int pairNumber = util::getRandomInt(0, remainingPairToDelete * 2 - 1); int locationNumber = util::getRandomInt(0, remainingPairToDelete * 2 - 1);
int pairID = 0; int pairID = 0;
int routeID = 0; int routeID = 0;
int count = 0; int position = 0;
Index index = std::make_tuple(0,0,0); Index index = std::make_tuple(0,0,0);
// retrieve index (route and position) // retrieve index (route and position)
for (const Route &route : solution.getRoutes()) for (const Route &route : solution.getRoutes())
{ {
count += route.getSize(); position += route.getSize();
if (pairNumber < count) if (locationNumber < position)
{ {
count = count - pairNumber; // calculate the location position
position = route.getSize() - (position - locationNumber);
std::get<0>(index) = routeID; // get location associated to the position
std::get<1>(index) = count; Location loc = solution.getData().getLocation(route.getRoute().at(position));
std::get<2>(index) = route.getPairLocationPosition(count, solution.getData());
// retrieve pickupID (= PairID) // retrieve pickupID (= PairID)
if (solution.getData().getLocation(route.getRoute().at(count)).getLocType() == LocType::PICKUP ) if (loc.getLocType() == LocType::PICKUP )
{ {
pairID = route.getRoute().at(count); pairID = route.getRoute().at(position);
std::get<1>(index) = position;
std::get<2>(index) = route.getPairLocationPosition(position, solution.getData());
} }
else else
{ {
pairID = route.getRoute().at(std::get<2>(index)); pairID = loc.getPair();
std::get<1>(index) = route.getPairLocationPosition(position, solution.getData());
std::get<2>(index) = position;
} }
std::get<0>(index) = routeID;
break; break;
} }
++routeID; ++routeID;
} }
RemovePair remPair = RemovePair(index, solution.getData().getPair(pairID)); RemovePair remPair = RemovePair(index, solution.getData().getPair(pairID));
// appliquer la modif (via solution method -> update correctement la solution)
solution.applyDestructSolution(remPair); solution.applyDestructSolution(remPair);
// update les compteurs // update les compteurs
......
#include "list_heuristic_cost_oriented.h" #include "list_heuristic_cost_oriented.h"
void ListHeuristicCostOriented::reconstructSolution(Solution &solution, double blinkRate, SortingStrategyType strategy, ListHeuristicCostOriented::ListHeuristicCostOriented(SortingStrategyType strategy, EnumerationType enumeration)
EnumerationType enumeration) const : strategy(strategy), enumeration(enumeration)
{}
void ListHeuristicCostOriented::reconstructSolution(Solution &solution, double blinkRate) const
{ {
std::vector<int> sortedPairs; std::vector<int> sortedPairs;
// selection strategy // selection strategy
switch (strategy) switch (strategy)
{ {
case SortingStrategyType::SHUFFLE: { case SortingStrategyType::SHUFFLE: {
std::cout << " \n(Shuffle)\n";
// copy // copy
std::cout << "S";
sortedPairs = sorting_strategy::Shuffle(solution).sortPairs(); sortedPairs = sorting_strategy::Shuffle(solution).sortPairs();
break; break;
} }
...@@ -19,6 +22,19 @@ void ListHeuristicCostOriented::reconstructSolution(Solution &solution, double b ...@@ -19,6 +22,19 @@ void ListHeuristicCostOriented::reconstructSolution(Solution &solution, double b
break; break;
} }
// just for print (no use)
switch (enumeration)
{
case EnumerationType::ALL_INSERT_PAIR: {
// copy
std::cout << "_AIP ";
}
default:
break;
}
for (int pairID: sortedPairs) for (int pairID: sortedPairs)
{ {
Pair const &pair = solution.getData().getPair(pairID); Pair const &pair = solution.getData().getPair(pairID);
...@@ -30,7 +46,6 @@ void ListHeuristicCostOriented::reconstructSolution(Solution &solution, double b ...@@ -30,7 +46,6 @@ void ListHeuristicCostOriented::reconstructSolution(Solution &solution, double b
switch (enumeration) switch (enumeration)
{ {
case EnumerationType::ALL_INSERT_PAIR: { case EnumerationType::ALL_INSERT_PAIR: {
std::cout << " \n(All insert pair) \n";
enumeration::enumerateAllInsertPair( enumeration::enumerateAllInsertPair(
solution, solution,
pair, pair,
...@@ -46,7 +61,6 @@ void ListHeuristicCostOriented::reconstructSolution(Solution &solution, double b ...@@ -46,7 +61,6 @@ void ListHeuristicCostOriented::reconstructSolution(Solution &solution, double b
if (bestRecreation) if (bestRecreation)
{ {
std::cout << "\n --- Apply recreation --- \n";
solution.applyRecreateSolution(*bestRecreation); solution.applyRecreateSolution(*bestRecreation);
} }
} }
......
...@@ -11,10 +11,15 @@ ...@@ -11,10 +11,15 @@
*/ */
class ListHeuristicCostOriented : public ReconstructionOperator class ListHeuristicCostOriented : public ReconstructionOperator
{ {
private:
SortingStrategyType strategy;
EnumerationType enumeration;
public: public:
using AtomicRecreationPtr = std::unique_ptr<AtomicRecreation>; using AtomicRecreationPtr = std::unique_ptr<AtomicRecreation>;
void reconstructSolution(Solution &solution, double blinkRate, SortingStrategyType strategy,
EnumerationType enumeration) const override; ListHeuristicCostOriented(SortingStrategyType strategy, EnumerationType enumeration);
void reconstructSolution(Solution &solution, double blinkRate) const override;
}; };
/** /**
...@@ -37,8 +42,6 @@ std::function<void(ModificationType &&)> keepBestSolution(Solution const &soluti ...@@ -37,8 +42,6 @@ std::function<void(ModificationType &&)> keepBestSolution(Solution const &soluti
// then store the best cost and the modification to the pointer // then store the best cost and the modification to the pointer
if (cost < bestCost && util::getRandom() >= blinkRate && solution.checkModification(modification)) if (cost < bestCost && util::getRandom() >= blinkRate && solution.checkModification(modification))
{ {
std::cout << " => Better Modification, update pointer"
<< "\n";
bestModificationPtr = std::make_unique<ModificationType>(modification); bestModificationPtr = std::make_unique<ModificationType>(modification);
bestCost = cost; bestCost = cost;
} }
......
...@@ -7,16 +7,17 @@ ...@@ -7,16 +7,17 @@
#include <concepts> #include <concepts>
ListHeuristicInsertion::ListHeuristicInsertion() = default; ListHeuristicInsertion::ListHeuristicInsertion(SortingStrategyType strategy, EnumerationType enumeration)
: strategy(strategy), enumeration(enumeration)
{}
void ListHeuristicInsertion::reconstructSolution(Solution &solution, double blinkRate, SortingStrategyType strategy, EnumerationType enumeration) const void ListHeuristicInsertion::reconstructSolution(Solution &solution, double blinkRate) const
{ {
std::vector<int> sortedPairs; std::vector<int> sortedPairs;
// selection strategy // selection strategy
switch (strategy) { switch (strategy) {
case SortingStrategyType::SHUFFLE: case SortingStrategyType::SHUFFLE:
{ {
std::cout << " \n(Shuffle)\n";
// copy // copy
sortedPairs = sorting_strategy::Shuffle(solution).sortPairs(); sortedPairs = sorting_strategy::Shuffle(solution).sortPairs();
break; break;
...@@ -52,7 +53,6 @@ std::unique_ptr<AtomicRecreation> ListHeuristicInsertion::selectRecreation(Solut ...@@ -52,7 +53,6 @@ std::unique_ptr<AtomicRecreation> ListHeuristicInsertion::selectRecreation(Solut
switch (enumeration) { switch (enumeration) {
case EnumerationType::ALL_INSERT_PAIR: case EnumerationType::ALL_INSERT_PAIR:
{ {
std::cout << " \n(All insert pair) \n";
enumeration::enumerateAllInsertPair(solution, pair, addToListIfValidTemplate<InsertPair>(solution, modifications)); enumeration::enumerateAllInsertPair(solution, pair, addToListIfValidTemplate<InsertPair>(solution, modifications));
break; break;
......