aGrUM
0.20.2
a C++ library for (probabilistic) graphical models
defaultPartialOrderedEliminationSequenceStrategy.cpp
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 An efficient unconstrained elimination sequence algorithm
24
*
25
* @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
26
*/
27
28
#
include
<
agrum
/
agrum
.
h
>
29
#
include
<
agrum
/
tools
/
core
/
math
/
math_utils
.
h
>
30
31
#
include
<
agrum
/
tools
/
graphs
/
algorithms
/
triangulations
/
eliminationStrategies
/
defaultPartialOrderedEliminationSequenceStrategy
.
h
>
32
#
include
<
agrum
/
tools
/
graphs
/
undiGraph
.
h
>
33
34
namespace
gum
{
35
36
/// default constructor (uses an empty graph)
37
DefaultPartialOrderedEliminationSequenceStrategy
::
38
DefaultPartialOrderedEliminationSequenceStrategy
(
double
theRatio
,
39
double
theThreshold
) :
40
simplicial_ratio__
(
theRatio
),
41
simplicial_threshold__
(
theThreshold
) {
42
// for debugging purposes
43
GUM_CONSTRUCTOR
(
DefaultPartialOrderedEliminationSequenceStrategy
);
44
}
45
46
/// constructor for an a priori non empty graph
47
DefaultPartialOrderedEliminationSequenceStrategy
::
48
DefaultPartialOrderedEliminationSequenceStrategy
(
49
UndiGraph
*
graph
,
50
const
NodeProperty
<
Size
>*
dom_sizes
,
51
const
List
<
NodeSet
>*
subsets
,
52
double
ratio
,
53
double
threshold
) :
54
simplicial_ratio__
(
ratio
),
55
simplicial_threshold__
(
threshold
) {
56
setGraph
(
graph
,
dom_sizes
);
57
setPartialOrder
(
subsets
);
58
59
// for debugging purposes
60
GUM_CONSTRUCTOR
(
DefaultPartialOrderedEliminationSequenceStrategy
);
61
}
62
63
/// copy constructor
64
DefaultPartialOrderedEliminationSequenceStrategy
::
65
DefaultPartialOrderedEliminationSequenceStrategy
(
66
const
DefaultPartialOrderedEliminationSequenceStrategy
&
from
) :
67
PartialOrderedEliminationSequenceStrategy
(
from
),
68
// no need to set log_weights__ because the copy of the simplicial set
69
// will set it properly
70
simplicial_set__
(
new
SimplicialSet
(*
from
.
simplicial_set__
,
71
graph_
,
72
&
log_domain_sizes_
,
73
&
log_weights__
,
74
false
)),
75
simplicial_ratio__
(
from
.
simplicial_ratio__
),
76
simplicial_threshold__
(
from
.
simplicial_threshold__
),
77
provide_fill_ins__
(
from
.
provide_fill_ins__
) {
78
// for debugging purposes
79
GUM_CONS_CPY
(
DefaultPartialOrderedEliminationSequenceStrategy
);
80
}
81
82
/// move constructor
83
DefaultPartialOrderedEliminationSequenceStrategy
::
84
DefaultPartialOrderedEliminationSequenceStrategy
(
85
DefaultPartialOrderedEliminationSequenceStrategy
&&
from
) :
86
PartialOrderedEliminationSequenceStrategy
(
std
::
move
(
from
)),
87
log_weights__
(
std
::
move
(
from
.
log_weights__
)),
88
simplicial_set__
(
from
.
simplicial_set__
),
89
simplicial_ratio__
(
from
.
simplicial_ratio__
),
90
simplicial_threshold__
(
from
.
simplicial_threshold__
),
91
provide_fill_ins__
(
from
.
provide_fill_ins__
) {
92
simplicial_set__
->
replaceLogWeights
(&
from
.
log_weights__
, &
log_weights__
);
93
from
.
simplicial_set__
=
nullptr
;
94
95
// for debugging purposes
96
GUM_CONS_MOV
(
DefaultPartialOrderedEliminationSequenceStrategy
);
97
}
98
99
/// destructor
100
DefaultPartialOrderedEliminationSequenceStrategy
::
101
~
DefaultPartialOrderedEliminationSequenceStrategy
() {
102
// for debugging purposes
103
GUM_DESTRUCTOR
(
DefaultPartialOrderedEliminationSequenceStrategy
);
104
105
if
(
simplicial_set__
)
delete
simplicial_set__
;
106
}
107
108
/// create a new simplicial set suited for the current graph
109
void
DefaultPartialOrderedEliminationSequenceStrategy
::
createSimplicialSet__
() {
110
// remove the old simplicial set, if any
111
if
(
simplicial_set__
!=
nullptr
) {
112
delete
simplicial_set__
;
113
simplicial_set__
=
nullptr
;
114
}
115
116
if
(
graph_
!=
nullptr
) {
117
// create a simplicial set suited for the graph
118
simplicial_set__
=
new
SimplicialSet
(
graph_
,
119
&
log_domain_sizes_
,
120
&
log_weights__
,
121
simplicial_ratio__
,
122
simplicial_threshold__
);
123
124
simplicial_set__
->
setFillIns
(
provide_fill_ins__
);
125
}
126
}
127
128
/// sets a new graph to be triangulated
129
bool
DefaultPartialOrderedEliminationSequenceStrategy
::
setGraph
(
130
UndiGraph
*
graph
,
131
const
NodeProperty
<
Size
>*
domain_sizes
) {
132
if
(
PartialOrderedEliminationSequenceStrategy
::
setGraph
(
graph
,
domain_sizes
)) {
133
createSimplicialSet__
();
134
return
true
;
135
}
136
137
return
false
;
138
}
139
140
/// clears the sequence (to prepare, for instance, a new elimination sequence)
141
void
DefaultPartialOrderedEliminationSequenceStrategy
::
clear
() {
142
PartialOrderedEliminationSequenceStrategy
::
clear
();
143
log_weights__
.
clear
();
144
145
if
(
simplicial_set__
!=
nullptr
) {
146
delete
simplicial_set__
;
147
simplicial_set__
=
nullptr
;
148
}
149
}
150
151
/// returns the best possible node to be eliminated
152
NodeId
DefaultPartialOrderedEliminationSequenceStrategy
::
nodeToEliminate__
(
153
const
PriorityQueue
<
NodeId
,
double
>&
possibleNodes
) {
154
bool
found
=
false
;
155
double
min_score
= 0;
156
NodeId
best_node
= 0;
157
158
for
(
const
auto
node
:
nodeset_
) {
159
try
{
160
double
score
=
possibleNodes
.
priority
(
node
);
161
162
if
(!
found
|| (
score
<
min_score
)) {
163
found
=
true
;
164
min_score
=
score
;
165
best_node
=
node
;
166
}
167
}
catch
(
NotFound
&) {}
168
}
169
170
if
(!
found
) {
GUM_ERROR
(
NotFound
,
"no possible node to eliminate"
); }
171
172
return
best_node
;
173
}
174
175
/// returns the new node to be eliminated within the triangulation algorithm
176
NodeId
DefaultPartialOrderedEliminationSequenceStrategy
::
nextNodeToEliminate
() {
177
// if there is no simplicial set, send an exception
178
if
(
graph_
==
nullptr
)
GUM_ERROR
(
NotFound
,
"the graph is empty"
);
179
180
if
(
partial_order_needed_
)
181
GUM_ERROR
(
NotFound
,
182
"the partial order does not cover all the nodes "
183
"of the graph"
);
184
185
if
(
nodeset_
.
empty
()) {
GUM_ERROR
(
NotFound
,
"no node is admissible"
); }
186
187
// select a node to be eliminated: try simplicial nodes, then almost
188
// simplicial nodes, then quasi-simplicial nodes
189
// note that if graph_ != nullptr, simplicial_set__ has been allocated
190
try
{
191
return
nodeToEliminate__
(
simplicial_set__
->
allSimplicialNodes
());
192
}
catch
(
NotFound
&) {}
193
194
try
{
195
return
nodeToEliminate__
(
simplicial_set__
->
allAlmostSimplicialNodes
());
196
}
catch
(
NotFound
&) {}
197
198
try
{
199
return
nodeToEliminate__
(
simplicial_set__
->
allQuasiSimplicialNodes
());
200
}
catch
(
NotFound
&) {}
201
202
// here: select the node through Kjaerulff's heuristic
203
auto
iter
=
nodeset_
.
cbegin
();
204
double
min_score
=
log_weights__
[*
iter
];
205
NodeId
best_node
= *
iter
;
206
207
for
(++
iter
;
iter
!=
nodeset_
.
cend
(); ++
iter
) {
208
double
score
=
log_weights__
[*
iter
];
209
210
if
(
score
<
min_score
) {
211
min_score
=
score
;
212
best_node
= *
iter
;
213
}
214
}
215
216
return
best_node
;
217
}
218
219
/** @brief if the elimination sequence is able to compute fill-ins, we
220
* indicatewhether we want this feature to be activated */
221
void
DefaultPartialOrderedEliminationSequenceStrategy
::
askFillIns
(
bool
do_it
) {
222
provide_fill_ins__
=
do_it
;
223
224
if
(
simplicial_set__
)
simplicial_set__
->
setFillIns
(
provide_fill_ins__
);
225
}
226
227
/** @brief indicates whether the new fill-ins generated by a new eliminated
228
* node, if needed, will be computed by the elimination sequence, or need be
229
* computed by the triangulation itself. */
230
bool
DefaultPartialOrderedEliminationSequenceStrategy
::
providesFillIns
()
const
{
231
return
provide_fill_ins__
;
232
}
233
234
/** @brief indicates whether the elimination sequence updates by itself the
235
* graph after a node has been eliminated */
236
bool
DefaultPartialOrderedEliminationSequenceStrategy
::
providesGraphUpdate
()
237
const
{
238
return
true
;
239
}
240
241
/// performs all the graph/fill-ins updates provided
242
void
DefaultPartialOrderedEliminationSequenceStrategy
::
eliminationUpdate
(
243
const
NodeId
id
) {
244
// check whether we can do something
245
if
(
simplicial_set__
!=
nullptr
) {
246
simplicial_set__
->
makeClique
(
id
);
247
simplicial_set__
->
eraseClique
(
id
);
248
249
if
(!
partial_order_needed_
) {
250
// remove the node from nodeset_
251
nodeset_
.
erase
(
id
);
252
253
if
(
nodeset_
.
empty
()) {
254
// go to the next non-empty subset
255
for
(++
subset_iter_
;
subset_iter_
!=
subsets_
->
cend
(); ++
subset_iter_
) {
256
for
(
const
auto
node
: *
subset_iter_
) {
257
if
(
graph_
->
existsNode
(
node
)) {
nodeset_
.
insert
(
node
); }
258
}
259
if
(!
nodeset_
.
empty
())
break
;
260
}
261
}
262
}
263
}
264
}
265
266
/** @brief in case fill-ins are provided, this function returns the fill-ins
267
* generated after the last node elimination */
268
const
EdgeSet
&
DefaultPartialOrderedEliminationSequenceStrategy
::
fillIns
() {
269
if
(!
provide_fill_ins__
|| (
simplicial_set__
==
nullptr
))
270
return
EliminationSequenceStrategy
::
fillIns
();
271
else
272
return
simplicial_set__
->
fillIns
();
273
}
274
275
/** @brief creates a new elimination sequence of the same type as the current
276
* object, but this sequence contains only an empty graph */
277
DefaultPartialOrderedEliminationSequenceStrategy
*
278
DefaultPartialOrderedEliminationSequenceStrategy
::
newFactory
()
const
{
279
return
new
DefaultPartialOrderedEliminationSequenceStrategy
(
280
simplicial_ratio__
,
281
simplicial_threshold__
);
282
}
283
284
/// virtual copy constructor
285
DefaultPartialOrderedEliminationSequenceStrategy
*
286
DefaultPartialOrderedEliminationSequenceStrategy
::
copyFactory
()
const
{
287
return
new
DefaultPartialOrderedEliminationSequenceStrategy
(*
this
);
288
}
289
290
}
/* namespace gum */
gum::Set::emplace
INLINE void emplace(Args &&... args)
Definition:
set_tpl.h:669