aGrUM 3.1.1
a C++ library for (probabilistic) graphical models
DFSTree_tpl.h
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2026 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2026 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40
41#pragma once
42
43
50
53
54namespace gum {
55 namespace prm {
56 namespace gspan {
57 template < GUM_Numeric GUM_SCALAR >
59 GUM_DESTRUCTOR(DFSTree);
60
61 for (const auto& elt: _data_) {
62 delete elt.first;
63 delete elt.second;
64 }
65
66 delete _strategy_;
67 }
68
69 template < GUM_Numeric GUM_SCALAR >
73
74 for (const auto& edge: _graph_->edges(&label)) {
75 bool u_first = (edge->l_u->id < edge->l_v->id);
76 Idx u_idx = (u_first) ? edge->l_u->id : edge->l_v->id;
77 Idx v_idx = (!u_first) ? edge->l_u->id : edge->l_v->id;
78
79 bool found = false;
80
81 for (const auto& elt: roots)
82 if ((elt.second.first == u_idx) && (elt.second.second == v_idx)) {
83 roots_edges[elt.first]->insert(edge);
84 found = true;
85 break;
86 }
87
89 if (!found) {
90 Pattern* p = new Pattern();
91 roots.insert(p, std::make_pair(u_idx, v_idx));
92 roots_edges.insert(p, new Sequence< EdgeData< GUM_SCALAR >* >());
93 roots_edges[p]->insert(edge);
95 NodeId u = p->addNodeWithLabel((u_first) ? *edge->l_u : *edge->l_v);
96 NodeId v = p->addNodeWithLabel((!u_first) ? *edge->l_u : *edge->l_v);
97 p->addArc(u, v, label);
98 _node_map_.insert(DiGraph::addNode(), p);
99 _data_.insert(p, data);
100 _roots_.push_back(_node_map_.first(p));
101 }
102 }
103
104 // This is used to compute the max independent set of p->max_indep_set
105 for (const auto& elt: roots_edges) {
106 _initialiaze_root_(elt.first, *elt.second);
107 strategy().accept_root(elt.first);
108 delete elt.second;
109 }
110 }
111
112 template < GUM_Numeric GUM_SCALAR >
113 void
115 Sequence< EdgeData< GUM_SCALAR >* >& edge_seq) {
117 std::vector< NodeId > degree_list;
118
119 for (auto iter = edge_seq.begin(); iter != edge_seq.end(); ++iter) {
120 const auto& edge = *iter;
123
124 // Creating the multiset of instances matching p
125 bool u_first = (edge->l_u->id < edge->l_v->id);
126 seq->insert((u_first) ? edge->u : edge->v);
127 seq->insert((!u_first) ? edge->u : edge->v);
128
129 NodeId an_id = data->iso_graph.addNode();
130 data->iso_map.insert(an_id, seq);
131 degree_list.push_back(an_id);
132
133 // Adding edges between two isomorphisms of p sharing at least one
134 // instance
135 for (const auto& elt: data->iso_map)
136 if (elt.first != an_id)
137 for (auto iter = elt.second->begin(); iter != elt.second->end(); ++iter)
138 if (seq->exists(*iter)) {
139 data->iso_graph.addEdge(an_id, elt.first);
140 break;
141 }
142 }
143
144 // Computing p->max_indep_set using a greedy algorithm
145 DFSTree< GUM_SCALAR >::NeighborDegreeSort my_operator(data->iso_graph);
146 std::sort(degree_list.begin(), degree_list.end(), my_operator);
147 Set< NodeId > removed;
148
149 for (const auto node: degree_list) {
150 if (!removed.exists(node)) {
151 removed.insert(node);
152
153 for (const auto neighbor: data->iso_graph.neighbours(node))
154 removed.insert(neighbor);
155
156 data->max_indep_set.insert(node);
157 }
158 }
159 }
160
161 template < GUM_Numeric GUM_SCALAR >
165 for (const auto& elt: iso_map) {
166 bool found = false;
167
168 for (const auto& inst: seq)
169 if (!(elt.second->exists(inst))) {
170 found = true;
171 break;
172 }
173
174 if (!found) { return false; }
175 }
176
177 return true;
178 }
179
180 template < GUM_Numeric GUM_SCALAR >
182 Pattern* child,
183 EdgeGrowth< GUM_SCALAR >& edge_growth) {
184 // Adding child to the tree
185 NodeId node = DiGraph::addNode();
186 _node_map_.insert(node, child);
187 // Adding child in p's children list
188 std::list< NodeId >& children = _data_[&p]->children;
189
190 if (children.empty()) {
191 children.push_back(node);
192 } else {
193 size_t size = children.size();
194
195 for (std::list< NodeId >::iterator iter = children.begin(); iter != children.end();
196 ++iter) {
197 if (child->code() < pattern(*iter).code()) {
198 children.insert(iter, node);
199 break;
200 }
201 }
202
203 if (size == children.size()) { children.push_back(node); }
204 }
205 }
206
207 template < GUM_Numeric GUM_SCALAR >
209 Pattern* child,
210 EdgeGrowth< GUM_SCALAR >& edge_growth) {
211 NodeId v = edge_growth.v;
212
213 // First we check if the edge is legal
214 if (v == 0) { v = child->addNodeWithLabel(*(edge_growth.l_v)); }
215
216 child->addArc(edge_growth.u, v, *(edge_growth.edge));
217 // Neighborhood restriction is checked by the Pattern class
218 const EdgeCode& edge = child->edgeCode(edge_growth.u, v);
219
220 // Then we check if the edge we added is valid
221 if (edge < *(child->code().codes.front())) {
223 "added edge code is lesser than the first "
224 "one in the pattern's DFSCode");
225 }
226
227 if (edge.isBackward()) {
228 for (auto iter = child->code().codes.begin(); (iter + 1) != child->code().codes.end();
229 ++iter) {
230 if ((((**iter).i == v) || ((**iter).j == v)) && edge < (**iter)) {
232 "added backward edge is lesser than an existing edge on v");
233 }
234 }
235 }
236
237 // Finally, we check if child is minimal.
238 if (!child->isMinimal()) {
239 GUM_ERROR(OperationNotAllowed, "the DFSCode for this growth is not minimal")
240 }
241 }
242
243 template < GUM_Numeric GUM_SCALAR >
245 EdgeGrowth< GUM_SCALAR >& edge_growth,
246 Size min_freq) {
247 auto* child = new Pattern(p);
248
249 try {
250 _checkGrowth_(p, child, edge_growth);
251 } catch (OperationNotAllowed const&) {
252 delete child;
253 throw;
254 }
255
256 // Now we need to build the pattern data about child
257 auto* data = new DFSTree< GUM_SCALAR >::PatternData(child);
258 std::vector< NodeId > degree_list;
259 NodeProperty< Sequence< PRMInstance< GUM_SCALAR >* >* >& p_iso_map = _data_[&p]->iso_map;
260 // typename NodeProperty< std::pair< PRMInstance< GUM_SCALAR >*,
261 // PRMInstance< GUM_SCALAR >* > >::iterator_safe match;
262 // Using p information to build child's isomorphism graph
263 NodeId id = 0;
264
265 for (const auto& elt: p_iso_map) {
266 auto match = edge_growth.matches.begin();
267
268 for (; match != edge_growth.matches.end(); ++match) {
269 // Adding the isomorphism in the iso_graph and building the iso_map.
270 if (child->code().codes.back()->isForward()) {
271 if (elt.second->exists(match.val().first)
272 && !(elt.second->exists(match.val().second))) {
273 // Let's see if the new match is already matched
274 auto* new_seq = new Sequence< PRMInstance< GUM_SCALAR >* >(*elt.second);
275 new_seq->insert(match.val().second);
276
277 if (_is_new_seq_(*new_seq, data->iso_map)) {
278 id = data->iso_graph.addNode();
279 data->iso_map.insert(id, new_seq);
280 } else {
281 delete new_seq;
282 }
283
284 break;
285 }
286 } else {
287 if (elt.second->exists(match.val().first) && elt.second->exists(match.val().second)) {
289 = new Sequence< PRMInstance< GUM_SCALAR >* >(*elt.second);
290
291 if (_is_new_seq_(*new_seq, data->iso_map)) {
292 id = data->iso_graph.addNode();
293 data->iso_map.insert(id, new_seq);
294 } else {
295 delete new_seq;
296 }
297
298 break;
299 }
300 }
301 }
302
303 if (match != edge_growth.matches.end()) {
304 // Adding edges in the iso_graph
305 for (const auto node: data->iso_graph.nodes())
306 if (node != id)
307 for (const auto m: *data->iso_map[id])
308 if (data->iso_map[node]->exists(m)) {
309 data->iso_graph.addEdge(node, id);
310 break;
311 }
312
313 degree_list.push_back(id);
314 edge_growth.matches.erase(match.key());
315 }
316 }
317
318 if (data->iso_graph.size() < min_freq) {
319 delete data;
320 delete child;
321 GUM_ERROR(OperationNotAllowed, "child is not frequent enough")
322 }
323
324 // Now we can compute the maximal independent set of child
325 DFSTree< GUM_SCALAR >::NeighborDegreeSort my_operator(data->iso_graph);
326 std::sort(degree_list.begin(), degree_list.end(), my_operator);
327 Set< NodeId > removed;
328
329 for (const auto node: degree_list) {
330 if (!removed.exists(node)) {
331 removed.insert(node);
332
333 for (const auto neighbor: data->iso_graph.neighbours(node))
334 removed.insert(neighbor);
335
336 data->max_indep_set.insert(node);
337 }
338 }
339
340 _data_.insert(child, data);
341
342 if (!_strategy_->accept_growth(&p, child, edge_growth)) {
343 _data_.erase(child);
344 delete data;
345 delete child;
346 GUM_ERROR(OperationNotAllowed, "child is not frequent enough")
347 }
348
349 _addChild_(p, child, edge_growth);
350 return *child;
351 }
352
353 template < GUM_Numeric GUM_SCALAR >
357 for (const auto& elt: x) {
358 if (auto p = y.tryGet(elt.first); !p || *p != elt.second) return false;
359 }
360
361 return true;
362 }
363
364 // PatternData
365 template < GUM_Numeric GUM_SCALAR >
368 max_indep_set(from.max_indep_set), cost(from.cost), gain(from.gain) {
370
371 for (const auto& elt: from.iso_map)
372 iso_map.insert(elt.first, new Sequence< PRMInstance< GUM_SCALAR >* >(*elt.second));
373 }
374
375 template < GUM_Numeric GUM_SCALAR >
378
379 for (const auto& elt: iso_map)
380 delete elt.second;
381 }
382
383 template < GUM_Numeric GUM_SCALAR >
393
394 template < GUM_Numeric GUM_SCALAR >
395 std::list< NodeId >& DFSTree< GUM_SCALAR >::roots() {
396 return _roots_;
397 }
398
399 template < GUM_Numeric GUM_SCALAR >
400 const std::list< NodeId >& DFSTree< GUM_SCALAR >::roots() const {
401 return _roots_;
402 }
403
404 template < GUM_Numeric GUM_SCALAR >
406 if (!_node_map_.existsSecond(const_cast< Pattern* >(&p))) {
407 GUM_ERROR(NotFound, "pattern not found in this DFSTree")
408 }
409 auto node = _node_map_.first(const_cast< Pattern* >(&p));
410 const auto& par = DiGraph::parents(node);
411 if (par.empty()) { GUM_ERROR(NotFound, "the given pattern is a root node") }
412 return *(_node_map_.second(*(par.begin())));
413 }
414
415 template < GUM_Numeric GUM_SCALAR >
417 if (!_node_map_.existsSecond(const_cast< Pattern* >(&p))) {
418 GUM_ERROR(NotFound, "pattern not found in this DFSTree")
419 }
420 auto node = _node_map_.first(const_cast< Pattern* >(&p));
421 const auto& par = DiGraph::parents(node);
422 if (par.empty()) { GUM_ERROR(NotFound, "the given pattern is a root node") }
423 return *(_node_map_.second(*(par.begin())));
424 }
425
426 template < GUM_Numeric GUM_SCALAR >
427 std::list< NodeId >& DFSTree< GUM_SCALAR >::children(const Pattern& p) {
428 auto pd = _data_.tryGet(const_cast< Pattern* >(&p));
429 if (!pd) GUM_ERROR(NotFound, "pattern not found in this DFSTree")
430 return (*pd)->children;
431 }
432
433 template < GUM_Numeric GUM_SCALAR >
434 const std::list< NodeId >& DFSTree< GUM_SCALAR >::children(const Pattern& p) const {
435 auto pd = _data_.tryGet(const_cast< Pattern* >(&p));
436 if (!pd) GUM_ERROR(NotFound, "pattern not found in this DFSTree")
437 return (*pd)->children;
438 }
439
440 template < GUM_Numeric GUM_SCALAR >
442 if (!_node_map_.existsFirst(id)) GUM_ERROR(NotFound, "no pattern matching the given id")
443 return *(_node_map_.second(id));
444 }
445
446 template < GUM_Numeric GUM_SCALAR >
448 if (!_node_map_.existsFirst(id)) GUM_ERROR(NotFound, "no pattern matching the given id")
449 return *(_node_map_.second(id));
450 }
451
452 template < GUM_Numeric GUM_SCALAR >
454 auto pd = _data_.tryGet(const_cast< Pattern* >(&p));
455 if (!pd) GUM_ERROR(NotFound, "pattern not found in this DFSTree")
456 return (*pd)->iso_graph;
457 }
458
459 template < GUM_Numeric GUM_SCALAR >
461 NodeId node) {
462 auto pd = _data_.tryGet(const_cast< Pattern* >(&p));
463 if (!pd) GUM_ERROR(NotFound, "pattern not found in this DFSTree")
464 auto p_iso = (*pd)->iso_map.tryGet(node);
465 if (!p_iso) GUM_ERROR(NotFound, "node not found in Pattern's isomorphism graph")
466 return *(*p_iso);
467 }
468
469 template < GUM_Numeric GUM_SCALAR >
471 auto pd = _data_.tryGet(const_cast< Pattern* >(&p));
472 if (!pd) GUM_ERROR(NotFound, "pattern not found in this DFSTree")
473 return (*pd)->max_indep_set;
474 }
475
476 template < GUM_Numeric GUM_SCALAR >
480
481 template < GUM_Numeric GUM_SCALAR >
482 std::ostream& operator<<(std::ostream& out, const EdgeGrowth< GUM_SCALAR >& edge) {
483 out << edge.u << ", " << *(edge.edge) << ", " << *(edge.l_v) << ", " << edge.v;
484 return out;
485 }
486
487 template < GUM_Numeric GUM_SCALAR >
489 return (double)_data_[const_cast< Pattern* >(&p)]->max_indep_set.size();
490 }
491
492 template < GUM_Numeric GUM_SCALAR >
494 return *(_data_[const_cast< Pattern* >(&p)]);
495 }
496
497 template < GUM_Numeric GUM_SCALAR >
500 return *(_data_[const_cast< Pattern* >(&p)]);
501 }
502
503 template < GUM_Numeric GUM_SCALAR >
507
508 template < GUM_Numeric GUM_SCALAR >
512
513 // NeighborDegreeSort
514
515 template < GUM_Numeric GUM_SCALAR >
519
520 template < GUM_Numeric GUM_SCALAR >
525
526 template < GUM_Numeric GUM_SCALAR >
530
531 template < GUM_Numeric GUM_SCALAR >
533 return g.neighbours(i).size() < g.neighbours(j).size();
534 }
535
536 // PatternData
537
538 template < GUM_Numeric GUM_SCALAR >
542
543 } /* namespace gspan */
544 } /* namespace prm */
545} /* namespace gum */
Headers of the DFSTree class.
const NodeSet & parents(NodeId id) const
returns the set of nodes with arc ingoing to a given node
The class for generic Hash Tables.
Definition hashTable.h:640
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
Size size() const
alias for sizeNodes
virtual NodeId addNode()
insert a new node and return its id
Exception : the element we looked for cannot be found.
Exception : operation not allowed.
void insert(const Key &k)
Insert an element at the end of the sequence.
bool exists(const Key &k) const
Check the existence of k in the sequence.
The generic class for storing (ordered) sequences of objects.
Definition sequence.h:994
bool exists(const Key &k) const
Indicates whether a given elements belong to the set.
Definition set_tpl.h:504
void insert(const Key &k)
Inserts a new element into the set.
Definition set_tpl.h:510
Base class for undirected graphs.
Definition undiGraph.h:130
Abstract class representing an element of PRM class.
An PRMInstance is a Bayesian network fragment defined by a Class and used in a PRMSystem.
Definition PRMInstance.h:79
std::vector< EdgeCode * > codes
The vector containing the EdgeCode composing this DFSCode.
Definition DFSCode.h:109
Sequence< PRMInstance< GUM_SCALAR > * > & iso_map(const Pattern &p, NodeId node)
Given a pattern and a node in its isomorphism graph, this methods returns the sequence of instance ma...
SearchStrategy< GUM_SCALAR > * _strategy_
The strategy used to prune the search tree.
Definition DFSTree.h:280
void _checkGrowth_(Pattern &p, Pattern *child, EdgeGrowth< GUM_SCALAR > &edge_growth)
Raise different exceptions if child is invalid or illegal.
std::list< NodeId > & children(const Pattern &p)
Returns the list of p children in this DFSTree.
bool _test_equality_(HashTable< PRMClassElement< GUM_SCALAR > *, Size > &x, HashTable< PRMClassElement< GUM_SCALAR > *, Size > &y)
SearchStrategy< GUM_SCALAR > & strategy()
strategy getter
double frequency(const Pattern &p) const
Returns the frequency of p respecting it's maximal independent set.
Pattern & parent(const Pattern &p)
Returns the parent of p in this DFSTree.
void addRoot(LabelData &data)
Add a one edge Pattern in this DFSTree.
Definition DFSTree_tpl.h:70
UndiGraph & iso_graph(const Pattern &p)
Returns the isomorphism graph of p in the interface graph.
DFSTree(const InterfaceGraph< GUM_SCALAR > &graph, SearchStrategy< GUM_SCALAR > *strategy=0)
Default constructor.
Pattern & growPattern(Pattern &p, EdgeGrowth< GUM_SCALAR > &edge_growth, Size min_freq)
Add a one edge growth of p as one of its child.
void _addChild_(Pattern &p, Pattern *child, EdgeGrowth< GUM_SCALAR > &edge_growth)
Add a child to this DFSTree.
PatternData & data(const Pattern &p)
void _initialiaze_root_(Pattern *p, Sequence< EdgeData< GUM_SCALAR > * > &seq)
This initialize the DSFTree with a new root.
std::list< NodeId > & roots()
Returns the list of root patterns in this DFSTree.
HashTable< Pattern *, PatternData * > _data_
Data about patterns in this DFSTree.
Definition DFSTree.h:277
bool _is_new_seq_(Sequence< PRMInstance< GUM_SCALAR > * > &seq, NodeProperty< Sequence< PRMInstance< GUM_SCALAR > * > * > &iso_map)
Check if an instance match is redundant.
Pattern & pattern(NodeId id)
Returns the pattern represented by id in this DFSTree.
const InterfaceGraph< GUM_SCALAR > & internalGraph() const
Returns the list of root patterns in this DFSTree.
~DFSTree() override
Destructor.
Definition DFSTree_tpl.h:58
Bijection< NodeId, Pattern * > _node_map_
The mapping between nodes in this DFSTree and the patterns they represents.
Definition DFSTree.h:274
const InterfaceGraph< GUM_SCALAR > * _graph_
The interface graph on which this DFSTree applies.
Definition DFSTree.h:267
Set< NodeId > & max_indep_set(const Pattern &p)
Returns the maximal independent set of p isomorphism graph.
std::list< NodeId > _roots_
The list of root patterns in this DFSTree.
Definition DFSTree.h:270
Inner class to handle data about edges in graph.
This class is used to define an edge growth of a pattern in this DFSTree.
Definition edgeGrowth.h:73
NodeId u
The id of the node from which we grow an edge.
Definition edgeGrowth.h:83
NodeProperty< std::pair< PRMInstance< GUM_SCALAR > *, PRMInstance< GUM_SCALAR > * > > matches
The mapping between the u and v for each match in the interface graph.
Definition edgeGrowth.h:95
NodeId v
If the growth is backward you must assigned the subscript of v, otherwise 0 is assigned (recall that ...
Definition edgeGrowth.h:90
LabelData * edge
The LabelData over the edge of this edge growth.
Definition edgeGrowth.h:85
LabelData * l_v
The LabelData over the node of this edge growth.
Definition edgeGrowth.h:87
This is class is an implementation of a simple serach strategy for the gspan algorithm: it accept a g...
This class represent the interface graph of a given gum::prm::PRMSystem<GUM_SCALAR>.
This contains all the information we want for a node in a DFSTree.
Definition pattern.h:90
bool isMinimal()
Returns the DFSCode of this Pattern.
Definition pattern.cpp:71
NodeId addNodeWithLabel(LabelData &l)
Insert a node with the given LabelData.
Definition pattern_inl.h:69
DFSCode & code()
Returns the DFSCode of this Pattern.
void addArc(NodeId i, NodeId j, LabelData &l)
Add an arc to this Pattern.
EdgeCode & edgeCode(NodeId tail, NodeId head)
Returns the EdgeCode of an edge of this Pattern.
This is an abstract class used to tune search strategies in the gspan algorithm.
Headers of the DFSTree class.
#define GUM_ERROR(type, msg)
Definition exceptions.h:76
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition types.h:74
Size Idx
Type for indexes.
Definition types.h:79
Size NodeId
Type for node ids.
HashTable< NodeId, VAL > NodeProperty
Property on graph elements.
std::ostream & operator<<(std::ostream &out, const DFSCode &code)
Print code in out.
Definition DFSCode.cpp:59
namespace for all probabilistic relational models entities
Definition agrum.h:68
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
This is used to generate the max_indep_set of a Pattern.
Definition DFSTree.h:250
NeighborDegreeSort(UndiGraph &graph)
Constructor.
bool operator()(NodeId i, NodeId j)
The operator used to sort stuff.
UndiGraph & g
The isomorphism graph.
Definition DFSTree.h:260
Pattern * pattern
The pattern.
Definition DFSTree.h:108
PatternData(Pattern *p)
Constructor.
Size cost
The cost of this Pattern.
Definition DFSTree.h:118
Size gain
The gain of this Pattern.
Definition DFSTree.h:120
NodeProperty< Sequence< PRMInstance< GUM_SCALAR > * > * > iso_map
The instances matching p in the interface graph.
Definition DFSTree.h:114
UndiGraph iso_graph
The isomorphism graph of the pattern.
Definition DFSTree.h:112
Set< NodeId > max_indep_set
The maximal independent set of p.
Definition DFSTree.h:116
std::list< NodeId > children
The list of the pattern's children, sorted lexicographically.
Definition DFSTree.h:110
represent a DFS code used by gspan.
Definition edgeCode.h:72
bool isBackward() const
Returns true if this EdgeCode is a backward edge.
Inner class to handle data about labels in this interface graph.