Ginkgo  Generated from pipelines/1330831941 branch based on master. Ginkgo version 1.8.0
A numerical linear algebra library targeting many-core architectures
matrix_data.hpp
1 // SPDX-FileCopyrightText: 2017 - 2024 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 
15 #include <ginkgo/core/base/dim.hpp>
16 #include <ginkgo/core/base/math.hpp>
17 #include <ginkgo/core/base/range.hpp>
18 #include <ginkgo/core/base/range_accessors.hpp>
19 #include <ginkgo/core/base/types.hpp>
20 #include <ginkgo/core/base/utils.hpp>
21 
22 
23 namespace gko {
24 
25 
26 namespace detail {
27 
28 
29 // internal structure used to get around explicit constructors in std::tuple
30 template <typename ValueType, typename IndexType>
31 struct input_triple {
32  IndexType row;
33  IndexType col;
34  ValueType val;
35 };
36 
37 
38 template <typename ValueType, typename Distribution, typename Generator>
39 typename std::enable_if<!is_complex_s<ValueType>::value, ValueType>::type
40 get_rand_value(Distribution&& dist, Generator&& gen)
41 {
42  return dist(gen);
43 }
44 
45 
46 template <typename ValueType, typename Distribution, typename Generator>
47 typename std::enable_if<is_complex_s<ValueType>::value, ValueType>::type
48 get_rand_value(Distribution&& dist, Generator&& gen)
49 {
50  return ValueType(dist(gen), dist(gen));
51 }
52 
53 
54 } // namespace detail
55 
56 
60 template <typename ValueType, typename IndexType>
62  using value_type = ValueType;
63  using index_type = IndexType;
64  matrix_data_entry() = default;
65 
66  GKO_ATTRIBUTES matrix_data_entry(index_type r, index_type c, value_type v)
67  : row(r), column(c), value(v)
68  {}
69 
70  bool operator==(const matrix_data_entry& other) const
71  {
72  return std::tie(this->row, this->column, this->value) ==
73  std::tie(other.row, other.column, other.value);
74  };
75  bool operator!=(const matrix_data_entry& other) const
76  {
77  return std::tie(this->row, this->column, this->value) !=
78  std::tie(other.row, other.column, other.value);
79  };
80 
81 #define GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(_op) \
82  bool operator _op(const matrix_data_entry& other) const \
83  { \
84  return std::tie(this->row, this->column) \
85  _op std::tie(other.row, other.column); \
86  }
87 
88  GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(<);
89  GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(>);
90  GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(<=);
91  GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(>=);
92 
93 #undef GKO_DEFINE_DEFAULT_COMPARE_OPERATOR
94 
95  friend std::ostream& operator<<(std::ostream& os,
96  const matrix_data_entry& x)
97  {
98  os << '(' << x.row << ',' << x.column << ',' << x.value << ')';
99  return os;
100  }
101 
102  index_type row;
103  index_type column;
104  value_type value;
105 };
106 
107 
126 template <typename ValueType = default_precision, typename IndexType = int32>
127 struct matrix_data {
128  using value_type = ValueType;
129  using index_type = IndexType;
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 
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>
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>
390  remove_complex<ValueType> condition_number,
391  RandomDistribution&& dist, RandomEngine&& engine,
392  size_type num_reflectors)
393  {
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>
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 
446 
454  std::vector<nonzero_type> nonzeros;
455 
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 
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 
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 
510 private:
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::is_zero
constexpr bool is_zero(T value)
Returns true if and only if the given value is zero.
Definition: math.hpp:812
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::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_entry
Type used to store nonzeros.
Definition: matrix_data.hpp:61
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(ForwardIterator begin, ForwardIterator end)
Initializes a block-diagonal matrix from a list of diagonal blocks.
Definition: matrix_data.hpp:335
gko::size_type
std::size_t size_type
Integral type used for allocation quantities.
Definition: types.hpp:108
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::is_nonzero
constexpr bool is_nonzero(T value)
Returns true if and only if the given value is not zero.
Definition: math.hpp:827
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::remove_zeros
void remove_zeros()
Remove entries with value zero from the matrix data.
Definition: matrix_data.hpp:478
gko::range
A range is a multidimensional view of the memory.
Definition: range.hpp:298
gko
The Ginkgo namespace.
Definition: abstract_factory.hpp:20
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::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::dim< 2 >
gko::matrix_data
This structure is used as an intermediate data type to store a sparse matrix.
Definition: matrix_data.hpp:127
gko::matrix_data::size
dim< 2 > size
Size of the matrix.
Definition: matrix_data.hpp:445
gko::conj
constexpr auto conj(const T &x)
Returns the conjugate of an object.
Definition: math.hpp:1043
gko::matrix_data::ensure_row_major_order
void ensure_row_major_order()
Sorts the nonzero vector so the values follow row-major order.
Definition: matrix_data.hpp:470
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:120
gko::range::length
constexpr size_type length(size_type dimension) const
Returns the length of the specified dimension of the range.
Definition: range.hpp:401
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(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_, RandomDistribution &&dist, RandomEngine &&engine)
Initializes a matrix with random values from the specified distribution.
Definition: matrix_data.hpp:163
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::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
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::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:326
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::zero
constexpr T zero()
Returns the additive identity for T.
Definition: math.hpp:747
gko::one
constexpr T one()
Returns the multiplicative identity for T.
Definition: math.hpp:775