aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
databaseTable_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright (c) 2005-2021 by 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 implementation of tabular databases stored in memory (RAM)
24  *
25  * @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
26  */
27 #include <agrum/tools/database/databaseTable.h>
28 
29 #ifndef DOXYGEN_SHOULD_SKIP_THIS
30 
31 namespace gum {
32 
33  namespace learning {
34 
35 
36  // default constructor
37  template < template < typename > class ALLOC >
38  template < template < typename > class XALLOC >
39  DatabaseTable< ALLOC >::DatabaseTable(
40  const typename DatabaseTable< ALLOC >::template MissingValType< XALLOC >& missing_symbols,
41  const DBTranslatorSet< ALLOC >& translators,
42  const typename DatabaseTable< ALLOC >::allocator_type& alloc) :
43  IDatabaseTable< DBTranslatedValue, ALLOC >(
44  missing_symbols,
45  std::vector< std::string, ALLOC< std::string > >(),
46  alloc),
47  _translators_(translators, alloc) {
48  if (translators.size()) {
49  // set the variables names according to those of the translators
50  std::vector< std::string, ALLOC< std::string > > var_names(translators.size());
51  for (std::size_t i = std::size_t(0), size = translators.size(); i < size; ++i) {
52  var_names[i] = _translators_.translator(i).variable()->name();
53  }
54  setVariableNames(var_names, false);
55  }
56 
57  GUM_CONSTRUCTOR(DatabaseTable);
58  }
59 
60 
61  // default constructor
62  template < template < typename > class ALLOC >
65  const typename DatabaseTable< ALLOC >::allocator_type& alloc) :
67  std::vector< std::string, ALLOC< std::string > >(),
68  std::vector< std::string, ALLOC< std::string > >(),
69  alloc),
71  if (translators.size()) {
72  // set the variables names according to those of the translators
74  for (std::size_t i = std::size_t(0), size = translators.size(); i < size; ++i) {
76  }
78  }
79 
81  }
82 
83 
84  // copy constructor with a given allocator
85  template < template < typename > class ALLOC >
87  const DatabaseTable< ALLOC >& from,
88  const typename DatabaseTable< ALLOC >::allocator_type& alloc) :
92  }
93 
94 
95  // copy constructor
96  template < template < typename > class ALLOC >
99 
100 
101  // move constructor with a given allocator
102  template < template < typename > class ALLOC >
104  DatabaseTable< ALLOC >&& from,
105  const typename DatabaseTable< ALLOC >::allocator_type& alloc) :
110  }
111 
112 
113  // move constructor
114  template < template < typename > class ALLOC >
117 
118 
119  // virtual copy constructor with a given allocator
120  template < template < typename > class ALLOC >
122  const typename DatabaseTable< ALLOC >::allocator_type& alloc) const {
125  try {
126  allocator.construct(new_db, *this, alloc);
127  } catch (...) {
129  throw;
130  }
131 
132  return new_db;
133  }
134 
135 
136  // virtual copy constructor
137  template < template < typename > class ALLOC >
138  DatabaseTable< ALLOC >* DatabaseTable< ALLOC >::clone() const {
139  return clone(this->getAllocator());
140  }
141 
142 
143  // destructor
144  template < template < typename > class ALLOC >
147  }
148 
149 
150  // copy operator
151  template < template < typename > class ALLOC >
153  if (this != &from) {
157  }
158 
159  return *this;
160  }
161 
162 
163  // move constructor
164  template < template < typename > class ALLOC >
166  if (this != &from) {
170  }
171 
172  return *this;
173  }
174 
175 
176  // a method to process the rows of the database in multithreading
177  template < template < typename > class ALLOC >
178  template < typename Functor1, typename Functor2 >
180  // compute the number of threads to execute the code, the number N of
181  // rows that each thread should process and the number of rows that
182  // would remain after each thread has processed its N rows. For instance,
183  // if the database has 105 rows and there are 10 threads, each thread
184  // should process 10 rows and there would remain 5 rows
185  const std::size_t db_size = this->rows_.size();
187  if (nb_threads < 1)
188  nb_threads = 1;
189  else if (nb_threads > this->max_nb_threads_)
190  nb_threads = this->max_nb_threads_;
193 
194  // if there is just one thread, let it process all the rows
195  if (nb_threads == 1) {
196  exec_func(std::size_t(0), db_size);
197  return;
198  }
199 
200  // here, we shall create the threads, but also one std::exception_ptr
201  // for each thread. This will allow us to catch the exception raised
202  // by the threads
203  std::vector< std::thread > threads;
206 
207  // create a lambda that will execute exec_func while catching its exceptions
208  auto real_exec_func
209  = [&exec_func](std::size_t begin, std::size_t end, std::exception_ptr& exc) -> void {
210  try {
211  exec_func(begin, end);
212  } catch (...) { exc = std::current_exception(); }
213  };
214 
215  // launch the threads
217  for (std::size_t i = std::size_t(0); i < nb_threads; ++i) {
219  if (rest_rows != std::size_t(0)) {
220  ++end_index;
221  --rest_rows;
222  }
224  begin_index,
225  end_index,
226  std::ref(func_exceptions[i])));
228  }
229 
230  // wait for the threads to complete their executions
232 
233  // now, check if one exception has been raised
234  bool exception_raised = false;
235  for (const auto& exc: func_exceptions) {
236  if (exc != nullptr) {
237  exception_raised = true;
238  break;
239  }
240  }
241 
242  if (exception_raised) {
243  // create a lambda that will execute undo_func while catching
244  // its exceptions
245  auto real_undo_func
246  = [&undo_func](std::size_t begin, std::size_t end, std::exception_ptr& exc) -> void {
247  try {
248  undo_func(begin, end);
249  } catch (...) { exc = std::current_exception(); }
250  };
251 
252  // launch the repair threads
253  threads.clear();
254  begin_index = std::size_t(0);
256  for (std::size_t i = std::size_t(0); i < nb_threads; ++i) {
258  if (rest_rows != std::size_t(0)) {
259  ++end_index;
260  --rest_rows;
261  }
262  // we just need to repair the threads that did not raise exceptions
263  if (func_exceptions[i] == nullptr)
265  begin_index,
266  end_index,
269  }
270 
271  // wait for the threads to complete their executions
273 
274  // rethrow the exception
275  for (const auto& exc: func_exceptions) {
276  if (exc != nullptr) { std::rethrow_exception(exc); }
277  }
278  }
279  }
280 
281 
282  /// insert a new translator into the database
283  template < template < typename > class ALLOC >
285  const std::size_t input_column,
286  const bool unique_column) {
287  // check that there is no ignored_column corresponding to column
290  "Column " << input_column << " is marked as being ignored. "
291  << "So it is forbidden to create a translator for that column.")
292 
293  // reserve some place for the new column in the records of the database
294  const std::size_t new_size = this->nbVariables() + 1;
295 
296  // create the lambda for reserving some memory for the new column
297  // and the one that undoes what it performed if some thread executing
298  // it raised an exception
299  auto reserve_lambda = [this, new_size](std::size_t begin, std::size_t end) -> void {
300  for (std::size_t i = begin; i < end; ++i)
301  this->rows_[i].row().reserve(new_size);
302  };
303 
304  auto undo_reserve_lambda = [](std::size_t begin, std::size_t end) -> void {
305  };
306 
307  // launch the threads executing the lambdas
309 
310  // insert the translator into the translator set
311  const std::size_t pos
313 
314  // insert the name of the translator's variable to the set of variable names
315  try {
317  } catch (...) {
319  throw;
320  }
321 
322  // if the databaseTable is not empty, fill the column of the database
323  // corresponding to the translator with missing values
326 
327  // create the lambda for adding a new column filled wih a missing value
328  auto fill_lambda = [this, missing](std::size_t begin, std::size_t end) -> void {
329  std::size_t i = begin;
330  try {
331  for (; i < end; ++i) {
332  this->rows_[i].row().push_back(missing);
334  }
335  } catch (...) {
336  for (std::size_t j = begin; j < i; ++j)
337  this->rows_[i].row().pop_back();
338  throw;
339  }
340  };
341 
342  auto undo_fill_lambda = [this](std::size_t begin, std::size_t end) -> void {
343  for (std::size_t i = begin; i < end; ++i)
344  this->rows_[i].row().pop_back();
345  };
346 
347  // launch the threads executing the lambdas
349  }
350 
351  return pos;
352  }
353 
354 
355  /// insert a new translator into the database
356  template < template < typename > class ALLOC >
358  const std::size_t input_column,
359  const bool unique_column) {
360  // check that there is no ignored_column corresponding to column
363  "Column " << input_column << " is marked as being ignored. "
364  << "So it is forbidden to create a translator for that column.")
365 
366  // if the databaseTable is not empty, we should fill the column of the
367  // database corresponding to the new translator with missing values. But, the
368  // current method assumes that the list of missing values is empty. Hence, it
369  // should raise an exception
372  "inserting a new translator into a database creates a new column "
373  << "with missing values. However, you did not define any symbol for "
374  << "such values.")
375  }
376 
377  // reserve some place for the new column in the records of the database
378  const std::size_t new_size = this->nbVariables() + 1;
379 
380  // create the lambda for reserving some memory for the new column
381  // and the one that undoes what it performed if some thread executing
382  // it raised an exception
383  auto reserve_lambda = [this, new_size](std::size_t begin, std::size_t end) -> void {
384  for (std::size_t i = begin; i < end; ++i)
385  this->rows_[i].row().reserve(new_size);
386  };
387 
388  auto undo_reserve_lambda = [](std::size_t begin, std::size_t end) -> void {
389  };
390 
391  // launch the threads executing the lambdas
393 
394  // insert the translator into the translator set
396 
397  // insert the name of the translator's variable to the set of variable names
398  try {
400  } catch (...) {
402  throw;
403  }
404 
405  return pos;
406  }
407 
408 
409  /// insert a new translator into the database
410  template < template < typename > class ALLOC >
411  template < template < typename > class XALLOC >
413  const Variable& var,
414  const std::size_t input_column,
416  const bool unique_column) {
417  // check that there is no ignored_column corresponding to column
420  "Column " << input_column << " is marked as being ignored. "
421  << "So it is forbidden to create a translator for that column.")
422 
423  // reserve some place for the new column in the records of the database
424  const std::size_t new_size = this->nbVariables() + 1;
425 
426  // create the lambda for reserving some memory for the new column
427  // and the one that undoes what it performed if some thread executing
428  // it raised an exception
429  auto reserve_lambda = [this, new_size](std::size_t begin, std::size_t end) -> void {
430  for (std::size_t i = begin; i < end; ++i)
431  this->rows_[i].row().reserve(new_size);
432  };
433 
434  auto undo_reserve_lambda = [](std::size_t begin, std::size_t end) -> void {
435  };
436 
437  // launch the threads executing the lambdas
439 
440  // insert the translator into the translator set
441  const std::size_t pos
443 
444  // insert the name of the translator's variable to the set of variable names
445  try {
447  } catch (...) {
449  throw;
450  }
451 
452  // if the databaseTable is not empty, fill the column of the database
453  // corresponding to the translator with missing values
456 
457  // create the lambda for adding a new column filled wih a missing value
458  auto fill_lambda = [this, missing](std::size_t begin, std::size_t end) -> void {
459  std::size_t i = begin;
460  try {
461  for (; i < end; ++i) {
462  this->rows_[i].row().push_back(missing);
464  }
465  } catch (...) {
466  for (std::size_t j = begin; j < i; ++j)
467  this->rows_[i].row().pop_back();
468  throw;
469  }
470  };
471 
472  auto undo_fill_lambda = [this](std::size_t begin, std::size_t end) -> void {
473  for (std::size_t i = begin; i < end; ++i)
474  this->rows_[i].row().pop_back();
475  };
476 
477  // launch the threads executing the lambdas
479  }
480 
481  return pos;
482  }
483 
484 
485  /** @brief returns the indices corresponding either to the kth translator
486  * or to all those that parse the kth column of the input dataset
487  *
488  * @warning the indices are sorted by deacreasing order */
489  template < template < typename > class ALLOC >
490  INLINE typename DatabaseTable< ALLOC >::template DBVector< std::size_t >
492  const bool k_is_input_col) const {
493  const std::size_t nb_trans = _translators_.size();
494  if (!k_is_input_col) {
495  if (k < nb_trans)
496  return DBVector< std::size_t >{k};
497  else
498  return DBVector< std::size_t >();
499  } else {
500  DBVector< std::size_t > trans;
501  for (std::size_t i = std::size_t(0), kk = nb_trans - 1; i < nb_trans; ++i, --kk) {
503  }
504  return trans;
505  }
506  }
507 
508 
509  // erases the kth translator or all those parsing the kth column of
510  // the input dataset
511  template < template < typename > class ALLOC >
512  void DatabaseTable< ALLOC >::eraseTranslators(const std::size_t k, const bool k_is_input_col) {
513  for (const auto kk: _getKthIndices_(k, k_is_input_col)) {
514  // erase the translator of index kk and the corresponding variable
515  // name. If there remains no more translator in the translator set,
516  // rows_ should become empty
517  this->variable_names_.erase(this->variable_names_.begin() + kk);
518  if (this->variable_names_.empty()) {
520  } else {
521  const std::size_t nb_trans = _translators_.size();
522 
523  auto erase_lambda = [this, nb_trans, kk](std::size_t begin, std::size_t end) -> void {
524  for (std::size_t i = begin; i < end; ++i) {
525  auto& row = this->rows_[i].row();
526  if (this->_translators_.isMissingValue(row[kk], kk)) {
527  bool has_missing_val = false;
528  for (std::size_t j = std::size_t(0); j < nb_trans; ++j) {
529  if ((j != kk) && this->_translators_.isMissingValue(row[j], j)) {
530  has_missing_val = true;
531  break;
532  }
533  }
535  }
536  row.erase(row.begin() + kk);
537  }
538  };
539 
540  auto undo_erase_lambda = [](std::size_t begin, std::size_t end) -> void {
541  };
542 
543  // launch the threads executing the lambdas
545  }
547  }
548  }
549 
550 
551  /// returns the set of translators
552  template < template < typename > class ALLOC >
554  return _translators_;
555  }
556 
557 
558  /** @brief returns the index corresponding either to the kth translator or
559  * to that of the first translator parsing the kth column of the
560  * input dataset */
561  template < template < typename > class ALLOC >
563  const bool k_is_input_col) const {
564  if (k_is_input_col) {
565  const std::size_t nb_trans = _translators_.size();
566  for (std::size_t i = std::size_t(0); i < nb_trans; ++i) {
567  if (_translators_.inputColumn(i) == k) { return i; }
568  }
569  return nb_trans + 1;
570  } else {
571  return k;
572  }
573  }
574 
575 
576  /// returns the kth translator of the database
577  template < template < typename > class ALLOC >
578  const DBTranslator< ALLOC >&
579  DatabaseTable< ALLOC >::translator(const std::size_t k, const bool k_is_input_col) const {
580  // find the position of the translator that we look for. This
581  // is variable kk below
582  const std::size_t nb_trans = _translators_.size();
584 
585  // check if the translator exists
586  if (nb_trans <= kk) {
587  if (k_is_input_col) {
589  "there is no translator in the database table that "
590  << "parses Column " << k)
591  } else {
593  "the database has " << nb_trans << " translators, so Translator #" << k
594  << " does not exist")
595  }
596  }
597 
598  return _translators_.translator(kk);
599  }
600 
601 
602  /// returns the kth variable of the database
603  template < template < typename > class ALLOC >
604  const Variable& DatabaseTable< ALLOC >::variable(const std::size_t k,
605  const bool k_is_input_col) const {
606  // find the position of the translator that contains the variable.
607  // This is variable kk below
608  const std::size_t nb_trans = _translators_.size();
610 
611  // check if the translator exists
612  if (nb_trans <= kk) {
613  if (k_is_input_col) {
615  "there is no variable in the database table that "
616  << "corresponds to Column " << k)
617  } else {
619  "the database has " << nb_trans << " variables, so Variable #" << k
620  << " does not exist")
621  }
622  }
623 
624  return _translators_.variable(kk);
625  }
626 
627 
628  /// sets the names of the variables
629  template < template < typename > class ALLOC >
631  const std::vector< std::string, ALLOC< std::string > >& names,
632  const bool from_external_object) {
633  const std::size_t size = names.size();
634  const std::size_t nb_trans = _translators_.size();
635  if (!from_external_object) {
636  if (nb_trans != size) {
638  "the number of variable's names (i.e., "
639  << size << ") does not correspond to the number of columns of the "
640  << "database table (i.e.," << nb_trans << ")")
641  }
642 
643  // update the translator names
644  for (std::size_t i = std::size_t(0); i < size; ++i) {
646  }
647  } else {
650  "the names vector has "
651  << size << " elements whereas it should have at least "
653  << "elements so that each translator is assigned a name")
654  }
655 
656  // update the translator names
657  for (std::size_t i = std::size_t(0); i < nb_trans; ++i) {
659  }
660  }
661 
662  // update variable_names_ using the newly assigned translators names
664  for (std::size_t i = std::size_t(0); i < nb_trans; ++i) {
666  }
667  }
668 
669 
670  /** @brief indicates that we should ignore the kth column of the original
671  * database when inserting new rows */
672  template < template < typename > class ALLOC >
673  void DatabaseTable< ALLOC >::ignoreColumn(const std::size_t k, const bool k_is_input_col) {
674  // indicate that the column will be forbidden. If the column is already
675  // forbidden, do nothing. But if the column is assigned to a translator
676  // that does not exist, raise an UndefinedElement exception
677  const std::size_t nb_trans = _translators_.size();
678  if (k_is_input_col) {
679  if (_ignored_cols_.exists(k)) return;
681  } else {
682  if (k < nb_trans) {
684  } else {
686  "It is impossible to ignore the column parsed by Translator #"
687  << k << "because there exist only " << nb_trans << " translators")
688  }
689  }
690 
691  // remove all the translators corresponding to k
693  }
694 
695 
696  /// returns the set of ignored columns
697  template < template < typename > class ALLOC >
698  const typename DatabaseTable< ALLOC >::template DBVector< std::size_t >
699  DatabaseTable< ALLOC >::ignoredColumns() const {
700  const std::size_t nb_trans = _translators_.size();
701 
702  if (nb_trans == std::size_t(0)) { return DBVector< std::size_t >{std::size_t(0)}; }
703 
704  // get the columns handled by the translators, sorted by increasing order
706  for (std::size_t i = std::size_t(0); i < nb_trans; ++i)
708  std::sort(cols.begin(), cols.end());
709 
710  // create a vector with all the possible input columns
714 
715  // remove from ignored_cols the elements of cols
716  for (std::size_t i = std::size_t(0), ii = highest - 1, k = std::size_t(0), kk = nb_trans - 1;
717  i < highest;
718  ++i, --ii) {
719  if (cols[kk] == ii) {
721  while ((k < nb_trans) && (cols[kk] == ii)) {
722  --kk;
723  ++k;
724  }
725  if (k == nb_trans) break;
726  }
727  }
728 
729  // add the column past the last translator
731 
732  return ignored_cols;
733  }
734 
735 
736  /// returns the set of columns parsed
737  template < template < typename > class ALLOC >
738  const typename DatabaseTable< ALLOC >::template DBVector< std::size_t >
739  DatabaseTable< ALLOC >::inputColumns() const {
740  const std::size_t nb_trans = _translators_.size();
741  if (nb_trans == std::size_t(0)) { return DBVector< std::size_t >(); }
742 
744  for (std::size_t i = std::size_t(0); i < nb_trans; ++i) {
746  }
747  return input_cols;
748  }
749 
750 
751  /// returns the domain size of the kth variable
752  template < template < typename > class ALLOC >
754  const bool k_is_input_col) const {
755  // find the position kk of the translator that contains the variable
756  const std::size_t nb_trans = _translators_.size();
758 
759  // check if the translator exists
760  if (nb_trans <= kk) {
761  if (k_is_input_col) {
763  "there is no variable in the database table that "
764  << "corresponds to Column " << k)
765  } else {
767  "the database has " << nb_trans << " variables, so Variable #" << k
768  << " does not exist")
769  }
770  }
771 
772  return _translators_.domainSize(kk);
773  }
774 
775 
776  /// returns the domain sizes of all the variables in the database table
777  template < template < typename > class ALLOC >
779  DatabaseTable< ALLOC >::domainSizes() const {
780  const std::size_t nb_trans = _translators_.size();
782  for (std::size_t i = std::size_t(0); i < nb_trans; ++i) {
784  }
785  return dom;
786  }
787 
788 
789  // indicates whether a reordering is needed to make the kth
790  // translator sorted by lexicographical order
791  template < template < typename > class ALLOC >
792  bool DatabaseTable< ALLOC >::needsReordering(const std::size_t k,
793  const bool k_is_input_col) const {
794  // find the position kk of the translator that contains the variable
795  const std::size_t nb_trans = _translators_.size();
797 
798  // check if the translator exists
799  if (nb_trans <= kk) {
800  if (k_is_input_col) {
802  "there is no translator in the database table that "
803  << "parses Column " << k)
804  } else {
806  "the database has " << nb_trans << " translators, so Translator #" << k
807  << " does not exist")
808  }
809  }
810 
812  }
813 
814 
815  // performs a reordering of the kth translator or of the first
816  // translator corresponding to the kth column of the input database
817  template < template < typename > class ALLOC >
818  void DatabaseTable< ALLOC >::reorder(const std::size_t k, const bool k_is_input_col) {
819  // find the position kk of the translator that contains the variable
820  const std::size_t nb_trans = _translators_.size();
822 
823  // check if the translator exists
824  if (nb_trans <= kk) {
825  if (k_is_input_col) {
827  "there is no translator in the database table that "
828  << "parses Column " << k)
829  } else {
831  "the database has " << nb_trans << " translators, so Translator #" << k
832  << " does not exist")
833  }
834  }
835 
836  // if the translator is not designed for a discrete variable, there
837  // is no reordering to apply
839 
840  // get the translation to perform
842  if (updates.empty()) return;
843 
844  std::size_t size = updates.size();
846  for (const auto& update: updates) {
847  if (update.first >= size) {
848  size = update.first + 1;
850  }
852  }
853 
854  // apply the translations
855  auto newtrans_lambda = [this, kk, &new_values](std::size_t begin, std::size_t end) -> void {
856  for (std::size_t i = begin; i < end; ++i) {
857  auto& elt = this->rows_[i][kk].discr_val;
858  if (elt != std::numeric_limits< std::size_t >::max()) elt = new_values[elt];
859  }
860  };
861 
862  auto undo_newtrans_lambda = [](std::size_t begin, std::size_t end) -> void {
863  };
864 
865  // launch the threads executing the lambdas
867  }
868 
869 
870  /// performs a reordering of all the columns
871  template < template < typename > class ALLOC >
872  INLINE void DatabaseTable< ALLOC >::reorder() {
873  const std::size_t nb_trans = _translators_.size();
874  for (std::size_t i = std::size_t(0); i < nb_trans; ++i)
875  reorder(i, false);
876  }
877 
878 
879  /// insert a new row at the end of the database
880  template < template < typename > class ALLOC >
881  void DatabaseTable< ALLOC >::insertRow(
882  const std::vector< std::string, ALLOC< std::string > >& new_row) {
883  // check that the row can be fully translated, i.e., it contains enough
884  // columns to be translated
885  const std::size_t row_size = new_row.size();
886  if (row_size == std::size_t(0)) return;
887 
890  "the new row has " << row_size
891  << " columns whereas the database requires at least "
892  << (_translators_.highestInputColumn() + 1) << " columns")
893  }
894 
895  // convert the new_row into a row of DBTranslatedValue
896  const std::size_t nb_trans = _translators_.size();
899  bool has_missing_val = false;
900  for (std::size_t i = std::size_t(0); i < nb_trans; ++i) {
904  }
905 
907  }
908 
909 
910  /** @brief check that a row's values are compatible with those of the
911  * translators' variables */
912  template < template < typename > class ALLOC >
914  const typename DatabaseTable< ALLOC >::template Row< DBTranslatedValue >& row) const {
915  // check that the size of the row corresponds to that of the translators
916  const std::size_t row_size = row.size();
917  if (row_size != _translators_.size()) return false;
918 
919  const auto& translators = _translators_.translators();
920  for (std::size_t i = std::size_t(0); i < row_size; ++i) {
921  switch (translators[i]->getValType()) {
923  if ((row[i].discr_val >= translators[i]->domainSize())
924  && (row[i].discr_val != std::numeric_limits< std::size_t >::max()))
925  return false;
926  break;
927 
929  const IContinuousVariable& var
930  = static_cast< const IContinuousVariable& >(*(translators[i]->variable()));
931  if (((var.lowerBoundAsDouble() > (double)row[i].cont_val)
932  || (var.upperBoundAsDouble() < (double)row[i].cont_val))
933  && (row[i].cont_val != std::numeric_limits< float >::max()))
934  return false;
935  break;
936  }
937 
938  default:
939  GUM_ERROR(NotImplementedYet, "Translated value type not supported yet")
940  }
941  }
942 
943  return true;
944  }
945 
946 
947  /// insert a new DBRow at the end of the database
948  template < template < typename > class ALLOC >
950  typename DatabaseTable< ALLOC >::template Row< DBTranslatedValue >&& new_row,
951  const typename DatabaseTable< ALLOC >::IsMissing contains_missing_data) {
952  // check that the new rows values are compatible with the values of
953  // the variables stored within the translators
954  if (!_isRowCompatible_(new_row)) {
955  if (new_row.size() != _translators_.size()) {
957  "The new row has " << new_row.size()
958  << " elements whereas the database table has "
959  << _translators_.size() << " columns")
960  } else {
961  GUM_ERROR(InvalidArgument, "the new row is not compatible with the current translators")
962  }
963  }
964 
967  }
968 
969 
970  /// insert a new row at the end of the database
971  template < template < typename > class ALLOC >
973  const typename DatabaseTable< ALLOC >::template Row< DBTranslatedValue >& new_row,
974  const typename DatabaseTable< ALLOC >::IsMissing contains_missing_data) {
975  // check that the new rows values are compatible with the values of
976  // the variables stored within the translators
977  if (!_isRowCompatible_(new_row)) {
978  if (new_row.size() != _translators_.size()) {
980  "The new row has " << new_row.size()
981  << " elements whereas the database table has "
982  << _translators_.size() << " columns")
983  } else {
984  GUM_ERROR(InvalidArgument, "the new row is not compatible with the current translators")
985  }
986  }
987 
989  }
990 
991 
992  // insert a new DBRow of DBCells at the end of the database
993  template < template < typename > class ALLOC >
994  void DatabaseTable< ALLOC >::insertRow(
995  const typename DatabaseTable< ALLOC >::template Row< DBCell >& new_row) {
996  GUM_ERROR(NotImplementedYet, "not implemented yet")
997  }
998 
999  // insert a new DBRow of DBCells at the end of the database
1000  template < template < typename > class ALLOC >
1001  void DatabaseTable< ALLOC >::insertRow(
1002  typename DatabaseTable< ALLOC >::template Row< DBCell >&& new_row) {
1003  GUM_ERROR(NotImplementedYet, "not implemented yet")
1004  }
1005 
1006 
1007  /// insert a set of new DBRows at the end of the database
1008  template < template < typename > class ALLOC >
1009  void DatabaseTable< ALLOC >::insertRows(
1010  typename DatabaseTable< ALLOC >::template Matrix< DBTranslatedValue >&& rows,
1011  const typename DatabaseTable< ALLOC >::template DBVector< IsMissing >&
1013  // check that the new rows values are compatible with the values of
1014  // the variables stored within the translators
1015  for (const auto& new_row: rows) {
1016  if (!_isRowCompatible_(new_row)) {
1017  if (new_row.size() != _translators_.size()) {
1019  "The new row has " << new_row.size()
1020  << " elements whereas the database table has "
1021  << _translators_.size() << " columns")
1022  } else {
1023  GUM_ERROR(InvalidArgument, "the new row is not compatible with the current translators")
1024  }
1025  }
1026  }
1027 
1030  }
1031 
1032 
1033  /// insert a set of new DBRows at the end of the database
1034  template < template < typename > class ALLOC >
1035  void DatabaseTable< ALLOC >::insertRows(
1036  const typename DatabaseTable< ALLOC >::template Matrix< DBTranslatedValue >& new_rows,
1037  const typename DatabaseTable< ALLOC >::template DBVector< IsMissing >&
1039  // check that the new rows values are compatible with the values of
1040  // the variables stored within the translators
1041  for (const auto& new_row: new_rows) {
1042  if (!_isRowCompatible_(new_row)) {
1043  if (new_row.size() != _translators_.size()) {
1045  "The new row has " << new_row.size()
1046  << " elements whereas the database table has "
1047  << _translators_.size() << " columns")
1048  } else {
1049  GUM_ERROR(InvalidArgument, "the new row is not compatible with the current translators")
1050  }
1051  }
1052  }
1053 
1055  }
1056 
1057 
1058  /// insert a set of new DBRows at the end of the database
1059  template < template < typename > class ALLOC >
1060  void DatabaseTable< ALLOC >::insertRows(
1061  typename DatabaseTable< ALLOC >::template Matrix< DBCell >&& new_rows) {
1062  GUM_ERROR(NotImplementedYet, "not implemented yet")
1063  }
1064 
1065 
1066  /// insert a set of new DBRows at the end of the database
1067  template < template < typename > class ALLOC >
1068  void DatabaseTable< ALLOC >::insertRows(
1069  const typename DatabaseTable< ALLOC >::template Matrix< DBCell >& new_rows) {
1070  GUM_ERROR(NotImplementedYet, "not implemented yet")
1071  }
1072 
1073 
1074  /// erase the content of the database, including the names of the variables
1075  template < template < typename > class ALLOC >
1076  void DatabaseTable< ALLOC >::clear() {
1077  _translators_.clear();
1080  }
1081 
1082 
1083  } /* namespace learning */
1084 
1085 } /* namespace gum */
1086 
1087 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:643
Database(const std::string &filename, const BayesNet< GUM_SCALAR > &bn, const std::vector< std::string > &missing_symbols)