SpECTRE Documentation Coverage Report
Current view: top level - DataStructures/Tensor/Expressions - SquareRoot.hpp Hit Total Coverage
Commit: 1c32b58340e006addc79befb2cdaa7547247e09c Lines: 25 28 89.3 %
Date: 2024-04-19 07:30:15
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14