From 7e00c1a4bfb39cab8186252a167abbf02808ad8a Mon Sep 17 00:00:00 2001 From: stevebronder Date: Wed, 9 Jun 2021 19:38:30 -0400 Subject: [PATCH 01/12] adds testing suite for nested binary var matrix functions --- stan/math/prim/fun/as_array_or_scalar.hpp | 20 +- stan/math/prim/fun/beta.hpp | 2 +- stan/math/rev/fun/bessel_first_kind.hpp | 4 + stan/math/rev/fun/binary_log_loss.hpp | 12 +- stan/math/rev/functor.hpp | 1 + stan/math/rev/functor/apply_scalar_binary.hpp | 250 ++++++++++++++++++ .../math/mix/fun/bessel_first_kind_test.cpp | 8 +- .../math/mix/fun/bessel_second_kind_test.cpp | 8 +- test/unit/math/mix/fun/beta_test.cpp | 13 + .../math/mix/fun/binary_log_loss_test.cpp | 14 +- .../math/mix/fun/falling_factorial_test.cpp | 6 +- test/unit/math/test_ad.hpp | 18 +- test/unit/math/test_ad_matvar.hpp | 183 ++++++++++++- 13 files changed, 507 insertions(+), 32 deletions(-) create mode 100644 stan/math/rev/functor/apply_scalar_binary.hpp diff --git a/stan/math/prim/fun/as_array_or_scalar.hpp b/stan/math/prim/fun/as_array_or_scalar.hpp index 8845c2432b2..e052ee07094 100644 --- a/stan/math/prim/fun/as_array_or_scalar.hpp +++ b/stan/math/prim/fun/as_array_or_scalar.hpp @@ -52,7 +52,8 @@ inline auto as_array_or_scalar(T&& v) { * @param v Specified vector. * @return Matrix converted to an array. */ -template * = nullptr> +template * = nullptr, +require_not_std_vector_t>* = nullptr> inline auto as_array_or_scalar(T&& v) { using T_map = Eigen::Map, Eigen::Dynamic, 1>>; @@ -60,6 +61,23 @@ inline auto as_array_or_scalar(T&& v) { std::forward(v)); } +/** + * Converts an std::vector to an Eigen Array. + * @tparam T A standard vector with inner container of a standard vector + * with an inner stan scalar. + * @param v specified vector of vectorised + * @return An Eigen Array with dynamic rows and columns. + */ +template * = nullptr, + require_std_vector_vt>* = nullptr> +inline auto as_array_or_scalar(T&& v) { + Eigen::Array, -1, -1> ret(v.size(), v[0].size()); + for (size_t i = 0; i < v.size(); ++i) { + ret.row(i) = Eigen::Map, 1, -1>>(v[i].data(), v[i].size()); + } + return ret; +} + } // namespace math } // namespace stan diff --git a/stan/math/prim/fun/beta.hpp b/stan/math/prim/fun/beta.hpp index da31af4bbb4..2ebc9cac2e4 100644 --- a/stan/math/prim/fun/beta.hpp +++ b/stan/math/prim/fun/beta.hpp @@ -69,7 +69,7 @@ template * = nullptr, require_all_not_var_matrix_t* = nullptr> inline auto beta(const T1& a, const T2& b) { return apply_scalar_binary( - a, b, [&](const auto& c, const auto& d) { return beta(c, d); }); + a, b, [](const auto& c, const auto& d) { return beta(c, d); }); } } // namespace math diff --git a/stan/math/rev/fun/bessel_first_kind.hpp b/stan/math/rev/fun/bessel_first_kind.hpp index f9abde37e3b..68bdcced999 100644 --- a/stan/math/rev/fun/bessel_first_kind.hpp +++ b/stan/math/rev/fun/bessel_first_kind.hpp @@ -18,6 +18,9 @@ inline var bessel_first_kind(int v, const var& a) { }); } +/** + * Overload with `var_value` for `int` and `std::vector` + */ template * = nullptr, require_eigen_t* = nullptr> inline auto bessel_first_kind(const T1& v, const var_value& a) { @@ -32,6 +35,7 @@ inline auto bessel_first_kind(const T1& v, const var_value& a) { }); } + } // namespace math } // namespace stan #endif diff --git a/stan/math/rev/fun/binary_log_loss.hpp b/stan/math/rev/fun/binary_log_loss.hpp index 116cca95105..f93d2fe960d 100644 --- a/stan/math/rev/fun/binary_log_loss.hpp +++ b/stan/math/rev/fun/binary_log_loss.hpp @@ -70,12 +70,13 @@ inline auto binary_log_loss(int y, const var_value& y_hat) { } } -template * = nullptr> -inline auto binary_log_loss(const std::vector& y, +/** + * Overload for std::vector and `var_value` + */ +template * = nullptr, require_st_integral* = nullptr> +inline auto binary_log_loss(const StdVec& y, const var_value& y_hat) { - arena_t> arena_y - = Eigen::Map>(y.data(), y.size()) - .cast(); + auto arena_y = to_arena(as_array_or_scalar(y).template cast()); auto ret_val = -(arena_y == 0) .select((-y_hat.val().array()).log1p(), y_hat.val().array().log()); @@ -87,6 +88,7 @@ inline auto binary_log_loss(const std::vector& y, }); } + } // namespace math } // namespace stan #endif diff --git a/stan/math/rev/functor.hpp b/stan/math/rev/functor.hpp index 4e36d2e7b14..f4c6923b43c 100644 --- a/stan/math/rev/functor.hpp +++ b/stan/math/rev/functor.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/rev/functor/apply_scalar_binary.hpp b/stan/math/rev/functor/apply_scalar_binary.hpp new file mode 100644 index 00000000000..d70ae1e1643 --- /dev/null +++ b/stan/math/rev/functor/apply_scalar_binary.hpp @@ -0,0 +1,250 @@ +#ifndef STAN_MATH_REV_FUNCTOR_APPLY_SCALAR_BINARY_HPP +#define STAN_MATH_REV_FUNCTOR_APPLY_SCALAR_BINARY_HPP + +#include +#include +#include +#include +#include +#include + +namespace stan { +namespace math { + + +/** + * Specialisation for use with two Eigen inputs. Eigen's binaryExpr framework + * is used for more efficient indexing of both row- and column-major inputs + * without separate loops. + * + * @tparam T1 Type of first argument to which functor is applied. + * @tparam T2 Type of second argument to which functor is applied. + * @tparam F Type of functor to apply. + * @param x First Eigen input to which operation is applied. + * @param y Second Eigen input to which operation is applied. + * @param f functor to apply to Eigen input. + * @return Eigen object with result of applying functor to inputs. + */ +template * = nullptr, + require_all_matrix_t* = nullptr> +inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { + check_matching_dims("Binary function", "x", x, "y", y); + return f(x, y); +} + +/** + * Specialisation for use with one Eigen vector (row or column) and + * a one-dimensional std::vector of integer types + * + * @tparam T1 Type of first argument to which functor is applied. + * @tparam T2 Type of second argument to which functor is applied. + * @tparam F Type of functor to apply. + * @param x Eigen input to which operation is applied. + * @param y Integer std::vector input to which operation is applied. + * @param f functor to apply to inputs. + * @return Eigen object with result of applying functor to inputs. + */ +template * = nullptr, + require_std_vector_vt* = nullptr> +inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { + check_matching_sizes("Binary function", "x", x, "y", y); + return f(x, y); +} + +/** + * Specialisation for use with a one-dimensional std::vector of integer types + * and one Eigen vector (row or column). + * + * @tparam T1 Type of first argument to which functor is applied. + * @tparam T2 Type of second argument to which functor is applied. + * @tparam F Type of functor to apply. + * @param x Integer std::vector input to which operation is applied. + * @param y Eigen input to which operation is applied. + * @param f functor to apply to inputs. + * @return Eigen object with result of applying functor to inputs. + */ +template * = nullptr, + require_var_matrix_t* = nullptr> +inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { + check_matching_sizes("Binary function", "x", x, "y", y); + return f(x, y); +} + +/** + * Specialisation for use with one Eigen matrix and + * a two-dimensional std::vector of integer types + * + * @tparam T1 Type of first argument to which functor is applied. + * @tparam T2 Type of second argument to which functor is applied. + * @tparam F Type of functor to apply. + * @param x Eigen matrix input to which operation is applied. + * @param y Nested integer std::vector input to which operation is applied. + * @param f functor to apply to inputs. + * @return Eigen object with result of applying functor to inputs. + */ +template * = nullptr, + require_std_vector_vt* = nullptr, + require_std_vector_st* = nullptr> +inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { + return f(x, y); +} + +/** + * Specialisation for use with a two-dimensional std::vector of integer types + * and one Eigen matrix. + * + * @tparam T1 Type of first argument to which functor is applied. + * @tparam T2 Type of second argument to which functor is applied. + * @tparam F Type of functor to apply. + * @param x Nested integer std::vector input to which operation is applied. + * @param y Eigen matrix input to which operation is applied. + * @param f functor to apply to inputs. + * @return Eigen object with result of applying functor to inputs. + */ +template * = nullptr, + require_std_vector_st* = nullptr, + require_var_matrix_t* = nullptr> +inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { + return f(x, y); +} + +/** + * Specialisation for use when the first input is an Eigen type and the second + * is a scalar. Eigen's unaryExpr framework is used for more efficient indexing + * of both row- and column-major inputs. The unaryExpr framework also allows + * for the scalar to be captured and applied to each element in the Eigen + * object. + * + * @tparam T1 Type of Eigen object to which functor is applied. + * @tparam T2 Type of scalar to which functor is applied. + * @tparam F Type of functor to apply. + * @param x Eigen input to which operation is applied. + * @param y Scalar input to which operation is applied. + * @param f functor to apply to Eigen and scalar inputs. + * @return Eigen object with result of applying functor to inputs. + * + * Note: The return expresssion needs to be evaluated, otherwise the captured + * function and scalar fall out of scope. + */ +template * = nullptr, + require_stan_scalar_t* = nullptr> +inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { + return f(x, y); +} + +/** + * Specialisation for use when the first input is an scalar and the second is + * an Eigen type. Eigen's unaryExpr framework is used for more efficient + * indexing of both row- and column-major inputs. The unaryExpr framework also + * allows for the scalar to be captured and applied to each element in the + * Eigen object. + * + * @tparam T1 Type of scalar to which functor is applied. + * @tparam T2 Type of Eigen object to which functor is applied. + * @tparam F Type of functor to apply. + * @param x Scalar input to which operation is applied. + * @param y Eigen input to which operation is applied. + * @param f functor to apply to Eigen and scalar inputs. + * @return Eigen object with result of applying functor to inputs. + * + * Note: The return expresssion needs to be evaluated, otherwise the captured + * function and scalar fall out of scope. + */ +template * = nullptr, require_var_matrix_t* = nullptr> +inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { + return f(x, y); +} + + +/** + * Specialisation for use when the first input is a nested std::vector and the + * second is a scalar. The returned scalar type is deduced to allow for cases + * where the input and return scalar types differ (e.g., functions implicitly + * promoting integers). + * + * @tparam T1 Type of std::vector to which functor is applied. + * @tparam T2 Type of scalar to which functor is applied. + * @tparam F Type of functor to apply. + * @param x std::vector input to which operation is applied. + * @param y Scalar input to which operation is applied. + * @param f functor to apply to inputs. + * @return std::vector with result of applying functor to inputs. + */ +template * = nullptr, + require_var_matrix_t>* = nullptr, + require_stan_scalar_t* = nullptr> +inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { + using T_return = plain_type_t; + size_t x_size = x.size(); + std::vector result(x_size); + for (size_t i = 0; i < x_size; ++i) { + result[i] = apply_scalar_binary(x[i], y, f); + } + return result; +} + +/** + * Specialisation for use when the first input is a scalar and the second is a + * nested std::vector. The returned scalar type is deduced to allow for cases + * where the input and return scalar types differ (e.g., functions implicitly + * promoting integers). + * + * @tparam T1 Type of scalar to which functor is applied. + * @tparam T2 Type of std::vector to which functor is applied. + * @tparam F Type of functor to apply. + * @param x Scalar input to which operation is applied. + * @param y std::vector input to which operation is applied. + * @param f functor to apply to inputs. + * @return std::vector with result of applying functor to inputs. + */ +template * = nullptr, + require_std_vector_t* = nullptr, + require_var_matrix_t>* = nullptr> +inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { + using T_return = plain_type_t; + size_t y_size = y.size(); + std::vector result(y_size); + for (size_t i = 0; i < y_size; ++i) { + result[i] = apply_scalar_binary(x, y[i], f); + } + return result; +} + +/** + * Specialisation for use with two nested containers (std::vectors). + * The returned scalar type is deduced to allow for cases where the input and + * return scalar types differ (e.g., functions implicitly promoting + * integers). + * + * @tparam T1 Type of first std::vector to which functor is applied. + * @tparam T2 Type of second std::vector to which functor is applied. + * @tparam F Type of functor to apply. + * @param x First std::vector input to which operation is applied. + * @param y Second std::vector input to which operation is applied. + * @param f functor to apply to std::vector inputs. + * @return std::vector with result of applying functor to inputs. + */ +template * =nullptr> +inline auto apply_scalar_binary(const std::vector& x, const std::vector& y, const F& f) { + check_matching_sizes("Binary function", "x", x, "y", y); + using T_return = plain_type_t; + size_t y_size = y.size(); + std::vector result(y_size); + for (size_t i = 0; i < y_size; ++i) { + result[i] = apply_scalar_binary(x[i], y[i], f); + } + return result; +} + +} // namespace math +} // namespace stan +#endif diff --git a/test/unit/math/mix/fun/bessel_first_kind_test.cpp b/test/unit/math/mix/fun/bessel_first_kind_test.cpp index a02df4cd333..4d81eaefec5 100644 --- a/test/unit/math/mix/fun/bessel_first_kind_test.cpp +++ b/test/unit/math/mix/fun/bessel_first_kind_test.cpp @@ -37,9 +37,7 @@ TEST(mathMixScalFun, besselFirstKind_matvec) { }; std::vector std_in1{3, 1}; - Eigen::VectorXd in2(2); - in2 << 0.5, 3.4; - stan::test::expect_ad_matvar(f, std_in1, in2); - - stan::test::expect_ad_matvar(f, std_in1[0], in2); + Eigen::MatrixXd in2(2, 2); + in2 << 0.5, 3.4, 0.5, 3.4; + stan::test::expect_ad_vectorized_matvar(f, std_in1, in2); } diff --git a/test/unit/math/mix/fun/bessel_second_kind_test.cpp b/test/unit/math/mix/fun/bessel_second_kind_test.cpp index eaf90a08fd3..6ff89f3db2f 100644 --- a/test/unit/math/mix/fun/bessel_second_kind_test.cpp +++ b/test/unit/math/mix/fun/bessel_second_kind_test.cpp @@ -38,8 +38,8 @@ TEST(mathMixScalFun, besselSecondKind_matvec) { }; std::vector std_in1{3, 1}; - Eigen::VectorXd in2(2); - in2 << 0.5, 3.4; - stan::test::expect_ad_matvar(f, std_in1, in2); - stan::test::expect_ad_matvar(f, std_in1[0], in2); + Eigen::MatrixXd in2(2, 2); + in2 << 0.5, 3.4, 0.5, 3.4; + stan::test::expect_ad_vectorized_matvar(f, std_in1, in2); + } diff --git a/test/unit/math/mix/fun/beta_test.cpp b/test/unit/math/mix/fun/beta_test.cpp index dad29034aa0..e7c80d91652 100644 --- a/test/unit/math/mix/fun/beta_test.cpp +++ b/test/unit/math/mix/fun/beta_test.cpp @@ -34,3 +34,16 @@ TEST(mathMixScalFun, beta_varmat) { stan::test::expect_ad_matvar(f, in1(0), in2); stan::test::expect_ad_matvar(f, in1, in2(0)); } + +TEST(mathMixScalFun, beta_varmat_vectorized) { + auto f = [](const auto& x1, const auto& x2) { + using stan::math::beta; + return beta(x1, x2); + }; + + Eigen::MatrixXd in1(2, 2); + in1 << 0.5, 3.4, 5.2, 0.5; + Eigen::MatrixXd in2(2, 2); + in2 << 3.3, 0.9, 6.7, 3.3; + stan::test::expect_ad_vectorized_matvar(f, in1, in2); +} diff --git a/test/unit/math/mix/fun/binary_log_loss_test.cpp b/test/unit/math/mix/fun/binary_log_loss_test.cpp index 78f115a888a..109cda944ab 100644 --- a/test/unit/math/mix/fun/binary_log_loss_test.cpp +++ b/test/unit/math/mix/fun/binary_log_loss_test.cpp @@ -29,7 +29,7 @@ TEST(mathMixScalFun, binaryLogLossvec) { stan::test::expect_ad_vectorized_binary(f, std_std_in1, mat_in2); } -TEST(mathMixScalFun, binaryLogLossmatvar) { +TEST(mathMixScalFun, binaryLogLossMatVar) { auto f = [](const auto& x1, const auto& x2) { using stan::math::binary_log_loss; return binary_log_loss(x1, x2); @@ -41,3 +41,15 @@ TEST(mathMixScalFun, binaryLogLossmatvar) { stan::test::expect_ad_matvar(f, std_in1, in2); stan::test::expect_ad_matvar(f, std_in1[0], in2); } + +TEST(mathMixScalFun, binaryLogLossMatVarVec) { + auto f = [](const auto& x1, const auto& x2) { + using stan::math::binary_log_loss; + return binary_log_loss(x1, x2); + }; + + std::vector std_in1{3, 1}; + Eigen::MatrixXd in2(2, 2); + in2 << 0.5, 3.4, 0.5, 3.5; + stan::test::expect_ad_vectorized_matvar(f, std_in1, in2); +} diff --git a/test/unit/math/mix/fun/falling_factorial_test.cpp b/test/unit/math/mix/fun/falling_factorial_test.cpp index 3772a4a9e6d..cda3d979620 100644 --- a/test/unit/math/mix/fun/falling_factorial_test.cpp +++ b/test/unit/math/mix/fun/falling_factorial_test.cpp @@ -43,9 +43,13 @@ TEST(mathMixScalFun, fallingFactorial_matvar) { return falling_factorial(x1, x2); }; + std::vector std_in2{3, 1}; Eigen::VectorXd in1(2); in1 << 0.5, 3.4; - std::vector std_in2{3, 1}; + Eigen::MatrixXd mat(2, 2); + mat << 0.5, 3.4, 0.5, 3.4; + stan::test::expect_ad_matvar(f, in1, std_in2); stan::test::expect_ad_matvar(f, in1, std_in2[0]); + stan::test::expect_ad_vectorized_matvar(f, mat, std_in2); } diff --git a/test/unit/math/test_ad.hpp b/test/unit/math/test_ad.hpp index a6dd3a1d0b5..e17e3427630 100644 --- a/test/unit/math/test_ad.hpp +++ b/test/unit/math/test_ad.hpp @@ -1306,15 +1306,15 @@ void expect_ad_vectorized_binary_impl(const ad_tolerances& tols, const F& f, std::vector nest_y{y, y}; std::vector> nest_nest_x{nest_x, nest_x}; std::vector> nest_nest_y{nest_y, nest_y}; - expect_ad(tols, f, x, y); - expect_ad(tols, f, x, y[0]); - expect_ad(tols, f, x[0], y); - expect_ad(tols, f, nest_x, nest_y); - expect_ad(tols, f, nest_x, y[0]); - expect_ad(tols, f, x[0], nest_y); - expect_ad(tols, f, nest_nest_x, nest_nest_y); - expect_ad(tols, f, nest_nest_x, y[0]); - expect_ad(tols, f, x[0], nest_nest_y); + expect_ad(tols, f, x, y); // mat, mat + expect_ad(tols, f, x, y[0]); // mat, scal + expect_ad(tols, f, x[0], y); // scal, mat + expect_ad(tols, f, nest_x, nest_y); // nest, nest + expect_ad(tols, f, nest_x, y[0]); // nest, scal + expect_ad(tols, f, x[0], nest_y); // scal, nest + expect_ad(tols, f, nest_nest_x, nest_nest_y); // nest>, nest> + expect_ad(tols, f, nest_nest_x, y[0]); // nest, scal + expect_ad(tols, f, x[0], nest_nest_y); // scal, nest } /** diff --git a/test/unit/math/test_ad_matvar.hpp b/test/unit/math/test_ad_matvar.hpp index 99add70c36b..602952c16bc 100644 --- a/test/unit/math/test_ad_matvar.hpp +++ b/test/unit/math/test_ad_matvar.hpp @@ -32,6 +32,7 @@ namespace test { * @param tols Tolerances for comparison */ template , value_type_t>* = nullptr, require_all_std_vector_st* = nullptr> void expect_near_rel_matvar(const std::string& message, T1&& x, T2&& y, const ad_tolerances& tols) { @@ -47,6 +48,20 @@ void expect_near_rel_matvar(const std::string& message, T1&& x, T2&& y, } } +template * = nullptr, + require_all_std_vector_st* = nullptr> +void expect_near_rel_matvar(const std::string& message, T1&& x, T2&& y, + const ad_tolerances& tols) { + stan::math::check_size_match("expect_near_rel_var", "x", x.size(), "y", + y.size()); + for (size_t i = 0; i < x.size(); ++i) { + expect_near_rel_matvar( + message + std::string(" elements at i = ") + std::to_string(i), + x[i], y[i], tols); + } +} + /** * Overload for non-`std::vector` arguments with scalar type `var` * @@ -307,8 +322,8 @@ auto make_matvar_compatible(const std::vector& x) { using vec_mat_var = std::vector>; vec_mat_var A_vec_mv; - for (auto xi : x) { - A_vec_mv.push_back(xi); + for (auto&& xi : x) { + A_vec_mv.push_back(make_matvar_compatible(xi)); } return A_vec_mv; } @@ -361,11 +376,22 @@ template * = nullptr, auto make_varmat_compatible(const std::vector& x) { using vec_var_mat = std::vector>>; vec_var_mat A_vec_vm; - for (auto xi : x) { - A_vec_vm.push_back(xi); + for (auto&& xi : x) { + A_vec_vm.push_back(make_varmat_compatible(xi)); + } + return A_vec_vm; +} +template * = nullptr, + require_st_arithmetic* = nullptr> +auto make_varmat_compatible(const std::vector>& x) { + using vec_var_mat = std::vector>>>; + vec_var_mat A_vec_vm; + for (auto&& xi : x) { + A_vec_vm.push_back(make_varmat_compatible(xi)); } return A_vec_vm; } + ///@} /** @@ -560,7 +586,7 @@ void expect_ad_matvar(const ad_tolerances& tols, const F& f, const EigMat1& x, using stan::math::var; using varmat = stan::math::var_value; - expect_ad_matvar_impl(tols, f, x, y); + expect_ad_matvar_impl, varmat>(tols, f, x, y); } template * = nullptr, require_all_not_st_integral* = nullptr> +void expect_ad_vectorized_matvar(const ad_tolerances& tols, const F& f, + const T1& x, const T2& y) { + auto x_scal = x.coeff(0, 0); + auto y_scal = y.coeff(0, 0); + auto x_vec = x.col(0).eval(); + auto y_vec = y.col(0).eval(); + auto x_rowvec = x.col(0).eval(); + auto y_rowvec = y.col(0).eval(); + + + std::vector> x_scal_stdvec {x_scal, x_scal}; + std::vector> y_scal_stdvec {y_scal, y_scal}; + std::vector>> x_scal_stdvec_stdvec {x_scal_stdvec, x_scal_stdvec}; + std::vector>> y_scal_stdvec_stdvec {x_scal_stdvec, x_scal_stdvec}; + std::vector x_mat_stdvec{x, x}; + std::vector y_mat_stdvec{y, y}; + std::vector> x_mat_stdvec_stdvec{x_mat_stdvec, x_mat_stdvec}; + std::vector> y_mat_stdvec_stdvec{y_mat_stdvec, y_mat_stdvec}; + expect_ad_matvar(tols, f, x_scal, y); // scal, mat + expect_ad_matvar(tols, f, x, y_scal); // mat, scal + expect_ad_matvar(tols, f, x, y); // mat, mat + expect_ad_matvar(tols, f, x_mat_stdvec, y_mat_stdvec); // nest, nest + expect_ad_matvar(tols, f, x_mat_stdvec, y_scal); // nest, scal + expect_ad_matvar(tols, f, x_scal, y_mat_stdvec); // scal, nest + expect_ad_matvar(tols, f, x_mat_stdvec_stdvec, y_mat_stdvec_stdvec); // nest>, nest> + expect_ad_matvar(tols, f, x_mat_stdvec_stdvec, y_scal); // nest, scal + expect_ad_matvar(tols, f, x_scal, y_mat_stdvec_stdvec); // scal, nest + + std::vector x_vec_stdvec{x_vec, x_vec}; + std::vector y_vec_stdvec{y_vec, y_vec}; + std::vector> x_vec_stdvec_stdvec{x_vec_stdvec, x_vec_stdvec}; + std::vector> y_vec_stdvec_stdvec{y_vec_stdvec, y_vec_stdvec}; + + expect_ad_matvar(tols, f, x_vec, y_scal); // vec, scal + expect_ad_matvar(tols, f, x_scal, y_vec); // scal, vec + expect_ad_matvar(tols, f, x_vec, y_vec); // vec, vec + expect_ad_matvar(tols, f, x_vec_stdvec, y_vec_stdvec); // nest, nest + expect_ad_matvar(tols, f, x_vec_stdvec, y_scal); // nest, scal + expect_ad_matvar(tols, f, x_scal, y_vec_stdvec); // scal, nest + expect_ad_matvar(tols, f, x_vec_stdvec_stdvec, y_vec_stdvec_stdvec); // nest>, nest> + expect_ad_matvar(tols, f, x_vec_stdvec_stdvec, y_scal); // nest, scal + expect_ad_matvar(tols, f, x_scal, y_vec_stdvec_stdvec); // scal, nest + + std::vector x_rowvec_stdvec{x_rowvec, x_rowvec}; + std::vector y_rowvec_stdvec{y_rowvec, y_rowvec}; + std::vector> x_rowvec_stdvec_stdvec{x_rowvec_stdvec, x_rowvec_stdvec}; + std::vector> y_rowvec_stdvec_stdvec{y_rowvec_stdvec, y_rowvec_stdvec}; + + expect_ad_matvar(tols, f, x_scal, y_rowvec); // scal, rowvec + expect_ad_matvar(tols, f, x_rowvec, y_scal); // rowvec, scal + expect_ad_matvar(tols, f, x_rowvec, y_rowvec); // rowvec, rowvec + expect_ad_matvar(tols, f, x_rowvec_stdvec, y_rowvec_stdvec); // nest, nest + expect_ad_matvar(tols, f, x_rowvec_stdvec, y_scal); // nest, scal + expect_ad_matvar(tols, f, x_scal, y_rowvec_stdvec); // scal, nest + expect_ad_matvar(tols, f, x_rowvec_stdvec_stdvec, y_rowvec_stdvec_stdvec); // nest>, nest> + expect_ad_matvar(tols, f, x_rowvec_stdvec_stdvec, y_scal); // nest, scal + expect_ad_matvar(tols, f, x_scal, y_rowvec_stdvec_stdvec); // scal, nest + +} + +/** + * Implementation function for testing that binary functions with vector inputs + * (both var_value and std::vector types) return the same first order + * derivative as if we were using Eigen inputs. + * + * @tparam F type of function + * @tparam T1 An Eigen matrix of floating point types + * @tparam T2 An std vector with inner integral type. + * @param f function to test + * @param x argument to test + * @param y argument to test + */ +template * = nullptr, + require_eigen_t* = nullptr> +void expect_ad_vectorized_matvar(const ad_tolerances& tols, const F& f, + const T1& x, const T2& y) { + auto x_scal = x[0]; + auto y_vec = y.col(0).eval(); + + std::vector x_stdvec{x, x}; + std::vector y_stdvec{y, y}; + std::vector y_stdvec_vec{y_vec, y_vec}; + std::vector> x_stdvec_stdvec{x_stdvec, x_stdvec}; + std::vector> y_stdvec_stdvec{y_stdvec, y_stdvec}; + expect_ad_matvar(tols, f, x[0], y); // scal, mat + expect_ad_matvar(tols, f, x[0], y_vec); // scal, mat + expect_ad_matvar(tols, f, x[0], y_stdvec); // scal, nest + expect_ad_matvar(tols, f, x, y_vec); // stdvec, vec + expect_ad_matvar(tols, f, x_stdvec, y_stdvec_vec); // nest, nest + expect_ad_matvar(tols, f, x_stdvec, y); // nest, mat + expect_ad_matvar(tols, f, x_stdvec_stdvec, y_stdvec); // nest>, nest +} + +/** + * Implementation function for testing that binary functions with vector inputs + * (both var_value and std::vector types) return the same first order + * derivative as if we were using Eigen inputs. + * + * This is a specialisation for use when the second input is an integer type. + * We reuse the code in the (std::vector, Eigen::Matrix) specialization + * by writing a lambda that flips the inputs passed to the original lambda. + * + * @tparam F type of function + * @tparam T1 An Eigen matrix of floating point types + * @tparam T2 An std vector with inner integral type. + * @param f function to test + * @param x argument to test + * @param y argument to test + */ +template * = nullptr, + require_std_vector_vt* = nullptr> +void expect_ad_vectorized_matvar(const ad_tolerances& tols, const F& f, + const T1& x, const T2& y) { + auto g = [&f](const auto& x, const auto& y) { + return f(y, x); + }; + expect_ad_vectorized_matvar(g, y, x); +} + + +/** + * Overload with default tolerances + * + * @tparam F Type of function to test + * @tparam EigVec Test input type + * @param tols Test tolerances + * @param f Function to test + * @param x Test input + */ +template +void expect_ad_vectorized_matvar(const F& f, const T1& x, const T2& y) { + ad_tolerances tols; + expect_ad_vectorized_matvar(tols, f, x, y); +} ///@} } // namespace test From f431f2ad30474ef13949e066713e306687af32f0 Mon Sep 17 00:00:00 2001 From: Stan Jenkins Date: Wed, 9 Jun 2021 23:48:02 +0000 Subject: [PATCH 02/12] [Jenkins] auto-formatting by clang-format version 6.0.0-1ubuntu2~16.04.1 (tags/RELEASE_600/final) --- stan/math/prim/fun/as_array_or_scalar.hpp | 7 +- stan/math/rev/fun/bessel_first_kind.hpp | 1 - stan/math/rev/fun/binary_log_loss.hpp | 7 +- stan/math/rev/functor/apply_scalar_binary.hpp | 13 +- .../math/mix/fun/bessel_second_kind_test.cpp | 1 - test/unit/math/test_ad.hpp | 19 +-- test/unit/math/test_ad_matvar.hpp | 151 ++++++++++-------- 7 files changed, 109 insertions(+), 90 deletions(-) diff --git a/stan/math/prim/fun/as_array_or_scalar.hpp b/stan/math/prim/fun/as_array_or_scalar.hpp index e052ee07094..6e91323d447 100644 --- a/stan/math/prim/fun/as_array_or_scalar.hpp +++ b/stan/math/prim/fun/as_array_or_scalar.hpp @@ -53,7 +53,7 @@ inline auto as_array_or_scalar(T&& v) { * @return Matrix converted to an array. */ template * = nullptr, -require_not_std_vector_t>* = nullptr> + require_not_std_vector_t>* = nullptr> inline auto as_array_or_scalar(T&& v) { using T_map = Eigen::Map, Eigen::Dynamic, 1>>; @@ -69,11 +69,12 @@ inline auto as_array_or_scalar(T&& v) { * @return An Eigen Array with dynamic rows and columns. */ template * = nullptr, - require_std_vector_vt>* = nullptr> + require_std_vector_vt>* = nullptr> inline auto as_array_or_scalar(T&& v) { Eigen::Array, -1, -1> ret(v.size(), v[0].size()); for (size_t i = 0; i < v.size(); ++i) { - ret.row(i) = Eigen::Map, 1, -1>>(v[i].data(), v[i].size()); + ret.row(i) = Eigen::Map, 1, -1>>( + v[i].data(), v[i].size()); } return ret; } diff --git a/stan/math/rev/fun/bessel_first_kind.hpp b/stan/math/rev/fun/bessel_first_kind.hpp index 68bdcced999..d85ffcd1534 100644 --- a/stan/math/rev/fun/bessel_first_kind.hpp +++ b/stan/math/rev/fun/bessel_first_kind.hpp @@ -35,7 +35,6 @@ inline auto bessel_first_kind(const T1& v, const var_value& a) { }); } - } // namespace math } // namespace stan #endif diff --git a/stan/math/rev/fun/binary_log_loss.hpp b/stan/math/rev/fun/binary_log_loss.hpp index f93d2fe960d..27920483433 100644 --- a/stan/math/rev/fun/binary_log_loss.hpp +++ b/stan/math/rev/fun/binary_log_loss.hpp @@ -73,9 +73,9 @@ inline auto binary_log_loss(int y, const var_value& y_hat) { /** * Overload for std::vector and `var_value` */ -template * = nullptr, require_st_integral* = nullptr> -inline auto binary_log_loss(const StdVec& y, - const var_value& y_hat) { +template * = nullptr, + require_st_integral* = nullptr> +inline auto binary_log_loss(const StdVec& y, const var_value& y_hat) { auto arena_y = to_arena(as_array_or_scalar(y).template cast()); auto ret_val = -(arena_y == 0) @@ -88,7 +88,6 @@ inline auto binary_log_loss(const StdVec& y, }); } - } // namespace math } // namespace stan #endif diff --git a/stan/math/rev/functor/apply_scalar_binary.hpp b/stan/math/rev/functor/apply_scalar_binary.hpp index d70ae1e1643..510f0157da7 100644 --- a/stan/math/rev/functor/apply_scalar_binary.hpp +++ b/stan/math/rev/functor/apply_scalar_binary.hpp @@ -11,7 +11,6 @@ namespace stan { namespace math { - /** * Specialisation for use with two Eigen inputs. Eigen's binaryExpr framework * is used for more efficient indexing of both row- and column-major inputs @@ -131,7 +130,8 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { * Note: The return expresssion needs to be evaluated, otherwise the captured * function and scalar fall out of scope. */ -template * = nullptr, +template * = nullptr, require_stan_scalar_t* = nullptr> inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { return f(x, y); @@ -156,12 +156,12 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { * function and scalar fall out of scope. */ template * = nullptr, require_var_matrix_t* = nullptr> + require_stan_scalar_t* = nullptr, + require_var_matrix_t* = nullptr> inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { return f(x, y); } - /** * Specialisation for use when the first input is a nested std::vector and the * second is a scalar. The returned scalar type is deduced to allow for cases @@ -233,8 +233,9 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { * @return std::vector with result of applying functor to inputs. */ template * =nullptr> -inline auto apply_scalar_binary(const std::vector& x, const std::vector& y, const F& f) { + require_any_var_matrix_t* = nullptr> +inline auto apply_scalar_binary(const std::vector& x, + const std::vector& y, const F& f) { check_matching_sizes("Binary function", "x", x, "y", y); using T_return = plain_type_t; size_t y_size = y.size(); diff --git a/test/unit/math/mix/fun/bessel_second_kind_test.cpp b/test/unit/math/mix/fun/bessel_second_kind_test.cpp index 6ff89f3db2f..20ac4eba54c 100644 --- a/test/unit/math/mix/fun/bessel_second_kind_test.cpp +++ b/test/unit/math/mix/fun/bessel_second_kind_test.cpp @@ -41,5 +41,4 @@ TEST(mathMixScalFun, besselSecondKind_matvec) { Eigen::MatrixXd in2(2, 2); in2 << 0.5, 3.4, 0.5, 3.4; stan::test::expect_ad_vectorized_matvar(f, std_in1, in2); - } diff --git a/test/unit/math/test_ad.hpp b/test/unit/math/test_ad.hpp index e17e3427630..eb4b474d93f 100644 --- a/test/unit/math/test_ad.hpp +++ b/test/unit/math/test_ad.hpp @@ -1306,15 +1306,16 @@ void expect_ad_vectorized_binary_impl(const ad_tolerances& tols, const F& f, std::vector nest_y{y, y}; std::vector> nest_nest_x{nest_x, nest_x}; std::vector> nest_nest_y{nest_y, nest_y}; - expect_ad(tols, f, x, y); // mat, mat - expect_ad(tols, f, x, y[0]); // mat, scal - expect_ad(tols, f, x[0], y); // scal, mat - expect_ad(tols, f, nest_x, nest_y); // nest, nest - expect_ad(tols, f, nest_x, y[0]); // nest, scal - expect_ad(tols, f, x[0], nest_y); // scal, nest - expect_ad(tols, f, nest_nest_x, nest_nest_y); // nest>, nest> - expect_ad(tols, f, nest_nest_x, y[0]); // nest, scal - expect_ad(tols, f, x[0], nest_nest_y); // scal, nest + expect_ad(tols, f, x, y); // mat, mat + expect_ad(tols, f, x, y[0]); // mat, scal + expect_ad(tols, f, x[0], y); // scal, mat + expect_ad(tols, f, nest_x, nest_y); // nest, nest + expect_ad(tols, f, nest_x, y[0]); // nest, scal + expect_ad(tols, f, x[0], nest_y); // scal, nest + expect_ad(tols, f, nest_nest_x, + nest_nest_y); // nest>, nest> + expect_ad(tols, f, nest_nest_x, y[0]); // nest, scal + expect_ad(tols, f, x[0], nest_nest_y); // scal, nest } /** diff --git a/test/unit/math/test_ad_matvar.hpp b/test/unit/math/test_ad_matvar.hpp index 602952c16bc..6b6304db0d4 100644 --- a/test/unit/math/test_ad_matvar.hpp +++ b/test/unit/math/test_ad_matvar.hpp @@ -31,9 +31,10 @@ namespace test { * @param y Second argument to compare * @param tols Tolerances for comparison */ -template , value_type_t>* = nullptr, - require_all_std_vector_st* = nullptr> +template < + typename T1, typename T2, + require_all_not_std_vector_t, value_type_t>* = nullptr, + require_all_std_vector_st* = nullptr> void expect_near_rel_matvar(const std::string& message, T1&& x, T2&& y, const ad_tolerances& tols) { stan::math::check_size_match("expect_near_rel_var", "x", x.size(), "y", @@ -49,7 +50,7 @@ void expect_near_rel_matvar(const std::string& message, T1&& x, T2&& y, } template * = nullptr, + require_all_std_vector_vt* = nullptr, require_all_std_vector_st* = nullptr> void expect_near_rel_matvar(const std::string& message, T1&& x, T2&& y, const ad_tolerances& tols) { @@ -57,8 +58,8 @@ void expect_near_rel_matvar(const std::string& message, T1&& x, T2&& y, y.size()); for (size_t i = 0; i < x.size(); ++i) { expect_near_rel_matvar( - message + std::string(" elements at i = ") + std::to_string(i), - x[i], y[i], tols); + message + std::string(" elements at i = ") + std::to_string(i), x[i], + y[i], tols); } } @@ -384,7 +385,8 @@ auto make_varmat_compatible(const std::vector& x) { template * = nullptr, require_st_arithmetic* = nullptr> auto make_varmat_compatible(const std::vector>& x) { - using vec_var_mat = std::vector>>>; + using vec_var_mat + = std::vector>>>; vec_var_mat A_vec_vm; for (auto&& xi : x) { A_vec_vm.push_back(make_varmat_compatible(xi)); @@ -860,9 +862,11 @@ void expect_ad_vector_matvar(const F& f, const EigVec& x) { * @param f Function to test * @param x Test input */ -template * = nullptr, require_all_not_st_integral* = nullptr> +template * = nullptr, + require_all_not_st_integral* = nullptr> void expect_ad_vectorized_matvar(const ad_tolerances& tols, const F& f, - const T1& x, const T2& y) { + const T1& x, const T2& y) { auto x_scal = x.coeff(0, 0); auto y_scal = y.coeff(0, 0); auto x_vec = x.col(0).eval(); @@ -870,55 +874,73 @@ void expect_ad_vectorized_matvar(const ad_tolerances& tols, const F& f, auto x_rowvec = x.col(0).eval(); auto y_rowvec = y.col(0).eval(); - - std::vector> x_scal_stdvec {x_scal, x_scal}; - std::vector> y_scal_stdvec {y_scal, y_scal}; - std::vector>> x_scal_stdvec_stdvec {x_scal_stdvec, x_scal_stdvec}; - std::vector>> y_scal_stdvec_stdvec {x_scal_stdvec, x_scal_stdvec}; + std::vector> x_scal_stdvec{x_scal, x_scal}; + std::vector> y_scal_stdvec{y_scal, y_scal}; + std::vector>> x_scal_stdvec_stdvec{ + x_scal_stdvec, x_scal_stdvec}; + std::vector>> y_scal_stdvec_stdvec{ + x_scal_stdvec, x_scal_stdvec}; std::vector x_mat_stdvec{x, x}; std::vector y_mat_stdvec{y, y}; - std::vector> x_mat_stdvec_stdvec{x_mat_stdvec, x_mat_stdvec}; - std::vector> y_mat_stdvec_stdvec{y_mat_stdvec, y_mat_stdvec}; - expect_ad_matvar(tols, f, x_scal, y); // scal, mat - expect_ad_matvar(tols, f, x, y_scal); // mat, scal - expect_ad_matvar(tols, f, x, y); // mat, mat - expect_ad_matvar(tols, f, x_mat_stdvec, y_mat_stdvec); // nest, nest - expect_ad_matvar(tols, f, x_mat_stdvec, y_scal); // nest, scal - expect_ad_matvar(tols, f, x_scal, y_mat_stdvec); // scal, nest - expect_ad_matvar(tols, f, x_mat_stdvec_stdvec, y_mat_stdvec_stdvec); // nest>, nest> - expect_ad_matvar(tols, f, x_mat_stdvec_stdvec, y_scal); // nest, scal - expect_ad_matvar(tols, f, x_scal, y_mat_stdvec_stdvec); // scal, nest + std::vector> x_mat_stdvec_stdvec{x_mat_stdvec, + x_mat_stdvec}; + std::vector> y_mat_stdvec_stdvec{y_mat_stdvec, + y_mat_stdvec}; + expect_ad_matvar(tols, f, x_scal, y); // scal, mat + expect_ad_matvar(tols, f, x, y_scal); // mat, scal + expect_ad_matvar(tols, f, x, y); // mat, mat + expect_ad_matvar(tols, f, x_mat_stdvec, + y_mat_stdvec); // nest, nest + expect_ad_matvar(tols, f, x_mat_stdvec, y_scal); // nest, scal + expect_ad_matvar(tols, f, x_scal, y_mat_stdvec); // scal, nest + expect_ad_matvar(tols, f, x_mat_stdvec_stdvec, + y_mat_stdvec_stdvec); // nest>, nest> + expect_ad_matvar(tols, f, x_mat_stdvec_stdvec, + y_scal); // nest, scal + expect_ad_matvar(tols, f, x_scal, + y_mat_stdvec_stdvec); // scal, nest std::vector x_vec_stdvec{x_vec, x_vec}; std::vector y_vec_stdvec{y_vec, y_vec}; - std::vector> x_vec_stdvec_stdvec{x_vec_stdvec, x_vec_stdvec}; - std::vector> y_vec_stdvec_stdvec{y_vec_stdvec, y_vec_stdvec}; - - expect_ad_matvar(tols, f, x_vec, y_scal); // vec, scal - expect_ad_matvar(tols, f, x_scal, y_vec); // scal, vec - expect_ad_matvar(tols, f, x_vec, y_vec); // vec, vec - expect_ad_matvar(tols, f, x_vec_stdvec, y_vec_stdvec); // nest, nest - expect_ad_matvar(tols, f, x_vec_stdvec, y_scal); // nest, scal - expect_ad_matvar(tols, f, x_scal, y_vec_stdvec); // scal, nest - expect_ad_matvar(tols, f, x_vec_stdvec_stdvec, y_vec_stdvec_stdvec); // nest>, nest> - expect_ad_matvar(tols, f, x_vec_stdvec_stdvec, y_scal); // nest, scal - expect_ad_matvar(tols, f, x_scal, y_vec_stdvec_stdvec); // scal, nest + std::vector> x_vec_stdvec_stdvec{x_vec_stdvec, + x_vec_stdvec}; + std::vector> y_vec_stdvec_stdvec{y_vec_stdvec, + y_vec_stdvec}; + + expect_ad_matvar(tols, f, x_vec, y_scal); // vec, scal + expect_ad_matvar(tols, f, x_scal, y_vec); // scal, vec + expect_ad_matvar(tols, f, x_vec, y_vec); // vec, vec + expect_ad_matvar(tols, f, x_vec_stdvec, + y_vec_stdvec); // nest, nest + expect_ad_matvar(tols, f, x_vec_stdvec, y_scal); // nest, scal + expect_ad_matvar(tols, f, x_scal, y_vec_stdvec); // scal, nest + expect_ad_matvar(tols, f, x_vec_stdvec_stdvec, + y_vec_stdvec_stdvec); // nest>, nest> + expect_ad_matvar(tols, f, x_vec_stdvec_stdvec, + y_scal); // nest, scal + expect_ad_matvar(tols, f, x_scal, + y_vec_stdvec_stdvec); // scal, nest std::vector x_rowvec_stdvec{x_rowvec, x_rowvec}; std::vector y_rowvec_stdvec{y_rowvec, y_rowvec}; - std::vector> x_rowvec_stdvec_stdvec{x_rowvec_stdvec, x_rowvec_stdvec}; - std::vector> y_rowvec_stdvec_stdvec{y_rowvec_stdvec, y_rowvec_stdvec}; - - expect_ad_matvar(tols, f, x_scal, y_rowvec); // scal, rowvec - expect_ad_matvar(tols, f, x_rowvec, y_scal); // rowvec, scal - expect_ad_matvar(tols, f, x_rowvec, y_rowvec); // rowvec, rowvec - expect_ad_matvar(tols, f, x_rowvec_stdvec, y_rowvec_stdvec); // nest, nest - expect_ad_matvar(tols, f, x_rowvec_stdvec, y_scal); // nest, scal - expect_ad_matvar(tols, f, x_scal, y_rowvec_stdvec); // scal, nest - expect_ad_matvar(tols, f, x_rowvec_stdvec_stdvec, y_rowvec_stdvec_stdvec); // nest>, nest> - expect_ad_matvar(tols, f, x_rowvec_stdvec_stdvec, y_scal); // nest, scal - expect_ad_matvar(tols, f, x_scal, y_rowvec_stdvec_stdvec); // scal, nest - + std::vector> x_rowvec_stdvec_stdvec{ + x_rowvec_stdvec, x_rowvec_stdvec}; + std::vector> y_rowvec_stdvec_stdvec{ + y_rowvec_stdvec, y_rowvec_stdvec}; + + expect_ad_matvar(tols, f, x_scal, y_rowvec); // scal, rowvec + expect_ad_matvar(tols, f, x_rowvec, y_scal); // rowvec, scal + expect_ad_matvar(tols, f, x_rowvec, y_rowvec); // rowvec, rowvec + expect_ad_matvar(tols, f, x_rowvec_stdvec, + y_rowvec_stdvec); // nest, nest + expect_ad_matvar(tols, f, x_rowvec_stdvec, y_scal); // nest, scal + expect_ad_matvar(tols, f, x_scal, y_rowvec_stdvec); // scal, nest + expect_ad_matvar(tols, f, x_rowvec_stdvec_stdvec, + y_rowvec_stdvec_stdvec); // nest>, nest> + expect_ad_matvar(tols, f, x_rowvec_stdvec_stdvec, + y_scal); // nest, scal + expect_ad_matvar(tols, f, x_scal, + y_rowvec_stdvec_stdvec); // scal, nest } /** @@ -937,7 +959,7 @@ template * = nullptr, require_eigen_t* = nullptr> void expect_ad_vectorized_matvar(const ad_tolerances& tols, const F& f, - const T1& x, const T2& y) { + const T1& x, const T2& y) { auto x_scal = x[0]; auto y_vec = y.col(0).eval(); @@ -946,13 +968,14 @@ void expect_ad_vectorized_matvar(const ad_tolerances& tols, const F& f, std::vector y_stdvec_vec{y_vec, y_vec}; std::vector> x_stdvec_stdvec{x_stdvec, x_stdvec}; std::vector> y_stdvec_stdvec{y_stdvec, y_stdvec}; - expect_ad_matvar(tols, f, x[0], y); // scal, mat - expect_ad_matvar(tols, f, x[0], y_vec); // scal, mat - expect_ad_matvar(tols, f, x[0], y_stdvec); // scal, nest - expect_ad_matvar(tols, f, x, y_vec); // stdvec, vec - expect_ad_matvar(tols, f, x_stdvec, y_stdvec_vec); // nest, nest - expect_ad_matvar(tols, f, x_stdvec, y); // nest, mat - expect_ad_matvar(tols, f, x_stdvec_stdvec, y_stdvec); // nest>, nest + expect_ad_matvar(tols, f, x[0], y); // scal, mat + expect_ad_matvar(tols, f, x[0], y_vec); // scal, mat + expect_ad_matvar(tols, f, x[0], y_stdvec); // scal, nest + expect_ad_matvar(tols, f, x, y_vec); // stdvec, vec + expect_ad_matvar(tols, f, x_stdvec, y_stdvec_vec); // nest, nest + expect_ad_matvar(tols, f, x_stdvec, y); // nest, mat + expect_ad_matvar(tols, f, x_stdvec_stdvec, + y_stdvec); // nest>, nest } /** @@ -971,18 +994,14 @@ void expect_ad_vectorized_matvar(const ad_tolerances& tols, const F& f, * @param x argument to test * @param y argument to test */ -template * = nullptr, +template * = nullptr, require_std_vector_vt* = nullptr> void expect_ad_vectorized_matvar(const ad_tolerances& tols, const F& f, - const T1& x, const T2& y) { - auto g = [&f](const auto& x, const auto& y) { - return f(y, x); - }; - expect_ad_vectorized_matvar(g, y, x); + const T1& x, const T2& y) { + auto g = [&f](const auto& x, const auto& y) { return f(y, x); }; + expect_ad_vectorized_matvar(g, y, x); } - /** * Overload with default tolerances * From 86a783a640dc000d2c94a7a1b681e522caaaa2d2 Mon Sep 17 00:00:00 2001 From: stevebronder Date: Wed, 9 Jun 2021 20:18:46 -0400 Subject: [PATCH 03/12] fix docs and breakup beta tests for windows --- stan/math/rev/fun/bessel_first_kind.hpp | 2 +- stan/math/rev/fun/bessel_second_kind.hpp | 3 + stan/math/rev/fun/binary_log_loss.hpp | 5 +- stan/math/rev/functor/apply_scalar_binary.hpp | 56 +++++++++---------- test/unit/math/mix/fun/beta2_test.cpp | 15 +++++ test/unit/math/mix/fun/beta_test.cpp | 13 ----- 6 files changed, 48 insertions(+), 46 deletions(-) create mode 100644 test/unit/math/mix/fun/beta2_test.cpp diff --git a/stan/math/rev/fun/bessel_first_kind.hpp b/stan/math/rev/fun/bessel_first_kind.hpp index d85ffcd1534..6ba3f3ff6f2 100644 --- a/stan/math/rev/fun/bessel_first_kind.hpp +++ b/stan/math/rev/fun/bessel_first_kind.hpp @@ -19,7 +19,7 @@ inline var bessel_first_kind(int v, const var& a) { } /** - * Overload with `var_value` for `int` and `std::vector` + * Overload with `var_value` for `int`, `std::vector`, and `std::vector>` */ template * = nullptr, require_eigen_t* = nullptr> diff --git a/stan/math/rev/fun/bessel_second_kind.hpp b/stan/math/rev/fun/bessel_second_kind.hpp index 28aeadae8de..9108de29bd1 100644 --- a/stan/math/rev/fun/bessel_second_kind.hpp +++ b/stan/math/rev/fun/bessel_second_kind.hpp @@ -17,6 +17,9 @@ inline var bessel_second_kind(int v, const var& a) { }); } +/** + * Overload with `var_value` for `int`, `std::vector`, and `std::vector>` + */ template * = nullptr, require_eigen_t* = nullptr> inline auto bessel_second_kind(const T1& v, const var_value& a) { diff --git a/stan/math/rev/fun/binary_log_loss.hpp b/stan/math/rev/fun/binary_log_loss.hpp index 27920483433..1f4ae518086 100644 --- a/stan/math/rev/fun/binary_log_loss.hpp +++ b/stan/math/rev/fun/binary_log_loss.hpp @@ -55,6 +55,9 @@ inline var binary_log_loss(int y, const var& y_hat) { } } +/** + * Overload with `int` and `var_value` + */ template * = nullptr> inline auto binary_log_loss(int y, const var_value& y_hat) { if (y == 0) { @@ -71,7 +74,7 @@ inline auto binary_log_loss(int y, const var_value& y_hat) { } /** - * Overload for std::vector and `var_value` + * Overload with `var_value` for `std::vector` and `std::vector>` */ template * = nullptr, require_st_integral* = nullptr> diff --git a/stan/math/rev/functor/apply_scalar_binary.hpp b/stan/math/rev/functor/apply_scalar_binary.hpp index 510f0157da7..65b483ab4af 100644 --- a/stan/math/rev/functor/apply_scalar_binary.hpp +++ b/stan/math/rev/functor/apply_scalar_binary.hpp @@ -12,17 +12,17 @@ namespace stan { namespace math { /** - * Specialisation for use with two Eigen inputs. Eigen's binaryExpr framework - * is used for more efficient indexing of both row- and column-major inputs - * without separate loops. + * Specialisation for use with combinations of + * `Eigen::Matrix` and `var_value` inputs. + * Eigen's binaryExpr framework is used for more efficient indexing of both row- and column-major inputs without separate loops. * * @tparam T1 Type of first argument to which functor is applied. * @tparam T2 Type of second argument to which functor is applied. * @tparam F Type of functor to apply. - * @param x First Eigen input to which operation is applied. - * @param y Second Eigen input to which operation is applied. - * @param f functor to apply to Eigen input. - * @return Eigen object with result of applying functor to inputs. + * @param x First Matrix input to which operation is applied. + * @param y Second Matrix input to which operation is applied. + * @param f functor to apply to Matrix inputs. + * @return `var_value` with result of applying functor to inputs. */ template * = nullptr, @@ -33,16 +33,16 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { } /** - * Specialisation for use with one Eigen vector (row or column) and + * Specialisation for use with one `var_value` (row or column) and * a one-dimensional std::vector of integer types * * @tparam T1 Type of first argument to which functor is applied. * @tparam T2 Type of second argument to which functor is applied. * @tparam F Type of functor to apply. - * @param x Eigen input to which operation is applied. + * @param x Matrix input to which operation is applied. * @param y Integer std::vector input to which operation is applied. * @param f functor to apply to inputs. - * @return Eigen object with result of applying functor to inputs. + * @return var_value object with result of applying functor to inputs. */ template * = nullptr, @@ -54,7 +54,7 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { /** * Specialisation for use with a one-dimensional std::vector of integer types - * and one Eigen vector (row or column). + * and one `var_value` (row or column). * * @tparam T1 Type of first argument to which functor is applied. * @tparam T2 Type of second argument to which functor is applied. @@ -73,13 +73,13 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { } /** - * Specialisation for use with one Eigen matrix and + * Specialisation for use with one `var_value` and * a two-dimensional std::vector of integer types * * @tparam T1 Type of first argument to which functor is applied. * @tparam T2 Type of second argument to which functor is applied. * @tparam F Type of functor to apply. - * @param x Eigen matrix input to which operation is applied. + * @param x var with Eigen matrix inner type to which operation is applied. * @param y Nested integer std::vector input to which operation is applied. * @param f functor to apply to inputs. * @return Eigen object with result of applying functor to inputs. @@ -94,13 +94,13 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { /** * Specialisation for use with a two-dimensional std::vector of integer types - * and one Eigen matrix. + * and one `var_value`. * * @tparam T1 Type of first argument to which functor is applied. * @tparam T2 Type of second argument to which functor is applied. * @tparam F Type of functor to apply. * @param x Nested integer std::vector input to which operation is applied. - * @param y Eigen matrix input to which operation is applied. + * @param y var value with inner Eigen matrix input to which operation is applied. * @param f functor to apply to inputs. * @return Eigen object with result of applying functor to inputs. */ @@ -113,19 +113,16 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { } /** - * Specialisation for use when the first input is an Eigen type and the second - * is a scalar. Eigen's unaryExpr framework is used for more efficient indexing - * of both row- and column-major inputs. The unaryExpr framework also allows - * for the scalar to be captured and applied to each element in the Eigen - * object. + * Specialisation for use when the first input is an `var_value type and the second + * is a scalar. * - * @tparam T1 Type of Eigen object to which functor is applied. + * @tparam T1 Type of `var_value` object to which functor is applied. * @tparam T2 Type of scalar to which functor is applied. * @tparam F Type of functor to apply. - * @param x Eigen input to which operation is applied. + * @param x Matrix input to which operation is applied. * @param y Scalar input to which operation is applied. - * @param f functor to apply to Eigen and scalar inputs. - * @return Eigen object with result of applying functor to inputs. + * @param f functor to apply to var matrix and scalar inputs. + * @return `var_value object with result of applying functor to inputs. * * Note: The return expresssion needs to be evaluated, otherwise the captured * function and scalar fall out of scope. @@ -139,18 +136,15 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { /** * Specialisation for use when the first input is an scalar and the second is - * an Eigen type. Eigen's unaryExpr framework is used for more efficient - * indexing of both row- and column-major inputs. The unaryExpr framework also - * allows for the scalar to be captured and applied to each element in the - * Eigen object. + * an `var_value`. * * @tparam T1 Type of scalar to which functor is applied. - * @tparam T2 Type of Eigen object to which functor is applied. + * @tparam T2 var value with inner Eigen type to which functor is applied. * @tparam F Type of functor to apply. * @param x Scalar input to which operation is applied. - * @param y Eigen input to which operation is applied. + * @param y var matrix input to which operation is applied. * @param f functor to apply to Eigen and scalar inputs. - * @return Eigen object with result of applying functor to inputs. + * @return var value with inner Eigen type with result of applying functor to inputs. * * Note: The return expresssion needs to be evaluated, otherwise the captured * function and scalar fall out of scope. diff --git a/test/unit/math/mix/fun/beta2_test.cpp b/test/unit/math/mix/fun/beta2_test.cpp new file mode 100644 index 00000000000..5423338028d --- /dev/null +++ b/test/unit/math/mix/fun/beta2_test.cpp @@ -0,0 +1,15 @@ +#include + + +TEST(mathMixScalFun, beta_varmat_vectorized) { + auto f = [](const auto& x1, const auto& x2) { + using stan::math::beta; + return beta(x1, x2); + }; + + Eigen::MatrixXd in1(2, 2); + in1 << 0.5, 3.4, 5.2, 0.5; + Eigen::MatrixXd in2(2, 2); + in2 << 3.3, 0.9, 6.7, 3.3; + stan::test::expect_ad_vectorized_matvar(f, in1, in2); +} diff --git a/test/unit/math/mix/fun/beta_test.cpp b/test/unit/math/mix/fun/beta_test.cpp index e7c80d91652..dad29034aa0 100644 --- a/test/unit/math/mix/fun/beta_test.cpp +++ b/test/unit/math/mix/fun/beta_test.cpp @@ -34,16 +34,3 @@ TEST(mathMixScalFun, beta_varmat) { stan::test::expect_ad_matvar(f, in1(0), in2); stan::test::expect_ad_matvar(f, in1, in2(0)); } - -TEST(mathMixScalFun, beta_varmat_vectorized) { - auto f = [](const auto& x1, const auto& x2) { - using stan::math::beta; - return beta(x1, x2); - }; - - Eigen::MatrixXd in1(2, 2); - in1 << 0.5, 3.4, 5.2, 0.5; - Eigen::MatrixXd in2(2, 2); - in2 << 3.3, 0.9, 6.7, 3.3; - stan::test::expect_ad_vectorized_matvar(f, in1, in2); -} From 9f65ddf2e00610ebc3e25feffc8232da2292067d Mon Sep 17 00:00:00 2001 From: Stan Jenkins Date: Thu, 10 Jun 2021 00:19:42 +0000 Subject: [PATCH 04/12] [Jenkins] auto-formatting by clang-format version 6.0.0-1ubuntu2~16.04.1 (tags/RELEASE_600/final) --- stan/math/rev/fun/bessel_first_kind.hpp | 3 ++- stan/math/rev/fun/bessel_second_kind.hpp | 3 ++- stan/math/rev/fun/binary_log_loss.hpp | 3 ++- stan/math/rev/functor/apply_scalar_binary.hpp | 13 ++++++++----- test/unit/math/mix/fun/beta2_test.cpp | 1 - 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/stan/math/rev/fun/bessel_first_kind.hpp b/stan/math/rev/fun/bessel_first_kind.hpp index 6ba3f3ff6f2..21e745b2d42 100644 --- a/stan/math/rev/fun/bessel_first_kind.hpp +++ b/stan/math/rev/fun/bessel_first_kind.hpp @@ -19,7 +19,8 @@ inline var bessel_first_kind(int v, const var& a) { } /** - * Overload with `var_value` for `int`, `std::vector`, and `std::vector>` + * Overload with `var_value` for `int`, `std::vector`, and + * `std::vector>` */ template * = nullptr, require_eigen_t* = nullptr> diff --git a/stan/math/rev/fun/bessel_second_kind.hpp b/stan/math/rev/fun/bessel_second_kind.hpp index 9108de29bd1..290f5d703ee 100644 --- a/stan/math/rev/fun/bessel_second_kind.hpp +++ b/stan/math/rev/fun/bessel_second_kind.hpp @@ -18,7 +18,8 @@ inline var bessel_second_kind(int v, const var& a) { } /** - * Overload with `var_value` for `int`, `std::vector`, and `std::vector>` + * Overload with `var_value` for `int`, `std::vector`, and + * `std::vector>` */ template * = nullptr, require_eigen_t* = nullptr> diff --git a/stan/math/rev/fun/binary_log_loss.hpp b/stan/math/rev/fun/binary_log_loss.hpp index 1f4ae518086..990a0b979c3 100644 --- a/stan/math/rev/fun/binary_log_loss.hpp +++ b/stan/math/rev/fun/binary_log_loss.hpp @@ -74,7 +74,8 @@ inline auto binary_log_loss(int y, const var_value& y_hat) { } /** - * Overload with `var_value` for `std::vector` and `std::vector>` + * Overload with `var_value` for `std::vector` and + * `std::vector>` */ template * = nullptr, require_st_integral* = nullptr> diff --git a/stan/math/rev/functor/apply_scalar_binary.hpp b/stan/math/rev/functor/apply_scalar_binary.hpp index 65b483ab4af..86c312ae767 100644 --- a/stan/math/rev/functor/apply_scalar_binary.hpp +++ b/stan/math/rev/functor/apply_scalar_binary.hpp @@ -14,7 +14,8 @@ namespace math { /** * Specialisation for use with combinations of * `Eigen::Matrix` and `var_value` inputs. - * Eigen's binaryExpr framework is used for more efficient indexing of both row- and column-major inputs without separate loops. + * Eigen's binaryExpr framework is used for more efficient indexing of both row- + * and column-major inputs without separate loops. * * @tparam T1 Type of first argument to which functor is applied. * @tparam T2 Type of second argument to which functor is applied. @@ -100,7 +101,8 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { * @tparam T2 Type of second argument to which functor is applied. * @tparam F Type of functor to apply. * @param x Nested integer std::vector input to which operation is applied. - * @param y var value with inner Eigen matrix input to which operation is applied. + * @param y var value with inner Eigen matrix input to which operation is + * applied. * @param f functor to apply to inputs. * @return Eigen object with result of applying functor to inputs. */ @@ -113,8 +115,8 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { } /** - * Specialisation for use when the first input is an `var_value type and the second - * is a scalar. + * Specialisation for use when the first input is an `var_value type and + * the second is a scalar. * * @tparam T1 Type of `var_value` object to which functor is applied. * @tparam T2 Type of scalar to which functor is applied. @@ -144,7 +146,8 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { * @param x Scalar input to which operation is applied. * @param y var matrix input to which operation is applied. * @param f functor to apply to Eigen and scalar inputs. - * @return var value with inner Eigen type with result of applying functor to inputs. + * @return var value with inner Eigen type with result of applying functor to + * inputs. * * Note: The return expresssion needs to be evaluated, otherwise the captured * function and scalar fall out of scope. diff --git a/test/unit/math/mix/fun/beta2_test.cpp b/test/unit/math/mix/fun/beta2_test.cpp index 5423338028d..14f3a1c3391 100644 --- a/test/unit/math/mix/fun/beta2_test.cpp +++ b/test/unit/math/mix/fun/beta2_test.cpp @@ -1,6 +1,5 @@ #include - TEST(mathMixScalFun, beta_varmat_vectorized) { auto f = [](const auto& x1, const auto& x2) { using stan::math::beta; From 3fb1507adb22d68aff4bbb7d29b871b5ac9c7ccc Mon Sep 17 00:00:00 2001 From: stevebronder Date: Wed, 9 Jun 2021 21:32:02 -0400 Subject: [PATCH 05/12] fix include order error --- test/unit/math/test_ad_matvar.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/math/test_ad_matvar.hpp b/test/unit/math/test_ad_matvar.hpp index 6b6304db0d4..1cde23558d9 100644 --- a/test/unit/math/test_ad_matvar.hpp +++ b/test/unit/math/test_ad_matvar.hpp @@ -999,7 +999,7 @@ template * = nullptr, void expect_ad_vectorized_matvar(const ad_tolerances& tols, const F& f, const T1& x, const T2& y) { auto g = [&f](const auto& x, const auto& y) { return f(y, x); }; - expect_ad_vectorized_matvar(g, y, x); + expect_ad_vectorized_matvar(tols, g, y, x); } /** From 3848b10ee4badaf3c74e2e5fc8ff58172f558d39 Mon Sep 17 00:00:00 2001 From: Steve Bronder Date: Tue, 22 Jun 2021 19:10:26 -0400 Subject: [PATCH 06/12] remove unneeded overloads of var for apply_scalar_binary and add is_container_or_var_matrix --- .../math/prim/functor/apply_scalar_binary.hpp | 7 +- stan/math/prim/functor/apply_vector_unary.hpp | 8 +- stan/math/prim/meta.hpp | 1 + .../prim/meta/is_container_or_var_matrix.hpp | 30 +++++ stan/math/rev/functor/apply_scalar_binary.hpp | 108 +----------------- test/unit/math/test_ad.hpp | 2 +- 6 files changed, 38 insertions(+), 118 deletions(-) create mode 100644 stan/math/prim/meta/is_container_or_var_matrix.hpp diff --git a/stan/math/prim/functor/apply_scalar_binary.hpp b/stan/math/prim/functor/apply_scalar_binary.hpp index 2fb63667057..5f02d3dc759 100644 --- a/stan/math/prim/functor/apply_scalar_binary.hpp +++ b/stan/math/prim/functor/apply_scalar_binary.hpp @@ -306,6 +306,7 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { return result; } + /** * Specialisation for use with two nested containers (std::vectors). * The returned scalar type is deduced to allow for cases where the input and @@ -321,7 +322,7 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { * @return std::vector with result of applying functor to inputs. */ template * = nullptr> + require_all_std_vector_vt* = nullptr> inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { check_matching_sizes("Binary function", "x", x, "y", y); using T_return = plain_type_t; @@ -348,7 +349,7 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { * @return std::vector with result of applying functor to inputs. */ template * = nullptr, + require_std_vector_vt* = nullptr, require_stan_scalar_t* = nullptr> inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { using T_return = plain_type_t; @@ -376,7 +377,7 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { */ template * = nullptr, - require_std_vector_vt* = nullptr> + require_std_vector_vt* = nullptr> inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { using T_return = plain_type_t; size_t y_size = y.size(); diff --git a/stan/math/prim/functor/apply_vector_unary.hpp b/stan/math/prim/functor/apply_vector_unary.hpp index 0b0db855aac..5c68d0b2b14 100644 --- a/stan/math/prim/functor/apply_vector_unary.hpp +++ b/stan/math/prim/functor/apply_vector_unary.hpp @@ -159,12 +159,6 @@ struct apply_vector_unary> { } }; -namespace internal { -template -using is_container_or_var_matrix - = disjunction, is_var_matrix>; -} - /** * Specialisation for use with nested containers (std::vectors). * For each of the member functions, an std::vector with the appropriate @@ -177,7 +171,7 @@ using is_container_or_var_matrix */ template struct apply_vector_unary< - T, require_std_vector_vt> { + T, require_std_vector_vt> { using T_vt = value_type_t; /** diff --git a/stan/math/prim/meta.hpp b/stan/math/prim/meta.hpp index f07d43820c9..adc3b92f12b 100644 --- a/stan/math/prim/meta.hpp +++ b/stan/math/prim/meta.hpp @@ -192,6 +192,7 @@ #include #include #include +#include #include #include #include diff --git a/stan/math/prim/meta/is_container_or_var_matrix.hpp b/stan/math/prim/meta/is_container_or_var_matrix.hpp new file mode 100644 index 00000000000..e07115714ad --- /dev/null +++ b/stan/math/prim/meta/is_container_or_var_matrix.hpp @@ -0,0 +1,30 @@ +#ifndef STAN_MATH_PRIM_META_IS_CONTAINER_OR_VAR_MATRIX_HPP +#define STAN_MATH_PRIM_META_IS_CONTAINER_OR_VAR_MATRIX_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace stan { + +/** + * Deduces whether type is eigen matrix, standard vector, or var. + * @tparam Container type to check + */ +template +using is_container_or_var_matrix = bool_constant< + math::disjunction, is_var_matrix>::value>; + +STAN_ADD_REQUIRE_UNARY(container_or_var_matrix, is_container_or_var_matrix, general_types); +STAN_ADD_REQUIRE_CONTAINER(container_or_var_matrix, is_container_or_var_matrix, general_types); + +} // namespace stan + +#endif diff --git a/stan/math/rev/functor/apply_scalar_binary.hpp b/stan/math/rev/functor/apply_scalar_binary.hpp index 86c312ae767..20a2da66abf 100644 --- a/stan/math/rev/functor/apply_scalar_binary.hpp +++ b/stan/math/rev/functor/apply_scalar_binary.hpp @@ -11,27 +11,7 @@ namespace stan { namespace math { -/** - * Specialisation for use with combinations of - * `Eigen::Matrix` and `var_value` inputs. - * Eigen's binaryExpr framework is used for more efficient indexing of both row- - * and column-major inputs without separate loops. - * - * @tparam T1 Type of first argument to which functor is applied. - * @tparam T2 Type of second argument to which functor is applied. - * @tparam F Type of functor to apply. - * @param x First Matrix input to which operation is applied. - * @param y Second Matrix input to which operation is applied. - * @param f functor to apply to Matrix inputs. - * @return `var_value` with result of applying functor to inputs. - */ -template * = nullptr, - require_all_matrix_t* = nullptr> -inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { - check_matching_dims("Binary function", "x", x, "y", y); - return f(x, y); -} + /** * Specialisation for use with one `var_value` (row or column) and @@ -126,8 +106,6 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { * @param f functor to apply to var matrix and scalar inputs. * @return `var_value object with result of applying functor to inputs. * - * Note: The return expresssion needs to be evaluated, otherwise the captured - * function and scalar fall out of scope. */ template * = nullptr, @@ -149,8 +127,6 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { * @return var value with inner Eigen type with result of applying functor to * inputs. * - * Note: The return expresssion needs to be evaluated, otherwise the captured - * function and scalar fall out of scope. */ template * = nullptr, @@ -159,89 +135,7 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { return f(x, y); } -/** - * Specialisation for use when the first input is a nested std::vector and the - * second is a scalar. The returned scalar type is deduced to allow for cases - * where the input and return scalar types differ (e.g., functions implicitly - * promoting integers). - * - * @tparam T1 Type of std::vector to which functor is applied. - * @tparam T2 Type of scalar to which functor is applied. - * @tparam F Type of functor to apply. - * @param x std::vector input to which operation is applied. - * @param y Scalar input to which operation is applied. - * @param f functor to apply to inputs. - * @return std::vector with result of applying functor to inputs. - */ -template * = nullptr, - require_var_matrix_t>* = nullptr, - require_stan_scalar_t* = nullptr> -inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { - using T_return = plain_type_t; - size_t x_size = x.size(); - std::vector result(x_size); - for (size_t i = 0; i < x_size; ++i) { - result[i] = apply_scalar_binary(x[i], y, f); - } - return result; -} - -/** - * Specialisation for use when the first input is a scalar and the second is a - * nested std::vector. The returned scalar type is deduced to allow for cases - * where the input and return scalar types differ (e.g., functions implicitly - * promoting integers). - * - * @tparam T1 Type of scalar to which functor is applied. - * @tparam T2 Type of std::vector to which functor is applied. - * @tparam F Type of functor to apply. - * @param x Scalar input to which operation is applied. - * @param y std::vector input to which operation is applied. - * @param f functor to apply to inputs. - * @return std::vector with result of applying functor to inputs. - */ -template * = nullptr, - require_std_vector_t* = nullptr, - require_var_matrix_t>* = nullptr> -inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { - using T_return = plain_type_t; - size_t y_size = y.size(); - std::vector result(y_size); - for (size_t i = 0; i < y_size; ++i) { - result[i] = apply_scalar_binary(x, y[i], f); - } - return result; -} -/** - * Specialisation for use with two nested containers (std::vectors). - * The returned scalar type is deduced to allow for cases where the input and - * return scalar types differ (e.g., functions implicitly promoting - * integers). - * - * @tparam T1 Type of first std::vector to which functor is applied. - * @tparam T2 Type of second std::vector to which functor is applied. - * @tparam F Type of functor to apply. - * @param x First std::vector input to which operation is applied. - * @param y Second std::vector input to which operation is applied. - * @param f functor to apply to std::vector inputs. - * @return std::vector with result of applying functor to inputs. - */ -template * = nullptr> -inline auto apply_scalar_binary(const std::vector& x, - const std::vector& y, const F& f) { - check_matching_sizes("Binary function", "x", x, "y", y); - using T_return = plain_type_t; - size_t y_size = y.size(); - std::vector result(y_size); - for (size_t i = 0; i < y_size; ++i) { - result[i] = apply_scalar_binary(x[i], y[i], f); - } - return result; -} } // namespace math } // namespace stan diff --git a/test/unit/math/test_ad.hpp b/test/unit/math/test_ad.hpp index eb4b474d93f..3ad6e552dc6 100644 --- a/test/unit/math/test_ad.hpp +++ b/test/unit/math/test_ad.hpp @@ -1315,7 +1315,7 @@ void expect_ad_vectorized_binary_impl(const ad_tolerances& tols, const F& f, expect_ad(tols, f, nest_nest_x, nest_nest_y); // nest>, nest> expect_ad(tols, f, nest_nest_x, y[0]); // nest, scal - expect_ad(tols, f, x[0], nest_nest_y); // scal, nest + expect_ad(tols, f, x[0], nest_nest_y); // scal, nest> } /** From 5da0a5dfe02ade8534753aebf22ce3e5d168fdea Mon Sep 17 00:00:00 2001 From: Stan Jenkins Date: Tue, 22 Jun 2021 23:13:58 +0000 Subject: [PATCH 07/12] [Jenkins] auto-formatting by clang-format version 6.0.0-1ubuntu2~16.04.1 (tags/RELEASE_600/final) --- stan/math/prim/functor/apply_scalar_binary.hpp | 6 +++--- stan/math/prim/meta/is_container_or_var_matrix.hpp | 11 +++++++---- stan/math/rev/functor/apply_scalar_binary.hpp | 4 ---- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/stan/math/prim/functor/apply_scalar_binary.hpp b/stan/math/prim/functor/apply_scalar_binary.hpp index 5f02d3dc759..5210e901121 100644 --- a/stan/math/prim/functor/apply_scalar_binary.hpp +++ b/stan/math/prim/functor/apply_scalar_binary.hpp @@ -306,7 +306,6 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { return result; } - /** * Specialisation for use with two nested containers (std::vectors). * The returned scalar type is deduced to allow for cases where the input and @@ -321,8 +320,9 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { * @param f functor to apply to std::vector inputs. * @return std::vector with result of applying functor to inputs. */ -template * = nullptr> +template < + typename T1, typename T2, typename F, + require_all_std_vector_vt* = nullptr> inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { check_matching_sizes("Binary function", "x", x, "y", y); using T_return = plain_type_t; diff --git a/stan/math/prim/meta/is_container_or_var_matrix.hpp b/stan/math/prim/meta/is_container_or_var_matrix.hpp index e07115714ad..ed692654218 100644 --- a/stan/math/prim/meta/is_container_or_var_matrix.hpp +++ b/stan/math/prim/meta/is_container_or_var_matrix.hpp @@ -19,11 +19,14 @@ namespace stan { * @tparam Container type to check */ template -using is_container_or_var_matrix = bool_constant< - math::disjunction, is_var_matrix>::value>; +using is_container_or_var_matrix + = bool_constant, + is_var_matrix>::value>; -STAN_ADD_REQUIRE_UNARY(container_or_var_matrix, is_container_or_var_matrix, general_types); -STAN_ADD_REQUIRE_CONTAINER(container_or_var_matrix, is_container_or_var_matrix, general_types); +STAN_ADD_REQUIRE_UNARY(container_or_var_matrix, is_container_or_var_matrix, + general_types); +STAN_ADD_REQUIRE_CONTAINER(container_or_var_matrix, is_container_or_var_matrix, + general_types); } // namespace stan diff --git a/stan/math/rev/functor/apply_scalar_binary.hpp b/stan/math/rev/functor/apply_scalar_binary.hpp index 20a2da66abf..17c8a6475dc 100644 --- a/stan/math/rev/functor/apply_scalar_binary.hpp +++ b/stan/math/rev/functor/apply_scalar_binary.hpp @@ -11,8 +11,6 @@ namespace stan { namespace math { - - /** * Specialisation for use with one `var_value` (row or column) and * a one-dimensional std::vector of integer types @@ -135,8 +133,6 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { return f(x, y); } - - } // namespace math } // namespace stan #endif From 447e001f49e6809490454550902e06348e17eaeb Mon Sep 17 00:00:00 2001 From: Steve Bronder Date: Tue, 22 Jun 2021 19:34:32 -0400 Subject: [PATCH 08/12] Update is_container_or_var_matrix.hpp --- stan/math/prim/meta/is_container_or_var_matrix.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/stan/math/prim/meta/is_container_or_var_matrix.hpp b/stan/math/prim/meta/is_container_or_var_matrix.hpp index ed692654218..5d970ce31da 100644 --- a/stan/math/prim/meta/is_container_or_var_matrix.hpp +++ b/stan/math/prim/meta/is_container_or_var_matrix.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include From 42b528745ef081ccb0a73d195e46003a3cbee35d Mon Sep 17 00:00:00 2001 From: Steve Bronder Date: Tue, 22 Jun 2021 19:52:05 -0400 Subject: [PATCH 09/12] add back apply_scalar_binary for var var ops --- stan/math/rev/functor/apply_scalar_binary.hpp | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/stan/math/rev/functor/apply_scalar_binary.hpp b/stan/math/rev/functor/apply_scalar_binary.hpp index 17c8a6475dc..0de7e5ade7e 100644 --- a/stan/math/rev/functor/apply_scalar_binary.hpp +++ b/stan/math/rev/functor/apply_scalar_binary.hpp @@ -11,6 +11,28 @@ namespace stan { namespace math { +/** + * Specialisation for use with combinations of + * `Eigen::Matrix` and `var_value` inputs. + * Eigen's binaryExpr framework is used for more efficient indexing of both row- + * and column-major inputs without separate loops. + * + * @tparam T1 Type of first argument to which functor is applied. + * @tparam T2 Type of second argument to which functor is applied. + * @tparam F Type of functor to apply. + * @param x First Matrix input to which operation is applied. + * @param y Second Matrix input to which operation is applied. + * @param f functor to apply to Matrix inputs. + * @return `var_value` with result of applying functor to inputs. + */ +template * = nullptr, + require_all_matrix_t* = nullptr> +inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { + check_matching_dims("Binary function", "x", x, "y", y); + return f(x, y); +} + /** * Specialisation for use with one `var_value` (row or column) and * a one-dimensional std::vector of integer types From dfe705e575bd8c8899f924f7985083d57e6dbf65 Mon Sep 17 00:00:00 2001 From: Steve Bronder Date: Tue, 29 Jun 2021 10:48:11 -0400 Subject: [PATCH 10/12] reduces overloads for apply_scalar_binary with var matrix as one of the inputs --- stan/math/rev/functor/apply_scalar_binary.hpp | 71 ++++--------------- 1 file changed, 15 insertions(+), 56 deletions(-) diff --git a/stan/math/rev/functor/apply_scalar_binary.hpp b/stan/math/rev/functor/apply_scalar_binary.hpp index 0de7e5ade7e..24ab80bba9e 100644 --- a/stan/math/rev/functor/apply_scalar_binary.hpp +++ b/stan/math/rev/functor/apply_scalar_binary.hpp @@ -73,26 +73,6 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { return f(x, y); } -/** - * Specialisation for use with one `var_value` and - * a two-dimensional std::vector of integer types - * - * @tparam T1 Type of first argument to which functor is applied. - * @tparam T2 Type of second argument to which functor is applied. - * @tparam F Type of functor to apply. - * @param x var with Eigen matrix inner type to which operation is applied. - * @param y Nested integer std::vector input to which operation is applied. - * @param f functor to apply to inputs. - * @return Eigen object with result of applying functor to inputs. - */ -template * = nullptr, - require_std_vector_vt* = nullptr, - require_std_vector_st* = nullptr> -inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { - return f(x, y); -} - /** * Specialisation for use with a two-dimensional std::vector of integer types * and one `var_value`. @@ -100,57 +80,36 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { * @tparam T1 Type of first argument to which functor is applied. * @tparam T2 Type of second argument to which functor is applied. * @tparam F Type of functor to apply. - * @param x Nested integer std::vector input to which operation is applied. - * @param y var value with inner Eigen matrix input to which operation is - * applied. + * @param x Either a var matrix or nested integer std::vector input to which operation is applied. + * @param x Either a var matrix or nested integer std::vector input to which operation is applied. * @param f functor to apply to inputs. * @return Eigen object with result of applying functor to inputs. */ template * = nullptr, - require_std_vector_st* = nullptr, - require_var_matrix_t* = nullptr> + require_any_std_vector_vt* = nullptr, + require_any_std_vector_st* = nullptr, + require_any_var_matrix_t* = nullptr> inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { return f(x, y); } + /** - * Specialisation for use when the first input is an `var_value type and - * the second is a scalar. + * Specialisation for use when the one input is an `var_value type and + * the other is a scalar. * - * @tparam T1 Type of `var_value` object to which functor is applied. - * @tparam T2 Type of scalar to which functor is applied. + * @tparam T1 Type of either `var_value` or scalar object to which functor is applied. + * @tparam T2 Type of either `var_value` or scalar object to which functor is applied. * @tparam F Type of functor to apply. - * @param x Matrix input to which operation is applied. - * @param y Scalar input to which operation is applied. + * @param x Matrix or Scalar input to which operation is applied. + * @param x Matrix or Scalar input to which operation is applied. * @param f functor to apply to var matrix and scalar inputs. * @return `var_value object with result of applying functor to inputs. * */ -template * = nullptr, - require_stan_scalar_t* = nullptr> -inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { - return f(x, y); -} - -/** - * Specialisation for use when the first input is an scalar and the second is - * an `var_value`. - * - * @tparam T1 Type of scalar to which functor is applied. - * @tparam T2 var value with inner Eigen type to which functor is applied. - * @tparam F Type of functor to apply. - * @param x Scalar input to which operation is applied. - * @param y var matrix input to which operation is applied. - * @param f functor to apply to Eigen and scalar inputs. - * @return var value with inner Eigen type with result of applying functor to - * inputs. - * - */ -template * = nullptr, - require_var_matrix_t* = nullptr> + template * = nullptr, + require_any_var_matrix_t* = nullptr> inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { return f(x, y); } From 6115bdd38848e652c71dbc45c01524b0d9869698 Mon Sep 17 00:00:00 2001 From: Steve Bronder Date: Tue, 29 Jun 2021 10:53:30 -0400 Subject: [PATCH 11/12] reduces overloads for apply_scalar_binary with var matrix as one of the inputs --- stan/math/rev/functor/apply_scalar_binary.hpp | 24 ++----------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/stan/math/rev/functor/apply_scalar_binary.hpp b/stan/math/rev/functor/apply_scalar_binary.hpp index 24ab80bba9e..6cee58b64f5 100644 --- a/stan/math/rev/functor/apply_scalar_binary.hpp +++ b/stan/math/rev/functor/apply_scalar_binary.hpp @@ -46,28 +46,8 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { * @return var_value object with result of applying functor to inputs. */ template * = nullptr, - require_std_vector_vt* = nullptr> -inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { - check_matching_sizes("Binary function", "x", x, "y", y); - return f(x, y); -} - -/** - * Specialisation for use with a one-dimensional std::vector of integer types - * and one `var_value` (row or column). - * - * @tparam T1 Type of first argument to which functor is applied. - * @tparam T2 Type of second argument to which functor is applied. - * @tparam F Type of functor to apply. - * @param x Integer std::vector input to which operation is applied. - * @param y Eigen input to which operation is applied. - * @param f functor to apply to inputs. - * @return Eigen object with result of applying functor to inputs. - */ -template * = nullptr, - require_var_matrix_t* = nullptr> + require_any_var_matrix_t* = nullptr, + require_any_std_vector_vt* = nullptr> inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { check_matching_sizes("Binary function", "x", x, "y", y); return f(x, y); From e23c84edc78b51cf70e15533c19ab80083720f11 Mon Sep 17 00:00:00 2001 From: Stan Jenkins Date: Tue, 29 Jun 2021 15:03:04 +0000 Subject: [PATCH 12/12] [Jenkins] auto-formatting by clang-format version 6.0.0-1ubuntu2~16.04.1 (tags/RELEASE_600/final) --- stan/math/rev/functor/apply_scalar_binary.hpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/stan/math/rev/functor/apply_scalar_binary.hpp b/stan/math/rev/functor/apply_scalar_binary.hpp index 6cee58b64f5..00269473cea 100644 --- a/stan/math/rev/functor/apply_scalar_binary.hpp +++ b/stan/math/rev/functor/apply_scalar_binary.hpp @@ -60,8 +60,10 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { * @tparam T1 Type of first argument to which functor is applied. * @tparam T2 Type of second argument to which functor is applied. * @tparam F Type of functor to apply. - * @param x Either a var matrix or nested integer std::vector input to which operation is applied. - * @param x Either a var matrix or nested integer std::vector input to which operation is applied. + * @param x Either a var matrix or nested integer std::vector input to which + * operation is applied. + * @param x Either a var matrix or nested integer std::vector input to which + * operation is applied. * @param f functor to apply to inputs. * @return Eigen object with result of applying functor to inputs. */ @@ -73,13 +75,14 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { return f(x, y); } - /** * Specialisation for use when the one input is an `var_value type and * the other is a scalar. * - * @tparam T1 Type of either `var_value` or scalar object to which functor is applied. - * @tparam T2 Type of either `var_value` or scalar object to which functor is applied. + * @tparam T1 Type of either `var_value` or scalar object to which + * functor is applied. + * @tparam T2 Type of either `var_value` or scalar object to which + * functor is applied. * @tparam F Type of functor to apply. * @param x Matrix or Scalar input to which operation is applied. * @param x Matrix or Scalar input to which operation is applied. @@ -87,7 +90,7 @@ inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) { * @return `var_value object with result of applying functor to inputs. * */ - template * = nullptr, require_any_var_matrix_t* = nullptr> inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) {