Fix result name overlapping in simultaneous experiments

This commit is contained in:
2025-08-04 13:10:48 +02:00
parent e8b35d4c5e
commit b7f4651e2c
6 changed files with 49 additions and 14 deletions

View File

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.20) cmake_minimum_required(VERSION 3.20)
project(Platform project(Platform
VERSION 1.1.0 VERSION 1.1.1
DESCRIPTION "Platform to run Experiments with classifiers." DESCRIPTION "Platform to run Experiments with classifiers."
HOMEPAGE_URL "https://github.com/rmontanana/platform" HOMEPAGE_URL "https://github.com/rmontanana/platform"
LANGUAGES CXX LANGUAGES CXX

View File

@@ -41,8 +41,7 @@ namespace platform {
} }
json bests; json bests;
for (const auto& file : files) { for (const auto& file : files) {
auto result = Result(); auto result = Result(path, file);
result.load(path, file);
auto data = result.getJson(); auto data = result.getJson();
for (auto const& item : data.at("results")) { for (auto const& item : data.at("results")) {
bool update = true; bool update = true;

View File

@@ -13,8 +13,7 @@ namespace platform {
for (const auto& file : directory_iterator(path)) { for (const auto& file : directory_iterator(path)) {
auto filename = file.path().filename().string(); auto filename = file.path().filename().string();
if (filename.find(".json") != std::string::npos && filename.find("results_") == 0) { if (filename.find(".json") != std::string::npos && filename.find("results_") == 0) {
auto result = Result(); auto result = Result(path, filename);
result.load(path, filename);
bool addResult = true; bool addResult = true;
if (platform != "any" && result.getPlatform() != platform if (platform != "any" && result.getPlatform() != platform
|| model != "any" && result.getModel() != model || model != "any" && result.getModel() != model

View File

@@ -1,6 +1,8 @@
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <random>
#include <cstdlib>
#include "best/BestScore.h" #include "best/BestScore.h"
#include "common/Colors.h" #include "common/Colors.h"
#include "common/DotEnv.h" #include "common/DotEnv.h"
@@ -34,14 +36,25 @@ namespace platform {
} }
Result::Result() Result::Result()
{ {
path = Paths::results();
fileName = "none";
data["date"] = get_actual_date(); data["date"] = get_actual_date();
data["time"] = get_actual_time(); data["time"] = get_actual_time();
data["results"] = json::array(); data["results"] = json::array();
data["seeds"] = json::array(); data["seeds"] = json::array();
complete = false;
} }
std::string Result::getFilename() const
Result& Result::load(const std::string& path, const std::string& fileName)
{ {
if (fileName == "none") {
throw std::runtime_error("Filename is not set. Use save() method to generate a filename.");
}
return fileName;
}
Result::Result(const std::string& path, const std::string& fileName)
{
this->path = path;
this->fileName = fileName;
std::ifstream resultData(path + "/" + fileName); std::ifstream resultData(path + "/" + fileName);
if (resultData.is_open()) { if (resultData.is_open()) {
data = json::parse(resultData); data = json::parse(resultData);
@@ -58,7 +71,6 @@ namespace platform {
score /= best.second; score /= best.second;
} }
complete = data["results"].size() > 1; complete = data["results"].size() > 1;
return *this;
} }
json Result::getJson() json Result::getJson()
{ {
@@ -71,11 +83,15 @@ namespace platform {
} }
void Result::save(const std::string& path) void Result::save(const std::string& path)
{ {
std::ofstream file(path + getFilename()); do {
fileName = generateFileName();
}
while (std::filesystem::exists(path + fileName));
std::ofstream file(path + fileName);
file << data; file << data;
file.close(); file.close();
} }
std::string Result::getFilename() const std::string Result::generateFileName()
{ {
std::ostringstream oss; std::ostringstream oss;
std::string stratified; std::string stratified;
@@ -85,13 +101,31 @@ namespace platform {
catch (nlohmann::json_abi_v3_11_3::detail::type_error) { catch (nlohmann::json_abi_v3_11_3::detail::type_error) {
stratified = data["stratified"].get<int>() == 1 ? "1" : "0"; stratified = data["stratified"].get<int>() == 1 ? "1" : "0";
} }
auto generateRandomString = [](int length) -> std::string {
const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
// Use thread-local static generator to avoid interfering with global random state
thread_local static std::random_device rd;
thread_local static std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, sizeof(alphanum) - 2);
std::string result;
for (int i = 0; i < length; ++i) {
result += alphanum[dis(gen)];
}
return result;
};
oss << "results_" oss << "results_"
<< data.at("score_name").get<std::string>() << "_" << data.at("score_name").get<std::string>() << "_"
<< data.at("model").get<std::string>() << "_" << data.at("model").get<std::string>() << "_"
<< data.at("platform").get<std::string>() << "_" << data.at("platform").get<std::string>() << "_"
<< data["date"].get<std::string>() << "_" << data["date"].get<std::string>() << "_"
<< data["time"].get<std::string>() << "_" << data["time"].get<std::string>() << "_"
<< stratified << ".json"; << stratified << "_"
<< generateRandomString(5) << ".json";
return oss.str(); return oss.str();
} }
std::string Result::to_string(int maxModel, int maxTitle) const std::string Result::to_string(int maxModel, int maxTitle) const

View File

@@ -5,6 +5,7 @@
#include <string> #include <string>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include "common/Timer.hpp" #include "common/Timer.hpp"
#include "common/Paths.h"
#include "main/HyperParameters.h" #include "main/HyperParameters.h"
#include "main/PartialResult.h" #include "main/PartialResult.h"
@@ -14,7 +15,7 @@ namespace platform {
class Result { class Result {
public: public:
Result(); Result();
Result& load(const std::string& path, const std::string& filename); Result(const std::string& path, const std::string& filename);
void save(const std::string& path); void save(const std::string& path);
std::vector<std::string> check(); std::vector<std::string> check();
// Getters // Getters
@@ -49,6 +50,9 @@ namespace platform {
void setNFolds(int nfolds) { data["folds"] = nfolds; }; void setNFolds(int nfolds) { data["folds"] = nfolds; };
void setPlatform(const std::string& platform_name) { data["platform"] = platform_name; }; void setPlatform(const std::string& platform_name) { data["platform"] = platform_name; };
private: private:
std::string generateFileName();
std::string path;
std::string fileName;
json data; json data;
bool complete; bool complete;
double score = 0.0; double score = 0.0;

View File

@@ -13,8 +13,7 @@ namespace platform {
for (const auto& file : directory_iterator(path)) { for (const auto& file : directory_iterator(path)) {
auto filename = file.path().filename().string(); auto filename = file.path().filename().string();
if (filename.find(".json") != std::string::npos && filename.find("results_") == 0) { if (filename.find(".json") != std::string::npos && filename.find("results_") == 0) {
auto result = Result(); auto result = Result(path, filename);
result.load(path, filename);
if (model != "any" && result.getModel() != model) if (model != "any" && result.getModel() != model)
continue; continue;
auto data = result.getData()["results"]; auto data = result.getData()["results"];