aGrUM
0.20.3
a C++ library for (probabilistic) graphical models
multiDimFunctionGraphManager_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
/**
23
* @file
24
* @brief Template methods of gum::MultiDimFunctionGraphManager.
25
*
26
* @author Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
27
* @author Pierre-Henri WUILLEMIN(@LIP6) and Jean-Christophe MAGNAN and Christophe
28
* GONZALES(@AMU)
29
*
30
*/
31
#
include
<
agrum
/
tools
/
core
/
sequence
.
h
>
32
#
include
<
agrum
/
tools
/
multidim
/
implementations
/
multiDimFunctionGraphManager
.
h
>
33
#
include
<
agrum
/
tools
/
multidim
/
utils
/
FunctionGraphUtilities
/
link
.
h
>
34
35
namespace
gum
{
36
37
// Default constructor
38
template
<
typename
GUM_SCALAR,
template
<
class
>
class
TerminalNodePolicy >
39
INLINE
40
MultiDimFunctionGraphManager<
GUM_SCALAR
,
TerminalNodePolicy
>::
MultiDimFunctionGraphManager
(
41
MultiDimFunctionGraph
<
GUM_SCALAR
,
TerminalNodePolicy
>*
mddg
) {
42
GUM_CONSTRUCTOR
(
MultiDimFunctionGraphManager
);
43
_functionGraph_
=
mddg
;
44
}
45
46
// Destructor
47
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
48
INLINE
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
49
TerminalNodePolicy
>::~
MultiDimFunctionGraphManager
() {
50
GUM_DESTRUCTOR
(
MultiDimFunctionGraphManager
);
51
}
52
53
/// Sets root node of decision diagram
54
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
55
INLINE
void
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
setRootNode
(
56
const
NodeId
&
root
) {
57
_functionGraph_
->
_root_
=
root
;
58
}
59
60
// Inserts a new non terminal node in graph.
61
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
62
INLINE
NodeId
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
addInternalNode
(
63
const
DiscreteVariable
*
var
,
64
NodeId
nid
) {
65
InternalNode
*
newNodeStruct
=
new
InternalNode
(
var
);
66
67
_functionGraph_
->
_internalNodeMap_
.
insert
(
nid
,
newNodeStruct
);
68
69
_functionGraph_
->
_var2NodeIdMap_
[
var
]->
addLink
(
nid
);
70
71
return
nid
;
72
}
73
74
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
75
INLINE
NodeId
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
addInternalNode
(
76
const
DiscreteVariable
*
var
) {
77
InternalNode
*
newNodeStruct
=
new
InternalNode
(
var
);
78
NodeId
nid
=
_functionGraph_
->
_model_
.
addNode
();
79
_functionGraph_
->
_internalNodeMap_
.
insert
(
nid
,
newNodeStruct
);
80
_functionGraph_
->
_var2NodeIdMap_
[
var
]->
addLink
(
nid
);
81
82
return
nid
;
83
}
84
85
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
86
INLINE
NodeId
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
addInternalNode_
(
87
const
DiscreteVariable
*
var
,
88
NodeId
*
sons
) {
89
InternalNode
*
newNodeStruct
=
new
InternalNode
(
var
,
sons
);
90
NodeId
nid
=
_functionGraph_
->
_model_
.
addNode
();
91
_functionGraph_
->
_internalNodeMap_
.
insert
(
nid
,
newNodeStruct
);
92
_functionGraph_
->
_var2NodeIdMap_
[
var
]->
addLink
(
nid
);
93
for
(
Idx
i
= 0;
i
<
newNodeStruct
->
nbSons
();
i
++)
94
if
(!
_functionGraph_
->
isTerminalNode
(
sons
[
i
]))
95
_functionGraph_
->
_internalNodeMap_
[
sons
[
i
]]->
addParent
(
nid
,
i
);
96
97
return
nid
;
98
}
99
100
// Adds a value to the MultiDimFunctionGraph.
101
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
102
INLINE
NodeId
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
addTerminalNode
(
103
const
GUM_SCALAR
&
value
) {
104
if
(
_functionGraph_
->
existsTerminalNodeWithValue
(
value
))
105
return
_functionGraph_
->
terminalNodeId
(
value
);
106
107
NodeId
node
=
_functionGraph_
->
_model_
.
addNode
();
108
_functionGraph_
->
addTerminalNode
(
node
,
value
);
109
return
node
;
110
}
111
112
// Erases a node from the diagram.
113
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
114
void
115
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
eraseNode
(
NodeId
eraseId
,
116
NodeId
replacingId
,
117
bool
updateParents
) {
118
if
(!
_functionGraph_
->
_model_
.
exists
(
eraseId
))
119
GUM_ERROR
(
NotFound
,
"Node : "
<<
eraseId
<<
" doesn't exists in the graph"
)
120
121
if
(
_functionGraph_
->
isTerminalNode
(
eraseId
)) {
122
for
(
auto
iterVar
=
_functionGraph_
->
variablesSequence
().
begin
();
123
iterVar
!=
_functionGraph_
->
variablesSequence
().
end
();
124
++
iterVar
) {
125
Link
<
NodeId
>*
nodeIter
=
_functionGraph_
->
_var2NodeIdMap_
[*
iterVar
]->
list
();
126
while
(
nodeIter
!=
nullptr
) {
127
for
(
Idx
modality
= 0;
modality
< (*
iterVar
)->
domainSize
(); ++
modality
)
128
if
(
_functionGraph_
->
node
(
nodeIter
->
element
())->
son
(
modality
) ==
eraseId
)
129
setSon
(
nodeIter
->
element
(),
modality
,
replacingId
);
130
131
nodeIter
=
nodeIter
->
nextLink
();
132
}
133
}
134
_functionGraph_
->
eraseTerminalNode
(
eraseId
);
135
136
}
else
{
137
InternalNode
*
eraseNode
=
_functionGraph_
->
_internalNodeMap_
[
eraseId
];
138
139
if
(
updateParents
) {
140
Link
<
Parent
>*
picle
=
eraseNode
->
parents
();
141
while
(
picle
!=
nullptr
) {
142
setSon
(
picle
->
element
().
parentId
,
picle
->
element
().
modality
,
replacingId
);
143
picle
=
picle
->
nextLink
();
144
}
145
}
146
147
_functionGraph_
->
_var2NodeIdMap_
[
_functionGraph_
->
_internalNodeMap_
[
eraseId
]->
nodeVar
()]
148
->
searchAndRemoveLink
(
eraseId
);
149
150
delete
_functionGraph_
->
_internalNodeMap_
[
eraseId
];
151
_functionGraph_
->
_internalNodeMap_
.
erase
(
eraseId
);
152
}
153
154
_functionGraph_
->
_model_
.
eraseNode
(
eraseId
);
155
156
if
(
_functionGraph_
->
_root_
==
eraseId
)
_functionGraph_
->
_root_
=
replacingId
;
157
}
158
159
/// Sets nodes son for given modality to designated son node
160
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
161
INLINE
void
162
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
setSon
(
const
NodeId
&
node
,
163
const
Idx
&
modality
,
164
const
NodeId
&
sonNode
) {
165
// Ensuring that both nodes exists in the graph
166
if
(!
_functionGraph_
->
_model_
.
exists
(
node
))
167
GUM_ERROR
(
NotFound
,
"Node : "
<<
node
<<
" doesn't exists in the graph"
)
168
if
(!
_functionGraph_
->
_model_
.
exists
(
sonNode
))
169
GUM_ERROR
(
NotFound
,
"Node : "
<<
sonNode
<<
" doesn't exists in the graph"
)
170
171
// Check if starting node is not terminal
172
if
(
_functionGraph_
->
isTerminalNode
(
node
))
173
GUM_ERROR
(
InvalidNode
,
"You cannot insert an arc from terminal node : "
<<
node
)
174
175
// Check if associated modality is lower than node bound variable domain
176
// size
177
if
(
_functionGraph_
->
isInternalNode
(
node
)
178
&&
modality
>
_functionGraph_
->
_internalNodeMap_
[
node
]->
nodeVar
()->
domainSize
() - 1)
179
GUM_ERROR
(
InvalidArgument
,
180
"Modality "
<<
modality
<<
"is higher than domain size "
181
<<
_functionGraph_
->
_internalNodeMap_
[
node
]->
nodeVar
()->
domainSize
()
182
<<
"minus 1 of variable "
183
<<
_functionGraph_
->
_internalNodeMap_
[
node
]->
nodeVar
()->
name
())
184
185
// Check if variable order is respected
186
if
(
_functionGraph_
->
isInternalNode
(
sonNode
)
187
&&
_functionGraph_
->
variablesSequence
().
pos
(
188
_functionGraph_
->
_internalNodeMap_
[
node
]->
nodeVar
())
189
>=
_functionGraph_
->
variablesSequence
().
pos
(
190
_functionGraph_
->
_internalNodeMap_
[
sonNode
]->
nodeVar
()))
191
GUM_ERROR
(
OperationNotAllowed
,
192
"Variable "
<<
_functionGraph_
->
_internalNodeMap_
[
node
]->
nodeVar
()
193
<<
" is after variable "
194
<<
_functionGraph_
->
_internalNodeMap_
[
sonNode
]->
nodeVar
()
195
<<
"in Function Graph order."
)
196
197
_functionGraph_
->
_internalNodeMap_
[
node
]->
setSon
(
modality
,
sonNode
);
198
if
(
sonNode
&& !
_functionGraph_
->
isTerminalNode
(
sonNode
))
199
_functionGraph_
->
_internalNodeMap_
[
sonNode
]->
addParent
(
node
,
modality
);
200
}
201
202
// Changes var position in variable sequence
203
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
204
void
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
minimizeSize
() {
205
// Ordering variables by number of nodes asssociated to them
206
Sequence
<
const
DiscreteVariable
* >
siftingSeq
;
207
HashTable
<
const
DiscreteVariable
*,
Idx
>
varLvlSize
;
208
for
(
SequenceIteratorSafe
<
const
DiscreteVariable
* >
varIter
209
=
_functionGraph_
->
variablesSequence
().
beginSafe
();
210
varIter
!=
_functionGraph_
->
variablesSequence
().
endSafe
();
211
++
varIter
) {
212
const
Link
<
NodeId
>*
curElem
=
_functionGraph_
->
_var2NodeIdMap_
[*
varIter
]->
list
();
213
Idx
nbElem
= 0;
214
for
(;
curElem
!=
nullptr
;
nbElem
++,
curElem
=
curElem
->
nextLink
())
215
;
216
varLvlSize
.
insert
(*
varIter
,
nbElem
);
217
siftingSeq
.
insert
(*
varIter
);
218
Idx
pos
=
siftingSeq
.
pos
(*
varIter
);
219
while
(
pos
> 0 &&
varLvlSize
[
siftingSeq
.
atPos
(
pos
- 1)] >
nbElem
) {
220
siftingSeq
.
swap
(
pos
- 1,
pos
);
221
pos
--;
222
}
223
}
224
225
// Sifting var par var
226
for
(
SequenceIteratorSafe
<
const
DiscreteVariable
* >
sifIter
=
siftingSeq
.
beginSafe
();
227
sifIter
!=
siftingSeq
.
endSafe
();
228
++
sifIter
) {
229
// Initialization
230
Idx
currentPos
=
_functionGraph_
->
variablesSequence
().
pos
(*
sifIter
);
231
Idx
bestSize
=
_functionGraph_
->
realSize
();
232
Idx
bestPos
=
currentPos
;
233
234
235
// Sifting towards upper places
236
while
(
currentPos
> 0) {
237
moveTo
(*
sifIter
,
currentPos
- 1);
238
currentPos
=
_functionGraph_
->
variablesSequence
().
pos
(*
sifIter
);
239
if
(
_functionGraph_
->
realSize
() <
bestSize
) {
240
bestPos
=
currentPos
;
241
bestSize
=
_functionGraph_
->
realSize
();
242
}
243
}
244
245
// Sifting towards lower places
246
while
(
currentPos
<
_functionGraph_
->
variablesSequence
().
size
() - 1) {
247
moveTo
(*
sifIter
,
currentPos
+ 1);
248
currentPos
=
_functionGraph_
->
variablesSequence
().
pos
(*
sifIter
);
249
if
(
_functionGraph_
->
realSize
() <
bestSize
) {
250
bestPos
=
currentPos
;
251
bestSize
=
_functionGraph_
->
realSize
();
252
}
253
}
254
255
moveTo
(*
sifIter
,
bestPos
);
256
}
257
}
258
259
// Changes var position in variable sequence
260
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
261
void
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
moveTo
(
262
const
DiscreteVariable
*
movedVar
,
263
Idx
desiredPos
) {
264
// First we determine the position of both variable
265
// We also determine which one precede the other
266
if
(
_functionGraph_
->
variablesSequence
().
pos
(
movedVar
) >
desiredPos
)
267
for
(
Idx
currentPos
=
_functionGraph_
->
variablesSequence
().
pos
(
movedVar
);
268
currentPos
!=
desiredPos
;
269
currentPos
--) {
270
const
DiscreteVariable
*
preVar
=
_functionGraph_
->
variablesSequence
().
atPos
(
currentPos
- 1);
271
if
(
_functionGraph_
->
_var2NodeIdMap_
[
preVar
]->
list
()
272
&&
_functionGraph_
->
_var2NodeIdMap_
[
movedVar
]->
list
())
273
_adjacentSwap_
(
preVar
,
movedVar
);
274
_functionGraph_
->
invert_
(
currentPos
- 1,
currentPos
);
275
}
276
else
277
for
(
Idx
currentPos
=
_functionGraph_
->
variablesSequence
().
pos
(
movedVar
);
278
currentPos
!=
desiredPos
;
279
currentPos
++) {
280
const
DiscreteVariable
*
suiVar
=
_functionGraph_
->
variablesSequence
().
atPos
(
currentPos
+ 1);
281
if
(
_functionGraph_
->
_var2NodeIdMap_
[
suiVar
]->
list
()
282
&&
_functionGraph_
->
_var2NodeIdMap_
[
movedVar
]->
list
())
283
_adjacentSwap_
(
movedVar
,
suiVar
);
284
_functionGraph_
->
invert_
(
currentPos
,
currentPos
+ 1);
285
}
286
}
287
288
// Swap two adjacent variable.
289
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
290
void
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
_adjacentSwap_
(
291
const
DiscreteVariable
*
x
,
292
const
DiscreteVariable
*
y
) {
293
LinkedList
<
NodeId
>*
oldxNodes
=
_functionGraph_
->
_var2NodeIdMap_
[
x
];
294
_functionGraph_
->
_var2NodeIdMap_
[
x
] =
new
LinkedList
<
NodeId
>();
295
LinkedList
<
NodeId
>*
oldyNodes
=
_functionGraph_
->
_var2NodeIdMap_
[
y
];
296
_functionGraph_
->
_var2NodeIdMap_
[
y
] =
new
LinkedList
<
NodeId
>();
297
298
299
InternalNode
*
currentOldXNode
=
nullptr
;
300
NodeId
*
currentNewXNodeSons
=
nullptr
;
301
Idx
indx
= 0;
302
303
NodeId
*
currentNewYNodeSons
=
nullptr
;
304
NodeId
currentNewYNodeId
= 0;
305
Idx
indy
= 0;
306
307
while
(
oldxNodes
->
list
()) {
308
// Recuperating a node associated to variables x
309
currentOldXNode
=
_functionGraph_
->
_internalNodeMap_
[
oldxNodes
->
list
()->
element
()];
310
311
// Creating a new node associated to variable y
312
currentNewYNodeSons
=
InternalNode
::
allocateNodeSons
(
y
);
313
314
// Now the graph needs to be remap by inserting nodes bound to x
315
// for each values assumed by y
316
for
(
indy
= 0;
indy
<
y
->
domainSize
(); ++
indy
) {
317
// Creating a new node bound to x that will be the son of the node
318
// tied to y for the current value assumed by y
319
currentNewXNodeSons
=
InternalNode
::
allocateNodeSons
(
x
);
320
321
// Iterating on the different values taht x can assumed to do the remap
322
for
(
indx
= 0;
indx
<
x
->
domainSize
(); ++
indx
) {
323
currentNewXNodeSons
[
indx
] =
currentOldXNode
->
son
(
indx
);
324
if
(!
_functionGraph_
->
isTerminalNode
(
currentOldXNode
->
son
(
indx
))
325
&&
_functionGraph_
->
node
(
currentOldXNode
->
son
(
indx
))->
nodeVar
() ==
y
)
326
currentNewXNodeSons
[
indx
]
327
=
_functionGraph_
->
node
(
currentOldXNode
->
son
(
indx
))->
son
(
indy
);
328
}
329
330
// Inserting the new node bound to x
331
currentNewYNodeSons
[
indy
] =
nodeRedundancyCheck_
(
x
,
currentNewXNodeSons
);
332
}
333
334
// Replacing old node x by new node y
335
currentNewYNodeId
=
currentNewYNodeSons
[0];
336
if
(
_isRedundant_
(
y
,
currentNewYNodeSons
)) {
337
migrateNode_
(
oldxNodes
->
list
()->
element
(),
currentNewYNodeId
);
338
SOA_DEALLOCATE
(
currentNewYNodeSons
,
y
->
domainSize
() *
sizeof
(
NodeId
));
339
}
else
{
340
currentNewYNodeId
=
_checkIsomorphism_
(
y
,
currentNewYNodeSons
);
341
if
(
currentNewYNodeId
!= 0) {
342
migrateNode_
(
oldxNodes
->
list
()->
element
(),
currentNewYNodeId
);
343
SOA_DEALLOCATE
(
currentNewYNodeSons
,
y
->
domainSize
() *
sizeof
(
NodeId
));
344
}
else
{
345
// Updating the sons (they must not consider old x as their parent)
346
for
(
Idx
i
= 0;
i
<
currentOldXNode
->
nodeVar
()->
domainSize
(); ++
i
) {
347
if
(
_functionGraph_
->
_internalNodeMap_
.
exists
(
currentOldXNode
->
son
(
i
))) {
348
_functionGraph_
->
_internalNodeMap_
[
currentOldXNode
->
son
(
i
)]->
removeParent
(
349
oldxNodes
->
list
()->
element
(),
350
i
);
351
}
352
}
353
// Reaffecting old node x internal attributes to correct new one
354
currentOldXNode
->
setNode
(
y
,
currentNewYNodeSons
);
355
// Updating new sons (they must consider the node as a parent)
356
for
(
Idx
i
= 0;
i
<
currentOldXNode
->
nodeVar
()->
domainSize
(); ++
i
) {
357
if
(
_functionGraph_
->
_internalNodeMap_
.
exists
(
currentNewYNodeSons
[
i
])) {
358
_functionGraph_
->
_internalNodeMap_
[
currentNewYNodeSons
[
i
]]->
addParent
(
359
oldxNodes
->
list
()->
element
(),
360
i
);
361
}
362
}
363
364
_functionGraph_
->
_var2NodeIdMap_
[
y
]->
addLink
(
oldxNodes
->
list
()->
element
());
365
}
366
}
367
368
oldxNodes
->
searchAndRemoveLink
(
oldxNodes
->
list
()->
element
());
369
}
370
delete
oldxNodes
;
371
372
while
(
oldyNodes
->
list
()) {
373
NodeId
curId
=
oldyNodes
->
list
()->
element
();
374
if
(
_functionGraph_
->
_internalNodeMap_
[
curId
]->
parents
() ==
nullptr
) {
375
for
(
Idx
i
= 0;
i
<
_functionGraph_
->
_internalNodeMap_
[
curId
]->
nodeVar
()->
domainSize
(); ++
i
)
376
if
(
_functionGraph_
->
_internalNodeMap_
.
exists
(
377
_functionGraph_
->
_internalNodeMap_
[
curId
]->
son
(
i
)))
378
_functionGraph_
->
_internalNodeMap_
[
_functionGraph_
->
_internalNodeMap_
[
curId
]->
son
(
i
)]
379
->
removeParent
(
curId
,
i
);
380
delete
_functionGraph_
->
_internalNodeMap_
[
curId
];
381
_functionGraph_
->
_internalNodeMap_
.
erase
(
curId
);
382
_functionGraph_
->
_model_
.
eraseNode
(
curId
);
383
}
else
{
384
_functionGraph_
->
_var2NodeIdMap_
[
y
]->
addLink
(
curId
);
385
}
386
oldyNodes
->
searchAndRemoveLink
(
curId
);
387
}
388
delete
oldyNodes
;
389
}
390
391
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
392
INLINE
void
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
migrateNode_
(
393
const
NodeId
&
origin
,
394
const
NodeId
&
destination
) {
395
InternalNode
*
org
=
_functionGraph_
->
_internalNodeMap_
[
origin
];
396
// Upating parents after the change
397
Link
<
Parent
>*
picle
=
org
->
parents
();
398
while
(
picle
!=
nullptr
) {
399
setSon
(
picle
->
element
().
parentId
,
picle
->
element
().
modality
,
destination
);
400
picle
=
picle
->
nextLink
();
401
}
402
403
// Updating sons after the change
404
for
(
Idx
i
= 0;
i
<
org
->
nbSons
(); ++
i
)
405
if
(
_functionGraph_
->
_internalNodeMap_
.
exists
(
org
->
son
(
i
)))
406
_functionGraph_
->
_internalNodeMap_
[
org
->
son
(
i
)]->
removeParent
(
origin
,
i
);
407
408
delete
org
;
409
_functionGraph_
->
_internalNodeMap_
.
erase
(
origin
);
410
_functionGraph_
->
_model_
.
eraseNode
(
origin
);
411
412
if
(
_functionGraph_
->
root
() ==
origin
)
this
->
setRootNode
(
destination
);
413
}
414
415
// Checks if a similar node does not already exists in the graph or
416
// if it has the same child for every variable value.
417
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
418
INLINE
NodeId
419
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
nodeRedundancyCheck_
(
420
const
DiscreteVariable
*
var
,
421
NodeId
*
sonsIds
) {
422
NodeId
newNode
=
sonsIds
[0];
423
424
if
(
_isRedundant_
(
var
,
sonsIds
)) {
425
SOA_DEALLOCATE
(
sonsIds
,
sizeof
(
NodeId
) *
var
->
domainSize
());
426
}
else
{
427
newNode
=
_checkIsomorphism_
(
var
,
sonsIds
);
428
if
(
newNode
== 0) {
429
newNode
=
addInternalNode_
(
var
,
sonsIds
);
430
}
else
{
431
SOA_DEALLOCATE
(
sonsIds
,
sizeof
(
NodeId
) *
var
->
domainSize
());
432
}
433
}
434
435
return
newNode
;
436
}
437
438
// Checks if a similar node does not already exists in the graph.
439
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
440
INLINE
NodeId
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
_checkIsomorphism_
(
441
const
DiscreteVariable
*
var
,
442
NodeId
*
sons
) {
443
const
InternalNode
*
nody
=
nullptr
;
444
Idx
i
= 0;
445
446
// Check abscence of identical node
447
Link
<
NodeId
>*
currentElem
=
_functionGraph_
->
_var2NodeIdMap_
[
var
]->
list
();
448
while
(
currentElem
!=
nullptr
) {
449
nody
=
_functionGraph_
->
_internalNodeMap_
[
currentElem
->
element
()];
450
451
// Check on the other sons
452
i
= 0;
453
while
(
i
<
var
->
domainSize
() &&
sons
[
i
] ==
nody
->
son
(
i
))
454
++
i
;
455
if
(
i
==
var
->
domainSize
())
return
currentElem
->
element
();
456
457
currentElem
=
currentElem
->
nextLink
();
458
}
459
return
0;
460
}
461
462
// Checks if node has the same child for every variable value
463
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
464
INLINE
bool
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
_isRedundant_
(
465
const
DiscreteVariable
*
var
,
466
NodeId
*
sons
) {
467
for
(
Idx
m
= 1;
m
<
var
->
domainSize
();
m
++)
468
if
(
sons
[
m
] !=
sons
[0])
return
false
;
469
return
true
;
470
}
471
472
// Ensures that every isomorphic subgraphs are merged together.
473
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
474
INLINE
void
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
reduce_
() {
475
Link
<
NodeId
>*
currentNodeId
=
nullptr
;
476
Link
<
NodeId
>*
nextNodeId
=
nullptr
;
477
InternalNode
*
currentNode
=
nullptr
;
478
bool
theSame
=
true
;
479
Idx
currentInd
;
480
481
for
(
SequenceIterator
<
const
DiscreteVariable
* >
varIter
482
=
_functionGraph_
->
variablesSequence
().
rbegin
();
483
varIter
!=
_functionGraph_
->
variablesSequence
().
rend
();
484
--
varIter
) {
485
currentNodeId
=
_functionGraph_
->
_var2NodeIdMap_
[*
varIter
]->
list
();
486
487
while
(
currentNodeId
!=
nullptr
) {
488
nextNodeId
=
currentNodeId
->
nextLink
();
489
currentNode
=
_functionGraph_
->
_internalNodeMap_
[
currentNodeId
->
element
()];
490
491
// First isomorphism to handle is the one where all node children are
492
// the same
493
theSame
=
true
;
494
for
(
currentInd
= 1;
currentInd
< (*
varIter
)->
domainSize
();
currentInd
++) {
495
if
(
currentNode
->
son
(
currentInd
) !=
currentNode
->
son
(0)) {
496
theSame
=
false
;
497
break
;
498
}
499
}
500
501
if
(
theSame
==
true
) {
502
migrateNode_
(
currentNodeId
->
element
(),
currentNode
->
son
(0));
503
_functionGraph_
->
_var2NodeIdMap_
[*
varIter
]->
searchAndRemoveLink
(
currentNodeId
->
element
());
504
currentNodeId
=
nextNodeId
;
505
continue
;
506
}
507
508
// Second isomorphism to handle is the one where two nodes have same
509
// variable and same children
510
if
(
nextNodeId
) {
511
Link
<
NodeId
>*
anotherNodeId
=
currentNodeId
->
nextLink
();
512
InternalNode
*
anotherNode
=
nullptr
;
513
Idx
modality
= 0;
514
while
(
anotherNodeId
->
nextLink
() !=
nullptr
) {
515
nextNodeId
=
anotherNodeId
->
nextLink
();
516
anotherNode
=
_functionGraph_
->
_internalNodeMap_
[
anotherNodeId
->
element
()];
517
518
// Check on the other sons
519
for
(
modality
= 0;
modality
< (*
varIter
)->
domainSize
(); ++
modality
) {
520
if
(
anotherNode
->
son
(
modality
) !=
currentNode
->
son
(
modality
))
break
;
521
if
(
modality
== (*
varIter
)->
domainSize
() - 1) {
522
migrateNode_
(
anotherNodeId
->
element
(),
currentNodeId
->
element
());
523
_functionGraph_
->
_var2NodeIdMap_
[*
varIter
]->
searchAndRemoveLink
(
524
anotherNodeId
->
element
());
525
}
526
}
527
528
anotherNodeId
=
nextNodeId
;
529
}
530
}
531
currentNodeId
=
currentNodeId
->
nextLink
();
532
}
533
}
534
}
535
536
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
537
INLINE
void
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
clean
() {
538
Sequence
<
const
DiscreteVariable
* >
oldSequence
(
_functionGraph_
->
variablesSequence
());
539
for
(
SequenceIterator
<
const
DiscreteVariable
* >
varIter
=
oldSequence
.
begin
();
540
varIter
!=
oldSequence
.
end
();
541
++
varIter
)
542
if
(!
_functionGraph_
->
varNodeListe
(*
varIter
)->
list
())
_functionGraph_
->
erase
(**
varIter
);
543
}
544
545
// ==========================================================================
546
// MultiDimFunctionGraphTreeManager
547
// ==========================================================================
548
549
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
550
MultiDimFunctionGraphTreeManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
551
MultiDimFunctionGraphTreeManager
(
552
MultiDimFunctionGraph
<
GUM_SCALAR
,
TerminalNodePolicy
>*
master
) :
553
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
TerminalNodePolicy
>(
master
) {
554
GUM_CONSTRUCTOR
(
MultiDimFunctionGraphTreeManager
);
555
}
556
557
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
558
MultiDimFunctionGraphTreeManager
<
GUM_SCALAR
,
559
TerminalNodePolicy
>::~
MultiDimFunctionGraphTreeManager
() {
560
GUM_DESTRUCTOR
(
MultiDimFunctionGraphTreeManager
);
561
}
562
563
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
564
NodeId
MultiDimFunctionGraphTreeManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
addInternalNode
(
565
const
DiscreteVariable
*
var
,
566
NodeId
*
sons
) {
567
return
this
->
addInternalNode_
(
var
,
sons
);
568
}
569
570
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
571
void
MultiDimFunctionGraphTreeManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
reduce
() {}
572
573
// ===========================================================================
574
// MultiDimFunctionGraphROManager
575
// ===========================================================================
576
577
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
578
MultiDimFunctionGraphROManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
MultiDimFunctionGraphROManager
(
579
MultiDimFunctionGraph
<
GUM_SCALAR
,
TerminalNodePolicy
>*
master
) :
580
MultiDimFunctionGraphManager
<
GUM_SCALAR
,
TerminalNodePolicy
>(
master
) {
581
GUM_CONSTRUCTOR
(
MultiDimFunctionGraphROManager
);
582
}
583
584
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
585
MultiDimFunctionGraphROManager
<
GUM_SCALAR
,
586
TerminalNodePolicy
>::~
MultiDimFunctionGraphROManager
() {
587
GUM_DESTRUCTOR
(
MultiDimFunctionGraphROManager
);
588
}
589
590
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
591
NodeId
MultiDimFunctionGraphROManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
addInternalNode
(
592
const
DiscreteVariable
*
var
,
593
NodeId
*
sons
) {
594
return
this
->
nodeRedundancyCheck_
(
var
,
sons
);
595
}
596
597
template
<
typename
GUM_SCALAR
,
template
<
class
>
class
TerminalNodePolicy
>
598
void
MultiDimFunctionGraphROManager
<
GUM_SCALAR
,
TerminalNodePolicy
>::
reduce
() {
599
this
->
reduce_
();
600
}
601
602
}
// namespace gum
gum::Set::emplace
INLINE void emplace(Args &&... args)
Definition:
set_tpl.h:643