From 0258fca25ed0ca20551390d8fbfa4275fefeec3e Mon Sep 17 00:00:00 2001 From: Steve Bronder Date: Wed, 5 Mar 2025 13:51:13 -0500 Subject: [PATCH 1/7] fixes signatures and rev for inv_logit --- stan/math/prim/fun/inv_logit.hpp | 36 +++++++++++++++++++------------- stan/math/rev/fun/inv_logit.hpp | 25 ++++++++++++++++++++++ 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/stan/math/prim/fun/inv_logit.hpp b/stan/math/prim/fun/inv_logit.hpp index efd69f53a34..0fc5a284e6e 100644 --- a/stan/math/prim/fun/inv_logit.hpp +++ b/stan/math/prim/fun/inv_logit.hpp @@ -49,15 +49,14 @@ namespace math { * @return Inverse logit of argument. */ inline double inv_logit(double a) { - using std::exp; if (a < 0) { - double exp_a = exp(a); + double exp_a = std::exp(a); if (a < LOG_EPSILON) { return exp_a; } - return exp_a / (1 + exp_a); + return exp_a / (1.0 + exp_a); } - return inv(1 + exp(-a)); + return inv(1 + std::exp(-a)); } /** @@ -74,22 +73,31 @@ struct inv_logit_fun { } }; + /** - * Vectorized version of inv_logit(). + * Vectorized version of inv_logit() for Eigen types with arithmetic value type. * - * @tparam T type of container - * @param x container + * @tparam T type of Eigen expression + * @param x Eigen expression * @return Inverse logit applied to each value in x. */ -template < - typename T, require_not_var_matrix_t* = nullptr, - require_all_not_nonscalar_prim_or_rev_kernel_expression_t* = nullptr> -inline auto inv_logit(const T& x) { - return apply_scalar_unary::apply(x); +template * = nullptr, + require_not_vt_var* = nullptr> +inline auto inv_logit(T&& x) { + return std::forward(x).array().logistic().matrix(); } -// TODO(Tadej): Eigen is introducing their implementation logistic() of this -// in 3.4. Use that once we switch to Eigen 3.4 +/** + * Vectorized version of inv_logit() for std::vector. + * + * @tparam T type of std::vector + * @param x std::vector + * @return Inverse logit applied to each value in x. + */ +template * = nullptr> +inline auto inv_logit(T&& x) { + return apply_scalar_unary>::apply(std::forward(x)); +} } // namespace math } // namespace stan diff --git a/stan/math/rev/fun/inv_logit.hpp b/stan/math/rev/fun/inv_logit.hpp index 086b5f45bc9..ffef93a0256 100644 --- a/stan/math/rev/fun/inv_logit.hpp +++ b/stan/math/rev/fun/inv_logit.hpp @@ -31,6 +31,31 @@ inline auto inv_logit(const var_value& a) { }); } +/** + * The inverse logit function for Eigen expressions with var value type. + * + * See inv_logit() for the double-based version. + * + * The derivative of inverse logit is + * + * \f$\frac{d}{dx} \mbox{logit}^{-1}(x) = \mbox{logit}^{-1}(x) (1 - + * \mbox{logit}^{-1}(x))\f$. + * + * @tparam T type of Eigen expression + * @param x Eigen expression + * @return Inverse logit of argument. + */ +template * = nullptr> +inline auto inv_logit(T&& x) { + auto x_arena = to_arena(std::forward(x)); + arena_t ret = inv_logit(x_arena.val()); + reverse_pass_callback([x_arena, ret]() mutable { + x_arena.adj().array() + += ret.adj().array() * ret.val().array() * (1.0 - ret.val().array()); + }); + return ret; +} + } // namespace math } // namespace stan #endif From 88eaa7c1e7727cbe49af54a607f9136045cedc8a Mon Sep 17 00:00:00 2001 From: Steve Bronder Date: Wed, 5 Mar 2025 13:54:20 -0500 Subject: [PATCH 2/7] docs --- stan/math/prim/fun/inv_logit.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stan/math/prim/fun/inv_logit.hpp b/stan/math/prim/fun/inv_logit.hpp index 0fc5a284e6e..3f3e22f2096 100644 --- a/stan/math/prim/fun/inv_logit.hpp +++ b/stan/math/prim/fun/inv_logit.hpp @@ -75,9 +75,9 @@ struct inv_logit_fun { /** - * Vectorized version of inv_logit() for Eigen types with arithmetic value type. + * Vectorized version of inv_logit() for Eigen types. * - * @tparam T type of Eigen expression + * @tparam T A type inheriting from `Eigen::DenseBase` that does not have a `var` scalar type. * @param x Eigen expression * @return Inverse logit applied to each value in x. */ From 5ec57f7af6421bfa20000fe4a63db0c11da0ab5c Mon Sep 17 00:00:00 2001 From: Stan Jenkins Date: Wed, 5 Mar 2025 14:01:40 -0500 Subject: [PATCH 3/7] [Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1 --- stan/math/prim/fun/inv_logit.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/stan/math/prim/fun/inv_logit.hpp b/stan/math/prim/fun/inv_logit.hpp index 3f3e22f2096..08b3e30c417 100644 --- a/stan/math/prim/fun/inv_logit.hpp +++ b/stan/math/prim/fun/inv_logit.hpp @@ -73,16 +73,16 @@ struct inv_logit_fun { } }; - /** * Vectorized version of inv_logit() for Eigen types. * - * @tparam T A type inheriting from `Eigen::DenseBase` that does not have a `var` scalar type. + * @tparam T A type inheriting from `Eigen::DenseBase` that does not have a + * `var` scalar type. * @param x Eigen expression * @return Inverse logit applied to each value in x. */ template * = nullptr, - require_not_vt_var* = nullptr> + require_not_vt_var* = nullptr> inline auto inv_logit(T&& x) { return std::forward(x).array().logistic().matrix(); } @@ -96,7 +96,8 @@ inline auto inv_logit(T&& x) { */ template * = nullptr> inline auto inv_logit(T&& x) { - return apply_scalar_unary>::apply(std::forward(x)); + return apply_scalar_unary>::apply( + std::forward(x)); } } // namespace math From 87bf54577e6bddc3eb2fafbc4533eab7d466af74 Mon Sep 17 00:00:00 2001 From: Steve Bronder Date: Fri, 7 Mar 2025 13:32:16 -0500 Subject: [PATCH 4/7] Allow Eigen to use the apply_scalar_unary framework --- stan/math/prim/fun/inv_logit.hpp | 39 ++++++++++--------- stan/math/prim/functor/apply_scalar_unary.hpp | 18 ++++----- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/stan/math/prim/fun/inv_logit.hpp b/stan/math/prim/fun/inv_logit.hpp index 08b3e30c417..51abe585f74 100644 --- a/stan/math/prim/fun/inv_logit.hpp +++ b/stan/math/prim/fun/inv_logit.hpp @@ -68,38 +68,41 @@ inline double inv_logit(double a) { */ struct inv_logit_fun { template - static inline auto fun(const T& x) { - return inv_logit(x); + static inline auto fun(T&& x) { + return inv_logit(std::forward(x)); } }; /** - * Vectorized version of inv_logit() for Eigen types. + * Vectorized version of inv_logit() for std::vector's containing ad types. * - * @tparam T A type inheriting from `Eigen::DenseBase` that does not have a - * `var` scalar type. - * @param x Eigen expression + * @tparam T type of std::vector + * @param x std::vector * @return Inverse logit applied to each value in x. */ -template * = nullptr, - require_not_vt_var* = nullptr> -inline auto inv_logit(T&& x) { - return std::forward(x).array().logistic().matrix(); +template * = nullptr, + require_all_not_nonscalar_prim_or_rev_kernel_expression_t* = nullptr, + require_not_rev_matrix_t* = nullptr> +inline auto inv_logit(Container&& x) { + return apply_scalar_unary::apply(std::forward(x)); } /** - * Vectorized version of inv_logit() for std::vector. + * Vectorized version of inv_logit() for Eigen types. * - * @tparam T type of std::vector - * @param x std::vector + * @tparam T A type of either `std::vector` whose inner type inherits from `Eigen::DenseBase` or a + * type that directly inherits from `Eigen::DenseBase`. The inner scalar type must not have a + * `var` scalar type. + * @param x Eigen expression * @return Inverse logit applied to each value in x. */ -template * = nullptr> -inline auto inv_logit(T&& x) { - return apply_scalar_unary>::apply( - std::forward(x)); +template * = nullptr, + require_all_not_nonscalar_prim_or_rev_kernel_expression_t* = nullptr> +inline auto inv_logit(Container&& x) { + return apply_vector_unary::apply( + std::forward(x), [](const auto& v) { return v.array().logistic(); }); } - } // namespace math } // namespace stan diff --git a/stan/math/prim/functor/apply_scalar_unary.hpp b/stan/math/prim/functor/apply_scalar_unary.hpp index e316d3033e5..30d085314c0 100644 --- a/stan/math/prim/functor/apply_scalar_unary.hpp +++ b/stan/math/prim/functor/apply_scalar_unary.hpp @@ -58,7 +58,7 @@ struct apply_scalar_unary> { * @return Componentwise application of the function specified * by F to the specified matrix. */ - static inline auto apply(const T& x) { + static inline auto apply(const std::decay_t& x) { return x.unaryExpr([](auto&& x) { return apply_scalar_unary>::apply(x); }); @@ -69,7 +69,7 @@ struct apply_scalar_unary> { * expression template of type T. */ using return_t = std::decay_t::apply(std::declval()))>; + apply_scalar_unary>::apply(std::declval()))>; }; /** @@ -83,7 +83,7 @@ struct apply_scalar_unary> { /** * The return type, double. */ - using return_t = std::decay_t()))>; + using return_t = std::decay_t>()))>; /** * Apply the function specified by F to the specified argument. @@ -114,11 +114,11 @@ struct apply_scalar_unary> { * @param x Argument scalar. * @return Result of applying F to the scalar. */ - static inline auto apply(const T& x) { return F::fun(x); } + static inline auto apply(const std::decay_t& x) { return F::fun(x); } /** * The return type */ - using return_t = std::decay_t()))>; + using return_t = std::decay_t>()))>; }; /** @@ -157,13 +157,13 @@ struct apply_scalar_unary> { * @tparam T Type of element contained in standard vector. */ template -struct apply_scalar_unary> { +struct apply_scalar_unary> { /** * Return type, which is calculated recursively as a standard * vector of the return type of the contained type T. */ using return_t = typename std::vector< - plain_type_t::return_t>>; + plain_type_t>>::return_t>>; /** * Apply the function specified by F elementwise to the @@ -174,10 +174,10 @@ struct apply_scalar_unary> { * @return Elementwise application of F to the elements of the * container. */ - static inline auto apply(const std::vector& x) { + static inline auto apply(const std::decay_t& x) { return_t fx(x.size()); for (size_t i = 0; i < x.size(); ++i) { - fx[i] = apply_scalar_unary::apply(x[i]); + fx[i] = apply_scalar_unary>::apply(x[i]); } return fx; } From 79a929a650b58d9f52447540769a77deea1cc1e8 Mon Sep 17 00:00:00 2001 From: Stan Jenkins Date: Fri, 7 Mar 2025 13:33:12 -0500 Subject: [PATCH 5/7] [Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1 --- stan/math/prim/fun/inv_logit.hpp | 20 +++++++++++-------- stan/math/prim/functor/apply_scalar_unary.hpp | 10 ++++++---- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/stan/math/prim/fun/inv_logit.hpp b/stan/math/prim/fun/inv_logit.hpp index 51abe585f74..f3186d8d6a1 100644 --- a/stan/math/prim/fun/inv_logit.hpp +++ b/stan/math/prim/fun/inv_logit.hpp @@ -81,27 +81,31 @@ struct inv_logit_fun { * @return Inverse logit applied to each value in x. */ template * = nullptr, - require_all_not_nonscalar_prim_or_rev_kernel_expression_t* = nullptr, - require_not_rev_matrix_t* = nullptr> + require_all_not_nonscalar_prim_or_rev_kernel_expression_t< + Container>* = nullptr, + require_not_rev_matrix_t* = nullptr> inline auto inv_logit(Container&& x) { - return apply_scalar_unary::apply(std::forward(x)); + return apply_scalar_unary::apply( + std::forward(x)); } /** * Vectorized version of inv_logit() for Eigen types. * - * @tparam T A type of either `std::vector` whose inner type inherits from `Eigen::DenseBase` or a - * type that directly inherits from `Eigen::DenseBase`. The inner scalar type must not have a - * `var` scalar type. + * @tparam T A type of either `std::vector` whose inner type inherits from + * `Eigen::DenseBase` or a type that directly inherits from `Eigen::DenseBase`. + * The inner scalar type must not have a `var` scalar type. * @param x Eigen expression * @return Inverse logit applied to each value in x. */ template * = nullptr, - require_all_not_nonscalar_prim_or_rev_kernel_expression_t* = nullptr> + require_all_not_nonscalar_prim_or_rev_kernel_expression_t< + Container>* = nullptr> inline auto inv_logit(Container&& x) { return apply_vector_unary::apply( - std::forward(x), [](const auto& v) { return v.array().logistic(); }); + std::forward(x), + [](const auto& v) { return v.array().logistic(); }); } } // namespace math } // namespace stan diff --git a/stan/math/prim/functor/apply_scalar_unary.hpp b/stan/math/prim/functor/apply_scalar_unary.hpp index 30d085314c0..2cbcae179aa 100644 --- a/stan/math/prim/functor/apply_scalar_unary.hpp +++ b/stan/math/prim/functor/apply_scalar_unary.hpp @@ -83,7 +83,8 @@ struct apply_scalar_unary> { /** * The return type, double. */ - using return_t = std::decay_t>()))>; + using return_t + = std::decay_t>()))>; /** * Apply the function specified by F to the specified argument. @@ -118,7 +119,8 @@ struct apply_scalar_unary> { /** * The return type */ - using return_t = std::decay_t>()))>; + using return_t + = std::decay_t>()))>; }; /** @@ -162,8 +164,8 @@ struct apply_scalar_unary> { * Return type, which is calculated recursively as a standard * vector of the return type of the contained type T. */ - using return_t = typename std::vector< - plain_type_t>>::return_t>>; + using return_t = typename std::vector>>::return_t>>; /** * Apply the function specified by F elementwise to the From d0921c8e64ef5f8075994cf1dc41bbc7dc6d65c6 Mon Sep 17 00:00:00 2001 From: Steve Bronder Date: Thu, 13 Mar 2025 16:52:23 -0400 Subject: [PATCH 6/7] update docs --- stan/math/prim/fun/inv_logit.hpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/stan/math/prim/fun/inv_logit.hpp b/stan/math/prim/fun/inv_logit.hpp index f3186d8d6a1..dc8a0d57f38 100644 --- a/stan/math/prim/fun/inv_logit.hpp +++ b/stan/math/prim/fun/inv_logit.hpp @@ -74,7 +74,7 @@ struct inv_logit_fun { }; /** - * Vectorized version of inv_logit() for std::vector's containing ad types. + * Vectorized version of inv_logit() for containers containing ad types. * * @tparam T type of std::vector * @param x std::vector @@ -90,11 +90,10 @@ inline auto inv_logit(Container&& x) { } /** - * Vectorized version of inv_logit() for Eigen types. + * Vectorized version of inv_logit() for containers with arithmetic scalar types. * - * @tparam T A type of either `std::vector` whose inner type inherits from - * `Eigen::DenseBase` or a type that directly inherits from `Eigen::DenseBase`. - * The inner scalar type must not have a `var` scalar type. + * @tparam T A type of either `std::vector` or a type that directly inherits from `Eigen::DenseBase`. + * The inner scalar type must not have an auto diff scalar type. * @param x Eigen expression * @return Inverse logit applied to each value in x. */ From b92cf295b3f8a00d50af5a8cc1c758213f3b1994 Mon Sep 17 00:00:00 2001 From: Stan Jenkins Date: Thu, 13 Mar 2025 16:53:23 -0400 Subject: [PATCH 7/7] [Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1 --- stan/math/prim/fun/inv_logit.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/stan/math/prim/fun/inv_logit.hpp b/stan/math/prim/fun/inv_logit.hpp index dc8a0d57f38..08f2a940a7f 100644 --- a/stan/math/prim/fun/inv_logit.hpp +++ b/stan/math/prim/fun/inv_logit.hpp @@ -90,10 +90,12 @@ inline auto inv_logit(Container&& x) { } /** - * Vectorized version of inv_logit() for containers with arithmetic scalar types. + * Vectorized version of inv_logit() for containers with arithmetic scalar + * types. * - * @tparam T A type of either `std::vector` or a type that directly inherits from `Eigen::DenseBase`. - * The inner scalar type must not have an auto diff scalar type. + * @tparam T A type of either `std::vector` or a type that directly inherits + * from `Eigen::DenseBase`. The inner scalar type must not have an auto diff + * scalar type. * @param x Eigen expression * @return Inverse logit applied to each value in x. */