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