aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
scoreLog2Likelihood_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright 2005-2020 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 /** @file
23  * @brief the class for computing Log2-Likelihood scores
24  *
25  * @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
26  */
27 
28 #ifndef DOXYGEN_SHOULD_SKIP_THIS
29 
30 # include <agrum/BN/learning/scores_and_tests/scoreLog2Likelihood.h>
31 # include <sstream>
32 
33 namespace gum {
34 
35  namespace learning {
36 
37  /// default constructor
38  template < template < typename > class ALLOC >
39  INLINE ScoreLog2Likelihood< ALLOC >::ScoreLog2Likelihood(
40  const DBRowGeneratorParser< ALLOC >& parser,
41  const Apriori< ALLOC >& apriori,
42  const std::vector< std::pair< std::size_t, std::size_t >,
43  ALLOC< std::pair< std::size_t, std::size_t > > >& ranges,
44  const Bijection< NodeId, std::size_t, ALLOC< std::size_t > >&
45  nodeId2columns,
46  const typename ScoreLog2Likelihood< ALLOC >::allocator_type& alloc) :
47  Score< ALLOC >(parser, apriori, ranges, nodeId2columns, alloc),
48  internal_apriori__(parser.database(), nodeId2columns) {
49  GUM_CONSTRUCTOR(ScoreLog2Likelihood);
50  }
51 
52 
53  /// default constructor
54  template < template < typename > class ALLOC >
55  INLINE ScoreLog2Likelihood< ALLOC >::ScoreLog2Likelihood(
56  const DBRowGeneratorParser< ALLOC >& parser,
57  const Apriori< ALLOC >& apriori,
58  const Bijection< NodeId, std::size_t, ALLOC< std::size_t > >&
59  nodeId2columns,
60  const typename ScoreLog2Likelihood< ALLOC >::allocator_type& alloc) :
61  Score< ALLOC >(parser, apriori, nodeId2columns, alloc),
62  internal_apriori__(parser.database(), nodeId2columns) {
63  GUM_CONSTRUCTOR(ScoreLog2Likelihood);
64  }
65 
66 
67  /// copy constructor with a given allocator
68  template < template < typename > class ALLOC >
69  INLINE ScoreLog2Likelihood< ALLOC >::ScoreLog2Likelihood(
70  const ScoreLog2Likelihood< ALLOC >& from,
71  const typename ScoreLog2Likelihood< ALLOC >::allocator_type& alloc) :
72  Score< ALLOC >(from, alloc),
73  internal_apriori__(from.internal_apriori__, alloc) {
74  GUM_CONS_CPY(ScoreLog2Likelihood);
75  }
76 
77 
78  /// copy constructor
79  template < template < typename > class ALLOC >
80  INLINE ScoreLog2Likelihood< ALLOC >::ScoreLog2Likelihood(
81  const ScoreLog2Likelihood< ALLOC >& from) :
82  ScoreLog2Likelihood< ALLOC >(from, from.getAllocator()) {}
83 
84 
85  /// move constructor with a given allocator
86  template < template < typename > class ALLOC >
87  INLINE ScoreLog2Likelihood< ALLOC >::ScoreLog2Likelihood(
88  ScoreLog2Likelihood< ALLOC >&& from,
89  const typename ScoreLog2Likelihood< ALLOC >::allocator_type& alloc) :
90  Score< ALLOC >(std::move(from), alloc),
91  internal_apriori__(std::move(from.internal_apriori__), alloc) {
92  GUM_CONS_MOV(ScoreLog2Likelihood);
93  }
94 
95 
96  /// move constructor
97  template < template < typename > class ALLOC >
98  INLINE ScoreLog2Likelihood< ALLOC >::ScoreLog2Likelihood(
99  ScoreLog2Likelihood< ALLOC >&& from) :
100  ScoreLog2Likelihood< ALLOC >(std::move(from), from.getAllocator()) {}
101 
102 
103  /// virtual copy constructor with a given allocator
104  template < template < typename > class ALLOC >
105  ScoreLog2Likelihood< ALLOC >* ScoreLog2Likelihood< ALLOC >::clone(
106  const typename ScoreLog2Likelihood< ALLOC >::allocator_type& alloc) const {
107  ALLOC< ScoreLog2Likelihood< ALLOC > > allocator(alloc);
108  ScoreLog2Likelihood< ALLOC >* new_score = allocator.allocate(1);
109  try {
110  allocator.construct(new_score, *this, alloc);
111  } catch (...) {
112  allocator.deallocate(new_score, 1);
113  throw;
114  }
115 
116  return new_score;
117  }
118 
119 
120  /// virtual copy constructor
121  template < template < typename > class ALLOC >
122  ScoreLog2Likelihood< ALLOC >* ScoreLog2Likelihood< ALLOC >::clone() const {
123  return clone(this->getAllocator());
124  }
125 
126 
127  /// destructor
128  template < template < typename > class ALLOC >
129  ScoreLog2Likelihood< ALLOC >::~ScoreLog2Likelihood() {
130  GUM_DESTRUCTOR(ScoreLog2Likelihood);
131  }
132 
133 
134  /// copy operator
135  template < template < typename > class ALLOC >
136  ScoreLog2Likelihood< ALLOC >& ScoreLog2Likelihood< ALLOC >::operator=(
137  const ScoreLog2Likelihood< ALLOC >& from) {
138  if (this != &from) {
139  Score< ALLOC >::operator=(from);
140  internal_apriori__ = from.internal_apriori__;
141  }
142  return *this;
143  }
144 
145 
146  /// move operator
147  template < template < typename > class ALLOC >
148  ScoreLog2Likelihood< ALLOC >& ScoreLog2Likelihood< ALLOC >::operator=(
149  ScoreLog2Likelihood< ALLOC >&& from) {
150  if (this != &from) {
151  Score< ALLOC >::operator=(std::move(from));
152  internal_apriori__ = std::move(from.internal_apriori__);
153  }
154  return *this;
155  }
156 
157 
158  /// indicates whether the apriori is compatible (meaningful) with the score
159  template < template < typename > class ALLOC >
160  std::string ScoreLog2Likelihood< ALLOC >::isAprioriCompatible(
161  const std::string& apriori_type,
162  double weight) {
163  // check that the apriori is compatible with the score
164  if ((apriori_type == AprioriDirichletType::type)
165  || (apriori_type == AprioriSmoothingType::type)
166  || (apriori_type == AprioriNoAprioriType::type)) {
167  return "";
168  }
169 
170  // apriori types unsupported by the type checker
171  std::stringstream msg;
172  msg << "The apriori '" << apriori_type
173  << "' is not yet supported by method isAprioriCompatible of "
174  << "Score Log2Likelihood";
175  return msg.str();
176  }
177 
178 
179  /// indicates whether the apriori is compatible (meaningful) with the score
180  template < template < typename > class ALLOC >
181  INLINE std::string ScoreLog2Likelihood< ALLOC >::isAprioriCompatible(
182  const Apriori< ALLOC >& apriori) {
183  return isAprioriCompatible(apriori.getType(), apriori.weight());
184  }
185 
186 
187  /// indicates whether the apriori is compatible (meaningful) with the score
188  template < template < typename > class ALLOC >
189  INLINE std::string ScoreLog2Likelihood< ALLOC >::isAprioriCompatible() const {
190  return isAprioriCompatible(*(this->apriori_));
191  }
192 
193 
194  /// returns the internal apriori of the score
195  template < template < typename > class ALLOC >
196  INLINE const Apriori< ALLOC >&
197  ScoreLog2Likelihood< ALLOC >::internalApriori() const {
198  return internal_apriori__;
199  }
200 
201 
202  /// returns the score corresponding to a given nodeset
203  template < template < typename > class ALLOC >
204  double ScoreLog2Likelihood< ALLOC >::score_(const IdCondSet< ALLOC >& idset) {
205  // get the counts for all the nodes in the idset and add the apriori
206  std::vector< double, ALLOC< double > > N_ijk(
207  this->counter_.counts(idset, true));
208  const bool informative_external_apriori = this->apriori_->isInformative();
209  if (informative_external_apriori)
210  this->apriori_->addAllApriori(idset, N_ijk);
211 
212  // here, we distinguish idsets with conditioning nodes from those
213  // without conditioning nodes
214  if (idset.hasConditioningSet()) {
215  // get the counts for the conditioning nodes
216  std::vector< double, ALLOC< double > > N_ij(
217  this->marginalize_(idset[0], N_ijk));
218 
219  // compute the score: it remains to compute the log likelihood, i.e.,
220  // sum_k=1^r_i sum_j=1^q_i N_ijk log (N_ijk / N_ij), which is also
221  // equivalent to:
222  // sum_j=1^q_i sum_k=1^r_i N_ijk log N_ijk - sum_j=1^q_i N_ij log N_ij
223  double score = 0.0;
224  for (const auto n_ijk: N_ijk) {
225  if (n_ijk) { score += n_ijk * std::log(n_ijk); }
226  }
227  for (const auto n_ij: N_ij) {
228  if (n_ij) { score -= n_ij * std::log(n_ij); }
229  }
230 
231  // divide by log(2), since the log likelihood uses log_2
232  score *= this->one_log2_;
233 
234  return score;
235  } else {
236  // here, there are no conditioning nodes
237 
238  // compute the score: it remains to compute the log likelihood, i.e.,
239  // sum_k=1^r_i N_ijk log (N_ijk / N), which is also
240  // equivalent to:
241  // sum_j=1^q_i sum_k=1^r_i N_ijk log N_ijk - N log N
242  double N = 0.0;
243  double score = 0.0;
244  for (const auto n_ijk: N_ijk) {
245  if (n_ijk) {
246  score += n_ijk * std::log(n_ijk);
247  N += n_ijk;
248  }
249  }
250  score -= N * std::log(N);
251 
252  // divide by log(2), since the log likelihood uses log_2
253  score *= this->one_log2_;
254 
255  return score;
256  }
257  }
258 
259 
260  /// returns the score corresponding to a given nodeset
261  template < template < typename > class ALLOC >
262  INLINE double
263  ScoreLog2Likelihood< ALLOC >::score(const IdCondSet< ALLOC >& idset) {
264  return score_(idset);
265  }
266 
267 
268  } /* namespace learning */
269 
270 } /* namespace gum */
271 
272 #endif /* DOXYGEN_SHOULD_SKIP_THIS */