aGrUM
0.20.3
a C++ library for (probabilistic) graphical models
DBRowGeneratorEM_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
/** @file
23
* @brief A DBRowGenerator class that returns incomplete rows as EM would do
24
*
25
* @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
26
*/
27
#
include
<
agrum
/
tools
/
database
/
DBRowGeneratorIdentity
.
h
>
28
29
#
ifndef
DOXYGEN_SHOULD_SKIP_THIS
30
31
namespace
gum
{
32
33
namespace
learning
{
34
35
/// returns the allocator used
36
template
<
typename
GUM_SCALAR
,
template
<
typename
>
class
ALLOC
>
37
INLINE
typename
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::
allocator_type
38
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::
getAllocator
()
const
{
39
return
DBRowGenerator
<
ALLOC
>::
getAllocator
();
40
}
41
42
43
/// default constructor
44
template
<
typename
GUM_SCALAR
,
template
<
typename
>
class
ALLOC
>
45
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::
DBRowGeneratorEM
(
46
const
std
::
vector
<
DBTranslatedValueType
,
ALLOC
<
DBTranslatedValueType
> >
column_types
,
47
const
BayesNet
<
GUM_SCALAR
>&
bn
,
48
const
Bijection
<
NodeId
,
std
::
size_t
,
ALLOC
<
std
::
size_t
> >&
nodeId2columns
,
49
const
typename
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::
allocator_type
&
alloc
) :
50
DBRowGeneratorWithBN
<
GUM_SCALAR
,
ALLOC
>(
column_types
,
51
bn
,
52
DBRowGeneratorGoal
::
ONLY_REMOVE_MISSING_VALUES
,
53
nodeId2columns
,
54
alloc
),
55
_filled_row1_
(
bn
.
size
(), 1.0,
alloc
),
_filled_row2_
(
bn
.
size
(), 1.0,
alloc
) {
56
setBayesNet
(
bn
);
57
58
GUM_CONSTRUCTOR
(
DBRowGeneratorEM
);
59
}
60
61
62
/// copy constructor with a given allocator
63
template
<
typename
GUM_SCALAR
,
template
<
typename
>
class
ALLOC
>
64
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::
DBRowGeneratorEM
(
65
const
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>&
from
,
66
const
typename
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::
allocator_type
&
alloc
) :
67
DBRowGeneratorWithBN
<
GUM_SCALAR
,
ALLOC
>(
from
,
alloc
),
68
_input_row_
(
from
.
_input_row_
),
_missing_cols_
(
from
.
_missing_cols_
),
69
_nb_miss_
(
from
.
_nb_miss_
),
_joint_proba_
(
from
.
_joint_proba_
),
70
_filled_row1_
(
from
.
_filled_row1_
),
_filled_row2_
(
from
.
_filled_row2_
),
71
_use_filled_row1_
(
from
.
_use_filled_row1_
),
_original_weight_
(
from
.
_original_weight_
) {
72
if
(
from
.
_joint_inst_
!=
nullptr
) {
73
_joint_inst_
=
new
Instantiation
(
_joint_proba_
);
74
const
auto
&
var_seq
=
_joint_inst_
->
variablesSequence
();
75
const
std
::
size_t
size
=
var_seq
.
size
();
76
for
(
std
::
size_t
i
=
std
::
size_t
(0);
i
<
size
; ++
i
) {
77
_joint_inst_
->
chgVal
(
Idx
(
i
),
from
.
_joint_inst_
->
val
(
i
));
78
}
79
}
80
81
GUM_CONS_CPY
(
DBRowGeneratorEM
);
82
}
83
84
85
/// copy constructor
86
template
<
typename
GUM_SCALAR
,
template
<
typename
>
class
ALLOC
>
87
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::
DBRowGeneratorEM
(
88
const
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>&
from
) :
89
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>(
from
,
from
.
getAllocator
()) {}
90
91
92
/// move constructor with a given allocator
93
template
<
typename
GUM_SCALAR
,
template
<
typename
>
class
ALLOC
>
94
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::
DBRowGeneratorEM
(
95
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>&&
from
,
96
const
typename
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::
allocator_type
&
alloc
) :
97
DBRowGeneratorWithBN
<
GUM_SCALAR
,
ALLOC
>(
std
::
move
(
from
),
alloc
),
98
_input_row_
(
from
.
_input_row_
),
_missing_cols_
(
std
::
move
(
from
.
_missing_cols_
)),
99
_nb_miss_
(
from
.
_nb_miss_
),
_joint_proba_
(
std
::
move
(
from
.
_joint_proba_
)),
100
_filled_row1_
(
std
::
move
(
from
.
_filled_row1_
)),
_filled_row2_
(
std
::
move
(
from
.
_filled_row2_
)),
101
_use_filled_row1_
(
from
.
_use_filled_row1_
),
_original_weight_
(
from
.
_original_weight_
) {
102
if
(
from
.
_joint_inst_
!=
nullptr
) {
103
_joint_inst_
=
new
Instantiation
(
_joint_proba_
);
104
const
auto
&
var_seq
=
_joint_inst_
->
variablesSequence
();
105
const
std
::
size_t
size
=
var_seq
.
size
();
106
for
(
std
::
size_t
i
=
std
::
size_t
(0);
i
<
size
; ++
i
) {
107
_joint_inst_
->
chgVal
(
Idx
(
i
),
from
.
_joint_inst_
->
val
(
i
));
108
}
109
}
110
111
GUM_CONS_MOV
(
DBRowGeneratorEM
);
112
}
113
114
115
/// move constructor
116
template
<
typename
GUM_SCALAR
,
template
<
typename
>
class
ALLOC
>
117
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::
DBRowGeneratorEM
(
118
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>&&
from
) :
119
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>(
std
::
move
(
from
),
from
.
getAllocator
()) {}
120
121
122
/// virtual copy constructor with a given allocator
123
template
<
typename
GUM_SCALAR
,
template
<
typename
>
class
ALLOC
>
124
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>*
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::
clone
(
125
const
typename
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::
allocator_type
&
alloc
)
const
{
126
ALLOC
<
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
> >
allocator
(
alloc
);
127
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>*
generator
=
allocator
.
allocate
(1);
128
try
{
129
allocator
.
construct
(
generator
, *
this
,
alloc
);
130
}
catch
(...) {
131
allocator
.
deallocate
(
generator
, 1);
132
throw
;
133
}
134
return
generator
;
135
}
136
137
138
/// virtual copy constructor
139
template
<
typename
GUM_SCALAR
,
template
<
typename
>
class
ALLOC
>
140
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>*
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::
clone
()
const
{
141
return
clone
(
this
->
getAllocator
());
142
}
143
144
145
/// destructor
146
template
<
typename
GUM_SCALAR
,
template
<
typename
>
class
ALLOC
>
147
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::~
DBRowGeneratorEM
() {
148
if
(
_joint_inst_
!=
nullptr
)
delete
_joint_inst_
;
149
GUM_DESTRUCTOR
(
DBRowGeneratorEM
);
150
}
151
152
153
/// copy operator
154
template
<
typename
GUM_SCALAR
,
template
<
typename
>
class
ALLOC
>
155
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>&
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::
operator
=(
156
const
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>&
from
) {
157
if
(
this
!= &
from
) {
158
DBRowGeneratorWithBN
<
GUM_SCALAR
,
ALLOC
>::
operator
=(
from
);
159
_input_row_
=
from
.
_input_row_
;
160
_missing_cols_
=
from
.
_missing_cols_
;
161
_nb_miss_
=
from
.
_nb_miss_
;
162
_joint_proba_
=
from
.
_joint_proba_
;
163
_filled_row1_
=
from
.
_filled_row1_
;
164
_filled_row2_
=
from
.
_filled_row2_
;
165
_use_filled_row1_
=
from
.
_use_filled_row1_
;
166
_original_weight_
=
from
.
_original_weight_
;
167
168
if
(
_joint_inst_
!=
nullptr
) {
169
delete
_joint_inst_
;
170
_joint_inst_
=
nullptr
;
171
}
172
173
if
(
from
.
_joint_inst_
!=
nullptr
) {
174
_joint_inst_
=
new
Instantiation
(
_joint_proba_
);
175
const
auto
&
var_seq
=
_joint_inst_
->
variablesSequence
();
176
const
std
::
size_t
size
=
var_seq
.
size
();
177
for
(
std
::
size_t
i
=
std
::
size_t
(0);
i
<
size
; ++
i
) {
178
_joint_inst_
->
chgVal
(
Idx
(
i
),
from
.
_joint_inst_
->
val
(
i
));
179
}
180
}
181
}
182
183
return
*
this
;
184
}
185
186
187
/// move operator
188
template
<
typename
GUM_SCALAR
,
template
<
typename
>
class
ALLOC
>
189
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>&
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::
operator
=(
190
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>&&
from
) {
191
if
(
this
!= &
from
) {
192
DBRowGeneratorWithBN
<
GUM_SCALAR
,
ALLOC
>::
operator
=(
std
::
move
(
from
));
193
_input_row_
=
from
.
_input_row_
;
194
_missing_cols_
=
std
::
move
(
from
.
_missing_cols_
);
195
_nb_miss_
=
from
.
_nb_miss_
;
196
_joint_proba_
=
std
::
move
(
from
.
_joint_proba_
);
197
_filled_row1_
=
std
::
move
(
from
.
_filled_row1_
);
198
_filled_row2_
=
std
::
move
(
from
.
_filled_row2_
);
199
_use_filled_row1_
=
from
.
_use_filled_row1_
;
200
_original_weight_
=
from
.
_original_weight_
;
201
202
if
(
_joint_inst_
!=
nullptr
) {
203
delete
_joint_inst_
;
204
_joint_inst_
=
nullptr
;
205
}
206
207
if
(
from
.
_joint_inst_
!=
nullptr
) {
208
_joint_inst_
=
new
Instantiation
(
_joint_proba_
);
209
const
auto
&
var_seq
=
_joint_inst_
->
variablesSequence
();
210
const
std
::
size_t
size
=
var_seq
.
size
();
211
for
(
std
::
size_t
i
=
std
::
size_t
(0);
i
<
size
; ++
i
) {
212
_joint_inst_
->
chgVal
(
Idx
(
i
),
from
.
_joint_inst_
->
val
(
i
));
213
}
214
}
215
}
216
217
return
*
this
;
218
}
219
220
221
/// generates new lines from those the generator gets in input
222
template
<
typename
GUM_SCALAR
,
template
<
typename
>
class
ALLOC
>
223
INLINE
const
DBRow
<
DBTranslatedValue
,
ALLOC
>&
224
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::
generate
() {
225
this
->
decreaseRemainingRows
();
226
227
// if everything is observed, return the input row
228
if
(
_input_row_
!=
nullptr
)
return
*
_input_row_
;
229
230
if
(
_use_filled_row1_
) {
231
// get the weight of the row from the joint probability
232
_filled_row1_
.
setWeight
(
_joint_proba_
.
get
(*
_joint_inst_
) *
_original_weight_
);
233
234
// fill the values of the row
235
for
(
std
::
size_t
i
=
std
::
size_t
(0);
i
<
_nb_miss_
; ++
i
)
236
_filled_row1_
[
_missing_cols_
[
i
]].
discr_val
=
_joint_inst_
->
val
(
i
);
237
238
_joint_inst_
->
inc
();
239
_use_filled_row1_
=
false
;
240
241
return
_filled_row1_
;
242
}
else
{
243
// get the weight of the row from the joint probability
244
_filled_row2_
.
setWeight
(
_joint_proba_
.
get
(*
_joint_inst_
) *
_original_weight_
);
245
246
// fill the values of the row
247
for
(
std
::
size_t
i
=
std
::
size_t
(0);
i
<
_nb_miss_
; ++
i
)
248
_filled_row2_
[
_missing_cols_
[
i
]].
discr_val
=
_joint_inst_
->
val
(
i
);
249
250
_joint_inst_
->
inc
();
251
_use_filled_row1_
=
true
;
252
253
return
_filled_row2_
;
254
}
255
}
256
257
258
/// computes the rows it will provide in output
259
template
<
typename
GUM_SCALAR
,
template
<
typename
>
class
ALLOC
>
260
INLINE
std
::
size_t
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::
computeRows_
(
261
const
DBRow
<
DBTranslatedValue
,
ALLOC
>&
row
) {
262
// check if there are unobserved values among the columns of interest.
263
// If this is the case, set them as targets
264
bool
found_unobserved
=
false
;
265
const
auto
&
xrow
=
row
.
row
();
266
for
(
const
auto
col
:
this
->
columns_of_interest_
) {
267
switch
(
this
->
column_types_
[
col
]) {
268
case
DBTranslatedValueType
::
DISCRETE
:
269
if
(
xrow
[
col
].
discr_val
==
std
::
numeric_limits
<
std
::
size_t
>::
max
()) {
270
if
(!
found_unobserved
) {
271
_missing_cols_
.
clear
();
272
found_unobserved
=
true
;
273
}
274
_missing_cols_
.
push_back
(
col
);
275
}
276
break
;
277
278
case
DBTranslatedValueType
::
CONTINUOUS
:
279
GUM_ERROR
(
NotImplementedYet
,
280
"The BDRowGeneratorEM does not handle yet continuous "
281
<<
"variables. But the variable in column"
<<
col
<<
" is continuous."
);
282
break
;
283
284
default
:
285
GUM_ERROR
(
NotImplementedYet
,
286
"DBTranslatedValueType "
<<
int
(
this
->
column_types_
[
col
])
287
<<
" is not supported yet"
);
288
}
289
}
290
291
// if there is no unobserved value, make the _input_row_ point to the row
292
if
(!
found_unobserved
) {
293
_input_row_
= &
row
;
294
return
std
::
size_t
(1);
295
}
296
297
_input_row_
=
nullptr
;
298
_nb_miss_
=
_missing_cols_
.
size
();
299
_original_weight_
=
row
.
weight
();
300
301
// here, there are missing symbols, so we should compute the distribution
302
// of the missing values. For this purpose, we use Variable Elimination
303
VariableElimination
<
GUM_SCALAR
>
ve
(
this
->
bn_
);
304
305
// add the targets and fill the output row with the observed values
306
NodeSet
target_set
(
_nb_miss_
);
307
if
(
this
->
nodeId2columns_
.
empty
()) {
308
std
::
size_t
i
=
std
::
size_t
(0);
309
bool
end_miss
=
false
;
310
for
(
const
auto
col
:
this
->
columns_of_interest_
) {
311
if
(!
end_miss
&& (
col
==
_missing_cols_
[
i
])) {
312
target_set
.
insert
(
NodeId
(
col
));
313
++
i
;
314
if
(
i
==
_nb_miss_
)
end_miss
=
true
;
315
}
else
{
316
_filled_row1_
[
col
].
discr_val
=
xrow
[
col
].
discr_val
;
317
_filled_row2_
[
col
].
discr_val
=
xrow
[
col
].
discr_val
;
318
}
319
}
320
}
else
{
321
std
::
size_t
i
=
std
::
size_t
(0);
322
bool
end_miss
=
false
;
323
for
(
const
auto
col
:
this
->
columns_of_interest_
) {
324
if
(!
end_miss
&& (
col
==
_missing_cols_
[
i
])) {
325
target_set
.
insert
(
this
->
nodeId2columns_
.
first
(
col
));
326
++
i
;
327
if
(
i
==
_nb_miss_
)
end_miss
=
true
;
328
}
else
{
329
_filled_row1_
[
col
].
discr_val
=
xrow
[
col
].
discr_val
;
330
_filled_row2_
[
col
].
discr_val
=
xrow
[
col
].
discr_val
;
331
}
332
}
333
}
334
335
ve
.
addJointTarget
(
target_set
);
336
337
// add the evidence and the target
338
const
std
::
size_t
row_size
=
xrow
.
size
();
339
if
(
this
->
nodeId2columns_
.
empty
()) {
340
for
(
std
::
size_t
col
=
std
::
size_t
(0);
col
<
row_size
; ++
col
) {
341
switch
(
this
->
column_types_
[
col
]) {
342
case
DBTranslatedValueType
::
DISCRETE
:
343
// only observed values are evidence
344
if
(
xrow
[
col
].
discr_val
!=
std
::
numeric_limits
<
std
::
size_t
>::
max
()) {
345
ve
.
addEvidence
(
NodeId
(
col
),
xrow
[
col
].
discr_val
);
346
}
347
break
;
348
349
case
DBTranslatedValueType
::
CONTINUOUS
:
350
GUM_ERROR
(
NotImplementedYet
,
351
"The BDRowGeneratorEM does not handle yet continuous "
352
<<
"variables. But the variable in column"
<<
col
<<
" is continuous."
);
353
break
;
354
355
default
:
356
GUM_ERROR
(
NotImplementedYet
,
357
"DBTranslatedValueType "
<<
int
(
this
->
column_types_
[
col
])
358
<<
" is not supported yet"
);
359
}
360
}
361
}
else
{
362
for
(
std
::
size_t
col
=
std
::
size_t
(0);
col
<
row_size
; ++
col
) {
363
switch
(
this
->
column_types_
[
col
]) {
364
case
DBTranslatedValueType
::
DISCRETE
:
365
// only observed values are evidence
366
if
(
xrow
[
col
].
discr_val
!=
std
::
numeric_limits
<
std
::
size_t
>::
max
()) {
367
ve
.
addEvidence
(
this
->
nodeId2columns_
.
first
(
col
),
xrow
[
col
].
discr_val
);
368
}
369
break
;
370
371
case
DBTranslatedValueType
::
CONTINUOUS
:
372
GUM_ERROR
(
NotImplementedYet
,
373
"The BDRowGeneratorEM does not handle yet continuous "
374
<<
"variables. But the variable in column"
<<
col
<<
" is continuous."
);
375
break
;
376
377
default
:
378
GUM_ERROR
(
NotImplementedYet
,
379
"DBTranslatedValueType "
<<
int
(
this
->
column_types_
[
col
])
380
<<
" is not supported yet"
);
381
}
382
}
383
}
384
385
// get the potential of the target set
386
Potential
<
GUM_SCALAR
>&
pot
387
=
const_cast
<
Potential
<
GUM_SCALAR
>& >(
ve
.
jointPosterior
(
target_set
));
388
_joint_proba_
=
std
::
move
(
pot
);
389
if
(
_joint_inst_
!=
nullptr
)
delete
_joint_inst_
;
390
_joint_inst_
=
new
Instantiation
(
_joint_proba_
);
391
392
// get the mapping between variables of the joint proba and the
393
// columns in the database
394
const
auto
&
var_sequence
=
_joint_proba_
.
variablesSequence
();
395
if
(
this
->
nodeId2columns_
.
empty
()) {
396
for
(
std
::
size_t
i
=
std
::
size_t
(0);
i
<
_nb_miss_
; ++
i
) {
397
_missing_cols_
[
i
] =
std
::
size_t
(
this
->
bn_
->
nodeId
(*(
var_sequence
[
i
])));
398
}
399
}
else
{
400
for
(
std
::
size_t
i
=
std
::
size_t
(0);
i
<
_nb_miss_
; ++
i
) {
401
_missing_cols_
[
i
] =
this
->
nodeId2columns_
.
second
(
this
->
bn_
->
nodeId
(*(
var_sequence
[
i
])));
402
}
403
}
404
405
return
std
::
size_t
(
_joint_proba_
.
domainSize
());
406
}
407
408
409
/// assign a new Bayes net to the generator
410
template
<
typename
GUM_SCALAR
,
template
<
typename
>
class
ALLOC
>
411
void
DBRowGeneratorEM
<
GUM_SCALAR
,
ALLOC
>::
setBayesNet
(
const
BayesNet
<
GUM_SCALAR
>&
new_bn
) {
412
// check that if nodeId2columns is not empty, then all the columns
413
// correspond to nodes of the BN
414
if
(!
this
->
nodeId2columns_
.
empty
()) {
415
const
DAG
&
dag
=
new_bn
.
dag
();
416
for
(
auto
iter
=
this
->
nodeId2columns_
.
begin
();
iter
!=
this
->
nodeId2columns_
.
end
();
417
++
iter
) {
418
if
(!
dag
.
existsNode
(
iter
.
first
())) {
419
GUM_ERROR
(
IdError
,
420
"Column "
<<
iter
.
second
() <<
" of the database is associated to Node ID "
421
<<
iter
.
first
()
422
<<
", which does not belong to the Bayesian network"
);
423
}
424
}
425
}
426
427
DBRowGeneratorWithBN
<
GUM_SCALAR
,
ALLOC
>::
setBayesNet
(
new_bn
);
428
429
// we determine the size of the filled rows
430
std
::
size_t
size
=
std
::
size_t
(0);
431
if
(
this
->
nodeId2columns_
.
empty
()) {
432
for
(
auto
node
:
new_bn
.
dag
())
433
if
(
std
::
size_t
(
node
) >
size
)
size
=
std
::
size_t
(
node
);
434
}
else
{
435
for
(
auto
iter
=
this
->
nodeId2columns_
.
begin
();
iter
!=
this
->
nodeId2columns_
.
end
();
436
++
iter
) {
437
if
(
iter
.
second
() >
size
)
size
=
iter
.
second
();
438
}
439
}
440
_filled_row1_
.
resize
(
size
+ 1);
441
_filled_row2_
.
resize
(
size
+ 1);
442
}
443
444
}
/* namespace learning */
445
446
}
/* namespace gum */
447
448
#
endif
/* DOXYGEN_SHOULD_SKIP_THIS */
gum::Set::emplace
INLINE void emplace(Args &&... args)
Definition:
set_tpl.h:643
gum::learning::genericBNLearner::Database::Database
Database(const std::string &filename, const BayesNet< GUM_SCALAR > &bn, const std::vector< std::string > &missing_symbols)
Definition:
genericBNLearner_tpl.h:31