Commit 6c4c3a5b authored by jonasseidel's avatar jonasseidel
Browse files

benders not working for unknown reasons

parent cffefd9c
......@@ -147,6 +147,7 @@ public:
// _special_members_and_operators:
void operator=(const Graph& graph);
std::pair< Graph, std::map<Node*, Node*> > copy_ret_lookup() const;
void operator=(Graph&& graph);
// _debug_helpers (Graph.ipp)
......
......@@ -11,20 +11,25 @@ Graph::Graph(Graph&& graph)
graph._template_edge_attributes = {};
}
void Graph::operator=(const Graph& graph){
this->_template_node_attributes = graph._template_node_attributes;
this->_template_edge_attributes = graph._template_edge_attributes;
std::pair< Graph, std::map<Node*, Node*> > Graph::copy_ret_lookup() const{
Graph copy (this->_template_edge_attributes, this->_template_node_attributes);
std::map<Node*, Node*> node_lookup;
for(Node* node : graph._nodes){
Node* new_node = this->add_node(node);
for(Node* node : this->_nodes){
Node* new_node = copy.add_node(node);
node_lookup.insert({node, new_node});
}
for(Edge* edge : graph._edges){
this->add_edge(edge, node_lookup);
for(Edge* edge : this->_edges){
copy.add_edge(edge, node_lookup);
}
return {std::move(copy), node_lookup};
}
void Graph::operator=(const Graph& graph){
*this = std::move(graph.copy_ret_lookup().first);
}
void Graph::operator=(Graph&& graph){
......
......@@ -40,7 +40,7 @@ Polyeder& Linear_Program::polyeder(){
return this->_polyeder;
}
SCIP* Linear_Program::computational_model(){
std::pair<SCIP*, std::unordered_map<Variable*, SCIP_VAR*> > Linear_Program::computational_model(){
SCIP* scip;
SCIPcreate(&scip);
SCIPincludeDefaultPlugins(scip);
......@@ -52,23 +52,21 @@ SCIP* Linear_Program::computational_model(){
}else{
SCIPsetObjsense(scip, SCIP_OBJSENSE_MINIMIZE);
}
std::cout << "generating variables" << std::endl;
std::unordered_map<Variable*, SCIP_VAR*> variable_lookup;
for(auto pair : this->_polyeder.variables()){
auto search = this->_direction.find(pair.left);
SCIP_VAR* computational_var = pair.left->computational_var(scip, (search != this->_direction.end() ? search->second.value() : 0));
variable_lookup.insert({pair.left, computational_var});
SCIPaddVar(scip, computational_var);
}
std::cout << "generating constraints" << std::endl;
for(Constraint con : this->_polyeder.constraints()){
SCIP_CONS* computational_con = con.computational_con(scip, variable_lookup);
SCIPaddCons(scip, computational_con);
}
return scip;
return {scip, variable_lookup};
}
void Linear_Program::operator=(Linear_Program& lp){
......@@ -80,7 +78,9 @@ void Linear_Program::operator=(Linear_Program& lp){
void Linear_Program::operator=(Linear_Program&& lp){
this->_maximum = lp._maximum;
this->_direction = std::move(lp._direction);
lp._direction = std::unordered_map<Variable*, Coefficient>();
this->_polyeder = std::move(lp._polyeder);
lp._polyeder = Polyeder();
}
Linear_Program Linear_Program::relaxation_dual(){
......
......@@ -35,7 +35,7 @@ public:
Coefficient direction_coefficient(Variable* index);
Polyeder& polyeder();
SCIP* computational_model();
std::pair<SCIP*, std::unordered_map<Variable*, SCIP_VAR*> > computational_model();
void operator=(Linear_Program& lp);
void operator=(Linear_Program&& lp);
......
......@@ -10,7 +10,7 @@ Polyeder::Polyeder(std::vector<Constraint> constraints, boost::bimap<Variable*,
// TODO: check that variables used in constraints are registered in variables?
}
boost::bimap<Variable*, size_t> Polyeder::variables(){
boost::bimap<Variable*, size_t>& Polyeder::variables(){
return this->_variables;
}
......
......@@ -21,7 +21,7 @@ public:
Polyeder(std::vector<Constraint> constraints, boost::bimap<Variable*, size_t> variables);
boost::bimap<Variable*, size_t> variables();
boost::bimap<Variable*, size_t>& variables();
size_t vs_dim();
Variable& variable(size_t index);
size_t variable(Variable& var);
......
......@@ -55,9 +55,11 @@ double& Variable::value(){
}
SCIP_VAR* Variable::computational_var(SCIP* scip, double direction_coefficient){
char name[SCIP_MAXSTRLEN];
SCIP_VAR* var;
char* name = new char[this->description().size()+1];
SCIP_CALL_ABORT( SCIPcreateVarBasic(scip, &var, strcpy(name, this->description().c_str()), this->computational_lower_bound(scip), this->computational_upper_bound(scip), direction_coefficient,
SCIPsnprintf(name, SCIP_MAXSTRLEN, this->description().c_str());
SCIP_CALL_ABORT( SCIPcreateVarBasic(scip, &var, name, this->computational_lower_bound(scip), this->computational_upper_bound(scip), direction_coefficient,
(this->is_integral() ? SCIP_VARTYPE_INTEGER : SCIP_VARTYPE_CONTINUOUS)));
return var;
}
......
......@@ -125,5 +125,6 @@ std::pair<
);
}
}
return {node_lookup, edge_lookup};
}
CXX := g++
CXXFLAGS := -O0 -g -std=c++2a #-Wall -Wextra -Wpedantic
LIBSCIPOPTN := /media/hwlr/Data/scipoptsuite-7.0.2/lib/libscipopt.so
LIBSCIPOPT := /usr/local/lib/libscip.so.7.0.2.0
GRAPH_DEP := $(patsubst %.cpp,%.o,$(shell find -type f -wholename "./Graphtheory/*"))
LP_DEP := $(patsubst %.cpp,%.o,$(shell find -type f -wholename "./Linear_Programming/*"))
LP_PROBLEMS_DEP := $(patsubst %.cpp,%.o,$(shell find -type f -wholename "./Specialization/LP_Problems/*"))
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"))
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
all: graph_test ass_test linear_program_test maintenance_problem_test benders_test scip_test
OUTS :=
......@@ -37,26 +40,31 @@ ass_test.o: assertion_test.cpp $(GRAPH_DEP) $(COMMON_DEP)
# Linear Program Test
linear_program_test: linear_program_test.o $(LP_OUT) /usr/local/lib/libscip.so.7.0.2.0
linear_program_test: linear_program_test.o $(LP_OUT) $(LIBSCIPOPT)
$(CXX) $(CXXFLAGS) $^ -o $@
linear_program_test.o: linear_programming_test.cpp ./Linear_Programming/Linear_Program.o
$(CXX) $(CXXFLAGS) -c $< -o $@
maintenance_problem_test: maintenance_problem_test.o $(LP_PROBLEMS_OUT) $(LP_OUT) $(GRAPH_OUT) Linear_Programming/lp_generator.o /usr/local/lib/libscip.so.7.0.2.0
maintenance_problem_test: maintenance_problem_test.o $(LP_PROBLEMS_OUT) $(LP_OUT) $(GRAPH_OUT) Linear_Programming/lp_generator.o $(LIBSCIPOPT)
$(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)
$(CXX) $(CXXFLAGS) -c $< -o $@
benders_test: benders_test.o /usr/local/lib/libscip.so.7.0.2.0
benders_test: benders_test.o $(LIBSCIPOPT)
$(CXX) $(CXXFLAGS) $^ -o $@
benders_test.o: benders_test.cpp
$(CXX) $(CXXFLAGS) -c $< -o $@
scip_test: scip_test.o $(LIBSCIPOPT)
$(CXX) $(CXXFLAGS) $^ -o $@
scip_test.o: scip_test.cpp
$(CXX) $(CXXFLAGS) -c $< -o $@
# Linear Programming Folder Object Files
.SECONDEXPANSION:LP
Graph := ./Graphtheory/
......
#include "Maintenance_Problem.h"
Maintenance_Problem::Maintenance_Problem() : Linear_Program(true), _number_of_epochs(0), _g({{"Flow", Attribute(max, 0)},{"Upper", Attribute(fix, 1)}, {"Selected", Attribute(fix, 0)}}) {
#include "computational_types/generate_nmp_bendersdecomp.h"
Maintenance_Problem::Maintenance_Problem() : Linear_Program(true), _number_of_epochs(0), _g({{"Flow", Attribute(max, 0)},{"Upper", Attribute(fix, 1)}, {"Selected", Attribute(fix, 0)}}), _source(nullptr), _target(nullptr) {
}
Maintenance_Problem::Maintenance_Problem(Maintenance_Problem& mp) : Linear_Program(mp), _number_of_epochs(mp._number_of_epochs), _g(mp._g) {
mp._g = Graph();
Maintenance_Problem::Maintenance_Problem(Maintenance_Problem& mp) : Linear_Program(true) {
*this = mp;
}
Maintenance_Problem::Maintenance_Problem(Maintenance_Problem&& mp) : Linear_Program(std::move(mp)), _number_of_epochs(std::move(mp._number_of_epochs)), _g(std::move(mp._g)) {
mp._g = Graph();
Maintenance_Problem::Maintenance_Problem(Maintenance_Problem&& mp) : Linear_Program(true){
*this = std::move(mp);
}
Maintenance_Problem::Maintenance_Problem(
......@@ -17,8 +19,22 @@ Maintenance_Problem::Maintenance_Problem(
Node* target,
size_t epochs
)
: Linear_Program(true), _number_of_epochs(epochs), _g(g)
: Linear_Program(true), _number_of_epochs(epochs)
{
// copy graph and transform source and target variables to ptrs in the copy
assert(g.nodes().find(source) != g.nodes().end());
assert(g.nodes().find(target) != g.nodes().end());
auto copy_and_lookup = g.copy_ret_lookup();
this->_g = std::move(copy_and_lookup.first);
auto source_lookup = copy_and_lookup.second.find(source);
if(source_lookup == copy_and_lookup.second.end()) throw std::invalid_argument("source not contained in graph");
this->_source = source_lookup->second;
auto target_lookup = copy_and_lookup.second.find(target);
if(target_lookup == copy_and_lookup.second.end()) throw std::invalid_argument("target not contained in graph");
this->_target = target_lookup->second;
// create lp
std::set<Edge*> critical = g.gather_edges({"Selected"});
for(std::string attr : std::vector({"Selected", "Upper", "Flow"})){
......@@ -134,16 +150,24 @@ Graph& Maintenance_Problem::network(){
return this->_g;
}
Node* Maintenance_Problem::source(){
return this->_source;
}
Node* Maintenance_Problem::target(){
return this->_target;
}
size_t Maintenance_Problem::number_of_epochs(){
return this->_number_of_epochs;
}
std::vector<SCIP*> Maintenance_Problem::all_computational_models(){
// basic model:
SCIP* scip_basic = Linear_Program::computational_model();
SCIP* scip_basic = Linear_Program::computational_model().first;
SCIPsolve(scip_basic);
/*
// semiassignment_branching
SCIP* scip_semiassign = Linear_Program::computational_model();
SCIP* scip_semiassign = Linear_Program::computational_model().first;
SCIP_CONS** conss = SCIPgetOrigConss(scip_semiassign);
std::vector<SCIP_CONS*> process_cons;
for(int cons_index = 0; cons_index < SCIPgetNOrigConss(scip_semiassign); cons_index++){
......@@ -156,23 +180,25 @@ std::vector<SCIP*> Maintenance_Problem::all_computational_models(){
SCIP_CONS** process_cons_array = new SCIP_CONS*[process_cons.size()];
std::copy(process_cons.begin(), process_cons.end(), process_cons_array);
SCIPincludeBranchruleSemiassign(scip_semiassign, process_cons.size(), process_cons_array);
*/
// benders
SCIP* scip_benders = generate_nmp_bendersdecomp(*this, scip_basic, SCIPgetBestSol(scip_basic));
// basic benders feasibility cuts:
SCIP* scip_benders_feas = this->nmp_generate_benders();
// benders feas with basic cut inequalities
SCIP* scip_benders_feas_basic_cut = this->nmp_generate_benders();
SCIP_BENDERS* benders_basic_cut = SCIPfindBenders(scip_benders_feas_basic_cut, "default");
SCIP_CALL_ABORT( SCIPincludeBenderscutBasicSepa(scip_benders_feas_basic_cut, benders_basic_cut));
return {scip_basic, scip_semiassign, scip_benders_feas, scip_benders_feas_basic_cut};
// return all models
return {scip_basic, /*scip_semiassign,*/ scip_benders};
}
void Maintenance_Problem::operator=(Maintenance_Problem& mp){
this->Linear_Program::operator=(mp);
this->_number_of_epochs = mp._number_of_epochs;
this->_g = mp._g;
mp._g = Graph();
auto copy_and_lookup = mp._g.copy_ret_lookup();
this->_g = copy_and_lookup.first;
auto source_lookup = copy_and_lookup.second.find(mp._source);
if(source_lookup == copy_and_lookup.second.end()) throw std::invalid_argument("source not contained in graph");
this->_source = source_lookup->second;
auto target_lookup = copy_and_lookup.second.find(mp._target);
if(target_lookup == copy_and_lookup.second.end()) throw std::invalid_argument("target not contained in graph");
this->_target = target_lookup->second;
}
void Maintenance_Problem::operator=(Maintenance_Problem&& mp){
......@@ -180,6 +206,8 @@ void Maintenance_Problem::operator=(Maintenance_Problem&& mp){
this->_number_of_epochs = std::move(mp._number_of_epochs);
this->_g = std::move(mp._g);
mp._g = Graph();
this->_source = mp._source;
this->_target = mp._target;
}
std::ostream& operator<<(std::ostream& os, Maintenance_Problem& mp){
......
......@@ -12,27 +12,24 @@
// computational
#include "computational_types/semiassignment_hdlr.h"
#include "computational_types/semiassignment_branch.h"
#include "computational_types/bulksepa/nmp_bulksepa.h"
#include <scip/scip.h>
#include <scip/scipshell.h>
#include <scip/scipdefplugins.h>
#include <scip/cons_benders.h>
#include <scip/cons_benderslp.h>
#include <scip/benders_default.h>
class Maintenance_Problem : public Linear_Program {
size_t _number_of_epochs;
Graph _g;
SCIP* nmp_generate_benders();
Node* _source;
Node* _target;
public:
Maintenance_Problem();
Maintenance_Problem(Maintenance_Problem& mp);
Maintenance_Problem(Maintenance_Problem&& mp);
Maintenance_Problem(Graph& g, Node* source, Node* target, size_t intervals);
Graph& network();
Graph& network(); // this better be const so that source and target may be set appropriately
Node* source();
Node* target();
size_t number_of_epochs();
std::vector<SCIP*> all_computational_models();
......
#include "generate_nmp_bendersdecomp.h"
#include "nmp_benders_conshdlr.h"
#include "../Maintenance_Problem.h"
#include <scip/prob.h>
#include <scip/struct_var.h>
struct SCIP_VarData_Master{
SCIP* subproblem_lpsol;
SCIP_VAR* edgepot_of_subproblem_lpsol;
SCIP* subproblem_heursol;
SCIP_VAR* edgepot_of_subproblem_heursol;
};
struct SCIP_Probdata_Subproblem{
int epoch;
int nepochs;
int nedges;
int number_of_added_cons;
};
struct SCIP_VarData_Subproblem{
SCIP_Real capacity;
SCIP* master;
SCIP_VAR* decision_of_master;
};
SCIP_RETCODE del_vardata_master(SCIP* scip, SCIP_VAR* var, SCIP_VARDATA** vardata_unpec){
std::cout << "deleting" << std::endl;
SCIP_VarData_Master** vardata = (SCIP_VarData_Master**) vardata_unpec;
SCIPreleaseVar((*vardata)->subproblem_lpsol, &(*vardata)->edgepot_of_subproblem_lpsol);
SCIPreleaseVar((*vardata)->subproblem_heursol, &(*vardata)->edgepot_of_subproblem_heursol);
SCIPfreeBlockMemory(scip, vardata);
return SCIP_OKAY;
}
SCIP_RETCODE del_vardata_subproblem(SCIP* scip, SCIP_VAR* var, SCIP_VARDATA** vardata_unpec){
std::cout << "deleting" << std::endl;
SCIP_VarData_Subproblem** vardata = (SCIP_VarData_Subproblem**) vardata_unpec;
SCIPreleaseVar((*vardata)->master, &(*vardata)->decision_of_master);
SCIPfreeBlockMemory(scip, vardata);
return SCIP_OKAY;
}
SCIP_RETCODE del_probdata_subproblem(SCIP* scip, SCIP_PROBDATA** probdata_unpec){
std::cout << "deleting" << std::endl;
SCIP_Probdata_Subproblem** probdata = (SCIP_Probdata_Subproblem**) probdata_unpec;
SCIPfreeBlockMemory(scip, probdata);
return SCIP_OKAY;
}
std::pair<
Linear_Program,
std::pair<
std::map<
std::pair<Node*,std::string>,
std::pair<Variable*, size_t>
>,
std::map<
std::pair<Edge*,std::string>,
std::pair<Variable*, size_t>
>
>
> generate_dual_flow_problem(Graph& graph, Node* source, Node* target){
Linear_Program lp(false);
assert(graph.nodes().find(source) != graph.nodes().end());
assert(graph.nodes().find(target) != graph.nodes().end());
for(std::string attr : std::vector({"Upper", "Flow"})){
if(!graph.edge_template(attr).first) {
std::cout << graph << std::endl;
throw std::invalid_argument("generate_dual_flow_problem needs Graph with predetermined attributes present");
}
}
std::pair<
std::map<
std::pair<Node*,std::string>,
std::pair<Variable*, size_t>
>,
std::map<
std::pair<Edge*,std::string>,
std::pair<Variable*, size_t>
>
> lookup;
/*
constraints
*/
lookup = lp_generator::grow_from_graph(
lp,
graph,
[](Edge* edge) -> std::vector<constraint_data> {
std::stringstream capacity_name;
capacity_name << "edge_" << edge->description();
std::vector<constraint_data> constraints;
constraints.push_back({capacity_name.str(), Inequality, {{{{edge->from(), "Nodepotential"}, -1}, {{edge->to(), "Nodepotential"}, 1}}, {{{edge, "Edgepotential"}, -1}}}, 0});
return constraints;
},
[source, target](Node* node) -> std::vector<constraint_data> {
std::vector<constraint_data> constraints;
if(node == source){
constraints.push_back({"set_source_potential", Equality, {{{{source, "Nodepotential"}, 1}}, {} }, -1});
}else if(node == target){
constraints.push_back({"set_target_potential", Equality, {{{{target, "Nodepotential"}, 1}}, {} }, 0});
}
return constraints;
},
{{"Edgepotential", {Continuous, {true, 0}, {false, 1}}}},
{{"Nodepotential", {Continuous, {false, 0}, {false, 0}}}},
""
);
return {lp, lookup};
}
std::pair<
Linear_Program,
std::vector<
std::pair<
std::map<
std::pair<Node*,std::string>,
std::pair<Variable*, size_t>
>,
std::map<
std::pair<Edge*,std::string>,
std::pair<Variable*, size_t>
>
>
>
> generate_master(Maintenance_Problem& nmp, Graph& graph, Node* source, Node* target){
Linear_Program lp(true);
std::set<Edge*> critical = graph.gather_edges({"Selected"});
for(std::string attr : std::vector({"Selected", "Upper", "Flow"})){
if(!graph.edge_template(attr).first) {
std::cout << graph << std::endl;
throw std::invalid_argument("Maintenance_Problem needs Graph with predetermined attributes present");
}
}
std::vector<
std::pair<
std::map<
std::pair<Node*,std::string>,
std::pair<Variable*, size_t>
>,
std::map<
std::pair<Edge*,std::string>,
std::pair<Variable*, size_t>
>
>
> lookup;
// generate variables and set decision for unmaintained edges
for(size_t epoch = 0; epoch < nmp.number_of_epochs(); ++epoch){
std::stringstream name_appendix;
name_appendix << "epoch_" << epoch;
lookup.push_back(lp_generator::grow_from_graph(
lp,
graph,
[&critical, epoch](Edge* edge) -> std::vector<constraint_data> {
std::stringstream non_critical_fix;
non_critical_fix << "edge_" << edge->description() << "_non_critical_epoch_" << epoch;
if(critical.find(edge) == critical.end()){
return {{non_critical_fix.str(), Equality, {{}, {{{edge, "Selected"}, 1}}}, 0}};
}
return {};
},
[](Node* node) -> std::vector<constraint_data> {
return {};
},
{{"Selected", {Integral, {true, 0}, {true, 1}}}},
{},
name_appendix.str()
));
}
/*
critical edges processed
*/
for(Edge* e : critical){
std::unordered_map<Variable*, Coefficient> lhs;
for(auto lookup_during_epoch : lookup){
lhs.insert({lookup_during_epoch.second.find({e, "Selected"})->second.first, {1}});
}
std::stringstream name;
name << "critical_edge_" << e->description() << "_processed";
lp.polyeder().add_constraint(
{ // constraint
name.str(),
Equality,
lhs,
1,
}