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