GEDLIB  1.0
walks.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_METHODS_WALKS_IPP_
28 #define SRC_METHODS_WALKS_IPP_
29 
30 namespace ged {
31 
32 // === Definitions of destructor and constructor. ===
33 template<class UserNodeLabel, class UserEdgeLabel>
34 Walks<UserNodeLabel, UserEdgeLabel>::
35 ~Walks() {}
36 
37 template<class UserNodeLabel, class UserEdgeLabel>
38 Walks<UserNodeLabel, UserEdgeLabel>::
39 Walks(const GEDData<UserNodeLabel, UserEdgeLabel> & ged_data) :
40 LSAPEBasedMethod<UserNodeLabel, UserEdgeLabel>(ged_data),
41 depth_{3},
42 min_depth_{1},
43 max_depth_{5},
44 infile_(""),
45 outfile_(""),
46 adj_graphs_() {
47  this->compute_lower_bound_ = false;
48 }
49 
50 // Definitions of member functions inherited from LSAPEBasedMethod.
51 template<class UserNodeLabel, class UserEdgeLabel>
52 void
55  depth_ = 3;
56  min_depth_ = 1;
57  max_depth_ = 5;
58  infile_ = std::string("");
59  outfile_ = std::string("");
60 }
61 
62 template<class UserNodeLabel, class UserEdgeLabel>
63 std::string
66  return "[--depth-range <arg>] [--load <arg>] [--save <arg>]";
67 }
68 
69 template<class UserNodeLabel, class UserEdgeLabel>
70 bool
72 lsape_parse_option_(const std::string & option, const std::string & arg) {
73  if (option == "load") {
74  infile_ = arg;
75  return true;
76  }
77  else if (option == "save") {
78  outfile_ = arg;
79  return true;
80  }
81  else if (option == "depth-range") {
82  std::stringstream depth_range(arg);
83  std::string min_depth, max_depth;
84  if (std::getline(depth_range, min_depth, ',') and std::getline(depth_range, max_depth, ',')) {
85  try {
86  min_depth_ = std::stoi(min_depth);
87  }
88  catch (...) {
89  throw Error(std::string("Invalid argument \"") + arg + "\" for option depth-range. Usage: options = \"[--depth-range <smaller convertible to int greater 0>,<larger convertible to int greater 0>] [...]");
90  }
91  try {
92  max_depth_ = std::stoi(max_depth);
93  }
94  catch (...) {
95  throw Error(std::string("Invalid argument \"") + arg + "\" for option depth-range. Usage: options = \"[--depth-range <smaller convertible to int greater 0>,<larger convertible to int greater 0>] [...]");
96  }
97  if ((min_depth_ > max_depth_) or (min_depth_ <= 0) or (max_depth_ <= 0)) {
98  throw Error(std::string("Invalid argument \"") + arg + "\" for option depth-range. Usage: options = \"[--depth-range <smaller convertible to int greater 0>,<larger convertible to int greater 0>] [...]");
99  }
100  }
101  else {
102  throw Error(std::string("Invalid argument \"") + arg + "\" for option depth-range. Usage: options = \"[--depth-range <smaller convertible to int greater 0>,<larger convertible to int greater 0>] [...]");
103  }
104  return true;
105  }
106  return false;
107 }
108 
109 template<class UserNodeLabel, class UserEdgeLabel>
110 void
112 lsape_init_graph_(const GEDGraph & graph) {
113  adj_graphs_[graph.id()] = AdjGraph_(graph);
114 }
115 
116 template<class UserNodeLabel, class UserEdgeLabel>
117 void
119 lsape_pre_graph_init_(bool called_at_runtime) {
120  if (load_config_file_()) {
121  std::map<std::string, std::string> options;
122  util::parse_config_file(infile_, options);
123  depth_ = std::stod(options.at("depth"));
124  }
125  else {
126  depth_ = (min_depth_ + max_depth_) / 2;
127  }
128 }
129 
130 template<class UserNodeLabel, class UserEdgeLabel>
131 void
134 
135  // Return, if a configuration file is provided or if the minimal depth equals the maximal depth.
136  if (load_config_file_() or (min_depth_ == max_depth_)) {
137  return;
138  }
139 
140  // Find the best depth.
141  std::size_t num_runs{(max_depth_ - min_depth_ + 1) * (this->ged_data_.num_graphs() * this->ged_data_.num_graphs())};
142  ProgressBar progress_bar(num_runs);
143  std::cout << "\r" << progress_bar << std::flush;
144  double best_avg_ub{std::numeric_limits<double>::infinity()};
145  std::size_t best_depth{min_depth_};
146  LSAPESolver lsape_solver;
147  lsape_solver.set_model(this->lsape_model_);
148  for (depth_ = min_depth_; depth_ <= max_depth_; depth_++) {
149  double avg_ub{0.0};
150  for (auto g = this->ged_data_.begin(); g != this->ged_data_.end(); g++) {
151  if (this->ged_data_.is_shuffled_graph_copy(g->id())) {
152  continue;
153  }
154  for (auto h = this->ged_data_.begin(); h != this->ged_data_.end(); h++) {
155  if (this->ged_data_.is_shuffled_graph_copy(h->id())) {
156  continue;
157  }
158  NodeMap node_map(g->num_nodes(), h->num_nodes());
159  DMatrix lsape_instance(g->num_nodes() + 1, h->num_nodes() + 1, 0.0);
160  lsape_solver.set_problem(&lsape_instance);
161  if (this->ged_data_.shuffled_graph_copies_available() and (g->id() == h->id())) {
162  GEDGraph::GraphID id_shuffled_graph_copy{this->ged_data_.id_shuffled_graph_copy(h->id())};
163  lsape_populate_instance_(*g, this->ged_data_.graph(id_shuffled_graph_copy), lsape_instance);
164  lsape_solver.solve();
165  util::construct_node_map_from_solver(lsape_solver, node_map);
166  this->ged_data_.compute_induced_cost(*g, this->ged_data_.graph(id_shuffled_graph_copy), node_map);
167  }
168  else {
169  lsape_populate_instance_(*g, *h, lsape_instance);
170  lsape_solver.solve();
171  util::construct_node_map_from_solver(lsape_solver, node_map);
172  this->ged_data_.compute_induced_cost(*g, *h, node_map);
173  }
174  avg_ub += node_map.induced_cost();
175  progress_bar.increment();
176  std::cout << "\r" << progress_bar << std::flush;
177  }
178  }
179  if (avg_ub < best_avg_ub) {
180  best_avg_ub = avg_ub;
181  best_depth = depth_;
182  }
183  }
184  std::cout << "\n";
185  depth_ = best_depth;
186 
187  // Save the found depth.
188  if (outfile_ != "") {
189  std::map<std::string, std::string> options;
190  options["depth"] = std::to_string(depth_);
191  util::save_as_config_file(outfile_, options);
192  }
193 }
194 
195 template<class UserNodeLabel, class UserEdgeLabel>
196 void
198 lsape_populate_instance_(const GEDGraph & g, const GEDGraph & h, DMatrix & master_problem) {
199 
200  // Initialize adjacency graphs and product graph.
201  std::set<LabelID> node_labels;
202  init_node_labels_(g, h, node_labels);
203  AdjGraph_ adj_graph_g(adj_graphs_.at(g.id()));
204  AdjGraph_ adj_graph_h(adj_graphs_.at(h.id()));
205  ProductGraph_ product_graph(g, h);
206 
207  // Compute number of unmatched walks.
208  adj_graph_g.compute_num_walks_(node_labels, depth_);
209  adj_graph_h.compute_num_walks_(node_labels, depth_);
210  product_graph.compute_num_unmatched_walks_(node_labels, adj_graph_g, adj_graph_h, depth_);
211 
212  // Collect mean costs.
213  double mean_node_subs_cost{this->ged_data_.mean_node_subs_cost(g, h)};
214  double mean_edge_subs_cost{this->ged_data_.mean_edge_subs_cost(g, h)};
215  double mean_node_ins_del_cost{this->ged_data_.mean_node_ins_cost(h) * static_cast<double>(h.num_nodes())};
216  mean_node_ins_del_cost += this->ged_data_.mean_node_del_cost(g) * static_cast<double>(g.num_nodes());
217  if (g.num_nodes() + h.num_nodes() > 0) {
218  mean_node_ins_del_cost /= static_cast<double>(g.num_nodes() + h.num_nodes());
219  }
220  double mean_edge_ins_del_cost{this->ged_data_.mean_edge_ins_cost(h) * static_cast<double>(h.num_edges())};
221  mean_edge_ins_del_cost += this->ged_data_.mean_edge_del_cost(g) * static_cast<double>(g.num_edges());
222  if (g.num_edges() + h.num_edges() > 0) {
223  mean_edge_ins_del_cost /= static_cast<double>(g.num_edges() + h.num_edges());
224  }
225 
226  // Populate master problem.
227  double depth{static_cast<double>(depth_)};
228 #ifdef _OPENMP
229  omp_set_num_threads(this->num_threads_ - 1);
230 #pragma omp parallel for if(this->num_threads_ > 1)
231 #endif
232  for (std::size_t row = 0; row < master_problem.num_rows(); row++) {
233  for (std::size_t col = 0; col < master_problem.num_cols(); col++) {
234  if ((row < g.num_nodes()) and (col < h.num_nodes())) {
235  double delta_1{g.get_node_label(adj_graph_g.node(row)) == h.get_node_label(adj_graph_h.node(col)) ? 0.0 : 1.0};
236  master_problem(row,col) = product_graph.num_substituted_walks_ending_at_same_label(row, col) * ((delta_1 + depth - 1) * mean_node_subs_cost + depth * mean_edge_subs_cost);
237  master_problem(row,col) += product_graph.num_substituted_walks_ending_at_different_labels(row, col) * ((delta_1 + depth) * mean_node_subs_cost + depth * mean_edge_subs_cost);
238  master_problem(row,col) += product_graph.num_inserted_or_deleted_walks(row, col) * ((delta_1 + depth) * mean_node_ins_del_cost + depth * mean_edge_ins_del_cost);
239  }
240  else if (row < g.num_nodes()) {
241  master_problem(row, h.num_nodes()) = product_graph.num_inserted_or_deleted_walks(row, master_problem.num_cols() - 1) * ((1 + depth) * mean_node_ins_del_cost + depth * mean_edge_ins_del_cost);
242  }
243  else if (col < h.num_nodes()) {
244  master_problem(g.num_nodes(), col) = product_graph.num_inserted_or_deleted_walks(master_problem.num_rows() - 1, col) * ((1 + depth) * mean_node_ins_del_cost + depth * mean_edge_ins_del_cost);
245  }
246  }
247  }
248 }
249 
250 // === Definition of private class AdjGraph_. ===
251 template<class UserNodeLabel, class UserEdgeLabel>
254 AdjGraph_(const AdjGraph_ & adj_graph) :
255 adj_matrix_(adj_graph.adj_matrix_),
256 num_walks_from_nodes_to_labels_(adj_graph.num_walks_from_nodes_to_labels_),
257 nodes_(adj_graph.nodes_),
258 inverse_label_index_(adj_graph.inverse_label_index_){}
259 
260 template<class UserNodeLabel, class UserEdgeLabel>
263 AdjGraph_() :
264 adj_matrix_(),
265 num_walks_from_nodes_to_labels_(),
266 nodes_(),
267 inverse_label_index_() {}
268 
269 template<class UserNodeLabel, class UserEdgeLabel>
272 AdjGraph_(const GEDGraph & g) :
273 adj_matrix_(g.num_nodes(), g.num_nodes()),
274 num_walks_from_nodes_to_labels_(),
275 nodes_(),
276 inverse_label_index_() {
277  std::size_t id{0};
278  for (auto node = g.nodes().first; node != g.nodes().second; node++) {
279  nodes_[id] = *node;
280  LabelID label{g.get_node_label(*node)};
281  if (inverse_label_index_.find(label) == inverse_label_index_.end()) {
282  inverse_label_index_[label] = std::vector<std::size_t>{id++};
283  }
284  else {
285  inverse_label_index_[label].push_back(id++);
286  }
287  }
288  for (std::size_t row{0}; row < adj_matrix_.num_rows(); row++) {
289  for (std::size_t col{0}; col < adj_matrix_.num_cols(); col++) {
290  if (not g.is_edge(node(row), node(col))) {
291  adj_matrix_(row, col) = 0;
292  continue;
293  }
294  adj_matrix_(row, col) = 1;
295  }
296  }
297 }
298 
299 template<class UserNodeLabel, class UserEdgeLabel>
300 void
303 operator=(const AdjGraph_ & adj_graph) {
304  adj_matrix_ = adj_graph.adj_matrix_;
305  num_walks_from_nodes_to_labels_ = adj_graph.num_walks_from_nodes_to_labels_;
306  nodes_ = adj_graph.nodes_;
307  inverse_label_index_ = adj_graph.inverse_label_index_;
308 }
309 
310 template<class UserNodeLabel, class UserEdgeLabel>
314 node(std::size_t node_id) const {
315  return nodes_.at(node_id);
316 }
317 
318 template<class UserNodeLabel, class UserEdgeLabel>
319 std::pair<std::vector<std::size_t>::const_iterator, std::vector<std::size_t>::const_iterator>
322 nodes_with_label(LabelID label) const {
323  if (inverse_label_index_.find(label) != inverse_label_index_.end()) {
324  return std::make_pair(inverse_label_index_.at(label).cbegin(), inverse_label_index_.at(label).cend());
325  }
326  return std::make_pair(inverse_label_index_.begin()->second.cend(), inverse_label_index_.begin()->second.cend());
327 }
328 
329 template<class UserNodeLabel, class UserEdgeLabel>
330 std::size_t
333 size() const {
334  return nodes_.size();
335 }
336 
337 template<class UserNodeLabel, class UserEdgeLabel>
338 const typename Walks<UserNodeLabel, UserEdgeLabel>::Histogram_ &
341 num_walks_from_node_to_labels(std::size_t node_id) const {
342  return num_walks_from_nodes_to_labels_.at(node_id);
343 }
344 
345 template<class UserNodeLabel, class UserEdgeLabel>
346 void
349 compute_num_walks_(const std::set<LabelID> & node_labels, std::size_t depth) {
350  adj_matrix_.power(depth);
351  for (std::size_t start_node{0}; start_node < size(); start_node++) {
352  Histogram_ num_walks_from_node_to_labels;
353  for (auto label = node_labels.begin(); label != node_labels.end(); label++) {
354  num_walks_from_node_to_labels[*label] = 0.0;
355  for (auto end_node = nodes_with_label(*label).first; end_node != nodes_with_label(*label).second; end_node++) {
356  num_walks_from_node_to_labels[*label] += adj_matrix_(start_node, *end_node);
357  }
358  }
359  num_walks_from_nodes_to_labels_.push_back(num_walks_from_node_to_labels);
360  }
361 }
362 
363 template<class UserNodeLabel, class UserEdgeLabel>
364 double
367 operator() (std::size_t row, std::size_t col) const {
368  return static_cast<double>(adj_matrix_(row, col));
369 }
370 
371 // === Definition of private class ProductGraph_. ===
372 template<class UserNodeLabel, class UserEdgeLabel>
375 ProductGraph_(const GEDGraph & g, const GEDGraph & h) :
376 adj_matrix_(),
377 num_substituted_walks_ending_at_same_label_(g.num_nodes(), h.num_nodes(), 0.0),
378 num_substituted_walks_ending_at_different_labels_(g.num_nodes(), h.num_nodes(), 0.0),
379 num_inserted_or_deleted_walks_(g.num_nodes() + 1, h.num_nodes() + 1, 0.0),
380 nodes_(),
381 inverse_label_index_(),
382 product_node_to_id_() {
383  std::size_t id{0};
384  for (auto node_g = g.nodes().first; node_g != g.nodes().second; node_g++) {
385  LabelID label_g{g.get_node_label(*node_g)};
386  for (auto node_h = h.nodes().first; node_h != h.nodes().second; node_h++) {
387  LabelID label_h{h.get_node_label(*node_h)};
388  if (label_g == label_h) {
389  nodes_.push_back(std::make_pair(*node_g, *node_h));
390  if (inverse_label_index_.find(label_g) == inverse_label_index_.end()) {
391  inverse_label_index_[label_g] = std::vector<std::size_t>{id++};
392  }
393  else {
394  inverse_label_index_[label_g].push_back(id++);
395  }
396  }
397  }
398  }
399  adj_matrix_.resize(nodes_.size(), nodes_.size());
400  for (std::size_t row{0}; row < adj_matrix_.num_rows(); row++) {
401  for (std::size_t col{0}; col < adj_matrix_.num_cols(); col++) {
402  if (not g.is_edge(nodes_.at(row).first, nodes_.at(col).first)) {
403  adj_matrix_(row, col) = 0;
404  continue;
405  }
406  if (not h.is_edge(nodes_.at(row).second, nodes_.at(col).second)) {
407  adj_matrix_(row, col) = 0;
408  continue;
409  }
410  if (g.get_edge_label(g.get_edge(nodes_.at(row).first, nodes_.at(col).first)) != h.get_edge_label(h.get_edge(nodes_.at(row).second, nodes_.at(col).second))) {
411  adj_matrix_(row, col) = 0;
412  continue;
413  }
414  adj_matrix_(row, col) = 1;
415  }
416  }
417 }
418 
419 template<class UserNodeLabel, class UserEdgeLabel>
420 std::pair<std::vector<std::size_t>::const_iterator, std::vector<std::size_t>::const_iterator>
423 nodes_with_label(LabelID label) const {
424  if (inverse_label_index_.find(label) != inverse_label_index_.end()) {
425  return std::make_pair(inverse_label_index_.at(label).cbegin(), inverse_label_index_.at(label).cend());
426  }
427  return std::make_pair(inverse_label_index_.begin()->second.cend(), inverse_label_index_.begin()->second.cend());
428 }
429 
430 template<class UserNodeLabel, class UserEdgeLabel>
431 std::size_t
434 node_id(GEDGraph::NodeID node_g, GEDGraph::NodeID node_h) const {
435  ProductNode_ node{std::make_pair(node_g, node_h)};
436  if (product_node_to_id_.find(node) != product_node_to_id_.end()) {
437  return product_node_to_id_.at(node);
438  }
439  return undefined_();
440 }
441 
442 template<class UserNodeLabel, class UserEdgeLabel>
443 void
446 compute_num_unmatched_walks_(const std::set<LabelID> & node_labels, const AdjGraph_ & adj_graph_g, const AdjGraph_ & adj_graph_h, std::size_t depth) {
447  adj_matrix_.power(depth);
448  for (std::size_t start_node_g{0}; start_node_g < adj_graph_g.size(); start_node_g++) {
449  for (std::size_t start_node_h{0}; start_node_h < adj_graph_h.size(); start_node_h++) {
450 
451  // compute histograms for product graph.
452  Histogram_ num_unmatched_walks_from_node_to_labels_g(adj_graph_g.num_walks_from_node_to_labels(start_node_g));
453  Histogram_ num_unmatched_walks_from_node_to_labels_h(adj_graph_h.num_walks_from_node_to_labels(start_node_h));
454  std::size_t start_node_product{node_id(adj_graph_g.node(start_node_g), adj_graph_h.node(start_node_h))};
455  if (start_node_product != undefined_()) {
456  for (auto label = node_labels.begin(); label != node_labels.end(); label++) {
457  double num_shared_paths_from_node_to_label{0.0};
458  for (auto end_node_product = nodes_with_label(*label).first; end_node_product != nodes_with_label(*label).second; end_node_product++) {
459  num_shared_paths_from_node_to_label += static_cast<double>(adj_matrix_(start_node_product, *end_node_product));
460  }
461  num_shared_paths_from_node_to_label = std::sqrt(num_shared_paths_from_node_to_label);
462  num_shared_paths_from_node_to_label = std::min(num_shared_paths_from_node_to_label, num_unmatched_walks_from_node_to_labels_g.at(*label));
463  num_shared_paths_from_node_to_label = std::min(num_shared_paths_from_node_to_label, num_unmatched_walks_from_node_to_labels_h.at(*label));
464  num_unmatched_walks_from_node_to_labels_g[*label] -= num_shared_paths_from_node_to_label;
465  num_unmatched_walks_from_node_to_labels_h[*label] -= num_shared_paths_from_node_to_label;
466  }
467  }
468 
469  // compute subsitution costs matrices.
470  double subs_same_sum{0.0};
471  double r_row_col{0.0};
472  double r_col_row{0.0};
473  for (auto label = node_labels.begin(); label != node_labels.end(); label++) {
474  double subs_same{std::min(num_unmatched_walks_from_node_to_labels_g.at(*label), num_unmatched_walks_from_node_to_labels_h.at(*label))};
475  subs_same_sum += subs_same;
476  r_row_col += num_unmatched_walks_from_node_to_labels_g.at(*label) - subs_same;
477  r_col_row += num_unmatched_walks_from_node_to_labels_h.at(*label) - subs_same;
478  }
479  num_substituted_walks_ending_at_same_label_(start_node_g, start_node_h) = subs_same_sum;
480  num_substituted_walks_ending_at_different_labels_(start_node_g, start_node_h) = std::min(r_row_col, r_col_row);
481  num_inserted_or_deleted_walks_(start_node_g, start_node_h) = std::fabs(r_row_col - r_col_row);
482  }
483  }
484 
485  // compute deletion costs matrix.
486  for (std::size_t node_id_1{0}; node_id_1 < adj_graph_g.size(); node_id_1++) {
487  for (std::size_t node_id_2{0}; node_id_2 < adj_graph_g.size(); node_id_2++) {
488  num_inserted_or_deleted_walks_(node_id_1, adj_graph_h.size()) += adj_graph_g(node_id_1, node_id_2);
489  }
490  }
491 
492  // compute insertion cost matrix.
493  for (std::size_t node_id_1{0}; node_id_1 < adj_graph_h.size(); node_id_1++) {
494  for (std::size_t node_id_2{0}; node_id_2 < adj_graph_h.size(); node_id_2++) {
495  num_inserted_or_deleted_walks_(adj_graph_g.size(), node_id_1) += adj_graph_h(node_id_1, node_id_2);
496  }
497  }
498 }
499 
500 template<class UserNodeLabel, class UserEdgeLabel>
501 double
504 num_substituted_walks_ending_at_same_label(std::size_t row, std::size_t col) const {
505  return num_substituted_walks_ending_at_same_label_(row, col);
506 }
507 
508 template<class UserNodeLabel, class UserEdgeLabel>
509 double
512 num_substituted_walks_ending_at_different_labels(std::size_t row, std::size_t col) const {
513  return num_substituted_walks_ending_at_different_labels_(row, col);
514 }
515 
516 template<class UserNodeLabel, class UserEdgeLabel>
517 double
520 num_inserted_or_deleted_walks(std::size_t row, std::size_t col) const {
521  return num_inserted_or_deleted_walks_(row, col);
522 }
523 
524 // === Definitions of private helper member functions. ===
525 template<class UserNodeLabel, class UserEdgeLabel>
526 void
528 init_node_labels_(const GEDGraph & g, const GEDGraph & h, std::set<LabelID> & node_labels) const {
529  node_labels.clear();
530  for (auto node_g = g.nodes().first; node_g != g.nodes().second; node_g++) {
531  node_labels.insert(g.get_node_label(*node_g));
532  }
533  for (auto node_h = h.nodes().first; node_h != h.nodes().second; node_h++) {
534  node_labels.insert(h.get_node_label(*node_h));
535  }
536 }
537 
538 template<class UserNodeLabel, class UserEdgeLabel>
539 bool
541 load_config_file_() const {
542  return (infile_ != "");
543 }
544 
545 }
546 
547 #endif /* SRC_METHODS_WALKS_IPP_ */
void set_model(const Model &model)
Makes the solver use a specific model for optimal solving.
std::size_t num_nodes() const
Returns the number of nodes.
Definition: ged_graph.ipp:211
std::size_t num_threads_
The number of threads to be used.
This class solves LSAPE instances by calling the library lsape available at https://bougleux.users.greyc.fr/lsape/.
virtual void lsape_init_graph_(const GEDGraph &graph) final
Initializes global variables for one graph.
Definition: walks.ipp:112
A class for node maps.
Definition: node_map.hpp:43
virtual void lsape_set_default_options_() final
Sets all options that are not among the ones shared by all derived classes of ged::LSAPEBasedMethod t...
Definition: walks.ipp:54
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
EdgeID get_edge(NodeID tail, NodeID head) const
Retrieves an edge from its incident nodes.
Definition: ged_graph.ipp:241
const GEDData< UserNodeLabel, UserEdgeLabel > & ged_data_
The data on which the method is run.
Definition: ged_method.hpp:124
virtual void lsape_init_() final
Initializes the method after initializing the global variables for the graphs.
Definition: walks.ipp:133
bool is_edge(NodeID tail, NodeID head) const
Checks if an edge exists.
Definition: ged_graph.ipp:262
void solve(int num_solutions=1)
Solves the LSAPE problem instance.
virtual void lsape_populate_instance_(const GEDGraph &g, const GEDGraph &h, DMatrix &master_problem) final
Populates the LSAPE instance.
Definition: walks.ipp:198
std::size_t num_cols() const
Returns the number of columns.
Definition: matrix.ipp:110
std::size_t LabelID
Internally used type of node and edge labels.
LabelID get_node_label(NodeID node) const
Returns the label of a given node.
Definition: ged_graph.ipp:126
std::size_t num_edges() const
Returns the number of edges.
Definition: ged_graph.ipp:223
Runtime error class.
Definition: error.hpp:37
void parse_config_file(const std::string &filename, std::map< std::string, std::string > &options)
Parses a configuration file.
Definition: misc.ipp:49
bool compute_lower_bound_
Flag that should be set to true if and only if the method computes a lower bound. ...
LSAPESolver::Model lsape_model_
Specifies model for optimal LSAPE solver.
LabelID get_edge_label(EdgeID edge) const
Returns the label of a given edge.
Definition: ged_graph.ipp:135
A progress bar class.
std::pair< node_iterator, node_iterator > nodes() const
Provides access to all nodes in the graph.
Definition: ged_graph.ipp:205
The normalized input graphs used by GEDLIB. All labels are integers.
Definition: ged_graph.hpp:104
virtual void lsape_pre_graph_init_(bool called_at_runtime) final
Initializes the method at runtime or during initialization before initializing the global variables f...
Definition: walks.ipp:119
Global namespace for GEDLIB.
void increment()
Increments the number of solved tasks.
virtual std::string lsape_valid_options_string_() const final
Returns string of all valid options that are not among the ones shared by all derived classes of ged:...
Definition: walks.ipp:65
void save_as_config_file(const std::string &filename, const std::map< std::string, std::string > &options)
Saves a string map as a configuration file as expected by parse_config_file().
Definition: misc.ipp:76
void construct_node_map_from_solver(const Solver &solver, NodeMap &node_map, std::size_t solution_id=0)
Constructs a node map from a solution to LSAPE or LSAPE stored in a ged::LSAPESolver or a ged::LSAPSo...
Definition: misc.ipp:86
void set_problem(const DMatrix *cost_matrix)
Sets the LSAPE problem instance.
std::size_t NodeID
Internally used vertex ID type.
Definition: ged_graph.hpp:108
GraphID id() const
Returns the ID of the graph.
Definition: ged_graph.ipp:184
std::size_t num_rows() const
Returns the number of rows.
Definition: matrix.ipp:85
virtual bool lsape_parse_option_(const std::string &option, const std::string &arg) final
Parses one option that is not among the ones shared by all derived classes of ged::LSAPEBasedMethod.
Definition: walks.ipp:72