aGrUM 3.1.1
a C++ library for (probabilistic) graphical models
IMarkovRandomField_tpl.h
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2026 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-2026 *
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#pragma once
42
43
50
51#include <limits>
52
55
56namespace gum {
57
58 // IMarkovRandomField
59
60 template < GUM_Numeric GUM_SCALAR >
64
65 template < GUM_Numeric GUM_SCALAR >
67 GUM_CONSTRUCTOR(IMarkovRandomField);
68 this->setProperty("name", name);
69 }
70
71 template < GUM_Numeric GUM_SCALAR >
76
77 template < GUM_Numeric GUM_SCALAR >
80 if (this != &source) { UGmodel::operator=(source); }
81
82 return *this;
83 }
84
85 template < GUM_Numeric GUM_SCALAR >
89
90 template < GUM_Numeric GUM_SCALAR >
92 Size res = 0;
93 for (auto f: factors()) {
94 res += f.second->domainSize();
95 }
96 return res;
97 }
98
99 template < GUM_Numeric GUM_SCALAR >
101 Size res = 0;
102 for (auto node: nodes()) {
103 auto v = variable(node).domainSize();
104 if (v > res) { res = v; }
105 }
106 return res;
107 }
108
109 template < GUM_Numeric GUM_SCALAR >
111 GUM_SCALAR res = 1.0;
112 for (auto elt: factors()) {
113 auto v = elt.second->min();
114 if (v < res) { res = v; }
115 }
116 return res;
117 }
118
119 template < GUM_Numeric GUM_SCALAR >
121 GUM_SCALAR res = 1.0;
122 for (auto elt: factors()) {
123 auto v = elt.second->max();
124 if (v > res) { res = v; }
125 }
126 return res;
127 }
128
129 template < GUM_Numeric GUM_SCALAR >
131 GUM_SCALAR res = 1.0;
132 for (auto elt: factors()) {
133 auto v = elt.second->minNonZero();
134 if (v < res) { res = v; }
135 }
136 return res;
137 }
138
139 template < GUM_Numeric GUM_SCALAR >
141 GUM_SCALAR res = 0.0;
142 for (auto elt: factors()) {
143 auto v = elt.second->maxNonOne();
144 if (v > res) { res = v; }
145 }
146 return res;
147 }
148
149 template < GUM_Numeric GUM_SCALAR >
151 Size param = 0;
152 double dSize = log10DomainSize();
153
154 for (auto factor: factors())
155 param += factor.second->content()->realSize();
156
157 std::stringstream s;
158 s << std::format("MRF{{nodes: {}, edges: {}, ", size(), graph().sizeEdges());
159
160 if (dSize > 6) s << std::format("domainSize: 10^{}", dSize);
161 else s << std::format("domainSize: {}", std::round(std::pow(10.0, dSize)));
162
163 s << std::format(", dim: {}}}", param);
164
165 return s.str();
166 }
167
168 template < GUM_Numeric GUM_SCALAR >
170 std::stringstream output;
171
172 std::string mn_name = this->propertyWithDefault("name", "no_name");
173
174 output << std::format("graph \"{}\" {{\n", mn_name);
175 output << std::format(" graph [bgcolor=transparent,label=\"{}\"];\n", mn_name);
176 output << " node [style=filled fillcolor=\"#ffffaa\"];" << std::endl << std::endl;
177
178 for (auto node: nodes())
179 output << std::format(" \"{}\" [comment=\"{}:{}\"];\n",
180 variable(node).name(),
181 node,
182 variable(node).toStringWithDescription());
183
184 output << std::endl;
185
186 std::string tab = " ";
187
188 for (auto node: nodes()) {
189 if (neighbours(node).size() > 0) {
190 for (auto nei: neighbours(node)) {
191 if (variable(node).name() < variable(nei).name()) {
192 output << std::format(" \"{}\" -- \"{}\";\n",
193 variable(node).name(),
194 variable(nei).name());
195 }
196 }
197 } else {
198 output << std::format(" \"{}\";\n", variable(node).name());
199 }
200 }
201
202 output << "}" << std::endl;
203
204 return output.str();
205 }
206
207 template < GUM_Numeric GUM_SCALAR >
209 std::stringstream output;
210 std::string mn_name = this->propertyWithDefault("name", "no_name");
211
212 output << std::format("graph FG_{} {{\n", mn_name);
213 output << " layout=neato;" << std::endl;
214 output << std::format(" graph [bgcolor=transparent,label=\"factor graph for {}\"];\n",
215 mn_name);
216
217 // the variables
218 output << " node [shape=rectangle,margin=0.04,width=0,height=0, "
219 "style=filled,color=\"coral\"];"
220 << std::endl;
221 for (auto nod: nodes()) {
222 output << std::format("\"{}\";\n", variable(nod).name());
223 }
224 output << std::endl;
225
226 // the factor
227 output << "node[shape = point,width = 0.1,height = 0.1,style = filled,color = "
228 "\"burlywood\"];"
229 << std::endl;
230 for (const auto& kv: factors()) {
231 output << " \"f";
232 for (NodeId nod: kv.first) {
233 output << "#" << variable(nod).name();
234 }
235 output << "\";" << std::endl;
236 }
237
238 // the link variable--factors
239 output << " edge[len = 0.7];" << std::endl;
240 for (const auto& kv: factors()) {
241 std::string clicname = "\"f";
242 for (NodeId nod: kv.first) {
243 clicname += "#";
244 clicname += variable(nod).name();
245 }
246 clicname += "\"";
247
248 for (NodeId nod: kv.first)
249 output << std::format(" {} -- \"{}\";\n", clicname, variable(nod).name());
250 }
251 output << "}" << std::endl;
252
253 return output.str();
254 }
255
256 template < GUM_Numeric GUM_SCALAR >
258 if (size() != from.size()) { return false; }
259
260 if (sizeEdges() != from.sizeEdges()) { return false; }
261
262 // alignment of variables between the 2 BNs
264
265 for (auto node: nodes()) {
266 const auto& v1 = variable(node);
267 if (!from.exists(v1.name())) return false;
268 const auto& v2 = from.variableFromName(v1.name());
269 if (v1 != v2) return false;
270
271 alignment.insert(&variable(node), &from.variableFromName(v1.name()));
272 }
273
274 for (const auto& elt: factors()) {
275 const auto& key = elt.first;
276 const auto& factor = *elt.second;
277
278 NodeSet fromkey;
279 for (const auto n: key)
280 fromkey.insert(from.idFromName(variable(n).name()));
281
282 if (!from.factors().exists(fromkey)) { return false; }
283
284 const auto& fromfactor = from.factor(fromkey);
285
287 Instantiation j(fromfactor);
288 for (i.setFirst(); !i.end(); i.inc()) {
289 for (Idx indice = 0; indice < factor.nbrDim(); ++indice) {
290 const DiscreteVariable* p = &(i.variable(indice));
291 j.chgVal(*(alignment.second(p)), i.val(*p));
292 }
293
294 if (std::pow(factor.get(i) - fromfactor.get(j), (GUM_SCALAR)2) > (GUM_SCALAR)1e-6) {
295 return false;
296 }
297 }
298 }
299 return true;
300 }
301
302 template < GUM_Numeric GUM_SCALAR >
303 std::ostream& operator<<(std::ostream& output, const IMarkovRandomField< GUM_SCALAR >& bn) {
304 output << bn.toString();
305 return output;
306 }
307
308 template < GUM_Numeric GUM_SCALAR >
309 const NodeSet&
311 if (!this->exists(name)) {
312 GUM_ERROR(NotFound, "No factor containing the variable <" << name << ">")
313 }
315 }
316
317 // visit the nodes and add some of node from soids in minimal
318 template < GUM_Numeric GUM_SCALAR >
320 const NodeSet& soids,
321 NodeSet& minimal,
322 NodeSet& alreadyVisited) const {
323 if (alreadyVisited.contains(node)) return;
324 alreadyVisited << node;
325
326 if (soids.contains(node)) {
327 minimal << node;
328 } else {
329 for (auto neig: graph_.neighbours(node))
330 _minimalCondSetVisit_(neig, soids, minimal, alreadyVisited);
331 }
332 }
333
334 template < GUM_Numeric GUM_SCALAR >
336 const NodeSet& soids) const {
337 if (soids.contains(target)) return NodeSet({target});
338
339 NodeSet res;
340 NodeSet alreadyVisited;
341 alreadyVisited << target;
342
343 for (auto neig: graph_.neighbours(target))
344 _minimalCondSetVisit_(neig, soids, res, alreadyVisited);
345 return res;
346 }
347
348 template < GUM_Numeric GUM_SCALAR >
350 const NodeSet& soids) const {
351 NodeSet res;
352 for (auto node: targets) {
353 res += minimalCondSet(node, soids);
354 }
355 return res;
356 }
357} /* namespace gum */
Class representing Markov random fields.
const T2 & second(const T1 &first) const
Returns the second value of a pair given its first value.
void insert(const T1 &first, const T2 &second)
Inserts a new association in the gum::Bijection.
Set of pairs of elements with fast search for both elements.
Definition bijection.h:1640
NodeId idFromName(std::string_view name) const override
Returns the NodeId of a variable given its name.
const DiscreteVariable & variableFromName(std::string_view name) const override
Returns a constant reference over a variable given its name.
const DiscreteVariable & variable(NodeId id) const override
Returns a constant reference over a variable given its node id.
Base class for discrete random variable.
void setProperty(std::string_view name, std::string_view value)
Add or change a property of this GraphicalModel.
double log10DomainSize() const
const std::string & propertyWithDefault(std::string_view name, const std::string &byDefault) const
Return the value of the property name of this GraphicalModel.
Class representing the minimal interface for Markov random field.
virtual std::string toDot() const
IMarkovRandomField()
Default constructor.
virtual const Tensor< GUM_SCALAR > & factor(const NodeSet &varIds) const =0
Returns the factor of a set of variable.
~IMarkovRandomField() override
Destructor.
virtual const FactorTable< GUM_SCALAR > & factors() const =0
Returns the set of factors as a IMarkovRandomField::FactorTable.
virtual std::string toDotAsFactorGraph() const
void _minimalCondSetVisit_(NodeId node, const NodeSet &soids, NodeSet &minimal, NodeSet &alreadyVisited) const
Size dim() const
Returns the dimension (the number of free parameters) in this bayes net.
bool operator==(const IMarkovRandomField< GUM_SCALAR > &from) const
This operator compares 2 BNs !
NodeSet minimalCondSet(NodeId target, const NodeSet &soids) const
IMarkovRandomField< GUM_SCALAR > & operator=(const IMarkovRandomField< GUM_SCALAR > &source)
Copy operator.
virtual const NodeSet & smallestFactorFromNode(NodeId node) const =0
Returns the smallest factor that contains this variable.
Class for assigning/browsing values to tuples of discrete variables.
Instantiation & chgVal(const DiscreteVariable &v, Idx newval)
Assign newval to variable v in the Instantiation.
bool end() const
Returns true if the Instantiation reached the end.
void inc()
Operator increment.
Idx val(Idx i) const
Returns the current value of the variable at position i.
void setFirst()
Assign the first values to the tuple of the Instantiation.
const DiscreteVariable & variable(Idx i) const final
Returns the variable at position i in the tuple.
Exception : the element we looked for cannot be found.
bool contains(const Key &k) const
Indicates whether a given elements belong to the set.
Definition set_tpl.h:468
void insert(const Key &k)
Inserts a new element into the set.
Definition set_tpl.h:510
UGmodel()
Default constructor.
Definition UGmodel.cpp:49
const NodeGraphPart & nodes() const final
Returns a named copy of the internal undirected graph: each node id is assigned the name of the corre...
Definition UGmodel_inl.h:97
UGmodel & operator=(const UGmodel &source)
Private copy operator.
Definition UGmodel.cpp:62
bool exists(NodeId node) const final
Return true if this node exists in this graphical model.
Definition UGmodel_inl.h:89
UndiGraph graph_
The DAG of this Directed Graphical Model.
Definition UGmodel.h:195
UndiGraph graph() const
Returns a named copy of the internal undirected graph: each node id is assigned the name of the corre...
Definition UGmodel_inl.h:61
const NodeSet & neighbours(const NodeId id) const
returns the neighbours of a node as set of nodes
Definition UGmodel_inl.h:83
Size sizeEdges() const
Returns the number of arcs in this Directed Graphical Model.
Definition UGmodel_inl.h:71
Size size() const final
Returns the number of variables in this Directed Graphical Model.
Definition UGmodel_inl.h:68
#define GUM_ERROR(type, msg)
Definition exceptions.h:76
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition types.h:74
Size Idx
Type for indexes.
Definition types.h:79
Size NodeId
Type for node ids.
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
std::ostream & operator<<(std::ostream &stream, const AVLTree< Val, Cmp > &tree)
display the content of a tree
Header of the Tensor class.