Ginkgo  Generated from tags/v1.0.0^0 branch based on master. Ginkgo version 1.0.0
A numerical linear algebra library targeting many-core architectures
matrix_data.hpp
1 /*******************************<GINKGO LICENSE>******************************
2 Copyright (c) 2017-2019, the Ginkgo authors
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 
16 3. Neither the name of the copyright holder nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
19 
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 ******************************<GINKGO LICENSE>*******************************/
32 
33 #ifndef GKO_CORE_BASE_MATRIX_DATA_HPP_
34 #define GKO_CORE_BASE_MATRIX_DATA_HPP_
35 
36 
37 #include <ginkgo/core/base/dim.hpp>
38 #include <ginkgo/core/base/math.hpp>
39 #include <ginkgo/core/base/range.hpp>
40 #include <ginkgo/core/base/range_accessors.hpp>
41 #include <ginkgo/core/base/types.hpp>
42 
43 
44 #include <algorithm>
45 #include <numeric>
46 #include <tuple>
47 #include <vector>
48 
49 
50 namespace gko {
51 
52 
53 namespace detail {
54 
55 
56 // internal structure used to get around explicit constructors in std::tuple
57 template <typename ValueType, typename IndexType>
58 struct input_triple {
59  IndexType row;
60  IndexType col;
61  ValueType val;
62 };
63 
64 
65 template <typename ValueType, typename Distribution, typename Generator>
66 typename std::enable_if<!is_complex<ValueType>(), ValueType>::type
67 get_rand_value(Distribution &&dist, Generator &&gen)
68 {
69  return dist(gen);
70 }
71 
72 
73 template <typename ValueType, typename Distribution, typename Generator>
74 typename std::enable_if<is_complex<ValueType>(), ValueType>::type
75 get_rand_value(Distribution &&dist, Generator &&gen)
76 {
77  return ValueType(dist(gen), dist(gen));
78 }
79 
80 
81 } // namespace detail
82 
83 
101 template <typename ValueType = default_precision, typename IndexType = int32>
102 struct matrix_data {
103  using value_type = ValueType;
104  using index_type = IndexType;
105 
109  struct nonzero_type {
110  nonzero_type() = default;
111 
112  nonzero_type(index_type r, index_type c, value_type v)
113  : row(r), column(c), value(v)
114  {}
115 
116 #define GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(_op) \
117  bool operator _op(const nonzero_type &other) const \
118  { \
119  return std::tie(this->row, this->column, this->value) \
120  _op std::tie(other.row, other.column, other.value); \
121  }
122 
123  GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(==);
124  GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(!=);
125  GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(<);
126  GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(>);
127  GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(<=);
128  GKO_DEFINE_DEFAULT_COMPARE_OPERATOR(>=);
129 
130 #undef GKO_DEFINE_DEFAULT_COMPARE_OPERATOR
131 
132  index_type row;
133  index_type column;
134  value_type value;
135  };
136 
143  matrix_data(dim<2> size_ = dim<2>{}, ValueType value = zero<ValueType>())
144  : size{size_}
145  {
146  if (value == zero<ValueType>()) {
147  return;
148  }
149  for (size_type row = 0; row < size[0]; ++row) {
150  for (size_type col = 0; col < size[1]; ++col) {
151  nonzeros.emplace_back(row, col, value);
152  }
153  }
154  }
155 
166  template <typename RandomDistribution, typename RandomEngine>
167  matrix_data(dim<2> size_, RandomDistribution &&dist, RandomEngine &&engine)
168  : size{size_}
169  {
170  for (size_type row = 0; row < size[0]; ++row) {
171  for (size_type col = 0; col < size[1]; ++col) {
172  const auto value =
173  detail::get_rand_value<ValueType>(dist, engine);
174  if (value != zero<ValueType>()) {
175  nonzeros.emplace_back(row, col, value);
176  }
177  }
178  }
179  }
180 
186  matrix_data(std::initializer_list<std::initializer_list<ValueType>> values)
187  : size{values.size(), 0}
188  {
189  for (size_type row = 0; row < values.size(); ++row) {
190  const auto row_data = begin(values)[row];
191  size[1] = std::max(size[1], row_data.size());
192  for (size_type col = 0; col < row_data.size(); ++col) {
193  const auto &val = begin(row_data)[col];
194  if (val != zero<ValueType>()) {
195  nonzeros.emplace_back(row, col, val);
196  }
197  }
198  }
199  }
200 
208  dim<2> size_,
209  std::initializer_list<detail::input_triple<ValueType, IndexType>>
210  nonzeros_)
211  : size{size_}, nonzeros()
212  {
213  nonzeros.reserve(nonzeros_.size());
214  for (const auto &elem : nonzeros_) {
215  nonzeros.emplace_back(elem.row, elem.col, elem.val);
216  }
217  }
218 
225  matrix_data(dim<2> size_, const matrix_data &block)
226  : size{size_ * block.size}
227  {
228  nonzeros.reserve(size_[0] * size_[1] * block.nonzeros.size());
229  for (size_type row = 0; row < size_[0]; ++row) {
230  for (size_type col = 0; col < size_[1]; ++col) {
231  for (const auto &elem : block.nonzeros) {
232  nonzeros.emplace_back(row * block.size[0] + elem.row,
233  col * block.size[1] + elem.column,
234  elem.value);
235  }
236  }
237  }
238  this->ensure_row_major_order();
239  }
240 
248  template <typename Accessor>
250  : size{data.length(0), data.length(1)}
251  {
252  for (gko::size_type row = 0; row < size[0]; ++row) {
253  for (gko::size_type col = 0; col < size[1]; ++col) {
254  if (data(row, col) != zero<ValueType>()) {
255  nonzeros.emplace_back(row, col, data(row, col));
256  }
257  }
258  }
259  }
260 
269  static matrix_data diag(dim<2> size_, ValueType value)
270  {
271  matrix_data res(size_);
272  if (value != zero<ValueType>()) {
273  const auto num_nnz = std::min(size_[0], size_[1]);
274  res.nonzeros.reserve(num_nnz);
275  for (size_type i = 0; i < num_nnz; ++i) {
276  res.nonzeros.emplace_back(i, i, value);
277  }
278  }
279  return res;
280  }
281 
290  static matrix_data diag(dim<2> size_,
291  std::initializer_list<ValueType> nonzeros_)
292  {
293  matrix_data res(size_);
294  res.nonzeros.reserve(nonzeros_.size());
295  int pos = 0;
296  for (auto value : nonzeros_) {
297  res.nonzeros.emplace_back(pos, pos, value);
298  ++pos;
299  }
300  return res;
301  }
302 
311  static matrix_data diag(dim<2> size_, const matrix_data &block)
312  {
313  matrix_data res(size_ * block.size);
314  const auto num_blocks = std::min(size_[0], size_[1]);
315  res.nonzeros.reserve(num_blocks * block.nonzeros.size());
316  for (size_type b = 0; b < num_blocks; ++b) {
317  for (const auto &elem : block.nonzeros) {
318  res.nonzeros.emplace_back(b * block.size[0] + elem.row,
319  b * block.size[1] + elem.column,
320  elem.value);
321  }
322  }
323  return res;
324  }
325 
337  template <typename ForwardIterator>
338  static matrix_data diag(ForwardIterator begin, ForwardIterator end)
339  {
340  matrix_data res(std::accumulate(
341  begin, end, dim<2>{}, [](dim<2> s, const matrix_data &d) {
342  return dim<2>{s[0] + d.size[0], s[1] + d.size[1]};
343  }));
344 
345  size_type row_offset{};
346  size_type col_offset{};
347  for (auto it = begin; it != end; ++it) {
348  for (const auto &elem : it->nonzeros) {
349  res.nonzeros.emplace_back(row_offset + elem.row,
350  col_offset + elem.column, elem.value);
351  }
352  row_offset += it->size[0];
353  col_offset += it->size[1];
354  }
355 
356  return res;
357  }
358 
367  static matrix_data diag(std::initializer_list<matrix_data> blocks)
368  {
369  return diag(begin(blocks), end(blocks));
370  }
371 
391  template <typename RandomDistribution, typename RandomEngine>
393  remove_complex<ValueType> condition_number,
394  RandomDistribution &&dist, RandomEngine &&engine,
395  size_type num_reflectors)
396  {
398  std::vector<ValueType> mtx_data(size * size, zero<ValueType>());
399  std::vector<ValueType> ref_data(size);
400  std::vector<ValueType> work(size);
401  range matrix(mtx_data.data(), size, size, size);
402  range reflector(ref_data.data(), size, 1u, 1u);
403 
404  initialize_diag_with_cond(condition_number, matrix);
405  for (size_type i = 0; i < num_reflectors; ++i) {
406  generate_random_reflector(dist, engine, reflector);
407  reflect_domain(reflector, matrix, work.data());
408  generate_random_reflector(dist, engine, reflector);
409  reflect_range(reflector, matrix, work.data());
410  }
411  return matrix;
412  }
413 
435  template <typename RandomDistribution, typename RandomEngine>
437  remove_complex<ValueType> condition_number,
438  RandomDistribution &&dist, RandomEngine &&engine)
439  {
440  return cond(size, condition_number,
441  std::forward<RandomDistribution>(dist),
442  std::forward<RandomEngine>(engine), size - 1);
443  }
444 
449 
457  std::vector<nonzero_type> nonzeros;
458 
463  {
464  std::sort(
465  begin(nonzeros), end(nonzeros), [](nonzero_type x, nonzero_type y) {
466  return std::tie(x.row, x.column) < std::tie(y.row, y.column);
467  });
468  }
469 
470 private:
471  template <typename Accessor>
472  static void initialize_diag_with_cond(
473  remove_complex<ValueType> condition_number,
474  const range<Accessor> &matrix)
475  {
476  using sigma_type = remove_complex<ValueType>;
477  const auto size = matrix.length(0);
478  const auto min_sigma = one(condition_number) / sqrt(condition_number);
479  const auto max_sigma = sqrt(condition_number);
480 
481  matrix = zero(matrix);
482  for (gko::size_type i = 0; i < size; ++i) {
483  matrix(i, i) = max_sigma * static_cast<sigma_type>(size - i - 1) /
484  static_cast<sigma_type>(size - 1) +
485  min_sigma * static_cast<sigma_type>(i) /
486  static_cast<sigma_type>(size - 1);
487  }
488  }
489 
490  template <typename RandomDistribution, typename RandomEngine,
491  typename Accessor>
492  static void generate_random_reflector(RandomDistribution &&dist,
493  RandomEngine &&engine,
494  const range<Accessor> &reflector)
495  {
496  for (gko::size_type i = 0; i < reflector.length(0); ++i) {
497  reflector(i, 0) = detail::get_rand_value<ValueType>(dist, engine);
498  }
499  }
500 
501  template <typename Accessor>
502  static void reflect_domain(const range<Accessor> &reflector,
503  const range<Accessor> &matrix,
504  ValueType *work_data)
505  {
506  const auto two = one<ValueType>() + one<ValueType>();
508  matrix.length(0), 1u, 1u);
509  work = mmul(matrix, reflector);
510  const auto ct_reflector = conj(transpose(reflector));
511  const auto scale = two / mmul(ct_reflector, reflector)(0, 0);
512  matrix = matrix - scale * mmul(work, ct_reflector);
513  }
514 
515  template <typename Accessor>
516  static void reflect_range(const range<Accessor> &reflector,
517  const range<Accessor> &matrix,
518  ValueType *work_data)
519  {
520  const auto two = one<ValueType>() + one<ValueType>();
522  work_data, 1u, matrix.length(0), matrix.length(0));
523  const auto ct_reflector = conj(transpose(reflector));
524  work = mmul(ct_reflector, matrix);
525  const auto scale = two / mmul(ct_reflector, reflector)(0, 0);
526  matrix = matrix - scale * mmul(reflector, work);
527  }
528 };
529 
530 
531 } // namespace gko
532 
533 
534 #endif // GKO_CORE_BASE_MATRIX_DATA_HPP_
static matrix_data diag(dim< 2 > size_, const matrix_data &block)
Initializes a block-diagonal matrix.
Definition: matrix_data.hpp:311
constexpr T zero()
Returns the additive identity for T.
Definition: math.hpp:292
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:392
std::size_t size_type
Integral type used for allocation quantities.
Definition: types.hpp:94
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:207
constexpr size_type length(size_type dimension) const
Returns the length of the specified dimension of the range.
Definition: range.hpp:387
matrix_data(std::initializer_list< std::initializer_list< ValueType >> values)
List-initializes the structure from a matrix of values.
Definition: matrix_data.hpp:186
The Ginkgo namespace.
Definition: abstract_factory.hpp:45
static matrix_data diag(dim< 2 > size_, ValueType value)
Initializes a diagonal matrix.
Definition: matrix_data.hpp:269
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:290
matrix_data(dim< 2 > size_, RandomDistribution &&dist, RandomEngine &&engine)
Initializes a matrix with random values from the specified distribution.
Definition: matrix_data.hpp:167
dim< 2 > size
Size of the matrix.
Definition: matrix_data.hpp:448
matrix_data(dim< 2 > size_, const matrix_data &block)
Initializes a matrix out of a matrix block via duplication.
Definition: matrix_data.hpp:225
void ensure_row_major_order()
Sorts the nonzero vector so the values follow row-major order.
Definition: matrix_data.hpp:462
static matrix_data diag(ForwardIterator begin, ForwardIterator end)
Initializes a block-diagonal matrix from a list of diagonal blocks.
Definition: matrix_data.hpp:338
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:436
T conj(const T &x)
Returns the conjugate of an object.
Definition: math.hpp:439
matrix_data(const range< Accessor > &data)
Initializes a matrix from a range.
Definition: matrix_data.hpp:249
std::vector< nonzero_type > nonzeros
A vector of tuples storing the non-zeros of the matrix.
Definition: matrix_data.hpp:457
typename detail::remove_complex_impl< T >::type remove_complex
Obtains a real counterpart of a std::complex type, and leaves the type unchanged if it is not a compl...
Definition: math.hpp:93
Type used to store nonzeros.
Definition: matrix_data.hpp:109
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:367
This structure is used as an intermediate data type to store a sparse matrix.
Definition: matrix_data.hpp:102
A range is a multidimensional view of the memory.
Definition: range.hpp:296
constexpr dim< 2, DimensionType > transpose(const dim< 2, DimensionType > &dimensions) noexcept
Returns a dim<2> object with its dimensions swapped.
Definition: dim.hpp:234
matrix_data(dim< 2 > size_=dim< 2 >{}, ValueType value=zero< ValueType >())
Initializes a matrix filled with the specified value.
Definition: matrix_data.hpp:143
constexpr T one()
Returns the multiplicative identity for T.
Definition: math.hpp:319