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#include <algorithm>
8#include <iterator>
9
15namespace raiigraph {
16
25template<class Ns_>
26class Matrix {
27private:
28 void setup(igraph_integer_t nr, igraph_integer_t nc) {
29 if (Ns_::init(&my_matrix, nr, nc)) {
30 throw std::runtime_error("failed to initialize igraph matrix of dimensions " + std::to_string(nr) + " x " + std::to_string(nc));
31 }
32 }
33
34public:
38 typedef typename Ns_::igraph_type igraph_type;
39
43 typedef typename Ns_::value_type value_type;
44
49
54
58 typedef igraph_integer_t size_type;
59
63 typedef igraph_integer_t difference_type;
64
69
73 typedef const value_type* const_iterator;
74
78 typedef std::reverse_iterator<iterator> reverse_iterator;
79
83 typedef std::reverse_iterator<const_iterator> reverse_const_iterator;
84
88 typedef typename Ns_::vector_type vector_type;
89
90public:
94 Matrix() : Matrix(0, 0) {}
95
102 setup(nr, nc);
103 if (val != 0) { // setup() already zero-initializes the backing array.
104 std::fill(begin(), end(), val);
105 }
106 }
107
111 Matrix(igraph_type&& matrix) : my_matrix(std::move(matrix)) {}
112
113public:
119 if (Ns_::copy(&my_matrix, &(other.my_matrix))) {
120 throw std::runtime_error("failed to copy-construct integer igraph matrix");
121 }
122 }
123
129 if (this != &other) {
130 if (Ns_::update(&my_matrix, &(other.my_matrix))) { // my_matrix should already be initialized before the assignment.
131 throw std::runtime_error("failed to copy-assign integer igraph matrix");
132 }
133 }
134 return *this;
135 }
136
142 setup(0, 0); // we must leave 'other' in a valid state.
143 std::swap(my_matrix, other.my_matrix);
144 }
145
151 if (this != &other) {
152 std::swap(my_matrix, other.my_matrix); // 'my_matrix' should already be initialized, so we're leaving 'other' in a valid state.
153 }
154 return *this;
155 }
156
161 Ns_::destroy(&my_matrix);
162 }
163
164public:
169 return Ns_::empty(&my_matrix);
170 }
171
175 size_type size() const {
176 return Ns_::size(&my_matrix);
177 }
178
182 size_type nrow() const {
183 return my_matrix.nrow;
184 }
185
189 size_type ncol() const {
190 return my_matrix.ncol;
191 }
192
196 constexpr size_type max_size() const { return IGRAPH_INTEGER_MAX; }
197
202 return my_matrix.data.stor_end - my_matrix.data.stor_begin;
203 }
204
205public:
209 void clear() {
210 resize(0, 0);
211 }
212
223 auto old_size = this->size();
224 check_code(Ns_::resize(&my_matrix, nr, nc));
225 auto new_size = this->size();
226 if (old_size < new_size) {
227 std::fill_n(begin() + old_size, new_size - old_size, val);
228 }
229 }
230
235 Ns_::shrink_to_fit(&my_matrix);
236 }
237
238public:
244 return *(begin() + i);
245 }
246
252 return *(begin() + i);
253 }
254
261 return *(begin() + r + c * my_matrix.nrow); // no need to worry about overflow as size_type is guaranteed to hold the full size.
262 }
263
270 return *(begin() + r + c * my_matrix.nrow);
271 }
272
277 return *(end() - 1);
278 }
279
284 return *(end() - 1);
285 }
286
291 return *(begin());
292 }
293
298 return *(begin());
299 }
300
301public:
306 return my_matrix.data.stor_begin;
307 }
308
313 return my_matrix.data.stor_end;
314 }
315
320 return cbegin();
321 }
322
327 return cend();
328 }
329
334 return my_matrix.data.stor_begin;
335 }
336
341 return my_matrix.data.stor_end;
342 }
343
348 return my_matrix.data.stor_begin;
349 }
350
354 const value_type* data() const {
355 return my_matrix.data.stor_begin;
356 }
357
362 return std::reverse_iterator(end());
363 }
364
369 return std::reverse_iterator(begin());
370 }
371
376 return std::reverse_iterator(end());
377 }
378
383 return std::reverse_iterator(begin());
384 }
385
390 return std::reverse_iterator(cend());
391 }
392
397 return std::reverse_iterator(cbegin());
398 }
399
400public:
411 template<typename BaseIterator, typename BaseReference>
412 class View {
416 public:
417 View(BaseIterator start, size_type step_size, size_type max_steps) : start(start), step_size(step_size), max_steps(max_steps) {}
418
419 private:
420 BaseIterator start;
421 size_type step_size, max_steps;
426 public:
430 bool empty() const {
431 return max_steps == 0;
432 }
433
437 size_type size() const {
438 return max_steps;
439 }
440
446 return *(start + i * step_size); // no need to cast to avoid overflow, as size_type determines the max size anyway.
447 }
448
453 return (*this)[max_steps - 1];
454 }
455
460 return *start;
461 }
462
463 public:
467 struct Iterator {
468 private:
469 BaseIterator start;
470 size_type step_size = 0;
471
472 // Note that we don't just shift 'start' directly as defining the
473 // 'end()' iterator of the view could up shifting 'start' to an
474 // address beyond the one-past-the-end of the backing array in the
475 // 'igraph_matrix_t'. Pointer arithmetic beyond the array bounds is
476 // undefined IIRC, so instead, we store the offset and att it to
477 // 'start' upon dereference of the iterator. This ensures that an
478 // invalid address is never constructed even if it is unused.
479 size_type offset = 0;
480
484 public:
485 using iterator_category = std::random_access_iterator_tag;
486 typedef typename Ns_::value_type value_type;
487 typedef decltype(&std::declval<BaseReference>()) pointer;
489 typedef BaseReference reference;
490
491 public:
492 explicit Iterator(BaseIterator start, size_type step_size, size_type position) :
493 start(std::move(start)), step_size(step_size), offset(position * step_size) {}
494
495 Iterator() = default;
496
497 public:
498 // List of required methods taken from https://cplusplus.com/reference/iterator/RandomAccessIterator/.
499 bool operator==(const Iterator& other) const {
500 // see comments at https://stackoverflow.com/questions/4657513/comparing-iterators-from-different-containers
501 // regarding the UB of comparing iterators from different containers, so we'll just quietly ignore it.
502 return offset == other.offset;
503 }
504
505 bool operator!=(const Iterator& other) const {
506 return offset != other.offset;
507 }
508
509 bool operator<(const Iterator& other) const {
510 return offset < other.offset;
511 }
512
513 bool operator>(const Iterator& other) const {
514 return offset > other.offset;
515 }
516
517 bool operator<=(const Iterator& other) const {
518 return offset <= other.offset;
519 }
520
521 bool operator>=(const Iterator& other) const {
522 return offset >= other.offset;
523 }
524
525 public:
526 BaseReference operator*() const {
527 return *(start + offset);
528 }
529
531 return *(start + offset + step_size * i);
532 }
533
534 public:
535 Iterator& operator++() {
536 offset += step_size;
537 return *this;
538 }
539
540 Iterator operator++(int) {
541 auto copy = *this;
542 offset += step_size;
543 return copy;
544 }
545
546 Iterator& operator--() {
547 offset -= step_size;
548 return *this;
549 }
550
551 Iterator operator--(int) {
552 auto copy = *this;
553 offset -= step_size;
554 return copy;
555 }
556
558 auto copy = *this;
559 copy.offset += step_size * n;
560 return copy;
561 }
562
564 offset += step_size * n;
565 return *this;
566 }
567
569 it.offset += it.step_size * n;
570 return it;
571 }
572
574 auto copy = *this;
575 copy.offset -= step_size * n;
576 return copy;
577 }
578
580 offset -= step_size * n;
581 return *this;
582 }
583
585 if (other.offset > offset) {
586 difference_type delta = (other.offset - offset) / step_size;
587 return -delta;
588 } else {
589 return (offset - other.offset) / step_size;
590 }
591 }
595 };
596
600 Iterator begin() const {
601 return Iterator(start, step_size, 0);
602 }
603
607 Iterator end() const {
608 return Iterator(start, step_size, max_steps);
609 }
610
614 Iterator cbegin() const {
615 return begin();
616 }
617
621 Iterator cend() const {
622 return end();
623 }
624
628 std::reverse_iterator<Iterator> rbegin() const {
629 return std::reverse_iterator(end());
630 }
631
635 std::reverse_iterator<Iterator> rend() const {
636 return std::reverse_iterator(begin());
637 }
638
642 std::reverse_iterator<Iterator> crbegin() const {
643 return std::reverse_iterator(cend());
644 }
645
649 std::reverse_iterator<Iterator> crend() const {
650 return std::reverse_iterator(cbegin());
651 }
652 };
653
659 return View<iterator, reference>(begin() + r, my_matrix.nrow, my_matrix.ncol);
660 }
661
667 return View<const_iterator, const_reference>(begin() + r, my_matrix.nrow, my_matrix.ncol);
668 }
669
676 check_code(Ns_::get_row(&my_matrix, output.get(), r));
677 return output;
678 }
679
685 return View<iterator, reference>(begin() + c * my_matrix.nrow, 1, my_matrix.nrow);
686 }
687
693 return View<const_iterator, const_reference>(begin() + c * my_matrix.nrow, 1, my_matrix.nrow);
694 }
695
702 check_code(Ns_::get_col(&my_matrix, output.get(), c));
703 return output;
704 }
705
706public:
711 operator igraph_type*() {
712 return &my_matrix;
713 }
714
719 operator const igraph_type*() const {
720 return &my_matrix;
721 }
722
728 return &my_matrix;
729 }
730
735 const igraph_type* get() const {
736 return &my_matrix;
737 }
738
739public:
745 // Swapping structures entirely to ensure that iterators and pointers
746 // remain valid; looks like igraph_matrix_swap does the same.
747 std::swap(my_matrix, other.my_matrix);
748 }
749
750private:
751 igraph_type my_matrix;
752};
753
757namespace matrix_internal {
758
759struct Integer {
760 typedef igraph_integer_t value_type;
761 typedef igraph_matrix_int_t igraph_type;
762 typedef IntVector vector_type;
763
764#define RAIIGRAPH_MATRIX_SUFFIX _int
765#include "fragments/matrix.hpp"
766#undef RAIIGRAPH_MATRIX_SUFFIX
767};
768
769struct Real {
770 typedef igraph_real_t value_type;
771 typedef igraph_matrix_t igraph_type;
772 typedef RealVector vector_type;
773
774#define RAIIGRAPH_MATRIX_SUFFIX
775#include "fragments/matrix.hpp"
776#undef RAIIGRAPH_MATRIX_SUFFIX
777};
778
779struct Bool {
780 typedef igraph_bool_t value_type;
781 typedef igraph_matrix_bool_t igraph_type;
782 typedef BoolVector vector_type;
783
784#define RAIIGRAPH_MATRIX_SUFFIX _bool
785#include "fragments/matrix.hpp"
786#undef RAIIGRAPH_MATRIX_SUFFIX
787};
788
789}
798
802// For back-compatibility.
803typedef IntMatrix IntegerMatrix;
812
817
818}
819
820
821#endif
Wrapper around igraph_vector_*_t objects with RAII behavior.
View into a row/column of the matrix.
Definition Matrix.hpp:412
std::reverse_iterator< Iterator > crbegin() const
Definition Matrix.hpp:642
bool empty() const
Definition Matrix.hpp:430
size_type size() const
Definition Matrix.hpp:437
BaseReference operator[](size_type i) const
Definition Matrix.hpp:445
Iterator end() const
Definition Matrix.hpp:607
std::reverse_iterator< Iterator > rbegin() const
Definition Matrix.hpp:628
std::reverse_iterator< Iterator > rend() const
Definition Matrix.hpp:635
BaseReference front() const
Definition Matrix.hpp:459
std::reverse_iterator< Iterator > crend() const
Definition Matrix.hpp:649
BaseReference back() const
Definition Matrix.hpp:452
Iterator begin() const
Definition Matrix.hpp:600
Iterator cend() const
Definition Matrix.hpp:621
Iterator cbegin() const
Definition Matrix.hpp:614
Wrapper around igraph_matrix_*_t objects with RAII behavior.
Definition Matrix.hpp:26
vector_type column_copy(size_type c) const
Definition Matrix.hpp:700
std::reverse_iterator< const_iterator > reverse_const_iterator
Definition Matrix.hpp:83
const_reference operator()(size_type r, size_type c) const
Definition Matrix.hpp:269
reverse_const_iterator crbegin() const
Definition Matrix.hpp:389
void clear()
Definition Matrix.hpp:209
Matrix(const Matrix< Ns_ > &other)
Definition Matrix.hpp:118
Ns_::igraph_type igraph_type
Definition Matrix.hpp:38
value_type * iterator
Definition Matrix.hpp:68
Matrix()
Definition Matrix.hpp:94
igraph_bool_t empty() const
Definition Matrix.hpp:168
View< iterator, reference > column(size_type c)
Definition Matrix.hpp:684
constexpr size_type max_size() const
Definition Matrix.hpp:196
Ns_::value_type value_type
Definition Matrix.hpp:43
const_reference back() const
Definition Matrix.hpp:283
const igraph_type * get() const
Definition Matrix.hpp:735
const_reference front() const
Definition Matrix.hpp:297
reverse_const_iterator crend() const
Definition Matrix.hpp:396
const_reference operator[](size_type i) const
Definition Matrix.hpp:251
View< const_iterator, const_reference > row(size_type r) const
Definition Matrix.hpp:666
View< const_iterator, const_reference > column(size_type c) const
Definition Matrix.hpp:692
void shrink_to_fit()
Definition Matrix.hpp:234
vector_type row_copy(size_type r) const
Definition Matrix.hpp:674
const value_type * data() const
Definition Matrix.hpp:354
value_type & reference
Definition Matrix.hpp:48
~Matrix()
Definition Matrix.hpp:160
reference back()
Definition Matrix.hpp:276
igraph_type * get()
Definition Matrix.hpp:727
void resize(size_type nr, size_type nc, value_type val=value_type())
Definition Matrix.hpp:222
Ns_::vector_type vector_type
Definition Matrix.hpp:88
size_type size() const
Definition Matrix.hpp:175
const value_type * const_iterator
Definition Matrix.hpp:73
const_iterator begin() const
Definition Matrix.hpp:319
size_type ncol() const
Definition Matrix.hpp:189
reverse_const_iterator rbegin() const
Definition Matrix.hpp:375
reverse_const_iterator rend() const
Definition Matrix.hpp:382
Matrix & operator=(Matrix< Ns_ > &&other)
Definition Matrix.hpp:150
View< iterator, reference > row(size_type r)
Definition Matrix.hpp:658
const_iterator cbegin() const
Definition Matrix.hpp:333
const value_type & const_reference
Definition Matrix.hpp:53
iterator end()
Definition Matrix.hpp:312
igraph_integer_t size_type
Definition Matrix.hpp:58
size_type nrow() const
Definition Matrix.hpp:182
reference operator()(size_type r, size_type c)
Definition Matrix.hpp:260
iterator begin()
Definition Matrix.hpp:305
void swap(Matrix< Ns_ > &other)
Definition Matrix.hpp:744
reference operator[](size_type i)
Definition Matrix.hpp:243
Matrix(igraph_type &&matrix)
Definition Matrix.hpp:111
Matrix(size_type nr, size_type nc, const value_type &val=value_type())
Definition Matrix.hpp:101
Matrix(Matrix< Ns_ > &&other)
Definition Matrix.hpp:141
const_iterator end() const
Definition Matrix.hpp:326
const_iterator cend() const
Definition Matrix.hpp:340
igraph_integer_t difference_type
Definition Matrix.hpp:63
reverse_iterator rend()
Definition Matrix.hpp:368
reference front()
Definition Matrix.hpp:290
reverse_iterator rbegin()
Definition Matrix.hpp:361
std::reverse_iterator< iterator > reverse_iterator
Definition Matrix.hpp:78
Matrix< Ns_ > & operator=(const Matrix< Ns_ > &other)
Definition Matrix.hpp:128
size_type capacity() const
Definition Matrix.hpp:201
value_type * data()
Definition Matrix.hpp:347
Error handling for raiigraph.
Utilities for manipulating igraph data structures in C++.
Definition error.hpp:11
Matrix< matrix_internal::Bool > BoolMatrix
Definition Matrix.hpp:816
Matrix< matrix_internal::Integer > IntMatrix
Definition Matrix.hpp:797
Vector< internal::Real > RealVector
Definition Vector.hpp:582
void check_code(igraph_error_t code)
Definition error.hpp:34
Matrix< matrix_internal::Real > RealMatrix
Definition Matrix.hpp:811
Vector< internal::Bool > BoolVector
Definition Vector.hpp:587
Random-access iterator through the view.
Definition Matrix.hpp:467