aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
marginalTargetedMNInference_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4  * info_at_agrum_dot_org
5  *
6  * This library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /**
23  * @file
24  * @brief Implementation of the generic class for the computation of
25  * (possibly incrementally) marginal posteriors
26  */
27 #include <iterator>
28 
29 namespace gum {
30 
31 
32  // Default Constructor
33  template < typename GUM_SCALAR >
34  MarginalTargetedMNInference< GUM_SCALAR >::MarginalTargetedMNInference(
35  const IMarkovNet< GUM_SCALAR >* mn) :
36  MarkovNetInference< GUM_SCALAR >(mn) {
37  // assign a MN if this has not been done before (due to virtual inheritance)
38  if (this->hasNoModel_()) {
39  MarkovNetInference< GUM_SCALAR >::_setMarkovNetDuringConstruction_(mn);
40  }
41 
42  // sets all the nodes as targets
43  if (mn != nullptr) {
44  _targeted_mode_ = false;
45  _targets_ = mn->graph().asNodeSet();
46  }
47 
48  GUM_CONSTRUCTOR(MarginalTargetedMNInference);
49  }
50 
51 
52  // Destructor
53  template < typename GUM_SCALAR >
54  MarginalTargetedMNInference< GUM_SCALAR >::~MarginalTargetedMNInference() {
55  GUM_DESTRUCTOR(MarginalTargetedMNInference);
56  }
57 
58 
59  // fired when a new MN is assigned to the inference engine
60  template < typename GUM_SCALAR >
61  void MarginalTargetedMNInference< GUM_SCALAR >::onModelChanged_(const GraphicalModel* mn) {
62  _targeted_mode_ = true;
63  _setAllMarginalTargets_();
64  }
65 
66 
67  // ##############################################################################
68  // Targets
69  // ##############################################################################
70 
71  // return true if variable is a target
72  template < typename GUM_SCALAR >
73  INLINE bool MarginalTargetedMNInference< GUM_SCALAR >::isTarget(NodeId node) const {
74  // check that the variable belongs to the mn
75  if (this->hasNoModel_())
76  GUM_ERROR(NullElement,
77  "No Markov net has been assigned to the "
78  "inference algorithm");
79  if (!this->MN().graph().exists(node)) {
80  GUM_ERROR(UndefinedElement, node << " is not a NodeId in the Markov network")
81  }
82 
83  return _targets_.contains(node);
84  }
85 
86  // Add a single target to the list of targets
87  template < typename GUM_SCALAR >
88  INLINE bool
89  MarginalTargetedMNInference< GUM_SCALAR >::isTarget(const std::string& nodeName) const {
90  return isTarget(this->MN().idFromName(nodeName));
91  }
92 
93 
94  // Clear all previously defined targets (single targets and sets of targets)
95  template < typename GUM_SCALAR >
96  INLINE void MarginalTargetedMNInference< GUM_SCALAR >::eraseAllTargets() {
97  onAllMarginalTargetsErased_();
98 
99  _targets_.clear();
100  setTargetedMode_(); // does nothing if already in targeted mode
101 
102  this->setState_(MarkovNetInference< GUM_SCALAR >::StateOfInference::OutdatedStructure);
103  }
104 
105 
106  // Add a single target to the list of targets
107  template < typename GUM_SCALAR >
108  void MarginalTargetedMNInference< GUM_SCALAR >::addTarget(NodeId target) {
109  // check if the node belongs to the Markov network
110  if (this->hasNoModel_())
111  GUM_ERROR(NullElement,
112  "No Markov net has been assigned to the "
113  "inference algorithm");
114 
115  if (!this->MN().graph().exists(target)) {
116  GUM_ERROR(UndefinedElement, target << " is not a NodeId in the Markov network")
117  }
118 
119  setTargetedMode_(); // does nothing if already in targeted mode
120  // add the new target
121  if (!_targets_.contains(target)) {
122  _targets_.insert(target);
123  onMarginalTargetAdded_(target);
124  this->setState_(MarkovNetInference< GUM_SCALAR >::StateOfInference::OutdatedStructure);
125  }
126  }
127 
128 
129  // Add all nodes as targets
130  template < typename GUM_SCALAR >
131  void MarginalTargetedMNInference< GUM_SCALAR >::addAllTargets() {
132  // check if the node belongs to the Markov network
133  if (this->hasNoModel_())
134  GUM_ERROR(NullElement,
135  "No Markov net has been assigned to the "
136  "inference algorithm");
137 
138 
139  setTargetedMode_(); // does nothing if already in targeted mode
140  for (const auto target: this->MN().graph()) {
141  if (!_targets_.contains(target)) {
142  _targets_.insert(target);
143  onMarginalTargetAdded_(target);
144  this->setState_(MarkovNetInference< GUM_SCALAR >::StateOfInference::OutdatedStructure);
145  }
146  }
147  }
148 
149 
150  // Add a single target to the list of targets
151  template < typename GUM_SCALAR >
152  void MarginalTargetedMNInference< GUM_SCALAR >::addTarget(const std::string& nodeName) {
153  // check if the node belongs to the Markov network
154  if (this->hasNoModel_())
155  GUM_ERROR(NullElement,
156  "No Markov net has been assigned to the "
157  "inference algorithm");
158 
159  addTarget(this->MN().idFromName(nodeName));
160  }
161 
162 
163  // removes an existing target
164  template < typename GUM_SCALAR >
165  void MarginalTargetedMNInference< GUM_SCALAR >::eraseTarget(NodeId target) {
166  // check if the node belongs to the Markov network
167  if (this->hasNoModel_())
168  GUM_ERROR(NullElement,
169  "No Markov net has been assigned to the "
170  "inference algorithm");
171 
172  if (!this->MN().graph().exists(target)) {
173  GUM_ERROR(UndefinedElement, target << " is not a NodeId in the Markov network")
174  }
175 
176 
177  if (_targets_.contains(target)) {
178  _targeted_mode_ = true; // we do not use setTargetedMode_ because we do not
179  // want to clear the targets
180  onMarginalTargetErased_(target);
181  _targets_.erase(target);
182  this->setState_(MarkovNetInference< GUM_SCALAR >::StateOfInference::OutdatedStructure);
183  }
184  }
185 
186 
187  // Add a single target to the list of targets
188  template < typename GUM_SCALAR >
189  void MarginalTargetedMNInference< GUM_SCALAR >::eraseTarget(const std::string& nodeName) {
190  // check if the node belongs to the Markov network
191  if (this->hasNoModel_())
192  GUM_ERROR(NullElement,
193  "No Markov net has been assigned to the "
194  "inference algorithm");
195 
196  eraseTarget(this->MN().idFromName(nodeName));
197  }
198 
199 
200  // returns the list of single targets
201  template < typename GUM_SCALAR >
202  INLINE const NodeSet& MarginalTargetedMNInference< GUM_SCALAR >::targets() const noexcept {
203  return _targets_;
204  }
205 
206  // returns the list of single targets
207  template < typename GUM_SCALAR >
208  INLINE const Size MarginalTargetedMNInference< GUM_SCALAR >::nbrTargets() const noexcept {
209  return _targets_.size();
210  }
211 
212 
213  /// sets all the nodes of the Markov net as targets
214  template < typename GUM_SCALAR >
215  void MarginalTargetedMNInference< GUM_SCALAR >::_setAllMarginalTargets_() {
216  _targets_.clear();
217  if (!this->hasNoModel_()) {
218  _targets_ = this->MN().graph().asNodeSet();
219  onAllMarginalTargetsAdded_();
220  }
221  }
222 
223 
224  // ##############################################################################
225  // Inference
226  // ##############################################################################
227 
228  // Compute the posterior of a node.
229  template < typename GUM_SCALAR >
230  const Potential< GUM_SCALAR >& MarginalTargetedMNInference< GUM_SCALAR >::posterior(NodeId node) {
231  if (this->hardEvidenceNodes().contains(node)) { return *(this->evidence()[node]); }
232 
233  if (!isTarget(node)) {
234  // throws UndefinedElement if var is not a target
235  GUM_ERROR(UndefinedElement, node << " is not a target node")
236  }
237 
238  if (!this->isInferenceDone()) { this->makeInference(); }
239 
240  return posterior_(node);
241  }
242 
243  // Compute the posterior of a node.
244  template < typename GUM_SCALAR >
245  const Potential< GUM_SCALAR >&
246  MarginalTargetedMNInference< GUM_SCALAR >::posterior(const std::string& nodeName) {
247  return posterior(this->MN().idFromName(nodeName));
248  }
249 
250  /* Entropy
251  * Compute Shanon's entropy of a node given the observation
252  */
253  template < typename GUM_SCALAR >
254  INLINE GUM_SCALAR MarginalTargetedMNInference< GUM_SCALAR >::H(NodeId X) {
255  return posterior(X).entropy();
256  }
257 
258  /* Entropy
259  * Compute Shanon's entropy of a node given the observation
260  */
261  template < typename GUM_SCALAR >
262  INLINE GUM_SCALAR MarginalTargetedMNInference< GUM_SCALAR >::H(const std::string& nodeName) {
263  return H(this->MN().idFromName(nodeName));
264  }
265 
266 
267  template < typename GUM_SCALAR >
268  Potential< GUM_SCALAR >
269  MarginalTargetedMNInference< GUM_SCALAR >::evidenceImpact(NodeId target, const NodeSet& evs) {
270  const auto& vtarget = this->MN().variable(target);
271 
272  if (evs.contains(target)) {
273  GUM_ERROR(InvalidArgument,
274  "Target <" << vtarget.name() << "> (" << target << ") can not be in evs (" << evs
275  << ").");
276  }
277  auto condset = this->MN().minimalCondSet(target, evs);
278 
279  Potential< GUM_SCALAR > res;
280  this->eraseAllTargets();
281  this->eraseAllEvidence();
282  res.add(this->MN().variable(target));
283  this->addTarget(target);
284  for (const auto& n: condset) {
285  res.add(this->MN().variable(n));
286  this->addEvidence(n, 0);
287  }
288 
289  Instantiation inst(res);
290  for (inst.setFirst(); !inst.end(); inst.incNotVar(vtarget)) {
291  // inferring
292  for (const auto& n: condset)
293  this->chgEvidence(n, inst.val(this->MN().variable(n)));
294  this->makeInference();
295  // populate res
296  for (inst.setFirstVar(vtarget); !inst.end(); inst.incVar(vtarget)) {
297  res.set(inst, this->posterior(target)[inst]);
298  }
299  inst.setFirstVar(vtarget); // remove inst.end() flag
300  }
301 
302  return res;
303  }
304 
305 
306  template < typename GUM_SCALAR >
307  Potential< GUM_SCALAR > MarginalTargetedMNInference< GUM_SCALAR >::evidenceImpact(
308  const std::string& target,
309  const std::vector< std::string >& evs) {
310  const auto& mn = this->MN();
311  return evidenceImpact(mn.idFromName(target), mn.nodeset(evs));
312  }
313 
314 
315  template < typename GUM_SCALAR >
316  INLINE bool MarginalTargetedMNInference< GUM_SCALAR >::isTargetedMode_() const {
317  return _targeted_mode_;
318  }
319  template < typename GUM_SCALAR >
320  INLINE void MarginalTargetedMNInference< GUM_SCALAR >::setTargetedMode_() {
321  if (!_targeted_mode_) {
322  _targets_.clear();
323  _targeted_mode_ = true;
324  }
325  }
326 } /* namespace gum */