aGrUM  0.14.2
DBRowGeneratorSet_tpl.h
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005 by Christophe GONZALES and Pierre-Henri WUILLEMIN *
3  * {prenom.nom}_at_lip6.fr *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19  ***************************************************************************/
26 #ifndef DOXYGEN_SHOULD_SKIP_THIS
27 
28 namespace gum {
29 
30  namespace learning {
31 
32 
34  template < template < typename > class ALLOC >
36  const typename DBRowGeneratorSet< ALLOC >::allocator_type& alloc) :
37  __generators(alloc),
38  __setInputRow_performed(alloc) {
39  GUM_CONSTRUCTOR(DBRowGeneratorSet);
40  }
41 
42 
44  template < template < typename > class ALLOC >
46  const DBRowGeneratorSet< ALLOC >& from,
47  const typename DBRowGeneratorSet< ALLOC >::allocator_type& alloc) :
48  __generators(from.__nb_generators, nullptr, alloc),
49  __nb_generators(from.__nb_generators),
50  __setInputRow_performed(from.__nb_generators, 0, alloc) {
51  // create the generators
52  for (std::size_t i = std::size_t(0); i < __nb_generators; ++i)
53  __generators[i] = from.__generators[i]->clone(alloc);
54 
55  GUM_CONS_CPY(DBRowGeneratorSet);
56  }
57 
58 
60  template < template < typename > class ALLOC >
62  const DBRowGeneratorSet< ALLOC >& from) :
63  DBRowGeneratorSet< ALLOC >(from, from.getAllocator()) {}
64 
65 
67  template < template < typename > class ALLOC >
69  DBRowGeneratorSet< ALLOC >&& from,
70  const typename DBRowGeneratorSet< ALLOC >::allocator_type& alloc) :
71  __generators(std::move(from.__generators), alloc),
72  __nb_generators(from.__nb_generators), __output_row(from.__output_row),
73  __setInputRow_performed(std::move(from.__setInputRow_performed), alloc) {
74  GUM_CONS_MOV(DBRowGeneratorSet);
75  }
76 
77 
79  template < template < typename > class ALLOC >
81  DBRowGeneratorSet< ALLOC >&& from) :
82  DBRowGeneratorSet< ALLOC >(std::move(from), from.getAllocator()) {}
83 
85  template < template < typename > class ALLOC >
86  DBRowGeneratorSet< ALLOC >* DBRowGeneratorSet< ALLOC >::clone(
87  const typename DBRowGeneratorSet< ALLOC >::allocator_type& alloc) const {
88  ALLOC< DBRowGeneratorSet< ALLOC > > allocator(alloc);
89  DBRowGeneratorSet< ALLOC >* generators = allocator.allocate(1);
90  try {
91  allocator.construct(generators, *this, alloc);
92  } catch (...) {
93  allocator.deallocate(generators, 1);
94  throw;
95  }
96  return generators;
97  }
98 
99 
101  template < template < typename > class ALLOC >
102  INLINE DBRowGeneratorSet< ALLOC >* DBRowGeneratorSet< ALLOC >::clone() const {
103  return clone(this->getAllocator());
104  }
105 
106 
108  template < template < typename > class ALLOC >
110  // delete all the generators
111  ALLOC< DBRowGenerator< ALLOC > > allocator(this->getAllocator());
112  for (auto gen : __generators) {
113  allocator.destroy(gen);
114  allocator.deallocate(gen, 1);
115  }
116 
117  // clear all the internal fields
118  __generators.clear();
119  __nb_generators = std::size_t(0);
120  __output_row = nullptr;
121  __setInputRow_performed.clear();
122  }
123 
124 
126  template < template < typename > class ALLOC >
128  GUM_DESTRUCTOR(DBRowGeneratorSet);
129  clear();
130  }
131 
132 
134  template < template < typename > class ALLOC >
135  DBRowGeneratorSet< ALLOC >& DBRowGeneratorSet< ALLOC >::
136  operator=(const DBRowGeneratorSet< ALLOC >& from) {
137  if (this != &from) {
138  // produce the new generators
139  ALLOC< DBRowGenerator< ALLOC > > allocator(this->getAllocator());
140  std::vector< DBRowGenerator< ALLOC >*, ALLOC< DBRowGenerator< ALLOC >* > >
141  new_generators(from.__nb_generators, nullptr, allocator);
142  for (std::size_t i = std::size_t(0); i < from.__nb_generators; ++i) {
143  try {
144  new_generators[i] = from.__generators[i]->clone(allocator);
145  } catch (...) {
146  for (std::size_t j = std::size_t(0); j < i; ++j) {
147  allocator.destroy(new_generators[j]);
148  allocator.deallocate(new_generators[j], 1);
149  }
150  throw;
151  }
152  }
153 
154  // create the setInputDBrow_performed vector
155  std::vector< int, ALLOC< int > > setInputDBrow_performed(
156  from.__nb_generators, 0, getAllocator());
157 
158  // remove the old generators and copy the new ones
159  clear();
160  __generators = std::move(new_generators);
161  __nb_generators = from.__nb_generators;
162  __output_row = nullptr;
163  __setInputRow_performed = std::move(setInputDBrow_performed);
164  }
165 
166  return *this;
167  }
168 
169 
171  template < template < typename > class ALLOC >
172  DBRowGeneratorSet< ALLOC >& DBRowGeneratorSet< ALLOC >::
173  operator=(DBRowGeneratorSet< ALLOC >&& from) {
174  if (this != &from) {
175  // remove the old generators and move the new ones
176  clear();
177  __generators = std::move(from.__generators);
178  __nb_generators = from.__nb_generators;
179  __output_row = from.__output_row;
180  __setInputRow_performed = std::move(from.__setInputRow_performed);
181  }
182  return *this;
183  }
184 
185 
187  template < template < typename > class ALLOC >
188  INLINE DBRowGenerator< ALLOC >& DBRowGeneratorSet< ALLOC >::
189  operator[](const std::size_t i) {
190  return *(__generators[i]);
191  }
192 
193 
195  template < template < typename > class ALLOC >
196  INLINE const DBRowGenerator< ALLOC >& DBRowGeneratorSet< ALLOC >::
197  operator[](const std::size_t i) const {
198  return *(__generators[i]);
199  }
200 
201 
203  template < template < typename > class ALLOC >
204  template < template < template < typename > class > class Generator >
205  void DBRowGeneratorSet< ALLOC >::insertGenerator(
206  const Generator< ALLOC >& generator) {
207  // check that no output row generation is still active
208  if (__output_row != nullptr)
209  GUM_ERROR(OperationNotAllowed,
210  "you cannot insert a new generator while a generation is "
211  "still being processed");
212 
213  ALLOC< DBRowGenerator< ALLOC > > allocator(this->getAllocator());
214  __generators.push_back(generator.clone(allocator));
215 
216  try {
217  __setInputRow_performed.push_back(0);
218  } catch (...) {
219  allocator.destroy(__generators.back());
220  allocator.deallocate(__generators.back(), 1);
221  throw;
222  }
223 
224  ++__nb_generators;
225  __output_row = nullptr;
226  }
227 
228 
230  template < template < typename > class ALLOC >
231  template < template < template < typename > class > class Generator >
232  void DBRowGeneratorSet< ALLOC >::insertGenerator(
233  const Generator< ALLOC >& generator, const std::size_t i) {
234  // check that no output row generation is still active
235  if (__output_row != nullptr)
236  GUM_ERROR(OperationNotAllowed,
237  "you cannot insert a new generator while a generation is "
238  "still being processed");
239 
240  ALLOC< DBRowGenerator< ALLOC > > allocator(this->getAllocator());
241  __generators.insert(__generators.begin() + i, generator.clone(allocator));
242 
243  try {
244  __setInputRow_performed.push_back(0);
245  } catch (...) {
246  allocator.destroy(*(__generators.begin() + i));
247  allocator.deallocate(*(__generators.begin() + i));
248  throw;
249  }
250 
251  ++__nb_generators;
252  __output_row = nullptr;
253  }
254 
255 
257  template < template < typename > class ALLOC >
258  INLINE std::size_t DBRowGeneratorSet< ALLOC >::nbGenerators() const noexcept {
259  return __nb_generators;
260  }
261 
262 
264  template < template < typename > class ALLOC >
265  template < typename GUM_SCALAR >
267  const BayesNet< GUM_SCALAR >& new_bn) {
268  HashTable< DBRowGeneratorWithBN< GUM_SCALAR, ALLOC >*,
269  const BayesNet< GUM_SCALAR >* >
270  old_bns;
271 
272  for (auto xgen : __generators) {
273  // check if the generator relies on a Bayes net
274  DBRowGeneratorWithBN< GUM_SCALAR, ALLOC >* gen = nullptr;
275  try {
276  gen = dynamic_cast< DBRowGeneratorWithBN< GUM_SCALAR, ALLOC >* >(xgen);
277  } catch (std::bad_cast&) {}
278 
279  if (gen != nullptr) {
280  // try to assign the new BN to the generator
281  try {
282  const BayesNet< GUM_SCALAR >* bn = &(gen->getBayesNet());
283  old_bns.insert(gen, bn);
284  gen->setBayesNet(new_bn);
285  } catch (...) {
286  // if we could not assign the new BN to the generator, then
287  // make all the generators that were successfully assigned this
288  // BN revert to the old BN they had
289  for (auto& generator : old_bns) {
290  generator.first->setBayesNet(*(generator.second));
291  }
292  throw;
293  }
294  }
295  }
296  }
297 
298 
300  template < template < typename > class ALLOC >
301  INLINE std::size_t DBRowGeneratorSet< ALLOC >::size() const noexcept {
302  return __nb_generators;
303  }
304 
305 
307  template < template < typename > class ALLOC >
309  return __output_row != nullptr;
310  }
311 
312 
313  // try to produce a new row
314  template < template < typename > class ALLOC >
315  bool DBRowGeneratorSet< ALLOC >::__produceNextRow(
316  const DBRow< DBTranslatedValue, ALLOC >* input_row, std::size_t i) {
317  // the generation of output rows can be viewed as the traversal of a
318  // tree: each node of the tree correspond to the input row received by
319  // a generator. So the root node is the row passed in argument to
320  // the setInputDBrow() Method. From these input rows, generators produce
321  // through their generate() method new output rows, which correspond to
322  // the input rows of the next level of the tree. If we traverse this tree
323  // in terms of generators rather than in terms of input rows, we should
324  // call once Method setInputDBrow() in order to update the generators
325  // data structures, and then, to call method generate() to create new
326  // output rows. When some generators are unable to produce output rows,
327  // we just need to backtrack in the tree
328 
329  // for the ith generator, we set the new input DBRow passed in
330  // argument of setInputDBRow. We ask it to generate a new output row.
331  // If this can be done, the new output row is passed as a new input DBRow
332  // for the next generator, and so on. If a generator cannot produce any
333  // output row, we ask its predecessors to generate new rows (backtrack),
334  // until all the generators have been able to generate at least one output
335  // row (or no output row can be produced from input_row).
336  const DBRow< DBTranslatedValue, ALLOC >* row = input_row;
337  while (i != __nb_generators) {
338  auto generator = __generators[i];
339 
340  // if we did not pass any row yet to the ith generator, do it
341  // else use method generate() to generate a new output row
342  if (__setInputRow_performed[i] == 0) {
343  // pass the current row
344  const bool has_rows = generator->setInputRow(*row);
345 
346  // if the generator could not create output rows, try to backtrack
347  if (!has_rows) {
348  if (i > std::size_t(0)) {
349  --i;
350  continue;
351  } else {
352  // here we were unable to generate output rows
353  __output_row = nullptr;
354  return false;
355  }
356  } else {
357  // here, the generator is able to generate output rows
358  // so, generate the first one
359  row = &(generator->generate());
360  __setInputRow_performed[i] = 1;
361 
362  // pass to the next generator
363  ++i;
364  }
365  } else {
366  // here, the generator has already performed its setInputDBRow call
367  // so we should ask it to generate a new row. If it cannot produce
368  // any more row, try to backtrack
369  if (generator->hasRows()) {
370  // get the new row
371  row = &(generator->generate());
372 
373  // pass to the next generator
374  ++i;
375  } else {
376  // indicate that the next time we use this generator, we will have
377  // to use method setInputDBRow and backtrack
378  __setInputRow_performed[i] = 0;
379  if (i > std::size_t(0)) {
380  --i;
381  continue;
382  } else {
383  // here we were unable to generate output rows
384  __output_row = nullptr;
385  return false;
386  }
387  }
388  }
389  }
390 
391  // here row contains a row generated on a leaf of the row generation tree
392  // we should keep it when the user will ask for the next row to generate
393  __output_row = row;
394  return true;
395  }
396 
397 
399  template < template < typename > class ALLOC >
401  const DBRow< DBTranslatedValue, ALLOC >& input_row) {
402  // reset all the generators: ask them to use method setInputDBRow
403  if (hasRows())
404  for (auto& performed : __setInputRow_performed)
405  performed = 0;
406 
407  // now, parse the row generation tree
408  return __produceNextRow(&input_row, std::size_t(0));
409  }
410 
411 
413  template < template < typename > class ALLOC >
414  INLINE const DBRow< DBTranslatedValue, ALLOC >&
416  // get the row that we should return
417  const auto row = __output_row;
418 
419  // we should ask the last generator to produce the next output row
420  __produceNextRow(__output_row, __nb_generators - 1);
421 
422  return *row;
423  }
424 
425 
427  template < template < typename > class ALLOC >
428  INLINE void DBRowGeneratorSet< ALLOC >::reset() {
429  for (auto gen : __generators)
430  gen->reset();
431  for (auto& performed : __setInputRow_performed)
432  performed = 0;
433  __output_row = nullptr;
434  }
435 
436 
439  template < template < typename > class ALLOC >
441  const std::vector< std::size_t, ALLOC< std::size_t > >& cols_of_interest) {
442  // check that no output row generation is still active
443  if (__output_row != nullptr)
444  GUM_ERROR(OperationNotAllowed,
445  "you cannot change the columns of interest while a "
446  "generation is still being processed");
447  for (auto gen : __generators)
448  gen->setColumnsOfInterest(cols_of_interest);
449  }
450 
451 
454  template < template < typename > class ALLOC >
456  std::vector< std::size_t, ALLOC< std::size_t > >&& cols_of_interest) {
457  if (__output_row != nullptr)
458  GUM_ERROR(OperationNotAllowed,
459  "you cannot change the columns of interest while a "
460  "generation is still being processed");
461  for (auto gen : __generators)
462  gen->setColumnsOfInterest(cols_of_interest);
463  }
464 
465 
467  template < template < typename > class ALLOC >
468  INLINE const std::vector< std::size_t, ALLOC< std::size_t > >&
470  if (__nb_generators == std::size_t(0)) {
471  GUM_ERROR(UndefinedElement,
472  "there are no generators yet in the generator set, so "
473  "there are no columns of interest");
474  }
475  return __generators[0]->columnsOfInterest();
476  }
477 
478 
480  template < template < typename > class ALLOC >
483  return allocator_type(__generators.get_allocator());
484  }
485 
486 
487  } /* namespace learning */
488 
489 } /* namespace gum */
490 
491 #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
gum is the global namespace for all aGrUM entities
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:52
bool hasRows()
returns true if there are still rows that can be output by the set of generators