1 #ifndef STAN_MATH_PRIM_FUN_OFFSET_MULTIPLIER_CONSTRAIN_HPP
2 #define STAN_MATH_PRIM_FUN_OFFSET_MULTIPLIER_CONSTRAIN_HPP
3
4 #include <stan/math/prim/meta.hpp>
5 #include <stan/math/prim/err.hpp>
6 #include <stan/math/prim/fun/fma.hpp>
7 #include <stan/math/prim/fun/identity_constrain.hpp>
8 #include <stan/math/prim/fun/multiply_log.hpp>
9 #include <stan/math/prim/fun/size.hpp>
10 #include <stan/math/prim/fun/sum.hpp>
11 #include <stan/math/prim/fun/to_ref.hpp>
12 #include <cmath>
13
14 namespace stan {
15 namespace math {
16
17 /**
18 * Return the linearly transformed value for the specified unconstrained input
19 * and specified offset and multiplier.
20 *
21 * <p>The transform applied is
22 *
23 * <p>\f$f(x) = mu + sigma * x\f$
24 *
25 * <p>where mu is the offset and sigma is the multiplier.
26 *
27 * <p>If the offset is zero and the multiplier is one this
28 * reduces to <code>identity_constrain(x)</code>.
29 *
30 * @tparam T type of scalar
31 * @tparam M type of offset
32 * @tparam S type of multiplier
33 * @param[in] x Unconstrained scalar input
34 * @param[in] mu offset of constrained output
35 * @param[in] sigma multiplier of constrained output
36 * @return linear transformed value corresponding to inputs
37 * @throw std::domain_error if sigma <= 0
38 * @throw std::domain_error if mu is not finite
39 */
40 template <typename T, typename M, typename S,
41 require_all_not_nonscalar_prim_or_rev_kernel_expression_t<
42 T, M, S>* = nullptr>
offset_multiplier_constrain(const T & x,const M & mu,const S & sigma)43 inline auto offset_multiplier_constrain(const T& x, const M& mu,
44 const S& sigma) {
45 const auto& mu_ref = to_ref(mu);
46 const auto& sigma_ref = to_ref(sigma);
47 if (is_matrix<T>::value && is_matrix<M>::value) {
48 check_matching_dims("offset_multiplier_constrain", "x", x, "mu", mu);
49 }
50 if (is_matrix<T>::value && is_matrix<S>::value) {
51 check_matching_dims("offset_multiplier_constrain", "x", x, "sigma", sigma);
52 } else if (is_matrix<M>::value && is_matrix<S>::value) {
53 check_matching_dims("offset_multiplier_constrain", "mu", mu, "sigma",
54 sigma);
55 }
56
57 check_finite("offset_multiplier_constrain", "offset", value_of_rec(mu_ref));
58 check_positive_finite("offset_multiplier_constrain", "multiplier",
59 value_of_rec(sigma_ref));
60 return fma(sigma_ref, x, mu_ref);
61 }
62
63 /**
64 * Return the linearly transformed value for the specified unconstrained input
65 * and specified offset and multiplier, incrementing the specified
66 * reference with the log absolute Jacobian determinant of the
67 * transform.
68 *
69 * <p>The transform applied is
70 *
71 * <p>\f$f(x) = mu + sigma * x\f$
72 *
73 * <p>where mu is the offset and sigma is the multiplier.
74 *
75 * If the offset is zero and multiplier is one, this function
76 * reduces to <code>identity_constraint(x, lp)</code>.
77 *
78 * @tparam T type of scalar
79 * @tparam M type of offset
80 * @tparam S type of multiplier
81 * @param[in] x Unconstrained scalar input
82 * @param[in] mu offset of constrained output
83 * @param[in] sigma multiplier of constrained output
84 * @param[in,out] lp Reference to log probability to increment.
85 * @return linear transformed value corresponding to inputs
86 * @throw std::domain_error if sigma <= 0
87 * @throw std::domain_error if mu is not finite
88 */
89 template <typename T, typename M, typename S,
90 require_all_not_nonscalar_prim_or_rev_kernel_expression_t<
91 T, M, S>* = nullptr>
offset_multiplier_constrain(const T & x,const M & mu,const S & sigma,return_type_t<T,M,S> & lp)92 inline auto offset_multiplier_constrain(const T& x, const M& mu, const S& sigma,
93 return_type_t<T, M, S>& lp) {
94 const auto& mu_ref = to_ref(mu);
95 const auto& sigma_ref = to_ref(sigma);
96 if (is_matrix<T>::value && is_matrix<M>::value) {
97 check_matching_dims("offset_multiplier_constrain", "x", x, "mu", mu);
98 }
99 if (is_matrix<T>::value && is_matrix<S>::value) {
100 check_matching_dims("offset_multiplier_constrain", "x", x, "sigma", sigma);
101 } else if (is_matrix<M>::value && is_matrix<S>::value) {
102 check_matching_dims("offset_multiplier_constrain", "mu", mu, "sigma",
103 sigma);
104 }
105
106 check_finite("offset_multiplier_constrain", "offset", value_of_rec(mu_ref));
107 check_positive_finite("offset_multiplier_constrain", "multiplier",
108 value_of_rec(sigma_ref));
109 if (size(sigma_ref) == 1) {
110 lp += sum(multiply_log(size(x), sigma_ref));
111 } else {
112 lp += sum(log(sigma_ref));
113 }
114 return fma(sigma_ref, x, mu_ref);
115 }
116
117 /**
118 * Overload for array of x and non-array mu and sigma
119 */
120 template <typename T, typename M, typename S,
121 require_all_not_std_vector_t<M, S>* = nullptr>
offset_multiplier_constrain(const std::vector<T> & x,const M & mu,const S & sigma)122 inline auto offset_multiplier_constrain(const std::vector<T>& x, const M& mu,
123 const S& sigma) {
124 std::vector<
125 plain_type_t<decltype(offset_multiplier_constrain(x[0], mu, sigma))>>
126 ret;
127 ret.reserve(x.size());
128 const auto& mu_ref = to_ref(mu);
129 const auto& sigma_ref = to_ref(sigma);
130 for (size_t i = 0; i < x.size(); ++i) {
131 ret.emplace_back(offset_multiplier_constrain(x[i], mu_ref, sigma_ref));
132 }
133 return ret;
134 }
135
136 /**
137 * Overload for array of x and non-array mu and sigma with lp
138 */
139 template <typename T, typename M, typename S,
140 require_all_not_std_vector_t<M, S>* = nullptr>
offset_multiplier_constrain(const std::vector<T> & x,const M & mu,const S & sigma,return_type_t<T,M,S> & lp)141 inline auto offset_multiplier_constrain(const std::vector<T>& x, const M& mu,
142 const S& sigma,
143 return_type_t<T, M, S>& lp) {
144 std::vector<
145 plain_type_t<decltype(offset_multiplier_constrain(x[0], mu, sigma, lp))>>
146 ret;
147 ret.reserve(x.size());
148 const auto& mu_ref = to_ref(mu);
149 const auto& sigma_ref = to_ref(sigma);
150 for (size_t i = 0; i < x.size(); ++i) {
151 ret.emplace_back(offset_multiplier_constrain(x[i], mu_ref, sigma_ref, lp));
152 }
153 return ret;
154 }
155
156 /**
157 * Overload for array of x and sigma and non-array mu
158 */
159 template <typename T, typename M, typename S,
160 require_not_std_vector_t<M>* = nullptr>
offset_multiplier_constrain(const std::vector<T> & x,const M & mu,const std::vector<S> & sigma)161 inline auto offset_multiplier_constrain(const std::vector<T>& x, const M& mu,
162 const std::vector<S>& sigma) {
163 check_matching_dims("offset_multiplier_constrain", "x", x, "sigma", sigma);
164 std::vector<
165 plain_type_t<decltype(offset_multiplier_constrain(x[0], mu, sigma[0]))>>
166 ret;
167 ret.reserve(x.size());
168 const auto& mu_ref = to_ref(mu);
169 for (size_t i = 0; i < x.size(); ++i) {
170 ret.emplace_back(offset_multiplier_constrain(x[i], mu_ref, sigma[i]));
171 }
172 return ret;
173 }
174
175 /**
176 * Overload for array of x and sigma and non-array mu with lp
177 */
178 template <typename T, typename M, typename S,
179 require_not_std_vector_t<M>* = nullptr>
offset_multiplier_constrain(const std::vector<T> & x,const M & mu,const std::vector<S> & sigma,return_type_t<T,M,S> & lp)180 inline auto offset_multiplier_constrain(const std::vector<T>& x, const M& mu,
181 const std::vector<S>& sigma,
182 return_type_t<T, M, S>& lp) {
183 check_matching_dims("offset_multiplier_constrain", "x", x, "sigma", sigma);
184 std::vector<plain_type_t<decltype(
185 offset_multiplier_constrain(x[0], mu, sigma[0], lp))>>
186 ret;
187 ret.reserve(x.size());
188 const auto& mu_ref = to_ref(mu);
189 for (size_t i = 0; i < x.size(); ++i) {
190 ret.emplace_back(offset_multiplier_constrain(x[i], mu_ref, sigma[i], lp));
191 }
192 return ret;
193 }
194
195 /**
196 * Overload for array of x and mu and non-array sigma
197 */
198 template <typename T, typename M, typename S,
199 require_not_std_vector_t<S>* = nullptr>
offset_multiplier_constrain(const std::vector<T> & x,const std::vector<M> & mu,const S & sigma)200 inline auto offset_multiplier_constrain(const std::vector<T>& x,
201 const std::vector<M>& mu,
202 const S& sigma) {
203 check_matching_dims("offset_multiplier_constrain", "x", x, "mu", mu);
204 std::vector<
205 plain_type_t<decltype(offset_multiplier_constrain(x[0], mu[0], sigma))>>
206 ret;
207 ret.reserve(x.size());
208 const auto& sigma_ref = to_ref(sigma);
209 for (size_t i = 0; i < x.size(); ++i) {
210 ret.emplace_back(offset_multiplier_constrain(x[i], mu[i], sigma_ref));
211 }
212 return ret;
213 }
214
215 /**
216 * Overload for array of x and mu and non-array sigma with lp
217 */
218 template <typename T, typename M, typename S,
219 require_not_std_vector_t<S>* = nullptr>
offset_multiplier_constrain(const std::vector<T> & x,const std::vector<M> & mu,const S & sigma,return_type_t<T,M,S> & lp)220 inline auto offset_multiplier_constrain(const std::vector<T>& x,
221 const std::vector<M>& mu,
222 const S& sigma,
223 return_type_t<T, M, S>& lp) {
224 check_matching_dims("offset_multiplier_constrain", "x", x, "mu", mu);
225 std::vector<plain_type_t<decltype(
226 offset_multiplier_constrain(x[0], mu[0], sigma, lp))>>
227 ret;
228 ret.reserve(x.size());
229 const auto& sigma_ref = to_ref(sigma);
230 for (size_t i = 0; i < x.size(); ++i) {
231 ret.emplace_back(offset_multiplier_constrain(x[i], mu[i], sigma_ref, lp));
232 }
233 return ret;
234 }
235
236 /**
237 * Overload for array of x, mu, and sigma
238 */
239 template <typename T, typename M, typename S>
offset_multiplier_constrain(const std::vector<T> & x,const std::vector<M> & mu,const std::vector<S> & sigma)240 inline auto offset_multiplier_constrain(const std::vector<T>& x,
241 const std::vector<M>& mu,
242 const std::vector<S>& sigma) {
243 check_matching_dims("offset_multiplier_constrain", "x", x, "mu", mu);
244 check_matching_dims("offset_multiplier_constrain", "x", x, "sigma", sigma);
245 std::vector<plain_type_t<decltype(
246 offset_multiplier_constrain(x[0], mu[0], sigma[0]))>>
247 ret;
248 ret.reserve(x.size());
249 for (size_t i = 0; i < x.size(); ++i) {
250 ret.emplace_back(offset_multiplier_constrain(x[i], mu[i], sigma[i]));
251 }
252 return ret;
253 }
254
255 /**
256 * Overload for array of x, mu, and sigma with lp
257 */
258 template <typename T, typename M, typename S>
offset_multiplier_constrain(const std::vector<T> & x,const std::vector<M> & mu,const std::vector<S> & sigma,return_type_t<T,M,S> & lp)259 inline auto offset_multiplier_constrain(const std::vector<T>& x,
260 const std::vector<M>& mu,
261 const std::vector<S>& sigma,
262 return_type_t<T, M, S>& lp) {
263 check_matching_dims("offset_multiplier_constrain", "x", x, "mu", mu);
264 check_matching_dims("offset_multiplier_constrain", "x", x, "sigma", sigma);
265 std::vector<plain_type_t<decltype(
266 offset_multiplier_constrain(x[0], mu[0], sigma[0], lp))>>
267 ret;
268 ret.reserve(x.size());
269 for (size_t i = 0; i < x.size(); ++i) {
270 ret.emplace_back(offset_multiplier_constrain(x[i], mu[i], sigma[i], lp));
271 }
272 return ret;
273 }
274
275 /**
276 * Return the linearly transformed value for the specified unconstrained input
277 * and specified offset and multiplier. If the `Jacobian` parameter is `true`,
278 * the log density accumulator is incremented with the log absolute Jacobian
279 * determinant of the transform. All of the transforms are specified with their
280 * Jacobians in the *Stan Reference Manual* chapter Constraint Transforms.
281 *
282 * @tparam Jacobian if `true`, increment log density accumulator with log
283 * absolute Jacobian determinant of constraining transform
284 * @tparam T A type inheriting from `Eigen::EigenBase`, a `var_value` with inner
285 * type inheriting from `Eigen::EigenBase`, a standard vector, or a scalar
286 * @tparam M A type inheriting from `Eigen::EigenBase`, a `var_value` with inner
287 * type inheriting from `Eigen::EigenBase`, a standard vector, or a scalar
288 * @tparam S A type inheriting from `Eigen::EigenBase`, a `var_value` with inner
289 * type inheriting from `Eigen::EigenBase`, a standard vector, or a scalar
290 * @param[in] x Unconstrained scalar input
291 * @param[in] mu offset of constrained output
292 * @param[in] sigma multiplier of constrained output
293 * @param[in, out] lp log density accumulator
294 * @return linear transformed value corresponding to inputs
295 * @throw std::domain_error if sigma <= 0
296 * @throw std::domain_error if mu is not finite
297 */
298 template <bool Jacobian, typename T, typename M, typename S>
offset_multiplier_constrain(const T & x,const M & mu,const S & sigma,return_type_t<T,M,S> & lp)299 inline auto offset_multiplier_constrain(const T& x, const M& mu, const S& sigma,
300 return_type_t<T, M, S>& lp) {
301 if (Jacobian) {
302 return offset_multiplier_constrain(x, mu, sigma, lp);
303 } else {
304 return offset_multiplier_constrain(x, mu, sigma);
305 }
306 }
307
308 } // namespace math
309 } // namespace stan
310
311 #endif
312