aGrUM
0.20.2
a C++ library for (probabilistic) graphical models
scorefNML_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
/** @file
23
* @brief the class for computing fNML scores
24
*
25
* @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
26
*/
27
28
#
ifndef
DOXYGEN_SHOULD_SKIP_THIS
29
30
#
include
<
agrum
/
BN
/
learning
/
scores_and_tests
/
scorefNML
.
h
>
31
32
namespace
gum
{
33
34
namespace
learning
{
35
36
/// default constructor
37
template
<
template
<
typename
>
class
ALLOC >
38
INLINE ScorefNML<
ALLOC
>::
ScorefNML
(
39
const
DBRowGeneratorParser
<
ALLOC
>&
parser
,
40
const
Apriori
<
ALLOC
>&
apriori
,
41
const
std
::
vector
<
std
::
pair
<
std
::
size_t
,
std
::
size_t
>,
42
ALLOC
<
std
::
pair
<
std
::
size_t
,
std
::
size_t
> > >&
ranges
,
43
const
Bijection
<
NodeId
,
std
::
size_t
,
ALLOC
<
std
::
size_t
> >&
44
nodeId2columns
,
45
const
typename
ScorefNML
<
ALLOC
>::
allocator_type
&
alloc
) :
46
Score
<
ALLOC
>(
parser
,
apriori
,
ranges
,
nodeId2columns
,
alloc
),
47
internal_apriori__
(
parser
.
database
(),
nodeId2columns
) {
48
GUM_CONSTRUCTOR
(
ScorefNML
);
49
}
50
51
52
/// default constructor
53
template
<
template
<
typename
>
class
ALLOC
>
54
INLINE
ScorefNML
<
ALLOC
>::
ScorefNML
(
55
const
DBRowGeneratorParser
<
ALLOC
>&
parser
,
56
const
Apriori
<
ALLOC
>&
apriori
,
57
const
Bijection
<
NodeId
,
std
::
size_t
,
ALLOC
<
std
::
size_t
> >&
58
nodeId2columns
,
59
const
typename
ScorefNML
<
ALLOC
>::
allocator_type
&
alloc
) :
60
Score
<
ALLOC
>(
parser
,
apriori
,
nodeId2columns
,
alloc
),
61
internal_apriori__
(
parser
.
database
(),
nodeId2columns
) {
62
GUM_CONSTRUCTOR
(
ScorefNML
);
63
}
64
65
66
/// copy constructor with a given allocator
67
template
<
template
<
typename
>
class
ALLOC
>
68
INLINE
ScorefNML
<
ALLOC
>::
ScorefNML
(
69
const
ScorefNML
<
ALLOC
>&
from
,
70
const
typename
ScorefNML
<
ALLOC
>::
allocator_type
&
alloc
) :
71
Score
<
ALLOC
>(
from
,
alloc
),
72
internal_apriori__
(
from
.
internal_apriori__
,
alloc
) {
73
GUM_CONS_CPY
(
ScorefNML
);
74
}
75
76
77
/// copy constructor
78
template
<
template
<
typename
>
class
ALLOC
>
79
INLINE
ScorefNML
<
ALLOC
>::
ScorefNML
(
const
ScorefNML
<
ALLOC
>&
from
) :
80
ScorefNML
<
ALLOC
>(
from
,
from
.
getAllocator
()) {}
81
82
83
/// move constructor with a given allocator
84
template
<
template
<
typename
>
class
ALLOC
>
85
INLINE
ScorefNML
<
ALLOC
>::
ScorefNML
(
86
ScorefNML
<
ALLOC
>&&
from
,
87
const
typename
ScorefNML
<
ALLOC
>::
allocator_type
&
alloc
) :
88
Score
<
ALLOC
>(
std
::
move
(
from
),
alloc
),
89
internal_apriori__
(
std
::
move
(
from
.
internal_apriori__
),
alloc
) {
90
GUM_CONS_MOV
(
ScorefNML
);
91
}
92
93
94
/// move constructor
95
template
<
template
<
typename
>
class
ALLOC
>
96
INLINE
ScorefNML
<
ALLOC
>::
ScorefNML
(
ScorefNML
<
ALLOC
>&&
from
) :
97
ScorefNML
<
ALLOC
>(
std
::
move
(
from
),
from
.
getAllocator
()) {}
98
99
100
/// virtual copy constructor with a given allocator
101
template
<
template
<
typename
>
class
ALLOC
>
102
ScorefNML
<
ALLOC
>*
ScorefNML
<
ALLOC
>::
clone
(
103
const
typename
ScorefNML
<
ALLOC
>::
allocator_type
&
alloc
)
const
{
104
ALLOC
<
ScorefNML
<
ALLOC
> >
allocator
(
alloc
);
105
ScorefNML
<
ALLOC
>*
new_score
=
allocator
.
allocate
(1);
106
try
{
107
allocator
.
construct
(
new_score
, *
this
,
alloc
);
108
}
catch
(...) {
109
allocator
.
deallocate
(
new_score
, 1);
110
throw
;
111
}
112
113
return
new_score
;
114
}
115
116
117
/// virtual copy constructor
118
template
<
template
<
typename
>
class
ALLOC
>
119
ScorefNML
<
ALLOC
>*
ScorefNML
<
ALLOC
>::
clone
()
const
{
120
return
clone
(
this
->
getAllocator
());
121
}
122
123
124
/// destructor
125
template
<
template
<
typename
>
class
ALLOC
>
126
ScorefNML
<
ALLOC
>::~
ScorefNML
() {
127
GUM_DESTRUCTOR
(
ScorefNML
);
128
}
129
130
131
/// copy operator
132
template
<
template
<
typename
>
class
ALLOC
>
133
ScorefNML
<
ALLOC
>&
134
ScorefNML
<
ALLOC
>::
operator
=(
const
ScorefNML
<
ALLOC
>&
from
) {
135
if
(
this
!= &
from
) {
136
Score
<
ALLOC
>::
operator
=(
from
);
137
internal_apriori__
=
from
.
internal_apriori__
;
138
}
139
return
*
this
;
140
}
141
142
143
/// move operator
144
template
<
template
<
typename
>
class
ALLOC
>
145
ScorefNML
<
ALLOC
>&
ScorefNML
<
ALLOC
>::
operator
=(
ScorefNML
<
ALLOC
>&&
from
) {
146
if
(
this
!= &
from
) {
147
Score
<
ALLOC
>::
operator
=(
std
::
move
(
from
));
148
internal_apriori__
=
std
::
move
(
from
.
internal_apriori__
);
149
}
150
return
*
this
;
151
}
152
153
154
/// indicates whether the apriori is compatible (meaningful) with the score
155
template
<
template
<
typename
>
class
ALLOC
>
156
std
::
string
157
ScorefNML
<
ALLOC
>::
isAprioriCompatible
(
const
std
::
string
&
apriori_type
,
158
double
weight
) {
159
// check that the apriori is compatible with the score
160
if
((
apriori_type
==
AprioriDirichletType
::
type
)
161
|| (
apriori_type
==
AprioriSmoothingType
::
type
)
162
|| (
apriori_type
==
AprioriNoAprioriType
::
type
)) {
163
return
""
;
164
}
165
166
// apriori types unsupported by the type checker
167
std
::
stringstream
msg
;
168
msg
<<
"The apriori '"
<<
apriori_type
169
<<
"' is not yet supported by method isAprioriCompatible os Score fNML"
;
170
return
msg
.
str
();
171
}
172
173
174
/// indicates whether the apriori is compatible (meaningful) with the score
175
template
<
template
<
typename
>
class
ALLOC
>
176
INLINE
std
::
string
177
ScorefNML
<
ALLOC
>::
isAprioriCompatible
(
const
Apriori
<
ALLOC
>&
apriori
) {
178
return
isAprioriCompatible
(
apriori
.
getType
(),
apriori
.
weight
());
179
}
180
181
182
/// indicates whether the apriori is compatible (meaningful) with the score
183
template
<
template
<
typename
>
class
ALLOC
>
184
INLINE
std
::
string
ScorefNML
<
ALLOC
>::
isAprioriCompatible
()
const
{
185
return
isAprioriCompatible
(*(
this
->
apriori_
));
186
}
187
188
189
/// returns the internal apriori of the score
190
template
<
template
<
typename
>
class
ALLOC
>
191
INLINE
const
Apriori
<
ALLOC
>&
ScorefNML
<
ALLOC
>::
internalApriori
()
const
{
192
return
internal_apriori__
;
193
}
194
195
196
/// returns the score corresponding to a given nodeset
197
template
<
template
<
typename
>
class
ALLOC
>
198
double
ScorefNML
<
ALLOC
>::
score_
(
const
IdCondSet
<
ALLOC
>&
idset
) {
199
// get the counts for all the nodes in the idset and add the apriori
200
std
::
vector
<
double
,
ALLOC
<
double
> >
N_ijk
(
201
this
->
counter_
.
counts
(
idset
,
true
));
202
const
bool
informative_external_apriori
=
this
->
apriori_
->
isInformative
();
203
if
(
informative_external_apriori
)
204
this
->
apriori_
->
addAllApriori
(
idset
,
N_ijk
);
205
const
std
::
size_t
all_size
=
N_ijk
.
size
();
206
207
// here, we distinguish idsets with conditioning nodes from those
208
// without conditioning nodes
209
if
(
idset
.
hasConditioningSet
()) {
210
// get the counts for the conditioning nodes
211
std
::
vector
<
double
,
ALLOC
<
double
> >
N_ij
(
212
this
->
marginalize_
(
idset
[0],
N_ijk
));
213
const
std
::
size_t
target_domsize
=
all_size
/
N_ij
.
size
();
214
215
// compute the score: it remains to compute the log likelihood, i.e.,
216
// sum_k=1^r_i sum_j=1^q_i N_ijk log (N_ijk / N_ij), which is also
217
// equivalent to:
218
// sum_j=1^q_i sum_k=1^r_i N_ijk log N_ijk - sum_j=1^q_i N_ij log N_ij
219
double
score
= 0.0;
220
for
(
const
auto
n_ijk
:
N_ijk
) {
221
if
(
n_ijk
) {
score
+=
n_ijk
*
std
::
log
(
n_ijk
); }
222
}
223
for
(
const
auto
n_ij
:
N_ij
) {
224
if
(
n_ij
) {
score
-=
n_ij
*
std
::
log
(
n_ij
); }
225
}
226
227
// divide by log(2), since the log likelihood uses log_2
228
score
*=
this
->
one_log2_
;
229
230
// finally, remove the penalty
231
double
penalty
= 0.0;
232
for
(
const
auto
n_ij
:
N_ij
) {
233
penalty
+=
ctable__
.
log2Cnr
(
target_domsize
,
n_ij
);
234
}
235
236
score
-=
penalty
;
237
238
return
score
;
239
}
else
{
240
// here, there are no conditioning nodes
241
242
// compute the score: it remains to compute the log likelihood, i.e.,
243
// sum_k=1^r_i N_ijk log (N_ijk / N), which is also
244
// equivalent to:
245
// sum_j=1^q_i sum_k=1^r_i N_ijk log N_ijk - N log N
246
double
N
= 0.0;
247
double
score
= 0.0;
248
for
(
const
auto
n_ijk
:
N_ijk
) {
249
if
(
n_ijk
) {
250
score
+=
n_ijk
*
std
::
log
(
n_ijk
);
251
N
+=
n_ijk
;
252
}
253
}
254
score
-=
N
*
std
::
log
(
N
);
255
256
// divide by log(2), since the log likelihood uses log_2
257
score
*=
this
->
one_log2_
;
258
259
// finally, remove the penalty
260
score
-=
ctable__
.
log2Cnr
(
all_size
,
N
);
261
262
return
score
;
263
}
264
}
265
266
}
/* namespace learning */
267
268
}
/* namespace gum */
269
270
#
endif
/* DOXYGEN_SHOULD_SKIP_THIS */
gum::Set::emplace
INLINE void emplace(Args &&... args)
Definition:
set_tpl.h:669
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