aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
DFSTree_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright 2005-2020 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();
73  = new DFSTree< GUM_SCALAR >::PatternData(p);
75  NodeId v = p->addNodeWithLabel((!u_first) ? *edge->l_u : *edge->l_v);
76  p->addArc(u, v, label);
78  data__.insert(p, data);
80  }
81  }
82 
83  // This is used to compute the max independent set of p->max_indep_set
84  for (const auto& elt: roots_edges) {
87  delete elt.second;
88  }
89  }
90 
91  template < typename GUM_SCALAR >
93  Pattern* p,
97 
98  for (auto iter = edge_seq.begin(); iter != edge_seq.end(); ++iter) {
99  const auto& edge = *iter;
101  = new Sequence< PRMInstance< GUM_SCALAR >* >();
102 
103  // Creating the multiset of instances matching p
104  bool u_first = (edge->l_u->id < edge->l_v->id);
105  seq->insert((u_first) ? edge->u : edge->v);
106  seq->insert((!u_first) ? edge->u : edge->v);
107 
111 
112  // Adding edges between two isomorphisms of p sharing at least one
113  // instance
114  for (const auto& elt: data->iso_map)
115  if (elt.first != an_id)
116  for (auto iter = elt.second->begin(); iter != elt.second->end();
117  ++iter)
118  if (seq->exists(*iter)) {
120  break;
121  }
122  }
123 
124  // Computing p->max_indep_set using a greedy algorithm
127  Set< NodeId > removed;
128 
129  for (const auto node: degree_list) {
130  if (!removed.exists(node)) {
132 
133  for (const auto neighbor: data->iso_graph.neighbours(node))
135 
137  }
138  }
139  }
140 
141  template < typename GUM_SCALAR >
145  for (const auto& elt: iso_map) {
146  bool found = false;
147 
148  for (const auto& inst: seq)
149  if (!(elt.second->exists(inst))) {
150  found = true;
151  break;
152  }
153 
154  if (!found) { return false; }
155  }
156 
157  return true;
158  }
159 
160  template < typename GUM_SCALAR >
161  void
163  Pattern* child,
165  // Adding child to the tree
166  NodeId node = DiGraph::addNode();
168  // Adding child in p's children list
169  std::list< NodeId >& children = data__[&p]->children;
170 
171  if (children.empty()) {
173  } else {
174  size_t size = children.size();
175 
176  for (std::list< NodeId >::iterator iter = children.begin();
177  iter != children.end();
178  ++iter) {
179  if (child->code() < pattern(*iter).code()) {
181  break;
182  }
183  }
184 
185  if (size == children.size()) { children.push_back(node); }
186  }
187  }
188 
189  template < typename GUM_SCALAR >
191  Pattern& p,
192  Pattern* child,
194  NodeId v = edge_growth.v;
195 
196  // First we check if the edge is legal
197  if (v == 0) { v = child->addNodeWithLabel(*(edge_growth.l_v)); }
198 
200  // Neighborhood restriction is checked by the Pattern class
202 
203  // Then we check if the edge we added is valid
204  if (edge < *(child->code().codes.front())) {
206  "added edge code is lesser than the first "
207  "one in the pattern's DFSCode");
208  }
209 
210  if (edge.isBackward()) {
211  typedef std::vector< EdgeCode* >::iterator EdgeIter;
212 
213  for (EdgeIter iter = child->code().codes.begin();
214  (iter + 1) != child->code().codes.end();
215  ++iter) {
216  if ((((**iter).i == v) || ((**iter).j == v)) && edge < (**iter)) {
217  GUM_ERROR(
219  "added backward edge is lesser than an existing edge on v");
220  }
221  }
222  }
223 
224  // Finally we check if child is minimal.
225  if (!child->isMinimal()) {
227  "the DFSCode for this growth is not minimal");
228  }
229  }
230 
231  template < typename GUM_SCALAR >
232  Pattern&
235  Size min_freq) {
236  Pattern* child = new Pattern(p);
237 
238  try {
240  } catch (OperationNotAllowed&) {
241  delete child;
242  throw;
243  }
244 
245  // Now we need to build the pattern data about child
247  = new DFSTree< GUM_SCALAR >::PatternData(child);
250  = data__[&p]->iso_map;
251  typename NodeProperty<
254  // Using p information to build child's isomorphism graph
255  NodeId id = 0;
256 
257  for (const auto& elt: p_iso_map) {
258  auto match = edge_growth.matches.begin();
259 
260  for (; match != edge_growth.matches.end(); ++match) {
261  // Adding the isomorphism in the iso_graph and building the iso_map.
262  if (child->code().codes.back()->isForward()) {
263  if (elt.second->exists(match.val().first)
264  && !(elt.second->exists(match.val().second))) {
265  // Let's see if the new match is already matched
267  = new Sequence< PRMInstance< GUM_SCALAR >* >(*elt.second);
269 
270  if (is_new_seq__(*new_seq, data->iso_map)) {
271  id = data->iso_graph.addNode();
273  } else {
274  delete new_seq;
275  }
276 
277  break;
278  }
279  } else {
280  if (elt.second->exists(match.val().first)
281  && elt.second->exists(match.val().second)) {
283  = new Sequence< PRMInstance< GUM_SCALAR >* >(*elt.second);
284 
285  if (is_new_seq__(*new_seq, data->iso_map)) {
286  id = data->iso_graph.addNode();
288  } else {
289  delete new_seq;
290  }
291 
292  break;
293  }
294  }
295  }
296 
297  if (match != edge_growth.matches.end()) {
298  // Adding edges in the iso_graph
299  for (const auto node: data->iso_graph.nodes())
300  if (node != id)
301  for (const auto m: *data->iso_map[id])
302  if (data->iso_map[node]->exists(m)) {
304  break;
305  }
306 
309  }
310  }
311 
312  if (data->iso_graph.size() < min_freq) {
313  delete data;
314  delete child;
315  GUM_ERROR(OperationNotAllowed, "child is not frequent enough");
316  }
317 
318  // Now we can compute the maximal independent set of child
321  Set< NodeId > removed;
322 
323  for (const auto node: degree_list) {
324  if (!removed.exists(node)) {
326 
327  for (const auto neighbor: data->iso_graph.neighbours(node))
329 
331  }
332  }
333 
335 
337  data__.erase(child);
338  delete data;
339  delete child;
340  GUM_ERROR(OperationNotAllowed, "child is not frequent enough");
341  }
342 
344  return *child;
345  }
346 
347  template < typename GUM_SCALAR >
351  try {
352  for (const auto& elt: x)
353  if (y[elt.first] != elt.second) return false;
354  } catch (NotFound&) { return false; }
355 
356  return true;
357  }
358 
359  // PatternData
360  template < typename GUM_SCALAR >
364  cost(from.cost), gain(from.gain) {
366 
367  for (const auto& elt: from.iso_map)
369  new Sequence< PRMInstance< GUM_SCALAR >* >(*elt.second));
370  }
371 
372  template < typename GUM_SCALAR >
375 
376  for (const auto& elt: iso_map)
377  delete elt.second;
378  }
379 
380  template < typename GUM_SCALAR >
382  const InterfaceGraph< GUM_SCALAR >& graph,
384  graph__(&graph),
387 
389 
390  strategy__->setTree(this);
391  }
392 
393  template < typename GUM_SCALAR >
395  return roots__;
396  }
397 
398  template < typename GUM_SCALAR >
399  INLINE const std::list< NodeId >& DFSTree< GUM_SCALAR >::roots() const {
400  return roots__;
401  }
402 
403  template < typename GUM_SCALAR >
405  try {
406  return *(node_map__.second(
407  *(DiGraph::parents(node_map__.first(const_cast< Pattern* >(&p)))
408  .begin())));
409  } catch (NotFound&) {
410  if (node_map__.existsSecond(const_cast< Pattern* >(&p))) {
411  GUM_ERROR(NotFound, "the given pattern is a root node");
412  } else {
413  GUM_ERROR(NotFound, "pattern not found in this DFSTree");
414  }
415  }
416  }
417 
418  template < typename GUM_SCALAR >
419  INLINE const Pattern& DFSTree< GUM_SCALAR >::parent(const Pattern& p) const {
420  try {
421  return *(node_map__.second(
422  *(DiGraph::parents(node_map__.first(const_cast< Pattern* >(&p)))
423  .begin())));
424  } catch (NotFound&) {
425  if (node_map__.existsSecond(const_cast< Pattern* >(&p))) {
426  GUM_ERROR(NotFound, "the given pattern is a root node");
427  } else {
428  GUM_ERROR(NotFound, "pattern not found in this DFSTree");
429  }
430  }
431  }
432 
433  template < typename GUM_SCALAR >
434  INLINE std::list< NodeId >&
436  try {
437  return data__[const_cast< Pattern* >(&p)]->children;
438  } catch (NotFound&) {
439  GUM_ERROR(NotFound, "pattern not found in this DFSTree");
440  }
441  }
442 
443  template < typename GUM_SCALAR >
444  INLINE const std::list< NodeId >&
445  DFSTree< GUM_SCALAR >::children(const Pattern& p) const {
446  try {
447  return data__[const_cast< Pattern* >(&p)]->children;
448  } catch (NotFound&) {
449  GUM_ERROR(NotFound, "pattern not found in this DFSTree");
450  }
451  }
452 
453  template < typename GUM_SCALAR >
455  try {
456  return *(node_map__.second(id));
457  } catch (NotFound&) {
458  GUM_ERROR(NotFound, "no pattern matching the given id");
459  }
460  }
461 
462  template < typename GUM_SCALAR >
464  try {
465  return *(node_map__.second(id));
466  } catch (NotFound&) {
467  GUM_ERROR(NotFound, "no pattern matching the given id");
468  }
469  }
470 
471  template < typename GUM_SCALAR >
473  try {
474  return data__[const_cast< Pattern* >(&p)]->iso_graph;
475  } catch (NotFound&) {
476  GUM_ERROR(NotFound, "pattern not found in this DFSTree");
477  }
478  }
479 
480  template < typename GUM_SCALAR >
483  try {
484  return *(data__[const_cast< Pattern* >(&p)]->iso_map[node]);
485  } catch (NotFound&) {
486  if (data__.exists(const_cast< Pattern* >(&p))) {
487  GUM_ERROR(NotFound, "node not found in Pattern's isomorphism graph");
488  } else {
489  GUM_ERROR(NotFound, "pattern not found in this DFSTree");
490  }
491  }
492  }
493 
494  template < typename GUM_SCALAR >
495  INLINE Set< NodeId >&
497  try {
498  return data__[const_cast< Pattern* >(&p)]->max_indep_set;
499  } catch (NotFound&) {
500  GUM_ERROR(NotFound, "pattern not found in this DFSTree");
501  }
502  }
503 
504  template < typename GUM_SCALAR >
506  DFSTree< GUM_SCALAR >::graph() const {
507  return *graph__;
508  }
509 
510  template < typename GUM_SCALAR >
512  const EdgeGrowth< GUM_SCALAR >& edge) {
513  out << edge.u << ", " << *(edge.edge) << ", " << *(edge.l_v) << ", "
514  << edge.v;
515  return out;
516  }
517 
518  template < typename GUM_SCALAR >
519  INLINE double DFSTree< GUM_SCALAR >::frequency(const Pattern& p) const {
520  return (double)data__[const_cast< Pattern* >(&p)]->max_indep_set.size();
521  }
522 
523  template < typename GUM_SCALAR >
524  INLINE typename DFSTree< GUM_SCALAR >::PatternData&
526  return *(data__[const_cast< Pattern* >(&p)]);
527  }
528 
529  template < typename GUM_SCALAR >
530  INLINE const typename DFSTree< GUM_SCALAR >::PatternData&
531  DFSTree< GUM_SCALAR >::data(const Pattern& p) const {
532  return *(data__[const_cast< Pattern* >(&p)]);
533  }
534 
535  template < typename GUM_SCALAR >
537  return *strategy__;
538  }
539 
540  template < typename GUM_SCALAR >
543  return *strategy__;
544  }
545 
546  // NeighborDegreeSort
547 
548  template < typename GUM_SCALAR >
550  UndiGraph& graph) :
551  g(graph) {
553  }
554 
555  template < typename GUM_SCALAR >
557  const NeighborDegreeSort& source) :
558  g(source.g) {
560  }
561 
562  template < typename GUM_SCALAR >
565  }
566 
567  template < typename GUM_SCALAR >
569  NodeId j) {
570  return g.neighbours(i).size() < g.neighbours(j).size();
571  }
572 
573  // PatternData
574 
575  template < typename GUM_SCALAR >
577  pattern(p), cost(0), gain(0) {
579  }
580 
581  } /* namespace gspan */
582  } /* namespace prm */
583 } /* namespace gum */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:669
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.