Automatic Differentiation
 
Loading...
Searching...
No Matches
apply_scalar_binary.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_PRIM_FUNCTOR_APPLY_SCALAR_BINARY_HPP
2#define STAN_MATH_PRIM_FUNCTOR_APPLY_SCALAR_BINARY_HPP
3
12#include <vector>
13
14namespace stan {
15namespace math {
16
35template <typename F, typename T1, typename T2,
36 require_all_stan_scalar_t<T1, T2>* = nullptr>
37inline auto apply_scalar_binary(F&& f, T1&& x, T2&& y) {
38 return std::forward<F>(f)(std::forward<T1>(x), std::forward<T2>(y));
39}
40
54template <typename F, typename T1, typename T2,
56inline auto apply_scalar_binary(F&& f, T1&& x, T2&& y) {
57 check_matching_dims("Binary function", "x", x, "y", y);
58 return make_holder(
59 [](auto&& f_inner, auto&& x_inner, auto&& y_inner) {
60 return std::forward<decltype(x_inner)>(x_inner).binaryExpr(
61 std::forward<decltype(y_inner)>(y_inner),
62 std::forward<decltype(f_inner)>(f_inner));
63 },
64 std::forward<F>(f), std::forward<T1>(x), std::forward<T2>(y));
65}
66
79template <typename F, typename T1, typename T2,
80 require_eigen_vector_vt<is_stan_scalar, T1>* = nullptr,
81 require_std_vector_vt<std::is_integral, T2>* = nullptr>
82inline auto apply_scalar_binary(F&& f, T1&& x, T2&& y) {
83 check_matching_sizes("Binary function", "x", x, "y", y);
84 return make_holder(
85 [](auto&& f_inner, auto&& x_inner, auto&& y_inner) {
86 using int_vec_t = promote_scalar_t<value_type_t<decltype(y_inner)>,
87 plain_type_t<decltype(x_inner)>>;
88 auto y_map = make_holder(
89 [](auto&& y_inner_) {
90 return Eigen::Map<const int_vec_t>(y_inner_.data(),
91 y_inner_.size());
92 },
93 std::forward<decltype(y_inner)>(y_inner));
94 return std::forward<decltype(x_inner)>(x_inner).binaryExpr(
95 y_map, std::forward<decltype(f_inner)>(f_inner));
96 },
97 std::forward<F>(f), std::forward<T1>(x), std::forward<T2>(y));
98}
99
112template <typename F, typename T1, typename T2,
115inline auto apply_scalar_binary(F&& f, T1&& x, T2&& y) {
116 check_matching_sizes("Binary function", "x", x, "y", y);
117 return make_holder(
118 [](auto&& f_inner, auto&& x_inner, auto&& y_inner) {
119 using int_vec_t = promote_scalar_t<value_type_t<decltype(x_inner)>,
120 plain_type_t<decltype(y_inner)>>;
121 auto x_map = make_holder(
122 [](auto&& x_inner_) {
123 return Eigen::Map<const int_vec_t>(x_inner_.data(),
124 x_inner_.size());
125 },
126 std::forward<decltype(x_inner)>(x_inner));
127 return x_map.binaryExpr(std::forward<decltype(y_inner)>(y_inner),
128 std::forward<decltype(f_inner)>(f_inner));
129 },
130 std::forward<F>(f), std::forward<T1>(x), std::forward<T2>(y));
131}
132
145template <typename F, typename T1, typename T2,
146 require_eigen_matrix_dynamic_vt<is_stan_scalar, T1>* = nullptr,
147 require_std_vector_vt<is_std_vector, T2>* = nullptr,
148 require_std_vector_st<std::is_integral, T2>* = nullptr>
149inline auto apply_scalar_binary(F&& f, T1&& x, T2&& y) {
150 if (num_elements(x) != num_elements(y)) {
151 std::ostringstream msg;
152 msg << "Inputs to vectorized binary function must match in"
153 << " size if one is not a scalar";
154 throw std::invalid_argument(msg.str());
155 }
156 using return_st = decltype(f(x(0), y[0][0]));
157 Eigen::Matrix<return_st, Eigen::Dynamic, Eigen::Dynamic> result(x.rows(),
158 x.cols());
159 for (size_t i = 0; i < y.size(); ++i) {
160 result.row(i) = apply_scalar_binary(f, x.row(i).transpose(),
162 }
163 return result;
164}
165
178template <typename F, typename T1, typename T2,
182inline auto apply_scalar_binary(F&& f, T1&& x, T2&& y) {
183 if (num_elements(x) != num_elements(y)) {
184 std::ostringstream msg;
185 msg << "Inputs to vectorized binary function must match in"
186 << " size if one is not a scalar";
187 throw std::invalid_argument(msg.str());
188 }
189 using return_st = decltype(f(x[0][0], y(0)));
190 Eigen::Matrix<return_st, Eigen::Dynamic, Eigen::Dynamic> result(y.rows(),
191 y.cols());
192 for (size_t i = 0; i < x.size(); ++i) {
193 result.row(i) = apply_scalar_binary(f, as_column_vector_or_scalar(x[i]),
194 y.row(i).transpose());
195 }
196 return result;
197}
198
214template <typename F, typename T1, typename T2, require_eigen_t<T1>* = nullptr,
215 require_stan_scalar_t<T2>* = nullptr>
216inline auto apply_scalar_binary(F&& f, T1&& x, T2&& y) {
217 return make_holder(
218 [](auto&& f_inner, auto&& x_inner, auto&& y_inner) {
219 return std::forward<decltype(x_inner)>(x_inner).unaryExpr(
220 [f_inner_ = std::forward<decltype(f_inner)>(f_inner),
221 y_inner](auto&& v) { return f_inner_(v, y_inner); });
222 },
223 std::forward<F>(f), std::forward<T1>(x), std::forward<T2>(y));
224}
225
241template <typename F, typename T1, typename T2,
242 require_stan_scalar_t<T1>* = nullptr, require_eigen_t<T2>* = nullptr>
243inline auto apply_scalar_binary(F&& f, T1&& x, T2&& y) {
244 return make_holder(
245 [](auto&& f_inner, auto&& x_inner, auto&& y_inner) {
246 return std::forward<decltype(y_inner)>(y_inner).unaryExpr(
247 [f_inner_ = std::forward<decltype(f_inner)>(f_inner),
248 x_inner](auto&& v) {
249 return f_inner_(x_inner, std::forward<decltype(v)>(v));
250 });
251 },
252 std::forward<F>(f), std::forward<T1>(x), std::forward<T2>(y));
253}
254
272template <typename F, typename T1, typename T2,
273 require_all_std_vector_vt<is_stan_scalar, T1, T2>* = nullptr>
274inline auto apply_scalar_binary(F&& f, T1&& x, T2&& y) {
275 check_matching_sizes("Binary function", "x", x, "y", y);
276 using T_return = std::decay_t<decltype(f(x[0], y[0]))>;
277 decltype(auto) x_vec = as_column_vector_or_scalar(std::forward<T1>(x));
278 decltype(auto) y_vec = as_column_vector_or_scalar(std::forward<T2>(y));
279 std::vector<T_return> result(x_vec.size());
280 Eigen::Map<Eigen::Matrix<T_return, -1, 1>>(result.data(), result.size())
281 = x_vec.binaryExpr(y_vec, std::forward<F>(f));
282 return result;
283}
284
303template <typename F, typename T1, typename T2,
304 require_std_vector_vt<is_stan_scalar, T1>* = nullptr,
305 require_stan_scalar_t<T2>* = nullptr>
306inline auto apply_scalar_binary(F&& f, T1&& x, T2&& y) {
307 decltype(auto) x_vec = as_column_vector_or_scalar(std::forward<T1>(x));
308 using T_return = std::decay_t<decltype(f(x[0], y))>;
309 std::vector<T_return> result(x_vec.size());
310 Eigen::Map<Eigen::Matrix<T_return, -1, 1>>(result.data(), result.size())
311 = x_vec.unaryExpr(
312 [f_ = std::forward<F>(f), y](auto&& v) { return f_(v, y); });
313 return result;
314}
315
334template <typename F, typename T1, typename T2,
335 require_stan_scalar_t<T1>* = nullptr,
336 require_std_vector_vt<is_stan_scalar, T2>* = nullptr>
337inline auto apply_scalar_binary(F&& f, T1&& x, T2&& y) {
338 using T_return = std::decay_t<decltype(f(x, y[0]))>;
339 decltype(auto) y_vec = as_column_vector_or_scalar(std::forward<T2>(y));
340 std::vector<T_return> result(y_vec.size());
341 Eigen::Map<Eigen::Matrix<T_return, -1, 1>>(result.data(), result.size())
342 = y_vec.unaryExpr(
343 [f_ = std::forward<F>(f), x](auto&& v) { return f_(x, v); });
344 return result;
345}
346
361template <
362 typename F, typename T1, typename T2,
363 require_all_std_vector_vt<is_container_or_var_matrix, T1, T2>* = nullptr>
364inline auto apply_scalar_binary(F&& f, T1&& x, T2&& y) {
365 check_matching_sizes("Binary function", "x", x, "y", y);
366 using T_return = plain_type_t<decltype(apply_scalar_binary(f, x[0], y[0]))>;
367 size_t y_size = y.size();
368 std::vector<T_return> result(y_size);
369 for (size_t i = 0; i < y_size; ++i) {
370 result[i] = apply_scalar_binary(f, x[i], y[i]);
371 }
372 return result;
373}
374
389template <typename F, typename T1, typename T2,
390 require_std_vector_vt<is_container_or_var_matrix, T1>* = nullptr,
391 require_stan_scalar_t<T2>* = nullptr>
392inline auto apply_scalar_binary(F&& f, T1&& x, T2&& y) {
393 using T_return = plain_type_t<decltype(apply_scalar_binary(f, x[0], y))>;
394 size_t x_size = x.size();
395 std::vector<T_return> result(x_size);
396 for (size_t i = 0; i < x_size; ++i) {
397 result[i] = apply_scalar_binary(f, x[i], y);
398 }
399 return result;
400}
401
416template <typename F, typename T1, typename T2,
417 require_stan_scalar_t<T1>* = nullptr,
418 require_std_vector_vt<is_container_or_var_matrix, T2>* = nullptr>
419inline auto apply_scalar_binary(F&& f, T1&& x, T2&& y) {
420 using T_return = plain_type_t<decltype(apply_scalar_binary(f, x, y[0]))>;
421 size_t y_size = y.size();
422 std::vector<T_return> result(y_size);
423 for (size_t i = 0; i < y_size; ++i) {
424 result[i] = apply_scalar_binary(f, x, y[i]);
425 }
426 return result;
427}
428
429} // namespace math
430} // namespace stan
431#endif
require_t< container_type_check_base< is_eigen_matrix_dynamic, value_type_t, TypeCheck, Check... > > require_eigen_matrix_dynamic_vt
Require type satisfies is_eigen_matrix_dynamic.
require_all_t< is_eigen< std::decay_t< Types > >... > require_all_eigen_t
Require all of the types satisfy is_eigen.
Definition is_eigen.hpp:123
require_t< container_type_check_base< is_eigen_vector, value_type_t, TypeCheck, Check... > > require_eigen_vector_vt
Require type satisfies is_eigen_vector.
auto as_column_vector_or_scalar(T &&a)
as_column_vector_or_scalar of a kernel generator expression.
require_t< container_type_check_base< is_std_vector, value_type_t, TypeCheck, Check... > > require_std_vector_vt
Require type satisfies is_std_vector.
require_t< container_type_check_base< is_std_vector, scalar_type_t, TypeCheck, Check... > > require_std_vector_st
Require type satisfies is_std_vector.
typename value_type< T >::type value_type_t
Helper function for accessing underlying type.
typename promote_scalar_type< std::decay_t< T >, std::decay_t< S > >::type promote_scalar_t
auto apply_scalar_binary(F &&f, T1 &&x, T2 &&y)
Base template function for vectorization of binary scalar functions defined by applying a functor to ...
void check_matching_dims(const char *function, const char *name1, const T1 &y1, const char *name2, const T2 &y2)
Check if the two containers have the same dimensions.
auto make_holder(F &&func, Args &&... args)
Calls given function with given arguments.
Definition holder.hpp:437
void check_matching_sizes(const char *function, const char *name1, const T_y1 &y1, const char *name2, const T_y2 &y2)
Check if two structures at the same size.
int64_t num_elements(const T &m)
Returns the number of the elements of a matrix_cl or var_value<matrix_cl<T>>.
typename plain_type< std::decay_t< T > >::type plain_type_t
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...