Loading [MathJax]/extensions/TeX/AMSsymbols.js
Automatic Differentiation
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
lub_constrain.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_PRIM_CONSTRAINT_LUB_CONSTRAIN_HPP
2#define STAN_MATH_PRIM_CONSTRAINT_LUB_CONSTRAIN_HPP
3
20#include <cmath>
21
22namespace stan {
23namespace math {
24
44template <typename T, typename L, typename U,
45 require_all_stan_scalar_t<T, L, U>* = nullptr,
46 require_not_var_t<return_type_t<T, L, U>>* = nullptr>
47inline auto lub_constrain(T&& x, L&& lb, U&& ub) {
48 const bool is_lb_inf = value_of(lb) == NEGATIVE_INFTY;
49 const bool is_ub_inf = value_of(ub) == INFTY;
50 if (unlikely(is_ub_inf && is_lb_inf)) {
51 return identity_constrain(x, lb, ub);
52 } else if (unlikely(is_ub_inf)) {
53 return lb_constrain(identity_constrain(x, ub), lb);
54 } else if (unlikely(is_lb_inf)) {
55 return ub_constrain(identity_constrain(x, lb), ub);
56 } else {
57 check_less("lub_constrain", "lb", value_of(lb), value_of(ub));
58 return (ub - lb) * inv_logit(x) + lb;
59 }
60}
61
95template <typename T, typename L, typename U, typename Lp,
99inline auto lub_constrain(T&& x, L&& lb, U&& ub, Lp& lp) {
100 const bool is_lb_inf = value_of(lb) == NEGATIVE_INFTY;
101 const bool is_ub_inf = value_of(ub) == INFTY;
102 if (unlikely(is_ub_inf && is_lb_inf)) {
103 return identity_constrain(x, ub, lb);
104 } else if (unlikely(is_ub_inf)) {
105 return lb_constrain(identity_constrain(x, ub), lb, lp);
106 } else if (unlikely(is_lb_inf)) {
107 return ub_constrain(identity_constrain(x, lb), ub, lp);
108 } else {
109 check_less("lub_constrain", "lb", value_of(lb), value_of(ub));
110 const auto diff = ub - lb;
111 lp += add(log(diff), subtract(-abs(x), multiply(2.0, log1p_exp(-abs(x)))));
112 return diff * inv_logit(x) + lb;
113 }
114}
115
119template <typename T, typename L, typename U, require_eigen_t<T>* = nullptr,
120 require_all_stan_scalar_t<L, U>* = nullptr,
121 require_not_var_t<return_type_t<T, L, U>>* = nullptr>
122inline auto lub_constrain(const T& x, const L& lb, const U& ub) {
123 return eval(
124 x.unaryExpr([ub, lb](auto&& xx) { return lub_constrain(xx, lb, ub); }));
125}
126
130template <typename T, typename L, typename U, typename Lp,
131 require_eigen_t<T>* = nullptr,
135inline auto lub_constrain(const T& x, const L& lb, const U& ub, Lp& lp) {
136 return eval(x.unaryExpr(
137 [lb, ub, &lp](auto&& xx) { return lub_constrain(xx, lb, ub, lp); }));
138}
139
144template <typename T, typename L, typename U,
145 require_all_eigen_t<T, L>* = nullptr,
146 require_stan_scalar_t<U>* = nullptr,
148inline auto lub_constrain(const T& x, const L& lb, const U& ub) {
149 check_matching_dims("lub_constrain", "x", x, "lb", lb);
150 return eval(x.binaryExpr(
151 lb, [ub](auto&& x, auto&& lb) { return lub_constrain(x, lb, ub); }));
152}
153
158template <typename T, typename L, typename U, typename Lp,
159 require_all_eigen_t<T, L>* = nullptr,
160 require_stan_scalar_t<U>* = nullptr,
161 require_not_var_t<return_type_t<T, L, U>>* = nullptr,
162 require_convertible_t<return_type_t<T, L, U>, Lp>* = nullptr>
163inline auto lub_constrain(const T& x, const L& lb, const U& ub, Lp& lp) {
164 check_matching_dims("lub_constrain", "x", x, "lb", lb);
165 return eval(x.binaryExpr(lb, [ub, &lp](auto&& x, auto&& lb) {
166 return lub_constrain(x, lb, ub, lp);
167 }));
168}
169
174template <typename T, typename L, typename U,
175 require_all_eigen_t<T, U>* = nullptr,
176 require_stan_scalar_t<L>* = nullptr,
177 require_not_var_t<return_type_t<T, L, U>>* = nullptr>
178inline auto lub_constrain(const T& x, const L& lb, const U& ub) {
179 check_matching_dims("lub_constrain", "x", x, "ub", ub);
180 return eval(x.binaryExpr(
181 ub, [lb](auto&& x, auto&& ub) { return lub_constrain(x, lb, ub); }));
182}
183
188template <typename T, typename L, typename U, typename Lp,
189 require_all_eigen_t<T, U>* = nullptr,
190 require_stan_scalar_t<L>* = nullptr,
191 require_not_var_t<return_type_t<T, L, U>>* = nullptr,
192 require_convertible_t<return_type_t<T, L, U>, Lp>* = nullptr>
193inline auto lub_constrain(const T& x, const L& lb, const U& ub, Lp& lp) {
194 check_matching_dims("lub_constrain", "x", x, "ub", ub);
195 return eval(x.binaryExpr(ub, [lb, &lp](auto&& x, auto&& ub) {
196 return lub_constrain(x, lb, ub, lp);
197 }));
198}
199
203template <typename T, typename L, typename U,
204 require_all_eigen_t<T, L, U>* = nullptr,
205 require_not_var_t<return_type_t<T, L, U>>* = nullptr>
206inline auto lub_constrain(const T& x, const L& lb, const U& ub) {
207 check_matching_dims("lub_constrain", "x", x, "lb", lb);
208 check_matching_dims("lub_constrain", "x", x, "ub", ub);
209 auto x_ref = to_ref(x);
210 auto lb_ref = to_ref(lb);
211 auto ub_ref = to_ref(ub);
212 promote_scalar_t<return_type_t<T, L, U>, T> x_ret(x.rows(), x.cols());
213 for (Eigen::Index j = 0; j < x_ref.cols(); ++j) {
214 for (Eigen::Index i = 0; i < x_ref.rows(); ++i) {
215 x_ret.coeffRef(i, j) = lub_constrain(
216 x_ref.coeff(i, j), lb_ref.coeff(i, j), ub_ref.coeff(i, j));
217 }
218 }
219 return x_ret;
220}
221
225template <typename T, typename L, typename U, typename Lp,
229inline auto lub_constrain(const T& x, const L& lb, const U& ub, Lp& lp) {
230 check_matching_dims("lub_constrain", "x", x, "lb", lb);
231 check_matching_dims("lub_constrain", "x", x, "ub", ub);
232 auto x_ref = to_ref(x);
233 auto lb_ref = to_ref(lb);
234 auto ub_ref = to_ref(ub);
235 promote_scalar_t<return_type_t<T, L, U>, T> x_ret(x.rows(), x.cols());
236 for (Eigen::Index j = 0; j < x_ref.cols(); ++j) {
237 for (Eigen::Index i = 0; i < x_ref.rows(); ++i) {
238 x_ret.coeffRef(i, j) = lub_constrain(
239 x_ref.coeff(i, j), lb_ref.coeff(i, j), ub_ref.coeff(i, j), lp);
240 }
241 }
242 return x_ret;
243}
244
248template <typename T, typename L, typename U,
250inline auto lub_constrain(const std::vector<T>& x, const L& lb, const U& ub) {
251 std::vector<plain_type_t<decltype(lub_constrain(x[0], lb, ub))>> ret(
252 x.size());
253 for (size_t i = 0; i < x.size(); ++i) {
254 ret[i] = lub_constrain(x[i], lb, ub);
255 }
256 return ret;
257}
258
262template <typename T, typename L, typename U, typename Lp,
265inline auto lub_constrain(const std::vector<T>& x, const L& lb, const U& ub,
266 Lp& lp) {
267 std::vector<plain_type_t<decltype(lub_constrain(x[0], lb, ub))>> ret(
268 x.size());
269 for (size_t i = 0; i < x.size(); ++i) {
270 ret[i] = lub_constrain(x[i], lb, ub, lp);
271 }
272 return ret;
273}
274
278template <typename T, typename L, typename U,
280inline auto lub_constrain(const std::vector<T>& x, const L& lb,
281 const std::vector<U>& ub) {
282 check_matching_dims("lub_constrain", "x", x, "ub", ub);
283 std::vector<plain_type_t<decltype(lub_constrain(x[0], lb, ub[0]))>> ret(
284 x.size());
285 for (size_t i = 0; i < x.size(); ++i) {
286 ret[i] = lub_constrain(x[i], lb, ub[i]);
287 }
288 return ret;
289}
290
294template <typename T, typename L, typename U, typename Lp,
297inline auto lub_constrain(const std::vector<T>& x, const L& lb,
298 const std::vector<U>& ub, Lp& lp) {
299 check_matching_dims("lub_constrain", "x", x, "ub", ub);
300 std::vector<plain_type_t<decltype(lub_constrain(x[0], lb, ub[0]))>> ret(
301 x.size());
302 for (size_t i = 0; i < x.size(); ++i) {
303 ret[i] = lub_constrain(x[i], lb, ub[i], lp);
304 }
305 return ret;
306}
307
311template <typename T, typename L, typename U,
313inline auto lub_constrain(const std::vector<T>& x, const std::vector<L>& lb,
314 const U& ub) {
315 check_matching_dims("lub_constrain", "x", x, "lb", lb);
316 std::vector<plain_type_t<decltype(lub_constrain(x[0], lb[0], ub))>> ret(
317 x.size());
318 for (size_t i = 0; i < x.size(); ++i) {
319 ret[i] = lub_constrain(x[i], lb[i], ub);
320 }
321 return ret;
322}
323
327template <typename T, typename L, typename U, typename Lp,
330inline auto lub_constrain(const std::vector<T>& x, const std::vector<L>& lb,
331 const U& ub, Lp& lp) {
332 check_matching_dims("lub_constrain", "x", x, "lb", lb);
333 std::vector<plain_type_t<decltype(lub_constrain(x[0], lb[0], ub))>> ret(
334 x.size());
335 for (size_t i = 0; i < x.size(); ++i) {
336 ret[i] = lub_constrain(x[i], lb[i], ub, lp);
337 }
338 return ret;
339}
340
344template <typename T, typename L, typename U>
345inline auto lub_constrain(const std::vector<T>& x, const std::vector<L>& lb,
346 const std::vector<U>& ub) {
347 check_matching_dims("lub_constrain", "x", x, "lb", lb);
348 check_matching_dims("lub_constrain", "x", x, "ub", ub);
349 std::vector<plain_type_t<decltype(lub_constrain(x[0], lb[0], ub[0]))>> ret(
350 x.size());
351 for (size_t i = 0; i < x.size(); ++i) {
352 ret[i] = lub_constrain(x[i], lb[i], ub[i]);
353 }
354 return ret;
355}
356
360template <typename T, typename L, typename U, typename Lp,
362inline auto lub_constrain(const std::vector<T>& x, const std::vector<L>& lb,
363 const std::vector<U>& ub, Lp& lp) {
364 check_matching_dims("lub_constrain", "x", x, "lb", lb);
365 check_matching_dims("lub_constrain", "x", x, "ub", ub);
366 std::vector<plain_type_t<decltype(lub_constrain(x[0], lb[0], ub[0]))>> ret(
367 x.size());
368 for (size_t i = 0; i < x.size(); ++i) {
369 ret[i] = lub_constrain(x[i], lb[i], ub[i], lp);
370 }
371 return ret;
372}
373
399template <bool Jacobian, typename T, typename L, typename U, typename Lp,
401inline auto lub_constrain(const T& x, const L& lb, const U& ub, Lp& lp) {
402 if constexpr (Jacobian) {
403 return lub_constrain(x, lb, ub, lp);
404 } else {
405 return lub_constrain(x, lb, ub);
406 }
407}
408
412template <typename T, typename L, typename U>
413inline auto lub_constrain(const T& x, const std::tuple<L, U>& bounds) {
414 return lub_constrain(x, std::get<0>(bounds), std::get<1>(bounds));
415}
416
420template <typename T, typename L, typename U, typename Lp,
422inline auto lub_constrain(const T& x, const std::tuple<L, U>& bounds, Lp& lp) {
423 return lub_constrain(x, std::get<0>(bounds), std::get<1>(bounds), lp);
424}
425
429template <bool Jacobian, typename T, typename L, typename U, typename Lp,
431inline auto lub_constrain(const T& x, const std::tuple<L, U>& bounds, Lp& lp) {
432 return lub_constrain<Jacobian>(x, std::get<0>(bounds), std::get<1>(bounds),
433 lp);
434}
435
436} // namespace math
437} // namespace stan
438
439#endif
#define unlikely(x)
require_t< std::is_convertible< std::decay_t< T >, std::decay_t< S > > > require_convertible_t
Require types T and S satisfies std::is_convertible.
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< is_eigen< std::decay_t< T > > > require_eigen_t
Require type satisfies is_eigen.
Definition is_eigen.hpp:110
subtraction_< as_operation_cl_t< T_a >, as_operation_cl_t< T_b > > subtract(T_a &&a, T_b &&b)
addition_< as_operation_cl_t< T_a >, as_operation_cl_t< T_b > > add(T_a &&a, T_b &&b)
require_all_t< is_stan_scalar< std::decay_t< Types > >... > require_all_stan_scalar_t
Require all of the types satisfy is_stan_scalar.
require_t< is_stan_scalar< std::decay_t< T > > > require_stan_scalar_t
Require type satisfies is_stan_scalar.
require_not_t< is_std_vector< std::decay_t< T > > > require_not_std_vector_t
Require type does not satisfy is_std_vector.
require_all_not_t< is_std_vector< std::decay_t< Types > >... > require_all_not_std_vector_t
Require none of the types satisfy is_std_vector.
require_not_t< is_var< std::decay_t< T > > > require_not_var_t
Require type does not satisfy is_var.
Definition is_var.hpp:29
fvar< T > abs(const fvar< T > &x)
Definition abs.hpp:15
typename promote_scalar_type< std::decay_t< T >, std::decay_t< S > >::type promote_scalar_t
T eval(T &&arg)
Inputs which have a plain_type equal to the own time are forwarded unmodified (for Eigen expressions ...
Definition eval.hpp:20
T value_of(const fvar< T > &v)
Return the value of the specified variable.
Definition value_of.hpp:18
fvar< T > log(const fvar< T > &x)
Definition log.hpp:18
static constexpr double NEGATIVE_INFTY
Negative infinity.
Definition constants.hpp:51
auto multiply(const Mat1 &m1, const Mat2 &m2)
Return the product of the specified matrices.
Definition multiply.hpp:19
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.
fvar< T > log1p_exp(const fvar< T > &x)
Definition log1p_exp.hpp:14
ref_type_t< T && > to_ref(T &&a)
This evaluates expensive Eigen expressions.
Definition to_ref.hpp:17
auto lb_constrain(T &&x, L &&lb)
Return the lower-bounded value for the specified unconstrained input and specified lower bound.
auto ub_constrain(T &&x, U &&ub)
Return the upper-bounded value for the specified unconstrained matrix and upper bound.
matrix_cl< double > lub_constrain(const T &x, const L &lb, const U &ub)
Return the lower and upper-bounded matrix derived by transforming the specified free matrix given the...
void check_less(const char *function, const char *name, const T_y &y, const T_high &high, Idxs... idxs)
Throw an exception if y is not strictly less than high.
fvar< T > inv_logit(const fvar< T > &x)
Returns the inverse logit function applied to the argument.
Definition inv_logit.hpp:20
auto identity_constrain(T &&x, Types &&...)
Returns the result of applying the identity constraint transform to the input.
static constexpr double INFTY
Positive infinity.
Definition constants.hpp:46
typename plain_type< T >::type plain_type_t
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...