aGrUM 2.3.2
a C++ library for (probabilistic) graphical models
essentialGraph.cpp
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2025 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2025 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40
41
50
51#ifdef GUM_NO_INLINE
53#endif // GU%_NO_INLINE
54
55namespace gum {
57
59
64
66 if (&g != this) {
69 }
70 return *this;
71 }
72
74
76 MixedGraph mg; // during the process, the graph may not be a PDAG
77 _pdag_.clear();
78 if (_dagmodel_ == nullptr) return;
79
80 for (const auto& node: _dagmodel_->nodes()) {
81 mg.addNodeWithId(node);
82 _pdag_.addNodeWithId(node);
83 }
84 for (const auto& arc: _dagmodel_->arcs()) {
85 mg.addArc(arc.tail(), arc.head());
86 }
87
88 std::vector< Arc > v;
89 do {
90 v.clear();
91 for (const auto x: _dagmodel_->topologicalOrder())
92 for (const auto y: mg.children(x))
93 if (!_strongly_protected_(mg, x, y)) v.emplace_back(x, y);
94
95 for (const auto& arc: v) {
96 mg.eraseArc(arc);
97 mg.addEdge(arc.tail(), arc.head());
98 }
99 } while (!v.empty());
100
101 for (const auto& arc: mg.arcs()) {
102 _pdag_.addArc(arc.tail(), arc.head());
103 }
104 for (const auto& edge: mg.edges()) {
105 _pdag_.addEdge(edge.first(), edge.second());
106 }
107 }
108
112
114 // testing a->b from
115 // A Characterization of Markov Equivalence Classes for Acyclic Digraphs (2001)
116 // Steen A. Andersson, David Madigan, and Michael D. Perlman*
117
118 // condition (a)
119 for (const auto& c: mg.parents(a)) {
120 if (!mg.existsArc(c, b)) { return true; }
121 }
122
123
124 for (const auto& c: mg.parents(b)) {
125 if (c == a) { continue; }
126 // condition (c)
127 if (mg.existsArc(a, c)) { return true; }
128
129 // condition (b) knowing that a can not be a parent of c (condition below)
130 if (!mg.existsEdge(a, c) && !mg.existsArc(c, a)) { return true; }
131 }
132
133 // condition (d)
134 bool oneFound = false;
135 for (const auto& c: mg.parents(b)) {
136 if (c == a) { continue; }
137 // condition (d)
138 if (mg.existsEdge(c, a)) {
139 if (oneFound) { // this is the second found
140 return true;
141 }
142 oneFound = true;
143 }
144 }
145
146 return false;
147 }
148
149 std::string EssentialGraph::toDot() const {
150 std::stringstream output;
151 std::stringstream nodeStream;
152 std::stringstream edgeStream;
153 List< NodeId > treatedNodes;
154 output << "digraph \""
155 << "no_name\" {" << std::endl;
156 nodeStream << "node [shape = ellipse];" << std::endl;
157 std::string tab = " ";
158 if (_dagmodel_ != nullptr) {
159 for (const auto node: _pdag_.nodes()) {
160 nodeStream << tab << node << "[label=\"" << _dagmodel_->variable(node).name() << "\"];";
161
162 for (const auto nei: _pdag_.neighbours(node))
163 if (!treatedNodes.exists(nei))
164 edgeStream << tab << node << " -> " << nei << " [dir=none];" << std::endl;
165
166 for (const auto chi: _pdag_.children(node))
167 edgeStream << tab << node << " -> " << chi << " [color=red];" << std::endl;
168
169 treatedNodes.insert(node);
170 }
171 }
172 output << nodeStream.str() << std::endl << edgeStream.str() << std::endl << "}" << std::endl;
173
174 return output.str();
175 }
176
178 UndiGraph skel;
179 for (const auto& n: nodes())
180 skel.addNodeWithId(n);
181 for (const auto& edge: edges())
182 skel.addEdge(edge.first(), edge.second());
183 for (const auto& arc: arcs())
184 skel.addEdge(arc.tail(), arc.head());
185 return skel;
186 }
187} // namespace gum
bool existsArc(const Arc &arc) const
indicates whether a given arc exists
const NodeSet & parents(NodeId id) const
returns the set of nodes with arc ingoing to a given node
NodeSet children(const NodeSet &ids) const
returns the set of children of a set of nodes
virtual void eraseArc(const Arc &arc)
removes an arc from the ArcGraphPart
const ArcSet & arcs() const
returns the set of arcs stored within the ArcGraphPart
Virtual base class for PGMs using a DAG.
Definition DAGmodel.h:64
virtual void addArc(const NodeId tail, const NodeId head)
insert a new arc into the directed graph
Definition diGraph_inl.h:55
const EdgeSet & edges() const
returns the set of edges stored within the EdgeGraphPart
bool existsEdge(const Edge &edge) const
indicates whether a given edge exists
const ArcSet & arcs() const
wrapping MixedGraph::arcs()
const DAGmodel * _dagmodel_
UndiGraph skeleton() const
const NodeGraphPart & nodes() const
wrapping MixedGraph::nodes()
EssentialGraph & operator=(const EssentialGraph &g)
bool _strongly_protected_(NodeId a, NodeId b) const
EssentialGraph()=default
std::string toDot() const
const EdgeSet & edges() const
wrapping MixedGraph::edges()
Generic doubly linked lists.
Definition list.h:379
bool exists(const Val &val) const
Checks whether there exists a given element in the list.
Definition list_tpl.h:1725
Val & insert(const Val &val)
Inserts a new element at the end of the chained list (alias of pushBack).
Definition list_tpl.h:1515
Base class for mixed graphs.
Definition mixedGraph.h:146
virtual void addNodeWithId(const NodeId id)
try to insert a node with the given id
Base class for partially directed acyclic graphs.
Definition PDAG.h:130
Base class for undirected graphs.
Definition undiGraph.h:128
void addEdge(NodeId first, NodeId second) override
insert a new edge into the undirected graph
Class building the essential Graph from a DAGmodel.
Inline implementation of the class building the essential Graph from a DAGmodel.
Size NodeId
Type for node ids.
gum is the global namespace for all aGrUM entities
Definition agrum.h:46