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 (2)
  • awenjb's avatar
    Atomic Modifications · 9829a4b0
    awenjb authored
    - add basic modification for a solution
    9829a4b0
  • awenjb's avatar
    add Constraint · 0a8185f2
    awenjb authored
    - Add TimeWIndow constraint
    - add Capacity constraint
     TODO
    - constraint check in O(1)
    - consrtaint tests
    - use constraints in solution
    - full solution checker
    0a8185f2
Showing
with 780 additions and 9 deletions
......@@ -8,7 +8,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
# link time optimisation (LTO) for release and release with debug info builds
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Finding dependencies
find_package(CLI11 REQUIRED)
......@@ -20,17 +20,24 @@ find_package(spdlog REQUIRED)
add_executable(pdptw src/main.cpp
src/input/data.cpp
src/input/location.cpp
src/input/pair.cpp
src/input/pdptw_data.cpp
src/input/time_window.cpp
src/input/json_parser.cpp
src/lns/solution/route.cpp
src/lns/solution/solution.cpp
src/lns/modification/insert_pair.cpp
src/lns/modification/insert_route_with_pair.cpp
src/lns/modification/insert_route.cpp
src/lns/modification/remove_pair.cpp
src/lns/modification/remove_route.cpp
src/lns/constraints/constraint.cpp
src/lns/constraints/capacity/capacity_constraint.cpp
src/lns/constraints/time_window/time_window_constraint.cpp
src/lns/modification/pair/insert_pair.cpp
src/lns/modification/pair/remove_pair.cpp
src/lns/modification/route/insert_route_with_pair.cpp
src/lns/modification/route/insert_route.cpp
src/lns/modification/route/remove_route.cpp
)
target_link_libraries(pdptw PRIVATE CLI11::CLI11 nlohmann_json::nlohmann_json spdlog::spdlog)
\ No newline at end of file
target_link_libraries(pdptw PRIVATE CLI11::CLI11 nlohmann_json::nlohmann_json spdlog::spdlog)
target_include_directories(pdptw PUBLIC ${CMAKE_SOURCE_DIR}/src)
#include "data.h"
double data::addedCostForInsertion(PDPTWData const &data, int before, int toInsert, int after)
{
const Matrix & matrix = data.getMatrix();
double cost = 0;
cost = matrix[before][toInsert] + matrix[toInsert][after] - matrix[before][after];
return cost;
}
double data::removedCostForSuppression(PDPTWData const &data, int before, int toRemove, int after)
{
const Matrix & matrix = data.getMatrix();
double cost = 0;
cost = matrix[before][after] - matrix[before][toRemove] - matrix[toRemove][after];
return cost;
}
double data::routeCost(PDPTWData const & data, Route const & route)
{
const Matrix & matrix = data.getMatrix();
const std::vector<int> & routeIDs = route.getRoute();
double cost = 0;
// cost from and to the depot
cost += matrix[0][routeIDs[0]];
//std::cout << "\n route cost : " << matrix[0][routeIDs[0]] << " ";
cost += matrix[routeIDs.back()][0];
// cost in the route
for (size_t i = 0; i < routeIDs.size() - 1; ++i) {
cost += matrix[routeIDs[i]][routeIDs[i+1]];
//std::cout << matrix[routeIDs[i]][routeIDs[i+1]] << " ";
}
//std::cout << matrix[routeIDs.back()][0] << " : " << cost << "\n";
return cost;
}
double data::TravelCost(PDPTWData const &data, int index1, int index2)
{
return data.getMatrix()[index1][index2];
}
double data::TravelTime(PDPTWData const &data, int from, int to)
{
return data.getMatrix()[from][to];
}
double data::SegmentCost(PDPTWData const &data, Route const &route, int start, int end)
{
// TO DO
return 0;
}
\ No newline at end of file
#pragma once
#include "time_window.h"
#include "pdptw_data.h"
#include "location.h"
#include "../lns/solution/route.h"
/**
* Functions for PDPTWData
*/
namespace data
{
/**
* Compute the cost added by an insertion of one location.
* Index are the id of the location (the same as in the cost matrix)
*/
double addedCostForInsertion(PDPTWData const &data, int before, int toInsert, int after);
/**
* Compute the gain of removing an location.
* Index are the id of the location (the same as in the cost matrix)
*/
double removedCostForSuppression(PDPTWData const &data, int before, int toRemove, int after);
/**
* Compute the cost of a route
*/
double routeCost(PDPTWData const &data, Route const &route);
/**
* Compute the cost of a segment of location in a route
* (does not take into accout that pair of pickup/delivery must be removed together)
*/
double SegmentCost(PDPTWData const &data, Route const &route, int start, int end);
/**
* Return the travel cost between two location
* (take location id in parameters)
*/
double TravelCost(PDPTWData const &data, int index1, int index2);
/**
* Return the travel time between two location
* (take location id in parameters)
*/
double TravelTime(PDPTWData const &data, int from, int to);
}
\ No newline at end of file
#include "pair.h"
Pair::Pair(const Location& pickupLoc, const Location& deliveryLoc)
: pickup(pickupLoc), delivery(deliveryLoc) {}
const Location& Pair::getPickup() const
{
return pickup.get();
}
const Location& Pair::getDelivery() const
{
return delivery.get();
}
\ No newline at end of file
#pragma once
#include "location.h"
// Represent a pair pickup/delivery of location
class Pair
{
private:
std::reference_wrapper<Location const> pickup;
std::reference_wrapper<Location const> delivery;
public:
Pair(const Location& pickupLoc, const Location& deliveryLoc);
const Location& getPickup() const;
const Location& getDelivery() const;
};
\ No newline at end of file
......@@ -12,7 +12,7 @@ unsigned int PDPTWData::getSize()
return size;
}
int PDPTWData::getCapacity()
int PDPTWData::getCapacity() const
{
return capacity;
}
......
......@@ -32,6 +32,7 @@ class PDPTWData
public:
PDPTWData();
PDPTWData(PDPTWData const &rhs) = delete;
PDPTWData(PDPTWData &&rhs) noexcept;
PDPTWData &operator=(PDPTWData &&rhs) noexcept;
......@@ -56,7 +57,7 @@ public:
Matrix const &getMatrix() const;
unsigned int getSize();
int getCapacity();
int getCapacity() const;
void print() const;
};
#include "capacity_constraint.h"
CapacityConstraint::CapacityConstraint(Solution const &solution) : Constraint(solution)
{
// Init an empty vector of reach time for all routes
//std::vector<CapacityVector> routeCapacities(getSolution().getRoutes().size(), CapacityVector());
routeCapacities.resize(getSolution().getRoutes().size());
}
std::unique_ptr<Constraint> CapacityConstraint::clone(Solution const &newOwningSolution) const {
std::unique_ptr<CapacityConstraint> clonePtr = std::make_unique<CapacityConstraint>(newOwningSolution);
clonePtr->routeCapacities = routeCapacities;
return clonePtr;
}
void CapacityConstraint::initCapacities()
{
routeCapacities = std::vector<CapacityVector>();
for (const Route& route : getSolution().getRoutes())
{
CapacityVector capacities;
int currentCapacity = 0;
for (int locationID : route.getRoute())
{
currentCapacity += getSolution().getData().getLocation(locationID).getDemand();
capacities.push_back(currentCapacity);
}
routeCapacities.push_back(capacities);
}
}
std::vector<int> const & CapacityConstraint::getRouteCapacities(int routeIndex) const
{
return routeCapacities[routeIndex];
}
// check for every location between the pickupPosition and the deliveryPosition
// not ideal
bool CapacityConstraint::checkModif(Pair const &pair, int routeIndex, int PickupPosition, int DeliveryPosition) const
{
std::cout << "\n";
int max_capacity = getSolution().getData().getCapacity();
// guardrail
if (pair.getPickup().getDemand() > max_capacity)
{
return false;
}
// check if the disponible capacity is enough are not
for (int i = PickupPosition; i <= DeliveryPosition; ++i) {
if ((i!=0) && (getRouteCapacities(routeIndex).at(i-1) + pair.getPickup().getDemand() >= max_capacity))
{
return false;
}
}
return true;
}
// update the route and the weight
// not ideal
void CapacityConstraint::applyModif(Pair const &pair, int routeIndex, int PickupPosition, int DeliveryPosition, bool addPair)
{
std::cout << "ok \n";
if (addPair)
{
// Insert new values
routeCapacities[routeIndex].insert(routeCapacities[routeIndex].begin()+DeliveryPosition, 0);
if (DeliveryPosition != 0)
{
routeCapacities[routeIndex][DeliveryPosition] += routeCapacities[routeIndex][DeliveryPosition-1];
}
routeCapacities[routeIndex].insert(routeCapacities[routeIndex].begin()+PickupPosition, pair.getPickup().getDemand());
if (PickupPosition != 0)
{
routeCapacities[routeIndex][PickupPosition] += routeCapacities[routeIndex][PickupPosition-1];
}
// Update value
for (int i = PickupPosition + 1; i < DeliveryPosition + 1; ++i)
{
routeCapacities[routeIndex][i] += pair.getPickup().getDemand();
}
}
else
{
for (int i = PickupPosition + 1; i < DeliveryPosition; ++i)
{
routeCapacities[routeIndex][i] += pair.getDelivery().getDemand();
}
// remove pair
routeCapacities[routeIndex].erase(routeCapacities[routeIndex].begin() + DeliveryPosition);
routeCapacities[routeIndex].erase(routeCapacities[routeIndex].begin() + PickupPosition);
}
}
bool CapacityConstraint::check(InsertPair const &op) const
{
return checkModif(op.getPair(), op.getRouteIndex(), op.getPickupInsertion(), op.getDeliveryInsertion());
}
void CapacityConstraint::apply(InsertPair const &op)
{
applyModif(op.getPair(), op.getRouteIndex(), op.getPickupInsertion(), op.getDeliveryInsertion(), true);
}
bool CapacityConstraint::check(InsertRoute const &op) const
{
return true;
}
void CapacityConstraint::apply(InsertRoute const &op)
{
// add new empty route
routeCapacities.emplace_back();
}
bool CapacityConstraint::check(RemovePair const &op) const
{
// Remove a pair (always true)
return true;
}
void CapacityConstraint::apply(RemovePair const &op)
{
applyModif(op.getPair(), op.getRouteIndex(), op.getPickupDeletion(), op.getDeliveryDeletion(), false);
}
bool CapacityConstraint::check(RemoveRoute const &op) const
{
return true;
}
void CapacityConstraint::apply(RemoveRoute const &op)
{
// add new empty route
routeCapacities.erase(routeCapacities.begin() + op.getRouteIndex());
}
void CapacityConstraint::print() const
{
std::cout << "Used capacity : \n";
int i = 0;
for (const auto& capaVector : routeCapacities)
{
std::cout << "#" << i << " : ";
for (const int capa : capaVector)
{
std::cout << capa << ", ";
}
std::cout << "\n ";
i++;
}
std::cout << "\n";
}
#pragma once
#include "./../constraint.h"
#include "./../../../input/pair.h"
/**
* Capacity constraint.
* To check this, we keep track of the sum of all requests and check it against the max capacity.
* TO DO, verification in O(1) by storing a matrix !
*/
class CapacityConstraint : public Constraint
{
public:
using CapacityVector = std::vector<int>;
private:
std::vector<CapacityVector> routeCapacities;
void apply(InsertPair const &op) override;
void apply(InsertRoute const &op) override;
void apply(RemovePair const &op) override;
void apply(RemoveRoute const &op) override;
bool check(InsertPair const &op) const override;
bool check(InsertRoute const &op) const override;
bool check(RemovePair const &op) const override;
bool check(RemoveRoute const &op) const override;
public:
explicit CapacityConstraint(Solution const &);
CapacityConstraint(CapacityConstraint const &) = default;
std::unique_ptr<Constraint> clone(Solution const &newOwningSolution) const override;
/*
* Given the solution, calculate the capacities when leaving each location
* Modify the routeCapacities vector !
*/
void initCapacities();
/*
* Return capacity vector of a route
*/
CapacityVector const &getRouteCapacities(int routeIndex) const;
/*
* Check if a modification is valid or not
* (for now, check only the position of the pickup)
* TO DO (1 or 2)
* 1) check if every index on the path can take the new capacity
* 2) store a matrix / Segment Tree ?? to evaluate the maximum load between two part of the route
* -> a matrix but check in O(1) (update in O(n))
*/
bool checkModif(Pair const &pair, int routeIndex, int position, int DeliveryPosition) const;
/*
* Update the weight
*/
void applyModif(Pair const &pair, int routeIndex, int PickupPosition, int DeliveryPosition, bool addPair);
void print() const;
};
\ No newline at end of file
#include "constraint.h"
Constraint::Constraint(Solution const &solution) : solution(solution) {}
Solution const &Constraint::getSolution() const
{
return solution.get();
}
PDPTWData const &Constraint::data() const
{
return getSolution().getData();
}
void Constraint::setSolution(Solution const &newSolutionOwner)
{
solution = newSolutionOwner;
}
void ModificationVisitor::applyVariant(ModificationApplyVariant const &applyModificationVariant)
{
// lambda auto&& + std::visit combo
// allows to split the variant to each strongly typed function for each modification (see the protected pure virtual functions apply)
// If compilation breaks here, it is likely that a type T in the ModificationApplyVariant has no function ModificationVisitor::apply(T const &) associated
std::visit([this](auto &&op) { this->apply(op); }, applyModificationVariant);
}
bool ConstraintVisitor::checkVariant(ModificationCheckVariant const &checkModificationVariant)
{
// lambda auto&& + std::visit combo
// allows to split the variant to each strongly typed function for each modification (see the protected pure virtual functions apply)
// If compilation breaks here, it is likely that a type T in the ModificationCheckVariant has no function ConstraintVisitor::apply(T const &) associated
return std::visit([this](auto &&op) { return this->check(op); }, checkModificationVariant);
}
#pragma once
#include <variant>
#include "./../solution/solution.h"
// all modifications
#include "./../modification/pair/insert_pair.h"
#include "./../modification/pair/remove_pair.h"
#include "./../modification/route/insert_route.h"
#include "./../modification/route/remove_route.h"
using ModificationApplyVariant =
std::variant<std::reference_wrapper<InsertPair const>, std::reference_wrapper<InsertRoute const>,
std::reference_wrapper<RemovePair const>, std::reference_wrapper<RemoveRoute const>>;
// defines the variant that can store all the modifications that can be checked (recreation modifications)
using ModificationCheckVariant =
std::variant<std::reference_wrapper<InsertPair const>, std::reference_wrapper<InsertRoute const>,
std::reference_wrapper<RemovePair const>, std::reference_wrapper<RemoveRoute const>>;
/**
* Visitor pattern for the modifications.
* It splits the variant into separate apply functions for each Modification.
*/
class ModificationVisitor
{
protected:
// A child class must handle all the modification types ie. implement all these functions
virtual void apply(InsertPair const &op) = 0;
virtual void apply(InsertRoute const &op) = 0;
virtual void apply(RemovePair const &op) = 0;
virtual void apply(RemoveRoute const &op) = 0;
public:
/**
* A modification has been applied to the solution,
* the constraint can use information from the modification to update its state.
*/
void applyVariant(ModificationApplyVariant const &applyModificationVariant);
};
/**
* Visitor pattern for the constraint. Adds the check part that constraints must implement
* It splits the variant into separate check/apply functions for each Modification.
*/
class ConstraintVisitor : public ModificationVisitor
{
protected:
// A child class must handle all the modification types ie. implement all these functions
virtual bool check(InsertPair const &op) const = 0;
virtual bool check(InsertRoute const &op) const = 0;
virtual bool check(RemovePair const &op) const = 0;
virtual bool check(RemoveRoute const &op) const = 0;
public:
virtual ~ConstraintVisitor() = default;
/**
* Checks that a modification is valid for the solution
* If a check fails it must return false.
*/
bool checkVariant(ModificationCheckVariant const &checkModificationVariant);
};
/**
* Base class for a constraint.
* It has to define all checks (from ConstraintVisitor),
* and can modify its state with the apply (from ModificationVisitor), it looks like a listener pattern
*/
class Constraint : public ConstraintVisitor
{
std::reference_wrapper<Solution const> solution;
protected:
explicit Constraint(Solution const &);
PDPTWData const &data() const;
public:
/**
* It is expected that the new Solution is in valid state regarding precedence graph and times when cloning
*/
virtual std::unique_ptr<Constraint> clone(Solution const &newOwningSolution) const = 0;
Solution const &getSolution() const;
// used when a solution is moved, we must update the owner
void setSolution(Solution const &newSolutionOwner);
~Constraint() override = default;
/**
* Callback when many destruction are done. It is expected that checks work after a call to this.
* Defaults to no op
*/
virtual void endOfDestructionCallback() {}
};
\ No newline at end of file
#include "time_window_constraint.h"
#include "input/data.h"
#include "input/pdptw_data.h"
#include "input/time_window.h"
#include "lns/solution/solution.h"
TimeWindowConstraint::TimeWindowConstraint(Solution const &solution) : Constraint(solution)
{
// Empty
}
std::unique_ptr<Constraint> TimeWindowConstraint::clone(Solution const &newOwningSolution) const {
std::unique_ptr<TimeWindowConstraint> clonePtr = std::make_unique<TimeWindowConstraint>(newOwningSolution);
clonePtr->allRouteReachTimes = allRouteReachTimes;
return clonePtr;
}
// Copie le vecteur de reach time de la route concernée
// Insère les positions pickup/delivery
// refait l'ordo sur le nouveau vecteur
bool TimeWindowConstraint::checkInsertion(const PDPTWData& data, const Pair & pair, int routeIndex, int pickupPos, int deliveryPos) const
{
ReachTimeVector const &reachTimes = allRouteReachTimes.at(routeIndex);
// COPY route vector
std::vector<int> route(getSolution().getRoute(routeIndex).getRoute().begin(), getSolution().getRoute(routeIndex).getRoute().end()) ;
// COPY reachTimes vector
ReachTimeVector newReachTimes(reachTimes.begin(), reachTimes.end());
// Insert pickup and delivery
route.insert(route.begin() + pickupPos, pair.getPickup().getId());
route.insert(route.begin() + deliveryPos, pair.getDelivery().getId());
// Compute new reach time
computeReachTimes(data, route, newReachTimes);
// Check Time Windows
for (int i = 0; i < reachTimes.size(); ++i)
{
if (! data.getLocation(route[i]).getTimeWindow().isValid(newReachTimes.at(i)) )
{
return false;
}
}
return true;
}
void TimeWindowConstraint::computeReachTimes(const PDPTWData& data, const std::vector<int> & routeIDs, ReachTimeVector & reachTimes) const
{
// Adjust the size of reachTimes vector
reachTimes.resize(routeIDs.size(), 0);
// Time to the first location
reachTimes[0] = data.getDepot().getTimeWindow().getStart() + data::TravelTime(data, 0, routeIDs.at(0));
// Compute other reachTimes (max between arrival and start of the time window)
for (int i = 1; i < routeIDs.size(); ++i) {
TimeInteger travelTime = data::TravelTime(data, routeIDs[i - 1], routeIDs[i]);
TimeInteger serviceTime = data.getLocation(routeIDs[i - 1]).getServiceDuration();
TimeInteger startTW = data.getLocation(routeIDs[i]).getTimeWindow().getStart();
reachTimes[i] = std::max(reachTimes[i - 1] + serviceTime + travelTime, startTW);
}
}
void TimeWindowConstraint::ApplyModif(const PDPTWData& data, const Pair & pair, int routeIndex, int pickupPos, int deliveryPos, bool addPair)
{
// COPY route vector
std::vector<int> routeIDs(getSolution().getRoute(routeIndex).getRoute().begin(), getSolution().getRoute(routeIndex).getRoute().end());
// Adjust pickup and delivery
if (addPair)
{
routeIDs.insert(routeIDs.begin() + pickupPos, pair.getPickup().getId());
routeIDs.insert(routeIDs.begin() + deliveryPos, pair.getDelivery().getId());
}
else
{
routeIDs.erase(routeIDs.begin() + deliveryPos);
routeIDs.erase(routeIDs.begin() + pickupPos);
}
// Adjust the size of reachTimes vector
allRouteReachTimes[routeIndex].resize(routeIDs.size(), 0);
// Time to the first location
allRouteReachTimes[routeIndex][0] = data.getDepot().getTimeWindow().getStart() + data::TravelTime(data, 0, routeIDs.at(0));
// Compute other reachTimes (max between arrival and start of the time window)
for (int i = 1; i < routeIDs.size(); ++i) {
TimeInteger travelTime = data::TravelTime(data, routeIDs[i - 1], routeIDs[i]);
TimeInteger serviceTime = data.getLocation(routeIDs[i - 1]).getServiceDuration();
TimeInteger startTW = data.getLocation(routeIDs[i]).getTimeWindow().getStart();
allRouteReachTimes[routeIndex][i] = std::max(allRouteReachTimes[routeIndex][i - 1] + serviceTime + travelTime, startTW);
}
}
bool TimeWindowConstraint::check(InsertPair const &op) const
{
return checkInsertion(getSolution().getData(), op.getPair(), op.getRouteIndex(), op.getPickupInsertion(), op.getDeliveryInsertion());
}
void TimeWindowConstraint::apply(InsertPair const &op)
{
ApplyModif(getSolution().getData(), op.getPair(), op.getRouteIndex(), op.getPickupInsertion(), op.getDeliveryInsertion(), true);
}
bool TimeWindowConstraint::check(InsertRoute const &op) const
{
return true;
}
void TimeWindowConstraint::apply(InsertRoute const &op)
{
allRouteReachTimes.emplace_back();
}
bool TimeWindowConstraint::check(RemovePair const &op) const
{
return true;
}
void TimeWindowConstraint::apply(RemovePair const &op)
{
ApplyModif(getSolution().getData(), op.getPair(), op.getRouteIndex(), op.getPickupDeletion(), op.getDeliveryDeletion(), false);
}
bool TimeWindowConstraint::check(RemoveRoute const &op) const
{
return true;
}
void TimeWindowConstraint::apply(RemoveRoute const &op)
{
allRouteReachTimes.erase(allRouteReachTimes.begin() + op.getRouteIndex());
}
#pragma once
#include "lns/constraints/constraint.h"
#include "input/pair.h"
#include "input/time_window.h"
#include <vector>
/**
* Time Window Constraint
* Check that the time windows are respected.
* For now, compute all time window in a route
* TO DO FTS
*/
class TimeWindowConstraint : public Constraint
{
public:
explicit TimeWindowConstraint(Solution const &);
TimeWindowConstraint(TimeWindowConstraint const &) = default;
std::unique_ptr<Constraint> clone(Solution const &newOwningSolution) const override;
private:
using ReachTimeVector = std::vector<TimeInteger>;
/**
* For each route, store the reach time of each location
*/
std::vector<ReachTimeVector> allRouteReachTimes;
// Recalcul tous les reachTimes pour une route
ReachTimeVector computeReachTimes(const Route& route) const;
bool updateReachTimes(const PDPTWData& data, Pair & pair,int routeIndex, int pickupPos, int deliveryPos);
/**
* Check if the insertion of a pair pickup/delivery is valid or not.
* COPY the route where we insert the pair !
*/
bool checkInsertion(const PDPTWData& data, const Pair & pair, int routeIndex, int pickupPos, int deliveryPos) const;
/**
* Given route IDs, compute the reachTimes of the route.
* If a vehicule is in advance, set the reach time to start of the timeWindow.
* Modify reachTimes vector !
*/
void computeReachTimes(const PDPTWData& data, const std::vector<int> & routeIDs, ReachTimeVector & reachTimes) const;
/**
* Given route IDs, modify the reachTimes
*/
void ApplyModif(const PDPTWData& data, const Pair & pair, int routeIndex, int pickupPos, int deliveryPos, bool addPair);
void apply(InsertPair const &op) override;
void apply(InsertRoute const &op) override;
void apply(RemovePair const &op) override;
void apply(RemoveRoute const &op) override;
bool check(InsertPair const &op) const override;
bool check(InsertRoute const &op) const override;
bool check(RemovePair const &op) const override;
bool check(RemoveRoute const &op) const override;
public:
};
\ No newline at end of file
#pragma once
#include "atomic_modification.h"
#include <vector>
class Location;
/**
* Abstract Modification that destruct the solution.
*/
class AtomicDestruction : public AtomicModification
{
public:
/**
* @return the location ID removed from the solution.
*/
virtual std::vector<int> const &getDeletedRequests() const = 0;
};
#pragma once
class Solution;
/**
* Represent a modification of the solution, it can recreate/destroy the solution.
*
* @see AtomicRecreation and AtomicDestruction
*/
class AtomicModification
{
public:
/**
* Return the cost of the operation.
* @return a positive number if the solution cost is bigger after the modification.
*/
virtual double evaluate(Solution const &solution) const = 0;
/**
* Apply of the modification to the solution.
* @note does not check the validity of the modification, does not update solution cost nor constraints
*/
virtual void modifySolution(Solution &solution) = 0;
};
#pragma once
#include "atomic_modification.h"
class Location;
/**
* Abstract specification of AtomicModification for modifications that recreate the solution.
*/
class AtomicRecreation : public AtomicModification
{
public:
/**
* @return the pickup location added to the solution, nullptr if none were added
*/
virtual Location const *getAddedLocation() const = 0;
};
\ No newline at end of file