TiledArray  0.7.0
btas.h
Go to the documentation of this file.
1 /*
2  * This file is a part of TiledArray.
3  * Copyright (C) 2018 Virginia Tech
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * btas.h
19  * Jul 11, 2017
20  *
21  */
22 
23 #ifndef TILEDARRAY_MATH_BTAS_H__INCLUDED
24 #define TILEDARRAY_MATH_BTAS_H__INCLUDED
25 
26 #include "TiledArray/config.h"
27 #include "TiledArray/math/blas.h"
31 
32 #include <btas/features.h>
33 #include <btas/generic/axpy_impl.h>
34 #include <btas/generic/permute.h>
35 #include <btas/tensor.h>
36 
37 #include <madness/world/archive.h>
38 
39 namespace TiledArray {
40 namespace detail {
41 // these convert any range into TiledArray::Range
42 
43 inline const TiledArray::Range& make_ta_range(const TiledArray::Range& range) {
44  return range;
45 }
46 
48 
51 template <CBLAS_ORDER Order, typename... Args>
53  const btas::RangeNd<Order, Args...>& range) {
54  TA_USER_ASSERT(Order == CblasRowMajor,
55  "TiledArray::detail::make_ta_range(btas::RangeNd<Order,...>): "
56  "not supported for col-major Order");
57  return TiledArray::Range(range.lobound(), range.upbound());
58 }
59 
60 } // namespace detail
61 } // namespace TiledArray
62 
63 namespace btas {
64 
65 template <typename... Args>
66 bool operator==(const TiledArray::Range& range1,
67  const btas::BaseRangeNd<Args...>& range2) {
68  const auto rank = range1.rank();
69  if (rank == range2.rank()) {
70  auto range1_lobound_data = range1.lobound_data();
71  using std::cbegin;
72  const auto lobound_match =
73  std::equal(range1_lobound_data, range1_lobound_data + rank,
74  cbegin(range2.lobound()));
75  if (lobound_match) {
76  auto range1_upbound_data = range1.upbound_data();
77  return std::equal(range1_upbound_data, range1_upbound_data + rank,
78  cbegin(range2.upbound()));
79  }
80  }
81  return false;
82 }
83 
85 template <typename T, typename Range, typename Storage>
86 btas::Tensor<T, Range, Storage> permute(
87  const btas::Tensor<T, Range, Storage>& arg,
88  const TiledArray::Permutation& perm) {
89  btas::Tensor<T, Range, Storage> result;
90  std::vector<size_t> p(perm.dim());
91  std::copy(perm.begin(), perm.end(), p.begin());
92  btas::permute(arg, p, result);
93  return result;
94 }
95 
97 template <typename T, typename Range, typename Storage>
98 void add_to(btas::Tensor<T, Range, Storage>& result,
99  const btas::Tensor<T, Range, Storage>& arg) {
100  btas::axpy(1.0, arg, result);
101 }
102 
104 template <typename T, typename Range, typename Storage>
105 btas::Tensor<T, Range, Storage> mult(
106  const btas::Tensor<T, Range, Storage>& arg1,
107  const btas::Tensor<T, Range, Storage>& arg2) {
108  assert(false);
109 }
110 
112 template <typename T, typename Range, typename Storage>
113 btas::Tensor<T, Range, Storage> mult(
114  const btas::Tensor<T, Range, Storage>& arg1,
115  const btas::Tensor<T, Range, Storage>& arg2,
116  const TiledArray::Permutation& perm) {
117  assert(false);
118 }
119 
121 template <typename T, typename Range, typename Storage>
122 btas::Tensor<T, Range, Storage>& mult_to(
123  btas::Tensor<T, Range, Storage>& result,
124  const btas::Tensor<T, Range, Storage>& arg) {
125  assert(false);
126 }
127 
128 template <typename T, typename Range, typename Storage>
129 btas::Tensor<T, Range, Storage> gemm(
130  const btas::Tensor<T, Range, Storage>& left,
131  const btas::Tensor<T, Range, Storage>& right, T factor,
132  const TiledArray::math::GemmHelper& gemm_helper) {
133  // Check that the arguments are not empty and have the correct ranks
134  TA_ASSERT(!left.empty());
135  TA_ASSERT(left.range().rank() == gemm_helper.left_rank());
136  TA_ASSERT(!right.empty());
137  TA_ASSERT(right.range().rank() == gemm_helper.right_rank());
138 
139  // Construct the result Tensor
140  typedef btas::Tensor<T, Range, Storage> Tensor;
141  Tensor result(
142  gemm_helper.make_result_range<Range>(left.range(), right.range()));
143 
144  // Check that the inner dimensions of left and right match
145  TA_ASSERT(
146  gemm_helper.left_right_congruent(std::cbegin(left.range().lobound()),
147  std::cbegin(right.range().lobound())));
148  TA_ASSERT(
149  gemm_helper.left_right_congruent(std::cbegin(left.range().upbound()),
150  std::cbegin(right.range().upbound())));
151  TA_ASSERT(gemm_helper.left_right_congruent(
152  std::cbegin(left.range().extent()), std::cbegin(right.range().extent())));
153 
154  // Compute gemm dimensions
155  integer m = 1, n = 1, k = 1;
156  gemm_helper.compute_matrix_sizes(m, n, k, left.range(), right.range());
157 
158  // Get the leading dimension for left and right matrices.
159  const integer lda =
160  (gemm_helper.left_op() == madness::cblas::NoTrans ? k : m);
161  const integer ldb =
162  (gemm_helper.right_op() == madness::cblas::NoTrans ? n : k);
163 
164  TiledArray::math::gemm(gemm_helper.left_op(), gemm_helper.right_op(), m, n, k,
165  factor, left.data(), lda, right.data(), ldb, T(0),
166  result.data(), n);
167 
168  return result;
169 }
170 
171 template <typename T, typename Range, typename Storage>
172 void gemm(btas::Tensor<T, Range, Storage>& result,
173  const btas::Tensor<T, Range, Storage>& left,
174  const btas::Tensor<T, Range, Storage>& right, T factor,
175  const TiledArray::math::GemmHelper& gemm_helper) {
176  // Check that this tensor is not empty and has the correct rank
177  TA_ASSERT(!result.empty());
178  TA_ASSERT(result.range().rank() == gemm_helper.result_rank());
179 
180  // Check that the arguments are not empty and have the correct ranks
181  TA_ASSERT(!left.empty());
182  TA_ASSERT(left.range().rank() == gemm_helper.left_rank());
183  TA_ASSERT(!right.empty());
184  TA_ASSERT(right.range().rank() == gemm_helper.right_rank());
185 
186  // Check that the outer dimensions of left match the the corresponding
187  // dimensions in result
188  TA_ASSERT(
189  gemm_helper.left_result_congruent(std::cbegin(left.range().lobound()),
190  std::cbegin(result.range().lobound())));
191  TA_ASSERT(
192  gemm_helper.left_result_congruent(std::cbegin(left.range().upbound()),
193  std::cbegin(result.range().upbound())));
194  TA_ASSERT(
195  gemm_helper.left_result_congruent(std::cbegin(left.range().extent()),
196  std::cbegin(result.range().extent())));
197 
198  // Check that the outer dimensions of right match the the corresponding
199  // dimensions in result
200  TA_ASSERT(gemm_helper.right_result_congruent(
201  std::cbegin(right.range().lobound()),
202  std::cbegin(result.range().lobound())));
203  TA_ASSERT(gemm_helper.right_result_congruent(
204  std::cbegin(right.range().upbound()),
205  std::cbegin(result.range().upbound())));
206  TA_ASSERT(
207  gemm_helper.right_result_congruent(std::cbegin(right.range().extent()),
208  std::cbegin(result.range().extent())));
209 
210  // Check that the inner dimensions of left and right match
211  TA_ASSERT(
212  gemm_helper.left_right_congruent(std::cbegin(left.range().lobound()),
213  std::cbegin(right.range().lobound())));
214  TA_ASSERT(
215  gemm_helper.left_right_congruent(std::cbegin(left.range().upbound()),
216  std::cbegin(right.range().upbound())));
217  TA_ASSERT(gemm_helper.left_right_congruent(
218  std::cbegin(left.range().extent()), std::cbegin(right.range().extent())));
219 
220  // Compute gemm dimensions
221  integer m, n, k;
222  gemm_helper.compute_matrix_sizes(m, n, k, left.range(), right.range());
223 
224  // Get the leading dimension for left and right matrices.
225  const integer lda =
226  (gemm_helper.left_op() == madness::cblas::NoTrans ? k : m);
227  const integer ldb =
228  (gemm_helper.right_op() == madness::cblas::NoTrans ? n : k);
229 
230  TiledArray::math::gemm(gemm_helper.left_op(), gemm_helper.right_op(), m, n, k,
231  factor, left.data(), lda, right.data(), ldb, T(1),
232  result.data(), n);
233 }
234 
235 //
236 // these are not used, but still must be declared for expressions to work
237 //
238 template <typename T, typename Range, typename Storage>
239 typename btas::Tensor<T, Range, Storage>::value_type trace(
240  const btas::Tensor<T, Range, Storage>& arg);
241 // foreach(i) result += arg[i]
242 template <typename T, typename Range, typename Storage>
243 typename btas::Tensor<T, Range, Storage>::value_type sum(
244  const btas::Tensor<T, Range, Storage>& arg);
245 // foreach(i) result *= arg[i]
246 template <typename T, typename Range, typename Storage>
247 typename btas::Tensor<T, Range, Storage>::value_type product(
248  const btas::Tensor<T, Range, Storage>& arg);
249 
250 
251 // foreach(i) result += arg[i] * arg[i]
252 template <typename T, typename Range, typename Storage>
253 typename btas::Tensor<T, Range, Storage>::value_type squared_norm(
254  const btas::Tensor<T, Range, Storage>& arg) {
255  integer size = arg.size();
256  double result = 0.0;
257  result = TiledArray::math::dot(size, arg.data(), arg.data());
258  return result;
259 };
260 
261 // sqrt(squared_norm(arg))
262 template <typename T, typename Range, typename Storage>
263 typename btas::Tensor<T, Range, Storage>::value_type norm(
264  const btas::Tensor<T, Range, Storage>& arg);
265 // foreach(i) result = max(result, arg[i])
266 template <typename T, typename Range, typename Storage>
267 typename btas::Tensor<T, Range, Storage>::value_type max(
268  const btas::Tensor<T, Range, Storage>& arg);
269 // foreach(i) result = min(result, arg[i])
270 template <typename T, typename Range, typename Storage>
271 typename btas::Tensor<T, Range, Storage>::value_type min(
272  const btas::Tensor<T, Range, Storage>& arg);
273 // foreach(i) result = max(result, abs(arg[i]))
274 template <typename T, typename Range, typename Storage>
275 typename btas::Tensor<T, Range, Storage>::value_type abs_max(
276  const btas::Tensor<T, Range, Storage>& arg);
277 // foreach(i) result = max(result, abs(arg[i]))
278 template <typename T, typename Range, typename Storage>
279 typename btas::Tensor<T, Range, Storage>::value_type abs_min(
280  const btas::Tensor<T, Range, Storage>& arg);
281 } // namespace btas
282 
283 namespace TiledArray {
284 template <typename Perm>
285 TiledArray::Range permute(const TiledArray::Range& r, const Perm& p) {
286  TiledArray::Permutation pp(p.begin(), p.end());
287  return pp * r;
288 }
289 
290 } // namespace TiledArray
291 
292 namespace TiledArray {
293 namespace detail {
294 
295 template <typename T, typename... Args>
296 struct is_tensor_helper<btas::Tensor<T, Args...>> : public std::true_type {};
297 
298 template <typename T, typename... Args>
300  : public std::true_type {};
301 
302 } // namespace detail
303 } // namespace TiledArray
304 
305 namespace TiledArray {
307 template <typename T, typename Allocator, typename Range_, typename Storage>
308 struct Cast<TiledArray::Tensor<T, Allocator>,
309  btas::Tensor<T, Range_, Storage>> {
310  auto operator()(const btas::Tensor<T, Range_, Storage>& arg) const {
312  using std::begin;
313  std::copy(btas::cbegin(arg), btas::cend(arg), begin(result));
314  return result;
315  }
316 };
317 } // namespace TiledArray
318 
319 namespace madness {
320 namespace archive {
321 
322 #ifdef BTAS_HAS_BOOST_CONTAINER
323 template <class Archive, typename T, std::size_t N, typename A>
324 struct ArchiveLoadImpl<Archive, boost::container::small_vector<T, N, A>> {
325  static inline void load(const Archive& ar,
326  boost::container::small_vector<T, N, A>& x) {
327  std::size_t n{};
328  ar& n;
329  x.resize(n);
330  for (auto& xi : x) ar& xi;
331  }
332 };
333 
334 template <class Archive, typename T, std::size_t N, typename A>
335 struct ArchiveStoreImpl<Archive, boost::container::small_vector<T, N, A>> {
336  static inline void store(const Archive& ar,
337  const boost::container::small_vector<T, N, A>& x) {
338  ar& x.size();
339  for (const auto& xi : x) ar& xi;
340  }
341 };
342 #endif
343 
344 template <class Archive, typename T>
345 struct ArchiveLoadImpl<Archive, btas::varray<T>> {
346  static inline void load(const Archive& ar, btas::varray<T>& x) {
347  typename btas::varray<T>::size_type n{};
348  ar& n;
349  x.resize(n);
350  for (typename btas::varray<T>::value_type& xi : x) ar& xi;
351  }
352 };
353 
354 template <class Archive, typename T>
355 struct ArchiveStoreImpl<Archive, btas::varray<T>> {
356  static inline void store(const Archive& ar, const btas::varray<T>& x) {
357  ar& x.size();
358  for (const typename btas::varray<T>::value_type& xi : x) ar& xi;
359  }
360 };
361 
362 template <class Archive, CBLAS_ORDER _Order, typename _Index>
363 struct ArchiveLoadImpl<Archive, btas::BoxOrdinal<_Order, _Index>> {
364  static inline void load(const Archive& ar,
365  btas::BoxOrdinal<_Order, _Index>& o) {
366  typename btas::BoxOrdinal<_Order, _Index>::stride_type stride{};
367  typename btas::BoxOrdinal<_Order, _Index>::value_type offset{};
368  bool cont{};
369  ar& stride& offset& cont;
370  o = btas::BoxOrdinal<_Order, _Index>(std::move(stride), std::move(offset),
371  std::move(cont));
372  }
373 };
374 
375 template <class Archive, CBLAS_ORDER _Order, typename _Index>
376 struct ArchiveStoreImpl<Archive, btas::BoxOrdinal<_Order, _Index>> {
377  static inline void store(const Archive& ar,
378  const btas::BoxOrdinal<_Order, _Index>& o) {
379  ar& o.stride() & o.offset() & o.contiguous();
380  }
381 };
382 
383 template <class Archive, CBLAS_ORDER _Order, typename _Index, typename _Ordinal>
384 struct ArchiveLoadImpl<Archive, btas::RangeNd<_Order, _Index, _Ordinal>> {
385  static inline void load(const Archive& ar,
386  btas::RangeNd<_Order, _Index, _Ordinal>& r) {
387  typedef typename btas::BaseRangeNd<
388  btas::RangeNd<_Order, _Index, _Ordinal>>::index_type index_type;
389  index_type lobound{}, upbound{};
390  _Ordinal ordinal{};
391  ar& lobound& upbound& ordinal;
392  r = btas::RangeNd<_Order, _Index, _Ordinal>(
393  std::move(lobound), std::move(upbound), std::move(ordinal));
394  }
395 };
396 
397 template <class Archive, CBLAS_ORDER _Order, typename _Index, typename _Ordinal>
398 struct ArchiveStoreImpl<Archive, btas::RangeNd<_Order, _Index, _Ordinal>> {
399  static inline void store(const Archive& ar,
400  const btas::RangeNd<_Order, _Index, _Ordinal>& r) {
401  ar& r.lobound() & r.upbound() & r.ordinal();
402  }
403 };
404 
405 template <class Archive, typename _T, class _Range, class _Store>
406 struct ArchiveLoadImpl<Archive, btas::Tensor<_T, _Range, _Store>> {
407  static inline void load(const Archive& ar,
408  btas::Tensor<_T, _Range, _Store>& t) {
409  _Range range{};
410  _Store store{};
411  ar& range& store;
412  t = btas::Tensor<_T, _Range, _Store>(std::move(range), std::move(store));
413  }
414 };
415 
416 template <class Archive, typename _T, class _Range, class _Store>
417 struct ArchiveStoreImpl<Archive, btas::Tensor<_T, _Range, _Store>> {
418  static inline void store(const Archive& ar,
419  const btas::Tensor<_T, _Range, _Store>& t) {
420  ar& t.range() & t.storage();
421  }
422 };
423 } // namespace archive
424 } // namespace madness
425 
426 #endif /* TILEDARRAY_MATH_BTAS_H__INCLUDED */
btas::Tensor< T, Range, Storage > gemm(const btas::Tensor< T, Range, Storage > &left, const btas::Tensor< T, Range, Storage > &right, T factor, const TiledArray::math::GemmHelper &gemm_helper)
Definition: btas.h:129
static void load(const Archive &ar, btas::RangeNd< _Order, _Index, _Ordinal > &r)
Definition: btas.h:385
Tile cast operation.
Definition: cast.h:34
A (hyperrectangular) interval on , space of integer n-indices.
Definition: range.h:39
static void load(const Archive &ar, btas::BoxOrdinal< _Order, _Index > &o)
Definition: btas.h:364
void compute_matrix_sizes(integer &m, integer &n, integer &k, const Left &left, const Right &right) const
Compute the matrix dimension that can be used in a *GEMM call.
Definition: gemm_helper.h:252
static void load(const Archive &ar, btas::Tensor< _T, _Range, _Store > &t)
Definition: btas.h:407
bool left_result_congruent(const Left &left, const Result &result) const
Test that the outer dimensions of left are congruent (have equal extent) with that of the result tens...
Definition: gemm_helper.h:205
btas::Tensor< T, Range, Storage >::value_type abs_min(const btas::Tensor< T, Range, Storage > &arg)
An N-dimensional tensor object.
Definition: foreach.h:40
bool right_result_congruent(const Right &right, const Result &result) const
Test that the outer dimensions of right are congruent (have equal extent) with that of the result ten...
Definition: gemm_helper.h:220
const_iterator end() const
End element iterator factory function.
Definition: permutation.h:221
madness::cblas::CBLAS_TRANSPOSE right_op() const
Definition: gemm_helper.h:274
bool left_right_congruent(const Left &left, const Right &right) const
Test that the inner dimensions of left are congruent (have equal extent) with that of right...
Definition: gemm_helper.h:236
btas::Tensor< T, Range, Storage > permute(const btas::Tensor< T, Range, Storage > &arg, const TiledArray::Permutation &perm)
Computes the result of applying permutation perm to arg.
Definition: btas.h:86
static void store(const Archive &ar, const btas::varray< T > &x)
Definition: btas.h:356
unsigned int result_rank() const
Result rank accessor.
Definition: gemm_helper.h:134
unsigned int rank() const
Rank accessor.
Definition: range.h:542
R make_result_range(const Left &left, const Right &right) const
Construct a result range based on left and right ranges.
Definition: gemm_helper.h:166
btas::Tensor< T, Range, Storage >::value_type squared_norm(const btas::Tensor< T, Range, Storage > &arg)
Definition: btas.h:253
size_t size(const DistArray< Tile, Policy > &a)
Definition: utils.h:49
const size_type * upbound_data() const
Range upper bound data accessor.
Definition: range.h:570
index_type dim() const
Domain size accessor.
Definition: permutation.h:206
static void store(const Archive &ar, const btas::Tensor< _T, _Range, _Store > &t)
Definition: btas.h:418
btas::Tensor< T, Range, Storage >::value_type min(const btas::Tensor< T, Range, Storage > &arg)
btas::Tensor< T, Range, Storage >::value_type abs_max(const btas::Tensor< T, Range, Storage > &arg)
btas::Tensor< T, Range, Storage >::value_type norm(const btas::Tensor< T, Range, Storage > &arg)
static void store(const Archive &ar, const btas::RangeNd< _Order, _Index, _Ordinal > &r)
Definition: btas.h:399
#define TA_ASSERT(a)
Definition: error.h:107
btas::Tensor< T, Range, Storage > mult(const btas::Tensor< T, Range, Storage > &arg1, const btas::Tensor< T, Range, Storage > &arg2)
result[i] = arg1[i] * arg2[i]
Definition: btas.h:105
void axpy(DistArray< Tile, Policy > &y, typename DistArray< Tile, Policy >::element_type a, const DistArray< Tile, Policy > &x)
Definition: utils.h:115
auto operator()(const btas::Tensor< T, Range_, Storage > &arg) const
Definition: btas.h:310
DistArray< Tile, Policy > copy(const DistArray< Tile, Policy > &a)
Definition: utils.h:58
btas::Tensor< T, Range, Storage >::value_type sum(const btas::Tensor< T, Range, Storage > &arg)
static void store(const Archive &ar, const btas::BoxOrdinal< _Order, _Index > &o)
Definition: btas.h:377
unsigned int right_rank() const
Right-hand argument rank accessor.
Definition: gemm_helper.h:144
T dot(const integer n, const T *x, const U *y)
Definition: blas.h:203
void gemm(madness::cblas::CBLAS_TRANSPOSE op_a, madness::cblas::CBLAS_TRANSPOSE op_b, const integer m, const integer n, const integer k, const S1 alpha, const T1 *a, const integer lda, const T2 *b, const integer ldb, const S2 beta, T3 *c, const integer ldc)
Definition: blas.h:39
Contraction to *GEMM helper.
Definition: gemm_helper.h:39
Permutation of a sequence of objects indexed by base-0 indices.
Definition: permutation.h:119
const size_type * lobound_data() const
Range lower bound data accessor.
Definition: range.h:548
const TiledArray::Range & make_ta_range(const TiledArray::Range &range)
Definition: btas.h:43
void add_to(btas::Tensor< T, Range, Storage > &result, const btas::Tensor< T, Range, Storage > &arg)
result[i] += arg[i]
Definition: btas.h:98
btas::Tensor< T, Range, Storage >::value_type max(const btas::Tensor< T, Range, Storage > &arg)
madness::cblas::CBLAS_TRANSPOSE left_op() const
Definition: gemm_helper.h:273
TiledArray::Range permute(const TiledArray::Range &r, const Perm &p)
Definition: btas.h:285
#define TA_USER_ASSERT(a, m)
Definition: error.h:123
Definition: btas.h:63
btas::Tensor< T, Range, Storage >::value_type trace(const btas::Tensor< T, Range, Storage > &arg)
btas::Tensor< T, Range, Storage > & mult_to(btas::Tensor< T, Range, Storage > &result, const btas::Tensor< T, Range, Storage > &arg)
result[i] *= arg[i]
Definition: btas.h:122
const_iterator begin() const
Begin element iterator factory function.
Definition: permutation.h:211
static void load(const Archive &ar, btas::varray< T > &x)
Definition: btas.h:346
unsigned int left_rank() const
Left-hand argument rank accessor.
Definition: gemm_helper.h:139
btas::Tensor< T, Range, Storage >::value_type product(const btas::Tensor< T, Range, Storage > &arg)
bool operator==(const TiledArray::Range &range1, const btas::BaseRangeNd< Args... > &range2)
Definition: btas.h:66