#include #include #include #include #include #include #include #include #include #include #include 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()(key.raw); } }; InstanceKey parse_instance_name(const std::string& stem) { InstanceKey k; k.raw = stem; std::vector 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, HashInstanceKey>& references, std::unordered_map, 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 collect_json_files(const fs::path& dir) { std::vector 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, 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] << " [dossier2 ...]\n"; return 1; } std::vector dirs; for (int i = 1; i < argc; ++i) dirs.emplace_back(argv[i]); // -- Collecte des fichiers unsigned int all_files = 0; std::unordered_map, HashInstanceKey> trades; std::unordered_map, 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; }