Commit 34a58031 authored by jonasseidel's avatar jonasseidel
Browse files

Graphtheory overhaul in anticipation of new graph generation system:

- Adding SubGraph class for easy manipulation of restricted graphs
parent 81e3a7cc
...@@ -3,33 +3,37 @@ ...@@ -3,33 +3,37 @@
#include <cstddef> #include <cstddef>
#include <random> #include <random>
#include <set> #include <unordered_set>
enum generation_type{
random_unused,
random_all_static,
random_all_dynamic
};
template <typename T> template <typename T>
class random_set_element_generator{ class random_set_element_generator{
std::default_random_engine _engine; static std::default_random_engine _engine;
std::set<T>* _set; std::unordered_set<T>* _dynamic_set;
std::unordered_set<T> _static_set;
std::unordered_set<T> _current_run_set;
generation_type _gen_type;
public: public:
random_set_element_generator(std::set<T>* s); random_set_element_generator(std::unordered_set<T>* s, generation_type gen_type);
random_set_element_generator(std::unordered_set<T> s, generation_type gen_type);
void reset();
bool has_next();
T next(); T next();
void operator>>(T& var); void operator>>(T& var);
}; };
template <typename T> template <typename T>
class random_set_element_generator_capture{ std::default_random_engine random_set_element_generator<T>::_engine((std::random_device())());
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" #include "random_set_element_generator.ipp"
......
template <typename T> template <typename T>
random_set_element_generator<T>::random_set_element_generator(std::set<T>* s) : _engine((std::random_device())()), _set(s){} random_set_element_generator<T>::random_set_element_generator(std::unordered_set<T>* s, generation_type gen_type) : _gen_type(gen_type){
switch(this->_gen_type){
case random_unused:
this->_current_run_set = this->_static_set = *s;
break;
case random_all_static:
this->_static_set = *s;
break;
case random_all_dynamic:
this->_dynamic_set = s;
break;
default:
throw std::invalid_argument("unknown generation_type in contructor of random_set_element_generator");
}
}
template <typename T>
random_set_element_generator<T>::random_set_element_generator(std::unordered_set<T> s, generation_type gen_type) : _gen_type(gen_type){
switch(this->_gen_type){
case random_unused:
this->_current_run_set = this->_static_set = std::move(s);
break;
case random_all_static:
this->_static_set = std::move(s);
break;
case random_all_dynamic:
throw std::invalid_argument("reference needed to generate dynamically");
default:
throw std::invalid_argument("unknown generation_type in contructor of random_set_element_generator");
}
}
template <typename T> template <typename T>
T random_set_element_generator<T>::next(){ T random_set_element_generator<T>::next(){
std::uniform_int_distribution<int> _dist(0, _set->size() - 1); typename std::unordered_set<T>::iterator set_iterator;
size_t current_set_size;
switch(this->_gen_type){
case random_unused:
set_iterator = this->_current_run_set.begin();
current_set_size = this->_current_run_set.size();
break;
case random_all_static:
set_iterator = this->_static_set.begin();
current_set_size = this->_static_set.size();
break;
case random_all_dynamic:
set_iterator = this->_dynamic_set->begin();
current_set_size = this->_dynamic_set->size();
break;
default:
throw std::invalid_argument("unknown generation_type in contructor of random_set_element_generator");
}
if(current_set_size == 0) throw std::range_error("can't generate from emtpy set");
std::uniform_int_distribution<int> _dist(0, current_set_size - 1);
typename std::set<T>::iterator iter = this->_set->begin(); size_t element_index = _dist(random_set_element_generator<T>::_engine);
if(iter == this->_set->end()) throw std::range_error("can't generate from emtpy set"); std::advance(set_iterator, element_index);
T return_before_iter_invalid = *set_iterator;
size_t limit = _dist(_engine); if(this->_gen_type == random_unused){
for(size_t i = 1; i <= limit; i++){ this->_current_run_set.erase(set_iterator);
iter++;
} }
return *iter; return return_before_iter_invalid;
} }
template <typename T> template <typename T>
...@@ -21,31 +71,26 @@ void random_set_element_generator<T>::operator>>(T& var){ ...@@ -21,31 +71,26 @@ void random_set_element_generator<T>::operator>>(T& var){
var = this->next(); var = this->next();
} }
template <typename T> 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){} void random_set_element_generator<T>::reset(){
this->_current_run_set = this->_set;
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> template <typename T>
void random_set_element_generator_capture<T>::operator>>(T& var){ bool random_set_element_generator<T>::has_next(){
var = this->next(); size_t current_set_size;
switch(this->_gen_type){
case random_unused:
current_set_size = this->_current_run_set.size();
break;
case random_all_static:
current_set_size = this->_static_set.size();
break;
case random_all_dynamic:
current_set_size = this->_dynamic_set->size();
break;
default:
throw std::invalid_argument("unknown generation_type in contructor of random_set_element_generator");
}
return (current_set_size > 0);
} }
...@@ -52,6 +52,17 @@ void Attribute::operator=(Attribute&& attr){ ...@@ -52,6 +52,17 @@ void Attribute::operator=(Attribute&& attr){
this->_value = std::move(attr._value); this->_value = std::move(attr._value);
} }
bool Attribute::operator!=(const Attribute& other) const {
if(this->_dir != other._dir) return true;
if(this->_integrality != other._integrality) return true;
if(this->_value != other._value) return true;
return false;
}
bool Attribute::operator==(const Attribute& other) const {
return !(*this != other);
}
const opt_dir& Attribute::optimization_direction() const { const opt_dir& Attribute::optimization_direction() const {
return this->_dir; return this->_dir;
} }
......
...@@ -11,7 +11,7 @@ enum opt_dir : int {max = 1, fix = 0, min = -1}; ...@@ -11,7 +11,7 @@ enum opt_dir : int {max = 1, fix = 0, min = -1};
class Attribute{ class Attribute{
opt_dir _dir; opt_dir _dir;
bool _dependent; bool _dependent; // misses proper support (never actually get set in constructor)
integrality _integrality; integrality _integrality;
double _value; double _value;
public: public:
...@@ -24,6 +24,9 @@ public: ...@@ -24,6 +24,9 @@ public:
void operator=(const Attribute& attr); void operator=(const Attribute& attr);
void operator=(Attribute&& attr); void operator=(Attribute&& attr);
bool operator!=(const Attribute& other) const ;
bool operator==(const Attribute& other) const ;
const opt_dir& optimization_direction() const; const opt_dir& optimization_direction() const;
opt_dir& optimization_direction(); opt_dir& optimization_direction();
const bool& is_dependent() const; const bool& is_dependent() const;
......
...@@ -2,17 +2,17 @@ ...@@ -2,17 +2,17 @@
#include "../Common/io_format.h" #include "../Common/io_format.h"
Edge::Edge(const Edge& remote_edge, const std::map<const Node*, Node*>& node_lookup) : _description(remote_edge._description), _from(node_lookup.find(remote_edge._from)->second), _to(node_lookup.find(remote_edge._to)->second), _attributes(remote_edge._attributes) { Edge::Edge(const Edge& remote_edge, const std::unordered_map<const Node*, Node*>& node_lookup) : _description(remote_edge._description), _from(node_lookup.find(remote_edge._from)->second), _to(node_lookup.find(remote_edge._to)->second), _attributes(remote_edge._attributes) {
this->_from->add_incident(this); this->_from->add_incident(this);
this->_to->add_incident(this); this->_to->add_incident(this);
} }
Edge::Edge(Node* from, Node* to, std::string description, std::map<std::string, Attribute> attributes) : _description(std::move(description)), _from(from), _to(to), _attributes(std::move(attributes)){ Edge::Edge(Node* from, Node* to, std::string description, std::unordered_map<std::string, Attribute> attributes) : _description(std::move(description)), _from(from), _to(to), _attributes(std::move(attributes)){
from->add_incident(this); from->add_incident(this);
to->add_incident(this); to->add_incident(this);
}; };
Edge::Edge(std::istream& is, const std::map<std::string, Node* >& name_lookup){ Edge::Edge(std::istream& is, const std::unordered_map<std::string, Node* >& name_lookup){
std::string curr; std::string curr;
is >> curr; is >> curr;
IO_THROW(curr, "Edge"); IO_THROW(curr, "Edge");
......
#ifndef EDGE_H #ifndef EDGE_H
#define EDGE_H #define EDGE_H
#include <set>
#include <map>
#include <cstddef> #include <cstddef>
#include <iostream> #include <unordered_map>
#include <stdexcept>
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <iostream>
#include <cassert> #include <cassert>
#include <stdexcept>
#include "Attribute.h" #include "Attribute.h"
#include "Node.h" #include "Node.h"
...@@ -20,14 +19,14 @@ class Edge{ ...@@ -20,14 +19,14 @@ class Edge{
Node* _from; Node* _from;
Node* _to; Node* _to;
std::map<std::string, Attribute> _attributes; std::unordered_map<std::string, Attribute> _attributes;
public: public:
Edge(const Edge& local_edge) : _description(local_edge._description), _from(local_edge._from), _to(local_edge._to), _attributes(local_edge._attributes) {} Edge(const Edge& local_edge) : _description(local_edge._description), _from(local_edge._from), _to(local_edge._to), _attributes(local_edge._attributes) {}
Edge(Edge&& local_edge) : _description(std::move(local_edge._description)), _from(std::move(local_edge._from)), _to(std::move(local_edge._to)), _attributes(std::move(local_edge._attributes)) {} Edge(Edge&& local_edge) : _description(std::move(local_edge._description)), _from(std::move(local_edge._from)), _to(std::move(local_edge._to)), _attributes(std::move(local_edge._attributes)) {}
Edge(const Edge& remote_edge, const std::map<const Node*, Node*>& node_lookup); Edge(const Edge& remote_edge, const std::unordered_map<const Node*, Node*>& node_lookup);
Edge(Node* from, Node* to, std::string description, std::map<std::string, Attribute> attributes = {}); Edge(Node* from, Node* to, std::string description, std::unordered_map<std::string, Attribute> attributes = {});
Edge(std::istream& is, const std::map<std::string, Node* >& name_lookup); Edge(std::istream& is, const std::unordered_map<std::string, Node* >& name_lookup);
const std::string& description() const { const std::string& description() const {
return this->_description; return this->_description;
...@@ -60,11 +59,11 @@ public: ...@@ -60,11 +59,11 @@ public:
return node == this->from() ? this->to() : this->from(); return node == this->from() ? this->to() : this->from();
} }
const std::map<std::string, Attribute>& attributes() const { const std::unordered_map<std::string, Attribute>& attributes() const {
return this->_attributes; return this->_attributes;
} }
std::map<std::string, Attribute>& attributes() { std::unordered_map<std::string, Attribute>& attributes() {
return this->_attributes; return this->_attributes;
} }
......
#include "random_attribute_generator.h" #include "random_attribute_generator.h"
random_attribute_generator::random_attribute_generator( random_attribute_generator::random_attribute_generator(
std::map< std::unordered_map<
std::string, std::string,
std::tuple<opt_dir, integrality, double, double> std::tuple<opt_dir, integrality, double, double>
> data > data
...@@ -19,8 +19,8 @@ random_attribute_generator::random_attribute_generator( ...@@ -19,8 +19,8 @@ random_attribute_generator::random_attribute_generator(
} }
} }
std::map<std::string, Attribute> random_attribute_generator::next(){ std::unordered_map<std::string, Attribute> random_attribute_generator::next(){
std::map<std::string, Attribute> instance; std::unordered_map<std::string, Attribute> instance;
for(std::pair<std::string, std::pair<opt_dir, integrality> > constr_pair : this->_constr_data){ for(std::pair<std::string, std::pair<opt_dir, integrality> > constr_pair : this->_constr_data){
if(constr_pair.second.second == Integral){ if(constr_pair.second.second == Integral){
instance.insert({constr_pair.first, {constr_pair.second.first, (double) (this->_integral_dist.find(constr_pair.first)->second)(this->_engine), constr_pair.second.second}} ); instance.insert({constr_pair.first, {constr_pair.second.first, (double) (this->_integral_dist.find(constr_pair.first)->second)(this->_engine), constr_pair.second.second}} );
...@@ -31,6 +31,6 @@ std::map<std::string, Attribute> random_attribute_generator::next(){ ...@@ -31,6 +31,6 @@ std::map<std::string, Attribute> random_attribute_generator::next(){
return instance; return instance;
} }
void random_attribute_generator::operator>>(std::map<std::string, Attribute>& var){ void random_attribute_generator::operator>>(std::unordered_map<std::string, Attribute>& var){
var = this->next(); var = this->next();
} }
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
#define RANDOM_ATTRIBUTE_GENERATOR_H #define RANDOM_ATTRIBUTE_GENERATOR_H
#include <cstddef> #include <cstddef>
#include <map>
#include <tuple> #include <tuple>
#include <string>
#include <random> #include <random>
#include <stdexcept> #include <unordered_map>
#include <cassert> #include <cassert>
#include <string> #include <stdexcept>
#include "../Attribute.h" #include "../Attribute.h"
...@@ -15,15 +15,15 @@ ...@@ -15,15 +15,15 @@
class random_attribute_generator{ class random_attribute_generator{
std::default_random_engine _engine; std::default_random_engine _engine;
std::map<std::string, std::pair<opt_dir, integrality>> _constr_data; std::unordered_map<std::string, std::pair<opt_dir, integrality>> _constr_data;
std::map<std::string, std::uniform_int_distribution<>> _integral_dist; std::unordered_map<std::string, std::uniform_int_distribution<>> _integral_dist;
std::map<std::string, std::uniform_real_distribution<>> _continuous_dist; std::unordered_map<std::string, std::uniform_real_distribution<>> _continuous_dist;
public: public:
random_attribute_generator(std::map<std::string, std::tuple<opt_dir, integrality, double, double> > data); random_attribute_generator(std::unordered_map<std::string, std::tuple<opt_dir, integrality, double, double> > data);
std::map<std::string, Attribute> next(); std::unordered_map<std::string, Attribute> next();
void operator>>(std::map<std::string, Attribute>& var); void operator>>(std::unordered_map<std::string, Attribute>& var);
}; };
#endif #endif
...@@ -4,8 +4,8 @@ random_graph_generator::random_graph_generator( ...@@ -4,8 +4,8 @@ random_graph_generator::random_graph_generator(
size_t number_of_edges, size_t number_of_nodes, size_t number_of_edges, size_t number_of_nodes,
random_attribute_generator edge_generator, random_attribute_generator edge_generator,
random_attribute_generator node_generator, random_attribute_generator node_generator,
std::map<std::string, Attribute> default_values_edge_attributes, std::unordered_map<std::string, Attribute> default_values_edge_attributes,
std::map<std::string, Attribute> default_values_node_attributes std::unordered_map<std::string, Attribute> default_values_node_attributes
) )
: _template_node_attributes(default_values_node_attributes), _template_edge_attributes(default_values_edge_attributes), _number_of_nodes(number_of_nodes), _number_of_edges(number_of_edges), _node_generator(node_generator), _edge_generator(edge_generator) {} : _template_node_attributes(default_values_node_attributes), _template_edge_attributes(default_values_edge_attributes), _number_of_nodes(number_of_nodes), _number_of_edges(number_of_edges), _node_generator(node_generator), _edge_generator(edge_generator) {}
...@@ -25,12 +25,12 @@ Graph random_graph_generator::next(){ ...@@ -25,12 +25,12 @@ Graph random_graph_generator::next(){
return g; return g;
} }
std::tuple<std::pair<Node*, Node*>, std::set<Edge*>, Graph> random_graph_generator::next_acyclic_2_tips(){ std::tuple<std::pair<Node*, Node*>, std::unordered_set<Edge*>, Graph> random_graph_generator::next_acyclic_2_tips(){
Graph g (this->_template_edge_attributes, this->_template_node_attributes); 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){ 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::cout << "generation failed; retrying!" << std::endl;
} }
std::set<Edge*> core_network = g.edges(); std::unordered_set<Edge*> core_network = g.export_edges();
auto [source, target] = g.tip_fringes(this->_edge_generator, this->_node_generator); auto [source, target] = g.tip_fringes(this->_edge_generator, this->_node_generator);
...@@ -40,18 +40,25 @@ std::tuple<std::pair<Node*, Node*>, std::set<Edge*>, Graph> random_graph_generat ...@@ -40,18 +40,25 @@ std::tuple<std::pair<Node*, Node*>, std::set<Edge*>, Graph> random_graph_generat
return {std::pair{source, target}, std::move(core_network), std::move(g)}; return {std::pair{source, target}, std::move(core_network), std::move(g)};
} }
std::tuple<std::pair<Node*, Node*>, std::set<Edge*>, Graph> random_graph_generator::next_acyclic_in_steps_2_tips(size_t steps, size_t fuzzing, bool only_tip_fringes, bool only_tip_extreme_layer, bool shelter_orphans, random_attribute_generator* connector_generator, random_attribute_generator* terminal_generator){ std::tuple<std::pair<Node*, Node*>, std::unordered_set<Edge*>, Graph> random_graph_generator::next_acyclic_in_steps_2_tips(size_t steps, size_t fuzzing, bool only_tip_fringes, bool only_tip_extreme_layer, bool shelter_orphans, random_attribute_generator* connector_generator, random_attribute_generator* terminal_generator){
Graph g (this->_template_edge_attributes, this->_template_node_attributes); Graph g (this->_template_edge_attributes, this->_template_node_attributes);
std::tuple<bool, std::vector<std::set<Node*>>, std::pair<std::vector<Node*>, std::vector<Edge*>>> tpl; auto graph_generation_data = random_graph_generator::grow_random_acyclic_in_steps(
while( !std::get<0>(tpl = std::move(random_graph_generator::grow_random_acyclic_in_steps(g, this->_number_of_nodes/steps, this->_number_of_edges/steps, steps, fuzzing, this->_edge_generator, this->_node_generator))) ){ g,
std::cout << "generation failed; retrying!" << std::endl; this->_number_of_nodes/steps,
} this->_number_of_edges/steps,
steps,
0, // fuzzing start
fuzzing,
this->_edge_generator,
this->_node_generator
);
std::set<Edge*> core_network = g.edges(); std::unordered_set<Edge*> core_network = g.export_edges();
if(connector_generator == nullptr) connector_generator = &this->_edge_generator; if(connector_generator == nullptr) connector_generator = &this->_edge_generator;
if(terminal_generator == nullptr) terminal_generator = &this->_node_generator; if(terminal_generator == nullptr) terminal_generator = &this->_node_generator;
Node* source; Node* source;
Node* target; Node* target;
if(only_tip_fringes){ if(only_tip_fringes){
...@@ -60,7 +67,7 @@ std::tuple<std::pair<Node*, Node*>, std::set<Edge*>, Graph> random_graph_generat ...@@ -60,7 +67,7 @@ std::tuple<std::pair<Node*, Node*>, std::set<Edge*>, Graph> random_graph_generat
if(only_tip_extreme_layer){ if(only_tip_extreme_layer){
// tips first and last layer // tips first and last layer
auto [source_, target_] = g.tip_fringes(std::get<1>(tpl).front(), std::get<1>(tpl).back(), *connector_generator, *terminal_generator, shelter_orphans); auto [source_, target_] = g.tip_fringes(std::get<0>(graph_generation_data).front(), std::get<0>(graph_generation_data).back(), *connector_generator, *terminal_generator, shelter_orphans);
source = source_; source = source_;
target = target_; target = target_;
}else{ }else{
...@@ -75,15 +82,15 @@ std::tuple<std::pair<Node*, Node*>, std::set<Edge*>, Graph> random_graph_generat ...@@ -75,15 +82,15 @@ std::tuple<std::pair<Node*, Node*>, std::set<Edge*>, Graph> random_graph_generat
assert(only_tip_extreme_layer); assert(only_tip_extreme_layer);
// only those nodes of the first and last generated layers (tipping just everything doesn't make sense) // only those nodes of the first and last generated layers (tipping just everything doesn't make sense)
Node* s = g.add_node(std::to_string(g.size().first), terminal_generator->next()); Node* s = g.add_node(std::to_string(g.size().nodes), terminal_generator->next());
for(Node* n : std::get<1>(tpl).front()){ for(Node* n : std::get<0>(graph_generation_data).front()){
if(!shelter_orphans && n->incident().size() == 0) continue; if(!shelter_orphans && n->incident().size() == 0) continue;
std::stringstream name; std::stringstream name;
name << s->description() << "_" << n->description(); name << s->description() << "_" << n->description();
g.add_edge(s, n, name.str(), connector_generator->next()); g.add_edge(s, n, name.str(), connector_generator->next());
} }
Node* t = g.add_node(std::to_string(g.size().first), terminal_generator->next()); Node* t = g.add_node(std::to_string(g.size().nodes), terminal_generator->next());
for(Node* n : std::get<1>(tpl).back()){ for(Node* n : std::get<0>(graph_generation_data).back()){
if(!shelter_orphans && n->incident().size() == 0) continue; if(!shelter_orphans && n->incident().size() == 0) continue;
std::stringstream name; std::stringstream name;
name << n->description() << "_" << t->description(); name << n->description() << "_" << t->description();
...@@ -146,25 +153,107 @@ random_attribute_generator& random_graph_generator::node_generator(){ ...@@ -146,25 +153,107 @@ random_attribute_generator& random_graph_generator::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::unordered_set<Edge*> random_graph_generator::connect_random(
std::vector<Node*> added_nodes; SubGraph& graph_superunion,
std::vector<Edge*> added_edges; SubGraph& subgraph_from,
SubGraph& subgraph_to,
random_attribute_generator& edge_attribute_generator,