Heidelberg Educational Numerics Library Version 0.27 (from 15 March 2021)
sparsematrix.hh
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2/*
3 * File: sparsematrix.hh
4 * Author: Christian Heusel <christian@heusel.eu>
5 *
6 * Created on August 25, 2020
7 */
8
9#ifndef SPARSEMATRIX_HH
10#define SPARSEMATRIX_HH
11
12#include <algorithm>
13#include <complex>
14#include <functional>
15#include <iomanip>
16#include <iostream>
17#include <map>
18#include <numeric>
19#include <string>
20#include <type_traits>
21#include <vector>
22
23#include "densematrix.hh"
24#include "vector.hh"
25
26namespace hdnum {
27
30template <typename REAL>
32public:
34 using size_type = std::size_t;
35
37 using column_iterator = typename std::vector<REAL>::iterator;
39 using const_column_iterator = typename std::vector<REAL>::const_iterator;
40
41private:
42 // Matrix data is stored in an STL vector!
43 std::vector<REAL> _data;
44
45 // The non-null indices are stored in STL vectors with the size_type!
46 // Explanation on how the mapping works can be found here:
47 // https://de.wikipedia.org/wiki/Compressed_Row_Storage
48 std::vector<size_type> _colIndices;
49 std::vector<size_type> _rowPtr;
50
51 size_type m_rows = 0; // Number of Matrix rows
52 size_type m_cols = 0; // Number of Matrix columns
53
54 static bool bScientific;
55 static size_type nIndexWidth;
56 static size_type nValueWidth;
57 static size_type nValuePrecision;
58 static const REAL _zero;
59
60 // !function that converts container contents into
61 // { 1, 2, 3, 4 }
62 template <typename T>
63 [[nodiscard]] std::string comma_fold(T container) const {
64 return "{ " +
65 std::accumulate(
66 std::next(container.cbegin()), container.cend(),
67 std::to_string(container[0]), // start with first element
68 [](const std::string &a, REAL b) {
69 return a + ", " + std::to_string(b);
70 }) +
71 " }";
72 }
73
74 // This code was copied from StackOverflow to gerneralize a check whether a
75 // template is a specialization i.e. for std::complex
76 // https://stackoverflow.com/questions/31762958/check-if-class-is-a-template-specialization
77 template <class T, template <class...> class Template>
78 struct is_specialization : std::false_type {};
79
80 template <template <class...> class Template, class... Args>
81 struct is_specialization<Template<Args...>, Template> : std::true_type {};
82
83 bool checkIfAccessIsInBounds(const size_type row_index,
84 const size_type col_index) const {
85 if (not (row_index < m_rows)) {
86 HDNUM_ERROR("Out of bounds access: row too big! -> " +
87 std::to_string(row_index) + " is not < " +
88 std::to_string(m_rows));
89 return false;
90 }
91 if (not (col_index < m_cols)) {
92 HDNUM_ERROR("Out of bounds access: column too big! -> " +
93 std::to_string(col_index) + " is not < " +
94 std::to_string(m_cols));
95 return false;
96 }
97 return true;
98 }
99
100public:
116 SparseMatrix() = default;
117
120 : _rowPtr(_rows + 1), m_rows(_rows), m_cols(_cols) {}
121
138 [[nodiscard]] size_type rowsize() const { return m_rows; }
139
155 [[nodiscard]] size_type colsize() const { return m_cols; }
156
158 [[nodiscard]] bool scientific() const { return bScientific; }
159
161 public:
163
164 // conform to the iterator traits
165 // https://en.cppreference.com/w/cpp/iterator/iterator_traits
166 using difference_type = std::ptrdiff_t;
167 using value_type = std::pair<REAL &, size_type const &>;
168 using pointer = value_type *;
169 using reference = value_type &;
170 using iterator_category = std::bidirectional_iterator_tag;
171
172 column_index_iterator(typename std::vector<REAL>::iterator valIter,
173 std::vector<size_type>::iterator colIndicesIter)
174 : _valIter(valIter), _colIndicesIter(colIndicesIter) {}
175
176 // prefix
177 self_type &operator++() {
178 _valIter++;
179 _colIndicesIter++;
180 return *this;
181 }
182
183 // postfix
184 self_type &operator++(int junk) {
185 self_type cached = *this;
186 _valIter++;
187 _colIndicesIter++;
188 return cached;
189 }
190
191 [[nodiscard]] value_type operator*() {
192 return std::make_pair(std::ref(*_valIter),
193 std::cref(*_colIndicesIter));
194 }
195 // [[nodiscard]] value_type operator->() {
196 // return std::make_pair(std::ref(*_valIter),
197 // std::cref(*_colIndicesIter));
198 // }
199
200 [[nodiscard]] typename value_type::first_type value() {
201 return std::ref(*_valIter);
202 }
203
204 [[nodiscard]] typename value_type::second_type index() {
205 return std::cref(*_colIndicesIter);
206 }
207
208 [[nodiscard]] bool operator==(const self_type &other) {
209 return (_valIter == other._valIter) and
210 (_colIndicesIter == other._colIndicesIter);
211 }
212 [[nodiscard]] bool operator!=(const self_type &other) {
213 return not (*this == other);
214 }
215
216 private:
217 typename std::vector<REAL>::iterator _valIter;
218 std::vector<size_type>::iterator _colIndicesIter;
219 };
220
222 public:
224
225 // conform to the iterator traits
226 // https://en.cppreference.com/w/cpp/iterator/iterator_traits
227 using difference_type = std::ptrdiff_t;
228 using value_type = std::pair<REAL const &, size_type const &>;
229 using pointer = value_type *;
230 using reference = value_type &;
231 using iterator_category = std::bidirectional_iterator_tag;
232
234 typename std::vector<REAL>::const_iterator valIter,
235 std::vector<size_type>::const_iterator colIndicesIter)
236 : _valIter(valIter), _colIndicesIter(colIndicesIter) {}
237
238 // prefix
239 self_type &operator++() {
240 _valIter++;
241 _colIndicesIter++;
242 return *this;
243 }
244
245 // postfix
246 self_type operator++(int junk) {
247 self_type cached = *this;
248 _valIter++;
249 _colIndicesIter++;
250 return cached;
251 }
252
253 [[nodiscard]] value_type operator*() {
254 return std::make_pair(std::ref(*_valIter),
255 std::cref(*_colIndicesIter));
256 }
257 // TODO: This is wrong
258 // [[nodiscard]] value_type operator->() {
259 // return std::make_pair(*_valIter, *_colIndicesIter);
260 // }
261
262 [[nodiscard]] typename value_type::first_type value() {
263 return std::ref(*_valIter);
264 }
265
266 [[nodiscard]] typename value_type::second_type index() {
267 return std::cref(*_colIndicesIter);
268 }
269
270 [[nodiscard]] bool operator==(const self_type &other) {
271 return (_valIter == other._valIter) and
272 (_colIndicesIter == other._colIndicesIter);
273 }
274 [[nodiscard]] bool operator!=(const self_type &other) {
275 return not (*this == other);
276 }
277
278 private:
279 typename std::vector<REAL>::const_iterator _valIter;
280 std::vector<size_type>::const_iterator _colIndicesIter;
281 };
282
284 public:
285 using self_type = row_iterator;
286
287 // conform to the iterator traits
288 // https://en.cppreference.com/w/cpp/iterator/iterator_traits
289 using difference_type = std::ptrdiff_t;
290 using value_type = self_type;
291 using pointer = self_type *;
292 using reference = self_type &;
293 using iterator_category = std::random_access_iterator_tag;
294
295 row_iterator(std::vector<size_type>::iterator rowPtrIter,
296 std::vector<size_type>::iterator colIndicesIter,
297 typename std::vector<REAL>::iterator valIter)
298 : _rowPtrIter(rowPtrIter), _colIndicesIter(colIndicesIter),
299 _valIter(valIter) {}
300
301 [[nodiscard]] column_iterator begin() {
302 return column_iterator((_valIter + *_rowPtrIter));
303 }
304 [[nodiscard]] column_iterator end() {
305 return column_iterator((_valIter + *(_rowPtrIter + 1)));
306 }
307
308 [[nodiscard]] column_index_iterator ibegin() {
309 return column_index_iterator((_valIter + *_rowPtrIter),
310 (_colIndicesIter + *_rowPtrIter));
311 }
314 (_valIter + *(_rowPtrIter + 1)),
315 (_colIndicesIter + *(_rowPtrIter + 1)));
316 }
317
318 // prefix
319 self_type &operator++() {
320 _rowPtrIter++;
321 return *this;
322 }
323
324 // postfix
325 self_type operator++(int junk) {
326 self_type cached = *this;
327 _rowPtrIter++;
328 return cached;
329 }
330
331 self_type &operator+=(difference_type offset) {
332 _rowPtrIter += offset;
333 return *this;
334 }
335
336 self_type &operator-=(difference_type offset) {
337 _rowPtrIter -= offset;
338 return *this;
339 }
340
341 // iter - n
342 self_type operator-(difference_type offset) {
343 self_type cache(*this);
344 cache -= offset;
345 return cache;
346 }
347
348 // iter + n
349 self_type operator+(difference_type offset) {
350 self_type cache(*this);
351 cache += offset;
352 return cache;
353 }
354 // n + iter
355 friend self_type operator+(const difference_type &offset,
356 const self_type &sec) {
358 cache += offset;
359 return cache;
360 }
361
362 reference operator[](difference_type offset) {
363 return *(*this + offset);
364 }
365
366 bool operator<(const self_type &other) {
367 return other - (*this) > 0; //
368 }
369
370 bool operator>(const self_type &other) {
371 return other < (*this); //
372 }
373
374 [[nodiscard]] self_type &operator*() { return *this; }
375 // [[nodiscard]] self_type &operator->() { return *this; }
376
377 [[nodiscard]] bool operator==(const self_type &rhs) {
378 return _rowPtrIter == rhs._rowPtrIter;
379 }
380 [[nodiscard]] bool operator!=(const self_type &rhs) {
381 return _rowPtrIter != rhs._rowPtrIter;
382 }
383
384 private:
385 std::vector<size_type>::iterator _rowPtrIter;
386 std::vector<size_type>::iterator _colIndicesIter;
387 typename std::vector<REAL>::iterator _valIter;
388 };
389
391 public:
393
394 // conform to the iterator traits
395 // https://en.cppreference.com/w/cpp/iterator/iterator_traits
396 using difference_type = std::ptrdiff_t;
397 using value_type = self_type;
398 using pointer = self_type *;
399 using reference = self_type &;
400 using iterator_category = std::bidirectional_iterator_tag;
401
403 std::vector<size_type>::const_iterator rowPtrIter,
404 std::vector<size_type>::const_iterator colIndicesIter,
405 typename std::vector<REAL>::const_iterator valIter)
406 : _rowPtrIter(rowPtrIter), _colIndicesIter(colIndicesIter),
407 _valIter(valIter) {}
408
409 [[nodiscard]] const_column_iterator begin() const {
410 return const_column_iterator((_valIter + *_rowPtrIter));
411 }
412 [[nodiscard]] const_column_iterator end() const {
413 return const_column_iterator((_valIter + *(_rowPtrIter + 1)));
414 }
415
416 [[nodiscard]] const_column_index_iterator ibegin() const {
418 (_valIter + *_rowPtrIter), (_colIndicesIter + *_rowPtrIter));
419 }
420 [[nodiscard]] const_column_index_iterator iend() const {
422 (_valIter + *(_rowPtrIter + 1)),
423 (_colIndicesIter + *(_rowPtrIter + 1)));
424 }
425
426 [[nodiscard]] const_column_iterator cbegin() const {
427 return this->begin();
428 }
429 [[nodiscard]] const_column_iterator cend() const {
430 return this->end(); //
431 }
432
433 // prefix
434 self_type &operator++() {
435 _rowPtrIter++;
436 return *this;
437 }
438
439 // postfix
440 self_type &operator++(int junk) {
441 self_type cached = *this;
442 _rowPtrIter++;
443 return cached;
444 }
445
446 self_type &operator+=(difference_type offset) {
447 _rowPtrIter += offset;
448 return *this;
449 }
450
451 self_type &operator-=(difference_type offset) {
452 _rowPtrIter -= offset;
453 return *this;
454 }
455
456 // iter - n
457 self_type operator-(difference_type offset) {
458 self_type cache(*this);
459 cache -= offset;
460 return cache;
461 }
462
463 // iter + n
464 self_type operator+(difference_type offset) {
465 self_type cache(*this);
466 cache += offset;
467 return cache;
468 }
469 // n + iter
470 friend self_type operator+(const difference_type &offset,
471 const self_type &sec) {
473 cache += offset;
474 return cache;
475 }
476
477 reference operator[](difference_type offset) {
478 return *(*this + offset);
479 }
480
481 bool operator<(const self_type &other) {
482 return other - (*this) > 0; //
483 }
484
485 bool operator>(const self_type &other) {
486 return other < (*this); //
487 }
488
489 [[nodiscard]] self_type &operator*() { return *this; }
490 // [[nodiscard]] self_type &operator->() { return this; }
491
492 [[nodiscard]] bool operator==(const self_type &rhs) {
493 return _rowPtrIter == rhs._rowPtrIter;
494 }
495 [[nodiscard]] bool operator!=(const self_type &rhs) {
496 return _rowPtrIter != rhs._rowPtrIter;
497 }
498
499 private:
500 std::vector<size_type>::const_iterator _rowPtrIter;
501 std::vector<size_type>::const_iterator _colIndicesIter;
502 typename std::vector<REAL>::const_iterator _valIter;
503 };
504
524 return row_iterator(_rowPtr.begin(), _colIndices.begin(),
525 _data.begin());
526 }
527
547 return row_iterator(_rowPtr.end() - 1, _colIndices.begin(),
548 _data.begin());
549 }
550
557 return const_row_iterator(_rowPtr.cbegin(), _colIndices.cbegin(),
558 _data.cbegin());
559 }
560
567 return const_row_iterator(_rowPtr.cend() - 1, _colIndices.cbegin(),
568 _data.cbegin());
569 }
570
572 [[nodiscard]] const_row_iterator begin() const { return this->cbegin(); }
574 [[nodiscard]] const_row_iterator end() const { return this->cend(); }
575
600 void scientific(bool b) const { bScientific = b; }
601
603 size_type iwidth() const { return nIndexWidth; }
604
606 size_type width() const { return nValueWidth; }
607
609 size_type precision() const { return nValuePrecision; }
610
612 void iwidth(size_type i) const { nIndexWidth = i; }
613
615 void width(size_type i) const { nValueWidth = i; }
616
618 void precision(size_type i) const { nValuePrecision = i; }
619
621 const size_type col_index) const {
622 checkIfAccessIsInBounds(row_index, col_index);
623
624 using value_pair = typename const_column_index_iterator::value_type;
625 auto row = const_row_iterator(_rowPtr.begin() + row_index,
626 _colIndices.begin(), _data.begin());
627 return std::find_if(row.ibegin(), row.iend(),
629 // only care for the index here since the value
630 // is unknown
631 return el.second == col_index;
632 });
633 }
634
635 bool exists(const size_type row_index, const size_type col_index) const {
636 auto row = const_row_iterator(_rowPtr.begin() + row_index,
637 _colIndices.begin(), _data.begin());
638 return find(row_index, col_index) != row.iend();
639 }
640
643 checkIfAccessIsInBounds(row_index, col_index);
644 // look for the entry
645 using value_pair = typename const_column_index_iterator::value_type;
646 auto row = row_iterator(_rowPtr.begin() + row_index,
647 _colIndices.begin(), _data.begin());
648 auto result =
649 std::find_if(row.ibegin(), row.iend(), [col_index](value_pair el) {
650 // only care for the index here
651 // since the value is unknown
652 // anyways
653 return el.second == col_index;
654 });
655 // we found something within the right row
656 if (result != row.iend()) {
657 return result.value();
658 }
659 throw std::out_of_range(
660 "There is no non-zero element for these given indicies!");
661 }
662
665 const size_type col_index) const {
666 checkIfAccessIsInBounds(row_index, col_index);
667
668 using value_pair = typename const_column_index_iterator::value_type;
669 auto row = const_row_iterator(_rowPtr.begin() + row_index,
670 _colIndices.begin(), _data.begin());
671 auto result =
672 std::find_if(row.ibegin(), row.iend(), [col_index](value_pair el) {
673 // only care for the index here since the value is unknown
674 return el.second == col_index;
675 });
676 // we found something within the right row
677 if (result != row.iend()) {
678 return result.value();
679 }
680 return _zero;
681 }
682
684 [[nodiscard]] bool operator==(const SparseMatrix &other) const {
685 return (_data == other._data) and //
686 (_rowPtr == other._rowPtr) and //
687 (_colIndices == other._colIndices) and //
688 (m_cols == other.m_cols) and //
689 (m_rows == other.m_rows);
690 }
691
693 [[nodiscard]] bool operator!=(const SparseMatrix &other) const {
694 return not (*this == other);
695 }
696
697 // delete all the invalid comparisons
698 bool operator<(const SparseMatrix &other) = delete;
699 bool operator>(const SparseMatrix &other) = delete;
700 bool operator<=(const SparseMatrix &other) = delete;
701 bool operator>=(const SparseMatrix &other) = delete;
702
703 SparseMatrix transpose() const {
704 // TODO: remove / find bug here!
705 SparseMatrix::builder builder(m_cols, m_rows);
707 for (auto &row : (*this)) {
708 for (auto it = row.ibegin(); it != row.iend(); it++) {
709 builder.addEntry(it.index(), curr_row, it.value());
710 }
711 curr_row++;
712 }
713
714 return builder.build();
715 }
716
720 // This could also be done out of order
721 std::transform(_data.cbegin(), _data.cend(), _data.begin(),
722 [&](REAL value) { return value * scalar; });
723 }
724
728 // This could also be done out of order
729 std::transform(_data.cbegin(), _data.cend(), _data.begin(),
730 [&](REAL value) { return value / scalar; });
731 }
732
741 template <class V>
742 void mv(Vector<V> &result, const Vector<V> &x) const {
743 static_assert(std::is_convertible<V, REAL>::value,
744 "The types in the Matrix vector multiplication cant be "
745 "converted properly!");
746
747 if (result.size() != this->colsize()) {
748 HDNUM_ERROR(
749 (std::string("The result vector has the wrong dimension! ") +
750 "Vector dimension " + std::to_string(result.size()) +
751 " != " + std::to_string(this->colsize()) + " colsize"));
752 }
753
754 if (x.size() != this->colsize()) {
755 HDNUM_ERROR(
756 (std::string("The input vector has the wrong dimension! ") +
757 "Vector dimension " + std::to_string(x.size()) +
758 " != " + std::to_string(this->colsize()) + " colsize"));
759 }
760
762 for (auto row : (*this)) {
763 result[curr_row] = std::accumulate(
764 row.ibegin(), row.iend(), V {}, [&](V result, auto el) -> V {
765 return result + (x[el.second] * el.first);
766 });
767 curr_row++;
768 }
769 }
770
780 this->mv(result, x);
781 return result;
782 }
783
792 template <class V>
793 void umv(Vector<V> &result, const Vector<V> &x) const {
794 static_assert(std::is_convertible<V, REAL>::value,
795 "The types in the Matrix vector multiplication cant be "
796 "converted properly!");
797
798 if (result.size() != this->colsize()) {
799 HDNUM_ERROR(
800 (std::string("The result vector has the wrong dimension! ") +
801 "Vector dimension " + std::to_string(result.size()) +
802 " != " + std::to_string(this->colsize()) + " colsize"));
803 }
804
805 if (x.size() != this->colsize()) {
806 HDNUM_ERROR(
807 (std::string("The input vector has the wrong dimension! ") +
808 "Vector dimension " + std::to_string(result.size()) +
809 " != " + std::to_string(this->colsize()) + " colsize"));
810 }
811
813 for (auto row : (*this)) {
814 result[curr_row] += std::accumulate(
815 row.ibegin(), row.iend(), V {}, [&](V result, auto el) -> V {
816 return result + (x[el.second] * el.first);
817 });
818 curr_row++;
819 }
820 }
821
822private:
823 template <typename norm_type>
824 norm_type norm_infty_impl() const {
825 norm_type norm {};
826 for (auto row : *this) {
827 norm_type rowsum =
828 std::accumulate(row.begin(), row.end(), norm_type {},
829 [](norm_type res, REAL value) -> norm_type {
830 return res + std::abs(value);
831 });
832 if (norm < rowsum) {
833 norm = rowsum;
834 }
835 }
836 return norm;
837 }
838
839public:
847 auto norm_infty() const {
848 if constexpr (is_specialization<REAL, std::complex> {}) {
850 } else {
851 return norm_infty_impl<REAL>();
852 }
853 }
854
855 [[nodiscard]] std::string to_string() const noexcept {
856 return "values=" + comma_fold(_data) + "\n" + //
857 "colInd=" + comma_fold(_colIndices) + "\n" + //
858 "rowPtr=" + comma_fold(_rowPtr) + "\n"; //
859 }
860
861 void print() const noexcept { std::cout << *this; }
862
888 for (typename SparseMatrix<REAL>::size_type i = 0; i < dimN; ++i) {
889 builder.addEntry(i, i, REAL {1});
890 }
891 return builder.build();
892 }
893
918 SparseMatrix<REAL> matchingIdentity() const { return identity(m_cols); }
919
920 class builder {
921 size_type m_rows {}; // Number of Matrix rows, 0 by default
922 size_type m_cols {}; // Number of Matrix columns, 0 by default
923 std::vector<std::map<size_type, REAL>> _rows;
924
925 public:
927 : m_rows {new_m_rows}, m_cols {new_m_cols}, _rows {m_rows} {}
928
929 builder(const std::initializer_list<std::initializer_list<REAL>> &v)
930 : m_rows {v.size()}, m_cols {v.begin()->size()}, _rows(m_rows) {
931 size_type i = 0;
932 for (auto &row : v) {
933 size_type j = 0;
934 for (const REAL &element : row) {
935 addEntry(i, j, element);
936 j++;
937 }
938 i++;
939 }
940 }
941
942 builder() = default;
943
944 std::pair<typename std::map<size_type, REAL>::iterator, bool> addEntry(
945 size_type i, size_type j, REAL value) {
946 return _rows.at(i).emplace(j, value);
947 }
948
949 std::pair<typename std::map<size_type, REAL>::iterator, bool> addEntry(
951 return addEntry(i, j, REAL {});
952 };
953
954 [[nodiscard]] bool operator==(
955 const SparseMatrix::builder &other) const {
956 return (m_rows == other.m_rows) and //
957 (m_cols == other.m_cols) and //
958 (_rows == other._rows);
959 }
960
961 [[nodiscard]] bool operator!=(
962 const SparseMatrix::builder &other) const {
963 return not (*this == other);
964 }
965
966 [[nodiscard]] size_type colsize() const noexcept { return m_cols; }
967 [[nodiscard]] size_type rowsize() const noexcept { return m_rows; }
968
969 size_type setNumCols(size_type new_m_cols) noexcept {
970 m_cols = new_m_cols;
971 return m_cols;
972 }
973 size_type setNumRows(size_type new_m_rows) {
974 m_rows = new_m_rows;
975 _rows.resize(m_cols);
976 return m_rows;
977 }
978
979 void clear() noexcept {
980 for (auto &row : _rows) {
981 row.clear();
982 }
983 }
984
985 [[nodiscard]] std::string to_string() const {
986 std::string output;
987 for (std::size_t i = 0; i < _rows.size(); i++) {
988 for (const auto &indexpair : _rows[i]) {
989 output += std::to_string(i) + ", " +
990 std::to_string(indexpair.first) + " => " +
991 std::to_string(indexpair.second) + "\n";
992 }
993 }
994 return output;
995 }
996
997 [[nodiscard]] SparseMatrix build() {
998 auto result = SparseMatrix<REAL>(m_rows, m_cols);
999
1000 for (std::size_t i = 0; i < _rows.size(); i++) {
1001 result._rowPtr[i + 1] = result._rowPtr[i];
1002 for (const auto &indexpair : _rows[i]) {
1003 result._colIndices.push_back(indexpair.first);
1004 result._data.push_back(indexpair.second);
1005 result._rowPtr[i + 1]++;
1006 }
1007 }
1008 return result;
1009 }
1010 };
1011};
1012
1013template <typename REAL>
1015template <typename REAL>
1016std::size_t SparseMatrix<REAL>::nIndexWidth = 10;
1017template <typename REAL>
1018std::size_t SparseMatrix<REAL>::nValueWidth = 10;
1019template <typename REAL>
1021template <typename REAL>
1023
1024template <typename REAL>
1025std::ostream &operator<<(std::ostream &s, const SparseMatrix<REAL> &A) {
1026 using size_type = typename SparseMatrix<REAL>::size_type;
1027
1028 s << std::endl;
1029 s << " " << std::setw(A.iwidth()) << " "
1030 << " ";
1031 for (size_type j = 0; j < A.colsize(); ++j) {
1032 s << std::setw(A.width()) << j << " ";
1033 }
1034 s << std::endl;
1035
1036 for (size_type i = 0; i < A.rowsize(); ++i) {
1037 s << " " << std::setw(A.iwidth()) << i << " ";
1038 for (size_type j = 0; j < A.colsize(); ++j) {
1039 if (A.scientific()) {
1040 s << std::setw(A.width()) << std::scientific << std::showpoint
1041 << std::setprecision(A.precision()) << A(i, j) << " ";
1042 } else {
1043 s << std::setw(A.width()) << std::fixed << std::showpoint
1044 << std::setprecision(A.precision()) << A(i, j) << " ";
1045 }
1046 }
1047 s << std::endl;
1048 }
1049 return s;
1050}
1051
1053template <typename REAL>
1054inline void zero(SparseMatrix<REAL> &A) {
1055 A = SparseMatrix<REAL>(A.rowsize(), A.colsize());
1056}
1057
1091template <class REAL>
1093 if (A.rowsize() != A.colsize()) {
1094 HDNUM_ERROR("Will not overwrite A since Dimensions are not equal!");
1095 }
1097}
1098
1099template <typename REAL>
1100inline void readMatrixFromFile(const std::string &filename,
1101 SparseMatrix<REAL> &A) {
1102 // Format taken from here:
1103 // https://math.nist.gov/MatrixMarket/formats.html#coord
1104
1105 using size_type = typename SparseMatrix<REAL>::size_type;
1106 std::string buffer;
1107 std::ifstream fin(filename);
1108 size_type i = 0;
1109 size_type j = 0;
1110 size_type non_zeros = 0;
1111
1112 if (fin.is_open()) {
1113 // ignore all comments from the file (starting with %)
1114 while (fin.peek() == '%') fin.ignore(2048, '\n');
1115
1116 std::getline(fin, buffer);
1117 std::istringstream first_line(buffer);
1118 first_line >> i >> j >> non_zeros;
1119
1120 auto builder = typename SparseMatrix<REAL>::builder(i, j);
1121
1122 while (std::getline(fin, buffer)) {
1123 std::istringstream iss(buffer);
1124
1125 REAL value {};
1126 iss >> i >> j >> value;
1127 // i-1, j-1, because matrix market does not use zero based indexing
1128 builder.addEntry(i - 1, j - 1, value);
1129 }
1130 A = builder.build();
1131 fin.close();
1132 } else {
1133 HDNUM_ERROR(("Could not osspen file! \"" + filename + "\""));
1134 }
1135}
1136
1137} // namespace hdnum
1138
1139#endif // SPARSEMATRIX_HH
Class with mathematical matrix operations.
Definition densematrix.hh:33
size_t rowsize() const
get number of rows of the matrix
Definition densematrix.hh:136
size_t colsize() const
get number of columns of the matrix
Definition densematrix.hh:153
Definition sparsematrix.hh:920
Definition sparsematrix.hh:160
Definition sparsematrix.hh:390
Definition sparsematrix.hh:283
Sparse matrix Class with mathematical matrix operations.
Definition sparsematrix.hh:31
void mv(Vector< V > &result, const Vector< V > &x) const
matrix vector product y = A*x
Definition sparsematrix.hh:742
std::size_t size_type
Types used for array indices.
Definition sparsematrix.hh:34
size_type rowsize() const
get number of rows of the matrix
Definition sparsematrix.hh:138
void precision(size_type i) const
set data precision for pretty-printing
Definition sparsematrix.hh:618
Vector< REAL > operator*(const Vector< REAL > &x) const
matrix vector product A*x
Definition sparsematrix.hh:778
const_row_iterator end() const
Definition sparsematrix.hh:574
static SparseMatrix identity(const size_type dimN)
identity for the matrix
Definition sparsematrix.hh:886
typename std::vector< REAL >::const_iterator const_column_iterator
type of a const regular column iterator (no access to indices)
Definition sparsematrix.hh:39
row_iterator begin()
get a (possibly modifying) row iterator for the sparse matrix
Definition sparsematrix.hh:523
bool operator!=(const SparseMatrix &other) const
checks whether two matricies are unequal based on values and dimension
Definition sparsematrix.hh:693
void umv(Vector< V > &result, const Vector< V > &x) const
update matrix vector product y += A*x
Definition sparsematrix.hh:793
size_type colsize() const
get number of columns of the matrix
Definition sparsematrix.hh:155
SparseMatrix< REAL > matchingIdentity() const
creates a matching identity
Definition sparsematrix.hh:918
SparseMatrix(const size_type _rows, const size_type _cols)
constructor with added dimensions and columns
Definition sparsematrix.hh:119
REAL & get(const size_type row_index, const size_type col_index)
write access on matrix element A_ij using A.get(i,j)
Definition sparsematrix.hh:642
SparseMatrix operator*=(const REAL scalar)
Definition sparsematrix.hh:719
size_type precision() const
get data precision for pretty-printing
Definition sparsematrix.hh:609
const_row_iterator cbegin() const
get a (non modifying) row iterator for the sparse matrix
Definition sparsematrix.hh:556
typename std::vector< REAL >::iterator column_iterator
type of a regular column iterator (no access to indices)
Definition sparsematrix.hh:37
void width(size_type i) const
set data field width for pretty-printing
Definition sparsematrix.hh:615
void identity(SparseMatrix< REAL > &A)
Definition sparsematrix.hh:1092
size_type width() const
get data field width for pretty-printing
Definition sparsematrix.hh:606
SparseMatrix operator/=(const REAL scalar)
Definition sparsematrix.hh:727
const_row_iterator cend() const
get a (non modifying) row iterator for the sparse matrix
Definition sparsematrix.hh:566
auto norm_infty() const
calculate row sum norm
Definition sparsematrix.hh:847
void scientific(bool b) const
Switch between floating point (default=true) and fixed point (false) display.
Definition sparsematrix.hh:600
const REAL & operator()(const size_type row_index, const size_type col_index) const
read-access on matrix element A_ij using A(i,j)
Definition sparsematrix.hh:664
void iwidth(size_type i) const
set index field width for pretty-printing
Definition sparsematrix.hh:612
size_type iwidth() const
get index field width for pretty-printing
Definition sparsematrix.hh:603
bool scientific() const
pretty-print output properties
Definition sparsematrix.hh:158
row_iterator end()
get a (possibly modifying) row iterator for the sparse matrix
Definition sparsematrix.hh:546
const_row_iterator begin() const
Definition sparsematrix.hh:572
bool operator==(const SparseMatrix &other) const
checks whether two matricies are equal based on values and dimension
Definition sparsematrix.hh:684
SparseMatrix()=default
default constructor (empty SparseMatrix)