aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
DBRowGeneratorSet_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 Template implementation of DBRowGeneratorSet
24  *
25  * @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
26  */
27 
28 #ifndef DOXYGEN_SHOULD_SKIP_THIS
29 
30 namespace gum {
31 
32  namespace learning {
33 
34 
35  /// default constructor
36  template < template < typename > class ALLOC >
37  INLINE DBRowGeneratorSet< ALLOC >::DBRowGeneratorSet(
38  const typename DBRowGeneratorSet< ALLOC >::allocator_type& alloc) :
42  }
43 
44 
45  /// copy constructor with a given allocator
46  template < template < typename > class ALLOC >
48  const DBRowGeneratorSet< ALLOC >& from,
49  const typename DBRowGeneratorSet< ALLOC >::allocator_type& alloc) :
53  // create the generators
54  for (std::size_t i = std::size_t(0); i < nb_generators__; ++i)
56 
58  }
59 
60 
61  /// copy constructor
62  template < template < typename > class ALLOC >
64  const DBRowGeneratorSet< ALLOC >& from) :
66 
67 
68  /// move constructor with a given allocator
69  template < template < typename > class ALLOC >
72  const typename DBRowGeneratorSet< ALLOC >::allocator_type& alloc) :
77  }
78 
79 
80  /// move constructor
81  template < template < typename > class ALLOC >
85 
86  /// virtual copy constructor with a given allocator
87  template < template < typename > class ALLOC >
89  const typename DBRowGeneratorSet< ALLOC >::allocator_type& alloc) const {
92  try {
94  } catch (...) {
96  throw;
97  }
98  return generators;
99  }
100 
101 
102  /// virtual copy constructor
103  template < template < typename > class ALLOC >
105  return clone(this->getAllocator());
106  }
107 
108 
109  /// removes all the generators
110  template < template < typename > class ALLOC >
111  void DBRowGeneratorSet< ALLOC >::clear() {
112  // delete all the generators
114  for (auto gen: generators__) {
117  }
118 
119  // clear all the internal fields
121  nb_generators__ = std::size_t(0);
122  output_row__ = nullptr;
124  }
125 
126 
127  /// destructor
128  template < template < typename > class ALLOC >
131  clear();
132  }
133 
134 
135  /// copy operator
136  template < template < typename > class ALLOC >
138  const DBRowGeneratorSet< ALLOC >& from) {
139  if (this != &from) {
140  // produce the new generators
144  for (std::size_t i = std::size_t(0); i < from.nb_generators__; ++i) {
145  try {
147  } catch (...) {
148  for (std::size_t j = std::size_t(0); j < i; ++j) {
151  }
152  throw;
153  }
154  }
155 
156  // create the setInputDBrow_performed vector
157  std::vector< int, ALLOC< int > > setInputDBrow_performed(
159  0,
160  getAllocator());
161 
162  // remove the old generators and copy the new ones
163  clear();
166  output_row__ = nullptr;
168  }
169 
170  return *this;
171  }
172 
173 
174  /// move operator
175  template < template < typename > class ALLOC >
178  if (this != &from) {
179  // remove the old generators and move the new ones
180  clear();
185  }
186  return *this;
187  }
188 
189 
190  /// returns the ith generator
191  template < template < typename > class ALLOC >
193  DBRowGeneratorSet< ALLOC >::operator[](const std::size_t i) {
194  return *(generators__[i]);
195  }
196 
197 
198  /// returns the ith generator
199  template < template < typename > class ALLOC >
200  INLINE const DBRowGenerator< ALLOC >&
201  DBRowGeneratorSet< ALLOC >::operator[](const std::size_t i) const {
202  return *(generators__[i]);
203  }
204 
205 
206  /// inserts a new generator at the end of the set
207  template < template < typename > class ALLOC >
208  template < template < template < typename > class > class Generator >
210  const Generator< ALLOC >& generator) {
211  // check that no output row generation is still active
212  if (output_row__ != nullptr)
214  "you cannot insert a new generator while a generation is "
215  "still being processed");
216 
219 
220  try {
222  } catch (...) {
225  throw;
226  }
227 
228  ++nb_generators__;
229  output_row__ = nullptr;
230  }
231 
232 
233  /// inserts a new generator at the end of the set
234  template < template < typename > class ALLOC >
235  template < template < template < typename > class > class Generator >
237  const Generator< ALLOC >& generator,
238  const std::size_t i) {
239  // check that no output row generation is still active
240  if (output_row__ != nullptr)
242  "you cannot insert a new generator while a generation is "
243  "still being processed");
244 
247 
248  try {
250  } catch (...) {
253  throw;
254  }
255 
256  ++nb_generators__;
257  output_row__ = nullptr;
258  }
259 
260 
261  /// returns the number of generators
262  template < template < typename > class ALLOC >
263  INLINE std::size_t DBRowGeneratorSet< ALLOC >::nbGenerators() const noexcept {
264  return nb_generators__;
265  }
266 
267 
268  /// assign a new Bayes net to all the generators that depend on a BN
269  template < template < typename > class ALLOC >
270  template < typename GUM_SCALAR >
272  const BayesNet< GUM_SCALAR >& new_bn) {
274  const BayesNet< GUM_SCALAR >* >
275  old_bns;
276 
277  for (auto xgen: generators__) {
278  // check if the generator relies on a Bayes net
279  DBRowGeneratorWithBN< GUM_SCALAR, ALLOC >* gen = nullptr;
280  try {
281  gen = dynamic_cast< DBRowGeneratorWithBN< GUM_SCALAR, ALLOC >* >(xgen);
282  } catch (std::bad_cast&) {}
283 
284  if (gen != nullptr) {
285  // try to assign the new BN to the generator
286  try {
287  const BayesNet< GUM_SCALAR >* bn = &(gen->getBayesNet());
288  old_bns.insert(gen, bn);
290  } catch (...) {
291  // if we could not assign the new BN to the generator, then
292  // make all the generators that were successfully assigned this
293  // BN revert to the old BN they had
294  for (auto& generator: old_bns) {
296  }
297  throw;
298  }
299  }
300  }
301  }
302 
303 
304  /// returns the number of generators (alias for nbGenerators)
305  template < template < typename > class ALLOC >
306  INLINE std::size_t DBRowGeneratorSet< ALLOC >::size() const noexcept {
307  return nb_generators__;
308  }
309 
310 
311  /// returns true if there are still rows that can be output by the RowFilter
312  template < template < typename > class ALLOC >
314  return output_row__ != nullptr;
315  }
316 
317 
318  // try to produce a new row
319  template < template < typename > class ALLOC >
322  std::size_t i) {
323  // the generation of output rows can be viewed as the traversal of a
324  // tree: each node of the tree correspond to the input row received by
325  // a generator. So the root node is the row passed in argument to
326  // the setInputDBrow() Method. From these input rows, generators produce
327  // through their generate() method new output rows, which correspond to
328  // the input rows of the next level of the tree. If we traverse this tree
329  // in terms of generators rather than in terms of input rows, we should
330  // call once Method setInputDBrow() in order to update the generators
331  // data structures, and then, to call method generate() to create new
332  // output rows. When some generators are unable to produce output rows,
333  // we just need to backtrack in the tree
334 
335  // for the ith generator, we set the new input DBRow passed in
336  // argument of setInputDBRow. We ask it to generate a new output row.
337  // If this can be done, the new output row is passed as a new input DBRow
338  // for the next generator, and so on. If a generator cannot produce any
339  // output row, we ask its predecessors to generate new rows (backtrack),
340  // until all the generators have been able to generate at least one output
341  // row (or no output row can be produced from input_row).
343  while (i != nb_generators__) {
344  auto generator = generators__[i];
345 
346  // if we did not pass any row yet to the ith generator, do it
347  // else use method generate() to generate a new output row
348  if (setInputRow_performed__[i] == 0) {
349  // pass the current row
350  const bool has_rows = generator->setInputRow(*row);
351 
352  // if the generator could not create output rows, try to backtrack
353  if (!has_rows) {
354  if (i > std::size_t(0)) {
355  --i;
356  continue;
357  } else {
358  // here we were unable to generate output rows
359  output_row__ = nullptr;
360  return false;
361  }
362  } else {
363  // here, the generator is able to generate output rows
364  // so, generate the first one
365  row = &(generator->generate());
367 
368  // pass to the next generator
369  ++i;
370  }
371  } else {
372  // here, the generator has already performed its setInputDBRow call
373  // so we should ask it to generate a new row. If it cannot produce
374  // any more row, try to backtrack
375  if (generator->hasRows()) {
376  // get the new row
377  row = &(generator->generate());
378 
379  // pass to the next generator
380  ++i;
381  } else {
382  // indicate that the next time we use this generator, we will have
383  // to use method setInputDBRow and backtrack
385  if (i > std::size_t(0)) {
386  --i;
387  continue;
388  } else {
389  // here we were unable to generate output rows
390  output_row__ = nullptr;
391  return false;
392  }
393  }
394  }
395  }
396 
397  // here row contains a row generated on a leaf of the row generation tree
398  // we should keep it when the user will ask for the next row to generate
399  output_row__ = row;
400  return true;
401  }
402 
403 
404  /// sets the input row from which the generator will create new rows
405  template < template < typename > class ALLOC >
407  const DBRow< DBTranslatedValue, ALLOC >& input_row) {
408  // reset all the generators: ask them to use method setInputDBRow
409  if (hasRows())
411  performed = 0;
412 
413  // now, parse the row generation tree
414  return produceNextRow__(&input_row, std::size_t(0));
415  }
416 
417 
418  /// generate new rows from the input row
419  template < template < typename > class ALLOC >
422  // get the row that we should return
423  const auto row = output_row__;
424 
425  // we should ask the last generator to produce the next output row
427 
428  return *row;
429  }
430 
431 
432  /// resets the filter
433  template < template < typename > class ALLOC >
434  INLINE void DBRowGeneratorSet< ALLOC >::reset() {
435  for (auto gen: generators__)
436  gen->reset();
438  performed = 0;
439  output_row__ = nullptr;
440  }
441 
442 
443  /// sets the columns of interest: the output DBRow needs only
444  /// contain values fot these columns
445  template < template < typename > class ALLOC >
447  const std::vector< std::size_t, ALLOC< std::size_t > >& cols_of_interest) {
448  // check that no output row generation is still active
449  if (output_row__ != nullptr)
451  "you cannot change the columns of interest while a "
452  "generation is still being processed");
453  for (auto gen: generators__)
455  }
456 
457 
458  /// sets the columns of interest: the output DBRow needs only
459  /// contain values fot these columns
460  template < template < typename > class ALLOC >
463  if (output_row__ != nullptr)
465  "you cannot change the columns of interest while a "
466  "generation is still being processed");
467  for (auto gen: generators__)
469  }
470 
471 
472  /// returns the current set of columns of interest
473  template < template < typename > class ALLOC >
474  INLINE const std::vector< std::size_t, ALLOC< std::size_t > >&
476  if (nb_generators__ == std::size_t(0)) {
478  "there are no generators yet in the generator set, so "
479  "there are no columns of interest");
480  }
481  return generators__[0]->columnsOfInterest();
482  }
483 
484 
485  /// returns the allocator used
486  template < template < typename > class ALLOC >
488  DBRowGeneratorSet< ALLOC >::getAllocator() const {
490  }
491 
492 
493  } /* namespace learning */
494 
495 } /* namespace gum */
496 
497 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:669
Database(const std::string &filename, const BayesNet< GUM_SCALAR > &bn, const std::vector< std::string > &missing_symbols)