GEDLIB  1.0
partition.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_PARTITION_IPP_
28 #define SRC_METHODS_PARTITION_IPP_
29 
30 namespace ged {
31 
32 // === Definitions of destructor and constructor. ===
33 template<class UserNodeLabel, class UserEdgeLabel>
34 Partition<UserNodeLabel, UserEdgeLabel>::
35 ~Partition() {}
36 
37 template<class UserNodeLabel, class UserEdgeLabel>
38 Partition<UserNodeLabel, UserEdgeLabel>::
39 Partition(const GEDData<UserNodeLabel, UserEdgeLabel> & ged_data) :
40 GEDMethod<UserNodeLabel, UserEdgeLabel>(ged_data),
41 substruct_maps_(),
42 unmatched_substructs_() {}
43 
44 // === Definitions of member functions inherited from GEDMethod. ===
45 template<class UserNodeLabel, class UserEdgeLabel>
46 void
49  for (auto graph = this->ged_data_.begin(); graph != this->ged_data_.end(); graph++) {
50  init_graph_(*graph);
51  }
52 }
53 
54 template<class UserNodeLabel, class UserEdgeLabel>
55 void
57 ged_run_(const GEDGraph & g, const GEDGraph & h, Result & result) {
58 
59  unmatched_substructs_.clear();
60  init_graphs_(g, h);
61 
62  SubstructMap_ & is_substruct_in_g = substruct_maps_.at(g.id());
63  unmatched_substructs_.clear();
64 
65  std::map<GEDGraph::NodeID, bool> is_deleted_node;
66  for (auto node_1 = h.nodes().first; node_1 != h.nodes().second; node_1++) {
67  is_deleted_node[*node_1] = false;
68  }
69  std::map<GEDGraph::EdgeID, bool> is_deleted_edge;
70  for (auto edge_1 = h.edges().first; edge_1 != h.edges().second; edge_1++) {
71  is_deleted_edge[*edge_1] = false;
72  }
73 
74  check_node_subtructs_(h, is_substruct_in_g, is_deleted_node);
75  check_edge_subtructs_(h, is_substruct_in_g, is_deleted_edge);
76  check_node_edge_subtructs_(h, is_substruct_in_g, is_deleted_node, is_deleted_edge);
77  check_node_edge_node_subtructs_(h, is_substruct_in_g, is_deleted_node, is_deleted_edge);
78  check_node_edge_edge_subtructs_(h, is_substruct_in_g, is_deleted_node, is_deleted_edge);
79 
80  result.set_lower_bound(static_cast<double>(unmatched_substructs_.size()) * this->ged_data_.min_edit_cost(g, h));
81 }
82 
83 // === Definitions of private helper member functions. ===
84 template<class UserNodeLabel, class UserEdgeLabel>
85 void
87 init_graph_(const GEDGraph & graph) {
88  substruct_maps_[graph.id()] = SubstructMap_();
89  SubstructMap_ & is_substruct = substruct_maps_.at(graph.id());
90  for (LabelID edge_label_1{1}; edge_label_1 < this->ged_data_.num_edge_labels(); edge_label_1++) {
91  Substruct_ edge_substruct(EDGE, edge_label_1);
92  is_substruct[edge_substruct] = contains_substruct_(graph, edge_substruct);
93  }
94  for (LabelID node_label_1{1}; node_label_1 < this->ged_data_.num_node_labels(); node_label_1++) {
95  Substruct_ node_substruct(NODE, node_label_1);
96  bool contains_node_substruct{contains_substruct_(graph, node_substruct)};
97  is_substruct[node_substruct] = contains_node_substruct;
98  for (LabelID edge_label_1{1}; edge_label_1 < this->ged_data_.num_edge_labels(); edge_label_1++) {
99  Substruct_ node_edge_substruct(NODE_EDGE, node_label_1, edge_label_1);
100  bool contains_node_edge_substruct{false};
101  if (contains_node_substruct) {
102  contains_node_edge_substruct = contains_substruct_(graph, node_edge_substruct);
103  is_substruct[node_edge_substruct] = contains_node_edge_substruct;
104  }
105  else {
106  is_substruct[node_edge_substruct] = false;
107  }
108  for (LabelID node_label_2{1}; node_label_2 < this->ged_data_.num_node_labels(); node_label_2++) {
109  Substruct_ node_edge_node_substruct(NODE_EDGE_NODE, node_label_1, edge_label_1, node_label_2);
110  if (contains_node_edge_substruct) {
111  is_substruct[node_edge_node_substruct] = contains_substruct_(graph, node_edge_node_substruct);
112  }
113  else {
114  is_substruct[node_edge_node_substruct] = false;
115  }
116  }
117  for (LabelID edge_label_2{1}; edge_label_2 < this->ged_data_.num_edge_labels(); edge_label_2++) {
118  Substruct_ node_edge_edge_substruct(NODE_EDGE_EDGE, node_label_1, edge_label_1, edge_label_2);
119  if (contains_node_edge_substruct) {
120  is_substruct[node_edge_edge_substruct] = contains_substruct_(graph, node_edge_edge_substruct);
121  }
122  else {
123  is_substruct[node_edge_edge_substruct] = false;
124  }
125  }
126  }
127  }
128 }
129 
130 template<class UserNodeLabel, class UserEdgeLabel>
131 void
133 init_graphs_(const GEDGraph & g, const GEDGraph & h) {
134 
135  std::vector<LabelID> node_labels_h;
136  for (auto node = h.nodes().first; node != h.nodes().second; node++) {
137  node_labels_h.push_back(h.get_node_label(*node));
138  }
139 
140  std::vector<LabelID> edge_labels_h;
141  for (auto edge = h.edges().first; edge != h.edges().second; edge++) {
142  edge_labels_h.push_back(h.get_edge_label(*edge));
143  }
144 
145  substruct_maps_[g.id()] = SubstructMap_();
146  SubstructMap_ & is_substruct = substruct_maps_.at(g.id());
147  for (LabelID edge_label_1 : edge_labels_h) {
148  Substruct_ edge_substruct(EDGE, edge_label_1);
149  is_substruct[edge_substruct] = contains_substruct_(g, edge_substruct);
150  }
151  for (LabelID node_label_1 : node_labels_h) {
152  Substruct_ node_substruct(NODE, node_label_1);
153  bool contains_node_substruct{contains_substruct_(g, node_substruct)};
154  is_substruct[node_substruct] = contains_node_substruct;
155  for (LabelID edge_label_1 : edge_labels_h) {
156  Substruct_ node_edge_substruct(NODE_EDGE, node_label_1, edge_label_1);
157  bool contains_node_edge_substruct{false};
158  if (contains_node_substruct) {
159  contains_node_edge_substruct = contains_substruct_(g, node_edge_substruct);
160  is_substruct[node_edge_substruct] = contains_node_edge_substruct;
161  }
162  else {
163  is_substruct[node_edge_substruct] = false;
164  }
165  for (LabelID node_label_2 : node_labels_h) {
166  Substruct_ node_edge_node_substruct(NODE_EDGE_NODE, node_label_1, edge_label_1, node_label_2);
167  if (contains_node_edge_substruct) {
168  is_substruct[node_edge_node_substruct] = contains_substruct_(g, node_edge_node_substruct);
169  }
170  else {
171  is_substruct[node_edge_node_substruct] = false;
172  }
173  }
174  for (LabelID edge_label_2 : edge_labels_h) {
175  Substruct_ node_edge_edge_substruct(NODE_EDGE_EDGE, node_label_1, edge_label_1, edge_label_2);
176  if (contains_node_edge_substruct) {
177  is_substruct[node_edge_edge_substruct] = contains_substruct_(g, node_edge_edge_substruct);
178  }
179  else {
180  is_substruct[node_edge_edge_substruct] = false;
181  }
182  }
183  }
184  }
185 }
186 
187 template<class UserNodeLabel, class UserEdgeLabel>
188 bool
190 contains_substruct_(const GEDGraph & g, const Substruct_ & substruct) const {
191  switch (substruct.type) {
192  case NODE:
193  return contains_node_substruct_(g, substruct);
194  case EDGE:
195  return contains_edge_substruct_(g, substruct);
196  case NODE_EDGE:
197  return contains_node_edge_substruct_(g, substruct);
198  case NODE_EDGE_NODE:
199  return contains_node_edge_node_substruct_(g, substruct);
200  case NODE_EDGE_EDGE:
201  return contains_node_edge_edge_substruct_(g, substruct);
202  }
203  return false;
204 }
205 
206 template<class UserNodeLabel, class UserEdgeLabel>
207 void
209 check_node_subtructs_(const GEDGraph & h, const SubstructMap_ & is_substruct_in_g, std::map<GEDGraph::NodeID, bool> & is_deleted_node) {
210  for (auto node_1 = h.nodes().first; node_1 != h.nodes().second; node_1++) {
211  Substruct_ node_substruct(NODE, h.get_node_label(*node_1), dummy_label(), dummy_label(), *node_1);
212  if (not is_substruct_in_g.at(node_substruct)) {
213  unmatched_substructs_.push_back(node_substruct);
214  is_deleted_node.at(*node_1) = true;
215  }
216  }
217 }
218 
219 template<class UserNodeLabel, class UserEdgeLabel>
220 bool
222 contains_node_substruct_(const GEDGraph & g, const Substruct_ & substruct) const {
223  for (auto node_1 = g.nodes().first; node_1 != g.nodes().second; node_1++) {
224  if (g.get_node_label(*node_1) == substruct.node_label_1) {
225  return true;
226  }
227  }
228  return false;
229 }
230 
231 template<class UserNodeLabel, class UserEdgeLabel>
232 void
234 check_edge_subtructs_(const GEDGraph & h, const SubstructMap_ & is_substruct_in_g, std::map<GEDGraph::EdgeID, bool> & is_deleted_edge) {
235  for (auto edge_1 = h.edges().first; edge_1 != h.edges().second; edge_1++) {
236  Substruct_ edge_substruct(EDGE, h.get_edge_label(*edge_1), dummy_label(), dummy_label(), GEDGraph::dummy_node(), *edge_1);
237  if (not is_substruct_in_g.at(edge_substruct)) {
238  unmatched_substructs_.push_back(edge_substruct);
239  is_deleted_edge.at(*edge_1) = true;
240  }
241  }
242 }
243 
244 template<class UserNodeLabel, class UserEdgeLabel>
245 bool
247 contains_edge_substruct_(const GEDGraph & g, const Substruct_ & substruct) const {
248  for (auto edge_1 = g.edges().first; edge_1 != g.edges().second; edge_1++) {
249  if (g.get_edge_label(*edge_1) == substruct.edge_label_1) {
250  return true;
251  }
252  }
253  return false;
254 }
255 
256 template<class UserNodeLabel, class UserEdgeLabel>
257 void
259 check_node_edge_subtructs_(const GEDGraph & h, const SubstructMap_ & is_substruct_in_g, std::map<GEDGraph::NodeID, bool> & is_deleted_node, std::map<GEDGraph::EdgeID, bool> & is_deleted_edge) {
260  for (auto node_1 = h.nodes().first; node_1 != h.nodes().second; node_1++) {
261  if (is_deleted_node.at(*node_1)) {
262  continue;
263  }
264  for (auto edge_1 = h.incident_edges(*node_1).first; edge_1 != h.incident_edges(*node_1).second; edge_1++) {
265  if (is_deleted_edge.at(*edge_1)) {
266  continue;
267  }
268  Substruct_ node_edge_substruct(NODE_EDGE, h.get_node_label(*node_1), h.get_edge_label(*edge_1), dummy_label(), *node_1, *edge_1);
269  if (not is_substruct_in_g.at(node_edge_substruct)) {
270  unmatched_substructs_.push_back(node_edge_substruct);
271  is_deleted_node.at(*node_1) = true;
272  is_deleted_edge.at(*edge_1) = true;
273  break;
274  }
275  }
276  }
277 }
278 
279 template<class UserNodeLabel, class UserEdgeLabel>
280 bool
282 contains_node_edge_substruct_(const GEDGraph & g, const Substruct_ & substruct) const {
283  std::vector<GEDGraph::NodeID> candidate_nodes;
284  for (auto node_1 = g.nodes().first; node_1 != g.nodes().second; node_1++) {
285  if (g.get_node_label(*node_1) == substruct.node_label_1) {
286  candidate_nodes.push_back(*node_1);
287  }
288  }
289  if (candidate_nodes.empty()) {
290  return false;
291  }
292  for (auto node_1 = candidate_nodes.begin(); node_1 != candidate_nodes.end(); node_1++) {
293  for (auto edge_1 = g.incident_edges(*node_1).first; edge_1 != g.incident_edges(*node_1).second; edge_1++) {
294  if (g.get_edge_label(*edge_1) == substruct.edge_label_1) {
295  return true;
296  }
297  }
298  }
299  return false;
300 }
301 
302 template<class UserNodeLabel, class UserEdgeLabel>
303 void
305 check_node_edge_node_subtructs_(const GEDGraph & h, const SubstructMap_ & is_substruct_in_g, std::map<GEDGraph::NodeID, bool> & is_deleted_node, std::map<GEDGraph::EdgeID, bool> & is_deleted_edge) {
306  for (auto node_1 = h.nodes().first; node_1 != h.nodes().second; node_1++) {
307  if (is_deleted_node.at(*node_1)) {
308  continue;
309  }
310  for (auto edge_1 = h.incident_edges(*node_1).first; edge_1 != h.incident_edges(*node_1).second; edge_1++) {
311  GEDGraph::NodeID node_2{h.head(*edge_1)};
312  if (is_deleted_edge.at(*edge_1) or is_deleted_node.at(node_2)) {
313  continue;
314  }
315  Substruct_ node_edge_node_substruct(NODE_EDGE_NODE, h.get_node_label(*node_1), h.get_edge_label(*edge_1), h.get_node_label(node_2), *node_1, *edge_1, node_2);
316  if (not is_substruct_in_g.at(node_edge_node_substruct)) {
317  unmatched_substructs_.push_back(node_edge_node_substruct);
318  is_deleted_node.at(*node_1) = true;
319  is_deleted_edge.at(*edge_1) = true;
320  is_deleted_node.at(node_2) = true;
321  break;
322  }
323  }
324  }
325 }
326 
327 template<class UserNodeLabel, class UserEdgeLabel>
328 bool
330 contains_node_edge_node_substruct_(const GEDGraph & g, const Substruct_ & substruct) const {
331  std::vector<GEDGraph::NodeID> candidate_nodes;
332  for (auto node_1 = g.nodes().first; node_1 != g.nodes().second; node_1++) {
333  if (g.get_node_label(*node_1) == substruct.node_label_1) {
334  candidate_nodes.push_back(*node_1);
335  }
336  }
337  if (candidate_nodes.empty()) {
338  return false;
339  }
340  for (auto node_1 = candidate_nodes.begin(); node_1 != candidate_nodes.end(); node_1++) {
341  for (auto edge_1 = g.incident_edges(*node_1).first; edge_1 != g.incident_edges(*node_1).second; edge_1++) {
342  if (g.get_edge_label(*edge_1) == substruct.edge_label_1) {
343  if (g.get_node_label(g.head(*edge_1)) == substruct.node_label_2) {
344  return true;
345  }
346  }
347  }
348  }
349  return false;
350 }
351 
352 template<class UserNodeLabel, class UserEdgeLabel>
353 void
355 check_node_edge_edge_subtructs_(const GEDGraph & h, const SubstructMap_ & is_substruct_in_g, std::map<GEDGraph::NodeID, bool> & is_deleted_node, std::map<GEDGraph::EdgeID, bool> & is_deleted_edge) {
356  for (auto node_1 = h.nodes().first; node_1 != h.nodes().second; node_1++) {
357  if (is_deleted_node.at(*node_1)) {
358  continue;
359  }
360  for (auto edge_1 = h.incident_edges(*node_1).first; edge_1 != h.incident_edges(*node_1).second; edge_1++) {
361  if (is_deleted_edge.at(*edge_1)) {
362  continue;
363  }
364  bool found_unmatched_substruct{false};
365  for (auto edge_2 = h.incident_edges(*node_1).first; edge_2 != h.incident_edges(*node_1).second; edge_2++) {
366  if ((*edge_1 == *edge_2) or is_deleted_edge.at(*edge_2)) {
367  continue;
368  }
369  Substruct_ node_edge_edge_substruct(NODE_EDGE_EDGE, h.get_node_label(*node_1), h.get_edge_label(*edge_1), h.get_edge_label(*edge_2), *node_1, *edge_1, GEDGraph::dummy_node(), *edge_2);
370  if (not is_substruct_in_g.at(node_edge_edge_substruct)) {
371  unmatched_substructs_.push_back(node_edge_edge_substruct);
372  is_deleted_node.at(*node_1) = true;
373  is_deleted_edge.at(*edge_1) = true;
374  is_deleted_edge.at(*edge_2) = true;
375  found_unmatched_substruct = true;
376  break;
377  }
378  }
379  if (found_unmatched_substruct) {
380  break;
381  }
382  }
383  }
384 }
385 
386 template<class UserNodeLabel, class UserEdgeLabel>
387 bool
389 contains_node_edge_edge_substruct_(const GEDGraph & g, const Substruct_ & substruct) const {
390  std::vector<GEDGraph::NodeID> candidate_nodes;
391  for (auto node_1 = g.nodes().first; node_1 != g.nodes().second; node_1++) {
392  if (g.get_node_label(*node_1) == substruct.node_label_1) {
393  candidate_nodes.push_back(*node_1);
394  }
395  }
396  if (candidate_nodes.empty()) {
397  return false;
398  }
399  for (auto node_1 = candidate_nodes.begin(); node_1 != candidate_nodes.end(); node_1++) {
400  for (auto edge_1 = g.incident_edges(*node_1).first; edge_1 != g.incident_edges(*node_1).second; edge_1++) {
401  if (g.get_edge_label(*edge_1) == substruct.edge_label_1) {
402  for (auto edge_2 = g.incident_edges(*node_1).first; edge_2 != g.incident_edges(*node_1).second; edge_2++) {
403  if (*edge_1 == *edge_2) {
404  continue;
405  }
406  if (g.get_edge_label(*edge_2) == substruct.edge_label_2) {
407  return true;
408  }
409  }
410  break;
411  }
412  }
413  }
414  return false;
415 }
416 
417 template<class UserNodeLabel, class UserEdgeLabel>
420 Substruct_(SubstructType_ type, LabelID label_1, LabelID label_2, LabelID label_3, GEDGraph::NodeID node_1, GEDGraph::EdgeID edge_1, GEDGraph::NodeID node_2, GEDGraph::EdgeID edge_2) :
421 type{type},
422 node_label_1{dummy_label()},
423 node_label_2{dummy_label()},
424 edge_label_1{dummy_label()},
425 edge_label_2{dummy_label()},
426 node_1{node_1},
427 node_2{node_2},
428 edge_1{edge_1},
429 edge_2{edge_2}{
430  switch (type) {
431  case NODE:
432  node_label_1 = label_1;
433  break;
434  case EDGE:
435  edge_label_1 = label_1;
436  break;
437  case NODE_EDGE:
438  node_label_1 = label_1;
439  edge_label_1 = label_2;
440  break;
441  case NODE_EDGE_NODE:
442  node_label_1 = label_1;
443  edge_label_1 = label_2;
444  node_label_2 = label_3;
445  break;
446  case NODE_EDGE_EDGE:
447  node_label_1 = label_1;
448  edge_label_1 = label_2;
449  edge_label_2 = label_3;
450  break;
451  }
452 }
453 
454 template<class UserNodeLabel, class UserEdgeLabel>
455 bool
458 operator<(const Substruct_ & rhs) const {
459  if (node_label_1 < rhs.node_label_1) {
460  return true;
461  }
462  if (node_label_1 > rhs.node_label_1) {
463  return false;
464  }
465  if (edge_label_1 < rhs.edge_label_1) {
466  return true;
467  }
468  if (edge_label_1 > rhs.edge_label_1) {
469  return false;
470  }
471  if (node_label_2 < rhs.node_label_2) {
472  return true;
473  }
474  if (node_label_2 > rhs.node_label_2) {
475  return false;
476  }
477  if (edge_label_2 < rhs.edge_label_2) {
478  return true;
479  }
480  if (edge_label_2 > rhs.edge_label_2) {
481  return false;
482  }
483  return false;
484 }
485 
486 template<class UserNodeLabel, class UserEdgeLabel>
487 const std::vector<typename Partition<UserNodeLabel, UserEdgeLabel>::Substruct_> &
490  return unmatched_substructs_;
491 }
492 
493 }
494 
495 #endif /* SRC_METHODS_PARTITION_IPP_ */
Computes a lower bound for uniform edit costs.
Definition: partition.hpp:42
const GEDData< UserNodeLabel, UserEdgeLabel > & ged_data_
The data on which the method is run.
Definition: ged_method.hpp:124
void set_lower_bound(double lower_bound)
Sets the lower bound for GED.
Definition: result.ipp:39
NodeID head(EdgeID edge) const
Returns the head of an edge.
Definition: ged_graph.ipp:199
virtual void ged_run_(const GEDGraph &g, const GEDGraph &h, Result &result) final
Runs the method with options specified by set_options().
Definition: partition.ipp:57
virtual void ged_init_() final
Initializes the method.
Definition: partition.ipp:48
A wrapper structure for the result of calls to ged::GEDMethod::run_as_util() and ged::GEDMethod::ged_...
Definition: result.hpp:38
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
static NodeID dummy_node()
Returns a dummy node.
Definition: ged_graph.ipp:56
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
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
detail::GedGraphAL::edge_descriptor EdgeID
Internally used edge ID type.
Definition: ged_graph.hpp:110
constexpr LabelID dummy_label()
Returns a dummy label.
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::pair< edge_iterator, edge_iterator > edges() const
Provides access to all edge in the graph.
Definition: ged_graph.ipp:217