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