aGrUM 2.3.2
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-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
48#include <iterator>
49
50namespace gum {
51
52
53 // Default Constructor
54 template < typename GUM_SCALAR >
56 const IMarkovRandomField< GUM_SCALAR >* mn) : MRFInference< GUM_SCALAR >(mn) {
57 // assign a MRF if this has not been done before (due to virtual inheritance)
59
60 // sets all the nodes as targets
61 if (mn != nullptr) {
62 _targeted_mode_ = false;
63 _targets_ = mn->graph().asNodeSet();
64 }
65
66 GUM_CONSTRUCTOR(MarginalTargetedMRFInference);
67 }
68
69 // Destructor
70 template < typename GUM_SCALAR >
74
75 // fired when a new MRF is assigned to the inference engine
76 template < typename GUM_SCALAR >
81
82 // ##############################################################################
83 // Targets
84 // ##############################################################################
85
86 // return true if variable is a target
87 template < typename GUM_SCALAR >
89 // check that the variable belongs to the mn
90 if (this->hasNoModel_())
92 "No Markov net has been assigned to the "
93 "inference algorithm");
94 if (!this->MRF().graph().exists(node)) {
95 GUM_ERROR(UndefinedElement, node << " is not a NodeId in the Markov random field")
96 }
97
98 return _targets_.contains(node);
99 }
100
101 // Add a single target to the list of targets
102 template < typename GUM_SCALAR >
103 INLINE bool
104 MarginalTargetedMRFInference< GUM_SCALAR >::isTarget(const std::string& nodeName) const {
105 return isTarget(this->MRF().idFromName(nodeName));
106 }
107
108 // Clear all previously defined targets (single targets and sets of targets)
109 template < typename GUM_SCALAR >
118
119 // Add a single target to the list of targets
120 template < typename GUM_SCALAR >
122 // check if the node belongs to the Markov random field
123 if (this->hasNoModel_())
125 "No Markov net has been assigned to the "
126 "inference algorithm");
127
128 if (!this->MRF().graph().exists(target)) {
129 GUM_ERROR(UndefinedElement, target << " is not a NodeId in the Markov random field")
130 }
131
132 setTargetedMode_(); // does nothing if already in targeted mode
133 // add the new target
134 if (!_targets_.contains(target)) {
135 _targets_.insert(target);
138 }
139 }
140
141 // Add all nodes as targets
142 template < typename GUM_SCALAR >
144 // check if the node belongs to the Markov random field
145 if (this->hasNoModel_())
147 "No Markov net has been assigned to the "
148 "inference algorithm");
149
150
151 setTargetedMode_(); // does nothing if already in targeted mode
152 for (const auto target: this->MRF().graph()) {
153 if (!_targets_.contains(target)) {
154 _targets_.insert(target);
157 }
158 }
159 }
160
161 // Add a single target to the list of targets
162 template < typename GUM_SCALAR >
164 // check if the node belongs to the Markov random field
165 if (this->hasNoModel_())
167 "No Markov net has been assigned to the "
168 "inference algorithm");
169
170 addTarget(this->MRF().idFromName(nodeName));
171 }
172
173 // removes an existing target
174 template < typename GUM_SCALAR >
176 // check if the node belongs to the Markov random field
177 if (this->hasNoModel_())
179 "No Markov net has been assigned to the "
180 "inference algorithm");
181
182 if (!this->MRF().graph().exists(target)) {
183 GUM_ERROR(UndefinedElement, target << " is not a NodeId in the Markov random field")
184 }
185
186
187 if (_targets_.contains(target)) {
188 _targeted_mode_ = true; // we do not use setTargetedMode_ because we do not
189 // want to clear the targets
191 _targets_.erase(target);
193 }
194 }
195
196 // Add a single target to the list of targets
197 template < typename GUM_SCALAR >
199 // check if the node belongs to the Markov random field
200 if (this->hasNoModel_())
202 "No Markov net has been assigned to the "
203 "inference algorithm");
204
205 eraseTarget(this->MRF().idFromName(nodeName));
206 }
207
208 // returns the list of single targets
209 template < typename GUM_SCALAR >
211 return _targets_;
212 }
213
214 // returns the list of single targets
215 template < typename GUM_SCALAR >
217 return _targets_.size();
218 }
219
221 template < typename GUM_SCALAR >
223 _targets_.clear();
224 if (!this->hasNoModel_()) {
225 _targets_ = this->MRF().graph().asNodeSet();
227 }
228 }
229
230 // ##############################################################################
231 // Inference
232 // ##############################################################################
233
234 // Compute the posterior of a node.
235 template < typename GUM_SCALAR >
237 if (this->hardEvidenceNodes().contains(node)) { return *(this->evidence()[node]); }
238
239 if (!isTarget(node)) {
240 // throws UndefinedElement if var is not a target
241 GUM_ERROR(UndefinedElement, node << " is not a target node")
242 }
243
244 if (!this->isInferenceDone()) { this->makeInference(); }
245
246 return posterior_(node);
247 }
248
249 // Compute the posterior of a node.
250 template < typename GUM_SCALAR >
251 const Tensor< GUM_SCALAR >&
253 return posterior(this->MRF().idFromName(nodeName));
254 }
255
256 /* Entropy
257 * Compute Shanon's entropy of a node given the observation
258 */
259 template < typename GUM_SCALAR >
261 return posterior(X).entropy();
262 }
263
264 /* Entropy
265 * Compute Shanon's entropy of a node given the observation
266 */
267 template < typename GUM_SCALAR >
268 INLINE GUM_SCALAR MarginalTargetedMRFInference< GUM_SCALAR >::H(const std::string& nodeName) {
269 return H(this->MRF().idFromName(nodeName));
270 }
271
272 template < typename GUM_SCALAR >
273 Tensor< GUM_SCALAR >
275 const NodeSet& evs) {
276 const auto& vtarget = this->MRF().variable(target);
277
278 if (evs.contains(target)) {
280 "Target <" << vtarget.name() << "> (" << target << ") can not be in evs (" << evs
281 << ").");
282 }
283 auto condset = this->MRF().minimalCondSet(target, evs);
284
285 Tensor< GUM_SCALAR > res;
286 this->eraseAllTargets();
287 this->eraseAllEvidence();
288 res.add(this->MRF().variable(target));
289 this->addTarget(target);
290 for (const auto& n: condset) {
291 res.add(this->MRF().variable(n));
292 this->addEvidence(n, 0);
293 }
294
295 Instantiation inst(res);
296 for (inst.setFirst(); !inst.end(); inst.incNotVar(vtarget)) {
297 // inferring
298 for (const auto& n: condset)
299 this->chgEvidence(n, inst.val(this->MRF().variable(n)));
300 this->makeInference();
301 // populate res
302 for (inst.setFirstVar(vtarget); !inst.end(); inst.incVar(vtarget)) {
303 res.set(inst, this->posterior(target)[inst]);
304 }
305 inst.setFirstVar(vtarget); // remove inst.end() flag
306 }
307
308 return res;
309 }
310
311 template < typename GUM_SCALAR >
313 const std::string& target,
314 const std::vector< std::string >& evs) {
315 const auto& mn = this->MRF();
316 return evidenceImpact(mn.idFromName(target), mn.nodeset(evs));
317 }
318
319 template < typename GUM_SCALAR >
323
324 template < typename GUM_SCALAR >
326 if (!_targeted_mode_) {
327 _targets_.clear();
328 _targeted_mode_ = true;
329 }
330 }
331} /* namespace gum */
virtual void setState_(const StateOfInference state) final
set the state of the inference engine and call the notification onStateChanged_ when necessary (i....
virtual void chgEvidence(NodeId id, const Idx val) final
change the value of an already existing hard evidence
virtual void addEvidence(NodeId id, const Idx val) final
adds a new hard evidence on node id
virtual void eraseAllEvidence() final
removes all the evidence entered into the network
const NodeSet & hardEvidenceNodes() const
returns the set of nodes with hard evidence
const NodeProperty< const Tensor< GUM_SCALAR > * > & evidence() const
returns the set of evidence
virtual void makeInference() final
perform the heavy computations needed to compute the targets' posteriors
virtual bool isInferenceDone() const noexcept final
returns whether the inference object is in a InferenceDone state
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 incNotVar(const DiscreteVariable &v)
Operator increment for vars which are not v.
void setFirstVar(const DiscreteVariable &v)
Assign the first value in the Instantiation for var 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.
virtual const IMarkovRandomField< GUM_SCALAR > & MRF() const final
Returns a constant reference over the IMarkovRandomField referenced by this class.
MRFInference(const IMarkovRandomField< GUM_SCALAR > *mn)
default constructor
void _setMRFDuringConstruction_(const IMarkovRandomField< GUM_SCALAR > *mn)
assigns a MRF during the inference engine construction
void _setAllMarginalTargets_()
sets all the nodes of the Markov net as targets
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
virtual bool isTarget(NodeId node) const final
return true if variable is a (marginal) target
bool _targeted_mode_
whether the actual targets are default
virtual void onAllMarginalTargetsErased_()=0
fired before a all marginal targets are removed
virtual const NodeSet & targets() const noexcept final
returns the list of marginal targets
NodeSet _targets_
the set of marginal targets
virtual void eraseTarget(NodeId target) final
removes an existing (marginal) target
Tensor< GUM_SCALAR > evidenceImpact(NodeId target, const NodeSet &evs)
Create a gum::Tensor for P(target|evs) (for all instanciation of target and evs).
virtual void addAllTargets() final
adds all nodes as targets
virtual void onModelChanged_(const GraphicalModel *mn)
fired after a new Markov net has been assigned to the engine
MarginalTargetedMRFInference(const IMarkovRandomField< GUM_SCALAR > *mn)
default constructor
virtual void addTarget(NodeId target) final
Add a marginal target to the list of targets.
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.
virtual GUM_SCALAR H(NodeId X) final
Entropy Compute Shanon's entropy of a node given the observation.
virtual void eraseAllTargets()
Clear all previously defined targets.
virtual Size nbrTargets() const noexcept final
returns the number of marginal targets
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:497
const UndiGraph & graph() const
Returns a constant reference to the dag of this Bayes Net.
Definition UGmodel_inl.h:57
Exception : a looked-for element could not be found.
#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 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