aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
DFSTree_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4  * info_at_agrum_dot_org
5  *
6  * This library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /**
23  * @file
24  * @brief Inline implementation of the DFSTree class.
25  *
26  * @author Lionel TORTI and Pierre-Henri WUILLEMIN(@LIP6)
27  */
28 
29 #include <agrum/PRM/gspan/DFSTree.h>
30 #include <agrum/PRM/gspan/edgeGrowth.h>
31 
32 namespace gum {
33  namespace prm {
34  namespace gspan {
35  template < typename GUM_SCALAR >
38 
39  for (const auto& elt: _data_) {
40  delete elt.first;
41  delete elt.second;
42  }
43 
44  delete _strategy_;
45  }
46 
47  template < typename GUM_SCALAR >
49  HashTable< Pattern*, std::pair< Idx, Idx > > roots;
51 
52  for (const auto& edge: _graph_->edges(&label)) {
53  bool u_first = (edge->l_u->id < edge->l_v->id);
54  Idx u_idx = (u_first) ? edge->l_u->id : edge->l_v->id;
55  Idx v_idx = (!u_first) ? edge->l_u->id : edge->l_v->id;
56 
57  bool found = false;
58 
59  for (const auto& elt: roots)
60  if ((elt.second.first == u_idx) && (elt.second.second == v_idx)) {
62  found = true;
63  break;
64  }
65 
66  /// Then we create a new pattern
67  if (!found) {
68  Pattern* p = new Pattern();
74  NodeId v = p->addNodeWithLabel((!u_first) ? *edge->l_u : *edge->l_v);
75  p->addArc(u, v, label);
77  _data_.insert(p, data);
79  }
80  }
81 
82  // This is used to compute the max independent set of p->max_indep_set
83  for (const auto& elt: roots_edges) {
86  delete elt.second;
87  }
88  }
89 
90  template < typename GUM_SCALAR >
91  void
96 
97  for (auto iter = edge_seq.begin(); iter != edge_seq.end(); ++iter) {
98  const auto& edge = *iter;
100  = new Sequence< PRMInstance< GUM_SCALAR >* >();
101 
102  // Creating the multiset of instances matching p
103  bool u_first = (edge->l_u->id < edge->l_v->id);
104  seq->insert((u_first) ? edge->u : edge->v);
105  seq->insert((!u_first) ? edge->u : edge->v);
106 
110 
111  // Adding edges between two isomorphisms of p sharing at least one
112  // instance
113  for (const auto& elt: data->iso_map)
114  if (elt.first != an_id)
115  for (auto iter = elt.second->begin(); iter != elt.second->end(); ++iter)
116  if (seq->exists(*iter)) {
118  break;
119  }
120  }
121 
122  // Computing p->max_indep_set using a greedy algorithm
125  Set< NodeId > removed;
126 
127  for (const auto node: degree_list) {
128  if (!removed.exists(node)) {
130 
131  for (const auto neighbor: data->iso_graph.neighbours(node))
133 
135  }
136  }
137  }
138 
139  template < typename GUM_SCALAR >
143  for (const auto& elt: iso_map) {
144  bool found = false;
145 
146  for (const auto& inst: seq)
147  if (!(elt.second->exists(inst))) {
148  found = true;
149  break;
150  }
151 
152  if (!found) { return false; }
153  }
154 
155  return true;
156  }
157 
158  template < typename GUM_SCALAR >
160  Pattern* child,
162  // Adding child to the tree
163  NodeId node = DiGraph::addNode();
165  // Adding child in p's children list
166  std::list< NodeId >& children = _data_[&p]->children;
167 
168  if (children.empty()) {
170  } else {
171  size_t size = children.size();
172 
173  for (std::list< NodeId >::iterator iter = children.begin(); iter != children.end();
174  ++iter) {
175  if (child->code() < pattern(*iter).code()) {
177  break;
178  }
179  }
180 
181  if (size == children.size()) { children.push_back(node); }
182  }
183  }
184 
185  template < typename GUM_SCALAR >
187  Pattern* child,
189  NodeId v = edge_growth.v;
190 
191  // First we check if the edge is legal
192  if (v == 0) { v = child->addNodeWithLabel(*(edge_growth.l_v)); }
193 
195  // Neighborhood restriction is checked by the Pattern class
197 
198  // Then we check if the edge we added is valid
199  if (edge < *(child->code().codes.front())) {
201  "added edge code is lesser than the first "
202  "one in the pattern's DFSCode");
203  }
204 
205  if (edge.isBackward()) {
206  typedef std::vector< EdgeCode* >::iterator EdgeIter;
207 
208  for (EdgeIter iter = child->code().codes.begin(); (iter + 1) != child->code().codes.end();
209  ++iter) {
210  if ((((**iter).i == v) || ((**iter).j == v)) && edge < (**iter)) {
212  "added backward edge is lesser than an existing edge on v");
213  }
214  }
215  }
216 
217  // Finally we check if child is minimal.
218  if (!child->isMinimal()) {
219  GUM_ERROR(OperationNotAllowed, "the DFSCode for this growth is not minimal")
220  }
221  }
222 
223  template < typename GUM_SCALAR >
226  Size min_freq) {
227  Pattern* child = new Pattern(p);
228 
229  try {
231  } catch (OperationNotAllowed&) {
232  delete child;
233  throw;
234  }
235 
236  // Now we need to build the pattern data about child
240  typename NodeProperty< std::pair< PRMInstance< GUM_SCALAR >*,
242  // Using p information to build child's isomorphism graph
243  NodeId id = 0;
244 
245  for (const auto& elt: p_iso_map) {
246  auto match = edge_growth.matches.begin();
247 
248  for (; match != edge_growth.matches.end(); ++match) {
249  // Adding the isomorphism in the iso_graph and building the iso_map.
250  if (child->code().codes.back()->isForward()) {
251  if (elt.second->exists(match.val().first)
252  && !(elt.second->exists(match.val().second))) {
253  // Let's see if the new match is already matched
255  = new Sequence< PRMInstance< GUM_SCALAR >* >(*elt.second);
257 
258  if (_is_new_seq_(*new_seq, data->iso_map)) {
259  id = data->iso_graph.addNode();
261  } else {
262  delete new_seq;
263  }
264 
265  break;
266  }
267  } else {
270  = new Sequence< PRMInstance< GUM_SCALAR >* >(*elt.second);
271 
272  if (_is_new_seq_(*new_seq, data->iso_map)) {
273  id = data->iso_graph.addNode();
275  } else {
276  delete new_seq;
277  }
278 
279  break;
280  }
281  }
282  }
283 
284  if (match != edge_growth.matches.end()) {
285  // Adding edges in the iso_graph
286  for (const auto node: data->iso_graph.nodes())
287  if (node != id)
288  for (const auto m: *data->iso_map[id])
289  if (data->iso_map[node]->exists(m)) {
291  break;
292  }
293 
296  }
297  }
298 
299  if (data->iso_graph.size() < min_freq) {
300  delete data;
301  delete child;
302  GUM_ERROR(OperationNotAllowed, "child is not frequent enough")
303  }
304 
305  // Now we can compute the maximal independent set of child
308  Set< NodeId > removed;
309 
310  for (const auto node: degree_list) {
311  if (!removed.exists(node)) {
313 
314  for (const auto neighbor: data->iso_graph.neighbours(node))
316 
318  }
319  }
320 
322 
324  _data_.erase(child);
325  delete data;
326  delete child;
327  GUM_ERROR(OperationNotAllowed, "child is not frequent enough")
328  }
329 
331  return *child;
332  }
333 
334  template < typename GUM_SCALAR >
338  try {
339  for (const auto& elt: x)
340  if (y[elt.first] != elt.second) return false;
341  } catch (NotFound&) { return false; }
342 
343  return true;
344  }
345 
346  // PatternData
347  template < typename GUM_SCALAR >
352 
353  for (const auto& elt: from.iso_map)
355  }
356 
357  template < typename GUM_SCALAR >
360 
361  for (const auto& elt: iso_map)
362  delete elt.second;
363  }
364 
365  template < typename GUM_SCALAR >
368  _graph_(&graph),
371 
373 
374  _strategy_->setTree(this);
375  }
376 
377  template < typename GUM_SCALAR >
379  return _roots_;
380  }
381 
382  template < typename GUM_SCALAR >
383  INLINE const std::list< NodeId >& DFSTree< GUM_SCALAR >::roots() const {
384  return _roots_;
385  }
386 
387  template < typename GUM_SCALAR >
389  try {
390  return *(_node_map_.second(
391  *(DiGraph::parents(_node_map_.first(const_cast< Pattern* >(&p))).begin())));
392  } catch (NotFound&) {
393  if (_node_map_.existsSecond(const_cast< Pattern* >(&p))) {
394  GUM_ERROR(NotFound, "the given pattern is a root node")
395  } else {
396  GUM_ERROR(NotFound, "pattern not found in this DFSTree")
397  }
398  }
399  }
400 
401  template < typename GUM_SCALAR >
402  INLINE const Pattern& DFSTree< GUM_SCALAR >::parent(const Pattern& p) const {
403  try {
404  return *(_node_map_.second(
405  *(DiGraph::parents(_node_map_.first(const_cast< Pattern* >(&p))).begin())));
406  } catch (NotFound&) {
407  if (_node_map_.existsSecond(const_cast< Pattern* >(&p))) {
408  GUM_ERROR(NotFound, "the given pattern is a root node")
409  } else {
410  GUM_ERROR(NotFound, "pattern not found in this DFSTree")
411  }
412  }
413  }
414 
415  template < typename GUM_SCALAR >
417  try {
418  return _data_[const_cast< Pattern* >(&p)]->children;
419  } catch (NotFound&) { GUM_ERROR(NotFound, "pattern not found in this DFSTree") }
420  }
421 
422  template < typename GUM_SCALAR >
423  INLINE const std::list< NodeId >& DFSTree< GUM_SCALAR >::children(const Pattern& p) const {
424  try {
425  return _data_[const_cast< Pattern* >(&p)]->children;
426  } catch (NotFound&) { GUM_ERROR(NotFound, "pattern not found in this DFSTree") }
427  }
428 
429  template < typename GUM_SCALAR >
431  try {
432  return *(_node_map_.second(id));
433  } catch (NotFound&) { GUM_ERROR(NotFound, "no pattern matching the given id") }
434  }
435 
436  template < typename GUM_SCALAR >
438  try {
439  return *(_node_map_.second(id));
440  } catch (NotFound&) { GUM_ERROR(NotFound, "no pattern matching the given id") }
441  }
442 
443  template < typename GUM_SCALAR >
445  try {
446  return _data_[const_cast< Pattern* >(&p)]->iso_graph;
447  } catch (NotFound&) { GUM_ERROR(NotFound, "pattern not found in this DFSTree") }
448  }
449 
450  template < typename GUM_SCALAR >
453  try {
454  return *(_data_[const_cast< Pattern* >(&p)]->iso_map[node]);
455  } catch (NotFound&) {
456  if (_data_.exists(const_cast< Pattern* >(&p))) {
457  GUM_ERROR(NotFound, "node not found in Pattern's isomorphism graph")
458  } else {
459  GUM_ERROR(NotFound, "pattern not found in this DFSTree")
460  }
461  }
462  }
463 
464  template < typename GUM_SCALAR >
466  try {
467  return _data_[const_cast< Pattern* >(&p)]->max_indep_set;
468  } catch (NotFound&) { GUM_ERROR(NotFound, "pattern not found in this DFSTree") }
469  }
470 
471  template < typename GUM_SCALAR >
473  return *_graph_;
474  }
475 
476  template < typename GUM_SCALAR >
478  out << edge.u << ", " << *(edge.edge) << ", " << *(edge.l_v) << ", " << edge.v;
479  return out;
480  }
481 
482  template < typename GUM_SCALAR >
483  INLINE double DFSTree< GUM_SCALAR >::frequency(const Pattern& p) const {
484  return (double)_data_[const_cast< Pattern* >(&p)]->max_indep_set.size();
485  }
486 
487  template < typename GUM_SCALAR >
488  INLINE typename DFSTree< GUM_SCALAR >::PatternData&
490  return *(_data_[const_cast< Pattern* >(&p)]);
491  }
492 
493  template < typename GUM_SCALAR >
494  INLINE const typename DFSTree< GUM_SCALAR >::PatternData&
495  DFSTree< GUM_SCALAR >::data(const Pattern& p) const {
496  return *(_data_[const_cast< Pattern* >(&p)]);
497  }
498 
499  template < typename GUM_SCALAR >
501  return *_strategy_;
502  }
503 
504  template < typename GUM_SCALAR >
506  return *_strategy_;
507  }
508 
509  // NeighborDegreeSort
510 
511  template < typename GUM_SCALAR >
513  g(graph) {
515  }
516 
517  template < typename GUM_SCALAR >
519  const NeighborDegreeSort& source) :
520  g(source.g) {
522  }
523 
524  template < typename GUM_SCALAR >
527  }
528 
529  template < typename GUM_SCALAR >
531  return g.neighbours(i).size() < g.neighbours(j).size();
532  }
533 
534  // PatternData
535 
536  template < typename GUM_SCALAR >
538  pattern(p), cost(0), gain(0) {
540  }
541 
542  } /* namespace gspan */
543  } /* namespace prm */
544 } /* namespace gum */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:643
ParamScopeData(const std::string &s, const PRMReferenceSlot< GUM_SCALAR > &ref, Idx d)
INLINE std::ostream & operator<<(std::ostream &out, const EdgeData< GUM_SCALAR > &data)
Print a EdgeData<GUM_SCALAR> in out.