SpECTRE Documentation Coverage Report
Current view: top level - DataStructures/Tensor/Expressions - Negate.hpp Hit Total Coverage
Commit: f23e75c235cae5144b8ac7ce01280be5b8cd2c8a Lines: 26 28 92.9 %
Date: 2024-09-07 06:21:00
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_.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             : }

Generated by: LCOV version 1.14