aGrUM
0.20.2
a C++ library for (probabilistic) graphical models
kNML_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 The class for the NML penalty used in 3off2
25
*
26
* @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
27
*/
28
29
#
ifndef
DOXYGEN_SHOULD_SKIP_THIS
30
31
namespace
gum
{
32
33
namespace
learning
{
34
35
/// default constructor
36
template
<
template
<
typename
>
class
ALLOC >
37
INLINE KNML<
ALLOC
>::
KNML
(
38
const
DBRowGeneratorParser
<
ALLOC
>&
parser
,
39
const
Apriori
<
ALLOC
>&
apriori
,
40
const
std
::
vector
<
std
::
pair
<
std
::
size_t
,
std
::
size_t
>,
41
ALLOC
<
std
::
pair
<
std
::
size_t
,
std
::
size_t
> > >&
ranges
,
42
const
Bijection
<
NodeId
,
std
::
size_t
,
ALLOC
<
std
::
size_t
> >&
43
nodeId2columns
,
44
const
typename
KNML
<
ALLOC
>::
allocator_type
&
alloc
) :
45
IndependenceTest
<
ALLOC
>(
parser
,
apriori
,
ranges
,
nodeId2columns
,
alloc
),
46
param_complexity__
(
alloc
) {
47
GUM_CONSTRUCTOR
(
KNML
);
48
}
49
50
51
/// default constructor
52
template
<
template
<
typename
>
class
ALLOC
>
53
INLINE
KNML
<
ALLOC
>::
KNML
(
54
const
DBRowGeneratorParser
<
ALLOC
>&
parser
,
55
const
Apriori
<
ALLOC
>&
apriori
,
56
const
Bijection
<
NodeId
,
std
::
size_t
,
ALLOC
<
std
::
size_t
> >&
57
nodeId2columns
,
58
const
typename
KNML
<
ALLOC
>::
allocator_type
&
alloc
) :
59
IndependenceTest
<
ALLOC
>(
parser
,
apriori
,
nodeId2columns
,
alloc
),
60
param_complexity__
(
alloc
) {
61
GUM_CONSTRUCTOR
(
KNML
);
62
}
63
64
65
/// copy constructor with a given allocator
66
template
<
template
<
typename
>
class
ALLOC
>
67
INLINE
68
KNML
<
ALLOC
>::
KNML
(
const
KNML
<
ALLOC
>&
from
,
69
const
typename
KNML
<
ALLOC
>::
allocator_type
&
alloc
) :
70
IndependenceTest
<
ALLOC
>(
from
,
alloc
),
71
param_complexity__
(
from
.
param_complexity__
,
alloc
) {
72
GUM_CONS_CPY
(
KNML
);
73
}
74
75
76
/// copy constructor
77
template
<
template
<
typename
>
class
ALLOC
>
78
INLINE
KNML
<
ALLOC
>::
KNML
(
const
KNML
<
ALLOC
>&
from
) :
79
KNML
<
ALLOC
>(
from
,
from
.
getAllocator
()) {}
80
81
82
/// move constructor with a given allocator
83
template
<
template
<
typename
>
class
ALLOC
>
84
INLINE
85
KNML
<
ALLOC
>::
KNML
(
KNML
<
ALLOC
>&&
from
,
86
const
typename
KNML
<
ALLOC
>::
allocator_type
&
alloc
) :
87
IndependenceTest
<
ALLOC
>(
std
::
move
(
from
),
alloc
),
88
param_complexity__
(
std
::
move
(
from
.
param_complexity__
),
alloc
) {
89
GUM_CONS_MOV
(
KNML
);
90
}
91
92
93
/// move constructor
94
template
<
template
<
typename
>
class
ALLOC
>
95
INLINE
KNML
<
ALLOC
>::
KNML
(
KNML
<
ALLOC
>&&
from
) :
96
KNML
<
ALLOC
>(
std
::
move
(
from
),
from
.
getAllocator
()) {}
97
98
99
/// virtual copy constructor with a given allocator
100
template
<
template
<
typename
>
class
ALLOC
>
101
KNML
<
ALLOC
>*
KNML
<
ALLOC
>::
clone
(
102
const
typename
KNML
<
ALLOC
>::
allocator_type
&
alloc
)
const
{
103
ALLOC
<
KNML
<
ALLOC
> >
allocator
(
alloc
);
104
KNML
<
ALLOC
>*
new_score
=
allocator
.
allocate
(1);
105
try
{
106
allocator
.
construct
(
new_score
, *
this
,
alloc
);
107
}
catch
(...) {
108
allocator
.
deallocate
(
new_score
, 1);
109
throw
;
110
}
111
112
return
new_score
;
113
}
114
115
116
/// virtual copy constructor
117
template
<
template
<
typename
>
class
ALLOC
>
118
KNML
<
ALLOC
>*
KNML
<
ALLOC
>::
clone
()
const
{
119
return
clone
(
this
->
getAllocator
());
120
}
121
122
123
/// destructor
124
template
<
template
<
typename
>
class
ALLOC
>
125
KNML
<
ALLOC
>::~
KNML
() {
126
GUM_DESTRUCTOR
(
KNML
);
127
}
128
129
130
/// copy operator
131
template
<
template
<
typename
>
class
ALLOC
>
132
KNML
<
ALLOC
>&
KNML
<
ALLOC
>::
operator
=(
const
KNML
<
ALLOC
>&
from
) {
133
if
(
this
!= &
from
) {
134
IndependenceTest
<
ALLOC
>::
operator
=(
from
);
135
param_complexity__
=
from
.
param_complexity__
;
136
}
137
return
*
this
;
138
}
139
140
141
/// move operator
142
template
<
template
<
typename
>
class
ALLOC
>
143
KNML
<
ALLOC
>&
KNML
<
ALLOC
>::
operator
=(
KNML
<
ALLOC
>&&
from
) {
144
if
(
this
!= &
from
) {
145
IndependenceTest
<
ALLOC
>::
operator
=(
std
::
move
(
from
));
146
param_complexity__
=
std
::
move
(
from
.
param_complexity__
);
147
}
148
return
*
this
;
149
}
150
151
152
/// clears all the data structures from memory, including the cache
153
template
<
template
<
typename
>
class
ALLOC
>
154
void
KNML
<
ALLOC
>::
clear
() {
155
IndependenceTest
<
ALLOC
>::
clear
();
156
param_complexity__
.
clearCache
();
157
}
158
159
160
/// clears the current cache
161
template
<
template
<
typename
>
class
ALLOC
>
162
void
KNML
<
ALLOC
>::
clearCache
() {
163
IndependenceTest
<
ALLOC
>::
clearCache
();
164
param_complexity__
.
clearCache
();
165
}
166
167
168
/// turn on/off the use of a cache of the previously computed score
169
template
<
template
<
typename
>
class
ALLOC
>
170
void
KNML
<
ALLOC
>::
useCache
(
const
bool
on_off
) {
171
IndependenceTest
<
ALLOC
>::
useCache
(
on_off
);
172
param_complexity__
.
useCache
(
on_off
);
173
}
174
175
176
/// returns the score corresponding to a given nodeset
177
template
<
template
<
typename
>
class
ALLOC
>
178
double
KNML
<
ALLOC
>::
score_
(
const
IdCondSet
<
ALLOC
>&
idset
) {
179
// perform the countings on the database for all the nodes in the idset
180
// This will help optimizing the computations of the Nxui, Nyui and Nui
181
// that we will be needed subsequently
182
this
->
counter_
.
counts
(
idset
,
true
);
183
184
const
bool
informative_external_apriori
=
this
->
apriori_
->
isInformative
();
185
186
// get the domain sizes of X and Y
187
const
auto
&
db
=
this
->
database
();
188
const
auto
&
node2cols
=
this
->
nodeId2Columns
();
189
std
::
size_t
r_x
,
r_y
;
190
if
(!
node2cols
.
empty
()) {
191
r_x
=
db
.
domainSize
(
node2cols
.
second
(
idset
[0]));
192
r_y
=
db
.
domainSize
(
node2cols
.
second
(
idset
[1]));
193
}
else
{
194
r_x
=
db
.
domainSize
(
idset
[0]);
195
r_y
=
db
.
domainSize
(
idset
[1]);
196
}
197
198
199
// here, we distinguish idsets with conditioning nodes from those
200
// without conditioning nodes
201
if
(
idset
.
hasConditioningSet
()) {
202
// now get the Nxui, Nyui and Nui
203
IdCondSet
<
ALLOC
>
idset_xui
=
idset
;
204
idset_xui
.
erase
(
idset
[1]);
205
IdCondSet
<
ALLOC
>
idset_yui
=
idset
;
206
idset_yui
.
erase
(
idset
[0]);
207
208
std
::
vector
<
double
,
ALLOC
<
double
> >
N_ui
209
=
this
->
counter_
.
counts
(
idset
.
conditionalIdCondSet
(),
false
);
210
std
::
vector
<
double
,
ALLOC
<
double
> >
N_xui
211
=
this
->
counter_
.
counts
(
idset_xui
,
false
);
212
std
::
vector
<
double
,
ALLOC
<
double
> >
N_yui
213
=
this
->
counter_
.
counts
(
idset_yui
,
false
);
214
215
if
(
informative_external_apriori
) {
216
this
->
apriori_
->
addConditioningApriori
(
idset
,
N_ui
);
217
this
->
apriori_
->
addAllApriori
(
idset
,
N_xui
);
218
this
->
apriori_
->
addAllApriori
(
idset
,
N_yui
);
219
}
220
221
222
// the value of kNML is equal to:
223
// 0.5 * sum_Z ( sum_X( log( C^(r_y)_#ZX ) ) - log( C^(r_y)_#Z ) +
224
// sum_Y( log( C^(r_x)_#ZY ) ) - log( C^(r_x)_#Z ) )
225
double
score
= 0.0;
226
for
(
auto
n_xui
:
N_xui
)
227
score
+=
param_complexity__
.
log2Cnr
(
r_y
,
n_xui
);
228
for
(
auto
n_yui
:
N_yui
)
229
score
+=
param_complexity__
.
log2Cnr
(
r_x
,
n_yui
);
230
for
(
auto
n_ui
:
N_ui
) {
231
score
-=
param_complexity__
.
log2Cnr
(
r_y
,
n_ui
);
232
score
-=
param_complexity__
.
log2Cnr
(
r_x
,
n_ui
);
233
}
234
235
score
*= 0.5;
236
237
return
score
;
238
}
else
{
239
// here, there is no conditioning set
240
// now get the Nxui, Nyui and Nui
241
IdCondSet
<
ALLOC
>
idset_xui
(
idset
[0],
this
->
empty_ids_
,
true
);
242
IdCondSet
<
ALLOC
>
idset_yui
(
idset
[1],
this
->
empty_ids_
,
true
);
243
244
std
::
vector
<
double
,
ALLOC
<
double
> >
N_xui
245
=
this
->
counter_
.
counts
(
idset_xui
,
false
);
246
std
::
vector
<
double
,
ALLOC
<
double
> >
N_yui
247
=
this
->
counter_
.
counts
(
idset_yui
,
false
);
248
249
if
(
informative_external_apriori
) {
250
this
->
apriori_
->
addAllApriori
(
idset
,
N_xui
);
251
this
->
apriori_
->
addAllApriori
(
idset
,
N_yui
);
252
}
253
254
255
// so, the formula for kNML is:
256
// 0.5 * ( sum_X( log( C^(r_y)_#X ) ) - log( C^(r_y)N_ ) +
257
// sum_Y( log( C^(r_x)_#Y ) ) - log( C^(r_x)N_ ) )
258
double
N
= 0.0;
259
double
score
= 0.0;
260
for
(
auto
n_xui
:
N_xui
) {
261
score
+=
param_complexity__
.
log2Cnr
(
r_y
,
n_xui
);
262
N
+=
n_xui
;
263
}
264
for
(
auto
n_yui
:
N_yui
)
265
score
+=
param_complexity__
.
log2Cnr
(
r_x
,
n_yui
);
266
score
-=
param_complexity__
.
log2Cnr
(
r_y
,
N
);
267
score
-=
param_complexity__
.
log2Cnr
(
r_x
,
N
);
268
269
score
*= 0.5;
270
271
return
score
;
272
}
273
}
274
275
}
/* namespace learning */
276
277
}
/* namespace gum */
278
279
#
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