initialCommit 4 ans en retard

This commit is contained in:
tom
2026-06-03 22:48:34 +02:00
commit 4fc8a7be89
163 changed files with 28981 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
build
lib
+298
View File
@@ -0,0 +1,298 @@
# Nous voulons un cmake "récent" pour utiliser les dernières fonctionnalités.
cmake_minimum_required(VERSION 3.20)
# Nom du projet.
set(ORDO OrdonnancementCorrectif)
set(INSGEN InstanceGenerator)
set(TESTS Tests)
project(${ORDO})
# Génération de la liste des fichiers sources.
file(GLOB_RECURSE
SRCS_Ordo
src/OrdoCorr/main.cpp
)
file(GLOB_RECURSE
SRCS_Insgen
src/InstanceGenerator/main.cpp
)
file(GLOB_RECURSE
SRCS_Gen
src/InstanceGenerator/Generator/*
)
file(GLOB_RECURSE
SRCS_Interface
src/OrdoCorr/Interface/*
)
file(GLOB_RECURSE
SRCS_Solver
src/OrdoCorr/Solver/*
)
file(GLOB_RECURSE
SRCS_Config
src/General/Configuration/*
)
file(GLOB_RECURSE
SRCS_Model
src/General/Model/*
)
file(GLOB_RECURSE
SRCS_Logs
src/General/Logs/*
)
file(GLOB_RECURSE
SRCS_Tester
src/OrdoCorr/Tester/*
)
# ---------------------------------------
# ------- Inclusion de JSONfMC++ --------
# JSONfMC++ Lib pour gestion fichier JSON, en mode header only.
if(WIN32)
set(JSONlib_DIR ./lib/CMake/Windows)
else()
set(JSONlib_DIR ./lib/CMake/Linux)
endif()
find_package(JSONlib REQUIRED)
if(JSONlib_FOUND)
message("lib JSONFMC++ Trouvé")
else()
message("lib JSONFMC++ Introuvable")
endif()
# ---------------------------------------
# ------- Inclusion de Boost Graph Library --------
# Boost Graph Library pour gestion des graphes en mode header only.
if(WIN32)
set(BOOSTGRAPHlib_DIR ./lib/CMake/Windows)
else()
set(BOOSTGRAPHlib_DIR ./lib/CMake/Linux)
endif()
find_package(BOOSTGRAPHlib REQUIRED)
if(BOOSTGRAPHlib_FOUND)
message("lib Boost Graph Trouvé")
else()
message("lib Boost Graph Introuvable")
endif()
# ---------------------------------------
# ------- Inclusion de httplib --------
# httplib Lib pour gestion des requetes web en mode header only.
if(WIN32)
set(HTTPlib_DIR ./lib/CMake/Windows)
else()
set(HTTPlib_DIR ./lib/CMake/Linux)
endif()
find_package(HTTPlib REQUIRED)
if(HTTPlib_FOUND)
message("lib HTTP Trouvé")
else()
message("lib HTTP Introuvable")
endif()
# ---------------------------------------
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/lib/CMake/Linux/")
find_package(GUROBI REQUIRED)
set_property(GLOBAL PROPERTY DEBUG_CONFIGURATIONS "Debug")
# Chemin executable
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin/${CMAKE_BUILD_TYPE}")
# On indique que l'on veut un exécutable nommé PROJECT compilé à partir des fichiers décrits par les variables SRCS et HEADERS.
add_executable(${ORDO} ${SRCS_Ordo})
add_executable(${INSGEN} ${SRCS_Insgen})
add_library(Interface STATIC ${SRCS_Interface})
add_library(Data STATIC ${SRCS_Model})
add_library(Solver STATIC ${SRCS_Solver})
add_library(Configuration STATIC ${SRCS_Config})
add_library(Logs STATIC ${SRCS_Logs})
add_library(Generator STATIC ${SRCS_Gen})
add_library(Tester STATIC ${SRCS_Tester})
add_dependencies(${ORDO} Interface Configuration Logs Data Solver Tester)
add_dependencies(Interface Configuration Logs Data Solver Tester)
add_dependencies(Solver Logs Configuration Data)
add_dependencies(Data Logs Configuration)
add_dependencies(Tester Solver Data Logs Configuration)
add_dependencies(${INSGEN} Data Logs Generator)
set_property(TARGET ${ORDO} PROPERTY CXX_STANDARD 17)
set_property(TARGET Interface PROPERTY CXX_STANDARD 17)
set_property(TARGET Data PROPERTY CXX_STANDARD 17)
set_property(TARGET Solver PROPERTY CXX_STANDARD 17)
set_property(TARGET Configuration PROPERTY CXX_STANDARD 17)
set_property(TARGET Logs PROPERTY CXX_STANDARD 17)
set_property(TARGET Tester PROPERTY CXX_STANDARD 17)
set_property(TARGET ${INSGEN} PROPERTY CXX_STANDARD 17)
set_property(TARGET Generator PROPERTY CXX_STANDARD 17)
# Fichier include
# CPLEX
# JSONFMCPP
include_directories(${JSONFMCPP_INCLUDE_DIRS})
include_directories(${HTTPLIB_INCLUDE_DIRS})
include_directories(${BOOSTGRAPH_INCLUDE_DIRS})
#cppunit
include_directories(${GUROBI_INCLUDE_DIRS})
# Fichier lib
target_link_libraries(${ORDO}
debug Interface
optimized Interface
)
target_link_libraries(${INSGEN}
debug Generator
optimized Generator
)
target_link_libraries(Interface
debug Solver
optimized Solver
debug Tester
optimized Tester
)
target_link_libraries(Generator
debug Data
optimized Data
)
target_link_libraries(Solver
debug ${CMAKE_DL_LIBS}
optimized ${CMAKE_DL_LIBS}
optimized ${GUROBI_CXX_LIBRARY}
debug ${GUROBI_CXX_DEBUG_LIBRARY}
optimized ${GUROBI_LIBRARY}
debug ${GUROBI_LIBRARY}
debug Data
optimized Data
)
target_link_libraries(Tester
debug Solver
optimized Solver
)
target_link_libraries(Data
debug Configuration
optimized Configuration
debug Logs
optimized Logs
)
# Fichier dll sous windows
if(WIN32)
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
endif()
# Paramètre de compilation
if (UNIX)
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
set(CMAKE_CXX_FLAGS "-Wall -Wno-deprecated -Wno-write-strings -Wno-maybe-uninitialized -pthread")
endif ()
foreach(source IN LISTS SRCS_Ordo)
get_filename_component(source_path "${source}" PATH)
STRING(REGEX REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" source_path ${source_path})
string(REPLACE "/" "\\" source_path_msvc "${source_path}")
source_group("${source_path_msvc}" FILES "${source}")
endforeach()
foreach(source IN LISTS SRCS_Interface)
get_filename_component(source_path "${source}" PATH)
STRING(REGEX REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" source_path ${source_path})
string(REPLACE "/" "\\" source_path_msvc "${source_path}")
source_group("${source_path_msvc}" FILES "${source}")
endforeach()
foreach(source IN LISTS SRCS_Solver)
get_filename_component(source_path "${source}" PATH)
STRING(REGEX REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" source_path ${source_path})
string(REPLACE "/" "\\" source_path_msvc "${source_path}")
source_group("${source_path_msvc}" FILES "${source}")
endforeach()
foreach(source IN LISTS SRCS_Config)
get_filename_component(source_path "${source}" PATH)
STRING(REGEX REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" source_path ${source_path})
string(REPLACE "/" "\\" source_path_msvc "${source_path}")
source_group("${source_path_msvc}" FILES "${source}")
endforeach()
foreach(source IN LISTS SRCS_Model)
get_filename_component(source_path "${source}" PATH)
STRING(REGEX REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" source_path ${source_path})
string(REPLACE "/" "\\" source_path_msvc "${source_path}")
source_group("${source_path_msvc}" FILES "${source}")
endforeach()
foreach(source IN LISTS SRCS_Logs)
get_filename_component(source_path "${source}" PATH)
STRING(REGEX REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" source_path ${source_path})
string(REPLACE "/" "\\" source_path_msvc "${source_path}")
source_group("${source_path_msvc}" FILES "${source}")
endforeach()
foreach(source IN LISTS SRCS_Insgen)
get_filename_component(source_path "${source}" PATH)
STRING(REGEX REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" source_path ${source_path})
string(REPLACE "/" "\\" source_path_msvc "${source_path}")
source_group("${source_path_msvc}" FILES "${source}")
endforeach()
foreach(source IN LISTS SRCS_Gen)
get_filename_component(source_path "${source}" PATH)
STRING(REGEX REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" source_path ${source_path})
string(REPLACE "/" "\\" source_path_msvc "${source_path}")
source_group("${source_path_msvc}" FILES "${source}")
endforeach()
foreach(source IN LISTS SRCS_Tester)
get_filename_component(source_path "${source}" PATH)
STRING(REGEX REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" source_path ${source_path})
string(REPLACE "/" "\\" source_path_msvc "${source_path}")
source_group("${source_path_msvc}" FILES "${source}")
endforeach()
message(STATUS "Tree reorganized")
Executable
+2736
View File
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,301 @@
#include "Configurations.h"
#include <fstream>
#include <vector>
namespace configlib {
SolverConfiguration Configuration::Solver = SolverConfiguration();
LogsConfiguration Configuration::Logs = LogsConfiguration();
GeneralConfiguration Configuration::Global = GeneralConfiguration();
InterfaceConfiguration Configuration::Interface = InterfaceConfiguration();
UtilsConfiguration Configuration::Utils = UtilsConfiguration();
GeneratorConfiguration Configuration::Generator = GeneratorConfiguration();
MetaConfiguration Configuration::Meta = MetaConfiguration();
void Configuration::init(const std::string& fileConf) {
try {
std::ifstream ifconfFile(fileConf);
nlohmann::json conf = nlohmann::json::parse(ifconfFile);
nlohmann::json solver = conf["Solver"];
nlohmann::json logs = conf["Logs"];
nlohmann::json inter = conf["Interface"];
nlohmann::json utilitaires = conf["Utilitaires"];
nlohmann::json general = conf["Global"];
nlohmann::json meta = conf["Meta"];
nlohmann::json generator = conf["Generator"];
ifconfFile.close();
Meta.DOCKER = meta["DOCKER"];
Meta.VERSION = meta["VERSION"];
Solver.FCT_OBJECTIF = solver["FCT_OBJECTIF"];
Solver.NB_DAYS_TO_PLANIF = solver["NB_DAYS_TO_PLANIF"];
Solver.MIP.KX = solver["MIP"]["KX"];
Solver.MIP.KY = solver["MIP"]["KY"];
Solver.MIP.KX_DIV = solver["MIP"]["KX_DIV"];
Solver.MIP.KY_DIV = solver["MIP"]["KY_DIV"];
Solver.MIP.T_LIM_FIRST = solver["MIP"]["T_LIM_FIRST"];
Solver.MIP.T_LIM_EXPL_NODE = solver["MIP"]["T_LIM_EXPL_NODE"];
Solver.MIP.LIM_NO_IMPROVE = solver["MIP"]["LIM_NO_IMPROVE"];
Solver.PPC.KX = solver["PPC"]["KX"];
Solver.PPC.KY = solver["PPC"]["KY"];
Solver.PPC.KX_DIV = solver["PPC"]["KX_DIV"];
Solver.PPC.KY_DIV = solver["PPC"]["KY_DIV"];
Solver.PPC.T_LIM_FIRST = solver["PPC"]["T_LIM_FIRST"];
Solver.PPC.T_LIM_EXPL_NODE = solver["PPC"]["T_LIM_EXPL_NODE"];
Solver.PPC.LIM_NO_IMPROVE = solver["PPC"]["LIM_NO_IMPROVE"];
Solver.PPC.NB_INTERVAL_VPLS = solver["PPC"]["NB_INTERVAL_VPLS"];
Solver.PPC.PROPORTION_VOIE_VPLS = solver["PPC"]["PROPORTION_VOIE_VPLS"];
Solver.PPC.INTERVAL_SIZE_VPLS = solver["PPC"]["INTERVAL_SIZE_VPLS"];
Solver.PPC.MAX_VOIE_VPLS = solver["PPC"]["MAX_VOIE_VPLS"];
Solver.Croisement.NB_MAX_SCENARIO_CROISEMENT = solver["Croisement"]["NB_MAX_SCENARIO_CROISEMENT"];
Solver.Croisement.MULTIPLE_CALL_OR_MODIFIED_MIP = solver["Croisement"]["MULTIPLE_CALL_OR_MODIFIED_MIP"];
Solver.Croisement.COMMON_TIME = solver["Croisement"]["COMMON_TIME"];
Solver.Recompo.NB_MAX_SCENARIO_RECOMPO = solver["Recompo"]["NB_MAX_SCENARIO_RECOMPO"];
Solver.Recompo.COMMON_TIME = solver["Recompo"]["COMMON_TIME"];
Solver.RBS.ALPHA = solver["RBS"]["ALPHA"];
Solver.RBS.FLOW = solver["RBS"]["FLOW"];
Solver.RBS.LISTHEURISTICS = solver["RBS"]["LISTHEURISTICS"];
Solver.RBS.NB_LISTHEURISTICS = solver["RBS"]["NB_LISTHEURISTICS"];
Solver.RBS.NB_BRANCH = solver["RBS"]["NB_BRANCH"];
Solver.RBS.NB_SOLUTION = solver["RBS"]["NB_SOLUTION"];
Solver.RBS.GLOBAL_RECOVERING = solver["RBS"]["GLOBAL_RECOVERING"];
Solver.RBS.LOCAL_RECOVERING = solver["RBS"]["LOCAL_RECOVERING"];
Solver.RBS.NODE_FILTERS = solver["RBS"]["NODE_FILTERS"];
Solver.RBS.SWAP_FILTERS = solver["RBS"]["SWAP_FILTERS"];
Solver.RBS.SAVEALLUB = solver["RBS"]["SAVEALLUB"];
Solver.Conditions.RLT_WITH_UM_RDV_OR_US = solver["Conditions"]["RLT_WITH_UM_RDV_OR_US"];
Solver.Conditions.RLT_WITH_UM_RDV_OR_US_RDV = solver["Conditions"]["RLT_WITH_UM_RDV_OR_US_RDV"];
Solver.Conditions.SWAP_NO_RDV = solver["Conditions"]["SWAP_NO_RDV"];
Solver.Conditions.SWAP_NOT_IMPERATIVE_RDV = solver["Conditions"]["SWAP_NOT_IMPERATIVE_RDV"];
Solver.Conditions.SWAP_ALL_RESCHEDULE_RDV = solver["Conditions"]["SWAP_ALL_RESCHEDULE_RDV"];
Solver.Conditions.SWAP_COMP_ON_NULL_US = solver["Conditions"]["SWAP_COMP_ON_NULL_US"];
Solver.Conditions.COMP_ONLY_ON_EQU_RDV = solver["Conditions"]["COMP_ONLY_ON_EQU_RDV"];
Solver.Conditions.COMP_TRIPLE_NOT_IN_MIDDLE = solver["Conditions"]["COMP_TRIPLE_NOT_IN_MIDDLE"];
Solver.Conditions.COMP_DOUBLE = solver["Conditions"]["COMP_DOUBLE"];
Solver.Conditions.COMP_MINIMALE_GAIN_TIME = solver["Conditions"]["COMP_MINIMALE_GAIN_TIME"];
Solver.Conditions.SWAP_MINIMALE_GAIN_TIME = solver["Conditions"]["SWAP_MINIMALE_GAIN_TIME"];
Solver.Conditions.COMP_MAXIMAL_PERTE_TIME = solver["Conditions"]["COMP_MAXIMAL_PERTE_TIME"];
Solver.Conditions.SAFETY_DEADLINE = solver["Conditions"]["SAFETY_DEADLINE"];
Solver.Conditions.DELAY_BEFORE_SWAP = solver["Conditions"]["DELAY_BEFORE_SWAP"];
Solver.Conditions.NO_SWAP_SLOTS = solver["Conditions"]["NO_SWAP_SLOTS"].get<std::vector<std::pair<unsigned int, unsigned int>>>();
for(auto& owl : logs.at(
"ORDO_WEB_LOGGERS"))
{
LogsConfiguration::loggerWebConf webConf;
webConf.jsonFormat = owl["jsonFormat"];
webConf.showType = owl["showType"];
for(auto& t : owl["types"])
{
webConf.types.push_back(t);
}
webConf.url = owl["url"];
webConf.port = owl["port"];
Logs.ORDO_WEB_LOGGERS.push_back(webConf);
}
for(auto& owl : logs.at(
"GENERATOR_WEB_LOGGERS"))
{
LogsConfiguration::loggerWebConf webConf;
webConf.jsonFormat = owl["jsonFormat"];
webConf.showType = owl["showType"];
for(auto& t : owl["types"])
{
webConf.types.push_back(t);
}
webConf.url = owl["url"];
webConf.port = owl["port"];
Logs.GENERATOR_WEB_LOGGERS.push_back(webConf);
}
for(auto& owl : logs.at(
"ORDO_FILE_LOGGERS"))
{
LogsConfiguration::loggerFileConf lfileConf;
lfileConf.jsonFormat = owl["jsonFormat"];
lfileConf.showType = owl["showType"];
for(auto& t : owl["types"])
{
lfileConf.types.push_back(t);
}
lfileConf.filename = owl["filename"];
Logs.ORDO_FILE_LOGGERS.push_back(lfileConf);
}
for(auto& owl : logs.at(
"GENERATOR_FILE_LOGGERS"))
{
LogsConfiguration::loggerFileConf lfileConf;
lfileConf.jsonFormat = owl["jsonFormat"];
lfileConf.showType = owl["showType"];
for(auto& t : owl["types"])
{
lfileConf.types.push_back(t);
}
lfileConf.filename = owl["filename"];
Logs.GENERATOR_FILE_LOGGERS.push_back(lfileConf);
}
for(auto& owl : logs.at(
"ORDO_STREAM_LOGGERS"))
{
LogsConfiguration::loggerStreamConf lfileConf;
lfileConf.jsonFormat = owl["jsonFormat"];
lfileConf.showType = owl["showType"];
for(auto& t : owl["types"])
{
lfileConf.types.push_back(t);
}
lfileConf.outstream = owl["outstream"];
Logs.ORDO_STREAM_LOGGERS.push_back(lfileConf);
}
for(auto& owl : logs.at(
"GENERATOR_STREAM_LOGGERS"))
{
LogsConfiguration::loggerStreamConf lfileConf;
lfileConf.jsonFormat = owl["jsonFormat"];
lfileConf.showType = owl["showType"];
for(auto& t : owl["types"])
{
lfileConf.types.push_back(t);
}
lfileConf.outstream = owl["outstream"];
Logs.GENERATOR_STREAM_LOGGERS.push_back(lfileConf);
}
Logs.ALGO_VERBOSE = logs["ALGO_VERBOSE"];
Logs.ALGO_VERBOSE_HEURISTICS = logs["ALGO_VERBOSE_HEURISTICS"];
Logs.ALGO_VERBOSE_NODES = logs["ALGO_VERBOSE_NODES"];
if (Meta.DOCKER) {
Solver.T_LIM_GLOBAL = std::stoi(std::getenv("T_LIM_GLOBAL"));
if(std::string(std::getenv("ENV_ORDO")) == std::string("DEV"))
{
Interface.SOLVER_URL = std::string(std::getenv("SOLVER_URL_DEV"));
Interface.SOLVER_PORT = std::stoi(std::getenv("SOLVER_PORT_DEV"));
}
else if(std::string(std::getenv("ENV_ORDO")) == std::string("REC"))
{
Interface.SOLVER_URL = std::string(std::getenv("SOLVER_URL_REC"));
Interface.SOLVER_PORT = std::stoi(std::getenv("SOLVER_PORT_REC"));
}
else if(std::string(std::getenv("ENV_ORDO")) == std::string("PROD"))
{
Interface.SOLVER_URL = std::string(std::getenv("SOLVER_URL_PROD"));
Interface.SOLVER_PORT = std::stoi(std::getenv("SOLVER_PORT_PROD"));
}
Global.ALLOW_SWAP = std::stoi(std::getenv("ALLOW_SWAP"));
if(std::getenv("ALLOW_COMP") != NULL)
Global.ALLOW_COMP = std::stoi(std::getenv("ALLOW_COMP"));
else
Global.ALLOW_COMP = false;
} else {
Solver.T_LIM_GLOBAL = solver["T_LIM_GLOBAL"];
Interface.SOLVER_URL = inter["SOLVER_URL"];
Interface.SOLVER_PORT = inter["SOLVER_PORT"];
Global.ALLOW_SWAP = general["ALLOW_SWAP"];
if(general.contains("ALLOW_COMP"))
{
Global.ALLOW_COMP = general["ALLOW_COMP"];
}
else
Global.ALLOW_COMP = false;
}
Global.MAXIMIZE_ADVANCE = general["MAXIMIZE_ADVANCE"];
Global.TIME_UNIT = general["TIME_UNIT"];
Global.SAVE_INPUT = general["SAVE_INPUT"];
Global.INPUT_LOCATION = general["INPUT_LOCATION"];
Global.SAVE_OUTPUT = general["SAVE_OUTPUT"];
Global.OUTPUT_FILENAME = general["OUTPUT_FILENAME"];
Global.OUTPUT_LOCATION = general["OUTPUT_LOCATION"];
Global.EPSILON = general["EPSILON"];
Global.SWAP_EPSILON = general["SWAP_EPSILON"];
Utils.MERGED_OUTPUT_LOCATION = utilitaires["MERGED_OUTPUT_LOCATION"];
Generator.NB_SITES_MAINTENANCE = generator.at("NB_SITES_MAINTENANCE").get<std::vector<unsigned int>>();
Generator.NB_VOIES = generator.at("NB_VOIES").get<std::vector<unsigned int>>();
Generator.NB_RAMES = generator.at("NB_RAMES").get<std::vector<unsigned int>>();
Generator.NB_INSTANCES_TO_GENERATE = generator["NB_INSTANCES_TO_GENERATE"];
Generator.MAX_BATCH_SIZE = generator["MAX_BATCH_SIZE"];
Generator.PROPORTION_RAME_SAINE = generator["PROPORTION_RAME_SAINE"];
Generator.PLAGE_NB_OPERATION_RAME = generator.at(
"PLAGE_NB_OPERATION_RAME").get<std::vector<std::pair<unsigned int, unsigned int>>>();
Generator.PLAGE_NB_INDISPO_VOIE = generator["PLAGE_NB_INDISPO_VOIE"];
Generator.NB_INFRA_TOTAL = generator["NB_INFRA_TOTAL"];
Generator.PLAGE_DUREE_OP = generator.at(
"PLAGE_DUREE_OP").get<std::vector<std::pair<unsigned int, unsigned int>>>();
Generator.PLAGE_CAPA_SITE = generator["PLAGE_CAPA_SITE"];
Generator.PLAGE_PROPORTION_DUREE_DIAG = generator["PLAGE_PROPORTION_DUREE_DIAG"];
Generator.PLAGE_DUREE_DISPO_RAME = generator["PLAGE_DUREE_DISPO_RAME"];
Generator.PLAGE_ECART_DISPO_RAME = generator["PLAGE_ECART_DISPO_RAME"];
Generator.PLAGE_NB_RDV_RAME = generator["PLAGE_NB_RDV_RAME"];
Generator.PROB_RDV_NON_ORIENTE = generator["PROB_RDV_NON_ORIENTE"];
Generator.PLAGE_DUREE_RDV = generator["PLAGE_DUREE_RDV"];
Generator.NB_SITES_GARE = generator.at("NB_SITES_GARE").get<std::vector<unsigned int>>();
Generator.MULTI_OP_INSTANCE = generator["MULTI_OP_INSTANCE"];
Generator.SWAP_INSTANCE = generator["SWAP_INSTANCE"];
Generator.RECOMPO_INSTANCE = generator["RECOMPO_INSTANCE"];
Generator.BATCHING = generator["BATCHING"];
Generator.WITH_RDVS = generator["WITH_RDVS"];
Generator.NB_JOBS = generator.at("NB_JOBS").get<std::vector<unsigned int>>();
Generator.PLAGE_DUREE_DISPO_RAME_GARE = generator.at(
"PLAGE_DUREE_DISPO_RAME_GARE").get<std::pair<unsigned int, unsigned int>>();
Generator.PLAGE_ECART_DISPO_RAME_GARE = generator.at(
"PLAGE_ECART_DISPO_RAME_GARE").get<std::pair<unsigned int, unsigned int>>();
Generator.PLAGE_NB_RDV_RAME = generator.at(
"PLAGE_NB_RDV_RAME").get<std::pair<unsigned int, unsigned int>>();
}
catch (std::exception &e) {
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "Error reading config file : " + std::string(e.what()));
Solver = SolverConfiguration();
Logs = LogsConfiguration();
Meta = MetaConfiguration();
Global = GeneralConfiguration();
Interface = InterfaceConfiguration();
Utils = UtilsConfiguration();
Generator = GeneratorConfiguration();
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "API will try to work with default values");
}
}
void Configuration::overrideConfig(nlohmann::json& json) {
if(json.contains("configuration")) {
Configuration::Global.EPSILON = json["configuration"]["epsilon"].get<unsigned int>();
Configuration::Global.SWAP_EPSILON = json["configuration"]["swap_epsilon"].get<unsigned int>();
Configuration::Solver.Croisement.COMMON_TIME = json["configuration"]["common_time"].get<unsigned int>();
Configuration::Solver.RBS.NB_SOLUTION = json["configuration"]["nb_solution"].get<unsigned int>();
if(Configuration::Solver.RBS.NB_BRANCH < Configuration::Solver.RBS.NB_SOLUTION)
Configuration::Solver.RBS.NB_BRANCH = Configuration::Solver.RBS.NB_SOLUTION;
Configuration::Solver.Conditions.RLT_WITH_UM_RDV_OR_US = json["configuration"]["except_for_us"].get<bool>();
Configuration::Solver.Conditions.RLT_WITH_UM_RDV_OR_US_RDV = json["configuration"]["allow_only_on_rdv"].get<bool>();
Configuration::Solver.Conditions.SWAP_NO_RDV = json["configuration"]["swap_no_rdv"].get<bool>();
Configuration::Solver.Conditions.SWAP_NOT_IMPERATIVE_RDV = json["configuration"]["swap_no_imperative_rdv"].get<bool>();
Configuration::Solver.Conditions.SWAP_ALL_RESCHEDULE_RDV = json["configuration"]["swap_reschedule_rdv"].get<bool>();
Configuration::Solver.Conditions.SAFETY_DEADLINE = 48;//json["configuration"]["safety_deadline"].get<bool>();
Configuration::Solver.Conditions.DELAY_BEFORE_SWAP = 2;//json["configuration"]["safety_deadline"].get<bool>();
Configuration::Solver.Conditions.NO_SWAP_SLOTS = {{7,10}, {17,20}};//json["configuration"]["safety_deadline"].get<bool>();
}
}
}
+584
View File
@@ -0,0 +1,584 @@
#ifndef CONFIGURATIONS_H
#define CONFIGURATIONS_H
#include <climits>
#include <string>
#include <map>
#include "../Logs/Loggers/Logger.h"
#include <nlohmann/json.hpp>
namespace configlib {
/*! @file Configurations.h*/
/**
* @brief Struct defining the possible parameters for the different algorithms
*/
using SolverConfiguration = struct solverConfig {
using RBSConfiguration = struct RBSConfig{
/**
* The weight to the cost of the maximum flow min cost algorithm relatively to the cost of list heuristics. Used only in the dedicated heuristic TODO change for creating heuristics specific parameters
*/
float ALPHA = 0.8f;
bool FLOW = true;
bool LISTHEURISTICS = true;
bool SAVEALLUB = false;
unsigned int NB_LISTHEURISTICS = 1;//max 6
/**
* The maximum number of explored branches at the same time in the dedicated heuristic. Used only in the dedicated heuristic TODO change for creating heuristics specific parameters
*/
unsigned int NB_BRANCH = 1U;
unsigned int NB_SOLUTION = 1U;
bool LOCAL_RECOVERING = false;
bool GLOBAL_RECOVERING = false;
bool SWAP_FILTERS = false;
bool NODE_FILTERS = false;
};
using CONDITIONConfiguration = struct CondConfig{
bool RLT_WITH_UM_RDV_OR_US = false;
bool RLT_WITH_UM_RDV_OR_US_RDV = false;
bool SWAP_NO_RDV = false;
bool SWAP_NOT_IMPERATIVE_RDV = false;
bool SWAP_ALL_RESCHEDULE_RDV = false;
bool SWAP_COMP_ON_NULL_US = false;
bool COMP_ONLY_ON_EQU_RDV = false;
bool COMP_TRIPLE_NOT_IN_MIDDLE = false;
bool COMP_DOUBLE = false;
unsigned int COMP_MINIMALE_GAIN_TIME = 0;
unsigned int SWAP_MINIMALE_GAIN_TIME = 0;
unsigned int COMP_MAXIMAL_PERTE_TIME = UINT_MAX; //UINT_MAX permet de désactiver la condition
unsigned int SAFETY_DEADLINE = 48;
unsigned int DELAY_BEFORE_SWAP = 2;
std::vector<std::pair<unsigned int, unsigned int>> NO_SWAP_SLOTS = {{7,10}, {17,20}};
};
/**
* @brief Struct defining the possible parameters for the MIP solver
*/
using MIPConfiguration = struct MIPConfig {
/**
* @brief Maximum changes allowed for the xijt variables of the MIP. Limit the corresponding Hamming distance.
*/
int KX = 120;
/**
* @brief Maximum changes allowed for the yi variables of the MIP. Limit the corresponding Hamming distance.
*/
int KY = 25;
/**
* @brief Maximum changes allowed for the xijt variables of the MIP. Force the corresponding Hamming distance to be greater than this value.
*/
int KX_DIV = 50;
/**
* @brief Maximum changes allowed for the yi variables of the MIP. Force the corresponding Hamming distance to be greater than this value.
*/
int KY_DIV = 50;
/**
* @brief The maximum time allowed for finding a feasible solution before launching the matheuristic (Local Branching)
*/
double T_LIM_FIRST = 20.;
/**
* @brief The maximum time allowed for exploring the current solution space
*/
double T_LIM_EXPL_NODE = 20.;
/**
* @brief The maximum number of iteration processed in a row without improving the solution
*/
int LIM_NO_IMPROVE = 5;
};
/**
* @brief Struct defining the parameters that allows one to chose the behavior of the CP model
*/
using PPCConfiguration = struct PPCConfig {
/**
* @brief Maximum changes allowed for the interval variables of the CP. Limit the corresponding Hamming distance - UNUSED BECAUSE OBSOLETE
*/
int KX = 120;
/**
* @brief Maximum changes allowed for the interval variables corresponding to the diagnosis mode of the CP model. Limit the corresponding Hamming distance - UNUSED BECAUSE OBSOLETE
*/
int KY = 25;
/**
* @brief Maximum changes allowed for the interval variables of the CP. Force the corresponding Hamming distance to be greater than this value.
*/
int KX_DIV = 50;
/**
* @brief Maximum changes allowed for the interval variables corresponding to the diagnosis mode of the CP model. Force the corresponding Hamming distance to be greater than this value.
*/
int KY_DIV = 50;
/**
* @brief The maximum time allowed for finding a feasible solution before launching the CPHeuristic (Variable Partitionning Local Search)
*/
double T_LIM_FIRST = 20.;
/**
* @brief The maximum time allowed for exploring the current solution space
*/
double T_LIM_EXPL_NODE = 20.;
/**
* @brief The maximum number of iteration processed in a row without improving the solution
*/
int LIM_NO_IMPROVE = 5;
/**
* @brief The number of randomly selected intervals for the VPLS algorithm (both intensification and diversification)
*/
int NB_INTERVAL_VPLS = 2;
/**
* @brief The proportion of tracks to be randomly selected for the VPLS algorithm (both intensification and diversification)
*/
float PROPORTION_VOIE_VPLS = 0.2f;
/**
* @brief The size of the randomly selected intervals
*/
int INTERVAL_SIZE_VPLS = 14;
/**
* The maximum number of selected tracks for VPLS. Works combined with PROPORTION_VOIE_VPLS
*/
int MAX_VOIE_VPLS = 5;
};
/**
* @brief Struct defining the parameters that allows one to chose the behavior and condition of swaps algorithms
*/
using CroisementConfiguration = struct croisementConfig {
/**
* @brief Set the maximum number of evaluated swap configurations. Used only with algorithms that need precalculated configurations for swaps.
*/
unsigned int NB_MAX_SCENARIO_CROISEMENT = 100U;
/**
* @brief indicate if we call the modified MIP with modes for swaps, or if we precalculate swaps and call NBMAXSCENARIOROISEMENT the needed solver
*/
bool MULTIPLE_CALL_OR_MODIFIED_MIP = false;
/**
* @brief Minimum stopping time required for two multiple units to be swap. The value here corresponds to minutes.
*/
unsigned int COMMON_TIME = 45U;
};
/**
* @brief Struct defining the parameters that allows one to chose the behavior and condition of swaps algorithms
*/
using RecompoConfiguration = struct recompoConfig {
/**
* @brief Set the maximum number of evaluated swap configurations. Used only with algorithms that need precalculated configurations for swaps.
*/
unsigned int NB_MAX_SCENARIO_RECOMPO = 100U;
/**
* @brief Minimum stopping time required for two multiple units to be swap. The value here corresponds to minutes.
*/
unsigned int COMMON_TIME = 120U;
};
/**
* @brief MIP configuration
*/
MIPConfiguration MIP;
/**
* @brief CP configuration
*/
PPCConfiguration PPC;
/**
* @brief Swaps configuration
*/
CroisementConfiguration Croisement;
/**
* @brief Recompo configuration
*/
RecompoConfiguration Recompo;
RBSConfiguration RBS;
CONDITIONConfiguration Conditions;
/**
* @brief Objective function name - OBSOLETE BUT USED TODO
*/
std::string FCT_OBJECTIF = "obj1";
/**
* @brief The maximum computation time allowed
*/
double T_LIM_GLOBAL = 300.;
/**
* @brief The planning horizon - in practice between 5 and 7 days
*/
unsigned int NB_DAYS_TO_PLANIF = 7U;
};
/**
* @brief Struct defining the different parameters for logs redirections
*/
using LogsConfiguration = struct _logsConfig {
using LoggerFileConf = struct loggerFileConf{
std::vector<unsigned int> types;
bool showType;
bool jsonFormat;
std::string filename;
};
using LoggerWebConf = struct loggerWebConf{
std::vector<unsigned int> types;
bool showType;
bool jsonFormat;
std::string url;
unsigned int port;
};
using LoggerStreamConf = struct loggerStreamConf{
std::vector<unsigned int> types;
unsigned int outstream;
bool showType;
bool jsonFormat;
};
bool ALGO_VERBOSE = false;
bool ALGO_VERBOSE_HEURISTICS = false;
bool ALGO_VERBOSE_NODES = false;
/**
* @brief The files for logging. Each file can log errors, info or other information depending on the integers given to the vector of uint
*/
std::vector<LoggerFileConf> ORDO_FILE_LOGGERS;
/**
* @brief The addresses for logging. Each address will receive the demanded log informations depending on the integers given to the first vector of uint
*/
std::vector<LoggerWebConf> ORDO_WEB_LOGGERS;
std::vector<LoggerStreamConf> ORDO_STREAM_LOGGERS;
/**
* @brief The files for logging. Each file can log errors, info or other information depending on the integers given to the vector of uint.
* This configuration only affects the instance generator.
*/
std::vector<LoggerFileConf> GENERATOR_FILE_LOGGERS;
std::vector<LoggerStreamConf> GENERATOR_STREAM_LOGGERS;
/**
* @brief The addresses for logging. Each address will receive the demanded log informations depending on the integers given to the first vector of uint
* This configuration only affects the instance generator.
*/
std::vector<LoggerWebConf> GENERATOR_WEB_LOGGERS;
};
/**
* @brief Struct defining the parameters of the interface system. Used for redirecting users requests
*/
using InterfaceConfiguration = struct _interfaceConfig {
/**
* @brief URL to the http server waiting for request to solvers
*/
std::string SOLVER_URL = "192.168.1.74";
/**
* @brief Port used by the http server waiting for requests to solvers
*/
unsigned int SOLVER_PORT = 5000U;
};
/**
* @brief Struct defining the parameters specifics to some function outside the scope of ordo_c or the instance generator
*/
using UtilsConfiguration = struct _utilsConfig {
/**
* @brief The path to the merged instances - OBSOLETE
*/
std::string MERGED_OUTPUT_LOCATION = "Merged";
};
/**
* @brief Struct defining meta informations of the solver
*/
using MetaConfiguration = struct _metaConfig {
/**
* Indicates if the solver is used inside a docker container
*/
bool DOCKER = false;
/**
* Indicates the version of the solver. Used in server mode mostly
*/
std::string VERSION = "1.0";
};
/**
* @brief Struct defining parameters available globally across the tool
*/
using GeneralConfiguration = struct _generalConfig {
/**
* @brief The value of the tiniest time value
* The default value 1 corresponds to 1 hour.
* Each increment of this value correspond to 1 hour divided by the parameter. Ex : TIME_UNIT = 2 means that the tiniest element of time lasts half an hour
*/
unsigned int TIME_UNIT = 1U;
/**
* @brief Indicate if we save the input instance file
*/
bool SAVE_INPUT = false;
/**
* @brief indicate if we save the result of the algorithm
*/
bool SAVE_OUTPUT = false;
bool OUTPUT_FILENAME = false;
/**
* @brief indicate if we allow to swap multiple units at particular train stations
* without recomposition
*/
bool ALLOW_SWAP = false;
/**
* @brief indicate if we allow to modify compositions at particular train stations
*/
bool ALLOW_COMP = false;
/**
* @brief Indicate the objective function. True means, we try to maximize the advance, which means put each job at the earliest time possible.
* False means that we minimize the tardiness of jobs. Before the due date, the cost in the objective function will be zero
*/
bool MAXIMIZE_ADVANCE = false;
/**
* @brief The maximum budget of jobs put in diagnosis mode
*/
unsigned int EPSILON = 30U;
/**
* @brief The maximum budget of performed swap
*/
unsigned int SWAP_EPSILON = 15U;
/**
* @brief The path where to save the instances if SAVE_INPUT is at true or the instance generator is used
*/
std::string INPUT_LOCATION = "Instances";
/**
* @brief The path where to save the results if SAVE_OUTPUT is at true
*/
std::string OUTPUT_LOCATION = "Planifications";
};
/**
* @brief Struct defining parameters that allows one to setup the instance generator
*/
using GeneratorConfiguration = struct _generatorConfig {
/**
* @brief The numbers of maintenance site. Each value set a type
*/
std::vector<unsigned int> NB_SITES_MAINTENANCE = {3U, 5U, 8U};
/**
* @brief The numbers of trains. Each value set a type
*/
std::vector<unsigned int> NB_RAMES = {10U, 50U, 100U};
/**
* @brief The numbers of tracks. Each value set a type
*/
std::vector<unsigned int> NB_VOIES = {20U, 40U, 60U};
/**
* The number of instances to generate per type.
* A type is defined as : NB_SITES_MAINTENANCE_NB_SITES_GARE_NB_VOIES_NB_RAMES_NB_JOBS
* The number of instances to be generated is : |NB_SITES_MAINTENANCE| * |B_SITES_GARE| * |NB_VOIES| * |NB_RAMES| * |NB_JOBS| * |NB_INSTANCES_TO_GENERATE|
*/
unsigned int NB_INSTANCES_TO_GENERATE = 1U;
unsigned int MAX_BATCH_SIZE = 300U;
/**
* @brief The number of type of infrastructure that can appear in an instance
*/
unsigned int NB_INFRA_TOTAL = 5U;
/**
* @brief The proportion of trains without jobs
*/
double PROPORTION_RAME_SAINE = 0.2;
/**
* @brief Indicate the ranges of number of jobs for a train depending of the severity. The severity of a train will be selected randomly, then, the corresponding range will be used for the train
*/
std::vector<std::pair<unsigned int, unsigned int>> PLAGE_NB_OPERATION_RAME = {{1U, 3U},
{3U, 5U},
{6U, 9U}};
/**
* @brief The number of time slot to be removed from a track's availabilities
*/
std::pair<unsigned int, unsigned int> PLAGE_NB_INDISPO_VOIE = {3U, 10U};
/**
* @brief Depending of the hierarchy of a job, this defines the ranges of processing times
*/
std::vector<std::pair<unsigned int, unsigned int>> PLAGE_DUREE_OP = {{2U, 6U},
{2U, 6U},
{2U, 6U}};
/**
* @brief The capacities of maintenance site for a given time slot. OBSOLETE at least for now
*/
std::pair<unsigned int, unsigned int> PLAGE_CAPA_SITE = {0U, 12U};
/**
* @brief The processing time in diagnosis mode for a job. This processing time is computed from a randomly selected proportion in this range and the range of processing times
*/
std::pair<double, double> PLAGE_PROPORTION_DUREE_DIAG = {0.23, 0.90};
/**
* @brief The range of the size of availabilities of trains
*/
std::pair<unsigned int, unsigned int> PLAGE_DUREE_DISPO_RAME = {5U, 12U};
/**
* @brief The range of the size of unavailability of trains
*/
std::pair<unsigned int, unsigned int> PLAGE_ECART_DISPO_RAME = {6U, 24U};
/**
* @brief The range of the size of availabilities of trains specifically in train station, not maintenance site (for swap algorithms)
*/
std::pair<unsigned int, unsigned int> PLAGE_DUREE_DISPO_RAME_GARE = {1U, 4U};
/**
* @brief The range of the size of unavailability of trains specifically in train station, not maintenance site (for swap algorithms)
*/
std::pair<unsigned int, unsigned int> PLAGE_ECART_DISPO_RAME_GARE = {2U, 6U};
/**
* @brief The numbers of train stations available for swap slots. Each value sets a type.
*/
std::vector<unsigned int> NB_SITES_GARE = {3U, 5U, 8U};
/**
* Indicates if we generate instances where trains can hold multiple jobs
*/
bool MULTI_OP_INSTANCE = false;
/**
* @brief indicates if we generate instances where there are stations in which swap is allowed
*/
bool SWAP_INSTANCE = false;
/**
* @brief indicates if we generate instances where there are stations in which recompo is allowed
*/
bool RECOMPO_INSTANCE = false;
/**
* @brief indicates if we generate instances where there are appointments for preventive maintenance in the circulation
*/
bool WITH_RDVS = false;
/**
* @brief Indicates if we split the generated instances in subdirectories (used only in laboratory for scaled testing)
*/
bool BATCHING = false;
/**
* @brief The numbers of jobs. Each value sets a type.
*/
std::vector<unsigned int> NB_JOBS = {10U, 50U, 100U};
/**
* @brief The range of number of rdv type of availability for a train. unused for now
*/
std::pair<unsigned int, unsigned int> PLAGE_NB_RDV_RAME = {0U, 3U};
/**
* @brief The probability of a rdv to be non honored initially
*/
double PROB_RDV_NON_ORIENTE = 0.15;
std::pair<unsigned int, unsigned int> PLAGE_DUREE_RDV = {2U, 8U};
};
/**
* @class Configuration
* @brief Class defining the configuration static attributes
* Purely static
*/
class Configuration {
public:
/**
* @brief The solver configuration
*/
static SolverConfiguration Solver;
/**
* @brief The logs configuration
*/
static LogsConfiguration Logs;
/**
* @brief The utils configuration
*/
static UtilsConfiguration Utils;
/**
* @brief The interface configuration
*/
static InterfaceConfiguration Interface;
/**
* @brief The meta configuration
*/
static MetaConfiguration Meta;
/**
* @brief The genera configuration
*/
static GeneralConfiguration Global;
/**
* @brief The instance generator configuration
*/
static GeneratorConfiguration Generator;
/**
* @brief Function to initialize the different configuration from a file
* @param fileConf the path to the config file
*/
static void init(const std::string& fileConf);
static void overrideConfig(nlohmann::json& json);
};
}
#endif
+36
View File
@@ -0,0 +1,36 @@
#include "IOHelper.h"
#include <filesystem>
#include <fstream>
namespace loggerlib {
void IOHelper::dump(const std::string& location, const std::string& content, const std::string& fileName) {
std::filesystem::directory_entry directory(location);
if (directory.exists()) {
if (directory.is_directory()) {
std::string path;
if (fileName.empty()) {
time_t now = time(nullptr);
struct tm *timeLoc = localtime(&now);
std::string timestamp =
std::to_string(timeLoc->tm_year + 1900) + "_" + std::to_string(timeLoc->tm_mon + 1) + "_" +
std::to_string(timeLoc->tm_mday) + "T" + std::to_string(timeLoc->tm_hour) + "_" +
std::to_string(timeLoc->tm_min) + "_" + std::to_string(timeLoc->tm_sec) + "Z.json";
path = location + "/" + timestamp;
} else {
path = location + "/" + fileName;
}
std::ofstream file(path, std::ios::out | std::ios::trunc);
file << content << std::endl;
file.close();
} else {
std::ofstream file(location, std::ios::out | std::ios::trunc);
file << content << std::endl;
file.close();
}
directory.refresh();
} else {
std::filesystem::create_directory(location);
dump(location, content, fileName);
}
}
}
+29
View File
@@ -0,0 +1,29 @@
#ifndef IOHELPER_H
#define IOHELPER_H
#include <string>
namespace loggerlib {
/**
* @class IOHelper
* @brief classe simplifiant l'criture de messages dans des sorties
*/
class IOHelper {
private:
public:
/**
* @brief Constructeur par defaut. Classe abstraite, on ne permet pas l'instanciation
*/
IOHelper() = delete;
/**
* @brief Fonction d'criture simple d'un message un endroit (fichier ou dossier)
* Si le fichier n'existe pas, le cr. Si le dossier n'existe pas le cre.
* Si un dossier est prcis, la sauvegarde se fera dans un fichier dont le nom est le timestamp du moment de l'criture
* @param location l'endroit ou crire le message
* @param content le message crire.
*/
static void dump(const std::string& location, const std::string& content, const std::string& fileName = "");
};
}
#endif
+32
View File
@@ -0,0 +1,32 @@
#include "FileLogger.h"
#include "nlohmann/json.hpp"
namespace loggerlib {
FileLogger::FileLogger(std::string& filePath, bool showType, bool jsonFormat, std::vector<unsigned int>& typesV): Logger(showType, jsonFormat, typesV) {
m_filePath = filePath;
std::ofstream file(m_filePath, std::ios::trunc | std::ios::out);
file.close();
}
void FileLogger::notify(const std::string& timestamp, const ELOGGER_TYPES type, const std::string& message) {
std::ofstream file(m_filePath, std::ios::app | std::ios::out);
if(isJsonFormat())
{
nlohmann::json json = nlohmann::json::object();
json["timestamp"] = timestamp;
json["message"] = message;
if(isShowType())
json["type"] = loggerTypesString[type];
file << json.dump() << std::endl;
}
else
{
file << "[" + timestamp + "]";
if(isShowType())
file << "<" + loggerTypesString[type] + ">";
file << "\t" + message << std::endl;
}
file.close();
}
}
+43
View File
@@ -0,0 +1,43 @@
#ifndef FILELOGGER_H
#define FILELOGGER_H
#include <iostream>
#include <string>
#include "Logger.h"
#include <fstream>
namespace loggerlib {
/*! @file FileLogger.h*/
/**
* @class FileLogger
* @brief Classe dfinissant un logger concret, communiquant par l'criture dans un fichier
*/
class FileLogger : public Logger {
private:
/**
* @brief le chemin du fichier de log dans lequel crire
*/
std::string m_filePath;
public:
/**
* @brief Constructeur par dfaut, inutilisable
*/
FileLogger() = delete;
/**
* @brief Constructeur de confort, le chemin du fichier de log est donn en paramtre
* @param Le chemin du fichier de log dans lequel crire
*/
explicit FileLogger(std::string& filePath, bool showType, bool jsonFormat, std::vector<unsigned int>& typesV);
/**
* @brief Surcharge de la fonction abstraite notify
* @param message le message crire dans le fichier
* Envoi du message : ici dans le fichier m_filePath
*/
void notify(const std::string& timestamp, ELOGGER_TYPES type, const std::string& message) override;
[[maybe_unused]] std::string getFilePath() { return m_filePath; };
};
}
#endif
+25
View File
@@ -0,0 +1,25 @@
#include "Logger.h"
#include <utility>
namespace loggerlib {
std::unordered_map<ELOGGER_TYPES, std::vector<Logger *>> Logger::systemLogger;
std::unordered_map<ELOGGER_TYPES, std::string> Logger::loggerTypesString = {
std::make_pair(LOGGER_ERRORS, "ERROR"),
std::make_pair(LOGGER_PROGRESS, "PROGRESS"),
std::make_pair(LOGGER_STATISTICS, "STATS"),
std::make_pair(LOGGER_INFO, "INFO"),
std::make_pair(LOGGER_DEBUG, "DEBUG"),
std::make_pair(LOGGER_WARRNING, "WARRNING")
};
std::unordered_map<ELOGGER_TYPES, std::pair<std::string, std::string>> Logger::loggerColorsString = {
std::make_pair(LOGGER_ERRORS, std::make_pair("\033[1;31m","\033[0m")),
std::make_pair(LOGGER_PROGRESS, std::make_pair("\033[1;32m","\033[0m")),
std::make_pair(LOGGER_STATISTICS, std::make_pair("\033[1;34m","\033[0m")),
std::make_pair(LOGGER_INFO, std::make_pair("\033[1;33m","\033[0m")),
std::make_pair(LOGGER_DEBUG, std::make_pair("\033[1;36m","\033[0m")),
std::make_pair(LOGGER_WARRNING, std::make_pair("\033[1;35m","\033[0m"))
};
Logger::~Logger() = default;
}
+190
View File
@@ -0,0 +1,190 @@
#ifndef LOGGER_H
#define LOGGER_H
#include <iostream>
#include <string>
#include <unordered_map>
#include <set>
#include <vector>
#include <chrono>
#include <iomanip>
namespace loggerlib {
/**
* @brief enum indiquant les diffrents types de logs
*/
enum ELOGGER_TYPES : unsigned int {
LOGGER_PROGRESS,
LOGGER_ERRORS,
LOGGER_STATISTICS,
LOGGER_INFO,
LOGGER_DEBUG,
LOGGER_WARRNING
};
/**
* @class Logger
* @brief Classe dcrivant l'outil de log. Abstraite, elle permet de dfinir la manire dont on communique les logs
*/
class Logger {
private:
/**
* @brief La map contenant tous les logger pour chaque type de logs. Une notification sur un type agit sur tous les logger du type
*/
static std::unordered_map<ELOGGER_TYPES, std::vector<Logger *>> systemLogger;
std::vector<unsigned int> types;
bool showType;
bool jsonFormat;
public:
/**
* @brief La map contenant titre informatif les noms au format string des types de log
*/
static std::unordered_map<ELOGGER_TYPES, std::string> loggerTypesString;
static std::unordered_map<ELOGGER_TYPES, std::pair<std::string, std::string>> loggerColorsString;
[[nodiscard]] const std::vector<unsigned int> &getTypes() const {
return types;
}
void setTypes(const std::vector<unsigned int> &typesV) {
Logger::types = typesV;
}
[[nodiscard]] bool isShowType() const {
return showType;
}
void setShowType(bool st) {
showType = st;
}
[[nodiscard]] bool isJsonFormat() const {
return jsonFormat;
}
void setJsonFormat(bool jf) {
jsonFormat = jf;
}
public:
Logger(bool show, bool json, std::vector<unsigned int>& typesV): types(typesV),showType(show), jsonFormat(json){};
/**
* @brief Fonction virtuelle d'envoi de message (log)
* @param message le mesage envoyer
* @return NEANT
*/
virtual void notify(const std::string& timestamp, const ELOGGER_TYPES type, const std::string& message) {};
/**
* @brief le destructeur
*/
virtual ~Logger();
/**
* @brief Gette sur la map des logger
* @return la map contenant les logger par rfrence
*/
static std::unordered_map<ELOGGER_TYPES, std::vector<Logger *>> &getSystemLogger() {
return systemLogger;
}
/**
* @brief Fonction principale faisant appel aux fonctions notify de chaque logger concern par le paramtre type
* @param type le type de logger qui doit envoyer le message
* @param message le message envoyer
* @return NEANT
*/
static void systemNotify(ELOGGER_TYPES type, const std::string& message) {
if (!systemLogger[type].empty()) {
char pretty = '0';
time_t now = time(
nullptr); //returns the current calendar time of the system in number of seconds elapsed since January 1, 1970.
struct tm *timeLoc = localtime(&now);
std::string year = std::to_string(1900 + timeLoc->tm_year);
std::string month = std::to_string(1 + timeLoc->tm_mon);
std::string day = std::to_string(timeLoc->tm_mday);
std::string hour = std::to_string(timeLoc->tm_hour);
std::string min = std::to_string(timeLoc->tm_min);
std::string sec = std::to_string(timeLoc->tm_sec);
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count() % 1000;
std::string millistr;
std::stringstream ss;
ss << std::setprecision(3) << millis;
ss >> millistr;
if (1 + timeLoc->tm_mon < 10)
month.insert(month.begin(), pretty);
if (timeLoc->tm_mday < 10)
day.insert(day.begin(), pretty);
if (timeLoc->tm_hour < 10)
hour.insert(hour.begin(), pretty);
if (timeLoc->tm_min < 10)
min.insert(min.begin(), pretty);
if (timeLoc->tm_sec < 10)
sec.insert(sec.begin(), pretty);
if(millistr.size() == 1)
millistr.push_back('0');
if(millistr.size() == 2)
millistr.push_back('0');
std::string timestamp = year + "-" + month + "-" + day + "T" + hour + ":" + min + ":" + sec + "." + millistr;
for (Logger *log: systemLogger[type]) {
log->notify(timestamp,type, message);
}
}
};
/**
* @brief Fonction d'ajout d'un logger d'un type donn
* @param type le type de log utilis pour le logger log
* @param log le log ajouter
* @return NEANT
*/
static void addLogger(ELOGGER_TYPES type, Logger *log) { systemLogger[type].push_back(log); };
/**
* @brief Fonction de nettoyage sans delete d'un type de logger
* @param type le type de log supprimer
* @return NEANT
*/
static void clearLogger(ELOGGER_TYPES type) { systemLogger[type].clear(); };
/**
* @brief Fonction de nettoyage avec delete d'un type de logger
* @param type le type de log supprimer
* @return NEANT
*/
static void destroy(ELOGGER_TYPES type) {
for (Logger *logger: systemLogger[type]) {
delete logger;
}
clearLogger(type);
};
/**
* @brief Fonction de nettoyage avec delete de tous les logger
* @return NEANT
*/
static void destroy() {
std::set<Logger *> loggersToDelete;
for (const auto& loggers: systemLogger) {
for (Logger *logger: loggers.second) {
loggersToDelete.insert(logger);
}
}
for (Logger *logger: loggersToDelete) {
delete logger;
}
systemLogger.clear();
};
};
}
#endif
+47
View File
@@ -0,0 +1,47 @@
#include "StreamLogger.h"
#include "nlohmann/json.hpp"
namespace loggerlib {
StreamLogger::StreamLogger(unsigned int out, bool show, bool json, std::vector<unsigned int>& typesV): Logger(show, json, typesV), outStreamObject(
nullptr) {
outStream = out;
switch (out) {
case 0:
outStreamObject.rdbuf(std::cout.rdbuf());
break;
case 1:
outStreamObject.rdbuf(std::cerr.rdbuf());
break;
case 2:
outStreamObject.rdbuf(std::clog.rdbuf());
break;
default:
loggerlib::Logger::systemNotify(LOGGER_ERRORS, "ERROR while defining a outstreambuffer, unrecognized buffer");
break;
}
}
void StreamLogger::notify(const std::string& timestamp, const ELOGGER_TYPES type, const std::string& message) {
if(isJsonFormat())
{
nlohmann::json json = nlohmann::json::object();
json["timestamp"] = timestamp;
json["name"] = "ORDO";//TODO a check
json["appName"] = "ORDO";//TODO a check
if(isShowType())
json["level"] = loggerTypesString[type];
json["message"] = message;
outStreamObject << json.dump() << std::endl;
}
else
{
std::string final = "[\033[1;34m" + timestamp + "\033[0m]";
if(isShowType())
final += "<" + loggerColorsString[type].first + loggerTypesString[type] + loggerColorsString[type].second + ">";
final += "\t" + message;
outStreamObject << final << std::endl;
}
}
}
+42
View File
@@ -0,0 +1,42 @@
#ifndef STREAMLOGGER_H
#define STREAMLOGGER_H
#include <iostream>
#include <string>
#include "Logger.h"
namespace loggerlib {
/*! @file StreamLogger.h*/
/**
* @class StreamLogger
* @brief Classe dfinissant un logger concret, communiquant par l'criture dans un stream
*/
class StreamLogger : public Logger {
private:
/**
* @brief le chemin du fichier de log dans lequel crire
*/
unsigned int outStream;
std::ostream outStreamObject;
//static std::unordered_map<unsigned int, std::ostream*> strandardsIndex;
public:
/**
* @brief Constructeur par dfaut, inutilisable
*/
StreamLogger(unsigned int out, bool show, bool json, std::vector<unsigned int>& typesV);
/**
* @brief Constructeur de confort, le chemin du fichier de log est donn en paramtre
* @param Le chemin du fichier de log dans lequel crire
*/
//StreamLogger(std::ostream& outStream);
/**
* @brief Surcharge de la fonction abstraite notify
* @param message le message crire dans le stream
* Envoi du message : ici dans le fichier m_outStream
*/
void notify(const std::string& timestamp, ELOGGER_TYPES type, const std::string& message) override;
};
}
#endif
+32
View File
@@ -0,0 +1,32 @@
#include "WebLogger.h"
#include "nlohmann/json.hpp"
namespace loggerlib {
WebLogger::WebLogger(const std::string& url, unsigned int port, bool show, bool json, std::vector<unsigned int>& typesV) : Logger(show, json, typesV), m_client(url, port) {
m_url = url;
m_port = port;
}
void WebLogger::notify(const std::string& timestamp, const ELOGGER_TYPES type, const std::string& message) {
if(isJsonFormat())
{
std::string format = "application/json";
nlohmann::json json;
json["timestamp"] = timestamp;
if(isShowType())
json["type"] = loggerTypesString[type];
json["message"] = message;
m_client.Post("/", json.dump(), format.c_str());
}
else
{
std::string final = "[" + timestamp + "]";
if(isShowType())
final += "["+ loggerTypesString[type] + "]";
final += "\t" + message;
m_client.Post("/", final, "text/plain");
}
}
}
+56
View File
@@ -0,0 +1,56 @@
#ifndef WEBLOGGER_H
#define WEBLOGGER_H
#include <iostream>
#include <string>
#include "httplib.h"
#include "Logger.h"
namespace loggerlib {
/*! @file WebLogger.h*/
/**
* @class WebLogger
* @brief Classe dcrivant un logger concret permettant la communication d'un message par requte HTTP
*/
class WebLogger : public Logger {
private:
/**
* @brief l'url laquelle envoyer le message
*/
std::string m_url;
/**
* @brief le port associ l'URL
*/
unsigned int m_port;
/**
* @brief l'instance du client HTTP utilis (permet d'viter la cration d'un client chaque notification)
*/
httplib::Client m_client;
public:
/**
* @brief Constructeur par defaut, inutilisable
*/
WebLogger() = delete;
/**
* @brief Constructeur de confort avec les informations de communication en paramtres
* @param url l'url laquelle envoyer le message
* @param port le port associ l'url
*/
WebLogger(const std::string& url, unsigned int port, bool show, bool json, std::vector<unsigned int>& typesV);
/**
* @brief surchage de la fonction de notification
* Envoi du message : ici par requte HTTP
* @param message le message envoyer
* @return NEANT
*/
void notify(const std::string& timestamp, ELOGGER_TYPES type, const std::string& message) override;
};
}
#endif
+37
View File
@@ -0,0 +1,37 @@
#include "CreneauHoraire.h"
namespace modellib {
CreneauHoraire::CreneauHoraire(const CreneauHoraire &creneau) : m_debut(creneau.getDebutC()),
m_fin(creneau.getFinC()) {
}
CreneauHoraire::CreneauHoraire(const SolverDate &pdebut, const SolverDate &pfin)
: m_debut(pdebut), m_fin(pfin) {
}
nlohmann::json CreneauHoraire::to_json(bool format) const {
nlohmann::json creneau = nlohmann::json::object();
if (format) {
creneau["debut"] = m_debut.to_json(true);
creneau["fin"] = m_fin.to_json(true);
} else {
creneau["debut"] = m_debut.to_json();
creneau["fin"] = m_fin.to_json();
}
return creneau;
}
CreneauHoraire CreneauHoraire::from_json(nlohmann::json &json, bool format) {
CreneauHoraire creneau;
if (format) {
creneau.m_debut = SolverDate::from_json(json["debut"], true);
creneau.m_fin = SolverDate::from_json(json["fin"], true);
} else {
creneau.m_debut = SolverDate::from_json(json["debut"]);
creneau.m_fin = SolverDate::from_json(json["fin"]);
}
return creneau;
}
}
+190
View File
@@ -0,0 +1,190 @@
#ifndef CRENEAUHORAIRE
#define CRENEAUHORAIRE
#include <vector>
#include <iostream>
#include "Date.h"
namespace modellib {
/*! @file CreneauHoraire.h*/
/**
* @class CreneauHoraire
* @brief Class describing a time slot
*/
class CreneauHoraire {
private:
/**
* @brief Begin date
*/
SolverDate m_debut;
/**
* @brief End date
*/
SolverDate m_fin;
public:
/**
* @brief Default constructor
*/
CreneauHoraire() = default;
/**
* @brief Copy constructor
* @param creneau the time slot to copy
*/
CreneauHoraire(const CreneauHoraire &creneau);
/**
* @brief Constructor
* @param debut begin of the time slot
* @param fin end of the time slot
*/
CreneauHoraire(const SolverDate &debut, const SolverDate &fin);
/**
* @brief Destructor
*/
virtual ~CreneauHoraire() = default;
/**
* @brief Getter to the beginning of the time slot, allow modification
* @return beginning of the time slot
*/
inline SolverDate &getDebut() { return m_debut; }
/**
* @brief Getter to the beginning of the time slot, doesnt allow modification
* @return beginning of the time slot
*/
[[nodiscard]] inline SolverDate const &getDebutC() const { return m_debut; }
/**
* @brief Getter to the end of the time slot, allow modification
* @return end of the time slot
*/
inline SolverDate &getFin() { return m_fin; }
/**
* @brief setter to the beginning of the time slot
* @param deb
*/
void setDebut(const SolverDate& deb) { m_debut = deb; };
/**
* @brief setter to the end of the time slot
* @param fin
*/
void setFin(const SolverDate& fin) { m_fin = fin; };
/**
* @brief Getter to the end of the time slot, doesnt allow modification
* @return end of the time slot
*/
[[nodiscard]] inline SolverDate const &getFinC() const { return m_fin; }
/**
* @brief Function to export the object in json format
* @param format if true the format respect the following "aaaa-mm-jjThh:mm:ssZ" else "annee": aaaa, "mois": mm, etc...
* @return the corresponding json
*/
[[nodiscard]] nlohmann::json to_json(bool format = false) const;
/**
* @brief Function to create a CreneauHoraire object from a json description
* @param json the input json
* @param format if true the format respect the following "aaaa-mm-jjThh:mm:ssZ" else "annee": aaaa, "mois": mm, etc...
* @return the newly created CreneauHoraire object
*/
static CreneauHoraire from_json(nlohmann::json &json, bool format = false);
/**
* @brief Function to check if two time slots are overlapping and return the overlap period
* @param trainSlot The first time slot
* @param trackSlot The second time slot
* @return a pair indicating if there is a match in the first value, and the overlapping period in the second value. The second value contains the beginning date of the overlap (relatively to date zero) and the duration of the overlap
*/
inline static std::pair<bool, std::pair<unsigned short, unsigned short>>
checkSlotsCompatibility(const CreneauHoraire &trainSlot, const CreneauHoraire &trackSlot) {
std::pair<bool, std::pair<unsigned short, unsigned short>> match;
match.first = false;
/*if (trackSlot.getDebutC() <= trainSlot.getDebutC() && trainSlot.getFinC() <= trackSlot.getFinC()
|| trainSlot.getDebutC() <= trackSlot.getDebutC() && trackSlot.getFinC() <= trainSlot.getFinC()
|| trackSlot.getDebutC() <= trainSlot.getFinC() && trainSlot.getDebutC() <= trackSlot.getDebutC()
|| trainSlot.getDebutC() <= trackSlot.getFinC() && trackSlot.getDebutC() <= trainSlot.getDebutC()
|| trackSlot.getFinC() <= trainSlot.getFinC() && trainSlot.getDebutC() <= trackSlot.getFinC()
|| trainSlot.getFinC() <= trackSlot.getFinC() && trackSlot.getDebutC() <= trainSlot.getFinC()
)*/
unsigned short begTrain = trainSlot.getDebutC().getRelativeDate();
unsigned short begTrack = trackSlot.getDebutC().getRelativeDate();
unsigned short endTrain = trainSlot.getFinC().getRelativeDate();
unsigned short endTrack = trackSlot.getFinC().getRelativeDate();
if ((begTrack <= begTrain && endTrain <= endTrack)
|| (begTrain <= begTrack && endTrack <= endTrain)
|| (begTrack <= endTrain && begTrain <= begTrack)
|| (begTrain <= endTrack && begTrack <= begTrain)
|| (endTrack <= endTrain && begTrain <= endTrack)
|| (endTrain <= endTrack && begTrack <= endTrain)
) {
unsigned short overlapBeginTime;
unsigned short overlapEndTime;
if ((begTrain) <= begTrack) {
overlapBeginTime = begTrack;// - *SolverDate::getDateDebut();
if ((trackSlot.getDebutC().t_timestampMinutes -
SolverDate::getDateDebut().t_timestampMinutes) % (60U / configlib::Configuration::Global.TIME_UNIT) !=
0U) {
overlapBeginTime++;
}
} else {
overlapBeginTime = begTrain; //- *SolverDate::getDateDebut();
if ((trainSlot.getDebutC().t_timestampMinutes -
SolverDate::getDateDebut().t_timestampMinutes) % (60U / configlib::Configuration::Global.TIME_UNIT) !=
0U) {
overlapBeginTime++;
}
}
if ((endTrain) <= endTrack) { overlapEndTime = (endTrain); }// - *SolverDate::getDateDebut(); }
else { overlapEndTime = endTrack; } //- *SolverDate::getDateDebut(); }
match.first = true;
match.second.first = overlapBeginTime;
match.second.second = overlapEndTime - overlapBeginTime;
}
return match;
}
/**
* @brief Function to check if two time slots have at least a certain duration of time (in minutes) in common.
* Similar to checkSlotsCompatibility but is needed for more precision (less than an hour of time unit) in swap algorithms.
* @param cr1 the first time slot
* @param cr2 the second time slot
* @param duration the duration in minutes we want to check
* @return true if the overlap timing if bigger of equal to duration. False otherwise or if there is no overlap
*/
inline static bool checkCommonDuration(const CreneauHoraire &cr1, const CreneauHoraire &cr2,
unsigned int duration)//duration in minutes under an hour
{
unsigned int beg = std::max(cr1.getDebutC().t_timestampMinutes,
cr2.getDebutC().t_timestampMinutes);
unsigned int end = std::min(cr1.getFinC().t_timestampMinutes,
cr2.getFinC().t_timestampMinutes);
return (end >= beg) && (end - beg) >= duration;
}
inline bool operator==(const CreneauHoraire& comp) const
{
return comp.getDebutC().getRelativeDate() == getDebutC().getRelativeDate() && comp.getFinC().getRelativeDate() == getFinC().getRelativeDate();
}
};
struct hash_creneau{
size_t operator()(const modellib::CreneauHoraire& val) const {
size_t h = std::hash<unsigned int>()(val.getDebutC().getRelativeDate());
size_t h2 = std::hash<unsigned int>()(val.getFinC().getRelativeDate());
return h^h2;
}
};
}
#endif
+348
View File
@@ -0,0 +1,348 @@
#include "CroisementUM.hpp"
#include "STFInstance.h"
#include "STFMockInstance.hpp"
#include "UM.h"
#include <algorithm>
#include <climits>
namespace modellib {
nlohmann::json CroisementUM::to_json() {
nlohmann::json json = nlohmann::json::object();
auto slot = getPotentialSwapSlot();
json["debutPotentiel"] = slot.getDebut().to_json();
json["finPotentielle"] = slot.getFin().to_json();
json["signalementDeclencheur"] = sigDeclencheur->to_json(false);
json["umCritique"] = nlohmann::json::object();
json["umCritique"]["rentree"] = stopUMCrit.getDispoStop().to_json();
json["umCritique"]["site"] = nlohmann::json::object();
json["umCritique"]["site"]["ref"] = STFMockInstance::stops[stopUMCrit.entree]->getLieuxArret().getRef();
json["umCritique"]["site"]["nameSlfrn"] = STFMockInstance::stops[stopUMCrit.entree]->getLieuxArret().getSlfrnName();
json["umCritique"]["site"]["gmaoOsmName"] = STFMockInstance::stops[stopUMCrit.entree]->getLieuxArret().getGmaoOsmName();
json["umCritique"]["numTrain"] = STFMockInstance::stops[stopUMCrit.entree]->getNumTrain();
json["umSaine"]["rentree"] = stopUMSane.getDispoStop().to_json();
json["umSaine"]["site"] = nlohmann::json::object();
json["umSaine"]["site"]["ref"] = STFMockInstance::stops[stopUMSane.entree]->getLieuxArret().getRef();
json["umSaine"]["site"]["nameSlfrn"] = STFMockInstance::stops[stopUMSane.entree]->getLieuxArret().getSlfrnName();
json["umSaine"]["site"]["gmaoOsmName"] = STFMockInstance::stops[stopUMSane.entree]->getLieuxArret().getGmaoOsmName();
json["umSaine"]["numTrain"] = STFMockInstance::stops[stopUMSane.entree]->getNumTrain();
json["site"]["ref"] = site->getRef();
json["site"]["nameSlfrn"] = site->getSlfrnName();
json["site"]["nameGmaoOsm"] = site->getGmaoOsmName();
unsigned int c = 0;
for(auto& us : um_crit.ramesInfo)
{
std::string numb = "us"+std::to_string(c+1);
json["umCritique"][numb]["numImmatEf"] = STFMockInstance::rames[us.id]->getNumeroEF();
json["umCritique"][numb]["ligne"] = um_crit.ramesInfo[c].ligne;
if(trajectoireTM.initialNextStopTM.at(us.id).first)
{
json["umCritique"][numb]["rentreeTMinitiale"] = trajectoireTM.initialNextStopTM.at(us.id).second.to_json(false);
}
else
json["umCritique"][numb]["rentreeTMinitiale"] = nullptr;
if(trajectoireTM.newNextStopTM.at(us.id).first)
{
json["umCritique"][numb]["rentreeTMpostcr"] = trajectoireTM.newNextStopTM.at(us.id).second.to_json(false);
}
else
json["umCritique"][numb]["rentreeTMpostcr"] = nullptr;
json["umCritique"][numb]["signalementsProposes"] = nlohmann::json::array();
json["umCritique"][numb]["signalements"] = nlohmann::json::array();
for(auto& sig : STFMockInstance::rames[us.id]->getSignalements())
{
json["umCritique"][numb]["signalementsProposes"].push_back(sig.to_json(false));
json["umCritique"][numb]["signalements"].push_back(sig.to_json(false));
}
++c;
}
c = 0;
for(auto& us : um_sane.ramesInfo)
{
std::string numb = "us"+std::to_string(c+1);
json["umSaine"][numb]["numImmatEf"] = STFMockInstance::rames[us.id]->getNumeroEF();
json["umSaine"][numb]["ligne"] = um_sane.ramesInfo[c].ligne;
if(trajectoireTM.initialNextStopTM.at(us.id).first)
{
json["umSaine"][numb]["rentreeTMinitiale"] = trajectoireTM.initialNextStopTM.at(us.id).second.to_json(false);
}
else
json["umSaine"][numb]["rentreeTMinitiale"] = nullptr;
if(trajectoireTM.newNextStopTM.at(us.id).first)
{
json["umSaine"][numb]["rentreeTMpostcr"] = trajectoireTM.newNextStopTM.at(us.id).second.to_json(false);
}
else
json["umSaine"][numb]["rentreeTMpostcr"] = nullptr;
json["umSaine"][numb]["signalementsProposes"] = nlohmann::json::array();
json["umSaine"][numb]["signalements"] = nlohmann::json::array();
for(auto& sig : STFMockInstance::rames[us.id]->getSignalements())
{
json["umSaine"][numb]["signalementsProposes"].push_back(sig.to_json(false));
json["umSaine"][numb]["signalements"].push_back(sig.to_json(false));
}
++c;
}
return json;
}
void CroisementUM::initTrajectoireTm(std::vector<TrajectoryStop>& trajStops,std::vector<std::vector<unsigned int>> &trajectories) {
auto findTM = [&](std::vector<RameUMInformation> rames, std::vector<unsigned int> &traj, unsigned int date) {
auto pos = std::find_if(traj.begin(), traj.end(), [&](unsigned int tr) {
if (std::find_if(STFInstance::getCurrentInstance()->getSitesMaintenance().begin(),
STFInstance::getCurrentInstance()->getSitesMaintenance().end(),
[&](MaintenanceSite &csite) {
return csite.getRef() == trajStops[tr].lieuArret->getRef();
}) != STFInstance::getCurrentInstance()->getSitesMaintenance().end()) {
if (STFMockInstance::stops[trajStops[tr].entree]->getDispo().getDebut().getRelativeDate() > date
&& std::is_permutation(trajStops[tr].um_entree.ramesInfo.begin(), trajStops[tr].um_entree.ramesInfo.end(), rames.begin()))
{
return true;
}
return false;
}
return false;
});
if (pos != traj.end()) {
return std::make_pair(true, trajStops[*pos]);
} else
return std::make_pair(false, TrajectoryStop());
};
for(auto& us : um_crit.ramesInfo)
{
trajectoireTM.initialNextStopTM[us.id] = findTM(um_crit.ramesInfo, trajectories[us.id], STFMockInstance::stops[stopUMCrit.sortie]->getDispo().getFin().getRelativeDate());
}
for(auto& us : um_sane.ramesInfo)
{
trajectoireTM.initialNextStopTM[us.id] = findTM(um_sane.ramesInfo, trajectories[us.id], STFMockInstance::stops[stopUMSane.sortie]->getDispo().getFin().getRelativeDate());
}
auto itUs = um_crit.ramesInfo.begin();
for(auto& us_s : um_sane.ramesInfo)
{
auto& earliestCrit = trajectoireTM.initialNextStopTM.at((*itUs).id);
auto& earliestSane = trajectoireTM.initialNextStopTM.at((us_s).id);
bool critGain = (!earliestCrit.first && earliestSane.first) || (earliestCrit.first && earliestSane.first && earliestCrit.second.getDispoStop().getDebutC().getRelativeDate() > earliestSane.second.getDispoStop().getDebutC().getRelativeDate());
trajectoireTM.newNextStopTM[(*itUs).id] = trajectoireTM.initialNextStopTM[us_s.id];
trajectoireTM.newNextStopTM[(*itUs).id].second.typeDispo.first = (critGain ? typeStop::RLT_POST_CROISEMENT_VOULU : typeStop::RLT_POST_CROISEMENT_SUBIT);
trajectoireTM.newNextStopTM[(*itUs).id].second.typeDispo.second = "";
trajectoireTM.newNextStopTM[(us_s).id] = trajectoireTM.initialNextStopTM[(*itUs).id];
trajectoireTM.newNextStopTM[(us_s).id].second.typeDispo.first = (critGain ? typeStop::RLT_POST_CROISEMENT_SUBIT : typeStop::RLT_POST_CROISEMENT_VOULU);
trajectoireTM.newNextStopTM[(us_s).id].second.typeDispo.second = "";
++itUs;
}
}
CroisementUM CroisementUM::from_json(nlohmann::json &json) {
CroisementUM cr_um;
auto curInst = STFInstance::getCurrentInstance();
auto curState = STFInstance::getCurrentInstance()->mockInstance;
unsigned int x = 1;
auto lbdFindUsCrit = [&](auto& r){return r.getNumeroEF() == json["umCritique"]["us"+ std::to_string(x)]["numImmatEf"];};
auto lbdFindUsSane = [&](auto& r){return r.getNumeroEF() == json["umSaine"]["us"+ std::to_string(x)]["numImmatEf"];};
while(json["umCritique"].contains("us"+ std::to_string(x)))
{
auto f = std::find_if(curInst->getRames().begin(), curInst->getRames().end(), lbdFindUsCrit);
if(f != curInst->getRames().end())
{
RameUMInformation rameinfo;
rameinfo.id = std::distance(curInst->getRames().begin(), f);
rameinfo.ligne = json["umCritique"]["us"+ std::to_string(x)]["ligne"];
/*** Rajouter le rang si nécessaire!! ***/
cr_um.um_crit.ramesInfo.push_back(rameinfo);
}
++x;
}
x = 1;
while(json["umSaine"].contains("us"+ std::to_string(x)))
{
auto f = std::find_if(curInst->getRames().begin(), curInst->getRames().end(), lbdFindUsSane);
if(f != curInst->getRames().end())
{
RameUMInformation rameinfo;
rameinfo.id = std::distance(curInst->getRames().begin(), f);
rameinfo.ligne = json["umSaine"]["us"+ std::to_string(x)]["ligne"];
/*** Rajouter le rang si nécessaire!! ***/
cr_um.um_sane.ramesInfo.push_back(rameinfo);
}
++x;
}
bool valid = true;
auto cr_crit = CreneauHoraire::from_json(json["umCritique"]["rentree"]);
auto cr_sane = CreneauHoraire::from_json(json["umSaine"]["rentree"]);
std::string refSite = "";
if(json["site"].is_string())
refSite = json["site"];
else
refSite = json["site"]["ref"];
for(auto& us : cr_um.um_crit.ramesInfo)
{
auto findDispUsCrit = std::find_if(curState->trajectories[us.id].begin(), curState->trajectories[us.id].end(),[&](unsigned int& tr){
auto disp = curState->trajectoryStops[tr].getDispoStop();
return curState->trajectoryStops[tr].lieuArret->getRef() == refSite && CreneauHoraire::checkSlotsCompatibility(disp, cr_crit).first;
});
if(findDispUsCrit != curState->trajectories[us.id].end())
{
cr_um.stopUMCrit = curState->trajectoryStops[*findDispUsCrit];
}
else
valid = false;
}
for(auto& us : cr_um.um_sane.ramesInfo)
{
auto findDispUsSane = std::find_if(curState->trajectories[us.id].begin(), curState->trajectories[us.id].end(),[&](unsigned int& tr){
auto disp = curState->trajectoryStops[tr].getDispoStop();
return curState->trajectoryStops[tr].lieuArret->getRef() == refSite && CreneauHoraire::checkSlotsCompatibility(disp, cr_sane).first;
});
if(findDispUsSane != curState->trajectories[us.id].end())
{
cr_um.stopUMSane = curState->trajectoryStops[*findDispUsSane];
}
else
valid = false;
}
if(!valid)
{
cr_um.um_crit.ramesInfo.clear();
cr_um.um_sane.ramesInfo.clear();
}
return cr_um;
}
unsigned int CroisementUM::getEntreeRame(unsigned short rame) const {
if (find(rame)) {
auto fc = std::find(um_crit.ramesInfo.begin(), um_crit.ramesInfo.end(), rame);
auto fs = std::find(um_sane.ramesInfo.begin(), um_sane.ramesInfo.end(), rame);
if(fc != um_crit.ramesInfo.end())
{
return STFMockInstance::stops[stopUMCrit.entree]->getDispo().getDebutC().getRelativeDate();
}
if(fs != um_sane.ramesInfo.end())
{
return STFMockInstance::stops[stopUMSane.entree]->getDispo().getDebutC().getRelativeDate();
}
}
return 0;
}
unsigned int CroisementUM::getSortieRame(unsigned short rame) const {
if (find(rame)) {
auto fc = std::find(um_crit.ramesInfo.begin(), um_crit.ramesInfo.end(), rame);
auto fs = std::find(um_sane.ramesInfo.begin(), um_sane.ramesInfo.end(), rame);
if(fc != um_crit.ramesInfo.end())
{
return STFMockInstance::stops[stopUMCrit.sortie]->getDispo().getFinC().getRelativeDate();//dispoStop ?? plutôt que de repasser par les EmplacementRame ?
}
if(fs != um_sane.ramesInfo.end())
{
return STFMockInstance::stops[stopUMSane.sortie]->getDispo().getFinC().getRelativeDate();
}
}
return 0;
}
unsigned int CroisementUM::getUMCriticity(TrajectoryStop &tr, std::unordered_map<unsigned short, Decision> &set) {
unsigned int most = 0;
for(auto& us : tr.um_entree.ramesInfo)
{
for (auto &s: STFMockInstance::operationsOfRames[us.id]) {
if (set.find(s) == set.end()) {
if (STFMockInstance::jobs[s]->getPoidsRetard() > most)
most = STFMockInstance::jobs[s]->getPoidsRetard();
}
}
}
return most;
}
unsigned int
CroisementUM::getUMCriticityHierarchy(TrajectoryStop &tr, std::unordered_map<unsigned short, Decision> &set){
unsigned int most = UINT_MAX;
for(auto& us : tr.um_entree.ramesInfo)
{
for (auto &s: STFMockInstance::operationsOfRames[us.id]) {
if (set.find(s) == set.end()) {
if (STFMockInstance::jobs[s]->getHierarchie() < most)
most = STFMockInstance::jobs[s]->getHierarchie();
}
}
}
if (most == UINT_MAX)
most = 0;
return most;
}
bool CroisementUM::find(const std::string &ef) const {
return um_crit.find(ef) || um_sane.find(ef);
}
bool CroisementUM::findInCrit(const std::string &ef) const {
return um_crit.find(ef);
}
bool CroisementUM::findInSane(const std::string &ef) const {
return um_sane.find(ef);
}
unsigned short
CroisementUM::getRameEarliestTMArrival(std::vector<RameUMInformation> &rames, std::vector<TrajectoryStop> &trajStops,
std::vector<std::vector<unsigned int>> &trajectories, unsigned short startingPoint)
{
unsigned short earliestArrival = USHRT_MAX;
unsigned short re = rames[0].id;
for(auto& rid : rames)
{
for(auto trId : trajectories[rid.id])
{
if(std::find_if(modellib::STFMockInstance::sites.begin(), modellib::STFMockInstance::sites.end(), [&](auto& s){return s->getRef() == trajStops[trId].lieuArret->getRef();}) != modellib::STFMockInstance::sites.end()
&& trajStops[trId].getDispoStop().getDebutC().getRelativeDate() < earliestArrival
&& trajStops[trId].getDispoStop().getDebutC().getRelativeDate() < startingPoint
&& std::is_permutation(trajStops[trId].um_entree.ramesInfo.begin(),trajStops[trId].um_entree.ramesInfo.end(), rames.begin())
)
{
earliestArrival = trajStops[trId].getDispoStop().getDebutC().getRelativeDate();
re = rid.id;
}
}
}
return re;
}
std::pair<bool, unsigned int>
CroisementUM::getEarliestTMArrival(std::vector<RameUMInformation> &rames, std::vector<TrajectoryStop> &trajStops,
std::vector<std::vector<unsigned int>> &trajectories, unsigned short startingPoint)
{
unsigned int earliestArrivalTR = 0;
unsigned short earliestArrival = USHRT_MAX;
bool f = false;
for(auto& rid : rames)
{
for(auto trId : trajectories[rid.id])
{
if(std::find_if(modellib::STFMockInstance::sites.begin(), modellib::STFMockInstance::sites.end(), [&](auto& s){return s->getRef() == trajStops[trId].lieuArret->getRef();}) != modellib::STFMockInstance::sites.end()
&& trajStops[trId].getDispoStop().getDebutC().getRelativeDate() < earliestArrival
&& trajStops[trId].getDispoStop().getDebutC().getRelativeDate() > startingPoint
&& std::is_permutation(trajStops[trId].um_entree.ramesInfo.begin(),trajStops[trId].um_entree.ramesInfo.end(), rames.begin())
)
{
f = true;
earliestArrivalTR = trId;
earliestArrival = trajStops[earliestArrivalTR].getDispoStop().getDebutC().getRelativeDate();
}
}
}
return {f, earliestArrivalTR};
}
}
+147
View File
@@ -0,0 +1,147 @@
#ifndef CROISEMENTUM_HPP
#define CROISEMENTUM_HPP
#include "TrajectoryStop.hpp"
#include "Decision.hpp"
#include "OperationRequise.h"
#include "UM.h"
namespace modellib {
enum class SwapColor{
GREEN,
YELLOW,
ORANGE,
RED,
BLACK
};
//todo rework de la structure croisement et adapatation de l'heuristique dans le cas général des ums qui peuvent être plus que double - long terme
/**
* @brief Struct indicating informative data about a swap
* Contains informations on the next stops in maintenance site, before and after swaps
*/
typedef struct _tmTraj {
std::unordered_map<unsigned short, std::pair<bool, TrajectoryStop>> initialNextStopTM;
std::unordered_map<unsigned short, std::pair<bool, TrajectoryStop>> newNextStopTM;
//todo il n'y a qu'un arrêt TM pour chaque UM pas chaque rame -> on récupère que la rentrée la plus tôt => sinon recompo
} TrajectoireTM;
/**
* @class CroisementUM
* @brief Defines the class that describes a swap without recomposition
*/
class CroisementUM {
private:
public:
SwapColor color = SwapColor::GREEN;
/**
* @brief The multiple unit trains that is the most critical
*/
UM um_crit;
/**
* @brief The multiple unit trains that is the least critical
*/
UM um_sane;
TrajectoryStop stopUMCrit;
TrajectoryStop stopUMSane;
/**
* @brief The site on which the swap is performed
*/
Site* site{};
/**
* @brief The informations on the next maintenance site stops
*/
TrajectoireTM trajectoireTM;
/**
* @brief The informations on the jobs of the trains
*/
OperationRequise* sigDeclencheur{};
unsigned int cost = 0;
/**
* @brief Default constructor
*/
CroisementUM() = default;
/**
* @brief Function to export the swap object to json format
* @return the json description of the object
*/
nlohmann::json to_json();
static CroisementUM from_json(nlohmann::json& json);
/**
* @brief Function to check if rame is one of the swapped trains
* @param rame the train to check the presence of by pointer
* @return true if rame is in one of the two multiple units
*/
inline bool find(unsigned short rame) const {
return um_crit.find(rame) || um_sane.find(rame);
}
bool find(const std::string& ef)const;
bool findInCrit(const std::string &ef) const;
bool findInSane(const std::string &ef) const;
/**
* @brief Function to get the overlapping period of availability of the two multiple units
* @return The overlapping time slot
*/
[[nodiscard]] inline CreneauHoraire getPotentialSwapSlot() const {
auto& cr1 = stopUMCrit.getDispoStop();//todo vérifier que c'est toujours le cas que les rames d'une même um repartent ensemble (je pense pas), si c'est pas le cas, il faut prendre le temps commun minimum d'arrêt en prenant en compte qu'au moins une des rames part plus tôt du coup
auto& cr2 = stopUMSane.getDispoStop();
SolverDate beg;
SolverDate end;
if (cr1.getDebutC() <= cr2.getDebutC()) {
beg = cr2.getDebutC();
} else
beg = cr1.getDebutC();
if (cr1.getFinC() <= cr2.getFinC()) {
end = cr1.getFinC();
} else
end = cr2.getFinC();
return {beg, end};
}
/**
* @brief Function to get the arrival of rame on the site
* @param rame the rame to get the arrival of
* @return the date of arrival or 0 if the rame is not concerned by the swap
*/
unsigned int getEntreeRame(unsigned short rame) const;
/**
* @brief Function to get the departure of rame of the site
* @param rame the rame to get the departure of
* @return the date of departure or 0 if the rame is not concerned by the swap
*/
unsigned int getSortieRame(unsigned short rame) const;
/**
* @brief Function to setup the informations of trajectories of trains of the swap
* @param trajectories the trajectories of all trains
*/
void initTrajectoireTm(std::vector<TrajectoryStop>& trajStops,std::vector<std::vector<unsigned int>> &trajectories);
static unsigned short getRameEarliestTMArrival(std::vector<RameUMInformation>& rames, std::vector<TrajectoryStop>& trajStops,std::vector<std::vector<unsigned int>> &trajectories, unsigned short startingPoint = 0);
static std::pair<bool, unsigned int> getEarliestTMArrival(std::vector<RameUMInformation>& rames, std::vector<TrajectoryStop>& trajStops,std::vector<std::vector<unsigned int>> &trajectories, unsigned short startingPoint = 0);
//faire la même fonction mais pour la date de départ ? en cas où on autorise le swap sur technicentre ? (recomposition?)
static unsigned int getUMCriticity(TrajectoryStop& tr, std::unordered_map<unsigned short, Decision> &set);
static unsigned int getUMCriticityHierarchy(TrajectoryStop& tr, std::unordered_map<unsigned short, Decision> &set);
};
}
#endif
+323
View File
@@ -0,0 +1,323 @@
#include "Date.h"
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/local_time/local_time.hpp>
namespace modellib {
SolverDate SolverDate::dateDebut = SolverDate();
bool SolverDate::zero_init = false;
SolverDate operator+(const SolverDate &date, const unsigned short &units) {
SolverDate dateRes(date);
dateRes.t_date = date.t_date + units;
//unsigned int heures = units / Configuration::usedConfiguration.TIMEUNIT;
dateRes.t_timestampMinutes = date.t_timestampMinutes + units*(60 / configlib::Configuration::Global.TIME_UNIT);
unsigned int heures = (dateRes.m_minute + units * (60 / configlib::Configuration::Global.TIME_UNIT)) / 60;
unsigned int nbJour = heures / 24;
if (dateRes.m_heure + (heures - nbJour * 24) >= 24 && dateRes.m_heure + (heures - nbJour * 24) < 48)
nbJour += 1;
else if (dateRes.m_heure + (heures - nbJour * 24) == 48)
nbJour += 2;
dateRes.m_heure = (dateRes.m_heure + heures) % 24;
dateRes.m_minute = (dateRes.m_minute + units * (60 / configlib::Configuration::Global.TIME_UNIT)) % 60;
for (unsigned int i = 0; i < nbJour; i++) {
bool bisextile = false;
if ((dateRes.m_annee % 4 == 0 && dateRes.m_annee % 100 == 0 && dateRes.m_annee % 400 == 0) ||
(dateRes.m_annee % 4 == 0 && dateRes.m_annee % 100 != 0)) {
bisextile = true;
}
if (((dateRes.m_jour == 28 && !bisextile) || (dateRes.m_jour == 29 && bisextile)) && dateRes.m_mois == 2) {
dateRes.m_jour = 1;
dateRes.m_mois = 3;
} else if (dateRes.m_jour == 31 && dateRes.m_mois == 12) {
dateRes.m_jour = 1;
dateRes.m_mois = 1;
dateRes.m_annee += 1;
} else if ((dateRes.m_jour == 30 &&
(dateRes.m_mois == 4 || dateRes.m_mois == 9 || dateRes.m_mois == 6 || dateRes.m_mois == 11)) ||
(dateRes.m_jour == 31 &&
(dateRes.m_mois == 1 || dateRes.m_mois == 3 || dateRes.m_mois == 5 || dateRes.m_mois == 7 ||
dateRes.m_mois == 8 || dateRes.m_mois == 10))) {
dateRes.m_jour = 1;
dateRes.m_mois += 1;
} else {
dateRes.m_jour += 1;
}
}
return dateRes;
}
bool operator<=(const SolverDate &date1, const SolverDate &date2) {
if (date1.m_annee > date2.m_annee) { return false; }
else if (date1.m_annee < date2.m_annee) { return true; }
else {
if (date1.m_mois > date2.m_mois) { return false; }
else if (date1.m_mois < date2.m_mois) { return true; }
else {
if (date1.m_jour > date2.m_jour) { return false; }
else if (date1.m_jour < date2.m_jour) { return true; }
else {
if (date1.m_heure > date2.m_heure) { return false; }
else if (date1.m_heure < date2.m_heure) { return true; }
else {
if (date1.m_minute > date2.m_minute) { return false; }
else {
return true;
}
}
}
}
}
}
bool operator<(const SolverDate &date1, const SolverDate &date2) {
if (date1.m_annee > date2.m_annee) { return false; }
else if (date1.m_annee < date2.m_annee) { return true; }
else {
if (date1.m_mois > date2.m_mois) { return false; }
else if (date1.m_mois < date2.m_mois) { return true; }
else {
if (date1.m_jour > date2.m_jour) { return false; }
else if (date1.m_jour < date2.m_jour) { return true; }
else {
if (date1.m_heure > date2.m_heure) { return false; }
else if (date1.m_heure < date2.m_heure) { return true; }
else {
if (date1.m_minute > date2.m_minute || date1.m_minute == date2.m_minute) { return false; }
else {
return true;
}
}
}
}
}
}
unsigned int operator-(const SolverDate &date1, const SolverDate &date2) {
if (date2 <= date1) {
unsigned int diff = date1.t_timestampMinutes - date2.t_timestampMinutes;
unsigned int units = (diff / 60) * configlib::Configuration::Global.TIME_UNIT;
/*if (diff % (60 / Configuration::usedConfiguration.TIMEUNIT) != 0)
{
units++;
} */
return units;
} else {
return (date2 - date1);
}
}
unsigned int SolverDate::toMinutes(const SolverDate &date) {
bool bisextile = false;
if (((date.m_annee & 3) == 0 && date.m_annee % 100 == 0 && date.m_annee % 400 == 0) ||
((date.m_annee & 3) == 0 && date.m_annee % 100 != 0)) {
bisextile = true;
}
unsigned int hoursMonth = 0;
for (unsigned int i = 1; i < date.m_mois; ++i) {
if(i == 2 && !bisextile)
{
hoursMonth += 672;
}
else
{
switch (i) {
case 2:
hoursMonth += 696;
break;
case 4:
hoursMonth += 720;
break;
case 6:
hoursMonth += 720;
break;
case 9:
hoursMonth += 720;
break;
case 11:
hoursMonth += 720;
break;
default:
hoursMonth += 744;
}
}
/*if (i == 2 && !bisextile)
hoursMonth += 672;//(28*24);
else if (i == 2)
hoursMonth += 696;//29*24
else if (i == 4 || i == 9 || i == 6 || i == 11)
hoursMonth += 720;//30*24
else if (i == 5 || i == 7 || i == 8 || i == 10 || i == 12 || i == 1 || i == 3)
hoursMonth += 744;//31*24;*/
}
unsigned int hoursYear;
if (bisextile)
hoursYear = 8784;//366 * 24;
else
hoursYear = 8760;//365 * 24;
//hoursYear = (date.m_annee - 1) * 365 + ((date.m_annee - 1) / 4) * 24;
return ((date.m_jour << 3) + (date.m_jour << 4) + hoursMonth + hoursYear + date.m_heure) * 60 + date.m_minute;
}
unsigned int SolverDate::toTimeUnit(const SolverDate &date) {
bool bisextile = false;
if ((date.m_annee % 4 == 0 && date.m_annee % 100 == 0 && date.m_annee % 400 == 0) ||
(date.m_annee % 4 == 0 && date.m_annee % 100 != 0)) {
bisextile = true;
}
unsigned int hoursMonth = 0;
for (unsigned int i = 1; i < date.m_mois; ++i) {
if (i == 2 && !bisextile)
hoursMonth += 28 * 24;
else if (i == 2)
hoursMonth += 29 * 24;
else if (i == 4 || i == 9 || i == 6 || i == 11)
hoursMonth += 30 * 24;
else if (i == 5 || i == 7 || i == 8 || i == 10 || i == 12 || i == 1 || i == 3)
hoursMonth += 24 * 31;
}
unsigned int hoursYear;
if (bisextile)
hoursYear = 366 * 24;
else
hoursYear = 365 * 24;
//hoursYear = (date.m_annee - 1) * 365 + ((date.m_annee - 1) / 4) * 24;
return (((date.m_jour * 24 + hoursMonth + hoursYear + date.m_heure) * 60 + date.m_minute) / 60) *
configlib::Configuration::Global.TIME_UNIT;
}
SolverDate SolverDate::todayObjFormat() {
time_t now = time(
nullptr); //returns the current calendar time of the system in number of seconds elapsed since January 1, 1970.
struct tm *timeLoc = localtime(&now);
return {(1900 + timeLoc->tm_year), (1 + timeLoc->tm_mon), timeLoc->tm_mday, timeLoc->tm_hour,
timeLoc->tm_min};
}
std::string SolverDate::todayStrFormat() {
time_t now = time(
nullptr); //returns the current calendar time of the system in number of seconds elapsed since January 1, 1970.
struct tm *timeLoc = localtime(&now);
return SolverDate((1900 + timeLoc->tm_year), (1 + timeLoc->tm_mon), timeLoc->tm_mday, timeLoc->tm_hour,
timeLoc->tm_min).to_json(true).dump();
}
nlohmann::json SolverDate::to_json(bool format) const {
nlohmann::json date = nlohmann::json::object();
if (!format) {
std::string returnString = std::to_string(m_annee);
if (m_mois < 10) {
returnString += "-0" + std::to_string(m_mois);
} else {
returnString += "-" + std::to_string(m_mois);
}
if (m_jour < 10) {
returnString += "-0" + std::to_string(m_jour);
} else {
returnString += "-" + std::to_string(m_jour);
}
if (m_heure < 10) {
returnString += "T0" + std::to_string(m_heure);
} else {
returnString += "T" + std::to_string(m_heure);
}
if (m_minute < 10) {
returnString += ":0" + std::to_string(m_minute) + ":00.000";
} else {
returnString += ":" + std::to_string(m_minute) + ":00.000";
}
date = returnString;
}
/*else
{
date["annee"] = m_annee;
date["mois"] = m_mois;
date["jour"] = m_jour;
date["heure"] = m_heure;
date["minute"] = m_minute;
} */
return date;
}
SolverDate SolverDate::from_json(nlohmann::json &json, bool format) {
SolverDate date;
if (!format) {
std::string dateSTR = json;
try {
boost::posix_time::ptime dt;
if (std::find(dateSTR.begin(), dateSTR.end(), 'Z') != dateSTR.end()) {
dateSTR = dateSTR.substr(0, dateSTR.size() - 1);
dt = boost::posix_time::from_iso_extended_string(dateSTR);
} else {
std::string offset = dateSTR.substr(dateSTR.size() - 6, 6);
std::stringstream sst(offset.substr(1, offset.size() - 1));
unsigned int oh;
unsigned int om;
sst >> oh;
sst >> om;
dt = boost::posix_time::from_iso_extended_string(dateSTR.substr(0, dateSTR.size() - 6));
/*if (offset[0] == '-')
{
dt += (boost::posix_time::hours(oh) + boost::posix_time::minutes(om));
}
else if (offset[0] == '+')
{
dt -= (boost::posix_time::hours(oh) + boost::posix_time::minutes(om));//j'ai change le 5 en oh jsp si ca casse un truc
}*/
}
//std::string date = boost::posix_time::to_iso_extended_string(dt);
date.m_annee = dt.date().year();
date.m_mois = dt.date().month();
date.m_jour = dt.date().day();
date.m_heure = dt.time_of_day().hours();
date.m_minute = dt.time_of_day().minutes();
}
catch (boost::exception &e) {
std::cout << "Error reading date" << std::endl;
}
date.t_timestampMinutes = toMinutes(date);
if (zero_init) {
if(date < dateDebut)
date.t_date = 0;
else
date.t_date = date - dateDebut;
}
/*for (size_t i = 0; i < (dateSTR.size() - 1); i++)
{
if (!std::isdigit(dateSTR[i]))
{
dateSTR.replace(dateSTR.begin() + i, dateSTR.begin() + i+1, " ");
}
}
std::stringstream ss(dateSTR);
ss >> date.m_annee;
ss >> date.m_mois;
ss >> date.m_jour;
ss >> date.m_heure;
ss >> date.m_minute; */
}
/*else
{
date.m_annee = json["annee"];
date.m_mois = json["mois"];
date.m_jour = json["jour"];
date.m_heure = json["heure"];
date.m_minute = json["minute"];
} */
return date;
}
SolverDate::SolverDate(int y, int m, int d, int h, int min): m_annee(y), m_mois(m), m_jour(d), m_heure(h), m_minute(min) {
}
}
+182
View File
@@ -0,0 +1,182 @@
#ifndef SOLVERDATE_H
#define SOLVERDATE_H
#include <iostream>
#include <sstream>
#include "nlohmann/json.hpp"
#include "../Configuration/Configurations.h"
namespace modellib {
/*! @file Date.h*/
/**
* @class SolverDate
* @brief Class describing a date
*/
class SolverDate {
private:
/**
* @brief The year
*/
unsigned short m_annee = 0;
/**
* @brief The month
*/
unsigned char m_mois = 0;
/**
* @brief The day
*/
unsigned char m_jour = 0;
/**
* @brief The hour
*/
unsigned char m_heure = 0;
/**
* @brief The minutes
*/
unsigned char m_minute = 0;
/**
* @brief The date relative to zero (beginning of planification)
* Used in every algorithm to avoid translating date to relative date each time
*/
unsigned short t_date = 0;
/**
* @brief Indicates if the zero date has been set
*/
static bool zero_init;
public:
unsigned int t_timestampMinutes = 0;
/**
* @brief Default constructor
*/
SolverDate() = default;
SolverDate(int y, int m, int d, int h, int min);
/**
* @brief Destructeur. Ne fait rien
*/
virtual ~SolverDate() = default;
/**
* @brief Getter simple sur l'anne de la date
* @return l'anne
*/
[[nodiscard]] inline unsigned short getAnnee() const { return m_annee; }
[[nodiscard]] inline unsigned short getRelativeDate() const { return t_date; };
/**
* @brief Getter simple sur le mois de la date
* @return le mois
*/
[[nodiscard]] inline unsigned char getMois() const { return m_mois; }
/**
* @brief Getter simple sur le jour de la date
* @return le jour
*/
[[nodiscard]] inline unsigned char getJour() const { return m_jour; }
/**
* @brief Getter simple sur l'heure de la date
* @return l'heure
*/
[[nodiscard]] inline unsigned char getHeure() const { return m_heure; }
/**
* @brief Getter simple sur les minutes de la date
* @return les minutes
*/
[[nodiscard]] inline unsigned char getMinute() const { return m_minute; }
inline static SolverDate &getDateDebut() { return dateDebut; }
static void setDateDebut(SolverDate &s) {
dateDebut = s;
zero_init = true;
};
static void resetDateDebut() { zero_init = false; };
static bool is_init() {
return zero_init;
}
/**
* @brief Fonction de conversion d'une date en unit de minutes
* Ex : aaaa/mm/jj => X * TIMEUNIT avec TIMEUNIT dfinissant si 1 correspond 10minutes/20minutes/.../1h
* (Voir documentation de Configurationpour une description de TIMEUNIT)
* @param date la date a convertir
* @return le nombre d'unit de temps correspondant la date au format classique
*/
static unsigned int toMinutes(const SolverDate &date);
static unsigned int toTimeUnit(const SolverDate &date);
static std::string todayStrFormat();
static SolverDate todayObjFormat();
static SolverDate dateDebut;
/**
* @brief Surcharge de l'oprateur + qui permet l'ajout d'une dure une date
* L'unit de la dure ajoute est 60/TIMEUNIT
* @param date la date laquelle on ajoute un temps
* @param units le nombre d'unit de temps ajouter
* @return La nouvelle date
*/
friend SolverDate operator+(const SolverDate &date, const unsigned short &units);
/**
* @brief Surcharge de l'oprateur <= qui permet de vrifier si une date est plus petite ou identique une autre
* @param date1 la premire date
* @param date2 la seconde date
* @return true si date1<= date2, false sinon
*/
friend bool operator<=(const SolverDate &date1, const SolverDate &date2);
/**
* @brief Surcharge de l'oprateur < qui permet de vrifier si une date est strictement plus petite
* @param date1 la premire date
* @param date2 la seconde date
* @return true si date1 < date2, false sinon
*/
friend bool operator<(const SolverDate &date1, const SolverDate &date2);
/**
* @brief Surcharge de l'oprateur - qui permet de rcuprer le temps coul entre deux dates
* Le temps coul est exprim en unit de temps dpendant de TIMEUNIT
* @param date1 la premire date
* @param date2 la seconde date
* @return le nombre d'unit de temps correspondant la priode coule entre date1 et date2
*/
friend unsigned int operator-(const SolverDate &date1, const SolverDate &date2);
/**
* @brief Fonction interface de traduction de l'objet SolverDate vers un objet JSON
* @param format si true on respecte le format "aaaa-mm-jjThh:mm:ssZ" sinon "annee": aaaa, "mois": mm, etc...
* @return le json dcrivant la date
*/
[[nodiscard]] nlohmann::json to_json(bool format = false) const;
/**
* @brief Fonction interface de traduction de l'objet JSON vers un objet SolverDate
* @param json le JSON dcrivant une date
* @param format si true on lis le format "aaaa-mm-jjThh:mm:ssZ" sinon "annee": aaaa, "mois": mm, etc...
* @return l'instance de la classe SolverDate correspondant l'objet JSON d'entre
*/
static SolverDate from_json(nlohmann::json &json, bool format = false);
};
}
#endif // !SOLVERDATE_H
+3
View File
@@ -0,0 +1,3 @@
#include "Decision.hpp"
namespace modellib {
}
+99
View File
@@ -0,0 +1,99 @@
#ifndef ORDONNANCEMENTCORRECTIF_DECISION_HPP
#define ORDONNANCEMENTCORRECTIF_DECISION_HPP
#include "CreneauHoraire.h"
namespace modellib {
/**
* @brief Struct defining a generic decision of the problem
*/
typedef struct decision {
/**
* @brief The stopping point of the train
*/
unsigned int empR = 0;
CreneauHoraire timeslotGraphSplited = CreneauHoraire();
/**
* @brief The availability of the track
*/
unsigned short empV = 0;
/**
* @brief Indicates if the job is set in diagnosis mode or not
*/
bool rejected = false;
/**
* @brief Indicates if the job is excluded completely or not
*/
bool excluded = false;
/**
* @brief The track on which the job is scheduled
*/
unsigned char voie = 0;
/**
* @brief The maintenance site on which the job is scheduled
*/
unsigned char site = 0;
/**
* @brief The begin and end date chosen for handling the job. May vary depending on the algorithms
*/
std::pair<unsigned short, unsigned short> lastCreneau = {0,0};
bool operator==(const decision& other) const
{
return empR == other.empR
&& empV == other.empV
&& rejected == other.rejected
&& excluded == other.excluded
&& voie == other.voie
&& site == other.site
&& timeslotGraphSplited == other.timeslotGraphSplited
&& lastCreneau == other.lastCreneau;
}
bool operator<(const decision& other) const {
if (voie != other.voie) return voie < other.voie;
if (lastCreneau != other.lastCreneau) return lastCreneau < other.lastCreneau;
if (rejected != other.rejected) return rejected < other.rejected;
if (excluded != other.excluded) return excluded < other.excluded;
if (empV != other.empV) return empV < other.empV;
if (empR != other.empR) return empR < other.empR;
return site < other.site;
}
} Decision;
/**
* @brief Struct defining a generic decision of the rdv conflict routing problem
*/
typedef struct rdvdecision {
/**
* @brief The stopping point of the train
*/
unsigned int empR = 0;
/**
* @brief The timeSlot of the RDV
*/
unsigned short empRdv = 0;
/**
* @brief Indicates if the rdv is excluded completely or not
*/
bool excluded = false;
/**
* @brief The maintenance site on which the job is scheduled
*/
unsigned char site = 0;
} RDVDecision;
}
#endif
+3
View File
@@ -0,0 +1,3 @@
#include "DispVoieRame.hpp"
namespace modellib {
}
+70
View File
@@ -0,0 +1,70 @@
#ifndef DISPVOIERAME_HPP
#define DISPVOIERAME_HPP
#include "STFInstance.h"
namespace modellib {
/**
* @class DispVoieRame
* @brief Class defining a common availability between a train and a track
*/
class DispVoieRame {
public:
/**
* @brief The train availability
*/
unsigned int dispoRame = 0;
/**
* @brief The track availability
*/
unsigned short dispoVoie = 0;
/**
* @brief The track
*/
unsigned char voie = 0;
/**
* @brief The maintenance site
*/
unsigned char site = 0;
unsigned short rame = 0;
unsigned short op = 0;
/**
* @brief The match of availability {begin, end}
*/
std::pair<unsigned short, unsigned short> match;
//unsigned int id;//peut faire sans je pense
/**
* @brief Default constructor
*/
DispVoieRame() = default;
/**
* @brief Destructor
*/
~DispVoieRame() = default;
/**
* Copy constructor
* @param disp availability to copy
*/
DispVoieRame(const DispVoieRame &disp) {
dispoVoie = disp.dispoVoie;
dispoRame = disp.dispoRame;
match = disp.match;
voie = disp.voie;
site = disp.site;
rame = disp.rame;
op = disp.op;
}
};
}
#endif
+206
View File
@@ -0,0 +1,206 @@
#include <algorithm>
#include <cstddef>
#include <regex>
#include <string>
#include "EmplacementRame.h"
#include "GareSite.h"
#include "MaintenanceSite.h"
#include "PreventiveMaintenanceRdv.hpp"
#include "Rame.h"
#include "nlohmann/json_fwd.hpp"
namespace modellib {
std::unordered_map<typeStop, std::string> EmplacementRame::smapTypeStops = {
{typeStop::RLT, "RLT"},
{typeStop::RLT_POST_CROISEMENT_VOULU, "CR_RLT_VOULU"},
{typeStop::RLT_POST_CROISEMENT_SUBIT, "CR_RLT_SUBIT"},
{typeStop::RDVM, "RDVM"},
{typeStop::RLT_POST_RECOMPO_VOULU, "COMP_RLT_VOULU"},
{typeStop::RLT_POST_RECOMPO_SUBIT, "COMP_RLT_SUBIT"},
{typeStop::RLT_POST_RECOMPO_UM_PARFAIT, "COMP_RLT_UM_PARFAIT"}
};
EmplacementRame::EmplacementRame(const Site &lieuarret, const CreneauHoraire &dispo)
: m_lieuArret(lieuarret), m_disponibilite(dispo) {
}
nlohmann::json EmplacementRame::to_json(bool verbose) {
nlohmann::json er = nlohmann::json::object();
er["site"]["ref"] = m_lieuArret.getRef();
er["site"]["nameSlfrn"] = m_lieuArret.getSlfrnName();
er["site"]["nameGmaoOsm"] = m_lieuArret.getGmaoOsmName();
er["rang"] = m_rang;
er["periode"] = m_disponibilite.to_json();
er["um"] = nlohmann::json::array();
if (verbose) {
for(auto& u : um)
{
nlohmann::json umObj;
umObj["numImmatEf"] = u.Ef;
umObj["ligne"] = u.ligne;
umObj["rang"] = u.rang;
er["um"].push_back(umObj);
}
er["ligne"] = ligne;
er["numTrain"] = numTrain;
}
std::string precision = !typeDispo.second.empty() ? " : " : "";
er["rdvm"] = rdv.has_value() ? rdv.value().to_json() : nullptr;
er["motif"] = EmplacementRame::smapTypeStops[typeDispo.first] + precision + typeDispo.second;
return er;
}
EmplacementRame EmplacementRame::from_json(nlohmann::json &json, std::vector<MaintenanceSite> &msites, std::vector<Site> &sites) {
EmplacementRame er;
bool isMaintenanceSite = false;
std::string refS = json["site"]["ref"];
auto findSM = std::find_if(msites.begin(), msites.end(), [&](auto& si){return si.getRef() == refS;});
if(findSM != msites.end())
{
auto& s = *findSM;
er.m_lieuArret = Site(s.getRef(),s.getSlfrnName(), s.getGmaoOsmName(), s.getType());
isMaintenanceSite = true;
}
else {
auto findCS = std::find_if(sites.begin(), sites.end(), [&](auto& si){return si.getRef() == refS;});
if (findCS != sites.end())
{
er.m_lieuArret = *findCS;
}
else // NE SERT QUE POUR LES INSTANCES SANS TABLEAU SITEGARE REMPLI
{
std::string name = "";
if(json["site"].contains("name"))
name = json["site"]["name"];
bool swap = false;
bool comp = false;
if(json["site"].contains("allowSwap"))
swap = json["site"]["allowSwap"];
if(json["site"].contains("allowComp"))
comp = json["site"]["allowComp"];
Site siteCr(refS, name, "", 2, swap, comp);
if(!name.empty())
{
auto pos = siteCr.getSlfrnName().find('-');
if(pos != std::string::npos)
{
siteCr.setZone(true, siteCr.getSlfrnName().substr(0,pos));
}
else {
siteCr.setZone(false, "");
}
}
else {
siteCr.setZone(false, "");
}
siteCr.setCompEnabled(true);
siteCr.setSwapEnabled(true);
sites.push_back(siteCr);
er.m_lieuArret = siteCr;
}
}
if (json.contains("ligne")) {
er.ligne = json["ligne"];
}
if (json.contains("numTrain")) {
er.numTrain = json["numTrain"];
}
if (json.contains("rang")) {
er.m_rang = json["rang"];
}
er.m_disponibilite = CreneauHoraire::from_json(json["periode"]);
if (json.contains("um") && json["um"].is_array())// && !json["um"]["numImmatEf"].is_null())
{
if (!isMaintenanceSite)
{
for(auto& u : json["um"])
{
if(!u["numImmatEf"].is_null() && !u["ligne"].is_null())// && !u["rang"].is_null())
{
er.um.emplace_back(u["numImmatEf"],u["ligne"],0);
}else if(u["numImmatEf"].is_null() && !u["ligne"].is_null()){// && !u["rang"].is_null()){
er.um.emplace_back("null",u["ligne"],0);
}
}
}
}
else if (json.contains("ums") && json["ums"].is_array())// && !json["um"]["numImmatEf"].is_null())
{
if (!isMaintenanceSite)
{
for(auto& u : json["ums"])
{
if(!u["numImmatEf"].is_null() && !u["ligne"].is_null())// && !u["rang"].is_null())
{
er.um.emplace_back(u["numImmatEf"],u["ligne"],0);
}else if(u["numImmatEf"].is_null() && !u["ligne"].is_null())// && !u["rang"].is_null())
{
er.um.emplace_back("null",u["ligne"],0);
}
}
}
}
else if(json.contains("um") && json["um"].is_object() && !json["um"]["numImmatEf"].is_null() && !json["um"]["ligne"].is_null())//&& !json["um"]["rang"].is_null())
{
if (!isMaintenanceSite)
{
er.um.emplace_back(json["um"]["numImmatEf"], json["um"]["ligne"],0);
}
}
if (json.contains("rdvm") && !json["rdvm"].is_null()) {
/*er.rdv.isImperative(json["rdvm"]["imperatif"].get<bool>());
auto l = json["rdvm"]["libelle"].get<std::string>();
er.rdv.setLibelle(l);
if(!json["rdvm"]["dateButee"].is_null())
{
auto dl = SolverDate::from_json(json["rdvm"]["dateButee"]);
er.rdv.setDeadline(dl);
}
else
{
auto dl = SolverDate::getDateDebut() + 336;
er.rdv.setDeadline(dl);
}
er.rdv.setRdvId(json["rdvm"]["rdvId"].get<unsigned int>());*/
er.rdv = PreventiveMaintenanceRdv::from_json(json["rdvm"], msites);
}
if (json.contains("motif")) {
std::string motif = json["motif"];
if (motif.find(smapTypeStops[typeStop::RLT]) != std::string::npos) {
er.typeDispo.first = typeStop::RLT;
} else if (motif.find(smapTypeStops[typeStop::RDVM]) != std::string::npos) {
er.typeDispo.first = typeStop::RDVM;
//std::string tmp = json["motif"];
std::string output = std::regex_replace(
motif,
std::regex("[^0-9]*([0-9]+).*"),
std::string("$1")
);
er.typeDispo.second += output;
} else
er.typeDispo.first = typeStop::RLT;
er.imperatif = json["motif"];
if ((er.imperatif.find(NOT_IMPERATIVE) == std::string::npos &&
er.imperatif.find(IMPERATIVE) != std::string::npos) ||
er.imperatif.find(IMP_BUTEE) != std::string::npos ||
er.imperatif.find(IMP_CRENEAU) != std::string::npos ||
er.imperatif.find(IMP_RAME) != std::string::npos) {
er.imperatif = IMPERATIVE;
} else if (er.imperatif.find(NOT_IMPERATIVE) != std::string::npos) {
er.imperatif = NOT_IMPERATIVE;
} else if (er.imperatif.find(IMPERATIVE) == std::string::npos)
er.imperatif = NOT_IMPERATIVE;
}
return er;
}
}
+176
View File
@@ -0,0 +1,176 @@
#ifndef EMPLACEMENTRAME_H
#define EMPLACEMENTRAME_H
#include <optional>
#include <string>
#define IMPERATIVE "Imperatif"
#define NOT_IMPERATIVE "Non-Imperatif"
#define IMP_CRENEAU "CRENEAU"
#define IMP_RAME "RAME"
#define IMP_BUTEE "BUTEE"
//#define RDVM "RDVM"
#include <iostream>
#include <utility>
#include "CreneauHoraire.h"
#include "GareSite.h"
#include "PreventiveMaintenanceRdv.hpp"
namespace modellib {
enum class typeStop: unsigned char{
RLT,
RLT_POST_CROISEMENT_VOULU,
RLT_POST_CROISEMENT_SUBIT,
RDVM,
RLT_POST_RECOMPO_VOULU,
RLT_POST_RECOMPO_SUBIT,
RLT_POST_RECOMPO_UM_PARFAIT
};
/**
* @brief Struct indicating informative data about the UM associate to the rame
*/
typedef struct _Rame_info {
std::string Ef;
std::string ligne;
unsigned short rang;
_Rame_info(const std::string& ef, const std::string l, unsigned short r): Ef(ef), ligne(l), rang(r){}
} RameInformation;
class MaintenanceSite;
/*! @file EmplacementRame.h*/
/**
* @class EmplacementRame
* @brief Classe dcrivant un creux de roulement d'une rame
*/
class EmplacementRame {
private:
/**
* @brief lieu d'arrt de la rame
*/
Site m_lieuArret;
/**
* @brief priode de disponibilit
*/
CreneauHoraire m_disponibilite;
//std::vector<std::pair<std::string,std::string>> ef_um;
std::vector<RameInformation> um;
std::pair<typeStop, std::string> typeDispo;
std::string imperatif;
std::string ligne;
std::string numTrain;
std::optional<PreventiveMaintenanceRdv> rdv;
unsigned short m_rang{};
public:
static std::unordered_map<typeStop, std::string> smapTypeStops;
/**
* @brief Constructeur par dfaut
*/
EmplacementRame() = default;
/**
* @brief Constructeur de confort
* @param lieuArret le lieu o la rame s'arrte
* @param disponibilite priode de disponibilit de la rame
* @param rdvMaintenance les rdv dj planifis
* @param rameAssocie la rame associe la disponibilit
*/
EmplacementRame(const Site &lieuArret, const CreneauHoraire &disponibilite);
/**
* @brief Destructeur. Ne fait rien
*/
virtual ~EmplacementRame() = default;
/**
* @brief Getter simple par rfrence du lieu arrt
* @return le lieu d'arrt du creux de roulement
*/
inline Site &getLieuxArret() { return m_lieuArret; };
inline void setRDV(PreventiveMaintenanceRdv& r){rdv = r;};
inline std::optional<PreventiveMaintenanceRdv>& getRDV(){return rdv;};
/**
* @brief Getter simple par rfrence sur la priode de disponibilit de la rame
* @return la priode de disponibilit de la rame
*/
inline CreneauHoraire &getDispo() { return m_disponibilite; };
inline std::optional<PreventiveMaintenanceRdv>& getPreventiveMaintenanceRdv(){return rdv;};
/**
* @brief Fonction interface de traduction de l'objet EmplacementRame vers un objet JSON
* @return le json dcrivant le creux de roulement
*/
nlohmann::json to_json(bool verbose = true);
[[nodiscard]] inline std::vector<RameInformation> getUM() const {
return um;
}
[[nodiscard]] inline std::vector<RameInformation>& getUMRef() {
return um;
}
inline void setUM(std::vector<RameInformation> &ef) {
um = ef;
}
[[nodiscard]] inline std::string getLigne() const {
return ligne;
}
inline void setLigne(std::string &l) {
ligne = l;
}
inline std::string &getNumTrain() {
return numTrain;
}
inline void setNumTrain(std::string numtrain) {
numTrain = std::move(numtrain);
}
[[nodiscard]] inline std::pair<typeStop, std::string> getTypeDispo() const {
return typeDispo;
}
inline void setTypeDispo(std::pair<typeStop, std::string> &td) {
typeDispo = td;
}
[[nodiscard]] inline std::string getImperative() const {
return imperatif;
}
inline void setImperative(std::string &td) {
imperatif = td;
}
unsigned short getRangC() const{return m_rang;}
unsigned short getRang() {return m_rang;}
void setRang(unsigned short val){m_rang = val;}
/**
* @brief Fonction interface de traduction de l'objet JSON vers un objet EmplacementRame
* @param json le JSON dcrivant un creux de roulement
* @param sites la liste des sites de maintenance
* @return l'instance de la classe EmplacementRame correspondant l'objet JSON d'entre
*/
static EmplacementRame from_json(nlohmann::json &json, std::vector<MaintenanceSite> &msites, std::vector<Site> &sites);
};
}
#endif
+25
View File
@@ -0,0 +1,25 @@
#include "EmplacementVoie.h"
#include <utility>
namespace modellib {
EmplacementVoie::EmplacementVoie(const CreneauHoraire &dispo, std::string specificTrain)
: m_disponibilite(dispo), m_specificTrain(std::move(specificTrain)) {
}
nlohmann::json EmplacementVoie::to_json() {
nlohmann::json ev = nlohmann::json::object();
ev["rameAffected"] = m_specificTrain;
ev["debut"] = m_disponibilite.getDebut().to_json();
ev["fin"] = m_disponibilite.getFin().to_json();
return ev;
}
EmplacementVoie EmplacementVoie::from_json(nlohmann::json &json) {
EmplacementVoie ev;
ev.m_specificTrain = json["rameAffected"];
ev.m_disponibilite.setDebut(SolverDate::from_json(json["debut"]));
ev.m_disponibilite.setFin(SolverDate::from_json(json["fin"]));
return ev;
}
}
+78
View File
@@ -0,0 +1,78 @@
#ifndef EMPLACEMENTVOIE_H
#define EMPLACEMENTVOIE_H
#include <iostream>
#include "CreneauHoraire.h"
namespace modellib {
/*! @file EmplacementVoie.h*/
/**
* @class EmplacementVoie
* @brief Classe dcrivant une disponibilit de voie
*/
class EmplacementVoie {
private:
/**
* @brief priode de disponibilit
*/
CreneauHoraire m_disponibilite;
/**
* @brief Le nom de la rame concerne par la dispo. Si vide, concerne toutes les rames
*/
std::string m_specificTrain;
public:
/**
* @brief Constructeur par dfaut
*/
EmplacementVoie() = default;
/**
* @brief Constructeur de confort
* @param lieuArret le lieu o la rame s'arrte
* @param disponibilite priode de disponibilit de la rame
* @param rdvMaintenance les rdv dj planifis
* @param rameAssocie la rame associe la disponibilit
*/
EmplacementVoie(const CreneauHoraire &disponibilite, std::string specificTrain);
/**
* @brief Destructeur. Ne fait rien
*/
virtual ~EmplacementVoie() = default;
/**
* @brief Getter simple par rfrence sur la priode de disponibilit de la rame
* @return la priode de disponibilit de la rame
*/
inline CreneauHoraire &getDispo() { return m_disponibilite; };
/**
* @brief Getter simple sur la rame associe
* @return le pointeur sur la rame associe la disponibilit
*/
inline std::string &getSpecificRame() { return m_specificTrain; };
inline void setSpecificTrain(const std::string &ef) { m_specificTrain = ef; };
/**
* @brief Fonction interface de traduction de l'objet EmplacementRame vers un objet JSON
* @return le json dcrivant le creux de roulement
*/
nlohmann::json to_json();
/**
* @brief Fonction interface de traduction de l'objet JSON vers un objet EmplacementRame
* @param json le JSON dcrivant un creux de roulement
* @param sites la liste des sites de maintenance
* @return l'instance de la classe EmplacementRame correspondant l'objet JSON d'entre
*/
static EmplacementVoie from_json(nlohmann::json &json);
};
}
#endif
+16
View File
@@ -0,0 +1,16 @@
#ifndef ORDONNANCEMENTCORRECTIF_EXCLUSIONINFO_HPP
#define ORDONNANCEMENTCORRECTIF_EXCLUSIONINFO_HPP
#include <string>
namespace modellib {
class ExclusionInfo {
public:
std::string id;
int idAnomalie;
unsigned int hierarchie;
bool solveur;
std::string raison;
};
}
#endif //ORDONNANCEMENTCORRECTIF_EXCLUSIONINFO_HPP
+8
View File
@@ -0,0 +1,8 @@
#include "GareSite.h"
namespace modellib {
GareSite::GareSite(const std::string& ref, const std::string& sn, const std::string& gmao,unsigned int type, bool swap, bool recompo)
: Site(ref, sn, gmao, type, swap, recompo) {
}
}
+38
View File
@@ -0,0 +1,38 @@
#ifndef GARESITE_H
#define GARESITE_H
#include <iostream>
#include <unordered_set>
#include "Site.h"
namespace modellib {
/*! @file GareSite.h*/
/**
* @class GareSite
* @brief Classe dcrivant un site de gare
*/
class GareSite :
public Site {
public:
/**
* @brief Constructeur par dfaut
*/
GareSite() = default;
/**
* @brief Constructeur de confort
* @param pramesArretees les rames arrtes en gare
* @param pdistance les distance entre ce site et les autres
* @param pIdSite l'identifiant du site
*/
GareSite(const std::string& ref, const std::string& sn, const std::string& gmao,unsigned int type, bool swap=false, bool recompo=false);
/**
* @brief destructeur. Ne fait rien
*/
~GareSite() override = default;
};
}
#endif // ! GARESITE_H
@@ -0,0 +1,28 @@
#include "HeurePointeCreneauxHoraire.h"
namespace modellib {
HeurePointeCreneauxHoraire::HeurePointeCreneauxHoraire(const HeurePointeCreneauxHoraire &creneau) : CreneauHoraire(
creneau.getDebutC(), creneau.getFinC()), m_nbMaxRameImmobilisees(creneau.m_nbMaxRameImmobilisees) {
}
HeurePointeCreneauxHoraire::HeurePointeCreneauxHoraire(SolverDate const &pDebut, SolverDate const &pFin, int nbRame)
:
CreneauHoraire(pDebut, pFin), m_nbMaxRameImmobilisees(nbRame) {
}
nlohmann::json HeurePointeCreneauxHoraire::to_json() {
nlohmann::json msc = nlohmann::json::object();
msc["nbMaxRameImmobilisees"] = m_nbMaxRameImmobilisees;
msc["debut"] = getDebut().to_json();
msc["fin"] = getFin().to_json();
return msc;
}
HeurePointeCreneauxHoraire HeurePointeCreneauxHoraire::from_json(nlohmann::json &json) {
return {SolverDate::from_json(json["debut"]), SolverDate::from_json(json["fin"]),
json["nbMaxRameImmobilisees"]};
}
}
@@ -0,0 +1,66 @@
#ifndef HEUREDEPOINTECRENEAUXHORRAIRE_H
#define HEUREDEPOINTECRENEAUXHORRAIRE_H
#include <iostream>
#include "CreneauHoraire.h"
namespace modellib {
/*! @file HeurePointeCreneauxHoraire.h*/
/**
* @class HeurePointeCreneauxHoraire
* @brief Classe dcrivant un creneau horaire heures de pointe spcifiant le nombre maximum de rentre de rames
*/
class [[maybe_unused]] HeurePointeCreneauxHoraire :
public CreneauHoraire {
private:
/**
* @brief nomre maximum de rames autorises rentrer sur site de maintenance
*/
unsigned int m_nbMaxRameImmobilisees{};
public:
/**
* @brief Constructeur par dfaut
*/
HeurePointeCreneauxHoraire() = default;
/**
* @brief Constructeur de copie
* @param creneau le creneau copier
*/
HeurePointeCreneauxHoraire(const HeurePointeCreneauxHoraire &creneau);
/**
* @brief Constructeur de confort
* @param pDebut la date de dbut du creneau
* @param pFin la date de fin du creneau
* @param nbRame le nombre de rames maximum immobilises
*/
HeurePointeCreneauxHoraire(SolverDate const &pDebut, SolverDate const &pFin, int nbRame);
/**
* @brief Destructeur. Ne fait rien
*/
~HeurePointeCreneauxHoraire() override = default;
/**
* @brief Getter sur le nombre maximum de rentres de rames sur site
*/
[[maybe_unused]] [[nodiscard]] unsigned int getNbMaxRamesImmobiles() const { return m_nbMaxRameImmobilisees; };
/**
* @brief Fonction interface de traduction de l'objet HeurePointeCreneauxHoraire vers un objet JSON
* @return le json dcrivant le creneau d'heure de pointe
*/
nlohmann::json to_json();
/**
* @brief Fonction interface de traduction de l'objet JSON vers un objet HeurePointeCreneauxHoraire
* @param json le JSON dcrivant un creneau d'heure de pointe
* @return l'instance de la classe HeurePointeCreneauxHoraire correspondant l'objet JSON d'entre
*/
static HeurePointeCreneauxHoraire from_json(nlohmann::json &json);
};
}
#endif
+85
View File
@@ -0,0 +1,85 @@
#include "MaintenanceSite.h"
namespace modellib {
MaintenanceSite::MaintenanceSite(std::vector<Voie> &pvoiesDuSite,
std::vector<MaintenanceSiteCapacite> &pcapaciteCreneaux, std::string &ref,
std::string &sn, std::string& gmao, unsigned int type)//, std::string name)
: Site(ref, sn, gmao, type), m_voiesDuSite(pvoiesDuSite), m_capaciteCreneaux(pcapaciteCreneaux)//, m_nameOsm(name)
{
}
MaintenanceSite::MaintenanceSite(const std::string &ref, const std::string &sn, const std::string &gmao,
unsigned int type)//, std::string name)
: Site(ref, sn, gmao, type)//, m_nameOsm(name)
{
}
nlohmann::json MaintenanceSite::to_json(bool withinfo) {
nlohmann::json ms = nlohmann::json::object();
if (withinfo) {
ms["voieDuSite"] = nlohmann::json::array();
for (auto& v: m_voiesDuSite) {
ms["voieDuSite"].push_back(v.to_json());
}
ms["capaciteCreneaux"] = nlohmann::json::array();
for (auto& capa : m_capaciteCreneaux) {
ms["capaciteCreneaux"].push_back(capa.to_json());
}
ms["typeSite"] = getType();
}
ms["ref"] = getRef();
ms["nameGmaoOsm"] = getGmaoOsmName();
ms["nameSlfrn"] = getSlfrnName();
return ms;
}
MaintenanceSite MaintenanceSite::from_json(nlohmann::json &json) {
MaintenanceSite ms;
if(json.contains("allowSwap"))
ms.setSwapEnabled(json["allowSwap"]);
else
ms.setSwapEnabled(false);
if (json.contains("ref"))
ms.setRef(json["ref"]);
else if (json.contains("refSite"))
ms.setRef(json["refSite"]);
if (json.contains("nameOsm"))
ms.setGmaoOsmName(json["nameOsm"]);
if (json.contains("name"))
{
ms.setSlfrnName(json["name"]);
auto pos = ms.getSlfrnName().find('-');
if(pos != std::string::npos)
{
ms.setZone(true, ms.getSlfrnName().substr(0,pos));
}
}
if (json.contains("nameSlfrn"))
{
ms.setSlfrnName(json["nameSlfrn"]);
auto pos = ms.getSlfrnName().find('-');
if(pos != std::string::npos)
{
ms.setZone(true, ms.getSlfrnName().substr(0,pos));
}
}
ms.setType(json["typeSite"]);
//ms.setNameOsm(json["nameOsm"]);
for (nlohmann::json &capa: json["capaciteCreneaux"]) {
ms.m_capaciteCreneaux.push_back(MaintenanceSiteCapacite::from_json(capa));
}
for (nlohmann::json &voie: json["voieDuSite"]) {
ms.m_voiesDuSite.push_back(Voie::from_json(voie));
}
for (nlohmann::json &voie: json["voiesDuSite"]) {
ms.m_voiesDuSite.push_back(Voie::from_json(voie));
}
return ms;
}
}
+99
View File
@@ -0,0 +1,99 @@
#ifndef MAINTENANCESITE_H
#define MAINTENANCESITE_H
#include "Site.h"
#include "Voie.h"
#include <vector>
#include "MaintenanceSiteCapacite.h"
namespace modellib {
/*! @file MaintenanceSite.h*/
/**
* @class MaintenanceSite
* @brief Classe dcrivant un site de maintenance
*/
class MaintenanceSite : public Site {
private:
/**
* @brief Liste des voies du site
*/
std::vector<Voie> m_voiesDuSite;
/**
* @brief Liste des creneaux de travail du site
*/
std::vector<MaintenanceSiteCapacite> m_capaciteCreneaux;
/*
* @brief nom du site
*/
//std::string m_nameOsm;
public:
/**
* @brief Constructeur par dfaut
*/
MaintenanceSite() = default;
/**
* @brief Constructeur de confort
* @param ramesArretees liste des rames rames arrtes sur le site
* @param distance distances entre ce site et tous les autres
* @param voiesDuSite liste des voies du site
* @param capaciteCreneaux liste des creneaux de travail du site
* @param pIdSite identifiant du site
* @param ref la rfrence du site
* @param type le type de site (1 = technicentre, 2 = site dport, autre = site gare)
* @param name le nom du site
* @param idWeb l'identifiant webmat du site
*/
MaintenanceSite(std::vector<Voie> &voiesDuSite, std::vector<MaintenanceSiteCapacite> &capaciteCreneaux,
std::string &ref, std::string &sn,std::string &gmao, unsigned int type);//, std::string name);
MaintenanceSite(const std::string &ref, const std::string &sn, const std::string &gmao, unsigned int type);//, std::string name);
/**
* @brief Destructeur. Ne fait rien
*/
~MaintenanceSite() override = default;
/**
* @brief Getter simple par rfrence sur la liste des voies du site
* @return la liste des voies du site
*/
inline std::vector<Voie> &getVoies() { return m_voiesDuSite; };
/**
* @brief Getter simple sur la liste des creneaux de travail du site
* @return la liste des creneaux de travail du site
*/
inline std::vector<MaintenanceSiteCapacite> &getCapacieCreneaux() { return m_capaciteCreneaux; };
/**
* @brief Setter simple sur le nom du site
* @param name le nom du site
*/
//void setNameOsm(std::string name) { m_nameOsm = name; };
/**
* @brief Getter simple sur le nom du site
* @return le nom du site
*/
//std::string getNameOsm() { return m_nameOsm; };
/**
* @brief Fonction interface de traduction de l'objet MaintenanceSite vers un objet JSON
* @return le json dcrivant le site
*/
nlohmann::json to_json(bool withinfo = true);
/**
* @brief Fonction interface de traduction de l'objet JSON vers un objet MaintenanceSite
* @param json le JSON dcrivant un site de maintenance
* @return l'instance de la classe MaintenanceSite correspondant l'objet JSON d'entre
*/
static MaintenanceSite from_json(nlohmann::json &json);
};
}
#endif
@@ -0,0 +1,22 @@
#include "MaintenanceSiteCapacite.h"
namespace modellib {
nlohmann::json MaintenanceSiteCapacite::to_json() {
nlohmann::json msc = nlohmann::json::object();
msc["nbMaxRames"] = m_nbMaxRames;
msc["creneauTravail"] = m_creneauHoraire.to_json();
return msc;
}
MaintenanceSiteCapacite MaintenanceSiteCapacite::from_json(nlohmann::json &json) {
MaintenanceSiteCapacite msc;
msc.m_nbMaxRames = json["nbMaxRames"];
msc.m_creneauHoraire = CreneauHoraire::from_json(json["creneauTravail"]);
return msc;
}
MaintenanceSiteCapacite::MaintenanceSiteCapacite(unsigned int maxrame, CreneauHoraire &cren) {
m_nbMaxRames = maxrame;
m_creneauHoraire = cren;
}
}
@@ -0,0 +1,60 @@
#ifndef MAINTENANCESITECAPACITE_H
#define MAINTENANCESITECAPACITE_H
#include "CreneauHoraire.h"
namespace modellib {
/*! @file MaintenanceSiteCapacite.h*/
/**
* @class MaintenanceSiteCapacite
* @brief Classe dcrivant un creneau de travail sur un site de maintenance
*/
class MaintenanceSiteCapacite {
private:
/**
* @brief Nombre maximum de rames arrtes
*/
unsigned int m_nbMaxRames{};
/**
* @brief Priode concerne par le creneau de travail
*/
CreneauHoraire m_creneauHoraire;
public:
/**
* @brief Destructeur. Ne fait rien
*/
~MaintenanceSiteCapacite() = default;
MaintenanceSiteCapacite() = default;
MaintenanceSiteCapacite(unsigned int maxrame, CreneauHoraire& cren);
/**
* @brief Getter simple sur le nombre de rames maximum arrtes sur le site
* @return le nombre de rames maximum arrtes sur le site
*/
[[nodiscard]] inline unsigned int getNbMaxRames() const { return m_nbMaxRames; };
/**
* @brief Getter simple sur la priode du creneau de travail
* @return la priode du creneau de travail
*/
inline CreneauHoraire &getCreneau() { return m_creneauHoraire; };
/**
* @brief Fonction interface de traduction de l'objet MaintenanceSiteCapacite vers un objet JSON
* @return le json dcrivant le creneau de travail du site
*/
nlohmann::json to_json();
/**
* @brief Fonction interface de traduction de l'objet JSON vers un objet MaintenanceSiteCapacite
* @param json le JSON dcrivant un creneau de travail d'un site
* @return l'instance de la classe MaintenanceSiteCapacite correspondant l'objet JSON d'entre
*/
static MaintenanceSiteCapacite from_json(nlohmann::json &json);
};
}
#endif
+3
View File
@@ -0,0 +1,3 @@
#include "OpRame.hpp"
namespace modellib {
}
+70
View File
@@ -0,0 +1,70 @@
#ifndef OPRAME_HPP
#define OPRAME_HPP
#include "DispVoieRame.hpp"
#include "TrajectoryStop.hpp"
#include <list>
namespace std{
template <> struct hash<modellib::EmplacementRame*>
{
size_t operator()(const modellib::EmplacementRame* val) const {
static const auto shift = (size_t)log2(1 + sizeof(modellib::EmplacementRame*));
size_t h = (size_t)(val) >> shift;
return h;
}
};
}
namespace modellib {
/**
* @class OpRame
* @brief Class wrapping a job and its associated train. Allowing to compute the availabilities between train and tracks
*/
class OpRame {
public:
/**
* @brief The train
*/
unsigned int rame;
/**
* @brief The job
*/
unsigned int op;
/**
* @brief The possible matches of availabilities between train and tracks on which job can be scheduled
*/
//std::vector<unsigned int> dispoVoiesRame;
/**
* @brief Default constructor
*/
OpRame() {
}
/**
* @brief Destructor
*/
~OpRame() {
/*for (auto i: dispoVoiesRame) {
delete i;
}*/
}
/**
* Copy constructor
* @param copy the job train wrapper to copy
*/
OpRame(const OpRame &copy) {
rame = copy.rame;
op = copy.op;
//dispoVoiesRame = copy.dispoVoiesRame;
/*dispoVoiesRame.reserve(copy.dispoVoiesRame.size());
for (auto &disp: copy.dispoVoiesRame) {
dispoVoiesRame.emplace_back(disp);
dispoVoiesRame.back().opRame = this;
}*/
}
};
}
#endif
+56
View File
@@ -0,0 +1,56 @@
#include "OperationPlanifie.h"
#include "CreneauHoraire.h"
#include "Date.h"
#include "STFMockInstance.hpp"
namespace modellib {
/*OperationPlanifie::OperationPlanifie(OperationRequise* poperation)
: m_voieAssignee(nullptr), m_siteAssocie(nullptr), m_operation(poperation), rentree(nullptr) {
//m_voieAssignee->setId(-1);
m_postCroisement = false;
m_rejete = false;
}*/
OperationPlanifie::OperationPlanifie(unsigned short op) : m_operation(op)
{
m_postCroisement = false;
m_rejete = false;
}
OperationPlanifie::OperationPlanifie(unsigned int short op, unsigned char voie, unsigned char site, unsigned int trStop, unsigned short intTrack, std::pair<unsigned short, unsigned short> slot, bool rejete, bool croise):
m_rejete(rejete), m_postCroisement(croise), m_voieAssignee(voie), m_siteAssocie(site), m_operation(op), rentree(trStop), intervalVoie(intTrack), creneau(slot)
{
}
nlohmann::json OperationPlanifie::to_json(std::shared_ptr<STFMockInstance> state) {
nlohmann::json op = nlohmann::json::object();
op["rejete"] = m_rejete;
op["croisement"] = m_postCroisement;
CreneauHoraire slot = {SolverDate::getDateDebut() + creneau.first, SolverDate::getDateDebut() + creneau.second};
nlohmann::json creneauJS = slot.to_json();
op["debut"] = creneauJS["debut"];
op["fin"] = creneauJS["fin"];
op["rentree"] = state->trajectoryStops[rentree].getDispoStop().getDebutC().to_json();
if(configlib::Configuration::Meta.DOCKER)
op["debut"] = op["rentree"];
nlohmann::json voie = STFMockInstance::tracks[m_voieAssignee]->to_json(false);
op["voieAssignee"] = voie["id"];
nlohmann::json site = STFMockInstance::sites[m_siteAssocie]->to_json(false);
op["siteAssocie"] = site;
op["operationRequise"] = STFMockInstance::jobs[m_operation]->to_json();
auto td = state->trajectoryStops[rentree].typeDispo;
std::string precision = !td.second.empty() ? " : " : "";
op["typeDispo"] = EmplacementRame::smapTypeStops[td.first] + precision + td.second;;
return op;
}
}
+149
View File
@@ -0,0 +1,149 @@
#ifndef OPERATIONPLANIFIE_H
#define OPERATIONPLANIFIE_H
#include "CreneauHoraire.h"
#include "Date.h"
#include <utility>
#include <nlohmann/json.hpp>
//TODO changer pour que la rentrée soit en fait un unsigned int sur le trajectory stop + plus besoin de typeDispo + plus besoin de mémoriser le creneau de l'op, seulement pair<int, int> et on reconstruit à la toute fin seulement (gain temps calcul)
namespace modellib {
class STFMockInstance;
/*! @file OperationPlanifie.h*/
/**
* @class OperationPlanifie
* @brief Classe dcrivant une opration une fois planifie en sortie du solveur
*/
class OperationPlanifie {
private:
/**
* @brief boolen indiquant si l'opration a t rejete
*/
bool m_rejete = false;
bool m_postCroisement = false;
/**
* @brief la voie assigne l'opration
*/
unsigned char m_voieAssignee;
/*
* @brief le site associ l'opration
*/
unsigned char m_siteAssocie;
/**
* @brief l'opration a effectuer
*/
unsigned short m_operation;
unsigned int rentree;
unsigned short intervalVoie;
std::pair<unsigned short, unsigned short> creneau;
public:
/**
* @brief Constructeur par dfaut
*/
OperationPlanifie() = default;
/**
* @brief Constructeur de copie
* @param operation l'opration copier
*/
//explicit OperationPlanifie(OperationRequise *operation);
explicit OperationPlanifie(unsigned short op);
OperationPlanifie(unsigned int short op, unsigned char voie, unsigned char site, unsigned int trStop, unsigned short intTrack, std::pair<unsigned short, unsigned short> slot, bool rejete = false, bool croise = false);
/**
* @brief Destructeur. Ne fait rien
*/
inline ~OperationPlanifie() = default;
/**
* @brief Setter simple sur le statut rejet ou non
* @param isRejete le statut de l'opration
*/
inline void setRejete(bool isRejete) { m_rejete = isRejete; };
/**
* @brief Getter simple sur le statut de rejet
* @return true si rejete, false sinon
*/
[[nodiscard]] inline bool getRejete() const { return m_rejete; };
inline void setCroisement(bool isPostCrois) { m_postCroisement = isPostCrois; };
[[nodiscard]] inline bool getCroisement() const { return m_postCroisement; };
//inline void setTypeDispo(std::pair<typeStop, std::string>& type) { typeDispo = type; };
/**
* @brief Setter sur la priode de maintenance choisie
* @param creneau la priode sur laquelle effectuer l'opration
*/
//inline void setCreneau(const CreneauHoraire &creneau) { m_creneauHoraire = creneau; };
/**
* @brief Getter simple sur la priode de maintenance
* @return la priode de maintenance
*/
[[nodiscard]] inline CreneauHoraire getCreneauHoraire() const { return CreneauHoraire(SolverDate::getDateDebut() + creneau.first,SolverDate::getDateDebut() + creneau.second);};
[[nodiscard]] inline std::pair<unsigned short, unsigned short> getCreneau() const { return creneau;};
/**
* @brief Setter simple sur la voie assigne
* @param voie la voie assigne l'opration
*/
//inline void setVoie(Voie *voie) { m_voieAssignee = voie; };
/**
* @brief Getter simple sur la voie assigne
* @return la voie assigne l'opration
*/
inline unsigned char getVoie() { return m_voieAssignee; };
inline unsigned short getTrackInterval() {return intervalVoie;};
/**
* @brief Setter simple sur le site assign
* @param voie le site assign l'opration
*/
//inline void setSite(MaintenanceSite* site) { m_siteAssocie = site; };
/**
* @brief Getter simple sur le site assign
* @return le site assign l'opration
*/
inline unsigned char getSite() { return m_siteAssocie; };
/**
* @brief Setter simple sue l'opration requise
* @param op l'opration effectuer
*/
//inline void setOpeReq(OperationRequise *op) { m_operation = op; };
/**
* @brief Getter simple sur l'opration requise
* @return l'opration effectuer
*/
inline unsigned short getOperationRequise() { return m_operation; };
inline unsigned int getRentree(){return rentree;};
//inline void setRentree(EmplacementRame* r){rentree = r;};
/**
* @brief Fonction interface de traduction de l'objet OperationPlanifie vers un objet JSON
* @return le json dcrivant l'opration planifie
*/
nlohmann::json to_json(std::shared_ptr<STFMockInstance> state);
};
}
#endif
+133
View File
@@ -0,0 +1,133 @@
#include "OperationRequise.h"
#include "CreneauHoraire.h"
#include "MaintenanceSite.h"
namespace modellib {
nlohmann::json OperationRequise::to_json(bool verbose) {
nlohmann::json opeReq = nlohmann::json::object();
if (verbose) {
opeReq["duree"] = (ceil(m_duree / configlib::Configuration::Global.TIME_UNIT)) * 60;
opeReq["dureeDiag"] = (ceil(m_dureeDiag / configlib::Configuration::Global.TIME_UNIT)) * 60;
opeReq["dateDue"] = m_dateDue.to_json();
//opeReq["idTypeOperation"] = m_idTypeOperation;
opeReq["id"] = m_idOperation;
opeReq["idAnomalie"] = m_idAnomalie;
opeReq["idRame"] = m_idRame;
opeReq["numeroEF"] = m_numeroEF;
opeReq["codeDefaut"] = m_codeDefaut;
opeReq["diagnosticPossible"] = m_diagnosticPossible;
opeReq["poidsRetardDefaut"] = m_poidsRetardDefaut;
opeReq["poidsRejetDefaut"] = m_poidsRejetDefaut;
opeReq["hierarchie"] = m_hierarchie;
opeReq["poidCustom"]["poidRejet"] = m_poidsRejet;
opeReq["poidCustom"]["poidRetard"] = m_poidsRetard;
opeReq["libelleSignalement"] = m_libelleSignalement;
//opeReq["libelleStatutAnomalie"] = m_libelleStatutAnomalie;
//opeReq["codePanne"] = m_codePanne;
opeReq["commentaireSignalement"] = m_commentaireSignalement;
for (auto& inf : m_infrastructure) {
opeReq["infrastructure"].push_back(inf.to_json());
}
} else {
opeReq["hierarchie"] = m_hierarchie;
opeReq["libelleSignalement"] = m_libelleSignalement;
//opeReq["libelleStatutAnomalie"] = m_libelleStatutAnomalie;
//opeReq["codePanne"] = m_codePanne;
opeReq["commentaireSignalement"] = m_commentaireSignalement;
opeReq["id"] = m_idOperation;
opeReq["idAnomalie"] = m_idAnomalie;
opeReq["idRame"] = m_idRame;
opeReq["numeroEF"] = m_numeroEF;
}
return opeReq;
}
OperationRequise OperationRequise::from_json(nlohmann::json &json) {
OperationRequise op;
if (json.contains("ocOperation")) {
op.m_duree = json["ocOperation"]["duree"];
op.m_duree = (ceil(op.m_duree / 60.0f)) * configlib::Configuration::Global.TIME_UNIT;
op.m_dureeDiag = json["ocOperation"]["dureeDiagnostic"];
op.m_dureeDiag = (ceil(op.m_dureeDiag / 60.0f)) * configlib::Configuration::Global.TIME_UNIT;
//op.m_idTypeOperation = json["ocOperation"]["id"];
op.m_codeDefaut = json["codeDefault"];
op.m_diagnosticPossible = json["ocOperation"]["diagnosticPossible"];
op.m_poidsRetardDefaut = json["ocOperation"]["poidsRetardDefaut"];
op.m_poidsRejetDefaut = json["ocOperation"]["poidsRejetDefaut"];
op.m_hierarchie = json["hierarchisation"];
op.m_poidsRejet = op.m_poidsRejetDefaut;//json["ocOperation"]["poidCustom"]["poidRejet"];
op.m_poidsRetard = op.m_poidsRetardDefaut; //json["ocOperation"]["poidCustom"]["poidRetard"];
for (nlohmann::json &infra: json["ocOperation"]["infrastructures"]) {
op.m_infrastructure.push_back(TypeInfrastructure::from_json(infra));
}
op.m_libelleSignalement = json["libelleSignalement"];
op.m_commentaireSignalement = json["commentaireSignalement"];
//op.m_codePanne = json["codePanne"];
//op.m_libelleStatutAnomalie = json["libelleStatutAnomalie"];
} else {
op.m_duree = json["duree"];
op.m_duree = (ceil(op.m_duree / 60.0f)) * configlib::Configuration::Global.TIME_UNIT;
op.m_dureeDiag = json["dureeDiag"];
op.m_dureeDiag = (ceil(op.m_dureeDiag / 60.0f)) * configlib::Configuration::Global.TIME_UNIT;
//op.m_idTypeOperation = json["idTypeOperation"];
op.m_codeDefaut = json["codeDefaut"];
op.m_diagnosticPossible = json["diagnosticPossible"];
op.m_poidsRetardDefaut = json["poidsRetardDefaut"];
op.m_poidsRejetDefaut = json["poidsRejetDefaut"];
op.m_hierarchie = json["hierarchie"];
for (nlohmann::json &infra: json["infrastructure"]) {
op.m_infrastructure.push_back(TypeInfrastructure::from_json(infra));
}
op.m_poidsRejet = json["poidCustom"]["poidRejet"];
op.m_poidsRetard = json["poidCustom"]["poidRetard"];
}
if (json.contains("siPlanned") && !json["siPlanned"].is_null() && !json["siPlanned"]["acceptation"].is_null()) {
//op.m_propositionExistante.proposition;
SolverDate debut = SolverDate::from_json(json["siPlanned"]["plnfDebut"]);
SolverDate fin = SolverDate::from_json(json["siPlanned"]["plnfFin"]);
op.m_propositionExistante.creneau = CreneauHoraire(debut, fin);
MaintenanceSite s(json["siPlanned"]["plnfSite"], "","", 1);
Voie v;
v.setId(json["siPlanned"]["plnfVoie"]);
op.m_propositionExistante.voie = v;
op.m_propositionExistante.site = s;
op.m_propositionExistante.exists = true;
op.m_propositionExistante.isKeep = json["siPlanned"]["acceptation"];
if (json["siPlanned"].contains("dtReport") && !json["siPlanned"]["dtReport"].is_null()) {
op.m_propositionExistante.afterDate = SolverDate::from_json(json["siPlanned"]["dtReport"]);
}
} else {
op.m_propositionExistante.exists = false;
op.m_propositionExistante.afterDate = SolverDate::getDateDebut();
//op.m_propositionExistante.proposition = nullptr;
}
if (configlib::Configuration::Global.MAXIMIZE_ADVANCE) {
op.m_dateDue = SolverDate::getDateDebut();
} else {
op.m_dateDue = SolverDate::from_json(json["dateDue"]);
}
if(json["id"].is_number_unsigned())
{
unsigned int id = json["id"].get<unsigned int>();
op.m_idOperation = std::to_string(id);
}
else
op.m_idOperation = json["id"].get<std::string>();
if (json.contains("idAnomalie")) {
op.m_idAnomalie = json["idAnomalie"];
} else {
op.m_idAnomalie = json["id"];//par dfaut si absent => id du sig
}
return op;
}
}
+294
View File
@@ -0,0 +1,294 @@
#ifndef OPERATIONREQUISE_H
#define OPERATIONREQUISE_H
#include <utility>
#include "Date.h"
#include "PropositionExistante.hpp"
namespace modellib {
/*! @file OperationRequise.h*/
/**
* @class OperationRequise
* @brief Classe dcrivant une opration effectuer sur une rame
*/
class OperationRequise {
private:
/**
* @brief le poids de retard associ l'opration
*/
unsigned long long m_poidsRetard{};
/**
* @brief le poids de rejet associ l'opration
*/
unsigned long m_poidsRejet{};
/**
* @brief la dure ncessaire la ralisation de l'opration
*/
unsigned short m_duree{};
/**
* @brief l'identifiant de l'opration => du signalement pour le moment
*/
std::string m_idOperation;
/**
* @brief l'identifiant de l'anomalie associe l'opration
*/
int m_idAnomalie{};
/**
* @brief la dure ncessaire pour diagnostiquer le problme
*/
unsigned short m_dureeDiag{};
/**
* @brief la date avant laquelle on veut commencer l'opration. Dpend de la hrarchie
*/
SolverDate m_dateDue;
/**
* @brief Le code dfaut associ au type d'opration
*/
std::string m_codeDefaut;
/**
* @brief Le poids de retard par dfaut associ l'opration
*/
unsigned long long m_poidsRetardDefaut{};
/**
* @brief Le poids de rejet par dfaut associ l'opration
*/
unsigned long m_poidsRejetDefaut{};
/**
* @brief boolen indiquant si on le droit de rejeter cette opration ou non
*/
bool m_diagnosticPossible{};
std::string m_libelleSignalement;
std::string m_commentaireSignalement;
std::string m_codePanne;
std::string m_libelleStatutAnomalie;
/**
* @brief La liste des infrastructures ncessaire la rparation
*/
std::vector<TypeInfrastructure> m_infrastructure;
/**
* @brief Le niveau de hirarchie associ (criticit)
*/
unsigned short m_hierarchie{};
unsigned int m_idRame{};
std::string m_numeroEF;
Proposition m_propositionExistante;
public:
[[nodiscard]] const std::string &getMLibelleSignalement() const {
return m_libelleSignalement;
}
void setMLibelleSignalement(const std::string &mLibelleSignalement) {
m_libelleSignalement = mLibelleSignalement;
}
[[nodiscard]] const std::string &getMCommentaireSignalement() const {
return m_commentaireSignalement;
}
void setMCommentaireSignalement(const std::string &mCommentaireSignalement) {
m_commentaireSignalement = mCommentaireSignalement;
}
[[nodiscard]] const std::string &getMCodePanne() const {
return m_codePanne;
}
void setMCodePanne(const std::string &mCodePanne) {
m_codePanne = mCodePanne;
}
[[nodiscard]] const std::string &getMLibelleStatutAnomalie() const {
return m_libelleStatutAnomalie;
}
void setMLibelleStatutAnomalie(const std::string &mLibelleStatutAnomalie) {
m_libelleStatutAnomalie = mLibelleStatutAnomalie;
}
/**
* @brief Constructeur par dfaut
*/
OperationRequise() = default;
/**
* @brief Destructeur. Ne fait rien
*/
virtual ~OperationRequise() = default;
/**
* @brief Setter simple sur le poids de retard
* @param poidsR le poids de retard
*/
inline void setPoidsRetard(unsigned long long poidsR) { m_poidsRetard = poidsR; };
/**
* @brief Setter simple sur le numro d'EF de la rame concerne
* @param ef le nom de la rame
*/
inline void setIdRame(unsigned int id) { m_idRame = id; };
/**
* @brief Getter simple sur le nom de la rame touche
* @return le nom de la rame rparer
*/
[[nodiscard]] inline unsigned int getIdRame() const { return m_idRame; };
inline void setNumeroEF(std::string numef) { m_numeroEF = std::move(numef); };
inline std::string getNumeroEF() { return m_numeroEF; };
/**
* @brief Getter simple sur le poids de retard
* @return le poids de retard
*/
[[nodiscard]] inline unsigned long long getPoidsRetard() const { return m_poidsRetard; };
/**
* @brief Setter simple sur le poids de rejet
* @param poidsR Le poids de rejet
*/
void setPoidsRejet(unsigned long poidsR) { m_poidsRejet = poidsR; };
void setPoidsRejetDefaut(unsigned long poidsR) { m_poidsRejetDefaut = poidsR; };
void setPoidsRetardDefaut(unsigned long long poidsR) { m_poidsRetardDefaut = poidsR; };
void setDiagnosticPossible(bool po) { m_diagnosticPossible = po; };
void setHierarchie(unsigned short h) { m_hierarchie = h; };
void setCodeDefaut(std::string code) { m_codeDefaut = std::move(code); };
inline Proposition &getPropositionExistante() { return m_propositionExistante; };
inline void setPropositionExistante(Proposition &op) { m_propositionExistante = op; };
/**
* @brief Getter simple sur le poids de rejet
* @return le poids de rejet
*/
[[nodiscard]] inline unsigned long getPoidsRejet() const { return m_poidsRejet; };
/**
* @brief Setter simple sur la dure d'opration
* @param d la dure de l'opration
*/
inline void setDuree(unsigned short d) { m_duree = d; };
/**
* @brief Getter simple sur la dure d'opration
* @return la dure d'opration
*/
[[nodiscard]] inline unsigned short getDuree() const { return m_duree; };
/**
* @brief Setter simple sur l'identifiant de l'opration
* @param id l'identifiant de l'opration
*/
inline void setOpId(std::string& id) { m_idOperation = id; };
/**
* @brief Getter simple sur l'identifiant de l'opration
* @return l'identifiant de l'opration
*/
[[nodiscard]] inline std::string getOpId() const { return m_idOperation; };
/**
* @brief Setter simple sur l'identifiant de l'anomalie
* @param id l'identifiant de l'anomalie
*/
inline void setAnomalieId(int id) { m_idAnomalie = id; };
/**
* @brief Getter simple sur l'identifiant de l'anomalie
* @return l'identifiant de l'anomalie
*/
[[nodiscard]] inline int getAnomalieId() const { return m_idAnomalie; };
/**
* @brief Setter simple sur la dure de diagnostique
* @param d la dure de diagnostique
*/
void setDureeDiag(unsigned short d) { m_dureeDiag = d; };
/**
* @brief Getter simple sur la dure de diagnostique
* @return la dure de diagnostique
*/
[[nodiscard]] inline unsigned short getDureeDiag() const { return m_dureeDiag; };
/**
* @brief Setter simple sur la date due
* @param date la date avant laquelle on veut avoir planifi la maintenance
*/
inline void setDateDue(const SolverDate &date) { m_dateDue = date; };
/**
* @brief Getter simple par valeur de la date due
* @return la date avant laquelle on veut avoir planifi
*/
[[nodiscard]] inline SolverDate getDateDue() const { return m_dateDue; };
/**
* @brief Setter simple sur le type d'opration
* @param op le type d'opration
*/
//void setTypeOp(TypeOperation& op) { m_type = op; };
/**
* @brief Getter simple par valeur sur le type d'opration
* @return le type d'opration
*/
//TypeOperation& getTypeOp() { return m_type; };
/**
* @brief Getter simple sur la hrarchie
* @return la hrarchie
*/
[[nodiscard]] inline unsigned short getHierarchie() const { return m_hierarchie; };
/**
* @brief Getter simple par rfrence sur les infrastructures ncessaires
* @return La liste des infrastructures ncessaires la rparation
*/
inline std::vector<TypeInfrastructure> &getInfrastructures() { return m_infrastructure; };
inline void setInfrastructures(std::vector<TypeInfrastructure> &infra) { m_infrastructure = infra; };
/**
* @brief Fonction interface de traduction de l'objet OperationRequise vers un objet JSON
* @return le json dcrivant l'opration
*/
nlohmann::json to_json(bool verbose = true);
/**
* @brief Fonction interface de traduction de l'objet JSON vers un objet OperationRequise
* @param json le JSON dcrivant une opration
* @param operations la liste des types d'oprations gnriques
* @return l'instance de la classe OperationRequise correspondant l'objet JSON d'entre
*/
static OperationRequise from_json(nlohmann::json &json);
};
}
#endif
+245
View File
@@ -0,0 +1,245 @@
#include "Planification.h"
#include "CreneauHoraire.h"
#include "Decision.hpp"
#include "STFMockInstance.hpp"
#include <iterator>
#include <memory>
#include <unordered_map>
#include <vector>
namespace modellib {
long Planification::sommeRetardsPonderes(bool withExclusion) {
long somme = 0.;
bool sol = false;
for (OperationPlanifie &op: m_operationsOrdonnance) {
if (op.getCreneau().first <= STFMockInstance::jobs[op.getOperationRequise()]->getDateDue().getRelativeDate()) {
somme += 0;
} else {
somme += (op.getCreneau().first - STFMockInstance::jobs[op.getOperationRequise()]->getDateDue().getRelativeDate()) *
STFMockInstance::jobs[op.getOperationRequise()]->getPoidsRetard();
}
sol = true;
}
if (withExclusion) {
for (auto &exc: m_opImplanifiables) {
somme += STFMockInstance::jobs[exc]->getPoidsRetard() * MAXIMUM_TIME_OFFSET;
}
}
if (sol) {
return somme;
} else { return -1; }
}
long Planification::sommeRejetsPonderes() {
long somme = 0;
bool sol = false;
for (OperationPlanifie &op: m_operationsOrdonnance) {
somme += op.getRejete() * STFMockInstance::jobs[op.getOperationRequise()]->getPoidsRejet();
sol = true;
}
if (sol) { return somme; }
else { return -1; }
}
long Planification::sommeRejets() {
long somme = 0;
bool sol = false;
for (OperationPlanifie &op: m_operationsOrdonnance) {
somme += op.getRejete();
sol = true;
}
if (sol) { return somme; }
else { return -1; }
}
long Planification::sommeSwapCosts() {
long somme = 0;
for(auto& s : m_croisementsEffectues)
{
somme += s.cost;
}
return somme;
}
long Planification::sommmeRecompoCosts() {
long somme = 0;
for(auto& s : m_recompositionsEffectuees)
{
somme += s.cost;
}
return somme;
}
unsigned long Planification::countSwap() {
return m_croisementsEffectues.size();
}
unsigned long Planification::countRecompo() {
return m_recompositionsEffectuees.size();
}
unsigned long Planification::countDoubleRecompo(){
unsigned long nb =0;
for(auto& recompo : m_recompositionsEffectuees){
if(recompo.is_double_recompo.first){
nb++;
}
}
return nb;
}
unsigned long Planification::countDiag(int h) {
long c = 0;
for(auto& d : m_operationsOrdonnance)
{
if(d.getRejete() && (STFMockInstance::jobs[d.getOperationRequise()]->getHierarchie() == (unsigned int)h || h == -1))
{
c++;
}
}
return c;
}
unsigned long Planification::countExcluded(int h) {
long c = 0;
for(auto& d : m_opImplanifiables)
{
if(STFMockInstance::jobs[d]->getHierarchie() == (unsigned int)h || h == -1)
{
c++;
}
}
return c;
}
void Planification::cleanSwap(){
std::vector<size_t> idx_to_remove;
for(auto& recompo : m_recompositionsEffectuees){
if(recompo.is_double_recompo.first){
auto pos = std::find(m_recompositionsEffectuees.begin(), m_recompositionsEffectuees.end(), *recompo.is_double_recompo.second);
if(pos != m_recompositionsEffectuees.end()){
recompo.recompo_done.push_back(pos->recompo_done[0]);
if(recompo.um_crit_init.find(pos->recompo_done[0].rame_critique)){
recompo.um_crit_end.swap(pos->recompo_done[0].rame_critique,pos->recompo_done[0].rame_saine);
recompo.um_saine_end.swap( pos->recompo_done[0].rame_saine, pos->recompo_done[0].rame_critique);
}else{
recompo.um_crit_end.swap(pos->recompo_done[0].rame_saine, pos->recompo_done[0].rame_critique);
recompo.um_saine_end.swap( pos->recompo_done[0].rame_critique,pos->recompo_done[0].rame_saine);
}
recompo.UM_crit_TM_arrival = pos->UM_crit_TM_arrival;
recompo.UM_saine_TM_arrival = pos->UM_saine_TM_arrival;
idx_to_remove.push_back(std::distance(m_recompositionsEffectuees.begin(), pos));
}else{
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "[cleanSwap] - Recomposition double trouvé mais pas trouvé sa première recomposition");
}
}
}
std::sort(idx_to_remove.rbegin(), idx_to_remove.rend());
for(size_t idx : idx_to_remove){
m_recompositionsEffectuees.erase(m_recompositionsEffectuees.begin()+idx);
}
idx_to_remove.clear();
for(auto recompoptr : state->recompos){
RecompoUM& recompo = *recompoptr;
if(recompo.is_double_recompo.first){
auto pos = std::find_if(state->recompos.begin(), state->recompos.end(),[&](std::shared_ptr<RecompoUM> recptr){
return *recptr == *recompo.is_double_recompo.second;
});
if(pos != state->recompos.end()){
RecompoUM& other_recompo = **pos;
recompo.recompo_done.push_back(other_recompo.recompo_done[0]);
if(recompo.um_crit_init.find(other_recompo.recompo_done[0].rame_critique)){
recompo.um_crit_end.swap(other_recompo.recompo_done[0].rame_critique,other_recompo.recompo_done[0].rame_saine);
recompo.um_saine_end.swap( other_recompo.recompo_done[0].rame_saine, other_recompo.recompo_done[0].rame_critique);
}else{
recompo.um_crit_end.swap(other_recompo.recompo_done[0].rame_saine, other_recompo.recompo_done[0].rame_critique);
recompo.um_saine_end.swap( other_recompo.recompo_done[0].rame_critique,other_recompo.recompo_done[0].rame_saine);
}
recompo.UM_crit_TM_arrival = other_recompo.UM_crit_TM_arrival;
recompo.UM_saine_TM_arrival = other_recompo.UM_saine_TM_arrival;
idx_to_remove.push_back(std::distance(state->recompos.begin(), pos));
}else{
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "[cleanSwap] - Recomposition double trouvé mais pas trouvé sa première recomposition");
}
}
}
std::sort(idx_to_remove.rbegin(), idx_to_remove.rend());
for(size_t idx : idx_to_remove){
//delete state->recompos[idx];
state->recompos.erase(state->recompos.begin()+idx);
}
}
void Planification::clean()
{
/*if(state)
delete state;*/
}
nlohmann::json Planification::to_json() {
nlohmann::json planif = nlohmann::json::object();
planif["sommeRetardPondere"] = sommeRetardsPonderes();
planif["sommeRetardPondereWithExclusions"] = sommeRetardsPonderes(true);
planif["sommeRejetPondere"] = sommeRejetsPonderes();
planif["operationsPlanifiees"] = nlohmann::json::array();
planif["opImplanifiables"] = nlohmann::json::array();
planif["rdvNonOrientes"] = nlohmann::json::array();
planif["statistiques"] = infos.to_json();
for (auto& croi : m_croisementsEffectues) {
planif["croisementsEffectues"].push_back(croi.to_json());
}
for (auto& rec : m_recompositionsEffectuees) {
planif["recompositionsEffectues"].push_back(rec.to_json());
}
for (auto& opo : m_operationsOrdonnance) {
planif["operationsPlanifiees"].push_back(opo.to_json(state));
}
for (auto& opi : m_opImplanifiables) {
planif["opImplanifiables"].push_back(STFMockInstance::jobs[opi]->to_json(false));
}
for(auto& rdv : getPlanificationState()->preventiveMaintenanceRdvms)
{
if(!rdv->isOriented())
planif["rdvNonOrientes"].push_back(rdv->to_json());
}
return planif;
}
std::unordered_map<unsigned short, Decision> Planification::getMapOfDecisions()
{
std::unordered_map<unsigned short, Decision> map;
for(auto& opPlan : this->getOperationsPlan())
{
map[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())
{
map[opPlan] = {
0,
CreneauHoraire(),
0,
false,
true,
0,
0,
{0,0}
};
}
return map;
}
}
+124
View File
@@ -0,0 +1,124 @@
#ifndef PLANIFICATION_H
#define PLANIFICATION_H
#include "Decision.hpp"
#include "OperationPlanifie.h"
#include "CroisementUM.hpp"
#include "PlanificationStats.hpp"
#include "RecompoUM.h"
#include <unordered_map>
#include <vector>
namespace modellib {
/*! @file Planification.h*/
class STFMockInstance;
/**
* @class Planification
* @brief Classe dcrivant la planification retourne par le solveur
*/
class Planification {
private:
/**
* @brief Liste des planifications associes aux oprations effectuer
*/
std::vector<OperationPlanifie> m_operationsOrdonnance;
std::vector<unsigned short> m_opImplanifiables;
std::vector<CroisementUM> m_croisementsEffectues;
std::vector<RecompoUM> m_recompositionsEffectuees;
std::shared_ptr<STFMockInstance> state{};
PlanificationStats infos;
public:
/**
* @brief Constructeur par dfaut
*/
Planification() = default;
/**
* @brief Destructeur. Ne fait rien
*/
virtual ~Planification() = default;
/**
* @brief Ajoute une operation planifiee a cette solution.
* @param operation la planification de l'opration
* @return NEANT
*/
void addOperation(OperationPlanifie &operation) { m_operationsOrdonnance.push_back(std::move(operation)); }
/**
* @brief Ajoute une rame implanifiable a cette solution.
* @param rameId le numro d'ef de la rame
* @return NEANT
*/
void addRameImpossible(unsigned short opId) { m_opImplanifiables.emplace_back(opId); };
/**
* @brief Renvoie la somme ponderee des retards de debut d'operation.
* @return La somme pondre des retards
*/
long sommeRetardsPonderes(bool withExclusion = false);
/**
* @brief Renvoie la somme ponderee des rejets des operations.
* @return La somme pondre des retards
*/
long sommeRejetsPonderes();
long sommeRejets();
long sommeSwapCosts();
long sommmeRecompoCosts();
unsigned long countRecompo();
unsigned long countSwap();
unsigned long countDoubleRecompo();
unsigned long countDiag(int h = -1);
unsigned long countExcluded(int h = -1);
/**
* @brief Getter spcifique par rfrence de la dernire opration ajoute la planification
* @return L'opration planifie ajoute en dernier
*/
//OperationPlanifie &getOperationLast() { return m_operationsOrdonnance.back(); };
/**
* @brief Getter simple par rfrence sur les oprations planifies
* @return La liste des oprations planifies
*/
std::vector<OperationPlanifie> &getOperationsPlan() { return m_operationsOrdonnance; };
std::vector<CroisementUM> &getCroisementsEffectues() { return m_croisementsEffectues; };
std::vector<RecompoUM> &getRecompositionsEffectuees() { return m_recompositionsEffectuees; };
std::vector<unsigned short> &getOpImplanifiables() { return m_opImplanifiables; };
std::shared_ptr<STFMockInstance> getPlanificationState(){
return state;
}
PlanificationStats& getInfos(){return infos;};
void clean();
void setPlanificationState(std::shared_ptr<STFMockInstance> s){
state = s;
}
void cleanSwap();
/**
* @brief Fonction interface de traduction de l'objet Planification vers un objet JSON
* @return le json dcrivant la planification
*/
nlohmann::json to_json();
std::unordered_map<unsigned short, Decision> getMapOfDecisions();
};
}
#endif
+64
View File
@@ -0,0 +1,64 @@
#include "PlanificationStats.hpp"
#include <algorithm>
#include <iostream>
namespace modellib {
nlohmann::json PlanificationStats::to_json() {
nlohmann::json json;
json["nbRames"] = nbRames;
json["nbSites"] = nbSites;
json["nbVoies"] = nbVoies;
auto lbdCountMap = [&](unsigned int sum, const std::pair<unsigned int, unsigned int> &p) {
return sum + p.second;
};
json["nbOperations"] = std::accumulate(std::begin(mapOpPlan), std::end(mapOpPlan), 0U, lbdCountMap) +
std::accumulate(std::begin(mapOpExcluAval), std::end(mapOpExcluAval), 0U, lbdCountMap) +
std::accumulate(std::begin(mapOpExcluAmont), std::end(mapOpExcluAmont), 0U, lbdCountMap);
json["nbOperationsDiagnostic"] = std::accumulate(std::begin(mapOpDiag), std::end(mapOpDiag), 0U, lbdCountMap);
json["nbOperationsExcluAval"] = std::accumulate(std::begin(mapOpExcluAval), std::end(mapOpExcluAval), 0U,
lbdCountMap);
json["nbOperationsExcluAmont"] = std::accumulate(std::begin(mapOpExcluAmont), std::end(mapOpExcluAmont), 0U,
lbdCountMap);
//key creation for known values
json["nbH1plan"] = 0;
json["nbH2plan"] = 0;
json["nbH3plan"] = 0;
json["nbH1excluAval"] = 0;
json["nbH2excluAval"] = 0;
json["nbH3excluAval"] = 0;
json["nbH1excluAmont"] = 0;
json["nbH2excluAmont"] = 0;
json["nbH3excluAmont"] = 0;
json["nbH1diag"] = 0;
json["nbH2diag"] = 0;
json["nbH3diag"] = 0;
for (auto &v: mapOpPlan) {
json["nbH" + std::to_string(v.first) + "plan"] = v.second;
}
for (auto &v: mapOpExcluAval) {
json["nbH" + std::to_string(v.first) + "excluAval"] = v.second;
}
for (auto &v: mapOpExcluAmont) {
json["nbH" + std::to_string(v.first) + "excluAmont"] = v.second;
}
for (auto &v: mapOpDiag) {
json["nbH" + std::to_string(v.first) + "diag"] = v.second;
}
json["impossibilites"] = nlohmann::json::object();
json["impossibilites"]["signalements"] = nlohmann::json::array();
for (auto &reason: m_reasons) {
nlohmann::json re = nlohmann::json::object();
re["solveur"] = reason.solveur;
re["raison"] = reason.raison;
re["id"] = reason.id;
re["hierarchie"] = reason.hierarchie;
re["idAnomalie"] = reason.idAnomalie;
json["impossibilites"]["signalements"].push_back(re);
}
// json["impossibilites"] = re;
return json;
}
}
+29
View File
@@ -0,0 +1,29 @@
#ifndef STFINSTANCEINFOSTATSV2_HPP
#define STFINSTANCEINFOSTATSV2_HPP
#include <map>
#include <string>
#include <nlohmann/json.hpp>
#include "ExclusionInfo.hpp"
namespace modellib {
class PlanificationStats {
private:
std::vector<ExclusionInfo> m_reasons;
public:
unsigned int nbRames;
unsigned int nbSites;
unsigned int nbVoies;
std::unordered_map<unsigned int, unsigned int> mapOpPlan;
std::unordered_map<unsigned int, unsigned int> mapOpExcluAmont;
std::unordered_map<unsigned int, unsigned int> mapOpExcluAval;
std::unordered_map<unsigned int, unsigned int> mapOpDiag;
PlanificationStats() = default;
std::vector<ExclusionInfo> &getReasons() { return m_reasons; };
nlohmann::json to_json();
};
}
#endif
@@ -0,0 +1,122 @@
#include "PreventiveMaintenanceRdv.hpp"
#include "CreneauHoraire.h"
#include "TypeInfrastructure.h"
#include "nlohmann/json_fwd.hpp"
#include <algorithm>
#include <sstream>
namespace modellib {
void PreventiveMaintenanceRdv::tokenize()
{
std::stringstream ss(getLibelle());
std::string intermediate;
while(getline(ss, intermediate, '+'))
{
tokens.insert(intermediate);
}
}
bool PreventiveMaintenanceRdv::areEquivalent(const PreventiveMaintenanceRdv& rdv1, const PreventiveMaintenanceRdv& rdv2)
{
auto& maxSizeRdv = rdv1.tokens.size() >= rdv2.tokens.size() ? rdv1 : rdv2;
auto& minSizeRdv = rdv1.tokens.size() < rdv2.tokens.size() ? rdv1 : rdv2;
float Score_size = 1 - ((float)(maxSizeRdv.tokens.size() - minSizeRdv.tokens.size())/(float)maxSizeRdv.tokens.size());
bool Score_infra = (maxSizeRdv.infra.first == false && minSizeRdv.infra.first == false) || (maxSizeRdv.infra.first == minSizeRdv.infra.first && maxSizeRdv.infra.second == minSizeRdv.infra.second);
unsigned int n = 0;
for(auto& tok : maxSizeRdv.tokens)
{
if(minSizeRdv.tokens.find(tok) != minSizeRdv.tokens.end())
{
++n;
}
}
float Score_similarite = (float)(n)/(float)(minSizeRdv.tokens.size());
float alpha = 0.75;
return Score_infra*(alpha*Score_size + (1.0f-alpha)*Score_similarite)*100.0f >= 75;
}
PreventiveMaintenanceRdv PreventiveMaintenanceRdv::from_json(nlohmann::json &json, std::vector<MaintenanceSite> &msites) {
PreventiveMaintenanceRdv rdv;
rdv.setOriented(true);
//rdv.isImperative(json["imperatif"].get<bool>());
auto l = json["libelle"].get<std::string>();
rdv.setLibelle(l);
if(!json["dateButee"].is_null())
{
auto dl = SolverDate::from_json(json["dateButee"]);
rdv.setDeadline(dl);
}
else if(json["interventions"].is_array() && !json["interventions"].empty())
{
SolverDate min = SolverDate::getDateDebut() + 336;
for(auto& inter : json["interventions"])
{
if(!inter["butee"].is_null())
{
auto tmp = SolverDate::from_json(inter["butee"]);
if(tmp < min)
{
min = tmp;
}
}
}
rdv.setDeadline(min);
}
else
{
auto dl = SolverDate::getDateDebut() + 336;
rdv.setDeadline(dl);
}
if(!json["rdvId"].is_null())
rdv.setRdvId(json["rdvId"].get<unsigned int>());
if(!json["id_rdv"].is_null())
rdv.setRdvId(json["id_rdv"].get<unsigned int>());
if(json.contains("infrastructure"))
{
rdv.infra.first = true;
rdv.infra.second = TypeInfrastructure::from_json(json["infrastructure"]);
}
else {
rdv.infra.first = false;
}
if(!json["siteRef"].is_null())
{
std::string ref = json["siteRef"].get<std::string>();
auto found = std::find_if(msites.begin(), msites.end(), [&](auto& site){return site.getRef() == ref;});
if(found != msites.end())
{
Site cop = *found;
rdv.setSite(cop);
}
}
if(!json["isOriented"].is_null())
{
rdv.setOriented(json["isOriented"].get<bool>());
}
rdv.creneau = CreneauHoraire::from_json(json["creneau"]);
rdv.tokenize();
return rdv;
}
nlohmann::json PreventiveMaintenanceRdv::to_json()
{
nlohmann::json json;
json["rdvId"] = rdvId;
json["dateButee"] = closestDeadline.to_json();
if(infra.first)
{
json["infrastructure"] = infra.second.to_json();
}
json["creneau"] = this->getCreneauChosen().to_json();
json["isOriented"] = this->oriented;
json["siteRef"] = this->site.getRef();
json["libelle"] = this->libelle;
return json;
}
}
@@ -0,0 +1,53 @@
#ifndef ORDONNANCEMENTCORRECTIF_PREVENTIVEMAINTENANCERDV_HPP
#define ORDONNANCEMENTCORRECTIF_PREVENTIVEMAINTENANCERDV_HPP
#include <string>
#include "CreneauHoraire.h"
#include "Date.h"
#include "MaintenanceSite.h"
#include "Site.h"
#include "TypeInfrastructure.h"
namespace modellib {
class PreventiveMaintenanceRdv {
private:
unsigned int rdvId;
bool imperative;
bool oriented;
std::string libelle;
SolverDate closestDeadline;
std::set<std::string> tokens;
std::pair<bool, TypeInfrastructure> infra;
CreneauHoraire creneau;
Site site;
public:
PreventiveMaintenanceRdv()=default;
[[nodiscard]] unsigned int getRdvId() const {return rdvId;}
bool isImperative() const {return imperative;}
const std::string& getLibelle() const {return libelle;}
const SolverDate& getDeadline() const {return closestDeadline;}
void setRdvId(unsigned int id){rdvId = id;}
void isImperative(bool i){imperative = i;}
void setOriented(bool i){oriented = i;}
bool isOriented(){ return oriented;};
void setLibelle(std::string& l){libelle = l;}
void setDeadline(SolverDate& d){closestDeadline = d;}
static PreventiveMaintenanceRdv from_json(nlohmann::json& json, std::vector<MaintenanceSite> &msites);
void tokenize();
std::string getSiteRef(){ return site.getRef();};
void setSite(Site& s){site= s;}
CreneauHoraire& getCreneauChosen(){ return creneau; };
std::pair<bool, TypeInfrastructure>& getInfra(){return infra;};
nlohmann::json to_json();
//todo matrice de compa entre chaque rdv => avoir une liste globale de rdv ?
//todo fonction compat rdv basé sur le libellé
//todo modifier le condition holder pour prendre en compte la contrainte sur l'équivalence de RDV avec la marge de manoeuvre sur la safety deadline
static bool areEquivalent(const PreventiveMaintenanceRdv& rdv1, const PreventiveMaintenanceRdv& rdv2);
};
}
#endif
@@ -0,0 +1,41 @@
#ifndef PROPOSITIONEXISTANTE_HPP
#define PROPOSITIONEXISTANTE_HPP
#include "MaintenanceSite.h"
namespace modellib {
/**
* @brief The structure containing the informations about a previous scheduling of a job
*/
typedef struct _propexistante {
/**
* @brief Indicates if the job has a previous scheduling proposal
*/
bool exists = false;
/**
* @brief Indicates if the proposal has been accepted or reported
*/
bool isKeep = false;
/**
* @brief The previous proposal period
*/
CreneauHoraire creneau;
/**
* @brief The track
*/
Voie voie;
/**
* @brief The maintenance site
*/
MaintenanceSite site;
/**
* The date after which the job has to be scheduled if isKeep is at false
*/
SolverDate afterDate;
} Proposition;
}
#endif
+59
View File
@@ -0,0 +1,59 @@
#include "Rame.h"
#include "MaintenanceSite.h"
#include "PreventiveMaintenanceRdv.hpp"
#include "nlohmann/json_fwd.hpp"
namespace modellib {
nlohmann::json Rame::to_json() {
nlohmann::json rame = nlohmann::json::object();
rame["numeroEF"] = m_numeroEF;
rame["id"] = m_idRame;
rame["signalements"] = nlohmann::json::array();
for (auto & i : m_signalement) {
rame["signalements"].push_back(i.to_json());
}
rame["presenceSite"] = nlohmann::json::array();
for (auto & i : m_creuxRoulement) {
rame["presenceSite"].push_back(i.to_json());
}
rame["rdvms"] = nlohmann::json::array();
for(auto& rdv : m_rdvms)
{
rame["rdvms"].push_back(rdv.to_json());
}
return rame;
}
Rame Rame::from_json(nlohmann::json &json, std::vector<MaintenanceSite> &msites, std::vector<Site> &sites) {
Rame rame;
rame.m_numeroEF = json["numeroEF"];
if(json.contains("lcn"))
rame.m_lcn = json["lcn"];
if(json.contains("serie"))
rame.m_serie = json["serie"];
rame.m_idRame = json["id"];
for (nlohmann::json &sig: json["signalements"]) {
rame.m_signalement.push_back(OperationRequise::from_json(sig));
}
for (nlohmann::json &creux: json["presenceSite"]) {
rame.m_creuxRoulement.push_back(EmplacementRame::from_json(creux, msites, sites));
}
for (nlohmann::json &creux: json["presencesSite"]) {
rame.m_creuxRoulement.push_back(EmplacementRame::from_json(creux, msites, sites));
}
if(json.contains("rdvms"))
{
for (nlohmann::json &rdv: json["rdvms"]) {
rame.m_rdvms.push_back(PreventiveMaintenanceRdv::from_json(rdv, msites));
}
}
return rame;
}
}
+99
View File
@@ -0,0 +1,99 @@
#ifndef RAME_H
#define RAME_H
#include <utility>
#include <vector>
#include "GareSite.h"
#include "OperationRequise.h"
#include "EmplacementRame.h"
#include "PreventiveMaintenanceRdv.hpp"
namespace modellib {
/*! @file Rame.h*/
/**
* @class Rame
* @brief Classe dcrivant une rame
*/
class Rame {
private:
/**
* @brief Liste des signalements associs la rame
*/
std::vector<OperationRequise> m_signalement;
/**
* @brief Liste des priodes de disponibilit de la rame
*/
std::vector<EmplacementRame> m_creuxRoulement;
std::vector<PreventiveMaintenanceRdv> m_rdvms;
std::string m_numeroEF;
std::string m_serie;
std::string m_lcn;
unsigned int m_idRame{};
public:
/**
* @brief Constructeur par dfaut
*/
Rame() = default;
/**
* @brief Destructeur. Ne fait rien
*/
virtual ~Rame() = default;
inline std::string getNumeroEF() { return m_numeroEF; };
inline std::string getSerie() { return m_serie; };
inline std::string getLcn() { return m_lcn; };
void setNumeroEF(std::string ef) { m_numeroEF = std::move(ef); };
void setSerie(std::string ser) { m_serie = std::move(ser); };
void setLCN(std::string l) { m_lcn = std::move(l); };
[[nodiscard]] inline unsigned int getId() const { return m_idRame; };
void setId(unsigned int id) { m_idRame = id; };
/**
* @brief Getter simple par rfrence sur les signalements
* @return la rfrence de la liste des signalements
*/
inline std::vector<OperationRequise> &getSignalements() { return m_signalement; };
/**
* @brief Getter simple par rfrence sur les creux de roulements
* @return la rfrence de la liste des creux de roulements
*/
inline std::vector<EmplacementRame> &getCreuxRoulement() { return m_creuxRoulement; };
inline std::vector<PreventiveMaintenanceRdv>& getRdvms(){return m_rdvms;};
/**
* @brief Fonction interface de traduction de l'objet Rame vers un objet JSON
* @return le json dcrivant la rame
*/
nlohmann::json to_json();
/**
* @brief Fonction interface de traduction de l'objet JSON vers un objet Rame
* @param json le JSON dcrivant une rame
* @param operations la liste des types d'oprations gnriques
* @return l'instance de la classe Rame correspondant l'objet JSON d'entre
*/
static Rame from_json(nlohmann::json &json, std::vector<MaintenanceSite> &msites, std::vector<Site> &sites);
};
}
#endif
+323
View File
@@ -0,0 +1,323 @@
#include "RecompoUM.h"
#include "STFInstance.h"
#include "STFMockInstance.hpp"
#include "TrajectoryStop.hpp"
#include <algorithm>
#include <climits>
namespace modellib {
nlohmann::json RecompoUM::to_json() {
nlohmann::json json = nlohmann::json::object();
auto slot = getPotentialRecompoSlot();
json["debutPotentiel"] = slot.getDebut().to_json();
json["finPotentielle"] = slot.getFin().to_json();
json["site"] = site->to_json(false);
json["umCritique"] = nlohmann::json::object();
json["umCritique"]["numTrain"] = STFMockInstance::stops[stopRame_UMCrit[0].entree]->getNumTrain();
json["umCritique"]["rentree"] = stopRame_UMCrit[0].getDispoStop().to_json();
json["umCritique"]["initial"] = nlohmann::json::object();
json["umCritique"]["end"] = nlohmann::json::object();
json["umSaine"] = nlohmann::json::object();
json["umSaine"]["numTrain"] = STFMockInstance::stops[stopRame_UMSane[0].entree]->getNumTrain();
json["umSaine"]["rentree"] = stopRame_UMSane[0].getDispoStop().to_json();
json["umSaine"]["initial"] = nlohmann::json::object();
json["umSaine"]["end"] = nlohmann::json::object();
json["umCritique"]["rentreeTM"] = nlohmann::json::array();
for(auto rame : UM_crit_TM_arrival){
if(rame.first){
nlohmann::json json_info = nlohmann::json::object();
json["umCritique"]["rentreeTM"].push_back(rame.second.to_json(false));
}else{
nlohmann::json json_noTM = nlohmann::json::object();
json["umCritique"]["rentreeTM"].push_back(json_noTM);
}
}
json["umSaine"]["rentreeTM"] = nlohmann::json::array();
for(auto rame : UM_saine_TM_arrival){
if(rame.first){
nlohmann::json json_info = nlohmann::json::object();
json["umSaine"]["rentreeTM"].push_back(rame.second.to_json(false));
}else{
nlohmann::json json_noTM = nlohmann::json::object();
json["umSaine"]["rentreeTM"].push_back(json_noTM);
}
}
unsigned int c = 0;
for(auto& us : um_crit_init.ramesInfo)
{
std::string numb = "us"+std::to_string(c+1);
json["umCritique"]["initial"][numb]["numImmatEf"] = STFMockInstance::rames[us.id]->getNumeroEF();
json["umCritique"]["initial"][numb]["ligne"] = um_crit_init.ramesInfo[c].ligne;
json["umCritique"]["initial"][numb]["rang"] = um_crit_init.ramesInfo[c].rang;
json["umCritique"]["initial"][numb]["signalementsProposes"] = nlohmann::json::array();
json["umCritique"]["initial"][numb]["signalements"] = nlohmann::json::array();
for(auto& sig : STFMockInstance::rames[us.id]->getSignalements())
{
json["umCritique"]["initial"][numb]["signalementsProposes"].push_back(sig.to_json(false));
json["umCritique"]["initial"][numb]["signalements"].push_back(sig.to_json(false));
}
++c;
}
c = 0;
for(auto& us : um_crit_end.ramesInfo)
{
std::string numb = "us"+std::to_string(c+1);
json["umCritique"]["end"][numb]["numImmatEf"] = STFMockInstance::rames[us.id]->getNumeroEF();
json["umCritique"]["end"][numb]["ligne"] = um_crit_end.ramesInfo[c].ligne;
json["umCritique"]["end"][numb]["rang"] = um_crit_end.ramesInfo[c].rang;
json["umCritique"]["end"][numb]["signalementsProposes"] = nlohmann::json::array();
json["umCritique"]["end"][numb]["signalements"] = nlohmann::json::array();
for(auto& sig : STFMockInstance::rames[us.id]->getSignalements())
{
json["umCritique"]["end"][numb]["signalementsProposes"].push_back(sig.to_json(false));
json["umCritique"]["end"][numb]["signalements"].push_back(sig.to_json(false));
}
++c;
}
c = 0;
for(auto& us : um_saine_init.ramesInfo)
{
std::string numb = "us"+std::to_string(c+1);
json["umSaine"]["initial"][numb]["numImmatEf"] = STFMockInstance::rames[us.id]->getNumeroEF();
json["umSaine"]["initial"][numb]["ligne"] = um_saine_init.ramesInfo[c].ligne;
json["umSaine"]["initial"][numb]["rang"] = um_saine_init.ramesInfo[c].rang;
json["umSaine"]["initial"][numb]["signalementsProposes"] = nlohmann::json::array();
json["umSaine"]["initial"][numb]["signalements"] = nlohmann::json::array();
for(auto& sig : STFMockInstance::rames[us.id]->getSignalements())
{
json["umSaine"]["initial"][numb]["signalementsProposes"].push_back(sig.to_json(false));
json["umSaine"]["initial"][numb]["signalements"].push_back(sig.to_json(false));
}
++c;
}
c = 0;
for(auto& us : um_saine_end.ramesInfo)
{
std::string numb = "us"+std::to_string(c+1);
json["umSaine"]["end"][numb]["numImmatEf"] = STFMockInstance::rames[us.id]->getNumeroEF();
json["umSaine"]["end"][numb]["ligne"] = um_saine_end.ramesInfo[c].ligne;
json["umSaine"]["end"][numb]["rang"] = um_saine_end.ramesInfo[c].rang;
json["umSaine"]["end"][numb]["signalementsProposes"] = nlohmann::json::array();
json["umSaine"]["end"][numb]["signalements"] = nlohmann::json::array();
for(auto& sig : STFMockInstance::rames[us.id]->getSignalements())
{
json["umSaine"]["end"][numb]["signalementsProposes"].push_back(sig.to_json(false));
json["umSaine"]["end"][numb]["signalements"].push_back(sig.to_json(false));
}
++c;
}
json["recompoInfo"] = nlohmann::json::array();
for(RecompoInfo r : recompo_done){
nlohmann::json json_info = nlohmann::json::object();
json_info["rameCritEf"] = STFMockInstance::rames[r.rame_critique]->getNumeroEF();
json_info["rameSaineEf"] = STFMockInstance::rames[r.rame_saine]->getNumeroEF();
json_info["reason"] = r.reason;
json_info["signalementDeclencheur"] = r.sigDeclencheur->to_json(false);
json["recompoInfo"].push_back(json_info);
}
return json;
}
short RecompoUM::find_idx_in_crit(unsigned int rame){
auto it = std::find(um_crit_end.ramesInfo.begin(), um_crit_end.ramesInfo.end(), rame);
if (it != um_crit_end.ramesInfo.end()) {
return static_cast<short>(std::distance(um_crit_end.ramesInfo.begin(), it));
} else {
return -1;
}
}
short RecompoUM::find_idx_in_saine(unsigned int rame){
auto it = std::find(um_saine_end.ramesInfo.begin(), um_saine_end.ramesInfo.end(), rame);
if (it != um_saine_end.ramesInfo.end()) {
return static_cast<short>(std::distance(um_saine_end.ramesInfo.begin(), it));
} else {
return -1;
}
}
unsigned int RecompoUM::getSortieRame(unsigned short rame){
if (recompo_done[0].rame_critique == rame || recompo_done[0].rame_saine == rame) {
auto fc = std::find(um_crit_end.ramesInfo.begin(), um_crit_end.ramesInfo.end(), rame);
auto fs = std::find(um_saine_end.ramesInfo.begin(), um_saine_end.ramesInfo.end(), rame);
if(fc != um_crit_end.ramesInfo.end())
{
short rame_idx = find_idx_in_crit(rame);
if(rame_idx == -1){
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "[RecompoUM::getSortieRame] - rame " + std::to_string(rame) + " n'est pas dans l'UM critique");
return 0;
}
return STFMockInstance::stops[stopRame_UMCrit[rame_idx].sortie]->getDispo().getFinC().getRelativeDate();//dispoStop ?? plutôt que de repasser par les EmplacementRame ?
}
if(fs != um_saine_end.ramesInfo.end())
{
short rame_idx = find_idx_in_saine(rame);
if(rame_idx == -1){
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "[RecompoUM::getSortieRame] - rame " + std::to_string(rame) + " n'est pas dans l'UM saine");
return 0;
}
return STFMockInstance::stops[stopRame_UMSane[rame_idx].sortie]->getDispo().getFinC().getRelativeDate();
}
}
return 0;
}
std::pair<bool, TrajectoryStop> RecompoUM::findTMRame(unsigned short rames, std::vector<unsigned int> &traj,std::vector<TrajectoryStop>& trajStops, unsigned int date){
unsigned int traj_select = 0;
bool founded = false;
for(unsigned int tr : traj){
if(std::find_if(STFInstance::getCurrentInstance()->getSitesMaintenance().begin(),
STFInstance::getCurrentInstance()->getSitesMaintenance().end(),
[&](MaintenanceSite &csite) {
return csite.getRef() == trajStops[tr].lieuArret->getRef();
}) != STFInstance::getCurrentInstance()->getSitesMaintenance().end()){
if(STFMockInstance::stops[trajStops[tr].entree]->getDispo().getDebut().getRelativeDate() > date){
if(founded){
if(STFMockInstance::stops[trajStops[tr].entree]->getDispo().getDebut().getRelativeDate()<STFMockInstance::stops[trajStops[traj_select].entree]->getDispo().getDebut().getRelativeDate()){
traj_select = tr;
}
}else{
traj_select = tr;
founded = true;
}
}
}
}
if (founded) {
return std::make_pair(true, trajStops[traj_select]);
}else{
return std::make_pair(false, TrajectoryStop());
}
}
void RecompoUM::initTMArrival(std::vector<TrajectoryStop>& trajStops,std::vector<std::vector<unsigned int>> &trajectories){
UM_crit_TM_arrival.resize(um_crit_init.ramesInfo.size());
for(unsigned int i=0; i< um_crit_init.ramesInfo.size(); i++){
UM_crit_TM_arrival[i] = RecompoUM::findTMRame(um_crit_init.ramesInfo[i].id, trajectories[um_crit_init.ramesInfo[i].id],trajStops, STFMockInstance::stops[stopRame_UMCrit[0].sortie]->getDispo().getFin().getRelativeDate());
}
UM_saine_TM_arrival.resize(um_saine_init.ramesInfo.size());
for(unsigned int i=0; i< um_saine_init.ramesInfo.size(); i++){
UM_saine_TM_arrival[i] = RecompoUM::findTMRame(um_saine_init.ramesInfo[i].id, trajectories[um_saine_init.ramesInfo[i].id],trajStops, STFMockInstance::stops[stopRame_UMSane[0].sortie]->getDispo().getFin().getRelativeDate());
}
for(unsigned int i=0; i< um_crit_end.ramesInfo.size(); i++){
if(um_crit_end.ramesInfo[i] == recompo_done[0].rame_saine){
if(UM_crit_TM_arrival[i].first){
UM_crit_TM_arrival[i].second.typeDispo.first = typeStop::RLT_POST_RECOMPO_SUBIT;
UM_crit_TM_arrival[i].second.typeDispo.second = "";
}
}else{
if(UM_crit_TM_arrival[i].first){
UM_crit_TM_arrival[i].second.typeDispo.first = typeStop::RLT;
UM_crit_TM_arrival[i].second.typeDispo.second = "";
}
}
}
for(unsigned int i=0; i< um_saine_end.ramesInfo.size(); i++){
if(um_saine_end.ramesInfo[i] == recompo_done[0].rame_critique){
if(UM_saine_TM_arrival[i].first){
UM_saine_TM_arrival[i].second.typeDispo.first = typeStop::RLT_POST_RECOMPO_VOULU;
UM_saine_TM_arrival[i].second.typeDispo.second = "";
}
}else{
if(UM_saine_TM_arrival[i].first){
UM_saine_TM_arrival[i].second.typeDispo.first = typeStop::RLT;
UM_saine_TM_arrival[i].second.typeDispo.second = "";
}
}
}
}
bool RecompoUM::is_creating_perfect_UM(){
bool is_other_us_critical = true;
unsigned short nb_us_to_perfect_um = 0;
unsigned short idx_us = 0;
unsigned short idx_us_saine = 0;
for(auto& us : um_saine_init.ramesInfo){
if(RecompoUM::getUSHierarchi(us.id) < 3 && UM_saine_TM_arrival[idx_us].first){
nb_us_to_perfect_um++;
}else if (us.id != recompo_done[0].rame_saine){
is_other_us_critical = false;
}
if(us.id == recompo_done[0].rame_saine){
idx_us_saine = idx_us;
}
idx_us++;
}
if(nb_us_to_perfect_um == um_saine_init.ramesInfo.size() || !is_other_us_critical || !UM_saine_TM_arrival[idx_us_saine].first) return false;
nb_us_to_perfect_um = 0;
idx_us = 0;
for(auto& us : um_crit_init.ramesInfo){
if(RecompoUM::getUSHierarchi(us.id) < 3 && UM_crit_TM_arrival[idx_us].first){
nb_us_to_perfect_um++;
}
idx_us++;
}
creatperfect_um = is_other_us_critical && !(nb_us_to_perfect_um == um_crit_init.ramesInfo.size());
if(creatperfect_um){
unsigned short idx_rame_saine = 0;
for(unsigned short i=0; i<UM_saine_TM_arrival.size(); i++){
if(recompo_done[0].rame_saine == um_saine_init.ramesInfo[i].id){
idx_rame_saine = i;
break;
}
}
UM_saine_TM_arrival[idx_rame_saine].second.typeDispo.first = modellib::typeStop::RLT_POST_RECOMPO_UM_PARFAIT;
}
return creatperfect_um;
}
unsigned long long RecompoUM::getUSCriticity(unsigned int rame){
unsigned long long crit = 0;
for(unsigned int op_idx : STFMockInstance::operationsOfRames[rame]){
if(STFMockInstance::jobs[op_idx]->getPoidsRetard() > crit){
crit = STFMockInstance::jobs[op_idx]->getPoidsRetard();
}
}
return crit;
}
unsigned short RecompoUM::getUSHierarchi(unsigned short rame){
unsigned short H = 1000;
for(unsigned int op_idx : STFMockInstance::operationsOfRames[rame]){
if(STFMockInstance::jobs[op_idx]->getHierarchie() < H){
H = STFMockInstance::jobs[op_idx]->getHierarchie();
}
}
return H;
}
unsigned long long RecompoUM::getminUSCriticity_in_UM(TrajectoryStop& stop, std::unordered_map<unsigned short, Decision> &set){
unsigned long long mincrit = LONG_LONG_MAX;
unsigned int long long crit_value;
for(auto rame : stop.um_entree.ramesInfo){
bool can_be_recomposed = true;
for(auto op : STFMockInstance::operationsOfRames[rame.id] ){
if(set.find(op) != set.end()){
can_be_recomposed = false;
}
}
if(can_be_recomposed){
crit_value = getUSCriticity(rame.id);
if(mincrit > crit_value){
mincrit = crit_value;
}
}
}
return mincrit;
}
}
+216
View File
@@ -0,0 +1,216 @@
#ifndef RECOMPOUM_HPP
#define RECOMPOUM_HPP
#include "Date.h"
#include "TrajectoryStop.hpp"
#include "Decision.hpp"
#include "OperationRequise.h"
#include <boost/range/detail/common.hpp>
#include <memory>
#include <utility>
#include <vector>
namespace modellib {
/**
* @brief Struct indicating informative data about a recomposition
*/
typedef struct _recompInfo{
unsigned int rame_critique;
unsigned int rame_saine;
OperationRequise* sigDeclencheur{};
std::string reason;
}RecompoInfo;
/**
* @class RecompoUM
* @brief Defines the class that describes a recomposition
*/
class RecompoUM {
private:
public:
bool creatperfect_um = false;
/**
* @brief Permet de savoir si la recomposition est double donc jumellé avec une autre recomposition
*/
std::pair<bool, std::shared_ptr<RecompoUM>> is_double_recompo = {false, nullptr};
/**
* @brief The multiple unit trains that is the most critical at the begining
*/
UM um_crit_init;
/**
* @brief The multiple unit trains that is the least critical at the begining
*/
UM um_saine_init;
/**
* @brief The multiple unit trains that is the most critical at the end
*/
UM um_crit_end;
/**
* @brief The multiple unit trains that is the least critical at the end
*/
UM um_saine_end;
/**
* @brief All the recomposition information.
*/
std::vector<RecompoInfo> recompo_done;
/**
* @brief Stop information about the multiple unit critical
*/
std::vector<TrajectoryStop> stopRame_UMCrit;
/**
* @brief Stop information about the multiple unit healthy
*/
std::vector<TrajectoryStop> stopRame_UMSane;
/**
* @brief Information about the next TM stop of each rame in the critical UM
*/
std::vector<std::pair<bool, TrajectoryStop>> UM_crit_TM_arrival;
/**
* @brief Information about the next TM stop of each rame in the healty UM
*/
std::vector<std::pair<bool, TrajectoryStop>> UM_saine_TM_arrival;
/**
* @brief The site on which the swap is performed
*/
Site* site{};
unsigned int cost = 0;
/**
* @brief Default constructor
*/
RecompoUM() = default;
/**
* @brief Function to get the overlapping period of availability of the two multiple units
* @return The overlapping time slot
*/
[[nodiscard]] inline CreneauHoraire getPotentialRecompoSlot() const {
SolverDate beg_crit(stopRame_UMCrit[0].getDispoStop().getDebutC());
SolverDate beg_saine(stopRame_UMSane[0].getDispoStop().getDebutC());
SolverDate end_crit(stopRame_UMCrit[0].getDispoStop().getFinC());
SolverDate end_saine(stopRame_UMSane[0].getDispoStop().getFinC());
for(auto& stop : stopRame_UMCrit){
if(beg_crit < stop.getDispoStop().getDebutC()){
beg_crit = stop.getDispoStop().getDebutC();
}
if(stop.getDispoStop().getFinC() < end_crit){
end_crit = stop.getDispoStop().getFinC();
}
}
for(auto& stop : stopRame_UMSane){
if(beg_saine < stop.getDispoStop().getDebutC()){
beg_saine = stop.getDispoStop().getDebutC();
}
if(stop.getDispoStop().getFinC() < end_saine){
end_saine = stop.getDispoStop().getFinC();
}
}
SolverDate beg, end;
if (beg_crit <= beg_saine) {
beg = beg_saine;
} else
beg = beg_crit;
if (end_crit <= end_saine) {
end = end_crit;
} else
end = end_saine;
return {beg, end};
}
static std::pair<bool, TrajectoryStop> findTMRame(unsigned short rames, std::vector<unsigned int> &traj,std::vector<TrajectoryStop>& trajStops, unsigned int date);
bool operator==(const RecompoUM& other) const{
if(recompo_done[0].rame_critique == other.recompo_done[0].rame_critique && recompo_done[0].rame_saine == other.recompo_done[0].rame_saine){
if(stopRame_UMCrit.size() == other.stopRame_UMCrit.size() && stopRame_UMSane.size() == other.stopRame_UMSane.size()){
if(stopRame_UMCrit == other.stopRame_UMCrit && stopRame_UMSane == other.stopRame_UMSane){
return true;
}
}
}
return false;
}
/**
* @brief Function to get the arrival of rame on the site
* @param rame the rame to get the arrival of
* @return the date of arrival or 0 if the rame is not concerned by the swap
*/
unsigned int getEntreeRame(unsigned short rame);
/**
* @brief Function to get the departure of rame of the site
* @param rame the rame to get the departure of
* @return the date of departure or 0 if the rame is not concerned by the swap
*/
unsigned int getSortieRame(unsigned short rame);
/**
* @brief Function to check if rame is one of the swapped trains
* @param rame the train to check the presence of by pointer
* @return true if rame is in one of the two multiple units
*/
inline bool find(unsigned short rame) const {
return um_crit_end.find(rame) || um_saine_end.find(rame);
}
/**
* @brief find the idx of the rame when it leaved the critical UM
* @return -1 if the rame is not in the UM
*/
short find_idx_in_crit(unsigned int rame);
/**
* @brief find the idx of the rame when it leaved the healthy UM
* @return -1 if the rame is not in the UM
*/
short find_idx_in_saine(unsigned int rame);
UM& getUMCritInit(){return um_crit_init;}
UM& getUMSaineInit(){return um_saine_init;}
UM& getUMCritEnd(){return um_crit_end;}
UM& getUMSaineEnd(){return um_saine_end;}
std::vector<RecompoInfo>& getRecompo_info(){return recompo_done;}
/**
* @brief Initialize the next arrival in TM for each UM
*/
void initTMArrival(std::vector<TrajectoryStop>& trajStops,std::vector<std::vector<unsigned int>> &trajectories);
bool is_creating_perfect_UM();
static unsigned short getUSHierarchi(unsigned short rame);
/**
* @brief Getter of the criticity of the US
*/
static unsigned long long getUSCriticity(unsigned int rame);
/**
* @brief Getter of the lowest criticity of an US ot the UM (can't sort if ce US in the UM allready have a plannified opération )
*/
static unsigned long long getminUSCriticity_in_UM(TrajectoryStop& stop, std::unordered_map<unsigned short, Decision> &set);
/**
* @brief Function to export the swap object to json format
* @return the json description of the object
*/
nlohmann::json to_json();
static RecompoUM from_json(nlohmann::json& json);
};
}
#endif
+794
View File
@@ -0,0 +1,794 @@
#include "STFInstance.h"
#include <algorithm>
#include <cstddef>
#include <memory>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <vector>
#include "CreneauHoraire.h"
#include "CroisementUM.hpp"
#include "Decision.hpp"
#include "EmplacementRame.h"
#include "GareSite.h"
#include "Rame.h"
#include "STFMockInstance.hpp"
#include "STFInstanceUtils.hpp"
#include "TrajectoryStop.hpp"
#include "UM.h"
namespace modellib {
STFInstance *STFInstance::currentInstance = nullptr;
STFInstance::STFInstance() : m_isValid(true), mockInstance(nullptr) {
currentInstance = this;
}
STFInstance::STFInstance(bool status) : m_isValid(status), mockInstance(nullptr) {
currentInstance = this;
}
nlohmann::json STFInstance::to_json() {
nlohmann::json stf = nlohmann::json::object();
stf["dateDebutPlanification"] = m_dateDebutPlanification.to_json();
stf["stfCode"] = m_idStf;
stf["rames"] = nlohmann::json::array();
for (auto & m_rame : m_rames) {
stf["rames"].push_back(m_rame.to_json());
}
stf["sitesGare"] = nlohmann::json::array();
for (auto & i : m_sitesGare) {
stf["sitesGare"].push_back(i.to_json(true));
}
stf["siteMaintenance"] = nlohmann::json::array();
for (auto & i : m_sitesMaintenance) {
stf["siteMaintenance"].push_back(i.to_json());
}
stf["planifications"] = nlohmann::json::array();
for (unsigned int i = 0; i < m_planningSolution.size(); ++i) {
stf["planifications"].push_back(m_planningSolution[i].to_json());
stf["planifications"][i]["stfCode"] = m_idStf;
stf["planifications"][i]["infos"] = m_infos.to_json();
}
return stf;
}
STFInstance STFInstance::from_json(nlohmann::json &json) {
configlib::Configuration::overrideConfig(json);
STFInstance instance(true);
try {
instance.m_dateDebutPlanification = SolverDate::from_json(json["dateDebutPlanification"]);
SolverDate::setDateDebut(instance.m_dateDebutPlanification);
if (json["sitesMaintenance"].empty() && json["siteMaintenance"].empty()) {
throw std::runtime_error("Aucun site de maintenance");
}
for (nlohmann::json &site: json["siteMaintenance"]) {
instance.m_sitesMaintenance.push_back(MaintenanceSite::from_json(site));
}
for (nlohmann::json &site: json["sitesMaintenance"]) {
instance.m_sitesMaintenance.push_back(MaintenanceSite::from_json(site));
}
for (nlohmann::json &site: json["sitesGare"]) {
instance.m_sitesGare.push_back(GareSite::from_json(site));
}
if (json["rames"].empty()) {
throw std::runtime_error("Aucune rame decrite. Aucun signalement");
}
for (nlohmann::json &rame: json["rames"]) {
instance.m_rames.push_back(Rame::from_json(rame, instance.m_sitesMaintenance, instance.m_sitesGare));
}
instance.m_idStf = json["stfCode"];
if(json.contains("lastCroisements") && !json["lastCroisements"].empty())
{
instance.previousInformations.lastCroisementsJS = json["lastCroisements"];
}
}
catch (std::exception &e) {
instance.m_isValid = false;
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, e.what());
}
if (instance.m_isValid) {
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Instance chargee et traduite en objets");
}
return instance;
}
void STFInstance::init() {
currentInstance = this;
STFInstanceUtils::pretreatmentOnInstance(*this);
create_null_rame();
/*** Test s'il y a des RDVMs sur le même creneau ***/
std::vector<unsigned int> trajRDV_added;
for(auto& rame : m_rames){
unsigned int rlt_idx = 0;
for(auto& rlt : rame.getCreuxRoulement()){
if(std::find(trajRDV_added.begin(), trajRDV_added.end(), rlt_idx) == trajRDV_added.end()){
if(rlt.getTypeDispo().first == typeStop::RDVM){
unsigned int rlt2_idx = 0;
for(auto& rlt2 : rame.getCreuxRoulement()){
if(rlt2_idx != rlt_idx
&& rlt2.getTypeDispo().first == typeStop::RDVM
&& CreneauHoraire::checkCommonDuration(rlt2.getDispo(), rlt.getDispo(), 1)){
loggerlib::Logger::systemNotify(loggerlib::LOGGER_WARRNING, "[double RDVM] - la rame: " + rame.getNumeroEF() + " à 2 RDVM qui ce chevauche: " + std::to_string(rlt.getPreventiveMaintenanceRdv().value().getRdvId()) + " - " + std::to_string(rlt2.getPreventiveMaintenanceRdv().value().getRdvId()));
trajRDV_added.push_back(rlt2_idx);
}
rlt2_idx++;
}
}
}
rlt_idx++;
}
}
initStaticInfos();
instanciateMock();
//previousInformations.init();
//STFInstanceUtils::applyUserDecisions(*this);
STFInstanceUtils::logResult(*this, true);
}
void STFInstance::clean() {
/*if(mockInstance)
delete mockInstance;*/
/*for(auto& pl: m_planningSolution)
pl.clean();*/
//Voie::clearIds();
SolverDate::resetDateDebut();
STFMockInstance::clean();
currentInstance = nullptr;
}
void STFInstance::create_null_rame(){
auto UM_str = [](const std::vector<RameInformation>& vect_rame) -> std::string {
std::string to_send;
for(auto& r : vect_rame){
to_send += ("[" + r.Ef + "]");
}
return to_send;
};
std::vector<EmplacementRame> emp_already_create;
std::vector<Rame> rame_to_add;
unsigned int number_of_null_rame_created = 0;
for(auto& r: m_rames){
if(r.getNumeroEF() != "null"){
for(auto& creux : r.getCreuxRoulement()){
unsigned int nb_null_rame = 0;
for(RameInformation& rinfo : creux.getUM()){
if( rinfo.Ef == "null"){
nb_null_rame++;
}
}
if(nb_null_rame > 0){
if(std::find_if(emp_already_create.begin(), emp_already_create.end(), [&](EmplacementRame creux2){
return creux2.getLieuxArret().getRef() == creux.getLieuxArret().getRef() && creux2.getDispo().getDebut().getRelativeDate() == creux.getDispo().getDebut().getRelativeDate();
}) == emp_already_create.end()){
Rame rame;
rame.setNumeroEF("null" + std::to_string(number_of_null_rame_created));
rame.setSerie(r.getSerie());
rame.setLCN(r.getLcn());
std::vector<RameInformation> UM_to_add;
UM_to_add.push_back(RameInformation(r.getNumeroEF(), creux.getLigne(), creux.getRang()));
if(creux.getUM().size() == 2){
std::vector<unsigned short> rangs = {1,2,3};
rangs.erase(std::remove(rangs.begin(),rangs.end(),creux.getRang()),rangs.end());
if(nb_null_rame == 1){
for(auto r_of_um : creux.getUM()){
if(r_of_um.Ef != "null"){
UM_to_add.push_back(r_of_um);
rangs.erase(std::remove(rangs.begin(),rangs.end(),r_of_um.rang),rangs.end());
}
}
EmplacementRame empl = creux;
empl.setRang(rangs[0]);
empl.setUM(UM_to_add);
rame.getCreuxRoulement().push_back(empl);
m_rames.push_back(rame);
loggerlib::Logger::systemNotify(loggerlib::LOGGER_WARRNING, "Création d'une rame " + rame.getNumeroEF() +" avec pour UM:" + UM_str(empl.getUM()));
auto rame_of_um = std::find_if(m_rames.begin(), m_rames.end(),[&](Rame& ramesearch){return ramesearch.getNumeroEF() == UM_to_add[1].Ef;});
auto creux_of_rame = std::find_if(rame_of_um->getCreuxRoulement().begin(), rame_of_um->getCreuxRoulement().end(), [&](EmplacementRame& empr){
return empr.getLieuxArret().getRef() == creux.getLieuxArret().getRef() && empr.getDispo().getDebut().getRelativeDate() == creux.getDispo().getDebut().getRelativeDate();
});
if(creux_of_rame == rame_of_um->getCreuxRoulement().end()){
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "[create_nul_rame] - Le creux de la deuxième rame de l'um n'est pas trouvé");
}else{
emp_already_create.push_back(*creux_of_rame);
for(auto& other_rame : creux_of_rame->getUMRef()){
if(other_rame.Ef == "null"){
other_rame.Ef = "null" + std::to_string(number_of_null_rame_created);
break;
}
}
}
for(auto& other_rame : creux.getUMRef()){
if(other_rame.Ef == "null"){
other_rame.Ef = "null" + std::to_string(number_of_null_rame_created);
}
}
number_of_null_rame_created++;
}else if (nb_null_rame == 2){
UM_to_add.push_back(RameInformation("null" + std::to_string(number_of_null_rame_created+1),creux.getLigne(),rangs[0]));
EmplacementRame empl = creux;
empl.setRang(rangs[1]);
empl.setUM(UM_to_add);
rame.getCreuxRoulement().push_back(empl);
m_rames.push_back(rame);
number_of_null_rame_created++;
Rame rame2;
rame2.setNumeroEF("null" + std::to_string(number_of_null_rame_created));
rame2.setSerie(r.getSerie());
rame2.setLCN(r.getLcn());
std::vector<RameInformation> UM_to_add2;
UM_to_add2.push_back(RameInformation(r.getNumeroEF(), creux.getLigne(), creux.getRang()));
UM_to_add2.push_back(RameInformation("null" + std::to_string(number_of_null_rame_created-1),creux.getLigne(),rangs[1]));
EmplacementRame empl2 = creux;
empl2.setRang(rangs[0]);
empl2.setUM(UM_to_add2);
rame2.getCreuxRoulement().push_back(empl2);
m_rames.push_back(rame2);
for(auto& other_rame : creux.getUMRef()){
if(other_rame.rang == rangs[0]) other_rame.Ef = "null" + std::to_string(number_of_null_rame_created);
else other_rame.Ef = "null" + std::to_string(number_of_null_rame_created-1);
}
number_of_null_rame_created++;
loggerlib::Logger::systemNotify(loggerlib::LOGGER_WARRNING, "Création d'une rame " + rame.getNumeroEF() +" avec pour UM:" + UM_str(empl.getUM()));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_WARRNING, "Création d'une rame " + rame2.getNumeroEF() +" avec pour UM:" + UM_str(empl2.getUM()));
}
}else{
EmplacementRame empl = creux;
empl.setRang(3-creux.getRang());
empl.setUM(UM_to_add);
rame.getCreuxRoulement().push_back(empl);
m_rames.push_back(rame);
loggerlib::Logger::systemNotify(loggerlib::LOGGER_WARRNING, "Création d'une rame " + rame.getNumeroEF() +" avec pour UM:" + UM_str(empl.getUM()));
creux.getUMRef()[0].Ef = "null" + std::to_string(number_of_null_rame_created);
number_of_null_rame_created++;
}
// for(auto r_of_um : creux.getUM()){
// if(r_of_um.Ef == "null" && nb_null_rame > 0)
// }
// m_rames.push_back(rame);
// unsigned int idx_of_um = 0;
// for(auto r_of_um : creux.getUM()){
// if(r_of_um.Ef == "null"){
// std::vector<RameInformation> UM_to_add;
// UM_to_add.push_back(RameInformation(r.getNumeroEF(), creux.getLigne(), creux.getRang()));
// if(creux.getUM().size() == 2){
// UM_to_add.push_back(RameInformation(creux.getUM()[1-idx_of_um]));
// }
// EmplacementRame empl_rame = creux;
// empl_rame.setUM(UM_to_add);
// m_rames[m_rames.size()].getCreuxRoulement().push_back(empl_rame);
// loggerlib::Logger::systemNotify(loggerlib::LOGGER_WARRNING, "Création d'une trajectoir de rame null rame : " + m_rames[m_rames.size()].getNumeroEF() +
// "UM = " + UM_str(m_rames[m_rames.size()].getNumeroEF(), empl_rame.getUM()));
// }else{
// auto rame_of_um = std::find_if(m_rames.begin(), m_rames.end(),[&](Rame& ramesearch){return ramesearch.getNumeroEF() == r_of_um.Ef;});
// auto creux_of_rame = std::find_if(rame_of_um->getCreuxRoulement().begin(), rame_of_um->getCreuxRoulement().end(), [&](EmplacementRame& empr){
// return empr.getLieuxArret().getRef() == creux.getLieuxArret().getRef() && empr.getDispo().getDebut().getRelativeDate() == creux.getDispo().getDebut().getRelativeDate();
// });
// if(creux_of_rame == rame_of_um->getCreuxRoulement().end()){
// loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "[create_nul_rame] - Le creux de la deuxième rame de l'um n'est pas trouvé");
// }else{
// emp_already_create.push_back(*creux_of_rame);
// }
// }
// idx_of_um++;
// }
}
}
}
}
}
}
void STFInstance::instanciateMock() {
mockInstance = std::make_shared<STFMockInstance>();
mockInstance->matches.resize(STFMockInstance::machines.size());
mockInstance->trajectories.resize(STFMockInstance::rames.size());
mockInstance->trajectoryStops.reserve(STFMockInstance::stops.size());
mockInstance->rameOftrajectories.resize(STFMockInstance::stops.size());
for(unsigned int rid = 0; rid < STFMockInstance::rames.size(); ++rid)
{
for (unsigned int empId = 0; empId < STFMockInstance::initialTrainStops[rid].size(); ++empId){
TrajectoryStop st;
st.entree = STFMockInstance::initialTrainStops[rid][empId];
st.sortie = STFMockInstance::initialTrainStops[rid][empId];
st.setDispoStop(STFMockInstance::stops[st.entree]->getDispo().getDebutC(),STFMockInstance::stops[st.sortie]->getDispo().getFinC());
if(STFMockInstance::stops[st.entree]->getTypeDispo().first == typeStop::RDVM)
{
unsigned int index = 0;
for(auto& rdvSt : STFMockInstance::preventiveMaintenanceRdvms)
{
if(rdvSt->getRdvId() == STFMockInstance::stops[st.entree]->getPreventiveMaintenanceRdv().value().getRdvId())
{
break;
}
++index;
}
st.rdvPreventif = index;
}
st.typeDispo = STFMockInstance::stops[st.entree]->getTypeDispo();
st.lieuArret = &STFMockInstance::stops[st.entree]->getLieuxArret();
UM um;
RameUMInformation info;
info.id = rid;
info.ligne = STFMockInstance::stops[STFMockInstance::initialTrainStops[rid][empId]]->getLigne();
info.rang = STFMockInstance::stops[STFMockInstance::initialTrainStops[rid][empId]]->getRang();
um.ramesInfo.push_back(info);
for(auto& ef : STFMockInstance::stops[STFMockInstance::initialTrainStops[rid][empId]]->getUM())
{
auto f = std::find_if(STFMockInstance::rames.begin(), STFMockInstance::rames.end(), [&](auto& rame){return rame->getNumeroEF() == ef.Ef;});
if(f != STFMockInstance::rames.end())
{
RameUMInformation info1;
info1.id = std::distance(STFMockInstance::rames.begin(), f);
info1.ligne = ef.ligne;
info1.rang = ef.rang;
um.ramesInfo.push_back(info1);
}/*else if(ef.Ef == "null"){
RameUMInformation info1;
info1.id = NULL_RAME;
info1.ligne = ef.ligne;
info1.rang = ef.rang;
um.ramesInfo.push_back(info1);
}*/
}
st.um_entree = um;
st.um_sortie = um;//changer dans le cas où c'est un technicentre ?
mockInstance->trajectories[rid].emplace_back(mockInstance->trajectoryStops.size());
mockInstance->rameOftrajectories[mockInstance->trajectoryStops.size()] = rid;
mockInstance->trajectoryStops.emplace_back(st);
}
}
for(unsigned int oid = 0; oid < STFMockInstance::jobs.size(); ++oid)
{
mockInstance->jobOrder.emplace_back(oid);
mockInstance->jobDispoVoiesRames.emplace_back();
unsigned int rid = STFMockInstance::rameOfOperations[oid];
auto& dtReport = STFMockInstance::jobs[oid]->getPropositionExistante().afterDate;
for(unsigned int empId = 0; empId < STFMockInstance::initialTrainStops[rid].size(); ++empId)
{
if(STFMockInstance::stops[STFMockInstance::initialTrainStops[rid][empId]]->getDispo().getDebutC().getRelativeDate() < dtReport.getRelativeDate())
continue;
for(unsigned int mid = 0; mid < STFMockInstance::machines.size(); ++mid)
{
auto siteTrack = STFMockInstance::siteTrackOfMachine[mid];
if(STFMockInstance::stops[STFMockInstance::initialTrainStops[rid][empId]]->getLieuxArret().getRef() == STFMockInstance::sites[siteTrack.first]->getRef()
&& STFMockInstance::infraComp[oid][siteTrack.second]
&& (STFMockInstance::machines[mid]->getSpecificRame() == STFMockInstance::rames[rid]->getNumeroEF() || STFMockInstance::machines[mid]->getSpecificRame().empty()))
{
auto match = CreneauHoraire::checkSlotsCompatibility(STFMockInstance::machines[mid]->getDispo(), STFMockInstance::stops[STFMockInstance::initialTrainStops[rid][empId]]->getDispo());
if (match.first && match.second.second >= STFMockInstance::jobs[oid]->getDureeDiag()) {
DispVoieRame disp;
disp.op = oid;
disp.rame = rid;
disp.dispoVoie = mid;
disp.dispoRame = mockInstance->trajectories[rid][empId];
disp.site = siteTrack.first;
disp.voie = siteTrack.second;
disp.match = {match.second.first,
match.second.first + match.second.second};
mockInstance->jobDispoVoiesRames[oid].emplace_back(mockInstance->dispoVoiesRames.size());
mockInstance->matches[mid].push_back(mockInstance->dispoVoiesRames.size());
mockInstance->dispoVoiesRames.push_back(disp);
}
}
}
}
}
initStaticInfos_from_instance();
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Applying necessary swaps");
previousInformations.init();
std::vector<CroisementUM> swapToKeep;
for(auto& opR : mockInstance->jobOrder) {
if(STFMockInstance::jobs[opR]->getPropositionExistante().exists && STFMockInstance::jobs[opR]->getPropositionExistante().isKeep) {
auto findSwap = std::find_if(previousInformations.lastCroisements.begin(),previousInformations.lastCroisements.end(), [&](CroisementUM& cr){
return cr.find(STFMockInstance::rameOfOperations[opR]) && cr.getEntreeRame(STFMockInstance::rameOfOperations[opR]) < STFMockInstance::jobs[opR]->getPropositionExistante().creneau.getDebutC().getRelativeDate();
});
if(findSwap != previousInformations.lastCroisements.end())
{
swapToKeep.push_back(*findSwap);
}
}
}
std::sort(swapToKeep.begin(), swapToKeep.end(),[&](auto& cr1, auto& cr2){
return cr1.getPotentialSwapSlot().getDebut().getRelativeDate() < cr2.getPotentialSwapSlot().getDebut().getRelativeDate();
});
for(auto& cr : swapToKeep)
{
cr.initTrajectoireTm(STFInstance::getCurrentInstance()->mockInstance->trajectoryStops, STFInstance::getCurrentInstance()->mockInstance->trajectories);
//TODO à décider si un croisement accepté ou une décisions acceptée coûte 0 ? à voir sur les contraintes epsilon pour le moment 0, le risque c'est de proposer plus de croisement que possible.
//TODO si changement, adapter la mise en place de dedicatedHeuristic pour que le noeud root commence avec les coûts à jour sur les contraintes epsilon (0 pour le moment)
cr.cost = 1;
STFInstance::getCurrentInstance()->mockInstance->swap(cr);
STFInstance::getCurrentInstance()->mockInstance->swaps.push_back(std::make_shared<CroisementUM>(cr));
}
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Applying users accepted previous propositions");
for(unsigned int oid = 0; oid < STFMockInstance::jobs.size(); ++oid)
{
auto& prop = STFMockInstance::jobs[oid]->getPropositionExistante();
if(prop.exists && prop.isKeep)
{
auto findDisp = std::find_if(mockInstance->jobDispoVoiesRames[oid].begin(), mockInstance->jobDispoVoiesRames[oid].end(), [&](unsigned int d){
CreneauHoraire cren(SolverDate::getDateDebut() + mockInstance->dispoVoiesRames[d].match.first, SolverDate::getDateDebut() + mockInstance->dispoVoiesRames[d].match.second);
return STFMockInstance::sites[mockInstance->dispoVoiesRames[d].site]->getRef() == prop.site.getRef() && STFMockInstance::tracks[mockInstance->dispoVoiesRames[d].voie]->getId() == prop.voie.getId() && CreneauHoraire::checkSlotsCompatibility(prop.creneau, cren).first;
});
if(findDisp != mockInstance->jobDispoVoiesRames[oid].end())
{
auto& disp = mockInstance->dispoVoiesRames[*findDisp];
Decision dec;
dec.empR = disp.dispoRame;
dec.empV = disp.dispoVoie;
dec.voie = disp.voie;
dec.site = disp.site;
dec.excluded = false;
dec.lastCreneau = {prop.creneau.getDebutC().getRelativeDate(), prop.creneau.getFinC().getRelativeDate()};
dec.rejected = dec.lastCreneau.second-dec.lastCreneau.first == STFMockInstance::jobs[oid]->getDureeDiag();
dec.timeslotGraphSplited = mockInstance->trajectoryStops[disp.dispoRame].getDispoStop();
previousInformations.initialDecisions[oid] = dec;
}
}
}
}
STFInstance STFInstance::createSTF(std::string &description) {
try {
nlohmann::json json = nlohmann::json::parse(description);
return STFInstance::from_json(json);
}
catch (std::exception &e) {
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, e.what());
}
return STFInstance(false);
}
STFInstance STFInstance::createSTF(std::ifstream &description) {
try {
nlohmann::json json = nlohmann::json::parse(description);
return STFInstance::from_json(json);
}
catch (std::exception &e) {
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, e.what());
}
return STFInstance(false);
}
void STFInstance::initStaticInfos() {
for (auto &r: getRames()) {
STFMockInstance::rames.push_back(&r);
STFMockInstance::operationsOfRames.emplace_back();
STFMockInstance::initialTrainStops.emplace_back();
for (auto &o: r.getSignalements()) {
STFMockInstance::infraComp.emplace_back();
STFMockInstance::jobs.push_back(&o);
STFMockInstance::rameOfOperations.push_back(STFMockInstance::rames.size()-1);
STFMockInstance::operationsOfRames.back().push_back(STFMockInstance::jobs.size()-1);
for (auto &s: getSitesMaintenance()) {
for (auto &v: s.getVoies()) {
//std::pair<unsigned int, unsigned int> opTrack = {STFMockInstance::jobs.size()-1, STFMockInstance::tracks.size()-1};
bool match = true;
for (auto &inf: o.getInfrastructures()) {
bool isThere = false;
for (auto &infV: v.getInfrastructures()) {
if (infV.getInfraType() == inf.getInfraType()) {
isThere = true;
}
}
if (!isThere) {
match = false;
break;
}
}
if (match) {
STFMockInstance::infraComp.back().push_back(true);
} else
STFMockInstance::infraComp.back().push_back(false);
}
}
}
for(auto& emp : r.getCreuxRoulement())
{
STFMockInstance::stops.push_back(&emp);
STFMockInstance::initialTrainStops.back().push_back(STFMockInstance::stops.size()-1);
}
for(auto& rdv : r.getRdvms())
{
STFMockInstance::preventiveMaintenanceRdvms.emplace_back(&rdv);
}
}
for(auto& s : getSitesMaintenance())
{
STFMockInstance::sites.push_back(&s);
for(auto& v : s.getVoies())
{
STFMockInstance::tracks.push_back(&v);
for(auto& emp : v.getDisponibilites())
{
STFMockInstance::machines.push_back(&emp);
STFMockInstance::siteTrackOfMachine.emplace_back(STFMockInstance::sites.size()-1, STFMockInstance::tracks.size()-1);
}
}
}
for(auto& s : getSites()){
STFMockInstance::siteGares.push_back(&s);
}
STFMockInstance::rdvComp.resize(STFMockInstance::preventiveMaintenanceRdvms.size());
unsigned int rdvId = 0;
for(auto& rdv : STFMockInstance::preventiveMaintenanceRdvms)
{
unsigned int rdv2Id = 0;
for(auto& rdv2 : STFMockInstance::preventiveMaintenanceRdvms)
{
if(rdvId != rdv2Id)
{
bool checkComp = PreventiveMaintenanceRdv::areEquivalent(*rdv, *rdv2);
if(checkComp)
{
STFMockInstance::rdvComp[rdvId].emplace_back(rdv2Id);
}
}
rdv2Id++;
}
rdvId++;
}
/*for (auto &st: STFMockInstance::operationsOfRames) {
staticInformations.multiIndicator += 1.0 / (double) st.second.size();
}
staticInformations.multiIndicator /= (double) staticInformations.operationsOfTrain.size();//staticInformations.multiIndicator;*/
//TODO Axel, peut-être rajouter l'initialisation dans le mock instance des sites hors TM. Attention à bien rajouter le clear pour les static dans la fonction de clean sinon en sortie de la résolution des instances tu vas avoir des surprises.
}
void STFInstance::initStaticInfos_from_instance(){
STFMockInstance::TrajectoryStopsofTrajectoryUM.resize(mockInstance->trajectoryStops.size());
std::vector<unsigned int> trajIdRDV_added;
for(unsigned int trId = 0; trId < mockInstance->trajectoryStops.size(); trId++){
if(mockInstance->trajectoryStops[trId].typeDispo.first == typeStop::RDVM){
STFMockInstance::TrajectoryStopsofTrajectoryUM[trId].push_back(trId);
trajIdRDV_added.push_back(trId);
continue;
}
for(unsigned int trId2 = 0; trId2 < mockInstance->trajectoryStops.size(); trId2++){
if(std::find(trajIdRDV_added.begin(), trajIdRDV_added.end(), trId2) == trajIdRDV_added.end()){
if(mockInstance->trajectoryStops[trId].lieuArret->getRef() == mockInstance->trajectoryStops[trId2].lieuArret->getRef() &&
mockInstance->trajectoryStops[trId].dispoStop.getDebutC().getRelativeDate() == mockInstance->trajectoryStops[trId2].dispoStop.getDebutC().getRelativeDate()){
if(mockInstance->trajectoryStops[trId].um_entree.ramesInfo.size() == mockInstance->trajectoryStops[trId2].um_entree.ramesInfo.size() &&
std::is_permutation(mockInstance->trajectoryStops[trId].um_entree.ramesInfo.begin(), mockInstance->trajectoryStops[trId].um_entree.ramesInfo.end(),
mockInstance->trajectoryStops[trId2].um_entree.ramesInfo.begin(), mockInstance->trajectoryStops[trId2].um_entree.ramesInfo.end())){
STFMockInstance::TrajectoryStopsofTrajectoryUM[trId].push_back(trId2);
if(mockInstance->trajectoryStops[trId2].typeDispo.first == typeStop::RDVM){
break;
}
}
}
}
}
}
/**** Checker ****/
unsigned int id = 0;
for(auto vect : STFMockInstance::TrajectoryStopsofTrajectoryUM){
if(vect.size() != mockInstance->trajectoryStops[id].um_entree.ramesInfo.size()){
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "[initStaticInfos_from_instance] - Erreur trajid:" + std::to_string(id)
+ ", rame=" + STFMockInstance::rames[mockInstance->rameOftrajectories[id]]->getNumeroEF() +
+ ", creneau=(" + std::to_string(mockInstance->trajectoryStops[id].getDispoStop().getDebutC().getRelativeDate()) + "-" + std::to_string(mockInstance->trajectoryStops[id].getDispoStop().getFinC().getRelativeDate())
+ "), taille souhaité=" + std::to_string(mockInstance->trajectoryStops[id].um_entree.ramesInfo.size())
+ ", taille obtenu=" + std::to_string(vect.size()));
}
++id;
}
/**** Init TrajectoryOfUM ****/
std::vector<unsigned int> trajId_added;
for(unsigned int traj_id = 0 ; traj_id<mockInstance->trajectoryStops.size(); traj_id++){
if(std::find(trajId_added.begin(), trajId_added.end(), traj_id) == trajId_added.end()){
std::vector<unsigned int> traj_of_um;
for(unsigned int traj_of_um_id=0; traj_of_um_id<STFMockInstance::TrajectoryStopsofTrajectoryUM[traj_id].size(); traj_of_um_id++){
if(std::find(trajId_added.begin(), trajId_added.end(), STFMockInstance::TrajectoryStopsofTrajectoryUM[traj_id][traj_of_um_id]) == trajId_added.end()){
traj_of_um.push_back(STFMockInstance::TrajectoryStopsofTrajectoryUM[traj_id][traj_of_um_id]);
if(traj_of_um_id > 0){
trajId_added.push_back(STFMockInstance::TrajectoryStopsofTrajectoryUM[traj_id][traj_of_um_id]);
}
}
}
STFMockInstance::TrajectoryStopfUM.push_back(traj_of_um);
}
}
/**** Checker ****/
unsigned int um_idx = 0;
for(auto um: STFMockInstance::TrajectoryStopfUM){
unsigned int traj_idx = 0;
for(unsigned int traj : um){
if(um.size() != STFMockInstance::TrajectoryStopsofTrajectoryUM[traj].size()){
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "[initStaticInfos_from_instance][TrajectoryOfUM] - Taille du vecteur TrajectoryStofUM[" + std::to_string(um_idx) +
"][" + std::to_string(traj_idx) +
"] =" + std::to_string(STFMockInstance::TrajectoryStopsofTrajectoryUM[traj].size()) +
" !=" + std::to_string(um.size()));
}else if(!std::is_permutation(um.begin(),um.end(),STFMockInstance::TrajectoryStopsofTrajectoryUM[traj].begin())){
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "[initStaticInfos_from_instance][TrajectoryOfUM] - Mauvaise permutation TrajectoryStofUM[" + std::to_string(um_idx) +
"][" + std::to_string(traj_idx) +
"]");
}
traj_idx++;
}
um_idx++;
}
STFMockInstance::UmOfTrajectoryStop.resize(mockInstance->trajectoryStops.size());
for(unsigned int traj_id = 0; traj_id < mockInstance->trajectoryStops.size(); traj_id++){
unsigned int um_idx = 0;
for(auto um : STFMockInstance::TrajectoryStopfUM){
if(std::find(um.begin(), um.end(), traj_id) != um.end()){
STFMockInstance::UmOfTrajectoryStop[traj_id] = um_idx;
}
um_idx++;
}
}
/**** Checker ****/
um_idx = 0;
for(auto um : STFMockInstance::TrajectoryStopfUM){
for(unsigned int traj: um){
if(um_idx != STFMockInstance::UmOfTrajectoryStop[traj]){
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "[initStaticInfos_from_instance][UmOfTrajectoryStop] - traj:" + std::to_string(traj) + ", um_idx:" + std::to_string(um_idx));
}
}
um_idx++;
}
STFMockInstance::crossedUM.resize(STFMockInstance::TrajectoryStopfUM.size());//*STFMockInstance::stops.size());
unsigned int nb_crossedUM = 0;
unsigned int trId = 0;
for(auto& um_traj : STFMockInstance::TrajectoryStopfUM)
{
auto& tr = mockInstance->trajectoryStops[um_traj[0]];
std::string serie = STFMockInstance::rames[tr.um_entree.ramesInfo[0].id]->getSerie();
unsigned int tr2Id = 0;
for(auto& um_tr2 : STFMockInstance::TrajectoryStopfUM)
{
auto& tr2 = mockInstance->trajectoryStops[um_tr2[0]];
if(tr2Id != trId)
{
std::string serieTr2 = STFMockInstance::rames[tr2.um_entree.ramesInfo[0].id]->getSerie();
auto& cr1 = tr.getDispoStop();
auto& cr2 = tr2.getDispoStop();
if(tr.um_entree.ramesInfo.size() == tr2.um_entree.ramesInfo.size()
&& !std::is_permutation(tr.um_entree.ramesInfo.begin(),tr.um_entree.ramesInfo.end(), tr2.um_entree.ramesInfo.begin())
&& (tr.lieuArret->getRef() == tr2.lieuArret->getRef() || (tr.lieuArret->getZone().first && tr2.lieuArret->getZone().first && tr.lieuArret->getZone().second == tr2.lieuArret->getZone().second))
&& serie == serieTr2
&& std::find_if(STFMockInstance::siteGares.begin(),STFMockInstance::siteGares.end(), [&](auto& s){return s->getRef() == tr.lieuArret->getRef() && s->getSwapEnabled();}) != STFMockInstance::siteGares.end()
&& CreneauHoraire::checkCommonDuration(cr1, cr2, configlib::Configuration::Solver.Croisement.COMMON_TIME))
{
STFMockInstance::crossedUM[trId].push_back(tr2Id);
nb_crossedUM++;
}
}
tr2Id++;
}
trId++;
}
if(nb_crossedUM%2 != 0){loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "Nombre de croisement impaire");}
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Nb_crossedUM = " + std::to_string(nb_crossedUM/2));
STFMockInstance::compTraj.resize(mockInstance->trajectoryStops.size());
unsigned int nb_compTraj = 0;
std::vector<unsigned int> nb_compTraj_compo(5,0);
trId = 0;
for(auto& tr : mockInstance->trajectoryStops)
{
if(std::find_if(STFMockInstance::siteGares.begin(),STFMockInstance::siteGares.end(), [&](auto& s){return s->getRef() == tr.lieuArret->getRef() && s->getCompEnabled();}) != STFMockInstance::siteGares.end()){
unsigned int tr2Id = 0;
for(auto& tr2 : mockInstance->trajectoryStops)
{
/*** Pas le même arrêt ce n'est pas 2 UM simple ***/
if(tr2Id != trId && !(tr2.um_entree.ramesInfo.size() == 1 && tr.um_entree.ramesInfo.size() == 1)){
/**** Attention est ce qu'on a vérifié tous les cas ****/
bool have_common_rame = std::any_of(tr.um_entree.ramesInfo.begin(), tr.um_entree.ramesInfo.end(), [&](RameUMInformation x) {
return std::find(tr2.um_entree.ramesInfo.begin(), tr2.um_entree.ramesInfo.end(), x) != tr2.um_entree.ramesInfo.end();
});
std::string serieTr1 = STFMockInstance::rames[tr.um_entree.ramesInfo[0].id]->getSerie();
std::string serieTr2 = STFMockInstance::rames[tr2.um_entree.ramesInfo[0].id]->getSerie();
auto& cr1 = tr.getDispoStop();
auto& cr2 = tr2.getDispoStop();
/**** Arrêt différent même au niveau de l'UM, même série de train et crénneau en commun suffisemment grand****/
if(!have_common_rame
&&(tr.lieuArret->getRef() == tr2.lieuArret->getRef())// || (tr.lieuArret->getZone().first && tr2.lieuArret->getZone().first && tr.lieuArret->getZone().second == tr2.lieuArret->getZone().second))
&& serieTr1 == serieTr2
&& CreneauHoraire::checkCommonDuration(cr1, cr2, configlib::Configuration::Solver.Recompo.COMMON_TIME))
{
STFMockInstance::compTraj[trId].emplace_back(tr2Id);
if(tr.um_entree.ramesInfo.size() == 3){
if(tr2.um_entree.ramesInfo.size() == 3){
nb_compTraj_compo[0]++;
}else if(tr2.um_entree.ramesInfo.size() == 2){
nb_compTraj_compo[1]++;
}else if(tr2.um_entree.ramesInfo.size() == 1){
nb_compTraj_compo[2]++;
}else{
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "Erreur - création de compUMs taille des UMs invalide :[" + std::to_string(tr.um_entree.ramesInfo.size()) + "-" + std::to_string(tr2.um_entree.ramesInfo.size()) + "]");
}
}else if(tr.um_entree.ramesInfo.size() == 2){
if(tr2.um_entree.ramesInfo.size() == 3){
nb_compTraj_compo[1]++;
}else if(tr2.um_entree.ramesInfo.size() == 2){
nb_compTraj_compo[3]++;
}else if(tr2.um_entree.ramesInfo.size() == 1){
nb_compTraj_compo[4]++;
}else{
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "Erreur - création de compUMs taille des UMs invalide :[" + std::to_string(tr.um_entree.ramesInfo.size()) + "-" + std::to_string(tr2.um_entree.ramesInfo.size()) + "]");
}
}else if(tr.um_entree.ramesInfo.size() == 1){
if(tr2.um_entree.ramesInfo.size() == 3){
nb_compTraj_compo[2]++;
}else if(tr2.um_entree.ramesInfo.size() == 2){
nb_compTraj_compo[4]++;
}else{
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "Erreur - création de compUMs taille des UMs invalide :[" + std::to_string(tr.um_entree.ramesInfo.size()) + "-" + std::to_string(tr2.um_entree.ramesInfo.size()) + "]");
}
}
nb_compTraj++;
}
}
tr2Id++;
}
}
trId++;
}
if(nb_compTraj%2 != 0)loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "Nombre de recomposition total impaire");
if(nb_compTraj_compo[0]%2 != 0)loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "Nombre de recomposition 3x3 impaire");
if(nb_compTraj_compo[1]%2 != 0)loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "Nombre de recomposition 3x2 impaire");
if(nb_compTraj_compo[2]%2 != 0)loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "Nombre de recomposition 3x1 impaire");
if(nb_compTraj_compo[3]%2 != 0)loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "Nombre de recomposition 2x2 impaire");
if(nb_compTraj_compo[4]%2 != 0)loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "Nombre de recomposition 2x1 impaire");
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Nb_compTraj = " + std::to_string(nb_compTraj/2));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "\t3x3 = " + std::to_string(nb_compTraj_compo[0]/2));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "\t3x2 = " + std::to_string(nb_compTraj_compo[1]/2));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "\t3x1 = " + std::to_string(nb_compTraj_compo[2]/2));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "\t2x2 = " + std::to_string(nb_compTraj_compo[3]/2));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "\t2x1 = " + std::to_string(nb_compTraj_compo[4]/2));
}
void prevInfo::init() {
if(!lastCroisementsJS.empty())
{
for(auto& cr : lastCroisementsJS)
{
lastCroisements.emplace_back(CroisementUM::from_json(cr));
if(lastCroisements.back().um_crit.ramesInfo.empty())
lastCroisements.erase(lastCroisements.end()-1);
}
lastCroisementsJS.clear();
}
}
}
+209
View File
@@ -0,0 +1,209 @@
#ifndef STFINSTANCE_H
#define STFINSTANCE_H
#include <iostream>
#include <unordered_map>
#include <utility>
#include <vector>
#include "Decision.hpp"
#include "Rame.h"
#include "MaintenanceSite.h"
#include "GareSite.h"
#include "HeurePointeCreneauxHoraire.h"
#include "Planification.h"
#include "STFInstanceInfoStats.hpp"
#include "PlanificationStats.hpp"
#include <fstream>
namespace modellib {
typedef struct prevInfo{
nlohmann::json lastCroisementsJS;
std::vector<CroisementUM> lastCroisements;
std::unordered_map<unsigned short, Decision> initialDecisions;
void init();
}PreviousInformations;
class STFMockInstance;
/*! @file STFInstance.h*/
/**
* @class STFInstance
* @brief Classe décrivant l'intégralité des informations nécessaire à la résolution du problème
*/
class STFInstance {
private:
/**
* @brief La date de début de planification. La date de fin est fixée à 7 jours plus tard (adaptée selon TIMEUNIT)
*/
SolverDate m_dateDebutPlanification;
/**
* @brief La liste des rames à ordonnancer
*/
std::vector<Rame> m_rames;
/**
* @brief La liste des sites de maintenance
*/
std::vector<MaintenanceSite> m_sitesMaintenance;
/**
* @brief La liste des sites de gare
*/
std::vector<Site> m_sitesGare;
/**
* @brief Le planning trouvé par le solveur. Vide au départ.
*/
std::vector<Planification> m_planningSolution;
/**
* @brief Booléen indiquant si l'instance est valide et peut être envoyée au solveur
*/
bool m_isValid;
std::string m_idStf;
STFInstanceInfoStats m_infos;
static STFInstance *currentInstance;
void instanciateMock();
public:
void init();
void clean();
PreviousInformations previousInformations;
std::shared_ptr<STFMockInstance> mockInstance;
/**
* @brief Constructeur par défaut
*/
STFInstance();
/**
* @brief Constructeur de confort
* @param status indique si l'instance est valide
*/
explicit STFInstance(bool status);
/**
* @brief Destructeur. Ne fait rien
*/
virtual ~STFInstance() = default;
/**
* @brief Fonction indiquant la validé de l'instance
* @return true si l'instance est valide, false sinon
*/
[[nodiscard]] bool isValid() const { return m_isValid; };
/**
* @brief Getter simple sur la date de début de planification
* @return la date de début de planification
*/
SolverDate &getDateDebutPlanification() { return m_dateDebutPlanification; };
void setDateDebutPlanification(SolverDate &date) { m_dateDebutPlanification = date; };
/**
* @brief Getter simple par référence sur la liste des rames
* @return la liste des rames
*/
inline std::vector<Rame> &getRames() { return m_rames; }
STFInstanceInfoStats &getInfos() { return m_infos; };
/**
* @brief Getter simple par référence sur la liste des sites de maintenance
* @return la liste des sites de maintenance
*/
inline std::vector<MaintenanceSite> &getSitesMaintenance() { return m_sitesMaintenance; }
/**
* @brief Getter spécifique sur le ième site de maintenance dans la liste
* @param i l'indice du site de maintenance
* @return le ième site de maintenance dans la liste
*/
MaintenanceSite &getSiteMaintenance(int i) { return m_sitesMaintenance[i]; }
/**
* @brief Getter simple par référence sur les sites de gare
* @return la liste des sites de gare
*/
std::vector<Site> &getSites() { return m_sitesGare; }
/**
* @brief Getter spécifique sur le ième site de gare dans la liste
* @param i l'indice du site de gare
* @return le ième site de gare dans la liste
*/
Site &getSite(int i) { return m_sitesGare[i]; }
/**
* @brief Getter simple sur la planification donnée par le solveur
* @return la planification
*/
std::vector<Planification> &getPlanningSolution() { return m_planningSolution; }
/**
* @brief Getter spécifique sur la ième planification dans la liste
* voir pour enlever ou définir si on propose plusieurs solutions
* @param i l'indice de la planification
* @return la ième planification
*/
Planification &getPlanningSolution(int i) { return m_planningSolution[i]; }
std::string getIdStf() { return m_idStf; };
void setIdStf(std::string& id) { m_idStf = std::move(id); };
/**
* @brief Fonction interface de traduction de l'objet STFInstance vers un objet JSON
* @return le json décrivant l'instance
*/
nlohmann::json to_json();
/**
* @brief Fonction interface de traduction de l'objet JSON vers un objet STFInstance
* @param json le JSON décrivant une instance
* @return l'instance de la classe STFInstance correspondant à l'objet JSON d'entrée
*/
static STFInstance from_json(nlohmann::json &json);
/**
* @brief fonction utilitaire simplifiant l'appel à from_json.
* Cette fonction s'occupe de convertir l'entrée au format json avant de faire appel à from_json
* @param description l'instance au format string
* @return l'instance de la classe STFInstance correspondant à l'objet JSON d'entrée
*/
static STFInstance createSTF(std::string &description);
/**
* @brief fonction utilitaire simplifiant l'appel à from_json.
* Cette fonction s'occupe de convertir l'entrée au format json avant de faire appel à from_json
* @param description l'instance au format ifstream
* @return l'instance de la classe STFInstance correspondant à l'objet JSON d'entrée
*/
static STFInstance createSTF(std::ifstream &description);
inline static STFInstance *getCurrentInstance() { return currentInstance; };
void initStaticInfos();
void initStaticInfos_from_instance();
/**
* @brief permet de créer la rame qui correspondera au trou dans le plan de transport
*/
void create_null_rame();
};
}
#endif
@@ -0,0 +1,28 @@
#include "STFInstanceInfoStats.hpp"
namespace modellib {
nlohmann::json STFInstanceInfoStats::to_json() {
nlohmann::json json = nlohmann::json::object();
json["nbRames"] = m_nbRames;
json["nbSites"] = m_nbSites;
json["nbVoies"] = m_nbVoies;
json["nbOperations"] = m_nbOperations;
json["proportionPlanifiees"] = m_propOpPanif;
json["proportionH1"] = m_propH1Planif;
json["proportionH2"] = m_propH2Planif;
json["proportionH3"] = m_propH3Planif;
json["proportionDiagnostique"] = m_propDiagnostic;
json["impossibilites"] = nlohmann::json::object();
json["impossibilites"]["signalements"] = nlohmann::json::array();
for (auto &reason: m_reasons) {
nlohmann::json re = nlohmann::json::object();
re["solveur"] = reason.solveur;
re["raison"] = reason.raison;
re["id"] = reason.id;
re["idAnomalie"] = reason.idAnomalie;
json["impossibilites"]["signalements"].push_back(re);
}
// json["impossibilites"] = re;
return json;
}
}
+172
View File
@@ -0,0 +1,172 @@
#ifndef STFINSTANCEINFOSTATS_HPP
#define STFINSTANCEINFOSTATS_HPP
#include <map>
#include <string>
#include <nlohmann/json.hpp>
#include "ExclusionInfo.hpp"
namespace modellib {
/**
* @class STFInstanceInfoStats
* @brief Class that allows one to fill some informations on the solved instance
*/
class STFInstanceInfoStats {
private:
/**
* @brief Number of trains in the instance
*/
unsigned int m_nbRames{};
/**
* @brief Number of maintenance site in the instance
*/
unsigned int m_nbSites{};
/**
* @brief Number of tracks available in the instance
*/
unsigned int m_nbVoies{};
/**
* @brief Number of jobs to schedule
*/
unsigned int m_nbOperations{};
/**
* @brief Proportion of scheduled jobs
*/
double m_propOpPanif{};
/**
* @brief Proportion of hierarchy 1 scheduled
*/
double m_propH1Planif{};
/**
* @brief Proportion of hierarchy 2 scheduled
*/
double m_propH2Planif{};
/**
* @brief Proportion of hierarchy 3 scheduled
*/
double m_propH3Planif{};
/**
* @brief Proportion of hierarchy 4 scheduled
*/
double m_propH4Planif{};
/**
* @brief Proportion of performed diagnosis
*/
double m_propDiagnostic{};
/**
* @brief Number of hierarchy 1 scheduled
*/
unsigned int m_nbH1{};
/**
* @brief Number of hierarchy 2 scheduled
*/
unsigned int m_nbH2{};
/**
* @brief Number of hierarchy 3 scheduled
*/
unsigned int m_nbH3{};
/**
* @brief Number of hierarchy 4 scheduled
*/
unsigned int m_nbH4{};
std::vector<ExclusionInfo> m_reasons;
public:
STFInstanceInfoStats() = default;
[[nodiscard]] unsigned int getNbH1() const {
return m_nbH1;
}
void setNbH1(unsigned int mNbH1) {
m_nbH1 = mNbH1;
}
[[nodiscard]] unsigned int getNbH2() const {
return m_nbH2;
}
void setNbH2(unsigned int mNbH2) {
m_nbH2 = mNbH2;
}
[[nodiscard]] unsigned int getNbH3() const {
return m_nbH3;
}
void setNbH3(unsigned int mNbH3) {
m_nbH3 = mNbH3;
}
[[nodiscard]] unsigned int getNbH4() const {
return m_nbH4;
}
void setNbH4(unsigned int mNbH4) {
m_nbH4 = mNbH4;
}
void setNbRames(unsigned int nbRames) {
m_nbRames = nbRames;
};
void setNbSites(unsigned int nbSites) {
m_nbSites = nbSites;
};
void setNbVoies(unsigned int nbVoies) {
m_nbVoies = nbVoies;
};
void setNbOperations(unsigned int nbOperations) {
m_nbOperations = nbOperations;
};
void setProportionPlanifiees(double propOpPanif) {
m_propOpPanif = propOpPanif;
};
void setProportionH1(double propOpPanif) {
m_propH1Planif = propOpPanif;
};
void setProportionH2(double propOpPanif) {
m_propH2Planif = propOpPanif;
};
void setProportionH3(double propOpPanif) {
m_propH3Planif = propOpPanif;
};
void setProportionH4(double propOpPanif) {
m_propH4Planif = propOpPanif;
};
void setProportionDiagnostique(double propOpPanif) {
m_propDiagnostic = propOpPanif;
};
[[nodiscard]] unsigned int getNbOperations() const {
return m_nbOperations;
}
std::vector<ExclusionInfo> &getReasons() { return m_reasons; };
nlohmann::json to_json();
};
}
#endif
@@ -0,0 +1 @@
#include "STFInstanceStaticInfo.hpp"
@@ -0,0 +1,45 @@
#ifndef ORDONNANCEMENTCORRECTIF_STFINSTANCESTATICINFO_HPP
#define ORDONNANCEMENTCORRECTIF_STFINSTANCESTATICINFO_HPP
#include <unordered_map>
#include <vector>
#include <cmath>
#include "EmplacementVoie.h"
namespace modellib {
class OperationRequise;
class Voie;
struct hash_pair {
size_t operator()(const std::pair<OperationRequise*, Voie*> &p) const {
auto hash1 = std::hash<OperationRequise*>{}(p.first);
auto hash2 = std::hash<Voie*>{}(p.second);
if (hash1 != hash2) {
return hash1 ^ hash2;
}
return hash1;
}
};
class Rame;
class STFInstanceStaticInfo {
private:
public:
std::unordered_map<std::pair<OperationRequise *, Voie*>, bool, hash_pair> matchesInfraOpTrack;
std::unordered_map<OperationRequise *, Rame *> trainOfOperation;
std::vector<std::pair<Rame *, std::vector<OperationRequise *>>> operationsOfTrain;
std::vector<EmplacementVoie*> trackIntervals;
std::unordered_map<EmplacementVoie*,unsigned int> trackIntervalsIds;
std::unordered_map<Rame*,unsigned int> ramesIds;
double multiIndicator{};
STFInstanceStaticInfo() = default;
};
}
#endif
File diff suppressed because it is too large Load Diff
+24
View File
@@ -0,0 +1,24 @@
#include "STFMockInstance.hpp"
#include "GareSite.h"
#include <vector>
namespace modellib {
std::vector<Rame*> STFMockInstance::rames;//
std::vector<EmplacementVoie*> STFMockInstance::machines;
std::vector<OperationRequise*> STFMockInstance::jobs;//
std::vector<EmplacementRame*> STFMockInstance::stops;//
std::vector<std::vector<unsigned int>> STFMockInstance::initialTrainStops;
std::vector<Voie*> STFMockInstance::tracks;//
std::vector<MaintenanceSite*> STFMockInstance::sites;//
std::vector<Site*> STFMockInstance::siteGares;//
std::vector<std::vector<unsigned short>> STFMockInstance::operationsOfRames;//
std::vector<unsigned short> STFMockInstance::rameOfOperations;//
std::vector<std::pair<unsigned char, unsigned char>> STFMockInstance::siteTrackOfMachine;//
std::vector<std::vector<bool>> STFMockInstance::infraComp;//
std::vector<PreventiveMaintenanceRdv*> STFMockInstance::preventiveMaintenanceRdvms;
std::vector<std::vector<unsigned int>> STFMockInstance::rdvComp;
std::vector<std::vector<unsigned int>> STFMockInstance::TrajectoryStopsofTrajectoryUM;
std::vector<unsigned int> STFMockInstance::UmOfTrajectoryStop;
std::vector<std::vector<unsigned int>> STFMockInstance::TrajectoryStopfUM;
std::vector<std::vector<unsigned int>> STFMockInstance::crossedUM;
std::vector<std::vector<unsigned int>> STFMockInstance::compTraj;
}
+847
View File
@@ -0,0 +1,847 @@
#ifndef STFMOCKINSTANCE_HPP
#define STFMOCKINSTANCE_HPP
#include "EmplacementRame.h"
#include "GareSite.h"
#include "OperationRequise.h"
#include "PreventiveMaintenanceRdv.hpp"
#include "Rame.h"
#include "RecompoUM.h"
#include "Site.h"
#include "TrajectoryStop.hpp"
#include <algorithm>
#include <memory>
#include <unordered_set>
#include <utility>
#include <vector>
#define MAXIMUM_TIME_OFFSET 250
#include "UM.h"
#include "CroisementUM.hpp"
#include "Decision.hpp"
#include "DispVoieRame.hpp"
namespace std {
template <> struct hash<modellib::TrajectoryStop>
{
size_t operator()(const modellib::TrajectoryStop& val) const {
//static const auto shift = (size_t)log2(1 + sizeof(modellib::EmplacementRame*));
if(val.entree != val.sortie)
{
auto h = val.entree;
auto h2 = val.sortie;
return h ^ h2;
}
else
{
auto h = val.entree;
return h;
}
}
};
template <> struct hash<std::pair<unsigned int, unsigned int>>
{
size_t operator()(const std::pair<unsigned int, unsigned int>& val)const{
return (size_t)val.first ^ (size_t)val.second;
}
};
}
namespace modellib {
class STFMockInstance {
private:
public:
static std::vector<Rame*> rames;//
static std::vector<EmplacementVoie*> machines;
static std::vector<OperationRequise*> jobs;//
static std::vector<EmplacementRame*> stops;//
static std::vector<std::vector<unsigned int>> initialTrainStops;
static std::vector<Voie*> tracks;//
static std::vector<MaintenanceSite*> sites;//
static std::vector<Site*> siteGares;//
static std::vector<std::vector<unsigned short>> operationsOfRames;//
static std::vector<unsigned short> rameOfOperations;//
static std::vector<std::pair<unsigned char, unsigned char>> siteTrackOfMachine;//
static std::vector<std::vector<bool>> infraComp;//
static std::vector<PreventiveMaintenanceRdv*> preventiveMaintenanceRdvms; //
static std::vector<std::vector<unsigned int>> rdvComp;
/**
* @brief Map permettant de retrouver les TrajectoryStop associer à l'UM d'une trajectoryStops
* @note TrajectoryStopsofTrajectoryUM[ID_TrajectoryStops] -> Vecteur d'ID de TrajectoryStop
*/
static std::vector<std::vector<unsigned int>> TrajectoryStopsofTrajectoryUM;
/**
* @brief Map permettant de retrouver l'UM associer à un trajectoryStops
* @note UmOfTrajectoryStop[ID_TrajectoryStops] -> ID de l'UM
*/
static std::vector<unsigned int> UmOfTrajectoryStop;
/**
* @brief Map permettant de retrouver les TrajectoryStop associer à l'indice d'un UM
* @note TrajectoryStopsofUM[ID_UM] -> Vecteur d'ID de TrajectoryStop
*/
static std::vector<std::vector<unsigned int>> TrajectoryStopfUM;
static std::vector<std::vector<unsigned int>> crossedUM;
static std::vector<std::vector<unsigned int>> compTraj;
std::vector<unsigned short> jobOrder;
std::vector<DispVoieRame> dispoVoiesRames;
std::vector<std::vector<unsigned int>> jobDispoVoiesRames;
std::vector<TrajectoryStop> trajectoryStops;
std::vector<std::vector<unsigned int>> matches;
//std::vector<std::vector<unsigned int>> crossedUMs;
std::vector<std::shared_ptr<CroisementUM>> swaps;
//std::vector<std::vector<unsigned int>> compUMs;
std::vector<std::shared_ptr<RecompoUM>> recompos;
std::vector<std::vector<unsigned int>> trajectories;
/**
* @brief Vecteur permettant de recupperer la rame associée à une TrajectoryStop.
* @note rameOftrajectories[ID_TrajectoryStops] -> ID de la rame
*/
std::vector<unsigned short> rameOftrajectories;
//TODO Axel, tu vas sûrement avoir besoin de redéfinir une classe comme CroisementUM (et de stocker les différentes recompo faites comme dans le vecteur "swaps" au dessus) qui sera similaire mais pas tout à fait pareil.
//tu vas aussi devoir faire une fonction d'échange comme celle de ce fichier en bas, qui fera grosso modo la même chose mais va gérer un peu différemment les modifs car les UMs sont modifiés.
//il est très probable que beaucoup du code se ressemble, n'hésite pas à factoriser (en faisant attention à ne pas casser les croisements bien sûr)
inline static void clean()
{
rames.clear();
machines.clear();
jobs.clear();
stops.clear();
initialTrainStops.clear();
tracks.clear();
sites.clear();
siteGares.clear();
operationsOfRames.clear();
rameOfOperations.clear();
siteTrackOfMachine.clear();
infraComp.clear();
preventiveMaintenanceRdvms.clear();
rdvComp.clear();
TrajectoryStopsofTrajectoryUM.clear();
UmOfTrajectoryStop.clear();
TrajectoryStopfUM.clear();
crossedUM.clear();
compTraj.clear();
}
inline void addDispoVoieRame(unsigned short op, unsigned int dispo) {
jobDispoVoiesRames[op].emplace_back(dispo);
matches[dispoVoiesRames[dispo].dispoVoie].emplace_back(dispo);
}
/**
* @brief Remove les dispo voie/rame des matrice matches et jobDispoVoiesRames
*/
inline void removeDispoVoieRame(unsigned short op, unsigned int dispo) {
auto posM = std::remove(matches[dispoVoiesRames[dispo].dispoVoie].begin(),
matches[dispoVoiesRames[dispo].dispoVoie].end(),dispo);
matches[dispoVoiesRames[dispo].dispoVoie].erase(posM);
auto posD = std::remove(jobDispoVoiesRames[op].begin(), jobDispoVoiesRames[op].end(), dispo);
jobDispoVoiesRames[op].erase(posD,jobDispoVoiesRames[op].end());
}
/**
* @brief Remove toutes les Dispo Voie/Rame associé au opération de la rame selon des conditions.
* @note [Recomposition UM nodes]
*/
inline void removeDispoVoieRameRecompo(std::vector<unsigned short>& opToRebuild_vect,std::pair<bool,TrajectoryStop> TMArrival, TrajectoryStop stopRame, unsigned int& rame){
for(unsigned short &op : operationsOfRames[rame]){
opToRebuild_vect.push_back(op);
auto v = jobDispoVoiesRames[op];
for (auto &disp_v_r: v) {
auto& cr = trajectoryStops[dispoVoiesRames[disp_v_r].dispoRame].getDispoStop();
auto& typeSt = trajectoryStops[dispoVoiesRames[disp_v_r].dispoRame].typeDispo;
/*On retire la dispo voie/rame si c'est un roulement et que la dispo voie/rame se trouve après le croisement. Si c'est la dispo du croisement on retir aussi
Dans le cas ou la dispo voie/rame est un RDV, on retir uniquement si la prochaine arrivé en TM était celle qui honore le RDV. Cela veux dire que le croisement à été éffectué pour croiser des rdv équivalent. */
if ((typeSt.first != typeStop::RDVM ||
CreneauHoraire::checkCommonDuration(cr, TMArrival.second.getDispoStop(), 1)) &&
(cr.getDebutC().getRelativeDate() >= stopRame.getDispoStop().getFinC().getRelativeDate() ||
CreneauHoraire::checkCommonDuration(cr, stopRame.getDispoStop(), 1))) {
removeDispoVoieRame(op, disp_v_r);
}
}
}
}
/**
* @brief Identifie et met à jour type d'arrêt des TrajectoryStop devenus obsolètes pour une rame donnée,
* tout en sauvegardant ceux supprimés dans usOldEmp et modifTrLookUp.
* @return Lidentifiant du TrajectoryStop qui a servi de point de croisement pour la rame.
*/
inline unsigned int changeTrajectoryStop_Status(std::vector<unsigned int>& usOldEmp, std::unordered_set<unsigned int>& modifTrLookUp, std::pair<bool, TrajectoryStop> TMArrival, TrajectoryStop UMofRameStop, unsigned int rame, bool critGain){
unsigned int usCrossed = 0;
for (auto &e: trajectories[rame]) {
const auto& cr = trajectoryStops[e].getDispoStop();
auto& typeSt = trajectoryStops[e].typeDispo;
if ((typeSt.first != typeStop::RDVM ||
(TMArrival.first && CreneauHoraire::checkCommonDuration(cr, TMArrival.second.getDispoStop(), 1))) &&
cr.getDebutC().getRelativeDate() >= UMofRameStop.getDispoStop().getFinC().getRelativeDate()) {
usOldEmp.emplace_back(e);
modifTrLookUp.insert(e);
if(critGain)
trajectoryStops[usOldEmp.back()].typeDispo.first = typeStop::RLT_POST_RECOMPO_SUBIT;
else
trajectoryStops[usOldEmp.back()].typeDispo.first = typeStop::RLT_POST_RECOMPO_VOULU;
trajectoryStops[usOldEmp.back()].typeDispo.second.clear();// = "";
}
if(UMofRameStop.entree == trajectoryStops[e].entree)
{
usCrossed = e;
}
}
return usCrossed;
}
inline void removeRDVM(std::vector<unsigned int>& usOldEmp, std::unordered_set<unsigned int>& modifTrLookUp, unsigned int rame_id){
std::vector<unsigned int> toRemSane;
for(auto& TrStopCrit : trajectories[rame_id])
{
for(auto& TrStopSaine_erased : usOldEmp)
{
auto& crO = trajectoryStops[TrStopSaine_erased].getDispoStop();
auto& crI = trajectoryStops[TrStopCrit].getDispoStop();
if(CreneauHoraire::checkCommonDuration(crI, crO, 1) && trajectoryStops[TrStopCrit].typeDispo.first == typeStop::RDVM)
{
toRemSane.emplace_back(TrStopSaine_erased);
if(modifTrLookUp.find(TrStopSaine_erased) != modifTrLookUp.end())
modifTrLookUp.erase(TrStopSaine_erased);
}
}
}
auto remS = std::remove_if(usOldEmp.begin(), usOldEmp.end(),[&](auto& el){return std::find(toRemSane.begin(), toRemSane.end(), el) != toRemSane.end();});
usOldEmp.erase(remS, usOldEmp.end());
}
/**
* @brief Fonction qui swap
*/
// void swap_TrajectoryStop_after_TM(unsigned int ts,unsigned short rames_than_change, unsigned short rames_to_change){
// for(unsigned int trajId : STFMockInstance::TrajectoryStopsofTrajectoryUM[ts]){
// for(unsigned int i=0; i< trajectoryStops[trajId].um_entree.ramesInfo.size(); i++){
// if (trajectoryStops[trajId].um_entree.ramesInfo[i] == rames_to_change) {
// trajectoryStops[trajId].um_entree.ramesInfo[i].id = rames_than_change;
// }
// }
// trajectoryStops[trajId].um_sortie = trajectoryStops[trajId].um_entree;
// }
// }
void swap_TrajectoryStop_after_TM(unsigned int ts,unsigned short rames_than_change, unsigned short rames_to_change, bool is_first){
for(unsigned int trajId : STFMockInstance::TrajectoryStopsofTrajectoryUM[ts]){
bool is_rames_than_change = false;
bool is_rame_to_change = false;
for(unsigned int i=0; i< trajectoryStops[trajId].um_entree.ramesInfo.size(); i++){
if(trajectoryStops[trajId].um_entree.ramesInfo[i] == rames_to_change) is_rame_to_change = true;
if(trajectoryStops[trajId].um_entree.ramesInfo[i] == rames_than_change) is_rames_than_change = true;
}
if(is_rames_than_change && is_rame_to_change){
if(!is_first){
for(unsigned int i=0; i< trajectoryStops[trajId].um_entree.ramesInfo.size(); i++){
if (trajectoryStops[trajId].um_entree.ramesInfo[i] == rames_to_change) {
trajectoryStops[trajId].um_entree.ramesInfo[i].id = rames_than_change;
continue;
}
if(trajectoryStops[trajId].um_entree.ramesInfo[i] == rames_than_change){
trajectoryStops[trajId].um_entree.ramesInfo[i].id = rames_to_change;
continue;
}
}
trajectoryStops[trajId].um_sortie = trajectoryStops[trajId].um_entree;
}
}else{
for(unsigned int i=0; i< trajectoryStops[trajId].um_entree.ramesInfo.size(); i++){
if (trajectoryStops[trajId].um_entree.ramesInfo[i] == rames_to_change) {
trajectoryStops[trajId].um_entree.ramesInfo[i].id = rames_than_change;
}
}
trajectoryStops[trajId].um_sortie = trajectoryStops[trajId].um_entree;
}
}
}
STFMockInstance() = default;
~STFMockInstance() = default;
static inline std::pair<bool, std::pair<unsigned short, unsigned short>>
checkSlots(std::pair<unsigned short, unsigned short> &cren_base, std::pair<unsigned short, unsigned short> &cren_rem) {
std::pair<bool, std::pair<unsigned short, unsigned short>> toReturn;
toReturn.first = false;
unsigned short begTrain = cren_base.first;
unsigned short begTrack = cren_rem.first;
unsigned short endTrain = cren_base.second;
unsigned short endTrack = cren_rem.second;
std::pair<bool, std::pair<unsigned short, unsigned short>> match;
if ((begTrack <= begTrain && endTrain <= endTrack)
|| (begTrain <= begTrack && endTrack <= endTrain)
|| (begTrack <= endTrain && begTrain <= begTrack)
|| (begTrain <= endTrack && begTrack <= begTrain)
|| (endTrack <= endTrain && begTrain <= endTrack)
|| (endTrain <= endTrack && begTrack <= endTrain)
) {
unsigned short overlapBeginTime;
unsigned short overlapEndTime;
if ((begTrain) <= begTrack) {
overlapBeginTime = begTrack;// - *SolverDate::getDateDebut();
} else {
overlapBeginTime = begTrain; //- *SolverDate::getDateDebut();
}
if ((endTrain) <= endTrack) { overlapEndTime = (endTrain); }// - *SolverDate::getDateDebut(); }
else { overlapEndTime = endTrack; } //- *SolverDate::getDateDebut(); }
match.first = true;
match.second.first = overlapBeginTime;
match.second.second = overlapEndTime;
}
if (match.first) {
if (cren_base.first < match.second.first
&& match.second.second < cren_base.second) {
toReturn.second = {match.second.second, cren_base.second};
toReturn.first = true;
cren_base.second = match.second.first;
} else if (cren_base.first == match.second.first && match.second.second == cren_base.second) {
cren_base.first = 0;
cren_base.second = 0;
} else if (cren_base.first == match.second.first && match.second.second < cren_base.second) {
cren_base.first = match.second.second;
} else if (cren_base.first < match.second.first
&& match.second.second == cren_base.second) {
cren_base.second = match.second.first;
}
}
return toReturn;
}
inline void update(unsigned short empV, std::pair<unsigned short, unsigned short> &cren) {
auto vR = matches[empV];
for (auto &disp: vR)
{
auto ret = checkSlots(dispoVoiesRames[disp].match, cren);
bool rem = false;
if ((dispoVoiesRames[disp].match.second - dispoVoiesRames[disp].match.first) < jobs[dispoVoiesRames[disp].op]->getDureeDiag()) {
rem = true;
}
if (ret.first && (ret.second.second - ret.second.first) >= jobs[dispoVoiesRames[disp].op]->getDureeDiag())
{
if(rem)
{
dispoVoiesRames[disp].match = ret.second;
rem = false;
}
else
{
auto cop = dispoVoiesRames[disp];
cop.match = ret.second;
dispoVoiesRames.push_back(cop);
dispoVoiesRames.back().op = dispoVoiesRames[disp].op;
addDispoVoieRame(dispoVoiesRames[disp].op, dispoVoiesRames.size()-1);
}
}
if(rem)
removeDispoVoieRame(dispoVoiesRames[disp].op, disp);
}
}
inline void update(unsigned short empV, std::pair<unsigned short, unsigned short> &cren, unsigned short oprame)
{
if(operationsOfRames[rameOfOperations[oprame]].size() > 1)
{
for(auto& opr : operationsOfRames[rameOfOperations[oprame]])
{
if(oprame != opr)
{
auto v = jobDispoVoiesRames[opr];
for(auto& disp : v)
{
if(dispoVoiesRames[disp].dispoVoie != empV)
{
auto ret = checkSlots(dispoVoiesRames[disp].match, cren);
bool rem = false;
if ((dispoVoiesRames[disp].match.second - dispoVoiesRames[disp].match.first) < jobs[dispoVoiesRames[disp].op]->getDureeDiag()) {
rem = true;
}
if (ret.first && (ret.second.second - ret.second.first) >= jobs[dispoVoiesRames[disp].op]->getDureeDiag()) {
if(rem)
{
dispoVoiesRames[disp].match = ret.second;
rem = false;
}
else
{
auto cop = dispoVoiesRames[disp];
cop.match = ret.second;
dispoVoiesRames.push_back(cop);
dispoVoiesRames.back().op = dispoVoiesRames[disp].op;
addDispoVoieRame(dispoVoiesRames[disp].op, dispoVoiesRames.size()-1);
}
}
if(rem)
removeDispoVoieRame(dispoVoiesRames[disp].op, disp);
}
}
}
}
}
}
inline static std::shared_ptr<STFMockInstance> copy(std::shared_ptr<STFMockInstance> toCopy, bool light = false) {
auto mock = std::make_shared<STFMockInstance>();
if(light)
{
mock->jobOrder.reserve(toCopy->jobOrder.size());
std::copy(toCopy->jobOrder.begin(), toCopy->jobOrder.end(), std::back_inserter(mock->jobOrder));
mock->jobDispoVoiesRames.reserve(toCopy->jobDispoVoiesRames.size());
std::copy(toCopy->jobDispoVoiesRames.begin(), toCopy->jobDispoVoiesRames.end(), std::back_inserter(mock->jobDispoVoiesRames));
mock->dispoVoiesRames.reserve(toCopy->dispoVoiesRames.size());
std::copy(toCopy->dispoVoiesRames.begin(), toCopy->dispoVoiesRames.end(), std::back_inserter(mock->dispoVoiesRames));
mock->matches.reserve(toCopy->matches.size());
std::copy(toCopy->matches.begin(), toCopy->matches.end(), std::back_inserter(mock->matches));
}
else
{
// mock->crossedUMs.reserve(toCopy->crossedUMs.size());
// std::copy(toCopy->crossedUMs.begin(), toCopy->crossedUMs.end(), std::back_inserter(mock->crossedUMs));
// mock->compUMs.reserve(toCopy->compUMs.size());
// std::copy(toCopy->compUMs.begin(), toCopy->compUMs.end(), std::back_inserter(mock->compUMs));
mock->trajectories.reserve(toCopy->trajectories.size());
std::copy(toCopy->trajectories.begin(), toCopy->trajectories.end(), std::back_inserter(mock->trajectories));
mock->rameOftrajectories.reserve(toCopy->rameOftrajectories.size());
std::copy(toCopy->rameOftrajectories.begin(), toCopy->rameOftrajectories.end(), std::back_inserter(mock->rameOftrajectories));
mock->jobDispoVoiesRames.reserve(toCopy->jobDispoVoiesRames.size());
std::copy(toCopy->jobDispoVoiesRames.begin(), toCopy->jobDispoVoiesRames.end(), std::back_inserter(mock->jobDispoVoiesRames));
mock->trajectoryStops.reserve(toCopy->trajectoryStops.size());
std::copy(toCopy->trajectoryStops.begin(), toCopy->trajectoryStops.end(), std::back_inserter(mock->trajectoryStops));
mock->swaps.reserve(toCopy->swaps.size());
std::copy(toCopy->swaps.begin(), toCopy->swaps.end(), std::back_inserter(mock->swaps));
mock->recompos.reserve(toCopy->recompos.size());
std::copy(toCopy->recompos.begin(), toCopy->recompos.end(), std::back_inserter(mock->recompos));
mock->jobOrder.reserve(toCopy->jobOrder.size());
std::copy(toCopy->jobOrder.begin(), toCopy->jobOrder.end(), std::back_inserter(mock->jobOrder));
mock->dispoVoiesRames.reserve(toCopy->dispoVoiesRames.size());
std::copy(toCopy->dispoVoiesRames.begin(), toCopy->dispoVoiesRames.end(), std::back_inserter(mock->dispoVoiesRames));
mock->matches.reserve(toCopy->matches.size());
std::copy(toCopy->matches.begin(), toCopy->matches.end(), std::back_inserter(mock->matches));
}
return mock;
}
inline void swap(CroisementUM& croisement) {
//TODO modifier trajectory stop pour qu'il contienne Um entrée et UM sortie. Faire un croisement revient à regarder pour chaque rame et chaque point d'arrêt, puis chaque autre rame et son point d'arrêt, si la taille de l'UM est identique en entrée, croisement possible.
//TODO modifier UM pour qu'il accepte, une deux ou trois rames => la taille de l'UM définit les croisements possible => pour généraliser les croisements et préparer le terrain à la recomposition => si chaque point d'arrêt connait l'um d'entrée et de sortie on connait toutes les affectations
//TODO maintenir l'objet croisement (en le mettant à jour sur les modif précédentes) pour avoir l'info de l'ensemble des croisements effectués et leur coût
auto& crStopCrit = croisement.stopUMCrit.getDispoStop();
auto& crStopSane = croisement.stopUMSane.getDispoStop();
std::vector<unsigned int> modifTr;
std::unordered_set<unsigned int> modifTrLookUp;
auto usCrit = croisement.um_crit.ramesInfo.begin();
/**** Parcour les rame de l'UM saine ****/
for(auto& usSane : croisement.um_sane.ramesInfo)
{
std::vector<unsigned short> mockRCrit = {(*usCrit).id};
std::vector<unsigned short> mockRSane = {(usSane).id};
auto& earliestCrit = croisement.trajectoireTM.initialNextStopTM.at((*usCrit).id);
auto& earliestSane = croisement.trajectoireTM.initialNextStopTM.at((usSane).id);
/**** Permet de dire si le croisement est utils(il y a un gain) ou non ****/
bool critGain = (!earliestCrit.first && earliestSane.first) || (earliestCrit.first && earliestSane.first && earliestCrit.second.getDispoStop().getDebutC().getRelativeDate() > earliestSane.second.getDispoStop().getDebutC().getRelativeDate());
std::vector<unsigned short> opToRebuild_crit; //stock toute les opération associer à l'UM critique
std::vector<unsigned short> opToRebuild_sane; //stock toute les opération associer à l'UM saine
/***** Parcours les opération de la rame critique courante (la première???) *****/
for (auto &op: operationsOfRames[(*usCrit).id])
{
opToRebuild_crit.push_back(op);
auto v = jobDispoVoiesRames[op];
//auto& c = croisement.stopUMCrit.getDispoStop();
for (auto &disp: v) {
auto& cr = trajectoryStops[dispoVoiesRames[disp].dispoRame].getDispoStop();
auto& typeSt = trajectoryStops[dispoVoiesRames[disp].dispoRame].typeDispo;
auto& um = trajectoryStops[dispoVoiesRames[disp].dispoRame].um_entree.ramesInfo;
/*On retire la dispo voie/rame si c'est un roulement et que la dispo voie/rame se trouve après le croisement. Si c'est la dispo du croisement on retir aussi
Dans le cas ou la dispo voie/rame est un RDV, on retir uniquement si la prochaine arrivé en TM était celle qui honore le RDV. Cela veux dire que le croisement à été éffectué pour croiser des rdv équivalent. */
if ((typeSt.first != typeStop::RDVM || (std::is_permutation(um.begin(), um.end(), croisement.um_crit.ramesInfo.begin()) && CreneauHoraire::checkCommonDuration(cr, earliestCrit.second.getDispoStop(), 1))) && (cr.getDebutC().getRelativeDate() >= crStopCrit.getFinC().getRelativeDate() ||
CreneauHoraire::checkCommonDuration(cr, crStopCrit, 1))) {
removeDispoVoieRame(op, disp);
}
}
}
for (auto &op: operationsOfRames[usSane.id]) {
opToRebuild_sane.push_back(op);
auto v = jobDispoVoiesRames[op];
//auto& c = croisement.stopUMSane.getDispoStop();
for (auto &disp: v) {
auto& cr = trajectoryStops[dispoVoiesRames[disp].dispoRame].getDispoStop();
auto& typeSt = trajectoryStops[dispoVoiesRames[disp].dispoRame].typeDispo;
auto& um = trajectoryStops[dispoVoiesRames[disp].dispoRame].um_entree.ramesInfo;
if ((typeSt.first != typeStop::RDVM || (std::is_permutation(um.begin(), um.end(), croisement.um_sane.ramesInfo.begin()) && CreneauHoraire::checkCommonDuration(cr, earliestSane.second.getDispoStop(), 1))) && (cr.getDebutC().getRelativeDate() >= crStopSane.getFinC().getRelativeDate() ||
CreneauHoraire::checkCommonDuration(cr, crStopSane, 1))) {
removeDispoVoieRame(op, disp);
}
}
}
std::vector<unsigned int> usCritOldEmp;
std::vector<unsigned int> usSaneOldEmp;
unsigned int usCritCrossed = 0;
unsigned int usSaneCrossed = 0;
/**** Parcours toute les trajectoryStop de la rame usCrit ****/
for (auto &e: trajectories[(*usCrit).id]) {
const auto& c = trajectoryStops[e].getDispoStop();
auto& typeSt = trajectoryStops[e].typeDispo;
auto& um = trajectoryStops[e].um_entree.ramesInfo;
if ((typeSt.first != typeStop::RDVM || (std::is_permutation(um.begin(), um.end(), croisement.um_crit.ramesInfo.begin()) && earliestCrit.first && CreneauHoraire::checkCommonDuration(c, earliestCrit.second.getDispoStop(), 1)))
&& c.getDebutC().getRelativeDate() >= croisement.stopUMCrit.getDispoStop().getFinC().getRelativeDate()) {
usCritOldEmp.emplace_back(e);
modifTrLookUp.insert(e);
if(critGain)
trajectoryStops[usCritOldEmp.back()].typeDispo.first = typeStop::RLT_POST_CROISEMENT_SUBIT;
else
trajectoryStops[usCritOldEmp.back()].typeDispo.first = typeStop::RLT_POST_CROISEMENT_VOULU;
trajectoryStops[usCritOldEmp.back()].typeDispo.second.clear();// = "";
}
if(croisement.stopUMCrit.entree == trajectoryStops[e].entree)
{
usCritCrossed = e;
}
}
for (auto &e: trajectories[usSane.id]) {
const auto& c = trajectoryStops[e].getDispoStop();
auto& typeSt = trajectoryStops[e].typeDispo;
auto& um = trajectoryStops[e].um_entree.ramesInfo;
if ((typeSt.first != typeStop::RDVM || (std::is_permutation(um.begin(), um.end(), croisement.um_sane.ramesInfo.begin()) && earliestSane.first && CreneauHoraire::checkCommonDuration(c, earliestSane.second.getDispoStop(), 1)))
&& c.getDebutC().getRelativeDate() >= croisement.stopUMSane.getDispoStop().getFinC().getRelativeDate()) {
usSaneOldEmp.emplace_back(e);
modifTrLookUp.insert(e);
if(critGain)
trajectoryStops[usSaneOldEmp.back()].typeDispo.first = typeStop::RLT_POST_CROISEMENT_VOULU;
else
trajectoryStops[usSaneOldEmp.back()].typeDispo.first = typeStop::RLT_POST_CROISEMENT_SUBIT;
trajectoryStops[usSaneOldEmp.back()].typeDispo.second.clear();// = "";
}
if(croisement.stopUMSane.entree == trajectoryStops[e].entree)
{
usSaneCrossed = e;
}
}
auto pos = std::remove_if(trajectories[(*usCrit).id].begin(), trajectories[(*usCrit).id].end(),
[&](unsigned int e) {
if(std::find(usCritOldEmp.begin(), usCritOldEmp.end(), e) != usCritOldEmp.end())
{
return true;
}
return false;
});
auto posSane = std::remove_if(trajectories[usSane.id].begin(), trajectories[usSane.id].end(),
[&](unsigned int e) {
if(std::find(usSaneOldEmp.begin(), usSaneOldEmp.end(), e) != usSaneOldEmp.end())
{
return true;
}
return false;
});
trajectories[(*usCrit).id].erase(pos, trajectories[(*usCrit).id].end());
trajectories[(usSane).id].erase(posSane, trajectories[(usSane).id].end());
auto tmpExit = trajectoryStops[usCritCrossed].sortie;
trajectoryStops[usCritCrossed].setSortie(trajectoryStops[usSaneCrossed].sortie,stops[trajectoryStops[usSaneCrossed].sortie]->getDispo().getFin());
trajectoryStops[usSaneCrossed].setSortie(tmpExit,stops[tmpExit]->getDispo().getFin());
removeRDVM(usSaneOldEmp, modifTrLookUp, (*usCrit).id);
removeRDVM(usCritOldEmp, modifTrLookUp, (usSane).id);
for(auto& ts : usSaneOldEmp)
{
swap_TrajectoryStop_after_TM(ts, (*usCrit).id, usSane.id,true);
trajectories[(*usCrit).id].emplace_back(ts);
rameOftrajectories[ts] = (*usCrit).id;
}
for(auto& ts : usCritOldEmp)
{
swap_TrajectoryStop_after_TM(ts, usSane.id, (*usCrit).id,false);
trajectories[usSane.id].emplace_back(ts);
rameOftrajectories[ts] = usSane.id;
}
rebuildDispVoiesRames(opToRebuild_crit, usSaneOldEmp);
rebuildDispVoiesRames(opToRebuild_sane, usCritOldEmp);
modifTr.reserve(usCritOldEmp.size() + usSaneOldEmp.size());
modifTr.insert(modifTr.end(),usCritOldEmp.begin(), usCritOldEmp.end());
modifTr.insert(modifTr.end(),usSaneOldEmp.begin(), usSaneOldEmp.end());
++usCrit;
}
//A retirer ça consomme beaucoup c'est pour mes teste pour être sur qu'il y a de la cohérance partout même après le swap
/*for(auto stop : trajectoryStops){
std::unordered_set<unsigned int> seen;
for(auto rame : stop.um_entree.ramesInfo){
if(seen.find(rame.id) != seen.end()){
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "OK c'est a partir d'ici que ça par en couille!");
}
seen.insert(rame.id);
}
}*/
// std::vector<unsigned int> toAdd;
// for(auto& el : modifTr)
// {
// for(auto& cr : crossedUMs[el])
// {
// if(modifTrLookUp.find(cr) == modifTrLookUp.end())
// {
// toAdd.emplace_back(cr);
// }
// }
// }
// updateCrossedUM(modifTr, toAdd);
// updateCompUM(modifTr, toAdd);
}
inline void tri(RecompoUM& recompo){
for(RecompoInfo comp : recompo.recompo_done){
unsigned int idx_Crit_Rame = 0;
unsigned int idx_Saine_Rame = 0;
auto it_crit = std::find(recompo.um_crit_init.ramesInfo.begin(), recompo.um_crit_init.ramesInfo.end(),comp.rame_critique);
if (it_crit != recompo.um_crit_init.ramesInfo.end()) {
idx_Crit_Rame = std::distance(recompo.um_crit_init.ramesInfo.begin(), it_crit);
} else {
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "Fonction tri: la rame critique ne fait pas parti de l'UM critique");
}
auto it_sain = std::find(recompo.um_saine_init.ramesInfo.begin(), recompo.um_saine_init.ramesInfo.end(),comp.rame_saine);
if (it_sain != recompo.um_saine_init.ramesInfo.end()) {
idx_Saine_Rame = std::distance(recompo.um_saine_init.ramesInfo.begin(), it_sain);
} else {
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "Fonction tri: la rame saine ne fait pas parti de l'UM saine");
}
bool critGain = (!recompo.UM_crit_TM_arrival[idx_Crit_Rame].first && recompo.UM_saine_TM_arrival[idx_Saine_Rame].first) ||
(recompo.UM_crit_TM_arrival[idx_Crit_Rame].first && recompo.UM_saine_TM_arrival[idx_Saine_Rame].first && recompo.UM_crit_TM_arrival[idx_Crit_Rame].second.getDispoStop().getDebutC().getRelativeDate() > recompo.UM_saine_TM_arrival[idx_Saine_Rame].second.getDispoStop().getDebutC().getRelativeDate());
std::vector<unsigned short> opToRebuild_crit; //stock toute les opération associer à l'UM critique
std::vector<unsigned short> opToRebuild_sane; //stock toute les opération associer à l'UM saine
removeDispoVoieRameRecompo(opToRebuild_crit,recompo.UM_crit_TM_arrival[idx_Crit_Rame],recompo.stopRame_UMCrit[idx_Crit_Rame], comp.rame_critique);
removeDispoVoieRameRecompo(opToRebuild_sane, recompo.UM_saine_TM_arrival[idx_Saine_Rame],recompo.stopRame_UMSane[idx_Saine_Rame], comp.rame_saine);
std::vector<unsigned int> usCritOldEmp;
std::vector<unsigned int> usSaneOldEmp;
std::unordered_set<unsigned int> modifTrLookUp;
unsigned int idx_TrajectoryStop_crit_comp = changeTrajectoryStop_Status(usCritOldEmp,modifTrLookUp, recompo.UM_crit_TM_arrival[idx_Crit_Rame],recompo.stopRame_UMCrit[idx_Crit_Rame],comp.rame_critique, critGain);
unsigned int idx_TrajectoryStop_saine_comp = changeTrajectoryStop_Status(usSaneOldEmp,modifTrLookUp, recompo.UM_saine_TM_arrival[idx_Saine_Rame], recompo.stopRame_UMSane[idx_Saine_Rame], comp.rame_saine, critGain);
/***** Retire des trajectories les id des TrajectoryStop qui ne font plus parti des trajectoires de la rame *****/
auto pos = std::remove_if(trajectories[comp.rame_critique].begin(), trajectories[comp.rame_critique].end(),
[&](unsigned int e) {
if(std::find(usCritOldEmp.begin(), usCritOldEmp.end(), e) != usCritOldEmp.end())
{
return true;
}
return false;
});
auto posSane = std::remove_if(trajectories[comp.rame_saine].begin(), trajectories[comp.rame_saine].end(),
[&](unsigned int e) {
if(std::find(usSaneOldEmp.begin(), usSaneOldEmp.end(), e) != usSaneOldEmp.end())
{
return true;
}
return false;
});
trajectories[comp.rame_critique].erase(pos, trajectories[comp.rame_critique].end());
trajectories[comp.rame_saine].erase(posSane, trajectories[comp.rame_saine].end());
/**** Met a jour la sorti du TrajectoryStop associé à la rame ****/
auto tmpExit = trajectoryStops[idx_TrajectoryStop_crit_comp].sortie;
trajectoryStops[idx_TrajectoryStop_crit_comp].setSortie(trajectoryStops[idx_TrajectoryStop_saine_comp].sortie,stops[trajectoryStops[idx_TrajectoryStop_saine_comp].sortie]->getDispo().getFin());
trajectoryStops[idx_TrajectoryStop_saine_comp].setSortie(tmpExit,stops[tmpExit]->getDispo().getFin());
/**** Je vois pas bien a quoi sert cette parti voir avec Tom plus tard****/
removeRDVM(usCritOldEmp, modifTrLookUp, comp.rame_saine);
removeRDVM(usSaneOldEmp, modifTrLookUp, comp.rame_critique);
for(auto& ts : usCritOldEmp)
{
swap_TrajectoryStop_after_TM(ts, comp.rame_saine, comp.rame_critique,true);
trajectories[comp.rame_saine].emplace_back(ts);
rameOftrajectories[ts] = comp.rame_saine;
}
for(auto& ts : usSaneOldEmp)
{
swap_TrajectoryStop_after_TM(ts, comp.rame_critique, comp.rame_saine,false);
trajectories[comp.rame_critique].emplace_back(ts);
rameOftrajectories[ts] = comp.rame_critique;
}
rebuildDispVoiesRames(opToRebuild_crit, usSaneOldEmp);
rebuildDispVoiesRames(opToRebuild_sane, usCritOldEmp);
std::vector<unsigned int> modifTr;
modifTr.reserve(usCritOldEmp.size() + usSaneOldEmp.size());
modifTr.insert(modifTr.end(),usCritOldEmp.begin(), usCritOldEmp.end());
modifTr.insert(modifTr.end(),usSaneOldEmp.begin(), usSaneOldEmp.end());
//A retirer ça consomme beaucoup c'est pour mes teste pour être sur qu'il y a de la cohérance partout même après le swap
/*for(auto stop : trajectoryStops){
std::unordered_set<unsigned int> seen;
for(auto rame : stop.um_entree.ramesInfo){
if(seen.find(rame.id) != seen.end()){
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, "OK c'est a partir d'ici que ça par en couille!");
}
seen.insert(rame.id);
}
}*/
/*** Cherche si dans les trajectoryStop modifier il y a des possibilité de croisement avec des TrajectoryStop qui n'ont pas été modifié ***/
// std::vector<unsigned int> toAdd;
// for(auto& el : modifTr)
// {
// for(auto& cr : compUMs[el])
// {
// if(modifTrLookUp.find(cr) == modifTrLookUp.end())
// {
// toAdd.emplace_back(cr);
// }
// }
// }
// updateCrossedUM(modifTr, toAdd);
// updateCompUM(modifTr, toAdd);
}
}
inline void rebuildDispVoiesRames(std::vector<unsigned short>& opToRebuild, std::vector<unsigned int>& newTrajectory)
{
for (auto &op: opToRebuild) {
for (auto &TrStopID: newTrajectory) {
if(STFMockInstance::stops[trajectoryStops[TrStopID].entree]->getDispo().getDebutC().getRelativeDate() < jobs[op]->getPropositionExistante().afterDate.getRelativeDate())
continue;
for(unsigned int mid = 0; mid < STFMockInstance::machines.size(); ++mid)
{
auto siteTrack = STFMockInstance::siteTrackOfMachine[mid];
if(STFMockInstance::stops[trajectoryStops[TrStopID].entree]->getLieuxArret().getRef() == STFMockInstance::sites[siteTrack.first]->getRef()
&& STFMockInstance::infraComp[op][siteTrack.second]
&& (STFMockInstance::machines[mid]->getSpecificRame() == STFMockInstance::rames[STFMockInstance::rameOfOperations[op]]->getNumeroEF() || STFMockInstance::machines[mid]->getSpecificRame().empty()))
{
auto& d = trajectoryStops[TrStopID].getDispoStop();
auto match = CreneauHoraire::checkSlotsCompatibility(d, machines[mid]->getDispo());
if (match.first && match.second.second >= jobs[op]->getDureeDiag()) {
DispVoieRame disp;
disp.dispoVoie = mid;
disp.dispoRame = TrStopID;
disp.site = siteTrack.first;
disp.voie = siteTrack.second;
disp.op = op;
disp.rame = STFMockInstance::rameOfOperations[op];
disp.match = {match.second.first,
match.second.first + match.second.second};
jobDispoVoiesRames[op].emplace_back(dispoVoiesRames.size());
matches[disp.dispoVoie].emplace_back(dispoVoiesRames.size());
dispoVoiesRames.emplace_back(disp);
}
}
}
}
}
}
void checkSwapMinimumDate(unsigned short r, unsigned int &lastSwapEmpR,
std::unordered_map<unsigned short, Decision> &decisions) {
for (auto &sw: swaps) {
unsigned int s = sw->getSortieRame(r);
if (lastSwapEmpR < s) {
lastSwapEmpR = s;
}
}
for (auto &s: operationsOfRames[r]) {
if (decisions.find(s) != decisions.end() && !decisions[s].excluded) {
if (lastSwapEmpR <= decisions[s].lastCreneau.second)
lastSwapEmpR = decisions[s].lastCreneau.second;
}
}
}
void checkRecompoMinimumDate(unsigned short r, unsigned int &lastSwapEmpR, std::unordered_map<unsigned short, Decision> &decisions){
for(auto &rec : recompos){
unsigned int val_r = rec->getSortieRame(r);
if(lastSwapEmpR < val_r){
lastSwapEmpR = val_r;
}
}
for (auto &s: operationsOfRames[r]) {
if (decisions.find(s) != decisions.end() && !decisions[s].excluded) {
if (lastSwapEmpR <= decisions[s].lastCreneau.second)
lastSwapEmpR = decisions[s].lastCreneau.second;
}
}
}
bool is_swap_in_creux(unsigned int creux1, unsigned int creux2){
for(auto &sw: swaps){
if((sw->stopUMCrit.entree == creux1 && sw->stopUMSane.entree == creux2)||
(sw->stopUMCrit.entree == creux2 && sw->stopUMSane.entree == creux1)){
return true;
}
}
return false;
}
bool is_recompo_in_creux_critique(unsigned int creux){
for(auto &rec : recompos){
for(auto& traj : rec->stopRame_UMCrit){
if(traj.entree == creux){
return true;
}
}
}
return false;
}
bool is_recompo_in_creux_saine(unsigned int creux){
for(auto &rec : recompos){
for(auto& traj : rec->stopRame_UMSane){
if(traj.entree == creux){
return true;
}
}
}
return false;
}
bool is_recompo_in_creux(unsigned int creux_crite, unsigned int creux_sain){
for(auto &rec : recompos){
if((rec->stopRame_UMCrit[0].entree == creux_crite && rec->stopRame_UMSane[0].entree == creux_sain) ||
(rec->stopRame_UMCrit[0].entree == creux_sain && rec->stopRame_UMSane[0].entree == creux_crite)){
return true;
}
}
return false;
}
std::shared_ptr<RecompoUM> getRecompo(unsigned int creux1, unsigned int creux2){
for(auto &rec : recompos){
for(auto& traj : rec->stopRame_UMCrit){
if(traj.entree == creux1 || traj.entree == creux2){
return rec;
}
}
}
return nullptr;
}
std::vector<TrajectoryStop> getAllTrajectoryStops(unsigned int traj_fixed){
std::vector<TrajectoryStop> allTrajecoryStop;
for(unsigned int all_traj: TrajectoryStopsofTrajectoryUM[traj_fixed]){
allTrajecoryStop.push_back(trajectoryStops[all_traj]);
}
return allTrajecoryStop;
}
};
}
#endif
+71
View File
@@ -0,0 +1,71 @@
#include "Site.h"
namespace modellib {
Site::Site(const std::string &ref, const std::string &name, const std::string &gmao, unsigned int type, bool swap, bool recompo) {
m_ref = ref;
m_nameSlfrn = name;
m_typeSite = type;
m_gmaoOsmName = gmao;
m_swapAllowed = swap;
m_compAllowed = recompo;
}
nlohmann::json Site::to_json(bool withinfo) {
nlohmann::json gs = nlohmann::json::object();
gs["ref"] = getRef();
gs["nameOsm"] = getGmaoOsmName();
gs["nameSlfrn"] = getSlfrnName();
if(withinfo){
gs["allowSwap"] = getSwapEnabled();
gs["allowComp"] = getCompEnabled();
gs["typeSite"] = getType();
}
return gs;
}
Site Site::from_json(nlohmann::json& json)
{
Site ms;
ms.m_zone.first = false;
ms.m_zone.second = "";
if(json.contains("allowSwap"))
ms.setSwapEnabled(json["allowSwap"]);
else
ms.setSwapEnabled(true);
if(json.contains("allowComp"))
ms.setCompEnabled(json["allowComp"]);
else
ms.setCompEnabled(true);
if (json.contains("ref"))
ms.setRef(json["ref"]);
else if (json.contains("refSite"))
ms.setRef(json["refSite"]);
if (json.contains("nameOsm"))
ms.setGmaoOsmName(json["nameOsm"]);
if (json.contains("name"))
{
ms.setSlfrnName(json["name"]);
auto pos = ms.getSlfrnName().find('-');
if(pos != std::string::npos)
{
ms.m_zone.first = true;
ms.m_zone.second = ms.getSlfrnName().substr(0,pos);
}
}
if (json.contains("nameSlfrn"))
{
ms.setSlfrnName(json["nameSlfrn"]);
auto pos = ms.getSlfrnName().find('-');
if(pos != std::string::npos)
{
ms.m_zone.first = true;
ms.m_zone.second = ms.getSlfrnName().substr(0,pos);
}
}
ms.setType(json["typeSite"]);
return ms;
}
}
+114
View File
@@ -0,0 +1,114 @@
#ifndef SITE_H
#define SITE_H
#include <unordered_set>
#include <utility>
#include <vector>
#include <unordered_map>
#include <nlohmann/json.hpp>
namespace modellib {
/*! @file Site.h*/
/**
* @class Site
* @brief Classe dcrivant un site gnrique
* contient les informations communes tous les types de site (gare et maintenance)
*/
class Site {
private:
/**
* @brief Map indiquant la distance avec les autres sites
* Distance = poids => voir comment le traduire en temps
*/
//std::unordered_map<unsigned int, unsigned int> m_distance;
/*
* @brief la rfrence du site
*/
std::string m_ref;
std::string m_gmaoOsmName;//m_gmaoOsmName;
std::string m_nameSlfrn;//m_nameSlfrn
std::pair<bool, std::string> m_zone;
/*
* @brief le type de site (1 = technicentre, 2 = site dport, autre = site gare)
*/
unsigned int m_typeSite{};
bool m_swapAllowed;
bool m_compAllowed;
public:
/**
* @brief Constructeur par dfaut
*/
Site() = default;
Site(const std::string& ref, const std::string& name, const std::string& gmao, unsigned int type, bool swap=false, bool recompo=false);
/**
* @brief Destructeur. Ne fait rien
*/
virtual ~Site() = default;
/**
* @brief Getter simple par rfrence des distances
* @return la rfrence sur les distances
*/
//std::unordered_map<unsigned int, unsigned int>& getDistances() { return m_distance; };
/**
* @brief Setter simple de la rfrence
* @param ref la rfrence du site
*/
inline void setRef(const std::string &ref) { m_ref = ref; };
inline void setSwapEnabled(bool isE){m_swapAllowed = isE;};
inline bool getSwapEnabled(){return m_swapAllowed;};
inline void setCompEnabled(bool isE){m_compAllowed = isE;};
inline bool getCompEnabled(){return m_compAllowed;};
/**
* @brief Getter simple de la rfrence
* @return la rfrence du site
*/
[[nodiscard]] inline std::string getRef() const { return m_ref; };
[[nodiscard]] inline std::string getGmaoOsmName() const { return m_gmaoOsmName; };
[[nodiscard]] inline std::string getSlfrnName() const { return m_nameSlfrn; };
inline void setGmaoOsmName(const std::string &shortN) { m_gmaoOsmName = shortN; };
inline void setSlfrnName(const std::string &name) { m_nameSlfrn = name; };
/**
* @brief Setter simple du type de site
* @param type le type de site
*/
inline void setType(unsigned int type) { m_typeSite = type; };
inline void setZone(bool exists, std::string name){ m_zone = {exists, name};};
inline std::pair<bool, std::string> getZone(){return m_zone;};
/**
* @brief Getter simple du type de site
* @return le type de site
*/
[[nodiscard]] inline unsigned int getType() const { return m_typeSite; };
nlohmann::json to_json(bool withinfo=false);
static Site from_json(nlohmann::json& json);
};
}
#endif
+24
View File
@@ -0,0 +1,24 @@
#include "TrajectoryStop.hpp"
#include "STFMockInstance.hpp"
namespace modellib {
nlohmann::json TrajectoryStop::to_json(bool verbose) const {
nlohmann::json er = nlohmann::json::object();
er["site"]["ref"] = STFMockInstance::stops[entree]->getLieuxArret().getRef();
er["site"]["nameSlfrn"] = STFMockInstance::stops[entree]->getLieuxArret().getSlfrnName();
er["site"]["gmaoOsmName"] = STFMockInstance::stops[entree]->getLieuxArret().getGmaoOsmName();
er["periode"] = dispoStop.to_json();
if (verbose) {
//er["um"] = entree->getEFUM();//todo change pour la vraie um d'entrée de sortie effective, pareil pour la ligne
er["ligne"] = STFMockInstance::stops[entree]->getLigne();
}
er["numTrain"] = STFMockInstance::stops[entree]->getNumTrain();//pour le tri il faudra différencier le numéro de train en entrée et en sortie je pense
std::string precision = !typeDispo.second.empty() ? " : " : "";
er["motif"] = EmplacementRame::smapTypeStops[typeDispo.first] + precision + typeDispo.second;
return er;
}
/*CreneauHoraire TrajectoryStop::getDispoStop() const {
return dispoStop;//{STFMockInstance::stops[entree]->getDispo().getDebut(), STFMockInstance::stops[sortie]->getDispo().getFin()};
}*/
}
+81
View File
@@ -0,0 +1,81 @@
#ifndef ORDONNANCEMENTCORRECTIF_TRAJECTORYSTOP_HPP
#define ORDONNANCEMENTCORRECTIF_TRAJECTORYSTOP_HPP
#include "CreneauHoraire.h"
#include "EmplacementRame.h"
#include "UM.h"
namespace modellib {
/**
* @class TrajectoryStop
* @brief Class defining an arrival and a departure of a station
*/
class TrajectoryStop {
public:
/**
* @brief The site
*/
Site* lieuArret{};
/**
* @brief The type of availability (informative data).
*/
std::pair<typeStop, std::string> typeDispo;
/**
* @brief Index of the rdv in RDV vector
*/
unsigned int rdvPreventif;
/**
* @brief Information of the other train of the multiple unit if it is one
*/
UM um_entree;
UM um_sortie;
/**
* @brief The timeslot of arrival (only the arrival will be used in this wrapper class) - uses the underlying constant data of the instance.
*/
unsigned int entree = 0;
/**
* @brief The timeslot of departure (only the departure will be used in this wrapper class)
*/
unsigned int sortie = 0;
CreneauHoraire dispoStop;
TrajectoryStop() = default;
/**
* @brief Function to get the effective timeslot of the stop (arrival, departure)
* @return a timeslot corresponding to the arrival and departure of the train to and from the site
*/
[[nodiscard]] inline const CreneauHoraire& getDispoStop() const{return dispoStop;};
inline void setSortie(unsigned int s, SolverDate& endDispoStop){
sortie = s;
dispoStop.setFin(endDispoStop);
}
inline void setDispoStop(const SolverDate& b, const SolverDate& e){
dispoStop.setDebut(b);
dispoStop.setFin(e);
}
inline bool operator==(const TrajectoryStop &ts) const {
return entree == ts.entree && sortie == ts.sortie;
}
inline bool operator!=(const TrajectoryStop &ts) const {
return entree != ts.entree || sortie != ts.sortie;
}
/**
* @brief Function to translate the object into json format
* @param verbose a boolean to indicate if we want every info or just the essential
* @return a json description of the object
*/
[[nodiscard]] nlohmann::json to_json(bool verbose) const;
};
}
#endif //ORDONNANCEMENTCORRECTIF_TRAJECTORYSTOP_HPP
+17
View File
@@ -0,0 +1,17 @@
#include "TypeInfrastructure.h"
namespace modellib {
nlohmann::json TypeInfrastructure::to_json() {
nlohmann::json typeInfra = nlohmann::json::object();
typeInfra["typeInfraName"] = m_infrastructureType;
typeInfra["id"] = m_idInfra;
return typeInfra;
}
TypeInfrastructure TypeInfrastructure::from_json(nlohmann::json &json) {
TypeInfrastructure type;
type.m_idInfra = json["id"];
type.m_infrastructureType = json["typeInfraName"];
return type;
}
}
+75
View File
@@ -0,0 +1,75 @@
#ifndef TYPEINFRASTRUCTURE
#define TYPEINFRASTRUCTURE
#include <iostream>
#include <string>
#include <vector>
#include <nlohmann/json.hpp>
namespace modellib {
/*! @file TypeInfrastructure.h*/
/**
* @class TypeInfrastructure
* @brief Classe dcrivant un type d'infrastructure
*/
class TypeInfrastructure {
private:
/**
* @brief identifiant unique de l'infrastructure => pas utilis ?
*/
unsigned int m_idInfra{};
/**
* @brief Type/Nom de l'infrastructure (unique)
*/
std::string m_infrastructureType;
public:
/**
* @brief Constructeur par dfaut
*/
TypeInfrastructure() = default;
/**
* @brief Destructeur. Ne fait rien
*/
virtual ~TypeInfrastructure() = default;
/**
* @brief Getter simple sur l'identifiant
* @return l'identifiant de l'infrastructure
*/
[[nodiscard]] unsigned int getId() const { return m_idInfra; };
void setId(unsigned int id) { m_idInfra = id; };
/**
* @brief Getter simple sur le nom/type de l'infrastructure
* @return le nom/type de l'infrastructure
*/
std::string getInfraType() { return m_infrastructureType; };
void setInfraType(std::string& infra){m_infrastructureType = infra;};
/**
* @brief Fonction interface de traduction de l'objet TypeInfrastructure vers un objet JSON
* @return le json dcrivant le type d'infrastructure
*/
nlohmann::json to_json();
/**
* @brief Fonction interface de traduction de l'objet JSON vers un objet TypeInfrastructure
* @param json le JSON dcrivant un type d'infrastructure
* @return l'instance de la classe TypeInfrastructure correspondant l'objet JSON d'entre
*/
static TypeInfrastructure from_json(nlohmann::json &json);
inline bool operator==(const TypeInfrastructure& inf) const
{
return inf.m_infrastructureType == m_infrastructureType;
}
};
}
#endif
+13
View File
@@ -0,0 +1,13 @@
#include "UM.h"
#include "STFMockInstance.hpp"
namespace modellib {
bool UM::find(const std::string &r) const {
return std::find_if(ramesInfo.begin(), ramesInfo.end(), [&](auto& rc){return STFMockInstance::rames[rc.id]->getNumeroEF() == r;}) != ramesInfo.end();
}
nlohmann::json UM::to_json(){
nlohmann::json json = nlohmann::json::object();
//json["numTrain"] = lignes;
return json;
}
}
+62
View File
@@ -0,0 +1,62 @@
#ifndef UM_H
#define UM_H
//#include "Rame.h"
#include <string>
#include <vector>
#include <algorithm>
#include <climits>
#include "nlohmann/json.hpp"
namespace modellib {
#define NULL_RAME 10000
struct RameUMInformation{
unsigned short id;
unsigned short rang;
std::string ligne;
bool operator==(const RameUMInformation& other)const{
return id == other.id;
}
bool operator==(const unsigned short& other)const{
return id == other;
}
bool operator==(const unsigned int& other)const{
return id == other;
}
};
class UM {
public:
std::vector<RameUMInformation> ramesInfo;
UM() = default;
[[nodiscard]] inline bool find(unsigned short r) const{
return std::find(ramesInfo.begin(), ramesInfo.end(), r) != ramesInfo.end();
}
bool find(const std::string& r) const;
inline bool operator==(const UM& other) const{return ramesInfo == other.ramesInfo;};
inline bool operator!=(const UM& other) const{return !(ramesInfo == other.ramesInfo);};
/**
* @brief Function to replace r1 by r2 in the multiple unit
* @param r1 the first rame
* @param r2 the second rame
* @return true if the replacement was done, false otherwise
* @warning ne change pas les lignes pour l'instant à prendre en compte lorsque la structure sera créé
*/
bool swap(unsigned short r1, unsigned short r2){
auto it = std::find(ramesInfo.begin(), ramesInfo.end(), r1);
if(it != ramesInfo.end()){
(*it).id = r2;
return true;
}
return false;
}
nlohmann::json to_json();
};
}
#endif
+39
View File
@@ -0,0 +1,39 @@
#include "Voie.h"
#include "TypeInfrastructure.h"
namespace modellib {
//std::unordered_set<int> Voie::ids;
nlohmann::json Voie::to_json(bool withinfo) {
nlohmann::json voie = nlohmann::json::object();
voie["id"] = m_idVoie;
if (withinfo) {
voie["periodeDisponible"] = nlohmann::json::array();
for (auto & i : m_periodesDisponibilite) {
voie["periodeDisponible"].push_back(i.to_json());
}
voie["infrastructures"] = nlohmann::json::array();
for (auto & m_infrastructure : m_infrastructures) {
voie["infrastructures"].push_back(m_infrastructure.to_json());
}
}
return voie;
}
Voie Voie::from_json(nlohmann::json &json) {
Voie voie;
if(json["id"].is_number())
voie.setId(std::to_string(json["id"].get<unsigned int>()));
else
voie.setId(json["id"].get<std::string>());
for (nlohmann::json &infra: json["infrastructures"]) {
voie.m_infrastructures.push_back(TypeInfrastructure::from_json(infra));
}
for (nlohmann::json &dispo: json["periodesDisponible"]) {
voie.m_periodesDisponibilite.push_back(EmplacementVoie::from_json(dispo));
}
for (nlohmann::json &dispo: json["periodeDisponible"]) {
voie.m_periodesDisponibilite.push_back(EmplacementVoie::from_json(dispo));
}
return voie;
}
}
+100
View File
@@ -0,0 +1,100 @@
#ifndef VOIE_H
#define VOIE_H
#include <iostream>
#include <vector>
#include <unordered_set>
#include "EmplacementVoie.h"
#include "TypeInfrastructure.h"
namespace modellib {
/*! @file Voie.h*/
/**
* @class Voie
* @brief Classe dcrivant une voie
*/
class Voie {
private:
//static std::unordered_set<int> ids;
/**
* @brief identifiant de la voie : unique
*/
std::string m_idVoie{};
/**
* @brief Vecteur contenant les priodes de disponibilits de la voie
*/
std::vector<EmplacementVoie> m_periodesDisponibilite;
/**
* @brief Vecteur contenant les infrastructures disponibles sur la voies
*/
std::vector<TypeInfrastructure> m_infrastructures;
public:
/**
* @brief Constructeur par dfaut
*/
Voie() = default;
explicit Voie(std::string id):m_idVoie(id){};
/**
* @brief Destructeur, ne fait rien
*/
virtual ~Voie() = default;
/**
* @brief Getter simple sur l'identifiant
* @return l'identifiant de la voie
*/
[[nodiscard]] inline std::string getId() const { return m_idVoie; };//todo passer en string
/**
* @brief Setter simple sur l'identifiant
* @param id le nouvel identifiant
* @return NEANT
*/
inline void setId(std::string id) {
/*auto f = ids.find(id);
while (f != ids.end()) {
id += ids.size();
f = ids.find(id);
}*/
m_idVoie = id;
//ids.insert(m_idVoie);
};
/**
* @brief Getter simple par rfrense sur les disponibilits
* @return la liste des priodes o la voie est disponible
*/
inline std::vector<EmplacementVoie> &getDisponibilites() { return m_periodesDisponibilite; };
/**
* @brief Getter simple par rfrence sur les infrastructures
* @return la liste des infrastructures que la voie possde
*/
inline std::vector<TypeInfrastructure> &getInfrastructures() { return m_infrastructures; };
/**
* @brief Fonction interface de traduction de l'objet Voie vers un objet JSON
* @param withinfo boolen indiquant le niveau de redondance des donnes
* Si withinfo == false l'unique information restante sera l'identifiant de la voie
* @return le json dcrivant la voie
*/
nlohmann::json to_json(bool withinfo = true);
/**
* @brief Fonction interface de traduction de l'objet JSON vers un objet Voie
* @param json le JSON dcrivant une voie
* @return l'instance de la classe Voie correspondant l'objet JSON d'entre
*/
static Voie from_json(nlohmann::json &json);
/*static void clearIds() {
ids.clear();
}*/
};
}
#endif
@@ -0,0 +1,308 @@
#include "Generator.hpp"
#include <random>
#include <string>
#include "../../General/Logs/IOHelper.h"
namespace insgenlib {
using namespace modellib;
using namespace configlib;
using namespace loggerlib;
//#define WH1 std::exp(6)
#define WH1D 6
//#define WH2 std::exp(5)
#define WH2D 3
//#define WH3 std::exp(4)
#define WH3D 1
static unsigned int countVoie = 0;
static unsigned int countOp = 0;
Generator::Generator() : m_instance(nullptr) {
std::random_device rd;
std::seed_seq seed{rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd()};
m_randomGenerator.seed(seed);
}
void Generator::initLoggers() {
for (auto &fileLog: Configuration::Logs.GENERATOR_FILE_LOGGERS) {
auto *l = new FileLogger(fileLog.filename, fileLog.showType, fileLog.jsonFormat, fileLog.types);
for (unsigned int type: fileLog.types) {
FileLogger::addLogger((ELOGGER_TYPES) type, l);
}
}
}
std::vector<nlohmann::json> Generator::generateInstances() {
SolverDate dateDebut = SolverDate::todayObjFormat();
std::vector<nlohmann::json> generatedInstances;
std::vector<std::pair<std::string,STFInstance*>> batching;
unsigned int nbBatch = 0;
for (auto &s: Configuration::Generator.NB_SITES_MAINTENANCE) {
for (auto &v: Configuration::Generator.NB_VOIES) {
for (auto &r: Configuration::Generator.NB_RAMES) {
for (unsigned int i = 0; i < Configuration::Generator.NB_INSTANCES_TO_GENERATE; ++i) {
countOp = 0;
countVoie = 0;
m_instance = new STFInstance();
m_instance->setDateDebutPlanification(dateDebut);
std::string n = std::to_string(i);
m_instance->setIdStf(n);
generateData(s, v, r);
Logger::systemNotify(LOGGER_INFO, "Instance " + std::to_string(i) + " of type : ");
Logger::systemNotify(LOGGER_INFO, std::to_string(s) + " sites");
Logger::systemNotify(LOGGER_INFO, std::to_string(v) + " voies par site");
Logger::systemNotify(LOGGER_INFO, std::to_string(r) + " rames/operations");
Logger::systemNotify(LOGGER_INFO, "has been generated");
std::string filename = std::to_string(s) + "_" + std::to_string(v) + "_" + std::to_string(r) + "_" + std::to_string(i) + ".json";
if(batching.size() + 1 > Configuration::Generator.MAX_BATCH_SIZE)
{
for(auto& ins : batching)
{
IOHelper::dump(Configuration::Global.INPUT_LOCATION + "/batch_" + std::to_string(nbBatch), ins.second->to_json().dump(2), ins.first);
delete ins.second;
}
batching.clear();
nbBatch++;
}
batching.emplace_back(filename,m_instance);
}
}
}
}
if(!batching.empty())
{
for(auto& ins : batching)
{
IOHelper::dump(Configuration::Global.INPUT_LOCATION + "/batch_" + std::to_string(nbBatch), ins.second->to_json().dump(2), ins.first);
delete ins.second;
}
batching.clear();
nbBatch++;
}
return generatedInstances;
}
void Generator::generateRames(unsigned int nbsite, unsigned int nbrame) {
std::binomial_distribution<unsigned int> randSeverite(1, 0.2);
for (unsigned int r = 0; r < nbrame; ++r) {
Rame rame;
rame.setNumeroEF("EF" + std::to_string(r));
rame.setId(r);
if (r >= nbrame * Configuration::Generator.PROPORTION_RAME_SAINE) {
unsigned int severite = randSeverite(m_randomGenerator);
generateOperations(rame, severite);
}
generateDisposRames(rame, nbsite);
m_instance->getRames().push_back(rame);
}
}
void Generator::generateSites(unsigned int nbsite, unsigned int nbvoie) {
std::vector sitevoieVec(nbsite, 0);
std::uniform_int_distribution<unsigned int> distVoieOnSite(0, nbsite-1);
for(unsigned int v = 0; v < nbvoie; ++v)
{
sitevoieVec[distVoieOnSite(m_randomGenerator)]++;
}
for (unsigned int s = 0; s < nbsite; ++s) {
MaintenanceSite site("ref" + std::to_string(s), "ref" + std::to_string(s),"ref" + std::to_string(s), 1);
/*if (s == 0)
generateVoies(site, nbVoieSitePrincipal);
else
generateVoies(site, nbVoieSiteDeporte);*/
generateVoies(site, sitevoieVec[s]);
//generateCapacitesSites(site);
m_instance->getSitesMaintenance().push_back(site);
}
}
void Generator::generateData(unsigned int nbsite, unsigned int nbvoie, unsigned int nbrame) {
generateSites(nbsite, nbvoie);
generateRames(nbsite, nbrame);
}
void Generator::generateVoies(MaintenanceSite &site, unsigned int nbvoie) {
std::uniform_int_distribution<unsigned int> randInfraNb(1, Configuration::Generator.NB_INFRA_TOTAL);
for (unsigned int v = 0; v < nbvoie; ++v) {
Voie voie;
voie.setId(std::to_string(countVoie));
++countVoie;
unsigned int nbInf = randInfraNb(m_randomGenerator);
std::vector<unsigned int> doublons;
for (unsigned int i = 0; i < nbInf; ++i) {
TypeInfrastructure infra = generateInfrastructure(doublons);
doublons.push_back(infra.getId() - 1);
voie.getInfrastructures().push_back(infra);
}
generateDisposVoies(voie);
site.getVoies().push_back(voie);
}
}
void Generator::generateDisposRames(Rame &rame, unsigned int nbsite) {
std::uniform_int_distribution<unsigned int> randDurationDisp(
Configuration::Generator.PLAGE_DUREE_DISPO_RAME.first,
Configuration::Generator.PLAGE_DUREE_DISPO_RAME.second);
std::uniform_int_distribution<unsigned int> randSiteId(0, nbsite - 1);
std::uniform_int_distribution<unsigned int> randEcart(Configuration::Generator.PLAGE_ECART_DISPO_RAME.first,
Configuration::Generator.PLAGE_ECART_DISPO_RAME.second);
unsigned int ecart = randEcart(m_randomGenerator);
unsigned int lastEnd = 0;
unsigned int H = (m_instance->getDateDebutPlanification() +
Configuration::Solver.NB_DAYS_TO_PLANIF * 24 * Configuration::Global.TIME_UNIT) -
m_instance->getDateDebutPlanification();
while (lastEnd < H) {
unsigned int duree = randDurationDisp(m_randomGenerator);
unsigned int siteId = randSiteId(m_randomGenerator);
SolverDate debutD = m_instance->getDateDebutPlanification() + lastEnd + ecart;
SolverDate end = m_instance->getDateDebutPlanification() +
(lastEnd + ecart + duree * Configuration::Global.TIME_UNIT);
lastEnd = end - m_instance->getDateDebutPlanification();
CreneauHoraire periode(debutD, end);
EmplacementRame dispo(m_instance->getSitesMaintenance()[siteId], periode);
rame.getCreuxRoulement().push_back(dispo);
}
}
void Generator::generateDisposVoies(Voie &voie) {
/*unsigned int nbDispo = Configuration::Solver.NB_DAYS_TO_PLANIF * 2; //randNBDispo(gen);
unsigned int offset = 0;
for (unsigned int d = 0; d < nbDispo; ++d) {
SolverDate debutD = m_instance->getDateDebutPlanification() + offset;
SolverDate end = m_instance->getDateDebutPlanification() + (offset + 12 * Configuration::Global.TIME_UNIT);
offset += 12 * Configuration::Global.TIME_UNIT;
CreneauHoraire periode(debutD, end);
EmplacementVoie dispo(periode, "");
voie.getDisponibilites().push_back(dispo);
}
std::uniform_int_distribution<unsigned int> randNbRDV(Configuration::Generator.PLAGE_NB_INDISPO_VOIE.first,
Configuration::Generator.PLAGE_NB_INDISPO_VOIE.second);
std::uniform_int_distribution<unsigned int> randDispConcernee(0, (Configuration::Solver.NB_DAYS_TO_PLANIF * 2) -
1);
unsigned int nbRDV = randNbRDV(m_randomGenerator);
for (unsigned int i = 0; i < nbRDV; ++i) {
std::uniform_int_distribution<unsigned int> randDispConcerneeL(0, (Configuration::Solver.NB_DAYS_TO_PLANIF *
2) - 1 - i);
unsigned int dispRDV = randDispConcerneeL(m_randomGenerator);
//voir pour sparer les rdv (spcifique aux rames) et les dispo supprimes. Pour le moment supprime juste les dispo selon les rdv
voie.getDisponibilites().erase(voie.getDisponibilites().begin() + dispRDV);
}*/
std::uniform_int_distribution<unsigned int> randDurationDisp(8,24);
std::uniform_int_distribution<unsigned int> randEcart(2,
24);
unsigned int ecart = randEcart(m_randomGenerator);
unsigned int lastEnd = 0;
unsigned int H = (m_instance->getDateDebutPlanification() +
Configuration::Solver.NB_DAYS_TO_PLANIF * 24 * Configuration::Global.TIME_UNIT) -
m_instance->getDateDebutPlanification();
while (lastEnd < H) {
unsigned int duree = randDurationDisp(m_randomGenerator);
SolverDate debutD = m_instance->getDateDebutPlanification() + lastEnd + ecart;
SolverDate end = m_instance->getDateDebutPlanification() +
(lastEnd + ecart + duree * Configuration::Global.TIME_UNIT);
lastEnd = end - m_instance->getDateDebutPlanification();
CreneauHoraire periode(debutD, end);
EmplacementVoie dispo(periode, "");
voie.getDisponibilites().push_back(dispo);
}
}
void Generator::generateOperations(Rame &rame, unsigned int severite) {
std::uniform_int_distribution<unsigned int> randH1W(20,30);
std::uniform_int_distribution<unsigned int> randH2W(5,10);
std::uniform_int_distribution<unsigned int> randH3W(1,3);
/*std::uniform_int_distribution<unsigned int> randNbOp(
Configuration::Generator.PLAGE_NB_OPERATION_RAME[severite].first,
Configuration::Generator.PLAGE_NB_OPERATION_RAME[severite].second);*/
std::binomial_distribution<unsigned int> randHierarchie(2, 0.70);
std::uniform_real_distribution<double> randDurationDiag(
Configuration::Generator.PLAGE_PROPORTION_DUREE_DIAG.first,
Configuration::Generator.PLAGE_PROPORTION_DUREE_DIAG.second);
unsigned int nbOp = 1;//randNbOp(m_randomGenerator);
for (unsigned int o = 0; o < nbOp; ++o) {
OperationRequise sig;
unsigned int h = randHierarchie(m_randomGenerator) + 1;
std::uniform_int_distribution<unsigned int> randDuration(
Configuration::Generator.PLAGE_DUREE_OP[h - 1].first,
Configuration::Generator.PLAGE_DUREE_OP[h - 1].second);
unsigned int wr = 0;
unsigned int wd = 0;
switch (h) {
case 1:
wr = randH1W(m_randomGenerator);
wd = WH1D;
break;
case 2:
wr = randH2W(m_randomGenerator);
wd = WH2D;
break;
case 3:
wr = randH3W(m_randomGenerator);
wd = WH3D;
break;
default:
break;
}
sig.setPoidsRejet(wd);
sig.setPoidsRetard(wr);
std::string strop = std::to_string(countOp);
sig.setOpId(strop);
std::bernoulli_distribution bd(0.25);
sig.getInfrastructures().push_back(generateInfrastructure({}));
sig.setPoidsRejetDefaut(wd);
sig.setPoidsRetardDefaut(wr);
sig.setDiagnosticPossible(true);
sig.setCodeDefaut("codeDefaut" + std::to_string(countOp));
sig.setHierarchie(h);
unsigned int d = randDuration(m_randomGenerator);
unsigned int ddiag = ceil(d * randDurationDiag(m_randomGenerator));
sig.setDuree(d);
sig.setDureeDiag(ddiag);
sig.setDateDue(m_instance->getDateDebutPlanification() + h * 24 * Configuration::Global.TIME_UNIT);
sig.setIdRame(rame.getId());
sig.setNumeroEF(rame.getNumeroEF());
rame.getSignalements().push_back(sig);
countOp++;
}
}
TypeInfrastructure Generator::generateInfrastructure(std::vector<unsigned int> excluded) {
//std::uniform_int_distribution<unsigned int> randInfraNb(1, Configuration::Generator.NB_INFRA_TOTAL);
std::vector<unsigned int> weight;
for (unsigned int i = 0; i < Configuration::Generator.NB_INFRA_TOTAL; ++i) {
if (std::find(excluded.begin(), excluded.end(), i) == excluded.end()) {
weight.push_back(1);
} else {
weight.push_back(0);
}
}
std::discrete_distribution<int> excludedDist(weight.begin(), weight.end());
unsigned int nbInf = excludedDist(m_randomGenerator) + 1;
TypeInfrastructure type;
std::string name = "infra" + std::to_string(nbInf);
type.setInfraType(name);
type.setId(nbInf);
return type;
}
}
@@ -0,0 +1,43 @@
#ifndef GENERATOR_HPP
#define GENERATOR_HPP
#include <string>
#include <nlohmann/json.hpp>
#include <vector>
#include <random>
#include "../../General/Logs/Loggers/FileLogger.h"
#include "../../General/Configuration/Configurations.h"
#include "../../General/Model/STFInstance.h"
namespace insgenlib {
using namespace modellib;
class Generator {
private:
STFInstance *m_instance;
std::mt19937 m_randomGenerator;
void generateRames(unsigned int nbsite, unsigned int nbrame);
void generateSites(unsigned int nbsite, unsigned int nbvoie);
void generateData(unsigned int nbsite, unsigned int nbvoie, unsigned int nbrame);
void generateVoies(MaintenanceSite &site, unsigned int nbvoie);
void generateDisposRames(Rame &rame, unsigned int nbsite);
void generateDisposVoies(Voie &voie);
void generateOperations(Rame &rame, unsigned int severite);
TypeInfrastructure generateInfrastructure(std::vector<unsigned int> excluded);
public:
Generator();
static void initLoggers();
std::vector<nlohmann::json> generateInstances();
};
}
#endif
@@ -0,0 +1,781 @@
#include "GeneratorRecompo.hpp"
#include <algorithm>
#include <filesystem>
#include <fstream>
#include <ios>
#include <random>
#include <queue>
#include <string>
#include <list>
#include <vector>
#include "../../General/Logs/IOHelper.h"
namespace insgenlib {
using namespace modellib;
using namespace loggerlib;
using namespace configlib;
#define WH1D 6
#define WH2D 3
#define WH3D 1
static unsigned int countVoie = 0;
static unsigned int countOp = 0;
GeneratorRecompo::GeneratorRecompo() : m_instance(nullptr) {
std::random_device rd;
std::seed_seq seed{rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd()};
m_randomGenerator.seed(seed);
}
void GeneratorRecompo::initLoggers() {
for (auto &fileLog: Configuration::Logs.GENERATOR_FILE_LOGGERS) {
FileLogger *l = new FileLogger(fileLog.filename, fileLog.showType, fileLog.jsonFormat, fileLog.types);
for (unsigned int type: fileLog.types) {
FileLogger::addLogger((ELOGGER_TYPES) type, l);
}
}
for(auto& sLogger : configlib::Configuration::Logs.ORDO_STREAM_LOGGERS)
{
auto lcout = new loggerlib::StreamLogger(sLogger.outstream, sLogger.showType, sLogger.jsonFormat, sLogger.types);
for(auto t : sLogger.types)
{
loggerlib::StreamLogger::addLogger((loggerlib::ELOGGER_TYPES) t, lcout);
}
}
}
std::vector<nlohmann::json> GeneratorRecompo::generateInstances() {
SolverDate dateDebut = SolverDate::todayObjFormat();
auto listFile = std::ofstream(Configuration::Global.INPUT_LOCATION + "/instanceslist.batch", std::ios::trunc);
multi_op = Configuration::Generator.MULTI_OP_INSTANCE;
std::vector<nlohmann::json> generatedInstances;
std::list<std::pair<std::string,STFInstance*>> batching;
unsigned int nbBatch = 0;
for (auto &s: Configuration::Generator.NB_SITES_MAINTENANCE) {
for (auto &sg: Configuration::Generator.NB_SITES_GARE) {
for (auto &v: Configuration::Generator.NB_VOIES) {
for (auto &r: Configuration::Generator.NB_RAMES) {
for (auto &j: Configuration::Generator.NB_JOBS) {
if(!(r < j && !multi_op))
{
for (unsigned int i = 0; i < Configuration::Generator.NB_INSTANCES_TO_GENERATE; ++i) {
countOp = 0;
countVoie = 0;
Logger::systemNotify(LOGGER_INFO, "Instance " + std::to_string(i) + " of type : ");
Logger::systemNotify(LOGGER_INFO, std::to_string(s) + " sites");
Logger::systemNotify(LOGGER_INFO, std::to_string(v) + " voies par site");
Logger::systemNotify(LOGGER_INFO, std::to_string(r) + " rames/operations");
Logger::systemNotify(LOGGER_INFO, "has been generated");
std::string filename = std::to_string(s) + "_" + std::to_string(sg) + "_" +
std::to_string(v) + "_" + std::to_string(r) + "_" +
std::to_string(j) + "_" + std::to_string(i) + ".json";
std::cout << "Generating: " << filename << std::endl;
m_instance = new STFInstance();
m_instance->setDateDebutPlanification(dateDebut);
std::string n = std::to_string(i);
m_instance->setIdStf(n);
generateData(s, sg, v, r, j);
if(batching.size() + 1 > Configuration::Generator.MAX_BATCH_SIZE)
{
for(auto& ins : batching)
{
IOHelper::dump(Configuration::Global.INPUT_LOCATION + "/batch_" + std::to_string(nbBatch), ins.second->to_json().dump(), ins.first);
auto list = std::ofstream(Configuration::Global.INPUT_LOCATION + "/instanceslist.batch", std::ios::app);
if(list)
{
list << std::filesystem::current_path().string() + "/" + Configuration::Global.INPUT_LOCATION + "/batch_" + std::to_string(nbBatch) + "/" + ins.first << std::endl;
list.close();
}
delete ins.second;
}
batching.clear();
nbBatch++;
}
batching.emplace_back(filename,m_instance);
}
}
}
}
}
}
}
if(!batching.empty())
{
for(auto& ins : batching)
{
IOHelper::dump(Configuration::Global.INPUT_LOCATION + "/batch_" + std::to_string(nbBatch), ins.second->to_json().dump(), ins.first);
delete ins.second;
}
batching.clear();
nbBatch++;
}
return generatedInstances;
}
void GeneratorRecompo::generateService(unsigned int nbsites, unsigned int nbsitesGares, std::vector<UM2> ums) {
std::string imp = IMPERATIVE;
std::string not_imp = NOT_IMPERATIVE;
if (!ums.empty())
{
std::uniform_int_distribution<unsigned int> randDurationDisp(
Configuration::Generator.PLAGE_DUREE_DISPO_RAME.first,
Configuration::Generator.PLAGE_DUREE_DISPO_RAME.second);
std::uniform_int_distribution<unsigned int> randDurationDispGare(
Configuration::Generator.PLAGE_DUREE_DISPO_RAME_GARE.first,
Configuration::Generator.PLAGE_DUREE_DISPO_RAME_GARE.second);
std::uniform_int_distribution<unsigned int> randSiteId(0, nbsites - 1);
std::uniform_int_distribution<unsigned int> randSiteIdStation(nbsites, nbsites + nbsitesGares-1);
std::bernoulli_distribution siteTypeDist(0.25);
std::bernoulli_distribution siteMaxMinDist(0.5);
std::bernoulli_distribution rdvImperatif(0.2);//1/5 que le rdv soit imperatif
/*std::uniform_int_distribution<unsigned int> randEcart(Configuration::Generator.PLAGE_ECART_DISPO_RAME.first,
Configuration::Generator.PLAGE_ECART_DISPO_RAME.second);*/
std::uniform_int_distribution<unsigned int> randEcartGare(
Configuration::Generator.PLAGE_ECART_DISPO_RAME_GARE.first,
Configuration::Generator.PLAGE_ECART_DISPO_RAME_GARE.second);
unsigned int lastEnd;
unsigned int H = (m_instance->getDateDebutPlanification() +
Configuration::Solver.NB_DAYS_TO_PLANIF * 24 * Configuration::Global.TIME_UNIT) -
m_instance->getDateDebutPlanification();
std::queue<UM2, std::deque<UM2>> umsToProcess(std::deque<UM2>(ums.begin(), ums.end()));
while (!umsToProcess.empty()) {
while (!umsToProcess.empty()) {
auto &u = umsToProcess.front();
lastEnd = 0;
if(!u.uss[0]->getCreuxRoulement().empty())
{
lastEnd = u.uss[0]->getCreuxRoulement().back().getDispo().getFinC().getRelativeDate();
}
bool typeSite;
do {
typeSite = siteTypeDist(m_randomGenerator);
unsigned int idSite = randSiteIdStation(m_randomGenerator);
if (typeSite) {
idSite = randSiteId(m_randomGenerator);
}
unsigned int ecart = randEcartGare(
m_randomGenerator);//randEcart(m_randomGenerator) * typeSite + !typeSite *
unsigned int duree = randDurationDisp(m_randomGenerator) * typeSite +
!typeSite * randDurationDispGare(m_randomGenerator);
SolverDate debutD = m_instance->getDateDebutPlanification() + lastEnd + ecart;
SolverDate end = m_instance->getDateDebutPlanification() +
(lastEnd + ecart + duree * Configuration::Global.TIME_UNIT);
lastEnd = end - m_instance->getDateDebutPlanification();
CreneauHoraire periode(debutD, end);
if (typeSite) {
EmplacementRame dispo(m_instance->getSitesMaintenance()[idSite], periode);
dispo.setImperative(not_imp);
for (auto &r: u.uss) {
std::vector<RameInformation> umR;
unsigned short idx = 1;
for (auto &r2: u.uss) {
if(r2 == r ){
dispo.setRang(idx);
}
if (r2 != r) {
umR.emplace_back(r2->getNumeroEF(), "l0", idx);
}
idx++;
}
dispo.setUM(umR);
r->getCreuxRoulement().push_back(dispo);
}
} else {
EmplacementRame dispo(m_instance->getSites()[idSite-nbsites], periode);
dispo.setImperative(not_imp);
for (auto &r: u.uss) {
std::vector<RameInformation> umR;
unsigned short idx = 1;
for (auto &r2: u.uss) {
if(r2 == r ){
dispo.setRang(idx);
}
if (r2 != r) {
umR.emplace_back(r2->getNumeroEF(), "l0",idx);
}
idx++;
}
dispo.setUM(umR);
r->getCreuxRoulement().push_back(dispo);
}
}
} while (!typeSite &&
lastEnd < H);//(lastEnd < H);//!typeSite && dans le cas ou on peut recomposer??
umsToProcess.pop();
}
std::vector<std::vector<Rame *>> pool;
EmplacementRame *currentCr = nullptr;
std::unordered_set<Rame *> setPooled;
while (setPooled.size() != m_instance->getRames().size()) {
pool.emplace_back();
for (auto &r: m_instance->getRames()) {
if (setPooled.find(&r) == setPooled.end()) {
if (currentCr == nullptr)
currentCr = &r.getCreuxRoulement().back();
if (r.getCreuxRoulement().back().getDispo().getFinC().getRelativeDate() < H
&& CreneauHoraire::checkCommonDuration(r.getCreuxRoulement().back().getDispo(),
currentCr->getDispo(), 120) && r.getCreuxRoulement().back().getLieuxArret().getRef() == currentCr->getLieuxArret().getRef()) {
pool.back().push_back(&r);
setPooled.insert(&r);
}
if(r.getCreuxRoulement().back().getDispo().getFinC().getRelativeDate() >= H)
setPooled.insert(&r);
}
}
currentCr = nullptr;
}
for (auto &p: pool) {
std::vector<unsigned int> weight(p.size(), 1);
std::discrete_distribution<unsigned int> umSizeR({15, 75, 10});
while (weight != std::vector<unsigned int>(p.size(), 0)) {
unsigned int currentUmSize = umSizeR(m_randomGenerator)+1;
unsigned int remainingToAttr = std::count(weight.begin(), weight.end(), 1);
if (currentUmSize > remainingToAttr)
currentUmSize = remainingToAttr;
UM2 currentUm;
for (unsigned int usI = 0; usI < currentUmSize; ++usI) {
std::discrete_distribution<unsigned int> excludedDist(weight.begin(), weight.end());
unsigned int id = excludedDist(m_randomGenerator);
weight[id] = 0;
currentUm.uss.push_back(p[id]);
}
auto lastBegin = 0;
for(auto& us : currentUm.uss)
{
if(us->getCreuxRoulement().back().getDispo().getDebutC().getRelativeDate() > lastBegin)
lastBegin = us->getCreuxRoulement().back().getDispo().getDebutC().getRelativeDate();
}
std::vector<SolverDate> endings;
for(auto& us : currentUm.uss)
{
if(us->getCreuxRoulement().back().getDispo().getFinC().getRelativeDate() > lastBegin)
endings.push_back(us->getCreuxRoulement().back().getDispo().getFinC());
}
std::uniform_int_distribution<unsigned int> lastDateDistrib(0, endings.size() - 1);
auto umDeparture = endings[lastDateDistrib(m_randomGenerator)];
for (auto &us: currentUm.uss) {
us->getCreuxRoulement().back().getDispo().getFin() = umDeparture;
}
umsToProcess.push(currentUm);
}
}
}
}
}
std::vector<UM2> GeneratorRecompo::generateUMs() {
std::vector<unsigned int> weight(m_instance->getRames().size(), 1);
std::vector<UM2> ums;
std::discrete_distribution<unsigned int> umSizeR({15,15,70});
while(weight != std::vector<unsigned int>(m_instance->getRames().size(), 0))
{
unsigned int currentUmSize = umSizeR(m_randomGenerator)+1;
unsigned int remainingToAttr = std::count(weight.begin(), weight.end(), 1);
if(currentUmSize > remainingToAttr)
currentUmSize = remainingToAttr;
UM2 currentUm;
for(unsigned int usI = 0; usI < currentUmSize; ++usI)
{
std::discrete_distribution<unsigned int> excludedDist(weight.begin(), weight.end());
unsigned int id = excludedDist(m_randomGenerator);
weight[id] = 0;
currentUm.uss.push_back(&(m_instance->getRames()[id]));
currentUm.rang.push_back(usI+1);
}
ums.push_back(currentUm);
}
return ums;
}
void GeneratorRecompo::generateCommercialServices(unsigned int nbsites, unsigned int nbsitesGares) {
//generate starting UM2s
//generate commercial services
//then generate rdvs
generateService(nbsites, nbsitesGares, generateUMs());
if(configlib::Configuration::Generator.WITH_RDVS)
{
generateRDVs(nbsites);
}
}
void GeneratorRecompo::generateRDVs(unsigned int nbSites)
{
//Check si deux rdv d'une même rame se superposent
unsigned int id = 0;
std::uniform_int_distribution<unsigned int> randNbRDV(configlib::Configuration::Generator.PLAGE_NB_RDV_RAME.first, configlib::Configuration::Generator.PLAGE_NB_RDV_RAME.second);
std::uniform_int_distribution<unsigned int> randDureeRdv(configlib::Configuration::Generator.PLAGE_DUREE_RDV.first, configlib::Configuration::Generator.PLAGE_DUREE_RDV.second);
std::uniform_int_distribution<unsigned int> randInfra(1, configlib::Configuration::Generator.NB_INFRA_TOTAL);
std::uniform_int_distribution<unsigned int> randDate(0, Configuration::Solver.NB_DAYS_TO_PLANIF * 24 * Configuration::Global.TIME_UNIT);
std::uniform_int_distribution<unsigned int> randSite(0, nbSites-1);
std::uniform_int_distribution<unsigned int> randRame(0, m_instance->getRames().size()-1);
std::bernoulli_distribution rdvOriented(configlib::Configuration::Generator.PROB_RDV_NON_ORIENTE);
for(auto& rame : m_instance->getRames())
{
unsigned int nbRdv = randNbRDV(m_randomGenerator);
for(unsigned int rdvind = 0; rdvind < nbRdv; ++rdvind)
{
unsigned int duration = randDureeRdv(m_randomGenerator);
unsigned int infra = randInfra(m_randomGenerator);
TypeInfrastructure type;
std::string typeinf = "infra" + std::to_string(infra);
type.setInfraType(typeinf);
type.setId(infra);
std::vector<unsigned int> indexPossible(rame.getCreuxRoulement().size(), 0);
Site site;
bool possibleAtAll = false;
for(unsigned int i = 0; i < rame.getCreuxRoulement().size(); ++i)
{
auto& el = rame.getCreuxRoulement()[i];
bool hasMatchInExistingRdv = false;
for(auto& exRdv : rame.getRdvms())
{
auto match = CreneauHoraire::checkSlotsCompatibility(el.getDispo(), exRdv.getCreneauChosen());
hasMatchInExistingRdv = match.first;
if(hasMatchInExistingRdv)
break;
}
auto overlapRDVsRame = std::find_if(rame.getRdvms().begin(), rame.getRdvms().end(), [&](auto& rd){
return CreneauHoraire::checkSlotsCompatibility(rd.getCreneauChosen(), el.getDispo()).first;
});
auto siteIte = std::find_if(m_instance->getSitesMaintenance().begin(), m_instance->getSitesMaintenance().end(), [&](auto& s){ return s.getRef() == el.getLieuxArret().getRef();});
if(!hasMatchInExistingRdv && siteIte != m_instance->getSitesMaintenance().end() && overlapRDVsRame == rame.getRdvms().end())
{
site.setRef(siteIte->getRef());
if(el.getDispo().getFinC() - el.getDispo().getDebutC() >= duration)
{
bool isP = false;
for(auto& v : siteIte->getVoies())
{
if(std::find_if(v.getInfrastructures().begin(), v.getInfrastructures().end(), [&](auto& el){return el.getInfraType() == type.getInfraType();}) != v.getInfrastructures().end())
{
auto find = std::find_if(v.getDisponibilites().begin(), v.getDisponibilites().end(), [&](auto& el){return el.getDispo().getFinC() - el.getDispo().getDebutC() >= duration;});
if(find != v.getDisponibilites().end())
{
isP = true;
break;
}
}
}
if(isP)
{
indexPossible[i] = 1;
possibleAtAll = true;
}
}
}
}
if(possibleAtAll)
{
std::discrete_distribution<unsigned int> randDispDist(indexPossible.begin(), indexPossible.end());
unsigned int disp = randDispDist(m_randomGenerator);
auto& chosenDisp = rame.getCreuxRoulement()[disp];
PreventiveMaintenanceRdv rdv;
rdv.getInfra().first = true;
rdv.getInfra().second = type;
rdv.setOriented(true);
rdv.getCreneauChosen().getDebut() = chosenDisp.getDispo().getDebut();
rdv.getCreneauChosen().getFin() = rdv.getCreneauChosen().getDebut() + duration;
rdv.setRdvId(id);
std::uniform_int_distribution<unsigned int> randDeadline(rdv.getCreneauChosen().getFin() - m_instance->getDateDebutPlanification(), Configuration::Solver.NB_DAYS_TO_PLANIF * 24 * Configuration::Global.TIME_UNIT*2);
unsigned int deadline = randDeadline(m_randomGenerator);
SolverDate deadlineObj = m_instance->getDateDebutPlanification() + deadline;
rdv.setDeadline(deadlineObj);
rdv.setSite(site);
std::string str = "tok";
rdv.setLibelle(str);
rame.getRdvms().push_back(rdv);
chosenDisp.setRDV(rdv);
auto types = std::make_pair(typeStop::RDVM, std::to_string(rdv.getRdvId()));
chosenDisp.setTypeDispo(types);
}
++id;
}
}
for(auto& rame : m_instance->getRames())
{
PreventiveMaintenanceRdv rdv;
unsigned int duration = randDureeRdv(m_randomGenerator);
unsigned int infra = randInfra(m_randomGenerator);
TypeInfrastructure type;
std::string typeinf = "infra" + std::to_string(infra);
type.setInfraType(typeinf);
type.setId(infra);
std::string str = "tok";
rdv.setLibelle(str);
rdv.getInfra().first = true;
rdv.getInfra().second = type;
rdv.setOriented(false);
rdv.tokenize();
bool notOriented = rdvOriented(m_randomGenerator) && rame.getRdvms().size() < configlib::Configuration::Generator.PLAGE_NB_RDV_RAME.second;
if(notOriented)
{
// Étape 1 : trouver toutes les rames ayant une rentrée naturelle sur technicentre
// avec durée suffisante + infra compatible sur le site
struct CandidateNaturelle {
Rame* rame;
unsigned int indexCreux;
Site site;
};
std::vector<CandidateNaturelle> candidatesNaturelles;
for(auto& otherRame : m_instance->getRames())
{
if(otherRame.getNumeroEF() == rame.getNumeroEF())
continue;
for(unsigned int i = 0; i < otherRame.getCreuxRoulement().size(); ++i)
{
auto& el = otherRame.getCreuxRoulement()[i];
// Le creux doit être sur un site de maintenance
auto siteIte = std::find_if(
m_instance->getSitesMaintenance().begin(),
m_instance->getSitesMaintenance().end(),
[&](auto& s){ return s.getRef() == el.getLieuxArret().getRef(); }
);
if(siteIte == m_instance->getSitesMaintenance().end())
continue;
// Durée suffisante
if(el.getDispo().getFinC() - el.getDispo().getDebutC() < duration)
continue;
// Pas d'overlap avec les RDVs existants de cette rame
bool hasOverlap = false;
for(auto& exRdv : otherRame.getRdvms())
{
if(CreneauHoraire::checkSlotsCompatibility(
el.getDispo(), exRdv.getCreneauChosen()).first)
{
hasOverlap = true;
break;
}
}
if(hasOverlap)
continue;
// Infra compatible + voie disponible sur ce site
bool infraOk = false;
for(auto& v : siteIte->getVoies())
{
bool hasInfra = std::find_if(
v.getInfrastructures().begin(),
v.getInfrastructures().end(),
[&](auto& inf){ return inf.getInfraType() == type.getInfraType(); }
) != v.getInfrastructures().end();
if(hasInfra)
{
auto find = std::find_if(
v.getDisponibilites().begin(),
v.getDisponibilites().end(),
[&](auto& d){
return d.getDispo().getFinC() - d.getDispo().getDebutC() >= duration;
}
);
if(find != v.getDisponibilites().end())
{
infraOk = true;
break;
}
}
}
if(!infraOk)
continue;
Site s;
s.setRef(siteIte->getRef());
candidatesNaturelles.push_back({&otherRame, i, s});
}
}
if(candidatesNaturelles.empty())
continue; // pas de rentrée naturelle possible => RDV non génératable
// Étape 2 : choisir une candidate naturelle au hasard => fixe le créneau du RDV
std::uniform_int_distribution<unsigned int> randCand(0, candidatesNaturelles.size() - 1);
auto& chosen = candidatesNaturelles[randCand(m_randomGenerator)];
auto& creuxNaturel = chosen.rame->getCreuxRoulement()[chosen.indexCreux];
SolverDate debutRdv = creuxNaturel.getDispo().getDebut();
SolverDate finRdv = debutRdv + duration;
// Créneau du RDV fixé sur la rentrée naturelle
CreneauHoraire creneauRdv;
creneauRdv.getDebut() = debutRdv;
creneauRdv.getFin() = finRdv;
// Étape 3 : vérifier qu'au moins une rame (dont la rame courante)
// peut recevoir un intervalle équivalent sans overlap
// => garantit que l'algo aura une solution de réaffectation
bool reassignPossible = false;
for(auto& anyRame : m_instance->getRames())
{
if(anyRame.getNumeroEF() == rame.getNumeroEF())
continue;
for(auto& creux : anyRame.getCreuxRoulement())
{
if(creux.getTypeDispo().first == typeStop::RDVM)
{
creux.getPreventiveMaintenanceRdv().value().tokenize();
bool compat = PreventiveMaintenanceRdv::areEquivalent(creux.getPreventiveMaintenanceRdv().value(), rdv);
if(!compat) continue;
bool hasOverlap = false;
// Pas d'overlap avec les RDVs existants de cette rame
for(auto& exRdv : rame.getCreuxRoulement())
{
if(CreneauHoraire::checkSlotsCompatibility(
creux.getDispo(), exRdv.getDispo()).first)
{
hasOverlap = true;
break;
}
}
if(hasOverlap)
continue;
reassignPossible = true;
break;
}
}
if(reassignPossible)
break;
}
if(!reassignPossible)
continue; // instance non résoluble pour ce RDV => on skip
// Étape 4 : construire et attacher le RDV à la rame courante
rdv.getCreneauChosen().getDebut() = debutRdv;
rdv.getCreneauChosen().getFin() = finRdv;
rdv.setRdvId(id);
rdv.setSite(chosen.site);
std::uniform_int_distribution<unsigned int> randDeadline(
finRdv - m_instance->getDateDebutPlanification(),
Configuration::Solver.NB_DAYS_TO_PLANIF * 24 * Configuration::Global.TIME_UNIT * 2
);
SolverDate dl = m_instance->getDateDebutPlanification() + randDeadline(m_randomGenerator);
rdv.setDeadline(dl);
rame.getRdvms().push_back(rdv);
// Pas de setRDV() sur le creux : c'est au solver de confirmer l'affectation
}
}
}
void GeneratorRecompo::generateRames(unsigned int nbrame, unsigned int nbjobs) {
std::binomial_distribution<unsigned int> randSeverite(1, 0.2);
unsigned int j = 0;
for (unsigned int r = 0; r < nbrame; ++r) {
Rame rame;
rame.setNumeroEF("EF" + std::to_string(r));
rame.setId(r);
m_instance->getRames().push_back(rame);
}
while (j != nbjobs) {
for(auto& rame : m_instance->getRames())
{
unsigned int severite = randSeverite(m_randomGenerator);
j += generateOperations(rame, severite, nbjobs);
}
}
}
void GeneratorRecompo::generateSites(unsigned int nbsite, unsigned int nbsitesGares, unsigned int nbvoie) {
std::vector sitevoieVec(nbsite, 0);
std::uniform_int_distribution<unsigned int> distVoieOnSite(0, nbsite-1);
std::bernoulli_distribution swap_proba(1);
std::bernoulli_distribution recompo_proba(0.4);
for(unsigned int v = 0; v < nbvoie; ++v)
{
sitevoieVec[distVoieOnSite(m_randomGenerator)]++;
}
for (unsigned int s = 0; s < nbsite; ++s) {
MaintenanceSite site("ref" + std::to_string(s), "ref" + std::to_string(s),"ref" + std::to_string(s), 1);
/*if (s == 0)
generateVoies(site, nbVoieSitePrincipal);
else
generateVoies(site, nbVoieSiteDeporte);*/
generateVoies(site, sitevoieVec[s]);
//generateCapacitesSites(site);
m_instance->getSitesMaintenance().push_back(site);
}
for(unsigned int s = nbsite; s < nbsite+nbsitesGares; s++){
bool isSwap = swap_proba(m_randomGenerator);
bool isRecompo = recompo_proba(m_randomGenerator);
Site site("ref" + std::to_string(s), "ref" + std::to_string(s),"ref" + std::to_string(s), 3,isSwap,isRecompo);
m_instance->getSites().push_back(site);
}
}
void GeneratorRecompo::generateData(unsigned int nbsite, unsigned int nbsitesGares, unsigned int nbvoie,
unsigned int nbrame, unsigned int nbjobs) {
generateSites(nbsite, nbsitesGares, nbvoie);
if (nbrame < nbjobs && !multi_op) {
nbrame = nbjobs;
}
generateRames(nbrame, nbjobs);
generateCommercialServices(nbsite, nbsitesGares);
}
void GeneratorRecompo::generateVoies(MaintenanceSite &site, unsigned int nbvoie) {
std::uniform_int_distribution<unsigned int> randInfraNb(1, Configuration::Generator.NB_INFRA_TOTAL);
for (unsigned int v = 0; v < nbvoie; ++v) {
Voie voie;
voie.setId(std::to_string(countVoie));
++countVoie;
unsigned int nbInf = randInfraNb(m_randomGenerator);
std::vector<unsigned int> doublons;
for (unsigned int i = 0; i < nbInf; ++i) {
TypeInfrastructure infra = generateInfrastructure(doublons);
doublons.push_back(infra.getId() - 1);
voie.getInfrastructures().push_back(infra);
}
generateDisposVoies(voie);
site.getVoies().push_back(voie);
}
}
void GeneratorRecompo::generateDisposVoies(Voie &voie) {
std::uniform_int_distribution<unsigned int> randDurationDisp(8,24);
std::uniform_int_distribution<unsigned int> randEcart(2,
24);
unsigned int ecart = randEcart(m_randomGenerator);
unsigned int lastEnd = 0;
unsigned int H = (m_instance->getDateDebutPlanification() +
Configuration::Solver.NB_DAYS_TO_PLANIF * 24 * Configuration::Global.TIME_UNIT) -
m_instance->getDateDebutPlanification();
while (lastEnd < H) {
unsigned int duree = randDurationDisp(m_randomGenerator);
SolverDate debutD = m_instance->getDateDebutPlanification() + lastEnd + ecart;
SolverDate end = m_instance->getDateDebutPlanification() +
(lastEnd + ecart + duree * Configuration::Global.TIME_UNIT);
lastEnd = end - m_instance->getDateDebutPlanification();
CreneauHoraire periode(debutD, end);
EmplacementVoie dispo(periode, "");
voie.getDisponibilites().push_back(dispo);
}
}
unsigned int GeneratorRecompo::generateOperations(Rame &rame, unsigned int severite, unsigned int nbjobs) {
std::uniform_int_distribution<unsigned int> randH1W(20,30);
std::uniform_int_distribution<unsigned int> randH2W(5,10);
std::uniform_int_distribution<unsigned int> randH3W(1,3);
std::uniform_int_distribution<unsigned int> randNbOp(
Configuration::Generator.PLAGE_NB_OPERATION_RAME[severite].first,
Configuration::Generator.PLAGE_NB_OPERATION_RAME[severite].second);
std::binomial_distribution<unsigned int> randHierarchie(2, 0.7);
std::uniform_real_distribution<double> randDurationDiag(
Configuration::Generator.PLAGE_PROPORTION_DUREE_DIAG.first,
Configuration::Generator.PLAGE_PROPORTION_DUREE_DIAG.second);
unsigned int nbOp = multi_op * randNbOp(m_randomGenerator) + !multi_op;
if(nbOp + countOp > nbjobs)
{
nbOp = nbjobs - countOp;
}
for (unsigned int o = 0; o < nbOp; ++o) {
OperationRequise sig;
unsigned int h = randHierarchie(m_randomGenerator) + 1;
std::uniform_int_distribution<unsigned int> randDuration(
Configuration::Generator.PLAGE_DUREE_OP[h - 1].first,
Configuration::Generator.PLAGE_DUREE_OP[h - 1].second);
unsigned int wr = 0;
unsigned int wd = 0;
switch (h) {
case 1:
wr = randH1W(m_randomGenerator);
wd = WH1D;
break;
case 2:
wr = randH2W(m_randomGenerator);
wd = WH2D;
break;
case 3:
wr = randH3W(m_randomGenerator);
wd = WH3D;
break;
default:
break;
}
sig.setPoidsRejet(wd);
sig.setPoidsRetard(wr);
std::string strop = std::to_string(countOp);
sig.setOpId(strop);
sig.getInfrastructures().push_back(generateInfrastructure({}));
sig.setPoidsRejetDefaut(wd);
sig.setPoidsRetardDefaut(wr);
sig.setDiagnosticPossible(true);
sig.setCodeDefaut("codeDefaut" + std::to_string(countOp));
sig.setHierarchie(h);
unsigned int d = randDuration(m_randomGenerator);
unsigned int ddiag = ceil(d * randDurationDiag(m_randomGenerator));
sig.setDuree(d);
sig.setDureeDiag(ddiag);
sig.setDateDue(m_instance->getDateDebutPlanification() + h * 24 * Configuration::Global.TIME_UNIT);
sig.setIdRame(rame.getId());
sig.setNumeroEF(rame.getNumeroEF());
rame.getSignalements().push_back(sig);
countOp++;
}
return nbOp;
}
TypeInfrastructure GeneratorRecompo::generateInfrastructure(std::vector<unsigned int> excluded) {
//std::uniform_int_distribution<unsigned int> randInfraNb(1, Configuration::Generator.NB_INFRA_TOTAL);
std::vector<unsigned int> weight;
for (unsigned int i = 0; i < Configuration::Generator.NB_INFRA_TOTAL; ++i) {
if (std::find(excluded.begin(), excluded.end(), i) == excluded.end()) {
weight.push_back(1);
} else {
weight.push_back(0);
}
}
std::discrete_distribution<int> excludedDist(weight.begin(), weight.end());
unsigned int nbInf = excludedDist(m_randomGenerator) + 1;
TypeInfrastructure type;
std::string typeinf = "infra" + std::to_string(nbInf);
type.setInfraType(typeinf);
type.setId(nbInf);
return type;
}
}
@@ -0,0 +1,58 @@
#ifndef GENERATORRECOMPO_HPP
#define GENERATORRECOMPO_HPP
#include <string>
#include <nlohmann/json.hpp>
#include <vector>
#include <random>
#include "../../General/Logs/Loggers/FileLogger.h"
#include "../../General/Logs/Loggers/StreamLogger.h"
#include "../../General/Configuration/Configurations.h"
#include "../../General/Model/STFInstance.h"
namespace insgenlib {
using namespace modellib;
typedef struct _um2 {
std::vector<Rame*> uss;
std::vector<unsigned short> rang;
} UM2;
class GeneratorRecompo {
private:
STFInstance *m_instance;
std::mt19937 m_randomGenerator;
bool multi_op;
void generateRames(unsigned int nbrame, unsigned int nbjobs);
void generateSites(unsigned int nbsite, unsigned int nbsitesGares, unsigned int nbvoie);
void generateData(unsigned int nbsite, unsigned int nbsitesGares, unsigned int nbvoie, unsigned int nbrame, unsigned int nbjobs);
void generateVoies(MaintenanceSite &site, unsigned int nbvoie);
void generateDisposVoies(Voie &voie);
unsigned int generateOperations(Rame &rame, unsigned int severite, unsigned int nbjobs);
void generateCommercialServices(unsigned int nbsites, unsigned int nbsitesGares);
void generateService(unsigned int nbsites, unsigned int nbsitesGares, std::vector<UM2> ums);
void generateRDVs(unsigned int nbsites);
std::vector<UM2> generateUMs();
TypeInfrastructure generateInfrastructure(std::vector<unsigned int> excluded);
public:
GeneratorRecompo();
void initLoggers();
std::vector<nlohmann::json> generateInstances();
};
}
#endif
@@ -0,0 +1,469 @@
#include "GeneratorSwap.hpp"
#include <random>
#include <queue>
#include <string>
#include "../../General/Logs/IOHelper.h"
namespace insgenlib {
using namespace modellib;
using namespace loggerlib;
using namespace configlib;
#define WH1D 6
#define WH2D 3
#define WH3D 1
static unsigned int countVoie = 0;
static unsigned int countOp = 0;
GeneratorSwap::GeneratorSwap() : m_instance(nullptr) {
std::random_device rd;
std::seed_seq seed{rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd()};
m_randomGenerator.seed(seed);
}
void GeneratorSwap::initLoggers() {
for (auto &fileLog: Configuration::Logs.GENERATOR_FILE_LOGGERS) {
FileLogger *l = new FileLogger(fileLog.filename, fileLog.showType, fileLog.jsonFormat, fileLog.types);
for (unsigned int type: fileLog.types) {
FileLogger::addLogger((ELOGGER_TYPES) type, l);
}
}
}
std::vector<nlohmann::json> GeneratorSwap::generateInstances() {
SolverDate dateDebut = SolverDate::todayObjFormat();
multi_op = Configuration::Generator.MULTI_OP_INSTANCE;
std::vector<nlohmann::json> generatedInstances;
std::vector<std::pair<std::string,STFInstance*>> batching;
unsigned int nbBatch = 0;
for (auto &s: Configuration::Generator.NB_SITES_MAINTENANCE) {
for (auto &sg: Configuration::Generator.NB_SITES_GARE) {
for (auto &v: Configuration::Generator.NB_VOIES) {
for (auto &r: Configuration::Generator.NB_RAMES) {
for (auto &j: Configuration::Generator.NB_JOBS) {
if(!(r < j && !multi_op))
{
for (unsigned int i = 0; i < Configuration::Generator.NB_INSTANCES_TO_GENERATE; ++i) {
countOp = 0;
countVoie = 0;
Logger::systemNotify(LOGGER_INFO, "Instance " + std::to_string(i) + " of type : ");
Logger::systemNotify(LOGGER_INFO, std::to_string(s) + " sites");
Logger::systemNotify(LOGGER_INFO, std::to_string(v) + " voies par site");
Logger::systemNotify(LOGGER_INFO, std::to_string(r) + " rames/operations");
Logger::systemNotify(LOGGER_INFO, "has been generated");
std::string filename = std::to_string(s) + "_" + std::to_string(sg) + "_" +
std::to_string(v) + "_" + std::to_string(r) + "_" +
std::to_string(j) + "_" + std::to_string(i) + ".json";
std::cout << "Generating: " << filename << std::endl;
m_instance = new STFInstance();
m_instance->setDateDebutPlanification(dateDebut);
std::string n = std::to_string(i);
m_instance->setIdStf(n);
generateData(s, sg, v, r, j);
if(batching.size() + 1 > Configuration::Generator.MAX_BATCH_SIZE)
{
for(auto& ins : batching)
{
IOHelper::dump(Configuration::Global.INPUT_LOCATION + "/batch_" + std::to_string(nbBatch), ins.second->to_json().dump(2), ins.first);
delete ins.second;
}
batching.clear();
nbBatch++;
}
batching.emplace_back(filename,m_instance);
}
}
}
}
}
}
}
if(!batching.empty())
{
for(auto& ins : batching)
{
IOHelper::dump(Configuration::Global.INPUT_LOCATION + "/batch_" + std::to_string(nbBatch), ins.second->to_json().dump(2), ins.first);
delete ins.second;
}
batching.clear();
nbBatch++;
}
return generatedInstances;
}
void GeneratorSwap::generateService(unsigned int nbsites, unsigned int nbsitesGares, std::vector<UM> ums) {
std::string imp = IMPERATIVE;
std::string not_imp = NOT_IMPERATIVE;
if (!ums.empty())
{
std::uniform_int_distribution<unsigned int> randDurationDisp(
Configuration::Generator.PLAGE_DUREE_DISPO_RAME.first,
Configuration::Generator.PLAGE_DUREE_DISPO_RAME.second);
std::uniform_int_distribution<unsigned int> randDurationDispGare(
Configuration::Generator.PLAGE_DUREE_DISPO_RAME_GARE.first,
Configuration::Generator.PLAGE_DUREE_DISPO_RAME_GARE.second);
std::uniform_int_distribution<unsigned int> randSiteId(0, nbsites - 1);
std::uniform_int_distribution<unsigned int> randSiteIdStation(nbsites, nbsites + nbsitesGares-1);
std::bernoulli_distribution siteTypeDist(0.25);
std::bernoulli_distribution siteMaxMinDist(0.5);
std::bernoulli_distribution rdvImperatif(0.2);//1/5 que le rdv soit imperatif
/*std::uniform_int_distribution<unsigned int> randEcart(Configuration::Generator.PLAGE_ECART_DISPO_RAME.first,
Configuration::Generator.PLAGE_ECART_DISPO_RAME.second);*/
std::uniform_int_distribution<unsigned int> randEcartGare(
Configuration::Generator.PLAGE_ECART_DISPO_RAME_GARE.first,
Configuration::Generator.PLAGE_ECART_DISPO_RAME_GARE.second);
unsigned int lastEnd;
unsigned int H = (m_instance->getDateDebutPlanification() +
Configuration::Solver.NB_DAYS_TO_PLANIF * 24 * Configuration::Global.TIME_UNIT) -
m_instance->getDateDebutPlanification();
std::queue<UM, std::deque<UM>> umsToProcess(std::deque<UM>(ums.begin(), ums.end()));
while (!umsToProcess.empty()) {
while (!umsToProcess.empty()) {
auto &u = umsToProcess.front();
lastEnd = 0;
if(!u.uss[0]->getCreuxRoulement().empty())
{
lastEnd = u.uss[0]->getCreuxRoulement().back().getDispo().getFinC().getRelativeDate();
}
bool typeSite;
do {
typeSite = siteTypeDist(m_randomGenerator);
unsigned int idSite = randSiteIdStation(m_randomGenerator);
if (typeSite) {
idSite = randSiteId(m_randomGenerator);
}
unsigned int ecart = randEcartGare(
m_randomGenerator);//randEcart(m_randomGenerator) * typeSite + !typeSite *
unsigned int duree = randDurationDisp(m_randomGenerator) * typeSite +
!typeSite * randDurationDispGare(m_randomGenerator);
SolverDate debutD = m_instance->getDateDebutPlanification() + lastEnd + ecart;
SolverDate end = m_instance->getDateDebutPlanification() +
(lastEnd + ecart + duree * Configuration::Global.TIME_UNIT);
lastEnd = end - m_instance->getDateDebutPlanification();
CreneauHoraire periode(debutD, end);
if (typeSite) {
EmplacementRame dispo(m_instance->getSitesMaintenance()[idSite], periode);
dispo.setImperative(not_imp);
for (auto &r: u.uss) {
std::vector<RameInformation> umR;
unsigned short idx = 1;
for (auto &r2: u.uss) {
if(r2 == r ){
dispo.setRang(idx);
}
if (r2 != r) {
umR.emplace_back(r2->getNumeroEF(), "l0", idx);
}
idx++;
}
dispo.setUM(umR);
r->getCreuxRoulement().push_back(dispo);
}
} else {
Site fs;
fs.setRef("Ref" + std::to_string(idSite));
fs.setType(2);
EmplacementRame dispo(fs, periode);
dispo.setImperative(not_imp);
for (auto &r: u.uss) {
std::vector<RameInformation> umR;
unsigned short idx = 1;
for (auto &r2: u.uss) {
if(r2 == r ){
dispo.setRang(idx);
}
if (r2 != r) {
umR.emplace_back(r2->getNumeroEF(), "l0", idx);
}
idx++;
}
dispo.setUM(umR);
r->getCreuxRoulement().push_back(dispo);
}
}
} while (!typeSite &&
lastEnd < H);//(lastEnd < H);//!typeSite && dans le cas ou on peut recomposer??
umsToProcess.pop();
}
std::vector<std::vector<Rame *>> pool;
EmplacementRame *currentCr = nullptr;
std::unordered_set<Rame *> setPooled;
while (setPooled.size() != m_instance->getRames().size()) {
pool.emplace_back();
for (auto &r: m_instance->getRames()) {
if (setPooled.find(&r) == setPooled.end()) {
if (currentCr == nullptr)
currentCr = &r.getCreuxRoulement().back();
if (r.getCreuxRoulement().back().getDispo().getFinC().getRelativeDate() < H
&& CreneauHoraire::checkCommonDuration(r.getCreuxRoulement().back().getDispo(),
currentCr->getDispo(), 120) && r.getCreuxRoulement().back().getLieuxArret().getRef() == currentCr->getLieuxArret().getRef()) {
pool.back().push_back(&r);
setPooled.insert(&r);
}
if(r.getCreuxRoulement().back().getDispo().getFinC().getRelativeDate() >= H)
setPooled.insert(&r);
}
}
currentCr = nullptr;
}
for (auto &p: pool) {
std::vector<unsigned int> weight(p.size(), 1);
std::discrete_distribution<unsigned int> umSizeR({15, 75, 10});
while (weight != std::vector<unsigned int>(p.size(), 0)) {
unsigned int currentUmSize = umSizeR(m_randomGenerator)+1;
unsigned int remainingToAttr = std::count(weight.begin(), weight.end(), 1);
if (currentUmSize > remainingToAttr)
currentUmSize = remainingToAttr;
UM currentUm;
for (unsigned int usI = 0; usI < currentUmSize; ++usI) {
std::discrete_distribution<unsigned int> excludedDist(weight.begin(), weight.end());
unsigned int id = excludedDist(m_randomGenerator);
weight[id] = 0;
currentUm.uss.push_back(p[id]);
}
auto lastBegin = 0;
for(auto& us : currentUm.uss)
{
if(us->getCreuxRoulement().back().getDispo().getDebutC().getRelativeDate() > lastBegin)
lastBegin = us->getCreuxRoulement().back().getDispo().getDebutC().getRelativeDate();
}
std::vector<SolverDate> endings;
for(auto& us : currentUm.uss)
{
if(us->getCreuxRoulement().back().getDispo().getFinC().getRelativeDate() > lastBegin)
endings.push_back(us->getCreuxRoulement().back().getDispo().getFinC());
}
std::uniform_int_distribution<unsigned int> lastDateDistrib(0, endings.size() - 1);
auto umDeparture = endings[lastDateDistrib(m_randomGenerator)];
for (auto &us: currentUm.uss) {
us->getCreuxRoulement().back().getDispo().getFin() = umDeparture;
}
umsToProcess.push(currentUm);
}
}
}
}
}
std::vector<UM> GeneratorSwap::generateUMs() {
std::vector<unsigned int> weight(m_instance->getRames().size(), 1);
std::vector<UM> ums;
std::discrete_distribution<unsigned int> umSizeR({15,75,10});
while(weight != std::vector<unsigned int>(m_instance->getRames().size(), 0))
{
unsigned int currentUmSize = umSizeR(m_randomGenerator)+1;
unsigned int remainingToAttr = std::count(weight.begin(), weight.end(), 1);
if(currentUmSize > remainingToAttr)
currentUmSize = remainingToAttr;
UM currentUm;
for(unsigned int usI = 0; usI < currentUmSize; ++usI)
{
std::discrete_distribution<unsigned int> excludedDist(weight.begin(), weight.end());
unsigned int id = excludedDist(m_randomGenerator);
weight[id] = 0;
currentUm.uss.push_back(&(m_instance->getRames()[id]));
}
ums.push_back(currentUm);
}
return ums;
}
void GeneratorSwap::generateCommercialServices(unsigned int nbsites, unsigned int nbsitesGares) {
//generate starting UMs
//generate commercial services
generateService(nbsites, nbsitesGares, generateUMs());
}
void GeneratorSwap::generateRames(unsigned int nbrame, unsigned int nbjobs) {
std::binomial_distribution<unsigned int> randSeverite(1, 0.2);
unsigned int j = 0;
for (unsigned int r = 0; r < nbrame; ++r) {
Rame rame;
rame.setNumeroEF("EF" + std::to_string(r));
rame.setId(r);
m_instance->getRames().push_back(rame);
}
while (j != nbjobs) {
for(auto& rame : m_instance->getRames())
{
unsigned int severite = randSeverite(m_randomGenerator);
j += generateOperations(rame, severite, nbjobs);
}
}
}
void GeneratorSwap::generateSites(unsigned int nbsite, unsigned int nbvoie) {
std::vector sitevoieVec(nbsite, 0);
std::uniform_int_distribution<unsigned int> distVoieOnSite(0, nbsite-1);
for(unsigned int v = 0; v < nbvoie; ++v)
{
sitevoieVec[distVoieOnSite(m_randomGenerator)]++;
}
for (unsigned int s = 0; s < nbsite; ++s) {
MaintenanceSite site("ref" + std::to_string(s), "ref" + std::to_string(s),"ref" + std::to_string(s), 1);
/*if (s == 0)
generateVoies(site, nbVoieSitePrincipal);
else
generateVoies(site, nbVoieSiteDeporte);*/
generateVoies(site, sitevoieVec[s]);
//generateCapacitesSites(site);
m_instance->getSitesMaintenance().push_back(site);
}
}
void GeneratorSwap::generateData(unsigned int nbsite, unsigned int nbsitesGares, unsigned int nbvoie,
unsigned int nbrame, unsigned int nbjobs) {
generateSites(nbsite, nbvoie);
if (nbrame < nbjobs && !multi_op) {
nbrame = nbjobs;
}
generateRames(nbrame, nbjobs);
generateCommercialServices(nbsite, nbsitesGares);
}
void GeneratorSwap::generateVoies(MaintenanceSite &site, unsigned int nbvoie) {
std::uniform_int_distribution<unsigned int> randInfraNb(1, Configuration::Generator.NB_INFRA_TOTAL);
for (unsigned int v = 0; v < nbvoie; ++v) {
Voie voie;
voie.setId(std::to_string(countVoie));
++countVoie;
unsigned int nbInf = randInfraNb(m_randomGenerator);
std::vector<unsigned int> doublons;
for (unsigned int i = 0; i < nbInf; ++i) {
TypeInfrastructure infra = generateInfrastructure(doublons);
doublons.push_back(infra.getId() - 1);
voie.getInfrastructures().push_back(infra);
}
generateDisposVoies(voie);
site.getVoies().push_back(voie);
}
}
void GeneratorSwap::generateDisposVoies(Voie &voie) {
std::uniform_int_distribution<unsigned int> randDurationDisp(8,24);
std::uniform_int_distribution<unsigned int> randEcart(2,
24);
unsigned int ecart = randEcart(m_randomGenerator);
unsigned int lastEnd = 0;
unsigned int H = (m_instance->getDateDebutPlanification() +
Configuration::Solver.NB_DAYS_TO_PLANIF * 24 * Configuration::Global.TIME_UNIT) -
m_instance->getDateDebutPlanification();
while (lastEnd < H) {
unsigned int duree = randDurationDisp(m_randomGenerator);
SolverDate debutD = m_instance->getDateDebutPlanification() + lastEnd + ecart;
SolverDate end = m_instance->getDateDebutPlanification() +
(lastEnd + ecart + duree * Configuration::Global.TIME_UNIT);
lastEnd = end - m_instance->getDateDebutPlanification();
CreneauHoraire periode(debutD, end);
EmplacementVoie dispo(periode, "");
voie.getDisponibilites().push_back(dispo);
}
}
unsigned int GeneratorSwap::generateOperations(Rame &rame, unsigned int severite, unsigned int nbjobs) {
std::uniform_int_distribution<unsigned int> randH1W(20,30);
std::uniform_int_distribution<unsigned int> randH2W(5,10);
std::uniform_int_distribution<unsigned int> randH3W(1,3);
std::uniform_int_distribution<unsigned int> randNbOp(
Configuration::Generator.PLAGE_NB_OPERATION_RAME[severite].first,
Configuration::Generator.PLAGE_NB_OPERATION_RAME[severite].second);
std::binomial_distribution<unsigned int> randHierarchie(2, 0.7);
std::uniform_real_distribution<double> randDurationDiag(
Configuration::Generator.PLAGE_PROPORTION_DUREE_DIAG.first,
Configuration::Generator.PLAGE_PROPORTION_DUREE_DIAG.second);
unsigned int nbOp = multi_op * randNbOp(m_randomGenerator) + !multi_op;
if(nbOp + countOp > nbjobs)
{
nbOp = nbjobs - countOp;
}
for (unsigned int o = 0; o < nbOp; ++o) {
OperationRequise sig;
unsigned int h = randHierarchie(m_randomGenerator) + 1;
std::uniform_int_distribution<unsigned int> randDuration(
Configuration::Generator.PLAGE_DUREE_OP[h - 1].first,
Configuration::Generator.PLAGE_DUREE_OP[h - 1].second);
unsigned int wr = 0;
unsigned int wd = 0;
switch (h) {
case 1:
wr = randH1W(m_randomGenerator);
wd = WH1D;
break;
case 2:
wr = randH2W(m_randomGenerator);
wd = WH2D;
break;
case 3:
wr = randH3W(m_randomGenerator);
wd = WH3D;
break;
default:
break;
}
sig.setPoidsRejet(wd);
sig.setPoidsRetard(wr);
std::string strop = std::to_string(countOp);
sig.setOpId(strop);
sig.getInfrastructures().push_back(generateInfrastructure({}));
sig.setPoidsRejetDefaut(wd);
sig.setPoidsRetardDefaut(wr);
sig.setDiagnosticPossible(true);
sig.setCodeDefaut("codeDefaut" + std::to_string(countOp));
sig.setHierarchie(h);
unsigned int d = randDuration(m_randomGenerator);
unsigned int ddiag = ceil(d * randDurationDiag(m_randomGenerator));
sig.setDuree(d);
sig.setDureeDiag(ddiag);
sig.setDateDue(m_instance->getDateDebutPlanification() + h * 24 * Configuration::Global.TIME_UNIT);
sig.setIdRame(rame.getId());
sig.setNumeroEF(rame.getNumeroEF());
rame.getSignalements().push_back(sig);
countOp++;
}
return nbOp;
}
TypeInfrastructure GeneratorSwap::generateInfrastructure(std::vector<unsigned int> excluded) {
//std::uniform_int_distribution<unsigned int> randInfraNb(1, Configuration::Generator.NB_INFRA_TOTAL);
std::vector<unsigned int> weight;
for (unsigned int i = 0; i < Configuration::Generator.NB_INFRA_TOTAL; ++i) {
if (std::find(excluded.begin(), excluded.end(), i) == excluded.end()) {
weight.push_back(1);
} else {
weight.push_back(0);
}
}
std::discrete_distribution<int> excludedDist(weight.begin(), weight.end());
unsigned int nbInf = excludedDist(m_randomGenerator) + 1;
TypeInfrastructure type;
std::string typeinf = "infra" + std::to_string(nbInf);
type.setInfraType(typeinf);
type.setId(nbInf);
return type;
}
}
@@ -0,0 +1,54 @@
#ifndef GENERATORSWAP_HPP
#define GENERATORSWAP_HPP
#include <string>
#include <nlohmann/json.hpp>
#include <vector>
#include <random>
#include "../../General/Logs/Loggers/FileLogger.h"
#include "../../General/Configuration/Configurations.h"
#include "../../General/Model/STFInstance.h"
namespace insgenlib {
using namespace modellib;
typedef struct _um {
std::vector<Rame*> uss;
} UM;
class GeneratorSwap {
private:
STFInstance *m_instance;
std::mt19937 m_randomGenerator;
bool multi_op;
void generateRames(unsigned int nbrame, unsigned int nbjobs);
void generateSites(unsigned int nbsite, unsigned int nbvoie);
void generateData(unsigned int nbsite, unsigned int nbsitesGares, unsigned int nbvoie, unsigned int nbrame, unsigned int nbjobs);
void generateVoies(MaintenanceSite &site, unsigned int nbvoie);
void generateDisposVoies(Voie &voie);
unsigned int generateOperations(Rame &rame, unsigned int severite, unsigned int nbjobs);
void generateCommercialServices(unsigned int nbsites, unsigned int nbsitesGares);
void generateService(unsigned int nbsites, unsigned int nbsitesGares, std::vector<UM> ums);
std::vector<UM> generateUMs();
TypeInfrastructure generateInfrastructure(std::vector<unsigned int> excluded);
public:
GeneratorSwap();
void initLoggers();
std::vector<nlohmann::json> generateInstances();
};
}
#endif
+31
View File
@@ -0,0 +1,31 @@
#include "Generator/GeneratorRecompo.hpp"
#include "Generator/GeneratorSwap.hpp"
#include "Generator/Generator.hpp"
using namespace insgenlib;
int main(int argc, char** argv)
{
configlib::Configuration::init("configuration.json");
if(configlib::Configuration::Generator.SWAP_INSTANCE)
{
GeneratorSwap generator;
generator.initLoggers();
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO,"Generateur selectionnée: Swap");
generator.generateInstances();
}
else if(configlib::Configuration::Generator.RECOMPO_INSTANCE)
{
GeneratorRecompo generator;
generator.initLoggers();
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO,"Generateur selectionnée: Recompo");
generator.generateInstances();
}
else
{
Generator generator;
generator.initLoggers();
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO,"Generateur selectionnée: Classique");
generator.generateInstances();
}
return 0;
}
@@ -0,0 +1,37 @@
{
"folders": [
{
"path": "../../.."
}
],
"settings": {},
"launch": {
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug",
"program": "${workspaceFolder}/build/bin/Debug/OrdonnancementCorrectif",
"args": ["--solve", "-TRACKPLANS", "1_3_10_100_100_0.json"],
"cwd": "${workspaceFolder}/build/bin/Debug/"
},
{
"type": "lldb",
"request": "launch",
"name": "DebugPrevRep",
"program": "${workspaceFolder}/build/bin/Debug/OrdonnancementCorrectif",
"args": ["--solve", "-PREVREP", "1_6_20_150_50_2.json"],
"cwd": "${workspaceFolder}/build/bin/Debug/"
},
{
"type": "lldb",
"request": "launch",
"name": "DebugIns",
"program": "${workspaceFolder}/build/bin/Debug/InstanceGenerator",
"args": [],
"cwd": "${workspaceFolder}/build/bin/Debug/"
}
]
}
}
+17
View File
@@ -0,0 +1,17 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug",
"program": "${workspaceFolder}/build/bin/Debug/OrdonnancementCorrectif",
"args": ["--solve", "-HEURISTIC", "soutenance.json"],
"cwd": "${workspaceFolder}/build/bin/Debug/"
}
]
}
+35
View File
@@ -0,0 +1,35 @@
#include "Interface.hpp"
#include "../Solver/ConditionHolder.hpp"
namespace interfacelib {
void Interface::initConfiguration(const std::string& path) {
configlib::Configuration::init(path);
solverlib::ConditionHolder::init();
}
void Interface::initLoggers() {
for (auto &fileLog: configlib::Configuration::Logs.ORDO_FILE_LOGGERS) {
auto l = new loggerlib::FileLogger(fileLog.filename, fileLog.showType, fileLog.jsonFormat, fileLog.types);
for (unsigned int type: fileLog.types) {
loggerlib::FileLogger::addLogger((loggerlib::ELOGGER_TYPES) type, l);
}
}
for(auto& sLogger : configlib::Configuration::Logs.ORDO_STREAM_LOGGERS)
{
auto lcout = new loggerlib::StreamLogger(sLogger.outstream, sLogger.showType, sLogger.jsonFormat, sLogger.types);
for(auto t : sLogger.types)
{
loggerlib::StreamLogger::addLogger((loggerlib::ELOGGER_TYPES) t, lcout);
}
}
for(auto& wLogger : configlib::Configuration::Logs.ORDO_WEB_LOGGERS)
{
auto lcout = new loggerlib::WebLogger(wLogger.url, wLogger.port, wLogger.showType, wLogger.jsonFormat, wLogger.types);
for(auto t : wLogger.types)
{
loggerlib::WebLogger::addLogger((loggerlib::ELOGGER_TYPES) t, lcout);
}
}
}
}
+40
View File
@@ -0,0 +1,40 @@
#ifndef INTERFACE_HPP
#define INTERFACE_HPP
#include "../../General/Logs/Loggers/WebLogger.h"
#include "../../General/Logs/Loggers/FileLogger.h"
#include "../../General/Logs/Loggers/StreamLogger.h"
#include "../../General/Configuration/Configurations.h"
namespace interfacelib {
/**
* @brief Classe dcrivant le lien entre l'api et un utilisateur extrieur
*/
class Interface {
private:
public:
/**
* @brief Constructeur par dfaut
*/
Interface() = default;
/**
* @brief Fonction de chargement des diffrentes configurations
* Si le fichier n'est pas bon ou qu'il n'existe pas, les valeurs par dfaut des configurations seront utilises
* @param[in] path le chemin vers le fichier de configuration. Par dfaut dans le dossier courant et nomm configuration.json
*/
static void initConfiguration(const std::string& path = "configuration.json");
/**
* @brief Fonction d'initialisation des diffrents logger, dpend de la configuration
*/
static void initLoggers();
/**
* @brief Destructeur, vide la mmoire des logger
*/
virtual ~Interface() {
loggerlib::Logger::destroy();
}
};
}
#endif
@@ -0,0 +1,95 @@
#include "InterfaceClassic.hpp"
#include "../Solver/solverAPI.h"
#include "../../General/Logs/IOHelper.h"
#include "../../General/Model/STFInstanceUtils.hpp"
namespace interfacelib {
void InterfaceClassic::directory(const std::filesystem::directory_entry &entry, const std::string &solver) {
std::filesystem::directory_iterator iter(entry);
std::filesystem::directory_iterator iterCount(entry);
unsigned int nbFiles = std::count_if(iterCount, {}, [](const std::filesystem::directory_entry &entry) {
return std::filesystem::is_regular_file(entry);
});
unsigned int count = 0;
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, std::to_string(nbFiles) + " instances trouvees");
//modellib::STFInstanceUtils::write_in_file("Comparaison_ISO_SWAP.csv", "\n Instance Name;Score;H1;H1;H2;H2;H3;H3;H4;H4;diag;sw;cp\n");
for (auto &ientry: iter) {
if (!ientry.is_directory()) {
configlib::Configuration::init("configuration.json");
file(ientry, solver);
count++;
double per = ((double) count / (double) nbFiles) * 100.0;
std::stringstream stream;
stream << std::fixed << std::setprecision(2) << per;
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, stream.str() + "%");
}
}
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, std::string("Finished"));
}
void InterfaceClassic::file(const std::filesystem::directory_entry &entry, const std::string &solver) {
std::ifstream file(entry.path());
modellib::STFInstance instance = modellib::STFInstance::createSTF(file);
file.close();
std::string filename = entry.path().filename().string().substr(0, entry.path().filename().string().find_last_of('.'));
if (instance.isValid() && configlib::Configuration::Global.SAVE_INPUT) {
auto json = instance.to_json();
auto jsonstr = json.dump(2);
loggerlib::IOHelper::dump(configlib::Configuration::Global.INPUT_LOCATION, jsonstr, filename);
}
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, std::string("Trying to launch solver on : ") +
entry.path().filename().string());
//modellib::STFInstanceUtils::write_in_file("Comparaison_ISO_SWAP.csv", entry.path().filename().string() + ";");
bool la = false;
if(solverlib::SolverAPI::apiFunctions.find(solver) != solverlib::SolverAPI::apiFunctions.end())
{
if(solver == "-HEURISTIC")
instance.init();
la = true;
solverlib::SolverAPI::apiFunctions[solver](instance, filename);
}
else
loggerlib::Logger::systemNotify(loggerlib::LOGGER_ERRORS, std::string("Cannot find specified solver in the API : ") + solver);
if (instance.isValid() && configlib::Configuration::Global.SAVE_OUTPUT) {
auto todump = instance.to_json();
todump = todump.at("planifications");
auto todumpstr = todump.dump(2);
if(configlib::Configuration::Global.OUTPUT_FILENAME)
{
loggerlib::IOHelper::dump(configlib::Configuration::Global.OUTPUT_LOCATION,
todumpstr, filename+"_p.json");
}
else
{
loggerlib::IOHelper::dump(configlib::Configuration::Global.OUTPUT_LOCATION,
todumpstr);
}
}
if(la && (solver == "-HEURISTIC"))
instance.clean();
}
void InterfaceClassic::redirect(const std::string &mode, const std::string &path, const std::string &solver) {
std::filesystem::directory_entry entry(path);
if (entry.exists()) {
if (solver.empty() && (mode == "--solve"))
loggerlib::FileLogger::systemNotify(loggerlib::LOGGER_INFO,
"WARNING solver argument is not set");
if (entry.is_directory()) {
if (mode == "--solve")
directory(entry, solver);
} else {
if (mode == "--solve")
file(entry, solver);
}
} else {
loggerlib::FileLogger::systemNotify(loggerlib::LOGGER_ERRORS, "Cannot find specified folder or instance:" + entry.path().string());
}
}
}
@@ -0,0 +1,43 @@
#ifndef INTERFACECLASSIC_HPP
#define INTERFACECLASSIC_HPP
#include <filesystem>
#include "Interface.hpp"
namespace interfacelib {
/**
* @brief Classe dcrivant une communication avec les solveurs au format direct en ligne de commande
*/
class InterfaceClassic : public Interface {
private:
/**
* @brief Fonction permettant la rsolution successive de toutes les instances d'un dossier
* @param[in] entry le dossier fourni
* @param[in] solver le nom du solveur utiliser
*/
static void directory(const std::filesystem::directory_entry &entry, const std::string &solver);
/**
* @brief Fonction permettant la rsolution d'une instance donne
* @param[in] entry le fichier contenant l'instance
* @param[in] solver le nom du solveur utiliser
*/
static void file(const std::filesystem::directory_entry &entry, const std::string &solver);
public:
/**
* @brief Constructeur par dfaut
*/
InterfaceClassic() = default;
/**
* @brief Fonction principale redirigeant sur les bons solveur en fonctions des paramtres
* @param[in] mode le mode choisi parmi le merge ou le solve (rsolution).
* @param[in] path le chemin vers le fichier ou dossier contenant l'/les instance(s)
* @param[in] solver le solveur utiliser dans le cas o mode = solve. Si solver n'est pas spcifi, par dfaut le solveur MIP sera appel
*/
static void redirect(const std::string &mode, const std::string &path, const std::string &solver = "");
};
}
#endif
@@ -0,0 +1,89 @@
#include "InterfaceServer.hpp"
#include "../../General/Logs/IOHelper.h"
#include "../Solver/solverAPI.h"
#include "../Solver/ConditionHolder.hpp"
#include <string>
#include <filesystem>
namespace interfacelib {
void InterfaceServer::initServer() {
m_server.new_task_queue = [] {
return new ThreadPool(1);
};//LIMIT THE NUMBER OF SIMULTANEOUS RESOLUTION TO 1 => TO CHANGE IT, MAKE THE HEURISTIC THREAD SAFE
m_server.Post("/Solver/LaunchSolver", [&](const Request &req, Response &res) {
loggerlib::WebLogger::systemNotify(loggerlib::LOGGER_INFO, "Request received trying to get instance and launch solver");
std::string body = req.body;
if (configlib::Configuration::Global.SAVE_INPUT) {
loggerlib::IOHelper::dump(configlib::Configuration::Global.INPUT_LOCATION, body);
}
modellib::STFInstance instance = modellib::STFInstance::createSTF(body);
loggerlib::WebLogger::systemNotify(loggerlib::LOGGER_INFO, "Launching solver on stf : " + instance.getIdStf() + " at : " +
modellib::SolverDate::todayStrFormat() + " on begindate : " +
instance.getDateDebutPlanification().to_json().dump());
instance.init();
solverlib::SolverAPI::solverHeuristic(instance, modellib::SolverDate::todayStrFormat() + "_" + instance.getIdStf());
nlohmann::json json;
json = instance.to_json()["planifications"];
res.body = json.dump();
instance.clean();
if (instance.isValid() && configlib::Configuration::Global.SAVE_OUTPUT) {
loggerlib::IOHelper::dump(configlib::Configuration::Global.OUTPUT_LOCATION, json.dump(2));
}
loggerlib::WebLogger::systemNotify(loggerlib::LOGGER_INFO, "Solver available for new request");
});
m_server.Get("/Solver/FetchData", [&](const Request &req, Response &res) {
std::filesystem::directory_entry entry(configlib::Configuration::Global.INPUT_LOCATION);
std::filesystem::directory_entry entry_plan(configlib::Configuration::Global.OUTPUT_LOCATION);
nlohmann::json json;
if (entry.exists()) {
if (entry.is_directory()) {
std::filesystem::directory_iterator iter(entry);
for (auto &ientry: iter) {
if (!ientry.is_directory()) {
std::ifstream file(ientry.path());
std::stringstream buf;
buf << file.rdbuf();
json["Instances"][ientry.path().filename().string()] = buf.str();
file.close();
}
}
}
}
if (entry_plan.exists()) {
if (entry_plan.is_directory()) {
std::filesystem::directory_iterator iter(entry_plan);
for (auto &ientry: iter) {
if (!ientry.is_directory()) {
std::ifstream file(ientry.path());
std::stringstream buf;
buf << file.rdbuf();
json["Planifications"][ientry.path().filename().string()] = buf.str();
file.close();
}
}
}
}
res.body = json.dump();
loggerlib::WebLogger::systemNotify(loggerlib::LOGGER_INFO, "Fetched Successfully, waiting for new request");
});
m_server.Get("/Solver/Version", [&](const Request &req, Response &res) {
res.body = configlib::Configuration::Meta.VERSION;
});
}
void InterfaceServer::listen() {
loggerlib::WebLogger::systemNotify(loggerlib::LOGGER_INFO, "Server started and waiting for requests");
std::cout << "Listening to " << configlib::Configuration::Interface.SOLVER_URL << ":"
<< configlib::Configuration::Interface.SOLVER_PORT << std::endl;
m_server.listen(configlib::Configuration::Interface.SOLVER_URL.c_str(), (int) configlib::Configuration::Interface.SOLVER_PORT);
}
}
@@ -0,0 +1,38 @@
#ifndef INTERFACESERVER_HPP
#define INTERFACESERVER_HPP
#include "Interface.hpp"
namespace interfacelib {
using namespace httplib;
/**
* @brief Classe décrivant une communication avec les solveurs au format serveur HTTP
*/
class InterfaceServer : public Interface {
private:
/**
* @brief Le serveur HTTP
*/
Server m_server;
public:
/**
* @brief Constructeur par defaut
*/
InterfaceServer() = default;
/**
* @brief Fonction d'initialisation du serveur, met en place les routes pour accéder aux solveurs
*/
void initServer();
/**
* @brief Fonction de démarrage du serveur, écoute pour les requêtes entrantes.
* Cette fonction est bloquant jusqu'à l'arrêt du serveur
*/
void listen();
};
}
#endif
@@ -0,0 +1,68 @@
#include "InterfaceTester.hpp"
#include "../Tester/TestManager.hpp"
#include "nlohmann/json_fwd.hpp"
namespace interfacelib {
void InterfaceTester::directory(const std::filesystem::directory_entry &entry, const std::string &solver) {
std::filesystem::directory_iterator iter(entry);
std::filesystem::directory_iterator iterCount(entry);
unsigned int nbFiles = std::count_if(iterCount, {}, [](const std::filesystem::directory_entry &entry) {
return std::filesystem::is_regular_file(entry);
});
unsigned int count = 0;
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, std::to_string(nbFiles) + " instances found");
for (auto &ientry: iter) {
if (!ientry.is_directory()) {
file(ientry, solver);
count++;
double per = ((double) count / (double) nbFiles) * 100.0;
std::stringstream stream;
stream << std::fixed << std::setprecision(2) << per;
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, stream.str() + "%");
}
}
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, std::string("All instances loaded and ready to start test procedure"));
}
void InterfaceTester::file(const std::filesystem::directory_entry &entry, const std::string &solver) {
std::ifstream file(entry.path());
std::ifstream fileConf(entry.path());
modellib::STFInstance instance = modellib::STFInstance::createSTF(file);
nlohmann::json config = nlohmann::json::parse(fileConf);
file.close();
fileConf.close();
std::string filename = entry.path().filename().string().substr(0, entry.path().filename().string().find_last_of('.'));
libTester::TestManager::registerInstance(std::move(instance), filename, config);
modellib::SolverDate::resetDateDebut();
}
void InterfaceTester::redirect(const std::string &mode, const std::string &path, const std::string &solver) {
std::filesystem::directory_entry entry(path);
if (entry.exists()) {
if (solver.empty() && (mode == "--test"))
loggerlib::FileLogger::systemNotify(loggerlib::LOGGER_INFO,
"WARNING solver argument is not set");
libTester::TestManager::init();
if (entry.is_directory()) {
if (mode == "--test")
directory(entry, solver);
} else {
if (mode == "--test")
{
loggerlib::FileLogger::systemNotify(loggerlib::LOGGER_INFO, "WARNING test should be used with multiple instances");
file(entry, solver);
}
}
libTester::TestManager::run(solver);
libTester::TestManager::reset();
} else {
loggerlib::FileLogger::systemNotify(loggerlib::LOGGER_ERRORS, "Cannot find specified folder or instance:" + entry.path().string());
}
}
}
@@ -0,0 +1,43 @@
#ifndef INTERFACETESTER_HPP
#define INTERFACETESTER_HPP
#include <filesystem>
#include "Interface.hpp"
namespace interfacelib {
/**
* @brief Classe dcrivant une communication avec les solveurs au format direct en ligne de commande
*/
class InterfaceTester : public Interface {
private:
/**
* @brief Fonction permettant la rsolution successive de toutes les instances d'un dossier
* @param[in] entry le dossier fourni
* @param[in] solver le nom du solveur utiliser
*/
static void directory(const std::filesystem::directory_entry &entry, const std::string &solver);
/**
* @brief Fonction permettant la rsolution d'une instance donne
* @param[in] entry le fichier contenant l'instance
* @param[in] solver le nom du solveur utiliser
*/
static void file(const std::filesystem::directory_entry &entry, const std::string &solver);
public:
/**
* @brief Constructeur par dfaut
*/
InterfaceTester() = default;
/**
* @brief Fonction principale redirigeant sur les bons solveur en fonctions des paramtres
* @param[in] mode le mode choisi parmi le merge ou le solve (rsolution).
* @param[in] path le chemin vers le fichier ou dossier contenant l'/les instance(s)
* @param[in] solver le solveur utiliser dans le cas o mode = solve. Si solver n'est pas spcifi, par dfaut le solveur MIP sera appel
*/
static void redirect(const std::string &mode, const std::string &path, const std::string &solver = "");
};
}
#endif
+120
View File
@@ -0,0 +1,120 @@
#include "Algorithm.h"
#include <ctime>
namespace solverlib {
Algorithm::Algorithm(STFInstance &stfInstance)
: _stfInstance(stfInstance) {
setDates();
//setNbRames();
/*setNbSitesMaintenance();
setNbGares();
setNbCreneauSites();
setNbVoies();
setBesoinNbTypesInfras();*/
}
void Algorithm::setDates() {
STFInstance stf = getStfInstance();
if (stf.getDateDebutPlanification().getAnnee() == 0U) {
time_t now = time(
nullptr); //returns the current calendar time of the system in number of seconds elapsed since January 1, 1970.
struct tm *timeLoc = localtime(&now);
/*struct tm {
int tm_sec; // seconds of minutes from 0 to 61
int tm_min; // minutes of hour from 0 to 59
int tm_hour; // hours of day from 0 to 24
int tm_mday; // day of month from 1 to 31
int tm_mon; // month of year from 0 to 11
int tm_year; // year since 1900
int tm_wday; // days since sunday
int tm_yday; // days since January 1st
int tm_isdst; // hours of daylight savings time
}*/
_dateDebut = modellib::SolverDate((1900 + timeLoc->tm_year), (1 + timeLoc->tm_mon), timeLoc->tm_mday,
timeLoc->tm_hour, timeLoc->tm_min);
_dateLimite = _dateDebut + configlib::Configuration::Solver.NB_DAYS_TO_PLANIF * 24U * configlib::Configuration::Global.TIME_UNIT;
} else {
_dateDebut = stf.getDateDebutPlanification();
_dateLimite =
_dateDebut + configlib::Configuration::Solver.NB_DAYS_TO_PLANIF * 24U * configlib::Configuration::Global.TIME_UNIT;//168
}
}
void Algorithm::setNbRames() {
_nbTotalRames = (_stfInstance.getRames()).size();
_nbHierarchies = {{1, 0},
{2, 0},
{3, 0},
{4, 0}}; //vector<unsigned int>(3, 0U);
bool signalement = true;
unsigned int i = 0U;
while (signalement && i < _nbTotalRames) {
if (_stfInstance.getRames()[i].getSignalements().empty()) {
signalement = false;
} else {
_nbHierarchies.at(_stfInstance.getRames()[i].getSignalements()[0U].getHierarchie()) += 1U;
}
++i;
}
_nbRamesSignalement =
_nbHierarchies.at(1U) + _nbHierarchies.at(2U) + _nbHierarchies.at(3U); //+ round(pow(exp(7 - 4), 2))
unsigned int nbRames = _nbRamesSignalement;
auto rfirst = _stfInstance.getRames().rbegin();
auto rit = _stfInstance.getRames().rbegin();
while ((*rfirst).getSignalements().empty() && rfirst != _stfInstance.getRames().rend()) {
++rfirst;
++rit;
}
while (rit != _stfInstance.getRames().rend() && nbRames > 0U) {
if ((*rit).getCreuxRoulement().empty()) {
rotate(rfirst, rit, rit + 1);
++rfirst;
--nbRames;
}
++rit;
}
_nbRamesAvRoulement = nbRames;
}
void Algorithm::setNbVoies() {
_nbVoies = 0U;
std::vector <MaintenanceSite> sitesM = _stfInstance.getSitesMaintenance();
for (unsigned int i = 0U; i < _nbSitesMaintenance; ++i) {
_nbVoies += sitesM[i].getVoies().size();
}
}
void Algorithm::setNbSitesMaintenance() { _nbSitesMaintenance = _stfInstance.getSitesMaintenance().size(); }
void Algorithm::setNbGares() { _nbGares = _stfInstance.getSites().size(); }
void Algorithm::setBesoinNbTypesInfras() {
_besoinTypesInfras = std::vector<std::string>();
for (auto &rame: _stfInstance.getRames()) {
for (auto ope: rame.getSignalements()) {
for (auto infra: ope.getInfrastructures()) {
auto infraIndex = find(_besoinTypesInfras.begin(), _besoinTypesInfras.end(), infra.getInfraType());
if (infraIndex >= _besoinTypesInfras.end()) {
_besoinTypesInfras.push_back(infra.getInfraType());
}
}
}
}
_nbTypesInfras = _besoinTypesInfras.size();
}
void Algorithm::setNbCreneauSites() {
_nbCreneauxSites = _stfInstance.getSiteMaintenance(0).getCapacieCreneaux().size();
}
void Algorithm::addPlanningSolution(const Planification &solution) {
_stfInstance.getPlanningSolution().push_back(solution);
}
}
+245
View File
@@ -0,0 +1,245 @@
#ifndef ALGORITHM_H
#define ALGORITHM_H
//#define IL_STD
#include "../../General/Model/STFInstance.h"
#include <algorithm>
#include <map>
#include <vector>
#include "../../General/Configuration/Configurations.h"
namespace solverlib {
using namespace modellib;
/** @file Algorithm.h*/
/** @class Algorithm
* @brief CLASSE ABSTRAITE POUR REPRESENTER N'IMPORTE QUEL ALGORITHME QUI RESOUT LE PROBLEME.
* @details Cette classe permet de représenter tout algorithme (resolution exacte comme approchee) qui peut résoudre le probleme.
* Tout algorithme possédera des donnees d'entrée et de sortie, ainsi qu'une méthode de resolution.
* @author Valentine Jourdan
* @date 07/2020
* @version 3
*/
class Algorithm {
private:
/**
* @brief L'instance à résoudre
*/
STFInstance &_stfInstance;
/**
* @brief La liste des types d'infrastructures
*/
std::vector<std::string> _besoinTypesInfras;
/**
* @brief La date de début de planification
*/
SolverDate _dateDebut;
/**
* @brief La date représentant l'horizon de planification
*/
SolverDate _dateLimite;
/**
* @brief Nombre total de rames
*/
unsigned int _nbTotalRames{};
/**
* @brief Nombre de rames avec des opérations à planifier
*/
unsigned int _nbRamesSignalement{};
/**
* @brief Nombre de rames avec des opérations et des disponibilités
*/
unsigned int _nbRamesAvRoulement{};
/**
* @brief Map contenant le nombre d'opération pour chaque hiérarchie
*/
std::map<unsigned int, unsigned int> _nbHierarchies;
/**
* @brief Le nombre de voie total
*/
unsigned int _nbVoies{};
/**
* @brief Le nombre de sites de maintenance
*/
unsigned int _nbSitesMaintenance{};
/**
* @brief Le nombre de site de gare (pas de maintenance possible)
*/
unsigned int _nbGares{};
/**
* @brief Le nombre d'infrastructure possible
*/
unsigned int _nbTypesInfras{};
/**
* @brief Le nombre de creneaux de travail pour les sites (non utilisé)
*/
unsigned int _nbCreneauxSites{};
/**
* @brief Fonction qui calcule la date à l'horizon de planification selon les configurations et l'instance
*/
void setDates();
/**
* @brief Fonction qui compte le nombre de rame selon certains critères (setter sur _nbRames...)
*/
void setNbRames();
/**
* @brief Setter sur le nombre de voie
*/
void setNbVoies();
/**
* @brief Setter sur le nombre de site de maintenance
*/
void setNbSitesMaintenance();
/**
* @brief Setter sur le nombre de sites de gare
*/
void setNbGares();
/**
* @brief Setter sur les types d'infrastructure et leur nombre
*/
void setBesoinNbTypesInfras();
/**
* @brief Setter sur les creneaux de travail des sites
*/
void setNbCreneauSites();
protected:
/*! @brief Ajoute une solution rsolue par l'algorithme.
* @param[in] solution Le planning obtenu par l'Algorithme.
*/
void addPlanningSolution(const Planification &solution);
public:
/** @brief Constructeur.
* @param[in] stfInstance Les données d'entrées de l'algorithme. Ce sont les données qui décrivent le problème.
*/
explicit Algorithm(STFInstance &stfInstance);
/** @brief Destructeur.
* @details Le destructeur est virtuel car la classe est abstraite.
*/
virtual ~Algorithm() = default;
/** @brief Getter sur les données d'entrée.
* @return Une référence à l'objet contenant les données d'entrée.
*/
STFInstance &getStfInstance() { return _stfInstance; }
/** @brief Getter sur la date horizon de planification.
* @return Une référence constante à la date de fin de planification.
*/
[[nodiscard]] SolverDate const &getDateLimite() const { return _dateLimite; }
/** @brief Getter sur la date de début de planification.
* @return Une référence constance à la date de début de planification.
*/
[[nodiscard]] SolverDate const &getDateDebut() const { return _dateDebut; }
/** @brief Getter sur le nombre de signalement h1.
* @return Le nombre de signalement h1.
*/
[[nodiscard]] unsigned int getNbH1() const { return _nbHierarchies.at(1U); }
/** @brief Getter sur le nombre de signalement h2.
* @return Le nombre de signalement h2.
*/
[[nodiscard]] unsigned int getNbH2() const { return _nbHierarchies.at(2U); }
/** @brief Getter sur le nombre de signalement h3.
* @return Le nombre de signalement h3.
*/
[[nodiscard]] unsigned int getNbH3() const { return _nbHierarchies.at(3U); }
/** @brief Getter sur le nombre de signalement h4.
* @return Le nombre de signalement h4.
*/
[[nodiscard]] unsigned int getNbH4() const { return _nbHierarchies.at(4U); }
/** @brief Getter sur le nombre total de rames.
* @return Le nombre total de rames.
*/
[[nodiscard]] unsigned int getNbTotalRames() const { return _nbTotalRames; }
/** @brief Getter sur le nombre de rames avec signalements.
* @return Le nombre de rames avec signalements.
*/
[[nodiscard]] unsigned int getNbRamesSignalement() const { return _nbRamesSignalement; }
/** @brief Getter sur le nombre de rames avec signalements et disponibilités.
* @return Le nombre de rames avec signalements et disponibilités.
*/
[[nodiscard]] unsigned int getNbRamesAvRoulement() const { return _nbRamesAvRoulement; }
/** @brief Getter sur le nombre de voies.
* @return Le nombre de voies.
*/
[[nodiscard]] unsigned int getNbVoies() const { return _nbVoies; }
/** @brief Getter sur le nombre de site de maintenance.
* @return Le nombre de sites de maintenance.
*/
[[nodiscard]] unsigned int getNbSitesMaintenance() const { return _nbSitesMaintenance; }
/** @brief Getter sur le nombre de gares.
* @return Le nombre de gares.
*/
[[nodiscard]] unsigned int getNbGares() const { return _nbGares; }
/** @brief Getter sur le nombre de type d'infrastructures possibles.
* @return Le nombre d'infrastructures différentes.
*/
[[nodiscard]] unsigned int getNbTypesInfras() const { return _nbTypesInfras; }
/** @brief Getter sur le nombre de creneaux de travail des sites.
* @return Le nombre de creneaux de travail des sites.
*/
[[nodiscard]] unsigned int getNbCreneauxSites() const { return _nbCreneauxSites; }
/** @brief Getter sur les types d'infrastructures.
* @return Une référence constante à la liste des types d'infra
*/
[[nodiscard]] std::vector<std::string> const &getBesoinTypesInfra() const { return _besoinTypesInfras; }
/** @brief Getter un type d'infrastructure.
* @param i l'indice de l'infrastructure dans la liste dont on veut le nom
* @return Une référence constante sur le nom de l'infrastructure
*/
[[nodiscard]] std::string const &getBesoinTypesInfra(const unsigned int i) const { return _besoinTypesInfras[i]; }
/** @brief Résout l'instance du problème.
* @details Résout le problème décrit par les données d'entrée, et rempli les données de sortie avec les résultats obtenus.
* @param[in] epsilon Un entier utilisé pour limiter le nombre de rejets dans la solution.
* @note cette fonction est virtuelle pure car elle s'adapte à chaque algorithme.
*/
virtual void solveInstance(const int &epsilon) = 0;
};
}
#endif // !ALGORITHM_H
+470
View File
@@ -0,0 +1,470 @@
#include "ConditionHolder.hpp"
#include <boost/type_traits/has_modulus.hpp>
#include <string>
namespace solverlib{
std::vector<std::function<bool(unsigned int rame, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state)>> ConditionHolder::rltValidationCheck_map;
std::vector<std::function<bool(modellib::CroisementUM& cr, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state)>> ConditionHolder::swapValidationCheck_map;
std::vector<std::function<bool(modellib::RecompoUM& cr, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state)>> ConditionHolder::compValidationCheck_map;
void ConditionHolder::init() {
rltValidationCheck_map.clear();
swapValidationCheck_map.clear();
compValidationCheck_map.clear();
if(configlib::Configuration::Solver.Conditions.RLT_WITH_UM_RDV_OR_US)
{
rltValidationCheck_map.emplace_back([&](unsigned int rame, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state){
auto& trStops = state->trajectoryStops;
if(trStops[tr].um_entree.ramesInfo.size() > 1)
{
if(trStops[tr].typeDispo.first != modellib::typeStop::RDVM)
{
for(auto& rid : trStops[tr].um_entree.ramesInfo)
{
auto found = std::find_if(state->trajectories[rid.id].begin(), state->trajectories[rid.id].end(), [&](auto& t){
auto cr1 = state->trajectoryStops[t].getDispoStop();
auto cr2 = state->trajectoryStops[t].getDispoStop();
return state->trajectoryStops[t].lieuArret == trStops[tr].lieuArret && modellib::CreneauHoraire::checkCommonDuration(cr1, cr2, 1);
});
if(found != state->trajectories[rid.id].end() && state->trajectoryStops[(*found)].typeDispo.first == modellib::typeStop::RDVM)
return true;
}
return false;
}
else
return true;
}
else
{
return true;
}
});
}
if(configlib::Configuration::Solver.Conditions.RLT_WITH_UM_RDV_OR_US_RDV)
{
rltValidationCheck_map.emplace_back([&](unsigned int rame, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state){
auto& trStops = state->trajectoryStops;
if(trStops[tr].um_entree.ramesInfo.size() > 1)
{
if(trStops[tr].typeDispo.first != modellib::typeStop::RDVM)
{
auto& opsOfRame = modellib::STFMockInstance::operationsOfRames[rame];
if(std::find_if(opsOfRame.begin(), opsOfRame.end(), [&](auto& el){return modellib::STFMockInstance::jobs[el]->getHierarchie() == 1;}) != opsOfRame.end())
return true;
for(auto& r : trStops[tr].um_entree.ramesInfo)
{
auto found = std::find_if(state->trajectories[r.id].begin(), state->trajectories[r.id].end(), [&](auto& t){
auto cr1 = state->trajectoryStops[t].getDispoStop();
auto cr2 = state->trajectoryStops[t].getDispoStop();
return state->trajectoryStops[t].lieuArret == trStops[tr].lieuArret && modellib::CreneauHoraire::checkCommonDuration(cr1, cr2, 1);
});
if(found != state->trajectories[r.id].end() && state->trajectoryStops[(*found)].typeDispo.first == modellib::typeStop::RDVM)
return true;
}
return false;
}
else
return true;
}
else
{
auto& operations = modellib::STFMockInstance::operationsOfRames[rame];
return trStops[tr].typeDispo.first == modellib::typeStop::RDVM || std::find_if(operations.begin(), operations.end(), [&](auto& el){return modellib::STFMockInstance::jobs[el]->getHierarchie() == 1;}) != operations.end();
}
});
}
if(configlib::Configuration::Solver.Conditions.SWAP_COMP_ON_NULL_US){
swapValidationCheck_map.emplace_back([&](modellib::CroisementUM& cr, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state){
bool has_null_us = false;
for(auto& us : cr.um_crit.ramesInfo){
if(modellib::STFMockInstance::rames[us.id]->getNumeroEF().substr(0,4) == "null"){
has_null_us = true;
break;
}
}
if(!has_null_us){
for(auto& us : cr.um_sane.ramesInfo){
if(modellib::STFMockInstance::rames[us.id]->getNumeroEF().substr(0,4) == "null"){
has_null_us = true;
break;
}
}
}
return !has_null_us;
});
compValidationCheck_map.emplace_back([&](modellib::RecompoUM& comp, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state){
bool has_null_us = ((modellib::STFMockInstance::rames[comp.recompo_done[0].rame_critique]->getNumeroEF().substr(0,4) == "null")
|| (modellib::STFMockInstance::rames[comp.recompo_done[0].rame_saine]->getNumeroEF().substr(0,4) == "null"));
return !has_null_us;
});
}
if(configlib::Configuration::Solver.Conditions.SWAP_NO_RDV)
{
swapValidationCheck_map.emplace_back([&](modellib::CroisementUM& cr, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state){
bool hasRdv = false;
auto& trStops = state->trajectoryStops;
for(auto& r : cr.um_crit.ramesInfo)
{
auto findRdv = std::find_if(state->trajectories[r.id].begin(), state->trajectories[r.id].end(), [&](auto& s){return trStops[tr].getDispoStop().getDebutC().getRelativeDate() < state->trajectoryStops[s].getDispoStop().getDebutC().getRelativeDate() && state->trajectoryStops[s].typeDispo.first == modellib::typeStop::RDVM;});
if(findRdv != state->trajectories[r.id].end())
{
hasRdv = true;
break;
}
}
for(auto& r : cr.um_sane.ramesInfo)
{
auto findRdv = std::find_if(state->trajectories[r.id].begin(), state->trajectories[r.id].end(), [&](auto& s){return trStops[tr].getDispoStop().getDebutC().getRelativeDate() < state->trajectoryStops[s].getDispoStop().getDebutC().getRelativeDate() && state->trajectoryStops[s].typeDispo.first == modellib::typeStop::RDVM;});
if(findRdv != state->trajectories[r.id].end())
{
hasRdv = true;
break;
}
}
return !hasRdv && std::find_if(modellib::STFInstance::getCurrentInstance()->getSitesMaintenance().begin(), modellib::STFInstance::getCurrentInstance()->getSitesMaintenance().end(), [&](auto& s){return trStops[tr].lieuArret->getRef() == s.getRef();}) == modellib::STFInstance::getCurrentInstance()->getSitesMaintenance().end();
});
}
if(configlib::Configuration::Solver.Conditions.SWAP_NOT_IMPERATIVE_RDV)
{
swapValidationCheck_map.emplace_back([&](modellib::CroisementUM& cr, const unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state){
bool hasRdv = false;
auto& trStops = state->trajectoryStops;
for(auto& r : cr.um_crit.ramesInfo)
{
auto findRdv = std::find_if(state->trajectories[r.id].begin(), state->trajectories[r.id].end(), [&](auto& s){return trStops[tr].getDispoStop().getDebutC().getRelativeDate() < state->trajectoryStops[s].getDispoStop().getDebutC().getRelativeDate() && state->trajectoryStops[s].typeDispo.first == modellib::typeStop::RDVM && modellib::STFMockInstance::stops[state->trajectoryStops[s].entree]->getImperative() == IMPERATIVE;});
if(findRdv != state->trajectories[r.id].end())
{
hasRdv = true;
break;
}
}
for(auto& r : cr.um_sane.ramesInfo)
{
auto findRdv = std::find_if(state->trajectories[r.id].begin(), state->trajectories[r.id].end(), [&](auto& s){return trStops[tr].getDispoStop().getDebutC().getRelativeDate() < state->trajectoryStops[s].getDispoStop().getDebutC().getRelativeDate() && state->trajectoryStops[s].typeDispo.first == modellib::typeStop::RDVM && modellib::STFMockInstance::stops[state->trajectoryStops[s].entree]->getImperative() == IMPERATIVE;});
if(findRdv != state->trajectories[r.id].end())
{
hasRdv = true;
break;
}
}
return !hasRdv && std::find_if(modellib::STFInstance::getCurrentInstance()->getSitesMaintenance().begin(), modellib::STFInstance::getCurrentInstance()->getSitesMaintenance().end(), [&](auto& s){return trStops[tr].lieuArret->getRef() == s.getRef();}) == modellib::STFInstance::getCurrentInstance()->getSitesMaintenance().end();
});
}
if(configlib::Configuration::Solver.Conditions.SWAP_ALL_RESCHEDULE_RDV)
{
swapValidationCheck_map.emplace_back([&](modellib::CroisementUM& cr, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state){
auto& trStops = state->trajectoryStops;
//todo ajouter le allowswap pour cas des sites multifonctions
bool isMaintenanceSite = std::find_if(modellib::STFInstance::getCurrentInstance()->getSitesMaintenance().begin(), modellib::STFInstance::getCurrentInstance()->getSitesMaintenance().end(), [&](auto& s){return trStops[tr].lieuArret->getRef() == s.getRef() && !s.getSwapEnabled();}) != modellib::STFInstance::getCurrentInstance()->getSitesMaintenance().end();
if(isMaintenanceSite)
return false;
std::vector<std::pair<unsigned int, unsigned int>> nextInForRdvUmCrit;
std::vector<std::pair<unsigned int, unsigned int>> nextInForRdvUmSane;
auto earliestUm_crit = modellib::CroisementUM::getEarliestTMArrival(cr.um_crit.ramesInfo, trStops, state->trajectories, cr.stopUMCrit.dispoStop.getFinC().getRelativeDate());
auto earliestUm_sane = modellib::CroisementUM::getEarliestTMArrival(cr.um_sane.ramesInfo, trStops, state->trajectories, cr.stopUMSane.dispoStop.getFinC().getRelativeDate());
bool umCritNotStop = false;
bool umSaneNotStop = false;
if(!earliestUm_crit.first || !earliestUm_sane.first)
{
umCritNotStop = !earliestUm_crit.first;
umSaneNotStop = !earliestUm_sane.first;
}
else {
//if(cr.sigDeclencheur->getHierarchie() == 1)
{
bool willBeLater = state->trajectoryStops[earliestUm_crit.second].dispoStop.getDebut().getRelativeDate() <= state->trajectoryStops[earliestUm_sane.second].dispoStop.getDebut().getRelativeDate();
bool notOriented = state->trajectoryStops[earliestUm_crit.second].typeDispo.first == modellib::typeStop::RDVM ? !modellib::STFMockInstance::preventiveMaintenanceRdvms[state->trajectoryStops[earliestUm_crit.second].rdvPreventif]->isOriented() : false;
notOriented = state->trajectoryStops[earliestUm_sane.second].typeDispo.first == modellib::typeStop::RDVM ? !modellib::STFMockInstance::preventiveMaintenanceRdvms[state->trajectoryStops[earliestUm_sane.second].rdvPreventif]->isOriented() : false;
if(willBeLater || notOriented)
return false;
}
}
//temporaire => évite les croisements inutiles => pas de possibilité de croisements multiples "chanceux"
//Si une rame ne rentre pas après le croisement et le croisement ne la fera pas rentrer non plus on skip
if(umCritNotStop && umSaneNotStop)
return false;
if(!umCritNotStop)
{
for(auto& r : cr.um_crit.ramesInfo)
{
auto findRdv = std::find_if(state->trajectories[r.id].begin(), state->trajectories[r.id].end(), [&](auto& s){return trStops[tr].getDispoStop().getDebutC().getRelativeDate() < state->trajectoryStops[s].getDispoStop().getDebutC().getRelativeDate() && modellib::CreneauHoraire::checkSlotsCompatibility(state->trajectoryStops[s].getDispoStop(), state->trajectoryStops[earliestUm_crit.second].getDispoStop()).first && state->trajectoryStops[s].typeDispo.first == modellib::typeStop::RDVM;
});
if(findRdv != state->trajectories[r.id].end())
{
nextInForRdvUmCrit.emplace_back(std::make_pair(trStops[(*findRdv)].rdvPreventif,(*findRdv)));
}
}
std::sort(nextInForRdvUmCrit.begin(), nextInForRdvUmCrit.end(), [&](auto& el, auto& el2){
return trStops[el.second].getDispoStop().getDebutC().getRelativeDate() < trStops[el2.second].getDispoStop().getDebutC().getRelativeDate();
});
auto remlongtermRdv = std::remove_if(nextInForRdvUmCrit.begin(), nextInForRdvUmCrit.end(), [&](auto& el){
return trStops[el.second].getDispoStop().getDebutC().getRelativeDate() > trStops[nextInForRdvUmCrit[0].second].getDispoStop().getFinC().getRelativeDate();
});
if(remlongtermRdv != nextInForRdvUmCrit.end())
{
nextInForRdvUmCrit.erase(remlongtermRdv, nextInForRdvUmCrit.end());
}
}
if(!umSaneNotStop)
{
for(auto& r : cr.um_sane.ramesInfo)
{
auto findRdv = std::find_if(state->trajectories[r.id].begin(), state->trajectories[r.id].end(), [&](auto& s){return trStops[tr].getDispoStop().getDebutC().getRelativeDate() < state->trajectoryStops[s].getDispoStop().getDebutC().getRelativeDate() && modellib::CreneauHoraire::checkSlotsCompatibility(state->trajectoryStops[s].getDispoStop(), state->trajectoryStops[earliestUm_sane.second].getDispoStop()).first && state->trajectoryStops[s].typeDispo.first == modellib::typeStop::RDVM;});
if(findRdv != state->trajectories[r.id].end())
{
nextInForRdvUmSane.emplace_back(std::make_pair(trStops[(*findRdv)].rdvPreventif,(*findRdv)));
}
}
std::sort(nextInForRdvUmSane.begin(), nextInForRdvUmSane.end(), [&](auto& el, auto& el2){
return trStops[el.second].getDispoStop().getDebutC().getRelativeDate() < trStops[el2.second].getDispoStop().getDebutC().getRelativeDate();
});
auto remlongtermRdvSa = std::remove_if(nextInForRdvUmSane.begin(), nextInForRdvUmSane.end(), [&](auto& el){
return trStops[el.second].getDispoStop().getDebutC().getRelativeDate() > trStops[nextInForRdvUmSane[0].second].getDispoStop().getFinC().getRelativeDate();
});
if(remlongtermRdvSa != nextInForRdvUmSane.end())
{
nextInForRdvUmSane.erase(remlongtermRdvSa, nextInForRdvUmSane.end());
}
}
bool ok = nextInForRdvUmCrit.size() == nextInForRdvUmSane.size();
if(!nextInForRdvUmCrit.empty() && nextInForRdvUmCrit.size() == nextInForRdvUmSane.size())
{
std::vector<std::vector<bool>> compats(nextInForRdvUmCrit.size(), std::vector<bool>(nextInForRdvUmSane.size(), false));
unsigned int id1 = 0;
for(auto& rdv: nextInForRdvUmCrit)
{
unsigned int id2 = 0;
for(auto& rdvComp: nextInForRdvUmSane)
{
bool f = std::find(modellib::STFMockInstance::rdvComp[rdv.first].begin(), modellib::STFMockInstance::rdvComp[rdv.first].end(), rdvComp.first) != modellib::STFMockInstance::rdvComp[rdv.first].end();
if(f)
{
compats[id1][id2] = f;
}
id2++;
}
id1++;
}
std::vector<unsigned int> permToTest(compats.size());
for (unsigned int i = 0; i < compats.size(); ++i) {
permToTest[i] = i;
}
bool valid = true;
do {
valid = true;
for (unsigned int i = 0; i < compats.size(); ++i) {
if (compats[i][permToTest[i]] != true) {
valid = false;
break;
}
}
} while (next_permutation(permToTest.begin(), permToTest.end()));
ok = valid;
if(ok)
{
for(auto& rdvCrit : nextInForRdvUmCrit)
{
if(trStops[earliestUm_sane.second].getDispoStop().getDebutC().getRelativeDate() > modellib::STFMockInstance::preventiveMaintenanceRdvms[rdvCrit.first]->getDeadline().getRelativeDate())
{
ok = false;
break;
}
}
for(auto& rdvSane : nextInForRdvUmSane)
{
if(trStops[earliestUm_crit.second].getDispoStop().getDebutC().getRelativeDate() > modellib::STFMockInstance::preventiveMaintenanceRdvms[rdvSane.first]->getDeadline().getRelativeDate())
{
ok = false;
break;
}
}
}
}
return ok;
});
}
if(true){
swapValidationCheck_map.emplace_back([&](modellib::CroisementUM& cr, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state){
std::pair<bool, unsigned int> stop_crit = {false, UINT_MAX};
for(auto rame : cr.stopUMCrit.um_entree.ramesInfo){
if(cr.trajectoireTM.initialNextStopTM[rame.id].first){
if(cr.trajectoireTM.initialNextStopTM[rame.id].second.dispoStop.getDebut().getRelativeDate() < stop_crit.second){
stop_crit = {true, cr.trajectoireTM.initialNextStopTM[rame.id].second.dispoStop.getDebut().getRelativeDate()};
}
}
}
std::pair<bool, unsigned int> stop_sain = {false, UINT_MAX};
for(auto rame : cr.stopUMSane.um_entree.ramesInfo){
if(cr.trajectoireTM.initialNextStopTM[rame.id].first){
if(cr.trajectoireTM.initialNextStopTM[rame.id].second.dispoStop.getDebut().getRelativeDate() < stop_sain.second){
stop_sain = {true, cr.trajectoireTM.initialNextStopTM[rame.id].second.dispoStop.getDebut().getRelativeDate()};
}
}
}
if(!stop_sain.second){
return false;
}
if(!stop_crit.first){
return true;
}
if((int)stop_crit.second - (int) stop_sain.second > (int)configlib::Configuration::Solver.Conditions.SWAP_MINIMALE_GAIN_TIME){
return true;
}
return false;
});
}
if(swapValidationCheck_map.empty())
{
swapValidationCheck_map.emplace_back([&](modellib::CroisementUM& cr, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state){
auto& trStops = state->trajectoryStops;
return std::find_if(modellib::STFInstance::getCurrentInstance()->getSitesMaintenance().begin(), modellib::STFInstance::getCurrentInstance()->getSitesMaintenance().end(), [&](auto& s){return trStops[tr].lieuArret->getRef() == s.getRef();}) == modellib::STFInstance::getCurrentInstance()->getSitesMaintenance().end();
});
}
if(configlib::Configuration::Solver.Conditions.COMP_ONLY_ON_EQU_RDV){
compValidationCheck_map.emplace_back([&](modellib::RecompoUM& comp, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state){
auto TMArrival_saine = modellib::RecompoUM::findTMRame(comp.recompo_done[0].rame_saine,
state->trajectories[comp.recompo_done[0].rame_saine],
state->trajectoryStops,
comp.stopRame_UMSane[0].dispoStop.getFin().getRelativeDate());
if(TMArrival_saine.first && (TMArrival_saine.second.typeDispo.first == modellib::typeStop::RDVM)){
auto TMArrival_crit = modellib::RecompoUM::findTMRame(comp.recompo_done[0].rame_critique,
state->trajectories[comp.recompo_done[0].rame_critique],
state->trajectoryStops,
comp.stopRame_UMCrit[0].dispoStop.getFin().getRelativeDate());
if(TMArrival_crit.first && (TMArrival_crit.second.typeDispo.first == modellib::typeStop::RDVM)){
bool f = std::find(modellib::STFMockInstance::rdvComp[TMArrival_crit.second.rdvPreventif].begin(), modellib::STFMockInstance::rdvComp[TMArrival_crit.second.rdvPreventif].end(), TMArrival_saine.second.rdvPreventif) != modellib::STFMockInstance::rdvComp[TMArrival_crit.second.rdvPreventif].end();
if(f){
return true;
}else{
return false;
}
}else{
return false;
}
}
return true;
});
}
if(configlib::Configuration::Solver.Conditions.COMP_TRIPLE_NOT_IN_MIDDLE){
compValidationCheck_map.emplace_back([&](modellib::RecompoUM& comp, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state){
if(!comp.is_double_recompo.first){
if(comp.um_crit_end.ramesInfo.size() == 3){
for(auto& us : comp.um_crit_init.ramesInfo){
if(us.id == comp.recompo_done[0].rame_critique){
if(us.rang == 2){
//loggerlib::Logger::systemNotify(loggerlib::LOGGER_DEBUG, "Filtré car au milieux d'un UM triple sur la rame critique");
return false;
}
break;
}
}
}
if(comp.um_saine_init.ramesInfo.size() == 3){
for(auto& us : comp.um_saine_init.ramesInfo){
if(us.id == comp.recompo_done[0].rame_saine){
if(us.rang == 2){
//loggerlib::Logger::systemNotify(loggerlib::LOGGER_DEBUG, "Filtré car au milieux d'un UM triple sur la rame saine");
return false;
}
break;
}
}
}
}
return true;
});
}
if(configlib::Configuration::Solver.Conditions.COMP_DOUBLE){
compValidationCheck_map.emplace_back([&](modellib::RecompoUM& comp, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state){
if(comp.is_double_recompo.first){
if(comp.um_crit_end.ramesInfo.size() == 3){
for(auto& us : comp.um_crit_init.ramesInfo){
if(us.id == comp.recompo_done[0].rame_critique){
if(us.rang != 2){
//loggerlib::Logger::systemNotify(loggerlib::LOGGER_DEBUG, "Filtré car au milieux d'un UM triple sur la rame critique");
return false;
}
break;
}
}
}
if(comp.um_saine_init.ramesInfo.size() == 3){
for(auto& us : comp.um_saine_init.ramesInfo){
if(us.id == comp.recompo_done[0].rame_saine){
if(us.rang != 2){
//loggerlib::Logger::systemNotify(loggerlib::LOGGER_DEBUG, "Filtré car au milieux d'un UM triple sur la rame saine");
return false;
}
break;
}
}
}
}
return true;
});
}
if(true){
compValidationCheck_map.emplace_back([&](modellib::RecompoUM& comp, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state){
unsigned short idx_rame_crit = 0;
unsigned short idx_rame_saine = 0;
for(unsigned short i=0; i<comp.UM_crit_TM_arrival.size(); i++){
if(comp.recompo_done[0].rame_critique == comp.um_crit_init.ramesInfo[i].id){
idx_rame_crit = i;
break;
}
}
for(unsigned short i=0; i<comp.UM_saine_TM_arrival.size(); i++){
if(comp.recompo_done[0].rame_saine == comp.um_saine_init.ramesInfo[i].id){
idx_rame_saine = i;
break;
}
}
/*** Si les condtions vérifié: ***/
/*** la rame ne rentre pas en TM ***/
if(!comp.UM_saine_TM_arrival[idx_rame_saine].first){
return false;
}
/*** la rame rentre alors qu'elle ne rentrais pas ***/
if(!comp.UM_crit_TM_arrival[idx_rame_crit].first){
return true;
}
unsigned short date_arrivee_saine = comp.UM_saine_TM_arrival[idx_rame_saine].second.dispoStop.getDebut().getRelativeDate();
unsigned short date_arrivee_crit = comp.UM_crit_TM_arrival[idx_rame_crit].second.dispoStop.getDebut().getRelativeDate();
/*** la rame rentre mais plus tard (cas particulier pour l'instant on autorise pas) (il rate des occasions car des fois c'est interessant) ***/
if(date_arrivee_saine > date_arrivee_crit){
if(date_arrivee_saine - date_arrivee_crit <= (int)configlib::Configuration::Solver.Conditions.COMP_MAXIMAL_PERTE_TIME){
comp.recompo_done[0].reason += "Rentre plus Tard de ~" + std::to_string(date_arrivee_saine - date_arrivee_crit) + " mais avantageux selon l'algo";
return true;
}
return false;
}
if(date_arrivee_crit - date_arrivee_saine >= (int)configlib::Configuration::Solver.Conditions.COMP_MINIMALE_GAIN_TIME){
return true;
}
if(comp.creatperfect_um){
comp.recompo_done[0].reason += "Gain inferieur à " + std::to_string(configlib::Configuration::Solver.Conditions.COMP_MINIMALE_GAIN_TIME) + "h mais créé un UM parfait";
return true;
}
return false;
});
}
if(compValidationCheck_map.empty()){
compValidationCheck_map.emplace_back([&](modellib::RecompoUM& comp, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state){
return true;
});
}
}
}
+56
View File
@@ -0,0 +1,56 @@
#ifndef ORDONNANCEMENTCORRECTIF_CONDITIONHOLDER_HPP
#define ORDONNANCEMENTCORRECTIF_CONDITIONHOLDER_HPP
#include <functional>
#include "../../General/Model/STFMockInstance.hpp"
namespace solverlib {
class ConditionHolder {
static std::vector<std::function<bool(unsigned int rame, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state)>> rltValidationCheck_map;
static std::vector<std::function<bool(modellib::CroisementUM& cr, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state)>> swapValidationCheck_map;
static std::vector<std::function<bool(modellib::RecompoUM& comp, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state)>> compValidationCheck_map;
public:
inline static bool rltValidationCheck(unsigned int rame, unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state)
{
bool valid = true;
for(auto& vc: rltValidationCheck_map)
{
valid = vc(rame, tr, state);
if(valid)
break;
}
return valid;
}
inline static bool swapValidationCheck(modellib::CroisementUM& cr, const unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state)
{
bool valid = true;
for(auto& vc: swapValidationCheck_map)
{
valid = vc(cr, tr, state);
//auto& trStops = state->trajectoryStops;
//valid = std::find_if(modellib::STFInstance::getCurrentInstance()->getSitesMaintenance().begin(), modellib::STFInstance::getCurrentInstance()->getSitesMaintenance().end(), [&](auto& s){return trStops[tr].lieuArret->getRef() == s.getRef();}) == modellib::STFInstance::getCurrentInstance()->getSitesMaintenance().end();
if(!valid)
return false;
}
return valid;
}
//TODO Axel - attention le premier paramètre est a adapter, d'où la virgule
inline static bool compValidationCheck(modellib::RecompoUM& comp, const unsigned int tr, std::shared_ptr<modellib::STFMockInstance> state)
{
bool valid = true;
for(auto& vc: compValidationCheck_map)
{
valid = vc(comp, tr, state);
if(!valid)
return false;
}
return valid;
}
static void init();
};
#endif
}
+694
View File
@@ -0,0 +1,694 @@
#include "DedicatedHeuristic.h"
#include "GraphTreeNode.hpp"
#include "InstanceStats.h"
#include "Recoverer.hpp"
#include "../../General/Model/STFInstance.h"
#include "../../General/Model/STFInstanceUtils.hpp"
#include <algorithm>
#include <climits>
#include <memory>
#include <string>
#include <utility>
namespace solverlib {
//! Default constructor for the dedicated heuristic
/*!
* Create the heuristic and initialize data lists and the graph manager
* @param MainController* mainController : the pointer to the main controller of the instance to solve
*/
DedicatedHeuristic::DedicatedHeuristic(STFInstance &instance)
: Algorithm(instance) {
}
//! Build the graph
/*!
* Build the max flow min cost graph with all data lists
*/
void DedicatedHeuristic::buildGraph(std::shared_ptr<GraphTreeNode>node) {
//sorter()(getStfInstance().mockInstance->opRames, OP_SORTING_RULE::HIERARCHIE_NBDISPO_ASC);
pgraphManager = GraphTreeNode::buildGraphFromState(node);
}
//! Apply a pretreatment on the graph
/*!
* Look in the graph to train time slots which involve infeasibility
*/
void DedicatedHeuristic::graphPretreatment() {
//todo
}
void DedicatedHeuristic::selectBestRules(std::vector<std::pair<unsigned long long, std::pair<OP_SORTING_RULE, DISPO_VOIE_RAME_SORTING_RULE>>>& bestRules){
GraphTreeNode::borneSup = ULLONG_MAX;
for (auto &opSort: opMapRule) {
for(auto& dispSort : dispVoieRameMapRule)
{
std::unordered_map<unsigned short, decision> decisions = getStfInstance().previousInformations.initialDecisions;
std::array<std::unordered_set<std::pair<unsigned int, unsigned int>>, 2> filters;
ListHeuristic h(decisions, filters);
h.no_planif = false;
unsigned long long obj = h.solveModeDispVoieRame(opSort.first, dispSort.first).second;
if (obj < GraphTreeNode::borneSup) {
GraphTreeNode::borneSup = obj;
/*if(GraphTreeNode::ubBestKnown.getPlanificationState())
delete GraphTreeNode::ubBestKnown.getPlanificationState();*/
GraphTreeNode::ubBestKnown = h.planning;
GraphTreeNode::ubBestKnown.setPlanificationState(STFMockInstance::copy(getStfInstance().mockInstance));
}
if(bestRules.size() < configlib::Configuration::Solver.RBS.NB_LISTHEURISTICS)
{
bestRules.push_back({obj, {opSort.first, dispSort.first}});
std::sort(bestRules.begin(), bestRules.end(), [&](auto& el1, auto& el2){
return el1.first < el2.first;
});
}
else
{
for(auto best = bestRules.begin(); best != bestRules.end(); best++)
{
if((*best).first > obj)
{
bestRules.insert(best, {obj,{opSort.first, dispSort.first}});//les x meilleures ??
if(bestRules.size() > configlib::Configuration::Solver.RBS.NB_LISTHEURISTICS)
bestRules.pop_back();
break;
}
}
}
/*if(bestRules.empty())
{
bestRules.push_back({obj, {opSort.first, dispSort.first}});
}
else
{
for(auto best = bestRules.begin(); best != bestRules.end(); best++)
{
if((*best).first > obj)
{
bestRules.insert(best, {obj,{opSort.first, dispSort.first}});//les x meilleures ??
if(bestRules.size() > configlib::Configuration::Solver.RBS.NB_LISTHEURISTICS)
bestRules.pop_back();
break;
}
}
}*/
}
}
sorter()(getStfInstance().mockInstance,getStfInstance().mockInstance->jobOrder, bestRules[0].second.first);
for(auto b : bestRules)
ListHeuristic::sortingRules.push_back(b.second);
}
void DedicatedHeuristic::createGraphe(unsigned int nbBranch, std::shared_ptr<GraphTreeNode> root){
GraphTreeNode::nbBranch = nbBranch;
GraphTreeNode::Alpha = configlib::Configuration::Solver.RBS.FLOW ? configlib::Configuration::Solver.RBS.ALPHA : 0.0f;
GraphTreeNode::ms_rootRef = root;
GraphTreeNode::nodesToProcess.push(root);
root->setRootStatus(true);
root->getData().setCurrentState(STFMockInstance::copy(getStfInstance().mockInstance));
root->getData().getDecisions() = getStfInstance().previousInformations.initialDecisions;
//GraphTreeNode::ubBestKnown.setPlanificationState(STFMockInstance::copy(root->getData().getCurrentState()));
root->evolutiveAlpha = GraphTreeNode::Alpha;
//GraphTreeNode::mockCounter[root->getData().getCurrentState()]++;
buildGraph(root);
root->pgraphManager = pgraphManager;
//GraphTreeNode::pointerCounter[pgraphManager]++;
GraphTreeNode::m_lastOperation = root->getData().getCurrentState()->jobOrder.size();
unsigned long long borneInf = 0;
if (configlib::Configuration::Solver.RBS.FLOW) {
borneInf = solverlib::GraphTreeNode::estimateLongTermCost(root).second;
root->getData().setFlowCostOfNode(borneInf);
GraphTreeNode::updateEvolutiveAlpha(root);
}
GraphTreeNode::borneInf = borneInf;
}
void DedicatedHeuristic::rbs(unsigned int nbBranch, unsigned int nbSolution, std::vector<Planification>& planning) {
auto presolveBegin = std::chrono::system_clock::now();
std::vector<std::pair<unsigned long long, std::pair<OP_SORTING_RULE, DISPO_VOIE_RAME_SORTING_RULE>>> bestRules;
selectBestRules(bestRules);
auto root = std::make_shared<GraphTreeNode>();
createGraphe(nbBranch, root);
std::chrono::duration<double> presolveTime = std::chrono::system_clock::now() - presolveBegin;
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Initial alpha: " + std::to_string(root->evolutiveAlpha));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Lambda: " + std::to_string(root->lambda));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Vertice number: " + std::to_string(pgraphManager->getNbVertices()));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Initial Min Cost Max Flow value: " + std::to_string(GraphTreeNode::borneInf));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Initial upper bound: " + std::to_string(GraphTreeNode::borneSup));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Presolve time: " + std::to_string(presolveTime.count()));
std::string HeaderLogs;
if(configlib::Configuration::Logs.ALGO_VERBOSE) {
HeaderLogs += "Lev | Prog | Alph | Node | SNode| CNode";
if(configlib::Configuration::Logs.ALGO_VERBOSE_NODES)
{
HeaderLogs += " | FNode | FSNode| FComp";
}
if(configlib::Configuration::Logs.ALGO_VERBOSE_HEURISTICS)
{
HeaderLogs +=" | TSNCr | TSubPb | TFlowMCM (TLbdU) | TLiHeur | TRecov";
}
HeaderLogs += " | ITime | TTime | Objective | LowerBound | UpperBound | FlowMCM | EstimatedTime";
std::string sub = "|";
size_t pos = HeaderLogs.find(sub, 0);
while(pos != std::string::npos)
{
logoffsetcolumns.push_back(pos);
pos = HeaderLogs.find(sub,pos+1);
}
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS,
HeaderLogs);
}
int countIte = 0;
float time = 0.0f;
std::vector<float> times;
times.reserve(GraphTreeNode::m_lastOperation);
float meanttime = 0.0f;
float timeIte = 0.0f;
//bool ubbestknownadded = false;
float totaltimefl = 0.0f;
float totaltimelh = 0.0f;
float totaltimelbd = 0.0f;
float totaltimerecover = 0.0f;
float totaltimecreatingSN = 0.0f;
float totaltimeOneMachineSubPb = 0.0f;
auto beginIterations = std::chrono::system_clock::now();
while (!GraphTreeNode::nodesToProcess.empty()) {
timeIte = 0.0;
auto iterTime = std::chrono::system_clock::now();
float timeRecovering = 0.0;
while(GraphTreeNode::nodesToProcess.front()->m_deepIndicator != GraphTreeNode::m_lastOperation && getStfInstance().previousInformations.initialDecisions.find(GraphTreeNode::nodesToProcess.front()->getData().getCurrentState()->jobOrder[GraphTreeNode::nodesToProcess.front()->m_deepIndicator]) != getStfInstance().previousInformations.initialDecisions.end())
{
GraphTreeNode::nodesToProcess.front()->m_deepIndicator++;
}
GraphTreeNode::nodesToProcess.front()->rbs();
GraphTreeNode::nodesToProcess.pop();
if(nbBranch == 1 && !GraphTreeNode::levelsSons.empty()) {
if(GraphTreeNode::levelsSons.front()->getData().getCompNodeStatus()){
if(GraphTreeNode::levelsSons.front()->getData().getRecompo()->is_double_recompo.first){
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Type of node : CompNode Double");
}else{
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Type of node : CompNode");
}
}else if(GraphTreeNode::levelsSons.front()->getData().getSwapNodeStatus()){
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Type of node : SwapNode");
}else if(GraphTreeNode::levelsSons.front()->getData().getScheduledStatus()){
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Type of node : Affectation");
}else if(GraphTreeNode::levelsSons.front()->getData().getRejectedStatus()){
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Type of node : Diagnostique");
}else{
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS, "Type of node : Rejeté");
}
}
if (GraphTreeNode::nodesToProcess.empty()) {
unsigned int level = 0;
float alphaLevel = 0.0f;
unsigned long long flowCostLevel = 0;
unsigned long long realCostLevel = 0;
unsigned long long lowerboundLevel = 0;
if (!GraphTreeNode::levelsSons.empty()) {
level = GraphTreeNode::levelsSons.front()->m_deepIndicator;
alphaLevel = GraphTreeNode::levelsSons.front()->evolutiveAlpha;
lowerboundLevel = GraphTreeNode::levelsSons.front()->lowerBound;
realCostLevel = GraphTreeNode::levelsSons.front()->getData().getRealCost();
flowCostLevel = GraphTreeNode::levelsSons.front()->getData().getFlowCostOfNode() + realCostLevel;
unsigned int count = 0;
//si timelimit
if (meanttime > configlib::Configuration::Solver.T_LIM_GLOBAL * 0.95) {
if(configlib::Configuration::Solver.RBS.LISTHEURISTICS)//si ub claculée uniquement
{
planning.push_back(GraphTreeNode::ubBestKnown);
//ubbestknownadded = true;
}
count++;
GraphTreeNode::levelsSons.sort([](std::shared_ptr<GraphTreeNode>n1, std::shared_ptr<GraphTreeNode>n2) {
if (n1->getData().getRealCost() < n2->getData().getRealCost()) {
return true;
} else if (n1->getData().getRealCost() == n2->getData().getRealCost()) {
return GraphTreeNode::countDiag(n1) < GraphTreeNode::countDiag(n2);
} else{
return GraphTreeNode::countSwaps(n1) < GraphTreeNode::countSwaps(n2);
}
});
for (auto son: GraphTreeNode::levelsSons)
{
if (count < GraphTreeNode::nbBranch && planning.size() < nbSolution) {
std::array<std::unordered_set<std::pair<unsigned int, unsigned int>>, 2> filters;
ListHeuristic h(son->getData().getDecisions(), filters, son->getData().getCurrentState());
h.no_planif = false;
h.solveModeDispVoieRame(ListHeuristic::sortingRules[0].first, ListHeuristic::sortingRules[0].second);
h.planning.setPlanificationState(STFMockInstance::copy(son->getData().getCurrentState()));
planning.push_back(h.planning);
count++;
}
}
}
else//cas branchement à nbbranch > 1, s'assurer qu'on ne passe au niveau suivant que quand un noeud d'affectation est choisi ? sinon on risque de comparer des choses ensemble qui n'ont pas de sens ? je ne sais pas trop
{
for (auto son: GraphTreeNode::levelsSons) {
if (count < GraphTreeNode::nbBranch) {
auto beginRecover = std::chrono::system_clock::now();
std::dynamic_pointer_cast<GraphTreeNode>(son->getParent().lock())->getData().cleanGraphData();
Recoverer::recover(son);
std::chrono::duration<float> diffR = std::chrono::system_clock::now() - beginRecover;
totaltimerecover += diffR.count();
timeRecovering = diffR.count();
if(son->getData().getRealCost() <= GraphTreeNode::borneSup || !planning.empty())
{
GraphTreeNode::nodesToProcess.push(son);
}
else if(planning.empty())
{
planning.push_back(GraphTreeNode::ubBestKnown);
//ubbestknownadded = true;
}
count++;
}
}
}
GraphTreeNode::levelsSons.clear();
}
if (GraphTreeNode::getLeafs().empty()) {
std::chrono::duration<float> diff = std::chrono::system_clock::now() - iterTime;
timeIte += diff.count();
meanttime += timeIte;
times.push_back(timeIte);
countIte++;
float per = ((float) level/
(float) (GraphTreeNode::m_lastOperation)) * 100.0f;
float estimate = (meanttime / (float) times.size()) *
((float) (GraphTreeNode::m_lastOperation) -(float)(level)) +
meanttime;
logs(countIte, per, alphaLevel, GraphTreeNode::count_nodes, GraphTreeNode::count_swap_nodes, GraphTreeNode::count_comp_nodes, GraphTreeNode::count_filtered, GraphTreeNode::count_filtered_swap, GraphTreeNode::count_filtered_comp, GraphTreeNode::timesOfLevels[0], GraphTreeNode::timesOfLevels[1], GraphTreeNode::timesOfLevels[2], timeRecovering, GraphTreeNode::timesOfLevels[4], GraphTreeNode::timesOfLevels[3],timeIte, meanttime, realCostLevel, flowCostLevel, GraphTreeNode::borneSup, estimate, lowerboundLevel);
totaltimeOneMachineSubPb += GraphTreeNode::timesOfLevels[0];
totaltimefl += GraphTreeNode::timesOfLevels[1];
totaltimelh += GraphTreeNode::timesOfLevels[2];
totaltimelbd += GraphTreeNode::timesOfLevels[3];
totaltimecreatingSN += GraphTreeNode::timesOfLevels[4];
GraphTreeNode::timesOfLevels[0] = 0;
GraphTreeNode::timesOfLevels[1] = 0;
GraphTreeNode::timesOfLevels[2] = 0;
GraphTreeNode::timesOfLevels[3] = 0;
GraphTreeNode::timesOfLevels[4] = 0;
GraphTreeNode::numbersOfLevels[0] = 0;
GraphTreeNode::numbersOfLevels[1] = 0;
GraphTreeNode::numbersOfLevels[2] = 0;
GraphTreeNode::numbersOfLevels[3] = 0;
GraphTreeNode::numbersOfLevels[4] = 0;
GraphTreeNode::total_count_nodes += GraphTreeNode::count_nodes;
GraphTreeNode::total_count_swap_nodes += GraphTreeNode::count_swap_nodes;
GraphTreeNode::total_count_comp_nodes+= GraphTreeNode::count_comp_nodes;
GraphTreeNode::total_count_filtered_node += GraphTreeNode::count_filtered;
GraphTreeNode::total_count_filtered_swap += GraphTreeNode::count_filtered_swap;
GraphTreeNode::total_count_filtered_comp += GraphTreeNode::count_filtered_comp;
GraphTreeNode::count_nodes = 0;
GraphTreeNode::count_filtered = 0;
GraphTreeNode::count_filtered_swap = 0;
GraphTreeNode::count_filtered_comp = 0;
GraphTreeNode::count_swap_nodes = 0;
GraphTreeNode::count_comp_nodes = 0;
}
}
}
Recoverer::triedExcluded.clear();
std::chrono::duration<float> diff = std::chrono::system_clock::now() - beginIterations;
time += diff.count();
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Solving took : " + std::to_string(time) + "s");
if(!GraphTreeNode::getLeafs().empty())
{
GraphTreeNode::getLeafs().sort([](std::weak_ptr<GraphTreeNode>n1, std::weak_ptr<GraphTreeNode>n2) {
if (n1.lock()->getData().getRealCost() < n2.lock()->getData().getRealCost()) {
return true;
} else if (n1.lock()->getData().getRealCost() == n2.lock()->getData().getRealCost()) {
return GraphTreeNode::countDiag(n1.lock()) < GraphTreeNode::countDiag(n2.lock());
} else {
return GraphTreeNode::countSwaps(n1.lock()) < GraphTreeNode::countSwaps(n2.lock());
}
});
for(auto leaf : GraphTreeNode::getLeafs())
{
if(planning.size() < nbSolution)
{
Planification plan;
auto& decisions = leaf.lock()->getData().getDecisions();
auto& swaps = leaf.lock()->getData().getCurrentState()->swaps;
auto& recompo = leaf.lock()->getData().getCurrentState()->recompos;
auto& trStops = leaf.lock()->getData().getCurrentState()->trajectoryStops;
for(auto& d : decisions)
{
if(!d.second.excluded)
{
unsigned int rameId = STFMockInstance::rameOfOperations[d.first];
STFMockInstance::jobs[d.first]->setIdRame(STFMockInstance::rames[rameId]->getId());
STFMockInstance::jobs[d.first]->setNumeroEF(STFMockInstance::rames[rameId]->getNumeroEF());
bool isPCr = trStops[d.second.empR].typeDispo.first == typeStop::RLT_POST_CROISEMENT_SUBIT || trStops[d.second.empR].typeDispo.first == typeStop::RLT_POST_CROISEMENT_VOULU;
std::pair<unsigned short, unsigned short> slot = d.second.rejected ? std::make_pair(d.second.lastCreneau.first, d.second.lastCreneau.first + STFMockInstance::jobs[d.first]->getDureeDiag()) : std::make_pair(d.second.lastCreneau.first, d.second.lastCreneau.first + STFMockInstance::jobs[d.first]->getDuree());
OperationPlanifie opPlan(d.first, d.second.voie, d.second.site, d.second.empR, d.second.empV, slot, d.second.rejected, isPCr);
plan.addOperation(opPlan);
}
else
{
unsigned int rameId = STFMockInstance::rameOfOperations[d.first];
STFMockInstance::jobs[d.first]->setIdRame(STFMockInstance::rames[rameId]->getId());
STFMockInstance::jobs[d.first]->setNumeroEF(STFMockInstance::rames[rameId]->getNumeroEF());
plan.getOpImplanifiables().push_back(d.first);
}
}
for(auto& s : swaps)
{
plan.getCroisementsEffectues().push_back(*s);
}
for(auto& comp : recompo){
plan.getRecompositionsEffectuees().push_back(*comp);
}
plan.setPlanificationState(STFMockInstance::copy(leaf.lock()->getData().getCurrentState()));
planning.push_back(plan);
}
}
}
for(auto& plan : planning){
plan.cleanSwap();
}
std::sort(planning.begin(), planning.end(), [&](Planification& pl, Planification& pl2){
long obj1 = pl.sommeRetardsPonderes(true);
long obj2 = pl2.sommeRetardsPonderes(true);
if(obj1 != obj2)
return obj1 < obj2;
else if(pl.sommeRejets() != pl2.sommeRejets())
return pl.sommeRejets() < pl2.sommeRejets();
else
return pl.getCroisementsEffectues().size() < pl2.getCroisementsEffectues().size();
});
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Total time spent in flow: " + std::to_string(totaltimefl)+ "s including " + std::to_string(totaltimelbd) + "s of updating lambda value");
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Total time spent in lh: " + std::to_string(totaltimelh));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Total time spent in recovering: " + std::to_string(totaltimerecover));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Total time spent in creating swapNodes: " + std::to_string(totaltimecreatingSN));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Total time spent in subproblem: " + std::to_string(totaltimeOneMachineSubPb));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Explored nodes: " + std::to_string(GraphTreeNode::total_count_nodes));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Explored swap nodes: " + std::to_string(GraphTreeNode::total_count_swap_nodes));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Explored comp nodes: " + std::to_string(GraphTreeNode::total_count_comp_nodes));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Filtered nodes: " + std::to_string(GraphTreeNode::total_count_filtered_node));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Filtered swap nodes: " + std::to_string(GraphTreeNode::total_count_filtered_swap));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Filtered comp nodes: " + std::to_string(GraphTreeNode::total_count_filtered_comp));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Total filtered nodes: " + std::to_string(GraphTreeNode::total_count_filtered_swap + GraphTreeNode::total_count_filtered_node + GraphTreeNode::total_count_filtered_comp));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Solutions: " + std::to_string(planning.size()));
if (InstanceStatsHeuristic::getCurrentInstance() != nullptr && !planning.empty()) {
InstanceStatsHeuristic::getCurrentInstance()->nbH1Exclu = planning[0].countExcluded(1);
InstanceStatsHeuristic::getCurrentInstance()->nbH2Exclu = planning[0].countExcluded(2);
InstanceStatsHeuristic::getCurrentInstance()->nbH3Exclu = planning[0].countExcluded(3);
InstanceStatsHeuristic::getCurrentInstance()->nbDiag = planning[0].countDiag();
InstanceStatsHeuristic::getCurrentInstance()->nbDiagH1 = planning[0].countDiag(1);
InstanceStatsHeuristic::getCurrentInstance()->nbDiagH2 = planning[0].countDiag(2);
InstanceStatsHeuristic::getCurrentInstance()->nbDiagH3 = planning[0].countDiag(3);
InstanceStatsHeuristic::getCurrentInstance()->nbNode = GraphTreeNode::total_count_nodes;
InstanceStatsHeuristic::getCurrentInstance()->nbFilteredNode = GraphTreeNode::total_count_filtered_node;
InstanceStatsHeuristic::getCurrentInstance()->nbSwapNode = GraphTreeNode::total_count_swap_nodes;
InstanceStatsHeuristic::getCurrentInstance()->nbFilteredSwapNode = GraphTreeNode::total_count_filtered_swap;
for(auto& op : planning[0].getOperationsPlan())
{
unsigned int dueDate = STFMockInstance::jobs[op.getOperationRequise()]->getDateDue().getRelativeDate();
if (op.getCreneauHoraire().getDebut().getRelativeDate() > dueDate) {
InstanceStatsHeuristic::getCurrentInstance()->nbH1Retard += STFMockInstance::jobs[op.getOperationRequise()]->getHierarchie() == 1;
InstanceStatsHeuristic::getCurrentInstance()->nbH2Retard += STFMockInstance::jobs[op.getOperationRequise()]->getHierarchie() == 2;
InstanceStatsHeuristic::getCurrentInstance()->nbH3Retard += STFMockInstance::jobs[op.getOperationRequise()]->getHierarchie() == 3;
InstanceStatsHeuristic::getCurrentInstance()->avgLatenessH1 += (float)(STFMockInstance::jobs[op.getOperationRequise()]->getHierarchie() == 1) *
(float)(op.getCreneauHoraire().getDebut().getRelativeDate() -
dueDate);
InstanceStatsHeuristic::getCurrentInstance()->avgLatenessH2 += (float)(STFMockInstance::jobs[op.getOperationRequise()]->getHierarchie() == 2) *
(float)(op.getCreneauHoraire().getDebut().getRelativeDate() -
dueDate);
InstanceStatsHeuristic::getCurrentInstance()->avgLatenessH3 += (float)(STFMockInstance::jobs[op.getOperationRequise()]->getHierarchie() == 3) *
(float)(op.getCreneauHoraire().getDebut().getRelativeDate() -
dueDate);
}
}
if (InstanceStatsHeuristic::getCurrentInstance()->nbH1Retard != 0)
InstanceStatsHeuristic::getCurrentInstance()->avgLatenessH1 /= (float) InstanceStatsHeuristic::getCurrentInstance()->nbH1Retard;
if (InstanceStatsHeuristic::getCurrentInstance()->nbH2Retard != 0)
InstanceStatsHeuristic::getCurrentInstance()->avgLatenessH2 /= (float) InstanceStatsHeuristic::getCurrentInstance()->nbH2Retard;
if (InstanceStatsHeuristic::getCurrentInstance()->nbH3Retard != 0)
InstanceStatsHeuristic::getCurrentInstance()->avgLatenessH3 /= (float) InstanceStatsHeuristic::getCurrentInstance()->nbH3Retard;
InstanceStatsHeuristic::getCurrentInstance()->setTime(time);
InstanceStatsHeuristic::getCurrentInstance()->setFctObj(planning[0].sommeRetardsPonderes(true));
InstanceStatsHeuristic::getCurrentInstance()->setSolutionStatus(planning[0].countExcluded() == 0);
InstanceStatsHeuristic::getCurrentInstance()->setNbExclusion(planning[0].countExcluded());
InstanceStatsHeuristic::getCurrentInstance()->setNbBranch(nbBranch);
InstanceStatsHeuristic::getCurrentInstance()->setBorneInf(GraphTreeNode::borneInf);
InstanceStatsHeuristic::getCurrentInstance()->setBorneSup(GraphTreeNode::borneSup);
InstanceStatsHeuristic::getCurrentInstance()->setNbCroisement(planning[0].countSwap());
InstanceStatsHeuristic::getCurrentInstance()->setStatus("Heuristic");
}
/*if(!ubbestknownadded)
delete GraphTreeNode::ubBestKnown.getPlanificationState();*/
}
void DedicatedHeuristic::solve(unsigned int nbBranch, unsigned int nbSolution) {
std::vector<Planification> solutions;
rbs(nbBranch, nbSolution, solutions);
for(auto& pl : solutions) {
/*for(auto& s : pl.getPlanificationState()->swaps)
{
pl.getCroisementsEffectues().push_back(*s);
}*/
auto pos = std::remove_if(pl.getOperationsPlan().begin(), pl.getOperationsPlan().end(), [&](modellib::OperationPlanifie& opPlan){
return STFMockInstance::jobs[opPlan.getOperationRequise()]->getPropositionExistante().exists && STFMockInstance::jobs[opPlan.getOperationRequise()]->getPropositionExistante().isKeep;
});
pl.getOperationsPlan().erase(pos, pl.getOperationsPlan().end());
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Swaps: " + std::to_string(pl.getPlanificationState()->swaps.size()));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Comp: " + std::to_string(pl.getPlanificationState()->recompos.size() - pl.countDoubleRecompo()));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Comp Double: " + std::to_string(pl.countDoubleRecompo()));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Excluded: " + std::to_string(pl.getOpImplanifiables().size()));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Diagnosis cost: " + std::to_string(pl.sommeRejetsPonderes()));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Swap cost: " + std::to_string(pl.sommeSwapCosts()));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Recompo cost: " + std::to_string(pl.sommmeRecompoCosts()));
loggerlib::Logger::systemNotify(loggerlib::LOGGER_INFO, "Objective function: " + std::to_string(pl.sommeRetardsPonderes(true)));
addPlanningSolution(pl);
}
//std::string str = std::to_string(solutions[0].)//std::to_string(solutions[0].sommeRetardsPonderes(true)) + ";";
//modellib::STFInstanceUtils::write_in_file("Comparaison_ISO_SWAP.csv",str);
ListHeuristic::sortingRules={};
//delete GraphTreeNode::ms_rootRef;
GraphTreeNode::clean();
//ListHeuristic_v2::opSortDispFindRules={};
}
void DedicatedHeuristic::logs(unsigned int l, float per, float alpha, unsigned int nodes, unsigned int swapnodes,unsigned int compnodes,
unsigned int filterednodes, unsigned int filteredswap,unsigned int filteredcomp, double timepse, double tf, double timelh, double trec, double tsncreate, double timelbd,
double tite, double ttotal, unsigned long long objective, unsigned long long fcost,
unsigned long long ub, float estimatetime, unsigned long long lowerboundLevel) {
std::string log;
if(configlib::Configuration::Logs.ALGO_VERBOSE) {
std::string prog = std::to_string(l);
std::stringstream ss;
ss << std::setprecision(3) << per;
std::string perstr;
ss >> perstr;
perstr += "%";
ss.clear();
ss << std::setprecision(2) << alpha;
std::string alphastr;
ss >> alphastr;
ss.clear();
std::string nodestr = std::to_string(nodes);
std::string swapnodestr = std::to_string(swapnodes);
std::string compnodestr = std::to_string(compnodes);
std::string fnodes = std::to_string(filterednodes);
std::string fsnodes = std::to_string(filteredswap);
std::string fcnodes = std::to_string(filteredcomp);
std::string tildeZero = "~0s";
std::string tpse;
if(timepse < 0.01 && timepse > 0)
{
tpse = tildeZero;
}
else
{
ss << std::setprecision(2) << timepse;
ss >> tpse;
tpse += "s";
ss.clear();
}
std::string tfstr;
if(tf < 0.01 && tf > 0)
{
tfstr = tildeZero;
}
else
{
ss << std::setprecision(2) << tf;
ss >> tfstr;
tfstr += "s";
ss.clear();
}
std::string tlh;
if(timelh < 0.01 && timelh > 0)
{
tlh = tildeZero;
}
else
{
ss << std::setprecision(2) << timelh;
ss >> tlh;
tlh += "s";
ss.clear();
}
std::string tlbd;
if(timelbd < 0.01 && timelbd > 0)
{
tlbd = tildeZero;
}
else
{
ss << std::setprecision(2) << timelbd;
ss >> tlbd;
tlbd += "s";
ss.clear();
}
std::string trecovering;
if(trec < 0.01 && trec > 0)
{
trecovering = tildeZero;
}
else
{
ss << std::setprecision(2) << trec;
ss >> trecovering;
trecovering += "s";
ss.clear();
}
std::string ti;
if(tite < 0.01 && tite > 0)
{
ti = tildeZero;
}
else
{
ss << std::setprecision(2) << tite;
ss >> ti;
ti += "s";
ss.clear();
}
std::string tsn;
if(tsncreate < 0.01 && tsncreate > 0)
{
tsn = tildeZero;
}
else
{
ss << std::setprecision(2) << tsncreate;
ss >> tsn;
tsn += "s";
ss.clear();
}
std::string tt;
if(ttotal < 0.01 && ttotal > 0)
{
tt = tildeZero;
}
else
{
ss << std::setprecision(2) << ttotal;
ss >> tt;
tt += "s";
ss.clear();
}
std::string obj = std::to_string(objective);
std::string fcstr = std::to_string(fcost);
std::string ubstr = std::to_string(ub);
std::string et;
std::string lb = std::to_string(lowerboundLevel);
if(estimatetime < 0.01 && estimatetime > 0)
{
et = tildeZero;
}
else
{
ss << std::setprecision(3) <<estimatetime;
ss >> et;
et += "s";
ss.clear();
}
std::vector<std::string> elements;
elements.push_back(prog);
elements.push_back(perstr);
elements.push_back(alphastr);
elements.push_back(nodestr);
elements.push_back(swapnodestr);
elements.push_back(compnodestr);
if(configlib::Configuration::Logs.ALGO_VERBOSE_NODES)
{
elements.push_back(fnodes);
elements.push_back(fsnodes);
elements.push_back(fcnodes);
}
if(configlib::Configuration::Logs.ALGO_VERBOSE_HEURISTICS)
{
elements.push_back(tsn);
elements.push_back(tpse);
elements.push_back(tfstr + " (" + tlbd + ")");
elements.push_back(tlh);
elements.push_back(trecovering);
}
elements.push_back(ti);
elements.push_back(tt);
elements.push_back(obj);
elements.push_back(lb);
elements.push_back(ubstr);
elements.push_back(fcstr);
elements.push_back(et);
unsigned int c = 0;
for(auto& e : elements)
{
log += e;
if(c < logoffsetcolumns.size())
{
while(log.size() < logoffsetcolumns[c])
log += " ";
log += "| ";
}
c++;
}
loggerlib::Logger::systemNotify(loggerlib::LOGGER_PROGRESS,
log);
}
}
}
+96
View File
@@ -0,0 +1,96 @@
#ifndef DEDICATEDHEURISTIC_H
#define DEDICATEDHEURISTIC_H
#include <chrono>
#include <vector>
#include "Algorithm.h"
#include "GraphManager.h"
#include "GraphTreeNode.hpp"
#include <boost/graph/graphviz.hpp>
namespace solverlib {
class GraphTreeNode;
//! Dedicated heuristic algorithm class implementation
/*!
* This is the class which implement the dedicated heuristic algorithm
* @author Mael Bervet && Tom Ray
* @date October 2023
* @version 2.0
*/
class DedicatedHeuristic : public Algorithm {
private:
//! The manager for graph build and modification
std::shared_ptr<GraphManager> pgraphManager = nullptr;
std::vector<unsigned int> logoffsetcolumns;
/**
* @brief Selection les regles qui on la meilleur hupper bound
*/
void selectBestRules(std::vector<std::pair<unsigned long long, std::pair<OP_SORTING_RULE, DISPO_VOIE_RAME_SORTING_RULE>>>& bestRules);
/**
* @brief Créé le Graph pour la hupper bound / Flow etc...
*/
void createGraphe(unsigned int nbBranch,std::shared_ptr<GraphTreeNode> root);
void rbs(unsigned int nbBranch, unsigned int nbSolution, std::vector<Planification>& planning);
public:
void logs(unsigned int l, float per, float alpha, unsigned int nodes, unsigned int swapnodes,unsigned int compnodes,
unsigned int filterednodes, unsigned int filteredswap,unsigned int filteredcomp, double timepse, double tf, double timelh, double trec, double tsncreate, double timelbd,
double tite, double ttotal, unsigned long long objective, unsigned long long fcost,
unsigned long long ub, float estimatetime, unsigned long long lowerboundLevel);
//! Default constructor for the dedicated heuristic
/*!
* Create the heuristic and initialize data lists and the graph manager
* @param MainController* mainController : the pointer to the main controller of the instance to solve
*/
explicit DedicatedHeuristic(STFInstance &instance);
//! Dedicated heuristic destructor
/*!
* Delete the heuristic and release the allocated memory for the main controller
*/
~DedicatedHeuristic() override = default;
//! Build the graph
/*!
* Build the max flow min cost graph with all data lists
*/
void buildGraph(std::shared_ptr<GraphTreeNode>node);
//! Apply a pretreatment on the graph
/*!
* Look in the graph to train time slots which involve infeasibility
*/
void graphPretreatment();
//! Solve the loaded instance
/*!
* Look for the best planification for the loaded instance
* Use a beam search type algorithm to find the best solution it can found
* @param unsigned int nbBranch : the number of branch to explore at each tree level
* @param unsigned int nbSolution : the final number of solution asked, can't be bigger than nbBranch
* @return vector<OutputData> outputs : found solutions in the asked number if it's possible
*/
void solve(unsigned int nbBranch, unsigned int nbSolution);
//! Convert all registered solutions to output data
/*!
* Create and fill output data objects with all registered solutions and return it in a vector
* @return vector<OutputData>* outputs : a pointer to the converted solutions
*/
//std::vector<OutputData> convertSolutionsToOutputData(std::vector<std::vector<std::map<std::string, unsigned int>>> toConvert);
void solveInstance(const int &ep) override {
}
};
}
#endif
+324
View File
@@ -0,0 +1,324 @@
#include "GraphManager.h"
#include "boost/graph/properties.hpp"
namespace solverlib {
//! Default constructor for graph manager
/*!
* Construct the manager and initialize the graph ans its properties
* @param unsigned int nbVertices : the number of vertex in the graph
*/
GraphManager::GraphManager(unsigned int nb) {
nbVertices = nb;
//! Create the graph and allocate the given number of vertex
pgraph = new Graph(nbVertices);
//! Create all graph vertices
/*for (unsigned int i = 0; i < nbVertices; i++) {
add_vertex(*pgraph);
}*/
//! Associate the manager attributs with created graph properties
weights = boost::get(boost::edge_weight, *pgraph);
capacities = boost::get(boost::edge_capacity, *pgraph);
residualCapacities = boost::get(boost::edge_residual_capacity, *pgraph);
reversedMap = boost::get(boost::edge_reverse, *pgraph);
edgeIndexMap = boost::get(boost::edge_index, *pgraph);
}
//! Default destructor for graph manager
/*!
* Release the allocated memory for the graph manager
*/
GraphManager::~GraphManager() {
pgraph->clear();
delete pgraph;
pgraph = nullptr;
}
//! Add a new vertex in the graph
/*!
* Add e new vertex in the graph and update the number of vertex
*/
void GraphManager::addVertex(VertexData &data) {
add_vertex(data, *pgraph);
nbVertices++;
}
//! Add a new edge in the graph
/*!
* Add a new edge with the given parameters
* @param vertex_descriptor v1 : the begin vertex of the edge
* @param vertex_descriptor v1 : the end vertex of the edge
* @param long capacity : the edge capacity
* @param long weight : the edge weight
*/
std::pair<edge_descriptor, edge_descriptor>
GraphManager::addEdge(vertex_descriptor origin, vertex_descriptor destination, long capacity, long weight) {
//! Create new edges
edge_descriptor in, out;
std::pair<bool, edge_descriptor> edgeCheck = findEdge(origin, destination);
//! If the edge doesn't exist
if (origin < nbVertices && destination < nbVertices && !edgeCheck.first) {
int indexIn = getEdges().size()+1;
int indexOut = getEdges().size();
//! Add the out edge of origin and its capacity and weight
out = add_edge(vertex(origin, *pgraph), vertex(destination, *pgraph), indexOut, *pgraph).first;
put(edgeIndexMap, out, indexOut);
capacities[out] = capacity;
residualCapacities[out] = capacity;
weights[out] = weight;
//! Add the in edge of origin and its capacity and weight
in = add_edge(vertex(destination, *pgraph), vertex(origin, *pgraph), indexIn, *pgraph).first;
put(edgeIndexMap, in, indexIn);
capacities[in] = 0;
residualCapacities[in] = 0;
weights[in] = -weight;
//! Set the reversed map for new edges
reversedMap[out] = in;
reversedMap[in] = out;
getEdges().push_back(in);
getEdges().push_back(out);
}
return {out, in};
}
//! Update the capacity of an edge
/*!
* Update the capacity of the edge between the origin and the destination
* @param vertex_descriptor origin : the begin vertex of the edge
* @param vertex_descriptor destination : the end vertex of the edge
* @param long capacity : the edge capacity
*/
void GraphManager::updateEdgeCapacity(vertex_descriptor origin, vertex_descriptor destination, long capacity) {
std::pair<bool, edge_descriptor> edge = findEdge(origin, destination);
if (edge.first) {
capacities[edge.second] = capacity;
}
}
//! Update the weight of an edge
/*!
* Update the weight of the edge between the origin and the destination
* @param vertex_descriptor origin : the begin vertex of the edge
* @param vertex_descriptor destination : the end vertex of the edge
* @param long weight : the edge weight
*/
void GraphManager::updateEdgeWeight(vertex_descriptor origin, vertex_descriptor destination, long weight) {
std::pair<bool, edge_descriptor> out = findEdge(origin, destination);
std::pair<bool, edge_descriptor> in = findEdge(destination, origin);
if (out.first && in.first) {
weights[out.second] = weight;
weights[in.second] = -weight;
}
}
//! Map arguments in a tuple
/*!
* Map arguments in a tuple made of two vertex iterators
* @param vertex_iterator& iterA : the first iterator to map
* @param vertex_iterator& iterB : the second iterator to map
* @return vertex_mapper map : the map of iteraors
*/
vertex_mapper GraphManager::map(vertex_iterator &iterA, vertex_iterator &iterB) {
return {iterA, iterB};
}
//! Map arguments in a tuple
/*!
* Map arguments in a tuple made of two out edge iterators
* @param out_edge_iterator& iterA : the first iterator to map
* @param out_edge_iterator& iterB : the second iterator to map
* @return out_edge_mapper map : the map of iteraors
*/
out_edge_mapper GraphManager::map(out_edge_iterator &iterA, out_edge_iterator &iterB) {
return {iterA, iterB};
}
/*out_edge_mapper_filtered GraphManager::map(out_edge_iterator_filtered &iterA, out_edge_iterator_filtered &iterB) {
return {iterA, iterB};
}*/
//! Return the vertices of the graph
/*!
* Return pointers to the first and the last vertex of the graphe in a pair
* @return pair<vertex_iterator, vertex_iterator> graphVertices : the pair of pointer
*/
std::pair<vertex_iterator, vertex_iterator> GraphManager::getVertices() {
std::pair<vertex_iterator, vertex_iterator> graphVertices = vertices(*pgraph);
graphVertices.second -= nbVertices;
return graphVertices;
}
//! Find and return an edge
/*!
* Find and return the edge between the origin and the destination
* @param vertex_descriptor v1 : the begin vertex of the edge
* @param vertex_descriptor v1 : the end vertex of the edge
* @return pair<bool, edge_descriptor> edgeFound : the corresponding edge and true if the edge was found, false and default edge descriptor otherwise
*/
std::pair<bool, edge_descriptor> GraphManager::findEdge(vertex_descriptor origin, vertex_descriptor destination) {
std::pair<bool, edge_descriptor> edgeFound = std::pair<bool, edge_descriptor>(false, edge_descriptor());
if (origin < nbVertices && destination < nbVertices) {
out_edge_iterator edgeIterator, edgesEnd;
for (tie(edgeIterator, edgesEnd) = out_edges(origin, *pgraph); edgeIterator != edgesEnd &&
!edgeFound.first; edgeIterator++) {
if (target(*edgeIterator, *pgraph) == destination) {
edgeFound.first = true;
edgeFound.second = *edgeIterator;
}
}
}
return edgeFound;
}
//! Return vertex out edges
/*!
* Return pointers to the first and the last out edge of the vertex in a pair
* @param vertexdescriptor v : the vertex to look for
* @return pair<out_edge_iterator, out_edge_iterator> outEdges : the pair of pointer
*/
std::pair<out_edge_iterator, out_edge_iterator> GraphManager::getOutEdges(vertex_descriptor v) {
std::pair<out_edge_iterator, out_edge_iterator> outEdges = std::pair<out_edge_iterator, out_edge_iterator>();
if (v < nbVertices) {
outEdges = out_edges(v, *pgraph);
//if(v != 0)
//outEdges.first += 1;
}
return outEdges;
}
//! Return edge source
/*!
* Return the source vertex of the edge
* @param edge_descriptor e : the edge to look for
* @return vertex_descriptor edgeSource : the source vertex
*/
vertex_descriptor GraphManager::getEdgeSource(edge_descriptor e) {
return e.m_source;
}
//! Return edge target
/*!
* Return the targeted vertex by the edge
* @param edge_descriptor e : the edge to look for
* @return vertex_descriptor edgeTarget : the targeted vertex
*/
vertex_descriptor GraphManager::getEdgeTarget(edge_descriptor e) {
return e.m_target;
}
//! Remove an edge from the graph
/*!
* Remove the edge from origin to destination and update graph data
* @param vertex_descriptor origin : the begin vertex of the edge
* @param vertex_descriptor destination : the end vertex of the edge
*/
void GraphManager::removeEdge(vertex_descriptor origin, vertex_descriptor destination) {
std::pair<bool, edge_descriptor> edgeFound = findEdge(origin, destination);
if (edgeFound.first) {
remove_edge(vertex(origin, *pgraph), vertex(destination, *pgraph), *pgraph);
remove_edge(vertex(destination, *pgraph), vertex(origin, *pgraph), *pgraph);
}
}
//! Remove the given vertex edges from the graph
/*!
* Remove a the given vertex edges from the graph
* @param vertex_descriptor vertex : the vertex
*/
void GraphManager::removeVertexEdges(vertex_descriptor v) {
if (v < nbVertices) {
clear_vertex(vertex(v, *pgraph), *pgraph);
}
}
//! Resolve the current graph
/*!
* Resolve the current graph and return its max flow
* Use the successive shortest path non negative weights algorithm
* @param vertex_descriptor source : the source vertex
* @param vertex_descriptor well : the well vertex
* @return int maxFlow : the graph max flow, or -1 in case of error
*/
long GraphManager::resolveGraph(vertex_descriptor source, vertex_descriptor well) {
long maxFlow = 0;
if (source < nbVertices && well < nbVertices) {
maxFlow = 0;
//successive_shortest_path_nonnegative_weights(*pgraph, source, well, capacity_map(capacities).residual_capacity_map(residualCapacities).reverse_edge_map(reversedMap).weight_map(weights).predecessor_map(predecessorMap).distance_map(distanceMap));
successive_shortest_path_nonnegative_weights(*pgraph, source, well);//topologicalOrder
vertex_iterator vertexIterator, verticesEnd;
out_edge_iterator edgeIterator, edgesEnd;
//! Browse the resulting graphe to get flow information
std::pair<out_edge_iterator, out_edge_iterator> outEdges = getOutEdges(well);
for (map(edgeIterator, edgesEnd) = outEdges; edgeIterator != edgesEnd; edgeIterator++) {
maxFlow += residualCapacities[*edgeIterator];
}
}
return maxFlow;
}
//! Find the flow cost
/*!
* Find the cost of the current graph flow
* To have the good cost you must resolve the graph before
* @return int cost : the flow cost
*/
long GraphManager::findFlowCost() {
return find_flow_cost(*pgraph);
}
/*GraphManager *GraphManager::copy() {
auto newGraph = new GraphManager(this);
return newGraph;
}*/
//! Check if the solution currently represent by the graph is feasible
/*!
* Look the current graph state and determine if the represent solution is feasible
* @param bool isSolved : tell if the graph is already solved to avoid usless resolution, by default is false
* @return bool feasible : true if the solution is feasible, false otherwise
*/
bool GraphManager::checkFlowFeasibility(unsigned int maxFlow) {
bool feasible = false;
std::pair<out_edge_iterator, out_edge_iterator> sourceEdges = getOutEdges(0);
unsigned int sumOperationsCapacity = 0;
//! Compute the sum of all operations set length of the graph
out_edge_iterator edgeIterator, edgesEnd;
for (map(edgeIterator, edgesEnd) = sourceEdges; edgeIterator != edgesEnd; edgeIterator++) {
sumOperationsCapacity += getCapacities()[*edgeIterator];
}
//! Check feasibility
if (maxFlow == sumOperationsCapacity) {
feasible = true;
}
//std::cout << maxFlow << " " << sumOperationsCapacity << std::endl;
return feasible;
}
}
+474
View File
@@ -0,0 +1,474 @@
#ifndef GRAPHMANAGER_H
#define GRAPHMANAGER_H
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/copy.hpp>
#include <boost/graph/successive_shortest_path_nonnegative_weights.hpp>
#include <boost/graph/find_flow_cost.hpp>
#include "../../General/Model/STFInstance.h"
#include "boost/graph/properties.hpp"
#include <unordered_map>
#include <variant>
namespace solverlib {
enum vertexType {
SOURCE,
WELL,
TRAIN,
TRAIN_SLOT,
TRACK_SLOT,
REJECT,
EJECTION
};
typedef struct customEmplacementRame {
unsigned int dispoRame;
modellib::CreneauHoraire timeSlot;
bool splited;
std::pair<unsigned int, unsigned int> rameOp;
} V_EmplacementRame;
typedef struct customEmplacementVoie {
unsigned int dispoVoie;
unsigned int voie;
unsigned int site;
} V_EmplacementVoie;
typedef struct vertex_data_s {
vertexType type;
std::variant<std::pair<unsigned int, unsigned int>, V_EmplacementRame, V_EmplacementVoie> data;
} VertexData;
//! Define the types of all descriptors
typedef boost::adjacency_list_traits<boost::vecS, boost::vecS, boost::directedS> Traits;
typedef Traits::vertex_descriptor vertex_descriptor;
typedef Traits::edge_descriptor edge_descriptor;
/*inline void hash_combine(size_t &seed, const vertex_descriptor &v) {
std::hash<vertex_descriptor> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}*/
/*struct hash_graph {
size_t operator()(const edge_descriptor val) const {
size_t hash = 0;
hash_combine(hash, val.m_source);
hash_combine(hash, val.m_target);
return hash;
}
};*/
//! Define the graph type
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, VertexData,
boost::property<boost::edge_capacity_t, long,
boost::property<boost::edge_residual_capacity_t, long,
boost::property<boost::edge_reverse_t, edge_descriptor,
boost::property<boost::edge_weight_t, long,
boost::property<boost::edge_index_t, long> > > > > > Graph;
//! Define all types of graph property
typedef boost::property_map<Graph, boost::edge_capacity_t>::type Capacity;
typedef boost::property_map<Graph, boost::edge_residual_capacity_t>::type ResidualCapacity;
typedef boost::property_map<Graph, boost::edge_weight_t>::type Weight;
typedef boost::property_map<Graph, boost::edge_reverse_t>::type Reversed;
typedef boost::property_map<Graph, boost::edge_index_t>::type EdgeIndex;
//! Define the types of all iterators
typedef boost::graph_traits<Graph>::vertex_iterator vertex_iterator;
typedef boost::graph_traits<Graph>::edge_iterator edge_iterator;
typedef boost::graph_traits<Graph>::out_edge_iterator out_edge_iterator;
//typedef boost::graph_traits<boost::filtered_graph<const Graph, boost::is_initial_residual_edge<Capacity, ResidualCapacity> >>::out_edge_iterator out_edge_iterator_filtered;
//! Define the types of all mappers
typedef boost::tuples::detail::tie_mapper<vertex_iterator, vertex_iterator>::type vertex_mapper;
typedef boost::tuples::detail::tie_mapper<out_edge_iterator, out_edge_iterator>::type out_edge_mapper;
//typedef boost::tuples::detail::tie_mapper<out_edge_iterator_filtered, out_edge_iterator_filtered>::type out_edge_mapper_filtered;
typedef boost::tuples::detail::tie_mapper<edge_iterator, edge_iterator>::type edge_mapper;
//! Class GraphManager
/*!
* Allow to create a boost graph with the given number of vertices
* and manage this graph as you want
*/
class GraphManager {
private:
//! The number of vertices in the graph
unsigned int nbVertices = 0;
//! A pointer to the graph managed
Graph *pgraph = nullptr;
//! All weights in the graph
Weight weights;
//! All capacity in the graph
Capacity capacities;
//! All residual capacities in the graph
ResidualCapacity residualCapacities;
//! The reversed map of the graph
Reversed reversedMap;
EdgeIndex edgeIndexMap;
std::vector<edge_descriptor> edges;
//std::unordered_map<unsigned long, unsigned int> rcapaflow;
std::unordered_map<unsigned long, unsigned int> ccapaflowBackup;
std::unordered_map<unsigned long, long> cweightsBackup;
std::unordered_map<unsigned short, vertex_descriptor> trackSlotVertexMap;
std::unordered_map<unsigned short, vertex_descriptor> opVertexMap;
std::vector<edge_descriptor> diagnosisEdgesMap;//map job, edge
//std::vector<vertex_descriptor> topologicalOrder;
public:
//! Default constructor for graph manager
/*!
* Construct the manager and initialize the graph ans its properties
* @param unsigned int nbVertices : the number of vertex in the graph
*/
explicit GraphManager(unsigned int nbVertices);
//! Default destructor for graph manager
/*!
* Release the allocated memory for the graph manager
*/
~GraphManager();
/*!
* Properties getter
*/
//! Number of vertex
/*!
* Return the number of vertex in the graph
* @return unsigned int nbVertices : the number of vertex
*/
[[nodiscard]] inline unsigned int getNbVertices() const { return nbVertices; }
inline std::unordered_map<unsigned short, vertex_descriptor>& getTrackSlotsVertex(){return trackSlotVertexMap;};
inline std::unordered_map<unsigned short, vertex_descriptor>& getOpVertex(){return opVertexMap;};
//! Graph
/*!
* Return the pointer to the graph managed
* @return Graph* pgraph : the pointer to the graph
*/
inline Graph *getGraph() { return pgraph; }
inline std::unordered_map<unsigned long, unsigned int>& getCapaBackup(){return ccapaflowBackup;};
inline void revertGraph(){
for(auto& e : edges)
{
auto index = getEdgeIndex(e);
capacities[e] = ccapaflowBackup[index];
weights[e] = cweightsBackup[index];
}
}
inline void saveGraph(){
for(auto& e : edges)
{
auto index = getEdgeIndex(e);
ccapaflowBackup[index] = capacities[e];
cweightsBackup[index] = weights[e];
}
out_edge_iterator edgeIterator, edgesEnd;
std::pair<out_edge_iterator, out_edge_iterator> outEdges = getOutEdges(getNbVertices() - 1);
for (map(edgeIterator, edgesEnd) = outEdges; edgeIterator != edgesEnd; edgeIterator++) {
vertex_descriptor v = getEdgeTarget(*edgeIterator);
if (((*getGraph())[v]).type == REJECT && residualCapacities[*edgeIterator] != 0) {
std::pair<out_edge_iterator, out_edge_iterator> edgesR = getOutEdges(v);
out_edge_iterator edgeR, edgeRend;
for (map(edgeR, edgeRend) = edgesR; edgeR != edgeRend; edgeR++) {
vertex_descriptor r = getEdgeTarget(*edgeR);
if (((*getGraph())[r]).type == TRAIN) {
diagnosisEdgesMap.push_back(*edgeR);
}
}
}
}
}
inline std::vector<edge_descriptor>& getDiagRevEdges(){return diagnosisEdgesMap;};
//! Weights
/*!
* Return all weights in the graph
* @return Weight weight : all graph weight
*/
inline Weight &getWeights() { return weights; }
//! Capacities
/*!
* Return all capacities in the graph
* @return Capacity capacities : all graph capacities
*/
inline Capacity &getCapacities() { return capacities; }
inline std::vector<edge_descriptor> &getEdges() { return edges; }
inline unsigned long getEdgeIndex(edge_descriptor edge){return get(edgeIndexMap, edge);};
//! Residual capacities
/*!
* Return all residual capacities in the graph
* @return ResidualCapacity residualCapacities : all graph residual capacities
*/
inline ResidualCapacity &getResidualCapacities() { return residualCapacities; }
//! Reversed map
/*!
* Return the reversed map of the graph
* @return Reversed reversedMap : the graph reversed map
*/
inline Reversed &getReversedMap() { return reversedMap; }
//! Check if the solution currently represent by the graph is feasible
/*!
* Look the current graph state and determine if the represent solution is feasible
* @param bool isSolved : tell if the graph is already solved to avoid usless resolution, by default is false
* @return bool feasible : true if the solution is feasible, false otherwise
*/
bool checkFlowFeasibility(unsigned int maxFlow);
/*!
* Graph modelisation methods
*/
//! Add a new vertex in the graph
/*!
* Add e new vertex in the graph and update the number of vertex
*/
void addVertex(VertexData &data);
//! Add a new edge in the graph
/*!
* Add a new edge with the given parameters
* @param vertex_descriptor origin : the begin vertex of the edge
* @param vertex_descriptor destination : the end vertex of the edge
* @param long capacity : the edge capacity
* @param long weight : the edge weight
* @return a pair of <out, in> edges
*/
::std::pair<edge_descriptor, edge_descriptor>
addEdge(vertex_descriptor origin, vertex_descriptor destination, long capacity, long weight);
//! Update the capacity of an edge
/*!
* Update the capacity of the edge between the origin and the destination
* @param vertex_descriptor origin : the begin vertex of the edge
* @param vertex_descriptor destination : the end vertex of the edge
* @param long capacity : the edge capacity
*/
void updateEdgeCapacity(vertex_descriptor origin, vertex_descriptor destination, long capacity);
//! Update the weight of an edge
/*!
* Update the weight of the edge between the origin and the destination
* @param vertex_descriptor origin : the begin vertex of the edge
* @param vertex_descriptor destination : the end vertex of the edge
* @param long weight : the edge weight
*/
void updateEdgeWeight(vertex_descriptor origin, vertex_descriptor destination, long weight);
//! Map arguments in a tuple
/*!
* Map arguments in a tuple made of two vertex iterators
* @param vertex_iterator& iterA : the first iterator to map
* @param vertex_iterator& iterB : the second iterator to map
* @return vertex_mapper map : the map of iteraors
*/
static vertex_mapper map(vertex_iterator &iterA, vertex_iterator &iterB);
//! Map arguments in a tuple
/*!
* Map arguments in a tuple made of two out edge iterators
* @param out_edge_iterator& iterA : the first iterator to map
* @param out_edge_iterator& iterB : the second iterator to map
* @return out_edge_mapper map : the map of iteraors
*/
static out_edge_mapper map(out_edge_iterator &iterA, out_edge_iterator &iterB);
//static out_edge_mapper_filtered map(out_edge_iterator_filtered &iterA, out_edge_iterator_filtered &iterB);
//! Return the vertices of the graph
/*!
* Return pointers to the first and the last vertex of the graphe in a pair
* @return pair<vertex_iterator, vertex_iterator> graphVertices : the pair of pointer
*/
std::pair<vertex_iterator, vertex_iterator> getVertices();
//! Find and return an edge
/*!
* Find and return the edge between the origin and the destination
* @param vertex_descriptor v1 : the begin vertex of the edge
* @param vertex_descriptor v1 : the end vertex of the edge
* @return pair<bool, edge_descriptor> edgeFound : the corresponding edge and true if the edge was found, false and default edge descriptor otherwise
*/
std::pair<bool, edge_descriptor> findEdge(vertex_descriptor origin, vertex_descriptor destination);
//! Return vertex out edges
/*!
* Return pointers to the first and the last out edge of the vertex in a pair
* @param vertexdescriptor v : the vertex to look for
* @return pair<out_edge_iterator, out_edge_iterator> outEdges : the pair of pointer
*/
std::pair<out_edge_iterator, out_edge_iterator> getOutEdges(vertex_descriptor v);
//! Return edge source
/*!
* Return the source vertex of the edge
* @param edge_descriptor e : the edge to look for
* @return vertex_descriptor edgeSource : the source vertex
*/
static vertex_descriptor getEdgeSource(edge_descriptor e);
//! Return edge target
/*!
* Return the targeted vertex by the edge
* @param edge_descriptor e : the edge to look for
* @return vertex_descriptor edgeTarget : the targeted vertex
*/
static vertex_descriptor getEdgeTarget(edge_descriptor e);
//! Remove an edge from the graph
/*!
* Remove the edge from origin to destination and update graph data
* @param vertex_descriptor origin : the begin vertex of the edge
* @param vertex_descriptor destination : the end vertex of the edge
*/
void removeEdge(vertex_descriptor origin, vertex_descriptor destination);
//! Remove the given vertex edges from the graph
/*!
* Remove a the given vertex edges from the graph
* @param vertex_descriptor vertex : the vertex
*/
void removeVertexEdges(vertex_descriptor v);
/*!
* Graph solving methods
*/
//! Resolve the current graph
/*!
* Resolve the current graph and return its max flow
* Use the successive shortest path non negative weights algorithm
* @param vertex_descriptor source : the source vertex
* @param vertex_descriptor well : the well vertex
* @return int maxFlow : the graph max flow, or -1 in case of error
*/
long resolveGraph(vertex_descriptor source, vertex_descriptor well);
//! Find the flow cost
/*!
* Find the cost of the current graph flow
* To have the good cost you must resolve the graph before
* @return int cost : the flow cost
*/
long findFlowCost();
long getFlowCostDiag() {
long cost = 0;
/*out_edge_iterator edgeIterator, edgesEnd;
std::pair<out_edge_iterator, out_edge_iterator> outEdges = getOutEdges(getNbVertices() - 1);
for (map(edgeIterator, edgesEnd) = outEdges; edgeIterator != edgesEnd; edgeIterator++) {
vertex_descriptor v = getEdgeTarget(*edgeIterator);
if (((*getGraph())[v]).type == REJECT && residualCapacities[*edgeIterator] != 0) {
std::pair<out_edge_iterator, out_edge_iterator> edgesR = getOutEdges(v);
out_edge_iterator edgeR, edgeRend;
for (map(edgeR, edgeRend) = edgesR; edgeR != edgeRend; edgeR++) {
vertex_descriptor r = getEdgeTarget(*edgeR);
if (((*getGraph())[r]).type == TRAIN && residualCapacities[*edgeR] != 0) {
cost += weights[*edgeR]*residualCapacities[*edgeR];
}
}
}
}*/
for(auto& e : diagnosisEdgesMap)
{
if(residualCapacities[e] != 0)
{
cost += weights[e]*residualCapacities[e];
}
}
return -cost;
}
bool checkStartingPointFlowFeasibility()
{
auto pv = getVertices();
for(auto v = pv.first; v != pv.second; ++v)
{
long incomingflow = 0;
long outgoingflow = 0;
for(auto& e : getEdges())
{
if(capacities[e] != 0)
{
if(getEdgeTarget(e) == *v)
{
incomingflow += capacities[e] - residualCapacities[e];
}
else if(getEdgeSource(e) == *v)
{
outgoingflow += capacities[e] - residualCapacities[e];
}
}
else
{
if(capacities[reversedMap[e]] - residualCapacities[reversedMap[e]] != residualCapacities[e])
{
std::cout << "ERREUR de flot retour" << std::endl;
return false;
}
}
}
if(incomingflow != outgoingflow)
{
std::cout << "ERREUR de flot" << std::endl;
return false;
}
}
return true;
}
//GraphManager *copy();
/*void topologicalSort()
{
topologicalOrder.reserve(getNbVertices());
// Call 'depth_first_visit', not 'topological_sort', because we don't
// want to traverse the entire graph, only vertices reachable from 's',
// and 'topological_sort' will traverse everything. The logic below
// is the same as for 'topological_sort', only we call 'depth_first_visit'
// and 'topological_sort' calls 'depth_first_search'.
boost::topo_sort_visitor< std::back_insert_iterator< std::vector< vertex_descriptor > > >
topo_visitor(std::back_inserter(topologicalOrder));
std::vector<boost::default_color_type> color(getNbVertices());
boost::filtered_graph< const Graph, boost::is_residual_edge< ResidualCapacity > > gres
= boost::detail::residual_graph(*pgraph,residualCapacities);
boost::bgl_named_params< int, boost::buffer_param_t > params(0);
auto ind = choose_const_pmap(get_param(params, boost::vertex_index), *pgraph, boost::vertex_index);
depth_first_visit(gres, 0, topo_visitor, make_iterator_property_map(color.begin(), ind , color[0]));
}*/
};
}
#endif
+118
View File
@@ -0,0 +1,118 @@
#include "GraphPrinter.hpp"
#include <fstream>
#include <queue>
namespace solverlib {
//modellib::SolverDate GraphPrinter::dateDebut;
/*void GraphPrinter::print(GraphManager *pgraphManager, const std::string& name) {
std::ofstream out(name + ".dot", std::ios::trunc | std::ios::out);
out << "digraph G {" << std::endl;
std::pair<edge_iterator, edge_iterator> es = boost::edges(*(pgraphManager->getGraph()));
edge_iterator edgeIte, edgeEnd;
for (edge_mapper(edgeIte, edgeEnd) = es;
edgeIte != edgeEnd;
edgeIte++)
{
vertex_descriptor source = solverlib::GraphManager::getEdgeSource(*edgeIte);
vertex_descriptor destination = solverlib::GraphManager::getEdgeTarget(*edgeIte);
long capa = pgraphManager->getCapacities()[*edgeIte];
long capaRes = pgraphManager->getResidualCapacities()[*edgeIte];
long w = pgraphManager->getWeights()[*edgeIte];
out << source << "->" << destination << "[label=\"c=" << capa << " cr=" << capaRes << " w=" << w << "\"];"
<< std::endl;
//std::cout << capa << " " << " " << capaRes << " " << w << std::endl;
}
out << "}";
out.close();
}*/
void GraphPrinter::print(GraphManager *pgraphManager, const std::string& name) {
std::ofstream out(name + ".dot", std::ios::trunc | std::ios::out);
out << "digraph G {" << std::endl;
// 1. D'ABORD, ÉCRIRE TOUS LES SOMMETS
std::pair<vertex_iterator, vertex_iterator> vs = vertices(*(pgraphManager->getGraph()));
vertex_iterator vertexIte, vertexEnd;
for (boost::tie(vertexIte, vertexEnd) = vs; vertexIte != vertexEnd; ++vertexIte) {
vertex_descriptor v = *vertexIte;
VertexData data = (*(pgraphManager->getGraph()))[v];
// Configurer l'apparence selon le type
switch (data.type) {
case SOURCE:
out << v << " [label=\"SOURCE\", shape=circle, style=filled, fillcolor=green];" << std::endl;
break;
case WELL:
out << v << " [label=\"WELL\", shape=circle, style=filled, fillcolor=red];" << std::endl;
break;
case TRAIN:
out << v << " [label=\"TRAIN " << v << "\", shape=ellipse];" << std::endl;
break;
case TRAIN_SLOT:
out << v << " [label=\"TS " << v << "\", shape=diamond];" << std::endl;
break;
case TRACK_SLOT:
out << v << " [label=\"TRACK " << v << "\", shape=hexagon];" << std::endl;
break;
case REJECT:
out << v << " [label=\"REJ " << v << "\", shape=triangle];" << std::endl;
break;
case EJECTION:
out << v << " [label=\"EJ " << v << "\", shape=invtriangle];" << std::endl;
break;
default:
out << v << " [label=\"NODE " << v << "\"];" << std::endl;
}
}
out << std::endl;
// 2. ENSUITE, ÉCRIRE LES ARCS
std::pair<edge_iterator, edge_iterator> es = boost::edges(*(pgraphManager->getGraph()));
edge_iterator edgeIte, edgeEnd;
int arcCount = 0;
for (boost::tie(edgeIte, edgeEnd) = es; edgeIte != edgeEnd; ++edgeIte) {
vertex_descriptor source = solverlib::GraphManager::getEdgeSource(*edgeIte);
vertex_descriptor destination = solverlib::GraphManager::getEdgeTarget(*edgeIte);
long capa = pgraphManager->getCapacities()[*edgeIte];
long capaRes = pgraphManager->getResidualCapacities()[*edgeIte];
long w = pgraphManager->getWeights()[*edgeIte];
// Vérifier que les sommets existent (debug)
if (source >= num_vertices(*(pgraphManager->getGraph())) ||
destination >= num_vertices(*(pgraphManager->getGraph()))) {
std::cerr << "ERREUR: Arc " << source << "->" << destination
<< " référence des sommets invalides!" << std::endl;
continue;
}
// Style différent selon le type d'arc
std::string style;
if (capa == 0) {
style = " [style=dashed, color=gray"; // Arc inverse
} else if (capaRes == 0) {
style = " [style=bold, color=blue"; // Arc saturé
} else {
style = " [color=black";
}
out << source << "->" << destination
<< style << ", label=\"c=" << capa << " cr=" << capaRes << " w=" << w << "\"];"
<< std::endl;
arcCount++;
}
out << "}" << std::endl;
out.close();
std::cout << "Fichier DOT généré: " << name << ".dot" << std::endl;
std::cout << " Sommets: " << num_vertices(*(pgraphManager->getGraph()))
<< ", Arcs: " << arcCount << std::endl;
}
}

Some files were not shown because too many files have changed in this diff Show More