1 /**
2  *
3  *   Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(_at_LIP6) & Christophe GONZALES(_at_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 This file contains abstract class definitions influence diagrams
25  *        inference classes.
26  *
27  * @author Pierre-Henri WUILLEMIN(_at_LIP6) and Christophe Gonzalez(@
28  */
29 #ifndef AGRUM_DECISIONPOTENTIAL_H
30 #define AGRUM_DECISIONPOTENTIAL_H
31 
32 #include <agrum/tools/core/set.h>
33 #include <agrum/tools/variables/discreteVariable.h>
34 #include <agrum/tools/multidim/instantiation.h>
35 #include <agrum/tools/multidim/potential.h>
36 
37 namespace gum {
38   /**
39    * @class DecisionPotential decisionPotential.h
40    *<agrum/ID/inference/decisionPotential.h>
41    * @brief Potential for optimization in LIMIDS (such as Single Policy Update)
42    */
43   template < typename GUM_SCALAR >
44   class DecisionPotential {
45     public:
46     Potential< GUM_SCALAR > probPot;
47     Potential< GUM_SCALAR > utilPot;
48 
DecisionPotential()49     explicit DecisionPotential() {
50       GUM_CONSTRUCTOR(DecisionPotential);
51       probPot.fillWith(GUM_SCALAR(1));
52       utilPot.fillWith(GUM_SCALAR(0));
53     }
54 
~DecisionPotential()55     ~DecisionPotential() {
56       GUM_DESTRUCTOR(DecisionPotential);
57       ;
58     }
59 
DecisionPotential(const Potential<GUM_SCALAR> & prob,const Potential<GUM_SCALAR> & util)60     DecisionPotential(const Potential< GUM_SCALAR >& prob, const Potential< GUM_SCALAR >& util) :
61         probPot(prob), utilPot(util) {
62       GUM_CONSTRUCTOR(DecisionPotential);
63     }
64 
DecisionPotential(const DecisionPotential<GUM_SCALAR> & dp)65     DecisionPotential(const DecisionPotential< GUM_SCALAR >& dp) :
66         probPot(dp.probPot), utilPot(dp.utilPot) {
67       GUM_CONS_CPY(DecisionPotential);
68     }
69 
clear()70     void clear() {
71       gum::Potential< GUM_SCALAR > p;
72       p.fillWith(GUM_SCALAR(1));
73       probPot = p;
74       p.fillWith(GUM_SCALAR(0));
75       utilPot = p;
76     }
77 
78     DecisionPotential< GUM_SCALAR >& operator=(const DecisionPotential< GUM_SCALAR >& src) {
79       GUM_OP_CPY(DecisionPotential);
80       if (&src == this) return *this;
81       probPot = src.probPot;
82       utilPot = src.utilPot;
83       return *this;
84     }
85 
DecisionPotential(DecisionPotential<GUM_SCALAR> && dp)86     DecisionPotential(DecisionPotential< GUM_SCALAR >&& dp) :
87         probPot(std::forward< Potential< GUM_SCALAR > >(dp.probPot)),
88         utilPot(std::forward< Potential< GUM_SCALAR > >(dp.utilPot)) {
89       GUM_CONS_MOV(DecisionPotential);
90     }
91 
92     DecisionPotential< GUM_SCALAR >& operator=(DecisionPotential< GUM_SCALAR >&& src) {
93       GUM_OP_MOV(DecisionPotential);
94       if (&src == this) return *this;
95       probPot = std::forward< Potential< GUM_SCALAR > >(src.probPot);
96       utilPot = std::forward< Potential< GUM_SCALAR > >(src.utilPot);
97       return *this;
98     }
99 
100     bool operator==(const DecisionPotential< GUM_SCALAR >& p) const {
101       // @see Evaluating Influence Diagrams using LIMIDS (2000) - section 3.3
102       return ((p.probPot == this->probPot)
103               && (p.probPot * p.utilPot == this->probPot * this->utilPot));
104     }
105 
106     bool operator!=(const DecisionPotential< GUM_SCALAR >& p) const { return !operator==(p); }
107 
variable(const std::string & name)108     const DiscreteVariable* variable(const std::string& name) const {
109       for (const auto& v: probPot.variablesSequence()) {
110         if (v->name() == name) return v;
111       }
112       for (const auto& v: utilPot.variablesSequence()) {
113         if (v->name() == name) return v;
114       }
115 
116       GUM_ERROR(NotFound, "'" << name << "' can not be found in DecisionPotential.")
117     }
118 
insertProba(const gum::Potential<GUM_SCALAR> & proba)119     void insertProba(const gum::Potential< GUM_SCALAR >& proba) { probPot *= proba; }
120 
insertUtility(const gum::Potential<GUM_SCALAR> & util)121     void insertUtility(const gum::Potential< GUM_SCALAR >& util) { utilPot += util; }
122 
123     DecisionPotential< GUM_SCALAR > operator*(const DecisionPotential< GUM_SCALAR >& dp1) const {
124       return DecisionPotential< GUM_SCALAR >::combination(*this, dp1);
125     }
126 
127     DecisionPotential< GUM_SCALAR > operator*=(const DecisionPotential< GUM_SCALAR >& dp1) {
128       *this = DecisionPotential< GUM_SCALAR >::combination(*this, dp1);
129       return *this;
130     }
131 
132     DecisionPotential< GUM_SCALAR > operator^(const Set< const DiscreteVariable* >& onto) const {
133       return DecisionPotential< GUM_SCALAR >::marginalization(*this, onto);
134     }
135 
136     DecisionPotential< GUM_SCALAR > operator^(const std::vector< std::string >& ontonames) const {
137       return DecisionPotential< GUM_SCALAR >::marginalization(*this, ontonames);
138     }
139 
140 
divideEvenZero(const Potential<GUM_SCALAR> & p1,const Potential<GUM_SCALAR> & p2)141     static Potential< GUM_SCALAR > divideEvenZero(const Potential< GUM_SCALAR >& p1,
142                                                   const Potential< GUM_SCALAR >& p2) {
143       Potential< GUM_SCALAR > res(p1);
144       Instantiation           I(res);
145       for (I.setFirst(); !I.end(); I.inc()) {
146         if (res[I] != 0) res.set(I, res[I] / p2[I]);
147       }
148       return res;
149     }
150 
combination(const DecisionPotential<GUM_SCALAR> & dp1,const DecisionPotential<GUM_SCALAR> & dp2)151     static DecisionPotential< GUM_SCALAR > combination(const DecisionPotential< GUM_SCALAR >& dp1,
152                                                        const DecisionPotential< GUM_SCALAR >& dp2) {
153       return DecisionPotential< GUM_SCALAR >(dp1.probPot * dp2.probPot, dp1.utilPot + dp2.utilPot);
154     }
155 
156     static DecisionPotential< GUM_SCALAR >
marginalization(const DecisionPotential<GUM_SCALAR> & dp,const Set<const DiscreteVariable * > & onto)157        marginalization(const DecisionPotential< GUM_SCALAR >& dp,
158                        const Set< const DiscreteVariable* >&  onto) {
159       const auto pr = dp.probPot.margSumIn(onto);
160       return DecisionPotential(pr, divideEvenZero((dp.probPot * dp.utilPot).margSumIn(onto), pr));
161     }
162 
163     static DecisionPotential< GUM_SCALAR >
marginalization(const DecisionPotential<GUM_SCALAR> & dp,const std::vector<std::string> & ontonames)164        marginalization(const DecisionPotential< GUM_SCALAR >& dp,
165                        const std::vector< std::string >&      ontonames) {
166       Set< const DiscreteVariable* > onto;
167       for (const auto& varname: ontonames) {
168         onto.insert(dp.variable(varname));
169       }
170       return marginalization(dp, onto);
171     }
172 
meanVar()173     std::pair< GUM_SCALAR, GUM_SCALAR > meanVar() {
174       auto       tmp = probPot * utilPot;
175       GUM_SCALAR s   = probPot.sum();
176       double     m   = tmp.sum() / s;
177       double     m2  = (tmp * utilPot).sum() / s;
178       return std::pair< GUM_SCALAR, GUM_SCALAR >(m, m2 - m * m);
179     }
180 
toString()181     virtual std::string toString() const {
182       return "prob : " + probPot.toString() + "    util:" + utilPot.toString();
183     }
184   };
185 
186   template < typename GUM_SCALAR >
187   std::ostream& operator<<(std::ostream& out, const DecisionPotential< GUM_SCALAR >& array) {
188     out << array.toString();
189     return out;
190   }
191 }   // namespace gum
192 
193 #endif   // AGRUM_DECISIONPOTENTIAL_H
194