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