GEDLIB  1.0
branch_uniform.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_UNIFORM_IPP_
28 #define SRC_METHODS_BRANCH_UNIFORM_IPP_
29 
30 namespace ged {
31 
32 // === Definitions of destructor and constructor. ===
33 template<class UserNodeLabel, class UserEdgeLabel>
34 BranchUniform<UserNodeLabel, UserEdgeLabel>::
35 ~BranchUniform() {}
36 
37 template<class UserNodeLabel, class UserEdgeLabel>
38 BranchUniform<UserNodeLabel, UserEdgeLabel>::
39 BranchUniform(const GEDData<UserNodeLabel, UserEdgeLabel> & ged_data) :
40 LSAPEBasedMethod<UserNodeLabel, UserEdgeLabel>(ged_data),
41 sort_method_{COUNTING},
42 wildcard_option_{false},
43 sorted_edge_labels_() {}
44 
45 // === Definitions of member functions inherited from LSAPEBasedMethod. ===
46 template<class UserNodeLabel, class UserEdgeLabel>
47 void
49 lsape_init_graph_(const GEDGraph & graph) {
50  sorted_edge_labels_[graph.id()] = SortedEdgeLabels_(graph, sort_method_);
51 }
52 
53 template<class UserNodeLabel, class UserEdgeLabel>
54 void
56 lsape_populate_instance_(const GEDGraph & g, const GEDGraph & h, DMatrix & master_problem) {
57 
58  const SortedEdgeLabels_ & sorted_edge_labels_g = sorted_edge_labels_.at(g.id());
59  const SortedEdgeLabels_ & sorted_edge_labels_h = sorted_edge_labels_.at(h.id());
60  double min_edge_subs_cost{this->ged_data_.min_edge_subs_cost(g, h)};
61  double min_edge_del_cost{this->ged_data_.min_edge_del_cost(g)};
62  double min_edge_ins_cost{this->ged_data_.min_edge_ins_cost(h)};
63 
64 #ifdef _OPENMP
65  omp_set_num_threads(this->num_threads_ - 1);
66 #pragma omp parallel for if(this->num_threads_ > 1)
67 #endif
68  for (std::size_t row_in_master = 0; row_in_master < master_problem.num_rows(); row_in_master++) {
69  for (std::size_t col_in_master = 0; col_in_master < master_problem.num_cols(); col_in_master++) {
70  if ((row_in_master < g.num_nodes()) and (col_in_master < h.num_nodes())) {
71  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, min_edge_subs_cost, min_edge_del_cost, min_edge_ins_cost);
72  }
73  else if (row_in_master < g.num_nodes()) {
74  master_problem(row_in_master, h.num_nodes()) = compute_deletion_cost_(g, row_in_master, min_edge_del_cost);
75  }
76  else if (col_in_master < h.num_nodes()) {
77  master_problem(g.num_nodes(), col_in_master) = compute_insertion_cost_(h, col_in_master, min_edge_ins_cost);
78  }
79  }
80  }
81 }
82 
83 template<class UserNodeLabel, class UserEdgeLabel>
84 void
87  sort_method_ = COUNTING;
88  wildcard_option_ = false;
89 }
90 
91 template<class UserNodeLabel, class UserEdgeLabel>
92 std::string
95  return "[--sort-method <arg>] [--wildcards <arg>]";
96 }
97 
98 template<class UserNodeLabel, class UserEdgeLabel>
99 bool
101 lsape_parse_option_(const std::string & option, const std::string & arg) {
102  if (option == "sort-method") {
103  if (arg == "STD") {
104  sort_method_ = STD;
105  }
106  else if (arg == "COUNTING") {
107  sort_method_ = COUNTING;
108  }
109  else {
110  throw Error(std::string("Invalid argument \"") + arg + "\" for option upper-bound. Usage: options = \"[--sort-method STD|COUNTING] [...]\"");
111  }
112  return true;
113  }
114  else if (option == "wildcards") {
115  if (arg == "NO") {
116  wildcard_option_ = false;
117  }
118  else if (arg == "YES") {
119  wildcard_option_ = true;
120  }
121  else {
122  throw Error(std::string("Invalid argument \"") + arg + "\" for option wildcards. Usage: options = \"[--wildcards YES|NO] [...]\"");
123  }
124  return true;
125  }
126  return false;
127 }
128 
129 // === Definition of private class SortedUserEdgeLabels_. ===
130 template<class UserNodeLabel, class UserEdgeLabel>
133 SortedEdgeLabels_(const GEDGraph & g, SortMethod_ sort_method):
134 sorted_edge_labels_(){
135  for (auto node = g.nodes().first; node != g.nodes().second; node++) {
136  sorted_edge_labels_[*node] = std::vector<LabelID>();
137  for (auto edge = g.incident_edges(*node).first; edge != g.incident_edges(*node).second; edge++) {
138  sorted_edge_labels_[*node].push_back(g.get_edge_label(*edge));
139  }
140  switch (sort_method) {
141  case STD:
142  std::sort(sorted_edge_labels_[*node].begin(), sorted_edge_labels_[*node].end());
143  break;
144  default:
145  util::counting_sort(sorted_edge_labels_[*node].begin(), sorted_edge_labels_[*node].end());
146  break;
147  }
148  }
149 }
150 
151 template<class UserNodeLabel, class UserEdgeLabel>
155 sorted_edge_labels_() {}
156 
157 template<class UserNodeLabel, class UserEdgeLabel>
158 void
161 operator=(const SortedEdgeLabels_ & sorted_edge_labels) {
162  sorted_edge_labels_ = sorted_edge_labels.sorted_edge_labels_;
163 }
164 
165 template<class UserNodeLabel, class UserEdgeLabel>
166 const std::vector<LabelID> &
170  return sorted_edge_labels_.at(node);
171 }
172 
173 // === Definitions of private helper member functions. ===
174 template<class UserNodeLabel, class UserEdgeLabel>
175 double
178  const SortedEdgeLabels_ & sorted_edge_labels_g, const SortedEdgeLabels_ & sorted_edge_labels_h,
179  double min_edge_subs_cost, double min_edge_del_cost, double min_edge_ins_cost) const {
180 
181  double cost{0.0};
182 
183  // Collect node substitution cost.
184  if ((not wildcard_option_) or (h.get_node_label(k) != dummy_label())) {
185  cost += this->ged_data_.node_cost(g.get_node_label(i), h.get_node_label(k));
186  }
187 
188  // Determine the number of wildcard edges.
189  std::size_t num_incident_wildard_edges{0};
190  if (wildcard_option_) {
191  for (auto label_h : sorted_edge_labels_h.get_incident_labels(k)) {
192  if (label_h == dummy_label()) {
193  num_incident_wildard_edges++;
194  }
195  }
196  }
197 
198  // Compute the size of the multiset intersection.
199  std::size_t intersection_size{0};
200  auto label_g = sorted_edge_labels_g.get_incident_labels(i).begin();
201  auto label_h = sorted_edge_labels_h.get_incident_labels(k).begin();
202  while ((label_g != sorted_edge_labels_g.get_incident_labels(i).end()) and (label_h != sorted_edge_labels_h.get_incident_labels(k).end())) {
203  if (*label_g == *label_h) {
204  intersection_size++;
205  label_g++;
206  label_h++;
207  }
208  else if (*label_g < *label_h) {
209  label_g++;
210  }
211  else {
212  label_h++;
213  }
214  }
215 
216  // Add edge deletion costs.
217  if (g.degree(i) > h.degree(k)) {
218  cost += static_cast<double>(g.degree(i) - h.degree(k)) * min_edge_del_cost * 0.5;
219  }
220 
221  // Add edge insertion costs.
222  if (g.degree(i) < h.degree(k)) {
223  std::size_t num_inserted_edges{h.degree(k) - g.degree(i)};
224  // Use as many wildcard edges as possible for insertion, if insertion is at least as expensive as substitution.
225  if (wildcard_option_) {
226  if (min_edge_ins_cost >= min_edge_subs_cost) {
227  if (num_inserted_edges >= num_incident_wildard_edges) {
228  num_inserted_edges -= num_incident_wildard_edges;
229  num_incident_wildard_edges = 0;
230  }
231  else {
232  num_incident_wildard_edges -= num_inserted_edges;
233  num_inserted_edges = 0;
234  }
235  }
236  else {
237  std::size_t num_substituted_edges{g.degree(i) - intersection_size};
238  // Use all wildcard edges for insertion that are not needed for substitution.
239  if (num_substituted_edges < num_incident_wildard_edges) {
240  num_inserted_edges -= (num_incident_wildard_edges - num_substituted_edges);
241  num_incident_wildard_edges = num_substituted_edges;
242  }
243  }
244  }
245  cost += static_cast<double>(num_inserted_edges) * min_edge_ins_cost * 0.5;
246  }
247 
248 
249  // Add edge substitution costs.
250  cost += static_cast<double>(std::min(g.degree(i), h.degree(k)) - intersection_size - num_incident_wildard_edges) * 0.5 * min_edge_subs_cost;
251 
252  // Return the overall substitution cost.
253  return cost;
254 }
255 
256 template<class UserNodeLabel, class UserEdgeLabel>
257 double
259 compute_deletion_cost_(const GEDGraph & g, GEDGraph::NodeID i, double min_edge_del_cost) const {
260  // Collect node deletion cost.
261  double cost{this->ged_data_.node_cost(g.get_node_label(i), dummy_label())};
262 
263  // Collect edge deletion cost.
264  cost += static_cast<double>(g.degree(i)) * 0.5 * min_edge_del_cost;
265 
266  // Return overall deletion cost.
267  return cost;
268 }
269 
270 template<class UserNodeLabel, class UserEdgeLabel>
271 double
273 compute_insertion_cost_(const GEDGraph & h, GEDGraph::NodeID k, double min_edge_ins_cost) const {
274  // Collect node insertion cost.
275  double cost{this->ged_data_.node_cost(dummy_label(), h.get_node_label(k))};
276 
277  // Collect edge insertion cost.
278  std::size_t num_incident_wildard_edges{0};
279  if (wildcard_option_) {
280  for (auto kl = h.incident_edges(k).first; kl != h.incident_edges(k).second; kl++) {
281  if (h.get_edge_label(*kl) == dummy_label()) {
282  num_incident_wildard_edges++;
283  }
284  }
285  }
286  cost += static_cast<double>(h.degree(k) - num_incident_wildard_edges) * 0.5 * min_edge_ins_cost;
287 
288  // Return overall insertion cost.
289  return cost;
290 }
291 
292 }
293 
294 #endif /* SRC_METHODS_BRANCH_UNIFORM_IPP_ */
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
std::size_t degree(NodeID node) const
Returns node degree.
Definition: ged_graph.ipp:162
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...
virtual void lsape_init_graph_(const GEDGraph &graph) final
Initializes global variables for one graph.
std::size_t num_cols() const
Returns the number of columns.
Definition: matrix.ipp:110
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
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
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:...
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.
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_populate_instance_(const GEDGraph &g, const GEDGraph &h, DMatrix &master_problem) final
Populates the LSAPE instance.
Global namespace for GEDLIB.
Computes lower and upper bounds for uniform edit costs.
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