Commit 98cc8d24 authored by jonasseidel's avatar jonasseidel
Browse files

csv support for test data; mp problem graph generation now supports setting...

csv support for test data; mp problem graph generation now supports setting edge capacities of tip edges to inf 
csv gather function aggregate everything into a single csv file; this 
behaviour will change in the future
parent bb26ac1f
......@@ -8,12 +8,15 @@ maintenance_problem_test
.test
*.lp
*.netw
*.mp
*.log
*.test_param
*.test_data
*.out
benders_test
preprocessor_test
scip_test
maintenance_problem_preformance_test
maintenance_problem_generate_test_data
maintenance_problem_test_incid_edges
gather_data_to_csv
......@@ -18,6 +18,19 @@ public:
void operator>>(T& var);
};
template <typename T>
class random_set_element_generator_capture{
std::default_random_engine _engine;
std::set<T> _set;
bool _random_unused;
public:
random_set_element_generator_capture(std::set<T>& s, bool force_unused = false);
T next();
void operator>>(T& var);
};
#include "random_set_element_generator.ipp"
#endif
......@@ -20,3 +20,32 @@ template <typename T>
void random_set_element_generator<T>::operator>>(T& var){
var = this->next();
}
template <typename T>
random_set_element_generator_capture<T>::random_set_element_generator_capture(std::set<T>& s, bool force_unused) : _engine((std::random_device())()), _set(s), _random_unused(force_unused){}
template <typename T>
T random_set_element_generator_capture<T>::next(){
std::uniform_int_distribution<int> _dist(0, _set.size() - 1);
typename std::set<T>::iterator iter = this->_set.begin();
if(iter == this->_set.end()) throw std::range_error("can't generate from emtpy set");
size_t limit = _dist(_engine);
for(size_t i = 1; i <= limit; i++){
iter++;
}
T ret = *iter;
if(this->_random_unused){
this->_set.erase(iter);
}
return ret;
}
template <typename T>
void random_set_element_generator_capture<T>::operator>>(T& var){
var = this->next();
}
......@@ -25,30 +25,36 @@ Graph random_graph_generator::next(){
return g;
}
std::pair<std::pair<Node*, Node*>,Graph> random_graph_generator::next_acyclic_2_tips(){
std::tuple<std::pair<Node*, Node*>, std::set<Edge*>, Graph> random_graph_generator::next_acyclic_2_tips(){
Graph g (this->_template_edge_attributes, this->_template_node_attributes);
while(!random_graph_generator::grow_random_acyclic(g, this->_number_of_nodes, this->_number_of_edges, this->_edge_generator, this->_node_generator).first){
std::cout << "generation failed; retrying!" << std::endl;
}
std::set<Edge*> core_network = g.edges();
auto [source, target] = g.tip_fringes(this->_edge_generator, this->_node_generator);
source->add_attribute("Source", Attribute({fix, 1, Integral}) );
target->add_attribute("Target", Attribute({fix, 1, Integral}) );
return {{source, target}, std::move(g)};
return {std::pair{source, target}, std::move(core_network), std::move(g)};
}
std::pair<std::pair<Node*, Node*>, Graph> random_graph_generator::next_acyclic_in_steps_2_tips(size_t steps, size_t fading){
std::tuple<std::pair<Node*, Node*>, std::set<Edge*>, Graph> random_graph_generator::next_acyclic_in_steps_2_tips(size_t steps, size_t fading, random_attribute_generator* connector_generator, random_attribute_generator* terminal_generator){
Graph g (this->_template_edge_attributes, this->_template_node_attributes);
while(!random_graph_generator::grow_random_acyclic_in_steps(g, this->_number_of_nodes/steps, this->_number_of_edges/steps, steps, fading, this->_edge_generator, this->_node_generator).first){
std::cout << "generation failed; retrying!" << std::endl;
}
auto [source, target] = g.tip_fringes(this->_edge_generator, this->_node_generator);
std::set<Edge*> core_network = g.edges();
if(connector_generator == nullptr) connector_generator = &this->_edge_generator;
if(terminal_generator == nullptr) terminal_generator = &this->_node_generator;
auto [source, target] = g.tip_fringes(*connector_generator, *terminal_generator);
source->add_attribute("Source", Attribute({fix, 1, Integral}) );
target->add_attribute("Target", Attribute({fix, 1, Integral}) );
return {{source, target}, std::move(g)};
return {std::pair{source, target}, std::move(core_network), std::move(g)};
}
......@@ -88,6 +94,15 @@ Attribute random_graph_generator::node_template_throwing(const std::string& attr
return search->second;
}
random_attribute_generator& random_graph_generator::edge_generator(){
return this->_edge_generator;
}
random_attribute_generator& random_graph_generator::node_generator(){
return this->_node_generator;
}
std::pair<bool, std::pair<std::vector<Node*>, std::vector<Edge*>>> random_graph_generator::grow_random(Graph& g, size_t number_of_nodes, size_t number_of_edges, random_attribute_generator& edge_attribute_generator, random_attribute_generator& node_attribute_generator){
std::vector<Node*> added_nodes;
std::vector<Edge*> added_edges;
......
#ifndef RANDOM_GRAPH_GENERATOR_H
#include <cstddef>
#include <map>
#include <tuple>
#include <iostream>
#include <string>
#include <sstream>
......@@ -26,8 +29,8 @@ public:
Graph next_acyclic();
Graph next();
std::pair<std::pair<Node*, Node*>, Graph> next_acyclic_2_tips();
std::pair<std::pair<Node*, Node*>, Graph> next_acyclic_in_steps_2_tips(size_t steps, size_t fading);
std::tuple<std::pair<Node*, Node*>, std::set<Edge*>, Graph> next_acyclic_2_tips();
std::tuple<std::pair<Node*, Node*>, std::set<Edge*>, Graph> next_acyclic_in_steps_2_tips(size_t steps, size_t fading, random_attribute_generator* connector_generator = nullptr, random_attribute_generator* terminal_generator = nullptr);
void operator>>(Graph& var);
......@@ -37,8 +40,13 @@ public:
Attribute edge_template_throwing(const std::string& attr);
Attribute node_template_throwing(const std::string& attr);
random_attribute_generator& node_generator();
random_attribute_generator& edge_generator();
public:
static std::pair<bool, std::pair<std::vector<Node*>, std::vector<Edge*>>> grow_random(Graph& g, size_t number_of_nodes, size_t number_of_edges, random_attribute_generator& edge_attribute_generator, random_attribute_generator& node_attribute_generator);
static std::pair<bool, std::pair<std::vector<Node*>, std::vector<Edge*>>> grow_random_acyclic(Graph& g, size_t number_of_nodes, size_t number_of_edges, random_attribute_generator& edge_attribute_generator, random_attribute_generator& node_attribute_generator);
static std::pair<bool, std::pair<std::vector<Node*>, std::vector<Edge*>>> grow_random_acyclic_in_steps(Graph& g, size_t number_of_nodes_per_step, size_t number_of_edges_per_step, size_t number_of_steps, size_t step_fading, random_attribute_generator& edge_attribute_generator, random_attribute_generator& node_attribute_generator);
};
#endif
CXX := g++
CXXFLAGS := -O0 -g -std=c++20 #-Wall -Wextra -Wpedantic
CXX := g++-10
CXXFLAGS := -O0 -g -std=c++17 #-Wall -Wextra -Wpedantic
LIBSCIPOPTN := /media/hwlr/Data/scipoptsuite-7.0.2/lib/libscipopt.so
LIBSCIPOPT := /usr/local/lib/libscip.so.7.0.2.0
LIBORTOOLS := /usr/local/lib/libortools.so
......@@ -17,7 +17,7 @@ LP_OUT := $(filter-out %lp_generator.o,$(patsubst %.cpp,%.o,$(shell find -wholen
LP_PROBLEMS_OUT := $(patsubst %.cpp,%.o,$(shell find -wholename "./Specialization/LP_Problems/*.cpp" ! -wholename "*retired*"))
COMMON_OUT := $(patsubst %.cpp,%.o,$(shell find -wholename "./Common_Types/*.cpp"))
targets := graph_test ass_test linear_program_test maintenance_problem_test benders_test scip_test preprocessor_test maintenance_problem_test_incid_edges
targets := graph_test ass_test linear_program_test maintenance_problem_test benders_test scip_test preprocessor_test maintenance_problem_test_incid_edges gather_data_to_csv
all: $(targets)
......@@ -80,6 +80,12 @@ maintenance_problem_test_incid_edges: maintenance_problem_test_incid_edges.o $(L
maintenance_problem_test_incid_edges.o: maintenance_problem_test_incid_edges.cpp
$(CXX) $(CXXFLAGS) -c $< -o $@
gather_data_to_csv: gather_data_to_csv.o $(LP_PROBLEMS_OUT) $(LP_OUT) $(GRAPH_OUT) Linear_Programming/lp_generator.o $(LIBSCIPOPT) $(LIBORTOOLS)
$(CXX) $(CXXFLAGS) $^ -o $@
gather_data_to_csv.o: gather_data_to_csv.cpp
$(CXX) $(CXXFLAGS) -c $< -o $@
# Linear Programming Folder Object Files
.SECONDEXPANSION:LP
......
#include <sstream>
#include <vector>
bool gather_data(int depth, std::filesystem::path path, std::vector<Data>& data_vector){
std::stringstream buffer;
for(int i = 0; i < depth; i++){
buffer << " ";
}
std::cout << buffer.str() << "--> going into " << path.string() << std::endl;
bool all_fine = true;
// iterate over instances in folder
for (const auto & entry : std::filesystem::directory_iterator(path)){
if(entry.is_directory()){
all_fine = ( all_fine && gather_data(depth+1, entry.path(), data_vector) );
}else{
// check if data describes instance and if it has previously been executed (all data has been calculated)
try{
std::fstream data_file;
data_file.open(entry.path(), std::ios::in);
data_vector.push_back(Data{});
Data& curr_data = data_vector.back();
data_file >> curr_data;
data_file.close();
if(!values_complete(curr_data)) {
all_fine = false;
data_vector.pop_back();
std::cout << "file contained instance test data, but not all values where determined!" << std::endl;
throw std::invalid_argument("not all data has been calculated; execute the models first");
}
std::cout << buffer.str() << "data appears correct; collecting..." << std::endl;
}catch(std::exception& e){
std::cout << buffer.str() << e.what() << std::endl;
std::cout << buffer.str() << "file doesn't appear to contain test data" << std::endl;
}
}
}
return all_fine;
}
std::pair<bool, std::vector<Data>> gather_data(std::filesystem::path path){
std::vector<Data> data_vector;
return {gather_data(0, path, data_vector), std::move(data_vector)};
}
bool data_to_csv(std::fstream& file, const std::vector<Data>& data_vector, const axis_data& x_axis_data, const axis_data& y_axis_data, const std::vector<std::string>& models){
bool all_belonged;
file << csv_test_data_title(x_axis_data, y_axis_data, models) << "\n";
for(const Data& data : data_vector){
std::cout << "start" << std::endl;
auto [belonged, csv_string] = csv(data, x_axis_data, y_axis_data, models);
all_belonged = (all_belonged && belonged);
file << csv_string << "\n";
std::cout << "end" << std::endl;
}
return all_belonged;
}
bool generate_and_execute_2d_plot_test(std::filesystem::path path, size_t number_of_instances_per_coord, axis_data x_axis_data, axis_data y_axis_data, std::function<Generation_Parameters(double x, double y)> test_generator){
bool generate_and_execute_2d_plot_test(std::filesystem::path path, size_t number_of_instances_per_coord, const axis_data& x_axis_data, const axis_data& y_axis_data, std::function<Generation_Parameters(double x, double y)> test_generator){
std::cout << "-----------------> starting testing raster in " << path.string() << std::endl;
bool success = true;
......@@ -9,12 +9,12 @@ bool generate_and_execute_2d_plot_test(std::filesystem::path path, size_t number
for(int yn = 0; yn < y_axis_data.resolution; yn++){
double x = ((double)xn/(x_axis_data.resolution-1))*x_axis_data.upper_bound + (1-(double)xn/(x_axis_data.resolution-1))*x_axis_data.lower_bound;
double y = ((double)yn/(y_axis_data.resolution-1))*y_axis_data.upper_bound + (1-(double)yn/(y_axis_data.resolution-1))*y_axis_data.lower_bound;
std::cout << "-----------------> rasterized testing loop state: " << x_axis_data.axis_name << " = " << x << ", " << y_axis_data.axis_name << " = " << y << std::endl;
std::cout << "-----------------> rasterized testing loop state: " << x_axis_data.name << " = " << x << ", " << y_axis_data.name << " = " << y << std::endl;
Generation_Parameters current_generation_parameters = test_generator(x, y);
std::stringstream folder;
folder << x << "_" << y;
folder << "raster_pos:" << x_axis_data.name << "=" << x << "_" << y_axis_data.name << "=" << y;
std::filesystem::path current_file_path = path/folder.str()/"test_parameters.test_param";
// check if the folder has been populated with an instance before
......
......@@ -28,7 +28,7 @@ bool generate_tests_data(std::filesystem::path path, int number_of_instances){
{{"Flow", Attribute(max, 0)},{"Upper", Attribute(fix, 1)}, {"Selected", Attribute(fix, 0)}, {"Edgepotential", Attribute(min, 0)}},
{{"Nodepotential", Attribute(min, 0)}}
),
(size_t) number_of_edges*test_parameters.share_of_critical, test_parameters.number_of_epochs
test_parameters.share_of_critical, test_parameters.number_of_epochs, test_parameters.core_network_problem
);
......
......@@ -14,18 +14,32 @@
std::ostream& operator<<(std::ostream& os, const Generation_Parameters& gen_param){
os << "Generation_Parameters {\n"
<< "graph_type: " << gen_param.graph_type << "\n"
<< "number_of_nodes: " << gen_param.number_of_nodes << "\n"
<< "avg_incid_per_node: " << gen_param.avg_incid_per_node << "\n"
<< "share_of_critical: " << gen_param.share_of_critical << "\n"
<< "nodes_per_step: " << gen_param.nodes_per_step << "\n"
<< "fuzzing: " << gen_param.fuzzing << "\n"
<< "number_of_epochs: " << gen_param.number_of_epochs << "\n"
<< "graph_type: " << gen_param.graph_type << "\n"
<< "core_network_problem: " << gen_param.core_network_problem
<< "number_of_nodes: " << gen_param.number_of_nodes << "\n"
<< "avg_incid_per_node: " << gen_param.avg_incid_per_node << "\n"
<< "share_of_critical: " << gen_param.share_of_critical << "\n"
<< "nodes_per_step: " << gen_param.nodes_per_step << "\n"
<< "fuzzing: " << gen_param.fuzzing << "\n"
<< "number_of_epochs: " << gen_param.number_of_epochs << "\n"
<< "}";
return os;
}
std::string csv(const Generation_Parameters& gen_param){
std::stringstream csv_string;
csv_string << gen_param.graph_type << ","
<< gen_param.core_network_problem << ","
<< gen_param.number_of_nodes << ","
<< gen_param.avg_incid_per_node << ","
<< gen_param.share_of_critical << ","
<< gen_param.nodes_per_step << ","
<< gen_param.fuzzing << ","
<< gen_param.number_of_epochs;
return csv_string.str();
}
std::istream& operator>>(std::istream& is, Generation_Parameters& gen_param){
std::string curr;
is >> curr;
......@@ -37,6 +51,7 @@ std::istream& operator>>(std::istream& is, Generation_Parameters& gen_param){
if(gen_param.graph_type.size() > 0 && gen_param.graph_type.c_str()[0] == ' '){
gen_param.graph_type = gen_param.graph_type.substr(1, std::string::npos);
}
IF_READ_VAR_SET_VAR_DIRECT(is, gen_param, core_network_problem, curr);
IF_READ_VAR_SET_VAR_DIRECT(is, gen_param, number_of_nodes, curr);
IF_READ_VAR_SET_VAR_DIRECT(is, gen_param, avg_incid_per_node, curr);
IF_READ_VAR_SET_VAR_DIRECT(is, gen_param, share_of_critical, curr);
......@@ -55,6 +70,7 @@ std::ostream& operator<<(std::ostream& os, const Derived_Problem_Data& prob_data
PRINT_IF_DEF(os, prob_data, number_of_nodes);
PRINT_IF_DEF(os, prob_data, avg_incid_per_node);
PRINT_IF_DEF(os, prob_data, number_of_critical_edges);
PRINT_IF_DEF(os, prob_data, share_of_critical);
PRINT_IF_DEF(os, prob_data, number_of_epochs);
PRINT_IF_DEF(os, prob_data, path_length_lower_bound);
......@@ -63,6 +79,21 @@ std::ostream& operator<<(std::ostream& os, const Derived_Problem_Data& prob_data
return os;
}
std::string csv(const Derived_Problem_Data& prob_data){
// only convert to csv if fully initialized
std::stringstream csv_string;
csv_string << prob_data.number_of_edges.second << ","
<< prob_data.number_of_nodes.second << ","
<< prob_data.avg_incid_per_node.second << ","
<< prob_data.number_of_critical_edges.second << ","
<< prob_data.share_of_critical.second << ","
<< prob_data.number_of_epochs.second << ","
<< prob_data.path_length_lower_bound.second;
return csv_string.str();
}
std::istream& operator>>(std::istream& is, Derived_Problem_Data& prob_data){
prob_data.number_of_edges.first = false;
prob_data.number_of_nodes.first = false;
......@@ -108,6 +139,75 @@ std::ostream& operator<<(std::ostream& os, const Derived_Performance_Data& exec_
return os;
}
std::string csv(const Derived_Performance_Data& exec_data){
// only convert to csv if fully initialized
std::stringstream csv_string;
csv_string << exec_data.time_in_sec.second << ","
<< exec_data.number_of_bnb_runs.second << ","
<< exec_data.number_of_reopt_runs.second << ","
<< exec_data.number_of_nodes_explored.second << ","
<< exec_data.max_depth.second << ","
<< exec_data.dual_bound.second << ","
<< exec_data.primal_bound.second << ","
<< exec_data.gap.second << ","
<< exec_data.number_of_primal_sols.second;
return csv_string.str();
}
std::string csv(const std::vector<Derived_Performance_Data>& exec_vector){
// only convert to csv if fully initialized
std::cout << "marker" << std::endl;
double time_in_sec = 0;
AVG_PERF_OVER_VEC(exec_vector, time_in_sec);
std::cout << "marker" << std::endl;
double number_of_bnb_runs = 0;
AVG_PERF_OVER_VEC(exec_vector, number_of_bnb_runs);
std::cout << "marker" << std::endl;
double number_of_reopt_runs = 0;
AVG_PERF_OVER_VEC(exec_vector, number_of_reopt_runs);
std::cout << "marker" << std::endl;
double number_of_nodes_explored = 0;
AVG_PERF_OVER_VEC(exec_vector, number_of_nodes_explored);
std::cout << "marker" << std::endl;
double max_depth = 0;
AVG_PERF_OVER_VEC(exec_vector, max_depth);
std::cout << "marker" << std::endl;
double dual_bound = 0;
AVG_PERF_OVER_VEC(exec_vector, dual_bound);
std::cout << "marker" << std::endl;
double gap = 0;
AVG_PERF_OVER_VEC(exec_vector, gap);
std::cout << "marker" << std::endl;
double primal_bound = 0;
AVG_PERF_OVER_VEC(exec_vector, primal_bound);
std::cout << "marker" << std::endl;
double number_of_primal_sols = 0;
AVG_PERF_OVER_VEC(exec_vector, number_of_primal_sols);
std::cout << "marker" << std::endl;
std::stringstream csv_string;
csv_string << time_in_sec << ","
<< number_of_bnb_runs << ","
<< number_of_reopt_runs << ","
<< number_of_nodes_explored << ","
<< max_depth << ","
<< dual_bound << ","
<< primal_bound << ","
<< gap << ","
<< number_of_primal_sols;
return csv_string.str();
}
std::istream& operator>>(std::istream& is, Derived_Performance_Data& exec_data){
exec_data.time_in_sec.first = false;
exec_data.number_of_bnb_runs.first = false;
......@@ -175,12 +275,12 @@ std::istream& operator>>(std::istream& is, std::map<std::string, std::vector<Der
std::ostream& operator<<(std::ostream& os, const Data& data){
os << "Performance_Tester_Data {\n"
<< "marked_for_inspection: " << data.marked_for_inspection << "\n"
<< "path: " << data.path << "\n"
<< "name: " << data.name << "\n"
<< "gen_data: " << data.gen_data << "\n"
<< "mp: " << data.mp << "\n"
<< "derived_problem: " << data.derived_problem << "\n"
<< "marked_for_inspection: " << data.marked_for_inspection << "\n"
<< "path: " << data.path << "\n"
<< "name: " << data.name << "\n"
<< "gen_data: " << data.gen_data << "\n"
<< "mp: " << data.mp << "\n"
<< "derived_problem: " << data.derived_problem << "\n"
<< "derived_performance: \n";
for(auto& [prob_name, exec_vector] : data.derived_performance){
os << "formulation: " << prob_name << "\n"
......@@ -195,6 +295,103 @@ std::ostream& operator<<(std::ostream& os, const Data& data){
return os;
}
std::string csv_test_data_title(const axis_data& x_axis_data, const axis_data& y_axis_data, const std::vector<std::string>& models){
std::stringstream csv_string;
csv_string << "marked_for_inspection" << ","
<< "path" << ","
<< "name" << ","
<< x_axis_data.name << ","
<< y_axis_data.name << ","
<< "graph_type" << ","
<< "number_of_nodes_gen" << ","
<< "avg_incid_per_node_gen" << ","
<< "share_of_critical_gen" << ","
<< "nodes_per_step_gen" << ","
<< "fuzzing_gen" << ","
<< "number_of_epochs_gen" << ","
<< "number_of_edges_actual" << ","
<< "number_of_nodes_actual" << ","
<< "avg_incid_per_node_actual" << ","
<< "number_of_critical_edges_actual" << ","
<< "share_of_critical_actual" << ","
<< "number_of_epochs_actual" << ","
<< "path_length_lower_bound_actual" << ",";
for(std::string model : models){
csv_string << "time_in_sec" << "_" << model << ","
<< "number_of_bnb_runs" << "_" << model << ","
<< "number_of_reopt_runs" << "_" << model << ","
<< "number_of_nodes_explored" << "_" << model << ","
<< "max_depth" << "_" << model << ","
<< "dual_bound" << "_" << model << ","
<< "primal_bound" << "_" << model << ","
<< "gap" << "_" << model << ","
<< "number_of_primal_sols" << "_" << model;
}
return csv_string.str();
}
// belongs|csv format
std::pair<bool, std::string> csv(const Data& data, const axis_data& x_axis_data, const axis_data& y_axis_data, const std::vector<std::string>& models){
std::cout << "start csv" << std::endl;
bool belongs = true;
std::stringstream csv_string;
std::string xval = "";
std::string yval = "";
std::filesystem::path data_path(data.path);
std::stringstream raster_entry_folder_name;
raster_entry_folder_name << data_path.parent_path().filename().string();
// parsing folder name
std::cout << "1" << std::endl;
std::string curr;
std::getline(raster_entry_folder_name, curr, ':');
if(curr == "raster_pos"){
// parse for x_axis_val
std::getline(raster_entry_folder_name, curr, '=');
if(curr != x_axis_data.name){
belongs = false;
}
std::getline(raster_entry_folder_name, xval, '_');
// parse for y_axis_val
std::getline(raster_entry_folder_name, curr, '=');
if(curr != x_axis_data.name){
belongs = false;
}
std::getline(raster_entry_folder_name, yval);
}else{
belongs = false;
}
std::cout << "2" << std::endl;
csv_string << data.marked_for_inspection << ","
<< data.path << ","
<< data.name << ","
<< xval << ","
<< yval << ","
<< csv(data.gen_data) << ","
<< csv(data.derived_problem);
for(std::string model : models){
std::cout << model << std::endl;
std::cout << data << std::endl;
auto exec_vector = data.derived_performance.find(model)->second;
for(int i = 0; i < exec_vector.size(); i++){
std::cout << exec_vector[i] << std::endl;
}
csv_string << ",";
csv_string << csv(exec_vector);
}
std::cout << "end" << std::endl;
return {belongs, csv_string.str()};
}