aGrUM  0.16.0
scoreK2_tpl.h
Go to the documentation of this file.
1 
29 #ifndef DOXYGEN_SHOULD_SKIP_THIS
30 
32 # include <sstream>
33 
34 namespace gum {
35 
36  namespace learning {
37 
39  template < template < typename > class ALLOC >
41  const DBRowGeneratorParser< ALLOC >& parser,
42  const Apriori< ALLOC >& apriori,
43  const std::vector< std::pair< std::size_t, std::size_t >,
44  ALLOC< std::pair< std::size_t, std::size_t > > >& ranges,
45  const Bijection< NodeId, std::size_t, ALLOC< std::size_t > >&
46  nodeId2columns,
47  const typename ScoreK2< ALLOC >::allocator_type& alloc) :
48  Score< ALLOC >(parser, apriori, ranges, nodeId2columns, alloc),
49  __internal_apriori(parser.database(), nodeId2columns) {
50  GUM_CONSTRUCTOR(ScoreK2);
51  }
52 
53 
55  template < template < typename > class ALLOC >
57  const DBRowGeneratorParser< ALLOC >& parser,
58  const Apriori< ALLOC >& apriori,
59  const Bijection< NodeId, std::size_t, ALLOC< std::size_t > >&
60  nodeId2columns,
61  const typename ScoreK2< ALLOC >::allocator_type& alloc) :
62  Score< ALLOC >(parser, apriori, nodeId2columns, alloc),
63  __internal_apriori(parser.database(), nodeId2columns) {
64  GUM_CONSTRUCTOR(ScoreK2);
65  }
66 
67 
69  template < template < typename > class ALLOC >
71  const ScoreK2< ALLOC >& from,
72  const typename ScoreK2< ALLOC >::allocator_type& alloc) :
73  Score< ALLOC >(from, alloc),
74  __internal_apriori(from.__internal_apriori, alloc),
75  __gammalog2(from.__gammalog2) {
76  GUM_CONS_CPY(ScoreK2);
77  }
78 
79 
81  template < template < typename > class ALLOC >
82  INLINE ScoreK2< ALLOC >::ScoreK2(const ScoreK2< ALLOC >& from) :
83  ScoreK2< ALLOC >(from, from.getAllocator()) {}
84 
85 
87  template < template < typename > class ALLOC >
89  ScoreK2< ALLOC >&& from,
90  const typename ScoreK2< ALLOC >::allocator_type& alloc) :
91  Score< ALLOC >(std::move(from), alloc),
92  __internal_apriori(std::move(from.__internal_apriori), alloc),
93  __gammalog2(std::move(from.__gammalog2)) {
94  GUM_CONS_MOV(ScoreK2);
95  }
96 
97 
99  template < template < typename > class ALLOC >
100  INLINE ScoreK2< ALLOC >::ScoreK2(ScoreK2< ALLOC >&& from) :
101  ScoreK2< ALLOC >(std::move(from), from.getAllocator()) {}
102 
103 
105  template < template < typename > class ALLOC >
106  ScoreK2< ALLOC >* ScoreK2< ALLOC >::clone(
107  const typename ScoreK2< ALLOC >::allocator_type& alloc) const {
108  ALLOC< ScoreK2< ALLOC > > allocator(alloc);
109  ScoreK2< ALLOC >* new_score = allocator.allocate(1);
110  try {
111  allocator.construct(new_score, *this, alloc);
112  } catch (...) {
113  allocator.deallocate(new_score, 1);
114  throw;
115  }
116 
117  return new_score;
118  }
119 
120 
122  template < template < typename > class ALLOC >
123  ScoreK2< ALLOC >* ScoreK2< ALLOC >::clone() const {
124  return clone(this->getAllocator());
125  }
126 
127 
129  template < template < typename > class ALLOC >
131  GUM_DESTRUCTOR(ScoreK2);
132  }
133 
134 
136  template < template < typename > class ALLOC >
137  ScoreK2< ALLOC >& ScoreK2< ALLOC >::operator=(const ScoreK2< ALLOC >& from) {
138  if (this != &from) {
140  __internal_apriori = from.__internal_apriori;
141  }
142  return *this;
143  }
144 
145 
147  template < template < typename > class ALLOC >
148  ScoreK2< ALLOC >& ScoreK2< ALLOC >::operator=(ScoreK2< ALLOC >&& from) {
149  if (this != &from) {
150  Score< ALLOC >::operator=(std::move(from));
151  __internal_apriori = std::move(from.__internal_apriori);
152  }
153  return *this;
154  }
155 
156 
158  template < template < typename > class ALLOC >
159  std::string
160  ScoreK2< ALLOC >::isAprioriCompatible(const std::string& apriori_type,
161  double weight) {
162  // check that the apriori is compatible with the score
163  if (apriori_type == AprioriNoAprioriType::type) { return ""; }
164 
165  if (weight == 0.0) {
166  return "The apriori is currently compatible with the K2 score but "
167  "if you change the weight, it will become incompatible.";
168  }
169 
170  // known incompatible aprioris
171  if ((apriori_type == AprioriDirichletType::type)
172  || (apriori_type == AprioriSmoothingType::type)) {
173  return "The K2 score already contains a different 'implicit' apriori. "
174  "Therefore, the learning will probably be biased.";
175  }
176 
177  // apriori types unsupported by the type checker
178  std::stringstream msg;
179  msg << "The apriori '" << apriori_type
180  << "' is not yet supported by method isAprioriCompatible os Score K2";
181  return msg.str();
182  }
183 
184 
186  template < template < typename > class ALLOC >
187  INLINE std::string
188  ScoreK2< ALLOC >::isAprioriCompatible(const Apriori< ALLOC >& apriori) {
189  return isAprioriCompatible(apriori.getType(), apriori.weight());
190  }
191 
192 
194  template < template < typename > class ALLOC >
195  INLINE std::string ScoreK2< ALLOC >::isAprioriCompatible() const {
196  return isAprioriCompatible(*(this->_apriori));
197  }
198 
199 
201  template < template < typename > class ALLOC >
202  INLINE const Apriori< ALLOC >& ScoreK2< ALLOC >::internalApriori() const {
203  return __internal_apriori;
204  }
205 
206 
208  template < template < typename > class ALLOC >
209  double ScoreK2< ALLOC >::_score(const IdSet< ALLOC >& idset) {
210  // get the counts for all the nodes in the idset and add the apriori
211  std::vector< double, ALLOC< double > > N_ijk(
212  this->_counter.counts(idset, true));
213  const std::size_t all_size = N_ijk.size();
214  const bool informative_external_apriori = this->_apriori->isInformative();
215  double score = 0.0;
216 
217  // here, we distinguish idsets with conditioning nodes from those
218  // without conditioning nodes
219  if (idset.hasConditioningSet()) {
220  // get the counts for the conditioning nodes
221  std::vector< double, ALLOC< double > > N_ij(
222  this->_marginalize(idset[0], N_ijk));
223  const std::size_t conditioning_size = N_ij.size();
224  const double ri = double(all_size / conditioning_size);
225 
226  if (informative_external_apriori) {
227  // the score to compute is that of BD with aprioris N'_ijk + 1
228  // (the + 1 is here to take into account the internal apriori of K2)
229  std::vector< double, ALLOC< double > > N_prime_ijk(all_size, 0.0);
230  this->_apriori->addAllApriori(idset, N_prime_ijk);
231  std::vector< double, ALLOC< double > > N_prime_ij(N_ij.size(), 0.0);
232  this->_apriori->addConditioningApriori(idset, N_prime_ij);
233 
234  // the K2 score can be computed as follows:
235  // sum_j=1^qi [ gammalog2 ( N'_ij + r_i ) -
236  // gammalog2 ( N_ij + N'_ij + r_i )
237  // + sum_k=1^ri { gammlog2 ( N_ijk + N'_ijk + 1 ) -
238  // gammalog2 ( N'_ijk + 1 ) } ]
239  for (std::size_t j = std::size_t(0); j < conditioning_size; ++j) {
240  score += __gammalog2(N_prime_ij[j] + ri)
241  - __gammalog2(N_ij[j] + N_prime_ij[j] + ri);
242  }
243  for (std::size_t k = std::size_t(0); k < all_size; ++k) {
244  score += __gammalog2(N_ijk[k] + N_prime_ijk[k] + 1.0)
245  - __gammalog2(N_prime_ijk[k] + 1.0);
246  }
247  } else {
248  // the K2 score can be computed as follows:
249  // qi log {(ri - 1)!} + sum_j=1^qi [ - log {(N_ij+ri-1)!} +
250  // sum_k=1^ri log { N_ijk! } ]
251  score = conditioning_size * __gammalog2(ri);
252 
253  for (const auto n_ij : N_ij) {
254  score -= __gammalog2(n_ij + ri);
255  }
256  for (const auto n_ijk : N_ijk) {
257  score += __gammalog2(n_ijk + 1);
258  }
259  }
260  } else {
261  // here, there are no conditioning nodes
262  const double ri = double(all_size);
263 
264  if (informative_external_apriori) {
265  // the score to compute is that of BD with aprioris N'_ijk + 1
266  // (the + 1 is here to take into account the internal apriori of K2)
267 
268  // the K2 score can be computed as follows:
269  // gammalog2 ( N' + r_i ) - gammalog2 ( N + N' + r_i )
270  // + sum_k=1^ri { gammlog2 ( N_i + N'_i + 1 ) - gammalog2 ( N'_i + 1 )
271  // }
272  std::vector< double, ALLOC< double > > N_prime_ijk(all_size, 0.0);
273  this->_apriori->addAllApriori(idset, N_prime_ijk);
274 
275  // the K2 score can be computed as follows:
276  double N = 0.0;
277  double N_prime = 0.0;
278  for (std::size_t k = std::size_t(0); k < all_size; ++k) {
279  score += __gammalog2(N_ijk[k] + N_prime_ijk[k] + 1)
280  - __gammalog2(N_prime_ijk[k] + 1);
281  N += N_ijk[k];
282  N_prime += N_prime_ijk[k];
283  }
284  score += __gammalog2(N_prime + ri) - __gammalog2(N + N_prime + ri);
285  } else {
286  // the K2 score can be computed as follows:
287  // log {(ri - 1)!} - log {(N + ri-1)!} + sum_k=1^ri log { N_ijk! } ]
288  score = __gammalog2(ri);
289  double N = 0;
290  for (const auto n_ijk : N_ijk) {
291  score += __gammalog2(n_ijk + 1);
292  N += n_ijk;
293  }
294  score -= __gammalog2(N + ri);
295  }
296  }
297 
298  return score;
299  }
300 
301  } /* namespace learning */
302 
303 } /* namespace gum */
304 
305 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
const DatabaseTable< ALLOC > & database() const
return the database used by the score
double score(const NodeId var)
returns the score of a single node
static const std::string type
Definition: aprioriTypes.h:43
Score(const DBRowGeneratorParser< ALLOC > &parser, const Apriori< ALLOC > &external_apriori, const std::vector< std::pair< std::size_t, std::size_t >, ALLOC< std::pair< std::size_t, std::size_t > > > &ranges, const Bijection< NodeId, std::size_t, ALLOC< std::size_t > > &nodeId2columns=Bijection< NodeId, std::size_t, ALLOC< std::size_t > >(), const allocator_type &alloc=allocator_type())
default constructor
static const std::string type
Definition: aprioriTypes.h:48
STL namespace.
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
Definition: agrum.h:25
std::vector< double, ALLOC< double > > _marginalize(const NodeId X_id, const std::vector< double, ALLOC< double > > &N_xyz) const
returns a counting vector where variables are marginalized from N_xyz
ScoreK2< ALLOC > & operator=(const ScoreK2< ALLOC > &from)
copy operator
virtual ScoreK2< ALLOC > * clone() const
virtual copy constructor
ScoreK2(const DBRowGeneratorParser< ALLOC > &parser, const Apriori< ALLOC > &apriori, const std::vector< std::pair< std::size_t, std::size_t >, ALLOC< std::pair< std::size_t, std::size_t > > > &ranges, const Bijection< NodeId, std::size_t, ALLOC< std::size_t > > &nodeId2columns=Bijection< NodeId, std::size_t, ALLOC< std::size_t > >(), const allocator_type &alloc=allocator_type())
default constructor
Score< ALLOC > & operator=(const Score< ALLOC > &from)
copy operator
virtual const Apriori< ALLOC > & internalApriori() const final
returns the internal apriori of the score
virtual std::string isAprioriCompatible() const final
indicates whether the apriori is compatible (meaningful) with the score
virtual double _score(const IdSet< ALLOC > &idset) final
returns the score for a given IdSet
allocator_type getAllocator() const
returns the allocator used by the score
virtual ~ScoreK2()
destructor
Apriori< ALLOC > * _apriori
the expert knowledge a priori we add to the score
Definition: score.h:242
static const std::string type
Definition: aprioriTypes.h:38
RecordCounter< ALLOC > _counter
the record counter used for the countings over discrete variables
Definition: score.h:245
Size NodeId
Type for node ids.
Definition: graphElements.h:98
ALLOC< NodeId > allocator_type
type for the allocators passed in arguments of methods
Definition: scoreK2.h:64