TensorAsExpression.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 expressions that represent tensors
6 
7 #pragma once
8 
9 #include <array>
10 #include <cstddef>
11 
12 #include "DataStructures/Tensor/Expressions/LhsTensorSymmAndIndices.hpp"
16 #include "Utilities/Algorithm.hpp"
19 #include "Utilities/TMPL.hpp"
20 #include "Utilities/TypeTraits/IsA.hpp"
21 
22 namespace TensorExpressions {
23 /// \ingroup TensorExpressionsGroup
24 /// \brief Defines an expression representing a Tensor
25 ///
26 /// \details
27 /// In order to represent a tensor as an expression, instead of having Tensor
28 /// derive off of TensorExpression, a TensorAsExpression derives off of
29 /// TensorExpression and contains a pointer to a Tensor. The reason having
30 /// Tensor derive off of TensorExpression is problematic is that the index
31 /// structure is part of the type of the TensorExpression, so every possible
32 /// permutation and combination of indices must be derived from. For a rank 3
33 /// tensor, this is already over 500 base classes, which the Intel compiler
34 /// takes too long to compile.
35 ///
36 /// \tparam T the type of Tensor being represented as an expression
37 /// \tparam ArgsList the tensor indices, e.g. `_a` and `_b` in `F(_a, _b)`
38 template <typename T, typename ArgsList>
40 
41 template <typename X, typename Symm, template <typename...> class IndexList,
42  typename... Indices, template <typename...> class ArgsList,
43  typename... Args>
44 struct TensorAsExpression<Tensor<X, Symm, IndexList<Indices...>>,
45  ArgsList<Args...>>
46  : public TensorExpression<
47  TensorAsExpression<Tensor<X, Symm, IndexList<Indices...>>,
48  ArgsList<Args...>>,
49  X, Symm, IndexList<Indices...>, ArgsList<Args...>> {
50  using type = X;
51  using symmetry = Symm;
52  using index_list = IndexList<Indices...>;
53  static constexpr auto num_tensor_indices = tmpl::size<index_list>::value;
54  using args_list = ArgsList<Args...>;
55 
56  /// Construct an expression from a Tensor
57  explicit TensorAsExpression(const Tensor<X, Symm, IndexList<Indices...>>& t)
58  : t_(&t) {}
59  ~TensorAsExpression() override = default;
60 
61  /// \brief Computes a transformation from the LHS tensor's multi-indices to
62  /// the equivalent RHS tensor's multi-indices, according to the differences in
63  /// the orderings of their generic indices
64  ///
65  /// \details
66  /// The elements of the transformation are the positions of the RHS generic
67  /// indices in the LHS generic indices. Put another way, for some `i`,
68  /// `rhs_tensorindices[i] == lhs_tensorindices[index_transformation[i]]`.
69  ///
70  /// Here is an example of what the algorithm does:
71  ///
72  /// Tensor equation: \f$L_{cab} = R_{abc}\f$
73  /// `lhs_tensorindices`:
74  /// \code
75  /// {2, 0, 1} // i.e. {c, a, b}
76  /// \endcode
77  /// `rhs_tensorindices`:
78  /// \code
79  /// {0, 1, 2} // i.e. {a, b, c}
80  /// \endcode
81  /// returned `index_transformation`:
82  /// \code
83  /// {1, 2, 0} // positions of RHS indices {c, a, b} in LHS indices {a, b, c}
84  /// \endcode
85  ///
86  /// \param lhs_tensorindices the TensorIndexs of the LHS tensor
87  /// \return a transformation from the LHS tensor's multi-indices to the
88  /// equivalent RHS tensor's multi-indices
91  lhs_tensorindices) noexcept {
92  constexpr std::array<size_t, num_tensor_indices> rhs_tensorindices = {
93  {Args::value...}};
94  std::array<size_t, num_tensor_indices> index_transformation{};
95  for (size_t i = 0; i < num_tensor_indices; i++) {
96  gsl::at(index_transformation, i) = static_cast<size_t>(std::distance(
97  lhs_tensorindices.begin(),
98  alg::find(lhs_tensorindices, gsl::at(rhs_tensorindices, i))));
99  }
100  return index_transformation;
101  }
102 
103  /// \brief Computes the RHS tensor multi-index that is equivalent to a given
104  /// LHS tensor multi-index, according to the differences in the orderings of
105  /// their generic indices
106  ///
107  /// \details
108  /// Here is an example of what the algorithm does:
109  ///
110  /// Tensor equation: \f$L_{cab} = R_{abc}\f$
111  /// `index_transformation`:
112  /// \code
113  /// {1, 2, 0} // positions of RHS indices {c, a, b} in LHS indices {a, b, c}
114  /// \endcode
115  /// `lhs_multi_index`:
116  /// \code
117  /// {3, 4, 5} // i.e. c = 3, a = 4, b = 5
118  /// \endcode
119  /// returned equivalent `rhs_multi_index`:
120  /// \code
121  /// {4, 5, 3} // i.e. a = 4, b = 5, c = 3
122  /// \endcode
123  ///
124  /// \param lhs_multi_index the multi-index of the LHS tensor
125  /// \param index_transformation the list of the positions of the RHS indices
126  /// in the LHS indices
127  /// \return the RHS tensor multi-index that is equivalent to
128  /// `lhs_tensor_index`
131  const std::array<size_t, num_tensor_indices>& lhs_multi_index,
133  index_transformation) noexcept {
134  std::array<size_t, num_tensor_indices> rhs_multi_index{};
135  for (size_t i = 0; i < num_tensor_indices; i++) {
136  gsl::at(rhs_multi_index, i) =
137  gsl::at(lhs_multi_index, gsl::at(index_transformation, i));
138  }
139  return rhs_multi_index;
140  }
141 
142  /// \brief Returns the value of a left hand side tensor's multi-index
143  ///
144  /// \details
145  /// One big challenge with TensorExpression implementation is the reordering
146  /// of the indices on the left hand side (LHS) and right hand side (RHS) of
147  /// the expression. The algorithms implemented in
148  /// `compute_index_transformation` and `compute_rhs_multi_index` handle the
149  /// index sorting by mapping between the generic index orders of the LHS and
150  /// RHS tensors.
151  ///
152  /// \tparam LhsIndices the TensorIndexs of the Tensor on the LHS of the tensor
153  /// expression
154  /// \param lhs_multi_index the multi-index of the LHS tensor component to
155  /// retrieve
156  /// \return the value of the DataType of the component at `lhs_multi_index` in
157  /// the LHS tensor
158  template <typename... LhsIndices>
159  SPECTRE_ALWAYS_INLINE decltype(auto) get(
160  const std::array<size_t, num_tensor_indices>& lhs_multi_index)
161  const noexcept {
162  if constexpr (std::is_same_v<tmpl::list<LhsIndices...>,
163  tmpl::list<Args...>>) {
164  return t_->get(lhs_multi_index);
165  } else {
166  constexpr std::array<size_t, num_tensor_indices> index_transformation =
167  compute_index_transformation({{LhsIndices::value...}});
168  return t_->get(
169  compute_rhs_multi_index(lhs_multi_index, index_transformation));
170  }
171  }
172 
173  /// Retrieve the i'th entry of the Tensor being held
174  SPECTRE_ALWAYS_INLINE type operator[](const size_t i) const {
175  return t_->operator[](i);
176  }
177 
178  private:
179  const Tensor<X, Symm, IndexList<Indices...>>* t_ = nullptr;
180 };
181 } // namespace TensorExpressions
gsl::at
constexpr T & at(std::array< T, N > &arr, Size index)
Retrieve a entry from a container, with checks in Debug mode that the index being retrieved is valid.
Definition: Gsl.hpp:125
TensorExpressions::TensorAsExpression< Tensor< X, Symm, IndexList< Indices... > >, ArgsList< Args... > >::operator[]
type operator[](const size_t i) const
Retrieve the i'th entry of the Tensor being held.
Definition: TensorAsExpression.hpp:174
TensorExpressions::TensorAsExpression< Tensor< X, Symm, IndexList< Indices... > >, ArgsList< Args... > >::compute_index_transformation
static constexpr std::array< size_t, num_tensor_indices > compute_index_transformation(const std::array< size_t, num_tensor_indices > &lhs_tensorindices) noexcept
Computes a transformation from the LHS tensor's multi-indices to the equivalent RHS tensor's multi-in...
Definition: TensorAsExpression.hpp:90
TensorExpression.hpp
get
constexpr Tag::type & get(Variables< TagList > &v) noexcept
Return Tag::type pointing into the contiguous array.
Definition: Variables.hpp:660
Symmetry.hpp
TensorExpressions::TensorAsExpression< Tensor< X, Symm, IndexList< Indices... > >, ArgsList< Args... > >::TensorAsExpression
TensorAsExpression(const Tensor< X, Symm, IndexList< Indices... >> &t)
Construct an expression from a Tensor.
Definition: TensorAsExpression.hpp:57
TensorExpressions::TensorAsExpression
Defines an expression representing a Tensor.
Definition: TensorAsExpression.hpp:39
TensorExpressions
Definition: AddSubtract.hpp:30
SPECTRE_ALWAYS_INLINE
#define SPECTRE_ALWAYS_INLINE
Definition: ForceInline.hpp:16
cstddef
Assert.hpp
array
ForceInline.hpp
alg::find
constexpr decltype(auto) find(Container &&c, const T &value)
Convenience wrapper around constexpr reimplementation of std::find.
Definition: Algorithm.hpp:225
Tensor.hpp
TensorExpressions::TensorAsExpression< Tensor< X, Symm, IndexList< Indices... > >, ArgsList< Args... > >::compute_rhs_multi_index
static constexpr std::array< size_t, num_tensor_indices > compute_rhs_multi_index(const std::array< size_t, num_tensor_indices > &lhs_multi_index, const std::array< size_t, num_tensor_indices > &index_transformation) noexcept
Computes the RHS tensor multi-index that is equivalent to a given LHS tensor multi-index,...
Definition: TensorAsExpression.hpp:130
TMPL.hpp