[llvm] [third-party] Update Boost.Math snapshot to 1.92 (PR #223166)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Sep 12 12:25:36 PDT 2026
https://github.com/PaulXiCao created https://github.com/llvm/llvm-project/pull/223166
Updating standalone snapshot of Boost.Math at `third-party/boost-math/` to version 1.92.
Previous version was initially added to llvm as a prerequisite for the C++17 mathematical special functions, see #141508 .
The current work on the mathematical special functions (see #205649) found an issue in Boost.Math which has been upstreamed and got released with v1.92 .
Updating Boost.Math instead of backporting to the older release was requested in the above mentioned pr.
>From 78305c1faab39de3e4a3550faa8083db8f3be03e Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 12 Sep 2026 21:15:16 +0200
Subject: [PATCH 1/2] edit update script
---
third-party/update_boost_math.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/third-party/update_boost_math.sh b/third-party/update_boost_math.sh
index 96cd73ed8c304..50d53ff150600 100755
--- a/third-party/update_boost_math.sh
+++ b/third-party/update_boost_math.sh
@@ -3,7 +3,7 @@
set -e # stop at the first error
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)
-VERSION="1.89.0"
+VERSION="1.92.0"
echo "This script deletes ${SCRIPT_DIR}/boost-math and re-downloads it from the standalone Boost.Math release version ${VERSION}."
echo "It then subsets it so it only contains the parts that are used in libc++."
>From 37df0cf2c6612dbde20a1066a7eb6f53989a1dba Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sat, 12 Sep 2026 21:17:18 +0200
Subject: [PATCH 2/2] update boost math to v1.92
---
third-party/boost-math/.drone.star | 21 +-
third-party/boost-math/.gitignore | 7 +-
third-party/boost-math/CMakeLists.txt | 137 ++-
third-party/boost-math/README.md | 8 +-
third-party/boost-math/build.jam | 1 -
.../include/boost/math/ccmath/round.hpp | 4 +-
.../include/boost/math/ccmath/signbit.hpp | 1 -
.../math/constants/calculate_constants.hpp | 8 +
.../boost/math/constants/constants.hpp | 7 +-
.../math/differentiation/autodiff_reverse.hpp | 811 +++++++++++++++++
...de_autodiff_basic_operator_expressions.hpp | 276 ++++++
.../reverse_mode_autodiff_basic_ops_et.hpp | 160 ++++
.../reverse_mode_autodiff_basic_ops_no_et.hpp | 154 ++++
...autodiff_comparison_operator_overloads.hpp | 167 ++++
.../reverse_mode_autodiff_erf_overloads.hpp | 234 +++++
...mode_autodiff_expression_template_base.hpp | 258 ++++++
...reverse_mode_autodiff_helper_functions.hpp | 18 +
...everse_mode_autodiff_memory_management.hpp | 462 ++++++++++
.../detail/reverse_mode_autodiff_stl_et.hpp | 275 ++++++
.../reverse_mode_autodiff_stl_expressions.hpp | 852 ++++++++++++++++++
.../reverse_mode_autodiff_stl_no_et.hpp | 266 ++++++
.../reverse_mode_autodiff_utilities.hpp | 51 ++
.../boost/math/distributions/arcsine.hpp | 273 +++---
.../boost/math/distributions/binomial.hpp | 20 +-
.../boost/math/distributions/cauchy.hpp | 18 +-
.../boost/math/distributions/chi_squared.hpp | 14 +-
.../math/distributions/extreme_value.hpp | 4 -
.../math/distributions/find_location.hpp | 19 +-
.../distributions/inverse_chi_squared.hpp | 2 +-
.../math/distributions/inverse_gaussian.hpp | 63 +-
.../boost/math/distributions/logistic.hpp | 48 +-
.../math/distributions/non_central_beta.hpp | 4 +
.../math/distributions/non_central_f.hpp | 295 +++++-
.../math/distributions/non_central_t.hpp | 81 +-
.../boost/math/distributions/students_t.hpp | 235 ++++-
.../math/interpolators/cubic_hermite.hpp | 7 +-
.../detail/barycentric_rational_detail.hpp | 15 +-
.../cardinal_quintic_b_spline_detail.hpp | 21 +-
.../detail/cubic_hermite_detail.hpp | 7 +-
.../detail/quintic_hermite_detail.hpp | 7 +-
.../detail/septic_hermite_detail.hpp | 7 +-
.../vector_barycentric_rational_detail.hpp | 15 +-
.../boost/math/interpolators/pchip.hpp | 5 +
.../math/interpolators/quintic_hermite.hpp | 7 +-
.../math/interpolators/septic_hermite.hpp | 7 +-
.../include/boost/math/octonion.hpp | 4 +
.../detail/differentiable_opt_utilties.hpp | 157 ++++
.../optimization/detail/gradient_opt_base.hpp | 92 ++
.../detail/line_search_policies.hpp | 206 +++++
.../detail/rdiff_optimization_policies.hpp | 134 +++
.../math/optimization/gradient_descent.hpp | 202 +++++
.../math/optimization/gradient_optimizers.hpp | 18 +
.../include/boost/math/optimization/jso.hpp | 2 +-
.../include/boost/math/optimization/lbfgs.hpp | 382 ++++++++
.../boost/math/optimization/minimizer.hpp | 336 +++++++
.../boost/math/optimization/nesterov.hpp | 208 +++++
.../boost/math/policies/error_handling.hpp | 8 +-
.../include/boost/math/policies/policy.hpp | 27 +-
.../detail/ooura_fourier_integrals_detail.hpp | 32 +-
.../math/quadrature/naive_monte_carlo.hpp | 61 +-
.../boost/math/special_functions/beta.hpp | 73 +-
.../special_functions/detail/bessel_jn.hpp | 2 +-
.../special_functions/detail/bessel_jy.hpp | 5 +-
.../special_functions/detail/fp_traits.hpp | 38 +-
.../hypergeometric_pFq_checked_series.hpp | 42 +-
.../detail/lambert_w_lookup_table.ipp | 170 ++--
.../boost/math/special_functions/ellint_2.hpp | 2 +-
.../boost/math/special_functions/erf.hpp | 32 +-
.../boost/math/special_functions/gamma.hpp | 128 ++-
.../special_functions/hypergeometric_pFq.hpp | 16 +-
.../boost/math/special_functions/hypot.hpp | 68 +-
.../boost/math/special_functions/lanczos.hpp | 2 +-
.../special_functions/logistic_sigmoid.hpp | 46 +
.../boost/math/special_functions/logit.hpp | 56 ++
.../boost/math/special_functions/math_fwd.hpp | 28 +-
.../boost/math/special_functions/next.hpp | 2 +-
.../boost/math/special_functions/sign.hpp | 4 +-
.../boost/math/special_functions/sin_pi.hpp | 1 -
.../include/boost/math/tools/config.hpp | 22 +-
.../include/boost/math/tools/cubic_roots.hpp | 26 +-
.../include/boost/math/tools/rational.hpp | 20 +-
.../include/boost/math/tools/roots.hpp | 10 +
.../include/boost/math/tools/type_traits.hpp | 5 -
83 files changed, 7452 insertions(+), 567 deletions(-)
create mode 100644 third-party/boost-math/include/boost/math/differentiation/autodiff_reverse.hpp
create mode 100644 third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_basic_operator_expressions.hpp
create mode 100644 third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_basic_ops_et.hpp
create mode 100644 third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_basic_ops_no_et.hpp
create mode 100644 third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_comparison_operator_overloads.hpp
create mode 100644 third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_erf_overloads.hpp
create mode 100644 third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_expression_template_base.hpp
create mode 100644 third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_helper_functions.hpp
create mode 100644 third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_memory_management.hpp
create mode 100644 third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_stl_et.hpp
create mode 100644 third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_stl_expressions.hpp
create mode 100644 third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_stl_no_et.hpp
create mode 100644 third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_utilities.hpp
create mode 100644 third-party/boost-math/include/boost/math/optimization/detail/differentiable_opt_utilties.hpp
create mode 100644 third-party/boost-math/include/boost/math/optimization/detail/gradient_opt_base.hpp
create mode 100644 third-party/boost-math/include/boost/math/optimization/detail/line_search_policies.hpp
create mode 100644 third-party/boost-math/include/boost/math/optimization/detail/rdiff_optimization_policies.hpp
create mode 100644 third-party/boost-math/include/boost/math/optimization/gradient_descent.hpp
create mode 100644 third-party/boost-math/include/boost/math/optimization/gradient_optimizers.hpp
create mode 100644 third-party/boost-math/include/boost/math/optimization/lbfgs.hpp
create mode 100644 third-party/boost-math/include/boost/math/optimization/minimizer.hpp
create mode 100644 third-party/boost-math/include/boost/math/optimization/nesterov.hpp
create mode 100644 third-party/boost-math/include/boost/math/special_functions/logistic_sigmoid.hpp
create mode 100644 third-party/boost-math/include/boost/math/special_functions/logit.hpp
diff --git a/third-party/boost-math/.drone.star b/third-party/boost-math/.drone.star
index bc51cc7e0e853..17b2006d7a0de 100644
--- a/third-party/boost-math/.drone.star
+++ b/third-party/boost-math/.drone.star
@@ -18,6 +18,7 @@ def main(ctx):
things_to_test = [ "special_fun", "distribution_tests", "mp", "misc", "interpolators", "quadrature", "autodiff", "long-running-tests", "float128_tests", "concepts" ]
gcc13_things_to_test = [ "special_fun", "distribution_tests", "mp", "misc", "interpolators", "quadrature", "autodiff", "long-running-tests", "float128_tests", "concepts", "new_floats" ]
sanitizer_test = [ "special_fun", "distribution_tests", "misc", "interpolators", "quadrature", "float128_tests" ]
+ reverse_mode_autodiff_test = [ "test_reverse_mode_autodiff", "autodiff-long-running-tests", "gradient_based_optimizers" ]
gnu_5_stds = [ "gnu++14", "c++14" ]
gnu_6_stds = [ "gnu++14", "c++14", "gnu++17", "c++17" ]
clang_6_stds = [ "c++14", "c++17" ]
@@ -46,28 +47,32 @@ def main(ctx):
result.append(linux_cxx("Ubuntu g++-8 " + cxx + " " + suite, "g++-8", packages="g++-8", buildtype="boost", image="cppalliance/droneubuntu2004:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-8', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
result.append(linux_cxx("Ubuntu g++-9 " + cxx + " " + suite, "g++-9", packages="g++-9", buildtype="boost", image="cppalliance/droneubuntu2004:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-9', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
for cxx in clang_6_stds:
- result.append(linux_cxx("Ubuntu clang++-6 " + cxx + " " + suite, "clang++-6.0", packages="clang-6.0", llvm_os="xenial", llvm_ver="6.0", buildtype="boost", image="cppalliance/droneubuntu1804:1", environment={'TOOLSET': 'clang', 'COMPILER': 'clang++-6.0', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
- result.append(linux_cxx("Ubuntu clang++-7 " + cxx + " " + suite, "clang++-7", packages="clang-7", llvm_os="xenial", llvm_ver="7", buildtype="boost", image="cppalliance/droneubuntu1804:1", environment={'TOOLSET': 'clang', 'COMPILER': 'clang++-7', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
- result.append(linux_cxx("Ubuntu clang++-8 " + cxx + " " + suite, "clang++-8", packages="clang-8", llvm_os="xenial", llvm_ver="8", buildtype="boost", image="cppalliance/droneubuntu1804:1", environment={'TOOLSET': 'clang', 'COMPILER': 'clang++-8', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
- result.append(linux_cxx("Ubuntu clang++-9 " + cxx + " " + suite, "clang++-9", packages="clang-9", llvm_os="xenial", llvm_ver="9", buildtype="boost", image="cppalliance/droneubuntu1804:1", environment={'TOOLSET': 'clang', 'COMPILER': 'clang++-9', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
+ result.append(linux_cxx("Ubuntu clang++-6 " + cxx + " " + suite, "clang++-6.0", packages="clang-6.0", llvm_os="bionic", llvm_ver="6.0", buildtype="boost", image="cppalliance/droneubuntu1804:1", environment={'TOOLSET': 'clang', 'COMPILER': 'clang++-6.0', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
+ result.append(linux_cxx("Ubuntu clang++-7 " + cxx + " " + suite, "clang++-7", packages="clang-7", llvm_os="bionic", llvm_ver="7", buildtype="boost", image="cppalliance/droneubuntu1804:1", environment={'TOOLSET': 'clang', 'COMPILER': 'clang++-7', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
+ result.append(linux_cxx("Ubuntu clang++-8 " + cxx + " " + suite, "clang++-8", packages="clang-8", llvm_os="bionic", llvm_ver="8", buildtype="boost", image="cppalliance/droneubuntu1804:1", environment={'TOOLSET': 'clang', 'COMPILER': 'clang++-8', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
+ result.append(linux_cxx("Ubuntu clang++-9 " + cxx + " " + suite, "clang++-9", packages="clang-9", llvm_os="focal", llvm_ver="9", buildtype="boost", image="cppalliance/droneubuntu2004:1", environment={'TOOLSET': 'clang', 'COMPILER': 'clang++-9', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
for cxx in gnu_9_stds:
- result.append(linux_cxx("Ubuntu g++-10 " + cxx + " " + suite, "g++-10", packages="g++-10", buildtype="boost", image="cppalliance/droneubuntu2004:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-10', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
- result.append(linux_cxx("Ubuntu g++-11 " + cxx + " " + suite, "g++-11", packages="g++-11", buildtype="boost", image="cppalliance/droneubuntu2004:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-11', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
+ result.append(linux_cxx("Ubuntu g++-10 " + cxx + " " + suite, "g++-10", packages="g++-10", buildtype="boost", image="cppalliance/droneubuntu2204:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-10', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
+ result.append(linux_cxx("Ubuntu g++-11 " + cxx + " " + suite, "g++-11", packages="g++-11", buildtype="boost", image="cppalliance/droneubuntu2204:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-11', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
result.append(linux_cxx("Ubuntu g++-12 " + cxx + " " + suite, "g++-12", packages="g++-12", buildtype="boost", image="cppalliance/droneubuntu2204:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-12', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
result.append(linux_cxx("Ubuntu clang++-14 " + cxx + " " + suite, "clang++-14", packages="clang-14", llvm_os="jammy", llvm_ver="14", buildtype="boost", image="cppalliance/droneubuntu2204:1", environment={'TOOLSET': 'clang', 'COMPILER': 'clang++-14', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
result.append(linux_cxx("Ubuntu clang++-15 " + cxx + " " + suite, "clang++-15", packages="clang-15", llvm_os="jammy", llvm_ver="15", buildtype="boost", image="cppalliance/droneubuntu2204:1", environment={'TOOLSET': 'clang', 'COMPILER': 'clang++-15', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
for cxx in clang_10_stds:
result.append(linux_cxx("Ubuntu clang++-10 " + cxx + " " + suite, "clang++-10", packages="clang-10", llvm_os="xenial", llvm_ver="10", buildtype="boost", image="cppalliance/droneubuntu1804:1", environment={'TOOLSET': 'clang', 'COMPILER': 'clang++-10', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
for cxx in gnu_non_native:
- result.append(linux_cxx("Ubuntu g++ s390s " + cxx + " " + suite, "g++", packages="g++", buildtype="boost", image="cppalliance/droneubuntu2204:multiarch", arch="s390x", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
+ result.append(linux_cxx("Ubuntu g++ s390s " + cxx + " " + suite, "g++", packages="g++", buildtype="boost", image="cppalliance/droneubuntu2404:multiarch", arch="s390x", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
for cxx in gnu_non_native:
- result.append(linux_cxx("Ubuntu g++ ARM64" + cxx + " " + suite, "g++", packages="g++", buildtype="boost", image="cppalliance/droneubuntu2204:multiarch", arch="arm64", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
+ result.append(linux_cxx("Ubuntu g++ ARM64" + cxx + " " + suite, "g++", packages="g++", buildtype="boost", image="cppalliance/droneubuntu2404:multiarch", arch="arm64", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
for cxx in gnu_non_native:
result.append(osx_cxx("M1 Clang " + cxx + " " + suite, "clang++", buildscript="drone", buildtype="boost", xcode_version="14.1", environment={'TOOLSET': 'clang', 'CXXSTD': cxx, 'TEST_SUITE': suite, 'DEFINE': 'BOOST_MATH_NO_REAL_CONCEPT_TESTS,BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS,BOOST_MATH_MULTI_ARCH_CI_RUN', }, globalenv=globalenv))
for suite in gcc13_things_to_test:
for cxx in gcc13_stds:
result.append(linux_cxx("Ubuntu g++-13 " + cxx + " " + suite, "g++-13", packages="g++-13", buildtype="boost", image="cppalliance/droneubuntu2404:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-13', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
result.append(linux_cxx("Ubuntu g++-14 " + cxx + " " + suite, "g++-14", packages="g++-14", buildtype="boost", image="cppalliance/droneubuntu2404:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-14', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
+ for suite in reverse_mode_autodiff_test:
+ for cxx in gcc13_stds:
+ result.append(linux_cxx("Ubuntu g++-13 " + cxx + " " + suite, "g++-13", packages="g++-13", buildtype="boost", image="cppalliance/droneubuntu2404:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-13', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
+ result.append(linux_cxx("Ubuntu g++-14 " + cxx + " " + suite, "g++-14", packages="g++-14", buildtype="boost", image="cppalliance/droneubuntu2404:1", environment={'TOOLSET': 'gcc', 'COMPILER': 'g++-14', 'CXXSTD': cxx, 'TEST_SUITE': suite, }, globalenv=globalenv))
return result
diff --git a/third-party/boost-math/.gitignore b/third-party/boost-math/.gitignore
index 6435addffdc9b..3158eb4a4b612 100644
--- a/third-party/boost-math/.gitignore
+++ b/third-party/boost-math/.gitignore
@@ -10,10 +10,12 @@ test/cuda
**/.temps/*
build/*
.vscode/*
-*.svg
+#*.svg
tools/bin/**
.idea/*
-
+# autogenerated for table in reverse mode docs
+doc/differentiation/compilation_table.txt
+test/test_reverse_mode_autodiff_special_functions_compile/generated_jam_compile_commands.txt
# CMake Related Options
*.a
*.o
@@ -28,3 +30,4 @@ cmake-build-debug/*
build.ninja
.ninja*
a.out
+
diff --git a/third-party/boost-math/CMakeLists.txt b/third-party/boost-math/CMakeLists.txt
index a1f6011d95e55..616c21e27f5e2 100644
--- a/third-party/boost-math/CMakeLists.txt
+++ b/third-party/boost-math/CMakeLists.txt
@@ -3,9 +3,9 @@
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
-cmake_minimum_required(VERSION 3.5...3.16)
+cmake_minimum_required(VERSION 3.8...3.16)
-project(boost_math VERSION 1.89.0 LANGUAGES CXX)
+project(boost_math VERSION 1.92.0 LANGUAGES CXX)
add_library(boost_math INTERFACE)
@@ -39,12 +39,143 @@ else()
Boost::lexical_cast
Boost::predef
Boost::random
- Boost::static_assert
Boost::throw_exception
)
endif()
+target_compile_features(boost_math INTERFACE cxx_std_14)
+
+# Legacy C99/TR1 compiled libraries
+option(BOOST_MATH_BUILD_WITH_LEGACY_FUNCTIONS "Build the C99 and TR1 compiled libraries" OFF)
+
+if(BOOST_MATH_BUILD_WITH_LEGACY_FUNCTIONS)
+
+include(CheckCXXSourceCompiles)
+set(_config_inc "")
+if(NOT BOOST_MATH_STANDALONE)
+ get_target_property(_config_type Boost::config TYPE)
+ if(_config_type STREQUAL "INTERFACE_LIBRARY")
+ get_target_property(_config_inc Boost::config INTERFACE_INCLUDE_DIRECTORIES)
+ endif()
+endif()
+set(CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/include" ${_config_inc})
+check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_long_double_support.cpp> \n int main() { return 0;}" BOOST_MATH_HAS_LONG_DOUBLE)
+unset(CMAKE_REQUIRED_INCLUDES)
+
+set(C99_SOURCES
+ acosh
+ asinh
+ atanh
+ cbrt
+ copysign
+ erfc
+ erf
+ expm1
+ fmax
+ fmin
+ fpclassify
+ hypot
+ lgamma
+ llround
+ log1p
+ lround
+ nextafter
+ nexttoward
+ round
+ tgamma
+ trunc
+)
+
+set(TR1_SOURCES
+ assoc_laguerre
+ assoc_legendre
+ beta
+ comp_ellint_1
+ comp_ellint_2
+ comp_ellint_3
+ cyl_bessel_i
+ cyl_bessel_j
+ cyl_bessel_k
+ cyl_neumann
+ ellint_1
+ ellint_2
+ ellint_3
+ expint
+ hermite
+ laguerre
+ legendre
+ riemann_zeta
+ sph_bessel
+ sph_legendre
+ sph_neumann
+)
+
+list(TRANSFORM C99_SOURCES PREPEND "src/tr1/")
+list(TRANSFORM TR1_SOURCES PREPEND "src/tr1/")
+
+list(TRANSFORM C99_SOURCES APPEND "f.cpp" OUTPUT_VARIABLE C99_SOURCESf)
+list(TRANSFORM TR1_SOURCES APPEND "f.cpp" OUTPUT_VARIABLE TR1_SOURCESf)
+
+set(types "" f)
+
+if(BOOST_MATH_HAS_LONG_DOUBLE)
+ list(TRANSFORM C99_SOURCES APPEND "l.cpp" OUTPUT_VARIABLE C99_SOURCESl)
+ list(TRANSFORM TR1_SOURCES APPEND "l.cpp" OUTPUT_VARIABLE TR1_SOURCESl)
+ list(APPEND types l)
+endif()
+
+list(TRANSFORM C99_SOURCES APPEND ".cpp")
+list(TRANSFORM TR1_SOURCES APPEND ".cpp")
+
+foreach(type IN LISTS types)
+ add_library(boost_math_tr1${type} ${TR1_SOURCES${type}})
+ add_library(Boost::math_tr1${type} ALIAS boost_math_tr1${type})
+ if(NOT BOOST_MATH_STANDALONE)
+ target_link_libraries(boost_math_tr1${type} PUBLIC Boost::config)
+ endif()
+ target_include_directories(boost_math_tr1${type} PRIVATE src/tr1)
+ target_include_directories(boost_math_tr1${type} PRIVATE include)
+
+ add_library(boost_math_c99${type} ${C99_SOURCES${type}})
+ add_library(Boost::math_c99${type} ALIAS boost_math_c99${type})
+ if(NOT BOOST_MATH_STANDALONE)
+ target_link_libraries(boost_math_c99${type} PUBLIC Boost::config)
+ endif()
+ target_include_directories(boost_math_c99${type} PRIVATE src/tr1)
+ target_include_directories(boost_math_c99${type} PRIVATE include)
+
+ if(BUILD_SHARED_LIBS)
+ target_compile_definitions(boost_math_tr1${type} PUBLIC BOOST_MATH_TR1_DYN_LINK=1)
+ target_compile_definitions(boost_math_c99${type} PUBLIC BOOST_MATH_TR1_DYN_LINK=1)
+ if(WIN32)
+ target_compile_definitions(boost_math_tr1${type} PRIVATE "BOOST_SYMBOL_EXPORT=__declspec(dllexport)" BOOST_ALL_NO_LIB)
+ target_compile_definitions(boost_math_c99${type} PRIVATE "BOOST_SYMBOL_EXPORT=__declspec(dllexport)" BOOST_ALL_NO_LIB)
+ else()
+ target_compile_definitions(boost_math_tr1${type} PRIVATE "BOOST_SYMBOL_EXPORT=__attribute__((visibility(\"default\")))" BOOST_ALL_NO_LIB)
+ target_compile_definitions(boost_math_c99${type} PRIVATE "BOOST_SYMBOL_EXPORT=__attribute__((visibility(\"default\")))" BOOST_ALL_NO_LIB)
+ endif()
+ endif()
+
+ target_compile_features(boost_math_tr1${type} PUBLIC cxx_std_14)
+ target_compile_features(boost_math_c99${type} PUBLIC cxx_std_14)
+
+ if(APPLE)
+ target_compile_definitions(boost_math_tr1${type} PRIVATE _DARWIN_C_SOURCE)
+ target_compile_definitions(boost_math_c99${type} PRIVATE _DARWIN_C_SOURCE)
+ endif()
+endforeach()
+
+if(BOOST_SUPERPROJECT_VERSION AND NOT CMAKE_VERSION VERSION_LESS 3.13)
+ set(boost_math_legacy_targets "")
+ foreach(type IN LISTS types)
+ list(APPEND boost_math_legacy_targets boost_math_c99${type} boost_math_tr1${type})
+ endforeach()
+ boost_install(TARGETS ${boost_math_legacy_targets} VERSION "${BOOST_SUPERPROJECT_VERSION}")
+endif()
+
+endif()
+
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
add_subdirectory(test)
diff --git a/third-party/boost-math/README.md b/third-party/boost-math/README.md
index 39b0bddd63201..b44755ec55f2c 100644
--- a/third-party/boost-math/README.md
+++ b/third-party/boost-math/README.md
@@ -138,8 +138,12 @@ The Boost Math Library is located in `libs/math/`.
### Running tests
-First, make sure you are in `libs/math/test`.
-You can either run all the tests listed in `Jamfile.v2` or run a single test:
+The Boost build program `b2` is used to run the tests. To build `b2`, from the
+top-level Boost directory, run either `./bootstrap.sh` (Linux/MacOS) or
+`bootstrap.bat` (Windows).
+
+Then move to `libs/math/test`. You can either run all the tests listed in
+`Jamfile.v2` or run a single test:
test$ ../../../b2 <- run all tests
test$ ../../../b2 static_assert_test <- single test
diff --git a/third-party/boost-math/build.jam b/third-party/boost-math/build.jam
index fb244e511db5e..8be6e64f9f69a 100644
--- a/third-party/boost-math/build.jam
+++ b/third-party/boost-math/build.jam
@@ -14,7 +14,6 @@ constant boost_dependencies :
/boost/lexical_cast//boost_lexical_cast
/boost/predef//boost_predef
/boost/random//boost_random
- /boost/static_assert//boost_static_assert
/boost/throw_exception//boost_throw_exception ;
project /boost/math
diff --git a/third-party/boost-math/include/boost/math/ccmath/round.hpp b/third-party/boost-math/include/boost/math/ccmath/round.hpp
index 334919e5260b2..776f341c5ce95 100644
--- a/third-party/boost-math/include/boost/math/ccmath/round.hpp
+++ b/third-party/boost-math/include/boost/math/ccmath/round.hpp
@@ -31,11 +31,11 @@ inline constexpr T round_impl(T arg) noexcept
const T x = boost::math::ccmath::modf(arg, &iptr);
constexpr T half = T(1)/2;
- if(x >= half && iptr > 0)
+ if(x >= half && iptr >= 0)
{
return iptr + 1;
}
- else if(boost::math::ccmath::abs(x) >= half && iptr < 0)
+ else if(boost::math::ccmath::abs(x) >= half && iptr <= 0)
{
return iptr - 1;
}
diff --git a/third-party/boost-math/include/boost/math/ccmath/signbit.hpp b/third-party/boost-math/include/boost/math/ccmath/signbit.hpp
index bb12a5b618f7e..87f4cc7c9fc08 100644
--- a/third-party/boost-math/include/boost/math/ccmath/signbit.hpp
+++ b/third-party/boost-math/include/boost/math/ccmath/signbit.hpp
@@ -14,7 +14,6 @@
#include <cstdint>
#include <boost/math/tools/assert.hpp>
-#include <boost/math/special_functions/detail/fp_traits.hpp>
#include <boost/math/ccmath/isnan.hpp>
#include <boost/math/ccmath/abs.hpp>
diff --git a/third-party/boost-math/include/boost/math/constants/calculate_constants.hpp b/third-party/boost-math/include/boost/math/constants/calculate_constants.hpp
index 3db74c3b66b7a..95f53d9e16aa2 100644
--- a/third-party/boost-math/include/boost/math/constants/calculate_constants.hpp
+++ b/third-party/boost-math/include/boost/math/constants/calculate_constants.hpp
@@ -95,6 +95,14 @@ inline T constant_one_div_two_pi<T>::compute(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_S
return 1 / two_pi<T, policies::policy<policies::digits2<N> > >();
}
+template <class T>
+template<int N>
+inline T constant_log_pi<T>::compute(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC((std::integral_constant<int, N>)))
+{
+ BOOST_MATH_STD_USING
+ return log(pi<T, policies::policy<policies::digits2<N> > >());
+}
+
template <class T>
template<int N>
inline T constant_root_pi<T>::compute(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC((std::integral_constant<int, N>)))
diff --git a/third-party/boost-math/include/boost/math/constants/constants.hpp b/third-party/boost-math/include/boost/math/constants/constants.hpp
index df702bf899324..3daf2d266e6ce 100644
--- a/third-party/boost-math/include/boost/math/constants/constants.hpp
+++ b/third-party/boost-math/include/boost/math/constants/constants.hpp
@@ -129,7 +129,7 @@ namespace boost{ namespace math
{
initializer()
{
- F();
+ (F)();
}
void force_instantiate()const{}
};
@@ -151,7 +151,7 @@ namespace boost{ namespace math
{
initializer()
{
- F();
+ (F)();
}
void force_instantiate()const{}
};
@@ -280,6 +280,7 @@ namespace constants {
BOOST_DEFINE_MATH_CONSTANT(four_thirds_pi, 4.188790204786390984616857844372670512e+00, "4.18879020478639098461685784437267051226289253250014109463325945641042187504827866483737976712282275730953078202e+00")
BOOST_DEFINE_MATH_CONSTANT(one_div_two_pi, 1.591549430918953357688837633725143620e-01, "1.59154943091895335768883763372514362034459645740456448747667344058896797634226535090113802766253085956072842727e-01")
BOOST_DEFINE_MATH_CONSTANT(one_div_root_two_pi, 3.989422804014326779399460599343818684e-01, "3.98942280401432677939946059934381868475858631164934657665925829670657925899301838501252333907306936430302558863e-01")
+ BOOST_DEFINE_MATH_CONSTANT(log_pi, 1.144729885849400174143427351353058711e+00, "1.14472988584940017414342735135305871164729481291531157151362307147213776988482607978362327027548970770200981223e+00")
BOOST_DEFINE_MATH_CONSTANT(root_pi, 1.772453850905516027298167483341145182e+00, "1.77245385090551602729816748334114518279754945612238712821380778985291128459103218137495065673854466541622682362e+00")
BOOST_DEFINE_MATH_CONSTANT(root_half_pi, 1.253314137315500251207882642405522626e+00, "1.25331413731550025120788264240552262650349337030496915831496178817114682730392098747329791918902863305800498633e+00")
BOOST_DEFINE_MATH_CONSTANT(root_two_pi, 2.506628274631000502415765284811045253e+00, "2.50662827463100050241576528481104525300698674060993831662992357634229365460784197494659583837805726611600997267e+00")
@@ -357,5 +358,3 @@ BOOST_MATH_GPU_ENABLED inline constexpr T tau() { return two_pi<T>(); }
#endif
#endif // BOOST_MATH_CONSTANTS_CONSTANTS_INCLUDED
-
-
diff --git a/third-party/boost-math/include/boost/math/differentiation/autodiff_reverse.hpp b/third-party/boost-math/include/boost/math/differentiation/autodiff_reverse.hpp
new file mode 100644
index 0000000000000..d7b5124ce5fb0
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/differentiation/autodiff_reverse.hpp
@@ -0,0 +1,811 @@
+// 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 BOOST_MATH_DIFFERENTIATION_AUTODIFF_REVERSE_HPP
+#define BOOST_MATH_DIFFERENTIATION_AUTODIFF_REVERSE_HPP
+
+#include <boost/math/constants/constants.hpp>
+
+#if defined(BOOST_MATH_REVERSE_MODE_ET_OFF) && defined(BOOST_MATH_REVERSE_MODE_ET_ON)
+#error "Cannot define both BOOST_MATH_REVERSE_MODE_ET_OFF and BOOST_MATH_REVERSE_MODE_ET_ON"
+#endif
+
+#if !defined(BOOST_MATH_REVERSE_MODE_ET_OFF) && !defined(BOOST_MATH_REVERSE_MODE_ET_ON)
+#define BOOST_MATH_REVERSE_MODE_ET_ON
+#endif
+
+#ifdef BOOST_MATH_REVERSE_MODE_ET_ON
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_basic_ops_et.hpp>
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_stl_et.hpp>
+#else
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_basic_ops_no_et.hpp>
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_stl_no_et.hpp>
+#endif
+
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_comparison_operator_overloads.hpp>
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_erf_overloads.hpp>
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_expression_template_base.hpp>
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_memory_management.hpp>
+#include <boost/math/special_functions/acosh.hpp>
+#include <boost/math/special_functions/asinh.hpp>
+#include <boost/math/special_functions/atanh.hpp>
+#include <boost/math/special_functions/digamma.hpp>
+#include <boost/math/special_functions/erf.hpp>
+#include <boost/math/special_functions/lambert_w.hpp>
+#include <boost/math/special_functions/polygamma.hpp>
+#include <boost/math/special_functions/round.hpp>
+#include <boost/math/special_functions/trunc.hpp>
+#include <boost/math/tools/config.hpp>
+#include <boost/math/tools/promotion.hpp>
+#include <cstddef>
+#include <iostream>
+#include <type_traits>
+#include <vector>
+#define BOOST_MATH_BUFFER_SIZE 65536
+
+namespace boost {
+namespace math {
+namespace differentiation {
+namespace reverse_mode {
+
+/* forward declarations for utitlity functions */
+template<typename RealType, size_t DerivativeOrder, class DerivedExpression>
+struct expression;
+
+template<typename RealType, size_t DerivativeOrder>
+class rvar;
+
+template<typename RealType,
+ size_t DerivativeOrder,
+ typename LHS,
+ typename RHS,
+ typename ConcreteBinaryOperation>
+struct abstract_binary_expression;
+
+template<typename RealType, size_t DerivativeOrder, typename ARG, typename ConcreteBinaryOperation>
+struct abstract_unary_expression;
+
+template<typename RealType, size_t DerivativeOrder>
+class gradient_node; // forward declaration for tape
+// manages nodes in computational graph
+template<typename RealType, size_t DerivativeOrder, size_t buffer_size = BOOST_MATH_BUFFER_SIZE>
+class gradient_tape
+{
+ /** @brief tape (graph) management class for autodiff
+ * holds all the data structures for autodiff */
+private:
+ /* type decays to order - 1 to support higher order derivatives */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+ /* adjoints are the overall derivative, and derivatives are the "local"
+ * derivative */
+ detail::flat_linear_allocator<inner_t, buffer_size> adjoints_;
+ detail::flat_linear_allocator<inner_t, buffer_size> derivatives_;
+ detail::flat_linear_allocator<gradient_node<RealType, DerivativeOrder>, buffer_size>
+ gradient_nodes_;
+ detail::flat_linear_allocator<gradient_node<RealType, DerivativeOrder> *, buffer_size>
+ argument_nodes_;
+
+ // compile time check if emplace_back calls on zero
+ template<size_t n>
+ gradient_node<RealType, DerivativeOrder> *fill_node_at_compile_time(
+ std::true_type, gradient_node<RealType, DerivativeOrder> *node_ptr)
+ {
+ node_ptr->derivatives_ = derivatives_.template emplace_back_n<n>();
+ node_ptr->argument_nodes_ = argument_nodes_.template emplace_back_n<n>();
+ return node_ptr;
+ }
+
+ template<size_t n>
+ gradient_node<RealType, DerivativeOrder> *fill_node_at_compile_time(
+ std::false_type, gradient_node<RealType, DerivativeOrder> *node_ptr)
+ {
+ node_ptr->derivatives_ = nullptr;
+ node_ptr->argument_adjoints_ = nullptr;
+ node_ptr->argument_nodes_ = nullptr;
+ return node_ptr;
+ }
+
+public:
+ /* gradient node stores iterators to its data memebers
+ * (adjoint/derivative/arguments) so that in case flat linear allocator
+ * reaches its block boundary and needs more memory for that node, the
+ * iterator can be invoked to access it */
+ using adjoint_iterator = typename detail::flat_linear_allocator<inner_t, buffer_size>::iterator;
+ using derivatives_iterator =
+ typename detail::flat_linear_allocator<inner_t, buffer_size>::iterator;
+ using gradient_nodes_iterator =
+ typename detail::flat_linear_allocator<gradient_node<RealType, DerivativeOrder>,
+ buffer_size>::iterator;
+ using argument_nodes_iterator =
+ typename detail::flat_linear_allocator<gradient_node<RealType, DerivativeOrder> *,
+ buffer_size>::iterator;
+
+ gradient_tape() { clear(); };
+
+ gradient_tape(const gradient_tape &) = delete;
+ gradient_tape &operator=(const gradient_tape &) = delete;
+ gradient_tape(gradient_tape &&other) = delete;
+ gradient_tape operator=(gradient_tape &&other) = delete;
+ ~gradient_tape() noexcept { clear(); }
+ void clear()
+ {
+ adjoints_.clear();
+ derivatives_.clear();
+ gradient_nodes_.clear();
+ argument_nodes_.clear();
+ }
+
+ // no derivatives or arguments
+ gradient_node<RealType, DerivativeOrder> *emplace_leaf_node()
+ {
+ gradient_node<RealType, DerivativeOrder> *node = &*gradient_nodes_.emplace_back();
+ node->adjoint_ = adjoints_.emplace_back();
+ node->derivatives_ = derivatives_iterator(); // nullptr;
+ node->argument_nodes_ = argument_nodes_iterator(); // nullptr;
+
+ return node;
+ };
+
+ // single argument, single derivative
+ gradient_node<RealType, DerivativeOrder> *emplace_active_unary_node()
+ {
+ gradient_node<RealType, DerivativeOrder> *node = &*gradient_nodes_.emplace_back();
+ node->n_ = 1;
+ node->adjoint_ = adjoints_.emplace_back();
+ node->derivatives_ = derivatives_.emplace_back();
+
+ return node;
+ };
+
+ // arbitrary number of arguments/derivatives (compile time)
+ template<size_t n>
+ gradient_node<RealType, DerivativeOrder> *emplace_active_multi_node()
+ {
+ gradient_node<RealType, DerivativeOrder> *node = &*gradient_nodes_.emplace_back();
+ node->n_ = n;
+ node->adjoint_ = adjoints_.emplace_back();
+ // emulate if constexpr
+ return fill_node_at_compile_time<n>(std::integral_constant<bool, (n > 0)>{}, node);
+ }
+
+ // same as above at runtime
+ gradient_node<RealType, DerivativeOrder> *emplace_active_multi_node(size_t n)
+ {
+ gradient_node<RealType, DerivativeOrder> *node = &*gradient_nodes_.emplace_back();
+ node->n_ = n;
+ node->adjoint_ = adjoints_.emplace_back();
+ if (n > 0) {
+ node->derivatives_ = derivatives_.emplace_back_n(n);
+ node->argument_nodes_ = argument_nodes_.emplace_back_n(n);
+ }
+ return node;
+ };
+ /* manual reset button for all adjoints */
+ void zero_grad()
+ {
+ const RealType zero = RealType(0.0);
+ adjoints_.fill(zero);
+ }
+
+ // return type is an iterator
+ auto begin() { return gradient_nodes_.begin(); }
+ auto end() { return gradient_nodes_.end(); }
+ auto find(gradient_node<RealType, DerivativeOrder> *node)
+ {
+ return gradient_nodes_.find(node);
+ };
+ void add_checkpoint()
+ {
+ gradient_nodes_.add_checkpoint();
+ adjoints_.add_checkpoint();
+ derivatives_.add_checkpoint();
+ argument_nodes_.add_checkpoint();
+ };
+
+ auto last_checkpoint() { return gradient_nodes_.last_checkpoint(); };
+ auto first_checkpoint() { return gradient_nodes_.last_checkpoint(); };
+ auto checkpoint_at(size_t index) { return gradient_nodes_.get_checkpoint_at(index); };
+ void rewind_to_last_checkpoint()
+ {
+ gradient_nodes_.rewind_to_last_checkpoint();
+ adjoints_.rewind_to_last_checkpoint();
+ derivatives_.rewind_to_last_checkpoint();
+ argument_nodes_.rewind_to_last_checkpoint();
+ };
+ void rewind_to_checkpoint_at(size_t index) // index is "checkpoint" index. so
+ // order which checkpoint was set
+ {
+ gradient_nodes_.rewind_to_checkpoint_at(index);
+ adjoints_.rewind_to_checkpoint_at(index);
+ derivatives_.rewind_to_checkpoint_at(index);
+ argument_nodes_.rewind_to_checkpoint_at(index);
+ }
+
+ // rewind to beginning of computational graph
+ void rewind()
+ {
+ gradient_nodes_.rewind();
+ adjoints_.rewind();
+ derivatives_.rewind();
+ argument_nodes_.rewind();
+ }
+
+ // random acces
+ gradient_node<RealType, DerivativeOrder> &operator[](size_t i) { return gradient_nodes_[i]; }
+ const gradient_node<RealType, DerivativeOrder> &operator[](size_t i) const
+ {
+ return gradient_nodes_[i];
+ }
+};
+// class rvar;
+template<typename RealType, size_t DerivativeOrder> // no CRTP, just storage
+class gradient_node
+{
+ /*
+ * @brief manages adjoints, derivatives, and stores points to argument
+ * adjoints pointers to arguments aren't needed here
+ * */
+public:
+ using adjoint_iterator = typename gradient_tape<RealType, DerivativeOrder>::adjoint_iterator;
+ using derivatives_iterator =
+ typename gradient_tape<RealType, DerivativeOrder>::derivatives_iterator;
+ using argument_nodes_iterator =
+ typename gradient_tape<RealType, DerivativeOrder>::argument_nodes_iterator;
+
+private:
+ size_t n_;
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+ /* these are iterators in case
+ * flat linear allocator is at capacity, and needs to allocate a new block of
+ * memory. */
+ adjoint_iterator adjoint_;
+ derivatives_iterator derivatives_;
+ argument_nodes_iterator argument_nodes_;
+
+public:
+ friend class gradient_tape<RealType, DerivativeOrder>;
+ friend class rvar<RealType, DerivativeOrder>;
+
+ gradient_node() = default;
+ explicit gradient_node(const size_t n)
+ : n_(n)
+ , adjoint_(nullptr)
+ , derivatives_(nullptr)
+ {}
+ explicit gradient_node(const size_t n,
+ RealType *adjoint,
+ RealType *derivatives,
+ rvar<RealType, DerivativeOrder> **arguments)
+ : n_(n)
+ , adjoint_(adjoint)
+ , derivatives_(derivatives)
+ { static_cast<void>(arguments); }
+
+ inner_t get_adjoint_v() const { return *adjoint_; }
+ inner_t get_derivative_v(size_t arg_id) const { return derivatives_[static_cast<ptrdiff_t>(arg_id)]; };
+ inner_t get_argument_adjoint_v(size_t arg_id) const
+ {
+ return *argument_nodes_[static_cast<ptrdiff_t>(arg_id)]->adjoint_;
+ }
+
+ adjoint_iterator get_adjoint_ptr() { return adjoint_; }
+ adjoint_iterator get_adjoint_ptr() const { return adjoint_; };
+ void update_adjoint_v(inner_t value) { *adjoint_ = value; };
+ void update_derivative_v(size_t arg_id, inner_t value) { derivatives_[static_cast<ptrdiff_t>(arg_id)] = value; };
+ void update_argument_adj_v(size_t arg_id, inner_t value)
+ {
+ argument_nodes_[static_cast<ptrdiff_t>(arg_id)]->update_adjoint_v(value);
+ };
+ void update_argument_ptr_at(size_t arg_id, gradient_node<RealType, DerivativeOrder> *node_ptr)
+ {
+ argument_nodes_[static_cast<ptrdiff_t>(arg_id)] = node_ptr;
+ }
+
+ void backward()
+ {
+ if (!n_) // leaf node
+ return;
+
+ using boost::math::differentiation::reverse_mode::fabs;
+ using std::fabs;
+ if (!adjoint_ || fabs(*adjoint_) < 2 * std::numeric_limits<RealType>::epsilon())
+ return;
+
+ if (!argument_nodes_) // no arguments
+ return;
+
+ if (!derivatives_) // no derivatives
+ return;
+
+ for (size_t i = 0; i < n_; ++i) {
+ auto adjoint = get_adjoint_v();
+ auto derivative = get_derivative_v(i);
+ auto argument_adjoint = get_argument_adjoint_v(i);
+ update_argument_adj_v(i, argument_adjoint + derivative * adjoint);
+ }
+ }
+};
+
+/****************************************************************************************************************/
+template<typename RealType, size_t DerivativeOrder>
+inline gradient_tape<RealType, DerivativeOrder, BOOST_MATH_BUFFER_SIZE> &get_active_tape()
+{
+ static BOOST_MATH_THREAD_LOCAL gradient_tape<RealType, DerivativeOrder, BOOST_MATH_BUFFER_SIZE>
+ tape;
+ return tape;
+}
+
+template<typename RealType, size_t DerivativeOrder = 1>
+class rvar : public expression<RealType, DerivativeOrder, rvar<RealType, DerivativeOrder>>
+{
+private:
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+ friend class gradient_node<RealType, DerivativeOrder>;
+ inner_t value_;
+ gradient_node<RealType, DerivativeOrder> *node_ = nullptr;
+ template<typename, size_t>
+ friend class rvar;
+ /*****************************************************************************************/
+ /**
+ * @brief implementation helpers for get_value_at
+ */
+ template<size_t target_order, size_t current_order>
+ struct get_value_at_impl
+ {
+ static_assert(target_order <= current_order, "Requested depth exceeds variable order.");
+
+ /** @return value_ at rvar_t<T,current_order - 1>
+ */
+ static auto &get(rvar<RealType, current_order> &v)
+ {
+ return get_value_at_impl<target_order, current_order - 1>::get(v.get_value());
+ }
+ /** @return const value_ at rvar_t<T,current_order - 1>
+ */
+ static const auto &get(const rvar<RealType, current_order> &v)
+ {
+ return get_value_at_impl<target_order, current_order - 1>::get(v.get_value());
+ }
+ };
+
+ /** @brief base case specialization for target_order == current order
+ */
+ template<size_t target_order>
+ struct get_value_at_impl<target_order, target_order>
+ {
+ /** @return value_ at rvar_t<T,target_order>
+ */
+ static auto &get(rvar<RealType, target_order> &v) { return v; }
+ /** @return const value_ at rvar_t<T,target_order>
+ */
+ static const auto &get(const rvar<RealType, target_order> &v) { return v; }
+ };
+ /*****************************************************************************************/
+ void make_leaf_node()
+ {
+ gradient_tape<RealType, DerivativeOrder, BOOST_MATH_BUFFER_SIZE> &tape
+ = get_active_tape<RealType, DerivativeOrder>();
+ node_ = tape.emplace_leaf_node();
+ }
+
+ void make_unary_node()
+ {
+ gradient_tape<RealType, DerivativeOrder, BOOST_MATH_BUFFER_SIZE> &tape
+ = get_active_tape<RealType, DerivativeOrder>();
+ node_ = tape.emplace_active_unary_node();
+ }
+
+ void make_multi_node(size_t n)
+ {
+ gradient_tape<RealType, DerivativeOrder, BOOST_MATH_BUFFER_SIZE> &tape
+ = get_active_tape<RealType, DerivativeOrder>();
+ node_ = tape.emplace_active_multi_node(n);
+ }
+
+ template<size_t n>
+ void make_multi_node()
+ {
+ gradient_tape<RealType, DerivativeOrder, BOOST_MATH_BUFFER_SIZE> &tape
+ = get_active_tape<RealType, DerivativeOrder>();
+ node_ = tape.template emplace_active_multi_node<n>();
+ }
+
+ template<typename E>
+ void make_rvar_from_expr(const expression<RealType, DerivativeOrder, E> &expr)
+ {
+ make_multi_node<detail::count_rvars<E, DerivativeOrder>>();
+ expr.template propagatex<0>(node_, inner_t(static_cast<RealType>(1.0)));
+ }
+ RealType get_item_impl(std::true_type) const
+ {
+ return value_.get_item_impl(std::integral_constant<bool, (DerivativeOrder - 1 > 1)>{});
+ }
+
+ RealType get_item_impl(std::false_type) const { return value_; }
+
+public:
+ using value_type = RealType;
+ static constexpr size_t DerivativeOrder_v = DerivativeOrder;
+ rvar()
+ : value_()
+ {
+ make_leaf_node();
+ }
+ rvar(const RealType value)
+ : value_(inner_t{static_cast<RealType>(value)})
+ {
+ make_leaf_node();
+ }
+
+ rvar &operator=(RealType v)
+ {
+ value_ = inner_t(v);
+ if (node_ == nullptr) {
+ make_leaf_node();
+ }
+ return *this;
+ }
+ rvar(const rvar<RealType, DerivativeOrder> &other) = default;
+ rvar &operator=(const rvar<RealType, DerivativeOrder> &other) = default;
+
+ template<size_t arg_index>
+ void propagatex(gradient_node<RealType, DerivativeOrder> *node, inner_t adj) const
+ {
+ node->update_derivative_v(arg_index, adj);
+ node->update_argument_ptr_at(arg_index, node_);
+ }
+
+ template<class E>
+ rvar(const expression<RealType, DerivativeOrder, E> &expr)
+ {
+ value_ = expr.evaluate();
+ make_rvar_from_expr(expr);
+ }
+
+ template<typename T,
+ typename = std::enable_if_t<is_floating_point_v<T> && !is_same_v<T, RealType>>>
+ rvar(T v)
+ : value_(inner_t{static_cast<RealType>(v)})
+ {
+ make_leaf_node();
+ }
+
+ template<class E>
+ rvar &operator=(const expression<RealType, DerivativeOrder, E> &expr)
+ {
+ value_ = expr.evaluate();
+ make_rvar_from_expr(expr);
+ return *this;
+ }
+ /***************************************************************************************************/
+ template<class E>
+ rvar<RealType, DerivativeOrder> &operator+=(const expression<RealType, DerivativeOrder, E> &expr)
+ {
+ *this = *this + expr;
+ return *this;
+ }
+
+ template<class E>
+ rvar<RealType, DerivativeOrder> &operator*=(const expression<RealType, DerivativeOrder, E> &expr)
+ {
+ *this = *this * expr;
+ return *this;
+ }
+
+ template<class E>
+ rvar<RealType, DerivativeOrder> &operator-=(const expression<RealType, DerivativeOrder, E> &expr)
+ {
+ *this = *this - expr;
+ return *this;
+ }
+
+ template<class E>
+ rvar<RealType, DerivativeOrder> &operator/=(const expression<RealType, DerivativeOrder, E> &expr)
+ {
+ *this = *this / expr;
+ return *this;
+ }
+ /***************************************************************************************************/
+ rvar<RealType, DerivativeOrder> &operator+=(const RealType &v)
+ {
+ *this = *this + v;
+ return *this;
+ }
+
+ rvar<RealType, DerivativeOrder> &operator*=(const RealType &v)
+ {
+ *this = *this * v;
+ return *this;
+ }
+
+ rvar<RealType, DerivativeOrder> &operator-=(const RealType &v)
+ {
+ *this = *this - v;
+ return *this;
+ }
+
+ rvar<RealType, DerivativeOrder> &operator/=(const RealType &v)
+ {
+ *this = *this / v;
+ return *this;
+ }
+
+ /***************************************************************************************************/
+ const inner_t &adjoint() const { return *node_->get_adjoint_ptr(); }
+ inner_t &adjoint() { return *node_->get_adjoint_ptr(); }
+
+ const inner_t &evaluate() const { return value_; };
+ inner_t &get_value() { return value_; };
+
+ explicit operator RealType() const { return item(); }
+
+ explicit operator int() const { return static_cast<int>(item()); }
+ explicit operator long() const { return static_cast<long>(item()); }
+ explicit operator long long() const { return static_cast<long long>(item()); }
+
+ /**
+ * @brief same as evaluate but returns proper depth for higher order derivatives
+ * @return value_ at depth N
+ */
+ template<size_t N>
+ auto &get_value_at()
+ {
+ static_assert(N <= DerivativeOrder, "Requested depth exceeds variable order.");
+ return get_value_at_impl<N, DerivativeOrder>::get(*this);
+ }
+ /** @brief same as above but const
+ */
+ template<size_t N>
+ const auto &get_value_at() const
+ {
+ static_assert(N <= DerivativeOrder, "Requested depth exceeds variable order.");
+ return get_value_at_impl<N, DerivativeOrder>::get(*this);
+ }
+
+ RealType item() const
+ {
+ return get_item_impl(std::integral_constant<bool, (DerivativeOrder > 1)>{});
+ }
+
+ void backward()
+ {
+ gradient_tape<RealType, DerivativeOrder, BOOST_MATH_BUFFER_SIZE> &tape
+ = get_active_tape<RealType, DerivativeOrder>();
+ auto it = tape.find(node_);
+ it->update_adjoint_v(inner_t(static_cast<RealType>(1.0)));
+ while (it != tape.begin()) {
+ it->backward();
+ --it;
+ }
+ it->backward();
+ }
+
+ void set_item(RealType value) { value_ = inner_t(value); }
+};
+
+template<typename RealType, size_t DerivativeOrder>
+std::ostream &operator<<(std::ostream &os, const rvar<RealType, DerivativeOrder> var)
+{
+ os << "rvar<" << DerivativeOrder << ">(" << var.item() << "," << var.adjoint() << ")";
+ return os;
+}
+
+template<typename RealType, size_t DerivativeOrder, typename E>
+std::ostream &operator<<(std::ostream &os, const expression<RealType, DerivativeOrder, E> &expr)
+{
+ rvar<RealType, DerivativeOrder> tmp = expr;
+ os << "rvar<" << DerivativeOrder << ">(" << tmp.item() << "," << tmp.adjoint() << ")";
+ return os;
+}
+
+template<typename RealType, size_t DerivativeOrder>
+rvar<RealType, DerivativeOrder> make_rvar(const RealType v)
+{
+ static_assert(DerivativeOrder > 0, "rvar order must be >= 1");
+ return rvar<RealType, DerivativeOrder>(v);
+}
+template<typename RealType, size_t DerivativeOrder, typename E>
+rvar<RealType, DerivativeOrder> make_rvar(const expression<RealType, DerivativeOrder, E> &expr)
+{
+ static_assert(DerivativeOrder > 0, "rvar order must be >= 1");
+ return rvar<RealType, DerivativeOrder>(expr);
+}
+
+namespace detail {
+
+/** @brief helper overload for grad implementation.
+ * @return vector<rvar<T,order-1> of gradients of the autodiff graph.
+ * specialization for autodiffing through autodiff. i.e. being able to
+ * compute higher order grads
+*/
+template<typename RealType, size_t DerivativeOrder>
+struct grad_op_impl
+{
+ std::vector<rvar<RealType, DerivativeOrder - 1>> operator()(
+ rvar<RealType, DerivativeOrder> &f, std::vector<rvar<RealType, DerivativeOrder> *> &x)
+ {
+ auto &tape = get_active_tape<RealType, DerivativeOrder>();
+ tape.zero_grad();
+ f.backward();
+
+ std::vector<rvar<RealType, DerivativeOrder - 1>> gradient_vector;
+ gradient_vector.reserve(x.size());
+
+ for (auto &xi : x) {
+ gradient_vector.emplace_back(xi->adjoint());
+ }
+ return gradient_vector;
+ }
+};
+/** @brief helper overload for grad implementation.
+ * @return vector<T> of gradients of the autodiff graph.
+ * base specialization for order 1 autodiff
+*/
+template<typename T>
+struct grad_op_impl<T, 1>
+{
+ std::vector<T> operator()(rvar<T, 1> &f, std::vector<rvar<T, 1> *> &x)
+ {
+ gradient_tape<T, 1, BOOST_MATH_BUFFER_SIZE> &tape = get_active_tape<T, 1>();
+ tape.zero_grad();
+ f.backward();
+ std::vector<T> gradient_vector;
+ gradient_vector.reserve(x.size());
+ for (auto &xi : x) {
+ gradient_vector.push_back(xi->adjoint());
+ }
+ return gradient_vector;
+ }
+};
+
+/** @brief helper overload for higher order autodiff
+ * @return nested vector representing N-d tensor of
+ * higher order derivatives
+ */
+template<size_t N,
+ typename RealType,
+ size_t DerivativeOrder_1,
+ size_t DerivativeOrder_2,
+ typename Enable = void>
+struct grad_nd_impl
+{
+ auto operator()(rvar<RealType, DerivativeOrder_1> &f,
+ std::vector<rvar<RealType, DerivativeOrder_2> *> &x)
+ {
+ static_assert(N > 1, "N must be greater than 1 for this template");
+
+ auto current_grad = grad(f, x); // vector<rvar<T,DerivativeOrder_1-1>> or vector<T>
+
+ std::vector<decltype(grad_nd_impl<N - 1, RealType, DerivativeOrder_1 - 1, DerivativeOrder_2>()(
+ current_grad[0], x))>
+ result;
+ result.reserve(current_grad.size());
+
+ for (auto &g_i : current_grad) {
+ result.push_back(
+ grad_nd_impl<N - 1, RealType, DerivativeOrder_1 - 1, DerivativeOrder_2>()(g_i, x));
+ }
+ return result;
+ }
+};
+/** @brief spcialization for order = 1,
+ * @return vector<rvar<T,DerivativeOrder_1-1>> gradients */
+template<typename RealType, size_t DerivativeOrder_1, size_t DerivativeOrder_2>
+struct grad_nd_impl<1, RealType, DerivativeOrder_1, DerivativeOrder_2>
+{
+ auto operator()(rvar<RealType, DerivativeOrder_1> &f,
+ std::vector<rvar<RealType, DerivativeOrder_2> *> &x)
+ {
+ return grad(f, x);
+ }
+};
+
+template<typename ptr>
+struct rvar_order;
+
+template<typename RealType, size_t DerivativeOrder>
+struct rvar_order<rvar<RealType, DerivativeOrder> *>
+{
+ static constexpr size_t value = DerivativeOrder;
+};
+
+} // namespace detail
+
+/**
+ * @brief grad computes gradient with respect to vector of pointers x
+ * @param f -> computational graph
+ * @param x -> variables gradients to record. Note ALL gradients of the graph
+ * are computed simultaneously, only the ones w.r.t. x are returned
+ * @return vector<rvar<T,DerivativeOrder_1 - 1> of gradients. in the case of DerivativeOrder_1 = 1
+ * rvar<T,DerivativeOrder_1-1> decays to T
+ *
+ * safe to call recursively with grad(grad(grad...
+ */
+template<typename RealType, size_t DerivativeOrder_1, size_t DerivativeOrder_2>
+auto grad(rvar<RealType, DerivativeOrder_1> &f, std::vector<rvar<RealType, DerivativeOrder_2> *> &x)
+{
+ static_assert(DerivativeOrder_1 <= DerivativeOrder_2,
+ "variable differentiating w.r.t. must have order >= function order");
+ std::vector<rvar<RealType, DerivativeOrder_1> *> xx;
+ xx.reserve(x.size());
+ for (auto &xi : x)
+ xx.push_back(&(xi->template get_value_at<DerivativeOrder_1>()));
+ return detail::grad_op_impl<RealType, DerivativeOrder_1>{}(f, xx);
+}
+/** @brief variadic overload of above
+ */
+template<typename RealType, size_t DerivativeOrder_1, typename First, typename... Other>
+auto grad(rvar<RealType, DerivativeOrder_1> &f, First first, Other... other)
+{
+ constexpr size_t DerivativeOrder_2 = detail::rvar_order<First>::value;
+ static_assert(DerivativeOrder_1 <= DerivativeOrder_2,
+ "variable differentiating w.r.t. must have order >= function order");
+ std::vector<rvar<RealType, DerivativeOrder_2> *> x_vec = {first, other...};
+ return grad(f, x_vec);
+}
+
+/** @brief computes hessian matrix of computational graph w.r.t.
+ * vector of variables x.
+ * @return std::vector<std::vector<rvar<T,DerivativeOrder_1-2>> hessian matrix
+ * rvar<T,2> decays to T
+ *
+ * NOT recursion safe, cannot do hess(hess(
+ */
+template<typename RealType, size_t DerivativeOrder_1, size_t DerivativeOrder_2>
+auto hess(rvar<RealType, DerivativeOrder_1> &f, std::vector<rvar<RealType, DerivativeOrder_2> *> &x)
+{
+ return detail::grad_nd_impl<2, RealType, DerivativeOrder_1, DerivativeOrder_2>{}(f, x);
+}
+/** @brief variadic overload of above
+ */
+template<typename RealType, size_t DerivativeOrder_1, typename First, typename... Other>
+auto hess(rvar<RealType, DerivativeOrder_1> &f, First first, Other... other)
+{
+ constexpr size_t DerivativeOrder_2 = detail::rvar_order<First>::value;
+ std::vector<rvar<RealType, DerivativeOrder_2> *> x_vec = {first, other...};
+ return hess(f, x_vec);
+}
+
+/** @brief comput N'th gradient of computational graph w.r.t. x
+ * @return vector<vector<.... up N nestings representing tensor
+ * of gradients of order N
+ *
+ * NOT recursively safe, cannot do grad_nd(grad_nd(... etc...
+ */
+template<size_t N, typename RealType, size_t DerivativeOrder_1, size_t DerivativeOrder_2>
+auto grad_nd(rvar<RealType, DerivativeOrder_1> &f,
+ std::vector<rvar<RealType, DerivativeOrder_2> *> &x)
+{
+ static_assert(DerivativeOrder_1 >= N, "Function order must be at least N");
+ static_assert(DerivativeOrder_2 >= DerivativeOrder_1,
+ "Variable order must be at least function order");
+
+ return detail::grad_nd_impl<N, RealType, DerivativeOrder_1, DerivativeOrder_2>()(f, x);
+}
+
+/** @brief variadic overload of above
+ */
+template<size_t N, typename ftype, typename First, typename... Other>
+auto grad_nd(ftype &f, First first, Other... other)
+{
+ using RealType = typename ftype::value_type;
+ constexpr size_t DerivativeOrder_1 = detail::rvar_order<ftype *>::value;
+ constexpr size_t DerivativeOrder_2 = detail::rvar_order<First>::value;
+ std::vector<rvar<RealType, DerivativeOrder_2> *> x_vec = {first, other...};
+ return detail::grad_nd_impl<N, RealType, DerivativeOrder_1, DerivativeOrder_1>{}(f, x_vec);
+}
+} // namespace reverse_mode
+} // namespace differentiation
+} // namespace math
+} // namespace boost
+namespace std {
+
+// copied from forward mode
+template<typename RealType, size_t DerivativeOrder>
+class numeric_limits<boost::math::differentiation::reverse_mode::rvar<RealType, DerivativeOrder>>
+ : public numeric_limits<typename boost::math::differentiation::reverse_mode::
+ rvar<RealType, DerivativeOrder>::value_type>
+{};
+} // namespace std
+#endif
diff --git a/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_basic_operator_expressions.hpp b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_basic_operator_expressions.hpp
new file mode 100644
index 0000000000000..9efd485bca0f1
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_basic_operator_expressions.hpp
@@ -0,0 +1,276 @@
+// 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_AUTODOFF_BASIC_OPERATOR_OVERLOADS_HPP
+#define REVERSE_MODE_AUTODOFF_BASIC_OPERATOR_OVERLOADS_HPP
+
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_expression_template_base.hpp>
+
+namespace boost {
+namespace math {
+namespace differentiation {
+namespace reverse_mode {
+/****************************************************************************************************************/
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+struct add_expr : public abstract_binary_expression<RealType,
+ DerivativeOrder,
+ LHS,
+ RHS,
+ add_expr<RealType, DerivativeOrder, LHS, RHS>>
+{
+ /* @brief addition
+ * rvar+rvar
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+ // Explicitly define constructor to forward to base class
+ explicit add_expr(const expression<RealType, DerivativeOrder, LHS> &left_hand_expr,
+ const expression<RealType, DerivativeOrder, RHS> &right_hand_expr)
+ : abstract_binary_expression<RealType,
+ DerivativeOrder,
+ LHS,
+ RHS,
+ add_expr<RealType, DerivativeOrder, LHS, RHS>>(left_hand_expr,
+ right_hand_expr)
+ {}
+
+ inner_t evaluate() const { return this->lhs.evaluate() + this->rhs.evaluate(); }
+ static const inner_t left_derivative(const inner_t & /*l*/,
+ const inner_t & /*r*/,
+ const inner_t & /*v*/)
+ {
+ return inner_t(static_cast<RealType>(1.0));
+ }
+ static const inner_t right_derivative(const inner_t & /*l*/,
+ const inner_t & /*r*/,
+ const inner_t & /*v*/)
+ {
+ return inner_t(static_cast<RealType>(1.0));
+ }
+};
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct add_const_expr
+ : public abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ add_const_expr<RealType, DerivativeOrder, ARG>>
+{
+ /* @brief
+ * rvar+float or float+rvar
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+ explicit add_const_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr,
+ const RealType v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ add_const_expr<RealType, DerivativeOrder, ARG>>(arg_expr, v){};
+ inner_t evaluate() const { return this->arg.evaluate() + inner_t(this->constant); }
+ static const inner_t derivative(const inner_t & /*argv*/,
+ const inner_t & /*v*/,
+ const RealType & /*constant*/)
+ {
+ return inner_t(static_cast<RealType>(1.0));
+ }
+};
+/****************************************************************************************************************/
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+struct mult_expr : public abstract_binary_expression<RealType,
+ DerivativeOrder,
+ LHS,
+ RHS,
+ mult_expr<RealType, DerivativeOrder, LHS, RHS>>
+{
+ /* @brief multiplication
+ * rvar * rvar
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+ explicit mult_expr(const expression<RealType, DerivativeOrder, LHS> &left_hand_expr,
+ const expression<RealType, DerivativeOrder, RHS> &right_hand_expr)
+ : abstract_binary_expression<RealType,
+ DerivativeOrder,
+ LHS,
+ RHS,
+ mult_expr<RealType, DerivativeOrder, LHS, RHS>>(left_hand_expr,
+ right_hand_expr)
+ {}
+
+ inner_t evaluate() const { return this->lhs.evaluate() * this->rhs.evaluate(); };
+ static const inner_t left_derivative(const inner_t & /*l*/,
+ const inner_t &r,
+ const inner_t & /*v*/) noexcept
+ {
+ return r;
+ };
+ static const inner_t right_derivative(const inner_t &l,
+ const inner_t & /*r*/,
+ const inner_t & /*v*/) noexcept
+ {
+ return l;
+ };
+};
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct mult_const_expr
+ : public abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ mult_const_expr<RealType, DerivativeOrder, ARG>>
+{
+ /* @brief
+ * rvar+float or float+rvar
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit mult_const_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr,
+ const RealType v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ mult_const_expr<RealType, DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const { return this->arg.evaluate() * inner_t(this->constant); }
+ static const inner_t derivative(const inner_t & /*argv*/,
+ const inner_t & /*v*/,
+ const RealType &constant)
+ {
+ return inner_t(constant);
+ }
+};
+/****************************************************************************************************************/
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+struct sub_expr : public abstract_binary_expression<RealType,
+ DerivativeOrder,
+ LHS,
+ RHS,
+ sub_expr<RealType, DerivativeOrder, LHS, RHS>>
+{
+ /* @brief addition
+ * rvar-rvar
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+ // Explicitly define constructor to forward to base class
+ explicit sub_expr(const expression<RealType, DerivativeOrder, LHS> &left_hand_expr,
+ const expression<RealType, DerivativeOrder, RHS> &right_hand_expr)
+ : abstract_binary_expression<RealType,
+ DerivativeOrder,
+ LHS,
+ RHS,
+ sub_expr<RealType, DerivativeOrder, LHS, RHS>>(left_hand_expr,
+ right_hand_expr)
+ {}
+
+ inner_t evaluate() const { return this->lhs.evaluate() - this->rhs.evaluate(); }
+ static const inner_t left_derivative(const inner_t & /*l*/,
+ const inner_t & /*r*/,
+ const inner_t & /*v*/)
+ {
+ return inner_t(static_cast<RealType>(1.0));
+ }
+ static const inner_t right_derivative(const inner_t & /*l*/,
+ const inner_t & /*r*/,
+ const inner_t & /*v*/)
+ {
+ return inner_t(static_cast<RealType>(-1.0));
+ }
+};
+
+/****************************************************************************************************************/
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+struct div_expr : public abstract_binary_expression<RealType,
+ DerivativeOrder,
+ LHS,
+ RHS,
+ div_expr<RealType, DerivativeOrder, LHS, RHS>>
+{
+ /* @brief multiplication
+ * rvar / rvar
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+ // Explicitly define constructor to forward to base class
+ explicit div_expr(const expression<RealType, DerivativeOrder, LHS> &left_hand_expr,
+ const expression<RealType, DerivativeOrder, RHS> &right_hand_expr)
+ : abstract_binary_expression<RealType,
+ DerivativeOrder,
+ LHS,
+ RHS,
+ div_expr<RealType, DerivativeOrder, LHS, RHS>>(left_hand_expr,
+ right_hand_expr)
+ {}
+
+ inner_t evaluate() const { return this->lhs.evaluate() / this->rhs.evaluate(); };
+ static const inner_t left_derivative(const inner_t & /*l*/,
+ const inner_t &r,
+ const inner_t & /*v*/)
+ {
+ return static_cast<RealType>(1.0) / r;
+ };
+ static const inner_t right_derivative(const inner_t &l, const inner_t &r, const inner_t & /*v*/)
+ {
+ return -l / (r * r);
+ };
+};
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct div_by_const_expr
+ : public abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ div_by_const_expr<RealType, DerivativeOrder, ARG>>
+{
+ /* @brief
+ * rvar/float
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit div_by_const_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr,
+ const RealType v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ div_by_const_expr<RealType, DerivativeOrder, ARG>>(arg_expr,
+ v){};
+
+ inner_t evaluate() const { return this->arg.evaluate() / inner_t(this->constant); }
+ static const inner_t derivative(const inner_t & /*argv*/,
+ const inner_t & /*v*/,
+ const RealType &constant)
+ {
+ return inner_t(1.0 / constant);
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct const_div_by_expr
+ : public abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ const_div_by_expr<RealType, DerivativeOrder, ARG>>
+{
+ /** @brief
+ * float/rvar
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit const_div_by_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr,
+ const RealType v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ const_div_by_expr<RealType, DerivativeOrder, ARG>>(arg_expr,
+ v){};
+
+ inner_t evaluate() const { return inner_t(this->constant) / this->arg.evaluate(); }
+ static const inner_t derivative(const inner_t &argv,
+ const inner_t & /*v*/,
+ const RealType &constant)
+ {
+ return -inner_t{constant} / (argv * argv);
+ }
+};
+/****************************************************************************************************************/
+
+} // namespace reverse_mode
+} // namespace differentiation
+} // namespace math
+} // namespace boost
+
+#endif
diff --git a/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_basic_ops_et.hpp b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_basic_ops_et.hpp
new file mode 100644
index 0000000000000..9d552fbe92a80
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_basic_ops_et.hpp
@@ -0,0 +1,160 @@
+// 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_BASIC_OPS_ET_HPP
+#define REVERSE_MODE_AUTODIFF_BASIC_OPS_ET_HPP
+
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_basic_operator_expressions.hpp>
+namespace boost {
+namespace math {
+namespace differentiation {
+namespace reverse_mode {
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+mult_expr<RealType, DerivativeOrder, LHS, RHS> operator*(
+ const expression<RealType, DerivativeOrder, LHS> &lhs,
+ const expression<RealType, DerivativeOrder, RHS> &rhs)
+{
+ return mult_expr<RealType, DerivativeOrder, LHS, RHS>(lhs, rhs);
+}
+
+/** @brief type promotion is handled by casting the numeric type to
+ * the type inside expression. This is to avoid converting the
+ * entire tape in case you have something like double * rvar<float>
+ * */
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ typename ARG,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+mult_const_expr<RealType1, DerivativeOrder, ARG> operator*(
+ const expression<RealType1, DerivativeOrder, ARG> &arg, const RealType2 &v)
+{
+ return mult_const_expr<RealType1, DerivativeOrder, ARG>(arg, static_cast<RealType1>(v));
+}
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ typename ARG,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+mult_const_expr<RealType1, DerivativeOrder, ARG> operator*(
+ const RealType2 &v, const expression<RealType1, DerivativeOrder, ARG> &arg)
+{
+ return mult_const_expr<RealType1, DerivativeOrder, ARG>(arg, static_cast<RealType1>(v));
+}
+/****************************************************************************************************************/
+/* + */
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+add_expr<RealType, DerivativeOrder, LHS, RHS> operator+(
+ const expression<RealType, DerivativeOrder, LHS> &lhs,
+ const expression<RealType, DerivativeOrder, RHS> &rhs)
+{
+ return add_expr<RealType, DerivativeOrder, LHS, RHS>(lhs, rhs);
+}
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ typename ARG,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+add_const_expr<RealType1, DerivativeOrder, ARG> operator+(
+ const expression<RealType1, DerivativeOrder, ARG> &arg, const RealType2 &v)
+{
+ return add_const_expr<RealType1, DerivativeOrder, ARG>(arg, static_cast<RealType1>(v));
+}
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ typename ARG,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+add_const_expr<RealType1, DerivativeOrder, ARG> operator+(
+ const RealType2 &v, const expression<RealType1, DerivativeOrder, ARG> &arg)
+{
+ return add_const_expr<RealType1, DerivativeOrder, ARG>(arg, static_cast<RealType1>(v));
+}
+/****************************************************************************************************************/
+/* - overload */
+/** @brief
+ * negation (-1.0*rvar) */
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+mult_const_expr<RealType, DerivativeOrder, ARG> operator-(
+ const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return mult_const_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(-1.0));
+}
+
+/** @brief
+ * subtraction rvar-rvar */
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+sub_expr<RealType, DerivativeOrder, LHS, RHS> operator-(
+ const expression<RealType, DerivativeOrder, LHS> &lhs,
+ const expression<RealType, DerivativeOrder, RHS> &rhs)
+{
+ return sub_expr<RealType, DerivativeOrder, LHS, RHS>(lhs, rhs);
+}
+
+/** @brief
+ * subtraction float - rvar */
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ typename ARG,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+add_const_expr<RealType1, DerivativeOrder, ARG> operator-(
+ const expression<RealType1, DerivativeOrder, ARG> &arg, const RealType2 &v)
+{
+ /* rvar - float = rvar + (-float) */
+ return add_const_expr<RealType1, DerivativeOrder, ARG>(arg, static_cast<RealType1>(-v));
+}
+
+/** @brief
+ * subtraction float - rvar
+ * @return add_expr<neg_expr<ARG>>
+ */
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ typename ARG,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+auto operator-(const RealType2 &v, const expression<RealType1, DerivativeOrder, ARG> &arg)
+{
+ auto neg = -arg;
+ return neg + static_cast<RealType1>(v);
+}
+/****************************************************************************************************************/
+/* / */
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+div_expr<RealType, DerivativeOrder, LHS, RHS> operator/(
+ const expression<RealType, DerivativeOrder, LHS> &lhs,
+ const expression<RealType, DerivativeOrder, RHS> &rhs)
+{
+ return div_expr<RealType, DerivativeOrder, LHS, RHS>(lhs, rhs);
+}
+
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ typename ARG,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+const_div_by_expr<RealType1, DerivativeOrder, ARG> operator/(
+ const RealType2 &v, const expression<RealType1, DerivativeOrder, ARG> &arg)
+{
+ return const_div_by_expr<RealType1, DerivativeOrder, ARG>(arg, static_cast<RealType1>(v));
+}
+
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ typename ARG,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+div_by_const_expr<RealType1, DerivativeOrder, ARG> operator/(
+ const expression<RealType1, DerivativeOrder, ARG> &arg, const RealType2 &v)
+{
+ return div_by_const_expr<RealType1, DerivativeOrder, ARG>(arg, static_cast<RealType1>(v));
+}
+} // namespace reverse_mode
+} // namespace differentiation
+} // namespace math
+} // namespace boost
+
+#endif // REVERSE_MODE_AUTODIFF_BASIC_OPS_ET_HPP
diff --git a/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_basic_ops_no_et.hpp b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_basic_ops_no_et.hpp
new file mode 100644
index 0000000000000..67c1fb77e968a
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_basic_ops_no_et.hpp
@@ -0,0 +1,154 @@
+// 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_BASIC_OPS_NO_ET_HPP
+#define REVERSE_MODE_AUTODIFF_BASIC_OPS_NO_ET_HPP
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_basic_operator_expressions.hpp>
+namespace boost {
+namespace math {
+namespace differentiation {
+namespace reverse_mode {
+
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+rvar<RealType, DerivativeOrder> operator*(const expression<RealType, DerivativeOrder, LHS> &lhs,
+ const expression<RealType, DerivativeOrder, RHS> &rhs)
+{
+ return mult_expr<RealType, DerivativeOrder, LHS, RHS>(lhs, rhs);
+}
+
+/** @brief type promotion is handled by casting the numeric type to
+ * the type inside expression. This is to avoid converting the
+ * entire tape in case you have something like double * rvar<float>
+ * */
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ typename ARG,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+rvar<RealType1, DerivativeOrder> operator*(const expression<RealType1, DerivativeOrder, ARG> &arg,
+ const RealType2 &v)
+{
+ return mult_const_expr<RealType1, DerivativeOrder, ARG>(arg, static_cast<RealType1>(v));
+}
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ typename ARG,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+rvar<RealType1, DerivativeOrder> operator*(const RealType2 &v,
+ const expression<RealType1, DerivativeOrder, ARG> &arg)
+{
+ return mult_const_expr<RealType1, DerivativeOrder, ARG>(arg, static_cast<RealType1>(v));
+}
+/****************************************************************************************************************/
+/* + */
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+rvar<RealType, DerivativeOrder> operator+(const expression<RealType, DerivativeOrder, LHS> &lhs,
+ const expression<RealType, DerivativeOrder, RHS> &rhs)
+{
+ return add_expr<RealType, DerivativeOrder, LHS, RHS>(lhs, rhs);
+}
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ typename ARG,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+rvar<RealType1, DerivativeOrder> operator+(const expression<RealType1, DerivativeOrder, ARG> &arg,
+ const RealType2 &v)
+{
+ return add_const_expr<RealType1, DerivativeOrder, ARG>(arg, static_cast<RealType1>(v));
+}
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ typename ARG,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+rvar<RealType1, DerivativeOrder> operator+(const RealType2 &v,
+ const expression<RealType1, DerivativeOrder, ARG> &arg)
+{
+ return add_const_expr<RealType1, DerivativeOrder, ARG>(arg, static_cast<RealType1>(v));
+}
+/****************************************************************************************************************/
+/* - overload */
+/** @brief
+ * negation (-1.0*rvar) */
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> operator-(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return mult_const_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(-1.0));
+}
+
+/** @brief
+ * subtraction rvar-rvar */
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+rvar<RealType, DerivativeOrder> operator-(const expression<RealType, DerivativeOrder, LHS> &lhs,
+ const expression<RealType, DerivativeOrder, RHS> &rhs)
+{
+ return sub_expr<RealType, DerivativeOrder, LHS, RHS>(lhs, rhs);
+}
+
+/** @brief
+ * subtraction float - rvar */
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ typename ARG,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+rvar<RealType1, DerivativeOrder> operator-(const expression<RealType1, DerivativeOrder, ARG> &arg,
+ const RealType2 &v)
+{
+ /* rvar - float = rvar + (-float) */
+ return add_const_expr<RealType1, DerivativeOrder, ARG>(arg, -static_cast<RealType1>(v));
+}
+
+/** @brief
+ * subtraction float - rvar
+ * @return add_expr<neg_expr<ARG>>
+ */
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ typename ARG,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+rvar<RealType1, DerivativeOrder> operator-(const RealType2 &v,
+ const expression<RealType1, DerivativeOrder, ARG> &arg)
+{
+ auto neg = -arg;
+ return neg + static_cast<RealType1>(v);
+}
+/****************************************************************************************************************/
+/* / */
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+rvar<RealType, DerivativeOrder> operator/(const expression<RealType, DerivativeOrder, LHS> &lhs,
+ const expression<RealType, DerivativeOrder, RHS> &rhs)
+{
+ return div_expr<RealType, DerivativeOrder, LHS, RHS>(lhs, rhs);
+}
+
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ typename ARG,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+rvar<RealType1, DerivativeOrder> operator/(const RealType2 &v,
+ const expression<RealType1, DerivativeOrder, ARG> &arg)
+{
+ return const_div_by_expr<RealType1, DerivativeOrder, ARG>(arg, static_cast<RealType1>(v));
+}
+
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ typename ARG,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+rvar<RealType1, DerivativeOrder> operator/(const expression<RealType1, DerivativeOrder, ARG> &arg,
+ const RealType2 &v)
+{
+ return div_by_const_expr<RealType1, DerivativeOrder, ARG>(arg, static_cast<RealType1>(v));
+}
+} // namespace reverse_mode
+} // namespace differentiation
+} // namespace math
+} // namespace boost
+#endif
diff --git a/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_comparison_operator_overloads.hpp b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_comparison_operator_overloads.hpp
new file mode 100644
index 0000000000000..768cdcc0848bb
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_comparison_operator_overloads.hpp
@@ -0,0 +1,167 @@
+// 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_COMPARISON_OPERATOR_OVERLOADS_HPP
+#define REVERSE_MODE_AUTODIFF_COMPARISON_OPERATOR_OVERLOADS_HPP
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_expression_template_base.hpp>
+namespace boost {
+namespace math {
+namespace differentiation {
+namespace reverse_mode {
+template<typename RealType, size_t DerivativeOrder1, size_t DerivativeOrder2, class LhsExpr, class RhsExpr>
+bool operator==(const expression<RealType, DerivativeOrder1, LhsExpr> &lhs,
+ const expression<RealType, DerivativeOrder2, RhsExpr> &rhs)
+{
+ return lhs.evaluate() == rhs.evaluate();
+}
+
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ class ArgExpr,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+bool operator==(const expression<RealType1, DerivativeOrder, ArgExpr> &lhs, const RealType2 &rhs)
+{
+ return lhs.evaluate() == static_cast<RealType1>(rhs);
+}
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ class ArgExpr,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+bool operator==(const RealType2 &lhs, const expression<RealType1, DerivativeOrder, ArgExpr> &rhs)
+{
+ return lhs == rhs.evaluate();
+}
+
+template<typename RealType, size_t DerivativeOrder1, size_t DerivativeOrder2, class LhsExpr, class RhsExpr>
+bool operator!=(const expression<RealType, DerivativeOrder1, LhsExpr> &lhs,
+ const expression<RealType, DerivativeOrder2, RhsExpr> &rhs)
+{
+ return lhs.evaluate() != rhs.evaluate();
+}
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ class ArgExpr,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+bool operator!=(const expression<RealType1, DerivativeOrder, ArgExpr> &lhs, const RealType2 &rhs)
+{
+ return lhs.evaluate() != rhs;
+}
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ class ArgExpr,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+bool operator!=(const RealType2 &lhs, const expression<RealType1, DerivativeOrder, ArgExpr> &rhs)
+{
+ return lhs != rhs.evaluate();
+}
+
+template<typename RealType, size_t DerivativeOrder1, size_t DerivativeOrder2, class LhsExpr, class RhsExpr>
+bool operator<(const expression<RealType, DerivativeOrder1, LhsExpr> &lhs,
+ const expression<RealType, DerivativeOrder2, RhsExpr> &rhs)
+{
+ return lhs.evaluate() < rhs.evaluate();
+}
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ class ArgExpr,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+bool operator<(const expression<RealType1, DerivativeOrder, ArgExpr> &lhs, const RealType2 &rhs)
+{
+ return lhs.evaluate() < rhs;
+}
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ class ArgExpr,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+bool operator<(const RealType2 &lhs, const expression<RealType1, DerivativeOrder, ArgExpr> &rhs)
+{
+ return lhs < rhs.evaluate();
+}
+
+template<typename RealType, size_t DerivativeOrder1, size_t DerivativeOrder2, class LhsExpr, class RhsExpr>
+bool operator>(const expression<RealType, DerivativeOrder1, LhsExpr> &lhs,
+ const expression<RealType, DerivativeOrder2, RhsExpr> &rhs)
+{
+ return lhs.evaluate() > rhs.evaluate();
+}
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ class ArgExpr,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+bool operator>(const expression<RealType1, DerivativeOrder, ArgExpr> &lhs, const RealType2 &rhs)
+{
+ return lhs.evaluate() > rhs;
+}
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ class ArgExpr,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+bool operator>(const RealType2 &lhs, const expression<RealType1, DerivativeOrder, ArgExpr> &rhs)
+{
+ return lhs > rhs.evaluate();
+}
+
+template<typename RealType, size_t DerivativeOrder1, size_t DerivativeOrder2, class LhsExpr, class RhsExpr>
+bool operator<=(const expression<RealType, DerivativeOrder1, LhsExpr> &lhs,
+ const expression<RealType, DerivativeOrder2, RhsExpr> &rhs)
+{
+ return lhs.evaluate() <= rhs.evaluate();
+}
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ class ArgExpr,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+bool operator<=(const expression<RealType1, DerivativeOrder, ArgExpr> &lhs, const RealType2 &rhs)
+{
+ return lhs.evaluate() <= rhs;
+}
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ class ArgExpr,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+bool operator<=(const RealType2 &lhs, const expression<RealType1, DerivativeOrder, ArgExpr> &rhs)
+{
+ return lhs <= rhs.evaluate();
+}
+
+template<typename RealType, size_t DerivativeOrder1, size_t DerivativeOrder2, class LhsExpr, class RhsExpr>
+bool operator>=(const expression<RealType, DerivativeOrder1, LhsExpr> &lhs,
+ const expression<RealType, DerivativeOrder2, RhsExpr> &rhs)
+{
+ return lhs.evaluate() >= rhs.evaluate();
+}
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ class ArgExpr,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+bool operator>=(const expression<RealType1, DerivativeOrder, ArgExpr> &lhs, const RealType2 &rhs)
+{
+ return lhs.evaluate() >= rhs;
+}
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ class ArgExpr,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+bool operator>=(const RealType2 &lhs, const expression<RealType1, DerivativeOrder, ArgExpr> &rhs)
+{
+ return lhs >= rhs.evaluate();
+}
+} // namespace reverse_mode
+} // namespace differentiation
+} // namespace math
+} // namespace boost
+#endif // REVERSE_MODE_AUTODIFF_COMPARISON_OPERATOR_OVERLOADS_HPP
diff --git a/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_erf_overloads.hpp b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_erf_overloads.hpp
new file mode 100644
index 0000000000000..5c885f9e2b2fb
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_erf_overloads.hpp
@@ -0,0 +1,234 @@
+// 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 <boost/math/constants/constants.hpp>
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_expression_template_base.hpp>
+
+#ifdef BOOST_MATH_REVERSE_MODE_ET_ON
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_stl_et.hpp>
+#else
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_stl_no_et.hpp>
+#endif
+
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_utilities.hpp>
+#include <boost/math/special_functions/erf.hpp>
+
+namespace boost {
+namespace math {
+namespace differentiation {
+namespace reverse_mode {
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct erf_expr;
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct erfc_expr;
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct erf_inv_expr;
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct erfc_inv_expr;
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+erf_expr<RealType, DerivativeOrder, ARG> erf(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return erf_expr<RealType, DerivativeOrder, ARG>(arg, 0.0);
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+erfc_expr<RealType, DerivativeOrder, ARG> erfc(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return erfc_expr<RealType, DerivativeOrder, ARG>(arg, 0.0);
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+erf_inv_expr<RealType, DerivativeOrder, ARG> erf_inv(
+ const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return erf_inv_expr<RealType, DerivativeOrder, ARG>(arg, 0.0);
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+erfc_inv_expr<RealType, DerivativeOrder, ARG> erfc_inv(
+ const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return erfc_inv_expr<RealType, DerivativeOrder, ARG>(arg, 0.0);
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct erf_expr : public abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ erf_expr<RealType, DerivativeOrder, ARG>>
+{
+ /** @brief erf(x)
+ *
+ * d/dx erf(x) = 2*exp(x^2)/sqrt(pi)
+ *
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit erf_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ erf_expr<RealType, DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ return detail::if_functional_dispatch<(DerivativeOrder > 1)>(
+ [this](auto &&x) { return reverse_mode::erf(std::forward<decltype(x)>(x)); },
+ [this](auto &&x) { return boost::math::erf(std::forward<decltype(x)>(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<RealType>(2.0) * exp(-argv * argv) / sqrt(constants::pi<RealType>());
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct erfc_expr : public abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ erfc_expr<RealType, DerivativeOrder, ARG>>
+{
+ /** @brief erfc(x)
+ *
+ * d/dx erf(x) = -2*exp(x^2)/sqrt(pi)
+ *
+ * */
+
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit erfc_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ erfc_expr<RealType, DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ return detail::if_functional_dispatch<((DerivativeOrder > 1))>(
+ [this](auto &&x) { return reverse_mode::erfc(std::forward<decltype(x)>(x)); },
+ [this](auto &&x) { return boost::math::erfc(std::forward<decltype(x)>(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<RealType>(-2.0) * exp(-argv * argv) / sqrt(constants::pi<RealType>());
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct erf_inv_expr : public abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ erf_inv_expr<RealType, DerivativeOrder, ARG>>
+{
+ /** @brief erf(x)
+ *
+ * d/dx erf(x) = 2*exp(x^2)/sqrt(pi)
+ *
+ * */
+
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit erf_inv_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr,
+ const RealType v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ erf_inv_expr<RealType, DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ return detail::if_functional_dispatch<((DerivativeOrder > 1))>(
+ [this](auto &&x) { return reverse_mode::erf_inv(std::forward<decltype(x)>(x)); },
+ [this](auto &&x) { return boost::math::erf_inv(std::forward<decltype(x)>(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<RealType>(0.5) * sqrt(constants::pi<RealType>())
+ * reverse_mode::exp(
+ reverse_mode::pow(reverse_mode::erf_inv(x), static_cast<RealType>(2.0)));
+ },
+ [](auto &&x) {
+ return static_cast<RealType>(0.5) * sqrt(constants::pi<RealType>())
+ * exp(pow(boost::math::erf_inv(x), static_cast<RealType>(2.0)));
+ },
+ argv);
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct erfc_inv_expr
+ : public abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ erfc_inv_expr<RealType, DerivativeOrder, ARG>>
+{
+ /** @brief erfc(x)
+ *
+ * d/dx erf(x) = -2*exp(x^2)/sqrt(pi)
+ *
+ * */
+
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit erfc_inv_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr,
+ const RealType v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ erfc_inv_expr<RealType, DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ return detail::if_functional_dispatch<((DerivativeOrder > 1))>(
+ [this](auto &&x) { return reverse_mode::erfc_inv(std::forward<decltype(x)>(x)); },
+ [this](auto &&x) { return boost::math::erfc_inv(std::forward<decltype(x)>(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<RealType>(-0.5) * sqrt(constants::pi<RealType>())
+ * reverse_mode::exp(reverse_mode::pow(reverse_mode::erfc_inv(x),
+ static_cast<RealType>(2.0)));
+ },
+ [](auto &&x) {
+ return static_cast<RealType>(-0.5) * sqrt(constants::pi<RealType>())
+ * exp(pow(boost::math::erfc_inv(x), static_cast<RealType>(2.0)));
+ },
+ argv);
+ }
+};
+
+} // namespace reverse_mode
+} // namespace differentiation
+} // namespace math
+} // namespace boost
+
+#endif // REVERSE_MODE_AUTODIFF_ERF_OVERLOADS_HPP
diff --git a/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_expression_template_base.hpp b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_expression_template_base.hpp
new file mode 100644
index 0000000000000..494b317c67925
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_expression_template_base.hpp
@@ -0,0 +1,258 @@
+// 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_EXPRESSION_TEMPLATE_BASE_HPP
+#define REVERSE_MODE_AUTODIFF_EXPRESSION_TEMPLATE_BASE_HPP
+#include <cstddef>
+#include <type_traits>
+namespace boost {
+namespace math {
+namespace differentiation {
+namespace reverse_mode {
+
+/* forward declarations for utitlity functions */
+struct expression_base
+{};
+
+template<typename RealType, size_t DerivativeOrder, class DerivedExpression>
+struct expression;
+
+template<typename RealType, size_t DerivativeOrder>
+class rvar;
+
+template<typename RealType,
+ size_t DerivativeOrder,
+ typename LHS,
+ typename RHS,
+ typename ConcreteBinaryOperation>
+struct abstract_binary_expression;
+
+template<typename RealType, size_t DerivativeOrder, typename ARG, typename ConcreteUnaryOperation>
+
+struct abstract_unary_expression;
+
+template<typename RealType, size_t DerivativeOrder>
+class gradient_node; // forward declaration for tape
+
+namespace detail {
+template<typename...>
+using void_t = void;
+// Check if T has a 'value_type' alias
+template<typename T, typename Enable = void>
+struct has_value_type : std::false_type
+{};
+template<typename T>
+struct has_value_type<T, void_t<typename T::value_type>> : std::true_type
+{};
+template<typename T, typename Enable = void>
+struct has_binary_sub_types : std::false_type
+{};
+template<typename T>
+struct has_binary_sub_types<T, void_t<typename T::lhs_type, typename T::rhs_type>> : std::true_type
+{};
+template<typename T, typename Enable = void>
+struct has_unary_sub_type : std::false_type
+{};
+template<typename T>
+struct has_unary_sub_type<T, void_t<typename T::arg_type>> : std::true_type
+{};
+
+template<typename T, size_t order, typename Enable = void>
+struct count_rvar_impl
+{
+ static constexpr std::size_t value = 0;
+};
+template<typename RealType, size_t DerivativeOrder>
+struct count_rvar_impl<rvar<RealType, DerivativeOrder>, DerivativeOrder>
+{
+ static constexpr std::size_t value = 1;
+};
+
+template<typename RealType, std::size_t DerivativeOrder>
+struct count_rvar_impl<
+ RealType,
+ DerivativeOrder,
+ std::enable_if_t<has_binary_sub_types<RealType>::value
+ && !std::is_same<RealType, rvar<typename RealType::value_type, DerivativeOrder>>::value
+ && !has_unary_sub_type<RealType>::value>>
+{
+ static constexpr std::size_t value
+ = count_rvar_impl<typename RealType::lhs_type, DerivativeOrder>::value
+ + count_rvar_impl<typename RealType::rhs_type, DerivativeOrder>::value;
+};
+
+template<typename RealType, size_t DerivativeOrder>
+struct count_rvar_impl<
+ RealType,
+ DerivativeOrder,
+ typename std::enable_if_t<
+ has_unary_sub_type<RealType>::value
+ && !std::is_same<RealType, rvar<typename RealType::value_type, DerivativeOrder>>::value
+ && !has_binary_sub_types<RealType>::value>>
+{
+ static constexpr std::size_t value
+ = count_rvar_impl<typename RealType::arg_type, DerivativeOrder>::value;
+};
+template<typename RealType, size_t DerivativeOrder>
+constexpr std::size_t count_rvars = detail::count_rvar_impl<RealType, DerivativeOrder>::value;
+
+template<typename T>
+struct is_expression : std::is_base_of<expression_base, typename std::decay<T>::type>
+{};
+
+template<typename RealType, size_t N>
+struct rvar_type_impl
+{
+ using type = rvar<RealType, N>;
+};
+
+template<typename RealType>
+struct rvar_type_impl<RealType, 0>
+{
+ using type = RealType;
+};
+
+} // namespace detail
+
+template<typename T, size_t N>
+using rvar_t = typename detail::rvar_type_impl<T, N>::type;
+
+template<typename RealType, size_t DerivativeOrder, class DerivedExpression>
+struct expression : expression_base
+{
+ /* @brief
+ * base expression class
+ * */
+
+ using value_type = RealType;
+ static constexpr size_t order_v = DerivativeOrder;
+ using derived_type = DerivedExpression;
+
+ static constexpr size_t num_literals = 0;
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+ inner_t evaluate() const { return static_cast<const DerivedExpression *>(this)->evaluate(); }
+
+ template<size_t arg_index>
+ void propagatex(gradient_node<RealType, DerivativeOrder> *node, inner_t adj) const
+ {
+ return static_cast<const DerivedExpression *>(this)->template propagatex<arg_index>(node,
+ adj);
+ }
+};
+
+template<typename RealType,
+ size_t DerivativeOrder,
+ typename LHS,
+ typename RHS,
+ typename ConcreteBinaryOperation>
+struct abstract_binary_expression
+ : public expression<
+ RealType,
+ DerivativeOrder,
+ abstract_binary_expression<RealType, DerivativeOrder, LHS, RHS, ConcreteBinaryOperation>>
+{
+ using lhs_type = LHS;
+ using rhs_type = RHS;
+ using value_type = RealType;
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+ const lhs_type lhs;
+ const rhs_type rhs;
+
+ explicit abstract_binary_expression(
+ const expression<RealType, DerivativeOrder, LHS> &left_hand_expr,
+ const expression<RealType, DerivativeOrder, RHS> &right_hand_expr)
+ : lhs(static_cast<const LHS &>(left_hand_expr))
+ , rhs(static_cast<const RHS &>(right_hand_expr)){};
+
+ inner_t evaluate() const
+ {
+ return static_cast<const ConcreteBinaryOperation *>(this)->evaluate();
+ };
+
+ template<size_t arg_index>
+ void propagatex(gradient_node<RealType, DerivativeOrder> *node, inner_t adj) const
+ {
+ const inner_t lv = lhs.evaluate();
+ const inner_t rv = rhs.evaluate();
+ const inner_t v = evaluate();
+ const inner_t partial_l = ConcreteBinaryOperation::left_derivative(lv, rv, v);
+ const inner_t partial_r = ConcreteBinaryOperation::right_derivative(lv, rv, v);
+
+ constexpr size_t num_lhs_args = detail::count_rvars<LHS, DerivativeOrder>;
+ constexpr size_t num_rhs_args = detail::count_rvars<RHS, DerivativeOrder>;
+
+ propagate_lhs<num_lhs_args, arg_index>(node, adj * partial_l);
+ propagate_rhs<num_rhs_args, arg_index + num_lhs_args>(node, adj * partial_r);
+ }
+
+private:
+ /* everything here just emulates c++17 if constexpr */
+
+ template<std::size_t num_args,
+ std::size_t arg_index_,
+ typename std::enable_if<(num_args > 0), int>::type = 0>
+ void propagate_lhs(gradient_node<RealType, DerivativeOrder> *node, inner_t adj) const
+ {
+ lhs.template propagatex<arg_index_>(node, adj);
+ }
+
+ template<std::size_t num_args,
+ std::size_t arg_index_,
+ typename std::enable_if<(num_args == 0), int>::type = 0>
+ void propagate_lhs(gradient_node<RealType, DerivativeOrder> *, inner_t) const
+ {}
+
+ template<std::size_t num_args,
+ std::size_t arg_index_,
+ typename std::enable_if<(num_args > 0), int>::type = 0>
+ void propagate_rhs(gradient_node<RealType, DerivativeOrder> *node, inner_t adj) const
+ {
+ rhs.template propagatex<arg_index_>(node, adj);
+ }
+
+ template<std::size_t num_args,
+ std::size_t arg_index_,
+ typename std::enable_if<(num_args == 0), int>::type = 0>
+ void propagate_rhs(gradient_node<RealType, DerivativeOrder> *, inner_t) const
+ {}
+};
+template<typename RealType, size_t DerivativeOrder, typename ARG, typename ConcreteUnaryOperation>
+
+struct abstract_unary_expression
+ : public expression<
+ RealType,
+ DerivativeOrder,
+ abstract_unary_expression<RealType, DerivativeOrder, ARG, ConcreteUnaryOperation>>
+{
+ using arg_type = ARG;
+ using value_type = RealType;
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+ const arg_type arg;
+ const RealType constant;
+ explicit abstract_unary_expression(const expression<RealType, DerivativeOrder, ARG> &arg_expr,
+ const RealType &constant)
+ : arg(static_cast<const ARG &>(arg_expr))
+ , constant(constant){};
+ inner_t evaluate() const
+ {
+ return static_cast<const ConcreteUnaryOperation *>(this)->evaluate();
+ };
+
+ template<size_t arg_index>
+ void propagatex(gradient_node<RealType, DerivativeOrder> *node, inner_t adj) const
+ {
+ inner_t argv = arg.evaluate();
+ inner_t v = evaluate();
+ inner_t partial_arg = ConcreteUnaryOperation::derivative(argv, v, constant);
+
+ arg.template propagatex<arg_index>(node, adj * partial_arg);
+ }
+};
+} // namespace reverse_mode
+} // namespace differentiation
+} // namespace math
+} // namespace boost
+
+#endif // REVERSE_MODE_AUTODIFF_EXPRESSION_TEMPLATE_BASE_HPP
diff --git a/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_helper_functions.hpp b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_helper_functions.hpp
new file mode 100644
index 0000000000000..4bd88ad68a666
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_helper_functions.hpp
@@ -0,0 +1,18 @@
+// 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 BOOST_REVERSE_MODE_AUTODIFF_HELPER_FUNCTIONS_HPP
+#define BOOST_REVERSE_MODE_AUTODIFF_HELPER_FUNCTIONS_HPP
+
+#include <cstddef>
+#include <type_traits>
+namespace boost {
+namespace math {
+namespace differentiation {
+namespace reverse_mode {} // namespace reverse_mode
+} // namespace differentiation
+} // namespace math
+} // namespace boost
+
+#endif
diff --git a/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_memory_management.hpp b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_memory_management.hpp
new file mode 100644
index 0000000000000..382af5f5c542e
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_memory_management.hpp
@@ -0,0 +1,462 @@
+// 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_MEMORY_MANAGEMENT_HPP
+#define REVERSE_MODE_AUTODIFF_MEMORY_MANAGEMENT_HPP
+
+#include <algorithm>
+#include <array>
+#include <boost/math/tools/assert.hpp>
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <vector>
+namespace boost {
+namespace math {
+namespace differentiation {
+namespace reverse_mode {
+namespace detail {
+template<typename allocator_type, size_t buffer_size>
+class flat_linear_allocator_iterator
+{
+ /**
+ * @brief enables iterating over linear allocator with
+ * c++ iterators
+ */
+public:
+ using raw_allocator_type = std::remove_const_t<allocator_type>;
+ using value_type = typename allocator_type::value_type;
+ using pointer = typename allocator_type::value_type*;
+ using const_ptr_type = const value_type*;
+ using reference = typename allocator_type::value_type&;
+ using const_reference_type = const value_type&;
+ using iterator_category = std::random_access_iterator_tag;
+ using difference_type = ptrdiff_t;
+
+private:
+ const allocator_type* storage_ = nullptr;
+ size_t index_ = 0;
+ size_t begin_ = 0;
+ size_t end_ = 0;
+
+public:
+ flat_linear_allocator_iterator() = default;
+
+ explicit flat_linear_allocator_iterator(allocator_type* storage, size_t index)
+ : storage_(storage)
+ , index_(index)
+ , begin_(0)
+ , end_(storage->size())
+ {
+ }
+
+ explicit flat_linear_allocator_iterator(allocator_type* storage,
+ size_t index,
+ size_t begin,
+ size_t end)
+ : storage_(storage)
+ , index_(index)
+ , begin_(begin)
+ , end_(end)
+ {
+ }
+
+ explicit flat_linear_allocator_iterator(const allocator_type* storage,
+ size_t index)
+ : storage_(storage)
+ , index_(index)
+ , begin_(0)
+ , end_(storage->size())
+ {
+ }
+
+ explicit flat_linear_allocator_iterator(const allocator_type* storage,
+ size_t index,
+ size_t begin,
+ size_t end)
+ : storage_(storage)
+ , index_(index)
+ , begin_(begin)
+ , end_(end)
+ {
+ }
+ reference operator*()
+ {
+ BOOST_MATH_ASSERT(index_ >= begin_ && index_ < end_);
+ return (*storage_->data_[index_ / buffer_size])[index_ % buffer_size];
+ }
+
+ const_reference_type operator*() const
+ {
+ BOOST_MATH_ASSERT(index_ >= begin_ && index_ < end_);
+ return (*storage_->data_[index_ / buffer_size])[index_ % buffer_size];
+ }
+
+ pointer operator->()
+ {
+ BOOST_MATH_ASSERT(index_ >= begin_ && index_ < end_);
+ return &operator*();
+ }
+
+ const_ptr_type operator->() const
+ {
+ BOOST_MATH_ASSERT(index_ >= begin_ && index_ < end_);
+ return &operator*();
+ }
+ flat_linear_allocator_iterator& operator++()
+ {
+ ++index_;
+ return *this;
+ }
+
+ flat_linear_allocator_iterator operator++(int)
+ {
+ auto tmp = *this;
+ ++(*this);
+ return tmp;
+ }
+
+ flat_linear_allocator_iterator& operator--()
+ {
+ --index_;
+ return *this;
+ }
+
+ flat_linear_allocator_iterator operator--(int)
+ {
+ auto tmp = *this;
+ --(*this);
+ return tmp;
+ }
+
+ bool operator==(const flat_linear_allocator_iterator& other) const
+ {
+ return index_ == other.index_ && storage_ == other.storage_;
+ }
+
+ bool operator!=(const flat_linear_allocator_iterator& other) const
+ {
+ return !(*this == other);
+ }
+
+ flat_linear_allocator_iterator operator+(difference_type n) const
+ {
+ return flat_linear_allocator_iterator(
+ storage_, index_ + static_cast<size_t>(n), begin_, end_);
+ }
+
+ flat_linear_allocator_iterator& operator+=(difference_type n)
+ {
+ index_ += n;
+ return *this;
+ }
+
+ flat_linear_allocator_iterator operator-(difference_type n) const
+ {
+ return flat_linear_allocator_iterator(storage_, index_ - n, begin_, end_);
+ }
+ flat_linear_allocator_iterator& operator-=(difference_type n)
+ {
+ index_ -= n;
+ return *this;
+ }
+
+ difference_type operator-(const flat_linear_allocator_iterator& other) const
+ {
+ return static_cast<difference_type>(index_) -
+ static_cast<difference_type>(other.index_);
+ }
+
+ reference operator[](difference_type n) { return *(*this + n); }
+
+ const_reference_type operator[](difference_type n) const
+ {
+ return *(*this + n);
+ }
+
+ bool operator<(const flat_linear_allocator_iterator& other) const
+ {
+ return index_ < other.index_;
+ }
+
+ bool operator>(const flat_linear_allocator_iterator& other) const
+ {
+ return index_ > other.index_;
+ }
+
+ bool operator<=(const flat_linear_allocator_iterator& other) const
+ {
+ return index_ <= other.index_;
+ }
+
+ bool operator>=(const flat_linear_allocator_iterator& other) const
+ {
+ return index_ >= other.index_;
+ }
+
+ bool operator!() const noexcept { return storage_ == nullptr; }
+};
+/* memory management helps for tape */
+template<typename RealType, size_t buffer_size>
+class flat_linear_allocator
+{
+ /** @brief basically a vector<array<T*, size>>
+ * intended to work like a vector that allocates memory in chunks
+ * and doesn't invalidate references
+ * */
+public:
+ // store vector of unique pointers to arrays
+ // to avoid vector reference invalidation
+ using buffer_type = std::array<RealType, buffer_size>;
+ using buffer_ptr = std::unique_ptr<std::array<RealType, buffer_size>>;
+
+private:
+ std::vector<buffer_ptr> data_;
+ size_t total_size_ = 0;
+ std::vector<size_t> checkpoints_; //{0};
+
+public:
+ friend class flat_linear_allocator_iterator<
+ flat_linear_allocator<RealType, buffer_size>,
+ buffer_size>;
+ friend class flat_linear_allocator_iterator<
+ const flat_linear_allocator<RealType, buffer_size>,
+ buffer_size>;
+ using value_type = RealType;
+ using iterator =
+ flat_linear_allocator_iterator<flat_linear_allocator<RealType, buffer_size>,
+ buffer_size>;
+ using const_iterator = flat_linear_allocator_iterator<
+ const flat_linear_allocator<RealType, buffer_size>,
+ buffer_size>;
+
+ size_t buffer_id() const noexcept { return total_size_ / buffer_size; }
+ size_t item_id() const noexcept { return total_size_ % buffer_size; }
+
+private:
+ void allocate_buffer()
+ {
+ data_.emplace_back(std::make_unique<buffer_type>());
+ }
+
+public:
+ flat_linear_allocator() { allocate_buffer(); }
+ flat_linear_allocator(const flat_linear_allocator&) = delete;
+ flat_linear_allocator& operator=(const flat_linear_allocator&) = delete;
+ flat_linear_allocator(flat_linear_allocator&&) = delete;
+ flat_linear_allocator& operator=(flat_linear_allocator&&) = delete;
+ ~flat_linear_allocator()
+ {
+ destroy_all();
+ data_.clear();
+ }
+
+ void destroy_all()
+ {
+ for (size_t i = 0; i < total_size_; ++i) {
+ size_t bid = i / buffer_size;
+ size_t iid = i % buffer_size;
+ (*data_[bid])[iid].~RealType();
+ }
+ }
+ /** @brief
+ * helper functions to clear tape and create block in tape
+ */
+ void clear()
+ {
+ data_.clear();
+ total_size_ = 0;
+ checkpoints_.clear();
+ allocate_buffer();
+ }
+
+ // doesn't delete anything, only sets the current index to zero
+ void reset() { total_size_ = 0; }
+ void rewind() { total_size_ = 0; };
+
+ // adds current index as a checkpoint to be able to walk back to
+ void add_checkpoint()
+ {
+ checkpoints_.push_back(total_size_);
+ /*
+ * if (total_size_ > 0) {
+ checkpoints_.push_back(total_size_ - 1);
+ } else {
+ checkpoints_.push_back(0);
+ }*/
+ };
+
+ /** @brief clears all checkpoints
+ * */
+ void reset_checkpoints() { checkpoints_.clear(); }
+
+ void rewind_to_last_checkpoint() { total_size_ = checkpoints_.back(); }
+ void rewind_to_checkpoint_at(size_t index)
+ {
+ total_size_ = checkpoints_[index];
+ }
+
+ void fill(const RealType& val)
+ {
+ for (size_t i = 0; i < total_size_; ++i) {
+ size_t bid = i / buffer_size;
+ size_t iid = i % buffer_size;
+ (*data_[bid])[iid] = val;
+ }
+ }
+
+ /** @brief emplaces back object at the end of the
+ * data structure, calls default constructor */
+ iterator emplace_back()
+ {
+ if (item_id() == 0 && total_size_ != 0) {
+ allocate_buffer();
+ }
+ size_t bid = buffer_id();
+ size_t iid = item_id();
+
+ RealType* ptr = &(*data_[bid])[iid];
+ new (ptr) RealType();
+ ++total_size_;
+ return iterator(this, total_size_ - 1);
+ };
+
+ /** @brief, emplaces back object at end of data structure,
+ * passes arguments to constructor */
+ template<typename... Args>
+ iterator emplace_back(Args&&... args)
+ {
+ if (item_id() == 0 && total_size_ != 0) {
+ allocate_buffer();
+ }
+ BOOST_MATH_ASSERT(buffer_id() < data_.size());
+ BOOST_MATH_ASSERT(item_id() < buffer_size);
+ RealType* ptr = &(*data_[buffer_id()])[item_id()];
+ new (ptr) RealType(std::forward<Args>(args)...);
+ ++total_size_;
+ return iterator(this, total_size_ - 1);
+ }
+ /** @brief default constructs n objects at end of
+ * data structure, n known at compile time */
+ template<size_t n>
+ iterator emplace_back_n()
+ {
+ size_t bid = buffer_id();
+ size_t iid = item_id();
+ if (iid + n < buffer_size) {
+ RealType* ptr = &(*data_[bid])[iid];
+ for (size_t i = 0; i < n; ++i) {
+ new (ptr + i) RealType();
+ }
+ total_size_ += n;
+ return iterator(this, total_size_ - n, total_size_ - n, total_size_);
+ } else {
+ size_t allocs_in_curr_buffer = buffer_size - iid;
+ size_t allocs_in_next_buffer = n - (buffer_size - iid);
+ RealType* ptr = &(*data_[bid])[iid];
+ for (size_t i = 0; i < allocs_in_curr_buffer; ++i) {
+ new (ptr + i) RealType();
+ }
+ allocate_buffer();
+ bid = data_.size() - 1;
+ iid = 0;
+ total_size_ += n;
+
+ RealType* ptr2 = &(*data_[bid])[iid];
+ for (size_t i = 0; i < allocs_in_next_buffer; i++) {
+ new (ptr2 + i) RealType();
+ }
+ return iterator(this, total_size_ - n, total_size_ - n, total_size_);
+ }
+ }
+ /** @brief default constructs n objects at end of
+ * data structure, n known at run time
+ */
+ iterator emplace_back_n(size_t n)
+ {
+ size_t bid = buffer_id();
+ size_t iid = item_id();
+ if (iid + n < buffer_size) {
+ RealType* ptr = &(*data_[bid])[iid];
+ for (size_t i = 0; i < n; ++i) {
+ new (ptr + i) RealType();
+ }
+ total_size_ += n;
+ return iterator(this, total_size_ - n, total_size_ - n, total_size_);
+ } else {
+ size_t allocs_in_curr_buffer = buffer_size - iid;
+ size_t allocs_in_next_buffer = n - (buffer_size - iid);
+ RealType* ptr = &(*data_[bid])[iid];
+ for (size_t i = 0; i < allocs_in_curr_buffer; ++i) {
+ new (ptr + i) RealType();
+ }
+ allocate_buffer();
+ bid = data_.size() - 1;
+ iid = 0;
+ total_size_ += n;
+
+ RealType* ptr2 = &(*data_[bid])[iid];
+ for (size_t i = 0; i < allocs_in_next_buffer; i++) {
+ new (ptr2 + i) RealType();
+ }
+ return iterator(this, total_size_ - n, total_size_ - n, total_size_);
+ }
+ }
+
+ /** @brief number of elements */
+ size_t size() const { return total_size_; }
+
+ /** @brief total capacity */
+ size_t capacity() const { return data_.size() * buffer_size; }
+
+ /** @brief iterator helpers */
+ iterator begin() { return iterator(this, 0); }
+ iterator end() { return iterator(this, total_size_); }
+ const_iterator begin() const { return const_iterator(this, 0); }
+ const_iterator end() const { return const_iterator(this, total_size_); }
+
+ iterator last_checkpoint()
+ {
+ return iterator(this, checkpoints_.back(), 0, total_size_);
+ }
+ iterator first_checkpoint()
+ {
+ return iterator(this, checkpoints_[0], 0, total_size_);
+ };
+ iterator checkpoint_at(size_t index)
+ {
+ return iterator(this, checkpoints_[index], 0, total_size_);
+ };
+
+ /** @brief searches for item in allocator
+ * only used to find gradient nodes for propagation */
+ iterator find(const RealType* const item)
+ {
+ return std::find_if(
+ begin(), end(), [&](const RealType& val) { return &val == item; });
+ }
+ /** @brief vector like access,
+ * currently unused anywhere but very useful for debugging
+ */
+ RealType& operator[](std::size_t i)
+ {
+ BOOST_MATH_ASSERT(i < total_size_);
+ return (*data_[i / buffer_size])[i % buffer_size];
+ }
+ const RealType& operator[](std::size_t i) const
+ {
+ BOOST_MATH_ASSERT(i < total_size_);
+ return (*data_[i / buffer_size])[i % buffer_size];
+ }
+};
+} // namespace detail
+} // namespace reverse_mode
+} // namespace differentiation
+} // namespace math
+} // namespace boost
+
+#endif
diff --git a/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_stl_et.hpp b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_stl_et.hpp
new file mode 100644
index 0000000000000..70bf4245908c7
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_stl_et.hpp
@@ -0,0 +1,275 @@
+// 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_STL_ET_HPP
+#define REVERSE_MODE_AUTODIFF_STL_ET_HPP
+
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_stl_expressions.hpp>
+namespace boost {
+namespace math {
+namespace differentiation {
+namespace reverse_mode {
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+fabs_expr<RealType, DerivativeOrder, ARG> fabs(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return fabs_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+auto abs(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return fabs(arg);
+}
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+ceil_expr<RealType, DerivativeOrder, ARG> ceil(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return ceil_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+floor_expr<RealType, DerivativeOrder, ARG> floor(
+ const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return floor_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+exp_expr<RealType, DerivativeOrder, ARG> exp(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return exp_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+pow_expr<RealType, DerivativeOrder, LHS, RHS> pow(
+ const expression<RealType, DerivativeOrder, LHS> &lhs,
+ const expression<RealType, DerivativeOrder, RHS> &rhs)
+{
+ return pow_expr<RealType, DerivativeOrder, LHS, RHS>(lhs, rhs);
+}
+
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ typename ARG,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+expr_pow_float_expr<RealType1, DerivativeOrder, ARG> pow(
+ const expression<RealType1, DerivativeOrder, ARG> &arg, const RealType2 &v)
+{
+ return expr_pow_float_expr<RealType1, DerivativeOrder, ARG>(arg, static_cast<RealType1>(v));
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+float_pow_expr_expr<RealType, DerivativeOrder, ARG> pow(
+ const RealType &v, const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return float_pow_expr_expr<RealType, DerivativeOrder, ARG>(arg, v);
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+log_expr<RealType, DerivativeOrder, ARG> log(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return log_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+sqrt_expr<RealType, DerivativeOrder, ARG> sqrt(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return sqrt_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+auto frexp(const expression<RealType, DerivativeOrder, ARG> &arg, int *i)
+{
+ BOOST_MATH_STD_USING
+ frexp(arg.evaluate(), i);
+ return arg / pow(static_cast<RealType>(2.0), *i);
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+auto ldexp(const expression<RealType, DerivativeOrder, ARG> &arg, const int &i)
+{
+ BOOST_MATH_STD_USING
+ return arg * pow(static_cast<RealType>(2.0), i);
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+cos_expr<RealType, DerivativeOrder, ARG> cos(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return cos_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+sin_expr<RealType, DerivativeOrder, ARG> sin(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return sin_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+tan_expr<RealType, DerivativeOrder, ARG> tan(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return tan_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+acos_expr<RealType, DerivativeOrder, ARG> acos(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return acos_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+asin_expr<RealType, DerivativeOrder, ARG> asin(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return asin_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+atan_expr<RealType, DerivativeOrder, ARG> atan(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return atan_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+};
+
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+atan2_expr<RealType, DerivativeOrder, LHS, RHS> atan2(
+ const expression<RealType, DerivativeOrder, LHS> &lhs,
+ const expression<RealType, DerivativeOrder, RHS> &rhs)
+{
+ return atan2_expr<RealType, DerivativeOrder, LHS, RHS>(lhs, rhs);
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+atan2_right_float_expr<RealType, DerivativeOrder, ARG> atan2(
+ const expression<RealType, DerivativeOrder, ARG> &arg, const RealType &v)
+{
+ return atan2_right_float_expr<RealType, DerivativeOrder, ARG>(arg, v);
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+atan2_left_float_expr<RealType, DerivativeOrder, ARG> atan2(
+ const RealType &v, const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return atan2_left_float_expr<RealType, DerivativeOrder, ARG>(arg, v);
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+trunc_expr<RealType, DerivativeOrder, ARG> trunc(
+ const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return trunc_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+auto fmod(const expression<RealType, DerivativeOrder, LHS> &lhs,
+ const expression<RealType, DerivativeOrder, RHS> &rhs)
+{
+ return fmod_expr<RealType, DerivativeOrder, LHS, RHS>(lhs, rhs);
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+auto fmod(const expression<RealType, DerivativeOrder, ARG> &lhs, const RealType rhs)
+{
+ return fmod_right_float_expr<RealType, DerivativeOrder, ARG>(lhs, rhs);
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+auto fmod(const RealType lhs, const expression<RealType, DerivativeOrder, ARG> &rhs)
+{
+ return fmod_left_float_expr<RealType, DerivativeOrder, ARG>(rhs, lhs);
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+round_expr<RealType, DerivativeOrder, ARG> round(
+ const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return round_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+int iround(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ rvar<RealType, DerivativeOrder> tmp = arg.evaluate();
+ return iround(tmp.item());
+}
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+long lround(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ BOOST_MATH_STD_USING
+ rvar<RealType, DerivativeOrder> tmp = arg.evaluate();
+ return lround(tmp.item());
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+long long llround(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ rvar<RealType, DerivativeOrder> tmp = arg.evaluate();
+ return llround(tmp.item());
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+int itrunc(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ rvar<RealType, DerivativeOrder> tmp = arg.evaluate();
+ return itrunc(tmp.item());
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+long ltrunc(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ rvar<RealType, DerivativeOrder> tmp = arg.evaluate();
+ return ltrunc(tmp.item());
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+long long lltrunc(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ rvar<RealType, DerivativeOrder> tmp = arg.evaluate();
+ return lltrunc(tmp.item());
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+sinh_expr<RealType, DerivativeOrder, ARG> sinh(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return sinh_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+cosh_expr<RealType, DerivativeOrder, ARG> cosh(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return cosh_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+tanh_expr<RealType, DerivativeOrder, ARG> tanh(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return tanh_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+log10_expr<RealType, DerivativeOrder, ARG> log10(
+ const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return log10_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+asinh_expr<RealType, DerivativeOrder, ARG> asinh(
+ const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return asinh_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+acosh_expr<RealType, DerivativeOrder, ARG> acosh(
+ const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return acosh_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+atanh_expr<RealType, DerivativeOrder, ARG> atanh(
+ const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return atanh_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+} // namespace reverse_mode
+} // namespace differentiation
+} // namespace math
+} // namespace boost
+
+#endif
diff --git a/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_stl_expressions.hpp b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_stl_expressions.hpp
new file mode 100644
index 0000000000000..b5f9570d356e6
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_stl_expressions.hpp
@@ -0,0 +1,852 @@
+// 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_STL_OVERLOADS
+#define REVERSE_MODE_AUTODIFF_STL_OVERLOADS
+/* stl support : expressions */
+
+#ifdef BOOST_MATH_REVERSE_MODE_ET_ON
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_basic_ops_et.hpp>
+#else
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_basic_ops_no_et.hpp>
+#endif
+
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_expression_template_base.hpp>
+#include <boost/math/special_functions/round.hpp>
+#include <boost/math/special_functions/trunc.hpp>
+#include <cmath>
+#include <complex>
+namespace boost {
+namespace math {
+namespace differentiation {
+namespace reverse_mode {
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct fabs_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, fabs_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief
+ * |x|
+ * d/dx |x| = 1 if x > 0
+ * -1 if x <= 0
+ *
+ * the choice is arbitrary and for optimization it is most likely
+ * more correct to chose this convention over d/dx = 0 at x = 0
+ * to avoid vanishing gradients
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit fabs_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ fabs_expr<RealType, DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return fabs(this->arg.evaluate());
+ }
+ static const inner_t derivative(const inner_t &argv,
+ const inner_t & /*v*/,
+ const RealType & /*constant*/)
+ {
+ return argv > 0.0 ? inner_t{static_cast<RealType>(1.0)}
+ : inner_t{static_cast<RealType>(-1.0)};
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct ceil_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, ceil_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief ceil(1.11) = 2.0
+ *
+ * d/dx ceil(x) = 0.0 for all x
+ *
+ * we avoid problematic points at x = 1,2,3...
+ * as with optimization its most likely intented
+ * this function's derivative is 0.0;
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit ceil_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ ceil_expr<RealType, DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return ceil(this->arg.evaluate());
+ }
+ static const inner_t derivative(const inner_t & /*argv*/,
+ const inner_t & /*v*/,
+ const RealType & /*constant*/)
+ {
+ return inner_t{0.0};
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct floor_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, floor_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief floor(1.11) = 1.0, floor(-1.11) = 2
+ *
+ * d/dx floor(x) = 0.0 for all x
+ *
+ * we avoid problematic points at x = 1,2,3...
+ * as with optimization its most likely intented
+ * this function's derivative is 0.0;
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit floor_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr,
+ const RealType &v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ floor_expr<RealType, DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return floor(this->arg.evaluate());
+ }
+ static const inner_t derivative(const inner_t & /*argv*/,
+ const inner_t & /*v*/,
+ const RealType & /*constant*/)
+ {
+ return inner_t{0.0};
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct trunc_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, trunc_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief trunc(1.11) = 1.0, trunc(-1.11) = -1.0
+ *
+ * d/dx trunc(x) = 0.0 for all x
+ *
+ * we avoid problematic points at x = 1,2,3...
+ * as with optimization its most likely intented
+ * this function's derivative is 0.0;
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit trunc_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr,
+ const RealType &v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ trunc_expr<RealType, DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return trunc(this->arg.evaluate());
+ }
+ static const inner_t derivative(const inner_t & /*argv*/,
+ const inner_t & /*v*/,
+ const RealType & /*constant*/)
+ {
+ return inner_t{0.0};
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct exp_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, exp_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief exp(x)
+ *
+ * d/dx exp(x) = exp(x)
+ *
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit exp_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ exp_expr<RealType, DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return exp(this->arg.evaluate());
+ }
+ static const inner_t derivative(const inner_t &argv,
+ const inner_t & /*v*/,
+ const RealType & /*constant*/)
+ {
+ BOOST_MATH_STD_USING
+ return exp(argv);
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+struct pow_expr
+ : public abstract_binary_expression<RealType, DerivativeOrder, LHS, RHS, pow_expr<RealType, DerivativeOrder, LHS, RHS>>
+{
+ /** @brief pow(x,y)
+ * d/dx pow(x,y) = y pow (x, y-1)
+ * d/dy pow(x,y) = pow(x,y) log(x)
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+ // Explicitly define constructor to forward to base class
+ explicit pow_expr(const expression<RealType, DerivativeOrder, LHS> &left_hand_expr,
+ const expression<RealType, DerivativeOrder, RHS> &right_hand_expr)
+ : abstract_binary_expression<RealType, DerivativeOrder, LHS, RHS, pow_expr<RealType, DerivativeOrder, LHS, RHS>>(
+ left_hand_expr, right_hand_expr)
+ {}
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return pow(this->lhs.evaluate(), this->rhs.evaluate());
+ };
+ static const inner_t left_derivative(const inner_t &l, const inner_t &r, const inner_t & /*v*/)
+ {
+ BOOST_MATH_STD_USING
+ return r * pow(l, r - static_cast<RealType>(1.0));
+ };
+ static const inner_t right_derivative(const inner_t &l, const inner_t &r, const inner_t & /*v*/)
+ {
+ BOOST_MATH_STD_USING
+ return pow(l, r) * log(l);
+ };
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct expr_pow_float_expr
+ : public abstract_unary_expression<RealType, DerivativeOrder, ARG, expr_pow_float_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief pow(rvar,float)
+ */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit expr_pow_float_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr,
+ const RealType &v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ expr_pow_float_expr<RealType, DerivativeOrder, ARG>>(arg_expr,
+ v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return pow(this->arg.evaluate(), this->constant);
+ }
+ static const inner_t derivative(const inner_t &argv, const inner_t & /*v*/, const RealType &constant)
+ {
+ BOOST_MATH_STD_USING
+ return inner_t{constant} * pow(argv, inner_t{constant - 1});
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct float_pow_expr_expr
+ : public abstract_unary_expression<RealType, DerivativeOrder, ARG, float_pow_expr_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief pow(float, rvar)
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit float_pow_expr_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr,
+ const RealType &v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ float_pow_expr_expr<RealType, DerivativeOrder, ARG>>(arg_expr,
+ v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return pow(this->constant, this->arg.evaluate());
+ }
+ static const inner_t derivative(const inner_t &argv, const inner_t & /*v*/, const RealType &constant)
+ {
+ BOOST_MATH_STD_USING
+ return pow(constant, argv) * log(constant);
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct sqrt_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, sqrt_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief sqrt(x)
+ * d/dx sqrt(x) = 1/(2 sqrt(x))
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit sqrt_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ sqrt_expr<RealType, DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return sqrt(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<RealType>(1.0) / (static_cast<RealType>(2.0) * sqrt(argv));
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct log_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, log_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief log(x)
+ * d/dx log(x) = 1/x
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit log_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ log_expr<RealType, DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return log(this->arg.evaluate());
+ }
+ static const inner_t derivative(const inner_t &argv,
+ const inner_t & /*v*/,
+ const RealType & /*constant*/)
+ {
+ return static_cast<RealType>(1.0) / argv;
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct cos_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, cos_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief cos(x)
+ * d/dx cos(x) = -sin(x)
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit cos_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ cos_expr<RealType, DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return cos(this->arg.evaluate());
+ }
+ static const inner_t derivative(const inner_t &argv,
+ const inner_t & /*v*/,
+ const RealType & /*constant*/)
+ {
+ BOOST_MATH_STD_USING
+ return -sin(argv);
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct sin_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, sin_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief sin(x)
+ * d/dx sin(x) = cos(x)
+ * */
+ using arg_type = ARG;
+ using value_type = RealType;
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit sin_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ sin_expr<RealType, DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return sin(this->arg.evaluate());
+ }
+ static const inner_t derivative(const inner_t &argv,
+ const inner_t & /*v*/,
+ const RealType & /*constant*/)
+ {
+ BOOST_MATH_STD_USING
+ return cos(argv);
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct tan_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, tan_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief tan(x)
+ * d/dx tan(x) = 1/cos^2(x)
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit tan_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType, DerivativeOrder, ARG, tan_expr<RealType,DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return tan(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<RealType>(1.0) / (cos(argv) * cos(argv));
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct acos_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, acos_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief acos(x)
+ * d/dx acos(x) = -1/sqrt(1-x^2)
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit acos_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType, DerivativeOrder, ARG, acos_expr<RealType,DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return acos(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<RealType>(-1.0) / sqrt(static_cast<RealType>(1.0) - argv * argv);
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct asin_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, asin_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief asin(x)
+ * d/dx asin = 1/sqrt(1-x^2)
+ * */
+ using arg_type = ARG;
+ using value_type = RealType;
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit asin_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType, DerivativeOrder, ARG, asin_expr<RealType,DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return asin(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<RealType>(1.0) / sqrt(static_cast<RealType>(1.0) - argv * argv);
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct atan_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, atan_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief atan(x)
+ * d/dx atan(x) = 1/x^2+1
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit atan_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType, DerivativeOrder, ARG, atan_expr<RealType,DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return atan(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<RealType>(1.0) / (static_cast<RealType>(1.0) + argv * argv);
+ }
+};
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+struct atan2_expr
+ : public abstract_binary_expression<RealType, DerivativeOrder, LHS, RHS, atan2_expr<RealType, DerivativeOrder, LHS, RHS>>
+{
+ /** @brief atan2(x,y)
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+ // Explicitly define constructor to forward to base class
+ explicit atan2_expr(const expression<RealType, DerivativeOrder, LHS> &left_hand_expr,
+ const expression<RealType, DerivativeOrder, RHS> &right_hand_expr)
+ : abstract_binary_expression<RealType, DerivativeOrder, LHS, RHS, atan2_expr<RealType, DerivativeOrder, LHS, RHS>>(
+ left_hand_expr, right_hand_expr)
+ {}
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return atan2(this->lhs.evaluate(), this->rhs.evaluate());
+ };
+ static const inner_t left_derivative(const inner_t &l, const inner_t &r, const inner_t & /*v*/)
+ {
+ return r / (l * l + r * r);
+ };
+ static const inner_t right_derivative(const inner_t &l, const inner_t &r, const inner_t & /*v*/)
+ {
+ return -l / (l * l + r * r);
+ };
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct atan2_left_float_expr
+ : public abstract_unary_expression<RealType, DerivativeOrder, ARG, atan2_left_float_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief atan2(float,rvar)
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit atan2_left_float_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType, DerivativeOrder, ARG, atan2_left_float_expr<RealType,DerivativeOrder, ARG>>(arg_expr,
+ v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return atan2(this->constant, this->arg.evaluate());
+ }
+ static const inner_t derivative(const inner_t &argv, const inner_t & /*v*/, const RealType &constant)
+ {
+ return -constant / (constant * constant + argv * argv);
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct atan2_right_float_expr
+ : public abstract_unary_expression<RealType, DerivativeOrder, ARG, atan2_right_float_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief atan2(rvar,float)
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit atan2_right_float_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType, DerivativeOrder, ARG, atan2_right_float_expr<RealType,DerivativeOrder, ARG>>(arg_expr,
+ v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return atan2(this->arg.evaluate(), this->constant);
+ }
+ static const inner_t derivative(const inner_t &argv, const inner_t & /*v*/, const RealType &constant)
+ {
+ return constant / (constant * constant + argv * argv);
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct round_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, round_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief round(x)
+ * d/dx round = 0
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit round_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType, DerivativeOrder, ARG, round_expr<RealType,DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return round(this->arg.evaluate());
+ }
+ static const inner_t derivative(const inner_t & /*argv*/,
+ const inner_t & /*v*/,
+ const RealType & /*constant*/)
+ {
+ return inner_t{0.0};
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct sinh_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, sinh_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief sinh(x)
+ * d/dx sinh(x) = cosh
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit sinh_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType, DerivativeOrder, ARG, sinh_expr<RealType,DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return sinh(this->arg.evaluate());
+ }
+ static const inner_t derivative(const inner_t &argv,
+ const inner_t & /*v*/,
+ const RealType & /*constant*/)
+ {
+ BOOST_MATH_STD_USING
+ return cosh(argv);
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct cosh_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, cosh_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief cosh(x)
+ * d/dx cosh(x) = sinh
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit cosh_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType, DerivativeOrder, ARG, cosh_expr<RealType,DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return cosh(this->arg.evaluate());
+ }
+ static const inner_t derivative(const inner_t &argv,
+ const inner_t & /*v*/,
+ const RealType & /*constant*/)
+ {
+ BOOST_MATH_STD_USING
+ return sinh(argv);
+ }
+};
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct tanh_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, tanh_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief tanh(x)
+ * d/dx tanh(x) = 1/cosh^2
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit tanh_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType, DerivativeOrder, ARG, tanh_expr<RealType,DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return tanh(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<RealType>(1.0) / (cosh(argv) * cosh(argv));
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct log10_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, log10_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief log10(x)
+ * d/dx log10(x) = 1/(x * log(10))
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit log10_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType, DerivativeOrder, ARG, log10_expr<RealType,DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return log10(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<RealType>(1.0) / (argv * log(static_cast<RealType>(10.0)));
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct acosh_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, acosh_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief acosh(x)
+ * d/dx acosh(x) = 1/(sqrt(x-1)sqrt(x+1)
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit acosh_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType, DerivativeOrder, ARG, acosh_expr<RealType,DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return acosh(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<RealType>(1.0)
+ / (sqrt(argv - static_cast<RealType>(1.0)) * sqrt(argv + static_cast<RealType>(1.0)));
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct asinh_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, asinh_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief asinh(x)
+ * d/dx asinh(x) = 1/(sqrt(1+x^2))
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit asinh_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType, DerivativeOrder, ARG, asinh_expr<RealType,DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return asinh(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<RealType>(1.0) / (sqrt(static_cast<RealType>(1.0) + argv * argv));
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct atanh_expr : public abstract_unary_expression<RealType, DerivativeOrder, ARG, atanh_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief atanh(x)
+ * d/dx atanh(x) = 1/(1-x^2)
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit atanh_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType, DerivativeOrder, ARG, atanh_expr<RealType,DerivativeOrder, ARG>>(arg_expr, v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return atanh(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<RealType>(1.0) / (static_cast<RealType>(1.0) - argv * argv);
+ }
+};
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+struct fmod_expr
+ : public abstract_binary_expression<RealType, DerivativeOrder, LHS, RHS, fmod_expr<RealType, DerivativeOrder, LHS, RHS>>
+{
+ /** @brief
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+ // Explicitly define constructor to forward to base class
+ explicit fmod_expr(const expression<RealType, DerivativeOrder, LHS> &left_hand_expr,
+ const expression<RealType, DerivativeOrder, RHS> &right_hand_expr)
+ : abstract_binary_expression<RealType, DerivativeOrder, LHS, RHS, fmod_expr<RealType, DerivativeOrder, LHS, RHS>>(
+ left_hand_expr, right_hand_expr)
+ {}
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return fmod(this->lhs.evaluate(), this->rhs.evaluate());
+ };
+ static const inner_t left_derivative(const inner_t & /*l*/,
+ const inner_t & /*r*/,
+ const inner_t & /*v*/)
+ {
+ return inner_t{1.0};
+ };
+ static const inner_t right_derivative(const inner_t &l, const inner_t &r, const inner_t & /*v*/)
+ {
+ BOOST_MATH_STD_USING
+ return static_cast<RealType>(-1.0) * trunc(l / r);
+ };
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct fmod_left_float_expr
+ : public abstract_unary_expression<RealType, DerivativeOrder, ARG, fmod_left_float_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit fmod_left_float_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr, const RealType &v)
+ : abstract_unary_expression<RealType, DerivativeOrder, ARG, fmod_left_float_expr<RealType,DerivativeOrder, ARG>>(arg_expr,
+ v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return fmod(this->constant, 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<RealType>(-1.0) * trunc(constant / argv);
+ }
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+struct fmod_right_float_expr
+ : public abstract_unary_expression<RealType, DerivativeOrder, ARG, fmod_right_float_expr<RealType,DerivativeOrder, ARG>>
+{
+ /** @brief
+ * */
+ using inner_t = rvar_t<RealType, DerivativeOrder - 1>;
+
+ explicit fmod_right_float_expr(const expression<RealType, DerivativeOrder, ARG> &arg_expr,
+ const RealType &v)
+ : abstract_unary_expression<RealType,
+ DerivativeOrder,
+ ARG,
+ fmod_right_float_expr<RealType, DerivativeOrder, ARG>>(arg_expr,
+ v){};
+
+ inner_t evaluate() const
+ {
+ BOOST_MATH_STD_USING
+ return fmod(this->arg.evaluate(), this->constant);
+ }
+ static const inner_t derivative(const inner_t & /*argv*/,
+ const inner_t & /*v*/,
+ const RealType & /*constant*/)
+ {
+ return inner_t{1.0};
+ }
+};
+/**************************************************************************************************/
+
+} // namespace reverse_mode
+} // namespace differentiation
+} // namespace math
+} // namespace boost
+#endif
diff --git a/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_stl_no_et.hpp b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_stl_no_et.hpp
new file mode 100644
index 0000000000000..e3f65c3a25716
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_stl_no_et.hpp
@@ -0,0 +1,266 @@
+// 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_STL_NO_ET_HPP
+#define REVERSE_MODE_AUTODIFF_STL_NO_ET_HPP
+
+#include <boost/math/differentiation/detail/reverse_mode_autodiff_stl_expressions.hpp>
+namespace boost {
+namespace math {
+namespace differentiation {
+namespace reverse_mode {
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> fabs(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return fabs_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> abs(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return fabs(arg);
+}
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> ceil(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return ceil_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> floor(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return floor_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> exp(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return exp_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+rvar<RealType, DerivativeOrder> pow(const expression<RealType, DerivativeOrder, LHS> &lhs,
+ const expression<RealType, DerivativeOrder, RHS> &rhs)
+{
+ return pow_expr<RealType, DerivativeOrder, LHS, RHS>(lhs, rhs);
+}
+
+template<typename RealType2,
+ typename RealType1,
+ size_t DerivativeOrder,
+ typename ARG,
+ typename = typename std::enable_if<!detail::is_expression<RealType2>::value>::type>
+rvar<RealType1, DerivativeOrder> pow(const expression<RealType1, DerivativeOrder, ARG> &arg,
+ const RealType2 &v)
+{
+ return expr_pow_float_expr<RealType1, DerivativeOrder, ARG>(arg, static_cast<RealType1>(v));
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> pow(const RealType &v,
+ const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return float_pow_expr_expr<RealType, DerivativeOrder, ARG>(arg, v);
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> log(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return log_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> sqrt(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return sqrt_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> frexp(const expression<RealType, DerivativeOrder, ARG> &arg, int *i)
+{
+ BOOST_MATH_STD_USING
+ frexp(arg.evaluate(), i);
+ return arg / pow(static_cast<RealType>(2.0), *i);
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+auto ldexp(const expression<RealType, DerivativeOrder, ARG> &arg, const int &i)
+{
+ BOOST_MATH_STD_USING
+ return arg * pow(static_cast<RealType>(2.0), i);
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> cos(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return cos_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> sin(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return sin_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> tan(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return tan_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> acos(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return acos_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> asin(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return asin_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> atan(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return atan_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+};
+
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+rvar<RealType, DerivativeOrder> atan2(const expression<RealType, DerivativeOrder, LHS> &lhs,
+ const expression<RealType, DerivativeOrder, RHS> &rhs)
+{
+ return atan2_expr<RealType, DerivativeOrder, LHS, RHS>(lhs, rhs);
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> atan2(const expression<RealType, DerivativeOrder, ARG> &arg,
+ const RealType &v)
+{
+ return atan2_right_float_expr<RealType, DerivativeOrder, ARG>(arg, v);
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> atan2(const RealType &v,
+ const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return atan2_left_float_expr<RealType, DerivativeOrder, ARG>(arg, v);
+};
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> trunc(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return trunc_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+
+template<typename RealType, size_t DerivativeOrder, typename LHS, typename RHS>
+auto fmod(const expression<RealType, DerivativeOrder, LHS> &lhs,
+ const expression<RealType, DerivativeOrder, RHS> &rhs)
+{
+ return fmod_expr<RealType, DerivativeOrder, LHS, RHS>(lhs, rhs);
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+auto fmod(const expression<RealType, DerivativeOrder, ARG> &lhs, const RealType rhs)
+{
+ return fmod_right_float_expr<RealType, DerivativeOrder, ARG>(lhs, rhs);
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+auto fmod(const RealType lhs, const expression<RealType, DerivativeOrder, ARG> &rhs)
+{
+ return fmod_left_float_expr<RealType, DerivativeOrder, ARG>(rhs, lhs);
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> round(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return round_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+int iround(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ rvar<RealType, DerivativeOrder> tmp = arg.evaluate();
+ return iround(tmp.item());
+}
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+long lround(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ BOOST_MATH_STD_USING
+ rvar<RealType, DerivativeOrder> tmp = arg.evaluate();
+ return lround(tmp.item());
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+long long llround(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ rvar<RealType, DerivativeOrder> tmp = arg.evaluate();
+ return llround(tmp.item());
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+int itrunc(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ rvar<RealType, DerivativeOrder> tmp = arg.evaluate();
+ return itrunc(tmp.item());
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+long ltrunc(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ rvar<RealType, DerivativeOrder> tmp = arg.evaluate();
+ return ltrunc(tmp.item());
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+long long lltrunc(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ rvar<RealType, DerivativeOrder> tmp = arg.evaluate();
+ return lltrunc(tmp.item());
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> sinh(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return sinh_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> cosh(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return cosh_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> tanh(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return tanh_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> log10(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return log10_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> asinh(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return asinh_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> acosh(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return acosh_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+template<typename RealType, size_t DerivativeOrder, typename ARG>
+rvar<RealType, DerivativeOrder> atanh(const expression<RealType, DerivativeOrder, ARG> &arg)
+{
+ return atanh_expr<RealType, DerivativeOrder, ARG>(arg, static_cast<RealType>(0.0));
+}
+} // namespace reverse_mode
+} // namespace differentiation
+} // namespace math
+} // namespace boost
+
+#endif
diff --git a/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_utilities.hpp b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_utilities.hpp
new file mode 100644
index 0000000000000..9452f8827c6f6
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/differentiation/detail/reverse_mode_autodiff_utilities.hpp
@@ -0,0 +1,51 @@
+// 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_UTILITIES_HPP
+#define REVERSE_MODE_AUTODIFF_UTILITIES_HPP
+
+#include <utility>
+
+namespace boost {
+namespace math {
+namespace differentiation {
+namespace reverse_mode {
+namespace detail {
+
+template<bool Condition>
+struct if_functional_dispatch_impl;
+
+template<>
+struct if_functional_dispatch_impl<true>
+{
+ template<typename F1, typename F2, typename... Args>
+ static decltype(auto) call(F1&& f1, F2&&, Args&&... args)
+ {
+ return std::forward<F1>(f1)(std::forward<Args>(args)...);
+ }
+};
+
+template<>
+struct if_functional_dispatch_impl<false>
+{
+ template<typename F1, typename F2, typename... Args>
+ static decltype(auto) call(F1&&, F2&& f2, Args&&... args)
+ {
+ return std::forward<F2>(f2)(std::forward<Args>(args)...);
+ }
+};
+
+template<bool Condition, typename F1, typename F2, typename... Args>
+decltype(auto) if_functional_dispatch(F1&& f1, F2&& f2, Args&&... args)
+{
+ return if_functional_dispatch_impl<Condition>::call(std::forward<F1>(f1),
+ std::forward<F2>(f2),
+ std::forward<Args>(args)...);
+}
+} // namespace detail
+} // namespace reverse_mode
+} // namespace differentiation
+} // namespace math
+} // namespace boost
+#endif // REVERSE_MODE_AUTODIFF_UTILITIES_HPP
diff --git a/third-party/boost-math/include/boost/math/distributions/arcsine.hpp b/third-party/boost-math/include/boost/math/distributions/arcsine.hpp
index 29feac48fe78a..4fe3c7d751f8e 100644
--- a/third-party/boost-math/include/boost/math/distributions/arcsine.hpp
+++ b/third-party/boost-math/include/boost/math/distributions/arcsine.hpp
@@ -164,7 +164,104 @@ namespace boost
return check_dist(function, x_min, x_max, result, pol)
&& check_prob(function, p, result, pol);
} // bool check_dist_and_prob
+
+ template <class RealType>
+ BOOST_MATH_GPU_ENABLED inline RealType arcsine_mean(const RealType x_min, const RealType x_max)
+ {
+ return (x_min + x_max) / 2;
+ }
+
+ template <class RealType>
+ BOOST_MATH_GPU_ENABLED inline RealType arcsine_variance(const RealType x_min, const RealType x_max)
+ {
+ return (x_max - x_min) * (x_max - x_min) / 8;
+ }
+ template <class RealType>
+ BOOST_MATH_GPU_ENABLED inline RealType arcsine_pdf(const RealType x, const RealType x_min, const RealType x_max)
+ {
+ BOOST_MATH_STD_USING
+ using boost::math::constants::pi;
+ return 1 / (pi<RealType>() * sqrt((x - x_min) * (x_max - x)));
+ }
+
+ template <class RealType>
+ BOOST_MATH_GPU_ENABLED inline RealType arcsine_cdf(const RealType x, const RealType x_min, const RealType x_max)
+ {
+ BOOST_MATH_STD_USING
+ // Special cases:
+ if (x == x_min)
+ {
+ return 0;
+ }
+ else if (x == x_max)
+ {
+ return 1;
+ }
+ using boost::math::constants::pi;
+ return 2 * asin(sqrt((x - x_min) / (x_max - x_min))) / pi<RealType>();
+ }
+
+ template <class RealType>
+ BOOST_MATH_GPU_ENABLED inline RealType arcsine_ccdf(const RealType x, const RealType x_min, const RealType x_max)
+ {
+ BOOST_MATH_STD_USING
+ // Special cases
+ if (x == x_min)
+ {
+ return 1;
+ }
+ else if (x == x_max)
+ {
+ return 0;
+ }
+ using boost::math::constants::pi;
+ // Naive version x = 1 - x;
+ // result = static_cast<RealType>(2) * asin(sqrt((x - x_min) / (x_max - x_min))) / pi<RealType>();
+ // is less accurate, so use acos instead of asin for complement.
+ return 2 * acos(sqrt((x - x_min) / (x_max - x_min))) / pi<RealType>();
+ }
+
+ template <class RealType>
+ BOOST_MATH_GPU_ENABLED inline RealType arcsine_quantile( const RealType p, const RealType x_min, const RealType x_max)
+ {
+ BOOST_MATH_STD_USING
+ // Special cases:
+ if (p == 0)
+ {
+ return 0;
+ }
+ if (p == 1)
+ {
+ return 1;
+ }
+ using boost::math::constants::half_pi;
+ RealType sin2hpip = sin(half_pi<RealType>() * p);
+ RealType sin2hpip2 = sin2hpip * sin2hpip;
+ return -x_min * sin2hpip2 + x_min + x_max * sin2hpip2;
+ }
+ template <class RealType>
+ BOOST_MATH_GPU_ENABLED inline RealType arcsine_cquantile(const RealType q, const RealType x_min, const RealType x_max)
+ {
+ BOOST_MATH_STD_USING
+ // Special cases:
+ if (q == 1)
+ {
+ return 0;
+ }
+ if (q == 0)
+ {
+ return 1;
+ }
+ // Naive RealType p = 1 - q; result = sin(half_pi<RealType>() * p); loses accuracy, so use a cos alternative instead.
+ //result = cos(half_pi<RealType>() * q); // for arcsine(0,1)
+ //result = result * result;
+ // For generalized arcsine:
+ using boost::math::constants::half_pi;
+ RealType cos2hpip = cos(half_pi<RealType>() * q);
+ RealType cos2hpip2 = cos2hpip * cos2hpip;
+ return -x_min * cos2hpip2 + x_min + x_max * cos2hpip2;
+ }
} // namespace arcsine_detail
template <class RealType = double, class Policy = policies::policy<> >
@@ -230,7 +327,7 @@ namespace boost
RealType x_min = dist.x_min();
RealType x_max = dist.x_max();
- if (false == arcsine_detail::check_dist(
+ if (!arcsine_detail::check_dist(
"boost::math::mean(arcsine_distribution<%1%> const&, %1% )",
x_min,
x_max,
@@ -239,7 +336,9 @@ namespace boost
{
return result;
}
- return (x_min + x_max) / 2;
+
+ typedef typename policies::evaluation_t<RealType, Policy> policy_promoted_type;
+ return static_cast<RealType>(arcsine_detail::arcsine_mean(static_cast<policy_promoted_type>(x_min), static_cast<policy_promoted_type>(x_max)));
} // mean
template <class RealType, class Policy>
@@ -248,7 +347,7 @@ namespace boost
RealType result;
RealType x_min = dist.x_min();
RealType x_max = dist.x_max();
- if (false == arcsine_detail::check_dist(
+ if (!arcsine_detail::check_dist(
"boost::math::variance(arcsine_distribution<%1%> const&, %1% )",
x_min,
x_max,
@@ -257,7 +356,9 @@ namespace boost
{
return result;
}
- return (x_max - x_min) * (x_max - x_min) / 8;
+
+ typedef typename policies::evaluation_t<RealType, Policy> policy_promoted_type;
+ return static_cast<RealType>(arcsine_detail::arcsine_variance(static_cast<policy_promoted_type>(x_min), static_cast<policy_promoted_type>(x_max)));
} // variance
template <class RealType, class Policy>
@@ -277,7 +378,7 @@ namespace boost
RealType x_min = dist.x_min();
RealType x_max = dist.x_max();
RealType result;
- if (false == arcsine_detail::check_dist(
+ if (!arcsine_detail::check_dist(
"boost::math::median(arcsine_distribution<%1%> const&, %1% )",
x_min,
x_max,
@@ -286,7 +387,9 @@ namespace boost
{
return result;
}
- return (x_min + x_max) / 2;
+ // The median is the same as the mean
+ typedef typename policies::evaluation_t<RealType, Policy> policy_promoted_type;
+ return static_cast<RealType>(arcsine_detail::arcsine_mean(static_cast<policy_promoted_type>(x_min), static_cast<policy_promoted_type>(x_max)));
}
template <class RealType, class Policy>
@@ -296,7 +399,7 @@ namespace boost
RealType x_min = dist.x_min();
RealType x_max = dist.x_max();
- if (false == arcsine_detail::check_dist(
+ if (!arcsine_detail::check_dist(
"boost::math::skewness(arcsine_distribution<%1%> const&, %1% )",
x_min,
x_max,
@@ -315,7 +418,7 @@ namespace boost
RealType x_min = dist.x_min();
RealType x_max = dist.x_max();
- if (false == arcsine_detail::check_dist(
+ if (!arcsine_detail::check_dist(
"boost::math::kurtosis_excess(arcsine_distribution<%1%> const&, %1% )",
x_min,
x_max,
@@ -324,8 +427,7 @@ namespace boost
{
return result;
}
- result = -3;
- return result / 2;
+ return static_cast<RealType>(-1.5f);
} // kurtosis_excess
template <class RealType, class Policy>
@@ -335,7 +437,7 @@ namespace boost
RealType x_min = dist.x_min();
RealType x_max = dist.x_max();
- if (false == arcsine_detail::check_dist(
+ if (!arcsine_detail::check_dist(
"boost::math::kurtosis(arcsine_distribution<%1%> const&, %1% )",
x_min,
x_max,
@@ -344,75 +446,61 @@ namespace boost
{
return result;
}
-
- return 3 + kurtosis_excess(dist);
+ return static_cast<RealType>(1.5f);
} // kurtosis
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline RealType pdf(const arcsine_distribution<RealType, Policy>& dist, const RealType& xx)
{ // Probability Density/Mass Function arcsine.
BOOST_FPU_EXCEPTION_GUARD
- BOOST_MATH_STD_USING // For ADL of std functions.
-
- constexpr auto function = "boost::math::pdf(arcsine_distribution<%1%> const&, %1%)";
- RealType lo = dist.x_min();
- RealType hi = dist.x_max();
+ RealType x_min = dist.x_min();
+ RealType x_max = dist.x_max();
RealType x = xx;
// Argument checks:
- RealType result = 0;
- if (false == arcsine_detail::check_dist_and_x(
- function,
- lo, hi, x,
+ RealType result;
+ if (!arcsine_detail::check_dist_and_x(
+ "boost::math::pdf(arcsine_distribution<%1%> const&, %1%)",
+ x_min,
+ x_max,
+ x,
&result, Policy()))
{
return result;
}
- using boost::math::constants::pi;
- result = static_cast<RealType>(1) / (pi<RealType>() * sqrt((x - lo) * (hi - x)));
- return result;
+ typedef typename policies::evaluation_t<RealType, Policy> policy_promoted_type;
+ return static_cast<RealType>(arcsine_detail::arcsine_pdf(static_cast<policy_promoted_type>(x),
+ static_cast<policy_promoted_type>(x_min),
+ static_cast<policy_promoted_type>(x_max)));
} // pdf
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline RealType cdf(const arcsine_distribution<RealType, Policy>& dist, const RealType& x)
{ // Cumulative Distribution Function arcsine.
- BOOST_MATH_STD_USING // For ADL of std functions.
-
- constexpr auto function = "boost::math::cdf(arcsine_distribution<%1%> const&, %1%)";
-
RealType x_min = dist.x_min();
RealType x_max = dist.x_max();
// Argument checks:
RealType result = 0;
- if (false == arcsine_detail::check_dist_and_x(
- function,
- x_min, x_max, x,
+ if (!arcsine_detail::check_dist_and_x(
+ "boost::math::cdf(arcsine_distribution<%1%> const&, %1%)",
+ x_min,
+ x_max,
+ x,
&result, Policy()))
{
return result;
}
- // Special cases:
- if (x == x_min)
- {
- return 0;
- }
- else if (x == x_max)
- {
- return 1;
- }
- using boost::math::constants::pi;
- result = static_cast<RealType>(2) * asin(sqrt((x - x_min) / (x_max - x_min))) / pi<RealType>();
- return result;
+ typedef typename policies::evaluation_t<RealType, Policy> policy_promoted_type;
+ return static_cast<RealType>(arcsine_detail::arcsine_cdf(static_cast<policy_promoted_type>(x),
+ static_cast<policy_promoted_type>(x_min),
+ static_cast<policy_promoted_type>(x_max)));
} // arcsine cdf
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline RealType cdf(const complemented2_type<arcsine_distribution<RealType, Policy>, RealType>& c)
{ // Complemented Cumulative Distribution Function arcsine.
- BOOST_MATH_STD_USING // For ADL of std functions.
- constexpr auto function = "boost::math::cdf(arcsine_distribution<%1%> const&, %1%)";
-
RealType x = c.param;
arcsine_distribution<RealType, Policy> const& dist = c.dist;
RealType x_min = dist.x_min();
@@ -420,27 +508,19 @@ namespace boost
// Argument checks:
RealType result = 0;
- if (false == arcsine_detail::check_dist_and_x(
- function,
- x_min, x_max, x,
+ if (!arcsine_detail::check_dist_and_x(
+ "boost::math::cdf(arcsine_distribution<%1%> const&, %1%)",
+ x_min,
+ x_max,
+ x,
&result, Policy()))
{
return result;
}
- if (x == x_min)
- {
- return 0;
- }
- else if (x == x_max)
- {
- return 1;
- }
- using boost::math::constants::pi;
- // Naive version x = 1 - x;
- // result = static_cast<RealType>(2) * asin(sqrt((x - x_min) / (x_max - x_min))) / pi<RealType>();
- // is less accurate, so use acos instead of asin for complement.
- result = static_cast<RealType>(2) * acos(sqrt((x - x_min) / (x_max - x_min))) / pi<RealType>();
- return result;
+ typedef typename policies::evaluation_t<RealType, Policy> policy_promoted_type;
+ return static_cast<RealType>(arcsine_detail::arcsine_ccdf(static_cast<policy_promoted_type>(x),
+ static_cast<policy_promoted_type>(x_min),
+ static_cast<policy_promoted_type>(x_max)));
} // arcsine ccdf
template <class RealType, class Policy>
@@ -454,37 +534,22 @@ namespace boost
// and return a value such that the probability that a random variable x
// will be less than or equal to that value
// is whatever probability you supplied as an argument.
- BOOST_MATH_STD_USING // For ADL of std functions.
-
- using boost::math::constants::half_pi;
-
- constexpr auto function = "boost::math::quantile(arcsine_distribution<%1%> const&, %1%)";
-
RealType result = 0; // of argument checks:
RealType x_min = dist.x_min();
RealType x_max = dist.x_max();
- if (false == arcsine_detail::check_dist_and_prob(
- function,
- x_min, x_max, p,
+ if (!arcsine_detail::check_dist_and_prob(
+ "boost::math::quantile(arcsine_distribution<%1%> const&, %1%)",
+ x_min,
+ x_max,
+ p,
&result, Policy()))
{
return result;
}
- // Special cases:
- if (p == 0)
- {
- return 0;
- }
- if (p == 1)
- {
- return 1;
- }
-
- RealType sin2hpip = sin(half_pi<RealType>() * p);
- RealType sin2hpip2 = sin2hpip * sin2hpip;
- result = -x_min * sin2hpip2 + x_min + x_max * sin2hpip2;
-
- return result;
+ typedef typename policies::evaluation_t<RealType, Policy> policy_promoted_type;
+ return static_cast<RealType>(arcsine_detail::arcsine_quantile(static_cast<policy_promoted_type>(p),
+ static_cast<policy_promoted_type>(x_min),
+ static_cast<policy_promoted_type>(x_max)));
} // quantile
template <class RealType, class Policy>
@@ -493,19 +558,14 @@ namespace boost
// Complement Quantile or Percent Point arcsine function.
// Return the number of expected x for a given
// complement of the probability q.
- BOOST_MATH_STD_USING // For ADL of std functions.
-
- using boost::math::constants::half_pi;
- constexpr auto function = "boost::math::quantile(arcsine_distribution<%1%> const&, %1%)";
-
// Error checks:
RealType q = c.param;
const arcsine_distribution<RealType, Policy>& dist = c.dist;
RealType result = 0;
RealType x_min = dist.x_min();
RealType x_max = dist.x_max();
- if (false == arcsine_detail::check_dist_and_prob(
- function,
+ if (!arcsine_detail::check_dist_and_prob(
+ "boost::math::quantile(arcsine_distribution<%1%> const&, %1%)",
x_min,
x_max,
q,
@@ -513,26 +573,11 @@ namespace boost
{
return result;
}
- // Special cases:
- if (q == 1)
- {
- return 0;
- }
- if (q == 0)
- {
- return 1;
- }
- // Naive RealType p = 1 - q; result = sin(half_pi<RealType>() * p); loses accuracy, so use a cos alternative instead.
- //result = cos(half_pi<RealType>() * q); // for arcsine(0,1)
- //result = result * result;
- // For generalized arcsine:
- RealType cos2hpip = cos(half_pi<RealType>() * q);
- RealType cos2hpip2 = cos2hpip * cos2hpip;
- result = -x_min * cos2hpip2 + x_min + x_max * cos2hpip2;
-
- return result;
+ typedef typename policies::evaluation_t<RealType, Policy> policy_promoted_type;
+ return static_cast<RealType>(arcsine_detail::arcsine_cquantile(static_cast<policy_promoted_type>(q),
+ static_cast<policy_promoted_type>(x_min),
+ static_cast<policy_promoted_type>(x_max)));
} // Quantile Complement
-
} // namespace math
} // namespace boost
diff --git a/third-party/boost-math/include/boost/math/distributions/binomial.hpp b/third-party/boost-math/include/boost/math/distributions/binomial.hpp
index b17893e422c14..262823170f45c 100644
--- a/third-party/boost-math/include/boost/math/distributions/binomial.hpp
+++ b/third-party/boost-math/include/boost/math/distributions/binomial.hpp
@@ -157,7 +157,7 @@ namespace boost
template <class RealType, class Policy>
BOOST_MATH_CUDA_ENABLED inline bool check_dist_and_prob(const char* function, const RealType& N, RealType p, RealType prob, RealType* result, const Policy& pol)
{
- if((check_dist(function, N, p, result, pol) && detail::check_probability(function, prob, result, pol)) == false)
+ if(!(check_dist(function, N, p, result, pol) && detail::check_probability(function, prob, result, pol)))
return false;
return true;
}
@@ -226,7 +226,7 @@ namespace boost
// but zero is the best we can do:
return 0;
}
- if(p == 1 || success_fraction == 1)
+ if(q == 0 || success_fraction == 1)
{ // Probability of n or fewer successes is always one,
// so n is the most sensible answer here:
return trials;
@@ -321,11 +321,11 @@ namespace boost
BOOST_MATH_STATIC const char* function = "boost::math::binomial_distribution<%1%>::find_lower_bound_on_p";
// Error checks:
RealType result = 0;
- if(false == binomial_detail::check_dist_and_k(
+ if(!(binomial_detail::check_dist_and_k(
function, trials, RealType(0), successes, &result, Policy())
&&
binomial_detail::check_dist_and_prob(
- function, trials, RealType(0), probability, &result, Policy()))
+ function, trials, RealType(0), probability, &result, Policy())))
{ return result; }
if(successes == 0)
@@ -346,11 +346,11 @@ namespace boost
BOOST_MATH_STATIC const char* function = "boost::math::binomial_distribution<%1%>::find_upper_bound_on_p";
// Error checks:
RealType result = 0;
- if(false == binomial_detail::check_dist_and_k(
+ if(!(binomial_detail::check_dist_and_k(
function, trials, RealType(0), successes, &result, Policy())
&&
binomial_detail::check_dist_and_prob(
- function, trials, RealType(0), probability, &result, Policy()))
+ function, trials, RealType(0), probability, &result, Policy())))
{ return result; }
if(trials == successes)
@@ -373,11 +373,11 @@ namespace boost
BOOST_MATH_STATIC const char* function = "boost::math::binomial_distribution<%1%>::find_minimum_number_of_trials";
// Error checks:
RealType result = 0;
- if(false == binomial_detail::check_dist_and_k(
+ if(!(binomial_detail::check_dist_and_k(
function, k, p, k, &result, Policy())
&&
binomial_detail::check_dist_and_prob(
- function, k, p, alpha, &result, Policy()))
+ function, k, p, alpha, &result, Policy())))
{ return result; }
result = ibetac_invb(k + 1, p, alpha, Policy()); // returns n - k
@@ -392,11 +392,11 @@ namespace boost
BOOST_MATH_STATIC const char* function = "boost::math::binomial_distribution<%1%>::find_maximum_number_of_trials";
// Error checks:
RealType result = 0;
- if(false == binomial_detail::check_dist_and_k(
+ if(!(binomial_detail::check_dist_and_k(
function, k, p, k, &result, Policy())
&&
binomial_detail::check_dist_and_prob(
- function, k, p, alpha, &result, Policy()))
+ function, k, p, alpha, &result, Policy())))
{ return result; }
result = ibeta_invb(k + 1, p, alpha, Policy()); // returns n - k
diff --git a/third-party/boost-math/include/boost/math/distributions/cauchy.hpp b/third-party/boost-math/include/boost/math/distributions/cauchy.hpp
index 00a9ac9ac94b1..5a19f499a31c0 100644
--- a/third-party/boost-math/include/boost/math/distributions/cauchy.hpp
+++ b/third-party/boost-math/include/boost/math/distributions/cauchy.hpp
@@ -57,11 +57,11 @@ BOOST_MATH_GPU_ENABLED RealType cdf_imp(const cauchy_distribution<RealType, Poli
RealType result = 0;
RealType location = dist.location();
RealType scale = dist.scale();
- if(false == detail::check_location(function, location, &result, Policy()))
+ if(!detail::check_location(function, location, &result, Policy()))
{
return result;
}
- if(false == detail::check_scale(function, scale, &result, Policy()))
+ if(!detail::check_scale(function, scale, &result, Policy()))
{
return result;
}
@@ -84,7 +84,7 @@ BOOST_MATH_GPU_ENABLED RealType cdf_imp(const cauchy_distribution<RealType, Poli
return static_cast<RealType>((complement) ? 1 : 0);
}
#endif
- if(false == detail::check_x(function, x, &result, Policy()))
+ if(!detail::check_x(function, x, &result, Policy()))
{ // Catches x == NaN
return result;
}
@@ -111,15 +111,15 @@ BOOST_MATH_GPU_ENABLED RealType quantile_imp(
RealType result = 0;
RealType location = dist.location();
RealType scale = dist.scale();
- if(false == detail::check_location(function, location, &result, Policy()))
+ if(!detail::check_location(function, location, &result, Policy()))
{
return result;
}
- if(false == detail::check_scale(function, scale, &result, Policy()))
+ if(!detail::check_scale(function, scale, &result, Policy()))
{
return result;
}
- if(false == detail::check_probability(function, p, &result, Policy()))
+ if(!detail::check_probability(function, p, &result, Policy()))
{
return result;
}
@@ -224,11 +224,11 @@ BOOST_MATH_GPU_ENABLED inline RealType pdf(const cauchy_distribution<RealType, P
RealType result = 0;
RealType location = dist.location();
RealType scale = dist.scale();
- if(false == detail::check_scale(function, scale, &result, Policy()))
+ if(!detail::check_scale(function, scale, &result, Policy()))
{
return result;
}
- if(false == detail::check_location(function, location, &result, Policy()))
+ if(!detail::check_location(function, location, &result, Policy()))
{
return result;
}
@@ -242,7 +242,7 @@ BOOST_MATH_GPU_ENABLED inline RealType pdf(const cauchy_distribution<RealType, P
// return 0;
//}
- if(false == detail::check_x(function, x, &result, Policy()))
+ if(!detail::check_x(function, x, &result, Policy()))
{ // Catches x = NaN
return result;
}
diff --git a/third-party/boost-math/include/boost/math/distributions/chi_squared.hpp b/third-party/boost-math/include/boost/math/distributions/chi_squared.hpp
index 3944569e89354..9823a2d555c56 100644
--- a/third-party/boost-math/include/boost/math/distributions/chi_squared.hpp
+++ b/third-party/boost-math/include/boost/math/distributions/chi_squared.hpp
@@ -103,7 +103,7 @@ BOOST_MATH_GPU_ENABLED RealType pdf(const chi_squared_distribution<RealType, Pol
constexpr auto function = "boost::math::pdf(const chi_squared_distribution<%1%>&, %1%)";
- if(false == detail::check_df(
+ if(!detail::check_df(
function, degrees_of_freedom, &error_result, Policy()))
return error_result;
@@ -142,7 +142,7 @@ BOOST_MATH_GPU_ENABLED inline RealType cdf(const chi_squared_distribution<RealTy
RealType error_result;
constexpr auto function = "boost::math::cdf(const chi_squared_distribution<%1%>&, %1%)";
- if(false == detail::check_df(
+ if(!detail::check_df(
function, degrees_of_freedom, &error_result, Policy()))
return error_result;
@@ -180,7 +180,7 @@ BOOST_MATH_GPU_ENABLED inline RealType cdf(const complemented2_type<chi_squared_
constexpr auto function = "boost::math::cdf(const chi_squared_distribution<%1%>&, %1%)";
// Error check:
RealType error_result;
- if(false == detail::check_df(
+ if(!detail::check_df(
function, degrees_of_freedom, &error_result, Policy()))
return error_result;
@@ -201,8 +201,7 @@ BOOST_MATH_GPU_ENABLED inline RealType quantile(const complemented2_type<chi_squ
constexpr auto function = "boost::math::quantile(const chi_squared_distribution<%1%>&, %1%)";
// Error check:
RealType error_result;
- if(false == (
- detail::check_df(function, degrees_of_freedom, &error_result, Policy())
+ if (!(detail::check_df(function, degrees_of_freedom, &error_result, Policy())
&& detail::check_probability(function, q, &error_result, Policy()))
)
return error_result;
@@ -310,9 +309,8 @@ BOOST_MATH_GPU_ENABLED RealType chi_squared_distribution<RealType, Policy>::find
constexpr auto function = "boost::math::chi_squared_distribution<%1%>::find_degrees_of_freedom(%1%,%1%,%1%,%1%,%1%)";
// Check for domain errors:
RealType error_result;
- if(false ==
- detail::check_probability(function, alpha, &error_result, Policy())
- && detail::check_probability(function, beta, &error_result, Policy()))
+ if(!(detail::check_probability(function, alpha, &error_result, Policy())
+ && detail::check_probability(function, beta, &error_result, Policy())))
{ // Either probability is outside 0 to 1.
return error_result;
}
diff --git a/third-party/boost-math/include/boost/math/distributions/extreme_value.hpp b/third-party/boost-math/include/boost/math/distributions/extreme_value.hpp
index 73454d29d4b85..7049ac6a155d3 100644
--- a/third-party/boost-math/include/boost/math/distributions/extreme_value.hpp
+++ b/third-party/boost-math/include/boost/math/distributions/extreme_value.hpp
@@ -173,8 +173,6 @@ BOOST_MATH_GPU_ENABLED inline RealType cdf(const extreme_value_distribution<Real
return result;
if(0 == detail::check_finite(function, a, &result, Policy()))
return result;
- if(0 == detail::check_finite(function, a, &result, Policy()))
- return result;
if(0 == detail::check_x("boost::math::cdf(const extreme_value_distribution<%1%>&, %1%)", x, &result, Policy()))
return result;
@@ -199,8 +197,6 @@ BOOST_MATH_GPU_ENABLED inline RealType logcdf(const extreme_value_distribution<R
return result;
if(0 == detail::check_finite(function, a, &result, Policy()))
return result;
- if(0 == detail::check_finite(function, a, &result, Policy()))
- return result;
if(0 == detail::check_x("boost::math::logcdf(const extreme_value_distribution<%1%>&, %1%)", x, &result, Policy()))
return result;
diff --git a/third-party/boost-math/include/boost/math/distributions/find_location.hpp b/third-party/boost-math/include/boost/math/distributions/find_location.hpp
index 33c2e64b622d4..c23b41eb1090b 100644
--- a/third-party/boost-math/include/boost/math/distributions/find_location.hpp
+++ b/third-party/boost-math/include/boost/math/distributions/find_location.hpp
@@ -10,6 +10,7 @@
#include <boost/math/distributions/fwd.hpp> // for all distribution signatures.
#include <boost/math/distributions/complement.hpp>
+#include <boost/math/distributions/detail/common_error_handling.hpp>
#include <boost/math/policies/policy.hpp>
#include <boost/math/tools/traits.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
@@ -51,10 +52,10 @@ namespace boost
return policies::raise_domain_error<typename Dist::value_type>(
function, "z parameter was %1%, but must be finite!", z, pol);
}
- if(!(boost::math::isfinite)(scale))
+ typename Dist::value_type result;
+ if(!(boost::math::detail::check_scale)(function, scale, &result, pol))
{
- return policies::raise_domain_error<typename Dist::value_type>(
- function, "scale parameter was %1%, but must be finite!", scale, pol);
+ return result;
}
//cout << "z " << z << ", p " << p << ", quantile(Dist(), p) "
@@ -94,11 +95,11 @@ namespace boost
return policies::raise_domain_error<typename Dist::value_type>(
function, "z parameter was %1%, but must be finite!", z, policies::policy<>());
}
+ typename Dist::value_type result;
typename Dist::value_type scale = c.param2;
- if(!(boost::math::isfinite)(scale))
+ if(!(boost::math::detail::check_scale)(function, scale, &result, policies::policy<>()))
{
- return policies::raise_domain_error<typename Dist::value_type>(
- function, "scale parameter was %1%, but must be finite!", scale, policies::policy<>());
+ return result;
}
// cout << "z " << c.dist << ", quantile (Dist(), " << c.param1 << ") * scale " << c.param2 << endl;
return z - quantile(Dist(), p) * scale;
@@ -123,11 +124,11 @@ namespace boost
return policies::raise_domain_error<typename Dist::value_type>(
function, "z parameter was %1%, but must be finite!", z, c.param3);
}
+ typename Dist::value_type result;
typename Dist::value_type scale = c.param2;
- if(!(boost::math::isfinite)(scale))
+ if(!(boost::math::detail::check_scale)(function, scale, &result, c.param3))
{
- return policies::raise_domain_error<typename Dist::value_type>(
- function, "scale parameter was %1%, but must be finite!", scale, c.param3);
+ return result;
}
// cout << "z " << c.dist << ", quantile (Dist(), " << c.param1 << ") * scale " << c.param2 << endl;
return z - quantile(Dist(), p) * scale;
diff --git a/third-party/boost-math/include/boost/math/distributions/inverse_chi_squared.hpp b/third-party/boost-math/include/boost/math/distributions/inverse_chi_squared.hpp
index 1a3c680d2360e..ca7e7f87e7a48 100644
--- a/third-party/boost-math/include/boost/math/distributions/inverse_chi_squared.hpp
+++ b/third-party/boost-math/include/boost/math/distributions/inverse_chi_squared.hpp
@@ -289,7 +289,7 @@ BOOST_MATH_GPU_ENABLED inline RealType mean(const inverse_chi_squared_distributi
if(df <= 2)
return policies::raise_domain_error<RealType>(
function,
- "inverse Chi-Squared distribution only has a mode for degrees of freedom > 2, but got degrees of freedom = %1%.",
+ "inverse Chi-Squared distribution only has a mean for degrees of freedom > 2, but got degrees of freedom = %1%.",
df, Policy());
return (df * scale) / (df - 2);
} // mean
diff --git a/third-party/boost-math/include/boost/math/distributions/inverse_gaussian.hpp b/third-party/boost-math/include/boost/math/distributions/inverse_gaussian.hpp
index 20d3b6bdd56ba..795ad23d4a005 100644
--- a/third-party/boost-math/include/boost/math/distributions/inverse_gaussian.hpp
+++ b/third-party/boost-math/include/boost/math/distributions/inverse_gaussian.hpp
@@ -52,6 +52,7 @@
#include <boost/math/tools/config.hpp>
#include <boost/math/tools/cstdint.hpp>
#include <boost/math/special_functions/erf.hpp> // for erf/erfc.
+#include <boost/math/special_functions/pow.hpp> // for erf/erfc.
#include <boost/math/distributions/complement.hpp>
#include <boost/math/distributions/detail/common_error_handling.hpp>
#include <boost/math/distributions/normal.hpp>
@@ -298,7 +299,7 @@ struct inverse_gaussian_quantile_complement_functor
namespace detail
{
template <class RealType>
- BOOST_MATH_GPU_ENABLED inline RealType guess_ig(RealType p, RealType mu = 1, RealType lambda = 1)
+ BOOST_MATH_GPU_ENABLED inline RealType guess_ig(RealType p, RealType q, RealType mu, RealType lambda)
{ // guess at random variate value x for inverse gaussian quantile.
BOOST_MATH_STD_USING
using boost::math::policies::policy;
@@ -323,27 +324,16 @@ namespace detail
x = mu * exp(quantile(n01, p) / sqrt(phi) - 1/(2 * phi));
}
else
- { // phi < 2 so much less symmetrical with long tail,
- // so use gamma distribution as an approximation.
- using boost::math::gamma_distribution;
-
- // Define the distribution, using gamma_nooverflow:
- using gamma_nooverflow = gamma_distribution<RealType, no_overthrow_policy>;
-
- gamma_nooverflow g(static_cast<RealType>(0.5), static_cast<RealType>(1.));
-
- // R qgamma(0.2, 0.5, 1) = 0.0320923
- RealType qg = quantile(complement(g, p));
- x = lambda / (qg * 2);
- //
- if (x > mu/2) // x > mu /2?
- { // x too large for the gamma approximation to work well.
- //x = qgamma(p, 0.5, 1.0); // qgamma(0.270614, 0.5, 1) = 0.05983807
- RealType q = quantile(g, p);
- // x = mu * exp(q * static_cast<RealType>(0.1)); // Said to improve at high p
- // x = mu * x; // Improves at high p?
- x = mu * exp(q / sqrt(phi) - 1/(2 * phi));
- }
+ {
+ // Construct a gamma distribution with the same mean and standard deviation, and hope it
+ // get's us in more or less the right ballpark:
+ inverse_gaussian_distribution<RealType> ig(mu, lambda);
+ RealType m = mean(ig);
+ RealType v = standard_deviation(ig);
+ RealType k = m * m / v;
+ RealType theta = v / m;
+ gamma_distribution<RealType> n01(k, theta);
+ x = p < q ? quantile(n01, p) : quantile(complement(n01, q));
}
return x;
} // guess_ig
@@ -379,7 +369,7 @@ BOOST_MATH_GPU_ENABLED inline RealType quantile(const inverse_gaussian_distribut
return result; // infinity;
}
- RealType guess = detail::guess_ig(p, dist.mean(), dist.scale());
+ RealType guess = detail::guess_ig(p, RealType(1 - p), dist.mean(), dist.scale());
using boost::math::tools::max_value;
RealType min = static_cast<RealType>(0); // Minimum possible value is bottom of range of distribution.
@@ -390,8 +380,19 @@ BOOST_MATH_GPU_ENABLED inline RealType quantile(const inverse_gaussian_distribut
int get_digits = policies::digits<RealType, Policy>();// get digits from policy,
boost::math::uintmax_t max_iter = policies::get_max_root_iterations<Policy>(); // and max iterations.
using boost::math::tools::newton_raphson_iterate;
+ inverse_gaussian_quantile_functor<RealType, Policy> func(dist, p);
+ //
+ // Our guess is often not very good, so lets bracket the root just in case:
+ //
+ RealType f0 = boost::math::get<0>(func(guess));
+ if (f0 < 0)
+ tools::detail::bracket_root_towards_max(func, guess, f0, min, max, max_iter);
+ else
+ tools::detail::bracket_root_towards_min(func, guess, f0, min, max, max_iter);
+ if((guess < min) || (guess > max))
+ guess = (min + max) / 2;
result =
- newton_raphson_iterate(inverse_gaussian_quantile_functor<RealType, Policy>(dist, p), guess, min, max, get_digits, max_iter);
+ newton_raphson_iterate(func, guess, min, max, get_digits, max_iter);
if (max_iter >= policies::get_max_root_iterations<Policy>())
{
return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:" // LCOV_EXCL_LINE
@@ -455,7 +456,7 @@ BOOST_MATH_GPU_ENABLED inline RealType quantile(const complemented2_type<inverse
if(false == detail::check_probability(function, q, &result, Policy()))
return result;
- RealType guess = detail::guess_ig(q, mean, scale);
+ RealType guess = detail::guess_ig(RealType(1 - q), q, mean, scale);
// Complement.
using boost::math::tools::max_value;
@@ -466,7 +467,17 @@ BOOST_MATH_GPU_ENABLED inline RealType quantile(const complemented2_type<inverse
int get_digits = policies::digits<RealType, Policy>();
boost::math::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
using boost::math::tools::newton_raphson_iterate;
- result = newton_raphson_iterate(inverse_gaussian_quantile_complement_functor<RealType, Policy>(c.dist, q), guess, min, max, get_digits, max_iter);
+ inverse_gaussian_quantile_complement_functor<RealType, Policy> func(c.dist, q);
+ RealType f0 = boost::math::get<0>(func(guess));
+ if (f0 > 0)
+ tools::detail::bracket_root_towards_max(func, guess, f0, min, max, max_iter);
+ else
+ tools::detail::bracket_root_towards_min(func, guess, f0, min, max, max_iter);
+ if ((guess < min) || (guess > max))
+ guess = (min + max) / 2;
+ result =
+ newton_raphson_iterate(func, guess, min, max, get_digits, max_iter);
+ result = newton_raphson_iterate(func, guess, min, max, get_digits, max_iter);
if (max_iter >= policies::get_max_root_iterations<Policy>())
{
return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:" // LCOV_EXCL_LINE
diff --git a/third-party/boost-math/include/boost/math/distributions/logistic.hpp b/third-party/boost-math/include/boost/math/distributions/logistic.hpp
index 56dc6e9f2f478..bc2dd1ff5a875 100644
--- a/third-party/boost-math/include/boost/math/distributions/logistic.hpp
+++ b/third-party/boost-math/include/boost/math/distributions/logistic.hpp
@@ -19,6 +19,8 @@
#include <boost/math/constants/constants.hpp>
#include <boost/math/policies/policy.hpp>
#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/special_functions/logit.hpp>
+#include <boost/math/special_functions/logistic_sigmoid.hpp>
namespace boost { namespace math {
@@ -144,13 +146,10 @@ namespace boost { namespace math {
{
return result;
}
- BOOST_MATH_STD_USING
- RealType power = (location - x) / scale;
- if(power > tools::log_max_value<RealType>())
- return 0;
- if(power < -tools::log_max_value<RealType>())
- return 1;
- return 1 / (1 + exp(power));
+
+ using promoted_real_type = typename policies::evaluation<RealType, Policy>::type;
+ promoted_real_type power = (static_cast<promoted_real_type>(x) - static_cast<promoted_real_type>(location)) / static_cast<promoted_real_type>(scale);
+ return logistic_sigmoid(power, policies::make_forwarding_policy_t<Policy>());
}
template <class RealType, class Policy>
@@ -159,7 +158,7 @@ namespace boost { namespace math {
RealType scale = dist.scale();
RealType location = dist.location();
RealType result = 0; // of checks.
- constexpr auto function = "boost::math::cdf(const logistic_distribution<%1%>&, %1%)";
+ constexpr auto function = "boost::math::logcdf(const logistic_distribution<%1%>&, %1%)";
if(false == detail::check_scale(function, scale, &result, Policy()))
{
return result;
@@ -199,7 +198,6 @@ namespace boost { namespace math {
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline RealType quantile(const logistic_distribution<RealType, Policy>& dist, const RealType& p)
{
- BOOST_MATH_STD_USING
RealType location = dist.location();
RealType scale = dist.scale();
@@ -221,21 +219,13 @@ namespace boost { namespace math {
{
return policies::raise_overflow_error<RealType>(function,"probability argument is 1, must be >0 and <1",Policy());
}
- //Expressions to try
- //return location+scale*log(p/(1-p));
- //return location+scale*log1p((2*p-1)/(1-p));
-
- //return location - scale*log( (1-p)/p);
- //return location - scale*log1p((1-2*p)/p);
- //return -scale*log(1/p-1) + location;
- return location - scale * log((1 - p) / p);
+ return location + scale * logit(p, Policy());
} // RealType quantile(const logistic_distribution<RealType, Policy>& dist, const RealType& p)
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline RealType cdf(const complemented2_type<logistic_distribution<RealType, Policy>, RealType>& c)
{
- BOOST_MATH_STD_USING
RealType location = c.dist.location();
RealType scale = c.dist.scale();
RealType x = c.param;
@@ -259,12 +249,10 @@ namespace boost { namespace math {
{
return result;
}
- RealType power = (x - location) / scale;
- if(power > tools::log_max_value<RealType>())
- return 0;
- if(power < -tools::log_max_value<RealType>())
- return 1;
- return 1 / (1 + exp(power));
+
+ using promoted_real_type = typename policies::evaluation<RealType, Policy>::type;
+ promoted_real_type power = (static_cast<promoted_real_type>(location) - static_cast<promoted_real_type>(x)) / static_cast<promoted_real_type>(scale);
+ return logistic_sigmoid(power, policies::make_forwarding_policy_t<Policy>());
}
template <class RealType, class Policy>
@@ -274,7 +262,7 @@ namespace boost { namespace math {
RealType location = c.dist.location();
RealType scale = c.dist.scale();
RealType x = c.param;
- constexpr auto function = "boost::math::cdf(const complement(logistic_distribution<%1%>&), %1%)";
+ constexpr auto function = "boost::math::logcdf(const complement(logistic_distribution<%1%>&), %1%)";
RealType result = 0;
if(false == detail::check_scale(function, scale, &result, Policy()))
@@ -306,7 +294,6 @@ namespace boost { namespace math {
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline RealType quantile(const complemented2_type<logistic_distribution<RealType, Policy>, RealType>& c)
{
- BOOST_MATH_STD_USING
RealType scale = c.dist.scale();
RealType location = c.dist.location();
constexpr auto function = "boost::math::quantile(const complement(logistic_distribution<%1%>&), %1%)";
@@ -328,15 +315,8 @@ namespace boost { namespace math {
{
return policies::raise_overflow_error<RealType>(function,"probability argument is 0, but must be >0 and <1",Policy());
}
- //Expressions to try
- //return location+scale*log((1-q)/q);
- return location + scale * log((1 - q) / q);
-
- //return location-scale*log(q/(1-q));
- //return location-scale*log1p((2*q-1)/(1-q));
- //return location+scale*log(1/q-1);
- //return location+scale*log1p(1/q-2);
+ return location - scale * logit(q, Policy());
}
template <class RealType, class Policy>
diff --git a/third-party/boost-math/include/boost/math/distributions/non_central_beta.hpp b/third-party/boost-math/include/boost/math/distributions/non_central_beta.hpp
index f311f77737c17..ea0c5a168e284 100644
--- a/third-party/boost-math/include/boost/math/distributions/non_central_beta.hpp
+++ b/third-party/boost-math/include/boost/math/distributions/non_central_beta.hpp
@@ -112,11 +112,15 @@ namespace boost
last_term = term;
}
last_term = 0;
+ T betaf_lim = betaf * tools::epsilon<T>() * 4;
for(auto i = k + 1; ; ++i)
{
poisf *= l2 / i;
xtermf *= (x * (a + b + i - 2)) / (a + i - 1);
betaf -= xtermf;
+
+ if (betaf < betaf_lim)
+ break; // nothing but garbage bits in betaf!!
T term = poisf * betaf;
sum += term;
diff --git a/third-party/boost-math/include/boost/math/distributions/non_central_f.hpp b/third-party/boost-math/include/boost/math/distributions/non_central_f.hpp
index dedd437144bd6..9bae5c41ff594 100644
--- a/third-party/boost-math/include/boost/math/distributions/non_central_f.hpp
+++ b/third-party/boost-math/include/boost/math/distributions/non_central_f.hpp
@@ -14,14 +14,173 @@
#include <boost/math/tools/tuple.hpp>
#include <boost/math/tools/promotion.hpp>
#include <boost/math/distributions/non_central_beta.hpp>
+#include <boost/math/distributions/non_central_chi_squared.hpp>
#include <boost/math/distributions/detail/generic_mode.hpp>
#include <boost/math/special_functions/pow.hpp>
#include <boost/math/policies/policy.hpp>
+#include <boost/math/distributions/complement.hpp> // complements
namespace boost
{
namespace math
{
+ namespace detail
+ {
+ template <class RealType, class Policy>
+ struct non_centrality_finder_f
+ {
+ BOOST_MATH_GPU_ENABLED non_centrality_finder_f(const RealType x_, const RealType v1_, const RealType v2_, const RealType p_, const bool c)
+ : x(x_), v1(v1_), v2(v2_), p(p_), comp(c) {}
+
+ BOOST_MATH_GPU_ENABLED RealType operator()(RealType nc) const
+ {
+ non_central_f_distribution<RealType, Policy> d(v1, v2, nc);
+ return comp ?
+ RealType(p - cdf(complement(d, x)))
+ : RealType(cdf(d, x) - p);
+ }
+ private:
+ RealType x, v1, v2, p;
+ bool comp;
+ };
+
+ template <class RealType, class Policy>
+ BOOST_MATH_GPU_ENABLED RealType find_non_centrality_f(const RealType x, const RealType v1, const RealType v2, const RealType p, const RealType q, const RealType p_q_precision, const Policy& pol)
+ {
+ constexpr auto function = "non_central_f<%1%>::find_non_centrality";
+
+ if ( p == 0 || q == 0) {
+ return policies::raise_domain_error<RealType>(function, "Can't find non centrality parameter when the probability is <=0 or >=1, only possible answer is %1%", // LCOV_EXCL_LINE
+ RealType(boost::math::numeric_limits<RealType>::quiet_NaN()), Policy()); // LCOV_EXCL_LINE
+ }
+
+ // Check if nc = 0 (which is just the F-distribution)
+ non_centrality_finder_f<RealType, Policy> f(x, v1, v2, p < q ? p : q, p < q ? false : true);
+ // This occurs when the root finder would need to find a result smaller than
+ // tools::min_value (which it cannot do). Note that we have to add in a small
+ // amount of "tolerance" since the subtraction in our termination condition
+ // implies a small amount of wobble in the result which should be of the
+ // order p * eps (note not q * eps, since q is calculated as 1-p).
+ // Also note that p_q_precision is passed down from our caller as the
+ // epsilon of the original called values, and not after possible promotion.
+ if (f(tools::min_value<RealType>()) <= 20 * p_q_precision * p){
+ return 0;
+ }
+
+ RealType guess = RealType(10); // Starting guess.
+ RealType factor = RealType(2); // How big steps to take when searching.
+ boost::math::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
+ tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
+
+ boost::math::pair<RealType, RealType> result_bracket = tools::bracket_and_solve_root(
+ f, guess, factor, false, tol, max_iter, pol);
+
+ RealType result = result_bracket.first + (result_bracket.second - result_bracket.first)/2;
+ if (max_iter >= policies::get_max_root_iterations<Policy>()) {
+ return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:" // LCOV_EXCL_LINE
+ " or there is no answer to problem. Current best guess is %1%", result, Policy()); // LCOV_EXCL_LINE
+ }
+ return result;
+ }
+
+ template <class RealType, class Policy>
+ struct f_degrees_of_freedom_finder
+ {
+ f_degrees_of_freedom_finder(
+ RealType x_, RealType v_, RealType nc_, bool find_v1_, RealType p_, bool c)
+ : x(x_), v(v_), nc(nc_), find_v1(find_v1_), p(p_), comp(c) {}
+
+ RealType operator()(const RealType& input_v)
+ {
+ RealType v1 = find_v1 ? input_v : v;
+ RealType v2 = find_v1 ? v : input_v;
+ non_central_f_distribution<RealType, Policy> d(v1, v2, nc);
+ return comp ?
+ p - cdf(complement(d, x))
+ : cdf(d, x) - p;
+ }
+ private:
+ RealType x;
+ RealType v;
+ RealType nc;
+ bool find_v1;
+ RealType p;
+ bool comp;
+ };
+
+ template <class RealType, class Policy>
+ RealType large_v2_approximation(RealType x, RealType v1, RealType p, RealType q, RealType nc)
+ { // For v2 -> inf approximate f_degreese_of_freedome_finder with chi squared distribution
+ // with degrees of freedom v1 at the cdf at x * v1
+ bool comp = p < q ? false : true;
+ RealType pval = p < q ? p : q;
+ non_central_chi_squared_distribution<RealType, Policy> d(v1, nc);
+ return comp ? pval - cdf(complement(d, x*v1)) : cdf(d, x*v1) - pval;
+ }
+
+ template <class RealType, class Policy>
+ inline RealType find_degrees_of_freedom_f(
+ const RealType x, const RealType v, const RealType nc, const bool find_v1, const RealType p, const RealType q, const Policy& pol)
+ {
+ BOOST_MATH_STD_USING
+ using std::fabs;
+ const char* function = "non_central_f<%1%>::find_degrees_of_freedom_f";
+ if((p == 0) || (q == 0))
+ {
+ //
+ // Can't find a thing if one of p and q is zero:
+ //
+ return policies::raise_domain_error<RealType>(function, "Can't find degrees of freedom when the probability is 0 or 1, only possible answer is %1%",
+ RealType(std::numeric_limits<RealType>::quiet_NaN()), Policy()); // LCOV_EXCL_LINE
+ }
+ if (x < tools::epsilon<RealType>())
+ {
+ return policies::raise_evaluation_error<RealType>(function, "Can't find degrees of freedom when the abscissa value is very close to zero as all degrees of freedom generate the same CDF at x=0: try again further out in the tails!!",
+ RealType(std::numeric_limits<RealType>::quiet_NaN()), Policy()); // LCOV_EXCL_LINE
+ }
+ f_degrees_of_freedom_finder<RealType, Policy> f(x, v, nc, find_v1, p < q ? p : q, p < q ? false : true);
+
+ // There are times when f has two roots - thus, two degrees of freedom can
+ // be found. We find this case by checking if the sign of f for large and
+ // small values of v have the same sign. If the sign is the same, then there
+ // are an even number of roots. If the signs differ, there is only one root
+ // and we can safely find the root.
+ RealType vLarge = sqrt(boost::math::tools::max_value<RealType>());
+ RealType vSmall = 1 / vLarge;
+
+ // As v2 -> infinity, noncentral f converges to chi-squared distribution.
+ // Rather than evaluating f(vLarge), we can use the more stable chi-squared approximation
+ RealType large_difference;
+ if (find_v1)
+ {
+ large_difference = large_v2_approximation<RealType, Policy>(x, v, p, q, nc);
+ }
+ else
+ large_difference = f(vLarge);
+
+ if ((large_difference < 0) == (f(vSmall) < 0)){
+ return policies::raise_evaluation_error<RealType>(function, "Can't find degrees of freedom because two degrees of freedom can be found using the given parameters",
+ RealType(std::numeric_limits<RealType>::quiet_NaN()), Policy()); // LCOV_EXCL_LINE
+ }
+
+ tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
+ std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
+ //
+ // Pick an initial guess:
+ //
+ RealType guess = 1;
+ std::pair<RealType, RealType> ir = tools::bracket_and_solve_root(
+ f, guess, RealType(2), f(guess) < 0 ? true : false, tol, max_iter, pol);
+ RealType result = ir.first + (ir.second - ir.first) / 2;
+ if(max_iter >= policies::get_max_root_iterations<Policy>())
+ {
+ return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:" // LCOV_EXCL_LINE
+ " or there is no answer to problem. Current best guess is %1%", result, Policy()); // LCOV_EXCL_LINE
+ }
+ return result;
+ }
+ } // namespace detail
+
template <class RealType = double, class Policy = policies::policy<> >
class non_central_f_distribution
{
@@ -58,6 +217,141 @@ namespace boost
{ // Private data getter function.
return ncp;
}
+ BOOST_MATH_GPU_ENABLED static RealType find_non_centrality(const RealType x, const RealType v1, const RealType v2, const RealType p)
+ {
+ constexpr auto function = "non_central_f_distribution<%1%>::find_non_centrality";
+ typedef typename policies::evaluation<RealType, Policy>::type eval_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+ eval_type result = detail::find_non_centrality_f(
+ static_cast<eval_type>(x),
+ static_cast<eval_type>(v1),
+ static_cast<eval_type>(v2),
+ static_cast<eval_type>(p),
+ static_cast<eval_type>(1-p),
+ static_cast<eval_type>(tools::epsilon<RealType>()),
+ forwarding_policy());
+ return policies::checked_narrowing_cast<RealType, forwarding_policy>(
+ result,
+ function);
+ }
+ template <class A, class B, class C, class D>
+ BOOST_MATH_GPU_ENABLED static RealType find_non_centrality(const complemented4_type<A,B,C, D>& c)
+ {
+ constexpr auto function = "non_central_f_distribution<%1%>::find_non_centrality";
+ typedef typename policies::evaluation<RealType, Policy>::type eval_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+ eval_type result = detail::find_non_centrality_f(
+ static_cast<eval_type>(c.dist),
+ static_cast<eval_type>(c.param1),
+ static_cast<eval_type>(c.param2),
+ static_cast<eval_type>(1-c.param3),
+ static_cast<eval_type>(c.param3),
+ static_cast<eval_type>(tools::epsilon<RealType>()),
+ forwarding_policy());
+ return policies::checked_narrowing_cast<RealType, forwarding_policy>(
+ result,
+ function);
+ }
+ BOOST_MATH_GPU_ENABLED static RealType find_v1(const RealType x, const RealType v2, const RealType nc, const RealType p)
+ {
+ constexpr auto function = "non_central_f_distribution<%1%>::find_v1";
+ typedef typename policies::evaluation<RealType, Policy>::type eval_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+ eval_type result = detail::find_degrees_of_freedom_f(
+ static_cast<eval_type>(x),
+ static_cast<eval_type>(v2),
+ static_cast<eval_type>(nc),
+ true,
+ static_cast<eval_type>(p),
+ static_cast<eval_type>(1-p),
+ forwarding_policy());
+ return policies::checked_narrowing_cast<RealType, forwarding_policy>(
+ result,
+ function);
+ }
+ template <class A, class B, class C, class D>
+ BOOST_MATH_GPU_ENABLED static RealType find_v1(const complemented4_type<A,B,C, D>& c)
+ {
+ constexpr auto function = "non_central_f_distribution<%1%>::find_non_centrality";
+ typedef typename policies::evaluation<RealType, Policy>::type eval_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+ eval_type result = detail::find_degrees_of_freedom_f(
+ static_cast<eval_type>(c.dist),
+ static_cast<eval_type>(c.param1),
+ static_cast<eval_type>(c.param2),
+ true,
+ static_cast<eval_type>(1-c.param3),
+ static_cast<eval_type>(c.param3),
+ forwarding_policy());
+ return policies::checked_narrowing_cast<RealType, forwarding_policy>(
+ result,
+ function);
+ }
+ BOOST_MATH_GPU_ENABLED static RealType find_v2(const RealType x, const RealType v2, const RealType nc, const RealType p)
+ {
+ constexpr auto function = "non_central_f_distribution<%1%>::find_v1";
+ typedef typename policies::evaluation<RealType, Policy>::type eval_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+ eval_type result = detail::find_degrees_of_freedom_f(
+ static_cast<eval_type>(x),
+ static_cast<eval_type>(v2),
+ static_cast<eval_type>(nc),
+ false,
+ static_cast<eval_type>(p),
+ static_cast<eval_type>(1-p),
+ forwarding_policy());
+ return policies::checked_narrowing_cast<RealType, forwarding_policy>(
+ result,
+ function);
+ }
+ template <class A, class B, class C, class D>
+ BOOST_MATH_GPU_ENABLED static RealType find_v2(const complemented4_type<A,B,C, D>& c)
+ {
+ constexpr auto function = "non_central_f_distribution<%1%>::find_non_centrality";
+ typedef typename policies::evaluation<RealType, Policy>::type eval_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+ eval_type result = detail::find_degrees_of_freedom_f(
+ static_cast<eval_type>(c.dist),
+ static_cast<eval_type>(c.param1),
+ static_cast<eval_type>(c.param2),
+ false,
+ static_cast<eval_type>(1-c.param3),
+ static_cast<eval_type>(c.param3),
+ forwarding_policy());
+ return policies::checked_narrowing_cast<RealType, forwarding_policy>(
+ result,
+ function);
+ }
private:
// Data member, initialized by constructor.
RealType v1; // alpha.
@@ -404,7 +698,6 @@ namespace boost
Policy());
return (x / (1 - x)) * (c.dist.degrees_of_freedom2() / c.dist.degrees_of_freedom1());
} // quantile complement.
-
} // namespace math
} // namespace boost
diff --git a/third-party/boost-math/include/boost/math/distributions/non_central_t.hpp b/third-party/boost-math/include/boost/math/distributions/non_central_t.hpp
index a6c988d758a8c..9bc1cf8ccc283 100644
--- a/third-party/boost-math/include/boost/math/distributions/non_central_t.hpp
+++ b/third-party/boost-math/include/boost/math/distributions/non_central_t.hpp
@@ -100,11 +100,15 @@ namespace boost
++count;
}
last_term = 0;
+ T betaf_lim = betaf * tools::epsilon<T>() * 4;
for(auto i = k + 1; ; ++i)
{
poisf *= d2 / (i + 0.5f);
xtermf *= (x * (v / 2 + i - 1)) / (i);
betaf -= xtermf;
+ if (betaf < betaf_lim)
+ break; // Nothing but garbage left in betaf now!!
+
T term = poisf * betaf;
sum += term;
if((fabs(last_term) >= fabs(term)) && (fabs(term/sum) < errtol))
@@ -715,11 +719,6 @@ namespace boost
return result;
}
-#if 0
- //
- // This code is disabled, since there can be multiple answers to the
- // question, and it's not clear how to find the "right" one.
- //
template <class RealType, class Policy>
struct t_degrees_of_freedom_finder
{
@@ -745,13 +744,19 @@ namespace boost
inline RealType find_t_degrees_of_freedom(
RealType delta, RealType x, RealType p, RealType q, const Policy& pol)
{
+ using std::fabs;
const char* function = "non_central_t<%1%>::find_degrees_of_freedom";
if((p == 0) || (q == 0))
{
//
- // Can't a thing if one of p and q is zero:
+ // Can't find a thing if one of p and q is zero:
//
- return policies::raise_evaluation_error<RealType>(function, "Can't find degrees of freedom when the probability is 0 or 1, only possible answer is %1%", // LCOV_EXCL_LINE
+ return policies::raise_evaluation_error<RealType>(function, "Can't find degrees of freedom when the probability is 0 or 1, only possible answer is %1%",
+ RealType(std::numeric_limits<RealType>::quiet_NaN()), Policy()); // LCOV_EXCL_LINE
+ }
+ if (fabs(x) < tools::epsilon<RealType>())
+ {
+ return policies::raise_evaluation_error<RealType>(function, "Can't find degrees of freedom when the abscissa value is very close to zero as all degrees of freedom generate the same CDF at x=0: try again further out in the tails!!",
RealType(std::numeric_limits<RealType>::quiet_NaN()), Policy()); // LCOV_EXCL_LINE
}
t_degrees_of_freedom_finder<RealType, Policy> f(delta, x, p < q ? p : q, p < q ? false : true);
@@ -762,7 +767,7 @@ namespace boost
//
RealType guess = 200;
std::pair<RealType, RealType> ir = tools::bracket_and_solve_root(
- f, guess, RealType(2), false, tol, max_iter, pol);
+ f, guess, RealType(2), x < 0 ? false : true, tol, max_iter, pol);
RealType result = ir.first + (ir.second - ir.first) / 2;
if(max_iter >= policies::get_max_root_iterations<Policy>())
{
@@ -815,9 +820,9 @@ namespace boost
//
RealType guess;
if(f(0) < 0)
- guess = 1;
- else
guess = -1;
+ else
+ guess = 1;
std::pair<RealType, RealType> ir = tools::bracket_and_solve_root(
f, guess, RealType(2), false, tol, max_iter, pol);
RealType result = ir.first + (ir.second - ir.first) / 2;
@@ -828,7 +833,6 @@ namespace boost
}
return result;
}
-#endif
} // namespace detail ======================================================================
template <class RealType = double, class Policy = policies::policy<> >
@@ -860,26 +864,22 @@ namespace boost
{ // Private data getter function.
return ncp;
}
-#if 0
- //
- // This code is disabled, since there can be multiple answers to the
- // question, and it's not clear how to find the "right" one.
- //
+
static RealType find_degrees_of_freedom(RealType delta, RealType x, RealType p)
{
const char* function = "non_central_t<%1%>::find_degrees_of_freedom";
- typedef typename policies::evaluation<RealType, Policy>::type value_type;
+ typedef typename policies::evaluation<RealType, Policy>::type eval_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
- value_type result = detail::find_t_degrees_of_freedom(
- static_cast<value_type>(delta),
- static_cast<value_type>(x),
- static_cast<value_type>(p),
- static_cast<value_type>(1-p),
+ eval_type result = detail::find_t_degrees_of_freedom(
+ static_cast<eval_type>(delta),
+ static_cast<eval_type>(x),
+ static_cast<eval_type>(p),
+ static_cast<eval_type>(1-p),
forwarding_policy());
return policies::checked_narrowing_cast<RealType, forwarding_policy>(
result,
@@ -889,18 +889,18 @@ namespace boost
static RealType find_degrees_of_freedom(const complemented3_type<A,B,C>& c)
{
const char* function = "non_central_t<%1%>::find_degrees_of_freedom";
- typedef typename policies::evaluation<RealType, Policy>::type value_type;
+ typedef typename policies::evaluation<RealType, Policy>::type eval_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
- value_type result = detail::find_t_degrees_of_freedom(
- static_cast<value_type>(c.dist),
- static_cast<value_type>(c.param1),
- static_cast<value_type>(1-c.param2),
- static_cast<value_type>(c.param2),
+ eval_type result = detail::find_t_degrees_of_freedom(
+ static_cast<eval_type>(c.dist),
+ static_cast<eval_type>(c.param1),
+ static_cast<eval_type>(1-c.param2),
+ static_cast<eval_type>(c.param2),
forwarding_policy());
return policies::checked_narrowing_cast<RealType, forwarding_policy>(
result,
@@ -909,18 +909,18 @@ namespace boost
static RealType find_non_centrality(RealType v, RealType x, RealType p)
{
const char* function = "non_central_t<%1%>::find_t_non_centrality";
- typedef typename policies::evaluation<RealType, Policy>::type value_type;
+ typedef typename policies::evaluation<RealType, Policy>::type eval_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
- value_type result = detail::find_t_non_centrality(
- static_cast<value_type>(v),
- static_cast<value_type>(x),
- static_cast<value_type>(p),
- static_cast<value_type>(1-p),
+ eval_type result = detail::find_t_non_centrality(
+ static_cast<eval_type>(v),
+ static_cast<eval_type>(x),
+ static_cast<eval_type>(p),
+ static_cast<eval_type>(1-p),
forwarding_policy());
return policies::checked_narrowing_cast<RealType, forwarding_policy>(
result,
@@ -930,24 +930,23 @@ namespace boost
static RealType find_non_centrality(const complemented3_type<A,B,C>& c)
{
const char* function = "non_central_t<%1%>::find_t_non_centrality";
- typedef typename policies::evaluation<RealType, Policy>::type value_type;
+ typedef typename policies::evaluation<RealType, Policy>::type eval_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
- value_type result = detail::find_t_non_centrality(
- static_cast<value_type>(c.dist),
- static_cast<value_type>(c.param1),
- static_cast<value_type>(1-c.param2),
- static_cast<value_type>(c.param2),
+ eval_type result = detail::find_t_non_centrality(
+ static_cast<eval_type>(c.dist),
+ static_cast<eval_type>(c.param1),
+ static_cast<eval_type>(1-c.param2),
+ static_cast<eval_type>(c.param2),
forwarding_policy());
return policies::checked_narrowing_cast<RealType, forwarding_policy>(
result,
function);
}
-#endif
private:
// Data member, initialized by constructor.
RealType v; // degrees of freedom
diff --git a/third-party/boost-math/include/boost/math/distributions/students_t.hpp b/third-party/boost-math/include/boost/math/distributions/students_t.hpp
index 39f20d6e4109c..859118768efc5 100644
--- a/third-party/boost-math/include/boost/math/distributions/students_t.hpp
+++ b/third-party/boost-math/include/boost/math/distributions/students_t.hpp
@@ -19,9 +19,11 @@
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/special_functions/beta.hpp> // for ibeta(a, b, x).
#include <boost/math/special_functions/digamma.hpp>
+#include <boost/math/special_functions/relative_difference.hpp>
#include <boost/math/distributions/complement.hpp>
#include <boost/math/distributions/detail/common_error_handling.hpp>
-#include <boost/math/distributions/normal.hpp>
+#include <boost/math/distributions/normal.hpp>
+#include <boost/math/distributions/cauchy.hpp>
#include <boost/math/policies/policy.hpp>
#ifdef _MSC_VER
@@ -56,7 +58,11 @@ class students_t_distribution
RealType alpha,
RealType beta,
RealType sd,
- RealType hint = 100);
+ RealType hint = 0);
+
+ BOOST_MATH_GPU_ENABLED static RealType find_degrees_of_freedom(
+ RealType t,
+ RealType p);
private:
// Data member:
@@ -123,6 +129,11 @@ BOOST_MATH_GPU_ENABLED inline RealType pdf(const students_t_distribution<RealTyp
}
else
{ //
+ if (fabs(x) > sqrt(tools::max_value<RealType>()))
+ {
+ // Exact limit: the pdf underflows to zero long before x * x can overflow.
+ return 0;
+ }
RealType basem1 = x * x / df;
if(basem1 < 0.125)
{
@@ -140,6 +151,8 @@ BOOST_MATH_GPU_ENABLED inline RealType pdf(const students_t_distribution<RealTyp
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline RealType cdf(const students_t_distribution<RealType, Policy>& dist, const RealType& x)
{
+ BOOST_MATH_STD_USING // for ADL of std functions
+
RealType error_result;
// degrees_of_freedom > 0 or infinity check:
RealType df = dist.degrees_of_freedom();
@@ -195,6 +208,11 @@ BOOST_MATH_GPU_ENABLED inline RealType cdf(const students_t_distribution<RealTyp
//
// 1 - x = t^2 / (df + t^2)
//
+ if (fabs(x) > sqrt(tools::max_value<RealType>()))
+ {
+ // Exact tail values: avoids a spurious intermediate overflow in x * x below.
+ return (x < 0) ? static_cast<RealType>(0) : static_cast<RealType>(1);
+ }
RealType x2 = x * x;
RealType probability;
if(df > 2 * x2)
@@ -281,6 +299,18 @@ BOOST_MATH_GPU_ENABLED inline RealType quantile(const complemented2_type<student
// Parameter estimation follows:
//
namespace detail{
+
+template <class Distribution, class RealType>
+BOOST_MATH_GPU_ENABLED inline bool analytical_df_if_cdf_matches(const Distribution& dist, RealType x, RealType p)
+{
+ RealType cdf_val = cdf(dist, x);
+ return epsilon_difference(cdf_val, p) < 4;
+}
+
+// Minimum degrees-of-freedom used as the warm-start fallback when the
+// Edgeworth approximation yields no valid positive root or is inaccurate
+constexpr double df_hint_fallback = 0.01;
+
//
// Functors for finding degrees of freedom:
//
@@ -297,8 +327,31 @@ struct sample_size_func
return 1;
}
students_t_distribution<RealType, Policy> t(df);
- RealType qa = quantile(complement(t, alpha));
- RealType qb = quantile(complement(t, beta));
+ RealType qa, qb;
+#ifndef BOOST_MATH_NO_EXCEPTIONS
+ try {
+#endif
+ qa = quantile(complement(t, alpha));
+#ifndef BOOST_MATH_NO_EXCEPTIONS
+ }
+ catch (const std::overflow_error&)
+ {
+ // Any arbitrary large value will do, must be positive since we calculate qa * qa below:
+ return tools::max_value<RealType>();
+ }
+#endif
+#ifndef BOOST_MATH_NO_EXCEPTIONS
+ try {
+#endif
+ qb = quantile(complement(t, beta));
+#ifndef BOOST_MATH_NO_EXCEPTIONS
+ }
+ catch (const std::overflow_error&)
+ {
+ // Any arbitrary large value will do, will be negative if beta < 0:
+ return beta < 0 ? -tools::max_value<RealType>() : tools::max_value<RealType>();
+ }
+#endif
qa += qb;
qa *= qa;
qa *= ratio;
@@ -308,6 +361,117 @@ struct sample_size_func
RealType alpha, beta, ratio;
};
+template <class RealType, class Policy>
+struct cdf_to_df_func
+{
+ BOOST_MATH_GPU_ENABLED cdf_to_df_func(RealType x_val, RealType p_val, bool c)
+ : x(x_val), p(p_val), comp(c) {}
+
+ BOOST_MATH_GPU_ENABLED RealType operator()(const RealType& df)
+ {
+ students_t_distribution<RealType, Policy> t(df);
+ return comp ?
+ RealType(p - cdf(complement(t, x)))
+ : RealType(cdf(t, x) - p);
+ }
+ RealType x, p;
+ bool comp;
+};
+
+//
+// Shared root-finding helper used by find_degrees_of_freedom.
+//
+template <class RealType, class Policy, class Func>
+BOOST_MATH_GPU_ENABLED RealType solve_for_degrees_of_freedom(
+ Func f,
+ RealType hint,
+ bool rising,
+ const char* function,
+ Policy const&)
+{
+ tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
+ boost::math::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
+ boost::math::pair<RealType, RealType> r = tools::bracket_and_solve_root(
+ f, hint, RealType(2), rising, tol, max_iter, Policy());
+ RealType result = r.first + (r.second - r.first) / 2;
+ if (max_iter >= policies::get_max_root_iterations<Policy>())
+ {
+ return policies::raise_evaluation_error<RealType>(function, // LCOV_EXCL_LINE
+ "Unable to locate solution in a reasonable time: either there is no answer to " // LCOV_EXCL_LINE
+ "the degrees of freedom or the answer is infinite. Current best guess is %1%", // LCOV_EXCL_LINE
+ result, Policy()); // LCOV_EXCL_LINE
+ }
+ return result;
+}
+
+//
+// Edgeworth warm-start for find_degrees_of_freedom(t, p).
+// On success writes a df estimate into 'result' and returns true.
+// Returns false when no positive root is found; 'result' is left unchanged.
+//
+template <class RealType, class Policy>
+BOOST_MATH_GPU_ENABLED bool approximate_df_with_edgeworth_expansion(RealType x, RealType p, RealType& result)
+{
+ BOOST_MATH_STD_USING
+ // F(x; nu) ~ cdf_normal(x) - pdf_normal(x)*(x + x^3)/(4*nu) + pdf_normal(x)*(3x + 5x^3 + 7x^5 - 3x^7)/(96*nu^2)
+ // Substituting u = 1/nu and setting F(x; nu) = p gives b*u^2 - a*u + c = 0, where:
+ // a = pdf_normal(x) * (x + x^3) / 4
+ // b = pdf_normal(x) * (3x + 5x^3 + 7x^5 - 3x^7) / 96
+ // c = cdf_normal(x) - p
+ normal_distribution<RealType, Policy> std_normal(0, 1);
+ RealType pdf_val = pdf(std_normal, x);
+ RealType cdf_val = cdf(std_normal, x);
+
+ RealType x2 = x * x;
+ RealType x3 = x2 * x;
+ RealType x5 = x3 * x2;
+ RealType x7 = x5 * x2;
+
+ RealType a = pdf_val * (x + x3) / 4;
+ RealType b = pdf_val * (3 * x + 5 * x3 + 7 * x5 - 3 * x7) / 96;
+ RealType c = cdf_val - p;
+
+ RealType discriminant = a * a - 4 * b * c;
+ if (discriminant >= 0 && b != 0)
+ {
+ RealType sqrt_disc = sqrt(discriminant);
+ // The two roots of b*u^2 - a*u + c = 0. Pick the smallest positive u (= largest df = 1/u).
+ RealType u = (a - sqrt_disc) / (2 * b);
+ if (u <= 0)
+ u = (a + sqrt_disc) / (2 * b);
+ if (u > 0)
+ {
+ result = 1 / u;
+ return true;
+ }
+ }
+ return false;
+}
+
+template <class RealType, class Policy>
+BOOST_MATH_GPU_ENABLED RealType calculate_hill_df_guess(
+ RealType difference_from_mean,
+ RealType alpha,
+ RealType beta,
+ RealType sd)
+
+ // Hill-corrected normal approximation used as an initial guess
+ // for find_degrees_of_freedom(difference_from_mean, alpha, beta, sd).
+ // t_p,nu approx z_p * (1 + (z_p^2 + 1) / (4*nu))
+ // nu + 1 = (sd/diff)^2 * (t_alpha + t_beta)^2
+
+{
+ BOOST_MATH_STD_USING
+ normal_distribution<RealType, Policy> n(0, 1);
+ RealType za = quantile(complement(n, alpha));
+ RealType zb = quantile(complement(n, beta));
+
+ RealType v_norm = pow((za + zb) * sd / difference_from_mean, 2) - 1;
+ RealType hint = v_norm + (za * za - za * zb + zb * zb + 1) / 2;
+
+ return (hint <= 0) ? RealType(1) : hint;
+}
+
} // namespace detail
template <class RealType, class Policy>
@@ -329,19 +493,64 @@ BOOST_MATH_GPU_ENABLED RealType students_t_distribution<RealType, Policy>::find_
return error_result;
if(hint <= 0)
- hint = 1;
+ hint = detail::calculate_hill_df_guess<RealType, Policy>(difference_from_mean, alpha, beta, sd);
detail::sample_size_func<RealType, Policy> f(alpha, beta, sd, difference_from_mean);
- tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
- boost::math::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
- boost::math::pair<RealType, RealType> r = tools::bracket_and_solve_root(f, hint, RealType(2), false, tol, max_iter, Policy());
- RealType result = r.first + (r.second - r.first) / 2;
- if(max_iter >= policies::get_max_root_iterations<Policy>())
+ return detail::solve_for_degrees_of_freedom(f, hint, false, function, Policy());
+}
+
+template <class RealType, class Policy>
+BOOST_MATH_GPU_ENABLED RealType students_t_distribution<RealType, Policy>::find_degrees_of_freedom(
+ RealType t,
+ RealType p)
+{
+ BOOST_MATH_STD_USING // for ADL of std functions
+ constexpr auto function = "boost::math::students_t_distribution<%1%>::find_degrees_of_freedom";
+ //
+ // Check for domain errors:
+ //
+ RealType error_result;
+ if (false == detail::check_probability(function, p, &error_result, Policy()))
+ return error_result;
+
+ if (t == 0)
{
- return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time: either there is no answer to how many degrees of freedom are required" // LCOV_EXCL_LINE
- " or the answer is infinite. Current best guess is %1%", result, Policy()); // LCOV_EXCL_LINE
+ // CDF(0; df) = 0.5 for all df; only solvable when p == 0.5.
+ if (p == static_cast<RealType>(0.5))
+ return policies::raise_overflow_error<RealType>(function, nullptr, Policy());
+ return policies::raise_domain_error<RealType>(
+ function,
+ "No degrees of freedom can satisfy CDF(0; df) == %1% (must be 0.5).",
+ p, Policy());
}
- return result;
+
+ // Analytical cases: df = infinity (normal), df = 1 (cauchy)
+ boost::math::normal_distribution<RealType, Policy> norm(0, 1);
+ if (detail::analytical_df_if_cdf_matches(norm, t, p))
+ return policies::raise_overflow_error<RealType>(function, nullptr, Policy());
+ boost::math::cauchy_distribution<RealType, Policy> cauchy(0, 1);
+ if (detail::analytical_df_if_cdf_matches(cauchy, t, p))
+ return RealType(1);
+
+ // Edgeworth warm start: compute a df estimate; fall back to df_hint_fallback if it fails
+ // or is too inaccurate
+ RealType hint = static_cast<RealType>(detail::df_hint_fallback);
+ if (detail::approximate_df_with_edgeworth_expansion<RealType, Policy>(t, p, hint))
+ {
+ // Check that approximation is at least somewhat close;
+ // for small degrees of freedom it does not fail but is very inaccurate.
+ RealType relative_error_threshold = static_cast<RealType>(0.1);
+ students_t_distribution<RealType, Policy> t_approx(hint);
+ RealType p_approx = cdf(t_approx, t);
+ if (relative_difference(p_approx, p) > relative_error_threshold)
+ hint = static_cast<RealType>(detail::df_hint_fallback);
+ }
+ // Root-find on f(df) = CDF(t; df) - p.
+ // CDF(t; df) is strictly increasing in df for t > 0, decreasing for t < 0.
+ // Use the smaller of p and q=1-p to avoid cancellation near 1.
+ RealType q = 1 - p;
+ detail::cdf_to_df_func<RealType, Policy> f(t, p < q ? p : q, p < q ? false : true);
+ return detail::solve_for_degrees_of_freedom(f, hint, t > 0, function, Policy());
}
template <class RealType, class Policy>
diff --git a/third-party/boost-math/include/boost/math/interpolators/cubic_hermite.hpp b/third-party/boost-math/include/boost/math/interpolators/cubic_hermite.hpp
index 48346ab1ec138..04d1fa787fbec 100644
--- a/third-party/boost-math/include/boost/math/interpolators/cubic_hermite.hpp
+++ b/third-party/boost-math/include/boost/math/interpolators/cubic_hermite.hpp
@@ -8,6 +8,7 @@
#define BOOST_MATH_INTERPOLATORS_CUBIC_HERMITE_HPP
#include <memory>
#include <boost/math/interpolators/detail/cubic_hermite_detail.hpp>
+#include <cstdint>
namespace boost {
namespace math {
@@ -41,7 +42,7 @@ class cubic_hermite {
impl_->push_back(x, y, dydx);
}
- int64_t bytes() const
+ std::int64_t bytes() const
{
return impl_->bytes() + sizeof(impl_);
}
@@ -80,7 +81,7 @@ class cardinal_cubic_hermite {
return os;
}
- int64_t bytes() const
+ std::int64_t bytes() const
{
return impl_->bytes() + sizeof(impl_);
}
@@ -121,7 +122,7 @@ class cardinal_cubic_hermite_aos {
return os;
}
- int64_t bytes() const
+ std::int64_t bytes() const
{
return impl_->bytes() + sizeof(impl_);
}
diff --git a/third-party/boost-math/include/boost/math/interpolators/detail/barycentric_rational_detail.hpp b/third-party/boost-math/include/boost/math/interpolators/detail/barycentric_rational_detail.hpp
index a363e1861bdbf..004bf3f9b5cd7 100644
--- a/third-party/boost-math/include/boost/math/interpolators/detail/barycentric_rational_detail.hpp
+++ b/third-party/boost-math/include/boost/math/interpolators/detail/barycentric_rational_detail.hpp
@@ -12,6 +12,7 @@
#include <utility> // for std::move
#include <algorithm> // for std::is_sorted
#include <string>
+#include <cstdint>
#include <boost/math/special_functions/fpclassify.hpp>
#include <boost/math/tools/assert.hpp>
@@ -100,22 +101,22 @@ template<class Real>
void barycentric_rational_imp<Real>::calculate_weights(size_t approximation_order)
{
using std::abs;
- int64_t n = m_x.size();
+ std::int64_t n = m_x.size();
m_w.resize(n, 0);
- for(int64_t k = 0; k < n; ++k)
+ for(std::int64_t k = 0; k < n; ++k)
{
- int64_t i_min = (std::max)(k - static_cast<int64_t>(approximation_order), static_cast<int64_t>(0));
- int64_t i_max = k;
+ std::int64_t i_min = (std::max)(k - static_cast<std::int64_t>(approximation_order), static_cast<std::int64_t>(0));
+ std::int64_t i_max = k;
if (k >= n - (std::ptrdiff_t)approximation_order)
{
i_max = n - approximation_order - 1;
}
- for(int64_t i = i_min; i <= i_max; ++i)
+ for(std::int64_t i = i_min; i <= i_max; ++i)
{
Real inv_product = 1;
- int64_t j_max = (std::min)(static_cast<int64_t>(i + approximation_order), static_cast<int64_t>(n - 1));
- for(int64_t j = i; j <= j_max; ++j)
+ std::int64_t j_max = (std::min)(static_cast<std::int64_t>(i + approximation_order), static_cast<std::int64_t>(n - 1));
+ for(std::int64_t j = i; j <= j_max; ++j)
{
if (j == k)
{
diff --git a/third-party/boost-math/include/boost/math/interpolators/detail/cardinal_quintic_b_spline_detail.hpp b/third-party/boost-math/include/boost/math/interpolators/detail/cardinal_quintic_b_spline_detail.hpp
index f189e79dd80a8..fcaa33661e047 100644
--- a/third-party/boost-math/include/boost/math/interpolators/detail/cardinal_quintic_b_spline_detail.hpp
+++ b/third-party/boost-math/include/boost/math/interpolators/detail/cardinal_quintic_b_spline_detail.hpp
@@ -7,6 +7,7 @@
#ifndef BOOST_MATH_INTERPOLATORS_CARDINAL_QUINTIC_B_SPLINE_DETAIL_HPP
#define BOOST_MATH_INTERPOLATORS_CARDINAL_QUINTIC_B_SPLINE_DETAIL_HPP
#include <cmath>
+#include <cstdint>
#include <vector>
#include <utility>
#include <boost/math/special_functions/cardinal_b_spline.hpp>
@@ -157,7 +158,7 @@ class cardinal_quintic_b_spline_detail
m_alpha[n+3] = rhs[n+3]/diagonal[n+3];
m_alpha[n+2] = rhs[n+2] - first_superdiagonal[n+2]*m_alpha[n+3];
- for (int64_t i = int64_t(n+1); i >= 0; --i) {
+ for (std::int64_t i = std::int64_t(n+1); i >= 0; --i) {
m_alpha[i] = rhs[i] - first_superdiagonal[i]*m_alpha[i+1] - second_superdiagonal[i]*m_alpha[i+2];
}
@@ -176,10 +177,10 @@ class cardinal_quintic_b_spline_detail
Real x = (t-m_t0)*m_inv_h;
// Support of B_5 is [-3, 3]. So -3 < x - j + 2 < 3, so x-1 < j < x+5.
// TODO: Zero pad m_alpha so that only the domain check is necessary.
- int64_t j_min = (std::max)(int64_t(0), int64_t(ceil(x-1)));
- int64_t j_max = (std::min)(int64_t(m_alpha.size() - 1), int64_t(floor(x+5)) );
+ std::int64_t j_min = (std::max)(std::int64_t(0), std::int64_t(ceil(x-1)));
+ std::int64_t j_max = (std::min)(std::int64_t(m_alpha.size() - 1), std::int64_t(floor(x+5)) );
Real s = 0;
- for (int64_t j = j_min; j <= j_max; ++j) {
+ for (std::int64_t j = j_min; j <= j_max; ++j) {
// TODO: Use Cox 1972 to generate all integer translates of B5 simultaneously.
s += m_alpha[j]*cardinal_b_spline<5, Real>(x - j + 2);
}
@@ -196,10 +197,10 @@ class cardinal_quintic_b_spline_detail
}
Real x = (t-m_t0)*m_inv_h;
// Support of B_5 is [-3, 3]. So -3 < x - j + 2 < 3, so x-1 < j < x+5
- int64_t j_min = (std::max)(int64_t(0), int64_t(ceil(x-1)));
- int64_t j_max = (std::min)(int64_t(m_alpha.size() - 1), int64_t(floor(x+5)) );
+ std::int64_t j_min = (std::max)(std::int64_t(0), std::int64_t(ceil(x-1)));
+ std::int64_t j_max = (std::min)(std::int64_t(m_alpha.size() - 1), std::int64_t(floor(x+5)) );
Real s = 0;
- for (int64_t j = j_min; j <= j_max; ++j) {
+ for (std::int64_t j = j_min; j <= j_max; ++j) {
s += m_alpha[j]*cardinal_b_spline_prime<5, Real>(x - j + 2);
}
return s*m_inv_h;
@@ -216,10 +217,10 @@ class cardinal_quintic_b_spline_detail
}
Real x = (t-m_t0)*m_inv_h;
// Support of B_5 is [-3, 3]. So -3 < x - j + 2 < 3, so x-1 < j < x+5
- int64_t j_min = (std::max)(int64_t(0), int64_t(ceil(x-1)));
- int64_t j_max = (std::min)(int64_t(m_alpha.size() - 1), int64_t(floor(x+5)) );
+ std::int64_t j_min = (std::max)(std::int64_t(0), std::int64_t(ceil(x-1)));
+ std::int64_t j_max = (std::min)(std::int64_t(m_alpha.size() - 1), std::int64_t(floor(x+5)) );
Real s = 0;
- for (int64_t j = j_min; j <= j_max; ++j) {
+ for (std::int64_t j = j_min; j <= j_max; ++j) {
s += m_alpha[j]*cardinal_b_spline_double_prime<5, Real>(x - j + 2);
}
return s*m_inv_h*m_inv_h;
diff --git a/third-party/boost-math/include/boost/math/interpolators/detail/cubic_hermite_detail.hpp b/third-party/boost-math/include/boost/math/interpolators/detail/cubic_hermite_detail.hpp
index 921902e1f2fc6..0e04d37390670 100644
--- a/third-party/boost-math/include/boost/math/interpolators/detail/cubic_hermite_detail.hpp
+++ b/third-party/boost-math/include/boost/math/interpolators/detail/cubic_hermite_detail.hpp
@@ -12,6 +12,7 @@
#include <iostream>
#include <sstream>
#include <limits>
+#include <cstdint>
namespace boost {
namespace math {
@@ -154,7 +155,7 @@ class cubic_hermite_detail {
return x_.size();
}
- int64_t bytes() const
+ std::int64_t bytes() const
{
return 3*x_.size()*sizeof(Real) + 3*sizeof(x_);
}
@@ -278,7 +279,7 @@ class cardinal_cubic_hermite_detail {
return y_.size();
}
- int64_t bytes() const
+ std::int64_t bytes() const
{
return 2*y_.size()*sizeof(Real) + 2*sizeof(y_) + 2*sizeof(Real);
}
@@ -413,7 +414,7 @@ class cardinal_cubic_hermite_detail_aos {
return dat_.size();
}
- int64_t bytes() const
+ std::int64_t bytes() const
{
return dat_.size()*dat_[0].size()*sizeof(Real) + sizeof(dat_) + 2*sizeof(Real);
}
diff --git a/third-party/boost-math/include/boost/math/interpolators/detail/quintic_hermite_detail.hpp b/third-party/boost-math/include/boost/math/interpolators/detail/quintic_hermite_detail.hpp
index 50c1b85ea75c4..ad7eee13a1c0d 100644
--- a/third-party/boost-math/include/boost/math/interpolators/detail/quintic_hermite_detail.hpp
+++ b/third-party/boost-math/include/boost/math/interpolators/detail/quintic_hermite_detail.hpp
@@ -11,6 +11,7 @@
#include <sstream>
#include <limits>
#include <cmath>
+#include <cstdint>
namespace boost {
namespace math {
@@ -193,7 +194,7 @@ class quintic_hermite_detail {
return os;
}
- int64_t bytes() const
+ std::int64_t bytes() const
{
return 4*x_.size()*sizeof(x_);
}
@@ -380,7 +381,7 @@ class cardinal_quintic_hermite_detail {
return d2ydx2;
}
- int64_t bytes() const
+ std::int64_t bytes() const
{
return 3*y_.size()*sizeof(Real) + 2*sizeof(Real);
}
@@ -561,7 +562,7 @@ class cardinal_quintic_hermite_detail_aos {
return d2ydx2;
}
- int64_t bytes() const
+ std::int64_t bytes() const
{
return data_.size()*data_[0].size()*sizeof(Real) + 2*sizeof(Real);
}
diff --git a/third-party/boost-math/include/boost/math/interpolators/detail/septic_hermite_detail.hpp b/third-party/boost-math/include/boost/math/interpolators/detail/septic_hermite_detail.hpp
index 47d155561b229..f4677ce0b6c5e 100644
--- a/third-party/boost-math/include/boost/math/interpolators/detail/septic_hermite_detail.hpp
+++ b/third-party/boost-math/include/boost/math/interpolators/detail/septic_hermite_detail.hpp
@@ -11,6 +11,7 @@
#include <sstream>
#include <limits>
#include <cmath>
+#include <cstdint>
namespace boost {
namespace math {
@@ -189,7 +190,7 @@ class septic_hermite_detail {
return os;
}
- int64_t bytes()
+ std::int64_t bytes()
{
return 5*x_.size()*sizeof(Real) + 5*sizeof(x_);
}
@@ -419,7 +420,7 @@ class cardinal_septic_hermite_detail {
return d2ydx2;
}
- int64_t bytes() const
+ std::int64_t bytes() const
{
return 4*y_.size()*sizeof(Real) + 2*sizeof(Real) + 4*sizeof(y_);
}
@@ -629,7 +630,7 @@ class cardinal_septic_hermite_detail_aos {
return d2ydx2;
}
- int64_t bytes() const
+ std::int64_t bytes() const
{
return data_.size()*data_[0].size()*sizeof(Real) + 2*sizeof(Real) + sizeof(data_);
}
diff --git a/third-party/boost-math/include/boost/math/interpolators/detail/vector_barycentric_rational_detail.hpp b/third-party/boost-math/include/boost/math/interpolators/detail/vector_barycentric_rational_detail.hpp
index f4650784bf931..fdece724c14b1 100644
--- a/third-party/boost-math/include/boost/math/interpolators/detail/vector_barycentric_rational_detail.hpp
+++ b/third-party/boost-math/include/boost/math/interpolators/detail/vector_barycentric_rational_detail.hpp
@@ -8,6 +8,7 @@
#ifndef BOOST_MATH_INTERPOLATORS_VECTOR_BARYCENTRIC_RATIONAL_DETAIL_HPP
#define BOOST_MATH_INTERPOLATORS_VECTOR_BARYCENTRIC_RATIONAL_DETAIL_HPP
+#include <cstdint>
#include <cmath>
#include <vector>
#include <utility> // for std::move
@@ -64,22 +65,22 @@ void vector_barycentric_rational_imp<TimeContainer, SpaceContainer>::calculate_w
{
using Real = typename TimeContainer::value_type;
using std::abs;
- int64_t n = t_.size();
+ std::int64_t n = t_.size();
w_.resize(n, Real(0));
- for(int64_t k = 0; k < n; ++k)
+ for(std::int64_t k = 0; k < n; ++k)
{
- int64_t i_min = (std::max)(k - static_cast<int64_t>(approximation_order), static_cast<int64_t>(0));
- int64_t i_max = k;
+ std::int64_t i_min = (std::max)(k - static_cast<std::int64_t>(approximation_order), static_cast<std::int64_t>(0));
+ std::int64_t i_max = k;
if (k >= n - (std::ptrdiff_t)approximation_order)
{
i_max = n - approximation_order - 1;
}
- for(int64_t i = i_min; i <= i_max; ++i)
+ for(std::int64_t i = i_min; i <= i_max; ++i)
{
Real inv_product = 1;
- int64_t j_max = (std::min)(static_cast<int64_t>(i + approximation_order), static_cast<int64_t>(n - 1));
- for(int64_t j = i; j <= j_max; ++j)
+ std::int64_t j_max = (std::min)(static_cast<std::int64_t>(i + approximation_order), static_cast<std::int64_t>(n - 1));
+ for(std::int64_t j = i; j <= j_max; ++j)
{
if (j == k)
{
diff --git a/third-party/boost-math/include/boost/math/interpolators/pchip.hpp b/third-party/boost-math/include/boost/math/interpolators/pchip.hpp
index 6697166df0caa..a4ad5a35799c8 100644
--- a/third-party/boost-math/include/boost/math/interpolators/pchip.hpp
+++ b/third-party/boost-math/include/boost/math/interpolators/pchip.hpp
@@ -121,6 +121,11 @@ class pchip {
}
}
+ std::pair<Real, Real> domain() const
+ {
+ return impl_->domain();
+ }
+
private:
std::shared_ptr<detail::cubic_hermite_detail<RandomAccessContainer>> impl_;
};
diff --git a/third-party/boost-math/include/boost/math/interpolators/quintic_hermite.hpp b/third-party/boost-math/include/boost/math/interpolators/quintic_hermite.hpp
index c0ba067de2411..1c00b15469e51 100644
--- a/third-party/boost-math/include/boost/math/interpolators/quintic_hermite.hpp
+++ b/third-party/boost-math/include/boost/math/interpolators/quintic_hermite.hpp
@@ -10,6 +10,7 @@
#include <algorithm>
#include <stdexcept>
#include <memory>
+#include <cstdint>
#include <boost/math/interpolators/detail/quintic_hermite_detail.hpp>
namespace boost {
@@ -50,7 +51,7 @@ class quintic_hermite {
impl_->push_back(x, y, dydx, d2ydx2);
}
- int64_t bytes() const
+ std::int64_t bytes() const
{
return impl_->bytes() + sizeof(impl_);
}
@@ -85,7 +86,7 @@ class cardinal_quintic_hermite {
return impl_->double_prime(x);
}
- int64_t bytes() const
+ std::int64_t bytes() const
{
return impl_->bytes() + sizeof(impl_);
}
@@ -123,7 +124,7 @@ class cardinal_quintic_hermite_aos {
return impl_->double_prime(x);
}
- int64_t bytes() const
+ std::int64_t bytes() const
{
return impl_->bytes() + sizeof(impl_);
}
diff --git a/third-party/boost-math/include/boost/math/interpolators/septic_hermite.hpp b/third-party/boost-math/include/boost/math/interpolators/septic_hermite.hpp
index f428a7651ab1c..e8cb8e5493747 100644
--- a/third-party/boost-math/include/boost/math/interpolators/septic_hermite.hpp
+++ b/third-party/boost-math/include/boost/math/interpolators/septic_hermite.hpp
@@ -9,6 +9,7 @@
#include <algorithm>
#include <stdexcept>
#include <memory>
+#include <cstdint>
#include <boost/math/interpolators/detail/septic_hermite_detail.hpp>
namespace boost {
@@ -47,7 +48,7 @@ class septic_hermite
return os;
}
- int64_t bytes() const
+ std::int64_t bytes() const
{
return impl_->bytes() + sizeof(impl_);
}
@@ -87,7 +88,7 @@ class cardinal_septic_hermite
return impl_->double_prime(x);
}
- int64_t bytes() const
+ std::int64_t bytes() const
{
return impl_->bytes() + sizeof(impl_);
}
@@ -126,7 +127,7 @@ class cardinal_septic_hermite_aos {
return impl_->double_prime(x);
}
- int64_t bytes() const
+ std::int64_t bytes() const
{
return impl_.size() + sizeof(impl_);
}
diff --git a/third-party/boost-math/include/boost/math/octonion.hpp b/third-party/boost-math/include/boost/math/octonion.hpp
index 5d147df58403b..4239140564d06 100644
--- a/third-party/boost-math/include/boost/math/octonion.hpp
+++ b/third-party/boost-math/include/boost/math/octonion.hpp
@@ -942,6 +942,10 @@ namespace boost
b /= rhs; \
c /= rhs; \
d /= rhs; \
+ e /= rhs; \
+ f /= rhs; \
+ g /= rhs; \
+ h /= rhs; \
\
return(*this); \
}
diff --git a/third-party/boost-math/include/boost/math/optimization/detail/differentiable_opt_utilties.hpp b/third-party/boost-math/include/boost/math/optimization/detail/differentiable_opt_utilties.hpp
new file mode 100644
index 0000000000000..8fd3c2a0834dc
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/optimization/detail/differentiable_opt_utilties.hpp
@@ -0,0 +1,157 @@
+// Copyright Maksym Zhelyenzyakov 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 BOOST_MATH_OPTIMIZATION_DETAIL_DIFFERENTIABLE_OPT_UTILITIES_HPP
+#define BOOST_MATH_OPTIMIZATION_DETAIL_DIFFERENTIABLE_OPT_UTILITIES_HPP
+#include <boost/math/differentiation/autodiff_reverse.hpp>
+#include <cmath>
+#include <random>
+#include <type_traits>
+#include <vector>
+
+namespace boost {
+namespace math {
+namespace optimization {
+
+namespace rdiff = boost::math::differentiation::reverse_mode;
+
+/** @brief> helper to get the underlying realtype from
+ * update policy
+ * */
+template<typename UpdPol>
+struct update_policy_real_type;
+
+template<template<typename> class UpdPol, typename RealType>
+struct update_policy_real_type<UpdPol<RealType>>
+{
+ using type = RealType;
+};
+
+template<typename UpdPol>
+using update_policy_real_type_t =
+ typename update_policy_real_type<typename std::decay<UpdPol>::type>::type;
+
+/** @brief> get realtype from argument container
+ * */
+template<class Container>
+struct argument_container_t
+{
+ using type = typename argument_container_t<typename std::decay<Container>::type>::type;
+};
+
+template<typename ValueType, std::size_t N>
+struct argument_container_t<std::array<ValueType, N>>
+{
+ using type = ValueType;
+};
+
+template<typename RealType, std::size_t M, std::size_t N>
+struct argument_container_t<std::array<rdiff::rvar<RealType, M>, N>>
+{
+ using type = RealType;
+};
+
+template<template<typename, typename...> class Container, typename ValueType, typename... Args>
+struct argument_container_t<Container<ValueType, Args...>>
+{
+ using type = ValueType;
+};
+
+template<template<typename, typename...> class Container,
+ typename RealType,
+ std::size_t N,
+ typename... Args>
+struct argument_container_t<Container<rdiff::rvar<RealType, N>, Args...>>
+{
+ using type = RealType;
+};
+/******************************************************************************/
+/** @brief simple blas helpers
+ */
+template<typename Container>
+auto
+dot(const Container& x, const Container& y) -> typename Container::value_type
+{
+ using T = typename Container::value_type;
+ BOOST_MATH_ASSERT(x.size() == y.size());
+ return std::inner_product(x.begin(), x.end(), y.begin(), T(0));
+}
+
+template<typename Container>
+auto
+norm_2(const Container& x) -> typename Container::value_type
+{
+ return sqrt(dot(x, x));
+}
+
+template<typename Container>
+auto
+norm_1(const Container& x) -> typename Container::value_type
+{
+ using T = typename Container::value_type;
+ T ret{ 0 };
+ for (auto& xi : x) {
+ ret += abs(xi);
+ }
+ return ret;
+}
+
+template<typename T>
+T
+norm_inf(const std::vector<T>& x)
+{
+ BOOST_ASSERT(!x.empty());
+
+ T max_val = std::abs(x[0]);
+ const std::size_t n = x.size();
+
+ for (std::size_t i = 1; i < n; ++i) {
+ const T abs_val = std::abs(x[i]);
+ if (abs_val > max_val)
+ max_val = abs_val;
+ }
+ return max_val;
+}
+/** @brief alpha*x (alpha is scalar, x is vector */
+template<typename Container, typename RealType>
+void
+scale(Container& x, const RealType& alpha)
+{
+ for (auto& xi : x) {
+ xi *= alpha;
+ }
+}
+
+/** @brief y += alpha * x
+ */
+template<typename ContainerX, typename ContainerY, typename RealType>
+void
+axpy(RealType alpha, const ContainerX& x, ContainerY& y)
+{
+ BOOST_MATH_ASSERT(x.size() == y.size());
+ const size_t n = x.size();
+ for (size_t i = 0; i < n; ++i) {
+ y[i] += alpha * x[i];
+ }
+}
+/******************************************************************************/
+template<typename RealType>
+std::vector<RealType>
+random_vector(size_t n)
+{
+ /** @brief> generates a random std::vector<RealType> of size n
+ * using mt19937 algorithm
+ */
+ static std::mt19937 rng{ std::random_device{}() };
+ static std::uniform_real_distribution<double> dist(0.0, 1.0);
+
+ std::vector<RealType> result(n);
+ std::generate(result.begin(), result.end(), [&] { return static_cast<RealType>(dist(rng)); });
+ return result;
+}
+
+} // namespace optimization
+} // namespace math
+} // namespace boost
+#endif
diff --git a/third-party/boost-math/include/boost/math/optimization/detail/gradient_opt_base.hpp b/third-party/boost-math/include/boost/math/optimization/detail/gradient_opt_base.hpp
new file mode 100644
index 0000000000000..e13b79279d0b0
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/optimization/detail/gradient_opt_base.hpp
@@ -0,0 +1,92 @@
+// Copyright Maksym Zhelyenzyakov 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 BOOST_MATH_OPTIMIZATION_DETAIL_GRADIENT_OPT_BASE_HPP
+#define BOOST_MATH_OPTIMIZATION_DETAIL_GRADIENT_OPT_BASE_HPP
+#include <boost/math/differentiation/autodiff_reverse.hpp>
+
+namespace boost {
+namespace math {
+namespace optimization {
+
+namespace rdiff = boost::math::differentiation::reverse_mode;
+
+/**
+ * @brief The abstract_optimizer class implementing common variables
+ * and methods across optimizers
+ *
+ * @tparam> ArgumentContainer
+ * @tparam> RealType
+ * @tparam> Objective
+ * @tparam> InitializationPolicy
+ *
+ */
+
+template<typename ArgumentContainer,
+ typename RealType,
+ class Objective,
+ class InitializationPolicy,
+ class ObjectiveEvalPolicy,
+ class GradEvalPolicy,
+ class UpdatePolicy,
+ typename DerivedOptimizer>
+class abstract_optimizer
+{
+protected:
+ Objective objective_; // obj function
+ ArgumentContainer& x_; // arguments to objective function
+ std::vector<RealType> g_; // container of references to gradients
+ ObjectiveEvalPolicy obj_eval_; // how to evaluate your funciton
+ GradEvalPolicy grad_eval_; // how to evaluate/bind gradients
+ InitializationPolicy init_; // how to initialize the problem
+ UpdatePolicy update_; // update step
+ RealType obj_v_; // objective value (for history)
+ // access derived class
+ DerivedOptimizer& derived() { return static_cast<DerivedOptimizer&>(*this); }
+ const DerivedOptimizer& derived() const
+ {
+ return static_cast<const DerivedOptimizer&>(*this);
+ }
+
+ void step_impl()
+ {
+ grad_eval_(objective_, x_, obj_eval_, obj_v_, g_);
+ for (size_t i = 0; i < x_.size(); ++i) {
+ update_(x_[i], g_[i]);
+ }
+ };
+
+public:
+ using argument_container_t = ArgumentContainer;
+ using real_type_t = RealType;
+
+ abstract_optimizer(Objective&& objective,
+ ArgumentContainer& x,
+ InitializationPolicy&& ip,
+ ObjectiveEvalPolicy&& oep,
+ GradEvalPolicy&& gep,
+ UpdatePolicy&& up)
+ : objective_(std::forward<Objective>(objective))
+ , x_(x)
+ , obj_eval_(std::forward<ObjectiveEvalPolicy>(oep))
+ , grad_eval_(std::forward<GradEvalPolicy>(gep))
+ , init_(std::forward<InitializationPolicy>(ip))
+ , update_(std::forward<UpdatePolicy>(up))
+ {
+ init_(x_); // initialize your problem
+ g_.resize(x_.size()); // initialize space for gradients
+ }
+
+ ArgumentContainer& arguments() { return derived().x_; }
+ const ArgumentContainer& arguments() const { return derived().x_; }
+
+ RealType& objective_value() { return derived().obj_v_; }
+ const RealType& objective_value() const { return derived().obj_v_; }
+ std::vector<RealType>& gradients() { return derived().g_; }
+ const std::vector<RealType>& gradients() const { return derived().g_; }
+};
+} // namespace optimization
+} // namespace math
+} // namespace boost
+#endif
diff --git a/third-party/boost-math/include/boost/math/optimization/detail/line_search_policies.hpp b/third-party/boost-math/include/boost/math/optimization/detail/line_search_policies.hpp
new file mode 100644
index 0000000000000..1bc3c1cc4df49
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/optimization/detail/line_search_policies.hpp
@@ -0,0 +1,206 @@
+// Copyright Maksym Zhelyenzyakov 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 BOOST_MATH_OPTIMIZATION_DETAIL_LINE_SEARCH_POLICIES_HPP
+#define BOOST_MATH_OPTIMIZATION_DETAIL_LINE_SEARCH_POLICIES_HPP
+
+#include <boost/math/optimization/detail/differentiable_opt_utilties.hpp>
+#include <cmath>
+#include <vector>
+namespace boost {
+namespace math {
+namespace optimization {
+
+/**
+ * @brief> Armijo condition backtracking line search
+ * https://en.wikipedia.org/wiki/Backtracking_line_search
+ *
+ * f(x+alpha p) <= f(x) + alpha * c * grad(f)^T
+ *
+ * Jorge Nocedal and Stephen J. Wright,
+ * Numerical Optimization, 2nd Edition,
+ * Springer, 2006.
+ *
+ * Algorithm 3.1: Backtracking Line Search
+ * (Page 37)
+ */
+template<typename RealType>
+class armijo_line_search_policy
+{
+private:
+ RealType alpha0_; // initial step size
+ RealType c_; // sufficient decrease constant
+ RealType rho_; // backtracking factor
+ int max_iter_; // maximum backtracking steps
+
+public:
+ armijo_line_search_policy(RealType alpha0 = 1.0,
+ RealType c = 1e-4,
+ RealType rho = 0.5,
+ int max_iter = 20)
+ : alpha0_(alpha0)
+ , c_(c)
+ , rho_(rho)
+ , max_iter_(max_iter)
+ {
+ }
+
+ template<class Objective,
+ class ObjectiveEvalPolicy,
+ class GradientEvalPolicy,
+ class ArgumentContainer>
+ RealType operator()(Objective& objective,
+ ObjectiveEvalPolicy& obj_eval,
+ GradientEvalPolicy& grad_eval,
+ ArgumentContainer& x,
+ const std::vector<RealType>& g,
+ const std::vector<RealType>& p,
+ RealType f_x) const
+ {
+ /** @brief> line search
+ * */
+ RealType alpha = alpha0_;
+ ArgumentContainer x_trial; // = x; // copy
+ const RealType gTp = dot(g, p);
+
+ for (int iter = 0; iter < max_iter_; ++iter) {
+ x_trial = x;
+ axpy(alpha, p, x_trial);
+ auto f_trial = obj_eval(objective, x_trial);
+ if (f_trial <=
+ f_x + c_ * alpha * gTp) // check if armijo condition is satisfied
+ return alpha;
+ alpha *= rho_;
+ }
+ return alpha;
+ }
+};
+
+/** @brief> Strong-Wolfe line search:
+ * Jorge Nocedal and Stephen J. Wright,
+ * Numerical Optimization, 2nd Edition,
+ * Springer, 2006.
+ *
+ * Algorithm 3.5 Line Search Algorithm (Strong Wolfe Conditions)
+ * pages 60-61
+ */
+template<typename RealType>
+class strong_wolfe_line_search_policy
+{
+private:
+ RealType alpha0_; // initial step size
+ RealType c1_; // Armijo constant (sufficient decrease)
+ RealType c2_; // curvature constant
+ RealType rho_; // backtracking factor
+ int max_iter_; // maximum iterations
+public:
+ strong_wolfe_line_search_policy(RealType alpha0 = 1.0,
+ RealType c1 = 1e-4,
+ RealType c2 = 0.9,
+ RealType rho = 2.0,
+ int max_iter = 20)
+ : alpha0_(alpha0)
+ , c1_(c1)
+ , c2_(c2)
+ , rho_(rho)
+ , max_iter_(max_iter)
+ {
+ }
+ template<class Objective,
+ class ObjectiveEvalPolicy,
+ class GradientEvalPolicy,
+ class ArgumentContainer>
+ RealType operator()(Objective& objective,
+ ObjectiveEvalPolicy& obj_eval,
+ GradientEvalPolicy& grad_eval,
+ ArgumentContainer& x,
+ const std::vector<RealType>& g,
+ const std::vector<RealType>& p,
+ RealType f_x) const
+ {
+ RealType gTp0 = dot(g, p);
+ RealType alpha_prev{0};
+ RealType f_prev = f_x;
+ RealType alpha = alpha0_;
+
+ ArgumentContainer x_trial;
+ std::vector<RealType> g_trial(g.size());
+ for (int i = 0; i < max_iter_; ++i) {
+ x_trial = x; // explicit copy
+ axpy(alpha, p, x_trial);
+ RealType f_trial = static_cast<RealType>(obj_eval(objective, x_trial));
+ if ((f_trial > f_x + c1_ * alpha * gTp0) ||
+ (i > 0 && f_trial >= f_prev)) {
+ return zoom(
+ objective, obj_eval, grad_eval, x, p, f_x, gTp0, alpha_prev, alpha);
+ }
+ grad_eval(objective, x_trial, obj_eval, f_trial, g_trial);
+ RealType gTp = dot(g_trial, p);
+
+ if (fabs(gTp) <= c2_ * fabs(gTp0)) {
+ return alpha;
+ }
+
+ if (gTp >= 0) {
+ return zoom(
+ objective, obj_eval, grad_eval, x, p, f_x, gTp0, alpha, alpha_prev);
+ }
+ alpha_prev = alpha;
+ f_prev = f_trial;
+ alpha *= rho_;
+ }
+
+ return alpha;
+ }
+
+private:
+ template<class Objective,
+ class ObjectiveEvalPolicy,
+ class GradientEvalPolicy,
+ class ArgumentContainer>
+ RealType zoom(Objective& objective,
+ ObjectiveEvalPolicy& obj_eval,
+ GradientEvalPolicy& grad_eval,
+ ArgumentContainer& x,
+ const std::vector<RealType>& p,
+ RealType f_x,
+ RealType gTp0,
+ RealType alpha_lo,
+ RealType alpha_hi) const
+ {
+ ArgumentContainer x_trial;
+ std::vector<RealType> g_trial(p.size());
+
+ for (int iter = 0; iter < max_iter_; ++iter) {
+ const RealType alpha_mid = 0.5 * (alpha_lo + alpha_hi);
+ x_trial = x;
+ axpy(alpha_mid, p, x_trial);
+ RealType f_mid;
+ grad_eval(objective, x_trial, obj_eval, f_mid, g_trial);
+ RealType gTp_mid = dot(g_trial, p);
+ ArgumentContainer x_lo = x;
+ axpy(alpha_lo, p, x_lo);
+ RealType f_lo = static_cast<RealType>(obj_eval(objective, x_lo));
+ if ((f_mid > f_x + c1_ * alpha_mid * gTp0) || (f_mid >= f_lo)) {
+ alpha_hi = alpha_mid;
+ } else {
+ if (fabs(gTp_mid) <= c2_ * fabs(gTp0)) {
+ return alpha_mid;
+ }
+ if (gTp_mid * (alpha_hi - alpha_lo) >= 0) {
+ alpha_hi = alpha_lo;
+ }
+ alpha_lo = alpha_mid;
+ }
+ }
+
+ return 0.5 * (alpha_lo + alpha_hi);
+ }
+};
+
+} // namespace optimization
+} // namespace math
+} // namespace boost
+#endif // LINE_SEARCH_POLICIES_HPP
diff --git a/third-party/boost-math/include/boost/math/optimization/detail/rdiff_optimization_policies.hpp b/third-party/boost-math/include/boost/math/optimization/detail/rdiff_optimization_policies.hpp
new file mode 100644
index 0000000000000..b4cad4b0041de
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/optimization/detail/rdiff_optimization_policies.hpp
@@ -0,0 +1,134 @@
+// Copyright Maksym Zhelyenzyakov 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 BOOST_MATH_OPTIMIZATION_DETAIL_RDIFF_OPTIMIZATION_POLICIES_HPP
+#define BOOST_MATH_OPTIMIZATION_DETAIL_RDIFF_OPTIMIZATION_POLICIES_HPP
+
+#include <boost/math/differentiation/autodiff_reverse.hpp>
+#include <random>
+#include <type_traits>
+
+namespace boost {
+namespace math {
+namespace optimization {
+
+namespace rdiff = boost::math::differentiation::reverse_mode;
+
+/******************************************************************/
+/**
+ * @brief> function evaluation policy for reverse mode autodiff
+ * @arg objective> objective function to evaluate
+ * @arg x> argument list
+ */
+template<typename RealType>
+struct reverse_mode_function_eval_policy
+{
+ template<typename Objective, class ArgumentContainer>
+ rdiff::rvar<RealType, 1> operator()(Objective&& objective,
+ ArgumentContainer& x)
+ {
+ auto& tape = rdiff::get_active_tape<RealType, 1>();
+ tape.zero_grad();
+ tape.rewind_to_last_checkpoint();
+
+ return objective(x);
+ }
+};
+/******************************************************************/
+
+/**
+ * @brief> gradient evaluation policy
+ * @arg obj_f> objective
+ * @arg x> argument list
+ * @arg f_eval_olicy> funciton evaluation policy. These need to be
+ * done in tandem
+ * @arg obj_v> reference to variable inside gradient class
+ */
+template<typename RealType>
+struct reverse_mode_gradient_evaluation_policy
+{
+ template<class Objective,
+ class ArgumentContainer,
+ class FunctionEvaluationPolicy>
+ void operator()(Objective&& obj_f,
+ ArgumentContainer& x,
+ FunctionEvaluationPolicy&& f_eval_pol,
+ RealType& obj_v,
+ std::vector<RealType>& g)
+ {
+ // compute objective via eval policy that takes care of tape
+ rdiff::rvar<RealType, 1> v = f_eval_pol(obj_f, x);
+ v.backward();
+ obj_v = v.item();
+ g.resize(x.size());
+
+ // copy gradients into gradient vector
+ for (size_t i = 0; i < x.size(); ++i) {
+ g[i] = x[i].adjoint();
+ }
+ }
+};
+/******************************************************************
+ * init policies
+ */
+template<typename RealType>
+struct tape_initializer_rvar
+{
+ template<class ArgumentContainer>
+ void operator()(ArgumentContainer& x) const noexcept
+ {
+ static_assert(std::is_same<typename ArgumentContainer::value_type,
+ rdiff::rvar<RealType, 1>>::value,
+ "ArgumentContainer::value_type must be rdiff::rvar<RealType,1>");
+ auto& tape = rdiff::get_active_tape<RealType, 1>();
+ tape.add_checkpoint();
+ }
+};
+
+template<typename RealType>
+struct random_uniform_initializer_rvar
+{
+ RealType low_, high_;
+ size_t seed_;
+ random_uniform_initializer_rvar(RealType low = 0,
+ RealType high = 1,
+ size_t seed = std::random_device{}())
+ : low_(low)
+ , high_(high)
+ , seed_(seed) {};
+
+ template<class ArgumentContainer>
+ void operator()(ArgumentContainer& x) const
+ {
+ static std::mt19937 gen{ std::random_device{}() };
+ static std::uniform_real_distribution<double> dist(0.0, 1.0);
+ for (auto& xi : x) {
+ xi = rdiff::rvar<RealType, 1>(static_cast<RealType>(dist(gen)));
+ }
+ auto& tape = rdiff::get_active_tape<RealType, 1>();
+ tape.add_checkpoint();
+ }
+};
+
+template<typename RealType>
+struct costant_initializer_rvar
+{
+ RealType constant;
+ explicit costant_initializer_rvar(RealType v = 0)
+ : constant(v) {};
+ template<class ArgumentContainer>
+ void operator()(ArgumentContainer& x) const
+ {
+ for (auto& xi : x) {
+ xi = rdiff::rvar<RealType, 1>(constant);
+ }
+ auto& tape = rdiff::get_active_tape<RealType, 1>();
+ tape.add_checkpoint();
+ }
+};
+} // namespace optimization
+} // namespace math
+} // namespace boost
+
+#endif
diff --git a/third-party/boost-math/include/boost/math/optimization/gradient_descent.hpp b/third-party/boost-math/include/boost/math/optimization/gradient_descent.hpp
new file mode 100644
index 0000000000000..68972e2968ae2
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/optimization/gradient_descent.hpp
@@ -0,0 +1,202 @@
+// Copyright Maksym Zhelyenzyakov 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 BOOST_MATH_OPTIMIZATION_GRADIENT_DESCENT_HPP
+#define BOOST_MATH_OPTIMIZATION_GRADIENT_DESCENT_HPP
+#include <boost/math/optimization/detail/differentiable_opt_utilties.hpp>
+#include <boost/math/optimization/detail/gradient_opt_base.hpp>
+#include <boost/math/optimization/detail/rdiff_optimization_policies.hpp>
+
+namespace boost {
+namespace math {
+namespace optimization {
+
+template<typename RealType>
+struct gradient_descent_update_policy
+{
+ RealType lr_;
+ gradient_descent_update_policy(RealType lr)
+ : lr_(lr) {};
+
+ template<typename ArgumentType,
+ typename = typename std::enable_if<
+ boost::math::differentiation::reverse_mode::detail::is_expression<
+ ArgumentType>::value>::type>
+ void operator()(ArgumentType& x, RealType& g)
+ {
+ x.get_value() -= lr_ * g;
+ }
+ template<typename ArgumentType,
+ typename std::enable_if<!boost::math::differentiation::reverse_mode::
+ detail::is_expression<ArgumentType>::value,
+ int>::type = 0>
+ void operator()(ArgumentType& x, RealType& g) const
+ {
+ x -= lr_ * g;
+ }
+};
+
+/**
+ * @brief> Gradient Descent Optimizer.
+ *
+ * This class implements a gradient descent optimization strategy using the
+ * policies provided for initialization, objective evaluation, and gradient
+ * computation. It inherits from `abstract_optimizer`, which provides the
+ * general optimization framework.
+ *
+ * @tparam> ArgumentContainer Type of the parameter container (e.g.
+ * std::vector<SomeDifferentiableType or RealType>).
+ * @tparam> RealType Floating-point type
+ * @tparam> Objective Objective function type (functor or callable).
+ * @tparam> InitializationPolicy Policy controlling initialization of
+ * differentiable variables.
+ * @tparam> ObjectiveEvalPolicy Policy defining how the objective is evaluated.
+ * @tparam> GradEvalPolicy Policy defining how the gradient is computed.
+ */
+
+template<typename ArgumentContainer,
+ typename RealType,
+ class Objective,
+ class InitializationPolicy,
+ class ObjectiveEvalPolicy,
+ class GradEvalPolicy>
+class gradient_descent
+ : public abstract_optimizer<ArgumentContainer,
+ RealType,
+ Objective,
+ InitializationPolicy,
+ ObjectiveEvalPolicy,
+ GradEvalPolicy,
+ gradient_descent_update_policy<RealType>,
+ gradient_descent<ArgumentContainer,
+ RealType,
+ Objective,
+ InitializationPolicy,
+ ObjectiveEvalPolicy,
+ GradEvalPolicy>>
+{
+ using base_opt = abstract_optimizer<ArgumentContainer,
+ RealType,
+ Objective,
+ InitializationPolicy,
+ ObjectiveEvalPolicy,
+ GradEvalPolicy,
+ gradient_descent_update_policy<RealType>,
+ gradient_descent<ArgumentContainer,
+ RealType,
+ Objective,
+ InitializationPolicy,
+ ObjectiveEvalPolicy,
+ GradEvalPolicy>>;
+
+public:
+ using base_opt::base_opt;
+ /**
+ * @brief Perform one optimization step.
+ *
+ * defaults to a regular update inside abstract optimizer
+ * x -= lr * grad(f)
+ */
+ void step() { this->step_impl(); }
+};
+
+/**
+ * @brief Create a gradient descent optimizer with default reverse-mode autodiff
+ policies.
+ *
+ * make_gradient_descent(objective, x)
+ * constructs gradient descent with objective function, and parameters x
+ *
+ * learning rate set to 0.01 by default
+ *
+ * initialization strategy : use specified, gradient tape taken care of by
+ * optimizer
+ * function eval policy : rvar function eval policy, to be used with
+ * boost::math::differentiation::reverse_mode::rvar
+ *
+ * gradient eval policy : rvar gradient evaluation policy
+ *
+ * gradient descent update policy :
+ * basically x -= lr * grad(f);
+ *
+ * make_gradient_descent(objective, x, lr)
+ * custom learning rate
+*/
+
+template<class Objective, typename ArgumentContainer, typename RealType>
+auto
+make_gradient_descent(Objective&& obj,
+ ArgumentContainer& x,
+ RealType lr = RealType{ 0.01 })
+{
+ return gradient_descent<ArgumentContainer,
+ RealType,
+ std::decay_t<Objective>,
+ tape_initializer_rvar<RealType>,
+ reverse_mode_function_eval_policy<RealType>,
+ reverse_mode_gradient_evaluation_policy<RealType>>(
+ std::forward<Objective>(obj),
+ x,
+ tape_initializer_rvar<RealType>{},
+ reverse_mode_function_eval_policy<RealType>{},
+ reverse_mode_gradient_evaluation_policy<RealType>{},
+ gradient_descent_update_policy<RealType>(lr));
+}
+
+template<class Objective,
+ typename ArgumentContainer,
+ typename RealType,
+ class InitializationPolicy>
+auto
+make_gradient_descent(Objective&& obj,
+ ArgumentContainer& x,
+ RealType lr,
+ InitializationPolicy&& ip)
+{
+ return gradient_descent<ArgumentContainer,
+ RealType,
+ std::decay_t<Objective>,
+ InitializationPolicy,
+ reverse_mode_function_eval_policy<RealType>,
+ reverse_mode_gradient_evaluation_policy<RealType>>(
+ std::forward<Objective>(obj),
+ x,
+ std::forward<InitializationPolicy>(ip),
+ reverse_mode_function_eval_policy<RealType>{},
+ reverse_mode_gradient_evaluation_policy<RealType>{},
+ gradient_descent_update_policy<RealType>(lr));
+}
+
+template<typename ArgumentContainer,
+ typename RealType,
+ class Objective,
+ class InitializationPolicy,
+ class ObjectiveEvalPolicy,
+ class GradEvalPolicy>
+auto
+make_gradient_descent(Objective&& obj,
+ ArgumentContainer& x,
+ RealType& lr,
+ InitializationPolicy&& ip,
+ ObjectiveEvalPolicy&& oep,
+ GradEvalPolicy&& gep)
+{
+ return gradient_descent<ArgumentContainer,
+ RealType,
+ std::decay_t<Objective>,
+ InitializationPolicy,
+ ObjectiveEvalPolicy,
+ GradEvalPolicy>(
+ std::forward<Objective>(obj),
+ x,
+ std::forward<InitializationPolicy>(ip),
+ std::forward<ObjectiveEvalPolicy>(oep),
+ std::forward<GradEvalPolicy>(gep),
+ gradient_descent_update_policy<RealType>{ lr });
+}
+
+} // namespace optimization
+} // namespace math
+} // namespace boost
+#endif
diff --git a/third-party/boost-math/include/boost/math/optimization/gradient_optimizers.hpp b/third-party/boost-math/include/boost/math/optimization/gradient_optimizers.hpp
new file mode 100644
index 0000000000000..f9e6a8de420a5
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/optimization/gradient_optimizers.hpp
@@ -0,0 +1,18 @@
+// Copyright Maksym Zhelyenzyakov 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 BOOST_MATH_OPTIMIZATION_GRADIENT_OPTIMIZERS_HPP
+#define BOOST_MATH_OPTIMIZATION_GRADIENT_OPTIMIZERS_HPP
+#include <boost/math/differentiation/autodiff_reverse.hpp>
+#include <boost/math/optimization/gradient_descent.hpp>
+#include <boost/math/optimization/lbfgs.hpp>
+#include <boost/math/optimization/nesterov.hpp>
+
+namespace boost {
+namespace math {
+namespace optimization {
+} // namespace optimization
+} // namespace math
+} // namespace boost
+#endif
diff --git a/third-party/boost-math/include/boost/math/optimization/jso.hpp b/third-party/boost-math/include/boost/math/optimization/jso.hpp
index e792298285142..44359a00dc2fc 100644
--- a/third-party/boost-math/include/boost/math/optimization/jso.hpp
+++ b/third-party/boost-math/include/boost/math/optimization/jso.hpp
@@ -389,7 +389,7 @@ jso(const Func cost_function, jso_parameters<ArgumentContainer> &jso_params,
throw std::logic_error(oss.str());
}
for (size_t i = 0; i < weights.size(); ++i) {
- weights[i] = delta_f[i] / delta_sum;
+ weights[i] = static_cast<DimensionlessReal>(delta_f[i] / delta_sum);
}
M_CR[k] = detail::weighted_lehmer_mean(S_CR, weights);
diff --git a/third-party/boost-math/include/boost/math/optimization/lbfgs.hpp b/third-party/boost-math/include/boost/math/optimization/lbfgs.hpp
new file mode 100644
index 0000000000000..5554b7721d667
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/optimization/lbfgs.hpp
@@ -0,0 +1,382 @@
+// Copyright Maksym Zhelyenzyakov 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 BOOST_MATH_OPTIMIZATION_LBFGS_HPP
+#define BOOST_MATH_OPTIMIZATION_LBFGS_HPP
+#include <boost/math/optimization/detail/differentiable_opt_utilties.hpp>
+#include <boost/math/optimization/detail/gradient_opt_base.hpp>
+#include <boost/math/optimization/detail/rdiff_optimization_policies.hpp>
+#include <vector>
+
+#include <boost/math/optimization/detail/line_search_policies.hpp>
+#include <deque>
+
+namespace boost {
+namespace math {
+namespace optimization {
+
+/** @brief> Helper struct for L-BFGS
+ *
+ * stores state of L-BFGS optimizer
+ * @param> m = 10 -> history (how far back to look)
+ * @param> S - > x_k - x_{k-1} ( m states )
+ * @param> Y - > g_k - g_{k-1} (m states)
+ * @param> rho - > 1/(y^T y)
+ * @param> g_prev, x_prev - > previous state of argument and gradient
+ * @param -> f_prev - > previous function value
+ *
+ * https://en.wikipedia.org/wiki/Limited-memory_BFGS
+ *
+ * Jorge Nocedal and Stephen J. Wright,
+ * Numerical Optimization, 2nd Edition,
+ * Springer, 2006.
+ *
+ * pages 176-180
+ * algorithms 7.4/7.5
+ * */
+template<typename RealType>
+struct lbfgs_optimizer_state
+{
+ size_t m = 10; // default history length
+ std::deque<std::vector<RealType>> S, Y;
+ std::deque<RealType> rho;
+ std::vector<RealType> g_prev, x_prev;
+ RealType f_prev = std::numeric_limits<RealType>::quiet_NaN();
+ const RealType EPS = std::numeric_limits<RealType>::epsilon();
+
+ template<typename ArgumentContainer>
+ void update_state(ArgumentContainer& x,
+ std::vector<RealType>& g_k,
+ RealType fk)
+ {
+
+ // iteration 0
+ if (g_prev.empty()) {
+ g_prev.assign(g_k.begin(), g_k.end());
+ x_prev.resize(x.size());
+ std::transform(x.begin(), x.end(), x_prev.begin(), [](const auto& xi) {
+ return static_cast<RealType>(xi);
+ });
+ f_prev = fk;
+ return;
+ }
+
+ std::vector<RealType> s_k(x.size()), y_k(g_k.size());
+ for (size_t i = 0; i < x.size(); ++i) {
+ s_k[i] = static_cast<RealType>(x[i]) - x_prev[i];
+ y_k[i] = g_k[i] - g_prev[i];
+ }
+
+ RealType ys = dot(y_k, s_k);
+ RealType sn = sqrt(dot(s_k, s_k));
+ RealType yn = sqrt(dot(y_k, y_k));
+
+ const RealType threshold = EPS * sn * yn;
+ if (ys > threshold && ys > RealType(0)) { // check if curvature if non-zero
+ if (S.size() == m) { // iteration > m
+ S.pop_front();
+ Y.pop_front();
+ rho.pop_front();
+ }
+ S.push_back(std::move(s_k));
+ Y.push_back(std::move(y_k));
+ rho.push_back(RealType(1) / ys);
+ }
+
+ g_prev.assign(g_k.begin(), g_k.end());
+ // safely cast to realtype
+ std::transform(x.begin(), x.end(), x_prev.begin(), [](const auto& xi) {
+ return static_cast<RealType>(xi);
+ });
+ f_prev = fk;
+ }
+};
+
+/** @brief> helper update for l-bfgs
+ * x += alpha * search direction
+ * */
+template<typename RealType>
+struct lbfgs_update_policy
+{
+ template<typename ArgumentType,
+ typename = typename std::enable_if<
+ boost::math::differentiation::reverse_mode::detail::is_expression<
+ ArgumentType>::value>::type>
+ void operator()(ArgumentType& x, RealType pk, RealType alpha)
+ {
+ x.get_value() += alpha * pk;
+ }
+ template<typename ArgumentType,
+ typename std::enable_if<!boost::math::differentiation::reverse_mode::
+ detail::is_expression<ArgumentType>::value,
+ int>::type = 0>
+ void operator()(ArgumentType& x, RealType pk, RealType alpha)
+ {
+ x += alpha * pk;
+ }
+};
+
+/**
+ *
+ * @brief Limited-memory BFGS (L-BFGS) optimizer
+ *
+ * The `lbfgs` class implements the Limited-memory BFGS optimization algorithm,
+ * a quasi-Newton method that approximates the inverse Hessian using a rolling
+ * window of the last `m` updates. It is suitable for medium- to large-scale
+ * optimization problems where full Hessian storage is infeasible.
+ *
+ * @tparam> ArgumentContainer: container type for parameters, e.g.
+ * std::vector<RealType>
+ * @tparam> RealType scalar floating type (e.g. double, float)
+ * @tparam> Objective: objective function. must support "f(x)" evaluation
+ * @tparam> InitializationPolicy: policy for initializing x
+ * @tparam> ObjectiveEvalPolicy: policy for computing the objective value
+ * @tparam> GradEvalPolicy: policy for computing gradients
+ * @tparam> LineaSearchPolicy: e.g. Armijo, StrongWolfe
+ *
+ * https://en.wikipedia.org/wiki/Limited-memory_BFGS
+ */
+
+template<typename ArgumentContainer,
+ typename RealType,
+ class Objective,
+ class InitializationPolicy,
+ class ObjectiveEvalPolicy,
+ class GradEvalPolicy,
+ class LineSearchPolicy>
+class lbfgs
+ : public abstract_optimizer<ArgumentContainer,
+ RealType,
+ Objective,
+ InitializationPolicy,
+ ObjectiveEvalPolicy,
+ GradEvalPolicy,
+ lbfgs_update_policy<RealType>,
+ lbfgs<ArgumentContainer,
+ RealType,
+ Objective,
+ InitializationPolicy,
+ ObjectiveEvalPolicy,
+ GradEvalPolicy,
+ LineSearchPolicy>>
+{
+ using base_opt = abstract_optimizer<ArgumentContainer,
+ RealType,
+ Objective,
+ InitializationPolicy,
+ ObjectiveEvalPolicy,
+ GradEvalPolicy,
+ lbfgs_update_policy<RealType>,
+ lbfgs<ArgumentContainer,
+ RealType,
+ Objective,
+ InitializationPolicy,
+ ObjectiveEvalPolicy,
+ GradEvalPolicy,
+ LineSearchPolicy>>;
+
+ const RealType EPS = std::numeric_limits<RealType>::epsilon();
+ lbfgs_optimizer_state<RealType> state_;
+ LineSearchPolicy line_search_;
+
+ std::vector<RealType> compute_direction(const std::vector<RealType>& gk)
+ {
+ const size_t n = gk.size();
+ const size_t L = state_.S.size(); // since S changes when iter < m
+
+ if (L == 0) {
+ std::vector<RealType> p(n);
+ std::transform(
+ gk.begin(), gk.end(), p.begin(), [](RealType gi) { return -gi; });
+ return p;
+ }
+
+ std::vector<RealType> q = gk;
+ std::vector<RealType> alpha(L, RealType(0));
+ for (size_t t = 0; t < L; ++t) {
+ const std::size_t i = L - 1 - t; // newest first
+ const RealType sTq = dot(state_.S[i], q);
+ alpha[i] = state_.rho[i] * sTq;
+ axpy(-alpha[i], state_.Y[i], q);
+ }
+
+ const RealType sTy = dot(state_.S.back(), state_.Y.back());
+ const RealType yTy = dot(state_.Y.back(), state_.Y.back());
+ const RealType gamma = (yTy > RealType(0)) ? (sTy / yTy) : RealType(1);
+
+ std::vector<RealType> r = q;
+ scale(r, gamma);
+
+ for (std::size_t i = 0; i < L; ++i) {
+ const RealType yTr = dot(state_.Y[i], r);
+ const RealType beta = state_.rho[i] * yTr;
+ axpy(alpha[i] - beta, state_.S[i], r);
+ }
+ scale(r, RealType{ -1 });
+ return r;
+ }
+
+public:
+ using base_opt::base_opt;
+ lbfgs(Objective&& objective,
+ ArgumentContainer& x,
+ size_t m,
+ InitializationPolicy&& ip,
+ ObjectiveEvalPolicy&& oep,
+ GradEvalPolicy&& gep,
+ lbfgs_update_policy<RealType>&& up,
+ LineSearchPolicy&& lsp)
+ : base_opt(std::forward<Objective>(objective),
+ x,
+ std::forward<InitializationPolicy>(ip),
+ std::forward<ObjectiveEvalPolicy>(oep),
+ std::forward<GradEvalPolicy>(gep),
+ std::forward<lbfgs_update_policy<RealType>>(up))
+ , line_search_(lsp)
+ {
+ state_.m = m;
+
+ state_.S.clear();
+ state_.Y.clear();
+ state_.rho.clear();
+ state_.g_prev.clear();
+ state_.f_prev = std::numeric_limits<RealType>::quiet_NaN();
+ }
+
+ void step()
+ {
+ auto& x = this->arguments();
+ auto& g = this->gradients();
+ auto& obj = this->objective_value();
+ auto& obj_eval = this->obj_eval_;
+ auto& grad_eval = this->grad_eval_;
+ auto& objective = this->objective_;
+ auto& update = this->update_;
+
+ grad_eval(objective, x, obj_eval, obj, g);
+ state_.update_state(x, g, obj);
+ std::vector<RealType> p = compute_direction(g);
+ RealType alpha = line_search_(objective, obj_eval, grad_eval, x, g, p, obj);
+ for (size_t i = 0; i < x.size(); ++i) {
+ update(x[i], p[i], alpha);
+ }
+ }
+};
+
+template<class Objective, typename ArgumentContainer>
+auto
+make_lbfgs(Objective&& obj, ArgumentContainer& x, std::size_t m = 10)
+{
+ using RealType = typename argument_container_t<ArgumentContainer>::type;
+ return lbfgs<ArgumentContainer,
+ RealType,
+ std::decay_t<Objective>,
+ tape_initializer_rvar<RealType>,
+ reverse_mode_function_eval_policy<RealType>,
+ reverse_mode_gradient_evaluation_policy<RealType>,
+ strong_wolfe_line_search_policy<RealType>>(
+ std::forward<Objective>(obj),
+ x,
+ m,
+ tape_initializer_rvar<RealType>{},
+ reverse_mode_function_eval_policy<RealType>{},
+ reverse_mode_gradient_evaluation_policy<RealType>{},
+ lbfgs_update_policy<RealType>{},
+ strong_wolfe_line_search_policy<RealType>{});
+}
+
+template<class Objective,
+ typename ArgumentContainer,
+ class InitializationPolicy>
+auto
+make_lbfgs(Objective&& obj,
+ ArgumentContainer& x,
+ std::size_t m,
+ InitializationPolicy&& ip)
+{
+ using RealType = typename argument_container_t<ArgumentContainer>::type;
+
+ return lbfgs<ArgumentContainer,
+ RealType,
+ std::decay_t<Objective>,
+ InitializationPolicy,
+ reverse_mode_function_eval_policy<RealType>,
+ reverse_mode_gradient_evaluation_policy<RealType>,
+ strong_wolfe_line_search_policy<RealType>>(
+ std::forward<Objective>(obj),
+ x,
+ m,
+ std::forward<InitializationPolicy>(ip),
+ reverse_mode_function_eval_policy<RealType>{},
+ reverse_mode_gradient_evaluation_policy<RealType>{},
+ lbfgs_update_policy<RealType>{},
+ strong_wolfe_line_search_policy<RealType>{});
+}
+
+template<class Objective,
+ typename ArgumentContainer,
+ class InitializationPolicy,
+ class LineSearchPolicy>
+auto
+make_lbfgs(Objective&& obj,
+ ArgumentContainer& x,
+ std::size_t m,
+ InitializationPolicy&& ip,
+ LineSearchPolicy&& lsp)
+{
+ using RealType = typename argument_container_t<ArgumentContainer>::type;
+
+ return lbfgs<ArgumentContainer,
+ RealType,
+ std::decay_t<Objective>,
+ InitializationPolicy,
+ reverse_mode_function_eval_policy<RealType>,
+ reverse_mode_gradient_evaluation_policy<RealType>,
+ LineSearchPolicy>(
+ std::forward<Objective>(obj),
+ x,
+ m,
+ std::forward<InitializationPolicy>(ip),
+ reverse_mode_function_eval_policy<RealType>{},
+ reverse_mode_gradient_evaluation_policy<RealType>{},
+ lbfgs_update_policy<RealType>{},
+ std::forward<LineSearchPolicy>(lsp));
+}
+
+template<class Objective,
+ typename ArgumentContainer,
+ class InitializationPolicy,
+ class FunctionEvalPolicy,
+ class GradientEvalPolicy,
+ class LineSearchPolicy>
+auto
+make_lbfgs(Objective&& obj,
+ ArgumentContainer& x,
+ std::size_t m,
+ InitializationPolicy&& ip,
+ FunctionEvalPolicy&& fep,
+ GradientEvalPolicy&& gep,
+ LineSearchPolicy&& lsp)
+{
+ using RealType = typename argument_container_t<ArgumentContainer>::type;
+ return lbfgs<ArgumentContainer,
+ RealType,
+ std::decay_t<Objective>,
+ InitializationPolicy,
+ FunctionEvalPolicy,
+ GradientEvalPolicy,
+ LineSearchPolicy>(std::forward<Objective>(obj),
+ x,
+ m,
+ std::forward<InitializationPolicy>(ip),
+ std::forward<FunctionEvalPolicy>(fep),
+ std::forward<GradientEvalPolicy>(gep),
+ lbfgs_update_policy<RealType>{},
+ std::forward<LineSearchPolicy>(lsp));
+}
+
+} // namespace optimization
+} // namespace math
+} // namespace boost
+#endif
diff --git a/third-party/boost-math/include/boost/math/optimization/minimizer.hpp b/third-party/boost-math/include/boost/math/optimization/minimizer.hpp
new file mode 100644
index 0000000000000..929c92b2f46c9
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/optimization/minimizer.hpp
@@ -0,0 +1,336 @@
+// Copyright Maksym Zhelyenzyakov 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 BOOST_MATH_OPTIMIZATION_MINIMIZER_HPP
+#define BOOST_MATH_OPTIMIZATION_MINIMIZER_HPP
+#include <boost/math/optimization/detail/differentiable_opt_utilties.hpp>
+#include <boost/math/optimization/gradient_optimizers.hpp>
+#include <vector>
+#include <chrono>
+namespace boost {
+namespace math {
+namespace optimization {
+template<typename RealType>
+struct optimization_result
+{
+ size_t num_iter = 0;
+ RealType objective_value;
+ std::vector<RealType> objective_history;
+ bool converged;
+};
+
+template<typename RealType>
+std::ostream&
+operator<<(std::ostream& os, const optimization_result<RealType>& r)
+{
+ os << "optimization_result {\n"
+ << " num_iter = " << r.num_iter << "\n"
+ << " objective_value = " << r.objective_value << "\n"
+ << " converged = " << std::boolalpha << r.converged << "\n"
+ << " objective_history = [";
+
+ for (std::size_t i = 0; i < r.objective_history.size(); ++i) {
+ os << r.objective_history[i];
+ if (i + 1 < r.objective_history.size()) {
+ os << ", ";
+ }
+ }
+ os << "]\n}\n";
+ return os;
+}
+/*****************************************************************************************/
+template<typename RealType>
+struct gradient_norm_convergence_policy
+{
+ RealType tol_;
+ explicit gradient_norm_convergence_policy(RealType tol)
+ : tol_(tol)
+ {
+ }
+
+ template<class GradientContainer>
+ bool operator()(const GradientContainer& g, RealType /*objective_v*/) const
+ {
+ return norm_2(g) < tol_;
+ }
+};
+
+template<typename RealType>
+struct objective_tol_convergence_policy
+{
+ RealType tol_;
+ mutable RealType last_value_;
+ mutable bool first_call_;
+
+ explicit objective_tol_convergence_policy(RealType tol)
+ : tol_(tol)
+ , last_value_(0)
+ , first_call_(true)
+ {
+ }
+
+ template<class GradientContainer>
+ bool operator()(const GradientContainer&, RealType objective_v) const
+ {
+ if (first_call_) {
+ last_value_ = objective_v;
+ first_call_ = false;
+ return false;
+ }
+ RealType diff = abs(objective_v - last_value_);
+ last_value_ = objective_v;
+ return diff < tol_;
+ }
+};
+
+template<typename RealType>
+struct relative_objective_tol_policy
+{
+ RealType rel_tol_;
+ mutable RealType last_value_;
+ mutable bool first_call_;
+
+ explicit relative_objective_tol_policy(RealType rel_tol)
+ : rel_tol_(rel_tol)
+ , last_value_(0)
+ , first_call_(true)
+ {
+ }
+
+ template<class GradientContainer>
+ bool operator()(const GradientContainer&, RealType objective_v) const
+ {
+ if (first_call_) {
+ last_value_ = objective_v;
+ first_call_ = false;
+ return false;
+ }
+ RealType denom = max<RealType>(1, abs(last_value_));
+ RealType rel_diff = abs(objective_v - last_value_) / denom;
+ last_value_ = objective_v;
+ return rel_diff < rel_tol_;
+ }
+};
+
+template<class Policy1, class Policy2>
+struct combined_convergence_policy
+{
+ Policy1 p1_;
+ Policy2 p2_;
+
+ combined_convergence_policy(Policy1 p1, Policy2 p2)
+ : p1_(p1)
+ , p2_(p2)
+ {
+ }
+
+ template<class GradientContainer, class RealType>
+ bool operator()(const GradientContainer& g, RealType obj) const
+ {
+ return p1_(g, obj) || p2_(g, obj);
+ }
+};
+
+/*****************************************************************************************/
+struct max_iter_termination_policy
+{
+ size_t max_iter_;
+ max_iter_termination_policy(size_t max_iter)
+ : max_iter_(max_iter) {};
+ bool operator()(size_t iter)
+ {
+ if (iter < max_iter_) {
+ return false;
+ }
+ return true;
+ }
+};
+
+struct wallclock_termination_policy
+{
+ std::chrono::steady_clock::time_point start_;
+ std::chrono::milliseconds max_time_;
+
+ explicit wallclock_termination_policy(std::chrono::milliseconds max_time)
+ : start_(std::chrono::steady_clock::now())
+ , max_time_(max_time)
+ {
+ }
+
+ bool operator()(size_t /*iter*/) const
+ {
+ return std::chrono::steady_clock::now() - start_ > max_time_;
+ }
+};
+
+/*****************************************************************************************/
+template<typename ArgumentContainer>
+struct unconstrained_policy
+{
+ void operator()(ArgumentContainer&) {}
+};
+
+template<typename ArgumentContainer, typename RealType>
+struct box_constraints
+{
+ RealType min_, max_;
+ box_constraints(RealType min, RealType max)
+ : min_(min)
+ , max_(max) {};
+ void operator()(ArgumentContainer& x)
+ {
+ for (auto& xi : x) {
+ xi = (xi < min_) ? min_ : (max_ < xi) ? max_ : xi;
+ }
+ }
+};
+
+template<typename ArgumentContainer, typename RealType>
+struct nonnegativity_constraint
+{
+ void operator()(ArgumentContainer& x) const
+ {
+ for (auto& xi : x) {
+ if (xi < RealType{ 0 })
+ xi = RealType{ 0 };
+ }
+ }
+};
+template<typename ArgumentContainer, typename RealType>
+struct l2_ball_constraint
+{
+ RealType radius_;
+
+ explicit l2_ball_constraint(RealType radius)
+ : radius_(radius)
+ {
+ }
+
+ void operator()(ArgumentContainer& x) const
+ {
+ RealType norm2v = norm_2(x);
+ if (norm2v > radius_) {
+ RealType scale = radius_ / norm2v;
+ for (auto& xi : x)
+ xi *= scale;
+ }
+ }
+};
+
+template<typename ArgumentContainer, typename RealType>
+struct l1_ball_constraint
+{
+ RealType radius_;
+
+ explicit l1_ball_constraint(RealType radius)
+ : radius_(radius)
+ {
+ }
+
+ void operator()(ArgumentContainer& x) const
+ {
+ RealType norm1v = norm_1(x);
+
+ if (norm1v > radius_) {
+ RealType scale = radius_ / norm1v;
+ for (auto& xi : x)
+ xi *= scale;
+ }
+ }
+};
+template<typename ArgumentContainer, typename RealType>
+struct simplex_constraint
+{
+ void operator()(ArgumentContainer& x) const
+ {
+ RealType sum = RealType{ 0 };
+ for (auto& xi : x) {
+ if (xi < RealType{ 0 })
+ xi = RealType{ 0 }; // clip negatives
+ sum += xi;
+ }
+ if (sum > RealType{ 0 }) {
+ for (auto& xi : x)
+ xi /= sum;
+ }
+ }
+};
+
+template<typename ArgumentContainer>
+struct function_constraint
+{
+ using func_t = void (*)(ArgumentContainer&);
+
+ func_t f_;
+
+ explicit function_constraint(func_t f)
+ : f_(f)
+ {
+ }
+
+ void operator()(ArgumentContainer& x) const { f_(x); }
+};
+template<typename ArgumentContainer, typename RealType>
+struct unit_sphere_constraint
+{
+ void operator()(ArgumentContainer& x) const
+ {
+ RealType norm = norm_2(x);
+ if (norm > RealType{ 0 }) {
+ for (auto& xi : x)
+ xi /= norm;
+ }
+ }
+};
+/*****************************************************************************************/
+
+template<class Optimizer,
+ class ConstraintPolicy,
+ class ConvergencePolicy,
+ class TerminationPolicy>
+auto
+minimize_impl(Optimizer& opt,
+ ConstraintPolicy project,
+ ConvergencePolicy converged,
+ TerminationPolicy terminate,
+ bool history)
+{
+ optimization_result<typename Optimizer::real_type_t> result;
+ size_t iter = 0;
+ do {
+ opt.step();
+ project(opt.arguments());
+ ++iter;
+ if (history) {
+ result.objective_history.push_back(opt.objective_value());
+ }
+
+ } while (!converged(opt.gradients(), opt.objective_value()) &&
+ !terminate(iter));
+ result.num_iter = iter;
+ result.objective_value = opt.objective_value();
+ result.converged = converged(opt.gradients(), opt.objective_value());
+ return result;
+}
+template<class Optimizer,
+ class ConstraintPolicy =
+ unconstrained_policy<typename Optimizer::argument_container_t>,
+ class ConvergencePolicy =
+ gradient_norm_convergence_policy<typename Optimizer::real_type_t>,
+ class TerminationPolicy = max_iter_termination_policy>
+auto
+minimize(Optimizer& opt,
+ ConstraintPolicy project = ConstraintPolicy{},
+ ConvergencePolicy converged =
+ ConvergencePolicy{
+ static_cast<typename Optimizer::real_type_t>(1e-3) },
+ TerminationPolicy terminate = TerminationPolicy(100000),
+ bool history = true)
+{
+ return minimize_impl(opt, project, converged, terminate, history);
+}
+} // namespace optimization
+} // namespace math
+} // namespace boost
+#endif
diff --git a/third-party/boost-math/include/boost/math/optimization/nesterov.hpp b/third-party/boost-math/include/boost/math/optimization/nesterov.hpp
new file mode 100644
index 0000000000000..1c882f4019c2e
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/optimization/nesterov.hpp
@@ -0,0 +1,208 @@
+// Copyright Maksym Zhelyenzyakov 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 BOOST_MATH_OPTIMIZATION_NESTEROV_HPP
+#define BOOST_MATH_OPTIMIZATION_NESTEROV_HPP
+#include <boost/math/optimization/detail/differentiable_opt_utilties.hpp>
+#include <boost/math/optimization/detail/gradient_opt_base.hpp>
+#include <boost/math/optimization/detail/rdiff_optimization_policies.hpp>
+#include <vector>
+
+namespace boost {
+namespace math {
+namespace optimization {
+
+namespace rdiff = boost::math::differentiation::reverse_mode;
+
+/**
+ * @brief The nesterov_update_policy class
+ */
+template<typename RealType>
+struct nesterov_update_policy
+{
+ RealType lr_, mu_;
+ nesterov_update_policy(RealType lr, RealType mu)
+ : lr_(lr)
+ , mu_(mu) {};
+
+ template<typename ArgumentType,
+ typename = typename std::enable_if<
+ boost::math::differentiation::reverse_mode::detail::is_expression<
+ ArgumentType>::value>::type>
+ void operator()(ArgumentType& x, RealType& g, RealType& v)
+ {
+ RealType v_prev = v;
+ v = mu_ * v - lr_ * g;
+ x.get_value() += -mu_ * v_prev + (static_cast<RealType>(1) + mu_) * v;
+ }
+ template<typename ArgumentType,
+ typename std::enable_if<!boost::math::differentiation::reverse_mode::
+ detail::is_expression<ArgumentType>::value,
+ int>::type = 0>
+ void operator()(ArgumentType& x, RealType& g, RealType& v) const
+ {
+ const RealType v_prev = v;
+ v = mu_ * v - lr_ * g;
+ x += -mu_ * v_prev + (static_cast<RealType>(1) + mu_) * v;
+ }
+ RealType lr() const noexcept { return lr_; }
+ RealType mu() const noexcept { return mu_; }
+};
+
+/**
+ * @brief The nesterov_accelerated_gradient class
+ *
+ * https://jlmelville.github.io/mize/nesterov.html
+ */
+template<typename ArgumentContainer,
+ typename RealType,
+ class Objective,
+ class InitializationPolicy,
+ class ObjectiveEvalPolicy,
+ class GradEvalPolicy>
+class nesterov_accelerated_gradient
+ : public abstract_optimizer<
+ ArgumentContainer,
+ RealType,
+ Objective,
+ InitializationPolicy,
+ ObjectiveEvalPolicy,
+ GradEvalPolicy,
+ nesterov_update_policy<RealType>,
+ nesterov_accelerated_gradient<ArgumentContainer,
+ RealType,
+ Objective,
+ InitializationPolicy,
+ ObjectiveEvalPolicy,
+ GradEvalPolicy>>
+{
+ using base_opt =
+ abstract_optimizer<ArgumentContainer,
+ RealType,
+ Objective,
+ InitializationPolicy,
+ ObjectiveEvalPolicy,
+ GradEvalPolicy,
+ nesterov_update_policy<RealType>,
+ nesterov_accelerated_gradient<ArgumentContainer,
+ RealType,
+ Objective,
+ InitializationPolicy,
+ ObjectiveEvalPolicy,
+ GradEvalPolicy>>;
+ std::vector<RealType> v_;
+
+public:
+ using base_opt::base_opt;
+ nesterov_accelerated_gradient(Objective&& objective,
+ ArgumentContainer& x,
+ InitializationPolicy&& ip,
+ ObjectiveEvalPolicy&& oep,
+ GradEvalPolicy&& gep,
+ nesterov_update_policy<RealType>&& up)
+ : base_opt(std::forward<Objective>(objective),
+ x,
+ std::forward<InitializationPolicy>(ip),
+ std::forward<ObjectiveEvalPolicy>(oep),
+ std::forward<GradEvalPolicy>(gep),
+ std::forward<nesterov_update_policy<RealType>>(up))
+ , v_(x.size(), RealType(0))
+ {
+ }
+
+ void step()
+ {
+ auto& x = this->arguments();
+ auto& g = this->gradients();
+ auto& obj = this->objective_value();
+ auto& obj_eval = this->obj_eval_;
+ auto& grad_eval = this->grad_eval_;
+ auto& objective = this->objective_;
+ auto& update = this->update_;
+
+ grad_eval(objective, x, obj_eval, obj, g);
+
+ for (size_t i = 0; i < x.size(); ++i) {
+ update(x[i], g[i], v_[i]);
+ }
+ }
+};
+template<class Objective, typename ArgumentContainer, typename RealType>
+auto
+make_nag(Objective&& obj,
+ ArgumentContainer& x,
+ RealType lr = RealType{ 0.01 },
+ RealType mu = RealType{ 0.95 })
+{
+ return nesterov_accelerated_gradient<
+ ArgumentContainer,
+ RealType,
+ std::decay_t<Objective>,
+ tape_initializer_rvar<RealType>,
+ reverse_mode_function_eval_policy<RealType>,
+ reverse_mode_gradient_evaluation_policy<RealType>>(
+ std::forward<Objective>(obj),
+ x,
+ tape_initializer_rvar<RealType>{},
+ reverse_mode_function_eval_policy<RealType>{},
+ reverse_mode_gradient_evaluation_policy<RealType>{},
+ nesterov_update_policy<RealType>(lr, mu));
+}
+template<class Objective,
+ typename ArgumentContainer,
+ typename RealType,
+ class InitializationPolicy>
+auto
+make_nag(Objective&& obj,
+ ArgumentContainer& x,
+ RealType lr,
+ RealType mu,
+ InitializationPolicy&& ip)
+{
+ return nesterov_accelerated_gradient<
+ ArgumentContainer,
+ RealType,
+ std::decay_t<Objective>,
+ InitializationPolicy,
+ reverse_mode_function_eval_policy<RealType>,
+ reverse_mode_gradient_evaluation_policy<RealType>>(
+ std::forward<Objective>(obj),
+ x,
+ std::forward<InitializationPolicy>(ip),
+ reverse_mode_function_eval_policy<RealType>{},
+ reverse_mode_gradient_evaluation_policy<RealType>{},
+ nesterov_update_policy<RealType>(lr, mu));
+}
+template<typename ArgumentContainer,
+ typename RealType,
+ class Objective,
+ class InitializationPolicy,
+ class ObjectiveEvalPolicy,
+ class GradEvalPolicy>
+auto
+make_nag(Objective&& obj,
+ ArgumentContainer& x,
+ RealType lr,
+ RealType mu,
+ InitializationPolicy&& ip,
+ ObjectiveEvalPolicy&& oep,
+ GradEvalPolicy&& gep)
+{
+ return nesterov_accelerated_gradient<ArgumentContainer,
+ RealType,
+ std::decay_t<Objective>,
+ InitializationPolicy,
+ ObjectiveEvalPolicy,
+ GradEvalPolicy>(
+ std::forward<Objective>(obj),
+ x,
+ std::forward<InitializationPolicy>(ip),
+ std::forward<ObjectiveEvalPolicy>(oep),
+ std::forward<GradEvalPolicy>(gep),
+ nesterov_update_policy<RealType>{ lr, mu });
+}
+} // namespace optimization
+} // namespace math
+} // namespace boost
+#endif
diff --git a/third-party/boost-math/include/boost/math/policies/error_handling.hpp b/third-party/boost-math/include/boost/math/policies/error_handling.hpp
index d7ba694564ba4..adcb56f3e528d 100644
--- a/third-party/boost-math/include/boost/math/policies/error_handling.hpp
+++ b/third-party/boost-math/include/boost/math/policies/error_handling.hpp
@@ -26,9 +26,9 @@
#include <complex>
#include <cstdint>
#include <cstring>
+#ifndef BOOST_MATH_NO_EXCEPTIONS
#include <iomanip>
#include <sstream>
-#ifndef BOOST_MATH_NO_EXCEPTIONS
#include <stdexcept>
#endif
#include <string>
@@ -95,6 +95,8 @@ T user_indeterminate_result_error(const char* function, const char* message, con
namespace detail
{
+#ifndef BOOST_MATH_NO_EXCEPTIONS
+// Only used to build exception messages; relies on <sstream>
template <class T>
inline std::string prec_format(const T& val)
{
@@ -124,7 +126,9 @@ inline std::string prec_format<std::float128_t>(const std::float128_t& val)
return std::string(buffer, r.ptr);
}
-#endif
+#endif // BOOST_MATH_USE_CHARCONV_FOR_CONVERSION
+
+#endif // BOOST_MATH_NO_EXCEPTIONS
inline void replace_all_in_string(std::string& result, const char* what, const char* with)
{
diff --git a/third-party/boost-math/include/boost/math/policies/policy.hpp b/third-party/boost-math/include/boost/math/policies/policy.hpp
index bec8886408161..6d80b2b292a7c 100644
--- a/third-party/boost-math/include/boost/math/policies/policy.hpp
+++ b/third-party/boost-math/include/boost/math/policies/policy.hpp
@@ -766,6 +766,9 @@ struct evaluation<double, Policy>
using type = typename boost::math::conditional<Policy::promote_double_type::value, long double, double>::type;
};
+template <class Real, class Policy>
+using evaluation_t = typename evaluation<Real, Policy>::type;
+
template <class Real, class Policy>
struct precision
{
@@ -942,7 +945,7 @@ template <typename P>
class is_policy_imp
{
public:
- static constexpr bool value = (sizeof(::boost::math::policies::detail::test_is_policy(static_cast<P*>(nullptr))) == sizeof(char));
+ static constexpr bool value = (sizeof(detail::test_is_policy(static_cast<boost::math::remove_reference_t<boost::math::remove_cv_t<P>>*>(nullptr))) == sizeof(char));
};
}
@@ -955,6 +958,9 @@ class is_policy
using type = boost::math::integral_constant<bool, value>;
};
+template <typename T>
+BOOST_MATH_INLINE_CONSTEXPR bool is_policy_v = is_policy<T>::value;
+
//
// Helper traits class for distribution error handling:
//
@@ -1003,6 +1009,25 @@ struct is_noexcept_error_policy
&& (t8::value != throw_on_error) && (t8::value != user_error));
};
+// Generate a forwarding policy to stop further promotion from occurring
+// For example if a special function for float promotes to double, we don't want the next
+// function in the call chain to then promote to long double
+template <typename Policy>
+struct make_forwarding_policy
+{
+ using type =
+ typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<>
+ >::type;
+};
+
+template <typename Policy>
+using make_forwarding_policy_t = typename make_forwarding_policy<Policy>::type;
+
}}} // namespaces
#endif // BOOST_MATH_POLICY_HPP
diff --git a/third-party/boost-math/include/boost/math/quadrature/detail/ooura_fourier_integrals_detail.hpp b/third-party/boost-math/include/boost/math/quadrature/detail/ooura_fourier_integrals_detail.hpp
index 49677a8d2912d..c677852da443b 100644
--- a/third-party/boost-math/include/boost/math/quadrature/detail/ooura_fourier_integrals_detail.hpp
+++ b/third-party/boost-math/include/boost/math/quadrature/detail/ooura_fourier_integrals_detail.hpp
@@ -195,11 +195,15 @@ class ooura_fourier_sin_detail {
lweights_.reserve(levels);
for (size_t i = 0; i < levels; ++i) {
- if (std::is_same<Real, float>::value) {
+ BOOST_MATH_IF_CONSTEXPR (std::is_same<Real, float>::value) {
add_level<double>(i);
}
- else if (std::is_same<Real, double>::value) {
+ else BOOST_MATH_IF_CONSTEXPR (std::is_same<Real, double>::value) {
+#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
add_level<long double>(i);
+#else
+ add_level<double>(i);
+#endif
}
else {
add_level<Real>(i);
@@ -266,11 +270,15 @@ class ooura_fourier_sin_detail {
size_t max_additional_levels = 4;
while (big_nodes_.size() < requested_levels_ + max_additional_levels) {
size_t ii = big_nodes_.size();
- if (std::is_same<Real, float>::value) {
+ BOOST_MATH_IF_CONSTEXPR (std::is_same<Real, float>::value) {
add_level<double>(ii);
}
- else if (std::is_same<Real, double>::value) {
+ else BOOST_MATH_IF_CONSTEXPR (std::is_same<Real, double>::value) {
+#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
add_level<long double>(ii);
+#else
+ add_level<double>(ii);
+#endif
}
else {
add_level<Real>(ii);
@@ -464,11 +472,15 @@ class ooura_fourier_cos_detail {
lweights_.reserve(levels);
for (size_t i = 0; i < levels; ++i) {
- if (std::is_same<Real, float>::value) {
+ BOOST_MATH_IF_CONSTEXPR (std::is_same<Real, float>::value) {
add_level<double>(i);
}
- else if (std::is_same<Real, double>::value) {
+ else BOOST_MATH_IF_CONSTEXPR (std::is_same<Real, double>::value) {
+#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
add_level<long double>(i);
+#else
+ add_level<double>(i);
+#endif
}
else {
add_level<Real>(i);
@@ -512,11 +524,15 @@ class ooura_fourier_cos_detail {
size_t max_additional_levels = 4;
while (big_nodes_.size() < requested_levels_ + max_additional_levels) {
size_t ii = big_nodes_.size();
- if (std::is_same<Real, float>::value) {
+ BOOST_MATH_IF_CONSTEXPR (std::is_same<Real, float>::value) {
add_level<double>(ii);
}
- else if (std::is_same<Real, double>::value) {
+ else BOOST_MATH_IF_CONSTEXPR (std::is_same<Real, double>::value) {
+#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
add_level<long double>(ii);
+#else
+ add_level<double>(ii);
+#endif
}
else {
add_level<Real>(ii);
diff --git a/third-party/boost-math/include/boost/math/quadrature/naive_monte_carlo.hpp b/third-party/boost-math/include/boost/math/quadrature/naive_monte_carlo.hpp
index 4ad95ad832370..954612c268f51 100644
--- a/third-party/boost-math/include/boost/math/quadrature/naive_monte_carlo.hpp
+++ b/third-party/boost-math/include/boost/math/quadrature/naive_monte_carlo.hpp
@@ -20,6 +20,7 @@
#include <chrono>
#include <map>
#include <type_traits>
+#include <cstdint>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
@@ -45,20 +46,20 @@ class naive_monte_carlo
std::vector<std::pair<Real, Real>> const & bounds,
Real error_goal,
bool singular = true,
- uint64_t threads = std::thread::hardware_concurrency(),
- uint64_t seed = 0) noexcept : m_num_threads{threads}, m_seed{seed}, m_volume(1)
+ std::uint64_t threads = std::thread::hardware_concurrency(),
+ std::uint64_t seed = 0) noexcept : m_num_threads{threads}, m_seed{seed}, m_volume(1)
{
using std::numeric_limits;
using std::sqrt;
using boost::math::isinf;
- uint64_t n = bounds.size();
+ std::uint64_t n = bounds.size();
m_lbs.resize(n);
m_dxs.resize(n);
m_limit_types.resize(n);
static const char* function = "boost::math::quadrature::naive_monte_carlo<%1%>";
- for (uint64_t i = 0; i < n; ++i)
+ for (std::uint64_t i = 0; i < n; ++i)
{
if (bounds[i].second <= bounds[i].first)
{
@@ -122,7 +123,7 @@ class naive_monte_carlo
m_integrand = [this, &integrand](std::vector<Real> & x)->Real
{
Real coeff = m_volume;
- for (uint64_t i = 0; i < x.size(); ++i)
+ for (std::uint64_t i = 0; i < x.size(); ++i)
{
// Variable transformation are listed at:
// https://en.wikipedia.org/wiki/Numerical_integration
@@ -170,15 +171,15 @@ class naive_monte_carlo
RandomNumberGenerator gen(seed);
Real inv_denom = 1/static_cast<Real>(((gen.max)()-(gen.min)()));
- m_num_threads = (std::max)(m_num_threads, static_cast<uint64_t>(1));
- m_thread_calls.reset(new std::atomic<uint64_t>[threads]);
+ m_num_threads = (std::max)(m_num_threads, static_cast<std::uint64_t>(1));
+ m_thread_calls.reset(new std::atomic<std::uint64_t>[threads]);
m_thread_Ss.reset(new std::atomic<Real>[threads]);
m_thread_averages.reset(new std::atomic<Real>[threads]);
Real avg = 0;
- for (uint64_t i = 0; i < m_num_threads; ++i)
+ for (std::uint64_t i = 0; i < m_num_threads; ++i)
{
- for (uint64_t j = 0; j < m_lbs.size(); ++j)
+ for (std::uint64_t j = 0; j < m_lbs.size(); ++j)
{
x[j] = (gen()-(gen.min)())*inv_denom;
}
@@ -263,7 +264,7 @@ class naive_monte_carlo
return m_avg.load();
}
- uint64_t calls() const
+ std::uint64_t calls() const
{
return m_total_calls.load(); // relaxed load
}
@@ -272,7 +273,7 @@ class naive_monte_carlo
Real m_integrate()
{
- uint64_t seed;
+ std::uint64_t seed;
// If the user tells us to pick a seed, pick a seed:
if (m_seed == 0)
{
@@ -307,23 +308,23 @@ class naive_monte_carlo
}
std::vector<std::thread> threads(m_num_threads);
- for (uint64_t i = 0; i < threads.size(); ++i)
+ for (std::uint64_t i = 0; i < threads.size(); ++i)
{
threads[i] = std::thread(&naive_monte_carlo::m_thread_monte, this, i, gen());
}
do {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
- uint64_t total_calls = 0;
- for (uint64_t i = 0; i < m_num_threads; ++i)
+ std::uint64_t total_calls = 0;
+ for (std::uint64_t i = 0; i < m_num_threads; ++i)
{
- uint64_t t_calls = m_thread_calls[i].load(std::memory_order_consume);
+ std::uint64_t t_calls = m_thread_calls[i].load(std::memory_order_consume);
total_calls += t_calls;
}
Real variance = 0;
Real avg = 0;
- for (uint64_t i = 0; i < m_num_threads; ++i)
+ for (std::uint64_t i = 0; i < m_num_threads; ++i)
{
- uint64_t t_calls = m_thread_calls[i].load(std::memory_order_consume);
+ std::uint64_t t_calls = m_thread_calls[i].load(std::memory_order_consume);
// Will this overflow? Not hard to remove . . .
avg += m_thread_averages[i].load(std::memory_order_relaxed)*(static_cast<Real>(t_calls) / static_cast<Real>(total_calls));
variance += m_thread_Ss[i].load(std::memory_order_relaxed);
@@ -346,18 +347,18 @@ class naive_monte_carlo
std::rethrow_exception(m_exception);
}
// Incorporate their work into the final estimate:
- uint64_t total_calls = 0;
- for (uint64_t i = 0; i < m_num_threads; ++i)
+ std::uint64_t total_calls = 0;
+ for (std::uint64_t i = 0; i < m_num_threads; ++i)
{
- uint64_t t_calls = m_thread_calls[i].load(std::memory_order_consume);
+ std::uint64_t t_calls = m_thread_calls[i].load(std::memory_order_consume);
total_calls += t_calls;
}
Real variance = 0;
Real avg = 0;
- for (uint64_t i = 0; i < m_num_threads; ++i)
+ for (std::uint64_t i = 0; i < m_num_threads; ++i)
{
- uint64_t t_calls = m_thread_calls[i].load(std::memory_order_consume);
+ std::uint64_t t_calls = m_thread_calls[i].load(std::memory_order_consume);
// Averages weighted by the number of calls the thread made:
avg += m_thread_averages[i].load(std::memory_order_relaxed)*(static_cast<Real>(t_calls) / static_cast<Real>(total_calls));
variance += m_thread_Ss[i].load(std::memory_order_relaxed);
@@ -375,7 +376,7 @@ class naive_monte_carlo
return m_avg.load(std::memory_order_consume);
}
- void m_thread_monte(uint64_t thread_index, uint64_t seed)
+ void m_thread_monte(std::uint64_t thread_index, std::uint64_t seed)
{
using std::numeric_limits;
try
@@ -390,7 +391,7 @@ class naive_monte_carlo
// The idea is that the unstabilized additions have error sigma(f)/sqrt(N) + epsilon*N, which diverges faster than it converges!
// Kahan summation turns this to sigma(f)/sqrt(N) + epsilon^2*N, and the random walk occurs on a timescale of 10^14 years (on current hardware)
Real compensator = 0;
- uint64_t k = m_thread_calls[thread_index].load(std::memory_order_consume);
+ std::uint64_t k = m_thread_calls[thread_index].load(std::memory_order_consume);
while (!m_done) // relaxed load
{
int j = 0;
@@ -401,7 +402,7 @@ class naive_monte_carlo
int magic_calls_before_update = 2048;
while (j++ < magic_calls_before_update)
{
- for (uint64_t i = 0; i < m_lbs.size(); ++i)
+ for (std::uint64_t i = 0; i < m_lbs.size(); ++i)
{
x[i] = (gen() - (gen.min)())*inv_denom;
}
@@ -412,7 +413,7 @@ class naive_monte_carlo
// The call to m_integrand transform x, so this error message states the correct node.
std::stringstream os;
os << "Your integrand was evaluated at {";
- for (uint64_t i = 0; i < x.size() -1; ++i)
+ for (std::uint64_t i = 0; i < x.size() -1; ++i)
{
os << x[i] << ", ";
}
@@ -443,18 +444,18 @@ class naive_monte_carlo
}
std::function<Real(std::vector<Real> &)> m_integrand;
- uint64_t m_num_threads;
- std::atomic<uint64_t> m_seed;
+ std::uint64_t m_num_threads;
+ std::atomic<std::uint64_t> m_seed;
std::atomic<Real> m_error_goal;
std::atomic<bool> m_done{};
std::vector<Real> m_lbs;
std::vector<Real> m_dxs;
std::vector<detail::limit_classification> m_limit_types;
Real m_volume;
- std::atomic<uint64_t> m_total_calls{};
+ std::atomic<std::uint64_t> m_total_calls{};
// I wanted these to be vectors rather than maps,
// but you can't resize a vector of atomics.
- std::unique_ptr<std::atomic<uint64_t>[]> m_thread_calls;
+ std::unique_ptr<std::atomic<std::uint64_t>[]> m_thread_calls;
std::atomic<Real> m_variance;
std::unique_ptr<std::atomic<Real>[]> m_thread_Ss;
std::atomic<Real> m_avg;
diff --git a/third-party/boost-math/include/boost/math/special_functions/beta.hpp b/third-party/boost-math/include/boost/math/special_functions/beta.hpp
index f6327fa220f80..5c3a762ca05da 100644
--- a/third-party/boost-math/include/boost/math/special_functions/beta.hpp
+++ b/third-party/boost-math/include/boost/math/special_functions/beta.hpp
@@ -19,7 +19,6 @@
#include <boost/math/tools/cstdint.hpp>
#include <boost/math/tools/tuple.hpp>
#include <boost/math/tools/promotion.hpp>
-#include <boost/math/tools/cstdint.hpp>
#include <boost/math/special_functions/gamma.hpp>
#include <boost/math/special_functions/erf.hpp>
#include <boost/math/special_functions/log1p.hpp>
@@ -475,7 +474,6 @@ BOOST_MATH_GPU_ENABLED T ibeta_power_terms(T a,
const char* = "boost::math::ibeta<%1%>(%1%, %1%, %1%)")
{
BOOST_MATH_STD_USING
-
if(!normalised)
{
return prefix * pow(x, a) * pow(y, b);
@@ -1142,7 +1140,20 @@ BOOST_MATH_GPU_ENABLED T ibeta_large_ab(T a, T b, T x, T y, bool invert, bool no
T x0 = a / (a + b);
T y0 = b / (a + b);
- T nu = x0 * log(x / x0) + y0 * log(y / y0);
+
+ // Expand nu about x0
+ T nu = 0;
+ for (int i=2; i<5; i++)
+ {
+ nu += pow(x-x0, i) / i * (pow(x0, -(i-1)) - pow(x0-1, -(i-1))) * pow(-1, i+1);
+ }
+ // Calculate the next term in the series
+ T remainder = pow(x-x0, 5) / 5 * (pow(x0, -4) - pow(x0-1, 4));
+
+ // If the remainder is large, then fall back to using the log formula
+ if (remainder >= tools::forth_root_epsilon<T>()){
+ nu = x0 * log(x / x0) + y0 * log(y / y0);
+ }
//
// Above compution is unstable, force nu to zero if
// something went wrong:
@@ -1181,7 +1192,7 @@ BOOST_MATH_GPU_ENABLED T ibeta_large_ab(T a, T b, T x, T y, bool invert, bool no
T mul = 1;
if (!normalised)
mul = boost::math::beta(a, b, pol);
-
+ // T log_erf_remainder = -0.5 * log(2 * constants::pi<T>() * (a+b)) + a * log(x / x0) + b * log((1-x) / (1-x0)) + log(abs(1/nu - sqrt(x0 * (1-x0)) / (x-x0)));
return mul * ((invert ? (1 + boost::math::erf(-nu * sqrt((a + b) / 2), pol)) / 2 : boost::math::erfc(-nu * sqrt((a + b) / 2), pol) / 2));
}
@@ -1571,37 +1582,47 @@ BOOST_MATH_GPU_ENABLED T ibeta_imp(T a, T b, T x, const Policy& pol, bool inv, b
else
{
// a and b both large:
- bool use_asym = false;
T ma = BOOST_MATH_GPU_SAFE_MAX(a, b);
- T xa = ma == a ? x : y;
T saddle = ma / (a + b);
- T powers = 0;
- if ((ma > 1e-5f / tools::epsilon<T>()) && (ma / BOOST_MATH_GPU_SAFE_MIN(a, b) < (xa < saddle ? 2 : 15)))
+ // If ma large and x is close to saddle, use `erf` approximation in `ibeta_large_ab`.
+ // In this case we don't need to invert
+ if ((ma > 1e-5f / tools::epsilon<T>()) && (fabs(saddle - x) < 1e-12) && (1 - saddle > 0.125))
{
- if (a == b)
- use_asym = true;
- else
- {
- powers = exp(log(x / (a / (a + b))) * a + log(y / (b / (a + b))) * b);
- if (powers < tools::epsilon<T>())
- use_asym = true;
- }
+ fract = ibeta_large_ab(a, b, x, y, invert, normalised, pol);
+ invert = false;
}
- if(use_asym)
+ else
{
- fract = ibeta_large_ab(a, b, x, y, invert, normalised, pol);
- if (fract * tools::epsilon<T>() < powers)
+ // This is the same logic that is in `ibeta_fraction2`. We have repeated
+ // the implementation here because when x is close to saddle, the continued
+ // fraction will not converge. If this occurs, we fall back to the `erf`
+ // approximation. Simply using `ibeta_fraction2` will cause an evaluation
+ // error to be thrown and we won't be able to use the `erf` approximation.
+ typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
+ T local_result = ibeta_power_terms(a, b, x, y, lanczos_type(), normalised, pol);
+ if (p_derivative)
{
- // Erf approximation failed, correction term is too large, fall back:
- fract = ibeta_fraction2(a, b, x, y, pol, normalised, p_derivative);
+ *p_derivative = local_result;
+ BOOST_MATH_ASSERT(*p_derivative >= 0);
+ }
+ if (local_result != 0)
+ {
+ ibeta_fraction2_t<T> f(a, b, x, y);
+ boost::math::uintmax_t max_terms = boost::math::policies::get_max_series_iterations<Policy>();
+ T local_fract = boost::math::tools::continued_fraction_b(f, boost::math::policies::get_epsilon<T, Policy>(), max_terms);
+ if (max_terms >= boost::math::policies::get_max_series_iterations<Policy>())
+ {
+ // Continued fraction failed, fall back to asymptotic expansion:
+ fract = ibeta_large_ab(a, b, x, y, invert, normalised, pol);
+ invert = false;
+ }
+ else{
+ fract = local_result / local_fract;
+ }
}
else
- invert = false;
+ fract = 0;
}
- else
- fract = ibeta_fraction2(a, b, x, y, pol, normalised, p_derivative);
-
- BOOST_MATH_INSTRUMENT_VARIABLE(fract);
}
}
if(p_derivative)
diff --git a/third-party/boost-math/include/boost/math/special_functions/detail/bessel_jn.hpp b/third-party/boost-math/include/boost/math/special_functions/detail/bessel_jn.hpp
index 6da09fbc4e18e..6400b27875bc4 100644
--- a/third-party/boost-math/include/boost/math/special_functions/detail/bessel_jn.hpp
+++ b/third-party/boost-math/include/boost/math/special_functions/detail/bessel_jn.hpp
@@ -84,7 +84,7 @@ BOOST_MATH_GPU_ENABLED T bessel_jn(int n, T x, const Policy& pol)
current = value;
}
}
- else if((x < 1) || (n > x * x / 4) || (x < 5))
+ else if((x < 5) || (n > x * x / 4))
{
return factor * bessel_j_small_z_series(T(n), x, pol);
}
diff --git a/third-party/boost-math/include/boost/math/special_functions/detail/bessel_jy.hpp b/third-party/boost-math/include/boost/math/special_functions/detail/bessel_jy.hpp
index fb1b5830b587f..2907f91eebd46 100644
--- a/third-party/boost-math/include/boost/math/special_functions/detail/bessel_jy.hpp
+++ b/third-party/boost-math/include/boost/math/special_functions/detail/bessel_jy.hpp
@@ -327,7 +327,10 @@ namespace boost { namespace math {
// x is positive until reflection
W = T(2) / (x * pi<T>()); // Wronskian
T Yv_scale = 1;
- if(((kind & need_y) == 0) && ((x < 1) || (v > x * x / 4) || (x < 5)))
+
+ const bool kind_does_not_need_y { ((kind & need_y) == 0) };
+
+ if(kind_does_not_need_y && ((x < 5) || (v > x * x / 4)))
{
//
// This series will actually converge rapidly for all small
diff --git a/third-party/boost-math/include/boost/math/special_functions/detail/fp_traits.hpp b/third-party/boost-math/include/boost/math/special_functions/detail/fp_traits.hpp
index 015ea9cd35949..7362d0fada7e6 100644
--- a/third-party/boost-math/include/boost/math/special_functions/detail/fp_traits.hpp
+++ b/third-party/boost-math/include/boost/math/special_functions/detail/fp_traits.hpp
@@ -24,6 +24,7 @@ With these techniques, the code could be simplified.
#include <cstring>
#include <cstdint>
#include <limits>
+#include <climits>
#include <type_traits>
#include <boost/math/tools/config.hpp>
#include <boost/math/tools/is_standalone.hpp>
@@ -269,8 +270,7 @@ template<> struct fp_traits_non_native<double, double_precision>
// long double (64 bits) -------------------------------------------------------
-#if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION)\
- || defined(BOOST_BORLANDC) || defined(__CODEGEAR__)
+#if LDBL_MANT_DIG == 53 || defined(__SYCL_DEVICE_ONLY__)
template<> struct fp_traits_non_native<long double, double_precision>
{
@@ -297,33 +297,9 @@ template<> struct fp_traits_non_native<long double, double_precision>
static constexpr int offset_ = BOOST_MATH_ENDIAN_BIG_BYTE ? 0 : 4;
};
-//..............................................................................
-
-#else
-
-template<> struct fp_traits_non_native<long double, double_precision>
-{
- typedef ieee_copy_all_bits_tag method;
-
- static const uint64_t sign = static_cast<uint64_t>(0x80000000u) << 32;
- static const uint64_t exponent = static_cast<uint64_t>(0x7ff00000) << 32;
- static const uint64_t flag = 0;
- static const uint64_t significand
- = (static_cast<uint64_t>(0x000fffff) << 32) + static_cast<uint64_t>(0xffffffffu);
-
- typedef uint64_t bits;
- static void get_bits(long double x, uint64_t& a) { std::memcpy(&a, &x, 8); }
- static void set_bits(long double& x, uint64_t a) { std::memcpy(&x, &a, 8); }
-};
-
-#endif
-
-
// long double (>64 bits), x86 and x64 -----------------------------------------
-#if defined(__i386) || defined(__i386__) || defined(_M_IX86) \
- || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) \
- || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64)
+#elif LDBL_MANT_DIG == 64
// Intel extended double precision format (80 bits)
@@ -378,6 +354,8 @@ struct fp_traits_non_native<long double, extended_double_precision>
// PowerPC extended double precision format (128 bits)
+static_assert(LDBL_MANT_DIG == 113, "Oops, assumption that long double is a 128-bit quantity is incorrect!!");
+
template<>
struct fp_traits_non_native<long double, extended_double_precision>
{
@@ -448,7 +426,7 @@ struct fp_traits_non_native<long double, extended_double_precision>
// long double (>64 bits), All other processors --------------------------------
-#else
+#elif (LDBL_MANT_DIG == 113)
// IEEE extended double precision format with 15 exponent bits (128 bits)
@@ -478,6 +456,10 @@ struct fp_traits_non_native<long double, extended_double_precision>
BOOST_MATH_STATIC constexpr int offset_ = BOOST_MATH_ENDIAN_BIG_BYTE ? 0 : 12;
};
+#else
+
+// Nothing in here, we don't understand the format!
+
#endif
//------------------------------------------------------------------------------
diff --git a/third-party/boost-math/include/boost/math/special_functions/detail/hypergeometric_pFq_checked_series.hpp b/third-party/boost-math/include/boost/math/special_functions/detail/hypergeometric_pFq_checked_series.hpp
index 3adc86f74fb5a..895c586482825 100644
--- a/third-party/boost-math/include/boost/math/special_functions/detail/hypergeometric_pFq_checked_series.hpp
+++ b/third-party/boost-math/include/boost/math/special_functions/detail/hypergeometric_pFq_checked_series.hpp
@@ -23,6 +23,7 @@
unsigned set_crossover_locations(const Seq& aj, const Seq& bj, const Real& z, unsigned int* crossover_locations)
{
BOOST_MATH_STD_USING
+ using nothrow_policy = typename boost::math::policies::normalise<boost::math::policies::policy<>, boost::math::policies::rounding_error<boost::math::policies::ignore_error>>::type;
unsigned N_terms = 0;
if(aj.size() == 1 && bj.size() == 1)
@@ -55,13 +56,13 @@
Real t = (-sqrt(sq) - b + z) / 2;
if (t >= 0)
{
- crossover_locations[N_terms] = itrunc(t);
+ crossover_locations[N_terms] = itrunc(t, nothrow_policy());
++N_terms;
}
t = (sqrt(sq) - b + z) / 2;
if (t >= 0)
{
- crossover_locations[N_terms] = itrunc(t);
+ crossover_locations[N_terms] = itrunc(t, nothrow_policy());
++N_terms;
}
}
@@ -71,13 +72,13 @@
Real t = (-sqrt(sq) - b - z) / 2;
if (t >= 0)
{
- crossover_locations[N_terms] = itrunc(t);
+ crossover_locations[N_terms] = itrunc(t, nothrow_policy());
++N_terms;
}
t = (sqrt(sq) - b - z) / 2;
if (t >= 0)
{
- crossover_locations[N_terms] = itrunc(t);
+ crossover_locations[N_terms] = itrunc(t, nothrow_policy());
++N_terms;
}
}
@@ -110,7 +111,7 @@
unsigned n = 0;
for (auto bi = bj.begin(); bi != bj.end(); ++bi, ++n)
{
- crossover_locations[n] = *bi >= 0 ? 0 : itrunc(-*bi) + 1;
+ crossover_locations[n] = *bi >= 0 ? 0 : itrunc(-*bi, nothrow_policy()) + 1;
}
std::sort(crossover_locations, crossover_locations + bj.size(), std::less<Real>());
N_terms = (unsigned)bj.size();
@@ -122,6 +123,7 @@
std::pair<Real, Real> hypergeometric_pFq_checked_series_impl(const Seq& aj, const Seq& bj, const Real& z, const Policy& pol, const Terminal& termination, long long& log_scale)
{
BOOST_MATH_STD_USING
+ using nothrow_policy = typename boost::math::policies::normalise<Policy, boost::math::policies::rounding_error<boost::math::policies::ignore_error>>::type;
Real result = 1;
Real abs_result = 1;
Real term = 1;
@@ -129,8 +131,19 @@
Real tol = boost::math::policies::get_epsilon<Real, Policy>();
std::uintmax_t k = 0;
Real upper_limit(sqrt(boost::math::tools::max_value<Real>())), diff;
+ if ((tools::max_value<Real>() / fabs(z) < upper_limit))
+ {
+ upper_limit = tools::max_value<Real>() / fabs(z);
+ }
+ for (auto pa = aj.begin(); pa != aj.end(); ++pa)
+ {
+ if (tools::max_value<Real>() / fabs(*pa) < upper_limit)
+ {
+ upper_limit = tools::max_value<Real>() / fabs(*pa);
+ }
+ }
Real lower_limit(1 / upper_limit);
- long long log_scaling_factor = lltrunc(boost::math::tools::log_max_value<Real>()) - 2;
+ long long log_scaling_factor = lltrunc(boost::math::tools::log_max_value<Real>(), nothrow_policy()) - 2;
Real scaling_factor = exp(Real(log_scaling_factor));
Real term_m1;
long long local_scaling = 0;
@@ -234,7 +247,10 @@
log_scale += log_scaling_factor;
local_scaling += log_scaling_factor;
}
- if (fabs(abs_result) < lower_limit)
+ /*
+ * rescaling to avoid underflow is pointless here, given that the first term is 1.
+ *
+ else if ((fabs(abs_result) < lower_limit) && (fabs(abs_result) * scaling_factor < upper_limit))
{
abs_result *= scaling_factor;
result *= scaling_factor;
@@ -242,7 +258,7 @@
log_scale -= log_scaling_factor;
local_scaling -= log_scaling_factor;
}
-
+ */
if ((abs(result * tol) > abs(term)) && (abs(term0) > abs(term)))
break;
if (abs_result * tol > abs(result))
@@ -321,7 +337,7 @@
else
{
int ls = 1;
- Real p = log_pochhammer(*ai, s, pol, &ls);
+ Real p = log_pochhammer(static_cast<Real>(*ai), s, pol, &ls);
s1 *= ls;
term += p;
loop_error_scale = (std::max)(p, loop_error_scale);
@@ -334,7 +350,7 @@
for (auto bi = bj.begin(); bi != bj.end(); ++bi)
{
int ls = 1;
- Real p = log_pochhammer(*bi, s, pol, &ls);
+ Real p = log_pochhammer(static_cast<Real>(*bi), s, pol, &ls);
s2 *= ls;
term -= p;
loop_error_scale = (std::max)(p, loop_error_scale);
@@ -371,13 +387,13 @@
if (term <= tools::log_min_value<Real>())
{
// rescale if we can:
- long long scale = lltrunc(floor(term - tools::log_min_value<Real>()) - 2);
+ long long scale = lltrunc(floor(term - tools::log_min_value<Real>()) - 2, nothrow_policy());
term -= scale;
loop_scale += scale;
}
if (term > 10)
{
- int scale = itrunc(floor(term));
+ long long scale = lltrunc(floor(term), nothrow_policy());
term -= scale;
loop_scale += scale;
}
@@ -402,7 +418,7 @@
term /= scaling_factor;
loop_scale += log_scaling_factor;
}
- if (fabs(loop_result) < lower_limit)
+ else if ((fabs(loop_result) < lower_limit) && (fabs(loop_result) * scaling_factor < upper_limit))
{
loop_result *= scaling_factor;
loop_abs_result *= scaling_factor;
diff --git a/third-party/boost-math/include/boost/math/special_functions/detail/lambert_w_lookup_table.ipp b/third-party/boost-math/include/boost/math/special_functions/detail/lambert_w_lookup_table.ipp
index b38aeb49c3241..9f1b488ead214 100644
--- a/third-party/boost-math/include/boost/math/special_functions/detail/lambert_w_lookup_table.ipp
+++ b/third-party/boost-math/include/boost/math/special_functions/detail/lambert_w_lookup_table.ipp
@@ -30,103 +30,131 @@ static constexpr std::size_t noof_wm1zs = 64;
static constexpr lookup_t halves[noof_halves] =
{ // Common to Lambert W0 and W-1 (and exactly representable).
- 0.5L, 0.25L, 0.125L, 0.0625L, 0.03125L, 0.015625L, 0.0078125L, 0.00390625L, 0.001953125L, 0.0009765625L, 0.00048828125L, 0.000244140625L
+ static_cast<lookup_t>(0.5L), static_cast<lookup_t>(0.25L), static_cast<lookup_t>(0.125L), static_cast<lookup_t>(0.0625L),
+ static_cast<lookup_t>(0.03125L), static_cast<lookup_t>(0.015625L), static_cast<lookup_t>(0.0078125L), static_cast<lookup_t>(0.00390625L),
+ static_cast<lookup_t>(0.001953125L), static_cast<lookup_t>(0.0009765625L), static_cast<lookup_t>(0.00048828125L), static_cast<lookup_t>(0.000244140625L)
}; // halves, 0.5, 0.25, ... 0.000244140625, common to W0 and W-1.
static constexpr lookup_t sqrtw0s[noof_sqrts] =
{ // For Lambert W0 only.
- 0.6065306597126334242631173765403218567L, 0.77880078307140486866846070009071995L, 0.882496902584595403104717592968701829L, 0.9394130628134757862473572557999761753L, 0.9692332344763440819139583751755278177L, 0.9844964370054084060204319075254540376L, 0.9922179382602435121227899136829802692L, 0.996101369470117490071323985506950379L, 0.9980487811074754727142805899944244847L, 0.9990239141819756622368328253791383317L, 0.9995118379398893653889967919448497792L, 0.9997558891748972165136242351259789505L
+ static_cast<lookup_t>(0.6065306597126334242631173765403218567L), static_cast<lookup_t>(0.7788007830714048686684607000907199500L),
+ static_cast<lookup_t>(0.8824969025845954031047175929687018290L), static_cast<lookup_t>(0.9394130628134757862473572557999761753L),
+ static_cast<lookup_t>(0.9692332344763440819139583751755278177L), static_cast<lookup_t>(0.9844964370054084060204319075254540376L),
+ static_cast<lookup_t>(0.9922179382602435121227899136829802692L), static_cast<lookup_t>(0.9961013694701174900713239855069503790L),
+ static_cast<lookup_t>(0.9980487811074754727142805899944244847L), static_cast<lookup_t>(0.9990239141819756622368328253791383317L),
+ static_cast<lookup_t>(0.9995118379398893653889967919448497792L), static_cast<lookup_t>(0.9997558891748972165136242351259789505L)
}; // sqrtw0s
static constexpr lookup_t sqrtwm1s[noof_sqrts] =
{ // For Lambert W-1 only.
- 1.648721270700128146848650787814163572L, 1.284025416687741484073420568062436458L, 1.133148453066826316829007227811793873L, 1.064494458917859429563390594642889673L, 1.031743407499102670938747815281507144L, 1.015747708586685747458535072082351749L, 1.007843097206447977693453559760123579L, 1.003913889338347573443609603903460282L, 1.001955033591002812046518898047477216L, 1.000977039492416535242845292611606506L, 1.000488400478694473126173623807163354L, 1.000244170429747854937005233924135774L
+ static_cast<lookup_t>(1.648721270700128146848650787814163572L), static_cast<lookup_t>(1.284025416687741484073420568062436458L),
+ static_cast<lookup_t>(1.133148453066826316829007227811793873L), static_cast<lookup_t>(1.064494458917859429563390594642889673L),
+ static_cast<lookup_t>(1.031743407499102670938747815281507144L), static_cast<lookup_t>(1.015747708586685747458535072082351749L),
+ static_cast<lookup_t>(1.007843097206447977693453559760123579L), static_cast<lookup_t>(1.003913889338347573443609603903460282L),
+ static_cast<lookup_t>(1.001955033591002812046518898047477216L), static_cast<lookup_t>(1.000977039492416535242845292611606506L),
+ static_cast<lookup_t>(1.000488400478694473126173623807163354L), static_cast<lookup_t>(1.000244170429747854937005233924135774L)
}; // sqrtwm1s
static constexpr lookup_t w0es[noof_w0zs] =
{ // Fukushima e powers array e[0] = 2.718, 1., e[2] = e^-1 = 0.135, e[3] = e^-2 = 0.133 ... e[64] = 4.3596100000630809736231248158884615452e-28.
- 2.7182818284590452353602874713526624978e+00L,
- 1.0000000000000000000000000000000000000e+00L, 3.6787944117144232159552377016146086745e-01L, 1.3533528323661269189399949497248440341e-01L, 4.9787068367863942979342415650061776632e-02L,
- 1.8315638888734180293718021273241242212e-02L, 6.7379469990854670966360484231484242488e-03L, 2.4787521766663584230451674308166678915e-03L, 9.1188196555451620800313608440928262647e-04L,
- 3.3546262790251183882138912578086101931e-04L, 1.2340980408667954949763669073003382607e-04L, 4.5399929762484851535591515560550610238e-05L, 1.6701700790245659312635517360580879078e-05L,
- 6.1442123533282097586823081788055323112e-06L, 2.2603294069810543257852772905386894694e-06L, 8.3152871910356788406398514256526229461e-07L, 3.0590232050182578837147949770228963937e-07L,
- 1.1253517471925911451377517906012719164e-07L, 4.1399377187851666596510277189552806229e-08L, 1.5229979744712628436136629233517431862e-08L, 5.6027964375372675400129828162064630798e-09L,
- 2.0611536224385578279659403801558209764e-09L, 7.5825604279119067279417432412681264430e-10L, 2.7894680928689248077189130306442932077e-10L, 1.0261879631701890303927527840612497760e-10L,
- 3.7751345442790977516449695475234067792e-11L, 1.3887943864964020594661763746086856910e-11L, 5.1090890280633247198744001934792157666e-12L, 1.8795288165390832947582704184221926212e-12L,
- 6.9144001069402030094125846587414092712e-13L, 2.5436656473769229103033856148576816666e-13L, 9.3576229688401746049158322233787067450e-14L, 3.4424771084699764583923893328515572846e-14L,
- 1.2664165549094175723120904155965096382e-14L, 4.6588861451033973641842455436101684114e-15L, 1.7139084315420129663027203425760492412e-15L, 6.3051167601469893856390211922465427614e-16L,
- 2.3195228302435693883122636097380800411e-16L, 8.5330476257440657942780498229412441658e-17L, 3.1391327920480296287089646522319196491e-17L, 1.1548224173015785986262442063323868655e-17L,
- 4.2483542552915889953292347828586580179e-18L, 1.5628821893349887680908829951058341550e-18L, 5.7495222642935598066643808805734234249e-19L, 2.1151310375910804866314010070226514702e-19L,
- 7.7811322411337965157133167292798981918e-20L, 2.8625185805493936444701216291839372068e-20L, 1.0530617357553812378763324449428108806e-20L, 3.8739976286871871129314774972691278293e-21L,
- 1.4251640827409351062853210280340602263e-21L, 5.2428856633634639371718053028323436716e-22L, 1.9287498479639177830173428165270125748e-22L, 7.0954741622847041389832693878080734877e-23L,
- 2.6102790696677048047026953153318648093e-23L, 9.6026800545086760302307696700074909076e-24L, 3.5326285722008070297353928101772088374e-24L, 1.2995814250075030736007134060714855303e-24L,
- 4.7808928838854690812771770423179628939e-25L, 1.7587922024243116489558751288034363178e-25L, 6.4702349256454603261540395529264893765e-26L, 2.3802664086944006058943245888024963309e-26L,
- 8.7565107626965203384887328007391660366e-27L, 3.2213402859925160890012477758489437534e-27L, 1.1850648642339810062850307390972809891e-27L, 4.3596100000630809736231248158884596428e-28L,
+ static_cast<lookup_t>(2.7182818284590452353602874713526624978e+00L),
+ static_cast<lookup_t>(1.0000000000000000000000000000000000000e+00L), static_cast<lookup_t>(3.6787944117144232159552377016146086745e-01L),
+ static_cast<lookup_t>(1.3533528323661269189399949497248440341e-01L), static_cast<lookup_t>(4.9787068367863942979342415650061776632e-02L),
+ static_cast<lookup_t>(1.8315638888734180293718021273241242212e-02L), static_cast<lookup_t>(6.7379469990854670966360484231484242488e-03L),
+ static_cast<lookup_t>(2.4787521766663584230451674308166678915e-03L), static_cast<lookup_t>(9.1188196555451620800313608440928262647e-04L),
+ static_cast<lookup_t>(3.3546262790251183882138912578086101931e-04L), static_cast<lookup_t>(1.2340980408667954949763669073003382607e-04L),
+ static_cast<lookup_t>(4.5399929762484851535591515560550610238e-05L), static_cast<lookup_t>(1.6701700790245659312635517360580879078e-05L),
+ static_cast<lookup_t>(6.1442123533282097586823081788055323112e-06L), static_cast<lookup_t>(2.2603294069810543257852772905386894694e-06L),
+ static_cast<lookup_t>(8.3152871910356788406398514256526229461e-07L), static_cast<lookup_t>(3.0590232050182578837147949770228963937e-07L),
+ static_cast<lookup_t>(1.1253517471925911451377517906012719164e-07L), static_cast<lookup_t>(4.1399377187851666596510277189552806229e-08L),
+ static_cast<lookup_t>(1.5229979744712628436136629233517431862e-08L), static_cast<lookup_t>(5.6027964375372675400129828162064630798e-09L),
+ static_cast<lookup_t>(2.0611536224385578279659403801558209764e-09L), static_cast<lookup_t>(7.5825604279119067279417432412681264430e-10L),
+ static_cast<lookup_t>(2.7894680928689248077189130306442932077e-10L), static_cast<lookup_t>(1.0261879631701890303927527840612497760e-10L),
+ static_cast<lookup_t>(3.7751345442790977516449695475234067792e-11L), static_cast<lookup_t>(1.3887943864964020594661763746086856910e-11L),
+ static_cast<lookup_t>(5.1090890280633247198744001934792157666e-12L), static_cast<lookup_t>(1.8795288165390832947582704184221926212e-12L),
+ static_cast<lookup_t>(6.9144001069402030094125846587414092712e-13L), static_cast<lookup_t>(2.5436656473769229103033856148576816666e-13L),
+ static_cast<lookup_t>(9.3576229688401746049158322233787067450e-14L), static_cast<lookup_t>(3.4424771084699764583923893328515572846e-14L),
+ static_cast<lookup_t>(1.2664165549094175723120904155965096382e-14L), static_cast<lookup_t>(4.6588861451033973641842455436101684114e-15L),
+ static_cast<lookup_t>(1.7139084315420129663027203425760492412e-15L), static_cast<lookup_t>(6.3051167601469893856390211922465427614e-16L),
+ static_cast<lookup_t>(2.3195228302435693883122636097380800411e-16L), static_cast<lookup_t>(8.5330476257440657942780498229412441658e-17L),
+ static_cast<lookup_t>(3.1391327920480296287089646522319196491e-17L), static_cast<lookup_t>(1.1548224173015785986262442063323868655e-17L),
+ static_cast<lookup_t>(4.2483542552915889953292347828586580179e-18L), static_cast<lookup_t>(1.5628821893349887680908829951058341550e-18L),
+ static_cast<lookup_t>(5.7495222642935598066643808805734234249e-19L), static_cast<lookup_t>(2.1151310375910804866314010070226514702e-19L),
+ static_cast<lookup_t>(7.7811322411337965157133167292798981918e-20L), static_cast<lookup_t>(2.8625185805493936444701216291839372068e-20L),
+ static_cast<lookup_t>(1.0530617357553812378763324449428108806e-20L), static_cast<lookup_t>(3.8739976286871871129314774972691278293e-21L),
+ static_cast<lookup_t>(1.4251640827409351062853210280340602263e-21L), static_cast<lookup_t>(5.2428856633634639371718053028323436716e-22L),
+ static_cast<lookup_t>(1.9287498479639177830173428165270125748e-22L), static_cast<lookup_t>(7.0954741622847041389832693878080734877e-23L),
+ static_cast<lookup_t>(2.6102790696677048047026953153318648093e-23L), static_cast<lookup_t>(9.6026800545086760302307696700074909076e-24L),
+ static_cast<lookup_t>(3.5326285722008070297353928101772088374e-24L), static_cast<lookup_t>(1.2995814250075030736007134060714855303e-24L),
+ static_cast<lookup_t>(4.7808928838854690812771770423179628939e-25L), static_cast<lookup_t>(1.7587922024243116489558751288034363178e-25L),
+ static_cast<lookup_t>(6.4702349256454603261540395529264893765e-26L), static_cast<lookup_t>(2.3802664086944006058943245888024963309e-26L),
+ static_cast<lookup_t>(8.7565107626965203384887328007391660366e-27L), static_cast<lookup_t>(3.2213402859925160890012477758489437534e-27L),
+ static_cast<lookup_t>(1.1850648642339810062850307390972809891e-27L), static_cast<lookup_t>(4.3596100000630809736231248158884596428e-28L),
}; // w0es
static constexpr lookup_t w0zs[noof_w0zs] =
{ // z values for W[0], W[1], W[2] ... W[64] (Fukushima array Fk).
- 0.0000000000000000000000000000000000000e+00L,
- 2.7182818284590452353602874713526624978e+00L, 1.4778112197861300454460854921150015626e+01L, 6.0256610769563003222785588963745153691e+01L, 2.1839260013257695631244104481144351361e+02L,
- 7.4206579551288301710557790020276139812e+02L, 2.4205727609564107356503230832603296776e+03L, 7.6764321089992101948460416680168500271e+03L, 2.3847663896333826197948736795623109390e+04L,
- 7.2927755348178456069389970204894839685e+04L, 2.2026465794806716516957900645284244366e+05L, 6.5861555886717600300859134371483559776e+05L, 1.9530574970280470496960624587818413980e+06L,
- 5.7513740961159665432393360873381476632e+06L, 1.6836459978306874888489314790750032292e+07L, 4.9035260587081659589527825691375819733e+07L, 1.4217776832812596218820837985250320561e+08L,
- 4.1063419681078006965118239806655900596e+08L, 1.1818794444719492004981570586630806042e+09L, 3.3911637183005579560532906419857313738e+09L, 9.7033039081958055593821366108308111737e+09L,
- 2.7695130424147508641409976558651358487e+10L, 7.8868082614895014356985518811525255163e+10L, 2.2413047926372475980079655175092843139e+11L, 6.3573893111624333505933989166748517618e+11L,
- 1.8001224834346468131040337866531539479e+12L, 5.0889698451498078710141863447784789126e+12L, 1.4365302496248562650461177217211790925e+13L, 4.0495197800161304862957327843914007993e+13L,
- 1.1400869461717722015726999684446230289e+14L, 3.2059423744573386440971405952224204950e+14L, 9.0051433962267018216365614546207459567e+14L, 2.5268147258457822451512967243234631750e+15L,
- 7.0832381329352301326018261305316090522e+15L, 1.9837699245933465967698692976753294646e+16L, 5.5510470830970075484537561902113104381e+16L, 1.5520433569614702817608320254284931407e+17L,
- 4.3360826779369661842459877227403719730e+17L, 1.2105254067703227363724895246493485480e+18L, 3.3771426165357561311906703760513324357e+18L, 9.4154106734807994163159964299613921804e+18L,
- 2.6233583234732252918129199544138403574e+19L, 7.3049547543861043990576614751671879498e+19L, 2.0329709713386190214340167519800405595e+20L, 5.6547040503180956413560918381429636734e+20L,
- 1.5720421975868292906615658755032744790e+21L, 4.3682149334771264822761478593874428627e+21L, 1.2132170565093316762294432610117848880e+22L, 3.3680332378068632345542636794533635462e+22L,
- 9.3459982052259884835729892206738573922e+22L, 2.5923527642935362320437266614667426924e+23L, 7.1876803203773878618909930893087860822e+23L, 1.9921241603726199616378561653688236827e+24L,
- 5.5192924995054165325072406547517121131e+24L, 1.5286067837683347062387143159276002521e+25L, 4.2321318958281094260005100745711666956e+25L, 1.1713293177672778461879598480402173158e+26L,
- 3.2408603996214813669049988277609543829e+26L, 8.9641258264226027960478448084812796397e+26L, 2.4787141382364034104243901241243054434e+27L, 6.8520443388941057019777430988685937812e+27L,
- 1.8936217407781711443114787060753312270e+28L, 5.2317811346197017832254642778313331353e+28L, 1.4450833904658542238325922893692265683e+29L, 3.9904954117194348050619127737142206367e+29L
+ static_cast<lookup_t>(0.0000000000000000000000000000000000000e+00L),
+ static_cast<lookup_t>(2.7182818284590452353602874713526624978e+00L), static_cast<lookup_t>(1.4778112197861300454460854921150015626e+01L), static_cast<lookup_t>(6.0256610769563003222785588963745153691e+01L), static_cast<lookup_t>(2.1839260013257695631244104481144351361e+02L),
+ static_cast<lookup_t>(7.4206579551288301710557790020276139812e+02L), static_cast<lookup_t>(2.4205727609564107356503230832603296776e+03L), static_cast<lookup_t>(7.6764321089992101948460416680168500271e+03L), static_cast<lookup_t>(2.3847663896333826197948736795623109390e+04L),
+ static_cast<lookup_t>(7.2927755348178456069389970204894839685e+04L), static_cast<lookup_t>(2.2026465794806716516957900645284244366e+05L), static_cast<lookup_t>(6.5861555886717600300859134371483559776e+05L), static_cast<lookup_t>(1.9530574970280470496960624587818413980e+06L),
+ static_cast<lookup_t>(5.7513740961159665432393360873381476632e+06L), static_cast<lookup_t>(1.6836459978306874888489314790750032292e+07L), static_cast<lookup_t>(4.9035260587081659589527825691375819733e+07L), static_cast<lookup_t>(1.4217776832812596218820837985250320561e+08L),
+ static_cast<lookup_t>(4.1063419681078006965118239806655900596e+08L), static_cast<lookup_t>(1.1818794444719492004981570586630806042e+09L), static_cast<lookup_t>(3.3911637183005579560532906419857313738e+09L), static_cast<lookup_t>(9.7033039081958055593821366108308111737e+09L),
+ static_cast<lookup_t>(2.7695130424147508641409976558651358487e+10L), static_cast<lookup_t>(7.8868082614895014356985518811525255163e+10L), static_cast<lookup_t>(2.2413047926372475980079655175092843139e+11L), static_cast<lookup_t>(6.3573893111624333505933989166748517618e+11L),
+ static_cast<lookup_t>(1.8001224834346468131040337866531539479e+12L), static_cast<lookup_t>(5.0889698451498078710141863447784789126e+12L), static_cast<lookup_t>(1.4365302496248562650461177217211790925e+13L), static_cast<lookup_t>(4.0495197800161304862957327843914007993e+13L),
+ static_cast<lookup_t>(1.1400869461717722015726999684446230289e+14L), static_cast<lookup_t>(3.2059423744573386440971405952224204950e+14L), static_cast<lookup_t>(9.0051433962267018216365614546207459567e+14L), static_cast<lookup_t>(2.5268147258457822451512967243234631750e+15L),
+ static_cast<lookup_t>(7.0832381329352301326018261305316090522e+15L), static_cast<lookup_t>(1.9837699245933465967698692976753294646e+16L), static_cast<lookup_t>(5.5510470830970075484537561902113104381e+16L), static_cast<lookup_t>(1.5520433569614702817608320254284931407e+17L),
+ static_cast<lookup_t>(4.3360826779369661842459877227403719730e+17L), static_cast<lookup_t>(1.2105254067703227363724895246493485480e+18L), static_cast<lookup_t>(3.3771426165357561311906703760513324357e+18L), static_cast<lookup_t>(9.4154106734807994163159964299613921804e+18L),
+ static_cast<lookup_t>(2.6233583234732252918129199544138403574e+19L), static_cast<lookup_t>(7.3049547543861043990576614751671879498e+19L), static_cast<lookup_t>(2.0329709713386190214340167519800405595e+20L), static_cast<lookup_t>(5.6547040503180956413560918381429636734e+20L),
+ static_cast<lookup_t>(1.5720421975868292906615658755032744790e+21L), static_cast<lookup_t>(4.3682149334771264822761478593874428627e+21L), static_cast<lookup_t>(1.2132170565093316762294432610117848880e+22L), static_cast<lookup_t>(3.3680332378068632345542636794533635462e+22L),
+ static_cast<lookup_t>(9.3459982052259884835729892206738573922e+22L), static_cast<lookup_t>(2.5923527642935362320437266614667426924e+23L), static_cast<lookup_t>(7.1876803203773878618909930893087860822e+23L), static_cast<lookup_t>(1.9921241603726199616378561653688236827e+24L),
+ static_cast<lookup_t>(5.5192924995054165325072406547517121131e+24L), static_cast<lookup_t>(1.5286067837683347062387143159276002521e+25L), static_cast<lookup_t>(4.2321318958281094260005100745711666956e+25L), static_cast<lookup_t>(1.1713293177672778461879598480402173158e+26L),
+ static_cast<lookup_t>(3.2408603996214813669049988277609543829e+26L), static_cast<lookup_t>(8.9641258264226027960478448084812796397e+26L), static_cast<lookup_t>(2.4787141382364034104243901241243054434e+27L), static_cast<lookup_t>(6.8520443388941057019777430988685937812e+27L),
+ static_cast<lookup_t>(1.8936217407781711443114787060753312270e+28L), static_cast<lookup_t>(5.2317811346197017832254642778313331353e+28L), static_cast<lookup_t>(1.4450833904658542238325922893692265683e+29L), static_cast<lookup_t>(3.9904954117194348050619127737142206367e+29L)
}; // w0zs
static constexpr lookup_t wm1es[noof_wm1es] =
{ // Fukushima e array e[0] = e^1 = 2.718, e[1] = e^2 = 7.39 ... e[64] = 4.60718e+28.
- 2.7182818284590452353602874713526624978e+00L,
- 7.3890560989306502272304274605750078132e+00L, 2.0085536923187667740928529654581717897e+01L, 5.4598150033144239078110261202860878403e+01L, 1.4841315910257660342111558004055227962e+02L,
- 4.0342879349273512260838718054338827961e+02L, 1.0966331584284585992637202382881214324e+03L, 2.9809579870417282747435920994528886738e+03L, 8.1030839275753840077099966894327599650e+03L,
- 2.2026465794806716516957900645284244366e+04L, 5.9874141715197818455326485792257781614e+04L, 1.6275479141900392080800520489848678317e+05L, 4.4241339200892050332610277594908828178e+05L,
- 1.2026042841647767777492367707678594494e+06L, 3.2690173724721106393018550460917213155e+06L, 8.8861105205078726367630237407814503508e+06L, 2.4154952753575298214775435180385823880e+07L,
- 6.5659969137330511138786503259060033569e+07L, 1.7848230096318726084491003378872270388e+08L, 4.8516519540979027796910683054154055868e+08L, 1.3188157344832146972099988837453027851e+09L,
- 3.5849128461315915616811599459784206892e+09L, 9.7448034462489026000346326848229752776e+09L, 2.6489122129843472294139162152811882341e+10L, 7.2004899337385872524161351466126157915e+10L,
- 1.9572960942883876426977639787609534279e+11L, 5.3204824060179861668374730434117744166e+11L, 1.4462570642914751736770474229969288569e+12L, 3.9313342971440420743886205808435276858e+12L,
- 1.0686474581524462146990468650741401650e+13L, 2.9048849665247425231085682111679825667e+13L, 7.8962960182680695160978022635108224220e+13L, 2.1464357978591606462429776153126088037e+14L,
- 5.8346174252745488140290273461039101900e+14L, 1.5860134523134307281296446257746601252e+15L, 4.3112315471151952271134222928569253908e+15L, 1.1719142372802611308772939791190194522e+16L,
- 3.1855931757113756220328671701298646000e+16L, 8.6593400423993746953606932719264934250e+16L, 2.3538526683701998540789991074903480451e+17L, 6.3984349353005494922266340351557081888e+17L,
- 1.7392749415205010473946813036112352261e+18L, 4.7278394682293465614744575627442803708e+18L, 1.2851600114359308275809299632143099258e+19L, 3.4934271057485095348034797233406099533e+19L,
- 9.4961194206024488745133649117118323102e+19L, 2.5813128861900673962328580021527338043e+20L, 7.0167359120976317386547159988611740546e+20L, 1.9073465724950996905250998409538484474e+21L,
- 5.1847055285870724640874533229334853848e+21L, 1.4093490824269387964492143312370168789e+22L, 3.8310080007165768493035695487861993899e+22L, 1.0413759433029087797183472933493796440e+23L,
- 2.8307533032746939004420635480140745409e+23L, 7.6947852651420171381827455901293939921e+23L, 2.0916594960129961539070711572146737782e+24L, 5.6857199993359322226403488206332533034e+24L,
- 1.5455389355901039303530766911174620068e+25L, 4.2012104037905142549565934307191617684e+25L, 1.1420073898156842836629571831447656302e+26L, 3.1042979357019199087073421411071003721e+26L,
- 8.4383566687414544890733294803731179601e+26L, 2.2937831594696098790993528402686136005e+27L, 6.2351490808116168829092387089284697448e+27L
+ static_cast<lookup_t>(2.7182818284590452353602874713526624978e+00L),
+ static_cast<lookup_t>(7.3890560989306502272304274605750078132e+00L), static_cast<lookup_t>(2.0085536923187667740928529654581717897e+01L), static_cast<lookup_t>(5.4598150033144239078110261202860878403e+01L), static_cast<lookup_t>(1.4841315910257660342111558004055227962e+02L),
+ static_cast<lookup_t>(4.0342879349273512260838718054338827961e+02L), static_cast<lookup_t>(1.0966331584284585992637202382881214324e+03L), static_cast<lookup_t>(2.9809579870417282747435920994528886738e+03L), static_cast<lookup_t>(8.1030839275753840077099966894327599650e+03L),
+ static_cast<lookup_t>(2.2026465794806716516957900645284244366e+04L), static_cast<lookup_t>(5.9874141715197818455326485792257781614e+04L), static_cast<lookup_t>(1.6275479141900392080800520489848678317e+05L), static_cast<lookup_t>(4.4241339200892050332610277594908828178e+05L),
+ static_cast<lookup_t>(1.2026042841647767777492367707678594494e+06L), static_cast<lookup_t>(3.2690173724721106393018550460917213155e+06L), static_cast<lookup_t>(8.8861105205078726367630237407814503508e+06L), static_cast<lookup_t>(2.4154952753575298214775435180385823880e+07L),
+ static_cast<lookup_t>(6.5659969137330511138786503259060033569e+07L), static_cast<lookup_t>(1.7848230096318726084491003378872270388e+08L), static_cast<lookup_t>(4.8516519540979027796910683054154055868e+08L), static_cast<lookup_t>(1.3188157344832146972099988837453027851e+09L),
+ static_cast<lookup_t>(3.5849128461315915616811599459784206892e+09L), static_cast<lookup_t>(9.7448034462489026000346326848229752776e+09L), static_cast<lookup_t>(2.6489122129843472294139162152811882341e+10L), static_cast<lookup_t>(7.2004899337385872524161351466126157915e+10L),
+ static_cast<lookup_t>(1.9572960942883876426977639787609534279e+11L), static_cast<lookup_t>(5.3204824060179861668374730434117744166e+11L), static_cast<lookup_t>(1.4462570642914751736770474229969288569e+12L), static_cast<lookup_t>(3.9313342971440420743886205808435276858e+12L),
+ static_cast<lookup_t>(1.0686474581524462146990468650741401650e+13L), static_cast<lookup_t>(2.9048849665247425231085682111679825667e+13L), static_cast<lookup_t>(7.8962960182680695160978022635108224220e+13L), static_cast<lookup_t>(2.1464357978591606462429776153126088037e+14L),
+ static_cast<lookup_t>(5.8346174252745488140290273461039101900e+14L), static_cast<lookup_t>(1.5860134523134307281296446257746601252e+15L), static_cast<lookup_t>(4.3112315471151952271134222928569253908e+15L), static_cast<lookup_t>(1.1719142372802611308772939791190194522e+16L),
+ static_cast<lookup_t>(3.1855931757113756220328671701298646000e+16L), static_cast<lookup_t>(8.6593400423993746953606932719264934250e+16L), static_cast<lookup_t>(2.3538526683701998540789991074903480451e+17L), static_cast<lookup_t>(6.3984349353005494922266340351557081888e+17L),
+ static_cast<lookup_t>(1.7392749415205010473946813036112352261e+18L), static_cast<lookup_t>(4.7278394682293465614744575627442803708e+18L), static_cast<lookup_t>(1.2851600114359308275809299632143099258e+19L), static_cast<lookup_t>(3.4934271057485095348034797233406099533e+19L),
+ static_cast<lookup_t>(9.4961194206024488745133649117118323102e+19L), static_cast<lookup_t>(2.5813128861900673962328580021527338043e+20L), static_cast<lookup_t>(7.0167359120976317386547159988611740546e+20L), static_cast<lookup_t>(1.9073465724950996905250998409538484474e+21L),
+ static_cast<lookup_t>(5.1847055285870724640874533229334853848e+21L), static_cast<lookup_t>(1.4093490824269387964492143312370168789e+22L), static_cast<lookup_t>(3.8310080007165768493035695487861993899e+22L), static_cast<lookup_t>(1.0413759433029087797183472933493796440e+23L),
+ static_cast<lookup_t>(2.8307533032746939004420635480140745409e+23L), static_cast<lookup_t>(7.6947852651420171381827455901293939921e+23L), static_cast<lookup_t>(2.0916594960129961539070711572146737782e+24L), static_cast<lookup_t>(5.6857199993359322226403488206332533034e+24L),
+ static_cast<lookup_t>(1.5455389355901039303530766911174620068e+25L), static_cast<lookup_t>(4.2012104037905142549565934307191617684e+25L), static_cast<lookup_t>(1.1420073898156842836629571831447656302e+26L), static_cast<lookup_t>(3.1042979357019199087073421411071003721e+26L),
+ static_cast<lookup_t>(8.4383566687414544890733294803731179601e+26L), static_cast<lookup_t>(2.2937831594696098790993528402686136005e+27L), static_cast<lookup_t>(6.2351490808116168829092387089284697448e+27L)
}; // wm1es
static constexpr lookup_t wm1zs[noof_wm1zs] =
{ // Fukushima G array of z values for integral K, (Fukushima Gk) g[0] (k = -1) = 1 ... g[64] = -1.0264389699511303e-26.
- -3.6787944117144232159552377016146086745e-01L,
- -2.7067056647322538378799898994496880682e-01L, -1.4936120510359182893802724695018532990e-01L, -7.3262555554936721174872085092964968848e-02L, -3.3689734995427335483180242115742121244e-02L,
- -1.4872513059998150538271004584900007349e-02L, -6.3831737588816134560219525908649783853e-03L, -2.6837010232200947105711130062468881545e-03L, -1.1106882367801159454787302165703044346e-03L,
- -4.5399929762484851535591515560550610238e-04L, -1.8371870869270225243899069096638966986e-04L, -7.3730548239938517104187698145666387735e-05L, -2.9384282290753706235208604777002963102e-05L,
- -1.1641402067449950376895791995913672125e-05L, -4.5885348075273868255721924655343445906e-06L, -1.8005627955081458322204028649620350662e-06L, -7.0378941219347833214067471222239770590e-07L,
- -2.7413963540482731185045932620331377352e-07L, -1.0645313231320808326024667350792279852e-07L, -4.1223072448771156559318807603116419528e-08L, -1.5923376898615004128677660806663065530e-08L,
- -6.1368298043116345769816086674174450569e-09L, -2.3602323152914347699033314033408744848e-09L, -9.0603229062698346039479269140561762700e-10L, -3.4719859662410051486654409365217142276e-10L,
- -1.3283631472964644271673440503045960993e-10L, -5.0747278046555248958473301297399200773e-11L, -1.9360320299432568426355237044475945959e-11L, -7.3766303773930764398798182830872768331e-12L,
- -2.8072868906520523814747496670136120235e-12L, -1.0671679036256927021016406931839827582e-12L, -4.0525329757101362313986893299088308423e-13L, -1.5374324278841211301808010293913555758e-13L,
- -5.8272886672428440854292491647585674200e-14L, -2.2067908660514462849736574172862899665e-14L, -8.3502821888768497979241489950570881481e-15L, -3.1572276215253043438828784344882603413e-15L,
- -1.1928704609782512589094065678481294667e-15L, -4.5038074274761565346423524046963087756e-16L, -1.6993417021166355981316939131434632072e-16L, -6.4078169762734539491726202799339200356e-17L,
- -2.4147993510032951187990399698408378385e-17L, -9.0950634616416460925150243301974013218e-18L, -3.4236981860988704669138593608831552044e-18L, -1.2881333612472271400115547331327717431e-18L,
- -4.8440839844747536942311292467369300505e-19L, -1.8207788854829779430777944237164900798e-19L, -6.8407875971564885101695409345634890862e-20L, -2.5690139750480973292141845983878483991e-20L,
- -9.6437492398195889150867140826350628738e-21L, -3.6186918227651991108814673877821174787e-21L, -1.3573451162272064984454015639725697008e-21L, -5.0894204288895982960223079251039701810e-22L,
- -1.9076194289884357960571121174956927722e-22L, -7.1476978375412669048039237333931704166e-23L, -2.6773000149758626855152191436980592206e-23L, -1.0025115553818576399048488234179587012e-23L,
- -3.7527362568743669891693429406973638384e-24L, -1.4043571811296963574776515073934728352e-24L, -5.2539064576179122030932396804434996219e-25L, -1.9650175744554348142907611432678556896e-25L,
- -7.3474021582506822389671905824031421322e-26L, -2.7465543000397410133825686340097295749e-26L, -1.0264389699511282259046957018510946438e-26L
+ static_cast<lookup_t>(-3.6787944117144232159552377016146086745e-01L),
+ static_cast<lookup_t>(-2.7067056647322538378799898994496880682e-01L), static_cast<lookup_t>(-1.4936120510359182893802724695018532990e-01L), static_cast<lookup_t>(-7.3262555554936721174872085092964968848e-02L), static_cast<lookup_t>(-3.3689734995427335483180242115742121244e-02L),
+ static_cast<lookup_t>(-1.4872513059998150538271004584900007349e-02L), static_cast<lookup_t>(-6.3831737588816134560219525908649783853e-03L), static_cast<lookup_t>(-2.6837010232200947105711130062468881545e-03L), static_cast<lookup_t>(-1.1106882367801159454787302165703044346e-03L),
+ static_cast<lookup_t>(-4.5399929762484851535591515560550610238e-04L), static_cast<lookup_t>(-1.8371870869270225243899069096638966986e-04L), static_cast<lookup_t>(-7.3730548239938517104187698145666387735e-05L), static_cast<lookup_t>(-2.9384282290753706235208604777002963102e-05L),
+ static_cast<lookup_t>(-1.1641402067449950376895791995913672125e-05L), static_cast<lookup_t>(-4.5885348075273868255721924655343445906e-06L), static_cast<lookup_t>(-1.8005627955081458322204028649620350662e-06L), static_cast<lookup_t>(-7.0378941219347833214067471222239770590e-07L),
+ static_cast<lookup_t>(-2.7413963540482731185045932620331377352e-07L), static_cast<lookup_t>(-1.0645313231320808326024667350792279852e-07L), static_cast<lookup_t>(-4.1223072448771156559318807603116419528e-08L), static_cast<lookup_t>(-1.5923376898615004128677660806663065530e-08L),
+ static_cast<lookup_t>(-6.1368298043116345769816086674174450569e-09L), static_cast<lookup_t>(-2.3602323152914347699033314033408744848e-09L), static_cast<lookup_t>(-9.0603229062698346039479269140561762700e-10L), static_cast<lookup_t>(-3.4719859662410051486654409365217142276e-10L),
+ static_cast<lookup_t>(-1.3283631472964644271673440503045960993e-10L), static_cast<lookup_t>(-5.0747278046555248958473301297399200773e-11L), static_cast<lookup_t>(-1.9360320299432568426355237044475945959e-11L), static_cast<lookup_t>(-7.3766303773930764398798182830872768331e-12L),
+ static_cast<lookup_t>(-2.8072868906520523814747496670136120235e-12L), static_cast<lookup_t>(-1.0671679036256927021016406931839827582e-12L), static_cast<lookup_t>(-4.0525329757101362313986893299088308423e-13L), static_cast<lookup_t>(-1.5374324278841211301808010293913555758e-13L),
+ static_cast<lookup_t>(-5.8272886672428440854292491647585674200e-14L), static_cast<lookup_t>(-2.2067908660514462849736574172862899665e-14L), static_cast<lookup_t>(-8.3502821888768497979241489950570881481e-15L), static_cast<lookup_t>(-3.1572276215253043438828784344882603413e-15L),
+ static_cast<lookup_t>(-1.1928704609782512589094065678481294667e-15L), static_cast<lookup_t>(-4.5038074274761565346423524046963087756e-16L), static_cast<lookup_t>(-1.6993417021166355981316939131434632072e-16L), static_cast<lookup_t>(-6.4078169762734539491726202799339200356e-17L),
+ static_cast<lookup_t>(-2.4147993510032951187990399698408378385e-17L), static_cast<lookup_t>(-9.0950634616416460925150243301974013218e-18L), static_cast<lookup_t>(-3.4236981860988704669138593608831552044e-18L), static_cast<lookup_t>(-1.2881333612472271400115547331327717431e-18L),
+ static_cast<lookup_t>(-4.8440839844747536942311292467369300505e-19L), static_cast<lookup_t>(-1.8207788854829779430777944237164900798e-19L), static_cast<lookup_t>(-6.8407875971564885101695409345634890862e-20L), static_cast<lookup_t>(-2.5690139750480973292141845983878483991e-20L),
+ static_cast<lookup_t>(-9.6437492398195889150867140826350628738e-21L), static_cast<lookup_t>(-3.6186918227651991108814673877821174787e-21L), static_cast<lookup_t>(-1.3573451162272064984454015639725697008e-21L), static_cast<lookup_t>(-5.0894204288895982960223079251039701810e-22L),
+ static_cast<lookup_t>(-1.9076194289884357960571121174956927722e-22L), static_cast<lookup_t>(-7.1476978375412669048039237333931704166e-23L), static_cast<lookup_t>(-2.6773000149758626855152191436980592206e-23L), static_cast<lookup_t>(-1.0025115553818576399048488234179587012e-23L),
+ static_cast<lookup_t>(-3.7527362568743669891693429406973638384e-24L), static_cast<lookup_t>(-1.4043571811296963574776515073934728352e-24L), static_cast<lookup_t>(-5.2539064576179122030932396804434996219e-25L), static_cast<lookup_t>(-1.9650175744554348142907611432678556896e-25L),
+ static_cast<lookup_t>(-7.3474021582506822389671905824031421322e-26L), static_cast<lookup_t>(-2.7465543000397410133825686340097295749e-26L), static_cast<lookup_t>(-1.0264389699511282259046957018510946438e-26L)
}; // wm1zs
} // namespace lambert_w_lookup
} // namespace detail
diff --git a/third-party/boost-math/include/boost/math/special_functions/ellint_2.hpp b/third-party/boost-math/include/boost/math/special_functions/ellint_2.hpp
index 0cc1fa0944295..501d36b66bcbe 100644
--- a/third-party/boost-math/include/boost/math/special_functions/ellint_2.hpp
+++ b/third-party/boost-math/include/boost/math/special_functions/ellint_2.hpp
@@ -122,7 +122,7 @@ BOOST_MATH_GPU_ENABLED T ellint_e_imp(T phi, T k, const Policy& pol)
rphi = constants::half_pi<T>() - rphi;
}
T k2 = k * k;
- if(boost::math::pow<3>(rphi) * k2 / 6 < tools::epsilon<T>() * fabs(rphi))
+ if(boost::math::pow<3>(rphi) * k2 / 6 <= tools::epsilon<T>() * fabs(rphi))
{
// See http://functions.wolfram.com/EllipticIntegrals/EllipticE2/06/01/03/0001/
result = s * rphi;
diff --git a/third-party/boost-math/include/boost/math/special_functions/erf.hpp b/third-party/boost-math/include/boost/math/special_functions/erf.hpp
index c1d9061dbab26..dffb0c59cc5c2 100644
--- a/third-party/boost-math/include/boost/math/special_functions/erf.hpp
+++ b/third-party/boost-math/include/boost/math/special_functions/erf.hpp
@@ -153,7 +153,19 @@ T erf_imp(T z, bool invert, const Policy& pol, const Tag& t)
if ((boost::math::isnan)(z))
return policies::raise_domain_error("boost::math::erf<%1%>(%1%)", "Expected a finite argument but got %1%", z, pol);
- if(z < 0)
+ if (fabs(z) < tools::root_epsilon<T>())
+ {
+ // Series[Erf[x], {x, 0, 4}]
+ // Series[Erfc[x], {x, 0, 4}]
+
+ const T term2 { z * 2 / constants::root_pi<T>() };
+
+ return invert ? 1 - term2 : term2;
+ }
+
+ const bool signbit_result = ((boost::math::signbit)(z) != 0);
+
+ if (signbit_result)
{
if(!invert)
return -erf_imp(T(-z), invert, pol, t);
@@ -172,32 +184,32 @@ T erf_imp(T z, bool invert, const Policy& pol, const Tag& t)
}
else
{
- T x = z * z;
+ const T z_sq { z * z };
+
if(z < 1.3f)
{
// Compute P:
// This is actually good for z p to 2 or so, but the cutoff given seems
- // to be the best compromise. Performance wise, this is way quicker than anything else...
+ // to be the best compromise. Regarding performance, this is way quicker than anything else...
result = erf_series_near_zero_sum(z, pol);
}
- else if(x > 1 / tools::epsilon<T>())
+ else if(z_sq > 1 / tools::epsilon<T>())
{
// http://functions.wolfram.com/06.27.06.0006.02
invert = !invert;
- result = exp(-x) / (constants::root_pi<T>() * z);
+ result = exp(-z_sq) / (constants::root_pi<T>() * z);
}
else
{
// Compute Q:
invert = !invert;
- result = z * exp(-x);
+ result = z * exp(-z_sq);
result /= boost::math::constants::root_pi<T>();
- result *= upper_gamma_fraction(T(0.5f), x, policies::get_epsilon<T, Policy>());
+ result *= upper_gamma_fraction(T(0.5f), z_sq, policies::get_epsilon<T, Policy>());
}
}
- if(invert)
- result = 1 - result;
- return result;
+
+ return ((!invert) ? result : 1 - result);
}
// LCOV_EXCL_STOP
diff --git a/third-party/boost-math/include/boost/math/special_functions/gamma.hpp b/third-party/boost-math/include/boost/math/special_functions/gamma.hpp
index 47b4f3d68defe..a9c17da88239a 100644
--- a/third-party/boost-math/include/boost/math/special_functions/gamma.hpp
+++ b/third-party/boost-math/include/boost/math/special_functions/gamma.hpp
@@ -1290,7 +1290,6 @@ BOOST_MATH_GPU_ENABLED T incomplete_tgamma_large_x(const T& a, const T& x, const
return result;
}
-
//
// Main incomplete gamma entry point, handles all four incomplete gamma's:
//
@@ -1772,6 +1771,87 @@ BOOST_MATH_GPU_ENABLED T gamma_incomplete_imp(T a, T x, bool normalised, bool in
return gamma_incomplete_imp_final(T(a), T(x), normalised, invert, pol, p_derivative);
}
+// Calculate log of incomplete gamma function
+template <class T, class Policy>
+BOOST_MATH_GPU_ENABLED T lgamma_incomplete_imp(T a, T x, const Policy& pol)
+{
+ using namespace boost::math; // temporary until we're in the right namespace
+
+ BOOST_MATH_STD_USING_CORE
+
+ // Check for invalid inputs (a < 0 or x < 0)
+ constexpr auto function = "boost::math::lgamma_q<%1%>(%1%, %1%)";
+ if(a <= 0)
+ return policies::raise_domain_error<T>(function, "Argument a to the incomplete gamma function must be greater than zero (got a=%1%).", a, pol);
+ if(x < 0)
+ return policies::raise_domain_error<T>(function, "Argument x to the incomplete gamma function must be >= 0 (got x=%1%).", x, pol);
+
+ if (((x > 1000) || (x > tools::log_max_value<T>() - 10)) && (a + 50 < x))
+ {
+ //
+ // Take the logarithmic version of the asymtotic expansion:
+ //
+ return log(detail::incomplete_tgamma_large_x(a, x, pol)) + a * log(x) - x - lgamma(a, pol) - log(x);
+ }
+ //
+ // Can't do better than taking the log of Q, but...
+ //
+ // Figure out whether we need P or Q, since if we calculate Q and it's too close to unity
+ // we will lose precision in the result, selection logic here is extracted from gamma_incomplete_imp_final:
+ //
+ bool need_p = false;
+ if ((x < 0.5) && (T(-0.4) / log(x) < a))
+ need_p = true;
+ else if ((x < 1.1) && (x >= 0.5) && (x * 0.75f < a))
+ need_p = true;
+ else if ((x < a) && (x >= 1.1))
+ need_p = true;
+
+ if (need_p)
+ return log1p(-gamma_p(a, x, pol), pol);
+ return log(gamma_q(a, x, pol));
+}
+
+// Calculate log of incomplete gamma function
+template <class T, class Policy>
+BOOST_MATH_GPU_ENABLED T lgamma_incomplete_lower_imp(T a, T x, const Policy& pol)
+{
+ using namespace boost::math; // temporary until we're in the right namespace
+
+ BOOST_MATH_STD_USING_CORE
+
+ // Check for invalid inputs (a < 0 or x < 0)
+ constexpr auto function = "boost::math::lgamma_p<%1%>(%1%, %1%)";
+ if(a <= 0)
+ return policies::raise_domain_error<T>(function, "Argument a to the incomplete gamma function must be greater than zero (got a=%1%).", a, pol);
+ if(x < 0)
+ return policies::raise_domain_error<T>(function, "Argument x to the incomplete gamma function must be >= 0 (got x=%1%).", x, pol);
+
+ // Taken from conditions on Line 1709. There are also
+ // conditions on Line 1368, but didn't implement that one here.
+ // The second condition ensures floats do not return -inf for small
+ // values of x.
+ if (((a > 4 * x) && (a >= max_factorial<T>::value)) || ((T(-0.4) / log(x) < a) && (x < T(1.0)))){
+ return log(detail::lower_gamma_series(a, x, pol)) - log(a) + a * log(x) - x - lgamma(a, pol);
+ }
+
+ //
+ // Can't do better than taking the log of P, but...
+ //
+ // Figure out whether we need P or Q, since if we calculate P and it's too close to unity
+ // we will lose precision in the result, selection logic here is extracted from gamma_incomplete_imp_final:
+ //
+ bool need_p = false;
+ if ((x < 1.1) && (x >= 0.5) && (x * 0.75f < a))
+ need_p = true;
+ else if ((x < a) && (x >= 1.1))
+ need_p = true;
+
+ if (need_p)
+ return log(gamma_p(a, x, pol));
+ return log1p(-gamma_q(a, x, pol), pol);
+}
+
//
// Ratios of two gamma functions:
//
@@ -2390,6 +2470,52 @@ BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2>
{
return gamma_q(a, z, policies::policy<>());
}
+
+template <class T1, class T2, class Policy>
+BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2> lgamma_q(T1 a, T2 z, const Policy& /* pol */)
+{
+ typedef tools::promote_args_t<T1, T2> result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(
+ detail::lgamma_incomplete_imp(static_cast<value_type>(a),
+ static_cast<value_type>(z), forwarding_policy()), "lgamma_q<%1%>(%1%, %1%)");
+}
+
+template <class T1, class T2>
+BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2> lgamma_q(T1 a, T2 z)
+{
+ return lgamma_q(a, z, policies::policy<>());
+}
+
+template <class T1, class T2, class Policy>
+BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2> lgamma_p(T1 a, T2 z, const Policy& /* pol */)
+{
+ typedef tools::promote_args_t<T1, T2> result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(
+ detail::lgamma_incomplete_lower_imp(static_cast<value_type>(a),
+ static_cast<value_type>(z), forwarding_policy()), "lgamma_p<%1%>(%1%, %1%)");
+}
+
+template <class T1, class T2>
+BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2> lgamma_p(T1 a, T2 z)
+{
+ return lgamma_p(a, z, policies::policy<>());
+}
//
// Regularised lower incomplete gamma:
//
diff --git a/third-party/boost-math/include/boost/math/special_functions/hypergeometric_pFq.hpp b/third-party/boost-math/include/boost/math/special_functions/hypergeometric_pFq.hpp
index 070b852dd2f9f..96f68e510ea1e 100644
--- a/third-party/boost-math/include/boost/math/special_functions/hypergeometric_pFq.hpp
+++ b/third-party/boost-math/include/boost/math/special_functions/hypergeometric_pFq.hpp
@@ -58,12 +58,22 @@ namespace boost {
BOOST_MATH_STD_USING
long long scale = 0;
+ static const char* function = "boost::math::hypergeometric_pFq<%1%>(%1%,%1%,%1%)";
std::pair<value_type, value_type> r = boost::math::detail::hypergeometric_pFq_checked_series_impl(aj, bj, value_type(z), pol, boost::math::detail::iteration_terminator(boost::math::policies::get_max_series_iterations<forwarding_policy>()), scale);
- r.first *= exp(Real(scale));
- r.second *= exp(Real(scale));
+ //
+ // Overflow check:
+ //
+ if (static_cast<Real>(scale) > tools::log_max_value<Real>())
+ return (r.first < 0 ? -1 : 1) * policies::raise_overflow_error<Real, Policy>(function, nullptr, pol);
+ Real mul = exp(Real(scale));
+ if(fabs(r.first) > 1)
+ if(tools::max_value<Real>() / fabs(r.first) < mul)
+ return (r.first < 0 ? -1 : 1) * policies::raise_overflow_error<Real, Policy>(function, nullptr, pol);
+ r.first *= mul;
+ r.second *= mul;
if (p_abs_error)
*p_abs_error = static_cast<Real>(r.second) * boost::math::tools::epsilon<Real>();
- return policies::checked_narrowing_cast<result_type, Policy>(r.first, "boost::math::hypergeometric_pFq<%1%>(%1%,%1%,%1%)");
+ return policies::checked_narrowing_cast<result_type, Policy>(r.first, function);
}
template <class Seq, class Real>
diff --git a/third-party/boost-math/include/boost/math/special_functions/hypot.hpp b/third-party/boost-math/include/boost/math/special_functions/hypot.hpp
index f38e37e872b33..66a9492541293 100644
--- a/third-party/boost-math/include/boost/math/special_functions/hypot.hpp
+++ b/third-party/boost-math/include/boost/math/special_functions/hypot.hpp
@@ -16,6 +16,8 @@
#include <boost/math/tools/type_traits.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/math/tools/utility.hpp>
+#include <boost/math/tools/numeric_limits.hpp>
namespace boost{ namespace math{ namespace detail{
@@ -53,6 +55,48 @@ BOOST_MATH_GPU_ENABLED T hypot_imp(T x, T y, const Policy& pol)
return x * sqrt(1 + rat*rat);
} // template <class T> T hypot(T x, T y)
+template <class T, class Policy>
+BOOST_MATH_GPU_ENABLED T hypot_imp(T x, T y, T z, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+
+ x = fabs(x);
+ y = fabs(y);
+ z = fabs(z);
+
+ #ifdef _MSC_VER
+ #pragma warning(push)
+ #pragma warning(disable: 4127)
+ #endif
+ // special case, see C99 Annex F:
+ BOOST_MATH_IF_CONSTEXPR (boost::math::numeric_limits<T>::has_infinity)
+ {
+ if(((x == boost::math::numeric_limits<T>::infinity())
+ || (y == boost::math::numeric_limits<T>::infinity())
+ || (z == boost::math::numeric_limits<T>::infinity())))
+ return policies::raise_overflow_error<T>("boost::math::hypot<%1%>(%1%,%1%,%1%)", nullptr, pol);
+ }
+ #ifdef _MSC_VER
+ #pragma warning(pop)
+ #endif
+
+ const T a {(max)((max)(x, y), z)};
+
+ if (a == T(0))
+ {
+ return a;
+ }
+
+ const T x_div_a {x / a};
+ const T y_div_a {y / a};
+ const T z_div_a {z / a};
+
+ return a * sqrt(x_div_a * x_div_a
+ + y_div_a * y_div_a
+ + z_div_a * z_div_a);
+
+}
+
}
template <class T1, class T2>
@@ -64,7 +108,7 @@ BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T1, T2>::type
static_cast<result_type>(x), static_cast<result_type>(y), policies::policy<>());
}
-template <class T1, class T2, class Policy>
+template <class T1, class T2, class Policy, boost::math::enable_if_t<policies::is_policy_v<Policy>, bool>>
BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T1, T2>::type
hypot(T1 x, T2 y, const Policy& pol)
{
@@ -73,6 +117,28 @@ BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T1, T2>::type
static_cast<result_type>(x), static_cast<result_type>(y), pol);
}
+template <class T1, class T2, class T3, boost::math::enable_if_t<!policies::is_policy_v<T3>, bool>>
+BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2, T3>
+ hypot(T1 x, T2 y, T3 z)
+{
+ using result_type = tools::promote_args_t<T1, T2, T3>;
+ return detail::hypot_imp(static_cast<result_type>(x),
+ static_cast<result_type>(y),
+ static_cast<result_type>(z),
+ policies::policy<>());
+}
+
+template <class T1, class T2, class T3, class Policy>
+BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2, T3>
+ hypot(T1 x, T2 y, T3 z, const Policy& pol)
+{
+ using result_type = tools::promote_args_t<T1, T2, T3>;
+ return detail::hypot_imp(static_cast<result_type>(x),
+ static_cast<result_type>(y),
+ static_cast<result_type>(z),
+ pol);
+}
+
} // namespace math
} // namespace boost
diff --git a/third-party/boost-math/include/boost/math/special_functions/lanczos.hpp b/third-party/boost-math/include/boost/math/special_functions/lanczos.hpp
index 0ec24bddbf000..409e14c5e1210 100644
--- a/third-party/boost-math/include/boost/math/special_functions/lanczos.hpp
+++ b/third-party/boost-math/include/boost/math/special_functions/lanczos.hpp
@@ -2751,7 +2751,7 @@ struct lanczos
} // namespace math
} // namespace boost
-#if !defined(_CRAYC) && !defined(__CUDACC__) && (!defined(__GNUC__) || (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ > 3)))
+#if !defined(_CRAYC) && !defined(BOOST_MATH_ENABLE_CUDA) && (!defined(__GNUC__) || (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ > 3)))
#if ((defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64)) && !defined(_MANAGED) && !defined(BOOST_MATH_HAS_GPU_SUPPORT)
#include <boost/math/special_functions/detail/lanczos_sse2.hpp>
#endif
diff --git a/third-party/boost-math/include/boost/math/special_functions/logistic_sigmoid.hpp b/third-party/boost-math/include/boost/math/special_functions/logistic_sigmoid.hpp
new file mode 100644
index 0000000000000..7279b17e6c630
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/special_functions/logistic_sigmoid.hpp
@@ -0,0 +1,46 @@
+// Copyright Matt Borland 2025.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt
+// or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_SF_EXPIT_HPP
+#define BOOST_MATH_SF_EXPIT_HPP
+
+#include <boost/math/policies/policy.hpp>
+#include <boost/math/tools/precision.hpp>
+#include <cmath>
+
+namespace boost {
+namespace math {
+
+template <typename RealType, typename Policy>
+BOOST_MATH_GPU_ENABLED RealType logistic_sigmoid(RealType x, const Policy&)
+{
+ BOOST_MATH_STD_USING
+
+ using promoted_real_type = typename policies::evaluation<RealType, Policy>::type;
+
+ if(-x >= tools::log_max_value<RealType>())
+ {
+ return static_cast<RealType>(0);
+ }
+ if(-x <= -tools::log_max_value<RealType>())
+ {
+ return static_cast<RealType>(1);
+ }
+
+ const auto res {static_cast<RealType>(1 / (1 + exp(static_cast<promoted_real_type>(-x))))};
+ return res;
+}
+
+template <typename RealType>
+BOOST_MATH_GPU_ENABLED RealType logistic_sigmoid(RealType x)
+{
+ return logistic_sigmoid(x, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_SF_EXPIT_HPP
diff --git a/third-party/boost-math/include/boost/math/special_functions/logit.hpp b/third-party/boost-math/include/boost/math/special_functions/logit.hpp
new file mode 100644
index 0000000000000..e9da275e70b8e
--- /dev/null
+++ b/third-party/boost-math/include/boost/math/special_functions/logit.hpp
@@ -0,0 +1,56 @@
+// Copyright Matt Borland 2025.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt
+// or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_SF_LOGIT_HPP
+#define BOOST_MATH_SF_LOGIT_HPP
+
+#include <boost/math/tools/config.hpp>
+#include <boost/math/policies/policy.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <cmath>
+#include <cfenv>
+
+namespace boost {
+namespace math {
+
+template <typename RealType, typename Policy>
+BOOST_MATH_GPU_ENABLED RealType logit(RealType p, const Policy&)
+{
+ BOOST_MATH_STD_USING
+ using std::atanh;
+
+ using promoted_real_type = typename policies::evaluation<RealType, Policy>::type;
+
+ if (p < tools::min_value<RealType>())
+ {
+ return -policies::raise_overflow_error<RealType>("logit", "sub-normals will overflow ln(x/(1-x))", Policy());
+ }
+
+ static const RealType crossover {RealType{1}/4};
+ const auto promoted_p {static_cast<promoted_real_type>(p)};
+ RealType result {};
+ if (p > crossover)
+ {
+ result = static_cast<RealType>(2 * atanh(2 * promoted_p - 1));
+ }
+ else
+ {
+ result = static_cast<RealType>(log(promoted_p / (1 - promoted_p)));
+ }
+
+ return result;
+}
+
+template <typename RealType>
+BOOST_MATH_GPU_ENABLED RealType logit(RealType p)
+{
+ return logit(p, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_SF_LOGIT_HPP
diff --git a/third-party/boost-math/include/boost/math/special_functions/math_fwd.hpp b/third-party/boost-math/include/boost/math/special_functions/math_fwd.hpp
index 54f51c531a13e..6c8394ddf9ac1 100644
--- a/third-party/boost-math/include/boost/math/special_functions/math_fwd.hpp
+++ b/third-party/boost-math/include/boost/math/special_functions/math_fwd.hpp
@@ -561,6 +561,18 @@ namespace boost
template <class RT1, class RT2, class Policy>
BOOST_MATH_GPU_ENABLED tools::promote_args_t<RT1, RT2> gamma_q(RT1 a, RT2 z, const Policy&);
+ template <class RT1, class RT2>
+ BOOST_MATH_GPU_ENABLED tools::promote_args_t<RT1, RT2> lgamma_q(RT1 a, RT2 z);
+
+ template <class RT1, class RT2, class Policy>
+ BOOST_MATH_GPU_ENABLED tools::promote_args_t<RT1, RT2> lgamma_q(RT1 a, RT2 z, const Policy&);
+
+ template <class RT1, class RT2>
+ BOOST_MATH_GPU_ENABLED tools::promote_args_t<RT1, RT2> lgamma_p(RT1 a, RT2 z);
+
+ template <class RT1, class RT2, class Policy>
+ BOOST_MATH_GPU_ENABLED tools::promote_args_t<RT1, RT2> lgamma_p(RT1 a, RT2 z, const Policy&);
+
template <class RT1, class RT2>
BOOST_MATH_GPU_ENABLED tools::promote_args_t<RT1, RT2> gamma_p(RT1 a, RT2 z);
@@ -636,10 +648,18 @@ namespace boost
BOOST_MATH_GPU_ENABLED tools::promote_args_t<T1, T2>
hypot(T1 x, T2 y);
- template <class T1, class T2, class Policy>
+ template <class T1, class T2, class Policy, boost::math::enable_if_t<policies::is_policy_v<Policy>, bool> = true>
BOOST_MATH_GPU_ENABLED tools::promote_args_t<T1, T2>
hypot(T1 x, T2 y, const Policy&);
+ template <class T1, class T2, class T3, boost::math::enable_if_t<!policies::is_policy_v<T3>, bool> = true>
+ BOOST_MATH_GPU_ENABLED tools::promote_args_t<T1, T2, T3>
+ hypot(T1 x, T2 y, T3 z);
+
+ template <class T1, class T2, class T3, class Policy>
+ BOOST_MATH_GPU_ENABLED tools::promote_args_t<T1, T2, T3>
+ hypot(T1 x, T2 y, T3 z, const Policy& pol);
+
// cbrt - cube root.
template <class RT>
BOOST_MATH_GPU_ENABLED tools::promote_args_t<RT> cbrt(RT z);
@@ -1508,6 +1528,12 @@ namespace boost
\
template <class RT1, class RT2>\
BOOST_MATH_GPU_ENABLED inline boost::math::tools::promote_args_t<RT1, RT2> gamma_q(RT1 a, RT2 z){ return boost::math::gamma_q(a, z, Policy()); }\
+\
+ template <class RT1, class RT2>\
+ BOOST_MATH_GPU_ENABLED inline boost::math::tools::promote_args_t<RT1, RT2> lgamma_q(RT1 a, RT2 z){ return boost::math::lgamma_q(a, z, Policy()); }\
+\
+ template <class RT1, class RT2>\
+ BOOST_MATH_GPU_ENABLED inline boost::math::tools::promote_args_t<RT1, RT2> lgamma_p(RT1 a, RT2 z){ return boost::math::lgamma_p(a, z, Policy()); }\
\
template <class RT1, class RT2>\
BOOST_MATH_GPU_ENABLED inline boost::math::tools::promote_args_t<RT1, RT2> gamma_p(RT1 a, RT2 z){ return boost::math::gamma_p(a, z, Policy()); }\
diff --git a/third-party/boost-math/include/boost/math/special_functions/next.hpp b/third-party/boost-math/include/boost/math/special_functions/next.hpp
index 74c34f06ad8ca..f73cb2f6a5320 100644
--- a/third-party/boost-math/include/boost/math/special_functions/next.hpp
+++ b/third-party/boost-math/include/boost/math/special_functions/next.hpp
@@ -25,7 +25,7 @@
#include <cfloat>
-#if !defined(_CRAYC) && !defined(__CUDACC__) && (!defined(__GNUC__) || (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ > 3)))
+#if !defined(_CRAYC) && !defined(BOOST_MATH_ENABLE_CUDA) && (!defined(__GNUC__) || (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ > 3)))
#if (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || defined(__SSE2__)
#include "xmmintrin.h"
#define BOOST_MATH_CHECK_SSE2
diff --git a/third-party/boost-math/include/boost/math/special_functions/sign.hpp b/third-party/boost-math/include/boost/math/special_functions/sign.hpp
index 4f76522654fb5..5d2dfc2e23238 100644
--- a/third-party/boost-math/include/boost/math/special_functions/sign.hpp
+++ b/third-party/boost-math/include/boost/math/special_functions/sign.hpp
@@ -14,7 +14,7 @@
#pragma once
#endif
-#ifndef __CUDACC_RTC__
+#ifndef BOOST_MATH_HAS_NVRTC
#include <boost/math/tools/config.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
@@ -234,7 +234,7 @@ BOOST_MATH_GPU_ENABLED T sign(T z)
} // namespace math
} // namespace boost
-#endif // __CUDACC_RTC__
+#endif // BOOST_MATH_HAS_NVRTC
#endif // BOOST_MATH_TOOLS_SIGN_HPP
diff --git a/third-party/boost-math/include/boost/math/special_functions/sin_pi.hpp b/third-party/boost-math/include/boost/math/special_functions/sin_pi.hpp
index e59e232e6dd23..05a155434a897 100644
--- a/third-party/boost-math/include/boost/math/special_functions/sin_pi.hpp
+++ b/third-party/boost-math/include/boost/math/special_functions/sin_pi.hpp
@@ -94,7 +94,6 @@ inline typename tools::promote_args<T>::type sin_pi(T x)
{
return boost::math::sin_pi(x, policies::policy<>());
}
-
} // namespace math
} // namespace boost
diff --git a/third-party/boost-math/include/boost/math/tools/config.hpp b/third-party/boost-math/include/boost/math/tools/config.hpp
index 964a2bf0bbab6..40346c9b0fbd2 100644
--- a/third-party/boost-math/include/boost/math/tools/config.hpp
+++ b/third-party/boost-math/include/boost/math/tools/config.hpp
@@ -11,7 +11,7 @@
#pragma once
#endif
-#ifndef __CUDACC_RTC__
+#if !(defined(__CUDACC_RTC__) && defined(BOOST_MATH_ENABLE_NVRTC))
#include <boost/math/tools/is_standalone.hpp>
@@ -84,6 +84,10 @@
#else // Things from boost/config that are required, and easy to replicate
+#if __has_include(<version>)
+#include <version>
+#endif
+
#define BOOST_MATH_PREVENT_MACRO_SUBSTITUTION
#define BOOST_MATH_NO_REAL_CONCEPT_TESTS
#define BOOST_MATH_NO_DISTRIBUTION_CONCEPT_TESTS
@@ -102,9 +106,9 @@
#if ((__cplusplus > 201700L) || (defined(_MSVC_LANG) && (_MSVC_LANG > 201700L)))
#define BOOST_MATH_IF_CONSTEXPR if constexpr
-// Clang on mac provides the execution header with none of the functionality. TODO: Check back on this
+// libc++ currently provides the execution header with none of the functionality.
// https://en.cppreference.com/w/cpp/compiler_support "Standardization of Parallelism TS"
-# if !__has_include(<execution>) || (defined(__APPLE__) && defined(__clang__))
+# if !__has_include(<execution>) || !defined(__cpp_lib_execution) || (__cpp_lib_execution < 201603L)
# define BOOST_MATH_NO_CXX17_HDR_EXECUTION
# endif
#else
@@ -164,7 +168,7 @@
# define BOOST_MATH_NOINLINE __declspec(noinline)
# elif defined(__GNUC__) && __GNUC__ > 3
// Clang also defines __GNUC__ (as 4)
-# if defined(__CUDACC__)
+# if defined(__CUDACC__) && defined(BOOST_MATH_ENABLE_CUDA)
// nvcc doesn't always parse __noinline__,
// see: https://svn.boost.org/trac/boost/ticket/9392
# define BOOST_MATH_NOINLINE __attribute__ ((noinline))
@@ -674,7 +678,7 @@ namespace boost{ namespace math{
// CUDA support:
//
-#ifdef __CUDACC__
+#if defined(__CUDACC__) && defined(BOOST_MATH_ENABLE_CUDA)
// We have to get our include order correct otherwise you get compilation failures
#include <cuda.h>
@@ -702,15 +706,11 @@ namespace boost{ namespace math{
# undef BOOST_MATH_FORCEINLINE
# define BOOST_MATH_FORCEINLINE __forceinline__
-#elif defined(SYCL_LANGUAGE_VERSION)
+#elif defined(BOOST_MATH_ENABLE_SYCL)
# define BOOST_MATH_SYCL_ENABLED SYCL_EXTERNAL
# define BOOST_MATH_HAS_GPU_SUPPORT
-# ifndef BOOST_MATH_ENABLE_SYCL
-# define BOOST_MATH_ENABLE_SYCL
-# endif
-
# ifndef BOOST_MATH_NO_EXCEPTIONS
# define BOOST_MATH_NO_EXCEPTIONS
# endif
@@ -774,7 +774,7 @@ BOOST_MATH_GPU_ENABLED constexpr T gpu_safe_max(const T& a, const T& b) { return
# define BOOST_MATH_STATIC_LOCAL_VARIABLE
# else
# define BOOST_MATH_INLINE_CONSTEXPR constexpr
-# define BOOST_MATH_STATIC constexpr
+# define BOOST_MATH_STATIC static
# define BOOST_MATH_STATIC_LOCAL_VARIABLE static
# endif
#endif
diff --git a/third-party/boost-math/include/boost/math/tools/cubic_roots.hpp b/third-party/boost-math/include/boost/math/tools/cubic_roots.hpp
index 451c5de813368..1097ad5ce473c 100644
--- a/third-party/boost-math/include/boost/math/tools/cubic_roots.hpp
+++ b/third-party/boost-math/include/boost/math/tools/cubic_roots.hpp
@@ -6,11 +6,33 @@
#define BOOST_MATH_TOOLS_CUBIC_ROOTS_HPP
#include <algorithm>
#include <array>
+#include <boost/math/special_functions/fpclassify.hpp>
#include <boost/math/special_functions/sign.hpp>
#include <boost/math/tools/roots.hpp>
namespace boost::math::tools {
+namespace detail {
+
+// Orders finite roots ascending and moves NaN entries to the back.
+// Sorting NaNs is UB when using vanilla operator< (comparisons to NaN are always false),
+// so we need to provide our own sort function that pushes NaN to the end
+template <typename Real>
+bool roots_less(const Real& lhs, const Real& rhs)
+{
+ if ((boost::math::isnan)(lhs))
+ {
+ return false;
+ }
+ if ((boost::math::isnan)(rhs))
+ {
+ return true;
+ }
+ return lhs < rhs;
+}
+
+} // namespace detail
+
// Solves ax^3 + bx^2 + cx + d = 0.
// Only returns the real roots, as types get weird for real coefficients and
// complex roots. Follows Numerical Recipes, Chapter 5, section 6. NB: A better
@@ -55,7 +77,7 @@ std::array<Real, 3> cubic_roots(Real a, Real b, Real c, Real d) {
roots[0] = x0;
roots[1] = x1;
roots[2] = 0;
- std::sort(roots.begin(), roots.end());
+ std::sort(roots.begin(), roots.end(), detail::roots_less<Real>);
return roots;
}
Real p = b / a;
@@ -115,7 +137,7 @@ std::array<Real, 3> cubic_roots(Real a, Real b, Real c, Real d) {
}
}
}
- std::sort(roots.begin(), roots.end());
+ std::sort(roots.begin(), roots.end(), detail::roots_less<Real>);
return roots;
}
diff --git a/third-party/boost-math/include/boost/math/tools/rational.hpp b/third-party/boost-math/include/boost/math/tools/rational.hpp
index 1079463d08c10..95ec97e375178 100644
--- a/third-party/boost-math/include/boost/math/tools/rational.hpp
+++ b/third-party/boost-math/include/boost/math/tools/rational.hpp
@@ -178,7 +178,7 @@ BOOST_MATH_GPU_ENABLED U evaluate_polynomial(const T* poly, U const& z, boost::m
namespace detail{
template <class T, class V, class Tag>
-BOOST_MATH_GPU_ENABLED BOOST_MATH_GPU_ENABLED inline V evaluate_polynomial_c_imp(const T* a, const V& val, const Tag*) BOOST_MATH_NOEXCEPT(V)
+BOOST_MATH_GPU_ENABLED inline V evaluate_polynomial_c_imp(const T* a, const V& val, const Tag*) BOOST_MATH_NOEXCEPT(V)
{
return evaluate_polynomial(a, val, Tag::value);
}
@@ -207,7 +207,7 @@ BOOST_MATH_GPU_ENABLED inline U evaluate_polynomial(const T* poly, U const& z, b
// implementations above:
//
template <boost::math::size_t N, class T, class V>
-BOOST_MATH_GPU_ENABLED BOOST_MATH_GPU_ENABLED inline V evaluate_polynomial(const T(&a)[N], const V& val) BOOST_MATH_NOEXCEPT(V)
+BOOST_MATH_GPU_ENABLED inline V evaluate_polynomial(const T(&a)[N], const V& val) BOOST_MATH_NOEXCEPT(V)
{
typedef boost::math::integral_constant<int, static_cast<int>(N)> tag_type;
return detail::evaluate_polynomial_c_imp(static_cast<const T*>(a), val, static_cast<tag_type const*>(nullptr));
@@ -215,7 +215,7 @@ BOOST_MATH_GPU_ENABLED BOOST_MATH_GPU_ENABLED inline V evaluate_polynomial(const
#ifndef BOOST_MATH_HAS_NVRTC
template <boost::math::size_t N, class T, class V>
-BOOST_MATH_GPU_ENABLED BOOST_MATH_GPU_ENABLED inline V evaluate_polynomial(const std::array<T,N>& a, const V& val) BOOST_MATH_NOEXCEPT(V)
+BOOST_MATH_GPU_ENABLED inline V evaluate_polynomial(const std::array<T,N>& a, const V& val) BOOST_MATH_NOEXCEPT(V)
{
typedef boost::math::integral_constant<int, static_cast<int>(N)> tag_type;
return detail::evaluate_polynomial_c_imp(static_cast<const T*>(a.data()), val, static_cast<tag_type const*>(nullptr));
@@ -231,14 +231,14 @@ BOOST_MATH_GPU_ENABLED inline U evaluate_even_polynomial(const T* poly, U z, boo
}
template <boost::math::size_t N, class T, class V>
-BOOST_MATH_GPU_ENABLED BOOST_MATH_GPU_ENABLED inline V evaluate_even_polynomial(const T(&a)[N], const V& z) BOOST_MATH_NOEXCEPT(V)
+BOOST_MATH_GPU_ENABLED inline V evaluate_even_polynomial(const T(&a)[N], const V& z) BOOST_MATH_NOEXCEPT(V)
{
return evaluate_polynomial(a, V(z*z));
}
#ifndef BOOST_MATH_HAS_NVRTC
template <boost::math::size_t N, class T, class V>
-BOOST_MATH_GPU_ENABLED BOOST_MATH_GPU_ENABLED inline V evaluate_even_polynomial(const std::array<T,N>& a, const V& z) BOOST_MATH_NOEXCEPT(V)
+BOOST_MATH_GPU_ENABLED inline V evaluate_even_polynomial(const std::array<T,N>& a, const V& z) BOOST_MATH_NOEXCEPT(V)
{
return evaluate_polynomial(a, V(z*z));
}
@@ -253,7 +253,7 @@ BOOST_MATH_GPU_ENABLED inline U evaluate_odd_polynomial(const T* poly, U z, boos
}
template <boost::math::size_t N, class T, class V>
-BOOST_MATH_GPU_ENABLED BOOST_MATH_GPU_ENABLED inline V evaluate_odd_polynomial(const T(&a)[N], const V& z) BOOST_MATH_NOEXCEPT(V)
+BOOST_MATH_GPU_ENABLED inline V evaluate_odd_polynomial(const T(&a)[N], const V& z) BOOST_MATH_NOEXCEPT(V)
{
typedef boost::math::integral_constant<int, static_cast<int>(N-1)> tag_type;
return a[0] + z * detail::evaluate_polynomial_c_imp(static_cast<const T*>(a) + 1, V(z*z), static_cast<tag_type const*>(nullptr));
@@ -261,7 +261,7 @@ BOOST_MATH_GPU_ENABLED BOOST_MATH_GPU_ENABLED inline V evaluate_odd_polynomial(c
#ifndef BOOST_MATH_HAS_NVRTC
template <boost::math::size_t N, class T, class V>
-BOOST_MATH_GPU_ENABLED BOOST_MATH_GPU_ENABLED inline V evaluate_odd_polynomial(const std::array<T,N>& a, const V& z) BOOST_MATH_NOEXCEPT(V)
+BOOST_MATH_GPU_ENABLED inline V evaluate_odd_polynomial(const std::array<T,N>& a, const V& z) BOOST_MATH_NOEXCEPT(V)
{
typedef boost::math::integral_constant<int, static_cast<int>(N-1)> tag_type;
return a[0] + z * detail::evaluate_polynomial_c_imp(static_cast<const T*>(a.data()) + 1, V(z*z), static_cast<tag_type const*>(nullptr));
@@ -274,7 +274,7 @@ BOOST_MATH_GPU_ENABLED V evaluate_rational(const T* num, const U* denom, const V
namespace detail{
template <class T, class U, class V, class Tag>
-BOOST_MATH_GPU_ENABLED BOOST_MATH_GPU_ENABLED inline V evaluate_rational_c_imp(const T* num, const U* denom, const V& z, const Tag*) BOOST_MATH_NOEXCEPT(V)
+BOOST_MATH_GPU_ENABLED inline V evaluate_rational_c_imp(const T* num, const U* denom, const V& z, const Tag*) BOOST_MATH_NOEXCEPT(V)
{
return boost::math::tools::evaluate_rational(num, denom, z, Tag::value);
}
@@ -322,14 +322,14 @@ BOOST_MATH_GPU_ENABLED V evaluate_rational(const T* num, const U* denom, const V
}
template <boost::math::size_t N, class T, class U, class V>
-BOOST_MATH_GPU_ENABLED BOOST_MATH_GPU_ENABLED inline V evaluate_rational(const T(&a)[N], const U(&b)[N], const V& z) BOOST_MATH_NOEXCEPT(V)
+BOOST_MATH_GPU_ENABLED inline V evaluate_rational(const T(&a)[N], const U(&b)[N], const V& z) BOOST_MATH_NOEXCEPT(V)
{
return detail::evaluate_rational_c_imp(a, b, z, static_cast<const boost::math::integral_constant<int, static_cast<int>(N)>*>(nullptr));
}
#ifndef BOOST_MATH_HAS_NVRTC
template <boost::math::size_t N, class T, class U, class V>
-BOOST_MATH_GPU_ENABLED BOOST_MATH_GPU_ENABLED inline V evaluate_rational(const std::array<T,N>& a, const std::array<U,N>& b, const V& z) BOOST_MATH_NOEXCEPT(V)
+BOOST_MATH_GPU_ENABLED inline V evaluate_rational(const std::array<T,N>& a, const std::array<U,N>& b, const V& z) BOOST_MATH_NOEXCEPT(V)
{
return detail::evaluate_rational_c_imp(a.data(), b.data(), z, static_cast<boost::math::integral_constant<int, static_cast<int>(N)>*>(nullptr));
}
diff --git a/third-party/boost-math/include/boost/math/tools/roots.hpp b/third-party/boost-math/include/boost/math/tools/roots.hpp
index b0b0fc246cfc9..af9b76d998a80 100644
--- a/third-party/boost-math/include/boost/math/tools/roots.hpp
+++ b/third-party/boost-math/include/boost/math/tools/roots.hpp
@@ -456,8 +456,13 @@ namespace detail {
if (count)
{
max = guess;
+ //
+ // We can't have this extra recursive tidy up step on CUDA:
+ //
+#if !defined(BOOST_MATH_ENABLE_CUDA) && !defined(BOOST_MATH_ENABLE_SYCL)
if (multiplier > 16)
return (guess0 - guess) + bracket_root_towards_min(f, guess, f_current, min, max, count);
+#endif
}
return guess0 - (max + min) / 2;
}
@@ -520,8 +525,13 @@ namespace detail {
if (count)
{
min = guess;
+ //
+ // We can't have this extra recursive tidy up step on CUDA:
+ //
+#if !defined(BOOST_MATH_ENABLE_CUDA) && !defined(BOOST_MATH_ENABLE_SYCL)
if (multiplier > 16)
return (guess0 - guess) + bracket_root_towards_max(f, guess, f_current, min, max, count);
+#endif
}
return guess0 - (max + min) / 2;
}
diff --git a/third-party/boost-math/include/boost/math/tools/type_traits.hpp b/third-party/boost-math/include/boost/math/tools/type_traits.hpp
index a13332797bfda..951f3a1bf87b0 100644
--- a/third-party/boost-math/include/boost/math/tools/type_traits.hpp
+++ b/third-party/boost-math/include/boost/math/tools/type_traits.hpp
@@ -52,7 +52,6 @@ using cuda::std::is_member_pointer;
// Type properties
using cuda::std::is_const;
using cuda::std::is_volatile;
-using cuda::std::is_trivial;
using cuda::std::is_trivially_copyable;
using cuda::std::is_standard_layout;
using cuda::std::is_empty;
@@ -199,7 +198,6 @@ using std::is_member_pointer;
// Type properties
using std::is_const;
using std::is_volatile;
-using std::is_trivial;
using std::is_trivially_copyable;
using std::is_standard_layout;
using std::is_empty;
@@ -380,9 +378,6 @@ BOOST_MATH_INLINE_CONSTEXPR bool is_const_v = boost::math::is_const<T>::value;
template <typename T>
BOOST_MATH_INLINE_CONSTEXPR bool is_volatile_v = boost::math::is_volatile<T>::value;
-template <typename T>
-BOOST_MATH_INLINE_CONSTEXPR bool is_trivial_v = boost::math::is_trivial<T>::value;
-
template <typename T>
BOOST_MATH_INLINE_CONSTEXPR bool is_trivially_copyable_v = boost::math::is_trivially_copyable<T>::value;
More information about the llvm-commits
mailing list