aGrUM
0.20.2
a C++ library for (probabilistic) graphical models
indexedTree_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 Implementation of tree data structures
25
*
26
* @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
27
*/
28
29
// to ease IDE parser
30
#
include
<
agrum
/
tools
/
core
/
indexedTree
.
h
>
31
32
namespace
gum
{
33
/* =========================================================================*/
34
/* =========================================================================*/
35
/* === IMPLEMENTATION OF NODES FOR GENERIC TREE (DATA) STRUCTURE === */
36
/* =========================================================================*/
37
/* =========================================================================*/
38
39
// creates a tree with one node (with or without data)
40
41
template
<
typename
Key,
typename
Data >
42
IndexedTree< Key, Data >::IndexedTree(
const
Key& theKey, Data* theData) :
43
key(theKey), data(theData), parent(0) {
44
// for debugging purposes
45
GUM_CONSTRUCTOR(IndexedTree);
46
}
47
48
// creates a tree with one node (with or without data)
49
50
template
<
typename
Key
,
typename
Data
>
51
IndexedTree
<
Key
,
Data
>::
IndexedTree
(
Data
*
theData
) :
data
(
theData
),
parent
(0) {
52
// for debugging purposes
53
GUM_CONSTRUCTOR
(
IndexedTree
);
54
}
55
56
// creates a tree with one node with data
57
58
template
<
typename
Key
,
typename
Data
>
59
IndexedTree
<
Key
,
Data
>::
IndexedTree
(
const
Key
&
theKey
,
const
Data
&
theData
) :
60
key
(
theKey
),
data
(
new
Data
(
theData
)),
parent
(0) {
61
// for debugging purposes
62
GUM_CONSTRUCTOR
(
IndexedTree
);
63
}
64
65
// copy constructor
66
67
template
<
typename
Key
,
typename
Data
>
68
IndexedTree
<
Key
,
Data
>::
IndexedTree
(
const
IndexedTree
<
Key
,
Data
>&
from
) :
69
key
(
from
.
key
),
data
(0),
parent
(0) {
70
// for debugging purposes
71
GUM_CONS_CPY
(
IndexedTree
);
72
73
try
{
74
// create the data of the node
75
if
(
from
.
data
)
data
=
new
Data
(*
from
.
data
);
76
77
// create and link properly the children
78
children
=
from
.
children
;
79
80
for
(
HashTableIteratorSafe
<
Key
,
IndexedTree
<
Key
,
Data
> >
iter
81
=
children
.
begin
();
82
iter
!=
children
.
end
();
83
++
iter
)
84
iter
->
parent
=
this
;
85
}
catch
(...) {
86
if
(
data
)
delete
data
;
87
88
children
.
clear
();
89
90
throw
;
91
}
92
}
93
94
// copy operator
95
96
template
<
typename
Key
,
typename
Data
>
97
IndexedTree
<
Key
,
Data
>&
98
IndexedTree
<
Key
,
Data
>::
operator
=(
const
IndexedTree
<
Key
,
Data
>&
from
) {
99
// avoid self assignment
100
if
(
this
!= &
from
) {
101
// for debugging purposes
102
GUM_OP_CPY
(
IndexedTree
);
103
104
try
{
105
key
=
from
.
key
;
106
107
if
(
data
)
delete
data
;
108
109
if
(
from
.
data
)
110
data
=
new
Data
(*
from
.
data
);
111
else
112
data
= 0;
113
114
children
=
from
.
children
;
115
116
for
(
HashTableIteratorSafe
<
Key
,
IndexedTree
<
Key
,
Data
> >
iter
117
=
children
.
begin
();
118
iter
!=
children
.
end
();
119
++
iter
)
120
iter
->
parent
=
this
;
121
}
catch
(...) {
122
if
(
data
)
delete
data
;
123
124
children
.
clear
();
125
126
throw
;
127
}
128
}
129
130
return
*
this
;
131
}
132
133
// destructor
134
135
template
<
typename
Key
,
typename
Data
>
136
IndexedTree
<
Key
,
Data
>::~
IndexedTree
() {
137
// for debugging purposes
138
GUM_DESTRUCTOR
(
IndexedTree
);
139
140
if
(
data
)
delete
data
;
141
}
142
143
// adds a new node into the tree
144
145
template
<
typename
Key
,
typename
Data
>
146
void
IndexedTree
<
Key
,
Data
>::
insertNode
(
const
std
::
vector
<
Key
>&
index
,
147
const
Data
*
theData
) {
148
// parse the tree until we are on the proper index. Then, insert the new
149
// node.
150
// current_node is a pointer on the node of the tree corresponding to
151
// position
152
// i in vector index. When i+2 < index.size(), we need go down into the tree
153
// structure before we can insert the new node
154
IndexedTree
<
Key
,
Data
>*
current_node
=
this
;
155
unsigned
int
i
;
156
157
for
(
i
= 0;
i
+ 1 <
index
.
size
(); ++
i
) {
158
// if the node that should be on the path between the root of the tree and
159
// the node that we wish to insert does not exist, create it
160
if
(!
children
.
exists
(
index
[
i
])) {
161
IndexedTree
<
Key
,
Data
>*
new_node
162
=
new
IndexedTree
<
Key
,
Data
>(
index
[
i
], (
Data
*)0);
163
current_node
->
children
.
insert
(
index
[
i
],
new_node
);
164
new_node
->
parent
=
this
;
165
current_node
=
new_node
;
166
}
else
167
current_node
=
current_node
->
children
[
index
[
i
]];
168
}
169
170
// here, we can insert the new node. if ind + 1 == index.size(), this means
171
// that
172
// the index vector was not empty, else the vector was empty and we are at
173
// the
174
// root of the tree
175
if
(
i
+ 1 ==
index
.
size
()) {
176
// if the node to be inserted already exist, throw an exception
177
if
(
current_node
->
children
.
exists
(
index
[
i
])) {
178
GUM_ERROR
(
DuplicateElement
,
"the indexed tree already contains the node"
);
179
}
180
181
// here, the node to be inserted does not exist, so we must create it
182
IndexedTree
<
Key
,
Data
>*
new_node
183
=
new
IndexedTree
<
Key
,
Data
>(
index
[
i
],
const_cast
<
Data
* >(
theData
));
184
185
current_node
->
children
.
insert
(
index
[
i
],
new_node
);
186
187
new_node
->
parent
=
current_node
;
188
}
else
{
189
// here, the node to be inserted is the root of the tree (so it already
190
// exists)
191
GUM_ERROR
(
DuplicateElement
,
"the indexed tree already contains the node"
);
192
}
193
}
194
195
// adds a new node into the tree
196
197
template
<
typename
Key
,
typename
Data
>
198
void
IndexedTree
<
Key
,
Data
>::
insertNode
(
const
std
::
vector
<
Key
>&
index
,
199
const
Data
&
theData
) {
200
// parse the tree until we are on the proper index. Then, insert the new
201
// node.
202
// current_node is a pointer on the node of the tree corresponding to
203
// position
204
// i in vector index. When i+2 < index.size(), we need go down into the tree
205
// structure before we can insert the new node
206
IndexedTree
<
Key
,
Data
>*
current_node
=
this
;
207
unsigned
int
i
;
208
209
for
(
i
= 0;
i
+ 1 <
index
.
size
(); ++
i
) {
210
// if the node that should be on the path between the root of the tree and
211
// the node that we wish to insert does not exist, create it
212
if
(!
children
.
exists
(
index
[
i
])) {
213
IndexedTree
<
Key
,
Data
>*
new_node
214
=
new
IndexedTree
<
Key
,
Data
>(
index
[
i
], (
Data
*)0);
215
current_node
->
children
.
insert
(
index
[
i
],
new_node
);
216
new_node
->
parent
=
this
;
217
current_node
=
new_node
;
218
}
else
219
current_node
=
current_node
->
children
[
index
[
i
]];
220
}
221
222
// here, we can insert the new node. if ind + 1 == index.size(), this means
223
// that
224
// the index vector was not empty, else the vector was empty and we are at
225
// the
226
// root of the tree
227
if
(
i
+ 1 ==
index
.
size
()) {
228
// if the node to be inserted already exist, throw an exception
229
if
(
current_node
->
children
.
exists
(
index
[
i
])) {
230
GUM_ERROR
(
DuplicateElement
,
"the indexed tree already contains the node"
);
231
}
232
233
// here, the node to be inserted does not exist, so we must create it
234
IndexedTree
<
Key
,
Data
>*
new_node
235
=
new
IndexedTree
<
Key
,
Data
>(
index
[
i
],
theData
);
236
237
current_node
->
children
.
insert
(
index
[
i
],
new_node
);
238
239
new_node
->
parent
=
current_node
;
240
}
else
{
241
// here, the node to be inserted is the root of the tree (so it already
242
// exists)
243
GUM_ERROR
(
DuplicateElement
,
"the indexed tree already contains the node"
);
244
}
245
}
246
247
// updates the value of a node (or adds it if it does not already exist)
248
249
template
<
typename
Key
,
typename
Data
>
250
void
IndexedTree
<
Key
,
Data
>::
setNode
(
const
std
::
vector
<
Key
>&
index
,
251
Data
*
theData
) {
252
// parse the tree until we are on the proper index. Then, insert the new
253
// node.
254
// current_node is a pointer on the node of the tree corresponding to
255
// position
256
// i in vector index. When i+2 < index.size(), we need go down into the tree
257
// structure before we can insert the new node
258
IndexedTree
<
Key
,
Data
>*
current_node
=
this
;
259
unsigned
int
i
;
260
261
for
(
i
= 0;
i
+ 1 <
index
.
size
(); ++
i
) {
262
// if the node that should be on the path between the root of the tree and
263
// the node that we wish to insert does not exist, create it
264
if
(!
children
.
exists
(
index
[
i
])) {
265
IndexedTree
<
Key
,
Data
>*
new_node
266
=
new
IndexedTree
<
Key
,
Data
>(
index
[
i
], (
Data
*)0);
267
current_node
->
children
.
insert
(
index
[
i
],
new_node
);
268
new_node
->
parent
=
this
;
269
current_node
=
new_node
;
270
}
else
271
current_node
=
current_node
->
children
[
index
[
i
]];
272
}
273
274
// here, we can set the new node. if ind + 1 == index.size(), this means
275
// that
276
// the index vector was not empty, else the vector was empty and we are at
277
// the
278
// root of the tree
279
if
(
i
+ 1 ==
index
.
size
()) {
280
// if the node to be set does not exist, create it, else modify it
281
if
(
current_node
->
children
.
exists
(
index
[
i
])) {
282
IndexedTree
<
Key
,
Data
>*
node
=
current_node
->
children
[
index
[
i
]];
283
284
if
(
node
->
data
)
delete
node
->
data
;
285
286
node
->
data
=
theData
;
287
}
else
{
288
// here, the node tobe set does not exist, so we must create it
289
IndexedTree
<
Key
,
Data
>*
new_node
290
=
new
IndexedTree
<
Key
,
Data
>(
index
[
i
],
theData
);
291
current_node
->
children
.
insert
(
index
[
i
],
new_node
);
292
new_node
->
parent
=
current_node
;
293
}
294
}
else
{
295
// here, the node to be set is the root of the tree (so it does already
296
// exist
297
if
(
data
)
delete
data
;
298
299
data
=
theData
;
300
}
301
}
302
303
// updates the value of a node (or adds it if it does not already exist)
304
305
template
<
typename
Key
,
typename
Data
>
306
void
IndexedTree
<
Key
,
Data
>::
setNode
(
const
std
::
vector
<
Key
>&
index
,
307
const
Data
&
theData
) {
308
// parse the tree until we are on the proper index. Then, insert the new
309
// node.
310
// current_node is a pointer on the node of the tree corresponding to
311
// position
312
// i in vector index. When i+2 < index.size(), we need go down into the tree
313
// structure before we can insert the new node
314
IndexedTree
<
Key
,
Data
>*
current_node
=
this
;
315
unsigned
int
i
;
316
317
for
(
i
= 0;
i
+ 1 <
index
.
size
(); ++
i
) {
318
// if the node that should be on the path between the root of the tree and
319
// the node that we wish to insert does not exist, create it
320
if
(!
children
.
exists
(
index
[
i
])) {
321
IndexedTree
<
Key
,
Data
>*
new_node
322
=
new
IndexedTree
<
Key
,
Data
>(
index
[
i
], (
Data
*)0);
323
current_node
->
children
.
insert
(
index
[
i
],
new_node
);
324
new_node
->
parent
=
this
;
325
current_node
=
new_node
;
326
}
else
327
current_node
=
current_node
->
children
[
index
[
i
]];
328
}
329
330
// here, we can set the new node. if ind + 1 == index.size(), this means
331
// that
332
// the index vector was not empty, else the vector was empty and we are at
333
// the
334
// root of the tree
335
if
(
i
+ 1 ==
index
.
size
()) {
336
// if the node to be set does not exist, create it, else modify it
337
if
(
current_node
->
children
.
exists
(
index
[
i
])) {
338
IndexedTree
<
Key
,
Data
>*
node
=
current_node
->
children
[
index
[
i
]];
339
340
if
(
node
->
data
)
delete
node
->
data
;
341
342
node
->
data
=
new
Data
(
theData
);
343
}
else
{
344
// here, the node tobe set does not exist, so we must create it
345
IndexedTree
<
Key
,
Data
>*
new_node
346
=
new
IndexedTree
<
Key
,
Data
>(
index
[
i
],
theData
);
347
current_node
->
children
.
insert
(
index
[
i
],
new_node
);
348
new_node
->
parent
=
current_node
;
349
}
350
}
else
{
351
// here, the node to be set is the root of the tree (so it does already
352
// exist
353
if
(
data
)
delete
data
;
354
355
data
=
new
Data
(
theData
);
356
}
357
}
358
359
// returns the value of a given test from the cache
360
361
template
<
typename
Key
,
typename
Data
>
362
INLINE
Data
&
363
IndexedTree
<
Key
,
Data
>::
getData
(
const
std
::
vector
<
Key
>&
index
)
const
{
364
IndexedTree
<
Key
,
Data
>*
current_node
365
=
const_cast
<
IndexedTree
<
Key
,
Data
>* >(
this
);
366
367
for
(
unsigned
int
i
= 0;
i
<
index
.
size
(); ++
i
)
368
current_node
=
current_node
->
children
[
index
[
i
]];
369
370
if
(
data
== 0) {
GUM_ERROR
(
NotFound
,
"the datum could not be found"
); }
371
372
return
*(
current_node
->
data
);
373
}
374
375
// returns a given node of the tree
376
377
template
<
typename
Key
,
typename
Data
>
378
INLINE
IndexedTree
<
Key
,
Data
>&
379
IndexedTree
<
Key
,
Data
>::
getNode
(
const
std
::
vector
<
Key
>&
index
)
const
{
380
IndexedTree
<
Key
,
Data
>*
current_node
381
=
const_cast
<
IndexedTree
<
Key
,
Data
>* >(
this
);
382
383
for
(
unsigned
int
i
= 0;
i
<
index
.
size
(); ++
i
)
384
current_node
=
current_node
->
children
[
index
[
i
]];
385
386
return
*
current_node
;
387
}
388
389
}
/* namespace gum */
gum::Set::emplace
INLINE void emplace(Args &&... args)
Definition:
set_tpl.h:669