xerus
a general purpose tensor library
sparseTimesFullContraction.cpp
Go to the documentation of this file.
1 // Xerus - A General Purpose Tensor Library
2 // Copyright (C) 2014-2017 Benjamin Huber and Sebastian Wolf.
3 //
4 // Xerus is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as published
6 // by the Free Software Foundation, either version 3 of the License,
7 // or (at your option) any later version.
8 //
9 // Xerus is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
13 //
14 // You should have received a copy of the GNU Affero General Public License
15 // along with Xerus. If not, see <http://www.gnu.org/licenses/>.
16 //
17 // For further information on Xerus visit https://libXerus.org
18 // or contact us at contact@libXerus.org.
19 
24 #include <memory>
25 
27 #include <xerus/misc/check.h>
31 #include <xerus/misc/internal.h>
32 
33 namespace xerus {
34 
35  XERUS_force_inline void transpose(double* const __restrict _out, const double* const __restrict _in, const size_t _leftDim, const size_t _rightDim) {
36  for(size_t i = 0; i < _leftDim; ++i) {
37  for(size_t j = 0; j < _rightDim; ++j) {
38  _out[j*_leftDim+i] = _in[i*_rightDim+j];
39  }
40  }
41  }
42 
43  XERUS_force_inline std::unique_ptr<double[]> transpose(const double* const _A, const size_t _leftDim, const size_t _rightDim) {
44  std::unique_ptr<double[]> AT(new double[_leftDim*_rightDim]);
45  transpose(AT.get(), _A, _leftDim, _rightDim);
46  return AT;
47  }
48 
49 
50  XERUS_force_inline void transpose(std::map<size_t, double>& __restrict _out, const std::map<size_t, double>& __restrict _in, const size_t _leftDim, const size_t _rightDim) {
51  for(const auto& entry : _in) {
52  const size_t i = entry.first/_rightDim;
53  const size_t j = entry.first%_rightDim;
54  _out.emplace(j*_leftDim + i, entry.second);
55  }
56  }
57 
58  XERUS_force_inline std::map<size_t, double> transpose(const std::map<size_t, double>& _A, const size_t _leftDim, const size_t _rightDim) {
59  std::map<size_t, double> AT;
60  transpose(AT, _A, _leftDim, _rightDim);
61  return AT;
62  }
63 
64  // - - - - - - - - - - - - - - - - - - - - - - - - - Mix to Full - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
65 
66  void matrix_matrix_product( double* const _C,
67  const size_t _leftDim,
68  const size_t _rightDim,
69  const double _alpha,
70  const std::map<size_t, double>& _A,
71  const bool _transposeA,
72  const size_t _midDim,
73  const double* const _B) {
75 
76  // Prepare output array
77  misc::set_zero(_C, _leftDim*_rightDim);
78 
79  // Transposition of A only changes how i and j are calculated
80  if(!_transposeA) {
81  for(const auto& entry : _A) {
82  const size_t i = entry.first/_midDim;
83  const size_t j = entry.first%_midDim;
84  misc::add_scaled(_C+i*_rightDim, _alpha*entry.second, _B+j*_rightDim, _rightDim);
85  }
86  } else {
87  for(const auto& entry : _A) {
88  const size_t i = entry.first%_leftDim;
89  const size_t j = entry.first/_leftDim;
90  misc::add_scaled(_C+i*_rightDim, _alpha*entry.second, _B+j*_rightDim, _rightDim);
91  }
92  }
93 
94  XERUS_PA_END("Mixed BLAS", "Matrix-Matrix-Multiplication ==> Full", misc::to_string(_leftDim)+"x"+misc::to_string(_midDim)+" * "+misc::to_string(_midDim)+"x"+misc::to_string(_rightDim));
95  }
96 
97  void matrix_matrix_product( double* const _C,
98  const size_t _leftDim,
99  const size_t _rightDim,
100  const double _alpha,
101  const std::map<size_t, double>& _A,
102  const bool _transposeA,
103  const size_t _midDim,
104  const double* const _B,
105  const bool _transposeB) {
106  if(_transposeB) {
107  const std::unique_ptr<double[]> BT = transpose(_B, _rightDim, _midDim);
108  matrix_matrix_product(_C, _leftDim, _rightDim, _alpha, _A, _transposeA, _midDim, BT.get());
109  } else {
110  matrix_matrix_product(_C, _leftDim, _rightDim, _alpha, _A, _transposeA, _midDim, _B);
111  }
112  }
113 
114  void matrix_matrix_product( double* const _C,
115  const size_t _leftDim,
116  const size_t _rightDim,
117  const double _alpha,
118  const double* const _A,
119  const bool _transposeA,
120  const size_t _midDim,
121  const std::map<size_t, double>& _B,
122  const bool _transposeB) {
123  // It is significantly faster to calculate (B^T * A*T)^T
124  const std::unique_ptr<double[]> CT(new double[_leftDim*_rightDim]);
125  matrix_matrix_product(CT.get(), _rightDim, _leftDim, _alpha, _B, !_transposeB, _midDim, _A, !_transposeA);
126  transpose(_C, CT.get(), _rightDim, _leftDim);
127  }
128 
129 
130  // - - - - - - - - - - - - - - - - - - - - - - - - - Mix to Sparse - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
131 
132  void matrix_matrix_product( std::map<size_t, double>& _C,
133  const size_t /*_leftDim*/,
134  const size_t _rightDim,
135  const double _alpha,
136  const std::map<size_t, double>& _A,
137  const size_t _midDim,
138  const double* const _B) {
140 
141  size_t currentRow = 0;
142  std::unique_ptr<double[]> row(new double[_rightDim]);
143  misc::set_zero(row.get(), _rightDim);
144 
145  for(const auto& entry : _A) {
146  const size_t i = entry.first/_midDim;
147  const size_t j = entry.first%_midDim;
148 
149  if(i == currentRow) {
150  misc::add_scaled(row.get(), _alpha*entry.second, _B+j*_rightDim, _rightDim);
151  } else {
152  INTERNAL_CHECK(i > currentRow, "Internal Error");
153 
154  // Copy old row to _C
155  for(size_t k = 0; k < _rightDim; ++k) {
156  #pragma GCC diagnostic push
157  #pragma GCC diagnostic ignored "-Wfloat-equal"
158  if(row.get()[k] != 0) {
159  _C.emplace(currentRow*_rightDim + k, row.get()[k]);
160  }
161  #pragma GCC diagnostic pop
162  }
163 
164  // Start new row
165  currentRow = i;
166  misc::copy_scaled(row.get(), _alpha*entry.second, _B+j*_rightDim, _rightDim);
167  }
168  }
169 
170  // Copy the last row to _C
171  for(size_t k = 0; k < _rightDim; ++k) {
172  #pragma GCC diagnostic push
173  #pragma GCC diagnostic ignored "-Wfloat-equal"
174  if(row.get()[k] != 0) {
175  _C.emplace(currentRow*_rightDim + k, row.get()[k]);
176  }
177  #pragma GCC diagnostic pop
178  }
179 
180  XERUS_PA_END("Mixed BLAS", "Matrix-Matrix-Multiplication ==> Sparse", "?x"+misc::to_string(_midDim)+" * "+misc::to_string(_midDim)+"x"+misc::to_string(_rightDim));
181  }
182 
183  void matrix_matrix_product( std::map<size_t, double>& _C,
184  const size_t _leftDim,
185  const size_t _rightDim,
186  const double _alpha,
187  const std::map<size_t, double>& _A,
188  const bool _transposeA,
189  const size_t _midDim,
190  const double* const _B,
191  const bool _transposeB) {
192  if(_transposeA) {
193  const std::map<size_t, double> AT = transpose(_A, _midDim, _leftDim);
194  if(_transposeB) {
195  std::unique_ptr<double[]> BT = transpose(_B, _rightDim, _midDim);
196  matrix_matrix_product(_C, _leftDim, _rightDim, _alpha, AT, _midDim, BT.get());
197  } else {
198  matrix_matrix_product(_C, _leftDim, _rightDim, _alpha, AT, _midDim, _B);
199  }
200  } else {
201  if(_transposeB) {
202  std::unique_ptr<double[]> BT = transpose(_B, _rightDim, _midDim);
203  matrix_matrix_product(_C, _leftDim, _rightDim, _alpha, _A, _midDim, BT.get());
204  } else {
205  matrix_matrix_product(_C, _leftDim, _rightDim, _alpha, _A, _midDim, _B);
206  }
207  }
208  }
209 
210  void matrix_matrix_product( std::map<size_t, double>& _C,
211  const size_t _leftDim,
212  const size_t _rightDim,
213  const double _alpha,
214  const double* const _A,
215  const bool _transposeA,
216  const size_t _midDim,
217  const std::map<size_t, double>& _B,
218  const bool _transposeB) {
219  // It is significantly faster to calculate (B^T * A*T)^T (this is only benchmarked for mix -> Full yet...)
220  std::map<size_t, double> CT;
221  matrix_matrix_product(CT, _rightDim, _leftDim, _alpha, _B, !_transposeB, _midDim, _A, !_transposeA);
222  transpose(_C, CT, _rightDim, _leftDim);
223  }
224 } // namespace xerus
Header file for CHECK and REQUIRE macros.
Header file for the performance analysis global objects and analysis function.
The main namespace of xerus.
Definition: basic.h:37
void copy_scaled(T *const __restrict _x, const T _alpha, const T *const _y, const size_t _n) noexcept
Copys _n entries from _y to _x, simulationously scaling each entry by the factor _alpha. I.e x = alpha*y.
Header file for the low level array support function.
Header file for comfort functions and macros that should not be exported in the library.
Header file for sparse matrix times dense matrix wrapper functions.
Header file for some elementary string manipulation routines.
#define XERUS_PA_END(group, name, parameter)
#define XERUS_PA_START
static XERUS_force_inline std::string to_string(const bool obj)
Definition: stringFromTo.h:41
void set_zero(T *const __restrict _x, const size_t _n) noexcept
Sets all entries equal to zero.
#define INTERNAL_CHECK
Definition: internal.h:37
void add_scaled(T *const __restrict _x, const T _alpha, const T *const __restrict _y, const size_t _n) noexcept
Adds _n entries of _y, scaled by _alpha to the ones of _x. I.e. x += alpha*y.
XERUS_force_inline void transpose(double *const __restrict _out, const double *const __restrict _in, const size_t _leftDim, const size_t _rightDim)
#define XERUS_force_inline
Collection of attributes to force gcc to inline a specific function.
Definition: standard.h:75
void matrix_matrix_product(double *const _C, const size_t _leftDim, const size_t _rightDim, const double _alpha, const std::map< size_t, double > &_A, const bool _transposeA, const size_t _midDim, const double *const _B, const bool _transposeB)