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