TensorAsExpressionRank3TestHelpers.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 
14 namespace TestHelpers::TensorExpressions {
15 /// \ingroup TestingFrameworkGroup
16 /// \brief Test that the transformation between LHS and RHS multi-indices and
17 /// the subsequent computed RHS multi-index of a rank 3 tensor is correctly
18 /// computed by the functions of TensorAsExpression, according to the orders of
19 /// the LHS and RHS generic indices
20 ///
21 /// \details The functions tested are:
22 /// - `TensorAsExpression::compute_index_transformation`
23 /// - `TensorAsExpression::compute_rhs_multi_index`
24 ///
25 /// If we consider the RHS tensor's generic indices to be (a, b, c), the
26 /// possible orderings of the LHS tensor's generic indices are: (a, b, c),
27 /// (a, c, b), (b, a, c), (b, c, a), (c, a, b), and (c, b, a). For each of these
28 /// cases, this test checks that for each LHS component's multi-index, the
29 /// equivalent RHS multi-index is correctly computed.
30 ///
31 /// \param tensorindex_a the first TensorIndex used on the RHS of the
32 /// TensorExpression, e.g. `ti_a`
33 /// \param tensorindex_b the second TensorIndex used on the RHS of the
34 /// TensorExpression, e.g. `ti_B`
35 /// \param tensorindex_c the third TensorIndex used on the RHS of the
36 /// TensorExpression, e.g. `ti_c`
37 template <typename TensorIndexA, typename TensorIndexB, typename TensorIndexC>
39  const TensorIndexA& tensorindex_a, const TensorIndexB& tensorindex_b,
40  const TensorIndexC& tensorindex_c) noexcept {
41  const size_t dim_a = 4;
42  const size_t dim_b = 2;
43  const size_t dim_c = 3;
44 
45  const IndexType indextype_a =
46  TensorIndexA::is_spacetime ? IndexType::Spacetime : IndexType::Spatial;
47  const IndexType indextype_b =
48  TensorIndexB::is_spacetime ? IndexType::Spacetime : IndexType::Spatial;
49  const IndexType indextype_c =
50  TensorIndexC::is_spacetime ? IndexType::Spacetime : IndexType::Spatial;
51 
52  Tensor<double, Symmetry<3, 2, 1>,
53  index_list<Tensor_detail::TensorIndexType<dim_a, TensorIndexA::valence,
54  Frame::Grid, indextype_a>,
55  Tensor_detail::TensorIndexType<dim_b, TensorIndexB::valence,
56  Frame::Grid, indextype_b>,
57  Tensor_detail::TensorIndexType<dim_c, TensorIndexC::valence,
58  Frame::Grid, indextype_c>>>
59  rhs_tensor{};
60  std::iota(rhs_tensor.begin(), rhs_tensor.end(), 0.0);
61  // Get TensorExpression from RHS tensor
62  const auto R_abc_expr =
63  rhs_tensor(tensorindex_a, tensorindex_b, tensorindex_c);
64 
65  const std::array<size_t, 3> index_order_abc = {
66  TensorIndexA::value, TensorIndexB::value, TensorIndexC::value};
67  const std::array<size_t, 3> index_order_acb = {
68  TensorIndexA::value, TensorIndexC::value, TensorIndexB::value};
69  const std::array<size_t, 3> index_order_bac = {
70  TensorIndexB::value, TensorIndexA::value, TensorIndexC::value};
71  const std::array<size_t, 3> index_order_bca = {
72  TensorIndexB::value, TensorIndexC::value, TensorIndexA::value};
73  const std::array<size_t, 3> index_order_cab = {
74  TensorIndexC::value, TensorIndexA::value, TensorIndexB::value};
75  const std::array<size_t, 3> index_order_cba = {
76  TensorIndexC::value, TensorIndexB::value, TensorIndexA::value};
77 
78  const std::array<size_t, 3> actual_abc_to_abc_transformation =
79  R_abc_expr.compute_index_transformation(index_order_abc);
80  const std::array<size_t, 3> expected_abc_to_abc_transformation = {0, 1, 2};
81  const std::array<size_t, 3> actual_acb_to_abc_transformation =
82  R_abc_expr.compute_index_transformation(index_order_acb);
83  const std::array<size_t, 3> expected_acb_to_abc_transformation = {0, 2, 1};
84  const std::array<size_t, 3> actual_bac_to_abc_transformation =
85  R_abc_expr.compute_index_transformation(index_order_bac);
86  const std::array<size_t, 3> expected_bac_to_abc_transformation = {1, 0, 2};
87  const std::array<size_t, 3> actual_bca_to_abc_transformation =
88  R_abc_expr.compute_index_transformation(index_order_bca);
89  const std::array<size_t, 3> expected_bca_to_abc_transformation = {2, 0, 1};
90  const std::array<size_t, 3> actual_cab_to_abc_transformation =
91  R_abc_expr.compute_index_transformation(index_order_cab);
92  const std::array<size_t, 3> expected_cab_to_abc_transformation = {1, 2, 0};
93  const std::array<size_t, 3> actual_cba_to_abc_transformation =
94  R_abc_expr.compute_index_transformation(index_order_cba);
95  const std::array<size_t, 3> expected_cba_to_abc_transformation = {2, 1, 0};
96 
97  CHECK(actual_abc_to_abc_transformation == expected_abc_to_abc_transformation);
98  CHECK(actual_acb_to_abc_transformation == expected_acb_to_abc_transformation);
99  CHECK(actual_bac_to_abc_transformation == expected_bac_to_abc_transformation);
100  CHECK(actual_bca_to_abc_transformation == expected_bca_to_abc_transformation);
101  CHECK(actual_cab_to_abc_transformation == expected_cab_to_abc_transformation);
102  CHECK(actual_cba_to_abc_transformation == expected_cba_to_abc_transformation);
103 
104  for (size_t i = 0; i < dim_a; i++) {
105  for (size_t j = 0; j < dim_b; j++) {
106  for (size_t k = 0; k < dim_c; k++) {
107  const std::array<size_t, 3> ijk = {i, j, k};
108  const std::array<size_t, 3> ikj = {i, k, j};
109  const std::array<size_t, 3> jik = {j, i, k};
110  const std::array<size_t, 3> jki = {j, k, i};
111  const std::array<size_t, 3> kij = {k, i, j};
112  const std::array<size_t, 3> kji = {k, j, i};
113 
114  // For L_{abc} = R_{abc}, check that L_{ijk} == R_{ijk}
115  CHECK(R_abc_expr.compute_rhs_multi_index(
116  ijk, expected_abc_to_abc_transformation) == ijk);
117  // For L_{acb} = R_{abc}, check that L_{ijk} == R_{ikj}
118  CHECK(R_abc_expr.compute_rhs_multi_index(
119  ijk, expected_acb_to_abc_transformation) == ikj);
120  // For L_{bac} = R_{abc}, check that L_{ijk} == R_{jik}
121  CHECK(R_abc_expr.compute_rhs_multi_index(
122  ijk, expected_bac_to_abc_transformation) == jik);
123  // For L_{bca} = R_{abc}, check that L_{ijk} == R_{kij}
124  CHECK(R_abc_expr.compute_rhs_multi_index(
125  ijk, expected_bca_to_abc_transformation) == kij);
126  // For L_{cab} = R_{abc}, check that L_{ijk} == R_{jki}
127  CHECK(R_abc_expr.compute_rhs_multi_index(
128  ijk, expected_cab_to_abc_transformation) == jki);
129  // For L_{cba} = R_{abc}, check that L_{ijk} == R_{kji}
130  CHECK(R_abc_expr.compute_rhs_multi_index(
131  ijk, expected_cba_to_abc_transformation) == kji);
132  }
133  }
134  }
135 }
136 } // namespace TestHelpers::TensorExpressions
TensorExpression.hpp
IndexType.hpp
Frame::Grid
Definition: IndexType.hpp:43
iterator
IndexType::Spatial
@ Spatial
The TensorIndexType is purely spatial.
IndexType::Spacetime
@ Spacetime
The TensorIndexType is a spacetime index.
cstddef
std::array< size_t, 3 >
IndexType
IndexType
Definition: IndexType.hpp:134
Tensor.hpp
numeric
TestHelpers::TensorExpressions::test_tensor_as_expression_rank_3
void test_tensor_as_expression_rank_3(const TensorIndexA &tensorindex_a, const TensorIndexB &tensorindex_b, const TensorIndexC &tensorindex_c) noexcept
Test that the transformation between LHS and RHS multi-indices and the subsequent computed RHS multi-...
Definition: TensorAsExpressionRank3TestHelpers.hpp:38
cpp2b::iota
constexpr void iota(ForwardIterator first, ForwardIterator last, T value)
Definition: Numeric.hpp:20