raiigraph
C++ RAII for igraph data structures
Loading...
Searching...
No Matches
Matrix.hpp
Go to the documentation of this file.
1#ifndef RAIIGRAPH_MATRIX_HPP
2#define RAIIGRAPH_MATRIX_HPP
3
4#include "igraph.h"
5#include "error.hpp"
6#include "Vector.hpp"
7
8#include <algorithm>
9#include <iterator>
10
16namespace raiigraph {
17
28template<class Ns_>
29class Matrix {
30private:
31 void setup(igraph_int_t nr, igraph_int_t nc) {
32 check_code(Ns_::init(&my_matrix, nr, nc));
33 }
34
35public:
39 typedef typename Ns_::igraph_type igraph_type;
40
44 typedef typename Ns_::value_type value_type;
45
50
55
59 typedef igraph_int_t size_type;
60
64 typedef igraph_int_t difference_type;
65
70
74 typedef const value_type* const_iterator;
75
79 typedef std::reverse_iterator<iterator> reverse_iterator;
80
84 typedef std::reverse_iterator<const_iterator> reverse_const_iterator;
85
89 typedef typename Ns_::vector_type vector_type;
90
91public:
95 Matrix() : Matrix(0, 0) {}
96
103 setup(nr, nc);
104 if (val != 0) { // setup() already zero-initializes the backing array.
105 std::fill(begin(), end(), val);
106 }
107 }
108
112 Matrix(igraph_type&& matrix) : my_matrix(std::move(matrix)) {}
113
114public:
119 Matrix(const Matrix<Ns_>& other) {
120 check_code(Ns_::copy(&my_matrix, &(other.my_matrix)));
121 }
122
128 if (this != &other) {
129 // my_matrix should already be initialized before the assignment.
130 check_code(Ns_::update(&my_matrix, &(other.my_matrix)));
131 }
132 return *this;
133 }
134
140 setup(0, 0); // we must leave 'other' in a valid state.
141 std::swap(my_matrix, other.my_matrix);
142 }
143
149 if (this != &other) {
150 std::swap(my_matrix, other.my_matrix); // 'my_matrix' should already be initialized, so we're leaving 'other' in a valid state.
151 }
152 return *this;
153 }
154
159 Ns_::destroy(&my_matrix);
160 }
161
162public:
166 igraph_bool_t empty() const {
167 return Ns_::empty(&my_matrix);
168 }
169
173 size_type size() const {
174 return Ns_::size(&my_matrix);
175 }
176
180 size_type nrow() const {
181 return my_matrix.nrow;
182 }
183
187 size_type ncol() const {
188 return my_matrix.ncol;
189 }
190
194 constexpr size_type max_size() const { return IGRAPH_INTEGER_MAX; }
195
200 return my_matrix.data.stor_end - my_matrix.data.stor_begin;
201 }
202
203public:
207 void clear() {
208 resize(0, 0);
209 }
210
221 auto old_size = this->size();
222 check_code(Ns_::resize(&my_matrix, nr, nc));
223 auto new_size = this->size();
224 if (old_size < new_size) {
225 std::fill_n(begin() + old_size, new_size - old_size, val);
226 }
227 }
228
233 Ns_::shrink_to_fit(&my_matrix);
234 }
235
236public:
242 return *(begin() + i);
243 }
244
250 return *(begin() + i);
251 }
252
259 return *(begin() + r + c * my_matrix.nrow); // no need to worry about overflow as size_type is guaranteed to hold the full size.
260 }
261
268 return *(begin() + r + c * my_matrix.nrow);
269 }
270
275 return *(end() - 1);
276 }
277
282 return *(end() - 1);
283 }
284
289 return *(begin());
290 }
291
296 return *(begin());
297 }
298
299public:
304 return my_matrix.data.stor_begin;
305 }
306
311 return my_matrix.data.stor_end;
312 }
313
318 return cbegin();
319 }
320
325 return cend();
326 }
327
332 return my_matrix.data.stor_begin;
333 }
334
339 return my_matrix.data.stor_end;
340 }
341
346 return my_matrix.data.stor_begin;
347 }
348
352 const value_type* data() const {
353 return my_matrix.data.stor_begin;
354 }
355
360 return std::reverse_iterator(end());
361 }
362
367 return std::reverse_iterator(begin());
368 }
369
374 return std::reverse_iterator(end());
375 }
376
381 return std::reverse_iterator(begin());
382 }
383
388 return std::reverse_iterator(cend());
389 }
390
395 return std::reverse_iterator(cbegin());
396 }
397
398public:
409 template<typename BaseIterator, typename BaseReference>
410 class View {
414 public:
415 View(BaseIterator start, size_type step_size, size_type max_steps) : start(start), step_size(step_size), max_steps(max_steps) {}
416
417 private:
418 BaseIterator start;
419 size_type step_size, max_steps;
424 public:
428 bool empty() const {
429 return max_steps == 0;
430 }
431
435 size_type size() const {
436 return max_steps;
437 }
438
443 BaseReference operator[](size_type i) const {
444 return *(start + i * step_size); // no need to cast to avoid overflow, as size_type determines the max size anyway.
445 }
446
450 BaseReference back() const {
451 return (*this)[max_steps - 1];
452 }
453
457 BaseReference front() const {
458 return *start;
459 }
460
461 public:
465 struct Iterator {
466 private:
467 BaseIterator start;
468 size_type step_size = 0;
469
470 // Note that we don't just shift 'start' directly as defining the
471 // 'end()' iterator of the view could up shifting 'start' to an
472 // address beyond the one-past-the-end of the backing array in the
473 // 'igraph_matrix_t'. Pointer arithmetic beyond the array bounds is
474 // undefined IIRC, so instead, we store the offset and att it to
475 // 'start' upon dereference of the iterator. This ensures that an
476 // invalid address is never constructed even if it is unused.
477 size_type offset = 0;
478
482 public:
483 using iterator_category = std::random_access_iterator_tag;
484 typedef typename Ns_::value_type value_type;
485 typedef decltype(&std::declval<BaseReference>()) pointer;
486 typedef igraph_int_t difference_type;
487 typedef BaseReference reference;
488
489 public:
490 explicit Iterator(BaseIterator start, size_type step_size, size_type position) :
491 start(std::move(start)), step_size(step_size), offset(position * step_size) {}
492
493 Iterator() = default;
494
495 public:
496 // List of required methods taken from https://cplusplus.com/reference/iterator/RandomAccessIterator/.
497 bool operator==(const Iterator& other) const {
498 // see comments at https://stackoverflow.com/questions/4657513/comparing-iterators-from-different-containers
499 // regarding the UB of comparing iterators from different containers, so we'll just quietly ignore it.
500 return offset == other.offset;
501 }
502
503 bool operator!=(const Iterator& other) const {
504 return offset != other.offset;
505 }
506
507 bool operator<(const Iterator& other) const {
508 return offset < other.offset;
509 }
510
511 bool operator>(const Iterator& other) const {
512 return offset > other.offset;
513 }
514
515 bool operator<=(const Iterator& other) const {
516 return offset <= other.offset;
517 }
518
519 bool operator>=(const Iterator& other) const {
520 return offset >= other.offset;
521 }
522
523 public:
524 BaseReference operator*() const {
525 return *(start + offset);
526 }
527
528 BaseReference operator[](size_type i) const {
529 return *(start + offset + step_size * i);
530 }
531
532 public:
533 Iterator& operator++() {
534 offset += step_size;
535 return *this;
536 }
537
538 Iterator operator++(int) {
539 auto copy = *this;
540 offset += step_size;
541 return copy;
542 }
543
544 Iterator& operator--() {
545 offset -= step_size;
546 return *this;
547 }
548
549 Iterator operator--(int) {
550 auto copy = *this;
551 offset -= step_size;
552 return copy;
553 }
554
555 Iterator operator+(difference_type n) const {
556 auto copy = *this;
557 copy.offset += step_size * n;
558 return copy;
559 }
560
561 Iterator& operator+=(difference_type n) {
562 offset += step_size * n;
563 return *this;
564 }
565
566 friend Iterator operator+(difference_type n, Iterator it) {
567 it.offset += it.step_size * n;
568 return it;
569 }
570
571 Iterator operator-(difference_type n) const {
572 auto copy = *this;
573 copy.offset -= step_size * n;
574 return copy;
575 }
576
577 Iterator& operator-=(difference_type n) {
578 offset -= step_size * n;
579 return *this;
580 }
581
582 difference_type operator-(const Iterator& other) const {
583 if (other.offset > offset) {
584 difference_type delta = (other.offset - offset) / step_size;
585 return -delta;
586 } else {
587 return (offset - other.offset) / step_size;
588 }
589 }
593 };
594
598 Iterator begin() const {
599 return Iterator(start, step_size, 0);
600 }
601
605 Iterator end() const {
606 return Iterator(start, step_size, max_steps);
607 }
608
612 Iterator cbegin() const {
613 return begin();
614 }
615
619 Iterator cend() const {
620 return end();
621 }
622
626 std::reverse_iterator<Iterator> rbegin() const {
627 return std::reverse_iterator(end());
628 }
629
633 std::reverse_iterator<Iterator> rend() const {
634 return std::reverse_iterator(begin());
635 }
636
640 std::reverse_iterator<Iterator> crbegin() const {
641 return std::reverse_iterator(cend());
642 }
643
647 std::reverse_iterator<Iterator> crend() const {
648 return std::reverse_iterator(cbegin());
649 }
650 };
651
657 return View<iterator, reference>(begin() + r, my_matrix.nrow, my_matrix.ncol);
658 }
659
665 return View<const_iterator, const_reference>(begin() + r, my_matrix.nrow, my_matrix.ncol);
666 }
667
673 vector_type output(ncol());
674 check_code(Ns_::get_row(&my_matrix, output.get(), r));
675 return output;
676 }
677
683 return View<iterator, reference>(begin() + c * my_matrix.nrow, 1, my_matrix.nrow);
684 }
685
691 return View<const_iterator, const_reference>(begin() + c * my_matrix.nrow, 1, my_matrix.nrow);
692 }
693
699 vector_type output(nrow());
700 check_code(Ns_::get_col(&my_matrix, output.get(), c));
701 return output;
702 }
703
704public:
709 operator igraph_type*() {
710 return &my_matrix;
711 }
712
717 operator const igraph_type*() const {
718 return &my_matrix;
719 }
720
726 return &my_matrix;
727 }
728
733 const igraph_type* get() const {
734 return &my_matrix;
735 }
736
737public:
742 void swap(Matrix<Ns_>& other) {
743 // Swapping structures entirely to ensure that iterators and pointers
744 // remain valid; looks like igraph_matrix_swap does the same.
745 std::swap(my_matrix, other.my_matrix);
746 }
747
748private:
749 igraph_type my_matrix;
750};
751
755namespace matrix_internal {
756
757struct Integer {
758 typedef igraph_int_t value_type;
759 typedef igraph_matrix_int_t igraph_type;
760 typedef IntVector vector_type;
761
762#define RAIIGRAPH_MATRIX_SUFFIX _int
763#include "fragments/matrix.hpp"
764#undef RAIIGRAPH_MATRIX_SUFFIX
765};
766
767struct Real {
768 typedef igraph_real_t value_type;
769 typedef igraph_matrix_t igraph_type;
770 typedef RealVector vector_type;
771
772#define RAIIGRAPH_MATRIX_SUFFIX
773#include "fragments/matrix.hpp"
774#undef RAIIGRAPH_MATRIX_SUFFIX
775};
776
777struct Bool {
778 typedef igraph_bool_t value_type;
779 typedef igraph_matrix_bool_t igraph_type;
780 typedef BoolVector vector_type;
781
782#define RAIIGRAPH_MATRIX_SUFFIX _bool
783#include "fragments/matrix.hpp"
784#undef RAIIGRAPH_MATRIX_SUFFIX
785};
786
787}
796
800// For back-compatibility.
801typedef IntMatrix IntegerMatrix;
810
815
816}
817
818
819#endif
Wrapper around igraph_vector_*_t objects with RAII behavior.
View into a row/column of the matrix.
Definition Matrix.hpp:410
std::reverse_iterator< Iterator > crbegin() const
Definition Matrix.hpp:640
bool empty() const
Definition Matrix.hpp:428
size_type size() const
Definition Matrix.hpp:435
BaseReference operator[](size_type i) const
Definition Matrix.hpp:443
Iterator end() const
Definition Matrix.hpp:605
std::reverse_iterator< Iterator > rbegin() const
Definition Matrix.hpp:626
std::reverse_iterator< Iterator > rend() const
Definition Matrix.hpp:633
BaseReference front() const
Definition Matrix.hpp:457
std::reverse_iterator< Iterator > crend() const
Definition Matrix.hpp:647
BaseReference back() const
Definition Matrix.hpp:450
Iterator begin() const
Definition Matrix.hpp:598
Iterator cend() const
Definition Matrix.hpp:619
Iterator cbegin() const
Definition Matrix.hpp:612
Wrapper around igraph_matrix_*_t objects with RAII behavior.
Definition Matrix.hpp:29
vector_type column_copy(size_type c) const
Definition Matrix.hpp:698
const_reference operator()(size_type r, size_type c) const
Definition Matrix.hpp:267
reverse_const_iterator crbegin() const
Definition Matrix.hpp:387
void clear()
Definition Matrix.hpp:207
Matrix(const Matrix< Ns_ > &other)
Definition Matrix.hpp:119
Ns_::value_type value_type
Definition Matrix.hpp:44
Ns_::igraph_type igraph_type
Definition Matrix.hpp:39
igraph_int_t size_type
Definition Matrix.hpp:59
Matrix()
Definition Matrix.hpp:95
igraph_bool_t empty() const
Definition Matrix.hpp:166
View< iterator, reference > column(size_type c)
Definition Matrix.hpp:682
constexpr size_type max_size() const
Definition Matrix.hpp:194
std::reverse_iterator< iterator > reverse_iterator
Definition Matrix.hpp:79
const_reference back() const
Definition Matrix.hpp:281
const igraph_type * get() const
Definition Matrix.hpp:733
const_reference front() const
Definition Matrix.hpp:295
reverse_const_iterator crend() const
Definition Matrix.hpp:394
const_reference operator[](size_type i) const
Definition Matrix.hpp:249
View< const_iterator, const_reference > row(size_type r) const
Definition Matrix.hpp:664
View< const_iterator, const_reference > column(size_type c) const
Definition Matrix.hpp:690
void shrink_to_fit()
Definition Matrix.hpp:232
vector_type row_copy(size_type r) const
Definition Matrix.hpp:672
const value_type * data() const
Definition Matrix.hpp:352
~Matrix()
Definition Matrix.hpp:158
reference back()
Definition Matrix.hpp:274
value_type & reference
Definition Matrix.hpp:49
igraph_type * get()
Definition Matrix.hpp:725
void resize(size_type nr, size_type nc, value_type val=value_type())
Definition Matrix.hpp:220
size_type size() const
Definition Matrix.hpp:173
const_iterator begin() const
Definition Matrix.hpp:317
size_type ncol() const
Definition Matrix.hpp:187
const value_type * const_iterator
Definition Matrix.hpp:74
reverse_const_iterator rbegin() const
Definition Matrix.hpp:373
reverse_const_iterator rend() const
Definition Matrix.hpp:380
Matrix & operator=(Matrix< Ns_ > &&other)
Definition Matrix.hpp:148
View< iterator, reference > row(size_type r)
Definition Matrix.hpp:656
const_iterator cbegin() const
Definition Matrix.hpp:331
iterator end()
Definition Matrix.hpp:310
size_type nrow() const
Definition Matrix.hpp:180
value_type * iterator
Definition Matrix.hpp:69
reference operator()(size_type r, size_type c)
Definition Matrix.hpp:258
Ns_::vector_type vector_type
Definition Matrix.hpp:89
iterator begin()
Definition Matrix.hpp:303
void swap(Matrix< Ns_ > &other)
Definition Matrix.hpp:742
reference operator[](size_type i)
Definition Matrix.hpp:241
Matrix(igraph_type &&matrix)
Definition Matrix.hpp:112
Matrix(size_type nr, size_type nc, const value_type &val=value_type())
Definition Matrix.hpp:102
Matrix(Matrix< Ns_ > &&other)
Definition Matrix.hpp:139
igraph_int_t difference_type
Definition Matrix.hpp:64
const_iterator end() const
Definition Matrix.hpp:324
const_iterator cend() const
Definition Matrix.hpp:338
std::reverse_iterator< const_iterator > reverse_const_iterator
Definition Matrix.hpp:84
reverse_iterator rend()
Definition Matrix.hpp:366
reference front()
Definition Matrix.hpp:288
reverse_iterator rbegin()
Definition Matrix.hpp:359
Matrix< Ns_ > & operator=(const Matrix< Ns_ > &other)
Definition Matrix.hpp:127
size_type capacity() const
Definition Matrix.hpp:199
value_type * data()
Definition Matrix.hpp:345
const value_type & const_reference
Definition Matrix.hpp:54
Error handling for raiigraph.
Utilities for manipulating igraph data structures in C++.
Definition error.hpp:11
Matrix< matrix_internal::Bool > BoolMatrix
Definition Matrix.hpp:814
Matrix< matrix_internal::Integer > IntMatrix
Definition Matrix.hpp:795
Vector< internal::Real > RealVector
Definition Vector.hpp:580
void check_code(igraph_error_t code)
Definition error.hpp:39
Matrix< matrix_internal::Real > RealMatrix
Definition Matrix.hpp:809
Vector< internal::Bool > BoolVector
Definition Vector.hpp:585
Random-access iterator through the view.
Definition Matrix.hpp:465