Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-17 08:48:09

0001 //           Copyright Maksym Zhelyenzyakov 2025-2026.
0002 // Distributed under the Boost Software License, Version 1.0.
0003 //      (See accompanying file LICENSE_1_0.txt or copy at
0004 //           https://www.boost.org/LICENSE_1_0.txt)
0005 
0006 #ifndef REVERSE_MODE_AUTODIFF_EXPRESSION_TEMPLATE_BASE_HPP
0007 #define REVERSE_MODE_AUTODIFF_EXPRESSION_TEMPLATE_BASE_HPP
0008 #include <cstddef>
0009 #include <type_traits>
0010 namespace boost {
0011 namespace math {
0012 namespace differentiation {
0013 namespace reverse_mode {
0014 
0015 /* forward declarations for utitlity functions */
0016 struct expression_base
0017 {};
0018 
0019 template<typename RealType, size_t DerivativeOrder, class DerivedExpression>
0020 struct expression;
0021 
0022 template<typename RealType, size_t DerivativeOrder>
0023 class rvar;
0024 
0025 template<typename RealType,
0026          size_t DerivativeOrder,
0027          typename LHS,
0028          typename RHS,
0029          typename ConcreteBinaryOperation>
0030 struct abstract_binary_expression;
0031 
0032 template<typename RealType, size_t DerivativeOrder, typename ARG, typename ConcreteUnaryOperation>
0033 
0034 struct abstract_unary_expression;
0035 
0036 template<typename RealType, size_t DerivativeOrder>
0037 class gradient_node; // forward declaration for tape
0038 
0039 namespace detail {
0040 template<typename...>
0041 using void_t = void;
0042 // Check if T has a 'value_type' alias
0043 template<typename T, typename Enable = void>
0044 struct has_value_type : std::false_type
0045 {};
0046 template<typename T>
0047 struct has_value_type<T, void_t<typename T::value_type>> : std::true_type
0048 {};
0049 template<typename T, typename Enable = void>
0050 struct has_binary_sub_types : std::false_type
0051 {};
0052 template<typename T>
0053 struct has_binary_sub_types<T, void_t<typename T::lhs_type, typename T::rhs_type>> : std::true_type
0054 {};
0055 template<typename T, typename Enable = void>
0056 struct has_unary_sub_type : std::false_type
0057 {};
0058 template<typename T>
0059 struct has_unary_sub_type<T, void_t<typename T::arg_type>> : std::true_type
0060 {};
0061 
0062 template<typename T, size_t order, typename Enable = void>
0063 struct count_rvar_impl
0064 {
0065     static constexpr std::size_t value = 0;
0066 };
0067 template<typename RealType, size_t DerivativeOrder>
0068 struct count_rvar_impl<rvar<RealType, DerivativeOrder>, DerivativeOrder>
0069 {
0070     static constexpr std::size_t value = 1;
0071 };
0072 
0073 template<typename RealType, std::size_t DerivativeOrder>
0074 struct count_rvar_impl<
0075     RealType,
0076     DerivativeOrder,
0077     std::enable_if_t<has_binary_sub_types<RealType>::value
0078                      && !std::is_same<RealType, rvar<typename RealType::value_type, DerivativeOrder>>::value
0079                      && !has_unary_sub_type<RealType>::value>>
0080 {
0081     static constexpr std::size_t value
0082         = count_rvar_impl<typename RealType::lhs_type, DerivativeOrder>::value
0083           + count_rvar_impl<typename RealType::rhs_type, DerivativeOrder>::value;
0084 };
0085 
0086 template<typename RealType, size_t DerivativeOrder>
0087 struct count_rvar_impl<
0088     RealType,
0089     DerivativeOrder,
0090     typename std::enable_if_t<
0091         has_unary_sub_type<RealType>::value
0092         && !std::is_same<RealType, rvar<typename RealType::value_type, DerivativeOrder>>::value
0093         && !has_binary_sub_types<RealType>::value>>
0094 {
0095     static constexpr std::size_t value
0096         = count_rvar_impl<typename RealType::arg_type, DerivativeOrder>::value;
0097 };
0098 template<typename RealType, size_t DerivativeOrder>
0099 constexpr std::size_t count_rvars = detail::count_rvar_impl<RealType, DerivativeOrder>::value;
0100 
0101 template<typename T>
0102 struct is_expression : std::is_base_of<expression_base, typename std::decay<T>::type>
0103 {};
0104 
0105 template<typename RealType, size_t N>
0106 struct rvar_type_impl
0107 {
0108     using type = rvar<RealType, N>;
0109 };
0110 
0111 template<typename RealType>
0112 struct rvar_type_impl<RealType, 0>
0113 {
0114     using type = RealType;
0115 };
0116 
0117 } // namespace detail
0118 
0119 template<typename T, size_t N>
0120 using rvar_t = typename detail::rvar_type_impl<T, N>::type;
0121 
0122 template<typename RealType, size_t DerivativeOrder, class DerivedExpression>
0123 struct expression : expression_base
0124 {
0125     /* @brief
0126    * base expression class
0127    * */
0128 
0129     using value_type                = RealType;
0130     static constexpr size_t order_v = DerivativeOrder;
0131     using derived_type              = DerivedExpression;
0132 
0133     static constexpr size_t num_literals = 0;
0134     using inner_t                        = rvar_t<RealType, DerivativeOrder - 1>;
0135     inner_t evaluate() const { return static_cast<const DerivedExpression *>(this)->evaluate(); }
0136 
0137     template<size_t arg_index>
0138     void propagatex(gradient_node<RealType, DerivativeOrder> *node, inner_t adj) const
0139     {
0140         return static_cast<const DerivedExpression *>(this)->template propagatex<arg_index>(node,
0141                                                                                             adj);
0142     }
0143 };
0144 
0145 template<typename RealType,
0146          size_t DerivativeOrder,
0147          typename LHS,
0148          typename RHS,
0149          typename ConcreteBinaryOperation>
0150 struct abstract_binary_expression
0151     : public expression<
0152           RealType,
0153           DerivativeOrder,
0154           abstract_binary_expression<RealType, DerivativeOrder, LHS, RHS, ConcreteBinaryOperation>>
0155 {
0156     using lhs_type   = LHS;
0157     using rhs_type   = RHS;
0158     using value_type = RealType;
0159     using inner_t    = rvar_t<RealType, DerivativeOrder - 1>;
0160     const lhs_type lhs;
0161     const rhs_type rhs;
0162 
0163     explicit abstract_binary_expression(
0164         const expression<RealType, DerivativeOrder, LHS> &left_hand_expr,
0165         const expression<RealType, DerivativeOrder, RHS> &right_hand_expr)
0166         : lhs(static_cast<const LHS &>(left_hand_expr))
0167         , rhs(static_cast<const RHS &>(right_hand_expr)){};
0168 
0169     inner_t evaluate() const
0170     {
0171         return static_cast<const ConcreteBinaryOperation *>(this)->evaluate();
0172     };
0173 
0174     template<size_t arg_index>
0175     void propagatex(gradient_node<RealType, DerivativeOrder> *node, inner_t adj) const
0176     {
0177         const inner_t lv        = lhs.evaluate();
0178         const inner_t rv        = rhs.evaluate();
0179         const inner_t v         = evaluate();
0180         const inner_t partial_l = ConcreteBinaryOperation::left_derivative(lv, rv, v);
0181         const inner_t partial_r = ConcreteBinaryOperation::right_derivative(lv, rv, v);
0182 
0183         constexpr size_t num_lhs_args = detail::count_rvars<LHS, DerivativeOrder>;
0184         constexpr size_t num_rhs_args = detail::count_rvars<RHS, DerivativeOrder>;
0185 
0186         propagate_lhs<num_lhs_args, arg_index>(node, adj * partial_l);
0187         propagate_rhs<num_rhs_args, arg_index + num_lhs_args>(node, adj * partial_r);
0188     }
0189 
0190 private:
0191     /* everything here just emulates c++17 if constexpr */
0192 
0193     template<std::size_t num_args,
0194              std::size_t arg_index_,
0195              typename std::enable_if<(num_args > 0), int>::type = 0>
0196     void propagate_lhs(gradient_node<RealType, DerivativeOrder> *node, inner_t adj) const
0197     {
0198         lhs.template propagatex<arg_index_>(node, adj);
0199     }
0200 
0201     template<std::size_t num_args,
0202              std::size_t arg_index_,
0203              typename std::enable_if<(num_args == 0), int>::type = 0>
0204     void propagate_lhs(gradient_node<RealType, DerivativeOrder> *, inner_t) const
0205     {}
0206 
0207     template<std::size_t num_args,
0208              std::size_t arg_index_,
0209              typename std::enable_if<(num_args > 0), int>::type = 0>
0210     void propagate_rhs(gradient_node<RealType, DerivativeOrder> *node, inner_t adj) const
0211     {
0212         rhs.template propagatex<arg_index_>(node, adj);
0213     }
0214 
0215     template<std::size_t num_args,
0216              std::size_t arg_index_,
0217              typename std::enable_if<(num_args == 0), int>::type = 0>
0218     void propagate_rhs(gradient_node<RealType, DerivativeOrder> *, inner_t) const
0219     {}
0220 };
0221 template<typename RealType, size_t DerivativeOrder, typename ARG, typename ConcreteUnaryOperation>
0222 
0223 struct abstract_unary_expression
0224     : public expression<
0225           RealType,
0226           DerivativeOrder,
0227           abstract_unary_expression<RealType, DerivativeOrder, ARG, ConcreteUnaryOperation>>
0228 {
0229     using arg_type   = ARG;
0230     using value_type = RealType;
0231     using inner_t    = rvar_t<RealType, DerivativeOrder - 1>;
0232     const arg_type arg;
0233     const RealType constant;
0234     explicit abstract_unary_expression(const expression<RealType, DerivativeOrder, ARG> &arg_expr,
0235                                        const RealType                                   &constant)
0236         : arg(static_cast<const ARG &>(arg_expr))
0237         , constant(constant){};
0238     inner_t evaluate() const
0239     {
0240         return static_cast<const ConcreteUnaryOperation *>(this)->evaluate();
0241     };
0242 
0243     template<size_t arg_index>
0244     void propagatex(gradient_node<RealType, DerivativeOrder> *node, inner_t adj) const
0245     {
0246         inner_t argv        = arg.evaluate();
0247         inner_t v           = evaluate();
0248         inner_t partial_arg = ConcreteUnaryOperation::derivative(argv, v, constant);
0249 
0250         arg.template propagatex<arg_index>(node, adj * partial_arg);
0251     }
0252 };
0253 } // namespace reverse_mode
0254 } // namespace differentiation
0255 } // namespace math
0256 } // namespace boost
0257 
0258 #endif // REVERSE_MODE_AUTODIFF_EXPRESSION_TEMPLATE_BASE_HPP