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 A Interface to all Causal Independence models
25  *
26  * Causal Independence (CI) is a method of defining a discrete distribution
27  * that can dramatically reduce the number of prior probabilities necessary to
28  * define a distribution.
29  *
30  * @author Pierre-Henri WUILLEMIN(_at_LIP6) & Christophe GONZALES(_at_AMU)
31  */
32 #include <agrum/tools/core/bijection.h>
33 #include <agrum/tools/multidim/ICIModels/multiDimICIModel.h>
34 #include <agrum/tools/multidim/implementations/multiDimReadOnly.h>
35 
36 namespace gum {
37 
38   // Default constructor
39   template < typename GUM_SCALAR >
MultiDimICIModel(GUM_SCALAR external_weight,GUM_SCALAR default_weight)40   INLINE MultiDimICIModel< GUM_SCALAR >::MultiDimICIModel(GUM_SCALAR external_weight,
41                                                           GUM_SCALAR default_weight) :
42       MultiDimReadOnly< GUM_SCALAR >(),
43       _external_weight_(external_weight), _default_weight_(default_weight) {
44     GUM_CONSTRUCTOR(MultiDimICIModel);
45   }
46 
47   // Default constructor
48   template < typename GUM_SCALAR >
49   INLINE
MultiDimICIModel(const MultiDimICIModel<GUM_SCALAR> & from)50      MultiDimICIModel< GUM_SCALAR >::MultiDimICIModel(const MultiDimICIModel< GUM_SCALAR >& from) :
51       MultiDimReadOnly< GUM_SCALAR >(from) {
52     GUM_CONS_CPY(MultiDimICIModel);
53     _default_weight_  = from._default_weight_;
54     _external_weight_ = from._external_weight_;
55     _causal_weights_  = from._causal_weights_;
56   }
57 
58   // Copy constructor using a bijection to replace variables from source.
59   template < typename GUM_SCALAR >
MultiDimICIModel(const Bijection<const DiscreteVariable *,const DiscreteVariable * > & bij,const MultiDimICIModel<GUM_SCALAR> & from)60   INLINE MultiDimICIModel< GUM_SCALAR >::MultiDimICIModel(
61      const Bijection< const DiscreteVariable*, const DiscreteVariable* >& bij,
62      const MultiDimICIModel< GUM_SCALAR >&                                from) :
63       MultiDimReadOnly< GUM_SCALAR >() {
64     GUM_CONSTRUCTOR(MultiDimICIModel);
65     _default_weight_  = from._default_weight_;
66     _external_weight_ = from._external_weight_;
67 
68     for (HashTableConstIteratorSafe< const DiscreteVariable*, GUM_SCALAR > iter
69          = from._causal_weights_.beginSafe();
70          iter != from._causal_weights_.endSafe();
71          ++iter) {
72       try {
73         causalWeight(*(bij.first(iter.key())), iter.val());
74       } catch (NotFound&) { causalWeight(*(iter.key()), iter.val()); }
75     }
76   }
77 
78   // destructor
79   template < typename GUM_SCALAR >
~MultiDimICIModel()80   INLINE MultiDimICIModel< GUM_SCALAR >::~MultiDimICIModel() {
81     GUM_DESTRUCTOR(MultiDimICIModel);
82   }
83 
84   template < typename GUM_SCALAR >
causalWeight(const DiscreteVariable & v)85   INLINE GUM_SCALAR MultiDimICIModel< GUM_SCALAR >::causalWeight(const DiscreteVariable& v) const {
86     return (_causal_weights_.exists(&v)) ? _causal_weights_[&v] : _default_weight_;
87   }
88 
89   template < typename GUM_SCALAR >
causalWeight(const DiscreteVariable & v,GUM_SCALAR w)90   INLINE void MultiDimICIModel< GUM_SCALAR >::causalWeight(const DiscreteVariable& v,
91                                                            GUM_SCALAR              w) const {
92     if (!this->contains(v)) {
93       GUM_ERROR(InvalidArgument, v.name() << " is not a cause for this CI Model")
94     }
95 
96     if (w == (GUM_SCALAR)0) { GUM_ERROR(gum::OutOfBounds, "causal weight in CI Model>0") }
97 
98     _causal_weights_.set(&v, w);
99   }
100 
101   template < typename GUM_SCALAR >
externalWeight()102   INLINE GUM_SCALAR MultiDimICIModel< GUM_SCALAR >::externalWeight() const {
103     return _external_weight_;
104   }
105 
106   template < typename GUM_SCALAR >
externalWeight(GUM_SCALAR w)107   INLINE void MultiDimICIModel< GUM_SCALAR >::externalWeight(GUM_SCALAR w) const {
108     _external_weight_ = w;
109   }
110 
111   template < typename GUM_SCALAR >
toString()112   std::string MultiDimICIModel< GUM_SCALAR >::toString() const {
113     std::stringstream s;
114     s << this->variable(0) << "=CIModel([" << externalWeight() << "],";
115 
116     for (Idx i = 1; i < this->nbrDim(); i++) {
117       s << this->variable(i) << "[" << causalWeight(this->variable(i)) << "]";
118     }
119 
120     s << ")";
121 
122     std::string res;
123     s >> res;
124     return res;
125   }
126   template < typename GUM_SCALAR >
copyFrom(const MultiDimContainer<GUM_SCALAR> & src)127   void MultiDimICIModel< GUM_SCALAR >::copyFrom(const MultiDimContainer< GUM_SCALAR >& src) const {
128     auto p = dynamic_cast< const MultiDimICIModel< GUM_SCALAR >* >(&src);
129     if (p == nullptr)
130       MultiDimReadOnly< GUM_SCALAR >::copyFrom(src);
131     else {
132       if (src.domainSize() != this->domainSize()) {
133         GUM_ERROR(OperationNotAllowed, "Domain sizes do not fit")
134       }
135       _external_weight_ = p->_external_weight_;
136       _default_weight_  = p->_default_weight_;
137       for (Idx i = 1; i < this->nbrDim(); i++) {
138         _causal_weights_.set(const_cast< const DiscreteVariable* >(&this->variable(i)),
139                              p->causalWeight(this->variable(i)));
140       }
141     }
142   }
143 
144   // returns the name of the implementation
145   template < typename GUM_SCALAR >
name()146   INLINE const std::string& MultiDimICIModel< GUM_SCALAR >::name() const {
147     static const std::string str = "MultiDimICIModel";
148     return str;
149   }
150 
151   template < typename GUM_SCALAR >
replace_(const DiscreteVariable * x,const DiscreteVariable * y)152   INLINE void MultiDimICIModel< GUM_SCALAR >::replace_(const DiscreteVariable* x,
153                                                        const DiscreteVariable* y) {
154     MultiDimReadOnly< GUM_SCALAR >::replace_(x, y);
155     _causal_weights_.insert(y, _causal_weights_[x]);
156     _causal_weights_.erase(x);
157   }
158 
159 } /* namespace gum */
160