#include "ForgettingExperiments.h" #include <iostream> #include <fstream> #include <chrono> #include <filesystem> namespace armarx::armem::server::test { void get_information_single_ltm( std::map<std::string, ltm::processor::SnapshotFilter::FilterStatistics>& filter ) { /* nlohmann::json info; for(const auto& pair: filter.second){ if(pair.second.accepted + pair.second.rejected < 1){ ended_without_recording = true; ARMARX_INFO << "Trying to not add JSON file because accepted + rejected < 1"; } std::map<std::string, std::string> information; information["Memory Name: "] = memoryName; information["additional time needed: "] = (std::to_string(pair.second.additional_time.count()) + " sec"); information["number of accepted elements: "] = std::to_string(pair.second.accepted); information["number of rejected elements: "] = std::to_string(pair.second.rejected); information["Additional information: "] = pair.second.additional_info; information["Similarity-Type: "] = std::to_string(pair.second.similarity_type); information["Number of objects compared each time: "] = std::to_string((pair.second.number_of_compared_objects)); information["Importance type: "] = pair.second.importance_type; auto time = std::chrono::high_resolution_clock::to_time_t(pair.second.start_time); auto t = localtime(&time); std::stringstream ss; ss << std::put_time(t, "%Y-%m-%d %H:%M:%S"); std::string timeString = ss.str(); information["Filter instance created at: "] = timeString; time = std::chrono::high_resolution_clock::to_time_t(pair.second.end_time); t = localtime(&time); std::stringstream s; s << std::put_time(t, "%Y-%m-%d %H:%M:%S"); timeString = s.str(); information["Filter instance last used at: "] = timeString; info[pair.first] = information; armarx::core::time::DateTime start_time = time_stats["Started " + filter.first]; auto started = start_time.toDateTimeString(); info["Started"] = started; ARMARX_INFO << started; armarx::core::time::DateTime stop_time = time_stats["Stopped " + filter.first]; auto stopped = stop_time.toDateTimeString(); info["Stopped"] = stopped; ARMARX_INFO << stopped; } jsonData[filter.first] = info; info.clear(); */ } void save_statistics( std::map<std::string, std::map<std::string, ltm::processor::SnapshotFilter::FilterStatistics>> stats, std::map<std::string, armarx::core::time::DateTime> time_stats, armarx::core::time::DateTime firstStartedRecording, armarx::core::time::DateTime firstStoppedRecording, std::filesystem::path exportPath, std::string exportName, std::string memoryName, std::string sim_json_data, std::string object_memory_json_data) { ARMARX_INFO << "Saving statistics"; std::filesystem::path d_p; try{ d_p = test::getStatisticsDirectory(exportPath, exportName, memoryName); std::filesystem::create_directories(d_p); ARMARX_INFO << "Experiments will be saved at: " << d_p.string(); } catch(...){ ARMARX_WARNING << "Creating needed directories for saving statistics did not work"; } //json object for statistics: nlohmann::json jsonData; //get current date: auto now = std::chrono::high_resolution_clock::now(); auto now_ax_datetime = DateTime::Now(); auto now_time = std::chrono::high_resolution_clock::to_time_t(now); auto time = localtime(&now_time); std::stringstream ss; ss << std::put_time(time, "%Y-%m-%d %H:%M:%S"); std::string timeString = ss.str(); std::stringstream s; s << std::put_time(time, "%Y%m%d%H%M%S"); std::string timeID = s.str(); jsonData["Statistics saved at"] = timeString; bool ended_without_recording = false; if(firstStoppedRecording.toMilliSecondsSinceEpoch() < firstStartedRecording.toMilliSecondsSinceEpoch()){ //this can happen if the recording is not propperly stopped but interrupted by stopping //the component firstStoppedRecording = now_ax_datetime; } for(const auto& filter: stats){ filter_statistics(filter.second, memoryName,firstStartedRecording, firstStoppedRecording, &jsonData); } if(ended_without_recording){ return; } /* if(sim_json_data.empty() || object_memory_json_data.empty()){ jsonData["Scene-Information for Simulation"] = load_scene_information("sim"); jsonData["Scene-Information for ObjectMemory"] = load_scene_information("om"); jsonData["Additional object in simulation"] = find_difference(jsonData["Scene-Information for ObjectMemory"], jsonData["Scene-Information for Simulation"]); }else { jsonData["Scene-Information for Simulation"] = sim_json_data; jsonData["Scene-Information for ObjectMemory"] = object_memory_json_data; } */ std::string path = d_p.string(); path += "/tmp_wm_"; path += timeID; path += ".json"; try{ std::ofstream outputFile; outputFile.open(path); if(outputFile.is_open()){ outputFile << jsonData.dump(4); outputFile.close(); } else { if(outputFile.fail()){ ARMARX_INFO << outputFile.rdstate(); outputFile.clear(); } ARMARX_INFO << "File is not open"; } } catch(...){ ARMARX_WARNING << "std::ofstream failed"; } ARMARX_INFO << "Saving statistics completed"; } nlohmann::json load_scene_information(std::string om_or_sim) { std::string home_dir = getenv("HOME"); if(home_dir.empty()){ ARMARX_WARNING << "Trying to open home directory but env variable HOME is not set"; } std::filesystem::path path = home_dir; path /= "code"; path /= "h2t" ; path /= "PriorKnowledgeData"; path /= "data"; path /= "PriorKnowledgeData"; path /= "scenes"; std::string name_for_current_scene = "ARMAR-III-kitchen"; //this can be changed later, maybe to something that indicates better that these are the changed files std::string file_name = name_for_current_scene + "_" + om_or_sim + ".json"; path /= file_name; std::ifstream ifs(path); nlohmann::json json_data = nlohmann::json::parse(ifs); return json_data; } nlohmann::json find_difference(nlohmann::json om, nlohmann::json sim) { //the new object is at the last position of sim at the moment auto objects = sim.at("objects"); int num_elements = objects.size(); auto object = objects[num_elements - 1]; return object; } /** * @brief getStatisticsDirectory returns the path to where the statistics for this forgetting process * should be saved * @param memoryName name of the memory, e.g. VisionMemory * @param exportName name of the export * @param exportPath path to the export folder with date for this LTM * @return path */ std::filesystem::path getStatisticsDirectory( std::filesystem::path exportPath, std::string exportName, std::string memoryName) { //path consists of exportPath/Date/exportName/memoryName with the date being the start date! std::filesystem::path statisticsPath = exportPath; //add parts to exportPath statisticsPath /= exportName; statisticsPath /= memoryName; //add Statistics Directory: statisticsPath /= "Statistics"; return statisticsPath; } void filter_statistics( std::map<std::string, ltm::processor::SnapshotFilter::FilterStatistics> statistics_processors, std::string memoryName, armarx::core::time::DateTime firstStartedRecording, armarx::core::time::DateTime firstStoppedRecording, nlohmann::json *statistics) { //TODO: start time of processor should be when enabling recording for filters... not creation //TODO: make sure order stays the way it was when added nlohmann::json ltm_information; for(const auto& statistics_processor: statistics_processors){ nlohmann::json processor_information; //get start time of the processor: auto time = std::chrono::high_resolution_clock::to_time_t(statistics_processor.second.start_time); auto t = localtime(&time); std::stringstream ss; ss << std::put_time(t, "%Y-%m-%d %H:%M:%S"); std::string timeStringStart = ss.str(); processor_information["Processor instance created at"] = timeStringStart; //get end time of the processor: auto timeEnd = std::chrono::high_resolution_clock::to_time_t(statistics_processor.second.end_time); auto t_end = localtime(&timeEnd); std::stringstream s; s << std::put_time(t_end, "%Y-%m-%d %H:%M:%S"); std::string timeStringEnd = s.str(); processor_information["Processor instance last used at"] = timeStringEnd; //get time the processor ran for in seconds: long seconds = timeEnd - time; processor_information["Lifetime of processor in sec"] = seconds; //actual runtime in first recording: processor_information["Processor started at"] = firstStartedRecording.toDateTimeString(); processor_information["Processor stopped at"] = firstStoppedRecording.toDateTimeString(); auto runtime = firstStoppedRecording.toMilliSecondsSinceEpoch() - firstStartedRecording.toMilliSecondsSinceEpoch(); auto seconds_runtime = runtime / 1000.0; processor_information["Duration of recording in seconds"] = seconds_runtime; //add additional information: processor_information["Additional information"] = statistics_processor.second.additional_info; //add number of accepted elements if this is a filter: processor_information["Accepted elements"] = statistics_processor.second.accepted; //add number of rejected elements if this is a filter: processor_information["Rejected elements"] = statistics_processor.second.rejected; //add additional time needed: processor_information["Additional time needed in sec"] = statistics_processor.second.additional_time.count(); //add importance or similarity type if this type of filter: auto importance_type = statistics_processor.second.importance_type; if (!importance_type.empty()){ processor_information["Importance type"] = importance_type; } auto similarity_type = statistics_processor.second.similarity_type; if(similarity_type != aron::similarity::NDArraySimilarity::Type::NONE){ processor_information["Similarity type"] = std::to_string(similarity_type); //add number of objects compared each time if similarity filter: processor_information["Number of objects compared each time"] = statistics_processor.second.number_of_compared_objects; } //add memory name as a sanity check: processor_information["Memory name"] = memoryName; // add information about this specific processor to the information about the ltm: ltm_information[statistics_processor.first] = processor_information; } // add the ltm information to the statistics json object: (*statistics)["Episodic Memory Information"] = ltm_information; } }