Modifs de SimAnn pour multistart
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
#include "STFMockInstance.hpp"
|
#include "STFMockInstance.hpp"
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
namespace modellib {
|
namespace modellib {
|
||||||
@@ -242,4 +243,38 @@ namespace modellib {
|
|||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::optional<Decision>> Planification::getVectorOfDecicions()
|
||||||
|
{
|
||||||
|
std::vector<std::optional<Decision>> vec(STFMockInstance::jobs.size(), std::nullopt);
|
||||||
|
|
||||||
|
for(auto& opPlan : this->getOperationsPlan())
|
||||||
|
{
|
||||||
|
vec[opPlan.getOperationRequise()] = {
|
||||||
|
opPlan.getRentree(),
|
||||||
|
state->trajectoryStops[opPlan.getRentree()].getDispoStop(),
|
||||||
|
opPlan.getTrackInterval(),
|
||||||
|
opPlan.getRejete(),
|
||||||
|
false,
|
||||||
|
opPlan.getVoie(),
|
||||||
|
opPlan.getSite(),
|
||||||
|
opPlan.getCreneau()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto& opPlan : this->getOpImplanifiables())
|
||||||
|
{
|
||||||
|
vec[opPlan] = {
|
||||||
|
0,
|
||||||
|
CreneauHoraire(),
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
{0,0}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "CroisementUM.hpp"
|
#include "CroisementUM.hpp"
|
||||||
#include "PlanificationStats.hpp"
|
#include "PlanificationStats.hpp"
|
||||||
#include "RecompoUM.h"
|
#include "RecompoUM.h"
|
||||||
|
#include <optional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
namespace modellib {
|
namespace modellib {
|
||||||
@@ -118,6 +119,7 @@ class STFMockInstance;
|
|||||||
nlohmann::json to_json();
|
nlohmann::json to_json();
|
||||||
|
|
||||||
std::unordered_map<unsigned short, Decision> getMapOfDecisions();
|
std::unordered_map<unsigned short, Decision> getMapOfDecisions();
|
||||||
|
std::vector<std::optional<Decision>> getVectorOfDecicions();
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace solverlib {
|
|||||||
auto tryInsert = [&](unsigned int insertedJob, unsigned int removedJob) -> std::optional<EdgeSolution>
|
auto tryInsert = [&](unsigned int insertedJob, unsigned int removedJob) -> std::optional<EdgeSolution>
|
||||||
{
|
{
|
||||||
|
|
||||||
if(solutionPool[0].decisions.find(insertedJob) == solutionPool[0].decisions.end() || solutionPool[0].decisions.find(removedJob) == solutionPool[0].decisions.end())
|
if(solutionPool[0].decisions[insertedJob] == std::nullopt || solutionPool[0].decisions[removedJob] == std::nullopt)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|
||||||
if(insertedJob >= solutionPool[0].mock->jobDispoVoiesRames.size() || removedJob >= solutionPool[0].mock->jobDispoVoiesRames.size())
|
if(insertedJob >= solutionPool[0].mock->jobDispoVoiesRames.size() || removedJob >= solutionPool[0].mock->jobDispoVoiesRames.size())
|
||||||
@@ -40,20 +40,20 @@ namespace solverlib {
|
|||||||
[&](auto& el) -> bool
|
[&](auto& el) -> bool
|
||||||
{
|
{
|
||||||
DispVoieRame& disp = solutionPool[0].mock->dispoVoiesRames[el];
|
DispVoieRame& disp = solutionPool[0].mock->dispoVoiesRames[el];
|
||||||
if(disp.dispoVoie != decRemoved.empV)
|
if(disp.dispoVoie != (*decRemoved).empV)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto TrStop = solutionPool[0].mock->trajectoryStops[disp.dispoRame].getDispoStop();
|
auto TrStop = solutionPool[0].mock->trajectoryStops[disp.dispoRame].getDispoStop();
|
||||||
auto match = CreneauHoraire::checkSlotsCompatibility(
|
auto match = CreneauHoraire::checkSlotsCompatibility(
|
||||||
TrStop,
|
TrStop,
|
||||||
STFMockInstance::machines[decRemoved.empV]->getDispo());
|
STFMockInstance::machines[(*decRemoved).empV]->getDispo());
|
||||||
if(!match.first)
|
if(!match.first)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
CreneauHoraire crenInserted(SolverDate::getDateDebut() + disp.match.first,
|
CreneauHoraire crenInserted(SolverDate::getDateDebut() + disp.match.first,
|
||||||
SolverDate::getDateDebut() + disp.match.second);
|
SolverDate::getDateDebut() + disp.match.second);
|
||||||
CreneauHoraire crenRemoved (SolverDate::getDateDebut() + decRemoved.lastCreneau.first,
|
CreneauHoraire crenRemoved (SolverDate::getDateDebut() + (*decRemoved).lastCreneau.first,
|
||||||
SolverDate::getDateDebut() + decRemoved.lastCreneau.second);
|
SolverDate::getDateDebut() + (*decRemoved).lastCreneau.second);
|
||||||
|
|
||||||
if(!CreneauHoraire::checkSlotsCompatibility(crenInserted, crenRemoved).first)
|
if(!CreneauHoraire::checkSlotsCompatibility(crenInserted, crenRemoved).first)
|
||||||
return false;
|
return false;
|
||||||
@@ -71,70 +71,74 @@ namespace solverlib {
|
|||||||
std::vector<std::pair<unsigned short, Decision>> schedule;
|
std::vector<std::pair<unsigned short, Decision>> schedule;
|
||||||
long oldCost = 0;
|
long oldCost = 0;
|
||||||
auto disp = solutionPool[0].mock->dispoVoiesRames[*dispFound];
|
auto disp = solutionPool[0].mock->dispoVoiesRames[*dispFound];
|
||||||
std::unordered_map<unsigned short, Decision> oldDec;
|
std::vector<std::optional<Decision>> oldDec;
|
||||||
|
|
||||||
for(auto& [id, dec] : solutionPool[0].decisions)
|
unsigned int op_id = 0;
|
||||||
|
for(auto& dec : solutionPool[0].decisions)
|
||||||
{
|
{
|
||||||
if(dec.excluded) continue;
|
if((*dec).excluded) continue;
|
||||||
if(dec.empV != decRemoved.empV) continue;
|
if((*dec).empV != (*decRemoved).empV) continue;
|
||||||
|
|
||||||
oldCost += STFMockInstance::jobs[id]->getPoidsRetard() * dec.lastCreneau.first;
|
oldCost += STFMockInstance::jobs[op_id]->getPoidsRetard() * (*dec).lastCreneau.first;
|
||||||
oldDec[id] = dec;
|
oldDec[op_id] = dec;
|
||||||
if(id == removedJob)
|
if(op_id == removedJob)
|
||||||
{
|
{
|
||||||
// Remplacer removedJob par insertedJob avec le même créneau
|
// Remplacer removedJob par insertedJob avec le même créneau
|
||||||
Decision decInsertedCopy = decInserted;
|
Decision decInsertedCopy = (*decInserted);
|
||||||
decInsertedCopy.lastCreneau = decRemoved.lastCreneau;
|
decInsertedCopy.lastCreneau = (*decRemoved).lastCreneau;
|
||||||
decInsertedCopy.empV = decRemoved.empV;
|
decInsertedCopy.empV = (*decRemoved).empV;
|
||||||
decInsertedCopy.empR = disp.dispoRame;
|
decInsertedCopy.empR = disp.dispoRame;
|
||||||
decInsertedCopy.voie = decRemoved.voie;
|
decInsertedCopy.voie = (*decRemoved).voie;
|
||||||
decInsertedCopy.site = decRemoved.site;
|
decInsertedCopy.site = (*decRemoved).site;
|
||||||
decInsertedCopy.timeslotGraphSplited = solutionPool[0].mock->trajectoryStops[disp.dispoRame].getDispoStop();
|
decInsertedCopy.timeslotGraphSplited = solutionPool[0].mock->trajectoryStops[disp.dispoRame].getDispoStop();
|
||||||
|
|
||||||
schedule.emplace_back(insertedJob, decInsertedCopy);
|
schedule.emplace_back(insertedJob, decInsertedCopy);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
schedule.emplace_back(id, dec);
|
schedule.emplace_back(op_id, *dec);
|
||||||
}
|
}
|
||||||
|
++op_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(schedule.begin(), schedule.end(), [](auto& a, auto& b){
|
std::sort(schedule.begin(), schedule.end(), [](auto& a, auto& b){
|
||||||
return a.second.lastCreneau.first < b.second.lastCreneau.first;
|
return a.second.lastCreneau.first < b.second.lastCreneau.first;
|
||||||
});
|
});
|
||||||
|
|
||||||
unsigned short lastEnd = STFMockInstance::machines[decRemoved.empV]
|
unsigned short lastEnd = STFMockInstance::machines[(*decRemoved).empV]
|
||||||
->getDispo().getDebut().getRelativeDate();
|
->getDispo().getDebut().getRelativeDate();
|
||||||
long newCost = 0;
|
long newCost = 0;
|
||||||
std::unordered_map<unsigned short, Decision> newSchedule;
|
std::vector<std::optional<Decision>> newSchedule;
|
||||||
for(auto& [id, dec] : schedule)
|
op_id = 0;
|
||||||
|
for(auto& dec : schedule)
|
||||||
{
|
{
|
||||||
auto TrStop = solutionPool[0].mock->trajectoryStops[dec.empR].getDispoStop();
|
auto TrStop = solutionPool[0].mock->trajectoryStops[dec.second.empR].getDispoStop();
|
||||||
auto match = CreneauHoraire::checkSlotsCompatibility(
|
auto match = CreneauHoraire::checkSlotsCompatibility(
|
||||||
TrStop,
|
TrStop,
|
||||||
STFMockInstance::machines[dec.empV]->getDispo()).second;
|
STFMockInstance::machines[dec.second.empV]->getDispo()).second;
|
||||||
auto duration = !dec.rejected * STFMockInstance::jobs[id]->getDuree()
|
auto duration = !dec.second.rejected * STFMockInstance::jobs[op_id]->getDuree()
|
||||||
+ dec.rejected * STFMockInstance::jobs[id]->getDureeDiag();
|
+ dec.second.rejected * STFMockInstance::jobs[op_id]->getDureeDiag();
|
||||||
|
|
||||||
newSchedule[id] = dec;
|
newSchedule[op_id] = dec.second;
|
||||||
newSchedule[id].lastCreneau.first = std::max(lastEnd, match.first);
|
(*newSchedule[op_id]).lastCreneau.first = std::max(lastEnd, match.first);
|
||||||
|
|
||||||
lastEnd = newSchedule[id].lastCreneau.first + duration;
|
lastEnd = (*newSchedule[op_id]).lastCreneau.first + duration;
|
||||||
|
|
||||||
newSchedule[id].lastCreneau.second = lastEnd;
|
(*newSchedule[op_id]).lastCreneau.second = lastEnd;
|
||||||
if(lastEnd > match.first + match.second)
|
if(lastEnd > match.first + match.second)
|
||||||
return std::nullopt; // jobs poussés à droite non faisables
|
return std::nullopt; // jobs poussés à droite non faisables
|
||||||
|
|
||||||
std::string ma = "insertedJob=" + std::to_string(insertedJob) + " removedJob=" + std::to_string(removedJob) + " Match[" + std::to_string(match.first) + " " + std::to_string(match.first + match.second) + "]";
|
std::string ma = "insertedJob=" + std::to_string(insertedJob) + " removedJob=" + std::to_string(removedJob) + " Match[" + std::to_string(match.first) + " " + std::to_string(match.first + match.second) + "]";
|
||||||
std::string fi = " - Final[" + std::to_string(newSchedule[id].lastCreneau.first) + " " + std::to_string(newSchedule[id].lastCreneau.second)+ "]";
|
std::string fi = " - Final[" + std::to_string((*newSchedule[op_id]).lastCreneau.first) + " " + std::to_string((*newSchedule[op_id]).lastCreneau.second)+ "]";
|
||||||
|
|
||||||
loggerlib::Logger::systemNotify(loggerlib::LOGGER_DEBUG, ma + fi);
|
loggerlib::Logger::systemNotify(loggerlib::LOGGER_DEBUG, ma + fi);
|
||||||
|
|
||||||
newCost += STFMockInstance::jobs[id]->getPoidsRetard()
|
newCost += STFMockInstance::jobs[op_id]->getPoidsRetard()
|
||||||
* std::max(lastEnd, match.first);
|
* std::max(lastEnd, match.first);
|
||||||
|
++op_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EdgeSolution{static_cast<long>(((oldCost + decInserted.lastCreneau.first * STFMockInstance::jobs[insertedJob]->getPoidsRetard()) - newCost)), newSchedule, oldDec};
|
return EdgeSolution{static_cast<long>(((oldCost + (*decInserted).lastCreneau.first * STFMockInstance::jobs[insertedJob]->getPoidsRetard()) - newCost)), newSchedule, oldDec};
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
};
|
};
|
||||||
@@ -151,7 +155,7 @@ namespace solverlib {
|
|||||||
auto& decJob = solutionPool[0].decisions[job];
|
auto& decJob = solutionPool[0].decisions[job];
|
||||||
auto& decOtherJob = solutionPool[0].decisions[other_job];
|
auto& decOtherJob = solutionPool[0].decisions[other_job];
|
||||||
|
|
||||||
if(decJob.excluded || decOtherJob.excluded || decJob.empV == decOtherJob.empV)
|
if((*decJob).excluded || (*decOtherJob).excluded || (*decJob).empV == (*decOtherJob).empV)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Arc job → other_job : insérer job à la place de other_job
|
// Arc job → other_job : insérer job à la place de other_job
|
||||||
@@ -179,23 +183,25 @@ namespace solverlib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<unsigned int, unsigned int> DynamicProgramming::evaluate(const std::unordered_map<unsigned short, Decision>& decs)
|
std::pair<unsigned int, unsigned int> DynamicProgramming::evaluate(const std::vector<std::optional<Decision>>& decs)
|
||||||
{
|
{
|
||||||
unsigned int cost = 0;
|
unsigned int cost = 0;
|
||||||
unsigned int diagCost = 0;
|
unsigned int diagCost = 0;
|
||||||
|
unsigned int id = 0;
|
||||||
for(auto& dec : decs)
|
for(auto& dec : decs)
|
||||||
{
|
{
|
||||||
if(dec.second.excluded)
|
if((*dec).excluded)
|
||||||
{
|
{
|
||||||
cost += MAXIMUM_TIME_OFFSET * modellib::STFMockInstance::jobs[dec.first]->getPoidsRetard();
|
cost += MAXIMUM_TIME_OFFSET * modellib::STFMockInstance::jobs[id]->getPoidsRetard();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
cost += modellib::STFMockInstance::jobs[dec.first]->getPoidsRetard() * dec.second.lastCreneau.first;
|
cost += modellib::STFMockInstance::jobs[id]->getPoidsRetard() * (*dec).lastCreneau.first;
|
||||||
|
|
||||||
if(dec.second.rejected)
|
if((*dec).rejected)
|
||||||
{
|
{
|
||||||
diagCost += modellib::STFMockInstance::jobs[dec.first]->getPoidsRejet();
|
diagCost += modellib::STFMockInstance::jobs[id]->getPoidsRejet();
|
||||||
}
|
}
|
||||||
|
++id;
|
||||||
}
|
}
|
||||||
return {cost, diagCost};
|
return {cost, diagCost};
|
||||||
}
|
}
|
||||||
@@ -236,26 +242,27 @@ namespace solverlib {
|
|||||||
|
|
||||||
auto& decInserted = solution.decisions[insertedJob];
|
auto& decInserted = solution.decisions[insertedJob];
|
||||||
auto& decRemoved = solution.decisions[removedJob];
|
auto& decRemoved = solution.decisions[removedJob];
|
||||||
|
unsigned int id = 0;
|
||||||
for(auto& [id, dec] : solution.decisions)
|
for(auto& dec : solution.decisions)
|
||||||
{
|
{
|
||||||
if(dec.excluded || dec.empV != decRemoved.empV) continue;
|
if((*dec).excluded || (*dec).empV != (*decRemoved).empV) continue;
|
||||||
if(id == removedJob)
|
if(id == removedJob)
|
||||||
{
|
{
|
||||||
Decision decInsertedCopy = decInserted;
|
Decision decInsertedCopy = *decInserted;
|
||||||
decInsertedCopy.lastCreneau = decRemoved.lastCreneau;
|
decInsertedCopy.lastCreneau = (*decRemoved).lastCreneau;
|
||||||
decInsertedCopy.empV = decRemoved.empV;
|
decInsertedCopy.empV = (*decRemoved).empV;
|
||||||
decInsertedCopy.empR = edgesData[index].updatedDecisions[insertedJob].empR;
|
decInsertedCopy.empR = (*edgesData[index].updatedDecisions[insertedJob]).empR;
|
||||||
decInsertedCopy.voie = decRemoved.voie;
|
decInsertedCopy.voie = (*decRemoved).voie;
|
||||||
decInsertedCopy.site = decRemoved.site;
|
decInsertedCopy.site = (*decRemoved).site;
|
||||||
decInsertedCopy.timeslotGraphSplited = solution.mock->trajectoryStops[decInsertedCopy.empR].getDispoStop();
|
decInsertedCopy.timeslotGraphSplited = solution.mock->trajectoryStops[decInsertedCopy.empR].getDispoStop();
|
||||||
|
|
||||||
newlyCreatedDecisionsFromCycle[decRemoved.empV].insert(std::make_pair(insertedJob, decInsertedCopy));
|
newlyCreatedDecisionsFromCycle[(*decRemoved).empV].insert(std::make_pair(insertedJob, decInsertedCopy));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newlyCreatedDecisionsFromCycle[decRemoved.empV].insert(std::make_pair(id, dec));
|
newlyCreatedDecisionsFromCycle[(*decRemoved).empV].insert(std::make_pair(id, *dec));
|
||||||
}
|
}
|
||||||
|
++id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,7 +303,7 @@ namespace solverlib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mettre à jour la solution courante immédiatement
|
// Mettre à jour la solution courante immédiatement
|
||||||
solution.decisions.insert_or_assign(id, dec);
|
solution.decisions[id] = dec;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!stepFeasible)
|
if(!stepFeasible)
|
||||||
@@ -355,24 +362,25 @@ namespace solverlib {
|
|||||||
auto& decInserted = solution.decisions[insertedJob];
|
auto& decInserted = solution.decisions[insertedJob];
|
||||||
auto& decRemoved = solution.decisions[removedJob];
|
auto& decRemoved = solution.decisions[removedJob];
|
||||||
|
|
||||||
for(auto& [id, dec] : solution.decisions)
|
unsigned int id = 0;
|
||||||
|
for(auto& dec : solution.decisions)
|
||||||
{
|
{
|
||||||
if(dec.excluded || dec.empV != decRemoved.empV) continue;
|
if((*dec).excluded || (*dec).empV != (*decRemoved).empV) continue;
|
||||||
if(id == removedJob)
|
if(id == removedJob)
|
||||||
{
|
{
|
||||||
Decision decInsertedCopy = decInserted;
|
Decision decInsertedCopy = *decInserted;
|
||||||
decInsertedCopy.lastCreneau = decRemoved.lastCreneau;
|
decInsertedCopy.lastCreneau = (*decRemoved).lastCreneau;
|
||||||
decInsertedCopy.empV = decRemoved.empV;
|
decInsertedCopy.empV = (*decRemoved).empV;
|
||||||
decInsertedCopy.empR = edgesData[index].updatedDecisions[insertedJob].empR;
|
decInsertedCopy.empR = (*edgesData[index].updatedDecisions[insertedJob]).empR;
|
||||||
decInsertedCopy.voie = decRemoved.voie;
|
decInsertedCopy.voie = (*decRemoved).voie;
|
||||||
decInsertedCopy.site = decRemoved.site;
|
decInsertedCopy.site = (*decRemoved).site;
|
||||||
decInsertedCopy.timeslotGraphSplited = solution.mock->trajectoryStops[decInsertedCopy.empR].getDispoStop();
|
decInsertedCopy.timeslotGraphSplited = solution.mock->trajectoryStops[decInsertedCopy.empR].getDispoStop();
|
||||||
|
|
||||||
newlyCreatedDecisionsFromCycle[decRemoved.empV].insert(std::make_pair(insertedJob, decInsertedCopy));
|
newlyCreatedDecisionsFromCycle[(*decRemoved).empV].insert(std::make_pair(insertedJob, decInsertedCopy));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newlyCreatedDecisionsFromCycle[decRemoved.empV].insert(std::make_pair(id, dec));
|
newlyCreatedDecisionsFromCycle[(*decRemoved).empV].insert(std::make_pair(id, *dec));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -414,7 +422,7 @@ namespace solverlib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mettre à jour la solution courante immédiatement
|
// Mettre à jour la solution courante immédiatement
|
||||||
solution.decisions.insert_or_assign(id, dec);
|
solution.decisions[id] = dec;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!stepFeasible)
|
if(!stepFeasible)
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
#define DYNAMICPROGRAMMING_HPP
|
#define DYNAMICPROGRAMMING_HPP
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <optional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "Random.hpp"
|
#include "Random.hpp"
|
||||||
#include "Solution.hpp"
|
#include "Solution.hpp"
|
||||||
@@ -16,8 +18,8 @@ namespace solverlib {
|
|||||||
private:
|
private:
|
||||||
struct EdgeSolution {
|
struct EdgeSolution {
|
||||||
long gain;
|
long gain;
|
||||||
std::unordered_map<unsigned short, Decision> updatedDecisions;
|
std::vector<std::optional<Decision>> updatedDecisions = std::vector<std::optional<Decision>>(STFMockInstance::jobs.size(), std::nullopt);
|
||||||
std::unordered_map<unsigned short, Decision> oldDecisions;
|
std::vector<std::optional<Decision>> oldDecisions = std::vector<std::optional<Decision>>(STFMockInstance::jobs.size(), std::nullopt);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<SASolution> solutionPool;
|
std::vector<SASolution> solutionPool;
|
||||||
@@ -37,7 +39,7 @@ namespace solverlib {
|
|||||||
void buildGraph();
|
void buildGraph();
|
||||||
long recursion(unsigned int startingNode, unsigned int node, unsigned int cycleLength, std::vector<bool>& states, std::vector<std::pair<simple_edge_descriptor,unsigned int>>& currentPath, std::vector<std::vector<std::pair<simple_edge_descriptor,unsigned int>>>& allPaths);
|
long recursion(unsigned int startingNode, unsigned int node, unsigned int cycleLength, std::vector<bool>& states, std::vector<std::pair<simple_edge_descriptor,unsigned int>>& currentPath, std::vector<std::vector<std::pair<simple_edge_descriptor,unsigned int>>>& allPaths);
|
||||||
SASolution solve();
|
SASolution solve();
|
||||||
std::pair<unsigned int, unsigned int> evaluate(const std::unordered_map<unsigned short, Decision>& decs);
|
std::pair<unsigned int, unsigned int> evaluate(const std::vector<std::optional<Decision>>& decs);
|
||||||
|
|
||||||
|
|
||||||
std::vector<SASolution>&& getSolutionPool(){return std::move(solutionPool);};
|
std::vector<SASolution>&& getSolutionPool(){return std::move(solutionPool);};
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace solverlib {
|
|||||||
m_env.start();
|
m_env.start();
|
||||||
m_model = std::make_unique<GRBModel>(m_env);
|
m_model = std::make_unique<GRBModel>(m_env);
|
||||||
m_model->set(GRB_DoubleParam_TuneTimeLimit, 3600);
|
m_model->set(GRB_DoubleParam_TuneTimeLimit, 3600);
|
||||||
m_model->set(GRB_DoubleParam_TimeLimit, 600);
|
m_model->set(GRB_DoubleParam_TimeLimit, 1800);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
MIPFocus 2
|
MIPFocus 2
|
||||||
@@ -228,7 +228,8 @@ namespace solverlib {
|
|||||||
{
|
{
|
||||||
m_model->optimize();
|
m_model->optimize();
|
||||||
//printSol();
|
//printSol();
|
||||||
return buildSolution();
|
auto plan = buildSolution();
|
||||||
|
return plan;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Planification> ILPTrackPlans::buildSolution()
|
std::optional<Planification> ILPTrackPlans::buildSolution()
|
||||||
@@ -392,7 +393,7 @@ namespace solverlib {
|
|||||||
void ILPTrackPlans::warmStart(std::vector<TrackPlan>& plans)
|
void ILPTrackPlans::warmStart(std::vector<TrackPlan>& plans)
|
||||||
{
|
{
|
||||||
std::vector<unsigned int> varToSet;
|
std::vector<unsigned int> varToSet;
|
||||||
|
std::set<unsigned short> jobs;
|
||||||
for(auto& plan : plans)
|
for(auto& plan : plans)
|
||||||
{
|
{
|
||||||
if(plan.isTrash)
|
if(plan.isTrash)
|
||||||
@@ -403,6 +404,7 @@ namespace solverlib {
|
|||||||
if(find != trackPlans.end())
|
if(find != trackPlans.end())
|
||||||
{
|
{
|
||||||
varToSet.push_back(std::distance(trackPlans.begin(), find));
|
varToSet.push_back(std::distance(trackPlans.begin(), find));
|
||||||
|
jobs.insert(plan.schedule.begin()->first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -412,9 +414,73 @@ namespace solverlib {
|
|||||||
if(find != trackPlans.end())
|
if(find != trackPlans.end())
|
||||||
{
|
{
|
||||||
varToSet.push_back(std::distance(trackPlans.begin(), find));
|
varToSet.push_back(std::distance(trackPlans.begin(), find));
|
||||||
|
for(auto& sche: plan.schedule)
|
||||||
|
{
|
||||||
|
jobs.insert(sche.first );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// DEBUG : pourquoi aucun match exact n'a été trouvé pour ce plan
|
||||||
|
std::cout << "[warmStart][MISS] track=" << plan.track
|
||||||
|
<< " cost=" << plan.cost << " diagCost=" << plan.diagCost
|
||||||
|
<< " nbJobs=" << plan.schedule.size() << std::endl;
|
||||||
|
|
||||||
|
// 1) Y a-t-il au moins une colonne sur la meme track ?
|
||||||
|
bool sameTrackFound = false;
|
||||||
|
for(auto& p : trackPlans)
|
||||||
|
{
|
||||||
|
if(!p.isTrash && p.track == plan.track)
|
||||||
|
{
|
||||||
|
sameTrackFound = true;
|
||||||
|
std::cout << " candidate same track: cost=" << p.cost
|
||||||
|
<< " diagCost=" << p.diagCost
|
||||||
|
<< " nbJobs=" << p.schedule.size() << std::endl;
|
||||||
|
|
||||||
|
if(p.schedule.size() != plan.schedule.size())
|
||||||
|
{
|
||||||
|
std::cout << " -> mismatch nbJobs" << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(p.cost != plan.cost)
|
||||||
|
std::cout << " -> mismatch cost (" << p.cost << " vs " << plan.cost << ")" << std::endl;
|
||||||
|
if(p.diagCost != plan.diagCost)
|
||||||
|
std::cout << " -> mismatch diagCost (" << p.diagCost << " vs " << plan.diagCost << ")" << std::endl;
|
||||||
|
|
||||||
|
// 2) Comparer job par job
|
||||||
|
for(auto& [jobId, dec] : plan.schedule)
|
||||||
|
{
|
||||||
|
auto it = p.schedule.find(jobId);
|
||||||
|
if(it == p.schedule.end())
|
||||||
|
{
|
||||||
|
std::cout << " -> job " << jobId << " ABSENT de la colonne candidate" << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const Decision& d2 = it->second;
|
||||||
|
if(!(dec == d2))
|
||||||
|
{
|
||||||
|
std::cout << " -> job " << jobId << " decision differente: "
|
||||||
|
<< "empR(" << dec.empR << "/" << d2.empR << ") "
|
||||||
|
<< "empV(" << dec.empV << "/" << d2.empV << ") "
|
||||||
|
<< "voie(" << (int)dec.voie << "/" << (int)d2.voie << ") "
|
||||||
|
<< "site(" << (int)dec.site << "/" << (int)d2.site << ") "
|
||||||
|
<< "rejected(" << dec.rejected << "/" << d2.rejected << ") "
|
||||||
|
<< "excluded(" << dec.excluded << "/" << d2.excluded << ") "
|
||||||
|
<< "lastCreneau(" << dec.lastCreneau.first << "-" << dec.lastCreneau.second
|
||||||
|
<< " / " << d2.lastCreneau.first << "-" << d2.lastCreneau.second << ")"
|
||||||
|
<< std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if(!sameTrackFound)
|
||||||
|
std::cout << " -> AUCUNE colonne du pool ILP n'existe pour la track " << plan.track << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*if(jobs.size() == STFMockInstance::jobs.size())
|
||||||
|
std::cout << "C OK" << std::endl;
|
||||||
|
else
|
||||||
|
std::cout << "C PAS OK" << std::endl;*/
|
||||||
|
|
||||||
|
|
||||||
for(auto& var : x_ks)
|
for(auto& var : x_ks)
|
||||||
|
|||||||
@@ -1,40 +1,43 @@
|
|||||||
#ifndef PENALTY_HPP
|
#ifndef PENALTY_HPP
|
||||||
#define PENALTY_HPP
|
#define PENALTY_HPP
|
||||||
#include <unordered_map>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
namespace solverlib {
|
namespace solverlib {
|
||||||
|
|
||||||
enum class EPenaltyType {
|
enum class EPenaltyType : int {
|
||||||
TIME_WINDOW_OVERRUN, // job dépasse sa fenêtre
|
TIME_WINDOW_OVERRUN, // job dépasse sa fenêtre
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using ArrayLambda = std::array<double, (int)((int)EPenaltyType::TIME_WINDOW_OVERRUN+1)>;
|
||||||
struct Penalty {
|
struct Penalty {
|
||||||
std::unordered_map<EPenaltyType, double> components;
|
|
||||||
|
ArrayLambda components = {0.0};
|
||||||
|
|
||||||
void add(EPenaltyType type, double value) {
|
void add(EPenaltyType type, double value) {
|
||||||
components[type] += value;
|
components[(int)type] += value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void subtract(EPenaltyType type, double value) {
|
void subtract(EPenaltyType type, double value) {
|
||||||
components[type] = std::max(0.0, components[type] - value);
|
components[(int)type] = std::max(0.0, components[(int)type] - value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Coût agrégé pondéré — les lambdas sont injectés depuis l'extérieur
|
// 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 weighted(const ArrayLambda& lambdas) const {
|
||||||
double total = 0.0;
|
double total = 0.0;
|
||||||
for (auto& [type, val] : components)
|
unsigned int type = 0;
|
||||||
|
for (auto& val : components)
|
||||||
{
|
{
|
||||||
auto it = lambdas.find(type);
|
auto it = lambdas[type];
|
||||||
if (it != lambdas.end())
|
total += it * val;
|
||||||
total += it->second * val;
|
type++;
|
||||||
}
|
}
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
double total() const {
|
double total() const {
|
||||||
double sum = 0.0;
|
double sum = 0.0;
|
||||||
for (auto& [_, v] : components) sum += v;
|
for (auto& v : components) sum += v;
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,15 +45,23 @@ namespace solverlib {
|
|||||||
|
|
||||||
Penalty operator+(const Penalty& o) const {
|
Penalty operator+(const Penalty& o) const {
|
||||||
Penalty res = *this;
|
Penalty res = *this;
|
||||||
for (auto& [type, val] : o.components)
|
unsigned int type= 0;
|
||||||
|
for (auto& val : o.components)
|
||||||
|
{
|
||||||
res.components[type] += val;
|
res.components[type] += val;
|
||||||
|
type++;
|
||||||
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
Penalty operator-(const Penalty& o) const {
|
Penalty operator-(const Penalty& o) const {
|
||||||
Penalty res = *this;
|
Penalty res = *this;
|
||||||
for (auto& [type, val] : o.components)
|
unsigned int type = 0;
|
||||||
|
for (auto& val : o.components)
|
||||||
|
{
|
||||||
res.components[type] = std::max(0.0, res.components[type] - val);
|
res.components[type] = std::max(0.0, res.components[type] - val);
|
||||||
|
type++;
|
||||||
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
namespace solverlib {
|
namespace solverlib {
|
||||||
using namespace random;
|
using namespace random;
|
||||||
|
|
||||||
bool StatSimulatedAnnealing::activate = true;
|
bool StatSimulatedAnnealing::activate = false;
|
||||||
bool SimulatedAnnealing::withDynProg = false;
|
bool SimulatedAnnealing::withDynProg = false;
|
||||||
bool SimulatedAnnealing::authorizeInfeasible = true;
|
bool SimulatedAnnealing::authorizeInfeasible = true;
|
||||||
|
|
||||||
@@ -39,7 +39,17 @@ 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();
|
||||||
|
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{};
|
||||||
|
}*/
|
||||||
|
|
||||||
|
SimulatedAnnealing::SimulatedAnnealing(std::vector<std::optional<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();
|
maxCostOfJob = (*std::max_element(STFMockInstance::jobs.begin(), STFMockInstance::jobs.end(), [&](auto op1, auto op2){return op1->getPoidsRetard() < op2->getPoidsRetard();}))->getPoidsRetard();
|
||||||
@@ -49,7 +59,19 @@ namespace solverlib {
|
|||||||
solutions[0].penaltyPerMachine[i] = Penalty{};
|
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)
|
||||||
|
{
|
||||||
|
auto costs = evaluate(decs);
|
||||||
|
if(!isPutFirst)
|
||||||
|
solutions.push_back({source, mock, decs, costs.first, costs.second});
|
||||||
|
else
|
||||||
|
{
|
||||||
|
solutions.insert(solutions.begin(), {source, mock, decs, costs.first, costs.second});
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
void SimulatedAnnealing::addSolutionToPool(std::vector<std::optional<Decision>>& decs, std::shared_ptr<modellib::STFMockInstance> mock, ESourceTrackPlan source, bool isPutFirst)
|
||||||
{
|
{
|
||||||
auto costs = evaluate(decs);
|
auto costs = evaluate(decs);
|
||||||
if(!isPutFirst)
|
if(!isPutFirst)
|
||||||
@@ -61,7 +83,7 @@ namespace solverlib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::pair<unsigned int, unsigned int> SimulatedAnnealing::evaluate(const std::unordered_map<unsigned short, Decision>& decs)
|
/*std::pair<unsigned int, unsigned int> SimulatedAnnealing::evaluate(const std::unordered_map<unsigned short, Decision>& decs)
|
||||||
{
|
{
|
||||||
unsigned int cost = 0;
|
unsigned int cost = 0;
|
||||||
unsigned int diagCost = 0;
|
unsigned int diagCost = 0;
|
||||||
@@ -80,6 +102,29 @@ namespace solverlib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {cost, diagCost};
|
return {cost, diagCost};
|
||||||
|
}*/
|
||||||
|
|
||||||
|
std::pair<unsigned int, unsigned int> SimulatedAnnealing::evaluate(const std::vector<std::optional<Decision>>& decs)
|
||||||
|
{
|
||||||
|
unsigned int cost = 0;
|
||||||
|
unsigned int diagCost = 0;
|
||||||
|
unsigned short id = 0;
|
||||||
|
for(auto& dec : decs)
|
||||||
|
{
|
||||||
|
if((*dec).excluded)
|
||||||
|
{
|
||||||
|
cost += MAXIMUM_TIME_OFFSET * modellib::STFMockInstance::jobs[id]->getPoidsRetard();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cost += modellib::STFMockInstance::jobs[id]->getPoidsRetard() * (*dec).lastCreneau.first;
|
||||||
|
|
||||||
|
if((*dec).rejected)
|
||||||
|
{
|
||||||
|
diagCost += modellib::STFMockInstance::jobs[id]->getPoidsRejet();
|
||||||
|
}
|
||||||
|
++id;
|
||||||
|
}
|
||||||
|
return {cost, diagCost};
|
||||||
}
|
}
|
||||||
|
|
||||||
EMovingOperators SimulatedAnnealing::pick_operator() {
|
EMovingOperators SimulatedAnnealing::pick_operator() {
|
||||||
@@ -136,6 +181,9 @@ namespace solverlib {
|
|||||||
rate = cooling_rate;
|
rate = cooling_rate;
|
||||||
std::uniform_real_distribution<double> uniform(0.0, 1.0);
|
std::uniform_real_distribution<double> uniform(0.0, 1.0);
|
||||||
|
|
||||||
|
auto bestPlansBeg = pool.getTrackPlansFromSolution(best, false);
|
||||||
|
for (auto& tp : bestPlansBeg) pool.addTrackPlan(std::move(tp));
|
||||||
|
|
||||||
while (T > Tmin + 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)
|
||||||
@@ -167,7 +215,6 @@ namespace solverlib {
|
|||||||
{
|
{
|
||||||
stats.addFailInfo(op, getP(delta, op), diff, delta, T, neighbor->penalty.isFeasible());
|
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, op))
|
if (delta < 0 || uniform(randomEngine) < getP(delta, op))
|
||||||
{
|
{
|
||||||
@@ -179,7 +226,12 @@ namespace solverlib {
|
|||||||
cost_best = cost_cur;
|
cost_best = cost_cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
solutions.push_back(current);
|
if (current.penalty.isFeasible()) {
|
||||||
|
auto tps = pool.getTrackPlansFromSolution(current, false);
|
||||||
|
for (auto& tp : tps)
|
||||||
|
pool.addTrackPlan(std::move(tp)); // dédup inline
|
||||||
|
}
|
||||||
|
//solutions.push_back(current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,19 +239,70 @@ namespace solverlib {
|
|||||||
//loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Temperature : " + std::to_string(T));
|
//loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Temperature : " + std::to_string(T));
|
||||||
//loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Solution pool : " + std::to_string(solutions.size()));
|
//loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Solution pool : " + std::to_string(solutions.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto bestPlansFin = pool.getTrackPlansFromSolution(best, false);
|
||||||
|
for (auto& tp : bestPlansFin) pool.addTrackPlan(std::move(tp));
|
||||||
//loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Best solution : " + std::to_string(best.cost));
|
//loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Best solution : " + std::to_string(best.cost));
|
||||||
|
|
||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SASolution SimulatedAnnealing::solveMultiStart(
|
||||||
|
double T_max, double T_min, double cooling_rate,
|
||||||
|
int iterations_per_temp, int n_restarts)
|
||||||
|
{
|
||||||
|
SASolution globalBest = solve(T_max, T_min, cooling_rate, iterations_per_temp);
|
||||||
|
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Best solution is " + std::string((globalBest.penalty.isFeasible() ? "feasible" : "not feasible")));
|
||||||
|
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Best solution : " + std::to_string(globalBest.cost));
|
||||||
|
|
||||||
|
for (int r = 0; r < n_restarts; ++r)
|
||||||
|
{
|
||||||
|
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Restart :" + std::to_string(r));
|
||||||
|
|
||||||
|
// Perturbation : repartir du meilleur mais bruité
|
||||||
|
SASolution perturbed = perturbSolution(globalBest);
|
||||||
|
solutions[0] = perturbed;
|
||||||
|
|
||||||
|
// Re-run avec température réduite (exploitation locale)
|
||||||
|
double t_restart = T_max * std::pow(0.5, r % 4); // alterne les températures
|
||||||
|
SASolution localBest = solve(t_restart, T_min, cooling_rate, iterations_per_temp);
|
||||||
|
|
||||||
|
if (localBest.penalty.isFeasible() && localBest.cost < globalBest.cost)
|
||||||
|
globalBest = localBest;
|
||||||
|
|
||||||
|
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Best solution restart is " + std::string((localBest.penalty.isFeasible() ? "feasible" : "not feasible")));
|
||||||
|
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Best solution restart : " + std::to_string(localBest.cost));
|
||||||
|
}
|
||||||
|
|
||||||
|
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Best solution restart : " + std::to_string(globalBest.cost));
|
||||||
|
|
||||||
|
return globalBest;
|
||||||
|
}
|
||||||
|
|
||||||
|
SASolution SimulatedAnnealing::perturbSolution(const SASolution& sol) {
|
||||||
|
SASolution perturbed = sol;
|
||||||
|
// Forcer N opérateurs aléatoires pour s'éloigner du bassin d'attraction
|
||||||
|
int n_kicks = 3 + randomEngine() % 5;
|
||||||
|
for (int k = 0; k < n_kicks; ++k) {
|
||||||
|
auto op = pick_operator();
|
||||||
|
auto neighbor = apply_operator(perturbed, op);
|
||||||
|
if (neighbor.has_value())
|
||||||
|
perturbed = std::move(*neighbor);
|
||||||
|
}
|
||||||
|
return perturbed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
double SimulatedAnnealing::effectiveCost(const SASolution& s) const {
|
double SimulatedAnnealing::effectiveCost(const SASolution& s) const {
|
||||||
return s.fictiveCost + s.penalty.weighted(effectiveLambdas());
|
return s.fictiveCost + s.penalty.weighted(effectiveLambdas());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<EPenaltyType, double> SimulatedAnnealing::effectiveLambdas() const {
|
ArrayLambda SimulatedAnnealing::effectiveLambdas() const {
|
||||||
double p = progress();
|
double p = progress();
|
||||||
return {
|
return {
|
||||||
{EPenaltyType::TIME_WINDOW_OVERRUN, std::exp(8*(p-0.2))-0.8},
|
{std::exp(18*(p-0.3))},//(int)EPenaltyType::TIME_WINDOW_OVERRUN,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +329,7 @@ namespace solverlib {
|
|||||||
case EMovingOperators::DYN_PROG:
|
case EMovingOperators::DYN_PROG:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return std::exp(-delta/T);
|
return std::exp(-delta/(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
//OPERATEURS
|
//OPERATEURS
|
||||||
@@ -246,19 +349,24 @@ namespace solverlib {
|
|||||||
if (!mock) return std::nullopt;
|
if (!mock) return std::nullopt;
|
||||||
|
|
||||||
std::vector<unsigned short> active_ops;
|
std::vector<unsigned short> active_ops;
|
||||||
for (auto& [op_id, dec] : sol.decisions)
|
unsigned int id = 0;
|
||||||
if (!dec.excluded) active_ops.push_back(op_id);
|
for (auto& dec : sol.decisions)
|
||||||
|
{
|
||||||
|
if (!(*dec).excluded)
|
||||||
|
active_ops.push_back(id);
|
||||||
|
++id;
|
||||||
|
}
|
||||||
if (active_ops.size() < 2) return std::nullopt;
|
if (active_ops.size() < 2) return std::nullopt;
|
||||||
|
|
||||||
std::uniform_int_distribution<int> dist(0, (int)active_ops.size() - 1);
|
std::uniform_int_distribution<int> dist(0, (int)active_ops.size() - 1);
|
||||||
unsigned short op_a = active_ops[dist(randomEngine)];
|
unsigned short op_a = active_ops[dist(randomEngine)];
|
||||||
const Decision& dec_a = sol.decisions.at(op_a);
|
const Decision& dec_a = *sol.decisions[op_a];
|
||||||
|
|
||||||
std::vector<unsigned short> seq_swap(1, op_a);
|
std::vector<unsigned short> seq_swap(1, op_a);
|
||||||
|
|
||||||
for (auto& op_id : active_ops) {
|
for (auto& op_id : active_ops) {
|
||||||
if (op_id == op_a) continue;
|
if (op_id == op_a) continue;
|
||||||
const Decision& dec_b = sol.decisions.at(op_id);
|
const Decision& dec_b = *sol.decisions[op_id];
|
||||||
if (dec_b.empV != dec_a.empV) continue;
|
if (dec_b.empV != dec_a.empV) continue;
|
||||||
|
|
||||||
seq_swap.push_back({
|
seq_swap.push_back({
|
||||||
@@ -268,8 +376,8 @@ namespace solverlib {
|
|||||||
if (seq_swap.size() == 1) return std::nullopt;
|
if (seq_swap.size() == 1) return std::nullopt;
|
||||||
|
|
||||||
std::sort(seq_swap.begin(), seq_swap.end(), [&](auto job1, auto job2){
|
std::sort(seq_swap.begin(), seq_swap.end(), [&](auto job1, auto job2){
|
||||||
const Decision& dec_a = sol.decisions.at(job1);
|
const Decision& dec_a = *sol.decisions[job1];
|
||||||
const Decision& dec_b = sol.decisions.at(job2);
|
const Decision& dec_b = *sol.decisions[job2];
|
||||||
|
|
||||||
return dec_a.lastCreneau.first < dec_b.lastCreneau.first;
|
return dec_a.lastCreneau.first < dec_b.lastCreneau.first;
|
||||||
});
|
});
|
||||||
@@ -292,16 +400,14 @@ namespace solverlib {
|
|||||||
std::vector<std::pair<unsigned short, Decision>> jobsSeq;
|
std::vector<std::pair<unsigned short, Decision>> jobsSeq;
|
||||||
jobsSeq.reserve(seqCop.size());
|
jobsSeq.reserve(seqCop.size());
|
||||||
for (auto& job_id : seqCop)
|
for (auto& job_id : seqCop)
|
||||||
jobsSeq.push_back({job_id, sol.decisions.at(job_id)});
|
jobsSeq.push_back({job_id, *sol.decisions[job_id]});
|
||||||
|
|
||||||
Penalty oldPen = sol.penaltyPerMachine.count(dec_a.empV)
|
Penalty oldPen = sol.penaltyPerMachine[dec_a.empV];
|
||||||
? sol.penaltyPerMachine.at(dec_a.empV)
|
|
||||||
: Penalty{};
|
|
||||||
|
|
||||||
unsigned int oldCost = 0;
|
unsigned int oldCost = 0;
|
||||||
for (auto& job_id : seq_swap)
|
for (auto& job_id : seq_swap)
|
||||||
oldCost += STFMockInstance::jobs[job_id]->getPoidsRetard()
|
oldCost += STFMockInstance::jobs[job_id]->getPoidsRetard()
|
||||||
* sol.decisions.at(job_id).lastCreneau.first;
|
* (*sol.decisions[job_id]).lastCreneau.first;
|
||||||
|
|
||||||
Penalty newPen; bool feasible = true;
|
Penalty newPen; bool feasible = true;
|
||||||
auto res = checkSequence(jobsSeq, dec_a.empV, newPen, feasible);
|
auto res = checkSequence(jobsSeq, dec_a.empV, newPen, feasible);
|
||||||
@@ -327,13 +433,18 @@ namespace solverlib {
|
|||||||
if (!mock) return std::nullopt;
|
if (!mock) return std::nullopt;
|
||||||
|
|
||||||
std::vector<unsigned short> active_ops;
|
std::vector<unsigned short> active_ops;
|
||||||
for (auto& [op_id, dec] : sol.decisions)
|
unsigned int id = 0;
|
||||||
if (!dec.excluded) active_ops.push_back(op_id);
|
for (auto& dec : sol.decisions)
|
||||||
|
{
|
||||||
|
if (!(*dec).excluded)
|
||||||
|
active_ops.push_back(id);
|
||||||
|
++id;
|
||||||
|
}
|
||||||
if (active_ops.size() < 2) return std::nullopt;
|
if (active_ops.size() < 2) return std::nullopt;
|
||||||
|
|
||||||
std::uniform_int_distribution<int> dist(0, (int)active_ops.size() - 1);
|
std::uniform_int_distribution<int> dist(0, (int)active_ops.size() - 1);
|
||||||
unsigned short op_a = active_ops[dist(randomEngine)];
|
unsigned short op_a = active_ops[dist(randomEngine)];
|
||||||
const Decision& dec_a = sol.decisions.at(op_a);
|
const Decision& dec_a = *sol.decisions[op_a];
|
||||||
|
|
||||||
struct SwapCandidate {
|
struct SwapCandidate {
|
||||||
unsigned short op_a;
|
unsigned short op_a;
|
||||||
@@ -347,7 +458,7 @@ namespace solverlib {
|
|||||||
//pair < op, empR post swap>
|
//pair < op, empR post swap>
|
||||||
for (auto& op_id : active_ops) {
|
for (auto& op_id : active_ops) {
|
||||||
if (op_id == op_a) continue;
|
if (op_id == op_a) continue;
|
||||||
const Decision& dec_b = sol.decisions.at(op_id);
|
const Decision& dec_b = *sol.decisions[op_id];
|
||||||
if (dec_b.empV == dec_a.empV) continue;
|
if (dec_b.empV == dec_a.empV) continue;
|
||||||
|
|
||||||
// Vérifier compatibilité infrastructure
|
// Vérifier compatibilité infrastructure
|
||||||
@@ -378,12 +489,12 @@ namespace solverlib {
|
|||||||
// Tirer deuxième op parmi les candidats
|
// Tirer deuxième op parmi les candidats
|
||||||
std::uniform_int_distribution<int> cand_dist(0, (int)swap_candidates.size() - 1);
|
std::uniform_int_distribution<int> cand_dist(0, (int)swap_candidates.size() - 1);
|
||||||
auto swap = swap_candidates[cand_dist(randomEngine)];
|
auto swap = swap_candidates[cand_dist(randomEngine)];
|
||||||
const Decision& dec_b = sol.decisions.at(swap.op_b);
|
const Decision& dec_b = *sol.decisions[swap.op_b];
|
||||||
|
|
||||||
// échanger tracks et slots
|
// échanger tracks et slots
|
||||||
SASolution neighbor = sol;
|
SASolution neighbor = sol;
|
||||||
Decision& new_dec_a = neighbor.decisions[op_a];
|
Decision& new_dec_a = *neighbor.decisions[op_a];
|
||||||
Decision& new_dec_b = neighbor.decisions[swap.op_b];
|
Decision& new_dec_b = *neighbor.decisions[swap.op_b];
|
||||||
|
|
||||||
new_dec_a.voie = dec_b.voie;
|
new_dec_a.voie = dec_b.voie;
|
||||||
new_dec_a.site = dec_b.site;
|
new_dec_a.site = dec_b.site;
|
||||||
@@ -403,29 +514,29 @@ namespace solverlib {
|
|||||||
auto oldCrenB = dec_b.lastCreneau;
|
auto oldCrenB = dec_b.lastCreneau;
|
||||||
|
|
||||||
// Pénalités anciennes O(1)
|
// Pénalités anciennes O(1)
|
||||||
Penalty oldPenA = sol.penaltyPerMachine.count(dec_a.empV)
|
Penalty oldPenA = sol.penaltyPerMachine[dec_a.empV];
|
||||||
? sol.penaltyPerMachine.at(dec_a.empV) : Penalty{};
|
Penalty oldPenB = sol.penaltyPerMachine[dec_b.empV];
|
||||||
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();
|
||||||
|
unsigned int op_id = 0;
|
||||||
for(auto& dec : neighbor.decisions)
|
for(auto& dec : neighbor.decisions)
|
||||||
{
|
{
|
||||||
if(!dec.second.excluded)
|
if(!(*dec).excluded)
|
||||||
{
|
{
|
||||||
if(dec.second.empV == new_dec_a.empV)
|
if((*dec).empV == new_dec_a.empV)
|
||||||
{
|
{
|
||||||
jobsEmpVA.push_back({dec.first, dec.second});
|
jobsEmpVA.push_back({op_id, (*dec)});
|
||||||
oldCost += dec.second.lastCreneau.first * STFMockInstance::jobs[dec.first]->getPoidsRetard();
|
oldCost += (*dec).lastCreneau.first * STFMockInstance::jobs[op_id]->getPoidsRetard();
|
||||||
}
|
}
|
||||||
if(dec.second.empV == new_dec_b.empV)
|
if((*dec).empV == new_dec_b.empV)
|
||||||
{
|
{
|
||||||
jobsEmpVB.push_back({dec.first, dec.second});
|
jobsEmpVB.push_back({op_id, (*dec)});
|
||||||
oldCost += dec.second.lastCreneau.first * STFMockInstance::jobs[dec.first]->getPoidsRetard();
|
oldCost += (*dec).lastCreneau.first * STFMockInstance::jobs[op_id]->getPoidsRetard();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
++op_id;
|
||||||
}
|
}
|
||||||
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;
|
||||||
@@ -481,8 +592,13 @@ namespace solverlib {
|
|||||||
if (!mock) return std::nullopt;
|
if (!mock) return std::nullopt;
|
||||||
|
|
||||||
std::vector<unsigned short> inactive_ops;
|
std::vector<unsigned short> inactive_ops;
|
||||||
for (auto& [op_id, dec] : sol.decisions)
|
unsigned int id = 0;
|
||||||
if (dec.excluded) inactive_ops.push_back(op_id);
|
for (auto& dec : sol.decisions)
|
||||||
|
{
|
||||||
|
if ((*dec).excluded)
|
||||||
|
inactive_ops.push_back(id);
|
||||||
|
++id;
|
||||||
|
}
|
||||||
if (inactive_ops.empty()) return std::nullopt;
|
if (inactive_ops.empty()) return std::nullopt;
|
||||||
|
|
||||||
std::uniform_int_distribution<int> dist(0, (int)inactive_ops.size() - 1);
|
std::uniform_int_distribution<int> dist(0, (int)inactive_ops.size() - 1);
|
||||||
@@ -508,7 +624,7 @@ namespace solverlib {
|
|||||||
|
|
||||||
//Construire le voisin - try insert
|
//Construire le voisin - try insert
|
||||||
SASolution neighbor = sol;
|
SASolution neighbor = sol;
|
||||||
Decision& new_dec_a = neighbor.decisions[op_a];
|
Decision& new_dec_a = *neighbor.decisions[op_a];
|
||||||
auto dur = mock->dispoVoiesRames[disp].match.second - mock->dispoVoiesRames[disp].match.first;
|
auto dur = mock->dispoVoiesRames[disp].match.second - mock->dispoVoiesRames[disp].match.first;
|
||||||
|
|
||||||
new_dec_a.rejected = dur >= STFMockInstance::jobs[op_a]->getDuree() ? false : true,
|
new_dec_a.rejected = dur >= STFMockInstance::jobs[op_a]->getDuree() ? false : true,
|
||||||
@@ -521,23 +637,24 @@ namespace solverlib {
|
|||||||
new_dec_a.lastCreneau = {0,0};
|
new_dec_a.lastCreneau = {0,0};
|
||||||
|
|
||||||
// Pénalité ancienne O(1) — séquence sans op_a
|
// Pénalité ancienne O(1) — séquence sans op_a
|
||||||
Penalty oldPen = sol.penaltyPerMachine.count(new_dec_a.empV)
|
Penalty oldPen = sol.penaltyPerMachine[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 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;
|
||||||
|
unsigned int op_id = 0;
|
||||||
for(auto& dec : neighbor.decisions)
|
for(auto& dec : neighbor.decisions)
|
||||||
{
|
{
|
||||||
if(!dec.second.excluded && dec.first != op_a)
|
if(!(*dec).excluded && op_id != op_a)
|
||||||
{
|
{
|
||||||
if(dec.second.empV == new_dec_a.empV)
|
if((*dec).empV == new_dec_a.empV)
|
||||||
{
|
{
|
||||||
jobsEmpVA.push_back({dec.first, dec.second});
|
jobsEmpVA.push_back({op_id, (*dec)});
|
||||||
oldCostScheduled += dec.second.lastCreneau.first * STFMockInstance::jobs[dec.first]->getPoidsRetard();
|
oldCostScheduled += (*dec).lastCreneau.first * STFMockInstance::jobs[op_id]->getPoidsRetard();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
++op_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(jobsEmpVA.begin(), jobsEmpVA.end(), [&](auto& el1, auto& el2){
|
std::sort(jobsEmpVA.begin(), jobsEmpVA.end(), [&](auto& el1, auto& el2){
|
||||||
@@ -566,8 +683,7 @@ namespace solverlib {
|
|||||||
|
|
||||||
applySequenceResult(neighbor, seq, *res, newCost, penA, feasA);
|
applySequenceResult(neighbor, seq, *res, newCost, penA, feasA);
|
||||||
|
|
||||||
double oldFictive = sol.fictiveExcludedCosts.count(op_a)
|
double oldFictive = neighbor.fictiveExcludedCosts[op_a] > 0.0 ? fictiveCostExcluded(op_a)
|
||||||
? fictiveCostExcluded(op_a)
|
|
||||||
: MAXIMUM_TIME_OFFSET * STFMockInstance::jobs[op_a]->getPoidsRetard();
|
: MAXIMUM_TIME_OFFSET * STFMockInstance::jobs[op_a]->getPoidsRetard();
|
||||||
|
|
||||||
unsigned int oldCostExcluded = MAXIMUM_TIME_OFFSET * STFMockInstance::jobs[op_a]->getPoidsRetard();
|
unsigned int oldCostExcluded = MAXIMUM_TIME_OFFSET * STFMockInstance::jobs[op_a]->getPoidsRetard();
|
||||||
@@ -576,7 +692,7 @@ namespace solverlib {
|
|||||||
neighbor.penaltyPerMachine[new_dec_a.empV] = penA;
|
neighbor.penaltyPerMachine[new_dec_a.empV] = penA;
|
||||||
neighbor.isFeasible = neighbor.penalty.isFeasible();
|
neighbor.isFeasible = neighbor.penalty.isFeasible();
|
||||||
neighbor.fictiveCost = (neighbor.fictiveCost - oldFictive - oldCostScheduled) + newCost;
|
neighbor.fictiveCost = (neighbor.fictiveCost - oldFictive - oldCostScheduled) + newCost;
|
||||||
neighbor.fictiveExcludedCosts.erase(op_a);
|
neighbor.fictiveExcludedCosts[op_a] = 0.0;
|
||||||
neighbor.diagCost = (neighbor.diagCost - oldDiagCost) + newDiagCost;
|
neighbor.diagCost = (neighbor.diagCost - oldDiagCost) + newDiagCost;
|
||||||
neighbor.cost = (neighbor.cost - oldCostExcluded - oldCostScheduled) + newCost;
|
neighbor.cost = (neighbor.cost - oldCostExcluded - oldCostScheduled) + newCost;
|
||||||
neighbor.source = ESourceTrackPlan::SimAn;
|
neighbor.source = ESourceTrackPlan::SimAn;
|
||||||
@@ -590,15 +706,21 @@ namespace solverlib {
|
|||||||
if (!mock) return std::nullopt;
|
if (!mock) return std::nullopt;
|
||||||
|
|
||||||
std::vector<unsigned short> active_ops;
|
std::vector<unsigned short> active_ops;
|
||||||
for (auto& [op_id, dec] : sol.decisions)
|
unsigned int id = 0;
|
||||||
if (!dec.excluded) active_ops.push_back(op_id);
|
for (auto& dec : sol.decisions)
|
||||||
|
{
|
||||||
|
if (!(*dec).excluded)
|
||||||
|
active_ops.push_back(id);
|
||||||
|
++id;
|
||||||
|
|
||||||
|
}
|
||||||
if (active_ops.empty()) return std::nullopt;
|
if (active_ops.empty()) return std::nullopt;
|
||||||
|
|
||||||
std::uniform_int_distribution<int> dist(0, (int)active_ops.size() - 1);
|
std::uniform_int_distribution<int> dist(0, (int)active_ops.size() - 1);
|
||||||
unsigned short op_a = active_ops[dist(randomEngine)];
|
unsigned short op_a = active_ops[dist(randomEngine)];
|
||||||
|
|
||||||
std::vector<unsigned int> dispCandidate;
|
std::vector<unsigned int> dispCandidate;
|
||||||
const Decision& dec_a = sol.decisions.at(op_a);
|
const Decision& dec_a = *sol.decisions[op_a];
|
||||||
|
|
||||||
for (auto& disp : mock->jobDispoVoiesRames[op_a]) {
|
for (auto& disp : mock->jobDispoVoiesRames[op_a]) {
|
||||||
if(dec_a.empV == mock->dispoVoiesRames[disp].dispoVoie)
|
if(dec_a.empV == mock->dispoVoiesRames[disp].dispoVoie)
|
||||||
@@ -621,7 +743,7 @@ namespace solverlib {
|
|||||||
|
|
||||||
//Construire le voisin - try insert
|
//Construire le voisin - try insert
|
||||||
SASolution neighbor = sol;
|
SASolution neighbor = sol;
|
||||||
Decision& new_dec_a = neighbor.decisions[op_a];
|
Decision& new_dec_a = *neighbor.decisions[op_a];
|
||||||
auto dur = mock->dispoVoiesRames[disp].match.second - mock->dispoVoiesRames[disp].match.first;
|
auto dur = mock->dispoVoiesRames[disp].match.second - mock->dispoVoiesRames[disp].match.first;
|
||||||
|
|
||||||
new_dec_a.rejected = dur >= STFMockInstance::jobs[op_a]->getDuree() ? false : true,
|
new_dec_a.rejected = dur >= STFMockInstance::jobs[op_a]->getDuree() ? false : true,
|
||||||
@@ -633,10 +755,8 @@ namespace solverlib {
|
|||||||
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
|
// Pénalités anciennes O(1) — machine de départ et machine d'arrivée
|
||||||
Penalty oldPenSrc = sol.penaltyPerMachine.count(dec_a.empV)
|
Penalty oldPenSrc = sol.penaltyPerMachine[dec_a.empV];
|
||||||
? sol.penaltyPerMachine.at(dec_a.empV) : Penalty{};
|
Penalty oldPenDst = sol.penaltyPerMachine[new_dec_a.empV];
|
||||||
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;
|
||||||
@@ -644,25 +764,26 @@ namespace solverlib {
|
|||||||
|
|
||||||
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 op_id = 0;
|
||||||
for(auto& dec : neighbor.decisions)
|
for(auto& dec : neighbor.decisions)
|
||||||
{
|
{
|
||||||
if(!dec.second.excluded && dec.first != op_a)
|
if(!(*dec).excluded && op_id != op_a)
|
||||||
{
|
{
|
||||||
if(dec.second.empV == new_dec_a.empV)
|
if((*dec).empV == new_dec_a.empV)
|
||||||
{
|
{
|
||||||
jobsEmpVA.push_back({dec.first, dec.second});
|
jobsEmpVA.push_back({op_id, (*dec)});
|
||||||
oldCost += dec.second.lastCreneau.first * STFMockInstance::jobs[dec.first]->getPoidsRetard();
|
oldCost += (*dec).lastCreneau.first * STFMockInstance::jobs[op_id]->getPoidsRetard();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!dec.second.excluded)
|
if(!(*dec).excluded)
|
||||||
{
|
{
|
||||||
if(dec.second.empV == dec_a.empV)
|
if((*dec).empV == dec_a.empV)
|
||||||
{
|
{
|
||||||
jobsEmpVB.push_back({dec.first, dec.second});
|
jobsEmpVB.push_back({op_id, (*dec)});
|
||||||
oldCost += dec.second.lastCreneau.first * STFMockInstance::jobs[dec.first]->getPoidsRetard();
|
oldCost += (*dec).lastCreneau.first * STFMockInstance::jobs[op_id]->getPoidsRetard();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
++op_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(jobsEmpVA.begin(), jobsEmpVA.end(), [&](auto& el1, auto& el2){
|
std::sort(jobsEmpVA.begin(), jobsEmpVA.end(), [&](auto& el1, auto& el2){
|
||||||
@@ -719,8 +840,13 @@ namespace solverlib {
|
|||||||
if (!mock) return std::nullopt;
|
if (!mock) return std::nullopt;
|
||||||
|
|
||||||
std::vector<unsigned short> active_ops;
|
std::vector<unsigned short> active_ops;
|
||||||
for (auto& [op_id, dec] : sol.decisions)
|
unsigned int id = 0;
|
||||||
if (!dec.excluded) active_ops.push_back(op_id);
|
for (auto& dec : sol.decisions)
|
||||||
|
{
|
||||||
|
if (!(*dec).excluded)
|
||||||
|
active_ops.push_back(id);
|
||||||
|
++id;
|
||||||
|
}
|
||||||
if (active_ops.empty()) return std::nullopt;
|
if (active_ops.empty()) return std::nullopt;
|
||||||
|
|
||||||
std::uniform_int_distribution<int> dist(0, (int)active_ops.size() - 1);
|
std::uniform_int_distribution<int> dist(0, (int)active_ops.size() - 1);
|
||||||
@@ -729,8 +855,8 @@ namespace solverlib {
|
|||||||
|
|
||||||
//Construire le voisin - exclure a
|
//Construire le voisin - exclure a
|
||||||
SASolution neighbor = sol;
|
SASolution neighbor = sol;
|
||||||
const Decision& dec_a = sol.decisions.at(op_a);
|
const Decision& dec_a = *sol.decisions[op_a];
|
||||||
Decision& new_dec_a = neighbor.decisions[op_a];
|
Decision& new_dec_a = *neighbor.decisions[op_a];
|
||||||
|
|
||||||
new_dec_a.rejected = false,
|
new_dec_a.rejected = false,
|
||||||
new_dec_a.excluded = true;
|
new_dec_a.excluded = true;
|
||||||
@@ -742,23 +868,24 @@ namespace solverlib {
|
|||||||
new_dec_a.lastCreneau = {0,0};
|
new_dec_a.lastCreneau = {0,0};
|
||||||
|
|
||||||
// Pénalité ancienne O(1) — inclut la contribution de op_a
|
// Pénalité ancienne O(1) — inclut la contribution de op_a
|
||||||
Penalty oldPen = sol.penaltyPerMachine.count(dec_a.empV)
|
Penalty oldPen = sol.penaltyPerMachine[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;
|
||||||
|
|
||||||
std::vector<std::pair<unsigned short, decision>> jobsEmpVA;
|
std::vector<std::pair<unsigned short, decision>> jobsEmpVA;
|
||||||
|
unsigned int op_id = 0;
|
||||||
for(auto& dec : neighbor.decisions)
|
for(auto& dec : neighbor.decisions)
|
||||||
{
|
{
|
||||||
if(!dec.second.excluded)
|
if(!(*dec).excluded)
|
||||||
{
|
{
|
||||||
if(dec.second.empV == dec_a.empV)
|
if((*dec).empV == dec_a.empV)
|
||||||
{
|
{
|
||||||
jobsEmpVA.push_back({dec.first, dec.second});
|
jobsEmpVA.push_back({op_id, (*dec)});
|
||||||
oldCost += dec.second.lastCreneau.first * STFMockInstance::jobs[dec.first]->getPoidsRetard();
|
oldCost += (*dec).lastCreneau.first * STFMockInstance::jobs[op_id]->getPoidsRetard();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
++op_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int remaining = 0.0;
|
unsigned int remaining = 0.0;
|
||||||
@@ -796,16 +923,21 @@ namespace solverlib {
|
|||||||
if (!mock) return std::nullopt;
|
if (!mock) return std::nullopt;
|
||||||
|
|
||||||
std::vector<unsigned short> active_ops;
|
std::vector<unsigned short> active_ops;
|
||||||
for (auto& [op_id, dec] : sol.decisions)
|
unsigned int id = 0;
|
||||||
if (!dec.excluded) active_ops.push_back(op_id);
|
for (auto& dec : sol.decisions)
|
||||||
|
{
|
||||||
|
if (!(*dec).excluded)
|
||||||
|
active_ops.push_back(id);
|
||||||
|
++id;
|
||||||
|
}
|
||||||
if (active_ops.empty()) return std::nullopt;
|
if (active_ops.empty()) return std::nullopt;
|
||||||
|
|
||||||
std::uniform_int_distribution<int> dist(0, (int)active_ops.size() - 1);
|
std::uniform_int_distribution<int> dist(0, (int)active_ops.size() - 1);
|
||||||
unsigned short op_a = active_ops[dist(randomEngine)];
|
unsigned short op_a = active_ops[dist(randomEngine)];
|
||||||
const Decision& dec_a = sol.decisions.at(op_a);
|
const Decision& dec_a = *sol.decisions[op_a];
|
||||||
|
|
||||||
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;
|
||||||
@@ -825,21 +957,22 @@ namespace solverlib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pénalité ancienne O(1)
|
// Pénalité ancienne O(1)
|
||||||
Penalty oldPen = sol.penaltyPerMachine.count(dec_a.empV)
|
Penalty oldPen = sol.penaltyPerMachine[dec_a.empV];
|
||||||
? sol.penaltyPerMachine.at(dec_a.empV) : Penalty{};
|
|
||||||
|
|
||||||
unsigned int oldCost = 0;
|
unsigned int oldCost = 0;
|
||||||
std::vector<std::pair<unsigned short, decision>> jobsEmpVA;
|
std::vector<std::pair<unsigned short, decision>> jobsEmpVA;
|
||||||
|
unsigned int op_id = 0;
|
||||||
for(auto& dec : neighbor.decisions)
|
for(auto& dec : neighbor.decisions)
|
||||||
{
|
{
|
||||||
if(!dec.second.excluded)
|
if(!(*dec).excluded)
|
||||||
{
|
{
|
||||||
if(dec.second.empV == dec_a.empV)
|
if((*dec).empV == dec_a.empV)
|
||||||
{
|
{
|
||||||
jobsEmpVA.push_back({dec.first, dec.second});
|
jobsEmpVA.push_back({op_id, (*dec)});
|
||||||
oldCost += dec.second.lastCreneau.first * STFMockInstance::jobs[dec.first]->getPoidsRetard();
|
oldCost += (*dec).lastCreneau.first * STFMockInstance::jobs[op_id]->getPoidsRetard();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
++op_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(jobsEmpVA.begin(), jobsEmpVA.end(), [&](auto& el1, auto& el2){
|
std::sort(jobsEmpVA.begin(), jobsEmpVA.end(), [&](auto& el1, auto& el2){
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "Penalty.hpp"
|
#include "Penalty.hpp"
|
||||||
|
#include "SolutionPoolManager.hpp"
|
||||||
#include "TrackPlan.hpp"
|
#include "TrackPlan.hpp"
|
||||||
#include "Solution.hpp"
|
#include "Solution.hpp"
|
||||||
namespace solverlib {
|
namespace solverlib {
|
||||||
@@ -70,6 +71,7 @@ namespace solverlib {
|
|||||||
|
|
||||||
class SimulatedAnnealing{
|
class SimulatedAnnealing{
|
||||||
private:
|
private:
|
||||||
|
SolutionPoolManager pool;
|
||||||
std::vector<SASolution> solutions;
|
std::vector<SASolution> solutions;
|
||||||
std::mt19937 randomEngine;
|
std::mt19937 randomEngine;
|
||||||
double T;
|
double T;
|
||||||
@@ -90,8 +92,8 @@ namespace solverlib {
|
|||||||
for (auto& job : seq)
|
for (auto& job : seq)
|
||||||
{
|
{
|
||||||
auto& dec = neighbor.decisions[job.first];
|
auto& dec = neighbor.decisions[job.first];
|
||||||
dec.lastCreneau = resolved[id].second.lastCreneau;
|
(*dec).lastCreneau = resolved[id].second.lastCreneau;
|
||||||
newCost += dec.lastCreneau.first * STFMockInstance::jobs[job.first]->getPoidsRetard();
|
newCost += (*dec).lastCreneau.first * STFMockInstance::jobs[job.first]->getPoidsRetard();
|
||||||
++id;
|
++id;
|
||||||
}
|
}
|
||||||
neighbor.penalty = neighbor.penalty + penaltyDelta;
|
neighbor.penalty = neighbor.penalty + penaltyDelta;
|
||||||
@@ -104,18 +106,21 @@ namespace solverlib {
|
|||||||
void setPenaltyWeights() {
|
void setPenaltyWeights() {
|
||||||
penaltyLambdas[EPenaltyType::TIME_WINDOW_OVERRUN] = 1.0;
|
penaltyLambdas[EPenaltyType::TIME_WINDOW_OVERRUN] = 1.0;
|
||||||
}
|
}
|
||||||
std::unordered_map<EPenaltyType, double> effectiveLambdas() const;
|
ArrayLambda effectiveLambdas() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static bool withDynProg;
|
static bool withDynProg;
|
||||||
static bool authorizeInfeasible;
|
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);
|
//SimulatedAnnealing(std::unordered_map<unsigned short, Decision>& decs, std::shared_ptr<modellib::STFMockInstance> mock, ESourceTrackPlan source);
|
||||||
|
SimulatedAnnealing(std::vector<std::optional<Decision>>& decs, std::shared_ptr<modellib::STFMockInstance> mock, ESourceTrackPlan source);
|
||||||
|
|
||||||
EMovingOperators pick_operator();
|
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);
|
||||||
|
SASolution solveMultiStart(double T_max, double T_min, double cooling_rate, int iterations_per_temp, int n_restarts);
|
||||||
|
SASolution perturbSolution(const SASolution& sol);
|
||||||
std::optional<SASolution> move_swap_within_interval(const SASolution& sol);
|
std::optional<SASolution> move_swap_within_interval(const SASolution& sol);
|
||||||
std::optional<SASolution> move_swap_WC(const SASolution& sol);
|
std::optional<SASolution> move_swap_WC(const SASolution& sol);
|
||||||
std::optional<SASolution> move_insert_WC(const SASolution& sol);
|
std::optional<SASolution> move_insert_WC(const SASolution& sol);
|
||||||
@@ -134,15 +139,19 @@ namespace solverlib {
|
|||||||
|
|
||||||
double fictiveCostExcluded(unsigned short op_id) 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> evaluate(const std::vector<std::optional<Decision>>& decs);
|
||||||
|
|
||||||
|
|
||||||
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());};
|
||||||
|
|
||||||
|
|
||||||
//unsigned long getUniquePlans(std::vector<TrackPlan>& plans);
|
//unsigned long getUniquePlans(std::vector<TrackPlan>& plans);
|
||||||
void addSolutionToPool(std::unordered_map<unsigned short, Decision>& decs, std::shared_ptr<modellib::STFMockInstance> mock, ESourceTrackPlan source, bool isFirst = false);
|
//void addSolutionToPool(std::unordered_map<unsigned short, Decision>& decs, std::shared_ptr<modellib::STFMockInstance> mock, ESourceTrackPlan source, bool isFirst = false);
|
||||||
|
void addSolutionToPool(std::vector<std::optional<Decision>>& decs, std::shared_ptr<modellib::STFMockInstance> mock, ESourceTrackPlan source, bool isFirst = false);
|
||||||
|
|
||||||
std::vector<SASolution>&& getSolutionPool(){return std::move(solutions);};
|
std::vector<SASolution>&& getSolutionPool(){return std::move(solutions);};
|
||||||
|
SolutionPoolManager& getPoolManager(){return pool;};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ namespace solverlib {
|
|||||||
typedef struct _sol{
|
typedef struct _sol{
|
||||||
ESourceTrackPlan source;
|
ESourceTrackPlan source;
|
||||||
std::shared_ptr<STFMockInstance> mock;
|
std::shared_ptr<STFMockInstance> mock;
|
||||||
std::unordered_map<unsigned short, Decision> decisions;
|
std::vector<std::optional<Decision>> decisions;
|
||||||
unsigned int cost;
|
unsigned int cost;
|
||||||
unsigned int diagCost;
|
unsigned int diagCost;
|
||||||
bool isFeasible = true;
|
bool isFeasible = true;
|
||||||
Penalty penalty;
|
Penalty penalty = Penalty{};
|
||||||
std::unordered_map<unsigned int, Penalty> penaltyPerMachine;
|
std::vector<Penalty> penaltyPerMachine = std::vector<Penalty>(STFMockInstance::machines.size(), Penalty{});
|
||||||
double fictiveCost = 0.0;
|
double fictiveCost = 0.0;
|
||||||
std::unordered_map<unsigned short, double> fictiveExcludedCosts;
|
std::vector<double> fictiveExcludedCosts = std::vector<double>(STFMockInstance::jobs.size(), 0.0);
|
||||||
}SASolution;
|
}SASolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "SolutionPoolManager.hpp"
|
#include "SolutionPoolManager.hpp"
|
||||||
|
#include "TrackPlan.hpp"
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -14,15 +15,18 @@ namespace solverlib {
|
|||||||
plans.resize(STFMockInstance::tracks.size());
|
plans.resize(STFMockInstance::tracks.size());
|
||||||
std::unordered_map<unsigned int, std::vector<std::pair<unsigned short, Decision>>> decisionsOnMachines;
|
std::unordered_map<unsigned int, std::vector<std::pair<unsigned short, Decision>>> decisionsOnMachines;
|
||||||
std::vector<std::set<unsigned int>> machineIdsFromTrackId(STFMockInstance::tracks.size());
|
std::vector<std::set<unsigned int>> machineIdsFromTrackId(STFMockInstance::tracks.size());
|
||||||
|
unsigned int id = 0;
|
||||||
for(auto& dec : sol.decisions)
|
for(auto& dec : sol.decisions)
|
||||||
{
|
{
|
||||||
if(!dec.second.excluded)
|
if(!dec) continue;
|
||||||
|
|
||||||
|
if(!(*dec).excluded)
|
||||||
{
|
{
|
||||||
plans[dec.second.voie].isTrash = false;
|
plans[(*dec).voie].isTrash = false;
|
||||||
plans[dec.second.voie].track = dec.second.voie;
|
plans[(*dec).voie].track = (*dec).voie;
|
||||||
plans[dec.second.voie].schedule[dec.first] = dec.second;
|
plans[(*dec).voie].schedule[id] = (*dec);
|
||||||
decisionsOnMachines[dec.second.empV].push_back({dec.first, dec.second});
|
decisionsOnMachines[(*dec).empV].push_back({id, (*dec)});
|
||||||
machineIdsFromTrackId[dec.second.voie].insert(dec.second.empV);
|
machineIdsFromTrackId[(*dec).voie].insert((*dec).empV);
|
||||||
}
|
}
|
||||||
else if(withTrash) {
|
else if(withTrash) {
|
||||||
TrackPlan trashTrack;
|
TrackPlan trashTrack;
|
||||||
@@ -31,18 +35,18 @@ namespace solverlib {
|
|||||||
trashTrack.mock = sol.mock;
|
trashTrack.mock = sol.mock;
|
||||||
trashTrack.diagCost = 0;
|
trashTrack.diagCost = 0;
|
||||||
trashTrack.track = 0;
|
trashTrack.track = 0;
|
||||||
trashTrack.schedule[dec.first] = {
|
trashTrack.schedule[id] = {
|
||||||
0,CreneauHoraire(), 0, false, true,0,0,{0,0}
|
0,CreneauHoraire(), 0, false, true,0,0,{0,0}
|
||||||
};
|
};
|
||||||
trashTrack.cost = STFMockInstance::jobs[dec.first]->getPoidsRetard() * MAXIMUM_TIME_OFFSET;
|
trashTrack.cost = STFMockInstance::jobs[id]->getPoidsRetard() * MAXIMUM_TIME_OFFSET;
|
||||||
trackPlans.push_back(trashTrack);
|
trackPlans.push_back(trashTrack);
|
||||||
}
|
}
|
||||||
|
++id;
|
||||||
}
|
}
|
||||||
for(auto& plan : plans)
|
for(auto& plan : plans)
|
||||||
{
|
{
|
||||||
if(!plan.schedule.empty())
|
if(!plan.schedule.empty())
|
||||||
{
|
{
|
||||||
|
|
||||||
bool feasible = true;
|
bool feasible = true;
|
||||||
if(!sol.penalty.isFeasible())
|
if(!sol.penalty.isFeasible())
|
||||||
{
|
{
|
||||||
@@ -70,8 +74,7 @@ namespace solverlib {
|
|||||||
return trackPlans;
|
return trackPlans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<TrackPlan> SolutionPoolManager::transformSolutionsIntoUniqueTrackPlans(bool makeTrash)
|
||||||
std::vector<TrackPlan> SolutionPoolManager::transformSolutionsIntoUniqueTrackPlans()
|
|
||||||
{
|
{
|
||||||
std::vector<TrackPlan> trackPlans;
|
std::vector<TrackPlan> trackPlans;
|
||||||
std::set<TrackPlan> uniqueSchedules;
|
std::set<TrackPlan> uniqueSchedules;
|
||||||
@@ -86,15 +89,18 @@ namespace solverlib {
|
|||||||
plans.resize(STFMockInstance::tracks.size());
|
plans.resize(STFMockInstance::tracks.size());
|
||||||
std::unordered_map<unsigned int, std::vector<std::pair<unsigned short, Decision>>> decisionsOnMachines;
|
std::unordered_map<unsigned int, std::vector<std::pair<unsigned short, Decision>>> decisionsOnMachines;
|
||||||
std::vector<std::set<unsigned int>> machineIdsFromTrackId(STFMockInstance::tracks.size());
|
std::vector<std::set<unsigned int>> machineIdsFromTrackId(STFMockInstance::tracks.size());
|
||||||
|
unsigned int id = 0;
|
||||||
for(auto& dec : sol.decisions)
|
for(auto& dec : sol.decisions)
|
||||||
{
|
{
|
||||||
if(!dec.second.excluded)
|
if(!dec) continue;
|
||||||
|
|
||||||
|
if(!(*dec).excluded)
|
||||||
{
|
{
|
||||||
plans[dec.second.voie].isTrash = false;
|
plans[(*dec).voie].isTrash = false;
|
||||||
plans[dec.second.voie].track = dec.second.voie;
|
plans[(*dec).voie].track = (*dec).voie;
|
||||||
plans[dec.second.voie].schedule[dec.first] = dec.second;
|
plans[(*dec).voie].schedule[id] = (*dec);
|
||||||
decisionsOnMachines[dec.second.empV].push_back({dec.first, dec.second});
|
decisionsOnMachines[(*dec).empV].push_back({id, (*dec)});
|
||||||
machineIdsFromTrackId[dec.second.voie].insert(dec.second.empV);
|
machineIdsFromTrackId[(*dec).voie].insert((*dec).empV);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -135,8 +141,10 @@ namespace solverlib {
|
|||||||
|
|
||||||
pool.pop_back();
|
pool.pop_back();
|
||||||
}
|
}
|
||||||
|
if(!uniqueSchedules.empty())
|
||||||
std::move(uniqueSchedules.begin(), uniqueSchedules.end(), std::back_inserter(trackPlans));
|
std::move(uniqueSchedules.begin(), uniqueSchedules.end(), std::back_inserter(trackPlans));
|
||||||
|
if(makeTrash)
|
||||||
|
{
|
||||||
for(unsigned short job = 0; job < STFMockInstance::jobs.size(); ++job)
|
for(unsigned short job = 0; job < STFMockInstance::jobs.size(); ++job)
|
||||||
{
|
{
|
||||||
TrackPlan trashTrack;
|
TrackPlan trashTrack;
|
||||||
@@ -150,12 +158,13 @@ namespace solverlib {
|
|||||||
trashTrack.cost = STFMockInstance::jobs[job]->getPoidsRetard() * MAXIMUM_TIME_OFFSET;
|
trashTrack.cost = STFMockInstance::jobs[job]->getPoidsRetard() * MAXIMUM_TIME_OFFSET;
|
||||||
trackPlans.push_back(trashTrack);
|
trackPlans.push_back(trashTrack);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto nbplan = trackPlans.size();
|
auto nbplan = trackPlans.size();
|
||||||
|
|
||||||
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Removed " + std::to_string(countD) + " non-unique or non-feasible 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));
|
||||||
|
pool.clear();
|
||||||
return trackPlans;
|
return trackPlans;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,4 +192,13 @@ namespace solverlib {
|
|||||||
std::move(solutions.begin(), solutions.end(), std::back_inserter(pool));
|
std::move(solutions.begin(), solutions.end(), std::back_inserter(pool));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SolutionPoolManager::provide(SolutionPoolManager& otherPool)
|
||||||
|
{
|
||||||
|
std::move(otherPool.getSolutions().begin(), otherPool.getSolutions().end(), std::back_inserter(pool));
|
||||||
|
for(auto& tr : otherPool.getTrackPlans())
|
||||||
|
{
|
||||||
|
uniquePlans.insert(tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3,22 +3,119 @@
|
|||||||
|
|
||||||
#include "Solution.hpp"
|
#include "Solution.hpp"
|
||||||
#include "TrackPlan.hpp"
|
#include "TrackPlan.hpp"
|
||||||
|
#include <iterator>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace solverlib {
|
namespace solverlib {
|
||||||
class SolutionPoolManager{
|
class SolutionPoolManager{
|
||||||
std::vector<SASolution> pool;
|
std::vector<SASolution> pool;
|
||||||
|
|
||||||
|
struct TrackPlanHash {
|
||||||
|
size_t operator()(const TrackPlan& tp) const {
|
||||||
|
size_t h = std::hash<unsigned short>{}(tp.track);
|
||||||
|
h ^= std::hash<unsigned int>{}(tp.cost) + 0x9e3779b9 + (h<<6) + (h>>2);
|
||||||
|
h ^= std::hash<unsigned int>{}(tp.diagCost) + 0x9e3779b9 + (h<<6) + (h>>2);
|
||||||
|
h ^= std::hash<bool>{}(tp.isTrash) + 0x9e3779b9 + (h<<6) + (h>>2);
|
||||||
|
|
||||||
|
std::vector<std::pair<unsigned short, Decision>> entries;
|
||||||
|
entries.reserve(tp.schedule.size());
|
||||||
|
for (auto& [jobId, dec] : tp.schedule)
|
||||||
|
entries.push_back({jobId, dec});
|
||||||
|
std::sort(entries.begin(), entries.end(), [](auto& el1, auto& el2){return el1.first < el2.first;});
|
||||||
|
|
||||||
|
for (auto& [jobId, dec] : entries) {
|
||||||
|
h ^= std::hash<unsigned short>{}(jobId) + 0x9e3779b9 + (h<<6) + (h>>2);
|
||||||
|
h ^= std::hash<unsigned short>{}(dec.empV) + 0x9e3779b9 + (h<<6) + (h>>2);
|
||||||
|
h ^= std::hash<unsigned int>{}(dec.empR) + 0x9e3779b9 + (h<<6) + (h>>2);
|
||||||
|
h ^= std::hash<unsigned short>{}(dec.lastCreneau.first) + 0x9e3779b9 + (h<<6) + (h>>2);
|
||||||
|
h ^= std::hash<unsigned short>{}(dec.lastCreneau.second) + 0x9e3779b9 + (h<<6) + (h>>2);
|
||||||
|
h ^= std::hash<bool>{}(dec.rejected) + 0x9e3779b9 + (h<<6) + (h>>2);
|
||||||
|
h ^= std::hash<unsigned char>{}(dec.site) + 0x9e3779b9 + (h<<6) + (h>>2);
|
||||||
|
h ^= std::hash<unsigned char>{}(dec.voie) + 0x9e3779b9 + (h<<6) + (h>>2);
|
||||||
|
h ^= std::hash<unsigned short>{}(dec.timeslotGraphSplited.getDebut().getRelativeDate()) + 0x9e3779b9 + (h<<6) + (h>>2);
|
||||||
|
h ^= std::hash<unsigned short>{}(dec.timeslotGraphSplited.getFin().getRelativeDate()) + 0x9e3779b9 + (h<<6) + (h>>2);
|
||||||
|
h ^= std::hash<bool>{}(dec.excluded) + 0x9e3779b9 + (h<<6) + (h>>2);
|
||||||
|
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_set<TrackPlan, TrackPlanHash> uniquePlans;
|
||||||
|
std::vector<TrackPlan> trashPlans;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void provide(std::vector<SASolution>&& solutions);
|
void provide(std::vector<SASolution>&& solutions);
|
||||||
|
void provide(SolutionPoolManager& otherPool);
|
||||||
|
void provideTrackPlanToSelf()
|
||||||
|
{
|
||||||
|
if(!pool.empty())
|
||||||
|
{
|
||||||
|
auto tr = transformSolutionsIntoUniqueTrackPlans(false);
|
||||||
|
for(auto& trplan : tr)
|
||||||
|
{
|
||||||
|
uniquePlans.insert(trplan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<TrackPlan> transformSolutionsIntoUniqueTrackPlans();
|
void addTrackPlan(TrackPlan&& tp) {
|
||||||
|
if (uniquePlans.insert(tp).second){}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SASolution> getFeasibleSolutions()
|
||||||
|
{
|
||||||
|
std::vector<SASolution> sols;
|
||||||
|
for(auto& sol : pool)
|
||||||
|
{
|
||||||
|
if(sol.penalty.isFeasible())
|
||||||
|
sols.push_back(sol);
|
||||||
|
}
|
||||||
|
return sols;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<TrackPlan>& getTrashTrackPlans()
|
||||||
|
{
|
||||||
|
return trashPlans;
|
||||||
|
}
|
||||||
|
|
||||||
|
void provideTrashPlans()
|
||||||
|
{
|
||||||
|
for(unsigned short job = 0; job < STFMockInstance::jobs.size(); ++job)
|
||||||
|
{
|
||||||
|
TrackPlan trashTrack;
|
||||||
|
trashTrack.isTrash = true;
|
||||||
|
trashTrack.diagCost = 0;
|
||||||
|
trashTrack.track = 0;
|
||||||
|
trashTrack.source = ESourceTrackPlan::Fake;
|
||||||
|
trashTrack.schedule[job] = {
|
||||||
|
0,CreneauHoraire(), 0, false, true,0,0,{0,0}
|
||||||
|
};
|
||||||
|
trashTrack.cost = STFMockInstance::jobs[job]->getPoidsRetard() * MAXIMUM_TIME_OFFSET;
|
||||||
|
trashPlans.push_back(trashTrack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::vector<TrackPlan> transformSolutionsIntoUniqueTrackPlans(bool makeTrash = true);
|
||||||
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);
|
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;};
|
||||||
|
|
||||||
|
std::vector<TrackPlan> getTrackPlans(){
|
||||||
|
std::vector<TrackPlan> trackPlans;
|
||||||
|
trackPlans.reserve(uniquePlans.size() + trashPlans.size());
|
||||||
|
for(auto& tr : uniquePlans)
|
||||||
|
{
|
||||||
|
trackPlans.push_back(tr);
|
||||||
|
}
|
||||||
|
for(auto& trash : trashPlans)
|
||||||
|
{
|
||||||
|
trackPlans.push_back(trash);
|
||||||
|
}
|
||||||
|
return trackPlans;
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
#ifndef SOURCESOLTRPLAN_HPP
|
#ifndef SOURCESOLTRPLAN_HPP
|
||||||
#define SOURCESOLTRPLAN_HPP
|
#define SOURCESOLTRPLAN_HPP
|
||||||
|
|
||||||
enum class ESourceTrackPlan{
|
#include <cstdint>
|
||||||
|
enum class ESourceTrackPlan: uint8_t{
|
||||||
SimAn,
|
SimAn,
|
||||||
DyProg,
|
DyProg,
|
||||||
ListHeu,
|
ListHeu,
|
||||||
|
|||||||
@@ -582,6 +582,7 @@ namespace solverlib {
|
|||||||
bool allowSwap;
|
bool allowSwap;
|
||||||
bool saveAllUB;
|
bool saveAllUB;
|
||||||
unsigned int multistartSiman = 0;
|
unsigned int multistartSiman = 0;
|
||||||
|
bool withPenalties = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StepResult {
|
struct StepResult {
|
||||||
@@ -610,7 +611,7 @@ namespace solverlib {
|
|||||||
sol.cost = best.sommeRetardsPonderes(true);
|
sol.cost = best.sommeRetardsPonderes(true);
|
||||||
sol.diagCost = best.sommeRejetsPonderes();
|
sol.diagCost = best.sommeRejetsPonderes();
|
||||||
sol.mock = best.getPlanificationState();
|
sol.mock = best.getPlanificationState();
|
||||||
sol.decisions = best.getMapOfDecisions();
|
sol.decisions = best.getVectorOfDecicions();
|
||||||
auto end = std::chrono::system_clock::now();
|
auto end = std::chrono::system_clock::now();
|
||||||
std::chrono::duration<double> duration = end - start;
|
std::chrono::duration<double> duration = end - start;
|
||||||
|
|
||||||
@@ -639,7 +640,7 @@ namespace solverlib {
|
|||||||
best.cost = obj;
|
best.cost = obj;
|
||||||
best.diagCost = bestPlanif.sommeRejetsPonderes();
|
best.diagCost = bestPlanif.sommeRejetsPonderes();
|
||||||
best.mock = bestPlanif.getPlanificationState();
|
best.mock = bestPlanif.getPlanificationState();
|
||||||
best.decisions = bestPlanif.getMapOfDecisions();
|
best.decisions = bestPlanif.getVectorOfDecicions();
|
||||||
best.source = ESourceTrackPlan::ListHeu;
|
best.source = ESourceTrackPlan::ListHeu;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -675,8 +676,17 @@ namespace solverlib {
|
|||||||
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Running ILP");
|
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Running ILP");
|
||||||
auto start = std::chrono::system_clock::now();
|
auto start = std::chrono::system_clock::now();
|
||||||
|
|
||||||
auto trackPlans = poolManager.transformSolutionsIntoUniqueTrackPlans();
|
poolManager.provideTrackPlanToSelf();
|
||||||
|
poolManager.provideTrashPlans();
|
||||||
|
auto trackPlans = poolManager.getTrackPlans();//poolManager.transformSolutionsIntoUniqueTrackPlans();
|
||||||
|
|
||||||
auto trackPlansBest = poolManager.getTrackPlansFromSolution(bestSoFar, true);
|
auto trackPlansBest = poolManager.getTrackPlansFromSolution(bestSoFar, true);
|
||||||
|
unsigned int co = 0;
|
||||||
|
for(auto& tr : trackPlansBest)
|
||||||
|
{
|
||||||
|
co += tr.cost;
|
||||||
|
}
|
||||||
|
std::cout << bestSoFar.cost << " " << co << std::endl;
|
||||||
|
|
||||||
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS,
|
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS,
|
||||||
"ILP: considering " + std::to_string(trackPlans.size()) + " track schedules");
|
"ILP: considering " + std::to_string(trackPlans.size()) + " track schedules");
|
||||||
@@ -700,7 +710,7 @@ namespace solverlib {
|
|||||||
result.cost = plan->sommeRetardsPonderes(true);
|
result.cost = plan->sommeRetardsPonderes(true);
|
||||||
result.diagCost = plan->sommeRejetsPonderes();
|
result.diagCost = plan->sommeRejetsPonderes();
|
||||||
result.mock = plan->getPlanificationState();
|
result.mock = plan->getPlanificationState();
|
||||||
result.decisions = plan->getMapOfDecisions();
|
result.decisions = plan->getVectorOfDecicions();
|
||||||
auto end = std::chrono::system_clock::now();
|
auto end = std::chrono::system_clock::now();
|
||||||
std::chrono::duration<double> duration = end - start;
|
std::chrono::duration<double> duration = end - start;
|
||||||
return { result, ALGO::ILP, false, duration.count() };
|
return { result, ALGO::ILP, false, duration.count() };
|
||||||
@@ -753,7 +763,7 @@ namespace solverlib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
auto map = plan.getMapOfDecisions();
|
auto map = plan.getVectorOfDecicions();
|
||||||
SimulatedAnnealing simAnn(map, plan.getPlanificationState(), ESourceTrackPlan::ListHeu);
|
SimulatedAnnealing simAnn(map, plan.getPlanificationState(), ESourceTrackPlan::ListHeu);
|
||||||
auto tmp = simAnn.solve(10, 0.01, 0.96, 20);
|
auto tmp = simAnn.solve(10, 0.01, 0.96, 20);
|
||||||
poolManager.provide({tmp});
|
poolManager.provide({tmp});
|
||||||
@@ -763,9 +773,8 @@ namespace solverlib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto map = plan.getMapOfDecisions();
|
|
||||||
SASolution sol;
|
SASolution sol;
|
||||||
sol.decisions = map;
|
sol.decisions = plan.getVectorOfDecicions();
|
||||||
sol.cost = plan.sommeRetardsPonderes(true);
|
sol.cost = plan.sommeRetardsPonderes(true);
|
||||||
sol.diagCost = plan.sommeRejetsPonderes();
|
sol.diagCost = plan.sommeRejetsPonderes();
|
||||||
sol.mock = plan.getPlanificationState();
|
sol.mock = plan.getPlanificationState();
|
||||||
@@ -789,23 +798,38 @@ namespace solverlib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static StepResult runSimAnn(
|
static StepResult runSimAnn(
|
||||||
|
Result& resultGlob,
|
||||||
SASolution& initial,
|
SASolution& initial,
|
||||||
SolutionPoolManager& poolManager,
|
SolutionPoolManager& poolManager,
|
||||||
bool withDyn = false
|
bool withDyn = false,
|
||||||
|
bool withPenalties = false,
|
||||||
|
unsigned int multistartSiman = 0
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
auto rng = random::makeEngine();
|
||||||
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Running SimulatedAnnealing");
|
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Running SimulatedAnnealing");
|
||||||
|
unsigned int i = 0;
|
||||||
|
auto sol = initial;
|
||||||
|
//do{
|
||||||
|
|
||||||
auto start = std::chrono::system_clock::now();
|
auto start = std::chrono::system_clock::now();
|
||||||
|
|
||||||
SimulatedAnnealing simAnn(initial.decisions, initial.mock, initial.source);
|
SimulatedAnnealing simAnn(sol.decisions, sol.mock, sol.source);
|
||||||
SimulatedAnnealing::withDynProg = withDyn;
|
SimulatedAnnealing::withDynProg = withDyn;
|
||||||
auto result = simAnn.solve(75, 0.01, 0.995, 200);
|
SimulatedAnnealing::authorizeInfeasible = withPenalties;
|
||||||
|
auto result = simAnn.solveMultiStart(80, 0.01, 0.995, 3000, multistartSiman);
|
||||||
|
|
||||||
auto end = std::chrono::system_clock::now();
|
auto end = std::chrono::system_clock::now();
|
||||||
poolManager.provide(simAnn.getSolutionPool());
|
|
||||||
|
|
||||||
std::chrono::duration<double> duration = end - start;
|
std::chrono::duration<double> duration = end - start;
|
||||||
|
poolManager.provide(simAnn.getPoolManager());
|
||||||
|
StepResult res = { result, ALGO::SIMANN, false, duration.count() };
|
||||||
|
resultGlob.stepsRes.push_back(res);
|
||||||
|
if(resultGlob.best.sol.cost > res.sol.cost)
|
||||||
|
{
|
||||||
|
resultGlob.best = res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool jsonOrCsv = false;
|
bool jsonOrCsv = false;
|
||||||
if(jsonOrCsv)
|
if(jsonOrCsv)
|
||||||
{
|
{
|
||||||
@@ -853,7 +877,7 @@ namespace solverlib {
|
|||||||
std::ostringstream csv;
|
std::ostringstream csv;
|
||||||
|
|
||||||
// En-têtes
|
// En-têtes
|
||||||
csv << "category;operator;index;probability;objectiveDiff;costDiff;temperature;isFeasible\n";
|
csv << "category;operator;index;probability;objectiveDiff;evaluationDiff;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)
|
||||||
@@ -890,9 +914,23 @@ namespace solverlib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// On expose le pool pour les étapes aval (DynProg / ILP)
|
/*if (multistartSiman > 0) {
|
||||||
// via un membre accessible, ou on passe simAnn par référence — voir note ci-dessous
|
//une itération sur deux part du meilleur connu
|
||||||
return { result, ALGO::SIMANN, false, duration.count() };
|
if (i % 2 == 0) {
|
||||||
|
sol = resultGlob.best.sol;
|
||||||
|
} else {
|
||||||
|
auto solsF = poolManager.getFeasibleSolutions();
|
||||||
|
std::uniform_int_distribution<unsigned int> distSol(0, solsF.size()-1);
|
||||||
|
sol = solsF[distSol(rng)];
|
||||||
|
std::cout << solsF.size() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
poolManager.provideTrackPlanToSelf();
|
||||||
|
++i;*/
|
||||||
|
//}while(multistartSiman != 0 && i != multistartSiman);
|
||||||
|
|
||||||
|
return resultGlob.best;
|
||||||
}
|
}
|
||||||
|
|
||||||
static nlohmann::json makeStepJson(const StepResult& r)
|
static nlohmann::json makeStepJson(const StepResult& r)
|
||||||
@@ -932,7 +970,7 @@ namespace solverlib {
|
|||||||
{
|
{
|
||||||
name += algoNames[step] + "_";
|
name += algoNames[step] + "_";
|
||||||
}
|
}
|
||||||
name += "_M" + std::to_string(r.multistartSiman) + "_" + (r.allowSwap ? "s" : "ns");
|
name += "_M" + std::to_string(r.multistartSiman) + (r.withPenalties ? "P" : "") + "_" + (r.allowSwap ? "s" : "ns");
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -944,7 +982,13 @@ 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, ALGO::ILP}, false, false, 7},
|
//{{ALGO::LH, ALGO::SIMANN}, false, false},
|
||||||
|
//{{ALGO::LH, ALGO::SIMANN}, false, false, 0, true},
|
||||||
|
//{{ALGO::LH, ALGO::SIMANN}, false, false, 7},
|
||||||
|
{{ALGO::LH, ALGO::SIMANN, ALGO::ILP}, false, false, 3, true},
|
||||||
|
|
||||||
|
//{{ALGO::LH, ALGO::SIMANN, ALGO::ILP}, false, false, 7},
|
||||||
|
// {{ALGO::LH, ALGO::SIMANN, ALGO::ILP}, false, false, 7, true},
|
||||||
|
|
||||||
/*{{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},
|
||||||
@@ -971,7 +1015,6 @@ namespace solverlib {
|
|||||||
|
|
||||||
// If the instance is valid
|
// If the instance is valid
|
||||||
nlohmann::json json;
|
nlohmann::json json;
|
||||||
auto rng = random::makeEngine();
|
|
||||||
if (instance.isValid()) {
|
if (instance.isValid()) {
|
||||||
|
|
||||||
for(auto& pipeline : pipelines)
|
for(auto& pipeline : pipelines)
|
||||||
@@ -993,31 +1036,12 @@ namespace solverlib {
|
|||||||
case ALGO::LH: result.stepsRes.push_back(runLH(instanceCopy)); result.best = result.stepsRes.back(); break;
|
case ALGO::LH: result.stepsRes.push_back(runLH(instanceCopy)); result.best = result.stepsRes.back(); break;
|
||||||
case ALGO::SIMANN:
|
case ALGO::SIMANN:
|
||||||
{
|
{
|
||||||
unsigned int i = 0;
|
auto res = runSimAnn(result, result.best.sol, poolManager, false, pipeline.withPenalties, pipeline.multistartSiman);
|
||||||
do{
|
|
||||||
auto sol = result.best.sol;
|
|
||||||
if(i > 0)
|
|
||||||
{
|
|
||||||
std::uniform_int_distribution<unsigned int> distSol(0, poolManager.getSolutions().size()-1);
|
|
||||||
do{
|
|
||||||
sol = poolManager.getSolutions()[distSol(rng)];
|
|
||||||
|
|
||||||
}while(!sol.penalty.isFeasible());
|
|
||||||
}
|
|
||||||
auto res = runSimAnn(sol, poolManager, false);
|
|
||||||
result.stepsRes.push_back(res);
|
|
||||||
if(result.best.sol.cost > res.sol.cost)
|
|
||||||
{
|
|
||||||
result.best = res;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}while(pipeline.multistartSiman != 0 && i !=pipeline.multistartSiman);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ALGO::SIMANN_DYN:
|
case ALGO::SIMANN_DYN:
|
||||||
{
|
{
|
||||||
auto res = runSimAnn(result.best.sol, poolManager, true);
|
auto res = runSimAnn(result, result.best.sol, poolManager, true);
|
||||||
result.stepsRes.push_back(res);
|
result.stepsRes.push_back(res);
|
||||||
if(result.best.sol.cost > res.sol.cost)
|
if(result.best.sol.cost > res.sol.cost)
|
||||||
{
|
{
|
||||||
@@ -1057,10 +1081,6 @@ 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();
|
||||||
@@ -1072,6 +1092,7 @@ namespace solverlib {
|
|||||||
|
|
||||||
json[namep] = makeStepJson(result.best);
|
json[namep] = makeStepJson(result.best);
|
||||||
json[namep]["timeFinal"] = timeFinal;
|
json[namep]["timeFinal"] = timeFinal;
|
||||||
|
json[namep]["fullSolution"] = std::find_if(result.best.sol.decisions.begin(), result.best.sol.decisions.end(), [](auto& el){return (*el).excluded;}) == result.best.sol.decisions.end();
|
||||||
json[namep]["stepsDetail"] = arrStep;
|
json[namep]["stepsDetail"] = arrStep;
|
||||||
instanceCopy.clean();
|
instanceCopy.clean();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user