aGrUM 2.3.2
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-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#pragma once
41
42
49
50#include <limits>
51
54
55#define EF get
56
57namespace gum {
58
59 // IMarkovRandomField
60
61 template < typename GUM_SCALAR >
65
66 template < typename GUM_SCALAR >
68 GUM_CONSTRUCTOR(IMarkovRandomField);
69 this->setProperty("name", name);
70 }
71
72 template < typename GUM_SCALAR >
77
78 template < typename GUM_SCALAR >
81 if (this != &source) { UGmodel::operator=(source); }
82
83 return *this;
84 }
85
86 template < typename GUM_SCALAR >
90
91 template < typename GUM_SCALAR >
93 Size res = 0;
94 for (auto f: factors()) {
95 res += f.second->domainSize();
96 }
97 return res;
98 }
99
100 template < typename GUM_SCALAR >
102 Size res = 0;
103 for (auto node: nodes()) {
104 auto v = variable(node).domainSize();
105 if (v > res) { res = v; }
106 }
107 return res;
108 }
109
110 template < typename GUM_SCALAR >
112 GUM_SCALAR res = 1.0;
113 for (auto elt: factors()) {
114 auto v = elt.second->min();
115 if (v < res) { res = v; }
116 }
117 return res;
118 }
119
120 template < typename GUM_SCALAR >
122 GUM_SCALAR res = 1.0;
123 for (auto elt: factors()) {
124 auto v = elt.second->max();
125 if (v > res) { res = v; }
126 }
127 return res;
128 }
129
130 template < typename GUM_SCALAR >
132 GUM_SCALAR res = 1.0;
133 for (auto elt: factors()) {
134 auto v = elt.second->minNonZero();
135 if (v < res) { res = v; }
136 }
137 return res;
138 }
139
140 template < typename GUM_SCALAR >
142 GUM_SCALAR res = 0.0;
143 for (auto elt: factors()) {
144 auto v = elt.second->maxNonOne();
145 if (v > res) { res = v; }
146 }
147 return res;
148 }
149
150 template < typename GUM_SCALAR >
152 Size param = 0;
153 double dSize = log10DomainSize();
154
155 for (auto factor: factors())
156 param += factor.second->content()->realSize();
157
158 std::stringstream s;
159 s << "MRF{nodes: " << size() << ", edges: " << graph().sizeEdges() << ", ";
160
161 if (dSize > 6) s << "domainSize: 10^" << dSize;
162 else s << "domainSize: " << std::round(std::pow(10.0, dSize));
163
164 s << ", dim: " << param << "}";
165
166 return s.str();
167 }
168
169 template < typename GUM_SCALAR >
171 std::stringstream output;
172 output << "graph \"";
173
174 std::string mn_name;
175
176 try {
177 mn_name = this->property("name");
178 } catch (NotFound const&) { mn_name = "no_name"; }
179
180 output << mn_name << "\" {" << std::endl;
181 output << " graph [bgcolor=transparent,label=\"" << mn_name << "\"];" << std::endl;
182 output << " node [style=filled fillcolor=\"#ffffaa\"];" << std::endl << std::endl;
183
184 for (auto node: nodes())
185 output << " \"" << variable(node).name() << "\" [comment=\"" << node << ":"
186 << variable(node).toStringWithDescription() << "\"];" << std::endl;
187
188 output << std::endl;
189
190 std::string tab = " ";
191
192 for (auto node: nodes()) {
193 if (neighbours(node).size() > 0) {
194 for (auto nei: neighbours(node)) {
195 if (variable(node).name() < variable(nei).name()) {
196 output << tab << "\"" << variable(node).name() << "\" -- "
197 << "\"" << variable(nei).name() << "\";" << std::endl;
198 }
199 }
200 } else {
201 output << tab << "\"" << variable(node).name() << "\";" << std::endl;
202 }
203 }
204
205 output << "}" << std::endl;
206
207 return output.str();
208 }
209
210 template < typename GUM_SCALAR >
212 std::stringstream output;
213 std::string mn_name;
214 try {
215 mn_name = this->property("name");
216 } catch (NotFound const&) { mn_name = "no_name"; }
217
218 output << "graph FG_" << mn_name << " {" << std::endl;
219 output << " layout=neato;" << std::endl;
220 output << " graph [bgcolor=transparent,label=\"factor graph for " << mn_name << "\"];"
221 << std::endl;
222
223 // the variables
224 output << " node [shape=rectangle,margin=0.04,width=0,height=0, "
225 "style=filled,color=\"coral\"];"
226 << std::endl;
227 for (auto nod: nodes()) {
228 output << "\"" << variable(nod).name() << "\";" << std::endl;
229 }
230 output << std::endl;
231
232 // the factor
233 output << "node[shape = point,width = 0.1,height = 0.1,style = filled,color = "
234 "\"burlywood\"];"
235 << std::endl;
236 for (const auto& kv: factors()) {
237 output << " \"f";
238 for (NodeId nod: kv.first) {
239 output << "#" << variable(nod).name();
240 }
241 output << "\";" << std::endl;
242 }
243
244 // the link variable--factors
245 output << " edge[len = 0.7];" << std::endl;
246 for (const auto& kv: factors()) {
247 std::string clicname = "\"f";
248 for (NodeId nod: kv.first) {
249 clicname += "#";
250 clicname += variable(nod).name();
251 }
252 clicname += "\"";
253
254 for (NodeId nod: kv.first)
255 output << " " << clicname << " -- \"" << variable(nod).name() << "\";" << std::endl;
256 }
257 output << "}" << std::endl;
258
259 return output.str();
260 }
261
262 template < typename GUM_SCALAR >
264 if (size() != from.size()) { return false; }
265
266 if (sizeEdges() != from.sizeEdges()) { return false; }
267
268 // alignment of variables between the 2 BNs
270
271 for (auto node: nodes()) {
272 try {
273 const auto& v1 = variable(node);
274 const auto& v2 = from.variableFromName(variable(node).name());
275 if (v1 != v2) return false;
276
277 alignment.insert(&variable(node), &from.variableFromName(variable(node).name()));
278 } catch (NotFound const&) {
279 // a name is not found in from
280 return false;
281 }
282 }
283
284 for (const auto& elt: factors()) {
285 const auto& key = elt.first;
286 const auto& factor = *elt.second;
287
288 NodeSet fromkey;
289 for (const auto n: key)
290 fromkey.insert(from.idFromName(variable(n).name()));
291
292 if (!from.factors().exists(fromkey)) { return false; }
293
294 const auto& fromfactor = from.factor(fromkey);
295
297 Instantiation j(fromfactor);
298 for (i.setFirst(); !i.end(); i.inc()) {
299 for (Idx indice = 0; indice < factor.nbrDim(); ++indice) {
300 const DiscreteVariable* p = &(i.variable(indice));
301 j.chgVal(*(alignment.second(p)), i.val(*p));
302 }
303
304 if (std::pow(factor.get(i) - fromfactor.get(j), (GUM_SCALAR)2) > (GUM_SCALAR)1e-6) {
305 return false;
306 }
307 }
308 }
309 return true;
310 }
311
312 template < typename GUM_SCALAR >
314 return !this->operator==(from);
315 }
316
317 template < typename GUM_SCALAR >
318 INLINE std::ostream& operator<<(std::ostream& output,
320 output << bn.toString();
321 return output;
322 }
323
324 template < typename GUM_SCALAR >
325 INLINE const NodeSet&
327 try {
329 } catch (NotFound const&) {
330 GUM_ERROR(NotFound, "No factor containing the variable <" << name << ">")
331 }
332 }
333
334 // visit the nodes and add some of node from soids in minimal
335 template < typename GUM_SCALAR >
337 const NodeSet& soids,
338 NodeSet& minimal,
339 NodeSet& alreadyVisited) const {
340 if (alreadyVisited.contains(node)) return;
341 alreadyVisited << node;
342
343 if (soids.contains(node)) {
344 minimal << node;
345 } else {
346 for (auto neig: graph_.neighbours(node))
347 _minimalCondSetVisit_(neig, soids, minimal, alreadyVisited);
348 }
349 }
350
351 template < typename GUM_SCALAR >
353 const NodeSet& soids) const {
354 if (soids.contains(target)) return NodeSet({target});
355
356 NodeSet res;
357 NodeSet alreadyVisited;
358 alreadyVisited << target;
359
360 for (auto neig: graph_.neighbours(target))
361 _minimalCondSetVisit_(neig, soids, res, alreadyVisited);
362 return res;
363 }
364
365 template < typename GUM_SCALAR >
367 const NodeSet& soids) const {
368 NodeSet res;
369 for (auto node: targets) {
370 res += minimalCondSet(node, soids);
371 }
372 return res;
373 }
374} /* namespace gum */
Class representing Markov random fields.
void insert(const T1 &first, const T2 &second)
Inserts a new association in the gum::Bijection.
const T2 & second(const T1 &first) const
Returns the second value of a pair given its first value.
Set of pairs of elements with fast search for both elements.
Definition bijection.h:1594
Base class for discrete random variable.
void setProperty(const std::string &name, const std::string &value)
Add or change a property of this GraphicalModel.
const std::string & property(const std::string &name) const
Return the value of the property name of this GraphicalModel.
double log10DomainSize() const
Class representing the minimal interface for Markov random field.
IMarkovRandomField()
Default constructor.
virtual std::string toDot() const
virtual const DiscreteVariable & variableFromName(const std::string &name) const =0
Getter by name.
virtual const Tensor< GUM_SCALAR > & factor(const NodeSet &varIds) const =0
Returns the factor of a set of variable.
bool operator!=(const IMarkovRandomField< GUM_SCALAR > &from) const
virtual const DiscreteVariable & variable(NodeId id) const =0
Returns a constant reference over a variable given it's node id.
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
bool operator==(const IMarkovRandomField< GUM_SCALAR > &from) const
This operator compares 2 BNs !
virtual ~IMarkovRandomField()
Destructor.
NodeSet minimalCondSet(NodeId target, const NodeSet &soids) const
IMarkovRandomField< GUM_SCALAR > & operator=(const IMarkovRandomField< GUM_SCALAR > &source)
Copy operator.
virtual NodeId idFromName(const std::string &name) const =0
Getter by name.
Size dim() const
Returns the dimension (the number of free parameters) in this bayes net.
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:497
void insert(const Key &k)
Inserts a new element into the set.
Definition set_tpl.h:539
UGmodel()
Default constructor.
Definition UGmodel.cpp:49
const NodeGraphPart & nodes() const final
Returns a constant reference to the dag of this Bayes Net.
Definition UGmodel_inl.h:89
UGmodel & operator=(const UGmodel &source)
Private copy operator.
Definition UGmodel.cpp:61
UndiGraph graph_
The DAG of this Directed Graphical Model.
Definition UGmodel.h:182
const UndiGraph & graph() const
Returns a constant reference to the dag of this Bayes Net.
Definition UGmodel_inl.h:57
const NodeSet & neighbours(const NodeId id) const
returns the neighbours of a node as set of nodes
Definition UGmodel_inl.h:75
Size sizeEdges() const
Returns the number of arcs in this Directed Graphical Model.
Definition UGmodel_inl.h:63
virtual Size size() const final
Returns the number of variables in this Directed Graphical Model.
Definition UGmodel_inl.h:60
#define GUM_ERROR(type, msg)
Definition exceptions.h:72
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
Definition AVLTree.h:913
bool operator==(const HashTableIteratorSafe< Key, Val > &from) const noexcept
Checks whether two iterators are pointing toward equal elements.
Header of the Tensor class.