aGrUM  0.16.0
DBRowGeneratorSet_tpl.h
Go to the documentation of this file.
1 
29 #ifndef DOXYGEN_SHOULD_SKIP_THIS
30 
31 namespace gum {
32 
33  namespace learning {
34 
35 
37  template < template < typename > class ALLOC >
39  const typename DBRowGeneratorSet< ALLOC >::allocator_type& alloc) :
40  __generators(alloc),
41  __setInputRow_performed(alloc) {
42  GUM_CONSTRUCTOR(DBRowGeneratorSet);
43  }
44 
45 
47  template < template < typename > class ALLOC >
49  const DBRowGeneratorSet< ALLOC >& from,
50  const typename DBRowGeneratorSet< ALLOC >::allocator_type& alloc) :
51  __generators(from.__nb_generators, nullptr, alloc),
52  __nb_generators(from.__nb_generators),
53  __setInputRow_performed(from.__nb_generators, 0, alloc) {
54  // create the generators
55  for (std::size_t i = std::size_t(0); i < __nb_generators; ++i)
56  __generators[i] = from.__generators[i]->clone(alloc);
57 
58  GUM_CONS_CPY(DBRowGeneratorSet);
59  }
60 
61 
63  template < template < typename > class ALLOC >
65  const DBRowGeneratorSet< ALLOC >& from) :
66  DBRowGeneratorSet< ALLOC >(from, from.getAllocator()) {}
67 
68 
70  template < template < typename > class ALLOC >
72  DBRowGeneratorSet< ALLOC >&& from,
73  const typename DBRowGeneratorSet< ALLOC >::allocator_type& alloc) :
74  __generators(std::move(from.__generators), alloc),
75  __nb_generators(from.__nb_generators), __output_row(from.__output_row),
76  __setInputRow_performed(std::move(from.__setInputRow_performed), alloc) {
77  GUM_CONS_MOV(DBRowGeneratorSet);
78  }
79 
80 
82  template < template < typename > class ALLOC >
84  DBRowGeneratorSet< ALLOC >&& from) :
85  DBRowGeneratorSet< ALLOC >(std::move(from), from.getAllocator()) {}
86 
88  template < template < typename > class ALLOC >
89  DBRowGeneratorSet< ALLOC >* DBRowGeneratorSet< ALLOC >::clone(
90  const typename DBRowGeneratorSet< ALLOC >::allocator_type& alloc) const {
91  ALLOC< DBRowGeneratorSet< ALLOC > > allocator(alloc);
92  DBRowGeneratorSet< ALLOC >* generators = allocator.allocate(1);
93  try {
94  allocator.construct(generators, *this, alloc);
95  } catch (...) {
96  allocator.deallocate(generators, 1);
97  throw;
98  }
99  return generators;
100  }
101 
102 
104  template < template < typename > class ALLOC >
105  INLINE DBRowGeneratorSet< ALLOC >* DBRowGeneratorSet< ALLOC >::clone() const {
106  return clone(this->getAllocator());
107  }
108 
109 
111  template < template < typename > class ALLOC >
113  // delete all the generators
114  ALLOC< DBRowGenerator< ALLOC > > allocator(this->getAllocator());
115  for (auto gen : __generators) {
116  allocator.destroy(gen);
117  allocator.deallocate(gen, 1);
118  }
119 
120  // clear all the internal fields
121  __generators.clear();
122  __nb_generators = std::size_t(0);
123  __output_row = nullptr;
124  __setInputRow_performed.clear();
125  }
126 
127 
129  template < template < typename > class ALLOC >
131  GUM_DESTRUCTOR(DBRowGeneratorSet);
132  clear();
133  }
134 
135 
137  template < template < typename > class ALLOC >
138  DBRowGeneratorSet< ALLOC >& DBRowGeneratorSet< ALLOC >::
139  operator=(const DBRowGeneratorSet< ALLOC >& from) {
140  if (this != &from) {
141  // produce the new generators
142  ALLOC< DBRowGenerator< ALLOC > > allocator(this->getAllocator());
143  std::vector< DBRowGenerator< ALLOC >*, ALLOC< DBRowGenerator< ALLOC >* > >
144  new_generators(from.__nb_generators, nullptr, allocator);
145  for (std::size_t i = std::size_t(0); i < from.__nb_generators; ++i) {
146  try {
147  new_generators[i] = from.__generators[i]->clone(allocator);
148  } catch (...) {
149  for (std::size_t j = std::size_t(0); j < i; ++j) {
150  allocator.destroy(new_generators[j]);
151  allocator.deallocate(new_generators[j], 1);
152  }
153  throw;
154  }
155  }
156 
157  // create the setInputDBrow_performed vector
158  std::vector< int, ALLOC< int > > setInputDBrow_performed(
159  from.__nb_generators, 0, getAllocator());
160 
161  // remove the old generators and copy the new ones
162  clear();
163  __generators = std::move(new_generators);
164  __nb_generators = from.__nb_generators;
165  __output_row = nullptr;
166  __setInputRow_performed = std::move(setInputDBrow_performed);
167  }
168 
169  return *this;
170  }
171 
172 
174  template < template < typename > class ALLOC >
175  DBRowGeneratorSet< ALLOC >& DBRowGeneratorSet< ALLOC >::
176  operator=(DBRowGeneratorSet< ALLOC >&& from) {
177  if (this != &from) {
178  // remove the old generators and move the new ones
179  clear();
180  __generators = std::move(from.__generators);
181  __nb_generators = from.__nb_generators;
182  __output_row = from.__output_row;
183  __setInputRow_performed = std::move(from.__setInputRow_performed);
184  }
185  return *this;
186  }
187 
188 
190  template < template < typename > class ALLOC >
191  INLINE DBRowGenerator< ALLOC >& DBRowGeneratorSet< ALLOC >::
192  operator[](const std::size_t i) {
193  return *(__generators[i]);
194  }
195 
196 
198  template < template < typename > class ALLOC >
199  INLINE const DBRowGenerator< ALLOC >& DBRowGeneratorSet< ALLOC >::
200  operator[](const std::size_t i) const {
201  return *(__generators[i]);
202  }
203 
204 
206  template < template < typename > class ALLOC >
207  template < template < template < typename > class > class Generator >
208  void DBRowGeneratorSet< ALLOC >::insertGenerator(
209  const Generator< ALLOC >& generator) {
210  // check that no output row generation is still active
211  if (__output_row != nullptr)
212  GUM_ERROR(OperationNotAllowed,
213  "you cannot insert a new generator while a generation is "
214  "still being processed");
215 
216  ALLOC< DBRowGenerator< ALLOC > > allocator(this->getAllocator());
217  __generators.push_back(generator.clone(allocator));
218 
219  try {
220  __setInputRow_performed.push_back(0);
221  } catch (...) {
222  allocator.destroy(__generators.back());
223  allocator.deallocate(__generators.back(), 1);
224  throw;
225  }
226 
227  ++__nb_generators;
228  __output_row = nullptr;
229  }
230 
231 
233  template < template < typename > class ALLOC >
234  template < template < template < typename > class > class Generator >
235  void DBRowGeneratorSet< ALLOC >::insertGenerator(
236  const Generator< ALLOC >& generator, const std::size_t i) {
237  // check that no output row generation is still active
238  if (__output_row != nullptr)
239  GUM_ERROR(OperationNotAllowed,
240  "you cannot insert a new generator while a generation is "
241  "still being processed");
242 
243  ALLOC< DBRowGenerator< ALLOC > > allocator(this->getAllocator());
244  __generators.insert(__generators.begin() + i, generator.clone(allocator));
245 
246  try {
247  __setInputRow_performed.push_back(0);
248  } catch (...) {
249  allocator.destroy(*(__generators.begin() + i));
250  allocator.deallocate(*(__generators.begin() + i));
251  throw;
252  }
253 
254  ++__nb_generators;
255  __output_row = nullptr;
256  }
257 
258 
260  template < template < typename > class ALLOC >
261  INLINE std::size_t DBRowGeneratorSet< ALLOC >::nbGenerators() const noexcept {
262  return __nb_generators;
263  }
264 
265 
267  template < template < typename > class ALLOC >
268  template < typename GUM_SCALAR >
270  const BayesNet< GUM_SCALAR >& new_bn) {
271  HashTable< DBRowGeneratorWithBN< GUM_SCALAR, ALLOC >*,
272  const BayesNet< GUM_SCALAR >* >
273  old_bns;
274 
275  for (auto xgen : __generators) {
276  // check if the generator relies on a Bayes net
277  DBRowGeneratorWithBN< GUM_SCALAR, ALLOC >* gen = nullptr;
278  try {
279  gen = dynamic_cast< DBRowGeneratorWithBN< GUM_SCALAR, ALLOC >* >(xgen);
280  } catch (std::bad_cast&) {}
281 
282  if (gen != nullptr) {
283  // try to assign the new BN to the generator
284  try {
285  const BayesNet< GUM_SCALAR >* bn = &(gen->getBayesNet());
286  old_bns.insert(gen, bn);
287  gen->setBayesNet(new_bn);
288  } catch (...) {
289  // if we could not assign the new BN to the generator, then
290  // make all the generators that were successfully assigned this
291  // BN revert to the old BN they had
292  for (auto& generator : old_bns) {
293  generator.first->setBayesNet(*(generator.second));
294  }
295  throw;
296  }
297  }
298  }
299  }
300 
301 
303  template < template < typename > class ALLOC >
304  INLINE std::size_t DBRowGeneratorSet< ALLOC >::size() const noexcept {
305  return __nb_generators;
306  }
307 
308 
310  template < template < typename > class ALLOC >
312  return __output_row != nullptr;
313  }
314 
315 
316  // try to produce a new row
317  template < template < typename > class ALLOC >
318  bool DBRowGeneratorSet< ALLOC >::__produceNextRow(
319  const DBRow< DBTranslatedValue, ALLOC >* input_row, std::size_t i) {
320  // the generation of output rows can be viewed as the traversal of a
321  // tree: each node of the tree correspond to the input row received by
322  // a generator. So the root node is the row passed in argument to
323  // the setInputDBrow() Method. From these input rows, generators produce
324  // through their generate() method new output rows, which correspond to
325  // the input rows of the next level of the tree. If we traverse this tree
326  // in terms of generators rather than in terms of input rows, we should
327  // call once Method setInputDBrow() in order to update the generators
328  // data structures, and then, to call method generate() to create new
329  // output rows. When some generators are unable to produce output rows,
330  // we just need to backtrack in the tree
331 
332  // for the ith generator, we set the new input DBRow passed in
333  // argument of setInputDBRow. We ask it to generate a new output row.
334  // If this can be done, the new output row is passed as a new input DBRow
335  // for the next generator, and so on. If a generator cannot produce any
336  // output row, we ask its predecessors to generate new rows (backtrack),
337  // until all the generators have been able to generate at least one output
338  // row (or no output row can be produced from input_row).
339  const DBRow< DBTranslatedValue, ALLOC >* row = input_row;
340  while (i != __nb_generators) {
341  auto generator = __generators[i];
342 
343  // if we did not pass any row yet to the ith generator, do it
344  // else use method generate() to generate a new output row
345  if (__setInputRow_performed[i] == 0) {
346  // pass the current row
347  const bool has_rows = generator->setInputRow(*row);
348 
349  // if the generator could not create output rows, try to backtrack
350  if (!has_rows) {
351  if (i > std::size_t(0)) {
352  --i;
353  continue;
354  } else {
355  // here we were unable to generate output rows
356  __output_row = nullptr;
357  return false;
358  }
359  } else {
360  // here, the generator is able to generate output rows
361  // so, generate the first one
362  row = &(generator->generate());
363  __setInputRow_performed[i] = 1;
364 
365  // pass to the next generator
366  ++i;
367  }
368  } else {
369  // here, the generator has already performed its setInputDBRow call
370  // so we should ask it to generate a new row. If it cannot produce
371  // any more row, try to backtrack
372  if (generator->hasRows()) {
373  // get the new row
374  row = &(generator->generate());
375 
376  // pass to the next generator
377  ++i;
378  } else {
379  // indicate that the next time we use this generator, we will have
380  // to use method setInputDBRow and backtrack
381  __setInputRow_performed[i] = 0;
382  if (i > std::size_t(0)) {
383  --i;
384  continue;
385  } else {
386  // here we were unable to generate output rows
387  __output_row = nullptr;
388  return false;
389  }
390  }
391  }
392  }
393 
394  // here row contains a row generated on a leaf of the row generation tree
395  // we should keep it when the user will ask for the next row to generate
396  __output_row = row;
397  return true;
398  }
399 
400 
402  template < template < typename > class ALLOC >
404  const DBRow< DBTranslatedValue, ALLOC >& input_row) {
405  // reset all the generators: ask them to use method setInputDBRow
406  if (hasRows())
407  for (auto& performed : __setInputRow_performed)
408  performed = 0;
409 
410  // now, parse the row generation tree
411  return __produceNextRow(&input_row, std::size_t(0));
412  }
413 
414 
416  template < template < typename > class ALLOC >
417  INLINE const DBRow< DBTranslatedValue, ALLOC >&
419  // get the row that we should return
420  const auto row = __output_row;
421 
422  // we should ask the last generator to produce the next output row
423  __produceNextRow(__output_row, __nb_generators - 1);
424 
425  return *row;
426  }
427 
428 
430  template < template < typename > class ALLOC >
431  INLINE void DBRowGeneratorSet< ALLOC >::reset() {
432  for (auto gen : __generators)
433  gen->reset();
434  for (auto& performed : __setInputRow_performed)
435  performed = 0;
436  __output_row = nullptr;
437  }
438 
439 
442  template < template < typename > class ALLOC >
444  const std::vector< std::size_t, ALLOC< std::size_t > >& cols_of_interest) {
445  // check that no output row generation is still active
446  if (__output_row != nullptr)
447  GUM_ERROR(OperationNotAllowed,
448  "you cannot change the columns of interest while a "
449  "generation is still being processed");
450  for (auto gen : __generators)
451  gen->setColumnsOfInterest(cols_of_interest);
452  }
453 
454 
457  template < template < typename > class ALLOC >
459  std::vector< std::size_t, ALLOC< std::size_t > >&& cols_of_interest) {
460  if (__output_row != nullptr)
461  GUM_ERROR(OperationNotAllowed,
462  "you cannot change the columns of interest while a "
463  "generation is still being processed");
464  for (auto gen : __generators)
465  gen->setColumnsOfInterest(cols_of_interest);
466  }
467 
468 
470  template < template < typename > class ALLOC >
471  INLINE const std::vector< std::size_t, ALLOC< std::size_t > >&
473  if (__nb_generators == std::size_t(0)) {
474  GUM_ERROR(UndefinedElement,
475  "there are no generators yet in the generator set, so "
476  "there are no columns of interest");
477  }
478  return __generators[0]->columnsOfInterest();
479  }
480 
481 
483  template < template < typename > class ALLOC >
486  return allocator_type(__generators.get_allocator());
487  }
488 
489 
490  } /* namespace learning */
491 
492 } /* namespace gum */
493 
494 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
allocator_type getAllocator() const
returns the allocator used
std::size_t size() const noexcept
returns the number of generators (alias for nbGenerators)
DBRowGeneratorSet(const allocator_type &alloc=allocator_type())
default constructor
STL namespace.
void clear()
removes all the generators
ALLOC< DBTranslatedValue > allocator_type
type for the allocators passed in arguments of methods
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
Definition: agrum.h:25
void setBayesNet(const BayesNet< GUM_SCALAR > &new_bn)
assign a new Bayes net to all the generators that depend on a BN
void setColumnsOfInterest(const std::vector< std::size_t, ALLOC< std::size_t > > &cols_of_interest)
sets the columns of interest: the output DBRow needs only contain correct values fot these columns ...
DBRowGeneratorSet< ALLOC > & operator=(const DBRowGeneratorSet< ALLOC > &from)
copy operator
const std::vector< std::size_t, ALLOC< std::size_t > > & columnsOfInterest() const
returns the current set of columns of interest
virtual DBRowGeneratorSet< ALLOC > * clone() const
virtual copy constructor
void reset()
resets all the generators
void insertGenerator(const Generator< ALLOC > &generator)
inserts a new generator at the end of the set
virtual ~DBRowGeneratorSet()
destructor
std::size_t nbGenerators() const noexcept
returns the number of generators
DBRowGenerator< ALLOC > & operator[](const std::size_t i)
returns the ith generator
const DBRow< DBTranslatedValue, ALLOC > & generate()
generates a new output row from the input row
bool setInputRow(const DBRow< DBTranslatedValue, ALLOC > &input_row)
sets the input row from which the generators will create new rows
#define GUM_ERROR(type, msg)
Definition: exceptions.h:55
bool hasRows()
returns true if there are still rows that can be output by the set of generators