Commit efb68ce6 authored by jonasseidel's avatar jonasseidel

test generation and execution routines

parent 974ad846
......@@ -9,3 +9,9 @@ maintenance_problem_test
*.lp
*.netw
*.log
*.test_param
benders_test
preprocessor_test
scip_test
maintenance_problem_preformance_test
maintenance_problem_generate_test_data
CXX := g++
CXXFLAGS := -O0 -g -std=c++2a #-Wall -Wextra -Wpedantic
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
......@@ -10,13 +11,14 @@ LP_DEP := $(patsubst %.cpp,%.o,$(shell find -type f -wholename "./Linear_Program
LP_PROBLEMS_DEP := $(patsubst %.cpp,%.o,$(shell find -type f -wholename "./Specialization/LP_Problems/*" ! -wholename "*retired*"))
COMMON_DEP := $(patsubst %.cpp,%.o,$(shell find -type f -wholename "./Common_Types/*"))
GRAPH_OUT := $(patsubst %.cpp,%.o,$(shell find -wholename "./Graphtheory/*.cpp"))
LP_OUT := $(filter-out %lp_generator.o,$(patsubst %.cpp,%.o,$(shell find -wholename "./Linear_Programming/*.cpp")))
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"))
all: graph_test ass_test linear_program_test maintenance_problem_test benders_test scip_test
all: graph_test ass_test linear_program_test maintenance_problem_test benders_test scip_test preprocessor_test maintenance_problem_generate_test_data maintenance_problem_performance_test
OUTS :=
......@@ -47,7 +49,7 @@ linear_program_test.o: linear_programming_test.cpp ./Linear_Programming/Linear_P
$(CXX) $(CXXFLAGS) -c $< -o $@
maintenance_problem_test: maintenance_problem_test.o $(LP_PROBLEMS_OUT) $(LP_OUT) $(GRAPH_OUT) Linear_Programming/lp_generator.o $(LIBSCIPOPT)
maintenance_problem_test: maintenance_problem_test.o $(LP_PROBLEMS_OUT) $(LP_OUT) $(GRAPH_OUT) Linear_Programming/lp_generator.o $(LIBSCIPOPT) $(LIBORTOOLS)
$(CXX) $(CXXFLAGS) $^ -o $@
maintenance_problem_test.o: maintenance_problem_test.cpp ./Specialization/LP_Problems/Maintenance_Problem/maintenance_problem_generator.o $(GRAPH_DEP) $(COMMON_DEP) $(LP_DEP) $(LP_PROBLEMS_DEP)
......@@ -65,6 +67,25 @@ scip_test: scip_test.o $(LIBSCIPOPT)
scip_test.o: scip_test.cpp
$(CXX) $(CXXFLAGS) -c $< -o $@
preprocessor_test: preprocessor_test.o
$(CXX) $(CXXFLAGS) $^ -o $@
preprocessor_test.o: preprocessor_test.cpp
$(CXX) $(CXXFLAGS) -c $< -o $@
maintenance_problem_generate_test_data: maintenance_problem_generate_test_data.o $(LP_PROBLEMS_OUT) $(LP_OUT) $(GRAPH_OUT) Linear_Programming/lp_generator.o $(LIBSCIPOPT) $(LIBORTOOLS)
$(CXX) $(CXXFLAGS) $^ -o $@
maintenance_problem_generate_test_data.o: maintenance_problem_generate_test_data.cpp
$(CXX) $(CXXFLAGS) -c $< -o $@
maintenance_problem_performance_test: maintenance_problem_performance_test.o $(LP_PROBLEMS_OUT) $(LP_OUT) $(GRAPH_OUT) Linear_Programming/lp_generator.o $(LIBSCIPOPT) $(LIBORTOOLS)
$(CXX) $(CXXFLAGS) $^ -o $@
maintenance_problem_performance_test.o: maintenance_problem_performance_test.cpp
$(CXX) $(CXXFLAGS) -c $< -o $@
# Linear Programming Folder Object Files
.SECONDEXPANSION:LP
Graph := ./Graphtheory/
......
#include "../../../Tester_Performance/Generic_Performance_Tester.h"
#include "maintenance_problem_generator.h"
#include <map>
#include <vector>
#include <cassert>
#include <filesystem>
#include <functional>
#include <cstddef>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
// macros to set vals
#define SET_VARIABLE(container, variable, new_val) \
if(check_all_problem_data){ \
if(container.variable.first && new_val != container.variable.second){ \
std::cout << "overriding " << #variable << " for " << data.path << "->" << data.name << "(previous: " << container.variable.second << ", new: " << new_val << ")" << std::endl; \
container.variable.first = false; \
} \
} \
if(!container.variable.first){ \
container.variable.second = new_val; \
container.variable.first = true; \
}
#define PRINT_IF_DEF(stream, container, variable) \
if(container.variable.first){ \
stream << #variable << ": " << container.variable.second << "\n"; \
}
#define IF_READ_VAR_SET_VAR_VALID_DIRECT(stream, container, variable, current_string) \
if(current_string == #variable ":" ){ \
stream >> container.variable.second; \
container.variable.first = true; \
}
#define IF_READ_VAR_SET_VAR_VALID_GETLINE(stream, container, variable, current_string) \
if(current_string == #variable ":" ){ \
std::getline(stream, current_string); \
container.variable.second = current_string; \
container.variable.first = true; \
}
#define IF_READ_VAR_SET_VAR_GETLINE(stream, container, variable, current_string) \
if(current_string == #variable ":" ){ \
std::getline(stream, current_string); \
container.variable = current_string; \
}
#define IF_READ_VAR_SET_VAR_DIRECT(stream, container, variable, current_string) \
if(current_string == #variable ":" ){ \
stream >> container.variable; \
}
// define a struct of data we wish to use in our execution function
struct Generation_Parameters{
std::string graph_type;
size_t number_of_nodes;
size_t avg_incid_per_node;
double share_of_critical;
size_t nodes_per_step;
size_t fuzzing;
size_t number_of_epochs;
};
struct Derived_Problem_Data{
std::pair<bool, size_t> number_of_edges;
std::pair<bool, size_t> number_of_nodes;
std::pair<bool, double> avg_incid_per_node;
std::pair<bool, size_t> number_of_critical_edges;
std::pair<bool, double> share_of_critical;
std::pair<bool, size_t> number_of_epochs;
std::pair<bool, size_t> path_length_lower_bound;
};
struct Derived_Performance_Data{
std::pair<bool, double> time_in_sec;
std::pair<bool, int> number_of_bnb_runs;
std::pair<bool, int> number_of_reopt_runs;
std::pair<bool, int> number_of_nodes_explored;
std::pair<bool, int> max_depth;
std::pair<bool, double> dual_bound;
std::pair<bool, double> primal_bound;
std::pair<bool, double> gap;
std::pair<bool, int> number_of_primal_sols;
};
struct Data{
bool marked_for_inspection;
std::string path;
std::string name;
Generation_Parameters gen_data;
Maintenance_Problem mp;
Derived_Problem_Data derived_problem;
std::map<std::string, std::vector<Derived_Performance_Data> > derived_performance;
};
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"
<< "}";
return os;
}
std::istream& operator>>(std::istream& is, Generation_Parameters& gen_param){
std::string curr;
is >> curr;
assert(curr == "Generation_Parameters");
is >> curr;
assert(curr == "{");
is >> curr;
while(curr != "}"){
IF_READ_VAR_SET_VAR_GETLINE(is, gen_param, graph_type, 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);
IF_READ_VAR_SET_VAR_DIRECT(is, gen_param, nodes_per_step, curr);
IF_READ_VAR_SET_VAR_DIRECT(is, gen_param, fuzzing, curr);
IF_READ_VAR_SET_VAR_DIRECT(is, gen_param, number_of_epochs, curr);
is >> curr;
}
return is;
}
std::ostream& operator<<(std::ostream& os, const Derived_Problem_Data& prob_data){
os << "Derived_Problem_Data {\n";
PRINT_IF_DEF(os, prob_data, number_of_edges);
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, number_of_epochs);
PRINT_IF_DEF(os, prob_data, path_length_lower_bound);
os << "}";
return os;
}
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;
prob_data.avg_incid_per_node.first = false;
prob_data.number_of_critical_edges.first = false;
prob_data.share_of_critical.first = false;
prob_data.number_of_epochs.first = false;
prob_data.path_length_lower_bound.first = false;
std::string curr;
is >> curr;
assert(curr == "Derived_Problem_Data");
is >> curr;
assert(curr == "{");
is >> curr;
while(curr != "}"){
IF_READ_VAR_SET_VAR_VALID_DIRECT(is, prob_data, number_of_edges, curr);
IF_READ_VAR_SET_VAR_VALID_DIRECT(is, prob_data, number_of_nodes, curr);
IF_READ_VAR_SET_VAR_VALID_DIRECT(is, prob_data, avg_incid_per_node, curr);
IF_READ_VAR_SET_VAR_VALID_DIRECT(is, prob_data, number_of_critical_edges, curr);
IF_READ_VAR_SET_VAR_VALID_DIRECT(is, prob_data, share_of_critical, curr);
IF_READ_VAR_SET_VAR_VALID_DIRECT(is, prob_data, number_of_epochs, curr);
IF_READ_VAR_SET_VAR_VALID_DIRECT(is, prob_data, path_length_lower_bound, curr);
is >> curr;
}
return is;
}
std::ostream& operator<<(std::ostream& os, const Derived_Performance_Data& exec_data){
os << "Derived_Exec_Data {\n";
PRINT_IF_DEF(os, exec_data, time_in_sec);
PRINT_IF_DEF(os, exec_data, number_of_bnb_runs);
PRINT_IF_DEF(os, exec_data, number_of_reopt_runs);
PRINT_IF_DEF(os, exec_data, number_of_nodes_explored);
PRINT_IF_DEF(os, exec_data, max_depth);
PRINT_IF_DEF(os, exec_data, dual_bound);
PRINT_IF_DEF(os, exec_data, primal_bound);
PRINT_IF_DEF(os, exec_data, gap);
PRINT_IF_DEF(os, exec_data, number_of_primal_sols);
os << "}";
return os;
}
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;
exec_data.number_of_reopt_runs.first = false;
exec_data.number_of_nodes_explored.first = false;
exec_data.max_depth.first = false;
exec_data.dual_bound.first = false;
exec_data.primal_bound.first = false;
exec_data.gap.first = false;
exec_data.number_of_primal_sols.first = false;
std::string curr;
is >> curr;
assert(curr == "Derived_Exec_Data");
is >> curr;
assert(curr == "{");
is >> curr;
while(curr != "}"){
IF_READ_VAR_SET_VAR_VALID_DIRECT(is, exec_data, time_in_sec, curr);
IF_READ_VAR_SET_VAR_VALID_DIRECT(is, exec_data, number_of_bnb_runs, curr);
IF_READ_VAR_SET_VAR_VALID_DIRECT(is, exec_data, number_of_reopt_runs, curr);
IF_READ_VAR_SET_VAR_VALID_DIRECT(is, exec_data, number_of_nodes_explored, curr);
IF_READ_VAR_SET_VAR_VALID_DIRECT(is, exec_data, max_depth, curr);
IF_READ_VAR_SET_VAR_VALID_DIRECT(is, exec_data, dual_bound, curr);
IF_READ_VAR_SET_VAR_VALID_DIRECT(is, exec_data, primal_bound, curr);
IF_READ_VAR_SET_VAR_VALID_DIRECT(is, exec_data, gap, curr);
IF_READ_VAR_SET_VAR_VALID_DIRECT(is, exec_data, number_of_primal_sols, curr);
is >> curr;
}
is >> curr;
return is;
}
std::istream& operator>>(std::istream& is, std::vector<Derived_Performance_Data>& exec_data){
std::string curr;
is >> curr;
assert(curr == "[");
auto pos = is.tellg();
is >> curr;
while(curr != "]"){
is.seekg(pos);
exec_data.push_back(Derived_Performance_Data{});
Derived_Performance_Data& back = exec_data.back();
is >> back;
pos = is.tellg();
is >> curr;
}
return is;
}
std::istream& operator>>(std::istream& is, std::map<std::string, std::vector<Derived_Performance_Data>>& formulation_exec_data){
std::string curr;
is >> curr;
while(curr == "formulation: "){
std::string formulation_name;
std::getline(is, formulation_name);
std::vector<Derived_Performance_Data> exec_vector;
is >> exec_vector;
formulation_exec_data.insert({formulation_name, std::move(exec_vector)});
is >> curr;
}
return is;
}
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"
<< "derived_performance: \n";
for(auto& [prob_name, exec_vector] : data.derived_performance){
os << "formulation: " << prob_name << "\n"
<< "[\n";
for(const Derived_Performance_Data& perf_data : exec_vector){
os << perf_data << " ,\n";
}
os << "] \n"
<< "}";
}
return os;
}
std::istream& operator>>(std::istream& is, Data& data){
std::string curr;
is >> curr;
assert(curr == "Performance_Tester_Data");
is >> curr;
assert(curr == "{");
is >> curr;
while(curr != "}"){
IF_READ_VAR_SET_VAR_DIRECT(is, data, marked_for_inspection, curr);
IF_READ_VAR_SET_VAR_GETLINE(is, data, path, curr);
IF_READ_VAR_SET_VAR_GETLINE(is, data, name, curr);
IF_READ_VAR_SET_VAR_DIRECT(is, data, gen_data, curr);
IF_READ_VAR_SET_VAR_DIRECT(is, data, mp, curr);
IF_READ_VAR_SET_VAR_DIRECT(is, data, derived_problem, curr);
IF_READ_VAR_SET_VAR_DIRECT(is, data, derived_performance, curr);
is >> curr;
}
return is;
}
#ifndef GENERIC_PERFORMANCE_TESTER_H
#define GENERIC_PERFORMANCE_TESTER_H
#include <functional>
#include <vector>
template <typename Data>
class Generic_Performance_Tester{
std::function<bool(Data&)> _exec;
public:
Data _data;
Generic_Performance_Tester(Data& data, std::function<bool(Data&)> exec);
bool populate_data();
};
#include "Generic_Performance_Tester.ipp"
#endif
template <typename Data>
Generic_Performance_Tester<Data>::Generic_Performance_Tester(Data& data, std::function<bool(Data&)> exec)
: _data(std::move(data)), _exec(exec) {}
template <typename Data>
bool Generic_Performance_Tester<Data>::populate_data(){
return this->_exec(this->_data);
}
......@@ -7,7 +7,7 @@ int main(){
auto var2 = new Variable("x2", Continuous, {true, 0});
auto var3 = new Variable("x3", Continuous, {false,0}, {true, 6});
std::vector<boost::bimap<Variable*, size_t>::value_type> v = {{var1, 0}, {var2, 1}, {var3, 2}};
Linear_Program lp (true, {{var1, 1}, {var2, -2}}, Polyeder({Constraint("1", Equality, {{var1, 1}, {var3, -1}}, 0), Constraint("2", Inequality, {{var1, 1}, {var2, 1}, {var3, 1}}, 1), Constraint("3", Inequality, {{var1, -1}, {var3, -1}}, 5)}, {v.begin(), v.end()}));
Linear_Program lp ("test", true, {{var1, 1}, {var2, -2}}, Polyeder({Constraint("1", Equality, {{var1, 1}, {var3, -1}}, 0), Constraint("2", Inequality, {{var1, 1}, {var2, 1}, {var3, 1}}, 1), Constraint("3", Inequality, {{var1, -1}, {var3, -1}}, 5)}, {v.begin(), v.end()}));
std::cout << lp << std::endl;
SCIP* model = lp.computational_model().first;
......
// include struct, classes, macros and io functions necessary
#include "Specialization/LP_Problems/Maintenance_Problem/maintenance_problem_test_data_functions.ipp"
#include <exception>
int main(int argc, char** argv){
// reading path from arguments
assert(argc == 3);
std::string folder_path(argv[1]);
std::stringstream param_path;
param_path << folder_path << "test_parameters.test_param";
std::cout << "reading " << param_path.str() << std::endl;
// reading number of instances
int number_of_instances = std::atoi(argv[2]);
// read generation parameters from top level folder
Generation_Parameters test_parameters;
std::fstream test_parameters_files;
test_parameters_files.open(param_path.str(), std::ios::in);
test_parameters_files >> test_parameters;
std::cout << "Test parameters are given as" << std::endl;
std::cout << test_parameters << std::endl;
// loop preparations
size_t number_of_edges = (size_t) (test_parameters.number_of_nodes*((double) test_parameters.avg_incid_per_node)/2);
// create generator
maintenance_problem_generator mpg (
random_graph_generator(
number_of_edges,
test_parameters.number_of_nodes,
random_attribute_generator({ {"Upper", {fix, Integral, 1, 100}} }),
random_attribute_generator({}),
{{"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
);
// populate folder with instances
for(int instance = 0; instance < number_of_instances; instance++){
std::stringstream current_file;
current_file << folder_path << instance << "/instance.test_data";
std::filesystem::path current_file_path(current_file.str());
// check if the folder has been populated with an instance before
if(std::filesystem::status(current_file_path.parent_path()).type() == std::filesystem::file_type::directory){
std::cout << current_file_path.parent_path() << " already exists, checking validity" << std::endl;
// try reading said instance
try{
std::fstream data_file;
data_file.open(current_file_path, std::ios::in);
Data curr_data = Data{};
data_file >> curr_data;
data_file.close();
std::cout << "data appears correct; skipping" << std::endl;
continue;
}catch(std::exception& e){
std::cout << "data failed check; overriding" << std::endl;
}
}else{
std::cout << "creating new dir" << std::endl;
assert(std::filesystem::create_directory(current_file_path.parent_path()));
}
Data new_data = {};
std::cout << "generation " << instance << ": " << "[metadata]" << std::flush;
new_data.marked_for_inspection = false;
new_data.path = current_file_path.parent_path().string();
new_data.name = current_file_path.filename().string();
new_data.gen_data = test_parameters;
std::cout << " [problem]" << std::flush;
new_data.mp = std::move(mpg.next(test_parameters.number_of_nodes/test_parameters.nodes_per_step, test_parameters.fuzzing));
std::cout << " [empty derived data]" << std::endl;
new_data.derived_problem = Derived_Problem_Data{
{false, 0},
{false, 0},
{false, 0},
{false, 0},
{false, 0},
{false, 0},
{false, 0}
};
new_data.derived_performance = {};
std::cout << std::endl << "writing instance data" << std::endl;
std::fstream data_file;
data_file.open(current_file_path, std::ios::out);
data_file << new_data << std::endl;
data_file.close();
}
}
// include struct, classes, macros and io functions necessary
#include "Specialization/LP_Problems/Maintenance_Problem/maintenance_problem_test_data_functions.ipp"
int main(int argc, char** argv){
// execution function
bool check_all_problem_data = false;
bool add_new_execution = false;
std::function<bool(Data&)> exec = [check_all_problem_data, add_new_execution](Data& data){
bool all_succeeded = true;
// determining derived problem data
Derived_Problem_Data& derived_prob_data = data.derived_problem;
// number_of_edges
SET_VARIABLE(derived_prob_data, number_of_edges, data.mp.network().edges().size());
// number_of_nodes
SET_VARIABLE(derived_prob_data, number_of_nodes, data.mp.network().nodes().size());
// avg incid per node
double avg_incid_per_node_val = 2*(double)data.mp.network().edges().size()/data.mp.network().nodes().size();
SET_VARIABLE(derived_prob_data, avg_incid_per_node, avg_incid_per_node_val);
// number_of_critical_edges
size_t number_of_critical_edges_val = 0;
for(const Edge* e : data.mp.network().edges()){
if(e->attribute_throwing("Selected").value()) number_of_critical_edges_val++;
}
SET_VARIABLE(derived_prob_data, number_of_critical_edges, number_of_critical_edges_val);
// share_of_critical
double share_of_critical_val = (double)number_of_critical_edges_val/data.mp.network().edges().size();
SET_VARIABLE(derived_prob_data, share_of_critical, share_of_critical_val);
// number_of_epochs
SET_VARIABLE(derived_prob_data, number_of_epochs, data.mp.number_of_epochs());
// path_length_lower_bound
auto path = data.mp.network().directed_admissible_st_path(data.mp.source(), data.mp.target(), [](const Node* from, const Edge* via){return (via->to(from) == via->to()); });
size_t path_length_lower_bound_val;
if(path.first){
path_length_lower_bound_val = path.second.number_of_edges();
}else{
std::cout << "no connecting path could be found" << std::endl;
path_length_lower_bound_val = SIZE_MAX;
}
SET_VARIABLE(derived_prob_data, path_length_lower_bound, path_length_lower_bound_val);
std::vector<SCIP*> computational_models = data.mp.all_computational_models();
for(SCIP* current_scip : computational_models){
auto scip_iterator = data.derived_performance.find(SCIPgetProbName(current_scip));
if(scip_iterator == data.derived_performance.end()) {
auto [new_scip_iterator, success] = data.derived_performance.insert({SCIPgetProbName(current_scip), std::vector<Derived_Performance_Data>()});
assert(success);
scip_iterator = new_scip_iterator;
}
auto& [name, exec_vector] = *scip_iterator;
if(!add_new_execution && exec_vector.size() != 0
&& exec_vector.back().time_in_sec.first
&& exec_vector.back().number_of_bnb_runs.first
&& exec_vector.back().number_of_reopt_runs.first
&& exec_vector.back().number_of_nodes_explored.first
&& exec_vector.back().max_depth.first
&& exec_vector.back().dual_bound.first
&& exec_vector.back().primal_bound.first
&& exec_vector.back().gap.first
&& exec_vector.back().number_of_primal_sols.first)
{
std::cout << "skipping execution of " << SCIPgetProbName(current_scip) << " due to it having been previously executed" << std::endl;