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 T1, typename T2, typename F,
36 require_all_stan_scalar_t<T1, T2>* = nullptr>
37inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) {
38 return f(x, y);
39}
40
54template <typename T1, typename T2, typename F,
56inline auto apply_scalar_binary(T1&& x, T2&& y, F&& f) {
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 x_inner.binaryExpr(y_inner, f_inner);
61 },
62 std::forward<F>(f), std::forward<T1>(x), std::forward<T2>(y));
63}
64
77template <typename T1, typename T2, typename F,
80inline auto apply_scalar_binary(T1&& x, T2&& y, F&& f) {
81 check_matching_sizes("Binary function", "x", x, "y", y);
82 return make_holder(
83 [](auto& f_inner, auto& x_inner, auto& y_inner) {
84 using int_vec_t = promote_scalar_t<value_type_t<decltype(y_inner)>,
85 plain_type_t<decltype(x_inner)>>;
86 Eigen::Map<const int_vec_t> y_map(y_inner.data(), y_inner.size());
87 return x_inner.binaryExpr(y_map, f_inner);
88 },
89 std::forward<F>(f), std::forward<T1>(x), std::forward<T2>(y));
90}
91
104template <typename T1, typename T2, typename F,
107inline auto apply_scalar_binary(T1&& x, T2&& y, F&& f) {
108 check_matching_sizes("Binary function", "x", x, "y", y);
109 return make_holder(
110 [](auto& f_inner, auto& x_inner, auto& y_inner) {
111 using int_vec_t = promote_scalar_t<value_type_t<decltype(x_inner)>,
112 plain_type_t<decltype(y_inner)>>;
113 Eigen::Map<const int_vec_t> x_map(x_inner.data(), x_inner.size());
114 return x_map.binaryExpr(y_inner, f_inner);
115 },
116 std::forward<F>(f), std::forward<T1>(x), std::forward<T2>(y));
117}
118
131template <typename T1, typename T2, typename F,
132 require_eigen_matrix_dynamic_vt<is_stan_scalar, T1>* = nullptr,
133 require_std_vector_vt<is_std_vector, T2>* = nullptr,
134 require_std_vector_st<std::is_integral, T2>* = nullptr>
135inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) {
136 if (num_elements(x) != num_elements(y)) {
137 std::ostringstream msg;
138 msg << "Inputs to vectorized binary function must match in"
139 << " size if one is not a scalar";
140 throw std::invalid_argument(msg.str());
141 }
142 using return_st = decltype(f(x(0), y[0][0]));
143 Eigen::Matrix<return_st, Eigen::Dynamic, Eigen::Dynamic> result(x.rows(),
144 x.cols());
145 for (size_t i = 0; i < y.size(); ++i) {
146 result.row(i) = apply_scalar_binary(x.row(i).transpose(),
148 }
149 return result;
150}
151
164template <typename T1, typename T2, typename F,
168inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) {
169 if (num_elements(x) != num_elements(y)) {
170 std::ostringstream msg;
171 msg << "Inputs to vectorized binary function must match in"
172 << " size if one is not a scalar";
173 throw std::invalid_argument(msg.str());
174 }
175 using return_st = decltype(f(x[0][0], y(0)));
176 Eigen::Matrix<return_st, Eigen::Dynamic, Eigen::Dynamic> result(y.rows(),
177 y.cols());
178 for (size_t i = 0; i < x.size(); ++i) {
180 y.row(i).transpose(), f);
181 }
182 return result;
183}
184
200template <typename T1, typename T2, typename F, require_eigen_t<T1>* = nullptr,
201 require_stan_scalar_t<T2>* = nullptr>
202inline auto apply_scalar_binary(T1&& x, T2&& y, F&& f) {
203 return make_holder(
204 [](auto& f_inner, auto& x_inner, auto& y_inner) {
205 return x_inner.unaryExpr(
206 [f_inner, y_inner](const auto& v) { return f_inner(v, y_inner); });
207 },
208 std::forward<F>(f), std::forward<T1>(x), std::forward<T2>(y));
209}
210
226template <typename T1, typename T2, typename F,
227 require_stan_scalar_t<T1>* = nullptr, require_eigen_t<T2>* = nullptr>
228inline auto apply_scalar_binary(T1&& x, T2&& y, F&& f) {
229 return make_holder(
230 [](auto& f_inner, auto& x_inner, auto& y_inner) {
231 return y_inner.unaryExpr(
232 [f_inner, x_inner](const auto& v) { return f_inner(x_inner, v); });
233 },
234 std::forward<F>(f), std::forward<T1>(x), std::forward<T2>(y));
235}
236
254template <typename T1, typename T2, typename F,
255 require_all_std_vector_vt<is_stan_scalar, T1, T2>* = nullptr>
256inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) {
257 check_matching_sizes("Binary function", "x", x, "y", y);
258 decltype(auto) x_vec = as_column_vector_or_scalar(x);
259 decltype(auto) y_vec = as_column_vector_or_scalar(y);
260 using T_return = std::decay_t<decltype(f(x[0], y[0]))>;
261 std::vector<T_return> result(x.size());
262 Eigen::Map<Eigen::Matrix<T_return, -1, 1>>(result.data(), result.size())
263 = x_vec.binaryExpr(y_vec, f);
264 return result;
265}
266
285template <typename T1, typename T2, typename F,
286 require_std_vector_vt<is_stan_scalar, T1>* = nullptr,
287 require_stan_scalar_t<T2>* = nullptr>
288inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) {
289 decltype(auto) x_vec = as_column_vector_or_scalar(x);
290 using T_return = std::decay_t<decltype(f(x[0], y))>;
291 std::vector<T_return> result(x.size());
292 Eigen::Map<Eigen::Matrix<T_return, -1, 1>>(result.data(), result.size())
293 = x_vec.unaryExpr([f, y](const auto& v) { return f(v, y); });
294 return result;
295}
296
315template <typename T1, typename T2, typename F,
316 require_stan_scalar_t<T1>* = nullptr,
318inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) {
319 decltype(auto) y_vec = as_column_vector_or_scalar(y);
320 using T_return = std::decay_t<decltype(f(x, y[0]))>;
321 std::vector<T_return> result(y.size());
322 Eigen::Map<Eigen::Matrix<T_return, -1, 1>>(result.data(), result.size())
323 = y_vec.unaryExpr([f, x](const auto& v) { return f(x, v); });
324 return result;
325}
326
341template <
342 typename T1, typename T2, typename F,
343 require_all_std_vector_vt<is_container_or_var_matrix, T1, T2>* = nullptr>
344inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) {
345 check_matching_sizes("Binary function", "x", x, "y", y);
346 using T_return = plain_type_t<decltype(apply_scalar_binary(x[0], y[0], f))>;
347 size_t y_size = y.size();
348 std::vector<T_return> result(y_size);
349 for (size_t i = 0; i < y_size; ++i) {
350 result[i] = apply_scalar_binary(x[i], y[i], f);
351 }
352 return result;
353}
354
369template <typename T1, typename T2, typename F,
370 require_std_vector_vt<is_container_or_var_matrix, T1>* = nullptr,
371 require_stan_scalar_t<T2>* = nullptr>
372inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) {
373 using T_return = plain_type_t<decltype(apply_scalar_binary(x[0], y, f))>;
374 size_t x_size = x.size();
375 std::vector<T_return> result(x_size);
376 for (size_t i = 0; i < x_size; ++i) {
377 result[i] = apply_scalar_binary(x[i], y, f);
378 }
379 return result;
380}
381
396template <typename T1, typename T2, typename F,
397 require_stan_scalar_t<T1>* = nullptr,
398 require_std_vector_vt<is_container_or_var_matrix, T2>* = nullptr>
399inline auto apply_scalar_binary(const T1& x, const T2& y, const F& f) {
400 using T_return = plain_type_t<decltype(apply_scalar_binary(x, y[0], f))>;
401 size_t y_size = y.size();
402 std::vector<T_return> result(y_size);
403 for (size_t i = 0; i < y_size; ++i) {
404 result[i] = apply_scalar_binary(x, y[i], f);
405 }
406 return result;
407}
408
409} // namespace math
410} // namespace stan
411#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:120
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< is_stan_scalar< std::decay_t< T > > > require_stan_scalar_t
Require type satisfies is_stan_scalar.
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.
auto make_holder(const F &func, Args &&... args)
Constructs an expression from given arguments using given functor.
Definition holder.hpp:352
typename promote_scalar_type< std::decay_t< T >, std::decay_t< S > >::type promote_scalar_t
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.
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.
auto apply_scalar_binary(const T1 &x, const T2 &y, const F &f)
Base template function for vectorization of binary scalar functions defined by applying a functor to ...
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< T >::type plain_type_t
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...