1 #ifndef STAN_MATH_PRIM_FUNCTOR_APPLY_VECTOR_UNARY_HPP 2 #define STAN_MATH_PRIM_FUNCTOR_APPLY_VECTOR_UNARY_HPP 3 4 #include <stan/math/prim/fun/Eigen.hpp> 5 #include <stan/math/prim/fun/as_column_vector_or_scalar.hpp> 6 #include <stan/math/prim/meta/is_stan_scalar.hpp> 7 #include <stan/math/prim/meta/is_container.hpp> 8 #include <stan/math/prim/meta/is_eigen_matrix_base.hpp> 9 #include <stan/math/prim/meta/plain_type.hpp> 10 #include <stan/math/prim/meta/require_generics.hpp> 11 #include <vector> 12 13 namespace stan { 14 namespace math { 15 // Forward declaration to allow specialisations 16 template <typename T, typename Enable = void> 17 struct apply_vector_unary {}; 18 19 /** 20 * Base template class for vectorization of unary vector functions 21 * defined by applying a functor to a standard library vector, Eigen dense 22 * matrix expression template, or container of these. For each specialisation, 23 * the same vector type as the input is returned. 24 * 25 * Two taxonomies of unary vector functions are implemented: 26 * - f(vector) -> vector 27 * - f(vector) -> scalar 28 * 29 * This base template class takes (and returns) Eigen expression templates. 30 */ 31 template <typename T> 32 struct apply_vector_unary<T, require_eigen_t<T>> { 33 /** 34 * Member function for applying a functor to a vector and subsequently 35 * returning a vector. 36 * 37 * @tparam T Type of argument to which functor is applied. 38 * @tparam F Type of functor to apply. 39 * @param x Eigen input to which operation is applied. 40 * @param f functor to apply to Eigen input. 41 * @return Eigen object with result of applying functor to input 42 */ 43 template <typename F, typename T2 = T, 44 require_t<is_eigen_matrix_base<plain_type_t<T2>>>* = nullptr> applystan::math::apply_vector_unary45 static inline auto apply(const T& x, const F& f) { 46 return make_holder([](const auto& a) { return a.matrix().derived(); }, 47 f(x)); 48 } 49 50 template <typename F, typename T2 = T, 51 require_t<is_eigen_array<plain_type_t<T2>>>* = nullptr> applystan::math::apply_vector_unary52 static inline auto apply(const T& x, const F& f) { 53 return make_holder([](const auto& a) { return a.array().derived(); }, f(x)); 54 } 55 56 /** 57 * Member function for applying a functor to a vector and subsequently 58 * returning a vector. This is a variant of `apply` that does not construct 59 * `holder`, so it is up to the caller to ensure the returned expression is 60 * evaluated before `x` is destructed. 61 * 62 * @tparam T Type of argument to which functor is applied. 63 * @tparam F Type of functor to apply. 64 * @param x Eigen input to which operation is applied. 65 * @param f functor to apply to Eigen input. 66 * @return Eigen object with result of applying functor to input 67 */ 68 template <typename F, typename T2 = T, 69 require_t<is_eigen_matrix_base<plain_type_t<T2>>>* = nullptr> apply_no_holderstan::math::apply_vector_unary70 static inline auto apply_no_holder(const T& x, const F& f) { 71 return f(x).matrix().derived(); 72 } 73 74 template <typename F, typename T2 = T, 75 require_t<is_eigen_array<plain_type_t<T2>>>* = nullptr> apply_no_holderstan::math::apply_vector_unary76 static inline auto apply_no_holder(const T& x, const F& f) { 77 return f(x).array().derived(); 78 } 79 80 /** 81 * Member function for applying a functor to a vector and subsequently 82 * returning a scalar. The reduction to a scalar needs to be implemented 83 * in the definition of the functor. 84 * 85 * @tparam T Type of argument to which functor is applied. 86 * @tparam F Type of functor to apply. 87 * @param x Eigen input to which operation is applied. 88 * @param f functor to apply to Eigen input. 89 * @return scalar result of applying functor to input. 90 */ 91 template <typename F> reducestan::math::apply_vector_unary92 static inline auto reduce(const T& x, const F& f) { 93 return f(x); 94 } 95 }; 96 97 /** 98 * Specialisation for use with (non-nested) std::vectors. Inputs are mapped 99 * to Eigen column vectors and then the result is evaluated directly into the 100 * returned std::vector (via Eigen::Map). 101 * 102 * The returned scalar type is deduced to allow for cases where the input and 103 * return scalar types differ (e.g., functions implicitly promoting 104 * integers). 105 */ 106 template <typename T> 107 struct apply_vector_unary<T, require_std_vector_vt<is_stan_scalar, T>> { 108 using T_vt = value_type_t<T>; 109 using T_map = typename Eigen::Map<const Eigen::Matrix<T_vt, -1, 1>>; 110 111 /** 112 * Member function for applying a functor to a vector and subsequently 113 * returning a vector. 114 * 115 * @tparam T Type of argument to which functor is applied. 116 * @tparam F Type of functor to apply. 117 * @param x std::vector input to which operation is applied. 118 * @param f functor to apply to vector input. 119 * @return std::vector with result of applying functor to input. 120 */ 121 template <typename F> applystan::math::apply_vector_unary122 static inline auto apply(const T& x, const F& f) { 123 using T_return = value_type_t<decltype(f(as_column_vector_or_scalar(x)))>; 124 std::vector<T_return> result(x.size()); 125 Eigen::Map<Eigen::Matrix<T_return, -1, 1>>(result.data(), result.size()) 126 = f(as_column_vector_or_scalar(x)).matrix(); 127 return result; 128 } 129 130 /** 131 * Member function for applying a functor to each container in an std::vector 132 * and subsequently returning an std::vector of containers. 133 * 134 * @tparam T Type of argument to which functor is applied. 135 * @tparam F Type of functor to apply. 136 * @param x std::vector of containers to which operation is applied. 137 * @param f functor to apply to vector input. 138 * @return std::vector of containers with result of applying functor to 139 * input. 140 */ 141 template <typename F> apply_no_holderstan::math::apply_vector_unary142 static inline auto apply_no_holder(const T& x, const F& f) { 143 return apply(x, f); 144 } 145 146 /** 147 * Member function for applying a functor to a vector and subsequently 148 * returning a scalar. 149 * 150 * @tparam T Type of argument to which functor is applied. 151 * @tparam F Type of functor to apply. 152 * @param x Eigen input to which operation is applied. 153 * @param f functor to apply to std::vector input. 154 * @return scalar result of applying functor to input vector. 155 */ 156 template <typename F> reducestan::math::apply_vector_unary157 static inline auto reduce(const T& x, const F& f) { 158 return apply_vector_unary<T_map>::reduce(as_column_vector_or_scalar(x), f); 159 } 160 }; 161 162 /** 163 * Specialisation for use with nested containers (std::vectors). 164 * For each of the member functions, an std::vector with the appropriate 165 * type (vector or scalar) is returned. 166 * 167 * The returned scalar type is deduced to allow for cases where the input and 168 * return scalar types differ (e.g., functions implicitly promoting 169 * integers). 170 * 171 */ 172 template <typename T> 173 struct apply_vector_unary< 174 T, require_std_vector_vt<is_container_or_var_matrix, T>> { 175 using T_vt = value_type_t<T>; 176 177 /** 178 * Member function for applying a functor to each container in an std::vector 179 * and subsequently returning an std::vector of containers. 180 * 181 * @tparam T Type of argument to which functor is applied. 182 * @tparam F Type of functor to apply. 183 * @param x std::vector of containers to which operation is applied. 184 * @param f functor to apply to vector input. 185 * @return std::vector of containers with result of applying functor to 186 * input. 187 */ 188 template <typename F> applystan::math::apply_vector_unary189 static inline auto apply(const T& x, const F& f) { 190 using T_return 191 = plain_type_t<decltype(apply_vector_unary<T_vt>::apply(x[0], f))>; 192 std::vector<T_return> result(x.size()); 193 std::transform(x.begin(), x.end(), result.begin(), [&f](auto&& xx) { 194 return apply_vector_unary<T_vt>::apply_no_holder(xx, f); 195 }); 196 return result; 197 } 198 199 /** 200 * Member function for applying a functor to each container in an std::vector 201 * and subsequently returning an std::vector of containers. 202 * 203 * @tparam T Type of argument to which functor is applied. 204 * @tparam F Type of functor to apply. 205 * @param x std::vector of containers to which operation is applied. 206 * @param f functor to apply to vector input. 207 * @return std::vector of containers with result of applying functor to 208 * input. 209 */ 210 template <typename F> apply_no_holderstan::math::apply_vector_unary211 static inline auto apply_no_holder(const T& x, const F& f) { 212 return apply(x, f); 213 } 214 215 /** 216 * Member function for applying a functor to each container in an 217 * std::vector and subsequently returning an std::vector of scalars. 218 * 219 * @tparam T Type of argument to which functor is applied. 220 * @tparam F Type of functor to apply. 221 * @param x std::vector of containers to which operation is applied. 222 * @param f functor to apply to vector input. 223 * @return std::vector of scalars with result of applying functor to input. 224 */ 225 template <typename F> reducestan::math::apply_vector_unary226 static inline auto reduce(const T& x, const F& f) { 227 size_t x_size = x.size(); 228 using T_return = decltype(apply_vector_unary<T_vt>::reduce(x[0], f)); 229 std::vector<T_return> result(x_size); 230 for (size_t i = 0; i < x_size; ++i) 231 result[i] = apply_vector_unary<T_vt>::reduce(x[i], f); 232 return result; 233 } 234 }; 235 236 } // namespace math 237 } // namespace stan 238 #endif 239