dyng
DynamicGraphLayout
dynamic_graph.h
1 /*
2  Copyright 2020 František Bráblík
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 #pragma once
17 
18 #include "graph.h"
19 #include "node.h"
20 #include "edge.h"
21 #include "exceptions.h"
22 
23 #include <vector>
24 #include <unordered_map>
25 #include <unordered_set>
26 #include <functional> // std::function
27 #include <utility> // std::move
28 #include <algorithm> // std::max_element, std::max
29 
30 namespace dyng {
31 
33 
43 public:
45  dynamic_graph() = default;
46 
54  node_id add_node(unsigned time) {
55  node_id id = m_last_node_id++;
56  add_modification(time, [n = node(id)](graph_state& graph){
57  graph.push_node(std::move(n));
58  });
59  return id;
60  }
61 
71  edge_id add_edge(unsigned time, node_id one, node_id two) {
72  edge_id id = m_last_edge_id++;
73  add_modification(time, [e = edge(id, one, two)](graph_state& graph){
74  graph.push_edge(std::move(e));
75  });
76  return id;
77  }
78 
85  void remove_node(unsigned time, node_id id) {
86  add_modification(time, [id](graph_state& graph){
87  graph.remove_node(id);
88  });
89  }
90 
97  void remove_edge(unsigned time, edge_id id) {
98  add_modification(time, [id](graph_state& graph){
99  graph.remove_edge(id);
100  });
101  }
102 
113  void build() {
114  m_states.clear();
115  apply_modifications();
116  set_bool_values();
117  }
118 
131  void build(std::vector<graph_state> states) {
132  m_modifications.clear();
133  m_states = std::move(states);
134  set_bool_values();
135  recalculate_ids();
136  }
137 
139  void clear() {
140  m_states.clear();
141  m_modifications.clear();
142  }
143 
145 
157  std::vector<graph_state>& states() { return m_states; }
158 
160 
170  const std::vector<graph_state>& states() const { return m_states; }
171 
173 
178  unsigned node_count() const { return m_last_node_id; }
179 
181 
186  unsigned edge_count() const { return m_last_edge_id; }
187 
188 private:
189  unsigned m_last_node_id = 0;
190  unsigned m_last_edge_id = 0;
191 
192  std::vector<graph_state> m_states;
193  std::vector<std::vector<std::function<void(graph_state&)>>> m_modifications;
194 
195 
196  void add_modification(unsigned time, std::function<void(graph_state&)> operation) {
197  if (time >= m_modifications.size()) {
198  m_modifications.resize(time + 1);
199  }
200  m_modifications[time].push_back(operation);
201  }
202 
203  void apply_modifications() {
204  m_states.reserve(m_modifications.size());
205  for (const auto& mod : m_modifications) {
206  graph_state new_state;
207  if (!m_states.empty()) {
208  new_state = m_states.back();
209  }
210  for (const auto& operation : mod) {
211  operation(new_state);
212  }
213  m_states.push_back(std::move(new_state));
214  }
215  // remove applied modifications
216  m_modifications.clear();
217  }
218 
219  void recalculate_ids() {
220  auto id_comp = [](const auto& a, const auto& b){ return a.id() < b.id(); };
221  auto max_id = [id_comp](auto begin, auto end){
222  return std::max_element(begin, end, id_comp)->id().value;
223  };
224  for (const auto& state : m_states) {
225  if (!state.nodes().empty()) {
226  m_last_node_id = std::max(m_last_node_id,
227  max_id(state.nodes().begin(), state.nodes().end()) + 1);
228  }
229  if (!state.edges().empty()) {
230  m_last_edge_id = std::max(m_last_edge_id,
231  max_id(state.edges().begin(), state.edges().end()) + 1);
232  }
233  }
234  }
235 
236  void set_bool_values() {
237  for (unsigned i = 0; i < m_states.size(); ++i) {
238  for (auto& node : m_states[i].nodes()) {
239  node.is_old((i < m_states.size() - 1)
240  && !m_states[i + 1].node_exists(node.id()));
241  node.is_new((i > 0)
242  && !m_states[i - 1].node_exists(node.id()));
243  }
244  for (auto& edge : m_states[i].edges()) {
245  edge.is_old((i < m_states.size() - 1)
246  && !m_states[i + 1].edge_exists(edge.id()));
247  edge.is_new((i > 0)
248  && !m_states[i - 1].edge_exists(edge.id()));
249  }
250  }
251  }
252 };
253 
254 } // namespace dyng
exceptions.h
dyng::dynamic_graph::clear
void clear()
Clears all states and queued modifications.
Definition: dynamic_graph.h:139
dyng::dynamic_graph::remove_node
void remove_node(unsigned time, node_id id)
Definition: dynamic_graph.h:85
dyng::edge_id
Type used as an identifier for edges.
Definition: identifiers.h:87
dyng::dynamic_graph::remove_edge
void remove_edge(unsigned time, edge_id id)
Definition: dynamic_graph.h:97
dyng::graph::push_node
NodeType & push_node(NodeType node)
Adds a new node to the graph.
Definition: graph.h:238
dyng::graph::remove_edge
void remove_edge(edge_id id)
Removes a single edge.
Definition: graph.h:217
dyng::dynamic_graph::dynamic_graph
dynamic_graph()=default
Default constructor.
dyng::dynamic_graph::states
std::vector< graph_state > & states()
Returns reference to the vector of graph states.
Definition: dynamic_graph.h:157
dyng::graph::push_edge
EdgeType & push_edge(EdgeType edge)
Adds a new edge to the graph.
Definition: graph.h:256
dyng::dynamic_graph::build
void build(std::vector< graph_state > states)
Definition: dynamic_graph.h:131
dyng::graph::remove_node
void remove_node(node_id id)
Removes a single node.
Definition: graph.h:230
dyng::dynamic_graph::build
void build()
Definition: dynamic_graph.h:113
dyng::node
Definition: node.h:32
dyng::edge
Definition: edge.h:119
dyng::dynamic_graph::node_count
unsigned node_count() const
Returns the number of unique nodes in this dynamic graph.
Definition: dynamic_graph.h:178
dyng::dynamic_graph::edge_count
unsigned edge_count() const
Returns the number of unique edges in this dynamic graph.
Definition: dynamic_graph.h:186
dyng::dynamic_graph::add_edge
edge_id add_edge(unsigned time, node_id one, node_id two)
Definition: dynamic_graph.h:71
dyng::dynamic_graph::states
const std::vector< graph_state > & states() const
Returns const reference to the vector of graph states.
Definition: dynamic_graph.h:170
dyng::dynamic_graph
Represents the sequence of states of a dynamic graph.
Definition: dynamic_graph.h:42
dyng::dynamic_graph::add_node
node_id add_node(unsigned time)
Definition: dynamic_graph.h:54
dyng::node_id
Type used as an identifier for nodes.
Definition: identifiers.h:77
dyng::graph
Templated class for representing a static graph and its layout.
Definition: graph.h:40