Ginkgo Generated from branch based on master. Ginkgo version 1.7.0
A numerical linear algebra library targeting many-core architectures
Loading...
Searching...
No Matches
matrix_data.hpp
1/*******************************<GINKGO LICENSE>******************************
2Copyright (c) 2017-2023, the Ginkgo authors
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions
7are met:
8
91. Redistributions of source code must retain the above copyright
10notice, this list of conditions and the following disclaimer.
11
122. Redistributions in binary form must reproduce the above copyright
13notice, this list of conditions and the following disclaimer in the
14documentation and/or other materials provided with the distribution.
15
163. Neither the name of the copyright holder nor the names of its
17contributors may be used to endorse or promote products derived from
18this software without specific prior written permission.
19
20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31******************************<GINKGO LICENSE>*******************************/
32
33#ifndef GKO_PUBLIC_CORE_BASE_MATRIX_DATA_HPP_
34#define GKO_PUBLIC_CORE_BASE_MATRIX_DATA_HPP_
35
36
37#include <algorithm>
38#include <numeric>
39#include <tuple>
40#include <vector>
41
42
43#include <ginkgo/core/base/dim.hpp>
44#include <ginkgo/core/base/math.hpp>
45#include <ginkgo/core/base/range.hpp>
46#include <ginkgo/core/base/range_accessors.hpp>
47#include <ginkgo/core/base/types.hpp>
48#include <ginkgo/core/base/utils.hpp>
49
50
51namespace gko {
52
53
54namespace detail {
55
56
57// internal structure used to get around explicit constructors in std::tuple
58template <typename ValueType, typename IndexType>
59struct input_triple {
60 IndexType row;
61 IndexType col;
62 ValueType val;
63};
64
65
66template <typename ValueType, typename Distribution, typename Generator>
67typename std::enable_if<!is_complex_s<ValueType>::value, ValueType>::type
68get_rand_value(Distribution&& dist, Generator&& gen)
69{
70 return dist(gen);
71}
72
73
74template <typename ValueType, typename Distribution, typename Generator>
75typename std::enable_if<is_complex_s<ValueType>::value, ValueType>::type
76get_rand_value(Distribution&& dist, Generator&& gen)
77{
78 return ValueType(dist(gen), dist(gen));
79}
80
81
82} // namespace detail
83
84
88template <typename ValueType, typename IndexType>
90 using value_type = ValueType;
91 using index_type = IndexType;
92 matrix_data_entry() = default;
93
94 GKO_ATTRIBUTES matrix_data_entry(index_type r, index_type c, value_type v)
95 : row(r), column(c), value(v)
96 {}
97
98 bool operator==(const matrix_data_entry& other) const
99 {
100 return std::tie(this->row, this->column, this->value) ==
101 std::tie(other.row, other.column, other.value);
102 };
103 bool operator!=(const matrix_data_entry& other) const
104 {
105 return std::tie(this->row, this->column, this->value) !=
106 std::tie(other.row, other.column, other.value);
107 };
108
109#define GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(_op) \
110 bool operator _op(const matrix_data_entry& other) const \
111 { \
112 return std::tie(this->row, this->column) \
113 _op std::tie(other.row, other.column); \
114 }
115
116 GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(<);
117 GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(>);
118 GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(<=);
119 GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(>=);
120
121#undef GKO_DEFINE_DEFAULT_COMPARE_OPERATOR
122
123 friend std::ostream& operator<<(std::ostream& os,
124 const matrix_data_entry& x)
125 {
126 os << '(' << x.row << ',' << x.column << ',' << x.value << ')';
127 return os;
128 }
129
130 index_type row;
131 index_type column;
132 value_type value;
133};
134
135
154template <typename ValueType = default_precision, typename IndexType = int32>
156 using value_type = ValueType;
157 using index_type = IndexType;
159
166 matrix_data(dim<2> size_ = dim<2>{}, ValueType value = zero<ValueType>())
167 : size{size_}
168 {
169 if (is_zero(value)) {
170 return;
171 }
172 nonzeros.reserve(size[0] * size[1]);
173 for (size_type row = 0; row < size[0]; ++row) {
174 for (size_type col = 0; col < size[1]; ++col) {
175 nonzeros.emplace_back(row, col, value);
176 }
177 }
178 }
179
190 template <typename RandomDistribution, typename RandomEngine>
192 : size{size_}
193 {
194 nonzeros.reserve(size[0] * size[1]);
195 for (size_type row = 0; row < size[0]; ++row) {
196 for (size_type col = 0; col < size[1]; ++col) {
197 const auto value =
198 detail::get_rand_value<ValueType>(dist, engine);
199 if (is_nonzero(value)) {
200 nonzeros.emplace_back(row, col, value);
201 }
202 }
203 }
204 }
205
211 matrix_data(std::initializer_list<std::initializer_list<ValueType>> values)
212 : size{values.size(), 0}
213 {
214 for (size_type row = 0; row < values.size(); ++row) {
215 const auto row_data = begin(values)[row];
216 size[1] = std::max(size[1], row_data.size());
217 for (size_type col = 0; col < row_data.size(); ++col) {
218 const auto& val = begin(row_data)[col];
219 if (is_nonzero(val)) {
220 nonzeros.emplace_back(row, col, val);
221 }
222 }
223 }
224 }
225
233 dim<2> size_,
234 std::initializer_list<detail::input_triple<ValueType, IndexType>>
235 nonzeros_)
236 : size{size_}, nonzeros()
237 {
238 nonzeros.reserve(nonzeros_.size());
239 for (const auto& elem : nonzeros_) {
240 nonzeros.emplace_back(elem.row, elem.col, elem.val);
241 }
242 }
243
251 : size{size_ * block.size}
252 {
253 nonzeros.reserve(size_[0] * size_[1] * block.nonzeros.size());
254 for (size_type row = 0; row < size_[0]; ++row) {
255 for (size_type col = 0; col < size_[1]; ++col) {
256 for (const auto& elem : block.nonzeros) {
257 nonzeros.emplace_back(row * block.size[0] + elem.row,
258 col * block.size[1] + elem.column,
259 elem.value);
260 }
261 }
262 }
264 }
265
273 template <typename Accessor>
275 : size{data.length(0), data.length(1)}
276 {
277 for (gko::size_type row = 0; row < size[0]; ++row) {
278 for (gko::size_type col = 0; col < size[1]; ++col) {
279 if (is_nonzero(data(row, col))) {
280 nonzeros.emplace_back(row, col, data(row, col));
281 }
282 }
283 }
284 }
285
294 static matrix_data diag(dim<2> size_, ValueType value)
295 {
296 matrix_data res(size_);
297 if (is_nonzero(value)) {
298 const auto num_nnz = std::min(size_[0], size_[1]);
299 res.nonzeros.reserve(num_nnz);
300 for (size_type i = 0; i < num_nnz; ++i) {
301 res.nonzeros.emplace_back(i, i, value);
302 }
303 }
304 return res;
305 }
306
315 static matrix_data diag(dim<2> size_,
316 std::initializer_list<ValueType> nonzeros_)
317 {
318 matrix_data res(size_);
319 res.nonzeros.reserve(nonzeros_.size());
320 int pos = 0;
321 for (auto value : nonzeros_) {
322 res.nonzeros.emplace_back(pos, pos, value);
323 ++pos;
324 }
325 return res;
326 }
327
337 {
338 matrix_data res(size_ * block.size);
339 const auto num_blocks = std::min(size_[0], size_[1]);
340 res.nonzeros.reserve(num_blocks * block.nonzeros.size());
341 for (size_type b = 0; b < num_blocks; ++b) {
342 for (const auto& elem : block.nonzeros) {
343 res.nonzeros.emplace_back(b * block.size[0] + elem.row,
344 b * block.size[1] + elem.column,
345 elem.value);
346 }
347 }
348 return res;
349 }
350
362 template <typename ForwardIterator>
364 {
365 matrix_data res(std::accumulate(
366 begin, end, dim<2>{}, [](dim<2> s, const matrix_data& d) {
367 return dim<2>{s[0] + d.size[0], s[1] + d.size[1]};
368 }));
369
372 for (auto it = begin; it != end; ++it) {
373 for (const auto& elem : it->nonzeros) {
374 res.nonzeros.emplace_back(row_offset + elem.row,
375 col_offset + elem.column, elem.value);
376 }
377 row_offset += it->size[0];
378 col_offset += it->size[1];
379 }
380
381 return res;
382 }
383
392 static matrix_data diag(std::initializer_list<matrix_data> blocks)
393 {
394 return diag(begin(blocks), end(blocks));
395 }
396
416 template <typename RandomDistribution, typename RandomEngine>
421 {
423 std::vector<ValueType> mtx_data(size * size, zero<ValueType>());
424 std::vector<ValueType> ref_data(size);
425 std::vector<ValueType> work(size);
426 range matrix(mtx_data.data(), size, size, size);
427 range reflector(ref_data.data(), size, 1u, 1u);
428
429 initialize_diag_with_cond(condition_number, matrix);
430 for (size_type i = 0; i < num_reflectors; ++i) {
431 generate_random_reflector(dist, engine, reflector);
432 reflect_domain(reflector, matrix, work.data());
433 generate_random_reflector(dist, engine, reflector);
434 reflect_range(reflector, matrix, work.data());
435 }
436 return matrix;
437 }
438
460 template <typename RandomDistribution, typename RandomEngine>
464 {
465 return cond(size, condition_number,
466 std::forward<RandomDistribution>(dist),
467 std::forward<RandomEngine>(engine), size - 1);
468 }
469
474
482 std::vector<nonzero_type> nonzeros;
483
488 {
489 std::sort(
490 begin(nonzeros), end(nonzeros), [](nonzero_type x, nonzero_type y) {
491 return std::tie(x.row, x.column) < std::tie(y.row, y.column);
492 });
493 }
494
499 {
500 nonzeros.erase(
501 std::remove_if(begin(nonzeros), end(nonzeros),
502 [](nonzero_type nz) { return is_zero(nz.value); }),
503 end(nonzeros));
504 }
505
511 {
513 std::vector<nonzero_type> new_nonzeros;
514 if (!nonzeros.empty()) {
515 new_nonzeros.emplace_back(nonzeros.front().row,
516 nonzeros.front().column,
518 for (auto entry : nonzeros) {
519 if (entry.row != new_nonzeros.back().row ||
520 entry.column != new_nonzeros.back().column) {
521 new_nonzeros.emplace_back(entry.row, entry.column,
523 }
524 new_nonzeros.back().value += entry.value;
525 }
526 nonzeros = std::move(new_nonzeros);
527 }
528 }
529
530private:
531 template <typename Accessor>
532 static void initialize_diag_with_cond(
534 const range<Accessor>& matrix)
535 {
537 const auto size = matrix.length(0);
538 const auto min_sigma = one(condition_number) / sqrt(condition_number);
539 const auto max_sigma = sqrt(condition_number);
540
541 matrix = zero(matrix);
542 for (gko::size_type i = 0; i < size; ++i) {
543 matrix(i, i) = max_sigma * static_cast<sigma_type>(size - i - 1) /
544 static_cast<sigma_type>(size - 1) +
545 min_sigma * static_cast<sigma_type>(i) /
546 static_cast<sigma_type>(size - 1);
547 }
548 }
549
550 template <typename RandomDistribution, typename RandomEngine,
551 typename Accessor>
552 static void generate_random_reflector(RandomDistribution&& dist,
555 {
556 for (gko::size_type i = 0; i < reflector.length(0); ++i) {
557 reflector(i, 0) = detail::get_rand_value<ValueType>(dist, engine);
558 }
559 }
560
561 template <typename Accessor>
562 static void reflect_domain(const range<Accessor>& reflector,
563 const range<Accessor>& matrix,
564 ValueType* work_data)
565 {
566 const auto two = one<ValueType>() + one<ValueType>();
568 matrix.length(0), 1u, 1u);
569 work = mmul(matrix, reflector);
570 const auto ct_reflector = conj(transpose(reflector));
571 const auto scale = two / mmul(ct_reflector, reflector)(0, 0);
572 matrix = matrix - scale * mmul(work, ct_reflector);
573 }
574
575 template <typename Accessor>
576 static void reflect_range(const range<Accessor>& reflector,
577 const range<Accessor>& matrix,
578 ValueType* work_data)
579 {
580 const auto two = one<ValueType>() + one<ValueType>();
582 work_data, 1u, matrix.length(0), matrix.length(0));
583 const auto ct_reflector = conj(transpose(reflector));
584 work = mmul(ct_reflector, matrix);
585 const auto scale = two / mmul(ct_reflector, reflector)(0, 0);
586 matrix = matrix - scale * mmul(reflector, work);
587 }
588};
589
590
591} // namespace gko
592
593
594#endif // GKO_PUBLIC_CORE_BASE_MATRIX_DATA_HPP_
A range is a multidimensional view of the memory.
Definition range.hpp:326
constexpr size_type length(size_type dimension) const
Returns the length of the specified dimension of the range.
Definition range.hpp:429
The Ginkgo namespace.
Definition abstract_factory.hpp:48
constexpr T one()
Returns the multiplicative identity for T.
Definition math.hpp:803
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:354
constexpr T zero()
Returns the additive identity for T.
Definition math.hpp:775
constexpr bool is_zero(T value)
Returns true if and only if the given value is zero.
Definition math.hpp:840
std::size_t size_type
Integral type used for allocation quantities.
Definition types.hpp:120
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:148
constexpr auto conj(const T &x)
Returns the conjugate of an object.
Definition math.hpp:1071
constexpr bool is_nonzero(T value)
Returns true if and only if the given value is not zero.
Definition math.hpp:855
A type representing the dimensions of a multidimensional object.
Definition dim.hpp:55
Type used to store nonzeros.
Definition matrix_data.hpp:89
This structure is used as an intermediate data type to store a sparse matrix.
Definition matrix_data.hpp:155
static matrix_data diag(dim< 2 > size_, const matrix_data &block)
Initializes a block-diagonal matrix.
Definition matrix_data.hpp:336
static matrix_data diag(dim< 2 > size_, ValueType value)
Initializes a diagonal matrix.
Definition matrix_data.hpp:294
dim< 2 > size
Size of the matrix.
Definition matrix_data.hpp:473
matrix_data(const range< Accessor > &data)
Initializes a matrix from a range.
Definition matrix_data.hpp:274
matrix_data(dim< 2 > size_=dim< 2 >{}, ValueType value=zero< ValueType >())
Initializes a matrix filled with the specified value.
Definition matrix_data.hpp:166
std::vector< nonzero_type > nonzeros
A vector of tuples storing the non-zeros of the matrix.
Definition matrix_data.hpp:482
void remove_zeros()
Remove entries with value zero from the matrix data.
Definition matrix_data.hpp:498
static matrix_data diag(ForwardIterator begin, ForwardIterator end)
Initializes a block-diagonal matrix from a list of diagonal blocks.
Definition matrix_data.hpp:363
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:417
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:392
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:315
matrix_data(dim< 2 > size_, const matrix_data &block)
Initializes a matrix out of a matrix block via duplication.
Definition matrix_data.hpp:250
void sum_duplicates()
Sum up all values that refer to the same matrix entry.
Definition matrix_data.hpp:510
matrix_data(std::initializer_list< std::initializer_list< ValueType > > values)
List-initializes the structure from a matrix of values.
Definition matrix_data.hpp:211
void ensure_row_major_order()
Sorts the nonzero vector so the values follow row-major order.
Definition matrix_data.hpp:487
matrix_data(dim< 2 > size_, RandomDistribution &&dist, RandomEngine &&engine)
Initializes a matrix with random values from the specified distribution.
Definition matrix_data.hpp:191
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:232
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:461