Recuit simulé ajout de remove et insert dépendant de la progression du recuit + autoriser le remove à couter quedalle au début puis un max et de même pour les violation d'intervales (pour l'instant une seule violation autorisée et compatibilisée à la detection)
This commit is contained in:
+3
-1
@@ -1,2 +1,4 @@
|
|||||||
build
|
build
|
||||||
lib
|
lib
|
||||||
|
Data
|
||||||
|
.cache
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"folders": [
|
|
||||||
{
|
|
||||||
"path": "../../.."
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"settings": {},
|
|
||||||
"launch": {
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"type": "lldb",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "Debug",
|
|
||||||
"program": "${workspaceFolder}/build/bin/Debug/OrdonnancementCorrectif",
|
|
||||||
"args": ["--solve", "-TRACKPLANS", "1_3_10_100_100_0.json"],
|
|
||||||
"cwd": "${workspaceFolder}/build/bin/Debug/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "lldb",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "DebugPrevRep",
|
|
||||||
"program": "${workspaceFolder}/build/bin/Debug/OrdonnancementCorrectif",
|
|
||||||
"args": ["--solve", "-PREVREP", "1_6_20_150_50_2.json"],
|
|
||||||
"cwd": "${workspaceFolder}/build/bin/Debug/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "lldb",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "DebugIns",
|
|
||||||
"program": "${workspaceFolder}/build/bin/Debug/InstanceGenerator",
|
|
||||||
"args": [],
|
|
||||||
"cwd": "${workspaceFolder}/build/bin/Debug/"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-17
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"type": "lldb",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "Debug",
|
|
||||||
"program": "${workspaceFolder}/build/bin/Debug/OrdonnancementCorrectif",
|
|
||||||
"args": ["--solve", "-HEURISTIC", "soutenance.json"],
|
|
||||||
"cwd": "${workspaceFolder}/build/bin/Debug/"
|
|
||||||
}
|
|
||||||
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#ifndef PENALTY_HPP
|
||||||
|
#define PENALTY_HPP
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace solverlib {
|
||||||
|
|
||||||
|
enum class EPenaltyType {
|
||||||
|
TIME_WINDOW_OVERRUN, // job dépasse sa fenêtre
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Penalty {
|
||||||
|
std::unordered_map<EPenaltyType, double> components;
|
||||||
|
|
||||||
|
void add(EPenaltyType type, double value) {
|
||||||
|
components[type] += value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subtract(EPenaltyType type, double value) {
|
||||||
|
components[type] = std::max(0.0, components[type] - value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Coût agrégé pondéré — les lambdas sont injectés depuis l'extérieur
|
||||||
|
double weighted(const std::unordered_map<EPenaltyType, double>& lambdas) const {
|
||||||
|
double total = 0.0;
|
||||||
|
for (auto& [type, val] : components)
|
||||||
|
{
|
||||||
|
auto it = lambdas.find(type);
|
||||||
|
if (it != lambdas.end())
|
||||||
|
total += it->second * val;
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
double total() const {
|
||||||
|
double sum = 0.0;
|
||||||
|
for (auto& [_, v] : components) sum += v;
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isFeasible() const { return total() == 0.0; }
|
||||||
|
|
||||||
|
Penalty operator+(const Penalty& o) const {
|
||||||
|
Penalty res = *this;
|
||||||
|
for (auto& [type, val] : o.components)
|
||||||
|
res.components[type] += val;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Penalty operator-(const Penalty& o) const {
|
||||||
|
Penalty res = *this;
|
||||||
|
for (auto& [type, val] : o.components)
|
||||||
|
res.components[type] = std::max(0.0, res.components[type] - val);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "SimulatedAnnealing.hpp"
|
#include "SimulatedAnnealing.hpp"
|
||||||
#include "../PseCarlierRivreau/omp.h"
|
#include "../PseCarlierRivreau/omp.h"
|
||||||
#include "DynamicProgramming.hpp"
|
#include "DynamicProgramming.hpp"
|
||||||
|
#include "Penalty.hpp"
|
||||||
#include "Solution.hpp"
|
#include "Solution.hpp"
|
||||||
#include "TrackPlan.hpp"
|
#include "TrackPlan.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -10,24 +11,28 @@
|
|||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "Random.hpp"
|
#include "Random.hpp"
|
||||||
#include "sourceSolTrPlan.hpp"
|
#include "sourceSolTrPlan.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace solverlib {
|
namespace solverlib {
|
||||||
using namespace random;
|
using namespace random;
|
||||||
|
|
||||||
bool StatSimulatedAnnealing::activate = true;
|
bool StatSimulatedAnnealing::activate = true;
|
||||||
bool SimulatedAnnealing::withDynProg = false;
|
bool SimulatedAnnealing::withDynProg = false;
|
||||||
|
bool SimulatedAnnealing::authorizeInfeasible = true;
|
||||||
|
|
||||||
|
constexpr double decreaseFunction(double p){return std::exp(-0.75*(1.0-p));};
|
||||||
|
|
||||||
std::unordered_map<EMovingOperators, std::string> StatSimulatedAnnealing::names = {
|
std::unordered_map<EMovingOperators, std::string> StatSimulatedAnnealing::names = {
|
||||||
{EMovingOperators::CHANGE_MODE_WITHOUT_CARLIER, "CHANGE_MODE"},
|
{EMovingOperators::CHANGE_MODE, "CHANGE_MODE"},
|
||||||
{EMovingOperators::INSERT_WITHOUT_CARLIER, "INSERT"},
|
{EMovingOperators::INSERT, "INSERT"},
|
||||||
{EMovingOperators::REMOVE_WITHOUT_CARLIER, "REMOVE"},
|
{EMovingOperators::REMOVE, "REMOVE"},
|
||||||
{EMovingOperators::SWAP_WITHOUT_CARLIER, "SWAP"},
|
{EMovingOperators::SWAP, "SWAP"},
|
||||||
{EMovingOperators::SWAP_WITHIN_INTERVAL, "SWAP_WITHIN_SEQUENCE"},
|
{EMovingOperators::SWAP_WITHIN_INTERVAL, "SWAP_WITHIN_SEQUENCE"},
|
||||||
{EMovingOperators::DYN_PROG, "DYN_PROG"},
|
{EMovingOperators::DYN_PROG, "DYN_PROG"},
|
||||||
{EMovingOperators::MOVE, "MOVE"}
|
{EMovingOperators::MOVE, "MOVE"}
|
||||||
@@ -37,7 +42,11 @@ namespace solverlib {
|
|||||||
SimulatedAnnealing::SimulatedAnnealing(std::unordered_map<unsigned short, Decision>& decs, std::shared_ptr<modellib::STFMockInstance> mock, ESourceTrackPlan source)
|
SimulatedAnnealing::SimulatedAnnealing(std::unordered_map<unsigned short, Decision>& decs, std::shared_ptr<modellib::STFMockInstance> mock, ESourceTrackPlan source)
|
||||||
{
|
{
|
||||||
randomEngine = solverlib::random::makeEngine();
|
randomEngine = solverlib::random::makeEngine();
|
||||||
|
maxCostOfJob = (*std::max_element(STFMockInstance::jobs.begin(), STFMockInstance::jobs.end(), [&](auto op1, auto op2){return op1->getPoidsRetard() < op2->getPoidsRetard();}))->getPoidsRetard();
|
||||||
|
setPenaltyWeights();
|
||||||
addSolutionToPool(decs, mock, source);
|
addSolutionToPool(decs, mock, source);
|
||||||
|
for (unsigned int i = 0; i< STFMockInstance::machines.size(); ++i)
|
||||||
|
solutions[0].penaltyPerMachine[i] = Penalty{};
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatedAnnealing::addSolutionToPool(std::unordered_map<unsigned short, Decision>& decs, std::shared_ptr<modellib::STFMockInstance> mock, ESourceTrackPlan source, bool isPutFirst)
|
void SimulatedAnnealing::addSolutionToPool(std::unordered_map<unsigned short, Decision>& decs, std::shared_ptr<modellib::STFMockInstance> mock, ESourceTrackPlan source, bool isPutFirst)
|
||||||
@@ -73,58 +82,24 @@ namespace solverlib {
|
|||||||
return {cost, diagCost};
|
return {cost, diagCost};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<unsigned int, unsigned int> SimulatedAnnealing::getCostOfSequence(std::vector<std::pair<unsigned short, decision>>& jobsSeq)
|
EMovingOperators SimulatedAnnealing::pick_operator() {
|
||||||
{
|
double p = progress();
|
||||||
unsigned int cost = 0;
|
|
||||||
unsigned int costDiag = 0;
|
|
||||||
for(auto& el : jobsSeq)
|
|
||||||
{
|
|
||||||
cost += STFMockInstance::jobs[el.first]->getPoidsRetard()*el.second.lastCreneau.first;
|
|
||||||
costDiag += STFMockInstance::jobs[el.first]->getPoidsRejet()*el.second.rejected;
|
|
||||||
}
|
|
||||||
return {cost, costDiag};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// tire un opérateur uniformément
|
|
||||||
EMovingOperators SimulatedAnnealing::pick_operator(double temp, double tmax) {
|
|
||||||
int N = withDynProg ? static_cast<int>(EMovingOperators::DYN_PROG)+1 : static_cast<int>(EMovingOperators::MOVE)+1;
|
|
||||||
std::vector<float> weights(N, 1);
|
|
||||||
|
|
||||||
|
float w_remove = static_cast<float>(2*std::max(0.0,1.0 - decreaseFunction(p)));
|
||||||
|
float w_insert = static_cast<float>(2*std::min(1.0, decreaseFunction(p)));
|
||||||
std::vector<float> base_weights = {
|
std::vector<float> base_weights = {
|
||||||
1.0f,
|
1,
|
||||||
1.0f,
|
w_insert,
|
||||||
1.0f,
|
w_remove,
|
||||||
1.0f,
|
1,
|
||||||
1.0f,
|
1,
|
||||||
1.0f
|
1
|
||||||
// DYN_PROG ajouté si besoin
|
// DYN_PROG ajouté si besoin
|
||||||
};
|
};
|
||||||
if (withDynProg) base_weights.push_back(0.5f); // DYN_PROG
|
if (withDynProg) base_weights.push_back(1.0f); // DYN_PROG
|
||||||
|
|
||||||
const float remove_base = 1.0f; // poids max du remove (en début de recuit)
|
|
||||||
const float t = temp / tmax; // 1.0 → 0.0
|
|
||||||
|
|
||||||
// Poids remove
|
|
||||||
const float w_remove = remove_base * t;
|
|
||||||
|
|
||||||
// Le budget récupéré est redistribué proportionnellement aux autres
|
|
||||||
const float base_sum = std::accumulate(base_weights.begin(), base_weights.end(), 0.0f);
|
|
||||||
const float bonus = remove_base * (1.0f - t);
|
|
||||||
|
|
||||||
// Index du REMOVE dans ton enum — à adapter
|
|
||||||
constexpr int REMOVE_IDX = 2;
|
|
||||||
|
|
||||||
for (int i = 0; i < N; ++i) {
|
|
||||||
if (i == REMOVE_IDX) {
|
|
||||||
weights[i] = w_remove;
|
|
||||||
} else {
|
|
||||||
weights[i] = base_weights[i] + bonus * (base_weights[i] / base_sum);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return static_cast<EMovingOperators>(
|
return static_cast<EMovingOperators>(
|
||||||
//std::uniform_int_distribution<int>(0, N)(randomEngine)
|
std::discrete_distribution<int>(base_weights.begin(), base_weights.end())(randomEngine)
|
||||||
std::discrete_distribution<int>(weights.begin(), weights.end())(randomEngine)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,10 +108,10 @@ namespace solverlib {
|
|||||||
{
|
{
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case EMovingOperators::SWAP_WITHOUT_CARLIER: return move_swap_WC(current);
|
case EMovingOperators::SWAP: return move_swap_WC(current);
|
||||||
case EMovingOperators::INSERT_WITHOUT_CARLIER: return move_insert_WC(current);
|
case EMovingOperators::INSERT: return move_insert_WC(current);
|
||||||
case EMovingOperators::REMOVE_WITHOUT_CARLIER: return move_remove_WC(current);
|
case EMovingOperators::REMOVE: return move_remove_WC(current);
|
||||||
case EMovingOperators::CHANGE_MODE_WITHOUT_CARLIER: return move_change_mode_WC(current);
|
case EMovingOperators::CHANGE_MODE: return move_change_mode_WC(current);
|
||||||
case EMovingOperators::SWAP_WITHIN_INTERVAL: return move_swap_within_interval(current);
|
case EMovingOperators::SWAP_WITHIN_INTERVAL: return move_swap_within_interval(current);
|
||||||
case EMovingOperators::MOVE: return move_move_WC(current);
|
case EMovingOperators::MOVE: return move_move_WC(current);
|
||||||
case EMovingOperators::DYN_PROG: return move_dynprog(current);
|
case EMovingOperators::DYN_PROG: return move_dynprog(current);
|
||||||
@@ -150,16 +125,22 @@ namespace solverlib {
|
|||||||
{
|
{
|
||||||
SASolution current = solutions[0];
|
SASolution current = solutions[0];
|
||||||
SASolution best = solutions[0];
|
SASolution best = solutions[0];
|
||||||
|
current.fictiveCost = current.cost;
|
||||||
|
best.fictiveCost = current.cost;
|
||||||
|
|
||||||
|
Tmax = T_max;
|
||||||
double cost_cur = current.cost;
|
double cost_cur = current.cost;
|
||||||
double cost_best= cost_cur;
|
double cost_best= cost_cur;
|
||||||
double T = T_max;
|
T = Tmax;
|
||||||
|
Tmin = T_min;
|
||||||
|
rate = cooling_rate;
|
||||||
std::uniform_real_distribution<double> uniform(0.0, 1.0);
|
std::uniform_real_distribution<double> uniform(0.0, 1.0);
|
||||||
|
|
||||||
while (T > T_min + 10e-6)
|
while (T > Tmin + 10e-6)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < iterations_per_temp; ++i)
|
for (int i = 0; i < iterations_per_temp; ++i)
|
||||||
{
|
{
|
||||||
EMovingOperators op = pick_operator(T, T_max);
|
EMovingOperators op = pick_operator();
|
||||||
stats.addUsed(op);
|
stats.addUsed(op);
|
||||||
auto neighbor = apply_operator(current, op);
|
auto neighbor = apply_operator(current, op);
|
||||||
|
|
||||||
@@ -167,23 +148,33 @@ namespace solverlib {
|
|||||||
|
|
||||||
auto costs_neighbor = std::make_pair(neighbor->cost, neighbor->diagCost);
|
auto costs_neighbor = std::make_pair(neighbor->cost, neighbor->diagCost);
|
||||||
|
|
||||||
double delta = costs_neighbor.first - cost_cur;
|
double delta = effectiveCost(*neighbor) - effectiveCost(current);
|
||||||
|
double diff = (double)neighbor->cost - (double)current.cost;
|
||||||
|
|
||||||
|
if(neighbor->penalty.isFeasible())
|
||||||
|
stats.addFeas(op);
|
||||||
|
|
||||||
stats.addFeas(op);
|
|
||||||
if(delta <= 0)
|
if(delta <= 0)
|
||||||
stats.addImproved(op);
|
stats.addImproved(op);
|
||||||
|
|
||||||
|
if(diff <= 0 && neighbor->penalty.isFeasible())
|
||||||
|
stats.addImprovedReal(op);
|
||||||
|
|
||||||
|
if(!neighbor->penalty.isFeasible())
|
||||||
|
stats.addInfeasible(op);
|
||||||
|
|
||||||
if(delta > 0)
|
if(delta > 0)
|
||||||
{
|
{
|
||||||
stats.addFailInfo(op, getP(delta, T, op), delta, T);
|
stats.addFailInfo(op, getP(delta, op), diff, delta, T, neighbor->penalty.isFeasible());
|
||||||
}
|
}
|
||||||
|
//TODO AJOUTER AUTORISER AVEC PENALITE LES INFEASABLES => NECESSITE DE METTRE À JOUR LA GENERATION TRACK PLAN POUR LE ILP ET IGNORER LES TRACKPLANS INF
|
||||||
|
|
||||||
if (delta < 0 || uniform(randomEngine) < getP(delta, T, op))
|
if (delta < 0 || uniform(randomEngine) < getP(delta, op))
|
||||||
{
|
{
|
||||||
current = std::move(*neighbor);
|
current = std::move(*neighbor);
|
||||||
cost_cur = costs_neighbor.first;
|
cost_cur = costs_neighbor.first;
|
||||||
|
|
||||||
if (cost_cur < cost_best) {
|
if (current.penalty.isFeasible() && cost_cur < cost_best) {
|
||||||
best = current;
|
best = current;
|
||||||
cost_best = cost_cur;
|
cost_best = cost_cur;
|
||||||
}
|
}
|
||||||
@@ -201,22 +192,43 @@ namespace solverlib {
|
|||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
|
|
||||||
double SimulatedAnnealing::getP(double delta, double temperature, EMovingOperators op)
|
double SimulatedAnnealing::effectiveCost(const SASolution& s) const {
|
||||||
|
return s.fictiveCost + s.penalty.weighted(effectiveLambdas());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<EPenaltyType, double> SimulatedAnnealing::effectiveLambdas() const {
|
||||||
|
double p = progress();
|
||||||
|
return {
|
||||||
|
{EPenaltyType::TIME_WINDOW_OVERRUN, std::exp(8*(p-0.2))-0.8},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
double SimulatedAnnealing::progress() const {
|
||||||
|
//return 1.0 - (T - Tmin) / (Tmax - Tmin); // 0 au début, 1 à la fin
|
||||||
|
return 1.0 - (std::log(T) - std::log(Tmin)) / (std::log(Tmax) - std::log(Tmin));
|
||||||
|
}
|
||||||
|
|
||||||
|
double SimulatedAnnealing::fictiveCostExcluded(unsigned short op_id) const {
|
||||||
|
return decreaseFunction(progress()) * MAXIMUM_TIME_OFFSET
|
||||||
|
* STFMockInstance::jobs[op_id]->getPoidsRetard();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double SimulatedAnnealing::getP(double delta, EMovingOperators op)
|
||||||
{
|
{
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case EMovingOperators::SWAP_WITHOUT_CARLIER:
|
case EMovingOperators::SWAP:
|
||||||
case EMovingOperators::INSERT_WITHOUT_CARLIER:
|
case EMovingOperators::INSERT: return std::exp(-delta/(T*50));
|
||||||
case EMovingOperators::REMOVE_WITHOUT_CARLIER: return std::exp(-delta/(temperature*100));
|
case EMovingOperators::REMOVE: return std::exp(-delta/(T*50));
|
||||||
case EMovingOperators::CHANGE_MODE_WITHOUT_CARLIER:
|
case EMovingOperators::CHANGE_MODE:
|
||||||
case EMovingOperators::SWAP_WITHIN_INTERVAL:
|
case EMovingOperators::SWAP_WITHIN_INTERVAL:
|
||||||
case EMovingOperators::MOVE: return std::exp(-delta/(temperature*10));
|
case EMovingOperators::MOVE: return std::exp(-delta/(T*20));
|
||||||
case EMovingOperators::DYN_PROG:
|
case EMovingOperators::DYN_PROG:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return std::exp(-delta/temperature);
|
return std::exp(-delta/T);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//OPERATEURS
|
//OPERATEURS
|
||||||
|
|
||||||
std::optional<SASolution> SimulatedAnnealing::move_dynprog(const SASolution& sol)
|
std::optional<SASolution> SimulatedAnnealing::move_dynprog(const SASolution& sol)
|
||||||
@@ -265,55 +277,48 @@ namespace solverlib {
|
|||||||
auto posA = std::find(seq_swap.begin(), seq_swap.end(), op_a);
|
auto posA = std::find(seq_swap.begin(), seq_swap.end(), op_a);
|
||||||
if(posA == seq_swap.end()) return std::nullopt;
|
if(posA == seq_swap.end()) return std::nullopt;
|
||||||
|
|
||||||
auto lbdBuildSeq = [&](std::vector<unsigned short>& seq) -> std::optional<SASolution> {
|
|
||||||
SASolution neighbor = sol;
|
|
||||||
auto creneauTrack = STFMockInstance::machines[dec_a.empV]->getDispo();
|
|
||||||
unsigned short lastEnd = 0;
|
|
||||||
unsigned int oldCost = 0;
|
|
||||||
unsigned int newCost = 0;
|
|
||||||
for(auto& job : seq)
|
|
||||||
{
|
|
||||||
Decision& dec_neih = neighbor.decisions.at(job);
|
|
||||||
auto creneauJob = mock->trajectoryStops[dec_neih.empR].getDispoStop();
|
|
||||||
auto match = CreneauHoraire::checkSlotsCompatibility(creneauJob, creneauTrack);
|
|
||||||
oldCost += STFMockInstance::jobs[job]->getPoidsRetard()*sol.decisions.at(job).lastCreneau.first;
|
|
||||||
if(match.first)
|
|
||||||
{
|
|
||||||
if(std::max(match.second.first, lastEnd) + dec_neih.rejected*STFMockInstance::jobs[job]->getDureeDiag() + !dec_neih.rejected*STFMockInstance::jobs[job]->getDuree() > match.second.first + match.second.second)
|
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
dec_neih.lastCreneau = {
|
|
||||||
std::max(match.second.first, lastEnd),
|
|
||||||
std::max(match.second.first, lastEnd)+ dec_neih.rejected*STFMockInstance::jobs[job]->getDureeDiag() + !dec_neih.rejected*STFMockInstance::jobs[job]->getDuree()
|
|
||||||
};
|
|
||||||
newCost += STFMockInstance::jobs[job]->getPoidsRetard()*dec_neih.lastCreneau.first;
|
|
||||||
lastEnd = std::max(match.second.first, lastEnd)+ dec_neih.rejected*STFMockInstance::jobs[job]->getDureeDiag() + !dec_neih.rejected*STFMockInstance::jobs[job]->getDuree();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
neighbor.cost = (neighbor.cost - oldCost) + newCost;
|
|
||||||
neighbor.source = ESourceTrackPlan::SimAn;
|
|
||||||
return neighbor;
|
|
||||||
};
|
|
||||||
|
|
||||||
//TEST SWAP
|
|
||||||
std::uniform_int_distribution<int> posR(0, (int)seq_swap.size()-1);
|
|
||||||
auto job = posR(randomEngine);
|
|
||||||
auto IposA = std::distance(seq_swap.begin(), posA);
|
auto IposA = std::distance(seq_swap.begin(), posA);
|
||||||
while(job == IposA)
|
|
||||||
job = posR(randomEngine);
|
// Tirer un index différent de IposA pour le swap
|
||||||
|
std::uniform_int_distribution<int> posR(0, (int)seq_swap.size() - 1);
|
||||||
|
int posB = posR(randomEngine);
|
||||||
|
while (posB == IposA)
|
||||||
|
posB = posR(randomEngine);
|
||||||
|
|
||||||
auto seqCop = seq_swap;
|
auto seqCop = seq_swap;
|
||||||
auto posJobInt = job;
|
std::swap(seqCop[IposA], seqCop[posB]);
|
||||||
seqCop[posJobInt] = *posA;
|
|
||||||
seqCop[IposA] = seq_swap[job];
|
|
||||||
auto res = lbdBuildSeq(seqCop);
|
|
||||||
if(res != std::nullopt)
|
|
||||||
return res;
|
|
||||||
|
|
||||||
return std::nullopt;
|
// Reconstruire le vecteur de décisions dans le bon ordre
|
||||||
|
std::vector<std::pair<unsigned short, Decision>> jobsSeq;
|
||||||
|
jobsSeq.reserve(seqCop.size());
|
||||||
|
for (auto& job_id : seqCop)
|
||||||
|
jobsSeq.push_back({job_id, sol.decisions.at(job_id)});
|
||||||
|
|
||||||
|
Penalty oldPen = sol.penaltyPerMachine.count(dec_a.empV)
|
||||||
|
? sol.penaltyPerMachine.at(dec_a.empV)
|
||||||
|
: Penalty{};
|
||||||
|
|
||||||
|
unsigned int oldCost = 0;
|
||||||
|
for (auto& job_id : seq_swap)
|
||||||
|
oldCost += STFMockInstance::jobs[job_id]->getPoidsRetard()
|
||||||
|
* sol.decisions.at(job_id).lastCreneau.first;
|
||||||
|
|
||||||
|
Penalty newPen; bool feasible = true;
|
||||||
|
auto res = checkSequence(jobsSeq, dec_a.empV, newPen, feasible);
|
||||||
|
if (!res) return std::nullopt;
|
||||||
|
|
||||||
|
// Construire le voisin
|
||||||
|
SASolution neighbor = sol;
|
||||||
|
unsigned int newCost = 0;
|
||||||
|
applySequenceResult(neighbor, jobsSeq, *res, newCost, newPen, feasible);
|
||||||
|
|
||||||
|
neighbor.penalty = sol.penalty - oldPen + newPen;
|
||||||
|
neighbor.penaltyPerMachine[dec_a.empV] = newPen;
|
||||||
|
neighbor.isFeasible = neighbor.penalty.isFeasible();
|
||||||
|
neighbor.fictiveCost = (neighbor.fictiveCost - oldCost) + newCost;
|
||||||
|
neighbor.cost = (neighbor.cost - oldCost) + newCost;
|
||||||
|
neighbor.source = ESourceTrackPlan::SimAn;
|
||||||
|
return neighbor;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<SASolution> SimulatedAnnealing::move_swap_WC(const SASolution& sol)
|
std::optional<SASolution> SimulatedAnnealing::move_swap_WC(const SASolution& sol)
|
||||||
@@ -397,6 +402,12 @@ namespace solverlib {
|
|||||||
auto oldCrenA = dec_a.lastCreneau;
|
auto oldCrenA = dec_a.lastCreneau;
|
||||||
auto oldCrenB = dec_b.lastCreneau;
|
auto oldCrenB = dec_b.lastCreneau;
|
||||||
|
|
||||||
|
// Pénalités anciennes O(1)
|
||||||
|
Penalty oldPenA = sol.penaltyPerMachine.count(dec_a.empV)
|
||||||
|
? sol.penaltyPerMachine.at(dec_a.empV) : Penalty{};
|
||||||
|
Penalty oldPenB = sol.penaltyPerMachine.count(dec_b.empV)
|
||||||
|
? sol.penaltyPerMachine.at(dec_b.empV) : Penalty{};
|
||||||
|
|
||||||
std::vector<std::pair<unsigned short, decision>> jobsEmpVA;
|
std::vector<std::pair<unsigned short, decision>> jobsEmpVA;
|
||||||
std::vector<std::pair<unsigned short, decision>> jobsEmpVB;
|
std::vector<std::pair<unsigned short, decision>> jobsEmpVB;
|
||||||
unsigned int oldCost = dec_a.lastCreneau.first * STFMockInstance::jobs[op_a]->getPoidsRetard() + dec_b.lastCreneau.first * STFMockInstance::jobs[swap.op_b]->getPoidsRetard();
|
unsigned int oldCost = dec_a.lastCreneau.first * STFMockInstance::jobs[op_a]->getPoidsRetard() + dec_b.lastCreneau.first * STFMockInstance::jobs[swap.op_b]->getPoidsRetard();
|
||||||
@@ -443,32 +454,24 @@ namespace solverlib {
|
|||||||
}
|
}
|
||||||
return cren1.first < cren2.first;
|
return cren1.first < cren2.first;
|
||||||
});
|
});
|
||||||
auto resA = checkSequence(jobsEmpVA, new_dec_a.empV);
|
|
||||||
auto resB = checkSequence(jobsEmpVB, new_dec_b.empV);
|
Penalty penA; Penalty penB;
|
||||||
|
bool feasA = true, feasB = true;
|
||||||
|
auto resA = checkSequence(jobsEmpVA, new_dec_a.empV, penA, feasA);
|
||||||
|
auto resB = checkSequence(jobsEmpVB, new_dec_b.empV, penB, feasB);
|
||||||
unsigned int newCost = 0;
|
unsigned int newCost = 0;
|
||||||
if(resA && resB)
|
if(!resA || !resB) return std::nullopt;
|
||||||
{
|
|
||||||
unsigned int id = 0;
|
applySequenceResult(neighbor, jobsEmpVA, *resA, newCost, penA, feasA);
|
||||||
for(auto& jobsA : jobsEmpVA)
|
applySequenceResult(neighbor, jobsEmpVB, *resB, newCost, penB, feasB);
|
||||||
{
|
|
||||||
auto& dec = neighbor.decisions[jobsA.first];
|
neighbor.penalty = sol.penalty - oldPenA - oldPenB + penA + penB;
|
||||||
dec.lastCreneau = resA.value()[id].second.lastCreneau;
|
neighbor.penaltyPerMachine[new_dec_a.empV] = penA;
|
||||||
newCost += dec.lastCreneau.first * STFMockInstance::jobs[jobsA.first]->getPoidsRetard();
|
neighbor.penaltyPerMachine[new_dec_b.empV] = penB;
|
||||||
++id;
|
neighbor.isFeasible = neighbor.penalty.isFeasible();
|
||||||
}
|
neighbor.fictiveCost = (neighbor.fictiveCost - oldCost) + newCost;
|
||||||
id = 0;
|
neighbor.cost = (neighbor.cost - oldCost) + newCost;
|
||||||
for(auto& jobsB : jobsEmpVB)
|
neighbor.source = ESourceTrackPlan::SimAn;
|
||||||
{
|
|
||||||
auto& dec = neighbor.decisions[jobsB.first];
|
|
||||||
dec.lastCreneau = resB.value()[id].second.lastCreneau;
|
|
||||||
newCost += dec.lastCreneau.first * STFMockInstance::jobs[jobsB.first]->getPoidsRetard();
|
|
||||||
++id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return std::nullopt;
|
|
||||||
neighbor.cost = (neighbor.cost - oldCost) + newCost;
|
|
||||||
neighbor.source = ESourceTrackPlan::SimAn;
|
|
||||||
return neighbor;
|
return neighbor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,8 +520,12 @@ namespace solverlib {
|
|||||||
new_dec_a.timeslotGraphSplited = mock->trajectoryStops[new_dec_a.empR].getDispoStop();
|
new_dec_a.timeslotGraphSplited = mock->trajectoryStops[new_dec_a.empR].getDispoStop();
|
||||||
new_dec_a.lastCreneau = {0,0};
|
new_dec_a.lastCreneau = {0,0};
|
||||||
|
|
||||||
unsigned int oldCost = MAXIMUM_TIME_OFFSET*STFMockInstance::jobs[op_a]->getPoidsRetard();
|
// Pénalité ancienne O(1) — séquence sans op_a
|
||||||
|
Penalty oldPen = sol.penaltyPerMachine.count(new_dec_a.empV)
|
||||||
|
? sol.penaltyPerMachine.at(new_dec_a.empV) : Penalty{};
|
||||||
|
|
||||||
unsigned int oldDiagCost = 0;
|
unsigned int oldDiagCost = 0;
|
||||||
|
unsigned int oldCostScheduled = 0;
|
||||||
unsigned int newDiagCost = new_dec_a.rejected ? STFMockInstance::jobs[op_a]->getPoidsRejet() : 0;
|
unsigned int newDiagCost = new_dec_a.rejected ? STFMockInstance::jobs[op_a]->getPoidsRejet() : 0;
|
||||||
std::vector<std::pair<unsigned short, decision>> jobsEmpVA;
|
std::vector<std::pair<unsigned short, decision>> jobsEmpVA;
|
||||||
for(auto& dec : neighbor.decisions)
|
for(auto& dec : neighbor.decisions)
|
||||||
@@ -528,7 +535,7 @@ namespace solverlib {
|
|||||||
if(dec.second.empV == new_dec_a.empV)
|
if(dec.second.empV == new_dec_a.empV)
|
||||||
{
|
{
|
||||||
jobsEmpVA.push_back({dec.first, dec.second});
|
jobsEmpVA.push_back({dec.first, dec.second});
|
||||||
oldCost += dec.second.lastCreneau.first * STFMockInstance::jobs[dec.first]->getPoidsRetard();
|
oldCostScheduled += dec.second.lastCreneau.first * STFMockInstance::jobs[dec.first]->getPoidsRetard();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -550,25 +557,31 @@ namespace solverlib {
|
|||||||
else {
|
else {
|
||||||
seq.insert(seq.begin() + pos, std::make_pair(op_a, new_dec_a));
|
seq.insert(seq.begin() + pos, std::make_pair(op_a, new_dec_a));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int newCost = 0;
|
unsigned int newCost = 0;
|
||||||
auto res = checkSequence(seq, new_dec_a.empV);
|
Penalty penA; bool feasA = true;
|
||||||
if(res)
|
auto res = checkSequence(seq, new_dec_a.empV, penA, feasA);
|
||||||
{
|
|
||||||
unsigned int id = 0;
|
if(!res) return std::nullopt;
|
||||||
for(auto& jobsA : seq)
|
|
||||||
{
|
|
||||||
auto& dec = neighbor.decisions[jobsA.first];
|
|
||||||
dec.lastCreneau = res.value()[id].second.lastCreneau;
|
|
||||||
newCost += dec.lastCreneau.first * STFMockInstance::jobs[jobsA.first]->getPoidsRetard();
|
|
||||||
++id;
|
|
||||||
}
|
|
||||||
neighbor.diagCost = (neighbor.diagCost - oldDiagCost) + newDiagCost;
|
|
||||||
neighbor.cost = (neighbor.cost - oldCost) + newCost;
|
|
||||||
neighbor.source = ESourceTrackPlan::SimAn;
|
|
||||||
return neighbor;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::nullopt;
|
applySequenceResult(neighbor, seq, *res, newCost, penA, feasA);
|
||||||
|
|
||||||
|
double oldFictive = sol.fictiveExcludedCosts.count(op_a)
|
||||||
|
? fictiveCostExcluded(op_a)
|
||||||
|
: MAXIMUM_TIME_OFFSET * STFMockInstance::jobs[op_a]->getPoidsRetard();
|
||||||
|
|
||||||
|
unsigned int oldCostExcluded = MAXIMUM_TIME_OFFSET * STFMockInstance::jobs[op_a]->getPoidsRetard();
|
||||||
|
|
||||||
|
neighbor.penalty = sol.penalty - oldPen + penA;
|
||||||
|
neighbor.penaltyPerMachine[new_dec_a.empV] = penA;
|
||||||
|
neighbor.isFeasible = neighbor.penalty.isFeasible();
|
||||||
|
neighbor.fictiveCost = (neighbor.fictiveCost - oldFictive - oldCostScheduled) + newCost;
|
||||||
|
neighbor.fictiveExcludedCosts.erase(op_a);
|
||||||
|
neighbor.diagCost = (neighbor.diagCost - oldDiagCost) + newDiagCost;
|
||||||
|
neighbor.cost = (neighbor.cost - oldCostExcluded - oldCostScheduled) + newCost;
|
||||||
|
neighbor.source = ESourceTrackPlan::SimAn;
|
||||||
|
|
||||||
|
return neighbor;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<SASolution> SimulatedAnnealing::move_move_WC(const SASolution& sol)
|
std::optional<SASolution> SimulatedAnnealing::move_move_WC(const SASolution& sol)
|
||||||
@@ -619,6 +632,12 @@ namespace solverlib {
|
|||||||
new_dec_a.timeslotGraphSplited = mock->trajectoryStops[new_dec_a.empR].getDispoStop();
|
new_dec_a.timeslotGraphSplited = mock->trajectoryStops[new_dec_a.empR].getDispoStop();
|
||||||
new_dec_a.lastCreneau = {0,0};
|
new_dec_a.lastCreneau = {0,0};
|
||||||
|
|
||||||
|
// Pénalités anciennes O(1) — machine de départ et machine d'arrivée
|
||||||
|
Penalty oldPenSrc = sol.penaltyPerMachine.count(dec_a.empV)
|
||||||
|
? sol.penaltyPerMachine.at(dec_a.empV) : Penalty{};
|
||||||
|
Penalty oldPenDst = sol.penaltyPerMachine.count(new_dec_a.empV)
|
||||||
|
? sol.penaltyPerMachine.at(new_dec_a.empV) : Penalty{};
|
||||||
|
|
||||||
unsigned int oldCost = dec_a.lastCreneau.first*STFMockInstance::jobs[op_a]->getPoidsRetard();
|
unsigned int oldCost = dec_a.lastCreneau.first*STFMockInstance::jobs[op_a]->getPoidsRetard();
|
||||||
unsigned int oldDiagCost = dec_a.rejected ? STFMockInstance::jobs[op_a]->getPoidsRejet() : 0;
|
unsigned int oldDiagCost = dec_a.rejected ? STFMockInstance::jobs[op_a]->getPoidsRejet() : 0;
|
||||||
unsigned int newDiagCost = new_dec_a.rejected ? STFMockInstance::jobs[op_a]->getPoidsRejet() : 0;
|
unsigned int newDiagCost = new_dec_a.rejected ? STFMockInstance::jobs[op_a]->getPoidsRejet() : 0;
|
||||||
@@ -658,17 +677,14 @@ namespace solverlib {
|
|||||||
});
|
});
|
||||||
|
|
||||||
unsigned int newCost = 0;
|
unsigned int newCost = 0;
|
||||||
|
Penalty penA; Penalty penB;
|
||||||
|
bool feasA = true; bool feasB = true;
|
||||||
//décale à gauche sur track de départ
|
//décale à gauche sur track de départ
|
||||||
auto resB = checkSequence(jobsEmpVB, dec_a.empV);
|
if(!jobsEmpVB.empty())
|
||||||
unsigned int id = 0;
|
|
||||||
for(auto& jobsB : jobsEmpVB)
|
|
||||||
{
|
{
|
||||||
auto& dec = neighbor.decisions[jobsB.first];
|
auto resB = checkSequence(jobsEmpVB, dec_a.empV, penB, feasB);
|
||||||
dec.lastCreneau = resB.value()[id].second.lastCreneau;
|
applySequenceResult(neighbor, jobsEmpVB, *resB, newCost, penB, feasB);
|
||||||
newCost+= dec.lastCreneau.first * STFMockInstance::jobs[jobsB.first]->getPoidsRetard();
|
|
||||||
++id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::uniform_int_distribution<unsigned int> distPos(0,jobsEmpVA.size());
|
std::uniform_int_distribution<unsigned int> distPos(0,jobsEmpVA.size());
|
||||||
auto pos = distPos(randomEngine);
|
auto pos = distPos(randomEngine);
|
||||||
@@ -681,24 +697,20 @@ namespace solverlib {
|
|||||||
else {
|
else {
|
||||||
seq.insert(seq.begin() + pos, std::make_pair(op_a, new_dec_a));
|
seq.insert(seq.begin() + pos, std::make_pair(op_a, new_dec_a));
|
||||||
}
|
}
|
||||||
auto res = checkSequence(seq, new_dec_a.empV);
|
auto res = checkSequence(seq, new_dec_a.empV, penA, feasA);
|
||||||
if(res)
|
if(!res) return std::nullopt;
|
||||||
{
|
|
||||||
unsigned int id = 0;
|
applySequenceResult(neighbor, seq, *res, newCost, penA, feasA);
|
||||||
for(auto& jobsA : seq)
|
|
||||||
{
|
|
||||||
auto& dec = neighbor.decisions[jobsA.first];
|
|
||||||
dec.lastCreneau = res.value()[id].second.lastCreneau;
|
|
||||||
newCost+= dec.lastCreneau.first * STFMockInstance::jobs[jobsA.first]->getPoidsRetard();
|
|
||||||
++id;
|
|
||||||
}
|
|
||||||
neighbor.diagCost = (neighbor.diagCost - oldDiagCost) + newDiagCost;
|
|
||||||
neighbor.cost = (neighbor.cost - oldCost) + newCost;
|
|
||||||
neighbor.source = ESourceTrackPlan::SimAn;
|
|
||||||
return neighbor;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::nullopt;
|
neighbor.penalty = sol.penalty - oldPenSrc - oldPenDst + penB + penA;
|
||||||
|
neighbor.penaltyPerMachine[dec_a.empV] = penB;
|
||||||
|
neighbor.penaltyPerMachine[new_dec_a.empV] = penA;
|
||||||
|
neighbor.isFeasible = neighbor.penalty.isFeasible();
|
||||||
|
neighbor.fictiveCost = (neighbor.fictiveCost - oldCost) + newCost;
|
||||||
|
neighbor.diagCost = (neighbor.diagCost - oldDiagCost) + newDiagCost;
|
||||||
|
neighbor.cost = (neighbor.cost - oldCost) + newCost;
|
||||||
|
neighbor.source = ESourceTrackPlan::SimAn;
|
||||||
|
return neighbor;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<SASolution> SimulatedAnnealing::move_remove_WC(const SASolution& sol)
|
std::optional<SASolution> SimulatedAnnealing::move_remove_WC(const SASolution& sol)
|
||||||
@@ -729,9 +741,12 @@ namespace solverlib {
|
|||||||
new_dec_a.timeslotGraphSplited = CreneauHoraire();
|
new_dec_a.timeslotGraphSplited = CreneauHoraire();
|
||||||
new_dec_a.lastCreneau = {0,0};
|
new_dec_a.lastCreneau = {0,0};
|
||||||
|
|
||||||
|
// Pénalité ancienne O(1) — inclut la contribution de op_a
|
||||||
|
Penalty oldPen = sol.penaltyPerMachine.count(dec_a.empV)
|
||||||
|
? sol.penaltyPerMachine.at(dec_a.empV) : Penalty{};
|
||||||
|
|
||||||
unsigned int oldCost = dec_a.lastCreneau.first * STFMockInstance::jobs[op_a]->getPoidsRetard();
|
unsigned int oldCost = dec_a.lastCreneau.first * STFMockInstance::jobs[op_a]->getPoidsRetard();
|
||||||
unsigned int oldDiagCost = dec_a.rejected ? STFMockInstance::jobs[op_a]->getPoidsRejet() : 0;
|
unsigned int oldDiagCost = dec_a.rejected ? STFMockInstance::jobs[op_a]->getPoidsRejet() : 0;
|
||||||
unsigned int newDiagCost = 0;
|
|
||||||
|
|
||||||
std::vector<std::pair<unsigned short, decision>> jobsEmpVA;
|
std::vector<std::pair<unsigned short, decision>> jobsEmpVA;
|
||||||
for(auto& dec : neighbor.decisions)
|
for(auto& dec : neighbor.decisions)
|
||||||
@@ -745,34 +760,33 @@ namespace solverlib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsigned int newCost = MAXIMUM_TIME_OFFSET * STFMockInstance::jobs[op_a]->getPoidsRetard();
|
|
||||||
|
|
||||||
|
unsigned int remaining = 0.0;
|
||||||
|
Penalty penA; bool feasA = true;
|
||||||
if(!jobsEmpVA.empty())
|
if(!jobsEmpVA.empty())
|
||||||
{
|
{
|
||||||
|
|
||||||
std::sort(jobsEmpVA.begin(), jobsEmpVA.end(), [&](auto& el1, auto& el2){
|
std::sort(jobsEmpVA.begin(), jobsEmpVA.end(), [&](auto& el1, auto& el2){
|
||||||
auto cren1 = el1.second.lastCreneau;
|
auto cren1 = el1.second.lastCreneau;
|
||||||
auto cren2 = el2.second.lastCreneau;
|
auto cren2 = el2.second.lastCreneau;
|
||||||
return cren1.first < cren2.first;
|
return cren1.first < cren2.first;
|
||||||
});
|
});
|
||||||
auto resA = checkSequence(jobsEmpVA, dec_a.empV);
|
auto resA = checkSequence(jobsEmpVA, dec_a.empV, penA, feasA);
|
||||||
if(resA)
|
if(!resA) return std::nullopt;
|
||||||
{
|
|
||||||
unsigned int id = 0;
|
applySequenceResult(neighbor, jobsEmpVA, *resA, remaining, penA, feasA);
|
||||||
for(auto& jobsA : jobsEmpVA)
|
|
||||||
{
|
|
||||||
auto& dec = neighbor.decisions[jobsA.first];
|
|
||||||
dec.lastCreneau = resA.value()[id].second.lastCreneau;
|
|
||||||
newCost += dec.lastCreneau.first * STFMockInstance::jobs[jobsA.first]->getPoidsRetard();
|
|
||||||
++id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
}
|
||||||
neighbor.diagCost = (neighbor.diagCost - oldDiagCost) + newDiagCost;
|
|
||||||
neighbor.cost = (neighbor.cost - oldCost) + newCost;
|
double fictivePenalty = fictiveCostExcluded(op_a);
|
||||||
neighbor.source = ESourceTrackPlan::SimAn;
|
unsigned int excludedCost = MAXIMUM_TIME_OFFSET * STFMockInstance::jobs[op_a]->getPoidsRetard();
|
||||||
|
|
||||||
|
neighbor.penalty = sol.penalty - oldPen + penA;
|
||||||
|
neighbor.penaltyPerMachine[dec_a.empV] = penA;
|
||||||
|
neighbor.isFeasible = neighbor.penalty.isFeasible();
|
||||||
|
neighbor.fictiveExcludedCosts[op_a] = fictivePenalty;
|
||||||
|
neighbor.fictiveCost = (neighbor.fictiveCost - oldCost) + fictivePenalty + remaining;
|
||||||
|
neighbor.diagCost = neighbor.diagCost - oldDiagCost;
|
||||||
|
neighbor.cost = (neighbor.cost - oldCost) + excludedCost + remaining;
|
||||||
|
neighbor.source = ESourceTrackPlan::SimAn;
|
||||||
return neighbor;
|
return neighbor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -793,9 +807,9 @@ namespace solverlib {
|
|||||||
SASolution neighbor = sol;
|
SASolution neighbor = sol;
|
||||||
Decision& new_dec_a = neighbor.decisions[op_a];
|
Decision& new_dec_a = neighbor.decisions[op_a];
|
||||||
|
|
||||||
|
|
||||||
unsigned int oldDiagCost = dec_a.rejected ? STFMockInstance::jobs[op_a]->getPoidsRejet() : 0;
|
unsigned int oldDiagCost = dec_a.rejected ? STFMockInstance::jobs[op_a]->getPoidsRejet() : 0;
|
||||||
unsigned int newDiagCost = dec_a.rejected ? 0 : STFMockInstance::jobs[op_a]->getPoidsRejet();
|
unsigned int newDiagCost = dec_a.rejected ? 0 : STFMockInstance::jobs[op_a]->getPoidsRejet();
|
||||||
unsigned int oldCost = 0;
|
|
||||||
if(dec_a.rejected)
|
if(dec_a.rejected)
|
||||||
{
|
{
|
||||||
new_dec_a.rejected = false;
|
new_dec_a.rejected = false;
|
||||||
@@ -810,6 +824,11 @@ namespace solverlib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pénalité ancienne O(1)
|
||||||
|
Penalty oldPen = sol.penaltyPerMachine.count(dec_a.empV)
|
||||||
|
? sol.penaltyPerMachine.at(dec_a.empV) : Penalty{};
|
||||||
|
|
||||||
|
unsigned int oldCost = 0;
|
||||||
std::vector<std::pair<unsigned short, decision>> jobsEmpVA;
|
std::vector<std::pair<unsigned short, decision>> jobsEmpVA;
|
||||||
for(auto& dec : neighbor.decisions)
|
for(auto& dec : neighbor.decisions)
|
||||||
{
|
{
|
||||||
@@ -829,26 +848,20 @@ namespace solverlib {
|
|||||||
return cren1.first < cren2.first;
|
return cren1.first < cren2.first;
|
||||||
});
|
});
|
||||||
unsigned int newCost = 0;
|
unsigned int newCost = 0;
|
||||||
if(!jobsEmpVA.empty())
|
|
||||||
{
|
Penalty penA; bool feasA = true;
|
||||||
auto resA = checkSequence(jobsEmpVA, dec_a.empV);
|
auto resA = checkSequence(jobsEmpVA, dec_a.empV, penA, feasA);
|
||||||
if(resA)
|
if(!resA) return std::nullopt;
|
||||||
{
|
|
||||||
unsigned int id = 0;
|
applySequenceResult(neighbor, jobsEmpVA, *resA, newCost, penA, feasA);
|
||||||
for(auto& jobsA : jobsEmpVA)
|
|
||||||
{
|
neighbor.penalty = sol.penalty - oldPen + penA;
|
||||||
auto& dec = neighbor.decisions[jobsA.first];
|
neighbor.penaltyPerMachine[dec_a.empV] = penA;
|
||||||
dec.lastCreneau = resA.value()[id].second.lastCreneau;
|
neighbor.isFeasible = neighbor.penalty.isFeasible();
|
||||||
newCost += dec.lastCreneau.first * STFMockInstance::jobs[jobsA.first]->getPoidsRetard();
|
neighbor.fictiveCost = (neighbor.fictiveCost - oldCost) + newCost;
|
||||||
++id;
|
neighbor.diagCost = (neighbor.diagCost - oldDiagCost) + newDiagCost;
|
||||||
}
|
neighbor.cost = (neighbor.cost - oldCost) + newCost;
|
||||||
}
|
neighbor.source = ESourceTrackPlan::SimAn;
|
||||||
else
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
neighbor.diagCost = (neighbor.diagCost - oldDiagCost) + newDiagCost;
|
|
||||||
neighbor.cost = (neighbor.cost - oldCost) + newCost;
|
|
||||||
neighbor.source = ESourceTrackPlan::SimAn;
|
|
||||||
return neighbor;
|
return neighbor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -872,53 +885,53 @@ namespace solverlib {
|
|||||||
return std::optional<std::vector<std::pair<unsigned short, Decision>>>(res);
|
return std::optional<std::vector<std::pair<unsigned short, Decision>>>(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::vector<std::pair<unsigned short, Decision>>>
|
||||||
std::pair<bool, std::vector<unsigned int>> SimulatedAnnealing::PSE_Carlier_Rivreau(std::vector<std::pair<unsigned short, decision>> &jobs, unsigned int voieMachine) {
|
SimulatedAnnealing::checkSequence(
|
||||||
|
const std::vector<std::pair<unsigned short, Decision>>& jobsDec,
|
||||||
std::stringstream fakeFile;
|
unsigned int machine,
|
||||||
|
Penalty& outPenalty,
|
||||||
for (unsigned int i = 0; i < jobs.size(); ++i) {
|
bool& outFeasible)
|
||||||
auto match = CreneauHoraire::checkSlotsCompatibility(jobs[i].second.timeslotGraphSplited,
|
|
||||||
STFMockInstance::machines[voieMachine]->getDispo());
|
|
||||||
fakeFile << i + 1;
|
|
||||||
fakeFile << " " << match.second.first;
|
|
||||||
if (!jobs[i].second.rejected) {
|
|
||||||
fakeFile << " " << STFMockInstance::jobs[jobs[i].first]->getDuree();
|
|
||||||
} else
|
|
||||||
fakeFile << " " << STFMockInstance::jobs[jobs[i].first]->getDureeDiag();
|
|
||||||
fakeFile << " " << match.second.first + match.second.second;
|
|
||||||
fakeFile << std::endl;
|
|
||||||
}
|
|
||||||
std::ifstream file;
|
|
||||||
file.basic_ios<char>::rdbuf(fakeFile.rdbuf());
|
|
||||||
Solution sol((int) jobs.size());
|
|
||||||
OneMachine machine(file);
|
|
||||||
machine.solve(sol);
|
|
||||||
|
|
||||||
std::vector<unsigned int> solution(jobs.size());
|
|
||||||
for (unsigned int i = 0; i < jobs.size(); ++i) {
|
|
||||||
solution[i] = sol.startTime[i+1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return {machine.checkSol(sol) && sol.Lmax <= 0, solution};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*unsigned long SimulatedAnnealing::getUniquePlans(std::vector<TrackPlan>& plans)
|
|
||||||
{
|
{
|
||||||
std::set<TrackPlan> uniqueSchedules;
|
auto machineDisp = STFMockInstance::machines[machine]->getDispo();
|
||||||
std::vector<TrackPlan> newTMPVec;
|
unsigned short minBegin = machineDisp.getDebut().getRelativeDate();
|
||||||
for(auto& trackSch : plans)
|
std::vector<std::pair<unsigned short, Decision>> res;
|
||||||
|
outFeasible = true;
|
||||||
|
|
||||||
|
for (auto& jobDec : jobsDec)
|
||||||
{
|
{
|
||||||
uniqueSchedules.insert(trackSch);
|
auto matchWithMachine = CreneauHoraire::checkSlotsCompatibility(
|
||||||
|
jobDec.second.timeslotGraphSplited, machineDisp).second;
|
||||||
|
|
||||||
|
minBegin = std::max(minBegin, matchWithMachine.first);
|
||||||
|
unsigned int duration = !jobDec.second.rejected
|
||||||
|
? STFMockInstance::jobs[jobDec.first]->getDuree()
|
||||||
|
: STFMockInstance::jobs[jobDec.first]->getDureeDiag();
|
||||||
|
|
||||||
|
unsigned int windowEnd = matchWithMachine.first + matchWithMachine.second;
|
||||||
|
unsigned int jobEnd = minBegin + duration;
|
||||||
|
|
||||||
|
if (jobEnd > windowEnd)
|
||||||
|
{
|
||||||
|
if (!authorizeInfeasible)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
// Planification forcée + pénalité
|
||||||
|
outFeasible = false;
|
||||||
|
double overrun = static_cast<double>(jobEnd - windowEnd);
|
||||||
|
outPenalty.add(EPenaltyType::TIME_WINDOW_OVERRUN, overrun);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto newJobDec = jobDec;
|
||||||
|
newJobDec.second.lastCreneau = {minBegin, jobEnd};
|
||||||
|
minBegin = jobEnd;
|
||||||
|
res.push_back(newJobDec);
|
||||||
}
|
}
|
||||||
auto uniqueNb = uniqueSchedules.size();
|
for (size_t i = 1; i < res.size(); ++i) {
|
||||||
std::move(uniqueSchedules.begin(), uniqueSchedules.end(), std::back_inserter(newTMPVec));
|
if (res[i].second.lastCreneau.first < res[i-1].second.lastCreneau.second && res[i].second.lastCreneau.first >= res[i-1].second.lastCreneau.first) {
|
||||||
std::swap(plans, newTMPVec);
|
std::cout << res[i].second.lastCreneau.first << " " << res[i].second.lastCreneau.second << " " << res[i-1].second.lastCreneau.first << " " << res[i-1].second.lastCreneau.second << std::endl;
|
||||||
|
throw std::logic_error("Chevauchement détecté");
|
||||||
return uniqueNb;
|
}
|
||||||
}*/
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -6,16 +6,17 @@
|
|||||||
#include <random>
|
#include <random>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include "Penalty.hpp"
|
||||||
#include "TrackPlan.hpp"
|
#include "TrackPlan.hpp"
|
||||||
#include "Solution.hpp"
|
#include "Solution.hpp"
|
||||||
namespace solverlib {
|
namespace solverlib {
|
||||||
using namespace modellib;
|
using namespace modellib;
|
||||||
|
|
||||||
enum class EMovingOperators{
|
enum class EMovingOperators{
|
||||||
SWAP_WITHOUT_CARLIER,
|
SWAP,
|
||||||
INSERT_WITHOUT_CARLIER,
|
INSERT,
|
||||||
REMOVE_WITHOUT_CARLIER,
|
REMOVE,
|
||||||
CHANGE_MODE_WITHOUT_CARLIER,
|
CHANGE_MODE,
|
||||||
SWAP_WITHIN_INTERVAL,
|
SWAP_WITHIN_INTERVAL,
|
||||||
MOVE,
|
MOVE,
|
||||||
DYN_PROG,
|
DYN_PROG,
|
||||||
@@ -24,13 +25,18 @@ namespace solverlib {
|
|||||||
struct StatSimulatedAnnealing{
|
struct StatSimulatedAnnealing{
|
||||||
struct failInf{
|
struct failInf{
|
||||||
double prob;
|
double prob;
|
||||||
unsigned int diff;
|
long diff;
|
||||||
|
double fictiveDiff;
|
||||||
double temperature;
|
double temperature;
|
||||||
|
bool isfeasible = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<EMovingOperators, unsigned int> nbUsed;
|
std::unordered_map<EMovingOperators, unsigned int> nbUsed;
|
||||||
std::unordered_map<EMovingOperators, unsigned int> nbFeas;
|
std::unordered_map<EMovingOperators, unsigned int> nbFeas;
|
||||||
std::unordered_map<EMovingOperators, unsigned int> nbImproved;
|
std::unordered_map<EMovingOperators, unsigned int> nbImproved;
|
||||||
|
std::unordered_map<EMovingOperators, unsigned int> nbImprovedReal;
|
||||||
|
std::unordered_map<EMovingOperators, unsigned int> nbInfeasible;
|
||||||
|
|
||||||
std::unordered_map<EMovingOperators, std::vector<failInf>> failInfos;
|
std::unordered_map<EMovingOperators, std::vector<failInf>> failInfos;
|
||||||
|
|
||||||
|
|
||||||
@@ -48,10 +54,17 @@ namespace solverlib {
|
|||||||
void addImproved(EMovingOperators op){
|
void addImproved(EMovingOperators op){
|
||||||
if(activate) nbImproved[op]++;
|
if(activate) nbImproved[op]++;
|
||||||
}
|
}
|
||||||
|
void addImprovedReal(EMovingOperators op){
|
||||||
|
if(activate) nbImprovedReal[op]++;
|
||||||
|
}
|
||||||
|
|
||||||
void addFailInfo(EMovingOperators op, double prob, unsigned int diff, double temp)
|
void addInfeasible(EMovingOperators op){
|
||||||
|
if(activate) nbInfeasible[op]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addFailInfo(EMovingOperators op, double prob, long diff, double fictiveDiff, double temp, bool isFeasible)
|
||||||
{
|
{
|
||||||
if(activate) failInfos[op].emplace_back(failInf{prob, diff, temp});
|
if(activate) failInfos[op].emplace_back(failInf{prob, diff, fictiveDiff, temp});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -59,12 +72,47 @@ namespace solverlib {
|
|||||||
private:
|
private:
|
||||||
std::vector<SASolution> solutions;
|
std::vector<SASolution> solutions;
|
||||||
std::mt19937 randomEngine;
|
std::mt19937 randomEngine;
|
||||||
|
double T;
|
||||||
|
double Tmax;
|
||||||
|
double Tmin;
|
||||||
|
double maxCostOfJob;
|
||||||
|
double rate;
|
||||||
|
|
||||||
|
void applySequenceResult(
|
||||||
|
SASolution& neighbor,
|
||||||
|
const std::vector<std::pair<unsigned short, Decision>>& seq,
|
||||||
|
const std::vector<std::pair<unsigned short, Decision>>& resolved,
|
||||||
|
unsigned int& newCost,
|
||||||
|
Penalty penaltyDelta, // pénalité de cette séquence
|
||||||
|
bool feasible)
|
||||||
|
{
|
||||||
|
unsigned int id = 0;
|
||||||
|
for (auto& job : seq)
|
||||||
|
{
|
||||||
|
auto& dec = neighbor.decisions[job.first];
|
||||||
|
dec.lastCreneau = resolved[id].second.lastCreneau;
|
||||||
|
newCost += dec.lastCreneau.first * STFMockInstance::jobs[job.first]->getPoidsRetard();
|
||||||
|
++id;
|
||||||
|
}
|
||||||
|
neighbor.penalty = neighbor.penalty + penaltyDelta;
|
||||||
|
if (!feasible) neighbor.isFeasible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<EPenaltyType, double> penaltyLambdas;
|
||||||
|
|
||||||
|
// Initialisation dans le constructeur ou avant solve()
|
||||||
|
void setPenaltyWeights() {
|
||||||
|
penaltyLambdas[EPenaltyType::TIME_WINDOW_OVERRUN] = 1.0;
|
||||||
|
}
|
||||||
|
std::unordered_map<EPenaltyType, double> effectiveLambdas() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static bool withDynProg;
|
static bool withDynProg;
|
||||||
|
static bool authorizeInfeasible;
|
||||||
StatSimulatedAnnealing stats;
|
StatSimulatedAnnealing stats;
|
||||||
SimulatedAnnealing() = delete;
|
SimulatedAnnealing() = delete;
|
||||||
explicit SimulatedAnnealing(std::unordered_map<unsigned short, Decision>& decs, std::shared_ptr<modellib::STFMockInstance> mock, ESourceTrackPlan source);
|
explicit SimulatedAnnealing(std::unordered_map<unsigned short, Decision>& decs, std::shared_ptr<modellib::STFMockInstance> mock, ESourceTrackPlan source);
|
||||||
EMovingOperators pick_operator(double tmax, double t);
|
EMovingOperators pick_operator();
|
||||||
std::optional<SASolution> apply_operator(const SASolution& current, EMovingOperators op);
|
std::optional<SASolution> apply_operator(const SASolution& current, EMovingOperators op);
|
||||||
SASolution solve(double T_max, double T_min, double cooling_rate, int iterations_per_temp);
|
SASolution solve(double T_max, double T_min, double cooling_rate, int iterations_per_temp);
|
||||||
|
|
||||||
@@ -77,15 +125,17 @@ namespace solverlib {
|
|||||||
std::optional<SASolution> move_dynprog(const SASolution& sol);
|
std::optional<SASolution> move_dynprog(const SASolution& sol);
|
||||||
|
|
||||||
std::optional<std::vector<std::pair<unsigned short, Decision>>> checkSequence(const std::vector<std::pair<unsigned short, Decision>>& jobsDec, unsigned int machine);
|
std::optional<std::vector<std::pair<unsigned short, Decision>>> checkSequence(const std::vector<std::pair<unsigned short, Decision>>& jobsDec, unsigned int machine);
|
||||||
|
std::optional<std::vector<std::pair<unsigned short, Decision>>> checkSequence(const std::vector<std::pair<unsigned short, Decision>>& jobsDec, unsigned int machine, Penalty& outPenalty, bool& outFeasible);
|
||||||
|
|
||||||
double getP(double delta, double temperature, EMovingOperators op);
|
double getP(double delta, EMovingOperators op);
|
||||||
|
double effectiveCost(const SASolution& s) const;
|
||||||
|
|
||||||
|
double progress() const;
|
||||||
|
|
||||||
|
double fictiveCostExcluded(unsigned short op_id) const;
|
||||||
|
|
||||||
std::pair<unsigned int, unsigned int> evaluate(const std::unordered_map<unsigned short, Decision>& decs);
|
std::pair<unsigned int, unsigned int> evaluate(const std::unordered_map<unsigned short, Decision>& decs);
|
||||||
|
|
||||||
std::pair<unsigned int, unsigned int> getCostOfSequence(std::vector<std::pair<unsigned short, decision>>& jobsSeq);
|
|
||||||
|
|
||||||
std::pair<bool, std::vector<unsigned int>> PSE_Carlier_Rivreau(std::vector<std::pair<unsigned short, decision>> &jobs, unsigned int voieMachine);
|
|
||||||
|
|
||||||
void addSolutions(std::vector<SASolution>& solPool){solutions.insert(solutions.end(), solPool.begin(), solPool.end());};
|
void addSolutions(std::vector<SASolution>& solPool){solutions.insert(solutions.end(), solPool.begin(), solPool.end());};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define SOLUTION_HPP
|
#define SOLUTION_HPP
|
||||||
|
|
||||||
#include "../../../General/Model/STFMockInstance.hpp"
|
#include "../../../General/Model/STFMockInstance.hpp"
|
||||||
|
#include "Penalty.hpp"
|
||||||
#include "sourceSolTrPlan.hpp"
|
#include "sourceSolTrPlan.hpp"
|
||||||
|
|
||||||
namespace solverlib {
|
namespace solverlib {
|
||||||
@@ -13,6 +14,11 @@ namespace solverlib {
|
|||||||
std::unordered_map<unsigned short, Decision> decisions;
|
std::unordered_map<unsigned short, Decision> decisions;
|
||||||
unsigned int cost;
|
unsigned int cost;
|
||||||
unsigned int diagCost;
|
unsigned int diagCost;
|
||||||
|
bool isFeasible = true;
|
||||||
|
Penalty penalty;
|
||||||
|
std::unordered_map<unsigned int, Penalty> penaltyPerMachine;
|
||||||
|
double fictiveCost = 0.0;
|
||||||
|
std::unordered_map<unsigned short, double> fictiveExcludedCosts;
|
||||||
}SASolution;
|
}SASolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "SolutionPoolManager.hpp"
|
#include "SolutionPoolManager.hpp"
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace solverlib {
|
namespace solverlib {
|
||||||
std::vector<TrackPlan> SolutionPoolManager::getTrackPlansFromSolution(SASolution& sol, bool withTrash)
|
std::vector<TrackPlan> SolutionPoolManager::getTrackPlansFromSolution(SASolution& sol, bool withTrash)
|
||||||
@@ -10,14 +12,17 @@ namespace solverlib {
|
|||||||
//id plan = id voie
|
//id plan = id voie
|
||||||
std::vector<TrackPlan> plans;
|
std::vector<TrackPlan> plans;
|
||||||
plans.resize(STFMockInstance::tracks.size());
|
plans.resize(STFMockInstance::tracks.size());
|
||||||
|
std::unordered_map<unsigned int, std::vector<std::pair<unsigned short, Decision>>> decisionsOnMachines;
|
||||||
|
std::vector<std::set<unsigned int>> machineIdsFromTrackId(STFMockInstance::tracks.size());
|
||||||
for(auto& dec : sol.decisions)
|
for(auto& dec : sol.decisions)
|
||||||
{
|
{
|
||||||
if(!dec.second.excluded)
|
if(!dec.second.excluded)
|
||||||
{
|
{
|
||||||
plans[dec.second.voie].source = sol.source;
|
|
||||||
plans[dec.second.voie].isTrash = false;
|
plans[dec.second.voie].isTrash = false;
|
||||||
plans[dec.second.voie].track = dec.second.voie;
|
plans[dec.second.voie].track = dec.second.voie;
|
||||||
plans[dec.second.voie].schedule[dec.first] = dec.second;
|
plans[dec.second.voie].schedule[dec.first] = dec.second;
|
||||||
|
decisionsOnMachines[dec.second.empV].push_back({dec.first, dec.second});
|
||||||
|
machineIdsFromTrackId[dec.second.voie].insert(dec.second.empV);
|
||||||
}
|
}
|
||||||
else if(withTrash) {
|
else if(withTrash) {
|
||||||
TrackPlan trashTrack;
|
TrackPlan trashTrack;
|
||||||
@@ -37,10 +42,28 @@ namespace solverlib {
|
|||||||
{
|
{
|
||||||
if(!plan.schedule.empty())
|
if(!plan.schedule.empty())
|
||||||
{
|
{
|
||||||
plan.mock = sol.mock;
|
|
||||||
plan.source = sol.source;
|
bool feasible = true;
|
||||||
plan.evaluate();
|
if(!sol.penalty.isFeasible())
|
||||||
trackPlans.push_back(plan);
|
{
|
||||||
|
for(auto& machine : machineIdsFromTrackId[plan.track])
|
||||||
|
{
|
||||||
|
std::sort(decisionsOnMachines[machine].begin(), decisionsOnMachines[machine].end(), [&](auto& el, auto& el2){
|
||||||
|
return el.second.lastCreneau.first < el2.second.lastCreneau.first;
|
||||||
|
});
|
||||||
|
feasible = checkSequence(decisionsOnMachines[machine], plan.track);
|
||||||
|
if(!feasible)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if(feasible)
|
||||||
|
{
|
||||||
|
plan.mock = sol.mock;
|
||||||
|
plan.source = sol.source;
|
||||||
|
plan.evaluate();
|
||||||
|
trackPlans.push_back(plan);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,11 +79,13 @@ namespace solverlib {
|
|||||||
trackPlans.reserve(STFMockInstance::tracks.size() * pool.size() + 1);
|
trackPlans.reserve(STFMockInstance::tracks.size() * pool.size() + 1);
|
||||||
while(!pool.empty())
|
while(!pool.empty())
|
||||||
{
|
{
|
||||||
auto& sol = pool.back();
|
auto sol = pool.back();
|
||||||
|
|
||||||
//id plan = id voie
|
//id plan = id voie
|
||||||
std::vector<TrackPlan> plans;
|
std::vector<TrackPlan> plans;
|
||||||
plans.resize(STFMockInstance::tracks.size());
|
plans.resize(STFMockInstance::tracks.size());
|
||||||
|
std::unordered_map<unsigned int, std::vector<std::pair<unsigned short, Decision>>> decisionsOnMachines;
|
||||||
|
std::vector<std::set<unsigned int>> machineIdsFromTrackId(STFMockInstance::tracks.size());
|
||||||
for(auto& dec : sol.decisions)
|
for(auto& dec : sol.decisions)
|
||||||
{
|
{
|
||||||
if(!dec.second.excluded)
|
if(!dec.second.excluded)
|
||||||
@@ -68,22 +93,46 @@ namespace solverlib {
|
|||||||
plans[dec.second.voie].isTrash = false;
|
plans[dec.second.voie].isTrash = false;
|
||||||
plans[dec.second.voie].track = dec.second.voie;
|
plans[dec.second.voie].track = dec.second.voie;
|
||||||
plans[dec.second.voie].schedule[dec.first] = dec.second;
|
plans[dec.second.voie].schedule[dec.first] = dec.second;
|
||||||
|
decisionsOnMachines[dec.second.empV].push_back({dec.first, dec.second});
|
||||||
|
machineIdsFromTrackId[dec.second.voie].insert(dec.second.empV);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(auto& plan : plans)
|
for(auto& plan : plans)
|
||||||
{
|
{
|
||||||
if(!plan.schedule.empty())
|
if(!plan.schedule.empty())
|
||||||
{
|
{
|
||||||
plan.mock = sol.mock;
|
bool feasible = true;
|
||||||
plan.source = sol.source;
|
if(!sol.penalty.isFeasible())
|
||||||
plan.evaluate();
|
|
||||||
auto inserted = uniqueSchedules.insert(plan);
|
|
||||||
if(!inserted.second)
|
|
||||||
{
|
{
|
||||||
|
for(auto& machine : machineIdsFromTrackId[plan.track])
|
||||||
|
{
|
||||||
|
std::sort(decisionsOnMachines[machine].begin(), decisionsOnMachines[machine].end(), [&](auto& el, auto& el2){
|
||||||
|
return el.second.lastCreneau.first < el2.second.lastCreneau.first;
|
||||||
|
});
|
||||||
|
feasible = checkSequence(decisionsOnMachines[machine], plan.track);
|
||||||
|
if(!feasible)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if(feasible)
|
||||||
|
{
|
||||||
|
plan.mock = sol.mock;
|
||||||
|
plan.source = sol.source;
|
||||||
|
plan.evaluate();
|
||||||
|
auto inserted = uniqueSchedules.insert(plan);
|
||||||
|
if(!inserted.second)
|
||||||
|
{
|
||||||
|
countD++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
countD++;
|
countD++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pool.pop_back();
|
pool.pop_back();
|
||||||
}
|
}
|
||||||
std::move(uniqueSchedules.begin(), uniqueSchedules.end(), std::back_inserter(trackPlans));
|
std::move(uniqueSchedules.begin(), uniqueSchedules.end(), std::back_inserter(trackPlans));
|
||||||
@@ -104,12 +153,31 @@ namespace solverlib {
|
|||||||
|
|
||||||
auto nbplan = trackPlans.size();
|
auto nbplan = trackPlans.size();
|
||||||
|
|
||||||
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Removed " + std::to_string(countD) + " non-unique track schedules");
|
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Removed " + std::to_string(countD) + " non-unique or non-feasible track schedules");
|
||||||
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Total track plans " + std::to_string(nbplan));
|
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Total track plans " + std::to_string(nbplan));
|
||||||
|
|
||||||
return trackPlans;
|
return trackPlans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SolutionPoolManager::checkSequence(const std::vector<std::pair<unsigned short, Decision>>& jobsDec, unsigned int machine)
|
||||||
|
{
|
||||||
|
auto machineDisp = STFMockInstance::machines[machine]->getDispo();
|
||||||
|
unsigned short minBegin = machineDisp.getDebut().getRelativeDate();
|
||||||
|
std::vector<std::pair<unsigned short, Decision>> res;
|
||||||
|
for(auto& jobDec : jobsDec)
|
||||||
|
{
|
||||||
|
auto matchWithMachine = CreneauHoraire::checkSlotsCompatibility(jobDec.second.timeslotGraphSplited, machineDisp).second;
|
||||||
|
minBegin = std::max(minBegin, matchWithMachine.first);
|
||||||
|
auto newJobDec = jobDec;
|
||||||
|
unsigned int duration = !jobDec.second.rejected ? STFMockInstance::jobs[jobDec.first]->getDuree() : STFMockInstance::jobs[jobDec.first]->getDureeDiag();
|
||||||
|
newJobDec.second.lastCreneau = {minBegin, minBegin + duration};
|
||||||
|
if(minBegin + duration > matchWithMachine.first + matchWithMachine.second)
|
||||||
|
return false;
|
||||||
|
minBegin = minBegin + duration;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void SolutionPoolManager::provide(std::vector<SASolution>&& solutions)
|
void SolutionPoolManager::provide(std::vector<SASolution>&& solutions)
|
||||||
{
|
{
|
||||||
std::move(solutions.begin(), solutions.end(), std::back_inserter(pool));
|
std::move(solutions.begin(), solutions.end(), std::back_inserter(pool));
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ namespace solverlib {
|
|||||||
|
|
||||||
std::vector<TrackPlan> getTrackPlansFromSolution(SASolution& sol, bool withTrash = false);
|
std::vector<TrackPlan> getTrackPlansFromSolution(SASolution& sol, bool withTrash = false);
|
||||||
|
|
||||||
|
bool checkSequence(const std::vector<std::pair<unsigned short, Decision>>& jobsDec, unsigned int machine);
|
||||||
|
|
||||||
const std::vector<SASolution>& getSolutions() const {return pool;};
|
const std::vector<SASolution>& getSolutions() const {return pool;};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -853,14 +853,14 @@ namespace solverlib {
|
|||||||
std::ostringstream csv;
|
std::ostringstream csv;
|
||||||
|
|
||||||
// En-têtes
|
// En-têtes
|
||||||
csv << "category;operator;index;probability;objectiveDiff;temperature \n";
|
csv << "category;operator;index;probability;objectiveDiff;costDiff;temperature;isFeasible\n";
|
||||||
|
|
||||||
// worseProb (map de vector)
|
// worseProb (map de vector)
|
||||||
for(auto& [key, val] : simAnn.stats.failInfos)
|
for(auto& [key, val] : simAnn.stats.failInfos)
|
||||||
{
|
{
|
||||||
for(size_t i = 0; i < val.size(); ++i)
|
for(size_t i = 0; i < val.size(); ++i)
|
||||||
{
|
{
|
||||||
csv << ";" << simAnn.stats.names[key] << ";" << i << ";" << val[i].prob << ";" << val[i].diff << ";" << val[i].temperature << "\n";
|
csv << ";" << simAnn.stats.names[key] << ";" << i << ";" << val[i].prob << ";" << val[i].diff << ";" << val[i].fictiveDiff << ";" << val[i].temperature << ";" << val[i].isfeasible << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -869,11 +869,16 @@ namespace solverlib {
|
|||||||
for(auto& [map, label] : std::vector<std::pair<std::unordered_map<EMovingOperators, unsigned int>, std::string>>{
|
for(auto& [map, label] : std::vector<std::pair<std::unordered_map<EMovingOperators, unsigned int>, std::string>>{
|
||||||
{simAnn.stats.nbUsed, "used"},
|
{simAnn.stats.nbUsed, "used"},
|
||||||
{simAnn.stats.nbFeas, "feas"},
|
{simAnn.stats.nbFeas, "feas"},
|
||||||
{simAnn.stats.nbImproved, "improved"}})
|
{simAnn.stats.nbImproved, "improved"},
|
||||||
|
{simAnn.stats.nbImprovedReal, "improvedRealCost"},
|
||||||
|
{simAnn.stats.nbInfeasible, "withPenalty"}
|
||||||
|
|
||||||
|
})
|
||||||
{
|
{
|
||||||
for(auto& [key, val] : map)
|
for(auto& [key, val] : map)
|
||||||
{
|
{
|
||||||
if(label == "used") nbIte += val;
|
if(label == "used") nbIte += val;
|
||||||
|
|
||||||
csv << label << ";" << simAnn.stats.names[key] << ";" << ";" << val << "\n";
|
csv << label << ";" << simAnn.stats.names[key] << ";" << ";" << val << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -939,7 +944,7 @@ namespace solverlib {
|
|||||||
std::vector<PipelineConfig> pipelines = {
|
std::vector<PipelineConfig> pipelines = {
|
||||||
|
|
||||||
//{{ALGO::LH, ALGO::DYNPROG }, false, false},
|
//{{ALGO::LH, ALGO::DYNPROG }, false, false},
|
||||||
{{ALGO::LH, ALGO::SIMANN}, false, false},
|
{{ALGO::LH, ALGO::SIMANN, ALGO::ILP}, false, false, 7},
|
||||||
|
|
||||||
/*{{ALGO::LH, ALGO::SIMANN, ALGO::ILP}, false, false},
|
/*{{ALGO::LH, ALGO::SIMANN, ALGO::ILP}, false, false},
|
||||||
{{ALGO::LH, ALGO::SIMANN, ALGO::ILP}, false, false, 1},
|
{{ALGO::LH, ALGO::SIMANN, ALGO::ILP}, false, false, 1},
|
||||||
@@ -994,7 +999,10 @@ namespace solverlib {
|
|||||||
if(i > 0)
|
if(i > 0)
|
||||||
{
|
{
|
||||||
std::uniform_int_distribution<unsigned int> distSol(0, poolManager.getSolutions().size()-1);
|
std::uniform_int_distribution<unsigned int> distSol(0, poolManager.getSolutions().size()-1);
|
||||||
sol = poolManager.getSolutions()[distSol(rng)];
|
do{
|
||||||
|
sol = poolManager.getSolutions()[distSol(rng)];
|
||||||
|
|
||||||
|
}while(!sol.penalty.isFeasible());
|
||||||
}
|
}
|
||||||
auto res = runSimAnn(sol, poolManager, false);
|
auto res = runSimAnn(sol, poolManager, false);
|
||||||
result.stepsRes.push_back(res);
|
result.stepsRes.push_back(res);
|
||||||
@@ -1049,6 +1057,11 @@ namespace solverlib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SASolution sol = result.best.sol;
|
||||||
|
SolutionPoolManager sp;
|
||||||
|
sp.provide({sol});
|
||||||
|
auto res = runILP(sol, sp);
|
||||||
|
|
||||||
double timeFinal = 0.0;
|
double timeFinal = 0.0;
|
||||||
nlohmann::json arrStep = nlohmann::json::array();
|
nlohmann::json arrStep = nlohmann::json::array();
|
||||||
for(auto& stepFinished : result.stepsRes)
|
for(auto& stepFinished : result.stepsRes)
|
||||||
|
|||||||
Reference in New Issue
Block a user