Line data Source code
1 1 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <array>
7 : #include <cstddef>
8 :
9 : #include "DataStructures/Tensor/Expressions/TensorIndex.hpp"
10 : #include "DataStructures/Tensor/IndexType.hpp"
11 : #include "DataStructures/Tensor/Symmetry.hpp"
12 : #include "Utilities/Algorithm.hpp"
13 : #include "Utilities/ConstantExpressions.hpp"
14 : #include "Utilities/Gsl.hpp"
15 : #include "Utilities/MakeArray.hpp"
16 : #include "Utilities/Requires.hpp"
17 : #include "Utilities/TMPL.hpp"
18 :
19 : /// \file
20 : /// Defines functions and metafunctions used for helping evaluate
21 : /// TensorExpression equations where generic spatial indices are used for
22 : /// spacetime indices
23 :
24 : namespace tenex {
25 : namespace detail {
26 : template <typename State, typename Element, typename Iteration,
27 : typename TensorIndexList>
28 : struct spatial_spacetime_index_positions_impl {
29 : using type = typename std::conditional_t<
30 : Element::index_type == IndexType::Spacetime and
31 : not tmpl::at<TensorIndexList, Iteration>::is_spacetime,
32 : tmpl::push_back<State, tmpl::integral_constant<size_t, Iteration::value>>,
33 : State>;
34 : };
35 :
36 : /// \brief Given a generic index list and tensor index list, returns the list of
37 : /// positions where the generic index is spatial and the tensor index is
38 : /// spacetime
39 : ///
40 : /// \tparam TensorIndexList the generic index list
41 : /// \tparam TensorIndexTypeList the list of
42 : /// \ref SpacetimeIndex "TensorIndexType"s
43 : template <typename TensorIndexTypeList, typename TensorIndexList>
44 : using spatial_spacetime_index_positions = tmpl::enumerated_fold<
45 : TensorIndexTypeList, tmpl::list<>,
46 : spatial_spacetime_index_positions_impl<
47 : tmpl::_state, tmpl::_element, tmpl::_3, tmpl::pin<TensorIndexList>>,
48 : tmpl::size_t<0>>;
49 :
50 : /// \brief Given a generic index list and tensor index list, returns the list of
51 : /// positions where the generic index is spatial and the tensor index is
52 : /// spacetime
53 : ///
54 : /// \tparam TensorIndexList the generic index list
55 : /// \tparam TensorIndexTypeList the list of
56 : /// \ref SpacetimeIndex "TensorIndexType"s
57 : /// \return the list of positions where the generic index is spatial and the
58 : /// tensor index is spacetime
59 : template <typename TensorIndexTypeList, typename TensorIndexList>
60 : constexpr auto get_spatial_spacetime_index_positions() {
61 : using spatial_spacetime_index_positions_ =
62 : spatial_spacetime_index_positions<TensorIndexTypeList, TensorIndexList>;
63 : using make_list_type = std::conditional_t<
64 : tmpl::size<spatial_spacetime_index_positions_>::value == 0, size_t,
65 : spatial_spacetime_index_positions_>;
66 : return make_array_from_list<make_list_type>();
67 : }
68 :
69 : /// @{
70 : /// \brief Given a tensor symmetry and the positions of indices where a generic
71 : /// spatial index is used for a spacetime index, this returns the symmetry
72 : /// after making those indices nonsymmetric with others
73 : ///
74 : /// \details
75 : /// Example: If `symmetry` is `[2, 1, 1, 1]` and
76 : /// `spatial_spacetime_index_positions` is `[1]`, then position 1 is the only
77 : /// position where a generic spatial index is used for a spacetime index. The
78 : /// resulting symmetry will make the index at position 1 no longer be symmetric
79 : /// with the indices at positions 2 and 3. Therefore, the resulting symmetry
80 : /// will be equivalent to the form of `[3, 2, 1, 1]`.
81 : ///
82 : /// Note: the symmetry returned by this function is not necessarily in the
83 : /// canonical form specified by ::Symmetry. In reality, for the example above,
84 : /// this function would return `[2, 3, 1, 1]`.
85 : ///
86 : /// \param symmetry the input tensor symmetry to transform
87 : /// \param spatial_spacetime_index_positions the positions of the indices of the
88 : /// tensor where a generic spatial index is used for a spacetime index
89 : /// \return the symmetry after making the `spatial_spacetime_index_positions` of
90 : /// `symmetry` nonsymmetric with other indices
91 : template <
92 : size_t NumIndices, size_t NumSpatialSpacetimeIndices,
93 : Requires<(NumIndices >= 2 and NumSpatialSpacetimeIndices != 0)> = nullptr>
94 : constexpr std::array<std::int32_t, NumIndices>
95 : get_spatial_spacetime_index_symmetry(
96 : const std::array<std::int32_t, NumIndices>& symmetry,
97 : const std::array<size_t, NumSpatialSpacetimeIndices>&
98 : spatial_spacetime_index_positions) {
99 : std::array<std::int32_t, NumIndices> spatial_spacetime_index_symmetry{};
100 : const std::int32_t max_symm_value =
101 : static_cast<std::int32_t>(*alg::max_element(symmetry));
102 : for (size_t i = 0; i < NumIndices; i++) {
103 : gsl::at(spatial_spacetime_index_symmetry, i) = gsl::at(symmetry, i);
104 : }
105 : for (size_t i = 0; i < NumSpatialSpacetimeIndices; i++) {
106 : gsl::at(spatial_spacetime_index_symmetry,
107 : gsl::at(spatial_spacetime_index_positions, i)) += max_symm_value;
108 : }
109 :
110 : return spatial_spacetime_index_symmetry;
111 : }
112 :
113 : template <
114 : size_t NumIndices, size_t NumSpatialSpacetimeIndices,
115 : Requires<(NumIndices < 2 or NumSpatialSpacetimeIndices == 0)> = nullptr>
116 : constexpr std::array<std::int32_t, NumIndices>
117 : get_spatial_spacetime_index_symmetry(
118 : const std::array<std::int32_t, NumIndices>& symmetry,
119 : const std::array<size_t, NumSpatialSpacetimeIndices>&
120 : /*spatial_spacetime_index_positions*/) {
121 : return symmetry;
122 : }
123 : /// @}
124 :
125 : template <typename S, typename E>
126 : struct replace_spatial_spacetime_indices_helper {
127 : using type = tmpl::replace_at<S, E, change_index_type<tmpl::at<S, E>>>;
128 : };
129 :
130 : // The list of indices resulting from taking `TensorIndexTypeList` and
131 : // replacing the spacetime indices at positions `SpatialSpacetimeIndexPositions`
132 : // with spatial indices
133 : template <typename TensorIndexTypeList, typename SpatialSpacetimeIndexPositions>
134 : using replace_spatial_spacetime_indices = tmpl::fold<
135 : SpatialSpacetimeIndexPositions, TensorIndexTypeList,
136 : replace_spatial_spacetime_indices_helper<tmpl::_state, tmpl::_element>>;
137 :
138 : /// \brief Given a number of tensor indices of two tensors and the positions of
139 : /// each tensor's spacetime indices for which a generic spatial index was used,
140 : /// compute the shift in the multi-index values from the first tensor's
141 : /// multi-indices to the second's
142 : ///
143 : /// \details
144 : /// Example: If we have \f$R_{ijk} + S_{ijk}\f$, where \f$R\f$'s first and
145 : /// 2nd indices are spacetime and \f$S\f$' first index and third index are
146 : /// spacetime, let \f$i = 0\f$, \f$j = 1\f$, and \f$k = 2\f$. The multi-index
147 : /// that represents \f$R_{012}\f$ is `{0 + 1, 1 + 1, 2} = {1, 2, 2}` and the
148 : /// multi-index that represents \f$S_{012}\f$ is
149 : /// `{0 + 1, 1, 2 + 1} = {1, 1, 3}`. The function returns the element-wise
150 : /// shift that is applied to convert the first multi-index to the other, which,
151 : /// in this case, would be: `{1, 1, 3} - {1, 2, 2} = {0, -1, 1}`.
152 : ///
153 : /// \tparam NumIndices number of indices of the two operands
154 : /// \param positions1 first operand's index positions where a generic spatial
155 : /// index is used for a spacetime index
156 : /// \param positions2 second operand's index positions where a generic spatial
157 : /// index is used for a spacetime index
158 : /// \return the element-wise multi-index shift from the first operand's
159 : /// multi-indices to the second's
160 : template <size_t NumIndices, size_t NumPositions1, size_t NumPositions2>
161 : constexpr std::array<std::int32_t, NumIndices>
162 : spatial_spacetime_index_transformation_from_positions(
163 : const std::array<size_t, NumPositions1>& positions1,
164 : const std::array<size_t, NumPositions2>& positions2) {
165 : std::array<std::int32_t, NumIndices> transformation =
166 : make_array<NumIndices, std::int32_t>(0);
167 : for (size_t i = 0; i < NumPositions1; i++) {
168 : gsl::at(transformation, gsl::at(positions1, i))--;
169 : }
170 : for (size_t i = 0; i < NumPositions2; i++) {
171 : gsl::at(transformation, gsl::at(positions2, i))++;
172 : }
173 : return transformation;
174 : }
175 : } // namespace detail
176 : } // namespace tenex
|