aGrUM 3.1.1
a C++ library for (probabilistic) graphical models
IDatabaseTable_tpl.h
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2026 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2026 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40
41#pragma once
42
43
50
51#ifndef DOXYGEN_SHOULD_SKIP_THIS
52
53namespace gum {
54
55 namespace learning {
56
57 // ===========================================================================
58 // Unsafe handlers
59 // ===========================================================================
60
61 // default constructor
62 template < typename T_DATA >
64 DBHandler< T_DATA >(), _db_(&db), _row_(&(db.content())),
65 _end_index_(std::size_t(_row_->size())) {
66 GUM_CONSTRUCTOR(IDatabaseTable::Handler);
67 }
68
69 // copy constructor
70 template < typename T_DATA >
71 IDatabaseTable< T_DATA >::Handler::Handler(
72 const typename IDatabaseTable< T_DATA >::Handler& h) :
73 DBHandler< T_DATA >(), _db_(h._db_), _row_(h._row_), _index_(h._index_),
74 _begin_index_(h._begin_index_), _end_index_(h._end_index_) {
75 GUM_CONS_CPY(IDatabaseTable::Handler);
76 }
77
78 // move constructor
79 template < typename T_DATA >
80 IDatabaseTable< T_DATA >::Handler::Handler(typename IDatabaseTable< T_DATA >::Handler&& h) :
81 DBHandler< T_DATA >(), _db_(h._db_), _row_(h._row_), _index_(h._index_),
82 _begin_index_(h._begin_index_), _end_index_(h._end_index_) {
83 GUM_CONS_MOV(IDatabaseTable::Handler);
84 }
85
86 // destructor
87 template < typename T_DATA >
88 IDatabaseTable< T_DATA >::Handler::~Handler() {
89 GUM_DESTRUCTOR(IDatabaseTable::Handler);
90 }
91
92 // copy operator
93 template < typename T_DATA >
94 typename IDatabaseTable< T_DATA >::Handler& IDatabaseTable< T_DATA >::Handler::operator=(
95 const typename IDatabaseTable< T_DATA >::Handler& h) {
96 _db_ = h._db_;
97 _row_ = h._row_;
98 _index_ = h._index_;
99 _begin_index_ = h._begin_index_;
100 _end_index_ = h._end_index_;
101 return *this;
102 }
103
104 // move operator
105 template < typename T_DATA >
106 typename IDatabaseTable< T_DATA >::Handler& IDatabaseTable< T_DATA >::Handler::operator=(
107 typename IDatabaseTable< T_DATA >::Handler&& h) {
108 _db_ = h._db_;
109 _row_ = h._row_;
110 _index_ = h._index_;
111 _begin_index_ = h._begin_index_;
112 _end_index_ = h._end_index_;
113 return *this;
114 }
115
116 // returns the current row pointed to by the handler
117 template < typename T_DATA >
118 typename IDatabaseTable< T_DATA >::Handler::const_reference
119 IDatabaseTable< T_DATA >::Handler::operator*() const {
120 return _row_->operator[](_index_);
121 }
122
123 // Dereferences the value pointed to by the handler (unsafe version)
124 template < typename T_DATA >
125 typename IDatabaseTable< T_DATA >::Handler::const_pointer
126 IDatabaseTable< T_DATA >::Handler::operator->() const {
127 return &(_row_->operator[](_index_));
128 }
129
130 // makes the handler point to the next row
131 template < typename T_DATA >
132 typename IDatabaseTable< T_DATA >::Handler& IDatabaseTable< T_DATA >::Handler::operator++() {
133 ++_index_;
134 return *this;
135 }
136
137 // makes the handler point to the previous row
138 template < typename T_DATA >
139 typename IDatabaseTable< T_DATA >::Handler& IDatabaseTable< T_DATA >::Handler::operator--() {
140 if (_index_ > _begin_index_) --_index_;
141 return *this;
142 }
143
144 // moves the handler by i rows
145 template < typename T_DATA >
146 typename IDatabaseTable< T_DATA >::Handler&
147 IDatabaseTable< T_DATA >::Handler::operator+=(const std::size_t i) {
148 _index_ += i;
149 return *this;
150 }
151
152 // moves back the handler by i rows
153 template < typename T_DATA >
154 typename IDatabaseTable< T_DATA >::Handler&
155 IDatabaseTable< T_DATA >::Handler::operator-=(const std::size_t i) {
156 if (_index_ >= _begin_index_ + i) _index_ -= i;
157 else _index_ = _begin_index_;
158 return *this;
159 }
160
161 // checks whether two handlers point on the same row
162 template < typename T_DATA >
163 bool IDatabaseTable< T_DATA >::Handler::operator==(const Handler& handler) const {
164 return _index_ == handler._index_;
165 }
166
167 // checks whether two handlers point to different rows
168 template < typename T_DATA >
169 bool IDatabaseTable< T_DATA >::Handler::operator!=(const Handler& handler) const {
170 return _index_ != handler._index_;
171 }
172
173 // returns the number of rows managed by the handler
174 template < typename T_DATA >
175 std::size_t IDatabaseTable< T_DATA >::Handler::size() const {
176 return _end_index_ - _begin_index_;
177 }
178
179 // return the number of rows of the whole database
180 template < typename T_DATA >
181 std::size_t IDatabaseTable< T_DATA >::Handler::DBSize() const {
182 if (_row_ != nullptr) return _row_->size();
183 else return std::size_t(0);
184 }
185
186 // returns the current row pointed to by the handler
187 template < typename T_DATA >
188 typename IDatabaseTable< T_DATA >::Handler::const_reference
189 IDatabaseTable< T_DATA >::Handler::rowSafe() const {
190 if (_index_ >= _end_index_) { GUM_ERROR(OutOfBounds, "the handler has reached its end") }
191
192 return _row_->operator[](_index_);
193 }
194
195 // returns the current row pointed to by the handler
196 template < typename T_DATA >
197 typename IDatabaseTable< T_DATA >::Handler::reference
198 IDatabaseTable< T_DATA >::Handler::rowSafe() {
199 if (_index_ >= _end_index_) { GUM_ERROR(OutOfBounds, "the handler has reached its end") }
200
201 return const_cast< Matrix< T_DATA >* >(_row_)->operator[](_index_);
202 }
203
204 // returns the current row pointed to by the handler (unsafe version)
205 template < typename T_DATA >
206 typename IDatabaseTable< T_DATA >::Handler::const_reference
207 IDatabaseTable< T_DATA >::Handler::row() const {
208 return _row_->operator[](_index_);
209 }
210
211 // returns the current row pointed to by the handler (unsafe version)
212 template < typename T_DATA >
213 typename IDatabaseTable< T_DATA >::Handler::reference IDatabaseTable< T_DATA >::Handler::row() {
214 return const_cast< Matrix< T_DATA >* >(_row_)->operator[](_index_);
215 }
216
217 // makes the handler point to the next row
218 template < typename T_DATA >
219 void IDatabaseTable< T_DATA >::Handler::nextRow() {
220 ++_index_;
221 }
222
223 // returns the number of the current row
224 template < typename T_DATA >
225 std::size_t IDatabaseTable< T_DATA >::Handler::numRow() const {
226 return (_index_ >= _begin_index_) ? _index_ - _begin_index_ : 0;
227 }
228
229 // indicates whether the handler has reached its end or not
230 template < typename T_DATA >
231 bool IDatabaseTable< T_DATA >::Handler::hasRows() const {
232 return (_index_ < _end_index_);
233 }
234
235 // puts the handler to the beginning of the database area it handles
236 template < typename T_DATA >
237 void IDatabaseTable< T_DATA >::Handler::reset() {
238 _index_ = _begin_index_;
239 }
240
241 // returns a new handler that points to the beginning of the
242 // database area of the current handler */
243 template < typename T_DATA >
244 typename IDatabaseTable< T_DATA >::Handler IDatabaseTable< T_DATA >::Handler::begin() const {
245 Handler handler(*this);
246 handler.reset();
247 return handler;
248 }
249
250 // returns a new handler that points to the end of the
251 // database area of the current handler */
252 template < typename T_DATA >
253 typename IDatabaseTable< T_DATA >::Handler IDatabaseTable< T_DATA >::Handler::end() const {
254 Handler handler(*this);
255 handler._index_ = _end_index_;
256 return handler;
257 }
258
259 // sets the area in the database the handler will handle
260 template < typename T_DATA >
261 void IDatabaseTable< T_DATA >::Handler::setRange(std::size_t first, std::size_t last) {
262 if (first > last) std::swap(first, last);
263
264 // check that the end belongs to the database, else raise an exception
265 if (_row_ == nullptr) GUM_ERROR(NullElement, "the handler does not point to any database")
266
267 if (last > _row_->size())
269 "the database has fewer rows (" << _row_->size() << ") than the upper range ("
270 << last << ") specified to the handler")
271
272 _begin_index_ = first;
273 _end_index_ = last;
274 _index_ = first;
275 }
276
277 // returns the current range of the handler
278 template < typename T_DATA >
279 std::pair< std::size_t, std::size_t > IDatabaseTable< T_DATA >::Handler::range() const {
280 return std::pair< std::size_t, std::size_t >(_begin_index_, _end_index_);
281 }
282
283 // returns the names of the variables
284 template < typename T_DATA >
285 const typename IDatabaseTable< T_DATA >::Handler::template DBVector< std::string >&
286 IDatabaseTable< T_DATA >::Handler::variableNames() const {
287 return _db_->variableNames();
288 }
289
290 // returns the number of variables (columns) of the database
291 template < typename T_DATA >
292 std::size_t IDatabaseTable< T_DATA >::Handler::nbVariables() const {
293 if (_db_ != nullptr) return _db_->variableNames().size();
294 else return 0;
295 }
296
297 // returns a pointer on the database
298 template < typename T_DATA >
299 const IDatabaseTable< T_DATA >& IDatabaseTable< T_DATA >::Handler::database() const {
300 if (_db_ == nullptr) {
301 GUM_ERROR(NullElement, "The database handler does not point toward a database")
302 }
303 return *_db_;
304 }
305
306 // ===========================================================================
307 // Safe handlers
308 // ===========================================================================
309
310 // attach a new handler to the database
311 template < typename T_DATA >
312 void IDatabaseTable< T_DATA >::HandlerSafe::_attachHandler_() {
313 if (this->_db_ != nullptr) { this->_db_->_attachHandler_(this); }
314 }
315
316 // detach a handler
317 template < typename T_DATA >
318 void IDatabaseTable< T_DATA >::HandlerSafe::_detachHandler_() {
319 if (this->_db_ != nullptr) { this->_db_->_detachHandler_(this); }
320 }
321
322 // default constructor
323 template < typename T_DATA >
324 IDatabaseTable< T_DATA >::HandlerSafe::HandlerSafe(const IDatabaseTable< T_DATA >& db) :
325 IDatabaseTable< T_DATA >::Handler(db) {
326 _attachHandler_();
327 GUM_CONSTRUCTOR(IDatabaseTable::HandlerSafe);
328 }
329
330 // copy constructor
331 template < typename T_DATA >
332 IDatabaseTable< T_DATA >::HandlerSafe::HandlerSafe(
333 const typename IDatabaseTable< T_DATA >::HandlerSafe& h) :
334 IDatabaseTable< T_DATA >::Handler(h) {
335 _attachHandler_();
336 GUM_CONS_CPY(IDatabaseTable::HandlerSafe);
337 }
338
339 // move constructor
340 template < typename T_DATA >
341 IDatabaseTable< T_DATA >::HandlerSafe::HandlerSafe(
342 typename IDatabaseTable< T_DATA >::HandlerSafe&& h) :
343 IDatabaseTable< T_DATA >::Handler(std::move(h)) {
344 _attachHandler_();
345 GUM_CONS_MOV(IDatabaseTable::HandlerSafe);
346 }
347
348 // destructor
349 template < typename T_DATA >
350 IDatabaseTable< T_DATA >::HandlerSafe::~HandlerSafe() {
351 _detachHandler_();
352 GUM_DESTRUCTOR(IDatabaseTable::HandlerSafe);
353 }
354
355 // copy operator
356 template < typename T_DATA >
357 typename IDatabaseTable< T_DATA >::HandlerSafe&
358 IDatabaseTable< T_DATA >::HandlerSafe::operator=(
359 const typename IDatabaseTable< T_DATA >::HandlerSafe& h) {
360 if (this->_db_ != h._db_) {
361 _detachHandler_();
362 this->_db_ = h._db_;
363 _attachHandler_();
364 }
365
366 IDatabaseTable< T_DATA >::Handler::operator=(h);
367 return *this;
368 }
369
370 // copy operator
371 template < typename T_DATA >
372 typename IDatabaseTable< T_DATA >::HandlerSafe&
373 IDatabaseTable< T_DATA >::HandlerSafe::operator=(
374 const typename IDatabaseTable< T_DATA >::Handler& h) {
375 return this->operator=(dynamic_cast< const IDatabaseTable< T_DATA >::HandlerSafe& >(h));
376 }
377
378 // move operator
379 template < typename T_DATA >
380 typename IDatabaseTable< T_DATA >::HandlerSafe&
381 IDatabaseTable< T_DATA >::HandlerSafe::operator=(
382 typename IDatabaseTable< T_DATA >::HandlerSafe&& h) {
383 if (this->_db_ != h._db_) {
384 _detachHandler_();
385 this->_db_ = h._db_;
386 _attachHandler_();
387 }
388
389 IDatabaseTable< T_DATA >::Handler::operator=(std::move(h));
390 return *this;
391 }
392
393 // move operator
394 template < typename T_DATA >
395 typename IDatabaseTable< T_DATA >::HandlerSafe&
396 IDatabaseTable< T_DATA >::HandlerSafe::operator=(
397 typename IDatabaseTable< T_DATA >::Handler&& h) {
398 return this->operator=(std::move(dynamic_cast< IDatabaseTable< T_DATA >::HandlerSafe& >(h)));
399 }
400
401 // ===========================================================================
402 // Database Tables
403 // ===========================================================================
404
405 // create the end iterators
406 template < typename T_DATA >
407 void IDatabaseTable< T_DATA >::_createEndIterators_() {
408 _end_ = new iterator(*this);
409 try {
410 _end_safe_ = new iterator_safe(*this);
411 } catch (...) {
412 delete _end_;
413 throw;
414 }
415 }
416
417 // default constructor
418 template < typename T_DATA >
419 IDatabaseTable< T_DATA >::IDatabaseTable(
420 const typename IDatabaseTable< T_DATA >::MissingValType& missing_symbols,
421 const std::vector< std::string >& var_names) :
422 variable_names_(var_names), missing_symbols_(missing_symbols) {
423 // create the end iterators
424 _createEndIterators_();
425
426 GUM_CONSTRUCTOR(IDatabaseTable);
427 }
428
429 // copy constructor
430 template < typename T_DATA >
431 IDatabaseTable< T_DATA >::IDatabaseTable(const IDatabaseTable< T_DATA >& from) :
432 variable_names_(from.variable_names_), rows_(from.rows_),
433 missing_symbols_(from.missing_symbols_), has_row_missing_val_(from.has_row_missing_val_),
434 max_nb_threads_(from.max_nb_threads_),
435 min_nb_rows_per_thread_(from.min_nb_rows_per_thread_) {
436 // create the end iterators
437 _createEndIterators_();
438
439 GUM_CONS_CPY(IDatabaseTable);
440 }
441
442 // move constructor
443 template < typename T_DATA >
444 IDatabaseTable< T_DATA >::IDatabaseTable(IDatabaseTable< T_DATA >&& from) :
445 variable_names_(std::move(from.variable_names_)), rows_(std::move(from.rows_)),
446 missing_symbols_(std::move(from.missing_symbols_)),
447 has_row_missing_val_(std::move(from.has_row_missing_val_)),
448 max_nb_threads_(from.max_nb_threads_),
449 min_nb_rows_per_thread_(from.min_nb_rows_per_thread_) {
450 // create the end iterators
451 _createEndIterators_();
452
453 GUM_CONS_MOV(IDatabaseTable);
454 }
455
456 // destructor
457 template < typename T_DATA >
458 IDatabaseTable< T_DATA >::~IDatabaseTable() {
459 // indicate to all the handlers that we are destructing the database
460 _safe_handlers_mutex_.lock();
461 for (auto handler: _list_of_safe_handlers_) {
462 handler->_db_ = nullptr;
463 handler->_row_ = nullptr;
464 handler->_end_index_ = 0;
465 handler->_index_ = 0;
466 }
467 _safe_handlers_mutex_.unlock();
468
469 delete _end_;
470 delete _end_safe_;
471
472 GUM_DESTRUCTOR(IDatabaseTable);
473 }
474
475 // copy operator
476 template < typename T_DATA >
477 IDatabaseTable< T_DATA >&
478 IDatabaseTable< T_DATA >::operator=(const IDatabaseTable< T_DATA >& from) {
479 if (this != &from) {
480 // invalidate the current handlers
481 _safe_handlers_mutex_.lock();
482 for (auto handler: _list_of_safe_handlers_) {
483 handler->_db_ = nullptr;
484 handler->_row_ = nullptr;
485 handler->_end_index_ = 0;
486 handler->_index_ = 0;
487 }
488 _list_of_safe_handlers_.clear();
489 _safe_handlers_mutex_.unlock();
490
491 rows_ = from.rows_;
492 variable_names_ = from.variable_names_;
493 missing_symbols_ = from.missing_symbols_;
494 has_row_missing_val_ = from.has_row_missing_val_;
495 max_nb_threads_ = from.max_nb_threads_;
496 min_nb_rows_per_thread_ = from.min_nb_rows_per_thread_;
497
498 // update the end iterators
499 const std::size_t db_size = rows_.size();
500 _end_->_index_ = db_size;
501 _end_->_end_index_ = db_size;
502 _end_safe_->_index_ = db_size;
503 _end_safe_->_end_index_ = db_size;
504 }
505
506 return *this;
507 }
508
509 // move operator
510 template < typename T_DATA >
511 IDatabaseTable< T_DATA >& IDatabaseTable< T_DATA >::operator=(IDatabaseTable< T_DATA >&& from) {
512 if (this != &from) {
513 // invalidate the current handlers
514 _safe_handlers_mutex_.lock();
515 for (auto handler: _list_of_safe_handlers_) {
516 handler->_db_ = nullptr;
517 handler->_row_ = nullptr;
518 handler->_end_index_ = 0;
519 handler->_index_ = 0;
520 }
521 _safe_handlers_mutex_.unlock();
522
523 rows_ = std::move(from.rows_);
524 variable_names_ = std::move(from.variable_names_);
525 missing_symbols_ = std::move(from.missing_symbols_);
526 has_row_missing_val_ = std::move(from.has_row_missing_val_);
527 max_nb_threads_ = from.max_nb_threads_;
528 min_nb_rows_per_thread_ = from.min_nb_rows_per_thread_;
529
530 // update the end iterators
531 const std::size_t db_size = rows_.size();
532 _end_->_index_ = db_size;
533 _end_->_end_index_ = db_size;
534 _end_safe_->_index_ = db_size;
535 _end_safe_->_end_index_ = db_size;
536 }
537
538 return *this;
539 }
540
541 // returns a new unsafe handler pointing to the beginning of the database
542 template < typename T_DATA >
543 typename IDatabaseTable< T_DATA >::Handler IDatabaseTable< T_DATA >::begin() const {
544 return Handler(*this);
545 }
546
547 // returns a new safe handler pointing to the beginning of the database
548 template < typename T_DATA >
549 typename IDatabaseTable< T_DATA >::HandlerSafe IDatabaseTable< T_DATA >::beginSafe() const {
550 return HandlerSafe(*this);
551 }
552
553 // returns a new unsafe handler pointing to the end of the database
554 template < typename T_DATA >
555 const typename IDatabaseTable< T_DATA >::Handler&
556 IDatabaseTable< T_DATA >::end() const noexcept {
557 return *_end_;
558 }
559
561 template < typename T_DATA >
562 const typename IDatabaseTable< T_DATA >::HandlerSafe&
563 IDatabaseTable< T_DATA >::endSafe() const noexcept {
564 return *_end_safe_;
565 }
566
567 // returns a new unsafe handler on the database
568 template < typename T_DATA >
569 typename IDatabaseTable< T_DATA >::Handler IDatabaseTable< T_DATA >::handler() const {
570 return Handler(*this);
571 }
572
573 // returns a new safe handler on the database
574 template < typename T_DATA >
575 typename IDatabaseTable< T_DATA >::HandlerSafe IDatabaseTable< T_DATA >::handlerSafe() const {
576 return HandlerSafe(*this);
577 }
578
579 // returns the content of the database
580 template < typename T_DATA >
581 const typename IDatabaseTable< T_DATA >::template Matrix< T_DATA >&
582 IDatabaseTable< T_DATA >::content() const noexcept {
583 return rows_;
584 }
585
587 template < typename T_DATA >
588 bool IDatabaseTable< T_DATA >::hasMissingValues() const {
589 for (const auto& status: has_row_missing_val_)
590 if (status == IsMissing::True) return true;
591 return false;
592 }
593
595 template < typename T_DATA >
596 bool IDatabaseTable< T_DATA >::hasMissingValues(const std::size_t k) const {
597 return has_row_missing_val_[k] == IsMissing::True;
598 }
599
600 // returns the variable names for all the columns
601 template < typename T_DATA >
602 const std::vector< std::string >& IDatabaseTable< T_DATA >::variableNames() const noexcept {
603 return variable_names_;
604 }
605
607 template < typename T_DATA >
608 const std::string& IDatabaseTable< T_DATA >::variableName(const std::size_t k) const {
609 if (variable_names_.size() <= k)
610 GUM_ERROR(OutOfBounds, "the database does not contain Column #" << k)
611 return variable_names_[k];
612 }
613
615 template < typename T_DATA >
616 std::size_t IDatabaseTable< T_DATA >::columnFromVariableName(std::string_view name) const {
617 const std::size_t size = variable_names_.size();
618 for (std::size_t i = 0; i < size; ++i)
619 if (variable_names_[i] == name) return i;
620
621 GUM_ERROR(UndefinedElement, "the database contains no column whose name is " << name)
622 }
623
625 template < typename T_DATA >
626 typename IDatabaseTable< T_DATA >::template DBVector< std::size_t >
627 IDatabaseTable< T_DATA >::columnsFromVariableName(std::string_view name) const {
628 const std::size_t size = variable_names_.size();
629 DBVector< std::size_t > cols;
630 for (std::size_t i = 0; i < size; ++i)
631 if (variable_names_[i] == name) cols.push_back(i);
632
633 if (cols.empty())
634 GUM_ERROR(UndefinedElement, "the database contains no column whose name is " << name)
635
636 return cols;
637 }
638
639 // returns the number of variables (columns) of the database
640 template < typename T_DATA >
641 std::size_t IDatabaseTable< T_DATA >::nbVariables() const noexcept {
642 return variable_names_.size();
643 }
644
645 // returns the number of records in the database
646 template < typename T_DATA >
647 std::size_t IDatabaseTable< T_DATA >::size() const noexcept {
648 return rows_.size();
649 }
650
651 // returns the number of records in the database
652 template < typename T_DATA >
653 std::size_t IDatabaseTable< T_DATA >::nbRows() const noexcept {
654 return rows_.size();
655 }
656
657 // indicates whether the database contains some records or not
658 template < typename T_DATA >
659 bool IDatabaseTable< T_DATA >::empty() const noexcept {
660 return rows_.empty();
661 }
662
663 // update the handlers when the size of the database changes
664 template < typename T_DATA >
665 void IDatabaseTable< T_DATA >::_updateHandlers_(std::size_t new_size) const {
666 const std::size_t db_size = rows_.size();
667
668 _safe_handlers_mutex_.lock();
669 for (auto handler: _list_of_safe_handlers_) {
670 if ((handler->_end_index_ == db_size) || (handler->_end_index_ > new_size)) {
671 handler->_end_index_ = new_size;
672 // there is no need to update the index because, in safe handlers,
673 // we always check that the index is less than end_index when trying
674 // to access the rows
675 }
676 }
677 _safe_handlers_mutex_.unlock();
678
679 // update the end iterators
680 _end_->_index_ = new_size;
681 _end_->_end_index_ = new_size;
682 _end_safe_->_index_ = new_size;
683 _end_safe_->_end_index_ = new_size;
684 }
685
686 // attach a new handler to the database
687 template < typename T_DATA >
688 void IDatabaseTable< T_DATA >::_attachHandler_(HandlerSafe* handler) const {
689 _safe_handlers_mutex_.lock();
690 _list_of_safe_handlers_.push_back(handler);
691 _safe_handlers_mutex_.unlock();
692 }
693
694 // detach a handler
695 template < typename T_DATA >
696 void IDatabaseTable< T_DATA >::_detachHandler_(HandlerSafe* handler) const {
697 _safe_handlers_mutex_.lock();
698
699 for (auto iter = _list_of_safe_handlers_.rbegin(); iter != _list_of_safe_handlers_.rend();
700 ++iter) {
701 if (*iter == handler) {
702 *iter = _list_of_safe_handlers_.back();
703 _list_of_safe_handlers_.pop_back();
704 break;
705 }
706 }
707
708 _safe_handlers_mutex_.unlock();
709 }
710
711 // checks whether a new row has the same size as the rest of the database
712 template < typename T_DATA >
713 bool IDatabaseTable< T_DATA >::isRowSizeOK_(const std::size_t size) const {
714 return (size == variable_names_.size());
715 }
716
717 // insert a new DBRow at the end of the database
718 template < typename T_DATA >
719 void IDatabaseTable< T_DATA >::insertRow(
720 const typename IDatabaseTable< T_DATA >::template Row< T_DATA >& row,
721 const typename IDatabaseTable< T_DATA >::IsMissing contains_missing) {
722 // this will call the insertRow with a Row< T_DATA >&&
723 this->insertRow(typename IDatabaseTable< T_DATA >::template Row< T_DATA >(row),
724 contains_missing);
725 }
726
727 // insert a new DBRow at the end of the database
728 template < typename T_DATA >
729 void IDatabaseTable< T_DATA >::insertRow(
730 typename IDatabaseTable< T_DATA >::template Row< T_DATA >&& new_row,
731 const typename IDatabaseTable< T_DATA >::IsMissing contains_missing) {
732 // check that the size of the row is the same as the rest of the database
733 if (!isRowSizeOK_(new_row.size()))
735 "the new row is of size " << new_row.size()
736 << ", which is different from the number of columns "
737 << "of the database, i.e., " << variable_names_.size());
738
739 _updateHandlers_(rows_.size() + 1);
740 rows_.push_back(std::move(new_row));
741 try {
742 has_row_missing_val_.push_back(contains_missing);
743 } catch (...) {
744 rows_.pop_back();
745 throw;
746 }
747 }
748
749 // insert a set of new DBRow at the end of the database
750 template < typename T_DATA >
751 void IDatabaseTable< T_DATA >::insertRows(
752 typename IDatabaseTable< T_DATA >::template Matrix< T_DATA >&& new_rows,
753 const typename IDatabaseTable< T_DATA >::template DBVector<
754 typename IDatabaseTable< T_DATA >::IsMissing >& rows_have_missing_vals) {
755 if (new_rows.empty()) return;
756
757 // check that the missing values indicators vector has the same size
758 // as the new rows
759 if (rows_have_missing_vals.size() != new_rows.size())
761 "the number of new rows (i.e., "
762 << new_rows.size()
763 << ") is different from the number of missing values indicators ("
764 << rows_have_missing_vals.size());
765
766 // check that all the rows have the same size
767 const std::size_t new_size = new_rows[0].size();
768
769 for (const auto& row: new_rows) {
770 if (row.size() != new_size) {
771 GUM_ERROR(SizeError, "all the new rows do not have the same number of columns")
772 }
773 }
774
775 // check that the sizes of the new rows are the same as the rest of
776 // the database
777 if (!isRowSizeOK_(new_size)) {
779 "the new rows have " << new_size
780 << " columns, which is different from the number of columns "
781 << "of the database, i.e., " << variable_names_.size());
782 }
783
784 const std::size_t nb_new_rows = new_rows.size();
785 const std::size_t new_db_size = rows_.size() + nb_new_rows;
786
787 rows_.reserve(new_db_size);
788 has_row_missing_val_.reserve(new_db_size);
789
790 for (std::size_t i = std::size_t(0); i < nb_new_rows; ++i) {
791 rows_.push_back(std::move(new_rows[i]));
792 has_row_missing_val_.push_back(rows_have_missing_vals[i]);
793 }
794
795 _updateHandlers_(new_db_size);
796 }
797
798 // insert a set of new DBRow at the end of the database
799 template < typename T_DATA >
800 void IDatabaseTable< T_DATA >::insertRows(
801 const typename IDatabaseTable< T_DATA >::template Matrix< T_DATA >& new_rows,
802 const typename IDatabaseTable< T_DATA >::template DBVector<
803 typename IDatabaseTable< T_DATA >::IsMissing >& rows_have_missing_vals) {
804 if (new_rows.empty()) return;
805
806 // check that the missing values indicators vector has the same size
807 // as the new rows
808 if (rows_have_missing_vals.size() != new_rows.size())
810 "the number of new rows (i.e., "
811 << new_rows.size()
812 << ") is different from the number of missing values indicators ("
813 << rows_have_missing_vals.size());
814
815 // check that all the rows have the same size
816 const std::size_t new_size = new_rows[0].size();
817
818 for (const auto& row: new_rows) {
819 if (row.size() != new_size) {
820 GUM_ERROR(SizeError, "all the new rows do not have the same number of columns")
821 }
822 }
823
824 // check that the sizes of the new rows are the same as the rest of
825 // the database
826 std::size_t db_size = rows_.size();
827
828 if (!isRowSizeOK_(new_size)) {
830 "the new rows have " << new_size
831 << " columns, which is different from the number of columns "
832 << "of the database, i.e., " << variable_names_.size());
833 }
834
835 const std::size_t nb_new_rows = new_rows.size();
836 const std::size_t new_db_size = rows_.size() + nb_new_rows;
837
838 rows_.reserve(new_db_size);
839 has_row_missing_val_.reserve(new_db_size);
840
841 for (std::size_t i = std::size_t(0); i < nb_new_rows; ++i) {
842 rows_.push_back(new_rows[i]);
843 has_row_missing_val_.push_back(rows_have_missing_vals[i]);
844 }
845
846 _updateHandlers_(db_size);
847 }
848
849 // erase a given row
850 template < typename T_DATA >
851 void IDatabaseTable< T_DATA >::eraseRow(std::size_t index) {
852 const std::size_t db_size = rows_.size();
853
854 if (index < db_size) {
855 _updateHandlers_(db_size - 1);
856 rows_.erase(rows_.begin() + index);
857 has_row_missing_val_.erase(has_row_missing_val_.begin() + index);
858 }
859 }
860
861 // erase the last row
862 template < typename T_DATA >
863 void IDatabaseTable< T_DATA >::eraseLastRow() {
864 const std::size_t db_size = rows_.size();
865
866 if (db_size) {
867 _updateHandlers_(db_size - 1);
868 rows_.pop_back();
869 has_row_missing_val_.pop_back();
870 }
871 }
872
873 // erase the first row
874 template < typename T_DATA >
875 void IDatabaseTable< T_DATA >::eraseFirstRow() {
876 const std::size_t db_size = rows_.size();
877
878 if (db_size) {
879 _updateHandlers_(db_size - 1);
880 rows_.erase(rows_.begin());
881 has_row_missing_val_.erase(has_row_missing_val_.begin());
882 }
883 }
884
885 // erase all the rows
886 template < typename T_DATA >
887 void IDatabaseTable< T_DATA >::eraseAllRows() {
888 _updateHandlers_(0);
889 rows_.clear();
890 has_row_missing_val_.clear();
891 }
892
893 // erase the k first rows
894 template < typename T_DATA >
895 void IDatabaseTable< T_DATA >::eraseFirstRows(const std::size_t nb_rows) {
896 const std::size_t db_size = rows_.size();
897
898 if (nb_rows >= db_size) {
899 eraseAllRows();
900 } else {
901 _updateHandlers_(db_size - nb_rows);
902 rows_.erase(rows_.begin(), rows_.begin() + nb_rows);
903 has_row_missing_val_.erase(has_row_missing_val_.begin(),
904 has_row_missing_val_.begin() + nb_rows);
905 }
906 }
907
908 // erase the k last rows
909 template < typename T_DATA >
910 void IDatabaseTable< T_DATA >::eraseLastRows(const std::size_t nb_rows) {
911 const std::size_t db_size = rows_.size();
912
913 if (nb_rows >= db_size) {
914 eraseAllRows();
915 } else {
916 _updateHandlers_(db_size - nb_rows);
917 rows_.erase(rows_.begin() + (db_size - nb_rows), rows_.begin() + db_size);
918 has_row_missing_val_.erase(has_row_missing_val_.begin() + (db_size - nb_rows),
919 has_row_missing_val_.begin() + db_size);
920 }
921 }
922
923 // erase the rows from the debth to the endth (not included)
924 template < typename T_DATA >
925 void IDatabaseTable< T_DATA >::eraseRows(std::size_t deb, std::size_t end) {
926 if (deb > end) std::swap(deb, end);
927
928 const std::size_t db_size = rows_.size();
929
930 if (end >= db_size) {
931 if (deb >= db_size) {
932 return;
933 } else {
934 eraseLastRows(db_size - deb);
935 }
936 } else {
937 _updateHandlers_(db_size - (end - deb));
938 rows_.erase(rows_.begin() + deb, rows_.begin() + end);
939 has_row_missing_val_.erase(has_row_missing_val_.begin() + deb,
940 has_row_missing_val_.begin() + end);
941 }
942 }
943
944 // erase the content of the database, including the names of the variables
945 template < typename T_DATA >
946 void IDatabaseTable< T_DATA >::clear() {
947 _updateHandlers_(0);
948 rows_.clear();
949 has_row_missing_val_.clear();
950 variable_names_.clear();
951 }
952
953 // returns the set of symbols for the missing values
954 template < typename T_DATA >
955 const std::vector< std::string >& IDatabaseTable< T_DATA >::missingSymbols() const {
956 return missing_symbols_;
957 }
958
960 template < typename T_DATA >
961 void IDatabaseTable< T_DATA >::setMaxNbThreads(const std::size_t nb) const {
962 if (nb == std::size_t(0)) max_nb_threads_ = std::size_t(1);
963 else max_nb_threads_ = nb;
964 }
965
967 template < typename T_DATA >
968 std::size_t IDatabaseTable< T_DATA >::nbThreads() const {
969 return max_nb_threads_;
970 }
971
974 template < typename T_DATA >
975 void IDatabaseTable< T_DATA >::setMinNbRowsPerThread(const std::size_t nb) const {
976 if (nb == std::size_t(0)) min_nb_rows_per_thread_ = std::size_t(1);
977 else min_nb_rows_per_thread_ = nb;
978 }
979
981 template < typename T_DATA >
982 std::size_t IDatabaseTable< T_DATA >::minNbRowsPerThread() const {
983 return min_nb_rows_per_thread_;
984 }
985
987 template < typename T_DATA >
988 std::size_t IDatabaseTable< T_DATA >::nbProcessingThreads_() const {
989 const std::size_t db_size = nbRows();
990 std::size_t nb_threads = db_size / min_nb_rows_per_thread_;
991 if (nb_threads < 1) nb_threads = 1;
992 else if (nb_threads > max_nb_threads_) nb_threads = max_nb_threads_;
993
994 return nb_threads;
995 }
996
998 template < typename T_DATA >
999 std::vector< std::pair< std::size_t, std::size_t > >
1000 IDatabaseTable< T_DATA >::rangesProcessingThreads_(const std::size_t nb_threads) const {
1001 std::vector< std::pair< std::size_t, std::size_t > > ranges;
1002 const std::size_t db_size = nbRows();
1003 std::size_t nb_rows_per_thread = db_size / nb_threads;
1004 std::size_t rest_rows = db_size - nb_rows_per_thread * nb_threads;
1005
1006 // assign to threads the ranges over which they should change the
1007 // rows weights
1008 std::size_t begin_index = std::size_t(0);
1009 for (std::size_t i = std::size_t(0); i < nb_threads; ++i) {
1010 std::size_t end_index = begin_index + nb_rows_per_thread;
1011 if (rest_rows != std::size_t(0)) {
1012 ++end_index;
1013 --rest_rows;
1014 }
1015 ranges.push_back(std::pair< std::size_t, std::size_t >(begin_index, end_index));
1016 begin_index = end_index;
1017 }
1018
1019 return ranges;
1020 }
1021
1023 template < typename T_DATA >
1024 void IDatabaseTable< T_DATA >::setAllRowsWeight(const double new_weight) {
1025 // determine the number of threads to use and the rows they should process
1026 const std::size_t nb_threads = nbProcessingThreads_();
1027 const std::vector< std::pair< std::size_t, std::size_t > > ranges
1028 = rangesProcessingThreads_(nb_threads);
1029
1030 // perform the assignment:
1031 // we create the lambda that will be executed by all the threads
1032 auto threadedAssign = [this, &ranges, new_weight](const std::size_t this_thread,
1033 const std::size_t nb_threads) -> void {
1034 const std::size_t begin_index = ranges[this_thread].first;
1035 const std::size_t end_index = ranges[this_thread].second;
1036
1037 for (std::size_t i = begin_index; i < end_index; ++i) {
1038 this->rows_[i].setWeight(new_weight);
1039 }
1040 };
1041
1042 // launch the threads
1043 ThreadExecutor::execute(nb_threads, threadedAssign);
1044 }
1045
1047 template < typename T_DATA >
1048 void IDatabaseTable< T_DATA >::setWeight(const std::size_t i, const double weight) {
1049 // check that i is less than the number of rows
1050 const std::size_t dbsize = nbRows();
1051 if (i >= dbsize) {
1053 "it is impossible to set the weight of record #"
1054 << i << " because the database contains only " << nbRows() << " records");
1055 }
1056
1057 // check that the weight is positive
1058 if (weight < 0) {
1060 "it is impossible to set " << weight << " as a weight of record #" << i
1061 << " because this weight is negative");
1062 }
1063
1064 rows_[i].setWeight(weight);
1065 }
1066
1068 template < typename T_DATA >
1069 double IDatabaseTable< T_DATA >::weight(const std::size_t i) const {
1070 // check that i is less than the number of rows
1071 const std::size_t dbsize = nbRows();
1072 if (i >= dbsize) {
1074 "it is impossible to get the weight of record #"
1075 << i << " because the database contains only " << nbRows() << " records");
1076 }
1077
1078 return rows_[i].weight();
1079 }
1080
1082 template < typename T_DATA >
1083 double IDatabaseTable< T_DATA >::weight() const {
1084 double w = 0.0;
1085 for (const auto& row: rows_)
1086 w += row.weight();
1087 return w;
1088 }
1089
1090
1091 } /* namespace learning */
1092
1093} /* namespace gum */
1094
1095#endif /* DOXYGEN_SHOULD_SKIP_THIS */
The common class for the tabular database tables.
Exception : a pointer or a reference on a nullptr (0) object.
Exception : out of bound.
Exception : problem with size.
Exception : a looked-for element could not be found.
The base class for all database handlers.
Definition DBHandler.h:140
Handler(const IDatabaseTable< T_DATA > &db)
default constructor
The common class for the tabular database tables.
#define GUM_ERROR(type, msg)
Definition exceptions.h:76
include the inlined functions if necessary
Definition CSVParser.h:55
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
STL namespace.