Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <type_traits>
7 :
8 : #include "DataStructures/Tensor/Expressions/TensorIndex.hpp"
9 : #include "DataStructures/Tensor/Expressions/TimeIndex.hpp"
10 : #include "DataStructures/Tensor/IndexType.hpp"
11 : #include "Utilities/TMPL.hpp"
12 :
13 : namespace tenex {
14 : namespace detail {
15 : /// @{
16 : /// \brief Helper struct for checking that one tensor's index is either a
17 : /// spacetime index where a concrete time index has been used or can be
18 : /// assigned to, added to, or subtracted from its corresponding index in another
19 : /// tensor
20 : ///
21 : /// \details
22 : /// Indices in one tensor correspond to those in another that use the same
23 : /// generic index, such as `ti::a`. For it to be possible to add, subtract, or
24 : /// assign one index to another, this checks that the following is true for the
25 : /// index and its corresponding index in another tensor:
26 : /// - has the same valence (`UpLo`)
27 : /// - has the same `Frame` type
28 : /// - has the same number of spatial dimensions (allowing for expressions that
29 : /// use generic spatial indices for spacetime indices on either side)
30 : ///
31 : /// \tparam IndexList1 the first tensor's \ref SpacetimeIndex "TensorIndexType"
32 : /// list
33 : /// \tparam IndexList2 the second tensor's \ref SpacetimeIndex "TensorIndexType"
34 : /// list
35 : /// \tparam TensorIndexList1 the first tensor's generic index list
36 : /// \tparam TensorIndexList2 the second tensor's generic index list
37 : /// \tparam CurrentTensorIndex1 the current generic index of the first tensor
38 : /// that is being checked, e.g. the type of `ti::a`
39 : /// \tparam Iteration the position of the current index of the first tensor
40 : /// being checked, e.g. the position of `ti::a` in the first tensor
41 : template <typename IndexList1, typename IndexList2, typename TensorIndexList1,
42 : typename TensorIndexList2, typename CurrentTensorIndex1,
43 : typename Iteration>
44 : struct IndexPropertyCheckImpl {
45 : using index1 = tmpl::at<IndexList1, Iteration>;
46 : using index2 =
47 : tmpl::at<IndexList2,
48 : tmpl::index_of<TensorIndexList2, CurrentTensorIndex1>>;
49 :
50 : using type = std::bool_constant<
51 : index1::ul == index2::ul and
52 : std::is_same_v<typename index1::Frame, typename index2::Frame> and
53 : ((index1::index_type == index2::index_type and
54 : index1::dim == index2::dim) or
55 : (index1::index_type == IndexType::Spacetime and
56 : index1::dim == index2::dim + 1) or
57 : (index2::index_type == IndexType::Spacetime and
58 : index1::dim + 1 == index2::dim))>;
59 : };
60 :
61 : template <typename IndexList1, typename IndexList2, typename TensorIndexList1,
62 : typename TensorIndexList2, typename Iteration>
63 : struct IndexPropertyCheckImpl<IndexList1, IndexList2, TensorIndexList1,
64 : TensorIndexList2, std::decay_t<decltype(ti::T)>,
65 : Iteration> {
66 : using index1 = tmpl::at<IndexList1, Iteration>;
67 : using type = std::bool_constant<index1::index_type == IndexType::Spacetime>;
68 : };
69 :
70 : template <typename IndexList1, typename IndexList2, typename TensorIndexList1,
71 : typename TensorIndexList2, typename Iteration>
72 : struct IndexPropertyCheckImpl<IndexList1, IndexList2, TensorIndexList1,
73 : TensorIndexList2, std::decay_t<decltype(ti::t)>,
74 : Iteration> {
75 : using index1 = tmpl::at<IndexList1, Iteration>;
76 : using type = std::bool_constant<index1::index_type == IndexType::Spacetime>;
77 : };
78 : /// @}
79 :
80 : /// \brief Helper struct for checking that one tensor's indices can be
81 : /// mathematically assigned to, added to, or subtracted from their
82 : /// corresponding indices in another tensor
83 : ///
84 : /// \details
85 : /// This struct checks that:
86 : /// (1) The shared generic indices between the two index lists can be
87 : /// mathematically assigned to, added to, or subtracted from one another
88 : /// (2) Any non-shared indices are spacetime indices where a concrete time index
89 : /// has been used
90 : ///
91 : /// This struct checks that (2) is true for the second tensor's time indices and
92 : /// calls `IndexPropertyCheckImpl` to check that (2) is true for the first
93 : /// tensor's time indices and that (1) is true. To see more details regarding
94 : /// how (1) is checked, see `IndexPropertyCheckImpl`.
95 : ///
96 : /// \tparam IndexList1 the first tensor's \ref SpacetimeIndex "TensorIndexType"
97 : /// list
98 : /// \tparam IndexList2 the second tensor's \ref SpacetimeIndex "TensorIndexType"
99 : /// list
100 : /// \tparam TensorIndexList1 the first tensor's generic index list
101 : /// \tparam TensorIndexList2 the second tensor's generic index list
102 : template <typename IndexList1, typename IndexList2, typename TensorIndexList1,
103 : typename TensorIndexList2>
104 : struct IndexPropertyCheckHelper;
105 :
106 : template <typename IndexList1, typename... RhsIndices,
107 : typename TensorIndexList1, typename... RhsTensorIndices>
108 : struct IndexPropertyCheckHelper<IndexList1, tmpl::list<RhsIndices...>,
109 : TensorIndexList1,
110 : tmpl::list<RhsTensorIndices...>> {
111 : static constexpr bool value =
112 : // Check that second tensor's concrete time indices are used with
113 : // spacetime indices
114 : (... and ((not tt::is_time_index<RhsTensorIndices>::value) or
115 : (tt::is_time_index<RhsTensorIndices>::value and
116 : RhsIndices::index_type == IndexType::Spacetime))) and
117 : // Check that:
118 : // - the first tensor's concrete time indices are used with spacetime
119 : // indices
120 : // - shared generic indices between the two tensors can be mathematically
121 : // assigned to, added to, or subtracted from one another
122 : (tmpl::enumerated_fold<
123 : TensorIndexList1, tmpl::bool_<true>,
124 : tmpl::and_<
125 : tmpl::_state,
126 : IndexPropertyCheckImpl<tmpl::pin<IndexList1>,
127 : tmpl::pin<tmpl::list<RhsIndices...>>,
128 : tmpl::pin<TensorIndexList1>,
129 : tmpl::pin<tmpl::list<RhsTensorIndices...>>,
130 : tmpl::_element, tmpl::_3>>,
131 : tmpl::size_t<0>>::value);
132 : };
133 :
134 : /// \brief Check that one tensor's indices can be mathematically assigned to,
135 : /// added to, or subtracted from their corresponding indices in another tensor
136 : ///
137 : /// \details
138 : /// For more details on what is checked, see `IndexPropertyCheckImpl` followed
139 : /// by `IndexPropertyCheckHelper`
140 : ///
141 : /// \tparam IndexList1 the first tensor's \ref SpacetimeIndex "TensorIndexType"
142 : /// list
143 : /// \tparam IndexList2 the second tensor's \ref SpacetimeIndex "TensorIndexType"
144 : /// list
145 : /// \tparam TensorIndexList1 the first tensor's generic index list
146 : /// \tparam TensorIndexList2 the second tensor's generic index list
147 : template <typename IndexList1, typename IndexList2, typename TensorIndexList1,
148 : typename TensorIndexList2>
149 : using IndexPropertyCheck =
150 : IndexPropertyCheckHelper<IndexList1, IndexList2, TensorIndexList1,
151 : TensorIndexList2>;
152 : } // namespace detail
153 : } // namespace tenex
|