aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
IDatabaseTable_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 the common class for tabular databases
24  *
25  * @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
26  */
27 #include <agrum/tools/database/IDatabaseTable.h>
28 
29 #ifndef DOXYGEN_SHOULD_SKIP_THIS
30 
31 namespace gum {
32 
33  namespace learning {
34 
35  // ===========================================================================
36  // Unsafe handlers
37  // ===========================================================================
38 
39  // default constructor
40  template < typename T_DATA, template < typename > class ALLOC >
41  INLINE IDatabaseTable< T_DATA, ALLOC >::Handler::Handler(
42  const IDatabaseTable< T_DATA, ALLOC >& db) :
43  DBHandler< T_DATA, ALLOC >(),
44  _db_(&db), _row_(&(db.content())), _end_index_(std::size_t(_row_->size())) {
46  }
47 
48 
49  // copy constructor
50  template < typename T_DATA, template < typename > class ALLOC >
52  const typename IDatabaseTable< T_DATA, ALLOC >::Handler& h) :
53  DBHandler< T_DATA, ALLOC >(),
57  }
58 
59 
60  // move constructor
61  template < typename T_DATA, template < typename > class ALLOC >
63  typename IDatabaseTable< T_DATA, ALLOC >::Handler&& h) :
64  DBHandler< T_DATA, ALLOC >(),
68  }
69 
70 
71  // destructor
72  template < typename T_DATA, template < typename > class ALLOC >
75  }
76 
77 
78  // copy operator
79  template < typename T_DATA, template < typename > class ALLOC >
82  const typename IDatabaseTable< T_DATA, ALLOC >::Handler& h) {
83  _db_ = h._db_;
84  _row_ = h._row_;
85  _index_ = h._index_;
88  return *this;
89  }
90 
91 
92  // move operator
93  template < typename T_DATA, template < typename > class ALLOC >
96  typename IDatabaseTable< T_DATA, ALLOC >::Handler&& h) {
97  _db_ = h._db_;
98  _row_ = h._row_;
99  _index_ = h._index_;
102  return *this;
103  }
104 
105 
106  // returns the current row pointed to by the handler
107  template < typename T_DATA, template < typename > class ALLOC >
109  IDatabaseTable< T_DATA, ALLOC >::Handler::operator*() const {
110  return _row_->operator[](_index_);
111  }
112 
113 
114  // Dereferences the value pointed to by the handler (unsafe version)
115  template < typename T_DATA, template < typename > class ALLOC >
117  IDatabaseTable< T_DATA, ALLOC >::Handler::operator->() const {
118  return &(_row_->operator[](_index_));
119  }
120 
121 
122  // makes the handler point to the next row
123  template < typename T_DATA, template < typename > class ALLOC >
124  INLINE typename IDatabaseTable< T_DATA, ALLOC >::Handler&
126  ++_index_;
127  return *this;
128  }
129 
130 
131  // makes the handler point to the previous row
132  template < typename T_DATA, template < typename > class ALLOC >
133  INLINE typename IDatabaseTable< T_DATA, ALLOC >::Handler&
135  if (_index_ > _begin_index_) --_index_;
136  return *this;
137  }
138 
139 
140  // moves the handler by i rows
141  template < typename T_DATA, template < typename > class ALLOC >
142  INLINE typename IDatabaseTable< T_DATA, ALLOC >::Handler&
144  _index_ += i;
145  return *this;
146  }
147 
148 
149  // moves back the handler by i rows
150  template < typename T_DATA, template < typename > class ALLOC >
151  INLINE typename IDatabaseTable< T_DATA, ALLOC >::Handler&
153  if (_index_ >= _begin_index_ + i)
154  _index_ -= i;
155  else
157  return *this;
158  }
159 
160 
161  // checks whether two handlers point on the same row
162  template < typename T_DATA, template < typename > class ALLOC >
163  INLINE bool IDatabaseTable< T_DATA, ALLOC >::Handler::operator==(const Handler& handler) const {
164  return _index_ == handler._index_;
165  }
166 
167 
168  // checks whether two handlers point to different rows
169  template < typename T_DATA, template < typename > class ALLOC >
170  INLINE bool IDatabaseTable< T_DATA, ALLOC >::Handler::operator!=(const Handler& handler) const {
171  return _index_ != handler._index_;
172  }
173 
174 
175  // returns the number of rows managed by the handler
176  template < typename T_DATA, template < typename > class ALLOC >
178  return _end_index_ - _begin_index_;
179  }
180 
181 
182  // return the number of rows of the whole database
183  template < typename T_DATA, template < typename > class ALLOC >
185  if (_row_ != nullptr)
186  return _row_->size();
187  else
188  return std::size_t(0);
189  }
190 
191 
192  // returns the current row pointed to by the handler
193  template < typename T_DATA, template < typename > class ALLOC >
195  IDatabaseTable< T_DATA, ALLOC >::Handler::rowSafe() const {
196  if (_index_ >= _end_index_) { GUM_ERROR(OutOfBounds, "the handler has reached its end") }
197 
198  return _row_->operator[](_index_);
199  }
200 
201 
202  // returns the current row pointed to by the handler
203  template < typename T_DATA, template < typename > class ALLOC >
206  if (_index_ >= _end_index_) { GUM_ERROR(OutOfBounds, "the handler has reached its end") }
207 
208  return const_cast< Matrix< T_DATA >* >(_row_)->operator[](_index_);
209  }
210 
211 
212  // returns the current row pointed to by the handler (unsafe version)
213  template < typename T_DATA, template < typename > class ALLOC >
215  IDatabaseTable< T_DATA, ALLOC >::Handler::row() const {
216  return _row_->operator[](_index_);
217  }
218 
219 
220  // returns the current row pointed to by the handler (unsafe version)
221  template < typename T_DATA, template < typename > class ALLOC >
224  return const_cast< Matrix< T_DATA >* >(_row_)->operator[](_index_);
225  }
226 
227 
228  // makes the handler point to the next row
229  template < typename T_DATA, template < typename > class ALLOC >
231  ++_index_;
232  }
233 
234 
235  // returns the number of the current row
236  template < typename T_DATA, template < typename > class ALLOC >
238  return (_index_ >= _begin_index_) ? _index_ - _begin_index_ : 0;
239  }
240 
241  // indicates whether the handler has reached its end or not
242  template < typename T_DATA, template < typename > class ALLOC >
243  INLINE bool IDatabaseTable< T_DATA, ALLOC >::Handler::hasRows() const {
244  return (_index_ < _end_index_);
245  }
246 
247  // puts the handler to the beginning of the database area it handles
248  template < typename T_DATA, template < typename > class ALLOC >
251  }
252 
253 
254  // returns a new handler that points to the beginning of the
255  // database area of the current handler */
256  template < typename T_DATA, template < typename > class ALLOC >
258  IDatabaseTable< T_DATA, ALLOC >::Handler::begin() const {
259  Handler handler(*this);
260  handler.reset();
261  return handler;
262  }
263 
264 
265  // returns a new handler that points to the end of the
266  // database area of the current handler */
267  template < typename T_DATA, template < typename > class ALLOC >
269  IDatabaseTable< T_DATA, ALLOC >::Handler::end() const {
270  Handler handler(*this);
272  return handler;
273  }
274 
275 
276  // sets the area in the database the handler will handle
277  template < typename T_DATA, template < typename > class ALLOC >
279  std::size_t last) {
280  if (first > last) std::swap(first, last);
281 
282  // check that the end belongs to the database, else raise an exception
283  if (_row_ == nullptr) GUM_ERROR(NullElement, "the handler does not point to any database")
284 
285  if (last > _row_->size())
287  "the database has fewer rows (" << _row_->size() << ") than the upper range ("
288  << last << ") specified to the handler")
289 
291  _end_index_ = last;
292  _index_ = first;
293  }
294 
295 
296  // returns the current range of the handler
297  template < typename T_DATA, template < typename > class ALLOC >
299  IDatabaseTable< T_DATA, ALLOC >::Handler::range() const {
301  }
302 
303 
304  // returns the names of the variables
305  template < typename T_DATA, template < typename > class ALLOC >
306  INLINE const typename IDatabaseTable< T_DATA,
307  ALLOC >::Handler::template DBVector< std::string >&
309  return _db_->variableNames();
310  }
311 
312 
313  // returns the number of variables (columns) of the database
314  template < typename T_DATA, template < typename > class ALLOC >
316  if (_db_ != nullptr)
317  return _db_->variableNames().size();
318  else
319  return 0;
320  }
321 
322 
323  // returns a pointer on the database
324  template < typename T_DATA, template < typename > class ALLOC >
325  INLINE const IDatabaseTable< T_DATA, ALLOC >&
326  IDatabaseTable< T_DATA, ALLOC >::Handler::database() const {
327  if (_db_ == nullptr) {
328  GUM_ERROR(NullElement, "The database handler does not point toward a database")
329  }
330  return *_db_;
331  }
332 
333 
334  // ===========================================================================
335  // Safe handlers
336  // ===========================================================================
337 
338  // attach a new handler to the database
339  template < typename T_DATA, template < typename > class ALLOC >
341  if (this->_db_ != nullptr) { this->_db_->_attachHandler_(this); }
342  }
343 
344 
345  // detach a handler
346  template < typename T_DATA, template < typename > class ALLOC >
348  if (this->_db_ != nullptr) { this->_db_->_detachHandler_(this); }
349  }
350 
351 
352  // default constructor
353  template < typename T_DATA, template < typename > class ALLOC >
355  const IDatabaseTable< T_DATA, ALLOC >& db) :
357  _attachHandler_();
359  }
360 
361 
362  // copy constructor
363  template < typename T_DATA, template < typename > class ALLOC >
365  const typename IDatabaseTable< T_DATA, ALLOC >::HandlerSafe& h) :
367  _attachHandler_();
369  }
370 
371 
372  // move constructor
373  template < typename T_DATA, template < typename > class ALLOC >
375  typename IDatabaseTable< T_DATA, ALLOC >::HandlerSafe&& h) :
377  _attachHandler_();
379  }
380 
381 
382  // destructor
383  template < typename T_DATA, template < typename > class ALLOC >
385  _detachHandler_();
387  }
388 
389 
390  // copy operator
391  template < typename T_DATA, template < typename > class ALLOC >
394  const typename IDatabaseTable< T_DATA, ALLOC >::HandlerSafe& h) {
395  if (this->_db_ != h._db_) {
396  _detachHandler_();
397  this->_db_ = h._db_;
398  _attachHandler_();
399  }
400 
402  return *this;
403  }
404 
405 
406  // copy operator
407  template < typename T_DATA, template < typename > class ALLOC >
410  const typename IDatabaseTable< T_DATA, ALLOC >::Handler& h) {
411  return this->operator=(
412  dynamic_cast< const IDatabaseTable< T_DATA, ALLOC >::HandlerSafe& >(h));
413  }
414 
415 
416  // move operator
417  template < typename T_DATA, template < typename > class ALLOC >
420  typename IDatabaseTable< T_DATA, ALLOC >::HandlerSafe&& h) {
421  if (this->_db_ != h._db_) {
422  _detachHandler_();
423  this->_db_ = h._db_;
424  _attachHandler_();
425  }
426 
428  return *this;
429  }
430 
431 
432  // move operator
433  template < typename T_DATA, template < typename > class ALLOC >
436  typename IDatabaseTable< T_DATA, ALLOC >::Handler&& h) {
437  return this->operator=(
438  std::move(dynamic_cast< IDatabaseTable< T_DATA, ALLOC >::HandlerSafe& >(h)));
439  }
440 
441 
442  // ===========================================================================
443  // Database Tables
444  // ===========================================================================
445 
446  // returns the allocator of the database
447  template < typename T_DATA, template < typename > class ALLOC >
449  return ALLOC< T_DATA >(*this);
450  }
451 
452 
453  // create the end iterators
454  template < typename T_DATA, template < typename > class ALLOC >
456  const IDatabaseTable< T_DATA, ALLOC >& db = *this;
457  ALLOC< iterator > allocator1(*this);
459  try {
461  } catch (...) {
463  throw;
464  }
465 
466  ALLOC< iterator_safe > allocator2(*this);
467  try {
469  try {
471  } catch (...) {
473  throw;
474  }
475  } catch (...) {
478  throw;
479  }
480  }
481 
482 
483  // default constructor
484  template < typename T_DATA, template < typename > class ALLOC >
485  template < template < typename > class VARALLOC, template < typename > class MISSALLOC >
487  const typename IDatabaseTable< T_DATA, ALLOC >::template MissingValType< MISSALLOC >&
489  const std::vector< std::string, VARALLOC< std::string > >& var_names,
490  const ALLOC< T_DATA >& alloc) :
491  ALLOC< T_DATA >(alloc),
494  // copy the names
496  for (const auto& name: var_names)
498 
499  // copy the missing symbols
501  for (const auto& missing_symbol: missing_symbols)
503 
504  // create the end iterators
506 
508  }
509 
510 
511  // copy constructor with a given allocator
512  template < typename T_DATA, template < typename > class ALLOC >
514  const IDatabaseTable< T_DATA, ALLOC >& from,
515  const typename IDatabaseTable< T_DATA, ALLOC >::allocator_type& alloc) :
516  ALLOC< T_DATA >(alloc),
522  // create the end iterators
524 
526  }
527 
528 
529  // copy constructor
530  template < typename T_DATA, template < typename > class ALLOC >
533 
534 
535  // move constructor with a given allocator
536  template < typename T_DATA, template < typename > class ALLOC >
539  const typename IDatabaseTable< T_DATA, ALLOC >::allocator_type& alloc) :
540  ALLOC< T_DATA >(alloc),
547  // create the end iterators
549 
551  }
552 
553 
554  // move constructor
555  template < typename T_DATA, template < typename > class ALLOC >
558 
559 
560  // destructor
561  template < typename T_DATA, template < typename > class ALLOC >
563  // indicate to all the handlers that we are destructing the database
565  for (auto handler: _list_of_safe_handlers_) {
566  handler->_db_ = nullptr;
567  handler->_row_ = nullptr;
568  handler->_end_index_ = 0;
569  handler->_index_ = 0;
570  }
572 
576 
580 
582  }
583 
584 
585  // copy operator
586  template < typename T_DATA, template < typename > class ALLOC >
589  if (this != &from) {
590  // invalidate the current handlers
592  for (auto handler: _list_of_safe_handlers_) {
593  handler->_db_ = nullptr;
594  handler->_row_ = nullptr;
595  handler->_end_index_ = 0;
596  handler->_index_ = 0;
597  }
600 
601  rows_ = from.rows_;
607 
608  // update the end iterators
609  const std::size_t db_size = rows_.size();
610  _end_->_index_ = db_size;
614  }
615 
616  return *this;
617  }
618 
619 
620  // move operator
621  template < typename T_DATA, template < typename > class ALLOC >
624  if (this != &from) {
625  // invalidate the current handlers
627  for (auto handler: _list_of_safe_handlers_) {
628  handler->_db_ = nullptr;
629  handler->_row_ = nullptr;
630  handler->_end_index_ = 0;
631  handler->_index_ = 0;
632  }
634 
635  rows_ = std::move(from.rows_);
641 
642  // update the end iterators
643  const std::size_t db_size = rows_.size();
644  _end_->_index_ = db_size;
648  }
649 
650  return *this;
651  }
652 
653 
654  // returns a new unsafe handler pointing to the beginning of the database
655  template < typename T_DATA, template < typename > class ALLOC >
657  IDatabaseTable< T_DATA, ALLOC >::begin() const {
658  return Handler(*this);
659  }
660 
661 
662  // returns a new safe handler pointing to the beginning of the database
663  template < typename T_DATA, template < typename > class ALLOC >
665  IDatabaseTable< T_DATA, ALLOC >::beginSafe() const {
666  return HandlerSafe(*this);
667  }
668 
669 
670  // returns a new unsafe handler pointing to the end of the database
671  template < typename T_DATA, template < typename > class ALLOC >
672  INLINE const typename IDatabaseTable< T_DATA, ALLOC >::Handler&
673  IDatabaseTable< T_DATA, ALLOC >::end() const noexcept {
674  return *_end_;
675  }
676 
677 
678  /// returns a new safe handler pointing to the beginning of the database
679  template < typename T_DATA, template < typename > class ALLOC >
680  INLINE const typename IDatabaseTable< T_DATA, ALLOC >::HandlerSafe&
681  IDatabaseTable< T_DATA, ALLOC >::endSafe() const noexcept {
682  return *_end_safe_;
683  }
684 
685 
686  // returns a new unsafe handler on the database
687  template < typename T_DATA, template < typename > class ALLOC >
689  IDatabaseTable< T_DATA, ALLOC >::handler() const {
690  return Handler(*this);
691  }
692 
693 
694  // returns a new safe handler on the database
695  template < typename T_DATA, template < typename > class ALLOC >
697  IDatabaseTable< T_DATA, ALLOC >::handlerSafe() const {
698  return HandlerSafe(*this);
699  }
700 
701 
702  // returns the content of the database
703  template < typename T_DATA, template < typename > class ALLOC >
704  INLINE const typename IDatabaseTable< T_DATA, ALLOC >::template Matrix< T_DATA >&
705  IDatabaseTable< T_DATA, ALLOC >::content() const noexcept {
706  return rows_;
707  }
708 
709 
710  /// indicates whether the database contains some missing values
711  template < typename T_DATA, template < typename > class ALLOC >
712  bool IDatabaseTable< T_DATA, ALLOC >::hasMissingValues() const {
713  for (const auto& status: has_row_missing_val_)
714  if (status == IsMissing::True) return true;
715  return false;
716  }
717 
718 
719  /// indicates whether the kth row contains some missing values
720  template < typename T_DATA, template < typename > class ALLOC >
721  INLINE bool IDatabaseTable< T_DATA, ALLOC >::hasMissingValues(const std::size_t k) const {
722  return has_row_missing_val_[k] == IsMissing::True;
723  }
724 
725 
726  // returns the variable names for all the columns
727  template < typename T_DATA, template < typename > class ALLOC >
728  INLINE const std::vector< std::string, ALLOC< std::string > >&
729  IDatabaseTable< T_DATA, ALLOC >::variableNames() const noexcept {
730  return variable_names_;
731  }
732 
733 
734  // sets the names of the variables
735  template < typename T_DATA, template < typename > class ALLOC >
736  template < template < typename > class OTHER_ALLOC >
738  const std::vector< std::string, OTHER_ALLOC< std::string > >& names,
739  const bool from_external_object) {
740  // copy the variable names into a vector allocated with the allocator
741  // used by the database
742  const std::size_t size = names.size();
744  for (std::size_t i = 0; i < size; ++i)
745  variable_names[i] = names[i];
746 
748  }
749 
750 
751  /// returns the name of the kth column of the database
752  template < typename T_DATA, template < typename > class ALLOC >
753  INLINE const std::string&
754  IDatabaseTable< T_DATA, ALLOC >::variableName(const std::size_t k) const {
755  if (variable_names_.size() <= k)
756  GUM_ERROR(OutOfBounds, "the database does not contain Column #" << k)
757  return variable_names_[k];
758  }
759 
760 
761  /// returns the index of the column whose name is passed in argument
762  template < typename T_DATA, template < typename > class ALLOC >
763  INLINE std::size_t
765  const std::size_t size = variable_names_.size();
766  for (std::size_t i = 0; i < size; ++i)
767  if (variable_names_[i] == name) return i;
768 
769  GUM_ERROR(UndefinedElement, "the database contains no column whose name is " << name)
770  }
771 
772 
773  /// returns the indices of the columns whose name is passed in argument
774  template < typename T_DATA, template < typename > class ALLOC >
775  INLINE typename IDatabaseTable< T_DATA, ALLOC >::template DBVector< std::size_t >
777  const std::size_t size = variable_names_.size();
778  DBVector< std::size_t > cols;
779  for (std::size_t i = 0; i < size; ++i)
780  if (variable_names_[i] == name) cols.push_back(i);
781 
782  if (cols.empty())
783  GUM_ERROR(UndefinedElement, "the database contains no column whose name is " << name)
784 
785  return cols;
786  }
787 
788 
789  // returns the number of variables (columns) of the database
790  template < typename T_DATA, template < typename > class ALLOC >
791  INLINE std::size_t IDatabaseTable< T_DATA, ALLOC >::nbVariables() const noexcept {
792  return variable_names_.size();
793  }
794 
795 
796  // returns the number of records in the database
797  template < typename T_DATA, template < typename > class ALLOC >
798  INLINE std::size_t IDatabaseTable< T_DATA, ALLOC >::size() const noexcept {
799  return rows_.size();
800  }
801 
802 
803  // returns the number of records in the database
804  template < typename T_DATA, template < typename > class ALLOC >
805  INLINE std::size_t IDatabaseTable< T_DATA, ALLOC >::nbRows() const noexcept {
806  return rows_.size();
807  }
808 
809 
810  // indicates whether the database contains some records or not
811  template < typename T_DATA, template < typename > class ALLOC >
812  INLINE bool IDatabaseTable< T_DATA, ALLOC >::empty() const noexcept {
813  return rows_.empty();
814  }
815 
816 
817  // update the handlers when the size of the database changes
818  template < typename T_DATA, template < typename > class ALLOC >
820  const std::size_t db_size = rows_.size();
821 
823  for (auto handler: _list_of_safe_handlers_) {
826  // there is no need to update the index because, in safe handlers,
827  // we always check that the index is less than end_index when trying
828  // to access the rows
829  }
830  }
832 
833  // update the end iterators
838  }
839 
840 
841  // attach a new handler to the database
842  template < typename T_DATA, template < typename > class ALLOC >
847  }
848 
849 
850  // detach a handler
851  template < typename T_DATA, template < typename > class ALLOC >
854 
856  ++iter) {
857  if (*iter == handler) {
860  break;
861  }
862  }
863 
865  }
866 
867 
868  // checks whether a new row has the same size as the rest of the database
869  template < typename T_DATA, template < typename > class ALLOC >
870  INLINE bool IDatabaseTable< T_DATA, ALLOC >::isRowSizeOK_(const std::size_t size) const {
871  return (size == variable_names_.size());
872  }
873 
874 
875  // insert a new row at the end of the database
876  template < typename T_DATA, template < typename > class ALLOC >
877  template < template < typename > class OTHER_ALLOC >
879  const std::vector< std::string, OTHER_ALLOC< std::string > >& new_row) {
880  const std::size_t size = new_row.size();
882  for (std::size_t i = 0; i < size; ++i)
884  this->insertRow(good_typed_row);
885  }
886 
887 
888  // insert a new DBRow at the end of the database
889  template < typename T_DATA, template < typename > class ALLOC >
891  typename IDatabaseTable< T_DATA, ALLOC >::template Row< T_DATA >&& new_row,
892  const typename IDatabaseTable< T_DATA, ALLOC >::IsMissing contains_missing) {
893  // check that the size of the row is the same as the rest of the database
894  if (!isRowSizeOK_(new_row.size()))
896  "the new row is of size " << new_row.size()
897  << ", which is different from the number of columns "
898  << "of the database, i.e., " << variable_names_.size());
899 
900  _updateHandlers_(rows_.size() + 1);
902  try {
904  } catch (...) {
905  rows_.pop_back();
906  throw;
907  }
908  }
909 
910 
911  // insert a new DBRow at the end of the database
912  template < typename T_DATA, template < typename > class ALLOC >
914  const typename IDatabaseTable< T_DATA, ALLOC >::template Row< T_DATA >& row,
915  const typename IDatabaseTable< T_DATA, ALLOC >::IsMissing contains_missing) {
916  this->insertRow(typename IDatabaseTable< T_DATA, ALLOC >::template Row< T_DATA >(row),
918  }
919 
920 
921  // insert a set of new DBRow at the end of the database
922  template < typename T_DATA, template < typename > class ALLOC >
924  typename IDatabaseTable< T_DATA, ALLOC >::template Matrix< T_DATA >&& new_rows,
925  const typename IDatabaseTable< T_DATA, ALLOC >::template DBVector<
927  if (new_rows.empty()) return;
928 
929  // check that the missing values indicators vector has the same size
930  // as the new rows
933  "the number of new rows (i.e., "
934  << new_rows.size()
935  << ") is different from the number of missing values indicators ("
937 
938  // check that all the rows have the same size
939  const std::size_t new_size = new_rows[0].size();
940 
941  for (const auto& row: new_rows) {
942  if (row.size() != new_size) {
943  GUM_ERROR(SizeError, "all the new rows do not have the same number of columns")
944  }
945  }
946 
947  // check that the sizes of the new rows are the same as the rest of
948  // the database
949  if (!isRowSizeOK_(new_size)) {
951  "the new rows have " << new_size
952  << " columns, which is different from the number of columns "
953  << "of the database, i.e., " << variable_names_.size());
954  }
955 
956  const std::size_t nb_new_rows = new_rows.size();
958 
961 
962  for (std::size_t i = std::size_t(0); i < nb_new_rows; ++i) {
965  }
966 
968  }
969 
970 
971  // insert a set of new DBRow at the end of the database
972  template < typename T_DATA, template < typename > class ALLOC >
974  const typename IDatabaseTable< T_DATA, ALLOC >::template Matrix< T_DATA >& new_rows,
975  const typename IDatabaseTable< T_DATA, ALLOC >::template DBVector<
977  if (new_rows.empty()) return;
978 
979  // check that the missing values indicators vector has the same size
980  // as the new rows
983  "the number of new rows (i.e., "
984  << new_rows.size()
985  << ") is different from the number of missing values indicators ("
987 
988  // check that all the rows have the same size
989  const std::size_t new_size = new_rows[0].size();
990 
991  for (const auto& row: new_rows) {
992  if (row.size() != new_size) {
993  GUM_ERROR(SizeError, "all the new rows do not have the same number of columns")
994  }
995  }
996 
997  // check that the sizes of the new rows are the same as the rest of
998  // the database
999  std::size_t db_size = rows_.size();
1000 
1001  if (!isRowSizeOK_(new_size)) {
1003  "the new rows have " << new_size
1004  << " columns, which is different from the number of columns "
1005  << "of the database, i.e., " << variable_names_.size());
1006  }
1007 
1008  const std::size_t nb_new_rows = new_rows.size();
1009  const std::size_t new_db_size = rows_.size() + nb_new_rows;
1010 
1013 
1014  for (std::size_t i = std::size_t(0); i < nb_new_rows; ++i) {
1017  }
1018 
1020  }
1021 
1022 
1023  // erase a given row
1024  template < typename T_DATA, template < typename > class ALLOC >
1026  const std::size_t db_size = rows_.size();
1027 
1028  if (index < db_size) {
1030  rows_.erase(rows_.begin() + index);
1032  }
1033  }
1034 
1035 
1036  // erase the last row
1037  template < typename T_DATA, template < typename > class ALLOC >
1039  const std::size_t db_size = rows_.size();
1040 
1041  if (db_size) {
1043  rows_.pop_back();
1045  }
1046  }
1047 
1048 
1049  // erase the first row
1050  template < typename T_DATA, template < typename > class ALLOC >
1052  const std::size_t db_size = rows_.size();
1053 
1054  if (db_size) {
1056  rows_.erase(rows_.begin());
1058  }
1059  }
1060 
1061 
1062  // erase all the rows
1063  template < typename T_DATA, template < typename > class ALLOC >
1065  _updateHandlers_(0);
1066  rows_.clear();
1068  }
1069 
1070 
1071  // erase the k first rows
1072  template < typename T_DATA, template < typename > class ALLOC >
1074  const std::size_t db_size = rows_.size();
1075 
1076  if (nb_rows >= db_size) {
1077  eraseAllRows();
1078  } else {
1083  }
1084  }
1085 
1086 
1087  // erase the k last rows
1088  template < typename T_DATA, template < typename > class ALLOC >
1090  const std::size_t db_size = rows_.size();
1091 
1092  if (nb_rows >= db_size) {
1093  eraseAllRows();
1094  } else {
1099  }
1100  }
1101 
1102 
1103  // erase the rows from the debth to the endth (not included)
1104  template < typename T_DATA, template < typename > class ALLOC >
1106  if (deb > end) std::swap(deb, end);
1107 
1108  const std::size_t db_size = rows_.size();
1109 
1110  if (end >= db_size) {
1111  if (deb >= db_size) {
1112  return;
1113  } else {
1115  }
1116  } else {
1118  rows_.erase(rows_.begin() + deb, rows_.begin() + end);
1121  }
1122  }
1123 
1124 
1125  // erase the content of the database, including the names of the variables
1126  template < typename T_DATA, template < typename > class ALLOC >
1127  INLINE void IDatabaseTable< T_DATA, ALLOC >::clear() {
1128  _updateHandlers_(0);
1129  rows_.clear();
1132  }
1133 
1134 
1135  // returns the set of symbols for the missing values
1136  template < typename T_DATA, template < typename > class ALLOC >
1137  INLINE const std::vector< std::string, ALLOC< std::string > >&
1138  IDatabaseTable< T_DATA, ALLOC >::missingSymbols() const {
1139  return missing_symbols_;
1140  }
1141 
1142 
1143  /// changes the max number of threads that a database can use
1144  template < typename T_DATA, template < typename > class ALLOC >
1145  void IDatabaseTable< T_DATA, ALLOC >::setMaxNbThreads(const std::size_t nb) const {
1146  if (nb == std::size_t(0))
1147  max_nb_threads_ = std::size_t(1);
1148  else
1149  max_nb_threads_ = nb;
1150  }
1151 
1152 
1153  /// returns the number of threads used to parse the database
1154  template < typename T_DATA, template < typename > class ALLOC >
1156  return max_nb_threads_;
1157  }
1158 
1159 
1160  /** @brief changes the number min of rows a thread should process in a
1161  * multithreading context */
1162  template < typename T_DATA, template < typename > class ALLOC >
1163  void IDatabaseTable< T_DATA, ALLOC >::setMinNbRowsPerThread(const std::size_t nb) const {
1164  if (nb == std::size_t(0))
1166  else
1168  }
1169 
1170 
1171  /// returns the minimum of rows that each thread should process
1172  template < typename T_DATA, template < typename > class ALLOC >
1174  return min_nb_rows_per_thread_;
1175  }
1176 
1177 
1178  /// insert new rows at the end of the database
1179  template < template < typename > class ALLOC >
1181  const typename IDatabaseTableInsert4DBCell< ALLOC, true >::template DBVector<
1182  DBVector< std::string > >& new_rows) {
1183  for (const auto& new_row: new_rows)
1184  this->insertRow(new_row);
1185  }
1186 
1187 
1188  /// insert new rows at the end of the database
1189  template < template < typename > class ALLOC >
1191  const typename IDatabaseTableInsert4DBCell< ALLOC, false >::template DBVector<
1192  DBVector< std::string > >& new_rows) {
1193  for (const auto& new_row: new_rows)
1194  this->insertRow(new_row);
1195  }
1196 
1197 
1198  /// assign a given weight to all the rows of the database
1199  template < typename T_DATA, template < typename > class ALLOC >
1200  void IDatabaseTable< T_DATA, ALLOC >::setAllRowsWeight(const double new_weight) {
1201  // determine the number of threads to use and the number of rows
1202  // they should process
1203  std::vector< std::pair< std::size_t, std::size_t > > ranges;
1204  const std::size_t db_size = nbRows();
1206  if (nb_threads < 1)
1207  nb_threads = 1;
1208  else if (nb_threads > max_nb_threads_)
1212 
1213  // assign to threads the ranges over which they should change the
1214  // rows weights
1215  std::size_t begin_index = std::size_t(0);
1216  for (std::size_t i = std::size_t(0); i < nb_threads; ++i) {
1218  if (rest_rows != std::size_t(0)) {
1219  ++end_index;
1220  --rest_rows;
1221  }
1224  }
1225 
1226  // perform the assignment:
1227  // launch the threads
1228  // here we use openMP for launching the threads because, experimentally,
1229  // it seems to provide results that are twice as fast as the results
1230  // with the std::thread
1231 # pragma omp parallel num_threads(int(nb_threads))
1232  {
1233  // get the number of the thread
1237 
1238  for (std::size_t i = begin_index; i < end_index; ++i) {
1240  }
1241  }
1242  }
1243 
1244  /// assigns a given weight to the ith row of the database
1245  template < typename T_DATA, template < typename > class ALLOC >
1246  void IDatabaseTable< T_DATA, ALLOC >::setWeight(const std::size_t i, const double weight) {
1247  // check that i is less than the number of rows
1248  const std::size_t dbsize = nbRows();
1249  if (i >= dbsize) {
1251  "it is impossible to set the weight of record #"
1252  << i << " because the database contains only " << nbRows() << " records");
1253  }
1254 
1255  // check that the weight is positive
1256  if (weight < 0) {
1258  "it is impossible to set " << weight << " as a weight of record #" << i
1259  << " because this weight is negative");
1260  }
1261 
1262  rows_[i].setWeight(weight);
1263  }
1264 
1265 
1266  /// returns the weight of the ith record
1267  template < typename T_DATA, template < typename > class ALLOC >
1268  double IDatabaseTable< T_DATA, ALLOC >::weight(const std::size_t i) const {
1269  // check that i is less than the number of rows
1270  const std::size_t dbsize = nbRows();
1271  if (i >= dbsize) {
1273  "it is impossible to get the weight of record #"
1274  << i << " because the database contains only " << nbRows() << " records");
1275  }
1276 
1277  return rows_[i].weight();
1278  }
1279 
1280 
1281  /// returns the weight of the whole database
1282  template < typename T_DATA, template < typename > class ALLOC >
1283  double IDatabaseTable< T_DATA, ALLOC >::weight() const {
1284  double w = 0.0;
1285  for (const auto& row: rows_)
1286  w += row.weight();
1287  return w;
1288  }
1289 
1290 
1291  } /* namespace learning */
1292 
1293 } /* namespace gum */
1294 
1295 #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)