aGrUM
0.20.2
a C++ library for (probabilistic) graphical models
DAGCycleDetector_inl.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
/** @file
23
* @brief A class for detecting directed cycles in DAGs when trying to apply
24
* many changes to the graph
25
*
26
* @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
27
*/
28
29
namespace
gum
{
30
31
/* ===========================================================================
32
*/
33
// CHANGES
34
/* ===========================================================================
35
*/
36
37
// default constructor
38
INLINE
DAGCycleDetector
::
Change
::
Change
(
ChangeType
type
,
39
NodeId
tail
,
40
NodeId
head
)
noexcept
:
41
type__
{
type
},
42
tail__
{
tail
},
head__
{
head
} {
43
GUM_CONSTRUCTOR
(
DAGCycleDetector
::
Change
);
44
}
45
46
// copy constructor
47
INLINE
48
DAGCycleDetector
::
Change
::
Change
(
const
DAGCycleDetector
::
Change
&
from
)
noexcept
:
49
type__
{
from
.
type__
},
tail__
{
from
.
tail__
},
head__
{
from
.
head__
} {
50
GUM_CONS_CPY
(
DAGCycleDetector
::
Change
);
51
}
52
53
// move constructor
54
INLINE
55
DAGCycleDetector
::
Change
::
Change
(
DAGCycleDetector
::
Change
&&
from
)
noexcept
:
56
type__
{
from
.
type__
},
tail__
{
from
.
tail__
},
head__
{
from
.
head__
} {
57
GUM_CONS_MOV
(
DAGCycleDetector
::
Change
);
58
}
59
60
// destructor
61
INLINE
DAGCycleDetector
::
Change
::~
Change
()
noexcept
{
62
GUM_DESTRUCTOR
(
DAGCycleDetector
::
Change
);
63
}
64
65
// copy operator
66
INLINE
DAGCycleDetector
::
Change
&
DAGCycleDetector
::
Change
::
operator
=(
67
const
DAGCycleDetector
::
Change
&
from
)
noexcept
{
68
type__
=
from
.
type__
;
69
tail__
=
from
.
tail__
;
70
head__
=
from
.
head__
;
71
return
*
this
;
72
}
73
74
// move operator
75
INLINE
DAGCycleDetector
::
Change
&
DAGCycleDetector
::
Change
::
operator
=(
76
DAGCycleDetector
::
Change
&&
from
)
noexcept
{
77
type__
=
from
.
type__
;
78
tail__
=
from
.
tail__
;
79
head__
=
from
.
head__
;
80
return
*
this
;
81
}
82
83
/// returns the type of the operation
84
INLINE
DAGCycleDetector
::
ChangeType
85
DAGCycleDetector
::
Change
::
type
()
const
noexcept
{
86
return
type__
;
87
}
88
89
/// indicates the tail of the arc involved in the modification
90
INLINE NodeId
DAGCycleDetector
::
Change
::
tail
()
const
noexcept
{
return
tail__
; }
91
92
/// indicates the head of the arc involved in the modification
93
INLINE
NodeId
DAGCycleDetector
::
Change
::
head
()
const
noexcept
{
return
head__
; }
94
95
/* ===========================================================================
96
*/
97
// ArcAdd
98
/* ===========================================================================
99
*/
100
101
/// default constructor
102
INLINE
DAGCycleDetector
::
ArcAdd
::
ArcAdd
(
NodeId
tail
,
NodeId
head
)
noexcept
:
103
DAGCycleDetector
::
Change
(
DAGCycleDetector
::
ChangeType
::
ARC_ADDITION
,
104
tail
,
105
head
) {
106
GUM_CONSTRUCTOR
(
DAGCycleDetector
::
ArcAdd
);
107
}
108
109
/// copy constructor
110
INLINE
111
DAGCycleDetector
::
ArcAdd
::
ArcAdd
(
const
DAGCycleDetector
::
ArcAdd
&
from
)
noexcept
:
112
DAGCycleDetector
::
Change
(
from
.
type
(),
from
.
tail
(),
from
.
head
()) {
113
GUM_CONS_CPY
(
DAGCycleDetector
::
ArcAdd
);
114
}
115
116
/// move constructor
117
INLINE
118
DAGCycleDetector
::
ArcAdd
::
ArcAdd
(
DAGCycleDetector
::
ArcAdd
&&
from
)
noexcept
:
119
DAGCycleDetector
::
Change
(
std
::
move
(
from
.
type
()),
120
std
::
move
(
from
.
tail
()),
121
std
::
move
(
from
.
head
())) {
122
GUM_CONS_MOV
(
DAGCycleDetector
::
ArcAdd
);
123
}
124
125
/// destructor
126
INLINE
DAGCycleDetector
::
ArcAdd
::~
ArcAdd
()
noexcept
{
127
GUM_DESTRUCTOR
(
DAGCycleDetector
::
ArcAdd
);
128
}
129
130
/// copy operator
131
INLINE
DAGCycleDetector
::
ArcAdd
&
DAGCycleDetector
::
ArcAdd
::
operator
=(
132
const
DAGCycleDetector
::
ArcAdd
&
from
)
noexcept
{
133
DAGCycleDetector
::
Change
::
operator
=(
from
);
134
return
*
this
;
135
}
136
137
/// move operator
138
INLINE
DAGCycleDetector
::
ArcAdd
&
DAGCycleDetector
::
ArcAdd
::
operator
=(
139
DAGCycleDetector
::
ArcAdd
&&
from
)
noexcept
{
140
DAGCycleDetector
::
Change
::
operator
=(
std
::
move
(
from
));
141
return
*
this
;
142
}
143
144
/* ===========================================================================
145
*/
146
// ArcDel
147
/* ===========================================================================
148
*/
149
150
/// default constructor
151
INLINE
DAGCycleDetector
::
ArcDel
::
ArcDel
(
NodeId
tail
,
NodeId
head
)
noexcept
:
152
DAGCycleDetector
::
Change
(
DAGCycleDetector
::
ChangeType
::
ARC_DELETION
,
153
tail
,
154
head
) {
155
GUM_CONSTRUCTOR
(
DAGCycleDetector
::
ArcDel
);
156
}
157
158
/// copy constructor
159
INLINE
160
DAGCycleDetector
::
ArcDel
::
ArcDel
(
const
DAGCycleDetector
::
ArcDel
&
from
)
noexcept
:
161
DAGCycleDetector
::
Change
(
from
.
type
(),
from
.
tail
(),
from
.
head
()) {
162
GUM_CONS_CPY
(
DAGCycleDetector
::
ArcDel
);
163
}
164
165
/// move constructor
166
INLINE
167
DAGCycleDetector
::
ArcDel
::
ArcDel
(
DAGCycleDetector
::
ArcDel
&&
from
)
noexcept
:
168
DAGCycleDetector
::
Change
(
std
::
move
(
from
.
type
()),
169
std
::
move
(
from
.
tail
()),
170
std
::
move
(
from
.
head
())) {
171
GUM_CONS_MOV
(
DAGCycleDetector
::
ArcDel
);
172
}
173
174
/// destructor
175
INLINE
DAGCycleDetector
::
ArcDel
::~
ArcDel
()
noexcept
{
176
GUM_DESTRUCTOR
(
DAGCycleDetector
::
ArcDel
);
177
}
178
179
/// copy operator
180
INLINE
DAGCycleDetector
::
ArcDel
&
DAGCycleDetector
::
ArcDel
::
operator
=(
181
const
DAGCycleDetector
::
ArcDel
&
from
)
noexcept
{
182
DAGCycleDetector
::
Change
::
operator
=(
from
);
183
return
*
this
;
184
}
185
186
/// move operator
187
INLINE
DAGCycleDetector
::
ArcDel
&
DAGCycleDetector
::
ArcDel
::
operator
=(
188
DAGCycleDetector
::
ArcDel
&&
from
)
noexcept
{
189
DAGCycleDetector
::
Change
::
operator
=(
std
::
move
(
from
));
190
return
*
this
;
191
}
192
193
/* ===========================================================================
194
*/
195
// ArcReverse
196
/* ===========================================================================
197
*/
198
199
/// default constructor
200
INLINE
DAGCycleDetector
::
ArcReverse
::
ArcReverse
(
NodeId
tail
,
201
NodeId
head
)
noexcept
:
202
DAGCycleDetector
::
Change
(
DAGCycleDetector
::
ChangeType
::
ARC_REVERSAL
,
203
tail
,
204
head
) {
205
GUM_CONSTRUCTOR
(
DAGCycleDetector
::
ArcReverse
);
206
}
207
208
/// copy constructor
209
INLINE
DAGCycleDetector
::
ArcReverse
::
ArcReverse
(
210
const
DAGCycleDetector
::
ArcReverse
&
from
)
noexcept
:
211
DAGCycleDetector
::
Change
(
from
.
type
(),
from
.
tail
(),
from
.
head
()) {
212
GUM_CONS_CPY
(
DAGCycleDetector
::
ArcReverse
);
213
}
214
215
/// move constructor
216
INLINE
DAGCycleDetector
::
ArcReverse
::
ArcReverse
(
217
DAGCycleDetector
::
ArcReverse
&&
from
)
noexcept
:
218
DAGCycleDetector
::
Change
(
std
::
move
(
from
.
type
()),
219
std
::
move
(
from
.
tail
()),
220
std
::
move
(
from
.
head
())) {
221
GUM_CONS_MOV
(
DAGCycleDetector
::
ArcReverse
);
222
}
223
224
/// destructor
225
INLINE
DAGCycleDetector
::
ArcReverse
::~
ArcReverse
()
noexcept
{
226
GUM_DESTRUCTOR
(
DAGCycleDetector
::
ArcReverse
);
227
}
228
229
/// copy operator
230
INLINE
DAGCycleDetector
::
ArcReverse
&
DAGCycleDetector
::
ArcReverse
::
operator
=(
231
const
DAGCycleDetector
::
ArcReverse
&
from
)
noexcept
{
232
DAGCycleDetector
::
Change
::
operator
=(
from
);
233
return
*
this
;
234
}
235
236
/// move operator
237
INLINE
DAGCycleDetector
::
ArcReverse
&
DAGCycleDetector
::
ArcReverse
::
operator
=(
238
DAGCycleDetector
::
ArcReverse
&&
from
)
noexcept
{
239
DAGCycleDetector
::
Change
::
operator
=(
std
::
move
(
from
));
240
return
*
this
;
241
}
242
243
/* ===========================================================================
244
*/
245
// DAGCycleDetector
246
/* ===========================================================================
247
*/
248
249
/// default constructor
250
INLINE
DAGCycleDetector
::
DAGCycleDetector
()
noexcept
{
251
GUM_CONSTRUCTOR
(
DAGCycleDetector
);
252
}
253
254
/// copy constructor
255
INLINE
DAGCycleDetector
::
DAGCycleDetector
(
const
DAGCycleDetector
&
from
) :
256
dag__
(
from
.
dag__
),
ancestors__
(
from
.
ancestors__
),
257
descendants__
(
from
.
descendants__
) {
258
GUM_CONS_CPY
(
DAGCycleDetector
);
259
}
260
261
/// move constructor
262
INLINE
DAGCycleDetector
::
DAGCycleDetector
(
DAGCycleDetector
&&
from
) :
263
dag__
(
std
::
move
(
from
.
dag__
)),
ancestors__
(
std
::
move
(
from
.
ancestors__
)),
264
descendants__
(
std
::
move
(
from
.
descendants__
)) {
265
GUM_CONS_MOV
(
DAGCycleDetector
);
266
}
267
268
/// destructor
269
INLINE
DAGCycleDetector
::~
DAGCycleDetector
() {
270
GUM_DESTRUCTOR
(
DAGCycleDetector
);
271
}
272
273
/// copy operator
274
INLINE
DAGCycleDetector
&
275
DAGCycleDetector
::
operator
=(
const
DAGCycleDetector
&
from
) {
276
if
(
this
!= &
from
) {
277
dag__
=
from
.
dag__
;
278
ancestors__
=
from
.
ancestors__
;
279
descendants__
=
from
.
descendants__
;
280
}
281
282
return
*
this
;
283
}
284
285
/// move operator
286
INLINE
DAGCycleDetector
&
DAGCycleDetector
::
operator
=(
DAGCycleDetector
&&
from
) {
287
if
(
this
!= &
from
) {
288
dag__
=
std
::
move
(
from
.
dag__
);
289
ancestors__
=
std
::
move
(
from
.
ancestors__
);
290
descendants__
=
std
::
move
(
from
.
descendants__
);
291
}
292
293
return
*
this
;
294
}
295
296
/// indicates whether an arc addition would create a cycle
297
INLINE
bool
DAGCycleDetector
::
hasCycleFromAddition
(
NodeId
x
,
298
NodeId
y
)
const
noexcept
{
299
return
descendants__
[
y
].
exists
(
x
);
300
}
301
302
/// indicates wether an arc reversal would create a cycle
303
INLINE
bool
DAGCycleDetector
::
hasCycleFromReversal
(
NodeId
x
,
304
NodeId
y
)
const
noexcept
{
305
return
(
ancestors__
[
y
][
x
] > 1);
306
}
307
308
/// indicates whether an arc deletion would create a cycle
309
INLINE
bool
DAGCycleDetector
::
hasCycleFromDeletion
(
NodeId
x
,
310
NodeId
y
)
const
noexcept
{
311
return
false
;
312
}
313
314
/// adds a nodeset to another (nodes are weighted, so weights are added)
315
INLINE
316
void
DAGCycleDetector
::
addWeightedSet__
(
NodeProperty
<
Size
>&
nodeset
,
317
const
NodeProperty
<
Size
>&
set_to_add
,
318
Size
multiplier
)
const
{
319
for
(
auto
iter
=
set_to_add
.
cbegin
();
iter
!=
set_to_add
.
cend
(); ++
iter
) {
320
if
(
nodeset
.
exists
(
iter
.
key
())) {
321
nodeset
[
iter
.
key
()] +=
iter
.
val
() *
multiplier
;
322
}
else
{
323
nodeset
.
insert
(
iter
.
key
(),
iter
.
val
() *
multiplier
);
324
}
325
}
326
}
327
328
/// removes a weighted nodeset from another (weights are subtracted)
329
INLINE
330
void
DAGCycleDetector
::
delWeightedSet__
(
NodeProperty
<
Size
>&
nodeset
,
331
const
NodeProperty
<
Size
>&
set_to_del
,
332
Size
multiplier
)
const
{
333
for
(
auto
iter
=
set_to_del
.
cbegin
();
iter
!=
set_to_del
.
cend
(); ++
iter
) {
334
if
(
nodeset
.
exists
(
iter
.
key
())) {
335
Size
&
weight
=
nodeset
[
iter
.
key
()];
336
weight
-=
iter
.
val
() *
multiplier
;
337
338
if
(!
weight
) {
nodeset
.
erase
(
iter
.
key
()); }
339
}
340
}
341
}
342
343
/** @brief put into a weighted nodeset the nodes of another weighted set that
344
* belong to a set of arc extremities */
345
INLINE
346
void
DAGCycleDetector
::
restrictWeightedSet__
(
347
NodeProperty
<
Size
>&
result_set
,
348
const
NodeProperty
<
Size
>&
set_to_restrict
,
349
const
NodeSet
&
extremities
)
const
{
350
for
(
auto
iter
=
set_to_restrict
.
cbegin
();
iter
!=
set_to_restrict
.
cend
();
351
++
iter
) {
352
if
(
extremities
.
exists
(
iter
.
key
())) {
353
result_set
.
insert
(
iter
.
key
(),
iter
.
val
());
354
}
355
}
356
}
357
358
/// reverses an arc from the DAG
359
INLINE
void
DAGCycleDetector
::
reverseArc
(
NodeId
tail
,
NodeId
head
) {
360
if
(
hasCycleFromReversal
(
tail
,
head
)) {
361
GUM_ERROR
(
InvalidDirectedCycle
,
362
"the arc would create a directed into a DAG"
);
363
}
364
365
eraseArc
(
tail
,
head
);
366
addArc
(
head
,
tail
);
367
}
368
369
/// check the equality between two DAGCycleDetectors
370
INLINE
bool
DAGCycleDetector
::
operator
==(
const
DAGCycleDetector
&
from
)
const
{
371
return
(
//( dagmodel__ == from.dagmodel__ ) &&
372
(
ancestors__
==
from
.
ancestors__
) && (
descendants__
==
from
.
descendants__
));
373
}
374
375
/// check the inequality between two DAGCycleDetectors
376
INLINE
bool
DAGCycleDetector
::
operator
!=(
const
DAGCycleDetector
&
from
)
const
{
377
return
!
operator
==(
from
);
378
}
379
380
}
/* namespace gum */
gum::Set::emplace
INLINE void emplace(Args &&... args)
Definition:
set_tpl.h:669