Files
StatisticDatabaseGeneratorA…/TradeOffsComparator/src/main.cpp
T
2026-06-03 23:24:12 +02:00

243 lines
8.5 KiB
C++

#include <functional>
#include <ios>
#include <nlohmann/json.hpp>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
#include <stdexcept>
namespace fs = std::filesystem;
using json = nlohmann::json;
// ─────────────────────────────────────────────────────────────
// Structure : nom d'instance décomposé depuis le nom de fichier
// Format : Site_SiteCr_Tracks_Rames_Jobs_ID
// ─────────────────────────────────────────────────────────────
struct InstanceKey {
int64_t site;
int64_t site_cr;
int64_t tracks;
int64_t rames;
int64_t jobs;
int64_t id;
std::string raw; // nom complet sans extension
bool operator == (const InstanceKey& key) const
{
return key.raw == raw;
}
};
struct HashInstanceKey
{
size_t operator() (const InstanceKey& key) const{
return std::hash<std::string>()(key.raw);
}
};
InstanceKey parse_instance_name(const std::string& stem) {
InstanceKey k;
k.raw = stem;
std::vector<int64_t> parts;
std::string token;
for (char c : stem) {
if (c == '_') {
if (!token.empty()) { parts.push_back(std::stoll(token)); token.clear(); }
} else {
token += c;
}
}
if (!token.empty()) parts.push_back(std::stoll(token));
if (parts.size() != 6)
throw std::runtime_error("Nom d'instance invalide (attendu 6 entiers) : " + stem);
k.site = parts[0];
k.site_cr = parts[1];
k.tracks = parts[2];
k.rames = parts[3];
k.jobs = parts[4];
k.id = parts[5];
return k;
}
struct InstanceTradeOff{
int64_t nbBranchBest;
double timeRatio;
};
// ─────────────────────────────────────────────────────────────
// Parse un fichier JSON et insère les résultats
// ─────────────────────────────────────────────────────────────
void process_file(const fs::path& path, std::unordered_map<InstanceKey, std::pair<unsigned int, double>, HashInstanceKey>& references, std::unordered_map<InstanceKey, std::optional<InstanceTradeOff>, HashInstanceKey>& trades) {
// -- Nom d'instance depuis le stem du fichier
InstanceKey key = parse_instance_name(path.stem().string());
// -- Lecture JSON
std::ifstream f(path);
if (!f) throw std::runtime_error("Impossible d'ouvrir : " + path.string());
json doc;
try { f >> doc; }
catch (const json::exception& e) {
throw std::runtime_error("JSON invalide dans " + path.string() + " : " + e.what());
}
if (!doc.is_object())
throw std::runtime_error("Le JSON doit être un objet à la racine : " + path.string());
// -- Chaque clé = un algo
for (auto& [algo_name, obj] : doc.items()) {
if (!obj.is_object()) continue;
if(algo_name == "rbs")
{
int64_t fct_obj = obj.value("fctObjectif", int64_t{0});
double time_f = obj.value("timeFinal", 0.0);
references[key] = {
fct_obj,
time_f
};
}
else
{
if(trades.find(key) != trades.end() && trades[key] != std::nullopt)
{
int64_t fct_obj = obj.value("fctObjectif", int64_t{0});
int64_t nbBranch = obj.value("nbBranch", int64_t{0});
double time_f = obj.value("timeFinal", 0.0);
auto& tradePrec = trades[key];
auto& ref = references[key];
if(fct_obj <= ref.first && tradePrec->nbBranchBest > nbBranch)
{
InstanceTradeOff tr = {
nbBranch,
time_f/ref.second
};
trades[key] = tr;
}
}
else
{
int64_t fct_obj = obj.value("fctObjectif", int64_t{0});
int64_t nbBranch = obj.value("nbBranch", int64_t{0});
double time_f = obj.value("timeFinal", 0.0);
auto& ref = references[key];
if(fct_obj <= ref.first)
{
InstanceTradeOff tr = {
nbBranch,
time_f/ref.second
};
trades[key] = tr;
}
else
{
trades[key] = std::nullopt;
}
}
}
}
}
// ─────────────────────────────────────────────────────────────
// Collecte récursive des .json dans un dossier
// ─────────────────────────────────────────────────────────────
std::vector<fs::path> collect_json_files(const fs::path& dir) {
std::vector<fs::path> files;
if (!fs::is_directory(dir)) {
std::cerr << "[WARN] Pas un dossier, ignoré : " << dir << "\n";
return files;
}
for (auto& entry : fs::recursive_directory_iterator(dir)) {
if (entry.is_regular_file() && entry.path().extension() == ".json")
files.push_back(entry.path());
}
return files;
}
void export_to_csv(std::unordered_map<InstanceKey, std::optional<InstanceTradeOff>, HashInstanceKey>& trades)
{
std::ofstream oFile("export_tradeoff.csv", std::ios_base::out | std::ios_base::trunc);
oFile << "Site;" << "SiteCr;" << "Tracks;" << "Rames;" << "Jobs;" << "ID;" << "NbBranch;" << "TimeRatio;\n";
for(const auto& [ins, trade] : trades)
{
oFile << ins.site << ";" << ins.site_cr << ";" << ins.tracks << ";" << ins.rames << ";" << ins.jobs << ";" << ins.id << ";";
if(trade)
{
oFile << trade->nbBranchBest << ";" << trade->timeRatio << ";\n";
}
else
{
oFile << -1 << ";" << -1 << ";\n";
}
}
oFile.close();
}
// ─────────────────────────────────────────────────────────────
// Main
// ─────────────────────────────────────────────────────────────
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <dossier1> [dossier2 ...]\n";
return 1;
}
std::vector<fs::path> dirs;
for (int i = 1; i < argc; ++i) dirs.emplace_back(argv[i]);
// -- Collecte des fichiers
unsigned int all_files = 0;
std::unordered_map<InstanceKey, std::optional<InstanceTradeOff>, HashInstanceKey> trades;
std::unordered_map<InstanceKey, std::pair<unsigned int, double>, HashInstanceKey> reference;
for (auto& d : dirs) {
auto files = collect_json_files(d);
all_files+= files.size();
try {
int ok = 0, err = 0;
for (auto& path : files) {
try {
process_file(path, reference, trades);
++ok;
if (ok % 100 == 0)
std::cout << " [" << ok << "/" << files.size() << "]\n";
} catch (const std::exception& e) {
std::cerr << "[ERR] " << path.filename() << " : " << e.what() << "\n";
++err;
}
}
std::cout << "[DONE] " << ok << " ok, " << err << " erreur(s).\n";
} catch (const std::exception& e) {
std::cerr << "[ERR] " << e.what() << "\n";
return 1;
}
}
if (all_files == 0) {
std::cerr << "[INFO] Aucun fichier .json trouvé.\n";
return 0;
}
std::cout << "[INFO] " << all_files << " fichier(s) trouvé(s).\n";
std::cout << "[INFO] " << "Exporting to CSV tradeoffs" << "\n";
export_to_csv(trades);
return 0;
}