aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
databaseTable_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 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 >&
41  missing_symbols,
42  const DBTranslatorSet< ALLOC >& translators,
43  const typename DatabaseTable< ALLOC >::allocator_type& alloc) :
44  IDatabaseTable< DBTranslatedValue, ALLOC >(
45  missing_symbols,
46  std::vector< std::string, ALLOC< std::string > >(),
47  alloc),
48  translators__(translators, alloc) {
49  if (translators.size()) {
50  // set the variables names according to those of the translators
51  std::vector< std::string, ALLOC< std::string > > var_names(
52  translators.size());
53  for (std::size_t i = std::size_t(0), size = translators.size(); i < size;
54  ++i) {
55  var_names[i] = translators__.translator(i).variable()->name();
56  }
57  setVariableNames(var_names, false);
58  }
59 
60  GUM_CONSTRUCTOR(DatabaseTable);
61  }
62 
63 
64  // default constructor
65  template < template < typename > class ALLOC >
68  const typename DatabaseTable< ALLOC >::allocator_type& alloc) :
70  std::vector< std::string, ALLOC< std::string > >(),
71  std::vector< std::string, ALLOC< std::string > >(),
72  alloc),
74  if (translators.size()) {
75  // set the variables names according to those of the translators
77  translators.size());
78  for (std::size_t i = std::size_t(0), size = translators.size(); i < size;
79  ++i) {
81  }
83  }
84 
86  }
87 
88 
89  // copy constructor with a given allocator
90  template < template < typename > class ALLOC >
92  const DatabaseTable< ALLOC >& from,
93  const typename DatabaseTable< ALLOC >::allocator_type& alloc) :
98  }
99 
100 
101  // copy constructor
102  template < template < typename > class ALLOC >
103  INLINE
106 
107 
108  // move constructor with a given allocator
109  template < template < typename > class ALLOC >
111  DatabaseTable< ALLOC >&& from,
112  const typename DatabaseTable< ALLOC >::allocator_type& alloc) :
117  }
118 
119 
120  // move constructor
121  template < template < typename > class ALLOC >
124 
125 
126  // virtual copy constructor with a given allocator
127  template < template < typename > class ALLOC >
129  const typename DatabaseTable< ALLOC >::allocator_type& alloc) const {
132  try {
133  allocator.construct(new_db, *this, alloc);
134  } catch (...) {
136  throw;
137  }
138 
139  return new_db;
140  }
141 
142 
143  // virtual copy constructor
144  template < template < typename > class ALLOC >
145  DatabaseTable< ALLOC >* DatabaseTable< ALLOC >::clone() const {
146  return clone(this->getAllocator());
147  }
148 
149 
150  // destructor
151  template < template < typename > class ALLOC >
154  }
155 
156 
157  // copy operator
158  template < template < typename > class ALLOC >
159  DatabaseTable< ALLOC >&
161  if (this != &from) {
165  }
166 
167  return *this;
168  }
169 
170 
171  // move constructor
172  template < template < typename > class ALLOC >
173  DatabaseTable< ALLOC >&
175  if (this != &from) {
179  }
180 
181  return *this;
182  }
183 
184 
185  // a method to process the rows of the database in multithreading
186  template < template < typename > class ALLOC >
187  template < typename Functor1, typename Functor2 >
189  Functor2& undo_func) {
190  // compute the number of threads to execute the code, the number N of
191  // rows that each thread should process and the number of rows that
192  // would remain after each thread has processed its N rows. For instance,
193  // if the database has 105 rows and there are 10 threads, each thread
194  // should process 10 rows and there would remain 5 rows
195  const std::size_t db_size = this->rows_.size();
197  if (nb_threads < 1)
198  nb_threads = 1;
199  else if (nb_threads > this->max_nb_threads_)
200  nb_threads = this->max_nb_threads_;
203 
204  // if there is just one thread, let it process all the rows
205  if (nb_threads == 1) {
206  exec_func(std::size_t(0), db_size);
207  return;
208  }
209 
210  // here, we shall create the threads, but also one std::exception_ptr
211  // for each thread. This will allow us to catch the exception raised
212  // by the threads
213  std::vector< std::thread > threads;
216 
217  // create a lambda that will execute exec_func while catching its exceptions
219  std::size_t end,
220  std::exception_ptr& exc) -> void {
221  try {
222  exec_func(begin, end);
223  } catch (...) { exc = std::current_exception(); }
224  };
225 
226  // launch the threads
228  for (std::size_t i = std::size_t(0); i < nb_threads; ++i) {
230  if (rest_rows != std::size_t(0)) {
231  ++end_index;
232  --rest_rows;
233  }
235  begin_index,
236  end_index,
237  std::ref(func_exceptions[i])));
239  }
240 
241  // wait for the threads to complete their executions
243  threads.end(),
244  std::mem_fn(&std::thread::join));
245 
246  // now, check if one exception has been raised
247  bool exception_raised = false;
248  for (const auto& exc: func_exceptions) {
249  if (exc != nullptr) {
250  exception_raised = true;
251  break;
252  }
253  }
254 
255  if (exception_raised) {
256  // create a lambda that will execute undo_func while catching
257  // its exceptions
259  std::size_t end,
260  std::exception_ptr& exc) -> void {
261  try {
262  undo_func(begin, end);
263  } catch (...) { exc = std::current_exception(); }
264  };
265 
266  // launch the repair threads
267  threads.clear();
268  begin_index = std::size_t(0);
270  nullptr);
271  for (std::size_t i = std::size_t(0); i < nb_threads; ++i) {
273  if (rest_rows != std::size_t(0)) {
274  ++end_index;
275  --rest_rows;
276  }
277  // we just need to repair the threads that did not raise exceptions
278  if (func_exceptions[i] == nullptr)
280  begin_index,
281  end_index,
284  }
285 
286  // wait for the threads to complete their executions
288  threads.end(),
289  std::mem_fn(&std::thread::join));
290 
291  // rethrow the exception
292  for (const auto& exc: func_exceptions) {
293  if (exc != nullptr) { std::rethrow_exception(exc); }
294  }
295  }
296  }
297 
298 
299  /// insert a new translator into the database
300  template < template < typename > class ALLOC >
302  const DBTranslator< ALLOC >& translator,
303  const std::size_t input_column,
304  const bool unique_column) {
305  // check that there is no ignored_column corresponding to column
307  GUM_ERROR(
309  "Column "
310  << input_column << " is marked as being ignored. "
311  << "So it is forbidden to create a translator for that column.");
312 
313  // reserve some place for the new column in the records of the database
314  const std::size_t new_size = this->nbVariables() + 1;
315 
316  // create the lambda for reserving some memory for the new column
317  // and the one that undoes what it performed if some thread executing
318  // it raised an exception
319  auto reserve_lambda
320  = [this, new_size](std::size_t begin, std::size_t end) -> void {
321  for (std::size_t i = begin; i < end; ++i)
322  this->rows_[i].row().reserve(new_size);
323  };
324 
325  auto undo_reserve_lambda = [](std::size_t begin, std::size_t end) -> void {
326  };
327 
328  // launch the threads executing the lambdas
330 
331  // insert the translator into the translator set
332  const std::size_t pos
334 
335  // insert the name of the translator's variable to the set of variable names
336  try {
338  } catch (...) {
340  throw;
341  }
342 
343  // if the databaseTable is not empty, fill the column of the database
344  // corresponding to the translator with missing values
347 
348  // create the lambda for adding a new column filled wih a missing value
349  auto fill_lambda
350  = [this, missing](std::size_t begin, std::size_t end) -> void {
351  std::size_t i = begin;
352  try {
353  for (; i < end; ++i) {
354  this->rows_[i].row().push_back(missing);
356  }
357  } catch (...) {
358  for (std::size_t j = begin; j < i; ++j)
359  this->rows_[i].row().pop_back();
360  throw;
361  }
362  };
363 
364  auto undo_fill_lambda
365  = [this](std::size_t begin, std::size_t end) -> void {
366  for (std::size_t i = begin; i < end; ++i)
367  this->rows_[i].row().pop_back();
368  };
369 
370  // launch the threads executing the lambdas
372  }
373 
374  return pos;
375  }
376 
377 
378  /// insert a new translator into the database
379  template < template < typename > class ALLOC >
380  std::size_t
382  const std::size_t input_column,
383  const bool unique_column) {
384  // check that there is no ignored_column corresponding to column
386  GUM_ERROR(
388  "Column "
389  << input_column << " is marked as being ignored. "
390  << "So it is forbidden to create a translator for that column.");
391 
392  // if the databaseTable is not empty, we should fill the column of the
393  // database corresponding to the new translator with missing values. But, the
394  // current method assumes that the list of missing values is empty. Hence, it
395  // should raise an exception
397  GUM_ERROR(
399  "inserting a new translator into a database creates a new column "
400  << "with missing values. However, you did not define any symbol for "
401  << "such values.");
402  }
403 
404  // reserve some place for the new column in the records of the database
405  const std::size_t new_size = this->nbVariables() + 1;
406 
407  // create the lambda for reserving some memory for the new column
408  // and the one that undoes what it performed if some thread executing
409  // it raised an exception
410  auto reserve_lambda
411  = [this, new_size](std::size_t begin, std::size_t end) -> void {
412  for (std::size_t i = begin; i < end; ++i)
413  this->rows_[i].row().reserve(new_size);
414  };
415 
416  auto undo_reserve_lambda = [](std::size_t begin, std::size_t end) -> void {
417  };
418 
419  // launch the threads executing the lambdas
421 
422  // insert the translator into the translator set
423  const std::size_t pos
425 
426  // insert the name of the translator's variable to the set of variable names
427  try {
429  } catch (...) {
431  throw;
432  }
433 
434  return pos;
435  }
436 
437 
438  /// insert a new translator into the database
439  template < template < typename > class ALLOC >
440  template < template < typename > class XALLOC >
442  const Variable& var,
443  const std::size_t input_column,
445  const bool unique_column) {
446  // check that there is no ignored_column corresponding to column
448  GUM_ERROR(
450  "Column "
451  << input_column << " is marked as being ignored. "
452  << "So it is forbidden to create a translator for that column.");
453 
454  // reserve some place for the new column in the records of the database
455  const std::size_t new_size = this->nbVariables() + 1;
456 
457  // create the lambda for reserving some memory for the new column
458  // and the one that undoes what it performed if some thread executing
459  // it raised an exception
460  auto reserve_lambda
461  = [this, new_size](std::size_t begin, std::size_t end) -> void {
462  for (std::size_t i = begin; i < end; ++i)
463  this->rows_[i].row().reserve(new_size);
464  };
465 
466  auto undo_reserve_lambda = [](std::size_t begin, std::size_t end) -> void {
467  };
468 
469  // launch the threads executing the lambdas
471 
472  // insert the translator into the translator set
474  input_column,
476  unique_column);
477 
478  // insert the name of the translator's variable to the set of variable names
479  try {
481  } catch (...) {
483  throw;
484  }
485 
486  // if the databaseTable is not empty, fill the column of the database
487  // corresponding to the translator with missing values
490 
491  // create the lambda for adding a new column filled wih a missing value
492  auto fill_lambda
493  = [this, missing](std::size_t begin, std::size_t end) -> void {
494  std::size_t i = begin;
495  try {
496  for (; i < end; ++i) {
497  this->rows_[i].row().push_back(missing);
499  }
500  } catch (...) {
501  for (std::size_t j = begin; j < i; ++j)
502  this->rows_[i].row().pop_back();
503  throw;
504  }
505  };
506 
507  auto undo_fill_lambda
508  = [this](std::size_t begin, std::size_t end) -> void {
509  for (std::size_t i = begin; i < end; ++i)
510  this->rows_[i].row().pop_back();
511  };
512 
513  // launch the threads executing the lambdas
515  }
516 
517  return pos;
518  }
519 
520 
521  /** @brief returns the indices corresponding either to the kth translator
522  * or to all those that parse the kth column of the input dataset
523  *
524  * @warning the indices are sorted by deacreasing order */
525  template < template < typename > class ALLOC >
526  INLINE typename DatabaseTable< ALLOC >::template DBVector< std::size_t >
528  const bool k_is_input_col) const {
529  const std::size_t nb_trans = translators__.size();
530  if (!k_is_input_col) {
531  if (k < nb_trans)
532  return DBVector< std::size_t >{k};
533  else
534  return DBVector< std::size_t >();
535  } else {
536  DBVector< std::size_t > trans;
537  for (std::size_t i = std::size_t(0), kk = nb_trans - 1; i < nb_trans;
538  ++i, --kk) {
540  }
541  return trans;
542  }
543  }
544 
545 
546  // erases the kth translator or all those parsing the kth column of
547  // the input dataset
548  template < template < typename > class ALLOC >
550  const bool k_is_input_col) {
551  for (const auto kk: getKthIndices__(k, k_is_input_col)) {
552  // erase the translator of index kk and the corresponding variable
553  // name. If there remains no more translator in the translator set,
554  // rows_ should become empty
555  this->variable_names_.erase(this->variable_names_.begin() + kk);
556  if (this->variable_names_.empty()) {
558  } else {
559  const std::size_t nb_trans = translators__.size();
560 
561  auto erase_lambda
562  = [this, nb_trans, kk](std::size_t begin, std::size_t end) -> void {
563  for (std::size_t i = begin; i < end; ++i) {
564  auto& row = this->rows_[i].row();
565  if (this->translators__.isMissingValue(row[kk], kk)) {
566  bool has_missing_val = false;
567  for (std::size_t j = std::size_t(0); j < nb_trans; ++j) {
568  if ((j != kk) && this->translators__.isMissingValue(row[j], j)) {
569  has_missing_val = true;
570  break;
571  }
572  }
573  if (!has_missing_val)
575  }
576  row.erase(row.begin() + kk);
577  }
578  };
579 
580  auto undo_erase_lambda = [](std::size_t begin, std::size_t end) -> void {
581  };
582 
583  // launch the threads executing the lambdas
585  }
587  }
588  }
589 
590 
591  /// returns the set of translators
592  template < template < typename > class ALLOC >
593  INLINE const DBTranslatorSet< ALLOC >&
594  DatabaseTable< ALLOC >::translatorSet() const {
595  return translators__;
596  }
597 
598 
599  /** @brief returns the index corresponding either to the kth translator or
600  * to that of the first translator parsing the kth column of the
601  * input dataset */
602  template < template < typename > class ALLOC >
603  INLINE std::size_t
605  const bool k_is_input_col) const {
606  if (k_is_input_col) {
607  const std::size_t nb_trans = translators__.size();
608  for (std::size_t i = std::size_t(0); i < nb_trans; ++i) {
609  if (translators__.inputColumn(i) == k) { return i; }
610  }
611  return nb_trans + 1;
612  } else {
613  return k;
614  }
615  }
616 
617 
618  /// returns the kth translator of the database
619  template < template < typename > class ALLOC >
620  const DBTranslator< ALLOC >&
622  const bool k_is_input_col) const {
623  // find the position of the translator that we look for. This
624  // is variable kk below
625  const std::size_t nb_trans = translators__.size();
627 
628  // check if the translator exists
629  if (nb_trans <= kk) {
630  if (k_is_input_col) {
632  "there is no translator in the database table that "
633  << "parses Column " << k);
634  } else {
636  "the database has " << nb_trans
637  << " translators, so Translator #" << k
638  << " does not exist");
639  }
640  }
641 
642  return translators__.translator(kk);
643  }
644 
645 
646  /// returns the kth variable of the database
647  template < template < typename > class ALLOC >
648  const Variable&
649  DatabaseTable< ALLOC >::variable(const std::size_t k,
650  const bool k_is_input_col) const {
651  // find the position of the translator that contains the variable.
652  // This is variable kk below
653  const std::size_t nb_trans = translators__.size();
655 
656  // check if the translator exists
657  if (nb_trans <= kk) {
658  if (k_is_input_col) {
660  "there is no variable in the database table that "
661  << "corresponds to Column " << k);
662  } else {
664  "the database has " << nb_trans << " variables, so Variable #"
665  << k << " does not exist");
666  }
667  }
668 
669  return translators__.variable(kk);
670  }
671 
672 
673  /// sets the names of the variables
674  template < template < typename > class ALLOC >
676  const std::vector< std::string, ALLOC< std::string > >& names,
677  const bool from_external_object) {
678  const std::size_t size = names.size();
679  const std::size_t nb_trans = translators__.size();
680  if (!from_external_object) {
681  if (nb_trans != size) {
683  "the number of variable's names (i.e., "
684  << size
685  << ") does not correspond to the number of columns of the "
686  << "database table (i.e.," << nb_trans << ")");
687  }
688 
689  // update the translator names
690  for (std::size_t i = std::size_t(0); i < size; ++i) {
692  }
693  } else {
696  "the names vector has "
697  << size << " elements whereas it should have at least "
699  << "elements so that each translator is assigned a name");
700  }
701 
702  // update the translator names
703  for (std::size_t i = std::size_t(0); i < nb_trans; ++i) {
706  }
707  }
708 
709  // update variable_names_ using the newly assigned translators names
711  for (std::size_t i = std::size_t(0); i < nb_trans; ++i) {
713  }
714  }
715 
716 
717  /** @brief indicates that we should ignore the kth column of the original
718  * database when inserting new rows */
719  template < template < typename > class ALLOC >
720  void DatabaseTable< ALLOC >::ignoreColumn(const std::size_t k,
721  const bool k_is_input_col) {
722  // indicate that the column will be forbidden. If the column is already
723  // forbidden, do nothing. But if the column is assigned to a translator
724  // that does not exist, raise an UndefinedElement exception
725  const std::size_t nb_trans = translators__.size();
726  if (k_is_input_col) {
727  if (ignored_cols__.exists(k)) return;
729  } else {
730  if (k < nb_trans) {
732  } else {
734  "It is impossible to ignore the column parsed by Translator #"
735  << k << "because there exist only " << nb_trans
736  << " translators");
737  }
738  }
739 
740  // remove all the translators corresponding to k
742  }
743 
744 
745  /// returns the set of ignored columns
746  template < template < typename > class ALLOC >
747  const typename DatabaseTable< ALLOC >::template DBVector< std::size_t >
748  DatabaseTable< ALLOC >::ignoredColumns() const {
749  const std::size_t nb_trans = translators__.size();
750 
751  if (nb_trans == std::size_t(0)) {
752  return DBVector< std::size_t >{std::size_t(0)};
753  }
754 
755  // get the columns handled by the translators, sorted by increasing order
757  for (std::size_t i = std::size_t(0); i < nb_trans; ++i)
759  std::sort(cols.begin(), cols.end());
760 
761  // create a vector with all the possible input columns
765 
766  // remove from ignored_cols the elements of cols
767  for (std::size_t i = std::size_t(0),
768  ii = highest - 1,
769  k = std::size_t(0),
770  kk = nb_trans - 1;
771  i < highest;
772  ++i, --ii) {
773  if (cols[kk] == ii) {
775  while ((k < nb_trans) && (cols[kk] == ii)) {
776  --kk;
777  ++k;
778  }
779  if (k == nb_trans) break;
780  }
781  }
782 
783  // add the column past the last translator
785 
786  return ignored_cols;
787  }
788 
789 
790  /// returns the set of columns parsed
791  template < template < typename > class ALLOC >
792  const typename DatabaseTable< ALLOC >::template DBVector< std::size_t >
793  DatabaseTable< ALLOC >::inputColumns() const {
794  const std::size_t nb_trans = translators__.size();
795  if (nb_trans == std::size_t(0)) { return DBVector< std::size_t >(); }
796 
798  for (std::size_t i = std::size_t(0); i < nb_trans; ++i) {
800  }
801  return input_cols;
802  }
803 
804 
805  /// returns the domain size of the kth variable
806  template < template < typename > class ALLOC >
807  std::size_t
809  const bool k_is_input_col) const {
810  // find the position kk of the translator that contains the variable
811  const std::size_t nb_trans = translators__.size();
813 
814  // check if the translator exists
815  if (nb_trans <= kk) {
816  if (k_is_input_col) {
818  "there is no variable in the database table that "
819  << "corresponds to Column " << k);
820  } else {
822  "the database has " << nb_trans << " variables, so Variable #"
823  << k << " does not exist");
824  }
825  }
826 
827  return translators__.domainSize(kk);
828  }
829 
830 
831  /// returns the domain sizes of all the variables in the database table
832  template < template < typename > class ALLOC >
834  DatabaseTable< ALLOC >::domainSizes() const {
835  const std::size_t nb_trans = translators__.size();
837  for (std::size_t i = std::size_t(0); i < nb_trans; ++i) {
839  }
840  return dom;
841  }
842 
843 
844  // indicates whether a reordering is needed to make the kth
845  // translator sorted by lexicographical order
846  template < template < typename > class ALLOC >
847  bool DatabaseTable< ALLOC >::needsReordering(const std::size_t k,
848  const bool k_is_input_col) const {
849  // find the position kk of the translator that contains the variable
850  const std::size_t nb_trans = translators__.size();
852 
853  // check if the translator exists
854  if (nb_trans <= kk) {
855  if (k_is_input_col) {
857  "there is no translator in the database table that "
858  << "parses Column " << k);
859  } else {
861  "the database has " << nb_trans
862  << " translators, so Translator #" << k
863  << " does not exist");
864  }
865  }
866 
868  }
869 
870 
871  // performs a reordering of the kth translator or of the first
872  // translator corresponding to the kth column of the input database
873  template < template < typename > class ALLOC >
874  void DatabaseTable< ALLOC >::reorder(const std::size_t k,
875  const bool k_is_input_col) {
876  // find the position kk of the translator that contains the variable
877  const std::size_t nb_trans = translators__.size();
879 
880  // check if the translator exists
881  if (nb_trans <= kk) {
882  if (k_is_input_col) {
884  "there is no translator in the database table that "
885  << "parses Column " << k);
886  } else {
888  "the database has " << nb_trans
889  << " translators, so Translator #" << k
890  << " does not exist");
891  }
892  }
893 
894  // if the translator is not designed for a discrete variable, there
895  // is no reordering to apply
898  return;
899 
900  // get the translation to perform
902  if (updates.empty()) return;
903 
904  std::size_t size = updates.size();
906  for (const auto& update: updates) {
907  if (update.first >= size) {
908  size = update.first + 1;
910  }
912  }
913 
914  // apply the translations
915  auto newtrans_lambda
916  = [this, kk, &new_values](std::size_t begin, std::size_t end) -> void {
917  for (std::size_t i = begin; i < end; ++i) {
918  auto& elt = this->rows_[i][kk].discr_val;
919  if (elt != std::numeric_limits< std::size_t >::max())
920  elt = new_values[elt];
921  }
922  };
923 
924  auto undo_newtrans_lambda = [](std::size_t begin, std::size_t end) -> void {
925  };
926 
927  // launch the threads executing the lambdas
929  }
930 
931 
932  /// performs a reordering of all the columns
933  template < template < typename > class ALLOC >
934  INLINE void DatabaseTable< ALLOC >::reorder() {
935  const std::size_t nb_trans = translators__.size();
936  for (std::size_t i = std::size_t(0); i < nb_trans; ++i)
937  reorder(i, false);
938  }
939 
940 
941  /// insert a new row at the end of the database
942  template < template < typename > class ALLOC >
943  void DatabaseTable< ALLOC >::insertRow(
944  const std::vector< std::string, ALLOC< std::string > >& new_row) {
945  // check that the row can be fully translated, i.e., it contains enough
946  // columns to be translated
947  const std::size_t row_size = new_row.size();
948  if (row_size == std::size_t(0)) return;
949 
952  "the new row has "
953  << row_size
954  << " columns whereas the database requires at least "
955  << (translators__.highestInputColumn() + 1) << " columns");
956  }
957 
958  // convert the new_row into a row of DBTranslatedValue
959  const std::size_t nb_trans = translators__.size();
962  bool has_missing_val = false;
963  for (std::size_t i = std::size_t(0); i < nb_trans; ++i) {
967  }
968 
969  this->insertRow(std::move(dbrow),
971  }
972 
973 
974  /** @brief check that a row's values are compatible with those of the
975  * translators' variables */
976  template < template < typename > class ALLOC >
978  const typename DatabaseTable< ALLOC >::template Row< DBTranslatedValue >&
979  row) const {
980  // check that the size of the row corresponds to that of the translators
981  const std::size_t row_size = row.size();
982  if (row_size != translators__.size()) return false;
983 
984  const auto& translators = translators__.translators();
985  for (std::size_t i = std::size_t(0); i < row_size; ++i) {
986  switch (translators[i]->getValType()) {
988  if ((row[i].discr_val >= translators[i]->domainSize())
989  && (row[i].discr_val != std::numeric_limits< std::size_t >::max()))
990  return false;
991  break;
992 
994  const IContinuousVariable& var
995  = static_cast< const IContinuousVariable& >(
996  *(translators[i]->variable()));
997  if (((var.lowerBoundAsDouble() > (double)row[i].cont_val)
998  || (var.upperBoundAsDouble() < (double)row[i].cont_val))
999  && (row[i].cont_val != std::numeric_limits< float >::max()))
1000  return false;
1001  break;
1002  }
1003 
1004  default:
1006  "Translated value type not supported yet");
1007  }
1008  }
1009 
1010  return true;
1011  }
1012 
1013 
1014  /// insert a new DBRow at the end of the database
1015  template < template < typename > class ALLOC >
1017  typename DatabaseTable< ALLOC >::template Row< DBTranslatedValue >&&
1018  new_row,
1019  const typename DatabaseTable< ALLOC >::IsMissing contains_missing_data) {
1020  // check that the new rows values are compatible with the values of
1021  // the variables stored within the translators
1022  if (!isRowCompatible__(new_row)) {
1023  if (new_row.size() != translators__.size()) {
1025  "The new row has "
1026  << new_row.size()
1027  << " elements whereas the database table has "
1028  << translators__.size() << " columns");
1029  } else {
1031  "the new row is not compatible with the current translators");
1032  }
1033  }
1034 
1037  }
1038 
1039 
1040  /// insert a new row at the end of the database
1041  template < template < typename > class ALLOC >
1043  const typename DatabaseTable< ALLOC >::template Row< DBTranslatedValue >&
1044  new_row,
1045  const typename DatabaseTable< ALLOC >::IsMissing contains_missing_data) {
1046  // check that the new rows values are compatible with the values of
1047  // the variables stored within the translators
1048  if (!isRowCompatible__(new_row)) {
1049  if (new_row.size() != translators__.size()) {
1051  "The new row has "
1052  << new_row.size()
1053  << " elements whereas the database table has "
1054  << translators__.size() << " columns");
1055  } else {
1057  "the new row is not compatible with the current translators");
1058  }
1059  }
1060 
1063  }
1064 
1065 
1066  // insert a new DBRow of DBCells at the end of the database
1067  template < template < typename > class ALLOC >
1068  void DatabaseTable< ALLOC >::insertRow(
1069  const typename DatabaseTable< ALLOC >::template Row< DBCell >& new_row) {
1070  GUM_ERROR(NotImplementedYet, "not implemented yet");
1071  }
1072 
1073  // insert a new DBRow of DBCells at the end of the database
1074  template < template < typename > class ALLOC >
1075  void DatabaseTable< ALLOC >::insertRow(
1076  typename DatabaseTable< ALLOC >::template Row< DBCell >&& new_row) {
1077  GUM_ERROR(NotImplementedYet, "not implemented yet");
1078  }
1079 
1080 
1081  /// insert a set of new DBRows at the end of the database
1082  template < template < typename > class ALLOC >
1083  void DatabaseTable< ALLOC >::insertRows(
1084  typename DatabaseTable< ALLOC >::template Matrix< DBTranslatedValue >&&
1085  rows,
1086  const typename DatabaseTable< ALLOC >::template DBVector< IsMissing >&
1088  // check that the new rows values are compatible with the values of
1089  // the variables stored within the translators
1090  for (const auto& new_row: rows) {
1091  if (!isRowCompatible__(new_row)) {
1092  if (new_row.size() != translators__.size()) {
1094  "The new row has "
1095  << new_row.size()
1096  << " elements whereas the database table has "
1097  << translators__.size() << " columns");
1098  } else {
1099  GUM_ERROR(
1101  "the new row is not compatible with the current translators");
1102  }
1103  }
1104  }
1105 
1107  std::move(rows),
1109  }
1110 
1111 
1112  /// insert a set of new DBRows at the end of the database
1113  template < template < typename > class ALLOC >
1114  void DatabaseTable< ALLOC >::insertRows(
1115  const typename DatabaseTable< ALLOC >::template Matrix< DBTranslatedValue >&
1116  new_rows,
1117  const typename DatabaseTable< ALLOC >::template DBVector< IsMissing >&
1119  // check that the new rows values are compatible with the values of
1120  // the variables stored within the translators
1121  for (const auto& new_row: new_rows) {
1122  if (!isRowCompatible__(new_row)) {
1123  if (new_row.size() != translators__.size()) {
1125  "The new row has "
1126  << new_row.size()
1127  << " elements whereas the database table has "
1128  << translators__.size() << " columns");
1129  } else {
1130  GUM_ERROR(
1132  "the new row is not compatible with the current translators");
1133  }
1134  }
1135  }
1136 
1138  new_rows,
1140  }
1141 
1142 
1143  /// insert a set of new DBRows at the end of the database
1144  template < template < typename > class ALLOC >
1145  void DatabaseTable< ALLOC >::insertRows(
1146  typename DatabaseTable< ALLOC >::template Matrix< DBCell >&& new_rows) {
1147  GUM_ERROR(NotImplementedYet, "not implemented yet");
1148  }
1149 
1150 
1151  /// insert a set of new DBRows at the end of the database
1152  template < template < typename > class ALLOC >
1153  void DatabaseTable< ALLOC >::insertRows(
1154  const typename DatabaseTable< ALLOC >::template Matrix< DBCell >&
1155  new_rows) {
1156  GUM_ERROR(NotImplementedYet, "not implemented yet");
1157  }
1158 
1159 
1160  /// erase the content of the database, including the names of the variables
1161  template < template < typename > class ALLOC >
1162  void DatabaseTable< ALLOC >::clear() {
1163  translators__.clear();
1166  }
1167 
1168 
1169  } /* namespace learning */
1170 
1171 } /* namespace gum */
1172 
1173 #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)