TensorExpression.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 class
6 
7 #pragma once
8 
9 #include <array>
10 #include <cstddef>
11 
12 #include "ErrorHandling/Assert.hpp" // IWYU pragma: keep
13 #include "Utilities/Requires.hpp"
14 #include "Utilities/TMPL.hpp"
15 #include "Utilities/TypeTraits.hpp"
16 
17 /*!
18  * \ingroup TensorExpressionsGroup
19  * \brief Represents the indices in a TensorExpression
20  *
21  * \details
22  * Used to denote a tensor index in a tensor slot. This allows the following
23  * type of expressions to work:
24  * \code{.cpp}
25  * auto T = evaluate<ti_a_t, ti_b_t>(F(ti_a, ti_b) + S(ti_b, ti_a));
26  * \endcode
27  * where `using ti_a_t = TensorIndex<0>;` and `TensorIndex<0> ti_a;`, that is,
28  * `ti_a` and `ti_b` are place holders for objects of type `TensorIndex<0>` and
29  * `TensorIndex<1>` respectively.
30  */
31 template <std::size_t I>
32 struct TensorIndex {
33  using value_type = std::size_t;
34  using type = TensorIndex<I>;
35  static constexpr value_type value = I;
36 };
37 
38 /// \ingroup TensorExpressionsGroup
39 /// Given an `TensorIndex<size_t>` return `TensorIndex<size_t + 1>`
40 /// \tparam T the args to increment
41 template <typename T>
43 
44 /// \ingroup TensorExpressionsGroup
45 /// Metafunction to return the sum of two TensorIndex's
46 template <typename A, typename B>
48 
49 // @{
50 /*!
51  * \ingroup TensorExpressionsGroup
52  * \brief The available TensorIndex's to use in a TensorExpression
53  *
54  * Available tensor indices to use in a Tensor Expression.
55  * \snippet Test_TensorExpressions.cpp use_tensor_index
56  *
57  * \note Because these are never actually used as objects and only for type
58  * manipulation they do not need to be instantiated anywhere.
59  */
60 extern TensorIndex<0> ti_a;
61 extern TensorIndex<0> ti_A;
62 extern TensorIndex<1> ti_b;
63 extern TensorIndex<1> ti_B;
64 extern TensorIndex<2> ti_c;
65 extern TensorIndex<2> ti_C;
66 extern TensorIndex<3> ti_d;
67 extern TensorIndex<3> ti_D;
68 extern TensorIndex<4> ti_e;
69 extern TensorIndex<4> ti_E;
70 extern TensorIndex<5> ti_f;
71 extern TensorIndex<5> ti_F;
72 extern TensorIndex<6> ti_g;
73 extern TensorIndex<6> ti_G;
74 extern TensorIndex<7> ti_h;
75 extern TensorIndex<7> ti_H;
76 extern TensorIndex<8> ti_i;
77 extern TensorIndex<8> ti_I;
78 extern TensorIndex<9> ti_j;
79 extern TensorIndex<9> ti_J;
80 
81 using ti_a_t = decltype(ti_a);
82 using ti_A_t = decltype(ti_A);
83 using ti_b_t = decltype(ti_b);
84 using ti_B_t = decltype(ti_B);
85 using ti_c_t = decltype(ti_c);
86 using ti_C_t = decltype(ti_C);
87 using ti_d_t = decltype(ti_d);
88 using ti_D_t = decltype(ti_D);
89 using ti_e_t = decltype(ti_e);
90 using ti_E_t = decltype(ti_E);
91 using ti_f_t = decltype(ti_f);
92 using ti_F_t = decltype(ti_F);
93 using ti_g_t = decltype(ti_g);
94 using ti_G_t = decltype(ti_G);
95 using ti_h_t = decltype(ti_h);
96 using ti_H_t = decltype(ti_H);
97 using ti_i_t = decltype(ti_i);
98 using ti_I_t = decltype(ti_I);
99 using ti_j_t = decltype(ti_j);
100 using ti_J_t = decltype(ti_J);
101 // @}
102 
103 /// \cond HIDDEN_SYMBOLS
104 /// \ingroup TensorExpressionsGroup
105 /// Type alias used when Tensor Expressions manipulate indices. These are used
106 /// to denote contracted as opposed to free indices.
107 template <int I>
108 using ti_contracted_t = TensorIndex<static_cast<size_t>(I + 1000)>;
109 
110 /// \ingroup TensorExpressionsGroup
111 template <int I>
112 TensorIndex<static_cast<size_t>(I + 1000)> ti_contracted();
113 /// \endcond
114 
115 namespace tt {
116 /*!
117  * \ingroup TypeTraitsGroup TensorExpressions
118  * \brief Check if a type `T` is a TensorIndex used in TensorExpressions
119  */
120 template <typename T>
122 template <size_t I>
124 } // namespace tt
125 
126 namespace detail {
127 template <typename State, typename Element, typename LHS>
128 struct rhs_elements_in_lhs_helper {
130  tmpl::no_such_type_>::value,
131  tmpl::push_back<State, Element>, State>;
132 };
133 } // namespace detail
134 
135 /// \ingroup TensorExpressionsGroup
136 /// Returns a list of all the elements in the typelist Rhs that are also in the
137 /// typelist Lhs.
138 ///
139 /// \details
140 /// Given two typelists `Lhs` and `Rhs`, returns a typelist of all the elements
141 /// in `Rhs` that are also in `Lhs` in the same order that they are in the
142 /// `Rhs`.
143 ///
144 /// ### Usage
145 /// For typelists `List1` and `List2`,
146 /// \code{.cpp}
147 /// using result = rhs_elements_in_lhs<List1, List2>;
148 /// \endcode
149 /// \metareturns
150 /// typelist
151 ///
152 /// \semantics
153 /// If `Lhs = tmpl::list<A, B, C, D>` and `Rhs = tmpl::list<B, E, A>`, then
154 /// \code{.cpp}
155 /// result = tmpl::list<B, A>;
156 /// \endcode
157 template <typename Lhs, typename Rhs>
158 using rhs_elements_in_lhs =
159  tmpl::fold<Rhs, tmpl::list<>,
160  detail::rhs_elements_in_lhs_helper<tmpl::_state, tmpl::_element,
161  tmpl::pin<Lhs>>>;
162 
163 namespace detail {
164 template <typename Element, typename Iteration, typename Lhs, typename Rhs,
165  typename RhsWithOnlyLhs, typename IndexInLhs>
166 struct generate_transformation_helper {
167  using tensor_index_to_find = tmpl::at<RhsWithOnlyLhs, IndexInLhs>;
168  using index_to_replace_with = tmpl::index_of<Rhs, tensor_index_to_find>;
170 };
171 
172 template <typename Element, typename Iteration, typename Lhs, typename Rhs,
173  typename RhsWithOnlyLhs>
174 struct generate_transformation_helper<Element, Iteration, Lhs, Rhs,
175  RhsWithOnlyLhs, tmpl::no_such_type_> {
176  using type = TensorIndex<Iteration::value>;
177 };
178 
179 template <typename State, typename Element, typename Iteration, typename Lhs,
180  typename Rhs, typename RhsWithOnlyLhs>
181 struct generate_transformation_impl {
182  using index_in_lhs = tmpl::index_of<Lhs, Element>;
183  using type = tmpl::push_back<State, typename generate_transformation_helper<
184  Element, Iteration, Lhs, Rhs,
185  RhsWithOnlyLhs, index_in_lhs>::type>;
186 };
187 } // namespace detail
188 
189 /// \ingroup TensorExpressionsGroup
190 /// \brief Generate transformation to account for index order difference in RHS
191 /// and LHS.
192 ///
193 /// \details
194 /// Generates the transformation \f$\mathcal{T}\f$ that rearranges the Tensor
195 /// index array to account for index order differences between the LHS and RHS
196 /// of the tensor expression.
197 ///
198 /// ### Usage
199 /// For typelists `Rhs`, `Lhs` and `RhsOnyWithLhs`, where `RhsOnlyWithLhs` is
200 /// the result of the metafunction rhs_elements_in_lhs,
201 /// \code{.cpp}
202 /// using result = generate_transformation<Rhs, Lhs, RhsOnlyWithLhs>;
203 /// \endcode
204 /// \metareturns
205 /// typelist
206 template <typename Rhs, typename Lhs, typename RhsOnyWithLhs>
207 using generate_transformation = tmpl::enumerated_fold<
208  Rhs, tmpl::list<>,
209  detail::generate_transformation_impl<tmpl::_state, tmpl::_element, tmpl::_3,
210  tmpl::pin<Lhs>, tmpl::pin<Rhs>,
211  tmpl::pin<RhsOnyWithLhs>>>;
212 
213 namespace detail {
214 template <typename Seq, typename S, typename E>
215 struct repeated_helper {
216  using type = typename std::conditional<
218  tmpl::size_t<2>>::value and
219  std::is_same<tmpl::index_of<S, E>, tmpl::no_such_type_>::value,
220  tmpl::push_back<S, E>, S>::type;
221 };
222 } // namespace detail
223 
224 /*!
225  * \ingroup TensorExpressionsGroup
226  * Returns a list of all the types that occurred more than once in List.
227  */
228 template <typename List>
229 using repeated = tmpl::fold<
230  List, tmpl::list<>,
231  detail::repeated_helper<tmpl::pin<List>, tmpl::_state, tmpl::_element>>;
232 
233 namespace detail {
234 template <typename List, typename Element, typename R>
235 using index_replace = tmpl::replace_at<
236  tmpl::replace_at<List, tmpl::index_of<List, Element>, R>,
237  tmpl::index_of<tmpl::replace_at<List, tmpl::index_of<List, Element>, R>,
238  Element>,
240 
241 /// \cond HIDDEN_SYMBOLS
242 template <typename List, typename ReplaceList, int I>
243 struct replace_indices_impl
244  : replace_indices_impl<
245  index_replace<List, tmpl::front<ReplaceList>, ti_contracted_t<2 * I>>,
246  tmpl::pop_front<ReplaceList>, I + 1> {};
247 /// \endcond
248 
249 template <typename List, int I>
250 struct replace_indices_impl<List, tmpl::list<>, I> {
251  using type = List;
252 };
253 } // namespace detail
254 
255 /*!
256  * \ingroup TensorExpressionsGroup
257  */
258 template <typename List, typename ReplaceList>
259 using replace_indices =
260  typename detail::replace_indices_impl<List, ReplaceList, 0>::type;
261 
262 /// \ingroup TensorExpressionsGroup
263 /// \brief Marks a class as being a TensorExpression
264 ///
265 /// \details
266 /// The empty base class that all TensorExpression`s must inherit from.
267 /// \derivedrequires
268 /// 1) The args_list will be the sorted args_list received as input
269 ///
270 /// 2) The tensor indices will be swapped to conform with mathematical notation
271 struct Expression {};
272 
273 /// \cond
274 template <typename DataType, typename Symm, typename IndexList>
275 class Tensor;
276 /// \endcond
277 
278 // @{
279 /// \ingroup TensorExpressionsGroup
280 /// \brief The base class all tensor expression implementations derive from
281 ///
282 /// \tparam Derived the derived class needed for
283 /// [CRTP](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)
284 /// \tparam DataType the type of the data being stored in the Tensor's
285 /// \tparam Symm the ::Symmetry of the Derived class
286 /// \tparam IndexList the list of \ref SpacetimeIndex "TensorIndex"'s
287 /// \tparam Args the tensor indices, e.g. `_a` and `_b` in `F(_a, _b)`
288 /// \cond HIDDEN_SYMBOLS
289 template <typename Derived, typename DataType, typename Symm,
290  typename IndexList, typename Args = tmpl::list<>,
291  typename ReducedArgs = tmpl::list<>>
292 struct TensorExpression;
293 /// \endcond
294 
295 template <typename Derived, typename DataType, typename Symm,
296  typename IndexList, template <typename...> class ArgsList,
297  typename... Args>
298 struct TensorExpression<Derived, DataType, Symm, IndexList, ArgsList<Args...>> {
299  static_assert(sizeof...(Args) == 0 or
300  sizeof...(Args) == tmpl::size<IndexList>::value,
301  "the number of Tensor indices must match the number of "
302  "components specified in an expression.");
303  using type = DataType;
304  using symmetry = Symm;
305  using index_list = IndexList;
306  static constexpr auto num_tensor_indices =
307  tmpl::size<index_list>::value == 0 ? 1 : tmpl::size<index_list>::value;
308  /// Typelist of the tensor indices, e.g. `_a_t` and `_b_t` in `F(_a, _b)`
309  using args_list = ArgsList<Args...>;
310 
311  // @{
312  /// Cast down to the derived class. This is enabled by the
313  /// [CRTP](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)
314  template <typename V = Derived,
316  SPECTRE_ALWAYS_INLINE const Derived& operator~() const {
317  return static_cast<const Derived&>(*this);
318  }
319  // @}
320  // @{
321  /// If the Derived class is a Tensor return a const reference to a
322  /// TensorExpression.
323  ///
324  /// Since Tensor is not derived from TensorExpression (because of
325  /// complications arising from the indices being part of the expression,
326  /// specifically Tensor may need to derive off of hundreds or thousands of
327  /// base classes, which is not feasible), return a reference to a
328  /// TensorExpression, which has a sufficient interface to evaluate the
329  /// expression.
330  /// \returns const TensorExpression<Derived, DataType, Symm, IndexList,
331  /// ArgsList<Args...>>&
332  template <typename V = Derived,
335  return static_cast<const TensorExpression<Derived, DataType, Symm,
336  IndexList, ArgsList<Args...>>&>(
337  *this);
338  }
339  // @}
340 
341  // @{
342  /// \cond HIDDEN_SYMBOLS
343  /// \ingroup TensorExpressionsGroup
344  /// Helper struct to compute the correct tensor index array from a
345  /// typelist of std::integral_constant's indicating the ordering. This is
346  /// needed for dealing with expressions such as \f$T_{ab} = F_{ba}\f$ and gets
347  /// the ordering on the RHS to be correct compared with where the indices are
348  /// on the LHS.
349  template <typename U>
350  struct ComputeCorrectTensorIndex;
351 
352  template <template <typename...> class RedArgsList, typename... RedArgs>
353  struct ComputeCorrectTensorIndex<RedArgsList<RedArgs...>> {
354  template <typename U, std::size_t Size>
356  const std::array<U, Size>& tensor_index) {
357  return std::array<U, Size>{{tensor_index[RedArgs::value]...}};
358  }
359  };
360  /// \endcond
361  // @}
362 
363  /// \brief return the value of type DataType with tensor index `tensor_index`
364  ///
365  /// \details
366  /// _Note:_ This version is selected if Derived is a Tensor
367  ///
368  /// One big challenge with a general Tensor Expression implementation is the
369  /// ordering of the Indices on the RHS and LHS of the expression. This
370  /// algorithm implemented in ::rhs_elements_in_lhs and
371  /// ::generate_transformation handles the index sorting.
372  ///
373  /// Here are some examples of what the algorithm does:
374  ///
375  /// LhsIndices is the desired ordering.
376  ///
377  /// LHS:
378  /// \code
379  /// <0, 1>
380  /// \endcode
381  /// RHS:
382  /// \code
383  /// <1, 2, 3, 0> -Transform> <3, 1, 2, 0>
384  /// \endcode
385  ///
386  /// LHS:
387  /// \code
388  /// <0, 1, 2> <a, b, c>
389  /// \endcode
390  /// RHS:
391  /// \code
392  /// <2, 0, 1> -Transform> <2 , 1, 0>
393  /// \endcode
394  ///
395  /// Below is pseudo-code of the algorithm written in a non-functional way
396  /// \verbatim
397  /// for Element in RHS:
398  /// if (Element in LHS):
399  /// index_in_LHS = index_of<LHS, Element>
400  /// tensor_index_to_find = at<RHS_with_only_LHS, index_in_LHS>
401  /// index_to_replace_with = index_of<RHS, tensor_index_to_find>
402  /// T_RHS = push_back<T_RHS, index_to_replace_with>
403  /// else:
404  /// T_RHS = push_back<T_RHS, iteration>
405  /// endif
406  /// end for
407  /// \endverbatim
408  ///
409  /// \tparam LhsIndices the tensor indices on the LHS on the expression
410  /// \tparam V used for SFINAE
411  /// \param tensor_index the tensor component to retrieve
412  /// \return the value of the DataType of component `tensor_index`
413  template <typename... LhsIndices, typename ArrayValueType,
414  typename V = Derived,
415  Requires<tt::is_a<Tensor, V>::value> = nullptr>
418  const {
419  ASSERT(t_ != nullptr,
420  "A TensorExpression that should be holding a pointer to a Tensor "
421  "is holding a nullptr.");
422  using rhs = args_list;
423  // To deal with Tensor products we need the ordering of only the subset of
424  // tensor indices present in this term
425  using lhs = rhs_elements_in_lhs<rhs, tmpl::list<LhsIndices...>>;
426  using rhs_only_with_lhs = rhs_elements_in_lhs<lhs, rhs>;
428  return t_->get(
430  }
431 
432  /// \brief return the value of type DataType with tensor index `tensor_index`
433  ///
434  /// \details
435  /// _Note:_ This version is selected if Derived is a TensorExpression
436  ///
437  /// Forward the tensor_index onwards to the next TensorExpression
438  ///
439  /// \tparam LhsIndices the tensor indices on the LHS on the expression
440  /// \tparam V used for SFINAE
441  /// \param tensor_index the tensor component to retrieve
442  /// \return the value of the DataType of component `tensor_index`
443  template <typename... LhsIndices, typename ArrayValueType,
444  typename V = Derived,
445  Requires<not tt::is_a<Tensor, V>::value> = nullptr>
448  const {
449  ASSERT(t_ == nullptr,
450  "A TensorExpression that shouldn't be holding a pointer to a "
451  "Tensor is holding one.");
452  return static_cast<const Derived&>(*this).template get<LhsIndices...>(
453  tensor_index);
454  }
455 
456  /// Retrieve the i'th entry of the Tensor being held
457  template <typename V = Derived,
458  Requires<tt::is_a<Tensor, V>::value> = nullptr>
459  SPECTRE_ALWAYS_INLINE type operator[](const size_t i) const {
460  return t_->operator[](i);
461  }
462 
463  /// \brief Construct a TensorExpression from another TensorExpression.
464  ///
465  /// In this case we do not need to store a pointer to the TensorExpression
466  /// since we can cast back to the derived class using operator~.
467  template <typename V = Derived,
468  Requires<not tt::is_a<Tensor, V>::value> = nullptr>
469  TensorExpression() {} // NOLINT
470 
471  /// \brief Construct a TensorExpression from a Tensor.
472  ///
473  /// We need to store a pointer to the Tensor in a member variable in order
474  /// to be able to access the data when later evaluating the tensor expression.
475  explicit TensorExpression(const Tensor<DataType, Symm, IndexList>& t)
476  : t_(&t) {}
477 
478  private:
479  /// Holds a pointer to a Tensor if the TensorExpression represents one.
480  ///
481  /// The pointer is needed so that the Tensor class need not derive from
482  /// TensorExpression. The reason deriving off of TensorExpression is
483  /// problematic for Tensor is that the index structure is part of the type
484  /// of the TensorExpression, so every possible permutation and combination of
485  /// indices must be derived from. For a rank-3 tensor this is already over 500
486  /// base classes, which the Intel compiler takes too long to compile.
487  ///
488  /// Benchmarking shows that GCC 6 and Clang 3.9.0 can derive off of 672 base
489  /// classes with compilation time of about 5 seconds, while the Intel compiler
490  /// v16.3 takes around 8 minutes. These tests were done on a Haswell Core i5.
491  const Derived* t_ = nullptr;
492 };
493 // @}
TensorIndex< 6 > ti_g
The available TensorIndex&#39;s to use in a TensorExpression.
TensorIndex< 4 > ti_E
The available TensorIndex&#39;s to use in a TensorExpression.
TensorIndex< 7 > ti_h
The available TensorIndex&#39;s to use in a TensorExpression.
decltype(ti_e) ti_e_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:89
TensorIndex< 7 > ti_H
The available TensorIndex&#39;s to use in a TensorExpression.
tmpl::enumerated_fold< Rhs, tmpl::list<>, detail::generate_transformation_impl< tmpl::_state, tmpl::_element, tmpl::_3, tmpl::pin< Lhs >, tmpl::pin< Rhs >, tmpl::pin< RhsOnyWithLhs > >> generate_transformation
Generate transformation to account for index order difference in RHS and LHS.
Definition: TensorExpression.hpp:211
Check if a type T is a TensorIndex used in TensorExpressions.
Definition: TensorExpression.hpp:121
TensorIndex< 5 > ti_f
The available TensorIndex&#39;s to use in a TensorExpression.
decltype(ti_G) ti_G_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:94
auto operator~() const
If the Derived class is a Tensor return a const reference to a TensorExpression.
Definition: TensorExpression.hpp:334
decltype(ti_a) ti_a_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:81
Marks a class as being a TensorExpression.
Definition: TensorExpression.hpp:271
TensorIndex< 2 > ti_C
The available TensorIndex&#39;s to use in a TensorExpression.
decltype(ti_A) ti_A_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:82
#define ASSERT(a, m)
Assert that an expression should be true.
Definition: Assert.hpp:49
TensorIndex< 9 > ti_J
The available TensorIndex&#39;s to use in a TensorExpression.
decltype(ti_F) ti_F_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:92
TensorIndex< 0 > ti_A
The available TensorIndex&#39;s to use in a TensorExpression.
Defines the type alias Requires.
constexpr auto apply(F &&f, const DataBox< BoxTags > &box, Args &&... args)
Apply the function f with argument Tags TagsList from DataBox box
Definition: DataBox.hpp:1595
TensorIndex< 1 > ti_b
The available TensorIndex&#39;s to use in a TensorExpression.
ArgsList< Args... > args_list
Typelist of the tensor indices, e.g. _a_t and _b_t in F(_a, _b)
Definition: TensorExpression.hpp:309
TensorIndex< 8 > ti_i
The available TensorIndex&#39;s to use in a TensorExpression.
decltype(ti_H) ti_H_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:96
decltype(ti_c) ti_c_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:85
tmpl::fold< List, tmpl::list<>, detail::repeated_helper< tmpl::pin< List >, tmpl::_state, tmpl::_element > > repeated
Definition: TensorExpression.hpp:231
TensorIndex< 6 > ti_G
The available TensorIndex&#39;s to use in a TensorExpression.
A collection of useful type traits.
Definition: TensorExpression.hpp:115
decltype(ti_i) ti_i_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:97
tmpl::fold< Rhs, tmpl::list<>, detail::rhs_elements_in_lhs_helper< tmpl::_state, tmpl::_element, tmpl::pin< Lhs > >> rhs_elements_in_lhs
Returns a list of all the elements in the typelist Rhs that are also in the typelist Lhs...
Definition: TensorExpression.hpp:161
decltype(ti_E) ti_E_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:90
Definition: Determinant.hpp:11
decltype(ti_I) ti_I_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:98
TensorIndex< 3 > ti_D
The available TensorIndex&#39;s to use in a TensorExpression.
#define SPECTRE_ALWAYS_INLINE
Always inline a function. Only use this if you benchmarked the code.
Definition: ForceInline.hpp:20
TensorIndex< 5 > ti_F
The available TensorIndex&#39;s to use in a TensorExpression.
TensorIndex< 2 > ti_c
The available TensorIndex&#39;s to use in a TensorExpression.
TensorIndex< 4 > ti_e
The available TensorIndex&#39;s to use in a TensorExpression.
A spectral element with knowledge of its neighbors.
Definition: Element.hpp:29
TensorIndex< 8 > ti_I
The available TensorIndex&#39;s to use in a TensorExpression.
TensorExpression()
Construct a TensorExpression from another TensorExpression.
Definition: TensorExpression.hpp:469
decltype(ti_J) ti_J_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:100
decltype(ti_C) ti_C_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:86
decltype(ti_d) ti_d_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:87
Defines macro ASSERT.
TensorIndex< 9 > ti_j
The available TensorIndex&#39;s to use in a TensorExpression.
decltype(ti_g) ti_g_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:93
type operator[](const size_t i) const
Retrieve the i&#39;th entry of the Tensor being held.
Definition: TensorExpression.hpp:459
decltype(ti_h) ti_h_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:95
Wraps the template metaprogramming library used (brigand)
decltype(ti_f) ti_f_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:91
decltype(ti_j) ti_j_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:99
decltype(ti_B) ti_B_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:84
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
decltype(ti_b) ti_b_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:83
decltype(ti_D) ti_D_t
The available TensorIndex&#39;s to use in a TensorExpression.
Definition: TensorExpression.hpp:88
TensorIndex< 0 > ti_a
The available TensorIndex&#39;s to use in a TensorExpression.
Defines type traits, some of which are future STL type_traits header.
const Derived & operator~() const
Cast down to the derived class. This is enabled by the CRTP
Definition: TensorExpression.hpp:316
TensorIndex< 1 > ti_B
The available TensorIndex&#39;s to use in a TensorExpression.
TensorExpression(const Tensor< DataType, Symm, IndexList > &t)
Construct a TensorExpression from a Tensor.
Definition: TensorExpression.hpp:475
Represents the indices in a TensorExpression.
Definition: TensorExpression.hpp:32
TensorIndex< 3 > ti_d
The available TensorIndex&#39;s to use in a TensorExpression.