AddSubtract.hpp
Go to the documentation of this file.
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 /// \file
5 /// Defines ET for adding and subtracting tensors
6 
7 #pragma once
8 
9 #include <algorithm>
10 #include <array>
11 #include <cstddef>
12 
14 #include "Utilities/Requires.hpp"
15 #include "Utilities/TMPL.hpp"
16 #include "Utilities/TypeTraits.hpp"
17 /// \cond
18 namespace TensorExpressions {
19 template <typename T1, typename T2, typename ArgsList1, typename ArgsList2,
20  int Sign>
21 struct AddSub;
22 } // namespace TensorExpressions
23 template <typename Derived, typename DataType, typename Symm,
24  typename IndexList, typename Args, typename ReducedArgs>
25 struct TensorExpression;
26 /// \endcond
27 
28 namespace TensorExpressions {
29 
30 namespace detail {
31 template <typename IndexList1, typename IndexList2, typename Args1,
32  typename Args2, typename Element>
33 struct AddSubIndexCheckHelper
34  : std::is_same<tmpl::at<IndexList1, tmpl::index_of<Args1, Element>>,
35  tmpl::at<IndexList2, tmpl::index_of<Args2, Element>>>::type {
36 };
37 
38 // Check to make sure that the tensor indices being added are of the same type,
39 // dimensionality and in the same frame
40 template <typename IndexList1, typename IndexList2, typename Args1,
41  typename Args2>
42 using AddSubIndexCheck = tmpl::fold<
43  Args1, tmpl::bool_<true>,
44  tmpl::and_<tmpl::_state,
45  AddSubIndexCheckHelper<tmpl::pin<IndexList1>,
46  tmpl::pin<IndexList2>, tmpl::pin<Args1>,
47  tmpl::pin<Args2>, tmpl::_element>>>;
48 } // namespace detail
49 
50 template <typename T1, typename T2, typename ArgsList1, typename ArgsList2,
51  int Sign>
52 struct AddSub;
53 
54 template <typename T1, typename T2, template <typename...> class ArgsList1,
55  template <typename...> class ArgsList2, typename... Args1,
56  typename... Args2, int Sign>
57 struct AddSub<T1, T2, ArgsList1<Args1...>, ArgsList2<Args2...>, Sign>
58  : public TensorExpression<
59  AddSub<T1, T2, ArgsList1<Args1...>, ArgsList2<Args2...>, Sign>,
60  typename T1::type,
61  tmpl::transform<typename T1::symmetry, typename T2::symmetry,
62  tmpl::append<tmpl::max<tmpl::_1, tmpl::_2>>>,
63  typename T1::index_list, tmpl::sort<typename T1::args_list>>,
64  public Expression {
66  "Cannot add or subtract Tensors holding different data types.");
67  static_assert(
68  detail::AddSubIndexCheck<typename T1::index_list, typename T2::index_list,
69  ArgsList1<Args1...>, ArgsList2<Args2...>>::value,
70  "You are attempting to add indices of different types, e.g. T^a_b + "
71  "S^b_a, which doesn't make sense. The indices may also be in different "
72  "frames, different types (spatial vs. spacetime) or of different "
73  "dimension.");
74 
75  using type = typename T1::type;
76  using symmetry = tmpl::transform<typename T1::symmetry, typename T2::symmetry,
77  tmpl::append<tmpl::max<tmpl::_1, tmpl::_2>>>;
78  using index_list = typename T1::index_list;
79  static constexpr auto num_tensor_indices =
80  tmpl::size<index_list>::value == 0 ? 1 : tmpl::size<index_list>::value;
81  using args_list = tmpl::sort<typename T1::args_list>;
82 
83  AddSub(T1 t1, T2 t2) : t1_(std::move(t1)), t2_(std::move(t2)) {}
84 
85  template <typename... LhsIndices, typename T, int U = Sign,
86  Requires<U == 1> = nullptr>
88  get(const std::array<T, num_tensor_indices>& tensor_index) const {
89  return t1_.template get<LhsIndices...>(tensor_index) +
90  t2_.template get<LhsIndices...>(tensor_index);
91  }
92 
93  template <typename... LhsIndices, typename T, int U = Sign,
94  Requires<U == -1> = nullptr>
96  get(const std::array<T, num_tensor_indices>& tensor_index) const {
97  return t1_.template get<LhsIndices...>(tensor_index) -
98  t2_.template get<LhsIndices...>(tensor_index);
99  }
100 
101  template <int U = Sign, Requires<U == 1> = nullptr>
102  SPECTRE_ALWAYS_INLINE typename T1::type operator[](size_t i) const {
103  return t1_[i] + t2_[i];
104  }
105 
106  template <int U = Sign, Requires<U == -1> = nullptr>
107  SPECTRE_ALWAYS_INLINE typename T1::type operator[](size_t i) const {
108  return t1_[i] - t2_[i];
109  }
110 
111  private:
112  const T1 t1_;
113  const T2 t2_;
114 };
115 } // namespace TensorExpressions
116 
117 /*!
118  * \ingroup TensorExpressionsGroup
119  */
120 template <typename T1, typename T2, typename X, typename Symm1, typename Symm2,
121  typename IndexList1, typename IndexList2, typename Args1,
122  typename Args2>
123 SPECTRE_ALWAYS_INLINE auto operator+(
124  const TensorExpression<T1, X, Symm1, IndexList1, Args1>& t1,
125  const TensorExpression<T2, X, Symm2, IndexList2, Args2>& t2) {
126  static_assert(tmpl::size<Args1>::value == tmpl::size<Args2>::value,
127  "Tensor addition is only possible with the same rank tensors");
128  static_assert(tmpl::equal_members<Args1, Args2>::value,
129  "The indices when adding two tensors must be equal. This error "
130  "occurs from expressions like A(_a, _b) + B(_c, _a)");
132  tmpl::conditional_t<std::is_base_of<Expression, T1>::value, T1,
133  TensorExpression<T1, X, Symm1, IndexList1, Args1>>,
134  tmpl::conditional_t<std::is_base_of<Expression, T2>::value, T2,
135  TensorExpression<T2, X, Symm2, IndexList2, Args2>>,
136  Args1, Args2, 1>(~t1, ~t2);
137 }
138 
139 /*!
140  * \ingroup TensorExpressionsGroup
141  */
142 template <typename T1, typename T2, typename X, typename Symm1, typename Symm2,
143  typename IndexList1, typename IndexList2, typename Args1,
144  typename Args2>
145 SPECTRE_ALWAYS_INLINE auto operator-(
146  const TensorExpression<T1, X, Symm1, IndexList1, Args1>& t1,
147  const TensorExpression<T2, X, Symm2, IndexList2, Args2>& t2) {
148  static_assert(tmpl::size<Args1>::value == tmpl::size<Args2>::value,
149  "Tensor addition is only possible with the same rank tensors");
150  static_assert(tmpl::equal_members<Args1, Args2>::value,
151  "The indices when adding two tensors must be equal. This error "
152  "occurs from expressions like A(_a, _b) - B(_c, _a)");
154  tmpl::conditional_t<std::is_base_of<Expression, T1>::value, T1,
155  TensorExpression<T1, X, Symm1, IndexList1, Args1>>,
156  tmpl::conditional_t<std::is_base_of<Expression, T2>::value, T2,
157  TensorExpression<T2, X, Symm2, IndexList2, Args2>>,
158  Args1, Args2, -1>(~t1, ~t2);
159 }
Marks a class as being a TensorExpression.
Definition: TensorExpression.hpp:271
Defines the type alias Requires.
Definition: Determinant.hpp:11
#define SPECTRE_ALWAYS_INLINE
Always inline a function. Only use this if you benchmarked the code.
Definition: ForceInline.hpp:20
Defines class.
Definition: AddSubtract.hpp:28
A spectral element with knowledge of its neighbors.
Definition: Element.hpp:29
Definition: AddSubtract.hpp:52
Wraps the template metaprogramming library used (brigand)
typename Requires_detail::requires_impl< B >::template_error_type_failed_to_meet_requirements_on_template_parameters Requires
Express requirements on the template parameters of a function or class, replaces std::enable_if_t ...
Definition: Requires.hpp:67
Defines type traits, some of which are future STL type_traits header.