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:
tom
2026-06-04 21:59:36 +02:00
parent 4fc8a7be89
commit 3c94d56120
10 changed files with 515 additions and 356 deletions
+3 -1
View File
@@ -1,2 +1,4 @@
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/"
}
]
}
}
-17
View File
@@ -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 "../PseCarlierRivreau/omp.h"
#include "DynamicProgramming.hpp"
#include "Penalty.hpp"
#include "Solution.hpp"
#include "TrackPlan.hpp"
#include <algorithm>
@@ -10,24 +11,28 @@
#include <iterator>
#include <optional>
#include <random>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
#include "Random.hpp"
#include "sourceSolTrPlan.hpp"
namespace solverlib {
using namespace random;
bool StatSimulatedAnnealing::activate = true;
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 = {
{EMovingOperators::CHANGE_MODE_WITHOUT_CARLIER, "CHANGE_MODE"},
{EMovingOperators::INSERT_WITHOUT_CARLIER, "INSERT"},
{EMovingOperators::REMOVE_WITHOUT_CARLIER, "REMOVE"},
{EMovingOperators::SWAP_WITHOUT_CARLIER, "SWAP"},
{EMovingOperators::CHANGE_MODE, "CHANGE_MODE"},
{EMovingOperators::INSERT, "INSERT"},
{EMovingOperators::REMOVE, "REMOVE"},
{EMovingOperators::SWAP, "SWAP"},
{EMovingOperators::SWAP_WITHIN_INTERVAL, "SWAP_WITHIN_SEQUENCE"},
{EMovingOperators::DYN_PROG, "DYN_PROG"},
{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)
{
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);
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)
@@ -73,58 +82,24 @@ namespace solverlib {
return {cost, diagCost};
}
std::pair<unsigned int, unsigned int> SimulatedAnnealing::getCostOfSequence(std::vector<std::pair<unsigned short, decision>>& jobsSeq)
{
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);
EMovingOperators SimulatedAnnealing::pick_operator() {
double p = progress();
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 = {
1.0f,
1.0f,
1.0f,
1.0f,
1.0f,
1.0f
1,
w_insert,
w_remove,
1,
1,
1
// 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>(
//std::uniform_int_distribution<int>(0, N)(randomEngine)
std::discrete_distribution<int>(weights.begin(), weights.end())(randomEngine)
std::discrete_distribution<int>(base_weights.begin(), base_weights.end())(randomEngine)
);
}
@@ -133,10 +108,10 @@ namespace solverlib {
{
switch (op)
{
case EMovingOperators::SWAP_WITHOUT_CARLIER: return move_swap_WC(current);
case EMovingOperators::INSERT_WITHOUT_CARLIER: return move_insert_WC(current);
case EMovingOperators::REMOVE_WITHOUT_CARLIER: return move_remove_WC(current);
case EMovingOperators::CHANGE_MODE_WITHOUT_CARLIER: return move_change_mode_WC(current);
case EMovingOperators::SWAP: return move_swap_WC(current);
case EMovingOperators::INSERT: return move_insert_WC(current);
case EMovingOperators::REMOVE: return move_remove_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::MOVE: return move_move_WC(current);
case EMovingOperators::DYN_PROG: return move_dynprog(current);
@@ -150,16 +125,22 @@ namespace solverlib {
{
SASolution current = solutions[0];
SASolution best = solutions[0];
current.fictiveCost = current.cost;
best.fictiveCost = current.cost;
Tmax = T_max;
double cost_cur = current.cost;
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);
while (T > T_min + 10e-6)
while (T > Tmin + 10e-6)
{
for (int i = 0; i < iterations_per_temp; ++i)
{
EMovingOperators op = pick_operator(T, T_max);
EMovingOperators op = pick_operator();
stats.addUsed(op);
auto neighbor = apply_operator(current, op);
@@ -167,23 +148,33 @@ namespace solverlib {
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)
stats.addImproved(op);
if(diff <= 0 && neighbor->penalty.isFeasible())
stats.addImprovedReal(op);
if(!neighbor->penalty.isFeasible())
stats.addInfeasible(op);
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);
cost_cur = costs_neighbor.first;
if (cost_cur < cost_best) {
if (current.penalty.isFeasible() && cost_cur < cost_best) {
best = current;
cost_best = cost_cur;
}
@@ -201,22 +192,43 @@ namespace solverlib {
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) {
case EMovingOperators::SWAP_WITHOUT_CARLIER:
case EMovingOperators::INSERT_WITHOUT_CARLIER:
case EMovingOperators::REMOVE_WITHOUT_CARLIER: return std::exp(-delta/(temperature*100));
case EMovingOperators::CHANGE_MODE_WITHOUT_CARLIER:
case EMovingOperators::SWAP:
case EMovingOperators::INSERT: return std::exp(-delta/(T*50));
case EMovingOperators::REMOVE: return std::exp(-delta/(T*50));
case EMovingOperators::CHANGE_MODE:
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:
break;
}
return std::exp(-delta/temperature);
return std::exp(-delta/T);
}
//OPERATEURS
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);
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);
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 posJobInt = job;
seqCop[posJobInt] = *posA;
seqCop[IposA] = seq_swap[job];
auto res = lbdBuildSeq(seqCop);
if(res != std::nullopt)
return res;
std::swap(seqCop[IposA], seqCop[posB]);
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)
@@ -397,6 +402,12 @@ namespace solverlib {
auto oldCrenA = dec_a.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>> jobsEmpVB;
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;
});
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;
if(resA && resB)
{
unsigned int id = 0;
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;
}
id = 0;
for(auto& jobsB : jobsEmpVB)
{
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;
if(!resA || !resB) return std::nullopt;
applySequenceResult(neighbor, jobsEmpVA, *resA, newCost, penA, feasA);
applySequenceResult(neighbor, jobsEmpVB, *resB, newCost, penB, feasB);
neighbor.penalty = sol.penalty - oldPenA - oldPenB + penA + penB;
neighbor.penaltyPerMachine[new_dec_a.empV] = penA;
neighbor.penaltyPerMachine[new_dec_b.empV] = penB;
neighbor.isFeasible = neighbor.penalty.isFeasible();
neighbor.fictiveCost = (neighbor.fictiveCost - oldCost) + newCost;
neighbor.cost = (neighbor.cost - oldCost) + newCost;
neighbor.source = ESourceTrackPlan::SimAn;
return neighbor;
}
@@ -517,8 +520,12 @@ namespace solverlib {
new_dec_a.timeslotGraphSplited = mock->trajectoryStops[new_dec_a.empR].getDispoStop();
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 oldCostScheduled = 0;
unsigned int newDiagCost = new_dec_a.rejected ? STFMockInstance::jobs[op_a]->getPoidsRejet() : 0;
std::vector<std::pair<unsigned short, decision>> jobsEmpVA;
for(auto& dec : neighbor.decisions)
@@ -528,7 +535,7 @@ namespace solverlib {
if(dec.second.empV == new_dec_a.empV)
{
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 {
seq.insert(seq.begin() + pos, std::make_pair(op_a, new_dec_a));
}
unsigned int newCost = 0;
auto res = checkSequence(seq, new_dec_a.empV);
if(res)
{
unsigned int id = 0;
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;
}
Penalty penA; bool feasA = true;
auto res = checkSequence(seq, new_dec_a.empV, penA, feasA);
if(!res) return std::nullopt;
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)
@@ -619,6 +632,12 @@ namespace solverlib {
new_dec_a.timeslotGraphSplited = mock->trajectoryStops[new_dec_a.empR].getDispoStop();
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 oldDiagCost = 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;
Penalty penA; Penalty penB;
bool feasA = true; bool feasB = true;
//décale à gauche sur track de départ
auto resB = checkSequence(jobsEmpVB, dec_a.empV);
unsigned int id = 0;
for(auto& jobsB : jobsEmpVB)
if(!jobsEmpVB.empty())
{
auto& dec = neighbor.decisions[jobsB.first];
dec.lastCreneau = resB.value()[id].second.lastCreneau;
newCost+= dec.lastCreneau.first * STFMockInstance::jobs[jobsB.first]->getPoidsRetard();
++id;
auto resB = checkSequence(jobsEmpVB, dec_a.empV, penB, feasB);
applySequenceResult(neighbor, jobsEmpVB, *resB, newCost, penB, feasB);
}
std::uniform_int_distribution<unsigned int> distPos(0,jobsEmpVA.size());
auto pos = distPos(randomEngine);
@@ -681,24 +697,20 @@ namespace solverlib {
else {
seq.insert(seq.begin() + pos, std::make_pair(op_a, new_dec_a));
}
auto res = checkSequence(seq, new_dec_a.empV);
if(res)
{
unsigned int id = 0;
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;
}
auto res = checkSequence(seq, new_dec_a.empV, penA, feasA);
if(!res) return std::nullopt;
applySequenceResult(neighbor, seq, *res, newCost, penA, feasA);
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)
@@ -729,9 +741,12 @@ namespace solverlib {
new_dec_a.timeslotGraphSplited = CreneauHoraire();
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 oldDiagCost = dec_a.rejected ? STFMockInstance::jobs[op_a]->getPoidsRejet() : 0;
unsigned int newDiagCost = 0;
std::vector<std::pair<unsigned short, decision>> jobsEmpVA;
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())
{
std::sort(jobsEmpVA.begin(), jobsEmpVA.end(), [&](auto& el1, auto& el2){
auto cren1 = el1.second.lastCreneau;
auto cren2 = el2.second.lastCreneau;
return cren1.first < cren2.first;
});
auto resA = checkSequence(jobsEmpVA, dec_a.empV);
if(resA)
{
unsigned int id = 0;
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;
auto resA = checkSequence(jobsEmpVA, dec_a.empV, penA, feasA);
if(!resA) return std::nullopt;
applySequenceResult(neighbor, jobsEmpVA, *resA, remaining, penA, feasA);
}
neighbor.diagCost = (neighbor.diagCost - oldDiagCost) + newDiagCost;
neighbor.cost = (neighbor.cost - oldCost) + newCost;
neighbor.source = ESourceTrackPlan::SimAn;
double fictivePenalty = fictiveCostExcluded(op_a);
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;
}
@@ -793,9 +807,9 @@ namespace solverlib {
SASolution neighbor = sol;
Decision& new_dec_a = neighbor.decisions[op_a];
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 oldCost = 0;
if(dec_a.rejected)
{
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;
for(auto& dec : neighbor.decisions)
{
@@ -829,26 +848,20 @@ namespace solverlib {
return cren1.first < cren2.first;
});
unsigned int newCost = 0;
if(!jobsEmpVA.empty())
{
auto resA = checkSequence(jobsEmpVA, dec_a.empV);
if(resA)
{
unsigned int id = 0;
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;
neighbor.source = ESourceTrackPlan::SimAn;
Penalty penA; bool feasA = true;
auto resA = checkSequence(jobsEmpVA, dec_a.empV, penA, feasA);
if(!resA) return std::nullopt;
applySequenceResult(neighbor, jobsEmpVA, *resA, newCost, penA, feasA);
neighbor.penalty = sol.penalty - oldPen + penA;
neighbor.penaltyPerMachine[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;
}
@@ -872,53 +885,53 @@ namespace solverlib {
return std::optional<std::vector<std::pair<unsigned short, Decision>>>(res);
}
std::pair<bool, std::vector<unsigned int>> SimulatedAnnealing::PSE_Carlier_Rivreau(std::vector<std::pair<unsigned short, decision>> &jobs, unsigned int voieMachine) {
std::stringstream fakeFile;
for (unsigned int i = 0; i < jobs.size(); ++i) {
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::optional<std::vector<std::pair<unsigned short, Decision>>>
SimulatedAnnealing::checkSequence(
const std::vector<std::pair<unsigned short, Decision>>& jobsDec,
unsigned int machine,
Penalty& outPenalty,
bool& outFeasible)
{
std::set<TrackPlan> uniqueSchedules;
std::vector<TrackPlan> newTMPVec;
for(auto& trackSch : plans)
auto machineDisp = STFMockInstance::machines[machine]->getDispo();
unsigned short minBegin = machineDisp.getDebut().getRelativeDate();
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();
std::move(uniqueSchedules.begin(), uniqueSchedules.end(), std::back_inserter(newTMPVec));
std::swap(plans, newTMPVec);
return uniqueNb;
}*/
for (size_t i = 1; i < res.size(); ++i) {
if (res[i].second.lastCreneau.first < res[i-1].second.lastCreneau.second && res[i].second.lastCreneau.first >= res[i-1].second.lastCreneau.first) {
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 res;
}
}
@@ -6,16 +6,17 @@
#include <random>
#include <unordered_map>
#include <vector>
#include "Penalty.hpp"
#include "TrackPlan.hpp"
#include "Solution.hpp"
namespace solverlib {
using namespace modellib;
enum class EMovingOperators{
SWAP_WITHOUT_CARLIER,
INSERT_WITHOUT_CARLIER,
REMOVE_WITHOUT_CARLIER,
CHANGE_MODE_WITHOUT_CARLIER,
SWAP,
INSERT,
REMOVE,
CHANGE_MODE,
SWAP_WITHIN_INTERVAL,
MOVE,
DYN_PROG,
@@ -24,13 +25,18 @@ namespace solverlib {
struct StatSimulatedAnnealing{
struct failInf{
double prob;
unsigned int diff;
long diff;
double fictiveDiff;
double temperature;
bool isfeasible = true;
};
std::unordered_map<EMovingOperators, unsigned int> nbUsed;
std::unordered_map<EMovingOperators, unsigned int> nbFeas;
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;
@@ -48,10 +54,17 @@ namespace solverlib {
void addImproved(EMovingOperators 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:
std::vector<SASolution> solutions;
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:
static bool withDynProg;
static bool authorizeInfeasible;
StatSimulatedAnnealing stats;
SimulatedAnnealing() = delete;
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);
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<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> 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());};
@@ -2,6 +2,7 @@
#define SOLUTION_HPP
#include "../../../General/Model/STFMockInstance.hpp"
#include "Penalty.hpp"
#include "sourceSolTrPlan.hpp"
namespace solverlib {
@@ -13,6 +14,11 @@ namespace solverlib {
std::unordered_map<unsigned short, Decision> decisions;
unsigned int cost;
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;
}
@@ -1,5 +1,7 @@
#include "SolutionPoolManager.hpp"
#include <iterator>
#include <unordered_map>
#include <vector>
namespace solverlib {
std::vector<TrackPlan> SolutionPoolManager::getTrackPlansFromSolution(SASolution& sol, bool withTrash)
@@ -10,14 +12,17 @@ namespace solverlib {
//id plan = id voie
std::vector<TrackPlan> plans;
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)
{
if(!dec.second.excluded)
{
plans[dec.second.voie].source = sol.source;
plans[dec.second.voie].isTrash = false;
plans[dec.second.voie].track = dec.second.voie;
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) {
TrackPlan trashTrack;
@@ -37,10 +42,28 @@ namespace solverlib {
{
if(!plan.schedule.empty())
{
plan.mock = sol.mock;
plan.source = sol.source;
plan.evaluate();
trackPlans.push_back(plan);
bool feasible = true;
if(!sol.penalty.isFeasible())
{
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);
while(!pool.empty())
{
auto& sol = pool.back();
auto sol = pool.back();
//id plan = id voie
std::vector<TrackPlan> plans;
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)
{
if(!dec.second.excluded)
@@ -68,22 +93,46 @@ namespace solverlib {
plans[dec.second.voie].isTrash = false;
plans[dec.second.voie].track = dec.second.voie;
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)
{
if(!plan.schedule.empty())
{
plan.mock = sol.mock;
plan.source = sol.source;
plan.evaluate();
auto inserted = uniqueSchedules.insert(plan);
if(!inserted.second)
bool feasible = true;
if(!sol.penalty.isFeasible())
{
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++;
}
}
}
pool.pop_back();
}
std::move(uniqueSchedules.begin(), uniqueSchedules.end(), std::back_inserter(trackPlans));
@@ -104,12 +153,31 @@ namespace solverlib {
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));
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)
{
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);
bool checkSequence(const std::vector<std::pair<unsigned short, Decision>>& jobsDec, unsigned int machine);
const std::vector<SASolution>& getSolutions() const {return pool;};
};
+18 -5
View File
@@ -853,14 +853,14 @@ namespace solverlib {
std::ostringstream csv;
// 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)
for(auto& [key, val] : simAnn.stats.failInfos)
{
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>>{
{simAnn.stats.nbUsed, "used"},
{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)
{
if(label == "used") nbIte += val;
csv << label << ";" << simAnn.stats.names[key] << ";" << ";" << val << "\n";
}
}
@@ -939,7 +944,7 @@ namespace solverlib {
std::vector<PipelineConfig> pipelines = {
//{{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, 1},
@@ -994,7 +999,10 @@ namespace solverlib {
if(i > 0)
{
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);
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;
nlohmann::json arrStep = nlohmann::json::array();
for(auto& stepFinished : result.stepsRes)