// Copyright Maksym Zhelyeznyakov 2025-2026. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // https://www.boost.org/LICENSE_1_0.txt) #ifndef REVERSE_MODE_AUTODIFF_ERF_OVERLOADS_HPP #define REVERSE_MODE_AUTODIFF_ERF_OVERLOADS_HPP #include #include #ifdef BOOST_MATH_REVERSE_MODE_ET_ON #include #else #include #endif #include #include namespace boost { namespace math { namespace differentiation { namespace reverse_mode { template struct erf_expr; template struct erfc_expr; template struct erf_inv_expr; template struct erfc_inv_expr; template erf_expr erf(const expression &arg) { return erf_expr(arg, 0.0); } template erfc_expr erfc(const expression &arg) { return erfc_expr(arg, 0.0); } template erf_inv_expr erf_inv( const expression &arg) { return erf_inv_expr(arg, 0.0); } template erfc_inv_expr erfc_inv( const expression &arg) { return erfc_inv_expr(arg, 0.0); } template struct erf_expr : public abstract_unary_expression> { /** @brief erf(x) * * d/dx erf(x) = 2*exp(x^2)/sqrt(pi) * * */ using inner_t = rvar_t; explicit erf_expr(const expression &arg_expr, const RealType v) : abstract_unary_expression>(arg_expr, v){}; inner_t evaluate() const { return detail::if_functional_dispatch<(DerivativeOrder > 1)>( [this](auto &&x) { return reverse_mode::erf(std::forward(x)); }, [this](auto &&x) { return boost::math::erf(std::forward(x)); }, this->arg.evaluate()); } static const inner_t derivative(const inner_t &argv, const inner_t & /*v*/, const RealType & /*constant*/) { BOOST_MATH_STD_USING return static_cast(2.0) * exp(-argv * argv) / sqrt(constants::pi()); } }; template struct erfc_expr : public abstract_unary_expression> { /** @brief erfc(x) * * d/dx erf(x) = -2*exp(x^2)/sqrt(pi) * * */ using inner_t = rvar_t; explicit erfc_expr(const expression &arg_expr, const RealType v) : abstract_unary_expression>(arg_expr, v){}; inner_t evaluate() const { return detail::if_functional_dispatch<((DerivativeOrder > 1))>( [this](auto &&x) { return reverse_mode::erfc(std::forward(x)); }, [this](auto &&x) { return boost::math::erfc(std::forward(x)); }, this->arg.evaluate()); } static const inner_t derivative(const inner_t &argv, const inner_t & /*v*/, const RealType & /*constant*/) { BOOST_MATH_STD_USING return static_cast(-2.0) * exp(-argv * argv) / sqrt(constants::pi()); } }; template struct erf_inv_expr : public abstract_unary_expression> { /** @brief erf(x) * * d/dx erf(x) = 2*exp(x^2)/sqrt(pi) * * */ using inner_t = rvar_t; explicit erf_inv_expr(const expression &arg_expr, const RealType v) : abstract_unary_expression>(arg_expr, v){}; inner_t evaluate() const { return detail::if_functional_dispatch<((DerivativeOrder > 1))>( [this](auto &&x) { return reverse_mode::erf_inv(std::forward(x)); }, [this](auto &&x) { return boost::math::erf_inv(std::forward(x)); }, this->arg.evaluate()); } static const inner_t derivative(const inner_t &argv, const inner_t & /*v*/, const RealType & /*constant*/) { BOOST_MATH_STD_USING return detail::if_functional_dispatch<((DerivativeOrder > 1))>( [](auto &&x) { return static_cast(0.5) * sqrt(constants::pi()) * reverse_mode::exp( reverse_mode::pow(reverse_mode::erf_inv(x), static_cast(2.0))); }, [](auto &&x) { return static_cast(0.5) * sqrt(constants::pi()) * exp(pow(boost::math::erf_inv(x), static_cast(2.0))); }, argv); } }; template struct erfc_inv_expr : public abstract_unary_expression> { /** @brief erfc(x) * * d/dx erf(x) = -2*exp(x^2)/sqrt(pi) * * */ using inner_t = rvar_t; explicit erfc_inv_expr(const expression &arg_expr, const RealType v) : abstract_unary_expression>(arg_expr, v){}; inner_t evaluate() const { return detail::if_functional_dispatch<((DerivativeOrder > 1))>( [this](auto &&x) { return reverse_mode::erfc_inv(std::forward(x)); }, [this](auto &&x) { return boost::math::erfc_inv(std::forward(x)); }, this->arg.evaluate()); } static const inner_t derivative(const inner_t &argv, const inner_t & /*v*/, const RealType & /*constant*/) { BOOST_MATH_STD_USING return detail::if_functional_dispatch<((DerivativeOrder > 1))>( [](auto &&x) { return static_cast(-0.5) * sqrt(constants::pi()) * reverse_mode::exp(reverse_mode::pow(reverse_mode::erfc_inv(x), static_cast(2.0))); }, [](auto &&x) { return static_cast(-0.5) * sqrt(constants::pi()) * exp(pow(boost::math::erfc_inv(x), static_cast(2.0))); }, argv); } }; } // namespace reverse_mode } // namespace differentiation } // namespace math } // namespace boost #endif // REVERSE_MODE_AUTODIFF_ERF_OVERLOADS_HPP