Ginkgo: ginkgo/core/base/matrix_data.hpp Source File

| Ginkgo Generated from branch based on main. Ginkgo version 1.11.0 A numerical linear algebra library targeting many-core architectures

Loading...
Searching...
No Matches
matrix_data.hpp
1// SPDX-FileCopyrightText: 2017 - 2025 The Ginkgo authors
2//
3// SPDX-License-Identifier: BSD-3-Clause
4
5#ifndef GKO_PUBLIC_CORE_BASE_MATRIX_DATA_HPP_
6#define GKO_PUBLIC_CORE_BASE_MATRIX_DATA_HPP_
7
8
9#include <algorithm>
10#include <numeric>
11#include <tuple>
12#include <vector>
13
14#include <ginkgo/core/base/dim.hpp>
15#include <ginkgo/core/base/math.hpp>
16#include <ginkgo/core/base/range.hpp>
17#include <ginkgo/core/base/range_accessors.hpp>
18#include <ginkgo/core/base/types.hpp>
19#include <ginkgo/core/base/utils.hpp>
20
21
22namespace gko {
23
24
25namespace detail {
26
27
28// internal structure used to get around explicit constructors in std::tuple
29template <typename ValueType, typename IndexType>
30struct input_triple {
31 IndexType row;
32 IndexType col;
33 ValueType val;
34};
35
36
37template <typename ValueType, typename Distribution, typename Generator>
38typename std::enable_if<!is_complex_s<ValueType>::value, ValueType>::type
39get_rand_value(Distribution&& dist, Generator&& gen)
40{
41 return dist(gen);
42}
43
44
45template <typename ValueType, typename Distribution, typename Generator>
46typename std::enable_if<is_complex_s<ValueType>::value, ValueType>::type
47get_rand_value(Distribution&& dist, Generator&& gen)
48{
49 return ValueType(dist(gen), dist(gen));
50}
51
52
53} // namespace detail
54
55
59template <typename ValueType, typename IndexType>
60 struct matrix_data_entry {
61 using value_type = ValueType;
62 using index_type = IndexType;
63 matrix_data_entry() = default;
64
65 GKO_ATTRIBUTES matrix_data_entry(index_type r, index_type c, value_type v)
66 : row(r), column(c), value(v)
67 {}
68
69 bool operator==(const matrix_data_entry& other) const
70 {
71 return std::tie(this->row, this->column, this->value) ==
72 std::tie(other.row, other.column, other.value);
73 };
74 bool operator!=(const matrix_data_entry& other) const
75 {
76 return std::tie(this->row, this->column, this->value) !=
77 std::tie(other.row, other.column, other.value);
78 };
79
80#define GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(_op) \
81 bool operator _op(const matrix_data_entry& other) const \
82 { \
83 return std::tie(this->row, this->column) \
84 _op std::tie(other.row, other.column); \
85 }
86
87 GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(<);
88 GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(>);
89 GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(<=);
90 GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(>=);
91
92#undef GKO_DEFINE_DEFAULT_COMPARE_OPERATOR
93
94 friend std::ostream& operator<<(std::ostream& os,
95 const matrix_data_entry& x)
96 {
97 os << '(' << x.row << ',' << x.column << ',' << x.value << ')';
98 return os;
99 }
100
101 index_type row;
102 index_type column;
103 value_type value;
104};
105
106
125template <typename ValueType = default_precision, typename IndexType = int32>
126 struct matrix_data {
127 GKO_ASSERT_SUPPORTED_VALUE_AND_INDEX_TYPE;
128 using value_type = ValueType;
129 using index_type = IndexType;
130 using nonzero_type = matrix_data_entry<value_type, index_type>;
131
138 matrix_data(dim<2> size_ = dim<2>{}, ValueType value = zero<ValueType>())
139 : size{size_}
140 {
141 if (is_zero(value)) {
142 return;
143 }
144 nonzeros.reserve(size[0] * size[1]);
145 for (size_type row = 0; row < size[0]; ++row) {
146 for (size_type col = 0; col < size[1]; ++col) {
147 nonzeros.emplace_back(row, col, value);
148 }
149 }
150 }
151
162 template <typename RandomDistribution, typename RandomEngine>
163 matrix_data(dim<2> size_, RandomDistribution&& dist, RandomEngine&& engine)
164 : size{size_}
165 {
166 nonzeros.reserve(size[0] * size[1]);
167 for (size_type row = 0; row < size[0]; ++row) {
168 for (size_type col = 0; col < size[1]; ++col) {
169 const auto value =
170 detail::get_rand_value<ValueType>(dist, engine);
171 if (is_nonzero(value)) {
172 nonzeros.emplace_back(row, col, value);
173 }
174 }
175 }
176 }
177
183 matrix_data(std::initializer_list<std::initializer_list<ValueType>> values)
184 : size{values.size(), 0}
185 {
186 for (size_type row = 0; row < values.size(); ++row) {
187 const auto row_data = begin(values)[row];
188 size[1] = std::max(size[1], row_data.size());
189 for (size_type col = 0; col < row_data.size(); ++col) {
190 const auto& val = begin(row_data)[col];
191 if (is_nonzero(val)) {
192 nonzeros.emplace_back(row, col, val);
193 }
194 }
195 }
196 }
197
204 matrix_data(
205 dim<2> size_,
206 std::initializer_list<detail::input_triple<ValueType, IndexType>>
207 nonzeros_)
208 : size{size_}, nonzeros()
209 {
210 nonzeros.reserve(nonzeros_.size());
211 for (const auto& elem : nonzeros_) {
212 nonzeros.emplace_back(elem.row, elem.col, elem.val);
213 }
214 }
215
222 matrix_data(dim<2> size_, const matrix_data& block)
223 : size{size_ * block.size}
224 {
225 nonzeros.reserve(size_[0] * size_[1] * block.nonzeros.size());
226 for (size_type row = 0; row < size_[0]; ++row) {
227 for (size_type col = 0; col < size_[1]; ++col) {
228 for (const auto& elem : block.nonzeros) {
229 nonzeros.emplace_back(row * block.size[0] + elem.row,
230 col * block.size[1] + elem.column,
231 elem.value);
232 }
233 }
234 }
235 this->sort_row_major();
236 }
237
245 template <typename Accessor>
246 matrix_data(const range<Accessor>& data)
247 : size{data.length(0), data.length(1)}
248 {
249 for (gko::size_type row = 0; row < size[0]; ++row) {
250 for (gko::size_type col = 0; col < size[1]; ++col) {
251 if (is_nonzero(data(row, col))) {
252 nonzeros.emplace_back(row, col, data(row, col));
253 }
254 }
255 }
256 }
257
266 static matrix_data diag(dim<2> size_, ValueType value)
267 {
268 matrix_data res(size_);
269 if (is_nonzero(value)) {
270 const auto num_nnz = std::min(size_[0], size_[1]);
271 res.nonzeros.reserve(num_nnz);
272 for (size_type i = 0; i < num_nnz; ++i) {
273 res.nonzeros.emplace_back(i, i, value);
274 }
275 }
276 return res;
277 }
278
287 static matrix_data diag(dim<2> size_,
288 std::initializer_list<ValueType> nonzeros_)
289 {
290 matrix_data res(size_);
291 res.nonzeros.reserve(nonzeros_.size());
292 int pos = 0;
293 for (auto value : nonzeros_) {
294 res.nonzeros.emplace_back(pos, pos, value);
295 ++pos;
296 }
297 return res;
298 }
299
308 static matrix_data diag(dim<2> size_, const matrix_data& block)
309 {
310 matrix_data res(size_ * block.size);
311 const auto num_blocks = std::min(size_[0], size_[1]);
312 res.nonzeros.reserve(num_blocks * block.nonzeros.size());
313 for (size_type b = 0; b < num_blocks; ++b) {
314 for (const auto& elem : block.nonzeros) {
315 res.nonzeros.emplace_back(b * block.size[0] + elem.row,
316 b * block.size[1] + elem.column,
317 elem.value);
318 }
319 }
320 return res;
321 }
322
334 template <typename ForwardIterator>
335 static matrix_data diag(ForwardIterator begin, ForwardIterator end)
336 {
337 matrix_data res(std::accumulate(
338 begin, end, dim<2>{}, [](dim<2> s, const matrix_data& d) {
339 return dim<2>{s[0] + d.size[0], s[1] + d.size[1]};
340 }));
341
342 size_type row_offset{};
343 size_type col_offset{};
344 for (auto it = begin; it != end; ++it) {
345 for (const auto& elem : it->nonzeros) {
346 res.nonzeros.emplace_back(row_offset + elem.row,
347 col_offset + elem.column, elem.value);
348 }
349 row_offset += it->size[0];
350 col_offset += it->size[1];
351 }
352
353 return res;
354 }
355
364 static matrix_data diag(std::initializer_list<matrix_data> blocks)
365 {
366 return diag(begin(blocks), end(blocks));
367 }
368
388 template <typename RandomDistribution, typename RandomEngine>
389 static matrix_data cond(size_type size,
390 remove_complex<ValueType> condition_number,
391 RandomDistribution&& dist, RandomEngine&& engine,
392 size_type num_reflectors)
393 {
394 using range = range<accessor::row_major<ValueType, 2>>;
395 std::vector<ValueType> mtx_data(size * size, zero<ValueType>());
396 std::vector<ValueType> ref_data(size);
397 std::vector<ValueType> work(size);
398 range matrix(mtx_data.data(), size, size, size);
399 range reflector(ref_data.data(), size, 1u, 1u);
400
401 initialize_diag_with_cond(condition_number, matrix);
402 for (size_type i = 0; i < num_reflectors; ++i) {
403 generate_random_reflector(dist, engine, reflector);
404 reflect_domain(reflector, matrix, work.data());
405 generate_random_reflector(dist, engine, reflector);
406 reflect_range(reflector, matrix, work.data());
407 }
408 return matrix;
409 }
410
432 template <typename RandomDistribution, typename RandomEngine>
433 static matrix_data cond(size_type size,
434 remove_complex<ValueType> condition_number,
435 RandomDistribution&& dist, RandomEngine&& engine)
436 {
437 return cond(size, condition_number,
438 std::forward<RandomDistribution>(dist),
439 std::forward<RandomEngine>(engine), size - 1);
440 }
441
445 dim<2> size;
446
454 std::vector<nonzero_type> nonzeros;
455
459 void sort_row_major()
460 {
461 std::sort(
462 begin(nonzeros), end(nonzeros), [](nonzero_type x, nonzero_type y) {
463 return std::tie(x.row, x.column) < std::tie(y.row, y.column);
464 });
465 }
466
470 GKO_DEPRECATED("Use sort_row_major() instead") void ensure_row_major_order()
471 {
472 this->sort_row_major();
473 }
474
478 void remove_zeros()
479 {
480 nonzeros.erase(
481 std::remove_if(begin(nonzeros), end(nonzeros),
482 [](nonzero_type nz) { return is_zero(nz.value); }),
483 end(nonzeros));
484 }
485
490 void sum_duplicates()
491 {
492 this->sort_row_major();
493 std::vector<nonzero_type> new_nonzeros;
494 if (!nonzeros.empty()) {
495 new_nonzeros.emplace_back(nonzeros.front().row,
496 nonzeros.front().column,
497 zero<ValueType>());
498 for (auto entry : nonzeros) {
499 if (entry.row != new_nonzeros.back().row ||
500 entry.column != new_nonzeros.back().column) {
501 new_nonzeros.emplace_back(entry.row, entry.column,
502 zero<ValueType>());
503 }
504 new_nonzeros.back().value += entry.value;
505 }
506 nonzeros = std::move(new_nonzeros);
507 }
508 }
509
510private:
511 template <typename Accessor>
512 static void initialize_diag_with_cond(
513 remove_complex<ValueType> condition_number,
514 const range<Accessor>& matrix)
515 {
516 using sigma_type = remove_complex<ValueType>;
517 const auto size = matrix.length(0);
518 const auto min_sigma = one(condition_number) / sqrt(condition_number);
519 const auto max_sigma = sqrt(condition_number);
520
521 matrix = zero(matrix);
522 for (gko::size_type i = 0; i < size; ++i) {
523 matrix(i, i) = max_sigma * static_cast<sigma_type>(size - i - 1) /
524 static_cast<sigma_type>(size - 1) +
525 min_sigma * static_cast<sigma_type>(i) /
526 static_cast<sigma_type>(size - 1);
527 }
528 }
529
530 template <typename RandomDistribution, typename RandomEngine,
531 typename Accessor>
532 static void generate_random_reflector(RandomDistribution&& dist,
533 RandomEngine&& engine,
534 const range<Accessor>& reflector)
535 {
536 for (gko::size_type i = 0; i < reflector.length(0); ++i) {
537 reflector(i, 0) = detail::get_rand_value<ValueType>(dist, engine);
538 }
539 }
540
541 template <typename Accessor>
542 static void reflect_domain(const range<Accessor>& reflector,
543 const range<Accessor>& matrix,
544 ValueType* work_data)
545 {
546 const auto two = one<ValueType>() + one<ValueType>();
547 range<accessor::row_major<ValueType, 2>> work(work_data,
548 matrix.length(0), 1u, 1u);
549 work = mmul(matrix, reflector);
550 const auto ct_reflector = conj(transpose(reflector));
551 const auto scale = two / mmul(ct_reflector, reflector)(0, 0);
552 matrix = matrix - scale * mmul(work, ct_reflector);
553 }
554
555 template <typename Accessor>
556 static void reflect_range(const range<Accessor>& reflector,
557 const range<Accessor>& matrix,
558 ValueType* work_data)
559 {
560 const auto two = one<ValueType>() + one<ValueType>();
561 range<accessor::row_major<ValueType, 2>> work(
562 work_data, 1u, matrix.length(0), matrix.length(0));
563 const auto ct_reflector = conj(transpose(reflector));
564 work = mmul(ct_reflector, matrix);
565 const auto scale = two / mmul(ct_reflector, reflector)(0, 0);
566 matrix = matrix - scale * mmul(reflector, work);
567 }
568};
569
570
571} // namespace gko
572
573
574#endif // GKO_PUBLIC_CORE_BASE_MATRIX_DATA_HPP_
gko::range
A range is a multidimensional view of the memory.
Definition range.hpp:304
gko::matrix
The matrix namespace.
Definition dense_cache.hpp:24
gko
The Ginkgo namespace.
Definition abstract_factory.hpp:20
gko::one
constexpr T one()
Returns the multiplicative identity for T.
Definition math.hpp:654
gko::remove_complex
typename detail::remove_complex_s< T >::type remove_complex
Obtain the type which removed the complex of complex/scalar type or the template parameter of class b...
Definition math.hpp:264
gko::zero
constexpr T zero()
Returns the additive identity for T.
Definition math.hpp:626
gko::is_zero
constexpr bool is_zero(T value)
Returns true if and only if the given value is zero.
Definition math.hpp:699
gko::size_type
std::size_t size_type
Integral type used for allocation quantities.
Definition types.hpp:90
gko::transpose
batch_dim< 2, DimensionType > transpose(const batch_dim< 2, DimensionType > &input)
Returns a batch_dim object with its dimensions swapped for batched operators.
Definition batch_dim.hpp:119
gko::conj
constexpr auto conj(const T &x)
Returns the conjugate of an object.
Definition math.hpp:930
gko::is_nonzero
constexpr bool is_nonzero(T value)
Returns true if and only if the given value is not zero.
Definition math.hpp:714
gko::dim
A type representing the dimensions of a multidimensional object.
Definition dim.hpp:26
gko::matrix_data_entry
Type used to store nonzeros.
Definition matrix_data.hpp:60
gko::matrix_data::diag
static matrix_data diag(dim< 2 > size_, const matrix_data &block)
Initializes a block-diagonal matrix.
Definition matrix_data.hpp:308
gko::matrix_data::diag
static matrix_data diag(dim< 2 > size_, ValueType value)
Initializes a diagonal matrix.
Definition matrix_data.hpp:266
gko::matrix_data::size
dim< 2 > size
Size of the matrix.
Definition matrix_data.hpp:445
gko::matrix_data::matrix_data
matrix_data(const range< Accessor > &data)
Initializes a matrix from a range.
Definition matrix_data.hpp:246
gko::matrix_data::matrix_data
matrix_data(dim< 2 > size_=dim< 2 >{}, ValueType value=zero< ValueType >())
Initializes a matrix filled with the specified value.
Definition matrix_data.hpp:138
gko::matrix_data::nonzeros
std::vector< nonzero_type > nonzeros
A vector of tuples storing the non-zeros of the matrix.
Definition matrix_data.hpp:454
gko::matrix_data::remove_zeros
void remove_zeros()
Remove entries with value zero from the matrix data.
Definition matrix_data.hpp:478
gko::matrix_data::diag
static matrix_data diag(ForwardIterator begin, ForwardIterator end)
Initializes a block-diagonal matrix from a list of diagonal blocks.
Definition matrix_data.hpp:335
gko::matrix_data::cond
static matrix_data cond(size_type size, remove_complex< ValueType > condition_number, RandomDistribution &&dist, RandomEngine &&engine, size_type num_reflectors)
Initializes a random dense matrix with a specific condition number.
Definition matrix_data.hpp:389
gko::matrix_data::diag
static matrix_data diag(std::initializer_list< matrix_data > blocks)
Initializes a block-diagonal matrix from a list of diagonal blocks.
Definition matrix_data.hpp:364
gko::matrix_data::diag
static matrix_data diag(dim< 2 > size_, std::initializer_list< ValueType > nonzeros_)
Initializes a diagonal matrix using a list of diagonal elements.
Definition matrix_data.hpp:287
gko::matrix_data::matrix_data
matrix_data(dim< 2 > size_, const matrix_data &block)
Initializes a matrix out of a matrix block via duplication.
Definition matrix_data.hpp:222
gko::matrix_data::sum_duplicates
void sum_duplicates()
Sum up all values that refer to the same matrix entry.
Definition matrix_data.hpp:490
gko::matrix_data::sort_row_major
void sort_row_major()
Sorts the nonzero vector so the values follow row-major order.
Definition matrix_data.hpp:459
gko::matrix_data::matrix_data
matrix_data(std::initializer_list< std::initializer_list< ValueType > > values)
List-initializes the structure from a matrix of values.
Definition matrix_data.hpp:183
gko::matrix_data< value_type, index_type >::ensure_row_major_order
void ensure_row_major_order()
Definition matrix_data.hpp:470
gko::matrix_data::matrix_data
matrix_data(dim< 2 > size_, RandomDistribution &&dist, RandomEngine &&engine)
Initializes a matrix with random values from the specified distribution.
Definition matrix_data.hpp:163
gko::matrix_data::matrix_data
matrix_data(dim< 2 > size_, std::initializer_list< detail::input_triple< ValueType, IndexType > > nonzeros_)
Initializes the structure from a list of nonzeros.
Definition matrix_data.hpp:204
gko::matrix_data::cond
static matrix_data cond(size_type size, remove_complex< ValueType > condition_number, RandomDistribution &&dist, RandomEngine &&engine)
Initializes a random dense matrix with a specific condition number.
Definition matrix_data.hpp:433