aGrUM
0.21.0
a C++ library for (probabilistic) graphical models
BayesNet_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 Template implementation of BN/BayesNet.h class.
25
*
26
* @author Pierre-Henri WUILLEMIN(@LIP6) and Lionel TORTI
27
*/
28
29
#
include
<
limits
>
30
#
include
<
set
>
31
#
include
<
algorithm
>
32
33
#
include
<
agrum
/
BN
/
BayesNet
.
h
>
34
35
#
include
<
agrum
/
tools
/
variables
/
rangeVariable
.
h
>
36
#
include
<
agrum
/
tools
/
variables
/
labelizedVariable
.
h
>
37
#
include
<
agrum
/
tools
/
variables
/
integerVariable
.
h
>
38
#
include
<
agrum
/
tools
/
variables
/
discretizedVariable
.
h
>
39
40
#
include
<
agrum
/
tools
/
multidim
/
aggregators
/
amplitude
.
h
>
41
#
include
<
agrum
/
tools
/
multidim
/
aggregators
/
and
.
h
>
42
#
include
<
agrum
/
tools
/
multidim
/
aggregators
/
count
.
h
>
43
#
include
<
agrum
/
tools
/
multidim
/
aggregators
/
exists
.
h
>
44
#
include
<
agrum
/
tools
/
multidim
/
aggregators
/
forall
.
h
>
45
#
include
<
agrum
/
tools
/
multidim
/
aggregators
/
max
.
h
>
46
#
include
<
agrum
/
tools
/
multidim
/
aggregators
/
median
.
h
>
47
#
include
<
agrum
/
tools
/
multidim
/
aggregators
/
min
.
h
>
48
#
include
<
agrum
/
tools
/
multidim
/
aggregators
/
or
.
h
>
49
#
include
<
agrum
/
tools
/
multidim
/
aggregators
/
sum
.
h
>
50
51
#
include
<
agrum
/
tools
/
multidim
/
ICIModels
/
multiDimNoisyAND
.
h
>
52
#
include
<
agrum
/
tools
/
multidim
/
ICIModels
/
multiDimNoisyORCompound
.
h
>
53
#
include
<
agrum
/
tools
/
multidim
/
ICIModels
/
multiDimNoisyORNet
.
h
>
54
55
#
include
<
agrum
/
tools
/
multidim
/
ICIModels
/
multiDimLogit
.
h
>
56
57
#
include
<
agrum
/
BN
/
generator
/
simpleCPTGenerator
.
h
>
58
#
include
<
agrum
/
tools
/
core
/
utils_string
.
h
>
59
60
namespace
gum
{
61
template
<
typename
GUM_SCALAR
>
62
NodeId
63
build_node
(
gum
::
BayesNet
<
GUM_SCALAR
>&
bn
,
std
::
string
node
,
gum
::
Size
default_domain_size
) {
64
std
::
string
name
=
node
;
65
auto
ds
=
default_domain_size
;
66
long
range_min
= 0;
67
long
range_max
=
long
(
ds
) - 1;
68
std
::
vector
<
std
::
string
>
labels
;
69
std
::
vector
<
GUM_SCALAR
>
ticks
;
70
71
if
(*(
node
.
rbegin
()) ==
']'
) {
72
auto
posBrack
=
node
.
find
(
'['
);
73
if
(
posBrack
!=
std
::
string
::
npos
) {
74
name
=
node
.
substr
(0,
posBrack
);
75
const
auto
&
s_args
=
node
.
substr
(
posBrack
+ 1,
node
.
size
() -
posBrack
- 2);
76
const
auto
&
args
=
split
(
s_args
,
","
);
77
if
(
args
.
size
() == 0) {
// n[]
78
GUM_ERROR
(
InvalidArgument
,
"Empty range for variable "
<<
node
)
79
}
else
if
(
args
.
size
() == 1) {
// n[4]
80
ds
=
static_cast
<
Size
>(
std
::
stoi
(
args
[0]));
81
range_min
= 0;
82
range_max
=
long
(
ds
) - 1;
83
}
else
if
(
args
.
size
() == 2) {
// n[5,10]
84
range_min
=
std
::
stol
(
args
[0]);
85
range_max
=
std
::
stol
(
args
[1]);
86
if
(1 +
range_max
-
range_min
< 2) {
87
GUM_ERROR
(
InvalidArgument
,
"Invalid range for variable "
<<
node
)
88
}
89
ds
=
static_cast
<
Size
>(1 +
range_max
-
range_min
);
90
}
else
{
// n[3.14,5,10,12]
91
for
(
const
auto
&
tick
:
args
) {
92
ticks
.
push_back
(
static_cast
<
GUM_SCALAR
>(
std
::
atof
(
tick
.
c_str
())));
93
}
94
ds
=
static_cast
<
Size
>(
args
.
size
() - 1);
95
}
96
}
97
}
else
if
(*(
node
.
rbegin
()) ==
'}'
) {
// node like "n{one|two|three}"
98
auto
posBrack
=
node
.
find
(
'{'
);
99
if
(
posBrack
!=
std
::
string
::
npos
) {
100
name
=
node
.
substr
(0,
posBrack
);
101
labels
=
split
(
node
.
substr
(
posBrack
+ 1,
node
.
size
() -
posBrack
- 2),
"|"
);
102
if
(
labels
.
size
() < 2) {
GUM_ERROR
(
InvalidArgument
,
"Not enough labels in node "
<<
node
) }
103
if
(!
hasUniqueElts
(
labels
)) {
104
GUM_ERROR
(
InvalidArgument
,
"Duplicate labels in node "
<<
node
)
105
}
106
ds
=
static_cast
<
Size
>(
labels
.
size
());
107
}
108
}
109
110
if
(
ds
== 0) {
111
GUM_ERROR
(
InvalidArgument
,
"No value for variable "
<<
name
<<
"."
)
112
}
else
if
(
ds
== 1) {
113
GUM_ERROR
(
InvalidArgument
,
114
"Only one value for variable "
<<
name
<<
" (2 at least are needed)."
)
115
}
116
117
std
::
vector
<
int
>
values
;
118
if
(!
labels
.
empty
()) {
119
if
(
std
::
all_of
(
labels
.
begin
(),
labels
.
end
(),
isInteger
)) {
120
for
(
const
auto
&
label
:
labels
)
121
values
.
push_back
(
std
::
stoi
(
label
));
122
}
123
}
124
125
// now we add the node in the BN
126
NodeId
idVar
;
127
try
{
128
idVar
=
bn
.
idFromName
(
name
);
129
}
catch
(
gum
::
NotFound
&) {
130
if
(!
values
.
empty
()) {
131
idVar
=
bn
.
add
(
IntegerVariable
(
name
,
name
,
values
));
132
}
else
if
(!
labels
.
empty
()) {
133
idVar
=
bn
.
add
(
LabelizedVariable
(
name
,
name
,
labels
));
134
}
else
if
(!
ticks
.
empty
()) {
135
idVar
=
bn
.
add
(
DiscretizedVariable
<
GUM_SCALAR
>(
name
,
name
,
ticks
));
136
}
else
{
137
idVar
=
bn
.
add
(
RangeVariable
(
name
,
name
,
range_min
,
range_max
));
138
}
139
}
140
141
return
idVar
;
142
}
143
144
template
<
typename
GUM_SCALAR >
145
BayesNet< GUM_SCALAR > BayesNet<
GUM_SCALAR
>::
fastPrototype
(
const
std
::
string
&
dotlike
,
146
Size
domainSize
) {
147
gum
::
BayesNet
<
GUM_SCALAR
>
bn
;
148
149
150
for
(
const
auto
&
chaine
:
split
(
dotlike
,
";"
)) {
151
NodeId
lastId
= 0;
152
bool
notfirst
=
false
;
153
for
(
const
auto
&
souschaine
:
split
(
chaine
,
"->"
)) {
154
bool
forward
=
true
;
155
for
(
const
auto
&
node
:
split
(
souschaine
,
"<-"
)) {
156
auto
idVar
=
build_node
(
bn
,
node
,
domainSize
);
157
if
(
notfirst
) {
158
if
(
forward
) {
159
bn
.
addArc
(
lastId
,
idVar
);
160
forward
=
false
;
161
}
else
{
162
bn
.
addArc
(
idVar
,
lastId
);
163
}
164
}
else
{
165
notfirst
=
true
;
166
forward
=
false
;
167
}
168
lastId
=
idVar
;
169
}
170
}
171
}
172
bn
.
generateCPTs
();
173
bn
.
setProperty
(
"name"
,
"fastPrototype"
);
174
return
bn
;
175
}
176
177
template
<
typename
GUM_SCALAR
>
178
INLINE
BayesNet
<
GUM_SCALAR
>::
BayesNet
() :
IBayesNet
<
GUM_SCALAR
>() {
179
GUM_CONSTRUCTOR
(
BayesNet
);
180
}
181
182
template
<
typename
GUM_SCALAR
>
183
INLINE
BayesNet
<
GUM_SCALAR
>::
BayesNet
(
std
::
string
name
) :
IBayesNet
<
GUM_SCALAR
>(
name
) {
184
GUM_CONSTRUCTOR
(
BayesNet
);
185
}
186
187
template
<
typename
GUM_SCALAR
>
188
BayesNet
<
GUM_SCALAR
>::
BayesNet
(
const
BayesNet
<
GUM_SCALAR
>&
source
) :
189
IBayesNet
<
GUM_SCALAR
>(
source
),
_varMap_
(
source
.
_varMap_
) {
190
GUM_CONS_CPY
(
BayesNet
);
191
192
_copyPotentials_
(
source
);
193
}
194
195
template
<
typename
GUM_SCALAR
>
196
BayesNet
<
GUM_SCALAR
>&
BayesNet
<
GUM_SCALAR
>::
operator
=(
const
BayesNet
<
GUM_SCALAR
>&
source
) {
197
if
(
this
!= &
source
) {
198
IBayesNet
<
GUM_SCALAR
>::
operator
=(
source
);
199
_varMap_
=
source
.
_varMap_
;
200
201
_clearPotentials_
();
202
_copyPotentials_
(
source
);
203
}
204
205
return
*
this
;
206
}
207
208
template
<
typename
GUM_SCALAR
>
209
BayesNet
<
GUM_SCALAR
>::~
BayesNet
() {
210
GUM_DESTRUCTOR
(
BayesNet
);
211
for
(
const
auto
p
:
_probaMap_
) {
212
delete
p
.
second
;
213
}
214
}
215
216
template
<
typename
GUM_SCALAR
>
217
INLINE
const
DiscreteVariable
&
BayesNet
<
GUM_SCALAR
>::
variable
(
NodeId
id
)
const
{
218
return
_varMap_
.
get
(
id
);
219
}
220
221
template
<
typename
GUM_SCALAR
>
222
INLINE
void
BayesNet
<
GUM_SCALAR
>::
changeVariableName
(
NodeId
id
,
const
std
::
string
&
new_name
) {
223
_varMap_
.
changeName
(
id
,
new_name
);
224
}
225
226
template
<
typename
GUM_SCALAR
>
227
INLINE
void
BayesNet
<
GUM_SCALAR
>::
changeVariableLabel
(
NodeId
id
,
228
const
std
::
string
&
old_label
,
229
const
std
::
string
&
new_label
) {
230
if
(
variable
(
id
).
varType
() !=
VarType
::
Labelized
)
231
GUM_ERROR
(
NotFound
,
"Variable "
<<
id
<<
" is not a LabelizedVariable."
)
232
233
LabelizedVariable
*
var
234
=
dynamic_cast
<
LabelizedVariable
* >(
const_cast
<
DiscreteVariable
* >(&
variable
(
id
)));
235
236
var
->
changeLabel
(
var
->
posLabel
(
old_label
),
new_label
);
237
}
238
239
240
template
<
typename
GUM_SCALAR
>
241
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
nodeId
(
const
DiscreteVariable
&
var
)
const
{
242
return
_varMap_
.
get
(
var
);
243
}
244
245
template
<
typename
GUM_SCALAR
>
246
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
add
(
const
DiscreteVariable
&
var
) {
247
auto
ptr
=
new
MultiDimArray
<
GUM_SCALAR
>();
248
try
{
249
return
add
(
var
,
ptr
);
250
}
catch
(
Exception
&) {
251
delete
ptr
;
252
throw
;
253
}
254
}
255
256
template
<
typename
GUM_SCALAR
>
257
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
add
(
const
std
::
string
&
name
,
unsigned
int
nbrmod
) {
258
if
(
nbrmod
< 2) {
259
GUM_ERROR
(
OperationNotAllowed
,
260
"Variable "
<<
name
<<
"needs more than "
<<
nbrmod
<<
" modalities"
)
261
}
262
263
RangeVariable
v
(
name
,
name
, 0,
nbrmod
- 1);
264
return
add
(
v
);
265
}
266
267
template
<
typename
GUM_SCALAR
>
268
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
add
(
const
DiscreteVariable
&
var
,
269
MultiDimImplementation
<
GUM_SCALAR
>*
aContent
) {
270
NodeId
proposedId
=
dag
().
nextNodeId
();
271
272
return
add
(
var
,
aContent
,
proposedId
);
273
}
274
275
template
<
typename
GUM_SCALAR
>
276
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
add
(
const
DiscreteVariable
&
var
,
NodeId
id
) {
277
auto
ptr
=
new
MultiDimArray
<
GUM_SCALAR
>();
278
279
try
{
280
return
add
(
var
,
ptr
,
id
);
281
282
}
catch
(
Exception
&) {
283
delete
ptr
;
284
throw
;
285
}
286
}
287
288
template
<
typename
GUM_SCALAR
>
289
NodeId
BayesNet
<
GUM_SCALAR
>::
add
(
const
DiscreteVariable
&
var
,
290
MultiDimImplementation
<
GUM_SCALAR
>*
aContent
,
291
NodeId
id
) {
292
_varMap_
.
insert
(
id
,
var
);
293
this
->
dag_
.
addNodeWithId
(
id
);
294
295
auto
cpt
=
new
Potential
<
GUM_SCALAR
>(
aContent
);
296
(*
cpt
) <<
variable
(
id
);
297
_probaMap_
.
insert
(
id
,
cpt
);
298
return
id
;
299
}
300
301
template
<
typename
GUM_SCALAR
>
302
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
idFromName
(
const
std
::
string
&
name
)
const
{
303
return
_varMap_
.
idFromName
(
name
);
304
}
305
306
template
<
typename
GUM_SCALAR
>
307
INLINE
const
DiscreteVariable
&
308
BayesNet
<
GUM_SCALAR
>::
variableFromName
(
const
std
::
string
&
name
)
const
{
309
return
_varMap_
.
variableFromName
(
name
);
310
}
311
312
template
<
typename
GUM_SCALAR
>
313
INLINE
const
Potential
<
GUM_SCALAR
>&
BayesNet
<
GUM_SCALAR
>::
cpt
(
NodeId
varId
)
const
{
314
return
*(
_probaMap_
[
varId
]);
315
}
316
317
template
<
typename
GUM_SCALAR
>
318
INLINE
const
VariableNodeMap
&
BayesNet
<
GUM_SCALAR
>::
variableNodeMap
()
const
{
319
return
_varMap_
;
320
}
321
322
template
<
typename
GUM_SCALAR
>
323
INLINE
void
BayesNet
<
GUM_SCALAR
>::
erase
(
const
DiscreteVariable
&
var
) {
324
erase
(
_varMap_
.
get
(
var
));
325
}
326
327
template
<
typename
GUM_SCALAR
>
328
void
BayesNet
<
GUM_SCALAR
>::
erase
(
NodeId
varId
) {
329
if
(
_varMap_
.
exists
(
varId
)) {
330
// Reduce the variable child's CPT
331
const
NodeSet
&
children
=
this
->
children
(
varId
);
332
333
for
(
const
auto
c
:
children
) {
334
_probaMap_
[
c
]->
erase
(
variable
(
varId
));
335
}
336
337
delete
_probaMap_
[
varId
];
338
339
_probaMap_
.
erase
(
varId
);
340
_varMap_
.
erase
(
varId
);
341
this
->
dag_
.
eraseNode
(
varId
);
342
}
343
}
344
345
template
<
typename
GUM_SCALAR
>
346
void
BayesNet
<
GUM_SCALAR
>::
clear
() {
347
if
(!
this
->
empty
()) {
348
auto
l
=
this
->
nodes
();
349
for
(
const
auto
no
:
l
) {
350
this
->
erase
(
no
);
351
}
352
}
353
}
354
355
template
<
typename
GUM_SCALAR
>
356
INLINE
void
BayesNet
<
GUM_SCALAR
>::
addArc
(
NodeId
tail
,
NodeId
head
) {
357
if
(
this
->
dag_
.
existsArc
(
tail
,
head
)) {
358
GUM_ERROR
(
DuplicateElement
,
"The arc ("
<<
tail
<<
","
<<
head
<<
") already exists."
)
359
}
360
361
this
->
dag_
.
addArc
(
tail
,
head
);
362
// Add parent in the child's CPT
363
(*(
_probaMap_
[
head
])) <<
variable
(
tail
);
364
}
365
366
template
<
typename
GUM_SCALAR
>
367
INLINE
void
BayesNet
<
GUM_SCALAR
>::
addArc
(
const
std
::
string
&
tail
,
const
std
::
string
&
head
) {
368
try
{
369
addArc
(
this
->
idFromName
(
tail
),
this
->
idFromName
(
head
));
370
}
catch
(
DuplicateElement
) {
371
GUM_ERROR
(
DuplicateElement
,
"The arc "
<<
tail
<<
"->"
<<
head
<<
" already exists."
)
372
}
373
}
374
375
template
<
typename
GUM_SCALAR
>
376
INLINE
void
BayesNet
<
GUM_SCALAR
>::
eraseArc
(
const
Arc
&
arc
) {
377
if
(
_varMap_
.
exists
(
arc
.
tail
()) &&
_varMap_
.
exists
(
arc
.
head
())) {
378
NodeId
head
=
arc
.
head
(),
tail
=
arc
.
tail
();
379
this
->
dag_
.
eraseArc
(
arc
);
380
// Remove parent from child's CPT
381
(*(
_probaMap_
[
head
])) >>
variable
(
tail
);
382
}
383
}
384
385
template
<
typename
GUM_SCALAR
>
386
INLINE
void
BayesNet
<
GUM_SCALAR
>::
eraseArc
(
NodeId
tail
,
NodeId
head
) {
387
eraseArc
(
Arc
(
tail
,
head
));
388
}
389
390
template
<
typename
GUM_SCALAR
>
391
void
BayesNet
<
GUM_SCALAR
>::
reverseArc
(
const
Arc
&
arc
) {
392
// check that the arc exists
393
if
(!
_varMap_
.
exists
(
arc
.
tail
()) || !
_varMap_
.
exists
(
arc
.
head
()) || !
dag
().
existsArc
(
arc
)) {
394
GUM_ERROR
(
InvalidArc
,
"a non-existing arc cannot be reversed"
)
395
}
396
397
NodeId
tail
=
arc
.
tail
(),
head
=
arc
.
head
();
398
399
// check that the reversal does not induce a cycle
400
try
{
401
DAG
d
=
dag
();
402
d
.
eraseArc
(
arc
);
403
d
.
addArc
(
head
,
tail
);
404
}
catch
(
Exception
&) {
405
GUM_ERROR
(
InvalidArc
,
"this arc reversal would induce a directed cycle"
)
406
}
407
408
// with the same notations as Shachter (1986), "evaluating influence
409
// diagrams", p.878, we shall first compute the product of probabilities:
410
// pi_j^old (x_j | x_c^old(j) ) * pi_i^old (x_i | x_c^old(i) )
411
Potential
<
GUM_SCALAR
>
prod
{
cpt
(
tail
) *
cpt
(
head
)};
412
413
// modify the topology of the graph: add to tail all the parents of head
414
// and add to head all the parents of tail
415
beginTopologyTransformation
();
416
NodeSet
new_parents
;
417
for
(
const
auto
node
:
this
->
parents
(
tail
))
418
new_parents
.
insert
(
node
);
419
for
(
const
auto
node
:
this
->
parents
(
head
))
420
new_parents
.
insert
(
node
);
421
// remove arc (head, tail)
422
eraseArc
(
arc
);
423
424
// add the necessary arcs to the tail
425
for
(
const
auto
p
:
new_parents
) {
426
if
((
p
!=
tail
) && !
dag
().
existsArc
(
p
,
tail
)) {
addArc
(
p
,
tail
); }
427
}
428
429
addArc
(
head
,
tail
);
430
// add the necessary arcs to the head
431
new_parents
.
erase
(
tail
);
432
433
for
(
const
auto
p
:
new_parents
) {
434
if
((
p
!=
head
) && !
dag
().
existsArc
(
p
,
head
)) {
addArc
(
p
,
head
); }
435
}
436
437
endTopologyTransformation
();
438
439
// update the conditional distributions of head and tail
440
Set
<
const
DiscreteVariable
* >
del_vars
;
441
del_vars
<< &(
variable
(
tail
));
442
Potential
<
GUM_SCALAR
>
new_cpt_head
=
prod
.
margSumOut
(
del_vars
).
putFirst
(&
variable
(
head
));
443
444
auto
&
cpt_head
=
const_cast
<
Potential
<
GUM_SCALAR
>& >(
cpt
(
head
));
445
cpt_head
=
std
::
move
(
new_cpt_head
);
446
447
Potential
<
GUM_SCALAR
>
new_cpt_tail
{(
prod
/
cpt_head
).
putFirst
(&
variable
(
tail
))};
448
auto
&
cpt_tail
=
const_cast
<
Potential
<
GUM_SCALAR
>& >(
cpt
(
tail
));
449
cpt_tail
=
std
::
move
(
new_cpt_tail
);
450
}
451
452
template
<
typename
GUM_SCALAR
>
453
INLINE
void
BayesNet
<
GUM_SCALAR
>::
reverseArc
(
NodeId
tail
,
NodeId
head
) {
454
reverseArc
(
Arc
(
tail
,
head
));
455
}
456
457
458
//==============================================
459
// Aggregators
460
//=============================================
461
template
<
typename
GUM_SCALAR
>
462
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addAMPLITUDE
(
const
DiscreteVariable
&
var
) {
463
return
add
(
var
,
new
aggregator
::
Amplitude
<
GUM_SCALAR
>());
464
}
465
466
template
<
typename
GUM_SCALAR
>
467
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addAND
(
const
DiscreteVariable
&
var
) {
468
if
(
var
.
domainSize
() > 2)
GUM_ERROR
(
SizeError
,
"an AND has to be boolean"
)
469
470
return
add
(
var
,
new
aggregator
::
And
<
GUM_SCALAR
>());
471
}
472
473
template
<
typename
GUM_SCALAR
>
474
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addCOUNT
(
const
DiscreteVariable
&
var
,
Idx
value
) {
475
return
add
(
var
,
new
aggregator
::
Count
<
GUM_SCALAR
>(
value
));
476
}
477
478
template
<
typename
GUM_SCALAR
>
479
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addEXISTS
(
const
DiscreteVariable
&
var
,
Idx
value
) {
480
if
(
var
.
domainSize
() > 2)
GUM_ERROR
(
SizeError
,
"an EXISTS has to be boolean"
)
481
482
return
add
(
var
,
new
aggregator
::
Exists
<
GUM_SCALAR
>(
value
));
483
}
484
485
template
<
typename
GUM_SCALAR
>
486
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addFORALL
(
const
DiscreteVariable
&
var
,
Idx
value
) {
487
if
(
var
.
domainSize
() > 2)
GUM_ERROR
(
SizeError
,
"an EXISTS has to be boolean"
)
488
489
return
add
(
var
,
new
aggregator
::
Forall
<
GUM_SCALAR
>(
value
));
490
}
491
492
template
<
typename
GUM_SCALAR
>
493
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addMAX
(
const
DiscreteVariable
&
var
) {
494
return
add
(
var
,
new
aggregator
::
Max
<
GUM_SCALAR
>());
495
}
496
497
template
<
typename
GUM_SCALAR
>
498
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addMEDIAN
(
const
DiscreteVariable
&
var
) {
499
return
add
(
var
,
new
aggregator
::
Median
<
GUM_SCALAR
>());
500
}
501
502
template
<
typename
GUM_SCALAR
>
503
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addMIN
(
const
DiscreteVariable
&
var
) {
504
return
add
(
var
,
new
aggregator
::
Min
<
GUM_SCALAR
>());
505
}
506
507
template
<
typename
GUM_SCALAR
>
508
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addOR
(
const
DiscreteVariable
&
var
) {
509
if
(
var
.
domainSize
() > 2)
GUM_ERROR
(
SizeError
,
"an OR has to be boolean"
)
510
511
return
add
(
var
,
new
aggregator
::
Or
<
GUM_SCALAR
>());
512
}
513
514
template
<
typename
GUM_SCALAR
>
515
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addSUM
(
const
DiscreteVariable
&
var
) {
516
return
add
(
var
,
new
aggregator
::
Sum
<
GUM_SCALAR
>());
517
}
518
519
//================================
520
// ICIModels
521
//================================
522
template
<
typename
GUM_SCALAR
>
523
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addNoisyOR
(
const
DiscreteVariable
&
var
,
524
GUM_SCALAR
external_weight
) {
525
return
addNoisyORCompound
(
var
,
external_weight
);
526
}
527
528
template
<
typename
GUM_SCALAR
>
529
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addNoisyORCompound
(
const
DiscreteVariable
&
var
,
530
GUM_SCALAR
external_weight
) {
531
return
add
(
var
,
new
MultiDimNoisyORCompound
<
GUM_SCALAR
>(
external_weight
));
532
}
533
534
template
<
typename
GUM_SCALAR
>
535
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addNoisyORNet
(
const
DiscreteVariable
&
var
,
536
GUM_SCALAR
external_weight
) {
537
return
add
(
var
,
new
MultiDimNoisyORNet
<
GUM_SCALAR
>(
external_weight
));
538
}
539
540
template
<
typename
GUM_SCALAR
>
541
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addNoisyAND
(
const
DiscreteVariable
&
var
,
542
GUM_SCALAR
external_weight
) {
543
return
add
(
var
,
new
MultiDimNoisyAND
<
GUM_SCALAR
>(
external_weight
));
544
}
545
546
template
<
typename
GUM_SCALAR
>
547
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addLogit
(
const
DiscreteVariable
&
var
,
548
GUM_SCALAR
external_weight
) {
549
return
add
(
var
,
new
MultiDimLogit
<
GUM_SCALAR
>(
external_weight
));
550
}
551
552
template
<
typename
GUM_SCALAR
>
553
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addNoisyOR
(
const
DiscreteVariable
&
var
,
554
GUM_SCALAR
external_weight
,
555
NodeId
id
) {
556
return
addNoisyORCompound
(
var
,
external_weight
,
id
);
557
}
558
559
template
<
typename
GUM_SCALAR
>
560
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addNoisyAND
(
const
DiscreteVariable
&
var
,
561
GUM_SCALAR
external_weight
,
562
NodeId
id
) {
563
return
add
(
var
,
new
MultiDimNoisyAND
<
GUM_SCALAR
>(
external_weight
),
id
);
564
}
565
566
template
<
typename
GUM_SCALAR
>
567
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addLogit
(
const
DiscreteVariable
&
var
,
568
GUM_SCALAR
external_weight
,
569
NodeId
id
) {
570
return
add
(
var
,
new
MultiDimLogit
<
GUM_SCALAR
>(
external_weight
),
id
);
571
}
572
573
template
<
typename
GUM_SCALAR
>
574
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addNoisyORCompound
(
const
DiscreteVariable
&
var
,
575
GUM_SCALAR
external_weight
,
576
NodeId
id
) {
577
return
add
(
var
,
new
MultiDimNoisyORCompound
<
GUM_SCALAR
>(
external_weight
),
id
);
578
}
579
580
template
<
typename
GUM_SCALAR
>
581
INLINE
NodeId
BayesNet
<
GUM_SCALAR
>::
addNoisyORNet
(
const
DiscreteVariable
&
var
,
582
GUM_SCALAR
external_weight
,
583
NodeId
id
) {
584
return
add
(
var
,
new
MultiDimNoisyORNet
<
GUM_SCALAR
>(
external_weight
),
id
);
585
}
586
587
template
<
typename
GUM_SCALAR
>
588
void
BayesNet
<
GUM_SCALAR
>::
addWeightedArc
(
NodeId
tail
,
NodeId
head
,
GUM_SCALAR
causalWeight
) {
589
auto
*
CImodel
=
dynamic_cast
<
const
MultiDimICIModel
<
GUM_SCALAR
>* >(
cpt
(
head
).
content
());
590
591
if
(
CImodel
!= 0) {
592
// or is OK
593
addArc
(
tail
,
head
);
594
595
CImodel
->
causalWeight
(
variable
(
tail
),
causalWeight
);
596
}
else
{
597
GUM_ERROR
(
InvalidArc
,
598
"Head variable ("
<<
variable
(
head
).
name
() <<
") is not a CIModel variable !"
)
599
}
600
}
601
602
template
<
typename
GUM_SCALAR
>
603
INLINE
std
::
ostream
&
operator
<<(
std
::
ostream
&
output
,
const
BayesNet
<
GUM_SCALAR
>&
bn
) {
604
output
<<
bn
.
toString
();
605
return
output
;
606
}
607
608
/// begin Multiple Change for all CPTs
609
template
<
typename
GUM_SCALAR
>
610
void
BayesNet
<
GUM_SCALAR
>::
beginTopologyTransformation
() {
611
for
(
const
auto
node
:
nodes
())
612
_probaMap_
[
node
]->
beginMultipleChanges
();
613
}
614
615
/// end Multiple Change for all CPTs
616
template
<
typename
GUM_SCALAR
>
617
void
BayesNet
<
GUM_SCALAR
>::
endTopologyTransformation
() {
618
for
(
const
auto
node
:
nodes
())
619
_probaMap_
[
node
]->
endMultipleChanges
();
620
}
621
622
/// clear all potentials
623
template
<
typename
GUM_SCALAR
>
624
void
BayesNet
<
GUM_SCALAR
>::
_clearPotentials_
() {
625
// Removing previous potentials
626
for
(
const
auto
&
elt
:
_probaMap_
) {
627
delete
elt
.
second
;
628
}
629
630
_probaMap_
.
clear
();
631
}
632
633
/// copy of potentials from a BN to another, using names of vars as ref.
634
template
<
typename
GUM_SCALAR
>
635
void
BayesNet
<
GUM_SCALAR
>::
_copyPotentials_
(
const
BayesNet
<
GUM_SCALAR
>&
source
) {
636
// Copying potentials
637
638
for
(
const
auto
src
:
source
.
_probaMap_
) {
639
// First we build the node's CPT
640
Potential
<
GUM_SCALAR
>*
copy_array
=
new
Potential
<
GUM_SCALAR
>();
641
copy_array
->
beginMultipleChanges
();
642
for
(
gum
::
Idx
i
= 0;
i
<
src
.
second
->
nbrDim
();
i
++) {
643
(*
copy_array
) <<
variableFromName
(
src
.
second
->
variable
(
i
).
name
());
644
}
645
copy_array
->
endMultipleChanges
();
646
copy_array
->
copyFrom
(*(
src
.
second
));
647
648
// We add the CPT to the CPT hashmap
649
_probaMap_
.
insert
(
src
.
first
,
copy_array
);
650
}
651
}
652
653
template
<
typename
GUM_SCALAR
>
654
INLINE
void
BayesNet
<
GUM_SCALAR
>::
generateCPTs
()
const
{
655
for
(
const
auto
node
:
nodes
())
656
generateCPT
(
node
);
657
}
658
659
template
<
typename
GUM_SCALAR
>
660
INLINE
void
BayesNet
<
GUM_SCALAR
>::
generateCPT
(
NodeId
node
)
const
{
661
SimpleCPTGenerator
<
GUM_SCALAR
>
generator
;
662
663
generator
.
generateCPT
(
cpt
(
node
).
pos
(
variable
(
node
)),
cpt
(
node
));
664
}
665
666
template
<
typename
GUM_SCALAR
>
667
void
BayesNet
<
GUM_SCALAR
>::
changePotential
(
NodeId
id
,
Potential
<
GUM_SCALAR
>*
newPot
) {
668
if
(
cpt
(
id
).
nbrDim
() !=
newPot
->
nbrDim
()) {
669
GUM_ERROR
(
OperationNotAllowed
,
670
"cannot exchange potentials with different "
671
"dimensions for variable with id "
672
<<
id
)
673
}
674
675
for
(
Idx
i
= 0;
i
<
cpt
(
id
).
nbrDim
();
i
++) {
676
if
(&
cpt
(
id
).
variable
(
i
) != &(
newPot
->
variable
(
i
))) {
677
GUM_ERROR
(
OperationNotAllowed
,
678
"cannot exchange potentials because, for variable with id "
679
<<
id
<<
", dimension "
<<
i
<<
" differs. "
)
680
}
681
}
682
683
_unsafeChangePotential_
(
id
,
newPot
);
684
}
685
686
template
<
typename
GUM_SCALAR
>
687
void
BayesNet
<
GUM_SCALAR
>::
_unsafeChangePotential_
(
NodeId
id
,
Potential
<
GUM_SCALAR
>*
newPot
) {
688
delete
_probaMap_
[
id
];
689
_probaMap_
[
id
] =
newPot
;
690
}
691
692
template
<
typename
GUM_SCALAR
>
693
void
BayesNet
<
GUM_SCALAR
>::
changePotential
(
const
std
::
string
&
name
,
694
Potential
<
GUM_SCALAR
>*
newPot
) {
695
changePotential
(
idFromName
(
name
),
newPot
);
696
}
697
698
}
/* namespace gum */
gum::Set::emplace
INLINE void emplace(Args &&... args)
Definition:
set_tpl.h:643
gum::build_node
NodeId build_node(gum::BayesNet< GUM_SCALAR > &bn, std::string node, gum::Size default_domain_size)
Definition:
BayesNet_tpl.h:63