1 #ifndef STAN_MATH_PRIM_META_RETURN_TYPE_HPP
2 #define STAN_MATH_PRIM_META_RETURN_TYPE_HPP
3 
4 #include <stan/math/prim/fun/Eigen.hpp>
5 #include <stan/math/prim/meta/promote_args.hpp>
6 #include <stan/math/prim/meta/base_type.hpp>
7 #include <stan/math/prim/meta/scalar_type.hpp>
8 #include <complex>
9 #include <vector>
10 
11 namespace stan {
12 
13 /**
14  * Provides a member type alias named `type`, the value of which is
15  * the least type under Stan's assignability relation that can be
16  * assigned a `double` and all of the base types of the specified
17  * arguments after removing qualifiers (`const` and `volatile`) and
18  * decaying (lvalue to rvalue by removing references) and array to
19  * pointer).   This type trait is used to calculate the return type
20  * of real-valued functions involving heterogeneous arguments.
21  *
22  * @tparam Ts sequence of template parameter types
23  * @see return_type for a definition of the type ordering
24  * @see base_type for definition of base type extraction
25  * @ingroup type_trait
26  */
27 template <typename... Ts>
28 struct real_return {
29   using type = double;
30 };
31 
32 template <typename T, typename... Ts>
33 struct real_return<T, Ts...> {
34   using type
35       = promote_args_t<base_type_t<T>, typename real_return<Ts...>::type>;
36 };
37 
38 /**
39  * Convenience type to calculate the real return type.
40  *
41  * @tparam Ts sequence of argument types
42  * @see real_return
43  * @ingroup type_trait
44  */
45 template <typename... Ts>
46 using real_return_t = typename real_return<Ts...>::type;
47 
48 /**
49  * Convenience type to calculate the complex return type, which wraps
50  * `std::complex` around the return type of the specified template parameters.
51  *
52  * @tparam Ts sequence of argument types
53  * @see real_return
54  * @ingroup type_trait
55  */
56 template <typename... Ts>
57 using complex_return_t = std::complex<real_return_t<Ts...>>;
58 
59 /**
60  * Convenience type to calculate the complex return type, which wraps
61  * `std::vector` around the return type of the specified template parameters.
62  *
63  * @tparam Ts sequence of argument types
64  * @see real_return
65  * @ingroup type_trait
66  */
67 template <typename... Ts>
68 using std_vector_return_t = std::vector<real_return_t<Ts...>>;
69 
70 /**
71  * Convenience type to calculate the complex return type, which wraps
72  * `Eigen::Matrix< , -1, -1>` around the return type of the specified
73  * template parameters.
74  *
75  * @tparam Ts sequence of argument types
76  * @see real_return
77  * @ingroup type_trait
78  */
79 template <typename... Ts>
80 using matrix_return_t = Eigen::Matrix<real_return_t<Ts...>, -1, -1>;
81 
82 /**
83  * Convenience type to calculate the complex return type, which wraps
84  * `Eigen::Matrix< , -1, 1>` around the return type of the specified
85  * template parameters.
86  *
87  * @tparam Ts sequence of argument types
88  * @see real_return
89  * @ingroup type_trait
90  */
91 template <typename... Ts>
92 using vector_return_t = Eigen::Matrix<real_return_t<Ts...>, -1, 1>;
93 
94 /**
95  * Convenience type to calculate the complex return type, which wraps
96  * `Eigen::Matrix< , 1, -1>` around the return type of the specified
97  * template parameters.
98  *
99  * @tparam Ts sequence of argument types
100  * @see real_return
101  * @ingroup type_trait
102  */
103 template <typename... Ts>
104 using row_vector_return_t = Eigen::Matrix<real_return_t<Ts...>, 1, -1>;
105 
106 /**
107  * Defines a member type named `type` that is the least scalar type to
108  * which both template parameter scalar types are assignable in Stan.
109  * The ordering of types for which this is the least-upper-bound
110  * operation is defined in the class documentation for `return_type`.
111  *
112  * @tparam T1 first scalar type
113  * @tparam T2 second scalar type
114  * @see return_type
115  * @ingroup type_trait
116  */
117 template <typename T1, typename T2>
118 struct scalar_lub {
119   using type = promote_args_t<T1, T2>;
120 };
121 
122 template <typename T1, typename T2>
123 struct scalar_lub<std::complex<T1>, T2> {
124   using type = std::complex<promote_args_t<T1, T2>>;
125 };
126 
127 template <typename T1, typename T2>
128 struct scalar_lub<T1, std::complex<T2>> {
129   using type = std::complex<promote_args_t<T1, T2>>;
130 };
131 
132 template <typename T1, typename T2>
133 struct scalar_lub<std::complex<T1>, std::complex<T2>> {
134   using type = std::complex<promote_args_t<T1, T2>>;
135 };
136 
137 /**
138  * Convenience type for the least upper bound of the specified
139  * template parameters in Stan's assignment ordering.
140  *
141  * @param T1 first type
142  * @param T2 second type
143  * @see scalar_lub
144  * @ingroup type_trait
145  */
146 template <typename T1, typename T2>
147 using scalar_lub_t = typename scalar_lub<T1, T2>::type;
148 
149 /**
150  * Template metaprogram to calculate the base scalar return type
151  * resulting from promoting all the scalar types of the template
152  * parameters to the least type to which all the base types of the
153  * arguments are assignable. The metaprogram can take an arbitrary
154  * number of template parameters.
155  *
156  * Complex numbers (instances of `std::complex<T>`) are considered
157  * scalars.  All C++ primitive types (except `long double`) are
158  * automatically promoted to `double`.
159  *
160  * The set of autodiff types is defined to be the smallest such that
161  * - `var` is an autodiff type,
162  * - `fvar<double>` is an autodiff type, and
163  * - `fvar<T>` is an autodiff type if `T` is an autodiff type.
164 
165  * The set of scalar types is defined to be the smallest such that
166  * - `double` and `long double` are scalar types,
167  * - `T` is a scalar type if `T` is an autodiff type,
168  * - `complex<double>` is a scalar type, and
169  * - `complex<T>` is a scalar type if `T` is an autodiff type.
170  *
171  * The assignability relation among scalar types is defined to be
172  * the smallest such that
173  * - `double` is assignable to any type `T`,
174  * - `T1` is assignable to `std::complex<T2>` if `T1` is assignable to
175  * - `T2`, and
176  * - `std::complex<T1>` is assignable to `std::complex<T2>` if `T1` is
177  * assignable to `T2`.
178  *
179  * Example usage:
180  *  - `return_type_t<int, double, float>` is `double`
181  *  - `return_type_t<double, var>` is `var`
182  *
183  * @tparam Ts sequence of input types
184  * @ingroup type_trait
185  */
186 template <typename... Ts>
187 struct return_type {
188   using type = double;
189 };
190 
191 template <typename T, typename... Ts>
192 struct return_type<T, Ts...> {
193   using type
194       = scalar_lub_t<scalar_type_t<T>, typename return_type<Ts...>::type>;
195 };
196 
197 /**
198  * Convenience type for the return type of the specified template
199  * parameters.
200  *
201  * @tparam Ts sequence of types
202  * @see return_type
203  * @ingroup type_trait
204  */
205 template <typename... Ts>
206 using return_type_t = typename return_type<Ts...>::type;
207 
208 /**
209  * \ingroup require_stan_scalar_real
210  * \addtogroup autodiff_types
211  * \brief Require return type from parameter pack satisfies `Check`
212  */
213 template <template <class...> class Check, typename... Ts>
214 using require_return_type_t = require_t<Check<return_type_t<Ts...>>>;
215 
216 /**
217  * \ingroup require_stan_scalar_real
218  * \addtogroup autodiff_types
219  * \brief Require return type from parameter pack does not satisfy `Check`
220  */
221 template <template <class...> class Check, typename... Ts>
222 using require_not_return_type_t = require_not_t<Check<return_type_t<Ts...>>>;
223 
224 }  // namespace stan
225 #endif
226