FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
sparse_matrix_banded.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
11#include <kernel/util/math.hpp>
12#include <kernel/lafem/forward.hpp>
13#include <kernel/lafem/container.hpp>
14#include <kernel/lafem/dense_vector.hpp>
15#include <kernel/lafem/sparse_layout.hpp>
16#include <kernel/lafem/arch/scale.hpp>
17#include <kernel/lafem/arch/axpy.hpp>
18#include <kernel/lafem/arch/apply.hpp>
19#include <kernel/lafem/arch/norm.hpp>
20#include <kernel/adjacency/graph.hpp>
21
22#include <fstream>
23#include <set>
24
25
26namespace FEAT
27{
28 namespace LAFEM
29 {
75 template <typename DT_, typename IT_ = Index>
76 class SparseMatrixBanded : public Container<DT_, IT_>
77 {
78 public:
85 {
86 public:
88 typedef DT_ DataType;
89 typedef IT_ IndexType;
90
91 private:
92#ifdef DEBUG
93 const IT_ _deadcode;
94#endif
95 Index _num_rows;
96 Index _num_cols;
97 Index _num_of_offsets;
98 IT_* _offsets;
99 IT_* _col_ptr;
100 DT_* _data;
101
102 public:
103 explicit ScatterAxpy(MatrixType& matrix) :
104#ifdef DEBUG
105 _deadcode(~IT_(0)),
106#endif
107 _num_rows(matrix.rows()),
108 _num_cols(matrix.columns()),
109 _num_of_offsets(matrix.num_of_offsets()),
110 _offsets(matrix.offsets()),
111 _col_ptr(nullptr),
112 _data(matrix.val())
113 {
114 // allocate column-pointer array
115 _col_ptr = new IT_[_num_cols];
116#ifdef DEBUG
117 for(Index i(0); i < _num_cols; ++i)
118 {
119 _col_ptr[i] = _deadcode;
120 }
121#endif
122 }
123
124 virtual ~ScatterAxpy()
125 {
126 if(_col_ptr != nullptr)
127 {
128 delete [] _col_ptr;
129 }
130 }
131
132 template<typename LocalMatrix_, typename RowMapping_, typename ColMapping_>
133 void operator()(const LocalMatrix_& loc_mat, const RowMapping_& row_map,
134 const ColMapping_& col_map, DT_ alpha = DT_(1))
135 {
136 // loop over all local row entries
137 for(int i(0); i < row_map.get_num_local_dofs(); ++i)
138 {
139 // fetch row index
140 const Index ix = row_map.get_index(i);
141
142 // build column pointer for this row entry contribution
143 for(IT_ k(0); k < _num_of_offsets; ++k)
144 {
145 if(_offsets[k] + ix + 1 >= _num_rows && _offsets[k] + ix + 1 < 2 * _num_rows)
146 {
147 _col_ptr[_offsets[k] + ix + 1 - _num_rows] = IT_(k * _num_rows + ix);
148 }
149 }
150
151 // loop over all local column entries
152 for(int j(0); j < col_map.get_num_local_dofs(); ++j)
153 {
154 // fetch column index
155 const Index jx = col_map.get_index(j);
156
157 // ensure that the column pointer is valid for this index
158 ASSERTM(_col_ptr[jx] != _deadcode, "invalid column index");
159
160 // incorporate data into global matrix
161 _data[_col_ptr[jx]] += alpha * loc_mat[i][j];
162
163 // continue with next column entry
164 }
165
166#ifdef DEBUG
167 // reformat column-pointer array
168 for(IT_ k(0); k < _num_of_offsets; ++k)
169 {
170 if(_offsets[k] + ix + 1 >= _num_rows && _offsets[k] + ix + 1 < 2 * _num_rows)
171 {
172 _col_ptr[_offsets[k] + ix + 1 - _num_rows] = _deadcode;
173 }
174 }
175#endif
176 // continue with next row entry
177 }
178 }
179 }; // class ScatterAxpy
180
187 {
188 public:
190 typedef DT_ DataType;
191 typedef IT_ IndexType;
192
193 private:
194#ifdef DEBUG
195 const IT_ _deadcode;
196#endif
197 Index _num_rows;
198 Index _num_cols;
199 Index _num_of_offsets;
200 const IT_* _offsets;
201 IT_* _col_ptr;
202 const DT_* _data;
203
204 public:
205 explicit GatherAxpy(const MatrixType& matrix) :
206#ifdef DEBUG
207 _deadcode(~IT_(0)),
208#endif
209 _num_rows(matrix.rows()),
210 _num_cols(matrix.columns()),
211 _num_of_offsets(matrix.num_of_offsets()),
212 _offsets(matrix.offsets()),
213 _col_ptr(nullptr),
214 _data(matrix.val())
215 {
216 // allocate column-pointer array
217 _col_ptr = new IT_[_num_cols];
218#ifdef DEBUG
219 for(Index i(0); i < _num_cols; ++i)
220 {
221 _col_ptr[i] = _deadcode;
222 }
223#endif
224 }
225
226 virtual ~GatherAxpy()
227 {
228 if(_col_ptr != nullptr)
229 {
230 delete [] _col_ptr;
231 }
232 }
233
234 template<typename LocalMatrix_, typename RowMapping_, typename ColMapping_>
235 void operator()(LocalMatrix_& loc_mat, const RowMapping_& row_map,
236 const ColMapping_& col_map, DT_ alpha = DT_(1))
237 {
238 // loop over all local row entries
239 for(int i(0); i < row_map.get_num_local_dofs(); ++i)
240 {
241 // fetch row index
242 const Index ix = row_map.get_index(i);
243
244 // build column pointer for this row entry contribution
245 for(IT_ k(0); k < _num_of_offsets; ++k)
246 {
247 if(_offsets[k] + ix + 1 >= _num_rows && _offsets[k] + ix + 1 < 2 * _num_rows)
248 {
249 _col_ptr[_offsets[k] + ix + 1 - _num_rows] = IT_(k * _num_rows + ix);
250 }
251 }
252
253 // loop over all local column entries
254 for(int j(0); j < col_map.get_num_local_dofs(); ++j)
255 {
256 // fetch column index
257 const Index jx = col_map.get_index(j);
258
259 // ensure that the column pointer is valid for this index
260 ASSERTM(_col_ptr[jx] != _deadcode, "invalid column index");
261
262 // update local matrix data
263 loc_mat[i][j] += alpha * _data[_col_ptr[jx]];
264
265 // continue with next column entry
266 }
267
268#ifdef DEBUG
269 // reformat column-pointer array
270 for(IT_ k(0); k < _num_of_offsets; ++k)
271 {
272 if(_offsets[k] + ix + 1 >= _num_rows && _offsets[k] + ix + 1 < 2 * _num_rows)
273 {
274 _col_ptr[_offsets[k] + ix + 1 - _num_rows] = _deadcode;
275 }
276 }
277#endif
278 // continue with next row entry
279 }
280 }
281 }; // class GatherAxpy
282
283 public: //shall be private
284 Index & _size()
285 {
286 return this->_scalar_index.at(0);
287 }
288
289 Index & _rows()
290 {
291 return this->_scalar_index.at(1);
292 }
293
294 Index & _columns()
295 {
296 return this->_scalar_index.at(2);
297 }
298
299 Index & _used_elements()
300 {
301 return this->_scalar_index.at(3);
302 }
303
304 Index & _num_of_offsets()
305 {
306 return this->_scalar_index.at(4);
307 }
308
309 public:
311 typedef DT_ DataType;
313 typedef IT_ IndexType;
321 typedef DT_ ValueType;
324 {
325 private:
326 IT_ _k;
327 const IT_ _s;
328 const IT_ * const _offsets;
329
330 public:
331 ImageIterator() : _k(IT_(0)), _s(IT_(0)), _offsets(nullptr) {}
332
333 ImageIterator(IT_ k, IT_ s, const IT_ * offsets) : _k(k), _s(s), _offsets(offsets) {}
334
335 ImageIterator& operator=(const ImageIterator& other)
336 {
337 _k = other._k;
338 _s = other._s;
339 _offsets = other._offsets;
340 return *this;
341 }
342
343 bool operator!=(const ImageIterator& other) const
344 {
345 return this->_k != other._k;
346 }
347
348 ImageIterator& operator++()
349 {
350 ++_k;
351 return *this;
352 }
353
354 Index operator*() const
355 {
356 return Index(_s + _offsets[_k]);
357 }
358 };
360 template <typename DT2_ = DT_, typename IT2_ = IT_>
362
364 template <typename DataType2_, typename IndexType2_>
366
373 Container<DT_, IT_> (0)
374 {
375 this->_scalar_index.push_back(0);
376 this->_scalar_index.push_back(0);
377 this->_scalar_index.push_back(0);
378 this->_scalar_index.push_back(0);
379 }
380
389 Container<DT_, IT_> (layout_in._scalar_index.at(0))
390 {
391 this->_indices.assign(layout_in._indices.begin(), layout_in._indices.end());
392 this->_indices_size.assign(layout_in._indices_size.begin(), layout_in._indices_size.end());
393 this->_scalar_index.assign(layout_in._scalar_index.begin(), layout_in._scalar_index.end());
394
395 for (auto i : this->_indices)
397
398 this->_elements.push_back(MemoryPool::template allocate_memory<DT_>(rows() * num_of_offsets()));
399 this->_elements_size.push_back(rows() * num_of_offsets());
400 }
401
412 explicit SparseMatrixBanded(const Index rows_in, const Index columns_in,
413 DenseVector<DT_, IT_> & val_in,
414 DenseVector<IT_, IT_> & offsets_in) :
415 Container<DT_, IT_>(rows_in * columns_in)
416 {
417 if (val_in.size() != rows_in * offsets_in.size())
418 {
419 XABORTM("Size of values does not match to number of offsets and row count!");
420 }
421
422 this->_scalar_index.push_back(rows_in);
423 this->_scalar_index.push_back(columns_in);
424
425 Index tused_elements(0);
426
427 for (Index i(0); i < offsets_in.size(); ++i)
428 {
429 const Index toffset(Index(offsets_in(i)));
430
431 if (toffset + Index(2) > rows_in + columns_in)
432 {
433 XABORTM("Offset out of matrix!");
434 }
435
436 tused_elements += columns_in + Math::min(rows_in, columns_in + rows_in - toffset - 1) - Math::max(columns_in + rows_in - toffset - 1, columns_in);
437 }
438
439 this->_scalar_index.push_back(tused_elements);
440 this->_scalar_index.push_back(offsets_in.size());
441
442 this->_elements.push_back(val_in.elements());
443 this->_elements_size.push_back(val_in.size());
444 this->_indices.push_back(offsets_in.elements());
445 this->_indices_size.push_back(offsets_in.size());
446
447 for (Index i(0) ; i < this->_elements.size() ; ++i)
449 for (Index i(0) ; i < this->_indices.size() ; ++i)
451 }
452
460 template <typename MT_>
461 explicit SparseMatrixBanded(const MT_ & other) :
462 Container<DT_, IT_>(other.size())
463 {
464 convert(other);
465 }
466
474 explicit SparseMatrixBanded(const Adjacency::Graph & graph) :
475 Container<DT_, IT_>(0)
476 {
477 Index num_rows = graph.get_num_nodes_domain();
478 Index num_cols = graph.get_num_nodes_image();
479
480 const Index * dom_ptr(graph.get_domain_ptr());
481 const Index * img_idx(graph.get_image_idx());
482
483 std::set<IT_> moffsets;
484
485 for(Index row(0); row < num_rows; ++row)
486 {
487 for(Index j(dom_ptr[row]); j < dom_ptr[row+1]; ++j)
488 {
489 moffsets.insert(IT_(num_rows - 1 + img_idx[j] - row));
490 }
491 }
492
493 DenseVector<IT_, IT_> toffsets(Index(moffsets.size()));
494 auto * ptoffsets = toffsets.elements();
495
496 IT_ idx(0);
497 for (auto off : moffsets)
498 {
499 ptoffsets[idx] = off;
500 ++idx;
501 }
502
503 DenseVector<IT_, IT_> toffsets_mem;
504 toffsets_mem.convert(toffsets);
505 DenseVector<DT_, IT_> tval_mem(Index(moffsets.size()) * num_rows, DT_(0));
506
507 this->move(SparseMatrixBanded(num_rows, num_cols, tval_mem, toffsets_mem));
508 }
509
518 explicit SparseMatrixBanded(FileMode mode, String filename) :
519 Container<DT_, IT_>(0)
520 {
521 read_from(mode, filename);
522 }
523
532 explicit SparseMatrixBanded(FileMode mode, std::istream& file) :
533 Container<DT_, IT_>(0)
534 {
535 read_from(mode, file);
536 }
537
545 template <typename DT2_ = DT_, typename IT2_ = IT_>
546 explicit SparseMatrixBanded(std::vector<char> input) :
547 Container<DT_, IT_>(0)
548 {
549 deserialize<DT2_, IT2_>(input);
550 }
551
560 Container<DT_, IT_>(std::forward<SparseMatrixBanded>(other))
561 {
562 }
563
572 {
573 this->move(std::forward<SparseMatrixBanded>(other));
574
575 return *this;
576 }
577
587 {
589 t.clone(*this, clone_mode);
590 return t;
591 }
592
601 template<typename DT2_, typename IT2_>
603 {
604 Container<DT_, IT_>::clone(other, clone_mode);
605 }
606
615 {
616 for (Index i(0) ; i < this->_elements.size() ; ++i)
618 for (Index i(0) ; i < this->_indices.size() ; ++i)
620
621 this->_elements.clear();
622 this->_indices.clear();
623 this->_elements_size.clear();
624 this->_indices_size.clear();
625 this->_scalar_index.clear();
626
627 this->_indices.assign(layout_in._indices.begin(), layout_in._indices.end());
628 this->_indices_size.assign(layout_in._indices_size.begin(), layout_in._indices_size.end());
629 this->_scalar_index.assign(layout_in._scalar_index.begin(), layout_in._scalar_index.end());
630
631 for (auto i : this->_indices)
633
634 this->_elements.push_back(MemoryPool::template allocate_memory<DT_>(rows() * num_of_offsets()));
635 this->_elements_size.push_back(rows() * num_of_offsets());
636
637 return *this;
638 }
639
647 template <typename DT2_, typename IT2_>
649 {
650 this->assign(other);
651 }
652
653 template <typename DT2_, typename IT2_>
654 void convert(const SparseMatrixCSR<DT2_, IT2_> & csr)
655 {
656 XASSERT(csr.template used_elements<Perspective::pod>() > 0);
657
658 std::set<IT_> offset_set;
659 Index nrows(csr.rows());
660 Index ncolumns(csr.columns());
661 for (Index row(0) ; row < nrows ; ++row)
662 {
663 for (Index i(csr.row_ptr()[row]) ; i < csr.row_ptr()[row+1] ; ++i)
664 {
665 //compute band offset for each non zero entry
666 IT_ off = IT_(csr.col_ind()[i] - row + nrows - 1);
667 offset_set.insert(off);
668 }
669 }
670
671 DenseVector<DT_, IT_> val_new(Index(offset_set.size()) * nrows, DT_(0));
672 for (Index row(0) ; row < nrows ; ++row)
673 {
674 for (Index i(csr.row_ptr()[row]) ; i < csr.row_ptr()[row+1] ; ++i)
675 {
676 Index col = csr.col_ind()[i];
677 Index offset = (col - row + nrows - 1);
678 Index band = Index(std::distance(offset_set.begin(), offset_set.find(IT_(offset))));
679 val_new.elements()[band * nrows + row] = csr.val()[i];
680 }
681 }
682
683 DenseVector<IT_, IT_> offsets_new(Index(offset_set.size()));
684 auto it_offset = offset_set.begin();
685 for (Index i(0) ; i < offset_set.size() ; ++i, ++it_offset)
686 {
687 offsets_new(i, *it_offset);
688 }
689 offset_set.clear();
690
691 SparseMatrixBanded<DT_, IT_> temp(nrows, ncolumns, val_new, offsets_new);
692 this->move(std::move(temp));
693 }
694
695
702 void write_out(FileMode mode, const String& filename) const
703 {
704 std::ios_base::openmode bin = std::ofstream::out | std::ofstream::binary;
705 if(mode == FileMode::fm_mtx)
706 bin = std::ofstream::out;
707 std::ofstream file;
708 char* buff = nullptr;
709 if(mode == FileMode::fm_mtx)
710 {
711 buff = new char[LAFEM::FileOutStreamBufferSize];
712 file.rdbuf()->pubsetbuf(buff, LAFEM::FileOutStreamBufferSize);
713 }
714 file.open(filename.c_str(), bin);
715 if(! file.is_open())
716 XABORTM("Unable to open Matrix file " + filename);
717 write_out(mode, file);
718 file.close();
719 delete[] buff;
720 }
727 void write_out(FileMode mode, std::ostream& file) const
728 {
729 switch(mode)
730 {
731 case FileMode::fm_bm:
733 if (! std::is_same<DT_, double>::value)
734 std::cout<<"Warning: You are writing out a banded matrix that is not double precision!\n";
735
736 this->template _serialize<double, std::uint64_t>(FileMode::fm_bm, file);
737 break;
738 default:
739 XABORTM("Filemode not supported!");
740 }
741 }
742
751 DT_ operator()(Index row, Index col) const
752 {
753 ASSERT(row < rows());
754 ASSERT(col < columns());
755
756 MemoryPool::synchronize();
757
758 const Index trows(this->_scalar_index.at(1));
759
760 for (Index i(0); i < this->_scalar_index.at(4); ++i)
761 {
762 const Index toffset(this->offsets()[i]);
763 if (row + toffset + Index(1) == col + trows)
764 {
765 return this->val()[i * trows + row];
766 }
767 }
768 return DT_(0.);
769 }
770
777 {
779 }
780
786 template <Perspective = Perspective::native>
787 Index rows() const
788 {
789 return this->_scalar_index.at(1);
790 }
791
797 template <Perspective = Perspective::native>
799 {
800 return this->_scalar_index.at(2);
801 }
802
808 template <Perspective = Perspective::native>
810 {
811 return this->_scalar_index.at(3);
812 }
813
820 {
821 return this->_scalar_index.at(4);
822 }
823
829 DT_ * val()
830 {
831 return this->_elements.at(0);
832 }
833
834 DT_ const * val() const
835 {
836 return this->_elements.at(0);
837 }
838
844 IT_ * offsets()
845 {
846 return this->_indices.at(0);
847 }
848
849 IT_ const * offsets() const
850 {
851 return this->_indices.at(0);
852 }
853
859 static String name()
860 {
861 return "SparseMatrixBanded";
862 }
863
870 void copy(const SparseMatrixBanded & x, bool full = false)
871 {
872 this->_copy_content(x, full);
873 }
874
877
884 void axpy(
885 const SparseMatrixBanded & x,
886 const DT_ alpha = DT_(1))
887 {
888 XASSERTM(x.rows() == this->rows(), "Matrix rows do not match!");
889 XASSERTM(x.columns() == this->columns(), "Matrix columns do not match!");
890 XASSERTM(x.num_of_offsets() == this->num_of_offsets(), "Matrix num_of_offsets do not match!");
891 XASSERTM(x.used_elements() == this->used_elements(), "Matrix used_elements do not match!");
892
893 TimeStamp ts_start;
894
896 Arch::Axpy::value(this->val(), alpha, x.val(), this->rows() * this->num_of_offsets());
897
898 TimeStamp ts_stop;
899 Statistics::add_time_axpy(ts_stop.elapsed(ts_start));
900 }
901
908 void scale(const SparseMatrixBanded & x, const DT_ alpha)
909 {
910 XASSERTM(x.rows() == this->rows(), "Matrix rows do not match!");
911 XASSERTM(x.columns() == this->columns(), "Matrix columns do not match!");
912 XASSERTM(x.num_of_offsets() == this->num_of_offsets(), "Matrix num_of_offsets do not match!");
913 XASSERTM(x.used_elements() == this->used_elements(), "Matrix used_elements do not match!");
914
915 TimeStamp ts_start;
916
918 Arch::Scale::value(this->val(), x.val(), alpha, this->rows() * this->num_of_offsets());
919
920 TimeStamp ts_stop;
921 Statistics::add_time_axpy(ts_stop.elapsed(ts_start));
922
923 }
924
930 DT_ norm_frobenius() const
931 {
932
933 TimeStamp ts_start;
934
936 DT_ result = Arch::Norm2::value(this->val(), this->rows() * this->num_of_offsets());
937
938 TimeStamp ts_stop;
939 Statistics::add_time_reduction(ts_stop.elapsed(ts_start));
940
941 return result;
942 }
943
951 {
952 XASSERTM(r.size() == this->rows(), "Vector size of r does not match!");
953 XASSERTM(x.size() == this->columns(), "Vector size of x does not match!");
954
955 XASSERTM(r.template elements<Perspective::pod>() != x.template elements<Perspective::pod>(), "Vector x and r must not share the same memory!");
956
957 TimeStamp ts_start;
959
960 Arch::Apply::banded(r.elements(),
961 DT_(1),
962 x.elements(),
963 DT_(0),
964 r.elements(),
965 this->val(),
966 this->offsets(),
967 this->num_of_offsets(),
968 this->rows(),
969 this->columns());
970
971 TimeStamp ts_stop;
972 Statistics::add_time_blas2(ts_stop.elapsed(ts_start));
973 }
974
982 {
983 XASSERTM(r.size() == this->columns(), "Vector size of r does not match!");
984 XASSERTM(x.size() == this->rows(), "Vector size of x does not match!");
985
986 XASSERTM(r.template elements<Perspective::pod>() != x.template elements<Perspective::pod>(), "Vector x and r must not share the same memory!");
987
988 TimeStamp ts_start;
990
991 Arch::Apply::banded_transposed(r.elements(),
992 DT_(1),
993 x.elements(),
994 DT_(0),
995 r.elements(),
996 this->val(),
997 this->offsets(),
998 this->num_of_offsets(),
999 this->rows(),
1000 this->columns());
1001
1002 TimeStamp ts_stop;
1003 Statistics::add_time_blas2(ts_stop.elapsed(ts_start));
1004 }
1005
1015 const DenseVector<DT_, IT_>& x,
1016 const DenseVector<DT_, IT_>& y,
1017 const DT_ alpha = DT_(1)) const
1018 {
1019 XASSERTM(r.size() == this->rows(), "Vector size of r does not match!");
1020 XASSERTM(x.size() == this->columns(), "Vector size of x does not match!");
1021 XASSERTM(y.size() == this->rows(), "Vector size of y does not match!");
1022
1023 XASSERTM(r.template elements<Perspective::pod>() != x.template elements<Perspective::pod>(), "Vector x and r must not share the same memory!");
1024
1025 if (this->used_elements() == 0 || Math::abs(alpha) < Math::eps<DT_>())
1026 {
1027 r.copy(y);
1028 //r.scale(beta);
1029 return;
1030 }
1031
1032 TimeStamp ts_start;
1033 Statistics::add_flops( 2 * (this->used_elements() + this->rows()) );
1034
1035 Arch::Apply::banded(r.elements(),
1036 alpha,
1037 x.elements(),
1038 DT_(1),
1039 y.elements(),
1040 this->val(),
1041 this->offsets(),
1042 this->num_of_offsets(),
1043 this->rows(),
1044 this->columns());
1045
1046 TimeStamp ts_stop;
1047 Statistics::add_time_blas2(ts_stop.elapsed(ts_start));
1048 }
1049
1059 const DenseVector<DT_, IT_>& x,
1060 const DenseVector<DT_, IT_>& y,
1061 const DT_ alpha = DT_(1)) const
1062 {
1063 XASSERTM(r.size() == this->columns(), "Vector size of r does not match!");
1064 XASSERTM(x.size() == this->rows(), "Vector size of x does not match!");
1065 XASSERTM(y.size() == this->columns(), "Vector size of y does not match!");
1066
1067 XASSERTM(r.template elements<Perspective::pod>() != x.template elements<Perspective::pod>(), "Vector x and r must not share the same memory!");
1068
1069 if (this->used_elements() == 0 || Math::abs(alpha) < Math::eps<DT_>())
1070 {
1071 r.copy(y);
1072 //r.scale(beta);
1073 return;
1074 }
1075
1076 TimeStamp ts_start;
1077 Statistics::add_flops( 2 * (this->used_elements() + this->rows()) );
1078
1079 Arch::Apply::banded_transposed(r.elements(),
1080 alpha,
1081 x.elements(),
1082 DT_(1),
1083 y.elements(),
1084 this->val(),
1085 this->offsets(),
1086 this->num_of_offsets(),
1087 this->rows(),
1088 this->columns());
1089
1090 TimeStamp ts_stop;
1091 Statistics::add_time_blas2(ts_stop.elapsed(ts_start));
1092 }
1094
1096 void extract_diag(VectorTypeL & diag) const
1097 {
1098 XASSERTM(diag.size() == rows(), "diag size does not match matrix row count!");
1099 XASSERTM(rows() == columns(), "matrix is not square!");
1100
1101 for (Index i(0) ; i < num_of_offsets() ; ++i)
1102 {
1103 if (this->offsets()[i] == this->rows() - 1)
1104 {
1105 MemoryPool::copy(diag.elements(), val() + i * rows(), rows());
1106 break;
1107 }
1108 }
1109 }
1110
1113 {
1115 extract_diag(diag);
1116 return diag;
1117 }
1118
1126 template <typename DT2_ = DT_, typename IT2_ = IT_>
1127 void deserialize(std::vector<char> input)
1128 {
1129 this->template _deserialize<DT2_, IT2_>(FileMode::fm_bm, input);
1130 }
1131
1139 {
1140 XASSERTM(x.used_elements() == this->used_elements(), "Nonzero count does not match!");
1141 TimeStamp ts_start;
1142
1143 DataType max_rel_diff = Arch::MaxRelDiff::value(this->val(), x.val(), this->used_elements());
1144
1145 TimeStamp ts_stop;
1146 Statistics::add_time_reduction(ts_stop.elapsed(ts_start));
1147
1148 return max_rel_diff;
1149 }
1150
1159 bool same_layout(const SparseMatrixBanded& x) const
1160 {
1161 if(this->size() == 0 && x.size() == 0 && this->get_elements().size() == 0 && this->get_indices().size() == 0 && x.get_elements().size() == 0 && x.get_indices().size() == 0)
1162 return true;
1163 if (this->rows() != x.rows())
1164 return false;
1165 if (this->columns() != x.columns())
1166 return false;
1167 if (this->num_of_offsets() != x.num_of_offsets())
1168 return false;
1169 if (this->used_elements() != x.used_elements())
1170 return false;
1171
1172 IT_ * offsets_a;
1173 IT_ * offsets_b;
1174
1175 offsets_a = const_cast<IT_*>(this->offsets());
1176 offsets_b = const_cast<IT_*>(x.offsets());
1177
1178 bool ret(true);
1179
1180 for (Index i(0); i < this->num_of_offsets(); ++i)
1181 {
1182 if (offsets_a[i] != offsets_b[i])
1183 {
1184 ret = false;
1185 break;
1186 }
1187 }
1188
1189 return ret;
1190 }
1191
1203 template <typename DT2_ = DT_, typename IT2_ = IT_>
1204 std::vector<char> serialize(const LAFEM::SerialConfig& config = SerialConfig()) const
1205 {
1206 return this->template _serialize<DT2_, IT2_>(FileMode::fm_bm, config);
1207 }
1208
1215 void read_from(FileMode mode, const String& filename)
1216 {
1217 std::ios_base::openmode bin = std::ifstream::in | std::ifstream::binary;
1218 if(mode == FileMode::fm_mtx)
1219 bin = std::ifstream::in;
1220 std::ifstream file(filename.c_str(), bin);
1221 if (! file.is_open())
1222 XABORTM("Unable to open Matrix file " + filename);
1223 read_from(mode, file);
1224 file.close();
1225 }
1232 void read_from(FileMode mode, std::istream& file)
1233 {
1234 switch(mode)
1235 {
1236 case FileMode::fm_bm:
1238 this->template _deserialize<double, std::uint64_t>(FileMode::fm_bm, file);
1239 break;
1240 default:
1241 XABORTM("Filemode not supported!");
1242 }
1243 }
1244
1247 {
1248 return VectorTypeL(this->rows());
1249 }
1250
1252 VectorTypeR create_vector_r() const
1253 {
1254 return VectorTypeR(this->columns());
1255 }
1256
1258 template <typename ITX_>
1259 inline Index _start_offset(const Index i, const ITX_ * const offsets,
1260 const Index rows_in, const Index columns_in, const Index noo) const
1261 {
1262 if (i == Index(-1))
1263 {
1264 return rows_in;
1265 }
1266 else if (i == noo)
1267 {
1268 return Index(0);
1269 }
1270 else
1271 {
1272 return Math::max(columns_in + Index(1), rows_in + columns_in - Index(offsets[i])) - columns_in - Index(1);
1273 }
1274 }
1275
1277 template <typename ITX_>
1278 inline Index _end_offset(const Index i, const ITX_ * const offsets,
1279 const Index rows_in, const Index columns_in, const Index noo) const
1280 {
1281 if (i == Index (-1))
1282 {
1283 return rows_in - 1;
1284 }
1285 else if (i == noo)
1286 {
1287 return Index(-1);
1288 }
1289 else
1290 {
1291 return Math::min(rows_in, columns_in + rows_in - Index(offsets[i]) - Index(1)) - Index(1);
1292 }
1293 }
1294
1296 Index start_offset(const Index i) const
1297 {
1298 return this->_start_offset(i, offsets(), rows(), columns(), num_of_offsets());
1299 }
1300
1302 Index end_offset(const Index i) const
1303 {
1304 return this->_end_offset(i, offsets(), rows(), columns(), num_of_offsets());
1305 }
1306
1307 /* ******************************************************************* */
1308 /* A D J A C T O R I N T E R F A C E I M P L E M E N T A T I O N */
1309 /* ******************************************************************* */
1310 public:
1313 {
1314 return rows();
1315 }
1316
1319 {
1320 return columns();
1321 }
1322
1324 inline ImageIterator image_begin(Index domain_node) const
1325 {
1326 XASSERT(domain_node < rows());
1327
1328 const IT_ * toffsets(offsets());
1329 const IT_ tnum_of_offsets(num_of_offsets());
1330 const Index trows(rows());
1331
1332 for(IT_ k(0); k < tnum_of_offsets; ++k)
1333 {
1334 if(toffsets[k] + domain_node + 1 >= trows)
1335 return ImageIterator(k, domain_node + 1 - trows, toffsets);
1336 }
1337 }
1338
1340 inline ImageIterator image_end(Index domain_node) const
1341 {
1342 XASSERT(domain_node < rows());
1343
1344 const IT_ * toffsets(offsets());
1345 const IT_ tnum_of_offsets(num_of_offsets());
1346 const Index trows(rows());
1347
1348 for(IT_ k(0); k < tnum_of_offsets; ++k)
1349 {
1350 if(toffsets[k] + domain_node + 1 >= 2 * trows)
1351 {
1352 return ImageIterator(k, domain_node + 1 - trows, toffsets);
1353 }
1354 }
1355 return ImageIterator(tnum_of_offsets, domain_node + 1 - trows, toffsets);
1356 }
1357
1364 friend std::ostream & operator<< (std::ostream & lhs, const SparseMatrixBanded & b)
1365 {
1366 lhs << "[\n";
1367 for (Index i(0) ; i < b.rows() ; ++i)
1368 {
1369 lhs << "[";
1370 for (Index j(0) ; j < b.columns() ; ++j)
1371 {
1372 lhs << " " << stringify(b(i, j));
1373 }
1374 lhs << "]\n";
1375 }
1376 lhs << "]\n";
1377
1378 return lhs;
1379 }
1380 };
1381
1382 } // namespace LAFEM
1383} // namespace FEAT
#define ASSERT(expr)
Debug-Assertion macro definition.
Definition: assertion.hpp:229
#define XABORTM(msg)
Abortion macro definition with custom message.
Definition: assertion.hpp:192
#define ASSERTM(expr, msg)
Debug-Assertion macro definition with custom message.
Definition: assertion.hpp:230
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
FEAT Kernel base header.
Adjacency Graph implementation.
Definition: graph.hpp:34
Index * get_domain_ptr()
Returns the domain pointer array.
Definition: graph.hpp:359
Index * get_image_idx()
Returns the image node index array.
Definition: graph.hpp:374
Container base class.
Definition: container.hpp:220
const std::vector< IT_ * > & get_indices() const
Returns a list of all Index arrays.
Definition: container.hpp:1078
std::vector< DT_ * > _elements
List of pointers to all datatype dependent arrays.
Definition: container.hpp:226
const std::vector< DT_ * > & get_elements() const
Returns a list of all data arrays.
Definition: container.hpp:1068
std::vector< Index > _elements_size
List of corresponding datatype array sizes.
Definition: container.hpp:230
Index size() const
Returns the containers size.
Definition: container.hpp:1136
void assign(const Container< DT2_, IT2_ > &other)
Assignment operation.
Definition: container.hpp:280
std::vector< IT_ * > _indices
List of pointers to all IT_ dependent arrays.
Definition: container.hpp:228
void clone(const Container &other, CloneMode clone_mode=CloneMode::Weak)
Clone operation.
Definition: container.hpp:902
void move(Container &&other)
Assignment move operation.
Definition: container.hpp:989
std::vector< Index > _indices_size
List of corresponding IT_ array sizes.
Definition: container.hpp:232
std::vector< Index > _scalar_index
List of scalars with datatype index.
Definition: container.hpp:234
Dense data vector class template.
void convert(const DenseVector< DT2_, IT2_ > &other)
Conversion method.
DT_ * elements()
Get a pointer to the data array.
void copy(const VT_ &a)
Performs .
Config class for serialize parameter.
Definition: container.hpp:47
Layout scheme for sparse matrix containers.
Gather-Axpy operation for SparseMatrixBanded.
ImageIterator class for Adjactor interface implementation.
Scatter-Axpy operation for SparseMatrixBanded.
void extract_diag(VectorTypeL &diag) const
SparseMatrixBanded clone(CloneMode clone_mode=CloneMode::Weak) const
Clone operation.
SparseMatrixBanded & operator=(SparseMatrixBanded &&other)
Move operator.
void read_from(FileMode mode, std::istream &file)
Read in matrix from stream.
friend std::ostream & operator<<(std::ostream &lhs, const SparseMatrixBanded &b)
SparseMatrixBanded streaming operator.
void apply(DenseVector< DT_, IT_ > &r, const DenseVector< DT_, IT_ > &x) const
Calculate .
void convert(const SparseMatrixBanded< DT2_, IT2_ > &other)
Conversion method.
Index rows() const
Retrieve matrix row count.
bool same_layout(const SparseMatrixBanded &x) const
Checks if the structural layout of this matrix matches that of another matrix. This excludes comparis...
SparseMatrixBanded(const SparseLayout< IT_, layout_id > &layout_in)
Constructor.
void copy(const SparseMatrixBanded &x, bool full=false)
Performs .
SparseLayout< IT_, layout_id > layout() const
Retrieve convenient sparse matrix layout object.
DenseVector< DataType, IT_ > VectorTypeR
Compatible R-vector type.
SparseMatrixBanded(const Index rows_in, const Index columns_in, DenseVector< DT_, IT_ > &val_in, DenseVector< IT_, IT_ > &offsets_in)
Constructor.
void deserialize(std::vector< char > input)
Deserialization of complete container entity.
IT_ * offsets()
Retrieve offsets array.
Index start_offset(const Index i) const
Returns first row-index of the diagonal matching to the offset i.
void write_out(FileMode mode, const String &filename) const
Write out matrix to file.
Index used_elements() const
Retrieve non zero element count.
static constexpr SparseLayoutId layout_id
Our used layout type.
SparseMatrixBanded(FileMode mode, String filename)
Constructor.
Index end_offset(const Index i) const
Returns last row-index of the diagonal matching to the offset i.
void apply_transposed(DenseVector< DT_, IT_ > &r, const DenseVector< DT_, IT_ > &x) const
Calculate .
DT_ * val()
Retrieve element array.
Index _start_offset(const Index i, const ITX_ *const offsets, const Index rows_in, const Index columns_in, const Index noo) const
Returns first row-index of the diagonal matching to the offset i.
VectorTypeL extract_diag() const
extract main diagonal vector from matrix
DT_ operator()(Index row, Index col) const
Retrieve specific matrix element.
DenseVector< DataType, IT_ > VectorTypeL
Compatible L-vector type.
void read_from(FileMode mode, const String &filename)
Read in matrix from file.
DT_ max_rel_diff(const SparseMatrixBanded &x) const
Retrieve the maximum relative difference of this matrix and another one y.max_rel_diff(x) returns .
Index num_of_offsets() const
Retrieve number of offsets.
SparseMatrixBanded(FileMode mode, std::istream &file)
Constructor.
Index _end_offset(const Index i, const ITX_ *const offsets, const Index rows_in, const Index columns_in, const Index noo) const
Returns last row-index of the diagonal matching to the offset i.
void write_out(FileMode mode, std::ostream &file) const
Write out matrix to file.
SparseMatrixBanded(const Adjacency::Graph &graph)
Constructor.
DT_ norm_frobenius() const
Calculates the Frobenius norm of this matrix.
void clone(const SparseMatrixBanded< DT2_, IT2_ > &other, CloneMode clone_mode=CloneMode::Weak)
Clone operation.
std::vector< char > serialize(const LAFEM::SerialConfig &config=SerialConfig()) const
Serialization of complete container entity.
VectorTypeL create_vector_l() const
Returns a new compatible L-Vector.
ImageIterator image_begin(Index domain_node) const
VectorTypeR create_vector_r() const
Returns a new compatible R-Vector.
ImageIterator image_end(Index domain_node) const
void apply(DenseVector< DT_, IT_ > &r, const DenseVector< DT_, IT_ > &x, const DenseVector< DT_, IT_ > &y, const DT_ alpha=DT_(1)) const
Calculate .
SparseMatrixBanded(std::vector< char > input)
Constructor.
void axpy(const SparseMatrixBanded &x, const DT_ alpha=DT_(1))
Calculate .
SparseMatrixBanded(const MT_ &other)
Constructor.
void scale(const SparseMatrixBanded &x, const DT_ alpha)
Calculate .
SparseMatrixBanded(SparseMatrixBanded &&other)
Move Constructor.
Index columns() const
Retrieve matrix column count.
void apply_transposed(DenseVector< DT_, IT_ > &r, const DenseVector< DT_, IT_ > &x, const DenseVector< DT_, IT_ > &y, const DT_ alpha=DT_(1)) const
Calculate .
static String name()
Returns a descriptive string.
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.
static void copy(DT_ *dest, const DT_ *src, const Index count)
Copy memory area from src to dest.
static void release_memory(void *address)
release memory or decrease reference counter
static void increase_memory(void *address)
increase memory counter
static void add_flops(Index flops)
Add an amount of flops to the global flop counter.
Definition: statistics.hpp:206
String class implementation.
Definition: string.hpp:46
Time stamp class.
Definition: time_stamp.hpp:54
double elapsed(const TimeStamp &before) const
Calculates the time elapsed between two time stamps.
Definition: time_stamp.hpp:100
constexpr std::size_t FileOutStreamBufferSize
OutStreamBufferSize.
Definition: base.hpp:124
SparseLayoutId
Definition: base.hpp:63
T_ abs(T_ x)
Returns the absolute value.
Definition: math.hpp:275
T_ min(T_ a, T_ b)
Returns the minimum of two values.
Definition: math.hpp:123
T_ max(T_ a, T_ b)
Returns the maximum of two values.
Definition: math.hpp:137
FEAT namespace.
Definition: adjactor.hpp:12
String stringify(const T_ &item)
Converts an item into a String.
Definition: string.hpp:944
std::uint64_t Index
Index data type.