aGrUM
0.20.2
a C++ library for (probabilistic) graphical models
essentialGraph.cpp
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 Source implementation of the class building the essential Graph from a
24
* DAGmodel
25
*
26
* @author Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
27
*
28
*/
29
#
include
<
agrum
/
BN
/
algorithms
/
essentialGraph
.
h
>
30
31
#
ifdef
GUM_NO_INLINE
32
#
include
<
agrum
/
BN
/
algorithms
/
essentialGraph_inl
.
h
>
33
#
endif
// GUM_NOINLINE
34
35
namespace
gum
{
36
EssentialGraph
::
EssentialGraph
(
const
DAGmodel
&
m
) :
dagmodel__
(&
m
) {
37
buildEssentialGraph__
();
38
}
39
40
EssentialGraph
::
EssentialGraph
(
const
DAGmodel
&
m
,
const
MixedGraph
&
mg
) :
41
dagmodel__
(&
m
),
mg__
(
mg
) {}
42
EssentialGraph
::
EssentialGraph
(
const
EssentialGraph
&
g
) {
43
dagmodel__
=
g
.
dagmodel__
;
44
buildEssentialGraph__
();
45
}
46
EssentialGraph
&
EssentialGraph
::
operator
=(
const
EssentialGraph
&
g
) {
47
if
(&
g
!=
this
) {
48
dagmodel__
=
g
.
dagmodel__
;
49
buildEssentialGraph__
();
50
}
51
return
*
this
;
52
}
53
54
EssentialGraph
::~
EssentialGraph
() =
default
;
55
56
void
EssentialGraph
::
buildEssentialGraph__
() {
57
mg__
.
clear
();
58
if
(
dagmodel__
==
nullptr
)
return
;
59
60
for
(
const
auto
&
node
:
dagmodel__
->
nodes
()) {
61
mg__
.
addNodeWithId
(
node
);
62
}
63
for
(
const
auto
&
arc
:
dagmodel__
->
arcs
()) {
64
mg__
.
addArc
(
arc
.
tail
(),
arc
.
head
());
65
}
66
67
std
::
vector
<
Arc
>
v
;
68
do
{
69
v
.
clear
();
70
for
(
const
auto
x
:
dagmodel__
->
topologicalOrder
())
71
for
(
const
auto
y
:
mg__
.
children
(
x
))
72
if
(!
strongly_protected__
(
x
,
y
))
v
.
emplace_back
(
x
,
y
);
73
74
for
(
const
auto
&
arc
:
v
) {
75
mg__
.
eraseArc
(
arc
);
76
mg__
.
addEdge
(
arc
.
tail
(),
arc
.
head
());
77
}
78
}
while
(!
v
.
empty
());
79
}
80
81
bool
EssentialGraph
::
strongly_protected__
(
NodeId
a
,
NodeId
b
) {
82
// testing a->b from
83
// A Characterization of Markov Equivalence Classes for Acyclic Digraphs (2001)
84
// Steen A. Andersson, David Madigan, and Michael D. Perlman*
85
86
// condition (a)
87
for
(
const
auto
&
c
:
mg__
.
parents
(
a
)) {
88
if
(!
mg__
.
existsArc
(
c
,
b
)) {
89
// GUM_TRACE(a << "->" << b << " with "<<c<<" : (a)")
90
return
true
;
91
}
92
}
93
94
95
for
(
const
auto
&
c
:
mg__
.
parents
(
b
)) {
96
if
(
c
==
a
) {
continue
; }
97
// condition (c)
98
if
(
mg__
.
existsArc
(
a
,
c
)) {
99
// GUM_TRACE(a << "->" << b << " with "<<c<<" : (c)")
100
return
true
;
101
}
102
103
// condition (b) knowing that a can not be a parent of c (condition below)
104
if
(!
mg__
.
existsEdge
(
a
,
c
) && !
mg__
.
existsArc
(
c
,
a
)) {
105
// GUM_TRACE(a << "->" << b << " with "<<c<<" : (b)")
106
return
true
;
107
}
108
}
109
110
// condition (d)
111
bool
oneFound
=
false
;
112
for
(
const
auto
&
c
:
mg__
.
parents
(
b
)) {
113
if
(
c
==
a
) {
continue
; }
114
// condition (d)
115
if
(
mg__
.
existsEdge
(
c
,
a
)) {
116
if
(
oneFound
) {
// this is the second found
117
// GUM_TRACE(a << "->" << b << " : (d)")
118
return
true
;
119
}
120
oneFound
=
true
;
121
}
122
}
123
124
return
false
;
125
}
126
127
std
::
string
EssentialGraph
::
toDot
()
const
{
128
std
::
stringstream
output
;
129
std
::
stringstream
nodeStream
;
130
std
::
stringstream
edgeStream
;
131
List
<
NodeId
>
treatedNodes
;
132
output
<<
"digraph \""
133
<<
"no_name\" {"
<<
std
::
endl
;
134
nodeStream
<<
"node [shape = ellipse];"
<<
std
::
endl
;
135
std
::
string
tab
=
" "
;
136
if
(
dagmodel__
!=
nullptr
) {
137
for
(
const
auto
node
:
mg__
.
nodes
()) {
138
nodeStream
<<
tab
<<
node
<<
"[label=\""
139
<<
dagmodel__
->
variable
(
node
).
name
() <<
"\"];"
;
140
141
for
(
const
auto
nei
:
mg__
.
neighbours
(
node
))
142
if
(!
treatedNodes
.
exists
(
nei
))
143
edgeStream
<<
tab
<<
node
<<
" -> "
<<
nei
<<
" [dir=none];"
144
<<
std
::
endl
;
145
146
for
(
const
auto
chi
:
mg__
.
children
(
node
))
147
edgeStream
<<
tab
<<
node
<<
" -> "
<<
chi
<<
" [color=red];"
148
<<
std
::
endl
;
149
150
treatedNodes
.
insert
(
node
);
151
}
152
}
153
output
<<
nodeStream
.
str
() <<
std
::
endl
154
<<
edgeStream
.
str
() <<
std
::
endl
155
<<
"}"
<<
std
::
endl
;
156
157
return
output
.
str
();
158
}
159
160
UndiGraph
EssentialGraph
::
skeleton
()
const
{
161
UndiGraph
skel
;
162
for
(
const
auto
&
n
:
nodes
())
163
skel
.
addNodeWithId
(
n
);
164
for
(
const
auto
&
edge
:
edges
())
165
skel
.
addEdge
(
edge
.
first
(),
edge
.
second
());
166
for
(
const
auto
&
arc
:
arcs
())
167
skel
.
addEdge
(
arc
.
tail
(),
arc
.
head
());
168
return
skel
;
169
}
170
}
// namespace gum
gum::Set::emplace
INLINE void emplace(Args &&... args)
Definition:
set_tpl.h:669