GEDLIB  1.0
branch_fast.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_BRANCH_FAST_IPP_
28 #define SRC_METHODS_BRANCH_FAST_IPP_
29 
30 namespace ged {
31 
32 // === Definitions of destructor and constructor. ===
33 template<class UserNodeLabel, class UserEdgeLabel>
34 BranchFast<UserNodeLabel, UserEdgeLabel>::
35 ~BranchFast() {}
36 
37 template<class UserNodeLabel, class UserEdgeLabel>
38 BranchFast<UserNodeLabel, UserEdgeLabel>::
39 BranchFast(const GEDData<UserNodeLabel, UserEdgeLabel> & ged_data) :
40 LSAPEBasedMethod<UserNodeLabel, UserEdgeLabel>(ged_data),
41 sort_method_{COUNTING},
42 sorted_edge_labels_() {}
43 
44 // === Definitions of member functions inherited from LSAPEBasedMethod. ===
45 template<class UserNodeLabel, class UserEdgeLabel>
46 void
48 lsape_init_graph_(const GEDGraph & graph) {
49  sorted_edge_labels_[graph.id()] = SortedEdgeLabels_(graph, sort_method_);
50 }
51 
52 template<class UserNodeLabel, class UserEdgeLabel>
53 void
56  sort_method_= COUNTING;
57 }
58 
59 template<class UserNodeLabel, class UserEdgeLabel>
60 std::string
63  return "[--sort-method <arg>]";
64 }
65 
66 template<class UserNodeLabel, class UserEdgeLabel>
67 bool
69 lsape_parse_option_(const std::string & option, const std::string & arg) {
70  if (option == "sort-method") {
71  if (arg == "STD") {
72  sort_method_ = STD;
73  }
74  else if (arg == "COUNTING") {
75  sort_method_ = COUNTING;
76  }
77  else {
78  throw Error(std::string("Invalid argument \"") + arg + "\" for option upper-bound. Usage: options = \"[--sort-method STD|COUNTING] [...]\"");
79  }
80  return true;
81  }
82  return false;
83 }
84 
85 template<class UserNodeLabel, class UserEdgeLabel>
86 void
88 lsape_populate_instance_(const GEDGraph & g, const GEDGraph & h, DMatrix & master_problem) {
89 
90  const SortedEdgeLabels_ & sorted_edge_labels_g = sorted_edge_labels_.at(g.id());
91  const SortedEdgeLabels_ & sorted_edge_labels_h = sorted_edge_labels_.at(h.id());
92 
93 #ifdef _OPENMP
94  omp_set_num_threads(this->num_threads_ - 1);
95 #pragma omp parallel for if(this->num_threads_ > 1)
96 #endif
97  for (std::size_t row_in_master = 0; row_in_master < master_problem.num_rows(); row_in_master++) {
98  for (std::size_t col_in_master = 0; col_in_master < master_problem.num_cols(); col_in_master++) {
99  if ((row_in_master < g.num_nodes()) and (col_in_master < h.num_nodes())) {
100  master_problem(row_in_master, col_in_master) = compute_substitution_cost_(g, h, row_in_master, col_in_master, sorted_edge_labels_g, sorted_edge_labels_h);
101  }
102  else if (row_in_master < g.num_nodes()) {
103  master_problem(row_in_master, h.num_nodes()) = compute_deletion_cost_(g, row_in_master);
104  }
105  else if (col_in_master < h.num_nodes()) {
106  master_problem(g.num_nodes(), col_in_master) = compute_insertion_cost_(h, col_in_master);
107  }
108  }
109  }
110 
111 }
112 
113 // === Definition of private class SortedUserEdgeLabels_. ===
114 template<class UserNodeLabel, class UserEdgeLabel>
117 SortedEdgeLabels_(const GEDGraph & g, SortMethod_ sort_method) :
118 sorted_edge_labels_() {
119  for (auto node = g.nodes().first; node != g.nodes().second; node++) {
120  sorted_edge_labels_[*node] = std::vector<LabelID>();
121  for (auto edge = g.incident_edges(*node).first; edge != g.incident_edges(*node).second; edge++) {
122  sorted_edge_labels_[*node].push_back(g.get_edge_label(*edge));
123  }
124  switch (sort_method) {
125  case STD:
126  std::sort(sorted_edge_labels_[*node].begin(), sorted_edge_labels_[*node].end());
127  break;
128  default:
129  util::counting_sort(sorted_edge_labels_[*node].begin(), sorted_edge_labels_[*node].end());
130  break;
131  }
132  }
133 }
134 
135 template<class UserNodeLabel, class UserEdgeLabel>
139 sorted_edge_labels_() {}
140 
141 template<class UserNodeLabel, class UserEdgeLabel>
142 void
145 operator=(const SortedEdgeLabels_ & sorted_edge_labels) {
146  sorted_edge_labels_ = sorted_edge_labels.sorted_edge_labels_;
147 }
148 
149 template<class UserNodeLabel, class UserEdgeLabel>
150 const std::vector<LabelID> &
154  return sorted_edge_labels_.at(node);
155 }
156 
157 // === Definition of private helper functions. ===
158 template<class UserNodeLabel, class UserEdgeLabel>
159 double
162  const SortedEdgeLabels_ & sorted_edge_labels_g, const SortedEdgeLabels_ & sorted_edge_labels_h) const {
163  // Collect node substitution cost.
164  double cost{this->ged_data_.node_cost(g.get_node_label(i), h.get_node_label(k))};
165 
166  // Compute and add minimal edge insertion costs.
167  if (g.degree(i) < h.degree(k)) {
168  double min_edge_ins_cost{std::numeric_limits<double>::infinity()};
169  for (auto label_h = sorted_edge_labels_h.get_incident_labels(k).begin(); label_h != sorted_edge_labels_h.get_incident_labels(k).end(); label_h++) {
170  min_edge_ins_cost = std::min(min_edge_ins_cost, this->ged_data_.edge_cost(dummy_label(), *label_h));
171  }
172  cost += static_cast<double>(h.degree(k) - g.degree(i)) * min_edge_ins_cost * 0.5;
173  }
174 
175  // Compute and add minimal edge deletion costs.
176  if (g.degree(i) > h.degree(k)) {
177  double min_edge_del_cost{std::numeric_limits<double>::infinity()};
178  for (auto label_g = sorted_edge_labels_g.get_incident_labels(i).begin(); label_g != sorted_edge_labels_g.get_incident_labels(i).end(); label_g++) {
179  min_edge_del_cost = std::min(min_edge_del_cost, this->ged_data_.edge_cost(*label_g, dummy_label()));
180  }
181  cost += static_cast<double>(g.degree(i) - h.degree(k)) * min_edge_del_cost * 0.5;
182  }
183 
184  // Compute minimal edge relabelling costs.
185  double min_edge_subs_cost{std::numeric_limits<double>::infinity()};
186  for (auto label_g = sorted_edge_labels_g.get_incident_labels(i).begin(); label_g != sorted_edge_labels_g.get_incident_labels(i).end(); label_g++) {
187  for (auto label_h = sorted_edge_labels_h.get_incident_labels(k).begin(); label_h != sorted_edge_labels_h.get_incident_labels(k).end(); label_h++) {
188  if (*label_g != *label_h) {
189  min_edge_subs_cost = std::min(min_edge_subs_cost, this->ged_data_.edge_cost(*label_g, *label_h));
190  }
191  }
192  }
193 
194  // Compute multiset intersection size.
195  std::size_t intersection_size{0};
196  auto label_g = sorted_edge_labels_g.get_incident_labels(i).begin();
197  auto label_h = sorted_edge_labels_h.get_incident_labels(k).begin();
198  while ((label_g != sorted_edge_labels_g.get_incident_labels(i).end()) and (label_h != sorted_edge_labels_h.get_incident_labels(k).end())) {
199  if (*label_g == *label_h) {
200  intersection_size++;
201  label_g++;
202  label_h++;
203  }
204  else if (*label_g < *label_h) {
205  label_g++;
206  }
207  else {
208  label_h++;
209  }
210  }
211 
212  // Collect edge relabelling costs.
213  if (std::min(g.degree(i), h.degree(k)) - intersection_size > 0) {
214  cost += static_cast<double>(std::min(g.degree(i), h.degree(k)) - intersection_size) * min_edge_subs_cost * 0.5;
215  }
216 
217  // Return overall substitution cost.
218  return cost;
219 }
220 
221 template<class UserNodeLabel, class UserEdgeLabel>
222 double
225  // Collect node deletion cost.
226  double cost{this->ged_data_.node_cost(g.get_node_label(i), ged::dummy_label())};
227 
228  // Collect edge deletion costs.
229  auto incident_edges_i = g.incident_edges(i);
230  for (auto ij = incident_edges_i.first; ij != incident_edges_i.second; ij++) {
231  cost += this->ged_data_.edge_cost(g.get_edge_label(*ij), ged::dummy_label()) * 0.5;
232  }
233 
234  // Return overall deletion cost.
235  return cost;
236 }
237 
238 template<class UserNodeLabel, class UserEdgeLabel>
239 double
242  // Collect node insertion cost.
243  double cost{this->ged_data_.node_cost(ged::dummy_label(), h.get_node_label(k))};
244 
245  // Collect edge insertion costs.
246  auto incident_edges_k = h.incident_edges(k);
247  for (auto kl = incident_edges_k.first; kl != incident_edges_k.second; kl++) {
248  cost += this->ged_data_.edge_cost(ged::dummy_label(), h.get_edge_label(*kl)) * 0.5;
249  }
250 
251  // Return overall insertion cost.
252  return cost;
253 }
254 
255 }
256 
257 #endif /* SRC_METHODS_BRANCH_FAST_IPP_ */
virtual void lsape_populate_instance_(const GEDGraph &g, const GEDGraph &h, DMatrix &master_problem) final
Populates the LSAPE instance.
Definition: branch_fast.ipp:88
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.
const GEDData< UserNodeLabel, UserEdgeLabel > & ged_data_
The data on which the method is run.
Definition: ged_method.hpp:124
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: branch_fast.ipp:55
std::size_t degree(NodeID node) const
Returns node degree.
Definition: ged_graph.ipp:162
std::size_t num_cols() const
Returns the number of columns.
Definition: matrix.ipp:110
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: branch_fast.ipp:62
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: branch_fast.ipp:69
void counting_sort(std::vector< LabelID >::iterator first, std::vector< LabelID >::iterator last)
Implementation of counting sort.
Definition: misc.ipp:111
LabelID get_node_label(NodeID node) const
Returns the label of a given node.
Definition: ged_graph.ipp:126
Runtime error class.
Definition: error.hpp:37
LabelID get_edge_label(EdgeID edge) const
Returns the label of a given edge.
Definition: ged_graph.ipp:135
Computes lower and upper bounds for general edit costs.
Definition: branch_fast.hpp:45
std::pair< incident_edge_iterator, incident_edge_iterator > incident_edges(NodeID node) const
Provides access to all incident edges of a node.
Definition: ged_graph.ipp:150
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
constexpr LabelID dummy_label()
Returns a dummy label.
virtual void lsape_init_graph_(const GEDGraph &graph) final
Initializes global variables for one graph.
Definition: branch_fast.ipp:48
Global namespace for GEDLIB.
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