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 "GenericMatrix.h"
11
12class StaticSparseMatrixAccessError : public std::runtime_error
13{
14 public:
16 : std::runtime_error("Accessing zero element at (" + std::to_string(row) + ","
17 + std::to_string(col) + ") in non-const context.")
18 {
19 }
20};
21
29template <typename T>
31{
32 private:
33 std::valarray<int> m_column_indices;
34 std::valarray<int> m_row_pointers;
35 int m_number_non_zeros{};
36 bool m_dynamic_creation{};
37 std::vector<std::tuple<T, int, int>> m_temporary_dynamic_create_storage{};
38
39 int findIndex(int rows, int cols) const;
40
41 public:
43 CsrSparseMatrix(const std::valarray<T>& values, const std::valarray<int>& column_indices,
44 const std::valarray<int>& row_pointers, int rows, int cols);
45
46 void registerElement(T value, int rows, int cols);
47 void buildAtRuntime();
48 void buildAtRuntime(int rows, int cols) override;
49
50 T& operator()(int rows, int cols) override;
51 T operator()(int rows, int cols) const override;
52
53 std::valarray<T> scalarAdd(T value) const override;
54 std::valarray<T> scalarSubtract(T value) const override;
55 std::valarray<T> scalarMultiply(T value) const override;
56 std::valarray<T> scalarDivide(T value) const override;
57
59
60 const std::vector<std::pair<int, int>>& getNonZeroElements() override
61 {
62 return this->m_non_zero_elements;
63 };
64 void updateNonZeroElements() override;
65
66 ~CsrSparseMatrix() override = default;
67};
68
73template <typename T>
75{
76}
77
89template <typename T>
91 const std::valarray<int>& column_indices,
92 const std::valarray<int>& row_pointers, int rows, int cols)
93 : GenericMatrix<T>{rows, cols, values, true},
94 m_column_indices{column_indices},
95 m_row_pointers{row_pointers}
96{
97}
98
107template <typename T>
108void CsrSparseMatrix<T>::registerElement(const T value, const int rows, const int cols)
109{
110 if (m_dynamic_creation)
111 {
112 m_temporary_dynamic_create_storage.emplace_back(value, rows, cols);
113 }
114}
115
126template <typename T>
128{
129 if (m_dynamic_creation)
130 {
131 const auto& max_row_ptr = std::max_element(
132 m_temporary_dynamic_create_storage.begin(), m_temporary_dynamic_create_storage.end(),
133 [](std::tuple<T, int, int> lhs, std::tuple<T, int, int> rhs)
134 { return std::get<1>(lhs) < std::get<1>(rhs); });
135 const auto& max_col_ptr = std::max_element(
136 m_temporary_dynamic_create_storage.begin(), m_temporary_dynamic_create_storage.end(),
137 [](std::tuple<T, int, int> lhs, std::tuple<T, int, int> rhs)
138 { return std::get<2>(lhs) < std::get<2>(rhs); });
139 this->m_rows = std::get<1>(*max_row_ptr) + 1;
140 this->m_cols = std::get<2>(*max_col_ptr) + 1;
141 // Do not use the max_ptrs afterwards, as we sort the elements and the pointers will lose
142 // their max property. Sort the temporary storage by rows (ascending) and within a row by
143 // columns (ascending).
144 std::sort(m_temporary_dynamic_create_storage.begin(),
145 m_temporary_dynamic_create_storage.end(),
146 [](std::tuple<T, int, int> lhs, std::tuple<T, int, int> rhs)
147 {
148 if (std::get<1>(lhs) == std::get<1>(rhs))
149 {
150 return std::get<2>(lhs) < std::get<2>(rhs);
151 }
152 return std::get<1>(lhs) < std::get<1>(rhs);
153 });
154 // All non-zero entries are known, so the valarray sizes can be finalized
155 this->m_matrix.resize(m_temporary_dynamic_create_storage.size());
156 m_column_indices.resize(m_temporary_dynamic_create_storage.size());
157 // The row pointer always has one element more that points to n+1, as to always define
158 // row_pointer[i+1].
159 m_row_pointers.resize(this->m_rows + 1);
160
161 auto current_row_start{m_temporary_dynamic_create_storage.begin()};
162 int current_row_int{0};
163 bool is_last{false};
164 // We need the +1 on the end iterator here, because we need the case it = .end() within the
165 // if condition
166 for (auto it{m_temporary_dynamic_create_storage.begin()};; it++)
167 {
168 is_last = (it == m_temporary_dynamic_create_storage.end());
169 if (is_last || std::get<1>(*it) != std::get<1>(*current_row_start))
170 {
171 // Set the row pointer for the current row to the element, which marks the start of
172 // that row.
173 m_row_pointers[current_row_int] = static_cast<int>(
174 current_row_start - m_temporary_dynamic_create_storage.begin());
177 }
178 if (is_last)
179 {
180 break;
181 }
182 }
183 // This element is not a part of the matrix, but it makes the expresion m_row_pointers[rows]
184 // and m_row_pointers[rows + 1] valid for all rows <= nr_of_rows!
185 // m_row_pointers[current_row_int] = static_cast<int>( current_row_start -
186 // m_temporary_dynamic_create_storage.begin() ); current_row_int++;
187 m_row_pointers[current_row_int] = this->m_matrix.size();
188
189 // After this block, the elements are all sorted by rows (ascending) and within one row by
190 // columns (ascending) and the beginnings of the rows are already marked, so we can simply
191 // write them directly to the arrays.
192 for (int i{0}; i < m_temporary_dynamic_create_storage.size(); i++)
193 {
194 this->m_matrix[i] = std::get<0>(m_temporary_dynamic_create_storage[i]);
195 m_column_indices[i] = std::get<2>(m_temporary_dynamic_create_storage[i]);
196 }
197 }
198}
199
212template <typename T>
214{
215 if (m_dynamic_creation)
216 {
217 this->m_rows = rows;
218 this->m_cols = cols;
219 // Do not use the max_ptrs afterwards, as we sort the elements and the pointers will lose
220 // their max property. Sort the temporary storage by rows (ascending) and within a row by
221 // columns (ascending).
222 std::sort(m_temporary_dynamic_create_storage.begin(),
223 m_temporary_dynamic_create_storage.end(),
224 [](std::tuple<T, int, int> lhs, std::tuple<T, int, int> rhs)
225 {
226 if (std::get<1>(lhs) == std::get<1>(rhs))
227 {
228 return std::get<2>(lhs) < std::get<2>(rhs);
229 }
230 return std::get<1>(lhs) < std::get<1>(rhs);
231 });
232 // All non-zero entries are known, so the valarray sizes can be finalized
233 this->m_matrix.resize(m_temporary_dynamic_create_storage.size());
234 m_column_indices.resize(m_temporary_dynamic_create_storage.size());
235 // The last row always has entries for all FEM/FV/FD discretizations, so we can set the row
236 // pointer array size to this value + 2
237 m_row_pointers.resize(rows + 1);
238
239 auto current_row_start{m_temporary_dynamic_create_storage.begin()};
240 int current_row_int{0};
241 bool is_last{false};
242 // We need the +1 on the end iterator here, because we need the case it = .end() within the
243 // if condition
244 for (auto it{m_temporary_dynamic_create_storage.begin()};; it++)
245 {
246 is_last = (it == m_temporary_dynamic_create_storage.end());
247 if (is_last || std::get<1>(*it) != std::get<1>(*current_row_start))
248 {
249 // Set the row pointer for the current row to the element, which marks the start of
250 // that row.
251 m_row_pointers[current_row_int] = static_cast<int>(
252 current_row_start - m_temporary_dynamic_create_storage.begin());
255 }
256 if (is_last)
257 {
258 break;
259 }
260 }
261 // This element is not a part of the matrix, but it makes the expresion m_row_pointers[rows]
262 // and m_row_pointers[rows + 1] valid for all rows <= nr_of_rows!
263 // m_row_pointers[current_row_int] = static_cast<int>( current_row_start -
264 // m_temporary_dynamic_create_storage.begin() ); current_row_int++;
265 m_row_pointers[current_row_int] = this->m_matrix.size();
266
267 // After this block, the elements are all sorted by rows (ascending) and within one row by
268 // columns (ascending) and the beginnings of the rows are already marked, so we can simply
269 // write them directly to the arrays.
270 for (int i{0}; i < m_temporary_dynamic_create_storage.size(); i++)
271 {
272 this->m_matrix[i] = std::get<0>(m_temporary_dynamic_create_storage[i]);
273 m_column_indices[i] = std::get<2>(m_temporary_dynamic_create_storage[i]);
274 }
275 }
276}
277
288template <typename T>
289int CsrSparseMatrix<T>::findIndex(const int rows, const int cols) const
290{
291 int lower_bounds{m_row_pointers[rows]};
292 int upper_bounds{m_row_pointers[rows + 1] - 1};
293 int test_index{-1};
294
295 // Use devide and conquer algorithm to find result in log(n) time
296 while (lower_bounds <= upper_bounds)
297 {
299 if (m_column_indices[test_index] < cols)
300 {
302 }
303 else if (m_column_indices[test_index] > cols)
304 {
306 }
307 else
308 {
309 return test_index;
310 }
311 }
312 // If no match was found, then return a negative value to show this.
313 return -1;
314}
315
325template <typename T>
327{
328 if (rows >= this->m_rows || cols >= this->m_cols)
329 {
330 throw MatrixOutOfBoundsError(rows, cols, this->m_rows, this->m_cols);
331 }
332
333 int matrix_value_index{findIndex(rows, cols)};
334 // If the value is non-zero, is has to be in the given row, whose values are all between
335 // m_row_pointers[rows] and m_row_pointers[rows + 1]
336
337 // If _find_index returned -1, it has to be a zero value.
338 // This is technically not intended to access 0 elements in non-const context, as we would need
339 // to write it into the matrix (which schould never carry elements that are zero) If we want to
340 // allow element insertion in place (warning, this can be VERY slow), then we can replace that
341 // here. Right now it's just a placeholder
342 if (matrix_value_index == -1)
343 {
345 }
346 return this->m_matrix[matrix_value_index];
347}
348
357template <typename T>
358T CsrSparseMatrix<T>::operator()(const int rows, const int cols) const
359{
360 if (rows >= this->m_rows || cols >= this->m_cols || rows < 0 || cols < 0)
361 {
362 throw MatrixOutOfBoundsError(rows, cols, this->m_rows, this->m_cols);
363 }
364
365 int matrix_value_index{findIndex(rows, cols)};
366
367 // If the value is a non-defined zero value, return zero.
368 if (matrix_value_index == -1)
369 {
370 throw static_cast<T>(0.0);
371 }
372 return this->m_matrix[matrix_value_index];
373}
374
379template <typename T>
380std::valarray<T> CsrSparseMatrix<T>::scalarAdd(const T value) const
381{
382 return this->m_matrix + value;
383}
384
390template <typename T>
391std::valarray<T> CsrSparseMatrix<T>::scalarSubtract(const T value) const
392{
393 return this->m_matrix - value;
394}
395
401template <typename T>
402std::valarray<T> CsrSparseMatrix<T>::scalarMultiply(const T value) const
403{
404 return this->m_matrix * value;
405}
406
412template <typename T>
413std::valarray<T> CsrSparseMatrix<T>::scalarDivide(const T value) const
414{
415 return this->m_matrix / value;
416}
417
421template <typename T>
423{
424 if (this->m_matrix.size() > 0)
425 {
426 for (int i{0}; i < m_row_pointers.size() - 1; i++)
427 {
428 std::valarray<int> column_values_in_row = m_column_indices[std::slice(
429 m_row_pointers[i], m_row_pointers[i + 1] - m_row_pointers[i], 1)];
430 int current_column_id{0};
431 for (int j{0}; j < this->m_cols; j++)
432 {
435 {
436 std::cout << this->m_matrix[m_row_pointers[i] + current_column_id] << ' ';
438 }
439 else
440 {
441 std::cout << "0" << ' ';
442 }
443 }
444 std::cout << "\n";
445 }
446 }
447 else
448 {
449 std::cout << "Matrix is empty\n";
450 }
451}
452
453template <typename T>
455{
456 for (const auto& position_tuple : m_temporary_dynamic_create_storage)
457 {
458 this->m_non_zero_elements.emplace_back(std::get<1>(position_tuple),
459 std::get<2>(position_tuple));
460 }
461}
462#endif
Concrete implementation of a matrix class representing a Compressed Sparse Rows (CSR) matrix....
Definition CsrMatrix.h:31
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:326
void printMatrixInDenseFormat()
Prints the entire matrix with zero values.
Definition CsrMatrix.h:422
std::valarray< T > scalarSubtract(T value) const override
Subtraction of a scalar from the matrix values element-wise.
Definition CsrMatrix.h:391
void registerElement(T value, int rows, int cols)
Registers the element and it's initial value within a COO style vector for dynamic creation.
Definition CsrMatrix.h:108
std::valarray< T > scalarDivide(T value) const override
Division of a scalar from the matrix values element-wise.
Definition CsrMatrix.h:413
const std::vector< std::pair< int, int > > & getNonZeroElements() override
Definition CsrMatrix.h:60
void updateNonZeroElements() override
Definition CsrMatrix.h:454
std::valarray< T > scalarMultiply(T value) const override
Multiplication of a scalar to the matrix values element-wise.
Definition CsrMatrix.h:402
CsrSparseMatrix()
Constructor for an empty CsrSparseMatrix object. Leaves all storage arrays empty but sets the flag to...
Definition CsrMatrix.h:74
~CsrSparseMatrix() override=default
std::valarray< T > scalarAdd(T value) const override
Addition of a scalar to the matrix values element-wise.
Definition CsrMatrix.h:380
void buildAtRuntime()
Builds the CSR matrix from the registered elements. It sorts all elements of the COO format vector by...
Definition CsrMatrix.h:127
Error class to throw when a module chain has circular or missing dependencies. Inherits from std::exc...
Definition ChainManager.h:28
Template generalized Matrix object that should be the base for all further implementations of a matri...
Definition GenericMatrix.h:17
std::vector< std::pair< int, int > > m_non_zero_elements
Definition GenericMatrix.h:23
Error class to throw when the matrix is accessed out of bounds. Inherits from std::exception.
Definition GenericMatrix.h:122
Definition CsrMatrix.h:13
StaticSparseMatrixAccessError(const int row, const int col)
Definition CsrMatrix.h:15