aGrUM 3.1.1
a C++ library for (probabilistic) graphical models
marginalTargetedMRFInference_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
49#include <iterator>
50
52
53namespace gum {
54
55
56 // Default Constructor
57 template < GUM_Numeric GUM_SCALAR >
59 const IMarkovRandomField< GUM_SCALAR >* mn) : MRFInference< GUM_SCALAR >(mn) {
60 // assign a MRF if this has not been done before (due to virtual inheritance)
62
63 // sets all the nodes as targets
64 if (mn != nullptr) {
65 _targeted_mode_ = false;
66 _targets_ = mn->graph().asNodeSet();
67 }
68
69 GUM_CONSTRUCTOR(MarginalTargetedMRFInference);
70 }
71
72 // Destructor
73 template < GUM_Numeric GUM_SCALAR >
77
78 // fired when a new MRF is assigned to the inference engine
79 template < GUM_Numeric GUM_SCALAR >
84
85 // ##############################################################################
86 // Targets
87 // ##############################################################################
88
89 // return true if variable is a target
90 template < GUM_Numeric GUM_SCALAR >
92 // check that the variable belongs to the mn
93 if (this->hasNoModel_())
95 "No Markov net has been assigned to the "
96 "inference algorithm");
97 if (!this->MRF().internalGraph().exists(node)) {
98 GUM_ERROR(UndefinedElement, node << " is not a NodeId in the Markov random field")
99 }
100
101 return _targets_.contains(node);
102 }
103
104 // Add a single target to the list of targets
105 template < GUM_Numeric GUM_SCALAR >
106 bool MarginalTargetedMRFInference< GUM_SCALAR >::isTarget(std::string_view nodeName) const {
107 return isTarget(this->MRF().idFromName(nodeName));
108 }
109
110 // Clear all previously defined targets (single targets and sets of targets)
111 template < GUM_Numeric GUM_SCALAR >
120
121 // Add a single target to the list of targets
122 template < GUM_Numeric GUM_SCALAR >
124 // check if the node belongs to the Markov random field
125 if (this->hasNoModel_())
127 "No Markov net has been assigned to the "
128 "inference algorithm");
129
130 if (!this->MRF().internalGraph().exists(target)) {
131 GUM_ERROR(UndefinedElement, target << " is not a NodeId in the Markov random field")
132 }
133
134 setTargetedMode_(); // does nothing if already in targeted mode
135 // add the new target
136 if (!_targets_.contains(target)) {
137 _targets_.insert(target);
140 }
141 }
142
143 // Add all nodes as targets
144 template < GUM_Numeric GUM_SCALAR >
146 // check if the node belongs to the Markov random field
147 if (this->hasNoModel_())
149 "No Markov net has been assigned to the "
150 "inference algorithm");
151
152
153 setTargetedMode_(); // does nothing if already in targeted mode
154 for (const auto target: this->MRF().internalGraph()) {
155 if (!_targets_.contains(target)) {
156 _targets_.insert(target);
159 }
160 }
161 }
162
163 // Add a single target to the list of targets
164 template < GUM_Numeric GUM_SCALAR >
166 // check if the node belongs to the Markov random field
167 if (this->hasNoModel_())
169 "No Markov net has been assigned to the "
170 "inference algorithm");
171
172 addTarget(this->MRF().idFromName(nodeName));
173 }
174
175 // removes an existing target
176 template < GUM_Numeric GUM_SCALAR >
178 // check if the node belongs to the Markov random field
179 if (this->hasNoModel_())
181 "No Markov net has been assigned to the "
182 "inference algorithm");
183
184 if (!this->MRF().internalGraph().exists(target)) {
185 GUM_ERROR(UndefinedElement, target << " is not a NodeId in the Markov random field")
186 }
187
188
189 if (_targets_.contains(target)) {
190 _targeted_mode_ = true; // we do not use setTargetedMode_ because we do not
191 // want to clear the targets
193 _targets_.erase(target);
195 }
196 }
197
198 // Add a single target to the list of targets
199 template < GUM_Numeric GUM_SCALAR >
201 // check if the node belongs to the Markov random field
202 if (this->hasNoModel_())
204 "No Markov net has been assigned to the "
205 "inference algorithm");
206
207 eraseTarget(this->MRF().idFromName(nodeName));
208 }
209
210 // returns the list of single targets
211 template < GUM_Numeric GUM_SCALAR >
213 return _targets_;
214 }
215
216 // returns the list of single targets
217 template < GUM_Numeric GUM_SCALAR >
219 return _targets_.size();
220 }
221
223 template < GUM_Numeric GUM_SCALAR >
225 _targets_.clear();
226 if (!this->hasNoModel_()) {
227 _targets_ = this->MRF().internalGraph().asNodeSet();
229 }
230 }
231
232 // ##############################################################################
233 // Inference
234 // ##############################################################################
235
236 // Compute the posterior of a node.
237 template < GUM_Numeric GUM_SCALAR >
239 if (this->hardEvidenceNodes().contains(node)) { return *(this->evidence()[node]); }
240
241 if (!isTarget(node)) {
242 // throws UndefinedElement if var is not a target
243 GUM_ERROR(UndefinedElement, node << " is not a target node")
244 }
245
246 if (!this->isInferenceDone()) { this->makeInference(); }
247
248 return posterior_(node);
249 }
250
251 // Compute the posterior of a node.
252 template < GUM_Numeric GUM_SCALAR >
253 const Tensor< GUM_SCALAR >&
255 return posterior(this->MRF().idFromName(nodeName));
256 }
257
258 /* Entropy
259 * Compute Shanon's entropy of a node given the observation
260 */
261 template < GUM_Numeric GUM_SCALAR >
263 return posterior(X).entropy();
264 }
265
266 /* Entropy
267 * Compute Shanon's entropy of a node given the observation
268 */
269 template < GUM_Numeric GUM_SCALAR >
270 GUM_SCALAR MarginalTargetedMRFInference< GUM_SCALAR >::H(std::string_view nodeName) {
271 return H(this->MRF().idFromName(nodeName));
272 }
273
274 template < GUM_Numeric GUM_SCALAR >
275 Tensor< GUM_SCALAR >
277 const NodeSet& evs) {
278 const auto& vtarget = this->MRF().variable(target);
279
280 if (evs.contains(target)) {
282 "Target <" << vtarget.name() << "> (" << target << ") can not be in evs (" << evs
283 << ").");
284 }
285 auto condset = this->MRF().minimalCondSet(target, evs);
286
287 Tensor< GUM_SCALAR > res;
288 this->eraseAllTargets();
289 this->eraseAllEvidence();
290 res.add(this->MRF().variable(target));
291 this->addTarget(target);
292 for (const auto& n: condset) {
293 res.add(this->MRF().variable(n));
294 this->addEvidence(n, 0);
295 }
296
297 Instantiation inst(res);
298 for (inst.setFirst(); !inst.end(); inst.incNotVar(vtarget)) {
299 // inferring
300 for (const auto& n: condset)
301 this->chgEvidence(n, inst.val(this->MRF().variable(n)));
302 this->makeInference();
303 // populate res
304 for (inst.setFirstVar(vtarget); !inst.end(); inst.incVar(vtarget)) {
305 res.set(inst, this->posterior(target)[inst]);
306 }
307 inst.setFirstVar(vtarget); // remove inst.end() flag
308 }
309
310 return res;
311 }
312
313 template < GUM_Numeric GUM_SCALAR >
315 std::string_view target,
316 const std::vector< std::string >& evs) {
317 const auto& mn = this->MRF();
318 return evidenceImpact(mn.idFromName(target), mn.nodeset(evs));
319 }
320
321 template < GUM_Numeric GUM_SCALAR >
325
326 template < GUM_Numeric GUM_SCALAR >
333} /* namespace gum */
virtual void chgEvidence(NodeId id, const Idx val) final
change the value of an already existing hard evidence
virtual bool isInferenceDone() const noexcept final
returns whether the inference object is in a InferenceDone state
const NodeProperty< const Tensor< GUM_SCALAR > * > & evidence() const
returns the set of evidence
virtual void setState_(const StateOfInference state) final
set the state of the inference engine and call the notification onStateChanged_ when necessary (i....
const NodeSet & hardEvidenceNodes() const
returns the set of nodes with hard evidence
virtual void eraseAllEvidence() final
removes all the evidence entered into the network
virtual void makeInference() final
perform the heavy computations needed to compute the targets' posteriors
virtual void addEvidence(NodeId id, const Idx val) final
adds a new hard evidence on node id
Virtual base class for probabilistic graphical models.
Class representing the minimal interface for Markov random field.
Class for assigning/browsing values to tuples of discrete variables.
bool end() const
Returns true if the Instantiation reached the end.
void incVar(const DiscreteVariable &v)
Operator increment for variable v only.
void setFirstVar(const DiscreteVariable &v)
Assign the first value in the Instantiation for var v.
void incNotVar(const DiscreteVariable &v)
Operator increment for vars which are not v.
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.
Exception: at least one argument passed to a function is not what was expected.
MRFInference(const IMarkovRandomField< GUM_SCALAR > *mn)
default constructor
void _setMRFDuringConstruction_(const IMarkovRandomField< GUM_SCALAR > *mn)
assigns a MRF during the inference engine construction
virtual const IMarkovRandomField< GUM_SCALAR > & MRF() const final
Returns a constant reference over the IMarkovRandomField referenced by this class.
virtual const NodeSet & targets() const noexcept final
returns the list of marginal targets
void _setAllMarginalTargets_()
sets all the nodes of the Markov net as targets
virtual Size nbrTargets() const noexcept final
returns the number of marginal targets
void onModelChanged_(const GraphicalModel *mn) override
fired after a new Markov net has been assigned to the engine
virtual void onAllMarginalTargetsAdded_()=0
fired after all the nodes of the MRF are added as marginal targets
virtual void onMarginalTargetErased_(const NodeId id)=0
fired before a marginal target is removed
bool _targeted_mode_
whether the actual targets are default
virtual void onAllMarginalTargetsErased_()=0
fired before a all marginal targets are removed
NodeSet _targets_
the set of marginal targets
virtual GUM_SCALAR H(NodeId X) final
Entropy Compute Shanon's entropy of a node given the observation.
virtual void eraseTarget(NodeId target) final
removes an existing (marginal) target
virtual void eraseAllTargets()
Clear all previously defined targets.
Tensor< GUM_SCALAR > evidenceImpact(NodeId target, const NodeSet &evs)
Create a gum::Tensor for P(target|evs) (for all instantiation of target and evs).
virtual void addAllTargets() final
adds all nodes as targets
MarginalTargetedMRFInference(const IMarkovRandomField< GUM_SCALAR > *mn)
default constructor
virtual void addTarget(NodeId target) final
Add a marginal target to the list of targets.
virtual bool isTarget(NodeId node) const final
return true if variable is a (marginal) target
virtual void onMarginalTargetAdded_(const NodeId id)=0
fired after a new marginal target is inserted
virtual const Tensor< GUM_SCALAR > & posterior_(NodeId id)=0
asks derived classes for the posterior of a given variable
virtual const Tensor< GUM_SCALAR > & posterior(NodeId node)
Computes and returns the posterior of a node.
NodeSet asNodeSet() const
returns a copy of the set of nodes represented by the NodeGraphPart
Exception : a pointer or a reference on a nullptr (0) object.
bool contains(const Key &k) const
Indicates whether a given elements belong to the set.
Definition set_tpl.h:468
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
Exception : a looked-for element could not be found.
#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 NodeId
Type for node ids.
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...
bool contains(std::string_view s, std::string_view needle)
true if needle in s
This file contains the abstract inference class definition for computing (incrementally) marginal pos...
gum is the global namespace for all aGrUM entities
Definition agrum.h:46