FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
matrix_mirror.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
8// includes, FEAT
9#include <kernel/adjacency/graph.hpp>
10#include <kernel/lafem/vector_mirror.hpp>
11#include <kernel/lafem/matrix_mirror_buffer.hpp>
12#include <kernel/lafem/sparse_matrix_bcsr.hpp>
13#include <kernel/lafem/sparse_matrix_csr.hpp>
14#include <kernel/lafem/sparse_matrix_banded.hpp>
15
16// includes, system
17#include <vector>
18#include <map>
19
20namespace FEAT
21{
22 namespace LAFEM
23 {
31 template<typename DT_, typename IT_>
33 {
34 public:
36 typedef DT_ DataType;
38 typedef IT_ IndexType;
41
42 protected:
47
48 public:
58 explicit MatrixMirror(const VectorMirrorType& row_mirror, const VectorMirrorType& col_mirror) :
59 _row_mirror(row_mirror),
60 _col_mirror(col_mirror)
61 {
62 }
63
68 {
69 }
70
72 virtual ~MatrixMirror()
73 {
74 }
75
78 {
79 return _row_mirror;
80 }
81
84 {
85 return _col_mirror;
86 }
87
98 template<int bw_, int bh_>
101 {
102 return LAFEM::MatrixMirrorBuffer<DT_, IT_>(_create_buffer_graph(matrix), Index(bw_*bh_));
103 }
104
116 const LAFEM::SparseMatrixCSR<DT_, IT_>& matrix) const
117 {
118 return LAFEM::MatrixMirrorBuffer<DT_, IT_>(_create_buffer_graph(matrix), Index(1));
119 }
120
132 const LAFEM::SparseMatrixBanded<DT_, IT_>& matrix) const
133 {
134 return LAFEM::MatrixMirrorBuffer<DT_, IT_>(_create_buffer_graph(matrix), Index(1));
135 }
136
146 void gather(
148 const LAFEM::SparseMatrixCSR<DT_, IT_>& matrix) const
149 {
150 XASSERT(buffer.entries_per_nonzero() == Index(1));
151 XASSERT(buffer.rows() == this->_row_mirror.num_indices());
152 XASSERT(buffer.columns() == this->_col_mirror.num_indices());
153 XASSERT(matrix.rows() == this->_row_mirror.size());
154 XASSERT(matrix.columns() == this->_col_mirror.size());
155
156 // fetch system matrix arrays
157 const IT_* row_ptr_a(matrix.row_ptr());
158 const IT_* col_idx_a(matrix.col_ind());
159 const DT_* val_a(matrix.val());
160
161 // fetch buffer arrays
162 const IT_* row_ptr_b(buffer.row_ptr());
163 const IT_* col_idx_b(buffer.col_ind());
164 DT_* val_b(buffer.val());
165
166 // fetch row/column mirror indices
167 const IT_* mir_idx_r(this->_row_mirror.indices());
168 const IT_* mir_idx_c(this->_col_mirror.indices());
169
170 // loop over all buffer matrix rows
171 for(IT_ i(0); i < IT_(buffer.rows()); ++i)
172 {
173 // get the row-index
174 const IT_ ridx = mir_idx_r[i];
175
176 // loop over all non-zeros in current row
177 for(IT_ j(row_ptr_b[i]); j < row_ptr_b[i+1]; ++j)
178 {
179 // format buffer entry
180 val_b[j] = DT_(0);
181
182 // get the column index
183 const IT_ cidx = mir_idx_c[col_idx_b[j]];
184
185 // try to find this entry in the input matrix
186 for(IT_ k(row_ptr_a[ridx]); k < row_ptr_a[ridx+1]; ++k)
187 {
188 if(col_idx_a[k] == cidx)
189 {
190 val_b[j] = val_a[k];
191 break;
192 }
193 }
194 }
195 }
196 }
197
213 const DT_ alpha = DT_(1)) const
214 {
215 XASSERT(buffer.entries_per_nonzero() == Index(1));
216 XASSERT(buffer.rows() == this->_row_mirror.num_indices());
217 XASSERT(buffer.columns() == this->_col_mirror.num_indices());
218 XASSERT(matrix.rows() == this->_row_mirror.size());
219 XASSERT(matrix.columns() == this->_col_mirror.size());
220
221 // fetch system matrix arrays
222 const IT_* row_ptr_a(matrix.row_ptr());
223 const IT_* col_idx_a(matrix.col_ind());
224 DT_* val_a(matrix.val());
225
226 // fetch buffer arrays
227 const IT_* row_ptr_b(buffer.row_ptr());
228 const IT_* col_idx_b(buffer.col_ind());
229 const DT_* val_b(buffer.val());
230
231 // fetch row/column mirror indices
232 const IT_* mir_idx_r(this->_row_mirror.indices());
233 const IT_* mir_idx_c(this->_col_mirror.indices());
234
235 // loop over all buffer matrix rows
236 for(IT_ i(0); i < IT_(buffer.rows()); ++i)
237 {
238 // get the row-index
239 const IT_ ridx = mir_idx_r[i];
240
241 // loop over all non-zeros in current row
242 for(IT_ j(row_ptr_b[i]); j < row_ptr_b[i+1]; ++j)
243 {
244 // get the column index
245 const IT_ cidx = mir_idx_c[col_idx_b[j]];
246
247 // try to find this entry in the input matrix
248 for(IT_ k(row_ptr_a[ridx]); k < row_ptr_a[ridx+1]; ++k)
249 {
250 if(col_idx_a[k] == cidx)
251 {
252 val_a[k] += alpha*val_b[j];
253 break;
254 }
255 }
256 }
257 }
258 }
259
269 template<int bw_, int bh_>
270 void gather(
273 {
274 XASSERT(buffer.entries_per_nonzero() == Index(bw_*bh_));
275 XASSERT(buffer.rows() == this->_row_mirror.num_indices());
276 XASSERT(buffer.columns() == this->_col_mirror.num_indices());
277 XASSERT(matrix.rows() == this->_row_mirror.size());
278 XASSERT(matrix.columns() == this->_col_mirror.size());
279
280 typedef Tiny::Matrix<DT_, bw_, bh_> ValueType;
281
282 // fetch system matrix arrays
283 const IT_* row_ptr_a(matrix.row_ptr());
284 const IT_* col_idx_a(matrix.col_ind());
285 const ValueType* val_a(matrix.val());
286
287 // fetch buffer arrays
288 const IT_* row_ptr_b(buffer.row_ptr());
289 const IT_* col_idx_b(buffer.col_ind());
290 ValueType* val_b = reinterpret_cast<ValueType*>(buffer.val());
291
292 // fetch row/column mirror indices
293 const IT_* mir_idx_r(this->_row_mirror.indices());
294 const IT_* mir_idx_c(this->_col_mirror.indices());
295
296 // loop over all buffer matrix rows
297 for(IT_ i(0); i < IT_(buffer.rows()); ++i)
298 {
299 // get the row-index
300 const IT_ ridx = mir_idx_r[i];
301
302 // loop over all non-zeros in current row
303 for(IT_ j(row_ptr_b[i]); j < row_ptr_b[i+1]; ++j)
304 {
305 // format buffer entry
306 val_b[j].format();
307
308 // get the column index
309 const IT_ cidx = mir_idx_c[col_idx_b[j]];
310
311 // try to find this entry in the input matrix
312 for(IT_ k(row_ptr_a[ridx]); k < row_ptr_a[ridx+1]; ++k)
313 {
314 if(col_idx_a[k] == cidx)
315 {
316 val_b[j] = val_a[k];
317 break;
318 }
319 }
320 }
321 }
322 }
323
336 template<int bw_, int bh_>
340 const DT_ alpha = DT_(1)) const
341 {
342 XASSERT(buffer.entries_per_nonzero() == Index(bw_*bh_));
343 XASSERT(buffer.rows() == this->_row_mirror.num_indices());
344 XASSERT(buffer.columns() == this->_col_mirror.num_indices());
345 XASSERT(matrix.rows() == this->_row_mirror.size());
346 XASSERT(matrix.columns() == this->_col_mirror.size());
347
348 typedef Tiny::Matrix<DT_, bw_, bh_> ValueType;
349
350 // fetch system matrix arrays
351 const IT_* row_ptr_a(matrix.row_ptr());
352 const IT_* col_idx_a(matrix.col_ind());
353 ValueType* val_a(matrix.val());
354
355 // fetch buffer arrays
356 const IT_* row_ptr_b(buffer.row_ptr());
357 const IT_* col_idx_b(buffer.col_ind());
358 const ValueType* val_b = reinterpret_cast<const ValueType*>(buffer.val());
359
360 // fetch row/column mirror indices
361 const IT_* mir_idx_r(this->_row_mirror.indices());
362 const IT_* mir_idx_c(this->_col_mirror.indices());
363
364 // loop over all buffer matrix rows
365 for(IT_ i(0); i < IT_(buffer.rows()); ++i)
366 {
367 // get the row-index
368 const IT_ ridx = mir_idx_r[i];
369
370 // loop over all non-zeros in current row
371 for(IT_ j(row_ptr_b[i]); j < row_ptr_b[i+1]; ++j)
372 {
373 // get the column index
374 const IT_ cidx = mir_idx_c[col_idx_b[j]];
375
376 // try to find this entry in the input matrix
377 for(IT_ k(row_ptr_a[ridx]); k < row_ptr_a[ridx+1]; ++k)
378 {
379 if(col_idx_a[k] == cidx)
380 {
381 val_a[k].axpy(alpha, val_b[j]);
382 break;
383 }
384 }
385 }
386 }
387 }
388
389 /*
390 * \brief Performs a gather-operation on an operator matrix.
391 *
392 * \param[in,out] buffer
393 * A reference to the buffer matrix.
394 *
395 * \param[in] matrix
396 * A reference to the operator matrix whose entries are to be gathered.
397 */
398 /*template<typename Tx_, typename Ix_, typename Ty_, typename Iy_>
399 void gather(
400 LAFEM::MatrixMirrorBuffer<Mem::Main, Tx_, Ix_>& buffer,
401 const LAFEM::SparseMatrixBanded<Mem::Main, Ty_, Iy_>& matrix) const
402 {
403 XASSERT(buffer.entries_per_nonzero() == Index(1));
404
405 //const typename VectorMirrorType::MirrorMatrixType& row_mir_mat(_row_mirror.get_gather());
406 //const typename VectorMirrorType::MirrorMatrixType& col_mir_mat(_col_mirror.get_gather());
407 const auto& row_mir_mat = _row_gather;
408 const auto& col_mir_mat = _col_gather;
409 DataType* _work = _vec_work.data();
410
411 // fetch row mirror arrays
412 const IndexType* row_ptr_a(row_mir_mat.row_ptr());
413 const IndexType* col_idx_a(row_mir_mat.col_ind());
414 const DataType* av(row_mir_mat.val());
415
416 // fetch col mirror arrays
417 const IndexType* row_ptr_b(col_mir_mat.row_ptr());
418 const IndexType* col_idx_b(col_mir_mat.col_ind());
419 const DataType* bv(col_mir_mat.val());
420
421 // fetch system matrix arrays
422 const Iy_ num_rows_y(Iy_(matrix.rows()));
423 const Iy_ num_of_offsets_y(Iy_(matrix.num_of_offsets()));
424 const Iy_* offsets_y(matrix.offsets());
425 const Ty_* yv(matrix.val());
426
427 // fetch buffer arrays
428 const Ix_* row_ptr_x(buffer.row_ptr());
429 const Ix_* col_idx_x(buffer.col_ind());
430 Tx_* xv(buffer.val());
431
432 // In the following, we have to compute:
433 // X := A * Z := A * Y * B^T,
434 // where:
435 // X is the buffer matrix
436 // Y is the system matrix
437 // A is the row-mirror gather matrix
438 // B is the col-mirror gather matrix
439
440 // loop over all buffer rows (X)
441 Index nrows_buf(buffer.rows());
442 for(Index irow_x(0); irow_x < nrows_buf; ++irow_x)
443 {
444 Index irow_a(irow_x); // row of a := row of x
445
446 // loop over all non-zeroes in the buffer row (X_i.)
447 for(Ix_ ix(row_ptr_x[irow_x]); ix < row_ptr_x[irow_x + 1]; ++ix)
448 {
449 // init result
450 Tx_ x_ij(Tx_(0));
451
452 // fetch the column index
453 Ix_ irow_b(col_idx_x[ix]); // row of b := col of x
454
455 // loop over all non-zeroes of the col-mirror (B_j.)
456 for(IndexType ib(row_ptr_b[irow_b]); ib < row_ptr_b[irow_b + 1]; ++ib)
457 {
458 // and densify the sparse row B_j.
459 _work[col_idx_b[ib]] = bv[ib];
460 }
461
462 // loop over all non-zeroes of the row-mirror (A_i.)
463 for(IndexType ia(row_ptr_a[irow_a]); ia < row_ptr_a[irow_a + 1]; ++ia)
464 {
465 // fetch the column index
466 Iy_ irow_y(col_idx_a[ia]); // row of y := col of a
467
468 // temporary entry: Z_kj := Y_k. * B_j.
469 Tx_ z_kj(Tx_(0));
470
471 // loop over all non-zeroes of the system matrix (Y_k.)
472 for(IndexType k(0); k < num_of_offsets_y; ++k)
473 {
474 if(offsets_y[k] + irow_y + 1 >= num_rows_y && offsets_y[k] + irow_y + 1 < 2 * num_rows_y)
475 {
476 z_kj += Tx_(yv[k * num_rows_y + irow_y]) * Tx_(_work[offsets_y[k] + irow_y + 1 - num_rows_y]);
477 }
478 }
479
480 // update x_ij += a_ik * z_kj
481 x_ij += Tx_(av[ia]) * z_kj;
482 }
483
484 // store X_ij
485 xv[ix] = x_ij;
486
487 // reset temporary data
488 for(IndexType ib(row_ptr_b[irow_b]); ib < row_ptr_b[irow_b + 1]; ++ib)
489 {
490 _work[col_idx_b[ib]] = DataType(0);
491 }
492 }
493 }
494 }*/
495
496 /*
497 * \brief Performs a scatter-axpy-operation on an operator matrix.
498 *
499 * \param[in,out] matrix
500 * A reference to the operator matrix.
501 *
502 * \param[in] buffer
503 * A reference to the buffer matrix whose entries are to be scattered.
504 *
505 * \param[in] alpha
506 * The scaling factor for the operation.
507 */
508 /*template<typename Ty_, typename Iy_, typename Tx_, typename Ix_>
509 void scatter_axpy(
510 LAFEM::SparseMatrixBanded<Mem::Main, Ty_, Iy_>& matrix,
511 const LAFEM::MatrixMirrorBuffer<Mem::Main, Tx_, Ix_>& buffer,
512 const Ty_ alpha = Ty_(1)) const
513 {
514 XASSERT(buffer.entries_per_nonzero() == Index(1));
515
516 //const typename VectorMirrorType::MirrorMatrixType& row_mir_mat(_row_mirror.get_scatter());
517 //const typename VectorMirrorType::MirrorMatrixType& col_mir_mat(_col_mirror.get_scatter());
518 const auto& row_mir_mat = _row_scatter;
519 const auto& col_mir_mat = _col_scatter;
520 DataType* _work = _vec_work.data();
521
522 // fetch row-mirror arrays
523 const IndexType* row_ptr_a(row_mir_mat.row_ptr());
524 const IndexType* col_idx_a(row_mir_mat.col_ind());
525 const DataType* av(row_mir_mat.val());
526
527 // fetch col-mirror arrays
528 const IndexType* row_ptr_b(col_mir_mat.row_ptr());
529 const IndexType* col_idx_b(col_mir_mat.col_ind());
530 const DataType* bv(col_mir_mat.val());
531
532 // fetch system matrix arrays
533 const Iy_ num_rows_y(Iy_(matrix.rows()));
534 const Iy_ num_of_offsets_y(Iy_(matrix.num_of_offsets()));
535 const Iy_* offsets_y(matrix.offsets());
536 Ty_* yv(matrix.val());
537
538 // fetch buffer arrays
539 const Ix_* row_ptr_x(buffer.row_ptr());
540 const Ix_* col_idx_x(buffer.col_ind());
541 const Tx_* xv(buffer.val());
542
543 // In the following, we have to compute:
544 // Y := B * Z := B * X * A^T,
545 // where:
546 // Y is the system matrix
547 // X is the buffer matrix
548 // A is the row-mirror scatter matrix
549 // B is the col-mirror scatter matrix
550
551 // loop over all system matrix rows (Y)
552 Index nrows_sys(matrix.rows());
553 for(Index irow_y(0); irow_y < nrows_sys; ++irow_y)
554 {
555 Index irow_a(irow_y); // row of a := row of y
556
557 // skip if the row of a is empty
558 if(row_ptr_a[irow_a] >= row_ptr_a[irow_a + 1])
559 continue;
560
561 // loop over all non-zeroes in the system row (Y_i.)
562 for(IndexType k(0); k < num_of_offsets_y; ++k)
563 {
564 if(offsets_y[k] + irow_y + 1 >= num_rows_y && offsets_y[k] + irow_y + 1 < 2 * num_rows_y)
565 {
566 Iy_ iy(k * num_rows_y + irow_y);
567 // init result
568 Ty_ y_ij(Ty_(0));
569
570 // fetch the column index
571 IndexType irow_b(offsets_y[k] + irow_y + 1 - num_rows_y); // row of b := col of y
572
573 // skip if the row of b is empty
574 if(row_ptr_b[irow_b] >= row_ptr_b[irow_b + 1])
575 continue;
576
577 // loop over all non-zeroes of the col-mirror (B_j.)
578 for(IndexType ib(row_ptr_b[irow_b]); ib < row_ptr_b[irow_b + 1]; ++ib)
579 {
580 // and densify the sparse row B_j.
581 _work[col_idx_b[ib]] = bv[ib];
582 }
583
584 // loop over all non-zeroes of the row-mirror (A_i.)
585 for(IndexType ia(row_ptr_a[irow_a]); ia < row_ptr_a[irow_a + 1]; ++ia)
586 {
587 // fetch the column index
588 IndexType irow_x(col_idx_a[ia]); // row of x := col of a
589
590 // temporary entry: Z_kj := X_k. * B_j.
591 Ty_ z_kj(Ty_(0));
592
593 // loop over all non-zeroes of the buffer matrix (X_k.)
594 for(Ix_ ix(row_ptr_x[irow_x]); ix < row_ptr_x[irow_x + 1]; ++ix)
595 {
596 z_kj += Ty_(xv[ix]) * Ty_(_work[col_idx_x[ix]]);
597 }
598
599 // update Y_ij += A_ik * Z_kj
600 y_ij += Ty_(av[ia]) * z_kj;
601 }
602
603 // store Y_ij
604 yv[iy] += alpha*y_ij;
605
606 // reset temporary data
607 for(IndexType ib(row_ptr_b[irow_b]); ib < row_ptr_b[irow_b + 1]; ++ib)
608 {
609 _work[col_idx_b[ib]] = DataType(0);
610 }
611 }
612 }
613 }
614 }*/
615
616 protected:
617 template<typename MT_>
618 Adjacency::Graph _create_buffer_graph(const MT_& tmpl_mat) const
619 {
620 // compute the sparsity pattern of
621 // X := A * Y * B^T,
622 // where:
623 // X is the buffer matrix
624 // Y is the system matrix
625 // A is the row-mirror gather matrix
626 // B is the col-mirror gather matrix
627
628 // render the matrix structure to a graph to obtain
629 // the celebrated ptr/idx array pair
631 const Index* dom_ptr = mat_graph.get_domain_ptr();
632 const Index* img_idx = mat_graph.get_image_idx();
633
634 // get row/column mirror indices
635 const Index nrows = _row_mirror.num_indices();
636 const Index ncols = _col_mirror.num_indices();
637 const auto* cidx = _col_mirror.indices();
638 const auto* ridx = _row_mirror.indices();
639
640 // build map of column mirror indices
641 std::map<Index,Index> col_map;
642 for(Index i(0); i < ncols; ++i)
643 col_map.emplace(cidx[i], i);
644
645 // count number of non-zeros in matrix buffer
646 Index count(0);
647 for(Index i(0); i < nrows; ++i)
648 {
649 const Index irow = ridx[i];
650 for(Index j(dom_ptr[irow]); j < dom_ptr[irow+1]; ++j)
651 {
652 if(col_map.find(img_idx[j]) != col_map.end())
653 ++count;
654 }
655 }
656
657 // allocate output graph
658 Adjacency::Graph graph(nrows, ncols, count);
659 Index* row_ptr = graph.get_domain_ptr();
660 Index* col_idx = graph.get_image_idx();
661
662 // compute output graph
663 row_ptr[0] = Index(0);
664 for(Index i(0); i < nrows; ++i)
665 {
666 const Index irow = ridx[i];
667 Index k = row_ptr[i];
668 for(Index j(dom_ptr[irow]); j < dom_ptr[irow+1]; ++j)
669 {
670 auto it = col_map.find(img_idx[j]);
671 if(it != col_map.end())
672 {
673 col_idx[k] = it->second;
674 ++k;
675 }
676 }
677 row_ptr[i+1] = k;
678 }
679 XASSERT(row_ptr[nrows] == count);
680
681 // sort column indices
682 graph.sort_indices();
683
684 return graph;
685 }
686 }; // class MatrixMirror<...>
687 } // namespace LAFEM
688} // namespace FEAT
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
Adjacency Graph implementation.
Definition: graph.hpp:34
Matrix Mirror Buffer class template.
DT_ * val()
Retrieve non zero element array.
Index columns() const
Retrieve matrix column count.
IT_ * row_ptr()
Retrieve row start index array.
IT_ * col_ind()
Retrieve column indices array.
Index entries_per_nonzero() const
Retrieve entries per non zero element count.
Index rows() const
Retrieve matrix row count.
Matrix-Mirror class template.
IT_ IndexType
index-type typedef
void scatter_axpy(LAFEM::SparseMatrixCSR< DT_, IT_ > &matrix, const LAFEM::MatrixMirrorBuffer< DT_, IT_ > &buffer, const DT_ alpha=DT_(1)) const
Performs a scatter-axpy-operation on an operator matrix.
MatrixMirror(MatrixMirror &&other)
move constructor
LAFEM::VectorMirror< DT_, IT_ > VectorMirrorType
vector mirror type
const VectorMirrorType & _row_mirror
row-mirror reference
MatrixMirror(const VectorMirrorType &row_mirror, const VectorMirrorType &col_mirror)
Constructor.
DT_ DataType
data-type typedef
void gather(LAFEM::MatrixMirrorBuffer< DT_, IT_ > &buffer, const LAFEM::SparseMatrixBCSR< DT_, IT_, bw_, bh_ > &matrix) const
Performs a gather-operation on an operator matrix.
LAFEM::MatrixMirrorBuffer< DT_, IT_ > create_buffer(const LAFEM::SparseMatrixBanded< DT_, IT_ > &matrix) const
Creates a buffer matrix based on a banded template matrix.
void scatter_axpy(LAFEM::SparseMatrixBCSR< DT_, IT_, bw_, bh_ > &matrix, const LAFEM::MatrixMirrorBuffer< DT_, IT_ > &buffer, const DT_ alpha=DT_(1)) const
Performs a scatter-axpy-operation on an operator matrix.
const VectorMirrorType & get_row_mirror() const
virtual ~MatrixMirror()
virtual destructor
LAFEM::MatrixMirrorBuffer< DT_, IT_ > create_buffer(const LAFEM::SparseMatrixBCSR< DT_, IT_, bw_, bh_ > &matrix) const
Creates a buffer matrix based on a BCSR template matrix.
const VectorMirrorType & get_col_mirror() const
LAFEM::MatrixMirrorBuffer< DT_, IT_ > create_buffer(const LAFEM::SparseMatrixCSR< DT_, IT_ > &matrix) const
Creates a buffer matrix based on a CSR template matrix.
const VectorMirrorType & _col_mirror
col-mirror reference
void gather(LAFEM::MatrixMirrorBuffer< DT_, IT_ > &buffer, const LAFEM::SparseMatrixCSR< DT_, IT_ > &matrix) const
Performs a gather-operation on an operator matrix.
CSR based blocked sparse matrix.
Index rows() const
Retrieve matrix row count.
IT_ * col_ind()
Retrieve column indices array.
IT_ * row_ptr()
Retrieve row start index array.
Index columns() const
Retrieve matrix column count.
auto val() const -> const typename Intern::BCSRPerspectiveHelper< DT_, BlockHeight_, BlockWidth_, perspective_ >::Type *
Retrieve non zero element array.
CSR based sparse matrix.
IT_ * col_ind()
Retrieve column indices array.
DT_ * val()
Retrieve non zero element array.
Index rows() const
Retrieve matrix row count.
Index columns() const
Retrieve matrix column count.
IT_ * row_ptr()
Retrieve row start index array.
Handles vector prolongation, restriction and serialization.
IT_ * indices()
Get a pointer to the non zero indices array.
Index num_indices() const
Returns the number of indices in the mirror.
Tiny Matrix class template.
@ injectify
Render-Injectified mode.
FEAT namespace.
Definition: adjactor.hpp:12
std::uint64_t Index
Index data type.