SpECTRE Documentation Coverage Report
Current view: top level - DataStructures/Tensor/Expressions - Negate.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 92.9 % 28 26
Test Date: 2026-10-22 17:29:42
Legend: Lines:     hit not hit

            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_.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_.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              : }
        

Generated by: LCOV version 2.0-1