aGrUM 2.3.2
a C++ library for (probabilistic) graphical models
structuralComparator.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
43
44
45#ifndef DOXYGEN_SHOULD_SKIP_THIS
46
47namespace gum {
49
52
53 void StructuralComparator::compare(const DiGraph& ref, const DiGraph& test) {
54 if (ref.size() != test.size()) { GUM_ERROR(OperationNotAllowed, "Graphs of different sizes") }
55 for (const NodeId node: ref.asNodeSet()) {
56 if (!test.existsNode(node)) {
57 GUM_ERROR(InvalidNode, "Test doesn't contain all nodes from ref")
58 }
59 }
60 // compute the orientation matrix
61 // no edges so these stay null
62 _true_edge_ = 0;
67 // these will be filled
68 _true_arc_ = 0;
69 _true_none_ = 0;
73
74 for (const Arc& arc: ref.arcs()) {
75 if (test.existsArc(arc)) {
76 ++_true_arc_;
77 } else if (test.existsArc(arc.head(), arc.tail())) {
79 } else {
81 }
82 }
83 for (const Arc& arc: test.arcs()) {
84 if (!ref.existsArc(arc) && !ref.existsArc(arc.head(), arc.tail())) { ++_wrong_arc_none_; }
85 }
86 // TN = #possible arcs - #existing arcs
87 _true_none_ = ref.size() * (ref.size() - 1) - _true_arc_ - _misoriented_arc_ - _wrong_arc_none_
89 }
90
91 void StructuralComparator::compare(const UndiGraph& ref, const UndiGraph& test) {
92 if (ref.size() != test.size()) { GUM_ERROR(OperationNotAllowed, "Graphs of different sizes") }
93 for (const NodeId node: ref.asNodeSet()) {
94 if (!test.existsNode(node)) {
95 GUM_ERROR(InvalidNode, "Test doesn't contain all nodes from ref")
96 }
97 }
98 // compute the orientation matrix
99 // no arcs so these stay null
100 _true_arc_ = 0;
106 // these will be filled
107 _true_edge_ = 0;
108 _true_none_ = 0;
111
112 for (const Edge& edge: ref.edges()) {
113 if (test.existsEdge(edge)) {
114 ++_true_edge_;
115 } else {
117 }
118 }
119 for (const Edge& edge: test.edges()) {
120 if (!ref.existsEdge(edge)) { ++_wrong_edge_none_; }
121 }
122 // TN = #possible edges - #existing edges
124 = ref.size() * (ref.size() - 1) / 2 - _true_edge_ - _wrong_edge_none_ - _wrong_none_edge_;
125 }
126
127 void StructuralComparator::compare(const PDAG& ref, const PDAG& test) {
128 if (ref.size() != test.size()) { GUM_ERROR(OperationNotAllowed, "Graphs of different sizes") }
129 for (const NodeId node: ref.asNodeSet()) {
130 if (!test.existsNode(node)) {
131 GUM_ERROR(InvalidNode, "Test doesn't contain all nodes from ref")
132 }
133 }
134
135 // compute the orientation matrix
136 _true_arc_ = 0;
137 _true_edge_ = 0;
138 _true_none_ = 0;
146
147 for (const Arc& arc: ref.arcs()) {
148 if (test.existsArc(arc)) {
149 ++_true_arc_;
150 } else if (test.existsArc(arc.head(), arc.tail())) {
152 } else if (test.existsEdge(arc.tail(), arc.head())) {
154 } else {
156 }
157 }
158 for (const Edge& edge: ref.edges()) {
159 if (test.existsEdge(edge)) {
160 ++_true_edge_;
161 } else if (test.existsArc(edge.first(), edge.second())
162 || test.existsArc(edge.second(), edge.first())) {
164 } else {
166 }
167 }
168 for (const Arc& arc: test.arcs()) {
169 if (!ref.existsArc(arc) && !ref.existsArc(arc.head(), arc.tail())
170 && !ref.existsEdge(arc.tail(), arc.head())) {
172 }
173 }
174 for (const Edge& edge: test.edges()) {
175 if (!ref.existsEdge(edge) && !ref.existsArc(edge.first(), edge.second())
176 && !ref.existsArc(edge.second(), edge.first())) {
178 }
179 }
180 // TN = #possible edges - #existing edges
181 _true_none_ = ref.size() * (ref.size() - 1) / 2 - _true_edge_ - _wrong_edge_none_
184 }
185
187 double tp, fp, precision;
190 precision = tp / (tp + fp);
191 return precision;
192 }
193
195 double tp, fn, recall;
198 recall = tp / (tp + fn);
199 return recall;
200 }
201
203 double tp, fp, fn, precision, recall, f_score;
207
208 precision = tp / (tp + fp);
209 recall = tp / (tp + fn);
211 return f_score;
212 }
213
214 double StructuralComparator::precision() const {
215 double tp, fp, precision;
216 tp = _true_arc_ + _true_edge_;
219 precision = tp / (tp + fp);
220 return precision;
221 }
222
223 double StructuralComparator::recall() const {
224 double tp, fn, recall;
225 tp = _true_arc_ + _true_edge_;
227 recall = tp / (tp + fn);
228 return recall;
229 }
230
231 double StructuralComparator::f_score() const {
232 double tp, fp, fn, precision, recall, f_score;
233 tp = _true_arc_ + _true_edge_;
237
238 precision = tp / (tp + fp);
239 recall = tp / (tp + fn);
240
242 return f_score;
243 }
244
245} /* namespace gum */
246
247#endif /* DOXYGEN_SHOULD_SKIP_THIS */
Base class for all oriented graphs.
Definition diGraph.h:130
Base class for partially directed acyclic graphs.
Definition PDAG.h:130
double _true_edge_
Confusion matrix.
~StructuralComparator()
destructor
double recall() const
compare two DiGraphs
double precision_skeleton() const
Measures for the skeleton, aka graph without orientations.
double precision() const
Measures for the graphs.
double recall_skeleton() const
compare two DiGraphs
StructuralComparator()
default constructor
double f_score_skeleton() const
compare two DiGraphs
void compare(const DiGraph &ref, const DiGraph &test)
compare two DiGraphs
double f_score() const
compare two DiGraphs
Base class for undirected graphs.
Definition undiGraph.h:128
#define GUM_ERROR(type, msg)
Definition exceptions.h:72
Size NodeId
Type for node ids.
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
A class for comparing graphs based on their structures.