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