GEDLIB  1.0
ged_env.ipp
Go to the documentation of this file.
1 /***************************************************************************
2  * *
3  * Copyright (C) 2018 by David B. Blumenthal *
4  * *
5  * This file is part of GEDLIB. *
6  * *
7  * GEDLIB is free software: you can redistribute it and/or modify it *
8  * under the terms of the GNU Lesser General Public License as published *
9  * by the Free Software Foundation, either version 3 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * GEDLIB is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU Lesser General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU Lesser General Public *
18  * License along with GEDLIB. If not, see <http://www.gnu.org/licenses/>. *
19  * *
20  ***************************************************************************/
21 
27 #ifndef SRC_ENV_GED_ENV_IPP_
28 #define SRC_ENV_GED_ENV_IPP_
29 
30 namespace ged {
31 
32 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
35  delete ged_method_;
36 }
37 
38 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
41 initialized_{false},
42 new_graph_ids_(),
43 ged_data_(),
44 lower_bounds_(),
45 upper_bounds_(),
46 runtimes_(),
47 node_maps_(),
48 original_to_internal_node_ids_(),
49 internal_to_original_node_ids_(),
50 ged_method_{nullptr} {}
51 
52 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
53 void
55 set_edit_costs(Options::EditCosts edit_costs, std::initializer_list<double> edit_cost_constants) {
56  ged_data_.set_edit_costs_(edit_costs, std::vector<double>(edit_cost_constants));
57 }
58 
59 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
60 void
63  ged_data_.set_edit_costs_(edit_costs);
64 }
65 
66 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
69 add_graph(const std::string & name, const std::string & graph_class) {
70  for (auto & graph : ged_data_.graphs_) {
71  graph.un_init();
72  }
73  initialized_ = false;
74  GEDGraph::GraphID graph_id{ged_data_.num_graphs_without_shuffled_copies_++};
75  new_graph_ids_.push_back(graph_id);
76  ged_data_.graphs_.emplace(ged_data_.graphs_.begin() + graph_id, graph_id);
77  ged_data_.graph_names_.insert(ged_data_.graph_names_.begin() + graph_id, name);
78  ged_data_.graph_classes_.insert(ged_data_.graph_classes_.begin() + graph_id, graph_class);
79  original_to_internal_node_ids_.insert(original_to_internal_node_ids_.begin() + graph_id, std::map<UserNodeID, GEDGraph::NodeID>());
80  internal_to_original_node_ids_.insert(internal_to_original_node_ids_.begin() + graph_id, std::map<GEDGraph::NodeID, UserNodeID>());
81  ged_data_.strings_to_internal_node_ids_.insert(ged_data_.strings_to_internal_node_ids_.begin() + graph_id, std::map<std::string, GEDGraph::NodeID>());
82  ged_data_.internal_node_ids_to_strings_.insert(ged_data_.internal_node_ids_to_strings_.begin() + graph_id, std::map<GEDGraph::NodeID, std::string>());
83  return graph_id;
84 }
85 
86 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
87 void
90  if (graph_id >= ged_data_.num_graphs_without_shuffled_copies()) {
91  throw Error("The graph " + get_graph_name(graph_id) + " has not been added to the environment.");
92  }
93  ged_data_.graphs_[graph_id].clear();
94  original_to_internal_node_ids_[graph_id].clear();
95  internal_to_original_node_ids_[graph_id].clear();
96  ged_data_.strings_to_internal_node_ids_[graph_id].clear();
97  ged_data_.internal_node_ids_to_strings_[graph_id].clear();
98  initialized_ = false;
99 }
100 
101 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
104 load_exchange_graph(const ged::ExchangeGraph<UserNodeID, UserNodeLabel, UserEdgeLabel> & exchange_graph, GEDGraph::GraphID graph_id, const std::string & graph_name, const std::string & graph_class) {
105  if (graph_id == ged::undefined()) {
106  graph_id = add_graph(graph_name, graph_class);
107  }
108  else {
109  clear_graph(graph_id);
110  }
111  for (GEDGraph::NodeID node_id{0}; node_id < exchange_graph.num_nodes; node_id++) {
112  add_node(graph_id, exchange_graph.original_node_ids.at(node_id), exchange_graph.node_labels.at(node_id));
113  }
114  for (GEDGraph::NodeID i{0}; i < exchange_graph.num_nodes; i++) {
115  for (GEDGraph::NodeID j{i + 1}; j < exchange_graph.num_nodes; j++) {
116  if (exchange_graph.adj_matrix.at(i).at(j) == 1) {
117  add_edge(graph_id, exchange_graph.original_node_ids.at(i), exchange_graph.original_node_ids.at(j), exchange_graph.edge_labels.at(std::make_pair(i, j)));
118  }
119  }
120  }
121  return graph_id;
122 }
123 
124 template<>
127 load_gxl_graph(const std::string & filename, Options::GXLNodeEdgeType node_type, Options::GXLNodeEdgeType edge_type,
128  const std::unordered_set<std::string> & irrelevant_node_attributes, const std::unordered_set<std::string> & irrelevant_edge_attributes, GEDGraph::GraphID graph_id, const std::string & graph_class) {
129 
130  // read the file into a property tree
131  boost::property_tree::ptree root;
132  try {
133  read_xml(filename, root);
134  }
135  catch (const boost::property_tree::xml_parser_error & error) {
136  throw Error(std::string("Error reading file ") + filename + ": " + error.message() + ".");
137  }
138 
139  // first sanity checks
140  if (root.count("gxl") == 0) {
141  throw Error("The file " + filename + " has the wrong format: no xml-element <gxl>.");
142  }
143  if (root.count("gxl") >= 2) {
144  throw Error("The file " + filename + " has the wrong format: more than one xml-element <gxl>.");
145  }
146  root = root.get_child("gxl");
147  if (root.count("graph") == 0) {
148  throw Error("The file " + filename + " has the wrong format: no xml-element <gxl>.<graph>");
149  }
150  if (root.count("graph") >= 2) {
151  throw Error("The file " + filename + " has the wrong format: more than one xml-element <gxl>.<graph>");
152  }
153  root = root.get_child("graph");
154 
155  // add new graph to the environment
156  if (graph_id == ged::undefined()) {
157  graph_id = add_graph(filename, graph_class);
158  }
159  else {
160  clear_graph(graph_id);
161  }
162 
163  // initialize local variables needed for construction of the graph
164  GXLLabel label;
165  std::string attr_name;
166  std::string attr_val;
167  GXLNodeID v_id, from, to;
168 
169  // iterate through the property tree to construct the graph
170  for (const boost::property_tree::ptree::value_type & node_or_edge : root) {
171 
172  // encountered a new vertex that has to be added to the graph
173  if (node_or_edge.first == "node") {
174  // determine the vertex ID
175  try {
176  v_id = node_or_edge.second.get<std::string>("<xmlattr>.id");
177  }
178  catch (const boost::property_tree::ptree_bad_path & error) {
179  throw Error("The file " + filename + " has the wrong format: missing xml-attribute \"id\" in element <gxl>.<graph>.<node>.");
180  }
181  // read the node label and add the vertex to the graph
182 
183  label.clear();
184  if (node_type == Options::GXLNodeEdgeType::LABELED) {
185  read_gxl_label_from_ptree_(node_or_edge, irrelevant_node_attributes, filename, label);
186  }
187  add_node(graph_id, v_id, label);
188  }
189 
190  // encountered a new edge that has to be added to the graph
191  else if (node_or_edge.first == "edge") {
192  // determine the edge's tail and head
193  try {
194  from = node_or_edge.second.get<std::string>("<xmlattr>.from");
195  }
196  catch (const boost::property_tree::ptree_bad_path & error) {
197  throw Error("The file " + filename + " has the wrong format: missing xml-attribute \"from\" in element <gxl>.<graph>.<edge>.");
198  }
199  try {
200  to = node_or_edge.second.get<std::string>("<xmlattr>.to");
201  }
202  catch (const boost::property_tree::ptree_bad_path & error) {
203  throw Error("The file " + filename + " has the wrong format: missing xml-attribute \"to\" in element <gxl>.<graph>.<edge>.");
204  }
205  // read the edge label and add the edge to the graph
206  label.clear();
207  if (edge_type == Options::GXLNodeEdgeType::LABELED) {
208  read_gxl_label_from_ptree_(node_or_edge, irrelevant_edge_attributes, filename, label);
209  }
210  add_edge(graph_id, from, to, label);
211  }
212 
213  // sanity check
214  else if (node_or_edge.first != "<xmlattr>"){
215  throw Error("The file " + filename + " has the wrong format: unexpected element <gxl>.<graph>.<" + node_or_edge.first + ">.");
216  }
217  }
218  // return ID of newly constructed graph
219  return graph_id;
220 }
221 
222 template<>
223 std::vector<GEDGraph::GraphID>
225 load_gxl_graphs(const std::string & graph_dir, const std::string & file, Options::GXLNodeEdgeType node_type, Options::GXLNodeEdgeType edge_type,
226  const std::unordered_set<std::string> & irrelevant_node_attributes, const std::unordered_set<std::string> & irrelevant_edge_attributes) {
227  // read the file into a property tree
228  boost::property_tree::ptree root;
229  try {
230  read_xml(file, root);
231  }
232  catch (const boost::property_tree::xml_parser_error & error) {
233  throw Error(std::string("Error reading file ") + file + ": " + error.message() + ".");
234  }
235  // first sanity checks
236  if (root.count("GraphCollection") == 0) {
237  throw Error("The file " + file + " has the wrong format: no xml-element <GraphCollection>.");
238  }
239  if (root.count("GraphCollection") >= 2) {
240  throw Error("The file " + file + " has the wrong format: more than one xml-element <GraphCollection>.");
241  }
242  root = root.get_child("GraphCollection");
243 
244 
245  // Read the listed .gxl-files into the environment.
246  std::vector<GEDGraph::GraphID> graph_ids;
247  std::string gxl_file("");
248  std::string graph_class("");
249  for (const boost::property_tree::ptree::value_type & val : root) {
250  if (val.first == "graph") {
251  try {
252  gxl_file = val.second.get<std::string>("<xmlattr>.file");
253  }
254  catch (const boost::property_tree::ptree_bad_path & error) {
255  throw Error("The file " + file + " has the wrong format: missing xml-attribute \"file\" in element <GraphCollection>.<graph>");
256  }
257  catch (const boost::property_tree::ptree_bad_data & error) {
258  throw Error("The file " + file + " has the wrong format: corrupted content in xml-attribute \"file\" of element <GraphCollection>.<graph>");
259  }
260  try {
261  graph_class = val.second.get<std::string>("<xmlattr>.class");
262  }
263  catch (const boost::property_tree::ptree_bad_path & error) {
264  throw Error("The file " + file + " has the wrong format: missing xml-attribute \"class\" in element <GraphCollection>.<graph>");
265  }
266  catch (const boost::property_tree::ptree_bad_data & error) {
267  throw Error("The file " + file + " has the wrong format: corrupted content in xml-attribute \"class\" of element <GraphCollection>.<graph>");
268  }
269  graph_ids.push_back(load_gxl_graph(graph_dir + gxl_file, node_type, edge_type, irrelevant_node_attributes, irrelevant_edge_attributes, ged::undefined(), graph_class));
270  }
271  else if (val.first != "<xmlattr>") {
272  throw Error("The file " + file + " has the wrong format: unexpected element <GraphCollection>.<" + val.first + ">.");
273  }
274  }
275  return graph_ids;
276 }
277 
278 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
279 void
281 read_gxl_label_from_ptree_(const boost::property_tree::ptree::value_type & node_or_edge, const std::unordered_set<std::string> & irrelevant_attributes, const std::string & file, GXLLabel & label) {
282  std::string attr_name, attr_val;
283  std::string info(node_or_edge.first);
284  // read the attributes into the label
285  for (const boost::property_tree::ptree::value_type & attr : node_or_edge.second) {
286 
287  if (attr.first == "attr") {
288  // determine the name of the attribute
289  try {
290  attr_name = attr.second.get<std::string>("<xmlattr>.name");
291  }
292  catch (const boost::property_tree::ptree_bad_path & error) {
293  throw Error("The file " + file + " has the wrong format: missing xml-attribute \"name\" in element <gxl>.<graph>.<" + info + ">.<attr>");
294  }
295  if (irrelevant_attributes.find(attr_name) != irrelevant_attributes.end()) {
296  continue;
297  }
298  // determine the value of the attribute
299  LabelID num_attr {0};
300  for (const boost::property_tree::ptree::value_type & val : attr.second) {
301  if (val.first != "<xmlattr>") {
302  // sanity check
303  if (++num_attr > 1) {
304  throw Error("The file " + file + " has the wrong format: each element <gxl>.<graph>.<" + info + ">.<attr> has to have exactly one child. Actual number of children: " + std::to_string(num_attr));
305  }
306  try {
307  attr_val = val.second.get<std::string>("");
308  }
309  catch (const boost::property_tree::ptree_bad_path & error) {
310  throw Error("The file " + file + " has the wrong format: missing content <gxl>.<graph>.<" + info + ">.<attr>.<[TYPENAME]>.___.");
311  }
312  catch (const boost::property_tree::ptree_bad_data & error) {
313  throw Error("The file " + file + " has the wrong format: corrupted content <gxl>.<graph>.<" + info + ">.<attr>.<[TYPENAME]>.___.");
314  }
315  }
316  }
317  // add the attribute to the label
318  label[attr_name] = attr_val;
319  }
320  // sanity check
321  else if (attr.first != "<xmlattr>"){
322  throw Error("The file " + file + " has the wrong format: unexpected element <gxl>.<graph>.<" + info + ">.<" + attr.first + ">.");
323  }
324  }
325 }
326 
327 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
328 std::string
330 to_string_(UserNodeID node_id) {
331  std::stringstream ss;
332  ss << node_id;
333  return ss.str();
334 }
335 
336 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
337 void
339 add_node(GEDGraph::GraphID graph_id, const UserNodeID & node_id, const UserNodeLabel & node_label) {
340  if (graph_id >= ged_data_.num_graphs()) {
341  throw Error("The graph " + get_graph_name(graph_id) + " with ID " + std::to_string(graph_id) + " has not been added to the environment. The environment contains " + std::to_string(ged_data_.num_graphs_without_shuffled_copies()) + " graphs.");
342  }
343  if (original_to_internal_node_ids_[graph_id].find(node_id) != original_to_internal_node_ids_[graph_id].end()) {
344  throw Error("The node " + to_string_(node_id) + " has already been added to the graph " + std::to_string(graph_id) + ": " + get_graph_name(graph_id) + ".");
345  }
346  initialized_ = false;
347  GEDGraph::NodeID internal_node_id{ged_data_.graphs_[graph_id].add_node()};
348  original_to_internal_node_ids_[graph_id][node_id] = internal_node_id;
349  internal_to_original_node_ids_[graph_id][internal_node_id] = node_id;
350  ged_data_.strings_to_internal_node_ids_[graph_id][to_string_(node_id)] = internal_node_id;
351  ged_data_.internal_node_ids_to_strings_[graph_id][internal_node_id] = to_string_(node_id);
352  LabelID label_id{ged_data_.node_label_to_id_(node_label)};
353  ged_data_.graphs_[graph_id].set_label(original_to_internal_node_ids_[graph_id][node_id], label_id);
354 }
355 
356 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
357 void
359 add_edge(GEDGraph::GraphID graph_id, const UserNodeID & from, const UserNodeID & to, const UserEdgeLabel & edge_label, bool ignore_duplicates) {
360  if (graph_id >= ged_data_.num_graphs()) {
361  throw Error("The graph " + get_graph_name(graph_id) + " with ID " + std::to_string(graph_id) + " has not been added to the environment. The environment contains " + std::to_string(ged_data_.num_graphs_without_shuffled_copies()) + " graphs.");
362  }
363  if (original_to_internal_node_ids_[graph_id].find(from) == original_to_internal_node_ids_[graph_id].end()) {
364  throw Error("The node " + to_string_(from) + " does not exist in the graph " + get_graph_name(graph_id) + ".");
365  }
366  if (original_to_internal_node_ids_[graph_id].find(to) == original_to_internal_node_ids_[graph_id].end()) {
367  throw Error("The node " + to_string_(to) + " does not exist in the graph " + get_graph_name(graph_id) + ".");
368  }
369  initialized_ = false;
370  if (ged_data_.graphs_[graph_id].safe_is_edge(original_to_internal_node_ids_[graph_id][from], original_to_internal_node_ids_[graph_id][to])) {
371  if (ignore_duplicates) {
372  return;
373  }
374  throw Error("An edge between " + to_string_(from) + " and " + to_string_(to) + " has already been added to the graph " + get_graph_name(graph_id) + ".");
375  }
376  GEDGraph::EdgeID edge_id{ged_data_.graphs_[graph_id].add_edge(original_to_internal_node_ids_[graph_id][from], original_to_internal_node_ids_[graph_id][to])};
377  LabelID label_id{ged_data_.edge_label_to_id_(edge_label)};
378  ged_data_.graphs_[graph_id].set_label(edge_id, label_id);
379 }
380 
381 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
382 void
384 set_method(Options::GEDMethod method, const std::string & options) {
385  delete ged_method_;
386  switch (method) {
388  ged_method_ = new Branch<UserNodeLabel, UserEdgeLabel>(ged_data_);
389  break;
391  ged_method_ = new BranchFast<UserNodeLabel, UserEdgeLabel>(ged_data_);
392  break;
394  ged_method_ = new BranchTight<UserNodeLabel, UserEdgeLabel>(ged_data_);
395  break;
397  ged_method_ = new BranchUniform<UserNodeLabel, UserEdgeLabel>(ged_data_);
398  break;
400  ged_method_ = new BranchCompact<UserNodeLabel, UserEdgeLabel>(ged_data_);
401  break;
403  ged_method_ = new Partition<UserNodeLabel, UserEdgeLabel>(ged_data_);
404  break;
406  ged_method_ = new Hybrid<UserNodeLabel, UserEdgeLabel>(ged_data_);
407  break;
409  ged_method_ = new Ring<UserNodeLabel, UserEdgeLabel>(ged_data_);
410  break;
412  ged_method_ = new AnchorAwareGED<UserNodeLabel, UserEdgeLabel>(ged_data_);
413  break;
415  ged_method_ = new Walks<UserNodeLabel, UserEdgeLabel>(ged_data_);
416  break;
418  ged_method_ = new IPFP<UserNodeLabel, UserEdgeLabel>(ged_data_);
419  break;
421  ged_method_ = new Bipartite<UserNodeLabel, UserEdgeLabel>(ged_data_);
422  break;
424  ged_method_ = new Subgraph<UserNodeLabel, UserEdgeLabel>(ged_data_);
425  break;
427  ged_method_ = new Node<UserNodeLabel, UserEdgeLabel>(ged_data_);
428  break;
430  ged_method_ = new RingML<UserNodeLabel, UserEdgeLabel>(ged_data_);
431  break;
433  ged_method_ = new BipartiteML<UserNodeLabel, UserEdgeLabel>(ged_data_);
434  break;
436  ged_method_ = new Refine<UserNodeLabel, UserEdgeLabel>(ged_data_);
437  break;
439  ged_method_ = new BPBeam<UserNodeLabel, UserEdgeLabel>(ged_data_);
440  break;
442  ged_method_ = new SimulatedAnnealing<UserNodeLabel, UserEdgeLabel>(ged_data_);
443  break;
445  ged_method_ = new HED<UserNodeLabel, UserEdgeLabel>(ged_data_);
446  break;
448  ged_method_ = new Star<UserNodeLabel, UserEdgeLabel>(ged_data_);
449  break;
450 #ifdef GUROBI
451  case Options::GEDMethod::F1:
452  ged_method_ = new F1<UserNodeLabel, UserEdgeLabel>(ged_data_);
453  break;
454  case Options::GEDMethod::F2:
455  ged_method_ = new F2<UserNodeLabel, UserEdgeLabel>(ged_data_);
456  break;
457  case Options::GEDMethod::COMPACT_MIP:
458  ged_method_ = new CompactMIP<UserNodeLabel, UserEdgeLabel>(ged_data_);
459  break;
460  case Options::GEDMethod::BLP_NO_EDGE_LABELS:
461  ged_method_ = new BLPNoEdgeLabels<UserNodeLabel, UserEdgeLabel>(ged_data_);
462  break;
463 #endif
464  }
465  ged_method_->set_options(options);
466 }
467 
468 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
469 void
472  if (g_id >= ged_data_.num_graphs()) {
473  throw Error("The graph with ID " + std::to_string(g_id) + " has not been added to the environment.");
474  }
475  if (h_id >= ged_data_.num_graphs()) {
476  throw Error("The graph with ID " + std::to_string(h_id) + " has not been added to the environment.");
477  }
478  if (not initialized_) {
479  throw Error("The environment is uninitialized. Call init() after adding all graphs to the environment.");
480  }
481  if (not ged_method_) {
482  throw Error("No method has been set. Call set_method() before calling run().");
483  }
484  // call selected GEDMethod and store results
485  if (ged_data_.shuffled_graph_copies_available() and (g_id == h_id)) {
486  ged_method_->run(g_id, ged_data_.id_shuffled_graph_copy(h_id));
487  }
488  else {
489  ged_method_->run(g_id, h_id);
490  }
491  std::pair<GEDGraph::GraphID, GEDGraph::GraphID> key(g_id, h_id);
492  lower_bounds_[key] = ged_method_->get_lower_bound();
493  upper_bounds_[key] = ged_method_->get_upper_bound();
494  runtimes_[key] = ged_method_->get_runtime();
495  auto it = node_maps_.find(key);
496  if (it == node_maps_.end()) {
497  node_maps_.emplace(key, ged_method_->get_node_map());
498  }
499  else {
500  it->second = ged_method_->get_node_map();
501  }
502 }
503 
504 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
505 std::pair<GEDGraph::GraphID, GEDGraph::GraphID>
507 graph_ids() const {
508  return std::make_pair(0, static_cast<GEDGraph::GraphID>(ged_data_.num_graphs_without_shuffled_copies()));
509 }
510 
511 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
512 std::size_t
514 num_graphs() const {
515  return ged_data_.num_graphs_without_shuffled_copies();
516 }
517 
518 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
519 void
522  if (not initialized_) {
523  throw Error("The environment is uninitialized. Call init() before calling init_method().");
524  }
525  if (not ged_method_) {
526  throw Error("No method has been set. Call set_method() before calling init_method().");
527  }
528  ged_method_->init();
529 }
530 
531 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
532 double
535  std::pair<GEDGraph::GraphID, GEDGraph::GraphID> key(g_id, h_id);
536  if (lower_bounds_.find(key) == lower_bounds_.end()) {
537  throw Error("Call run(" + std::to_string(g_id) + "," + std::to_string(h_id) + ") before calling get_lower_bound(" + std::to_string(g_id) + "," + std::to_string(h_id) + ").");
538  }
539  return lower_bounds_.at(key);
540 }
541 
542 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
543 double
546  std::pair<GEDGraph::GraphID, GEDGraph::GraphID> key(g_id, h_id);
547  if (upper_bounds_.find(key) == upper_bounds_.end()) {
548  throw Error("Call run(" + std::to_string(g_id) + "," + std::to_string(h_id) + ") before calling get_upper_bound(" + std::to_string(g_id) + "," + std::to_string(h_id) + ").");
549  }
550  return upper_bounds_.at(key);
551 }
552 
553 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
554 const NodeMap &
557  std::pair<GEDGraph::GraphID, GEDGraph::GraphID> key(g_id, h_id);
558  if (node_maps_.find(key) == node_maps_.end()) {
559  throw Error("Call run(" + std::to_string(g_id) + "," + std::to_string(h_id) + ") before calling get_node_map(" + std::to_string(g_id) + "," + std::to_string(h_id) + ").");
560  }
561  return node_maps_.at(key);
562 }
563 
564 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
565 double
568  std::pair<GEDGraph::GraphID, GEDGraph::GraphID> key(g_id, h_id);
569  if (runtimes_.find(key) == runtimes_.end()) {
570  throw Error("Call run(" + std::to_string(g_id) + "," + std::to_string(h_id) + ") before calling get_runtime(" + std::to_string(g_id) + "," + std::to_string(h_id) + ").");
571  }
572  return runtimes_.at(key).count();
573 }
574 
575 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
576 const std::string &
579  return ged_data_.graph_classes_.at(graph_id);
580 }
581 
582 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
583 std::size_t
586  return ged_data_.graph(graph_id).num_nodes();
587 }
588 
589 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
590 double
593  std::size_t sum_num_nodes{0};
594  for (std::size_t graph_id{0}; graph_id < ged_data_.num_graphs_without_shuffled_copies(); graph_id++) {
595  sum_num_nodes += ged_data_.graph(graph_id).num_nodes();
596  }
597  return static_cast<double>(sum_num_nodes) / static_cast<double>(ged_data_.num_graphs_without_shuffled_copies());
598 }
599 
600 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
601 const std::string &
604  return ged_data_.graph_names_.at(graph_id);
605 }
606 
607 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
610 get_graph(GEDGraph::GraphID graph_id) const {
612  const GEDGraph & graph{ged_data_.graphs_.at(graph_id)};
613  exchange_graph.id = graph.id();
614  exchange_graph.num_nodes = graph.num_nodes();
615  exchange_graph.num_edges = graph.num_edges();
616  exchange_graph.adj_matrix = std::vector<std::vector<std::size_t>>(exchange_graph.num_nodes, std::vector<std::size_t>(exchange_graph.num_nodes, 0));
617  for (GEDGraph::NodeID node_id{0}; node_id < exchange_graph.num_nodes; node_id++) {
618  exchange_graph.original_node_ids.emplace_back(internal_to_original_node_ids_.at(graph_id).at(node_id));
619  exchange_graph.node_labels.emplace_back(ged_data_.node_labels_.at(graph.get_node_label(node_id) - 1));
620  }
621  for (auto eitr = graph.edges(); eitr.first != eitr.second; eitr.first++) {
622  GEDGraph::EdgeID edge(*eitr.first);
623  exchange_graph.adj_matrix[graph.tail(edge)][graph.head(edge)] = 1;
624  exchange_graph.adj_matrix[graph.head(edge)][graph.tail(edge)] = 1;
625  exchange_graph.edge_labels[std::make_pair(graph.tail(edge),graph.head(edge))] = ged_data_.edge_labels_.at(graph.get_edge_label(edge) - 1);
626  exchange_graph.edge_labels[std::make_pair(graph.head(edge),graph.tail(edge))] = ged_data_.edge_labels_.at(graph.get_edge_label(edge) - 1);
627  }
628  return exchange_graph;
629 }
630 
631 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
632 double
634 get_init_time() const {
635  return ged_method_->get_init_time().count();
636 }
637 
638 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
639 void
642  ged_data_.compute_induced_cost(ged_data_.graphs_.at(g_id), ged_data_.graphs_.at(h_id), node_map);
643 }
644 
645 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
646 bool
649  return ged_data_.quasimetric_costs();
650 }
651 
652 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
653 void
656 
657  // Throw an exception if no edit costs have been selected.
658  if (not ged_data_.edit_costs_) {
659  throw Error("No edit costs have been selected. Call set_edit_costs() before calling init().");
660  }
661 
662  // Return if the environment is initialized.
663  if (initialized_) {
664  return;
665  }
666 
667  // Set initialization type.
668  ged_data_.init_type_ = init_type;
669 
670  // Construct shuffled graph copies if necessary.
671  if (ged_data_.shuffled_graph_copies_available()) {
672  for (auto graph_id : new_graph_ids_) {
673  construct_shuffled_graph_copy_(graph_id);
674  }
675  }
676 
677  // Re-initialize adjacency matrices (also previously initialized graphs must be re-initialized because of possible re-allocation).
678  for (auto & graph : ged_data_.graphs_) {
679  if (not graph.initialized()) {
680  graph.setup_adjacency_matrix();
681  ged_data_.max_num_nodes_ = std::max(ged_data_.max_num_nodes_, graph.num_nodes());
682  ged_data_.max_num_edges_ = std::max(ged_data_.max_num_edges_, graph.num_edges());
683  }
684  }
685 
686  // Initialize cost matrices if necessary.
687  if (ged_data_.eager_init_()) {
688  ged_data_.init_cost_matrices_();
689  }
690 
691  // Mark environment as initialized.
692  initialized_ = true;
693  new_graph_ids_.clear();
694 }
695 
696 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
700  GEDGraph::GraphID copied_graph_id{ged_data_.id_shuffled_graph_copy(graph_id)};
701  if (copied_graph_id < ged_data_.num_graphs()) {
702  ged_data_.graphs_[copied_graph_id].clear();
703  original_to_internal_node_ids_[copied_graph_id].clear();
704  ged_data_.strings_to_internal_node_ids_[copied_graph_id].clear();
705  internal_to_original_node_ids_[copied_graph_id].clear();
706  ged_data_.internal_node_ids_to_strings_[copied_graph_id].clear();
707  }
708  else if (copied_graph_id == ged_data_.num_graphs()) {
709  ged_data_.graphs_.emplace_back(copied_graph_id);
710  ged_data_.graph_names_.push_back(get_graph_name(graph_id));
711  ged_data_.graph_classes_.push_back(get_graph_class(graph_id));
712  original_to_internal_node_ids_.push_back(std::map<UserNodeID, GEDGraph::NodeID>());
713  ged_data_.strings_to_internal_node_ids_.push_back(std::map<std::string, GEDGraph::NodeID>());
714  internal_to_original_node_ids_.push_back(std::map<GEDGraph::NodeID, UserNodeID>());
715  ged_data_.internal_node_ids_to_strings_.push_back(std::map<GEDGraph::NodeID, std::string>());
716  }
717  else {
718  throw Error("Unexpected copied graph ID " + std::to_string(copied_graph_id) + " for graph with ID " + std::to_string(graph_id) + ". Number of graphs in environment: " + std::to_string(ged_data_.num_graphs()) + ".");
719  }
720  return copied_graph_id;
721 }
722 
723 template<class UserNodeID, class UserNodeLabel, class UserEdgeLabel>
724 void
727  GEDGraph::GraphID copied_graph_id{add_or_clear_shuffled_graph_copy_(graph_id)};
728  const GEDGraph & graph{ged_data_.graph(graph_id)};
729  std::vector<std::pair<UserNodeID, UserNodeLabel>> nodes;
730  for (auto node = graph.nodes().first; node != graph.nodes().second; node++) {
731  nodes.emplace_back(internal_to_original_node_ids_.at(graph_id).at(*node), ged_data_.id_to_node_label(graph.get_node_label(*node)));
732  }
733  std::random_device rng_g;
734  std::mt19937 urng_g(rng_g());
735  std::shuffle(nodes.begin(), nodes.end(), urng_g);
736  for (const auto & node : nodes) {
737  add_node(copied_graph_id, node.first, node.second);
738  }
739  for (auto edge = graph.edges().first; edge != graph.edges().second; edge++) {
740  add_edge(copied_graph_id, internal_to_original_node_ids_.at(graph_id).at(graph.tail(*edge)), internal_to_original_node_ids_.at(graph_id).at(graph.head(*edge)), ged_data_.id_to_edge_label(graph.get_edge_label(*edge)));
741  }
742 }
743 
744 }
745 
746 #endif /* SRC_ENV_GED_ENV_IPP_ */
Computes lower and upper bounds for general edit costs.
Definition: branch.hpp:42
Computes a lower bound for uniform edit costs.
Definition: partition.hpp:42
Computes a lower bound for general edit costs.
Definition: hed.hpp:46
GEDGraph::GraphID load_gxl_graph(const std::string &file_name, Options::GXLNodeEdgeType node_type, Options::GXLNodeEdgeType edge_type, const std::unordered_set< std::string > &irrelevant_node_attributes, const std::unordered_set< std::string > &irrelevant_edge_attributes, GEDGraph::GraphID graph_id=ged::undefined(), const std::string &graph_class="")
Load graph given in the GXL file format.
Computes an upper bound for general edit costs.
Definition: bp_beam.hpp:52
A class for node maps.
Definition: node_map.hpp:43
std::string GXLNodeID
Type of node IDs of graphs given in the .gxl file format.
std::size_t id
Internal ID of the graph.
Mixed integer linear programming formulation of the graph edit distance.
Definition: f1.hpp:42
std::size_t num_graphs() const
The number of graphs contained in the environment.
Definition: ged_env.ipp:514
bool quasimetric_costs() const
Checks if the edit costs are quasimetric.
Definition: ged_env.ipp:648
std::pair< GEDGraph::GraphID, GEDGraph::GraphID > graph_ids() const
Provides access to the IDs of the graphs contained in the environment.
Definition: ged_env.ipp:507
std::vector< GEDGraph >::size_type GraphID
Type of internally used graph IDs.
Definition: ged_graph.hpp:112
Computes an upper bound for general edit costs.
Definition: walks.hpp:47
Selects ged::Branch.
void init(Options::InitType init_type=Options::InitType::EAGER_WITHOUT_SHUFFLED_COPIES)
Initializes the environment.
Definition: ged_env.ipp:655
ExchangeGraph< UserNodeID, UserNodeLabel, UserEdgeLabel > get_graph(GEDGraph::GraphID graph_id) const
Returns ged::ExchangeGraph representation.
Definition: ged_env.ipp:610
std::vector< std::vector< std::size_t > > adj_matrix
Adjacency matrix.
Uses characteristics of an LSAPE instance for defining feature vectors for node edit operations...
GEDGraph::GraphID load_exchange_graph(const ged::ExchangeGraph< UserNodeID, UserNodeLabel, UserEdgeLabel > &exchange_graph, GEDGraph::GraphID graph_id=ged::undefined(), const std::string &graph_name="", const std::string &graph_class="")
Loads ged::ExchangeGraph into the environment.
Definition: ged_env.ipp:104
Selects ged::BranchFast.
std::vector< GEDGraph::GraphID > load_gxl_graphs(const std::string &graph_dir, const std::string &collection_file, Options::GXLNodeEdgeType node_type=Options::GXLNodeEdgeType::LABELED, Options::GXLNodeEdgeType edge_type=Options::GXLNodeEdgeType::LABELED, const std::unordered_set< std::string > &irrelevant_node_attributes=std::unordered_set< std::string >(), const std::unordered_set< std::string > &irrelevant_edge_attributes=std::unordered_set< std::string >())
Loads graphs given in the GXL file format.
Computes lower and upper bounds for uniform edit costs.
Definition: star.hpp:45
Selects ged::AnchorAwareGED.
double get_init_time() const
Returns initialization time.
Definition: ged_env.ipp:634
Simple graph class used for communication with user.
Computes lower and upper bounds for general edit costs.
Definition: node.hpp:42
void set_edit_costs(Options::EditCosts edit_costs, std::initializer_list< double > edit_cost_constants={})
Sets the edit costs to one of the predefined edit costs.
Definition: ged_env.ipp:55
void init_method()
Initializes the method specified by call to set_method().
Definition: ged_env.ipp:521
Computes lower and upper bounds for general edit costs.
Selects ged::Walks.
GEDMethod
Selects the method.
std::vector< UserNodeLabel > node_labels
The labels of all nodes.
GXLNodeEdgeType
Selects whether nodes or edges of graphs given in GXL file format are labeled or unlabeled.
const std::string & get_graph_class(GEDGraph::GraphID graph_id) const
Returns the graph class.
Definition: ged_env.ipp:578
std::vector< UserNodeID > original_node_ids
The original IDs of all nodes.
Selects ged::BranchTight.
std::size_t LabelID
Internally used type of node and edge labels.
Uses ring structures for defining feature vectors for node edit operations.
Definition: ring_ml.hpp:48
Mixed integer linear programming formulation of the graph edit distance.
Definition: compact_mip.hpp:43
double get_runtime(GEDGraph::GraphID g_id, GEDGraph::GraphID h_id) const
Returns runtime.
Definition: ged_env.ipp:567
Selects ged::Partition.
Runtime error class.
Definition: error.hpp:37
InitType
Selects the initialization type of the environment.
GEDEnv()
Constructor.
Definition: ged_env.ipp:40
Computes lower and upper bounds for general edit costs.
Definition: bipartite.hpp:42
double get_avg_num_nodes() const
Returns average number of nodes.
Definition: ged_env.ipp:592
Computes lower and upper bounds for general edit costs.
Definition: branch_fast.hpp:45
Binary linear programming formulation of the graph edit distance without edge labels.
void add_node(GEDGraph::GraphID graph_id, const UserNodeID &node_id, const UserNodeLabel &node_label)
Adds a labeled node.
Definition: ged_env.ipp:339
void compute_induced_cost(GEDGraph::GraphID g_id, GEDGraph::GraphID h_id, NodeMap &node_map) const
Computes the edit cost between two graphs induced by a node map.
Definition: ged_env.ipp:641
Selects ged::SimulatedAnnealing.
Selects ged::BipartiteML.
Selects ged::Bipartite.
std::map< std::string, std::string > GXLLabel
Type of node and edge labels of graphs given in the .gxl file format.
double get_upper_bound(GEDGraph::GraphID g_id, GEDGraph::GraphID h_id) const
Returns upper bound for edit distance between the input graphs.
Definition: ged_env.ipp:545
The normalized input graphs used by GEDLIB. All labels are integers.
Definition: ged_graph.hpp:104
std::size_t num_nodes
The number of nodes. Nodes have IDs between 0 and num_nodes - 1.
detail::GedGraphAL::edge_descriptor EdgeID
Internally used edge ID type.
Definition: ged_graph.hpp:110
std::size_t num_edges
The number of edges.
std::map< std::pair< std::size_t, std::size_t >, UserEdgeLabel > edge_labels
A hash map with a key-value pair ((internal_tail_id, internal_head_id), label) for each edge...
std::size_t get_num_nodes(GEDGraph::GraphID graph_id) const
Returns the number of nodes.
Definition: ged_env.ipp:585
constexpr std::size_t undefined()
Returns undefined size.
void clear_graph(GEDGraph::GraphID graph_id)
Clears and de-initializes a graph that has previously been added to the environment. Call init() after calling this method.
Definition: ged_env.ipp:89
Computes a lower bound for uniform edit costs.
Definition: hybrid.hpp:47
Computes an upper bound for general edit costs.
Definition: refine.hpp:47
void run_method(GEDGraph::GraphID g_id, GEDGraph::GraphID h_id)
Runs the GED method specified by call to set_method() between the graphs with IDs g_id and h_id...
Definition: ged_env.ipp:471
void set_method(Options::GEDMethod method, const std::string &options=std::string(""))
Sets the GEDMethod to be used by run_method().
Definition: ged_env.ipp:384
Global namespace for GEDLIB.
void add_edge(GEDGraph::GraphID graph_id, const UserNodeID &tail, const UserNodeID &head, const UserEdgeLabel &edge_label, bool ignore_duplicates=true)
Adds a labeled edge.
Definition: ged_env.ipp:359
EditCosts
Selects the edit costs.
const NodeMap & get_node_map(GEDGraph::GraphID g_id, GEDGraph::GraphID h_id) const
Returns node map between the input graphs.
Definition: ged_env.ipp:556
Selects ged::Refine.
Computes upper bounds for general edit costs.
Definition: subgraph.hpp:49
Computes the exact graph edit distance for general edit costs.
Selects ged::Hybrid.
Selects ged::BranchUniform.
const std::string & get_graph_name(GEDGraph::GraphID graph_id) const
Returns the graph name.
Definition: ged_env.ipp:603
GEDGraph::GraphID add_graph(const std::string &graph_name="", const std::string &graph_class="")
Adds a new uninitialized graph to the environment. Call init() after calling this method...
Definition: ged_env.ipp:69
~GEDEnv()
Destructor.
Definition: ged_env.ipp:34
Computes a lower bound for uniform edit costs.
Computes an upper bound for general edit costs.
Definition: ring.hpp:51
Computes an upper bound for general edit costs.
Definition: ipfp.hpp:64
Computes lower and upper bounds for uniform edit costs.
std::size_t NodeID
Internally used vertex ID type.
Definition: ged_graph.hpp:108
Uses LSAPE instances to approximate GED via simulated annealing.
Selects ged::Subgraph.
Mixed integer linear programming formulation of the graph edit distance.
Definition: f2.hpp:42
Abstract class for defining edit cost functions.
Definition: edit_costs.hpp:38
double get_lower_bound(GEDGraph::GraphID g_id, GEDGraph::GraphID h_id) const
Returns lower bound for edit distance between the input graphs.
Definition: ged_env.ipp:534
Provides the API of GEDLIB.
Definition: ged_data.hpp:48
Selects ged::BranchCompact.