EvaluateRank3TestHelpers.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <cstddef>
7 #include <iterator>
8 #include <numeric>
9 
13 #include "Utilities/GenerateInstantiations.hpp"
14 #include "Utilities/Literals.hpp"
15 #include "Utilities/TMPL.hpp"
16 
17 namespace TestHelpers::TensorExpressions {
18 
19 /// \ingroup TestingFrameworkGroup
20 /// \brief Test that evaluating a right hand side tensor expression containing a
21 /// single rank 3 tensor correctly assigns the data to the evaluated left hand
22 /// side tensor
23 ///
24 /// \details `TensorIndexA`, `TensorIndexB`, and `TensorIndexC` can be any type
25 /// of TensorIndex and are not necessarily `ti_a`, `ti_b`, and `ti_c`. The
26 /// "A", "B", and "C" suffixes just denote the ordering of the generic indices
27 /// of the RHS tensor expression. In the RHS tensor expression, it means
28 /// `TensorIndexA` is the first index used, `TensorIndexB` is the second index
29 /// used, and `TensorIndexC` is the third index used.
30 ///
31 /// If we consider the RHS tensor's generic indices to be (a, b, c), then this
32 /// test checks that the data in the evaluated LHS tensor is correct according
33 /// to the index orders of the LHS and RHS. The possible cases that are checked
34 /// are when the LHS tensor is evaluated with index orders: (a, b, c),
35 /// (a, c, b), (b, a, c), (b, c, a), (c, a, b), and (c, b, a).
36 ///
37 /// \tparam DataType the type of data being stored in the Tensors
38 /// \tparam RhsSymmetry the ::Symmetry of the RHS Tensor
39 /// \tparam RhsTensorIndexTypeList the RHS Tensor's typelist of
40 /// \ref SpacetimeIndex "TensorIndexType"s
41 /// \tparam TensorIndexA the first TensorIndex used on the RHS of the
42 /// TensorExpression, e.g. `ti_a`
43 /// \tparam TensorIndexB the second TensorIndex used on the RHS of the
44 /// TensorExpression, e.g. `ti_B`
45 /// \tparam TensorIndexC the third TensorIndex used on the RHS of the
46 /// TensorExpression, e.g. `ti_c`
47 template <typename DataType, typename RhsSymmetry,
48  typename RhsTensorIndexTypeList, auto& TensorIndexA,
49  auto& TensorIndexB, auto& TensorIndexC>
50 void test_evaluate_rank_3_impl() noexcept {
51  Tensor<DataType, RhsSymmetry, RhsTensorIndexTypeList> R_abc(5_st);
52  std::iota(R_abc.begin(), R_abc.end(), 0.0);
53 
54  // Used for enforcing the ordering of the symmetry and TensorIndexTypes of the
55  // LHS Tensor returned by `evaluate`
56  const std::int32_t rhs_symmetry_element_a = tmpl::at_c<RhsSymmetry, 0>::value;
57  const std::int32_t rhs_symmetry_element_b = tmpl::at_c<RhsSymmetry, 1>::value;
58  const std::int32_t rhs_symmetry_element_c = tmpl::at_c<RhsSymmetry, 2>::value;
59  using rhs_tensorindextype_a = tmpl::at_c<RhsTensorIndexTypeList, 0>;
60  using rhs_tensorindextype_b = tmpl::at_c<RhsTensorIndexTypeList, 1>;
61  using rhs_tensorindextype_c = tmpl::at_c<RhsTensorIndexTypeList, 2>;
62 
63  // L_{abc} = R_{abc}
64  // Use explicit type (vs auto) so the compiler checks the return type of
65  // `evaluate`
66  const Tensor<DataType, RhsSymmetry, RhsTensorIndexTypeList> L_abc =
67  ::TensorExpressions::evaluate<TensorIndexA, TensorIndexB, TensorIndexC>(
68  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
69 
70  // L_{acb} = R_{abc}
71  using L_acb_symmetry =
72  Symmetry<rhs_symmetry_element_a, rhs_symmetry_element_c,
73  rhs_symmetry_element_b>;
74  using L_acb_tensorindextype_list =
75  tmpl::list<rhs_tensorindextype_a, rhs_tensorindextype_c,
76  rhs_tensorindextype_b>;
77  const Tensor<DataType, L_acb_symmetry, L_acb_tensorindextype_list> L_acb =
78  ::TensorExpressions::evaluate<TensorIndexA, TensorIndexC, TensorIndexB>(
79  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
80 
81  // L_{bac} = R_{abc}
82  using L_bac_symmetry =
83  Symmetry<rhs_symmetry_element_b, rhs_symmetry_element_a,
84  rhs_symmetry_element_c>;
85  using L_bac_tensorindextype_list =
86  tmpl::list<rhs_tensorindextype_b, rhs_tensorindextype_a,
87  rhs_tensorindextype_c>;
88  const Tensor<DataType, L_bac_symmetry, L_bac_tensorindextype_list> L_bac =
89  ::TensorExpressions::evaluate<TensorIndexB, TensorIndexA, TensorIndexC>(
90  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
91 
92  // L_{bca} = R_{abc}
93  using L_bca_symmetry =
94  Symmetry<rhs_symmetry_element_b, rhs_symmetry_element_c,
95  rhs_symmetry_element_a>;
96  using L_bca_tensorindextype_list =
97  tmpl::list<rhs_tensorindextype_b, rhs_tensorindextype_c,
98  rhs_tensorindextype_a>;
99  const Tensor<DataType, L_bca_symmetry, L_bca_tensorindextype_list> L_bca =
100  ::TensorExpressions::evaluate<TensorIndexB, TensorIndexC, TensorIndexA>(
101  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
102 
103  // L_{cab} = R_{abc}
104  using L_cab_symmetry =
105  Symmetry<rhs_symmetry_element_c, rhs_symmetry_element_a,
106  rhs_symmetry_element_b>;
107  using L_cab_tensorindextype_list =
108  tmpl::list<rhs_tensorindextype_c, rhs_tensorindextype_a,
109  rhs_tensorindextype_b>;
110  const Tensor<DataType, L_cab_symmetry, L_cab_tensorindextype_list> L_cab =
111  ::TensorExpressions::evaluate<TensorIndexC, TensorIndexA, TensorIndexB>(
112  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
113 
114  // L_{cba} = R_{abc}
115  using L_cba_symmetry =
116  Symmetry<rhs_symmetry_element_c, rhs_symmetry_element_b,
117  rhs_symmetry_element_a>;
118  using L_cba_tensorindextype_list =
119  tmpl::list<rhs_tensorindextype_c, rhs_tensorindextype_b,
120  rhs_tensorindextype_a>;
121  const Tensor<DataType, L_cba_symmetry, L_cba_tensorindextype_list> L_cba =
122  ::TensorExpressions::evaluate<TensorIndexC, TensorIndexB, TensorIndexA>(
123  R_abc(TensorIndexA, TensorIndexB, TensorIndexC));
124 
125  const size_t dim_a = tmpl::at_c<RhsTensorIndexTypeList, 0>::dim;
126  const size_t dim_b = tmpl::at_c<RhsTensorIndexTypeList, 1>::dim;
127  const size_t dim_c = tmpl::at_c<RhsTensorIndexTypeList, 2>::dim;
128 
129  for (size_t i = 0; i < dim_a; ++i) {
130  for (size_t j = 0; j < dim_b; ++j) {
131  for (size_t k = 0; k < dim_c; ++k) {
132  // For L_{abc} = R_{abc}, check that L_{ijk} == R_{ijk}
133  CHECK(L_abc.get(i, j, k) == R_abc.get(i, j, k));
134  // For L_{acb} = R_{abc}, check that L_{ikj} == R_{ijk}
135  CHECK(L_acb.get(i, k, j) == R_abc.get(i, j, k));
136  // For L_{bac} = R_{abc}, check that L_{jik} == R_{ijk}
137  CHECK(L_bac.get(j, i, k) == R_abc.get(i, j, k));
138  // For L_{bca} = R_{abc}, check that L_{jki} == R_{ijk}
139  CHECK(L_bca.get(j, k, i) == R_abc.get(i, j, k));
140  // For L_{cab} = R_{abc}, check that L_{kij} == R_{ijk}
141  CHECK(L_cab.get(k, i, j) == R_abc.get(i, j, k));
142  // For L_{cba} = R_{abc}, check that L_{kji} == R_{ijk}
143  CHECK(L_cba.get(k, j, i) == R_abc.get(i, j, k));
144  }
145  }
146  }
147 }
148 
149 /// \ingroup TestingFrameworkGroup
150 /// \brief Iterate testing of evaluating single rank 3 Tensors on multiple Frame
151 /// types and dimension combinations
152 ///
153 /// We test various different symmetries across several functions to ensure that
154 /// the code works correctly with symmetries. This function tests one of the
155 /// following symmetries:
156 /// - <3, 2, 1> (`test_evaluate_rank_3_no_symmetry`)
157 /// - <2, 2, 1> (`test_evaluate_rank_3_ab_symmetry`)
158 /// - <2, 1, 2> (`test_evaluate_rank_3_ac_symmetry`)
159 /// - <2, 1, 1> (`test_evaluate_rank_3_bc_symmetry`)
160 /// - <1, 1, 1> (`test_evaluate_rank_3_abc_symmetry`)
161 ///
162 /// \details `TensorIndexA`, `TensorIndexB`, and `TensorIndexC` can be any type
163 /// of TensorIndex and are not necessarily `ti_a`, `ti_b`, and `ti_c`. The
164 /// "A", "B", and "C" suffixes just denote the ordering of the generic indices
165 /// of the RHS tensor expression. In the RHS tensor expression, it means
166 /// `TensorIndexA` is the first index used, `TensorIndexB` is the second index
167 /// used, and `TensorIndexC` is the third index used.
168 ///
169 /// Note: the functions dealing with symmetric indices have fewer template
170 /// parameters due to the indices having a shared \ref SpacetimeIndex
171 /// "TensorIndexType" and valence
172 ///
173 /// \tparam DataType the type of data being stored in the Tensors
174 /// \tparam TensorIndexTypeA the \ref SpacetimeIndex "TensorIndexType" of the
175 /// first index of the RHS Tensor
176 /// \tparam TensorIndexTypeB the \ref SpacetimeIndex "TensorIndexType" of the
177 /// second index of the RHS Tensor
178 /// \tparam TensorIndexTypeC the \ref SpacetimeIndex "TensorIndexType" of the
179 /// third index of the RHS Tensor
180 /// \tparam ValenceA the valence of the first index used on the RHS of the
181 /// TensorExpression
182 /// \tparam ValenceB the valence of the second index used on the RHS of the
183 /// TensorExpression
184 /// \tparam ValenceC the valence of the third index used on the RHS of the
185 /// TensorExpression
186 /// \tparam TensorIndexA the first TensorIndex used on the RHS of the
187 /// TensorExpression, e.g. `ti_a`
188 /// \tparam TensorIndexB the second TensorIndex used on the RHS of the
189 /// TensorExpression, e.g. `ti_B`
190 /// \tparam TensorIndexC the third TensorIndex used on the RHS of the
191 /// TensorExpression, e.g. `ti_c`
192 template <typename DataType,
193  template <size_t, UpLo, typename> class TensorIndexTypeA,
194  template <size_t, UpLo, typename> class TensorIndexTypeB,
195  template <size_t, UpLo, typename> class TensorIndexTypeC,
196  UpLo ValenceA, UpLo ValenceB, UpLo ValenceC, auto& TensorIndexA,
197  auto& TensorIndexB, auto& TensorIndexC>
199 #define DIM_A(data) BOOST_PP_TUPLE_ELEM(0, data)
200 #define DIM_B(data) BOOST_PP_TUPLE_ELEM(1, data)
201 #define DIM_C(data) BOOST_PP_TUPLE_ELEM(2, data)
202 #define FRAME(data) BOOST_PP_TUPLE_ELEM(3, data)
203 
204 #define CALL_TEST_EVALUATE_RANK_3_IMPL(_, data) \
205  test_evaluate_rank_3_impl< \
206  DataType, Symmetry<3, 2, 1>, \
207  index_list<TensorIndexTypeA<DIM_A(data), ValenceA, FRAME(data)>, \
208  TensorIndexTypeB<DIM_B(data), ValenceB, FRAME(data)>, \
209  TensorIndexTypeC<DIM_C(data), ValenceC, FRAME(data)>>, \
210  TensorIndexA, TensorIndexB, TensorIndexC>();
211 
212  GENERATE_INSTANTIATIONS(CALL_TEST_EVALUATE_RANK_3_IMPL, (1, 2, 3), (1, 2, 3),
213  (1, 2, 3), (Frame::Grid, Frame::Inertial))
214 
215 #undef CALL_TEST_EVALUATE_RANK_3_IMPL
216 #undef FRAME
217 #undef DIM_C
218 #undef DIM_B
219 #undef DIM_A
220 }
221 
222 /// \ingroup TestingFrameworkGroup
223 /// \copydoc test_evaluate_rank_3_no_symmetry()
224 template <typename DataType,
225  template <size_t, UpLo, typename> class TensorIndexTypeAB,
226  template <size_t, UpLo, typename> class TensorIndexTypeC,
227  UpLo ValenceAB, UpLo ValenceC, auto& TensorIndexA, auto& TensorIndexB,
228  auto& TensorIndexC>
230 #define DIM_AB(data) BOOST_PP_TUPLE_ELEM(0, data)
231 #define DIM_C(data) BOOST_PP_TUPLE_ELEM(1, data)
232 #define FRAME(data) BOOST_PP_TUPLE_ELEM(2, data)
233 
234 #define CALL_TEST_EVALUATE_RANK_3_IMPL(_, data) \
235  test_evaluate_rank_3_impl< \
236  DataType, Symmetry<2, 2, 1>, \
237  index_list<TensorIndexTypeAB<DIM_AB(data), ValenceAB, FRAME(data)>, \
238  TensorIndexTypeAB<DIM_AB(data), ValenceAB, FRAME(data)>, \
239  TensorIndexTypeC<DIM_C(data), ValenceC, FRAME(data)>>, \
240  TensorIndexA, TensorIndexB, TensorIndexC>();
241 
242  GENERATE_INSTANTIATIONS(CALL_TEST_EVALUATE_RANK_3_IMPL, (1, 2, 3), (1, 2, 3),
244 
245 #undef CALL_TEST_EVALUATE_RANK_3_IMPL
246 #undef FRAME
247 #undef DIM_C
248 #undef DIM_AB
249 }
250 
251 /// \ingroup TestingFrameworkGroup
252 /// \copydoc test_evaluate_rank_3_no_symmetry()
253 template <typename DataType,
254  template <size_t, UpLo, typename> class TensorIndexTypeAC,
255  template <size_t, UpLo, typename> class TensorIndexTypeB,
256  UpLo ValenceAC, UpLo ValenceB, auto& TensorIndexA, auto& TensorIndexB,
257  auto& TensorIndexC>
259 #define DIM_AC(data) BOOST_PP_TUPLE_ELEM(0, data)
260 #define DIM_B(data) BOOST_PP_TUPLE_ELEM(1, data)
261 #define FRAME(data) BOOST_PP_TUPLE_ELEM(2, data)
262 
263 #define CALL_TEST_EVALUATE_RANK_3_IMPL(_, data) \
264  test_evaluate_rank_3_impl< \
265  DataType, Symmetry<2, 1, 2>, \
266  index_list<TensorIndexTypeAC<DIM_AC(data), ValenceAC, FRAME(data)>, \
267  TensorIndexTypeB<DIM_B(data), ValenceB, FRAME(data)>, \
268  TensorIndexTypeAC<DIM_AC(data), ValenceAC, FRAME(data)>>, \
269  TensorIndexA, TensorIndexB, TensorIndexC>();
270 
271  GENERATE_INSTANTIATIONS(CALL_TEST_EVALUATE_RANK_3_IMPL, (1, 2, 3), (1, 2, 3),
273 
274 #undef CALL_TEST_EVALUATE_RANK_3_IMPL
275 #undef FRAME
276 #undef DIM_B
277 #undef DIM_AC
278 }
279 
280 /// \ingroup TestingFrameworkGroup
281 /// \copydoc test_evaluate_rank_3_no_symmetry()
282 template <
283  typename DataType, template <size_t, UpLo, typename> class TensorIndexTypeA,
284  template <size_t, UpLo, typename> class TensorIndexTypeBC, UpLo ValenceA,
285  UpLo ValenceBC, auto& TensorIndexA, auto& TensorIndexB, auto& TensorIndexC>
287 #define DIM_A(data) BOOST_PP_TUPLE_ELEM(0, data)
288 #define DIM_BC(data) BOOST_PP_TUPLE_ELEM(1, data)
289 #define FRAME(data) BOOST_PP_TUPLE_ELEM(2, data)
290 
291 #define CALL_TEST_EVALUATE_RANK_3_IMPL(_, data) \
292  test_evaluate_rank_3_impl< \
293  DataType, Symmetry<2, 1, 1>, \
294  index_list<TensorIndexTypeA<DIM_A(data), ValenceA, FRAME(data)>, \
295  TensorIndexTypeBC<DIM_BC(data), ValenceBC, FRAME(data)>, \
296  TensorIndexTypeBC<DIM_BC(data), ValenceBC, FRAME(data)>>, \
297  TensorIndexA, TensorIndexB, TensorIndexC>();
298 
299  GENERATE_INSTANTIATIONS(CALL_TEST_EVALUATE_RANK_3_IMPL, (1, 2, 3), (1, 2, 3),
301 
302 #undef CALL_TEST_EVALUATE_RANK_3_IMPL
303 #undef FRAME
304 #undef DIM_BC
305 #undef DIM_A
306 }
307 
308 /// \ingroup TestingFrameworkGroup
309 /// \copydoc test_evaluate_rank_3_no_symmetry()
310 template <typename DataType,
311  template <size_t, UpLo, typename> class TensorIndexType, UpLo Valence,
312  auto& TensorIndexA, auto& TensorIndexB, auto& TensorIndexC>
314 #define DIM(data) BOOST_PP_TUPLE_ELEM(0, data)
315 #define FRAME(data) BOOST_PP_TUPLE_ELEM(1, data)
316 
317 #define CALL_TEST_EVALUATE_RANK_3_IMPL(_, data) \
318  test_evaluate_rank_3_impl< \
319  DataType, Symmetry<1, 1, 1>, \
320  index_list<TensorIndexType<DIM(data), Valence, FRAME(data)>, \
321  TensorIndexType<DIM(data), Valence, FRAME(data)>, \
322  TensorIndexType<DIM(data), Valence, FRAME(data)>>, \
323  TensorIndexA, TensorIndexB, TensorIndexC>();
324 
325  GENERATE_INSTANTIATIONS(CALL_TEST_EVALUATE_RANK_3_IMPL, (1, 2, 3),
327 
328 #undef CALL_TEST_EVALUATE_RANK_3_IMPL
329 #undef FRAME
330 #undef DIM
331 }
332 
333 } // namespace TestHelpers::TensorExpressions
TestHelpers::TensorExpressions::test_evaluate_rank_3_impl
void test_evaluate_rank_3_impl() noexcept
Test that evaluating a right hand side tensor expression containing a single rank 3 tensor correctly ...
Definition: EvaluateRank3TestHelpers.hpp:50
Frame::Inertial
Definition: IndexType.hpp:44
TensorExpression.hpp
TestHelpers::TensorExpressions::test_evaluate_rank_3_ac_symmetry
void test_evaluate_rank_3_ac_symmetry() noexcept
Iterate testing of evaluating single rank 3 Tensors on multiple Frame types and dimension combination...
Definition: EvaluateRank3TestHelpers.hpp:258
UpLo
UpLo
Definition: IndexType.hpp:20
Frame::Grid
Definition: IndexType.hpp:43
Literals.hpp
TestHelpers::TensorExpressions::test_evaluate_rank_3_bc_symmetry
void test_evaluate_rank_3_bc_symmetry() noexcept
Iterate testing of evaluating single rank 3 Tensors on multiple Frame types and dimension combination...
Definition: EvaluateRank3TestHelpers.hpp:286
iterator
TestHelpers::TensorExpressions::test_evaluate_rank_3_ab_symmetry
void test_evaluate_rank_3_ab_symmetry() noexcept
Iterate testing of evaluating single rank 3 Tensors on multiple Frame types and dimension combination...
Definition: EvaluateRank3TestHelpers.hpp:229
cstddef
std::int32_t
Symmetry
typename detail::SymmetryImpl< std::make_index_sequence< sizeof...(T)>, tmpl::integral_list< std::int32_t, T... > >::type Symmetry
Computes the canonical symmetry from the integers T
Definition: Symmetry.hpp:81
Tensor.hpp
numeric
TestHelpers::TensorExpressions::test_evaluate_rank_3_no_symmetry
void test_evaluate_rank_3_no_symmetry() noexcept
Iterate testing of evaluating single rank 3 Tensors on multiple Frame types and dimension combination...
Definition: EvaluateRank3TestHelpers.hpp:198
TestHelpers::TensorExpressions::test_evaluate_rank_3_abc_symmetry
void test_evaluate_rank_3_abc_symmetry() noexcept
Iterate testing of evaluating single rank 3 Tensors on multiple Frame types and dimension combination...
Definition: EvaluateRank3TestHelpers.hpp:313
GENERATE_INSTANTIATIONS
#define GENERATE_INSTANTIATIONS(INSTANTIATION_MACRO,...)
Macro useful for generating many explicit instantiations of function or class templates.
Definition: GenerateInstantiations.hpp:160
TMPL.hpp
Evaluate.hpp
cpp2b::iota
constexpr void iota(ForwardIterator first, ForwardIterator last, T value)
Definition: Numeric.hpp:20