Line data Source code
1 1 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : /// \file 5 : /// Defines the tensor expression representing negation 6 : 7 : #pragma once 8 : 9 : #include <array> 10 : #include <cstddef> 11 : #include <limits> 12 : #include <utility> 13 : 14 : #include "DataStructures/Tensor/Expressions/NumberAsExpression.hpp" 15 : #include "DataStructures/Tensor/Expressions/TensorExpression.hpp" 16 : #include "Utilities/ForceInline.hpp" 17 : #include "Utilities/Gsl.hpp" 18 : #include "Utilities/TMPL.hpp" 19 : 20 : namespace tenex { 21 : /// \ingroup TensorExpressionsGroup 22 : /// \brief Defines the tensor expression representing the negation of a tensor 23 : /// expression 24 : /// 25 : /// \details 26 : /// For details on aliases and members defined in this class, as well as general 27 : /// `TensorExpression` terminology used in its members' documentation, see 28 : /// documentation for `TensorExpression`. 29 : /// 30 : /// \tparam T the type of tensor expression being negated 31 : template <typename T> 32 1 : struct Negate 33 : : public TensorExpression<Negate<T>, typename T::type, typename T::symmetry, 34 : typename T::index_list, typename T::args_list> { 35 : // === Index properties === 36 : /// The type of the data being stored in the result of the expression 37 1 : using type = typename T::type; 38 : /// The ::Symmetry of the result of the expression 39 1 : using symmetry = typename T::symmetry; 40 : /// The list of \ref SpacetimeIndex "TensorIndexType"s of the result of the 41 : /// expression 42 1 : using index_list = typename T::index_list; 43 : /// The list of generic `TensorIndex`s of the result of the expression 44 1 : using args_list = typename T::args_list; 45 : /// The number of tensor indices in the result of the expression 46 1 : static constexpr auto num_tensor_indices = tmpl::size<index_list>::value; 47 : 48 : // === Expression subtree properties === 49 : /// The number of arithmetic tensor operations done in the subtree for the 50 : /// left operand 51 1 : static constexpr size_t num_ops_left_child = T::num_ops_subtree; 52 : /// The number of arithmetic tensor operations done in the subtree for the 53 : /// right operand. This is 0 because this expression represents a unary 54 : /// operation. 55 1 : static constexpr size_t num_ops_right_child = 0; 56 : /// The total number of arithmetic tensor operations done in this expression's 57 : /// whole subtree 58 1 : static constexpr size_t num_ops_subtree = num_ops_left_child + 1; 59 : /// The height of this expression's node in the expression tree relative to 60 : /// the closest `TensorAsExpression` leaf in its subtree 61 1 : static constexpr size_t height_relative_to_closest_tensor_leaf_in_subtree = 62 : T::height_relative_to_closest_tensor_leaf_in_subtree != 63 : std::numeric_limits<size_t>::max() 64 : ? T::height_relative_to_closest_tensor_leaf_in_subtree + 1 65 : : T::height_relative_to_closest_tensor_leaf_in_subtree; 66 : 67 : // === Properties for splitting up subexpressions along the primary path === 68 : // These definitions only have meaning if this expression actually ends up 69 : // being along the primary path that is taken when evaluating the whole tree. 70 : // See documentation for `TensorExpression` for more details. 71 : /// If on the primary path, whether or not the expression is an ending point 72 : /// of a leg 73 1 : static constexpr bool is_primary_end = T::is_primary_start; 74 : /// If on the primary path, this is the remaining number of arithmetic tensor 75 : /// operations that need to be done in the subtree of the child along the 76 : /// primary path, given that we will have already computed the whole subtree 77 : /// at the next lowest leg's starting point. 78 1 : static constexpr size_t num_ops_to_evaluate_primary_left_child = 79 : is_primary_end ? 0 : T::num_ops_to_evaluate_primary_subtree; 80 : /// If on the primary path, this is the remaining number of arithmetic tensor 81 : /// operations that need to be done in the right operand's subtree. No 82 : /// splitting is currently done, so this is just `num_ops_right_child`. 83 1 : static constexpr size_t num_ops_to_evaluate_primary_right_child = 84 : num_ops_right_child; 85 : /// If on the primary path, this is the remaining number of arithmetic tensor 86 : /// operations that need to be done for this expression's subtree, given that 87 : /// we will have already computed the subtree at the next lowest leg's 88 : /// starting point 89 1 : static constexpr size_t num_ops_to_evaluate_primary_subtree = 90 : num_ops_to_evaluate_primary_left_child + 91 : num_ops_to_evaluate_primary_right_child + 1; 92 : /// If on the primary path, whether or not the expression is a starting point 93 : /// of a leg 94 1 : static constexpr bool is_primary_start = 95 : num_ops_to_evaluate_primary_subtree >= 96 : detail::max_num_ops_in_sub_expression<type>; 97 : /// If on the primary path, whether or not the expression's child along the 98 : /// primary path is a subtree that contains a starting point of a leg along 99 : /// the primary path 100 1 : static constexpr bool primary_child_subtree_contains_primary_start = 101 : T::primary_subtree_contains_primary_start; 102 : /// If on the primary path, whether or not this subtree contains a starting 103 : /// point of a leg along the primary path 104 1 : static constexpr bool primary_subtree_contains_primary_start = 105 : is_primary_start or primary_child_subtree_contains_primary_start; 106 : 107 0 : Negate(T t) : t_(std::move(t)) {} 108 0 : ~Negate() override = default; 109 : 110 : /// \brief Assert that the LHS tensor of the equation does not also appear in 111 : /// this expression's subtree 112 : template <typename LhsTensor> 113 1 : SPECTRE_ALWAYS_INLINE void assert_lhs_tensor_not_in_rhs_expression( 114 : const gsl::not_null<LhsTensor*> lhs_tensor) const { 115 : if constexpr (not std::is_base_of_v<MarkAsNumberAsExpression, T>) { 116 : t_.assert_lhs_tensor_not_in_rhs_expression(lhs_tensor); 117 : } 118 : } 119 : 120 : /// \brief Assert that each instance of the LHS tensor in the RHS tensor 121 : /// expression uses the same generic index order that the LHS uses 122 : /// 123 : /// \tparam LhsTensorIndices the list of generic `TensorIndex`s of the LHS 124 : /// result `Tensor` being computed 125 : /// \param lhs_tensor the LHS result `Tensor` being computed 126 : template <typename LhsTensorIndices, typename LhsTensor> 127 1 : SPECTRE_ALWAYS_INLINE void assert_lhs_tensorindices_same_in_rhs( 128 : const gsl::not_null<LhsTensor*> lhs_tensor) const { 129 : if constexpr (not std::is_base_of_v<MarkAsNumberAsExpression, T>) { 130 : t_.template assert_lhs_tensorindices_same_in_rhs<LhsTensorIndices>( 131 : lhs_tensor); 132 : } 133 : } 134 : 135 : /// \brief Get the size of a component from a `Tensor` in this expression's 136 : /// subtree of the RHS `TensorExpression` 137 : /// 138 : /// \return the size of a component from a `Tensor` in this expression's 139 : /// subtree of the RHS `TensorExpression` 140 1 : SPECTRE_ALWAYS_INLINE size_t get_rhs_tensor_component_size() const { 141 : return t_.get_rhs_tensor_component_size(); 142 : } 143 : 144 : /// \brief Return the value of the component of the negated tensor expression 145 : /// at a given multi-index 146 : /// 147 : /// \param multi_index the multi-index of the component to retrieve from the 148 : /// negated tensor expression 149 : /// \return the value of the component at `multi_index` in the negated tensor 150 : /// expression 151 1 : SPECTRE_ALWAYS_INLINE decltype(auto) get( 152 : const std::array<size_t, num_tensor_indices>& multi_index) const { 153 : return -t_.get(multi_index); 154 : } 155 : 156 : /// \brief Return the value of the component of the negated tensor expression 157 : /// at a given multi-index 158 : /// 159 : /// \details 160 : /// This function differs from `get` in that it takes into account whether we 161 : /// have already computed part of the result component at a lower subtree. 162 : /// In recursively computing this negation, the current result component will 163 : /// be substituted in for the most recent (highest) subtree below it that has 164 : /// already been evaluated. 165 : /// 166 : /// \param result_component the LHS tensor component to evaluate 167 : /// \param multi_index the multi-index of the component to retrieve from the 168 : /// negated tensor expression 169 : /// \return the value of the component at `multi_index` in the negated tensor 170 : /// expression 171 : template <typename ResultType> 172 1 : SPECTRE_ALWAYS_INLINE decltype(auto) get_primary( 173 : const ResultType& result_component, 174 : const std::array<size_t, num_tensor_indices>& multi_index) const { 175 : if constexpr (is_primary_end) { 176 : (void)multi_index; 177 : // We've already computed the whole child subtree on the primary path, so 178 : // just return the negation of the current result component 179 : return -result_component; 180 : } else { 181 : // We haven't yet evaluated the whole subtree for this expression, so 182 : // return the negation of this expression's subtree 183 : return -t_.template get_primary(result_component, multi_index); 184 : } 185 : } 186 : 187 : /// \brief Successively evaluate the LHS Tensor's result component at each 188 : /// leg in this expression's subtree 189 : /// 190 : /// \details 191 : /// This function takes into account whether we have already computed part of 192 : /// the result component at a lower subtree. In recursively computing this 193 : /// negation, the current result component will be substituted in for the most 194 : /// recent (highest) subtree below it that has already been evaluated. 195 : /// 196 : /// \param result_component the LHS tensor component to evaluate 197 : /// \param multi_index the multi-index of the component of the result tensor 198 : /// to evaluate 199 : template <typename ResultType> 200 1 : SPECTRE_ALWAYS_INLINE void evaluate_primary_subtree( 201 : ResultType& result_component, 202 : const std::array<size_t, num_tensor_indices>& multi_index) const { 203 : if constexpr (primary_child_subtree_contains_primary_start) { 204 : // The primary child's subtree contains at least one leg, so recurse down 205 : // and evaluate that first 206 : t_.template evaluate_primary_subtree(result_component, multi_index); 207 : } 208 : if constexpr (is_primary_start) { 209 : // We want to evaluate the subtree for this expression 210 : result_component = get_primary(result_component, multi_index); 211 : } 212 : } 213 : 214 : private: 215 : /// Operand expression 216 1 : T t_; 217 : }; 218 : } // namespace tenex 219 : 220 : /// \ingroup TensorExpressionsGroup 221 : /// \brief Returns the tensor expression representing the negation of a tensor 222 : /// expression 223 : /// 224 : /// \param t the tensor expression 225 : /// \return the tensor expression representing the negation of `t` 226 : template <typename T> 227 1 : SPECTRE_ALWAYS_INLINE auto operator-( 228 : const TensorExpression<T, typename T::type, typename T::symmetry, 229 : typename T::index_list, typename T::args_list>& t) { 230 : return tenex::Negate<T>(~t); 231 : }