MoCSI API Reference
Loading...
Searching...
No Matches
CsrMatrix.h
Go to the documentation of this file.
1#ifndef CSR_MATRIX_H
2#define CSR_MATRIX_H
3
4#include <algorithm>
5#include <iostream>
6#include <tuple>
7#include <valarray>
8#include <vector>
9
10#include "CoreEnums.h"
11#include "GenericMatrix.h"
12
16class StaticSparseMatrixAccessError : public std::runtime_error
17{
18 public:
20 : std::runtime_error("Accessing zero element at (" + std::to_string(row) + ","
21 + std::to_string(col) + ") in non-const context.")
22 {
23 }
24};
25
33template <typename T>
35{
36 private:
37 std::valarray<int> m_column_indices;
38 std::valarray<int> m_row_pointers;
39 int m_number_non_zeros{};
40 bool m_dynamic_creation{};
41 std::vector<std::tuple<T, int, int>> m_temporary_dynamic_create_storage{};
42
43 int findIndex(int rows, int cols) const;
44
45 public:
47 CsrSparseMatrix(const std::valarray<T>& values, const std::valarray<int>& column_indices,
48 const std::valarray<int>& row_pointers, int rows, int cols);
49
50 void registerElement(T value, int rows, int cols) override;
51 void buildAtRuntime();
52 void buildAtRuntime(int rows, int cols) override;
53
54 T& operator()(int rows, int cols) override;
55 T operator()(int rows, int cols) const override;
56
57 std::valarray<T> scalarAdd(T value) const override;
58 std::valarray<T> scalarSubtract(T value) const override;
59 std::valarray<T> scalarMultiply(T value) const override;
60 std::valarray<T> scalarDivide(T value) const override;
61
62 std::valarray<T> vectorElemAdd(const std::valarray<T>& value) const override;
63 std::valarray<T> vectorElemSubtract(const std::valarray<T>& value) const override;
64 std::valarray<T> vectorElemMultiply(const std::valarray<T>& value) const override;
65 std::valarray<T> vectorElemDivide(const std::valarray<T>& value) const override;
66
67 std::valarray<T> matrixVectorMultiplication(const std::valarray<T>& value) const override;
68
69 const MatrixType getMatrixType() override { return MatrixType::Csr; }
70
72
73 const std::vector<std::pair<int, int>>& getNonZeroElements() override
74 {
75 return this->m_non_zero_elements;
76 };
77
78 int getNonZeroElementNumber() const { return this->m_matrix.size(); }
79 const std::valarray<int>& getColumnIndices() { return this->m_column_indices; }
80 const std::valarray<int>& getRowPointers() { return this->m_row_pointers; }
81 const std::valarray<T>& getMatrixElements() { return this->m_matrix; }
82 void updateNonZeroElements() override;
83
84 ~CsrSparseMatrix() override = default;
85};
86
91template <typename T>
93{
94}
95
107template <typename T>
109 const std::valarray<int>& column_indices,
110 const std::valarray<int>& row_pointers, int rows, int cols)
111 : GenericMatrix<T>{rows, cols, values, true},
112 m_column_indices{column_indices},
113 m_row_pointers{row_pointers}
114{
115}
116
125template <typename T>
126void CsrSparseMatrix<T>::registerElement(const T value, const int rows, const int cols)
127{
128 if (m_dynamic_creation)
129 {
130 m_temporary_dynamic_create_storage.emplace_back(value, rows, cols);
131 }
132}
133
144template <typename T>
146{
147 if (m_dynamic_creation)
148 {
149 const auto& max_row_ptr = std::max_element(
150 m_temporary_dynamic_create_storage.begin(), m_temporary_dynamic_create_storage.end(),
151 [](std::tuple<T, int, int> lhs, std::tuple<T, int, int> rhs)
152 { return std::get<1>(lhs) < std::get<1>(rhs); });
153 const auto& max_col_ptr = std::max_element(
154 m_temporary_dynamic_create_storage.begin(), m_temporary_dynamic_create_storage.end(),
155 [](std::tuple<T, int, int> lhs, std::tuple<T, int, int> rhs)
156 { return std::get<2>(lhs) < std::get<2>(rhs); });
157 this->m_rows = std::get<1>(*max_row_ptr) + 1;
158 this->m_cols = std::get<2>(*max_col_ptr) + 1;
159 // Do not use the max_ptrs afterwards, as we sort the elements and the pointers will lose
160 // their max property. Sort the temporary storage by rows (ascending) and within a row by
161 // columns (ascending).
162 std::sort(m_temporary_dynamic_create_storage.begin(),
163 m_temporary_dynamic_create_storage.end(),
164 [](std::tuple<T, int, int> lhs, std::tuple<T, int, int> rhs)
165 {
166 if (std::get<1>(lhs) == std::get<1>(rhs))
167 {
168 return std::get<2>(lhs) < std::get<2>(rhs);
169 }
170 return std::get<1>(lhs) < std::get<1>(rhs);
171 });
172 // Clear out duplicate entries. They can be produced when building a global matrix from
173 // smaller ones that overlap in some entries, like when using finite elements.
174 for (auto it = m_temporary_dynamic_create_storage.begin();;)
175 {
176 if (std::get<1>(*it) == std::get<1>(*(it + 1))
177 && std::get<2>(*it) == std::get<2>(*(it + 1)))
178 {
179 it = m_temporary_dynamic_create_storage.erase(it);
180 }
181 else
182 {
183 ++it;
184 }
185 if (it + 1 == m_temporary_dynamic_create_storage.end())
186 {
187 break;
188 }
189 }
190 // All non-zero entries are known, so the valarray sizes can be finalized
191 this->m_matrix.resize(m_temporary_dynamic_create_storage.size());
192 m_column_indices.resize(m_temporary_dynamic_create_storage.size());
193 // The row pointer always has one element more that points to n+1, as to always define
194 // row_pointer[i+1].
195 m_row_pointers.resize(this->m_rows + 1);
196
197 auto current_row_start{m_temporary_dynamic_create_storage.begin()};
198 bool is_last{false};
199 // We need the +1 on the end iterator here, because we need the case it = .end() within the
200 // if condition
201 for (auto it{m_temporary_dynamic_create_storage.begin()};; it++)
202 {
203 is_last = (it == m_temporary_dynamic_create_storage.end());
204 if (is_last || std::get<1>(*it) != std::get<1>(*current_row_start))
205 {
206 // Set the row pointer for the current row to the element, which marks the start of
207 // that row.
208 m_row_pointers[std::get<1>(*current_row_start)] = static_cast<int>(
209 current_row_start - m_temporary_dynamic_create_storage.begin());
211 }
212 if (is_last)
213 {
214 break;
215 }
216 }
217 // This element is not a part of the matrix, but it makes the expresion m_row_pointers[rows]
218 // and m_row_pointers[rows + 1] valid for all rows <= nr_of_rows!
219 // m_row_pointers[current_row_int] = static_cast<int>( current_row_start -
220 // m_temporary_dynamic_create_storage.begin() ); current_row_int++;
221 m_row_pointers[this->m_rows] = this->m_matrix.size();
222
223 // After this block, the elements are all sorted by rows (ascending) and within one row by
224 // columns (ascending) and the beginnings of the rows are already marked, so we can simply
225 // write them directly to the arrays.
226 for (int i{0}; i < m_temporary_dynamic_create_storage.size(); i++)
227 {
228 this->m_matrix[i] = std::get<0>(m_temporary_dynamic_create_storage[i]);
229 m_column_indices[i] = std::get<2>(m_temporary_dynamic_create_storage[i]);
230 }
231 }
232}
233
246template <typename T>
248{
249 if (m_dynamic_creation)
250 {
251 this->m_rows = rows;
252 this->m_cols = cols;
253 // Do not use the max_ptrs afterwards, as we sort the elements and the pointers will lose
254 // their max property. Sort the temporary storage by rows (ascending) and within a row by
255 // columns (ascending).
256 std::sort(m_temporary_dynamic_create_storage.begin(),
257 m_temporary_dynamic_create_storage.end(),
258 [](std::tuple<T, int, int> lhs, std::tuple<T, int, int> rhs)
259 {
260 if (std::get<1>(lhs) == std::get<1>(rhs))
261 {
262 return std::get<2>(lhs) < std::get<2>(rhs);
263 }
264 return std::get<1>(lhs) < std::get<1>(rhs);
265 });
266 // Clear out duplicate entries. They can be produced when building a global matrix from
267 // smaller ones that overlap in some entries, like when using finite elements.
268 for (auto it = m_temporary_dynamic_create_storage.begin();;)
269 {
270 if (std::get<1>(*it) == std::get<1>(*(it + 1))
271 && std::get<2>(*it) == std::get<2>(*(it + 1)))
272 {
273 it = m_temporary_dynamic_create_storage.erase(it);
274 }
275 else
276 {
277 ++it;
278 }
279 if (it + 1 == m_temporary_dynamic_create_storage.end())
280 {
281 break;
282 }
283 }
284 // All non-zero entries are known, so the valarray sizes can be finalized
285 this->m_matrix.resize(m_temporary_dynamic_create_storage.size());
286 m_column_indices.resize(m_temporary_dynamic_create_storage.size());
287 // The last row always has entries for all FEM/FV/FD discretizations, so we can set the row
288 // pointer array size to this value + 2
289 m_row_pointers.resize(rows + 1);
290
291 auto current_row_start{m_temporary_dynamic_create_storage.begin()};
292 bool is_last{false};
293 // We need the +1 on the end iterator here, because we need the case it = .end() within the
294 // if condition
295 for (auto it{m_temporary_dynamic_create_storage.begin()};; it++)
296 {
297 is_last = (it == m_temporary_dynamic_create_storage.end());
298 if (is_last || std::get<1>(*it) != std::get<1>(*current_row_start))
299 {
300 // Set the row pointer for the current row to the element, which marks the start of
301 // that row.
302 m_row_pointers[std::get<1>(*current_row_start)] = static_cast<int>(
303 current_row_start - m_temporary_dynamic_create_storage.begin());
305 }
306 if (is_last)
307 {
308 break;
309 }
310 }
311 // This element is not a part of the matrix, but it makes the expresion m_row_pointers[rows]
312 // and m_row_pointers[rows + 1] valid for all rows <= nr_of_rows!
313 // m_row_pointers[current_row_int] = static_cast<int>( current_row_start -
314 // m_temporary_dynamic_create_storage.begin() ); current_row_int++;
315 m_row_pointers[rows] = this->m_matrix.size();
316
317 // After this block, the elements are all sorted by rows (ascending) and within one row by
318 // columns (ascending) and the beginnings of the rows are already marked, so we can simply
319 // write them directly to the arrays.
320 for (int i{0}; i < m_temporary_dynamic_create_storage.size(); i++)
321 {
322 this->m_matrix[i] = std::get<0>(m_temporary_dynamic_create_storage[i]);
323 m_column_indices[i] = std::get<2>(m_temporary_dynamic_create_storage[i]);
324 }
325 }
326}
327
338template <typename T>
339int CsrSparseMatrix<T>::findIndex(const int rows, const int cols) const
340{
341 int lower_bounds{m_row_pointers[rows]};
342 int upper_bounds{m_row_pointers[rows + 1] - 1};
343 int test_index{-1};
344
345 // Use devide and conquer algorithm to find result in log(n) time
346 while (lower_bounds <= upper_bounds)
347 {
349 if (m_column_indices[test_index] < cols)
350 {
352 }
353 else if (m_column_indices[test_index] > cols)
354 {
356 }
357 else
358 {
359 return test_index;
360 }
361 }
362 // If no match was found, then return a negative value to show this.
363 return -1;
364}
365
375template <typename T>
377{
378 if (rows >= this->m_rows || cols >= this->m_cols)
379 {
380 throw MatrixOutOfBoundsError(rows, cols, this->m_rows, this->m_cols);
381 }
382
383 int matrix_value_index{findIndex(rows, cols)};
384 // If the value is non-zero, is has to be in the given row, whose values are all between
385 // m_row_pointers[rows] and m_row_pointers[rows + 1]
386
387 // If _find_index returned -1, it has to be a zero value.
388 // This is technically not intended to access 0 elements in non-const context, as we would need
389 // to write it into the matrix (which schould never carry elements that are zero) If we want to
390 // allow element insertion in place (warning, this can be VERY slow), then we can replace that
391 // here. Right now it's just a placeholder
392 if (matrix_value_index == -1)
393 {
395 }
396 return this->m_matrix[matrix_value_index];
397}
398
407template <typename T>
408T CsrSparseMatrix<T>::operator()(const int rows, const int cols) const
409{
410 if (rows >= this->m_rows || cols >= this->m_cols || rows < 0 || cols < 0)
411 {
412 throw MatrixOutOfBoundsError(rows, cols, this->m_rows, this->m_cols);
413 }
414
415 int matrix_value_index{findIndex(rows, cols)};
416
417 // If the value is a non-defined zero value, return zero.
418 if (matrix_value_index == -1)
419 {
420 throw static_cast<T>(0.0);
421 }
422 return this->m_matrix[matrix_value_index];
423}
424
429template <typename T>
430std::valarray<T> CsrSparseMatrix<T>::scalarAdd(const T value) const
431{
432 return this->m_matrix + value;
433}
434
440template <typename T>
441std::valarray<T> CsrSparseMatrix<T>::scalarSubtract(const T value) const
442{
443 return this->m_matrix - value;
444}
445
451template <typename T>
452std::valarray<T> CsrSparseMatrix<T>::scalarMultiply(const T value) const
453{
454 return this->m_matrix * value;
455}
456
462template <typename T>
463std::valarray<T> CsrSparseMatrix<T>::scalarDivide(const T value) const
464{
465 return this->m_matrix / value;
466}
467
472template <typename T>
473std::valarray<T> CsrSparseMatrix<T>::vectorElemAdd(const std::valarray<T>& value) const
474{
475 return this->m_matrix + value;
476}
477
483template <typename T>
484std::valarray<T> CsrSparseMatrix<T>::vectorElemSubtract(const std::valarray<T>& value) const
485{
486 return this->m_matrix - value;
487}
488
494template <typename T>
495std::valarray<T> CsrSparseMatrix<T>::vectorElemMultiply(const std::valarray<T>& value) const
496{
497 return this->m_matrix * value;
498}
499
505template <typename T>
506std::valarray<T> CsrSparseMatrix<T>::vectorElemDivide(const std::valarray<T>& value) const
507{
508 return this->m_matrix / value;
509}
510
518template <typename T>
519std::valarray<T> CsrSparseMatrix<T>::matrixVectorMultiplication(const std::valarray<T>& value) const
520{
521 std::valarray<T> result(this->m_rows);
522 int index_row_start;
523 int index_row_end;
524 for (int i{0}; i < this->m_rows; i++)
525 {
526 index_row_start = m_row_pointers[i];
527 index_row_end = m_row_pointers[i + 1];
528 for (int j{index_row_start}; j < index_row_end; j++)
529 {
530 result[i] += this->m_matrix[j] * value[m_column_indices[j]];
531 }
532 }
533 return result;
534}
535
539template <typename T>
541{
542 if (this->m_matrix.size() > 0)
543 {
544 for (int i{0}; i < m_row_pointers.size() - 1; i++)
545 {
546 std::valarray<int> column_values_in_row = m_column_indices[std::slice(
547 m_row_pointers[i], m_row_pointers[i + 1] - m_row_pointers[i], 1)];
548 int current_column_id{0};
549 for (int j{0}; j < this->m_cols; j++)
550 {
553 {
554 std::cout << this->m_matrix[m_row_pointers[i] + current_column_id] << ' ';
556 }
557 else
558 {
559 std::cout << "0" << ' ';
560 }
561 }
562 std::cout << "\n";
563 }
564 }
565 else
566 {
567 std::cout << "Matrix is empty\n";
568 }
569}
570
576template <typename T>
578{
579 for (const auto& position_tuple : m_temporary_dynamic_create_storage)
580 {
581 this->m_non_zero_elements.emplace_back(std::get<1>(position_tuple),
582 std::get<2>(position_tuple));
583 }
584}
585#endif
MatrixType
Definition CoreEnums.h:33
Concrete implementation of a matrix class representing a Compressed Sparse Rows (CSR) matrix....
Definition CsrMatrix.h:35
void registerElement(T value, int rows, int cols) override
Registers the element and it's initial value within a COO style vector for dynamic creation.
Definition CsrMatrix.h:126
T & operator()(int rows, int cols) override
Parentheses operator to allow access to the non-zero matrix values as Matrix(row,column)....
Definition CsrMatrix.h:376
void printMatrixInDenseFormat()
Prints the entire matrix with zero values.
Definition CsrMatrix.h:540
std::valarray< T > scalarSubtract(T value) const override
Subtraction of a scalar from the matrix values element-wise.
Definition CsrMatrix.h:441
std::valarray< T > scalarDivide(T value) const override
Division of a scalar from the matrix values element-wise.
Definition CsrMatrix.h:463
const std::vector< std::pair< int, int > > & getNonZeroElements() override
Definition CsrMatrix.h:73
void updateNonZeroElements() override
Sets the m_non_zero_elememts parameter of the parent class.
Definition CsrMatrix.h:577
std::valarray< T > vectorElemMultiply(const std::valarray< T > &value) const override
Multiplication of a vector to the matrix values element-wise.
Definition CsrMatrix.h:495
std::valarray< T > scalarMultiply(T value) const override
Multiplication of a scalar to the matrix values element-wise.
Definition CsrMatrix.h:452
const std::valarray< int > & getColumnIndices()
Definition CsrMatrix.h:79
int getNonZeroElementNumber() const
Definition CsrMatrix.h:78
CsrSparseMatrix()
Constructor for an empty CsrSparseMatrix object. Leaves all storage arrays empty but sets the flag to...
Definition CsrMatrix.h:92
~CsrSparseMatrix() override=default
const std::valarray< int > & getRowPointers()
Definition CsrMatrix.h:80
std::valarray< T > scalarAdd(T value) const override
Addition of a scalar to the matrix values element-wise.
Definition CsrMatrix.h:430
std::valarray< T > vectorElemSubtract(const std::valarray< T > &value) const override
Subtraction of a vector from the matrix values element-wise.
Definition CsrMatrix.h:484
std::valarray< T > matrixVectorMultiplication(const std::valarray< T > &value) const override
Matrix-vector-multiplication for sparse matrices.
Definition CsrMatrix.h:519
std::valarray< T > vectorElemAdd(const std::valarray< T > &value) const override
Addition of a vector to the matrix values element-wise.
Definition CsrMatrix.h:473
const MatrixType getMatrixType() override
Definition CsrMatrix.h:69
std::valarray< T > vectorElemDivide(const std::valarray< T > &value) const override
Division of a vector from the matrix values element-wise.
Definition CsrMatrix.h:506
void buildAtRuntime()
Builds the CSR matrix from the registered elements. It sorts all elements of the COO format vector by...
Definition CsrMatrix.h:145
const std::valarray< T > & getMatrixElements()
Definition CsrMatrix.h:81
Template generalized Matrix object that should be the base for all further implementations of a matri...
Definition GenericMatrix.h:19
std::valarray< T > m_matrix
Definition GenericMatrix.h:24
std::vector< std::pair< int, int > > m_non_zero_elements
Definition GenericMatrix.h:25
std::pair< int, int > size() const
Function that returns the size of the matrix as a pair in (rows, columns) format.
Definition GenericMatrix.h:118
int m_rows
Definition GenericMatrix.h:21
int m_cols
Definition GenericMatrix.h:22
Error class to throw when the matrix is accessed out of bounds. Inherits from std::exception.
Definition GenericMatrix.h:150
Error class to be thrown when a zero element is tried to be accessed as a reference.
Definition CsrMatrix.h:17
StaticSparseMatrixAccessError(const int row, const int col)
Definition CsrMatrix.h:19