Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adds testing suite for nested binary var matrix functions #2502

Merged
merged 15 commits into from
Jun 30, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
[Jenkins] auto-formatting by clang-format version 6.0.0-1ubuntu2~16.0…
…4.1 (tags/RELEASE_600/final)
  • Loading branch information
stan-buildbot committed Jun 9, 2021
commit f431f2ad30474ef13949e066713e306687af32f0
7 changes: 4 additions & 3 deletions stan/math/prim/fun/as_array_or_scalar.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ inline auto as_array_or_scalar(T&& v) {
* @return Matrix converted to an array.
*/
template <typename T, require_std_vector_t<T>* = nullptr,
require_not_std_vector_t<value_type_t<T>>* = nullptr>
require_not_std_vector_t<value_type_t<T>>* = nullptr>
inline auto as_array_or_scalar(T&& v) {
using T_map
= Eigen::Map<const Eigen::Array<value_type_t<T>, Eigen::Dynamic, 1>>;
Expand All @@ -69,11 +69,12 @@ inline auto as_array_or_scalar(T&& v) {
* @return An Eigen Array with dynamic rows and columns.
*/
template <typename T, require_std_vector_vt<is_std_vector, T>* = nullptr,
require_std_vector_vt<is_stan_scalar, value_type_t<T>>* = nullptr>
require_std_vector_vt<is_stan_scalar, value_type_t<T>>* = nullptr>
inline auto as_array_or_scalar(T&& v) {
Eigen::Array<scalar_type_t<T>, -1, -1> ret(v.size(), v[0].size());
for (size_t i = 0; i < v.size(); ++i) {
ret.row(i) = Eigen::Map<const Eigen::Array<scalar_type_t<T>, 1, -1>>(v[i].data(), v[i].size());
ret.row(i) = Eigen::Map<const Eigen::Array<scalar_type_t<T>, 1, -1>>(
v[i].data(), v[i].size());
}
return ret;
}
Expand Down
1 change: 0 additions & 1 deletion stan/math/rev/fun/bessel_first_kind.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ inline auto bessel_first_kind(const T1& v, const var_value<T2>& a) {
});
}


} // namespace math
} // namespace stan
#endif
7 changes: 3 additions & 4 deletions stan/math/rev/fun/binary_log_loss.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ inline auto binary_log_loss(int y, const var_value<Mat>& y_hat) {
/**
* Overload for std::vector<int> and `var_value<Vector>`
*/
template <typename StdVec, typename Mat, require_eigen_t<Mat>* = nullptr, require_st_integral<StdVec>* = nullptr>
inline auto binary_log_loss(const StdVec& y,
const var_value<Mat>& y_hat) {
template <typename StdVec, typename Mat, require_eigen_t<Mat>* = nullptr,
require_st_integral<StdVec>* = nullptr>
inline auto binary_log_loss(const StdVec& y, const var_value<Mat>& y_hat) {
auto arena_y = to_arena(as_array_or_scalar(y).template cast<bool>());
auto ret_val
= -(arena_y == 0)
Expand All @@ -88,7 +88,6 @@ inline auto binary_log_loss(const StdVec& y,
});
}


} // namespace math
} // namespace stan
#endif
13 changes: 7 additions & 6 deletions stan/math/rev/functor/apply_scalar_binary.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 <typename T1, typename T2, typename F, require_var_matrix_t<T1>* = nullptr,
template <typename T1, typename T2, typename F,
require_var_matrix_t<T1>* = nullptr,
require_stan_scalar_t<T2>* = nullptr>
inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) {
return f(x, y);
Expand All @@ -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 <typename T1, typename T2, typename F,
require_stan_scalar_t<T1>* = nullptr, require_var_matrix_t<T2>* = nullptr>
require_stan_scalar_t<T1>* = nullptr,
require_var_matrix_t<T2>* = 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
Expand Down Expand Up @@ -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 <typename T1, typename T2, typename F,
require_any_var_matrix_t<T1, T2>* =nullptr>
inline auto apply_scalar_binary(const std::vector<T1>& x, const std::vector<T2>& y, const F& f) {
require_any_var_matrix_t<T1, T2>* = nullptr>
inline auto apply_scalar_binary(const std::vector<T1>& x,
const std::vector<T2>& y, const F& f) {
check_matching_sizes("Binary function", "x", x, "y", y);
using T_return = plain_type_t<decltype(apply_scalar_binary(x[0], y[0], f))>;
size_t y_size = y.size();
Expand Down
1 change: 0 additions & 1 deletion test/unit/math/mix/fun/bessel_second_kind_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

}
19 changes: 10 additions & 9 deletions test/unit/math/test_ad.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1306,15 +1306,16 @@ void expect_ad_vectorized_binary_impl(const ad_tolerances& tols, const F& f,
std::vector<T2> nest_y{y, y};
std::vector<std::vector<T1>> nest_nest_x{nest_x, nest_x};
std::vector<std::vector<T2>> 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<mat>, nest<mat>
expect_ad(tols, f, nest_x, y[0]); // nest<mat>, scal
expect_ad(tols, f, x[0], nest_y); // scal, nest<mat>
expect_ad(tols, f, nest_nest_x, nest_nest_y); // nest<nest<mat>>, nest<nest<mat>>
expect_ad(tols, f, nest_nest_x, y[0]); // nest<nest<mat>, scal
expect_ad(tols, f, x[0], nest_nest_y); // scal, nest<nest<mat>
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<mat>, nest<mat>
expect_ad(tols, f, nest_x, y[0]); // nest<mat>, scal
expect_ad(tols, f, x[0], nest_y); // scal, nest<mat>
expect_ad(tols, f, nest_nest_x,
nest_nest_y); // nest<nest<mat>>, nest<nest<mat>>
expect_ad(tols, f, nest_nest_x, y[0]); // nest<nest<mat>, scal
expect_ad(tols, f, x[0], nest_nest_y); // scal, nest<nest<mat>
andrjohns marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down
151 changes: 85 additions & 66 deletions test/unit/math/test_ad_matvar.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ namespace test {
* @param y Second argument to compare
* @param tols Tolerances for comparison
*/
template <typename T1, typename T2,
require_all_not_std_vector_t<value_type_t<T1>, value_type_t<T2>>* = nullptr,
require_all_std_vector_st<is_var, T1, T2>* = nullptr>
template <
typename T1, typename T2,
require_all_not_std_vector_t<value_type_t<T1>, value_type_t<T2>>* = nullptr,
require_all_std_vector_st<is_var, T1, T2>* = 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",
Expand All @@ -49,16 +50,16 @@ void expect_near_rel_matvar(const std::string& message, T1&& x, T2&& y,
}

template <typename T1, typename T2,
require_all_std_vector_vt<is_std_vector, T1, T2>* = nullptr,
require_all_std_vector_vt<is_std_vector, T1, T2>* = nullptr,
require_all_std_vector_st<is_var, T1, T2>* = nullptr>
andrjohns marked this conversation as resolved.
Show resolved Hide resolved
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);
message + std::string(" elements at i = ") + std::to_string(i), x[i],
y[i], tols);
}
}

Expand Down Expand Up @@ -384,7 +385,8 @@ auto make_varmat_compatible(const std::vector<S>& x) {
template <typename T, typename S, require_var_matrix_t<T>* = nullptr,
require_st_arithmetic<S>* = nullptr>
auto make_varmat_compatible(const std::vector<std::vector<S>>& x) {
using vec_var_mat = std::vector<std::vector<stan::math::var_value<plain_type_t<S>>>>;
using vec_var_mat
= std::vector<std::vector<stan::math::var_value<plain_type_t<S>>>>;
vec_var_mat A_vec_vm;
for (auto&& xi : x) {
A_vec_vm.push_back(make_varmat_compatible<T>(xi));
Expand Down Expand Up @@ -860,65 +862,85 @@ void expect_ad_vector_matvar(const F& f, const EigVec& x) {
* @param f Function to test
* @param x Test input
*/
template <typename F, typename T1, typename T2, require_all_eigen_t<T1, T2>* = nullptr, require_all_not_st_integral<T1, T2>* = nullptr>
template <typename F, typename T1, typename T2,
require_all_eigen_t<T1, T2>* = nullptr,
require_all_not_st_integral<T1, T2>* = 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();
auto y_vec = y.col(0).eval();
auto x_rowvec = x.col(0).eval();
auto y_rowvec = y.col(0).eval();


std::vector<value_type_t<T1>> x_scal_stdvec {x_scal, x_scal};
std::vector<value_type_t<T2>> y_scal_stdvec {y_scal, y_scal};
std::vector<std::vector<value_type_t<T1>>> x_scal_stdvec_stdvec {x_scal_stdvec, x_scal_stdvec};
std::vector<std::vector<value_type_t<T2>>> y_scal_stdvec_stdvec {x_scal_stdvec, x_scal_stdvec};
std::vector<value_type_t<T1>> x_scal_stdvec{x_scal, x_scal};
std::vector<value_type_t<T2>> y_scal_stdvec{y_scal, y_scal};
std::vector<std::vector<value_type_t<T1>>> x_scal_stdvec_stdvec{
x_scal_stdvec, x_scal_stdvec};
std::vector<std::vector<value_type_t<T2>>> y_scal_stdvec_stdvec{
x_scal_stdvec, x_scal_stdvec};
std::vector<Eigen::MatrixXd> x_mat_stdvec{x, x};
std::vector<Eigen::MatrixXd> y_mat_stdvec{y, y};
std::vector<std::vector<Eigen::MatrixXd>> x_mat_stdvec_stdvec{x_mat_stdvec, x_mat_stdvec};
std::vector<std::vector<Eigen::MatrixXd>> 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<mat>, nest<mat>
expect_ad_matvar(tols, f, x_mat_stdvec, y_scal); // nest<mat>, scal
expect_ad_matvar(tols, f, x_scal, y_mat_stdvec); // scal, nest<mat>
expect_ad_matvar(tols, f, x_mat_stdvec_stdvec, y_mat_stdvec_stdvec); // nest<nest<mat>>, nest<nest<mat>>
expect_ad_matvar(tols, f, x_mat_stdvec_stdvec, y_scal); // nest<nest<mat>, scal
expect_ad_matvar(tols, f, x_scal, y_mat_stdvec_stdvec); // scal, nest<nest<mat>
std::vector<std::vector<Eigen::MatrixXd>> x_mat_stdvec_stdvec{x_mat_stdvec,
x_mat_stdvec};
std::vector<std::vector<Eigen::MatrixXd>> 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<mat>, nest<mat>
expect_ad_matvar(tols, f, x_mat_stdvec, y_scal); // nest<mat>, scal
expect_ad_matvar(tols, f, x_scal, y_mat_stdvec); // scal, nest<mat>
expect_ad_matvar(tols, f, x_mat_stdvec_stdvec,
y_mat_stdvec_stdvec); // nest<nest<mat>>, nest<nest<mat>>
expect_ad_matvar(tols, f, x_mat_stdvec_stdvec,
y_scal); // nest<nest<mat>, scal
expect_ad_matvar(tols, f, x_scal,
y_mat_stdvec_stdvec); // scal, nest<nest<mat>

std::vector<Eigen::VectorXd> x_vec_stdvec{x_vec, x_vec};
std::vector<Eigen::VectorXd> y_vec_stdvec{y_vec, y_vec};
std::vector<std::vector<Eigen::VectorXd>> x_vec_stdvec_stdvec{x_vec_stdvec, x_vec_stdvec};
std::vector<std::vector<Eigen::VectorXd>> 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<vec>, nest<vec>
expect_ad_matvar(tols, f, x_vec_stdvec, y_scal); // nest<vec>, scal
expect_ad_matvar(tols, f, x_scal, y_vec_stdvec); // scal, nest<vec>
expect_ad_matvar(tols, f, x_vec_stdvec_stdvec, y_vec_stdvec_stdvec); // nest<nest<vec>>, nest<nest<vec>>
expect_ad_matvar(tols, f, x_vec_stdvec_stdvec, y_scal); // nest<nest<vec>, scal
expect_ad_matvar(tols, f, x_scal, y_vec_stdvec_stdvec); // scal, nest<nest<vec>
std::vector<std::vector<Eigen::VectorXd>> x_vec_stdvec_stdvec{x_vec_stdvec,
x_vec_stdvec};
std::vector<std::vector<Eigen::VectorXd>> 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<vec>, nest<vec>
expect_ad_matvar(tols, f, x_vec_stdvec, y_scal); // nest<vec>, scal
expect_ad_matvar(tols, f, x_scal, y_vec_stdvec); // scal, nest<vec>
expect_ad_matvar(tols, f, x_vec_stdvec_stdvec,
y_vec_stdvec_stdvec); // nest<nest<vec>>, nest<nest<vec>>
expect_ad_matvar(tols, f, x_vec_stdvec_stdvec,
y_scal); // nest<nest<vec>, scal
expect_ad_matvar(tols, f, x_scal,
y_vec_stdvec_stdvec); // scal, nest<nest<vec>

std::vector<Eigen::RowVectorXd> x_rowvec_stdvec{x_rowvec, x_rowvec};
std::vector<Eigen::RowVectorXd> y_rowvec_stdvec{y_rowvec, y_rowvec};
std::vector<std::vector<Eigen::RowVectorXd>> x_rowvec_stdvec_stdvec{x_rowvec_stdvec, x_rowvec_stdvec};
std::vector<std::vector<Eigen::RowVectorXd>> 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<vec>, nest<vec>
expect_ad_matvar(tols, f, x_rowvec_stdvec, y_scal); // nest<vec>, scal
expect_ad_matvar(tols, f, x_scal, y_rowvec_stdvec); // scal, nest<vec>
expect_ad_matvar(tols, f, x_rowvec_stdvec_stdvec, y_rowvec_stdvec_stdvec); // nest<nest<vec>>, nest<nest<vec>>
expect_ad_matvar(tols, f, x_rowvec_stdvec_stdvec, y_scal); // nest<nest<vec>, scal
expect_ad_matvar(tols, f, x_scal, y_rowvec_stdvec_stdvec); // scal, nest<nest<vec>

std::vector<std::vector<Eigen::RowVectorXd>> x_rowvec_stdvec_stdvec{
x_rowvec_stdvec, x_rowvec_stdvec};
std::vector<std::vector<Eigen::RowVectorXd>> 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<vec>, nest<vec>
expect_ad_matvar(tols, f, x_rowvec_stdvec, y_scal); // nest<vec>, scal
expect_ad_matvar(tols, f, x_scal, y_rowvec_stdvec); // scal, nest<vec>
expect_ad_matvar(tols, f, x_rowvec_stdvec_stdvec,
y_rowvec_stdvec_stdvec); // nest<nest<vec>>, nest<nest<vec>>
expect_ad_matvar(tols, f, x_rowvec_stdvec_stdvec,
y_scal); // nest<nest<vec>, scal
expect_ad_matvar(tols, f, x_scal,
y_rowvec_stdvec_stdvec); // scal, nest<nest<vec>
}

/**
Expand All @@ -937,7 +959,7 @@ template <typename F, typename T1, typename T2,
require_std_vector_vt<std::is_integral, T1>* = nullptr,
require_eigen_t<T2>* = 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();

Expand All @@ -946,13 +968,14 @@ void expect_ad_vectorized_matvar(const ad_tolerances& tols, const F& f,
std::vector<decltype(y_vec)> y_stdvec_vec{y_vec, y_vec};
std::vector<std::vector<T1>> x_stdvec_stdvec{x_stdvec, x_stdvec};
std::vector<std::vector<T2>> 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<mat>
expect_ad_matvar(tols, f, x, y_vec); // stdvec, vec
expect_ad_matvar(tols, f, x_stdvec, y_stdvec_vec); // nest<stdvec>, nest<vec>
expect_ad_matvar(tols, f, x_stdvec, y); // nest<stdvec>, mat
expect_ad_matvar(tols, f, x_stdvec_stdvec, y_stdvec); // nest<nest<stdvec>>, nest<mat>
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<mat>
expect_ad_matvar(tols, f, x, y_vec); // stdvec, vec
expect_ad_matvar(tols, f, x_stdvec, y_stdvec_vec); // nest<stdvec>, nest<vec>
expect_ad_matvar(tols, f, x_stdvec, y); // nest<stdvec>, mat
expect_ad_matvar(tols, f, x_stdvec_stdvec,
y_stdvec); // nest<nest<stdvec>>, nest<mat>
}

/**
Expand All @@ -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 <typename F, typename T1, typename T2,
require_eigen_t<T1>* = nullptr,
template <typename F, typename T1, typename T2, require_eigen_t<T1>* = nullptr,
require_std_vector_vt<std::is_integral, T2>* = 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
*
Expand Down