Skip to content

Commit e95b3f1

Browse files
authored
Merge pull request #2373 from stan-dev/feature/lb_constrain-matvar
Adds lb/ub/lub_constrain specializations
2 parents bcd293c + 5a6079a commit e95b3f1

38 files changed

+4936
-784
lines changed

stan/math/prim/fun/identity_constrain.hpp

+8-27
Original file line numberDiff line numberDiff line change
@@ -8,37 +8,18 @@ namespace math {
88

99
/**
1010
* Returns the result of applying the identity constraint
11-
* transform to the input.
11+
* transform to the input. This promotes the input to the least upper
12+
* bound of the input types.
1213
*
13-
* <p>This method is effectively a no-op and is mainly useful as a
14-
* placeholder in auto-generated code.
15-
*
16-
* @tparam T Any type.
17-
* @param[in] x object
18-
* @return transformed input
19-
*/
20-
template <typename T>
21-
inline auto identity_constrain(T&& x) {
22-
return std::forward<T>(x);
23-
}
24-
25-
/**
26-
* Returns the result of applying the identity constraint
27-
* transform to the input and increments the log probability
28-
* reference with the log absolute Jacobian determinant.
29-
*
30-
* <p>This method is effectively a no-op and mainly useful as a
31-
* placeholder in auto-generated code.
32-
*
33-
* @tparam T Any type
34-
* @tparam S type of log probability
14+
* @tparam T type of value to promote
15+
* @tparam Types Other types.
3516
* @param[in] x object
36-
* @param[in] lp log density reference
3717
* @return transformed input
3818
*/
39-
template <typename T, typename S>
40-
inline auto identity_constrain(T&& x, S& lp) {
41-
return std::forward<T>(x);
19+
template <typename T, typename... Types,
20+
require_all_not_var_matrix_t<T, Types...>* = nullptr>
21+
inline auto identity_constrain(T&& x, Types&&... /* args */) {
22+
return promote_scalar_t<return_type_t<T, Types...>, T>(x);
4223
}
4324

4425
} // namespace math

stan/math/prim/fun/identity_free.hpp

+9-8
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,19 @@ namespace math {
88

99
/**
1010
* Returns the result of applying the inverse of the identity
11-
* constraint transform to the input.
11+
* constraint transform to the input. This promotes the input to the least upper
12+
* bound of the input types.
1213
*
13-
* <p>This function is a no-op and mainly useful as a placeholder
14-
* in auto-generated code.
1514
*
16-
* @tparam T type of value
17-
* @param[in] y value
15+
* @tparam T type of value to promote
16+
* @tparam Types Other types.
17+
* @param[in] x value to promote
1818
* @return value
1919
*/
20-
template <typename T>
21-
inline auto identity_free(T&& y) {
22-
return std::forward<T>(y);
20+
template <typename T, typename... Types,
21+
require_all_not_var_matrix_t<T, Types...>* = nullptr>
22+
inline auto identity_free(T&& x, Types&&... /* args */) {
23+
return promote_scalar_t<return_type_t<T, Types...>, T>(x);
2324
}
2425

2526
} // namespace math

stan/math/prim/fun/lb_constrain.hpp

+180-17
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33

44
#include <stan/math/prim/meta.hpp>
55
#include <stan/math/prim/err.hpp>
6+
#include <stan/math/prim/fun/constants.hpp>
7+
#include <stan/math/prim/fun/identity_constrain.hpp>
8+
#include <stan/math/prim/fun/identity_free.hpp>
69
#include <stan/math/prim/fun/add.hpp>
710
#include <stan/math/prim/fun/exp.hpp>
11+
#include <stan/math/prim/fun/eval.hpp>
812
#include <stan/math/prim/fun/sum.hpp>
913
#include <stan/math/prim/fun/value_of.hpp>
1014
#include <cmath>
@@ -22,17 +26,20 @@ namespace math {
2226
*
2327
* <p>where \f$L\f$ is the constant lower bound.
2428
*
25-
* @tparam T type of Matrix
26-
* @tparam L type of lower bound
27-
* @param[in] x Unconstrained Matrix input
29+
* @tparam T Scalar.
30+
* @tparam L Scalar.
31+
* @param[in] x Unconstrained input
2832
* @param[in] lb Lower bound
2933
* @return Constrained matrix
3034
*/
31-
template <typename T, typename L>
35+
template <typename T, typename L, require_all_stan_scalar_t<T, L>* = nullptr,
36+
require_all_not_st_var<T, L>* = nullptr>
3237
inline auto lb_constrain(const T& x, const L& lb) {
33-
auto& lb_ref = to_ref(lb);
34-
check_finite("lb_constrain", "lb", value_of(lb_ref));
35-
return eval(add(exp(x), lb_ref));
38+
if (unlikely(value_of_rec(lb) == NEGATIVE_INFTY)) {
39+
return identity_constrain(x, lb);
40+
} else {
41+
return add(exp(x), lb);
42+
}
3643
}
3744

3845
/**
@@ -41,21 +48,177 @@ inline auto lb_constrain(const T& x, const L& lb) {
4148
* reference with the log absolute Jacobian determinant of the
4249
* transform.
4350
*
44-
* @tparam T Type of Matrix
45-
* @tparam L type of lower bound
46-
* @tparam S type of log probability
47-
* @param[in] x unconstrained Matrix input
51+
* @tparam T Scalar.
52+
* @tparam L Scalar.
53+
* @param[in] x unconstrained input
4854
* @param[in] lb lower bound on output
4955
* @param[in,out] lp reference to log probability to increment
5056
* @return lower-bound constrained value corresponding to inputs
5157
*/
52-
template <typename T, typename L>
58+
template <typename T, typename L, require_all_stan_scalar_t<T, L>* = nullptr,
59+
require_all_not_st_var<T, L>* = nullptr>
60+
inline auto lb_constrain(const T& x, const L& lb, return_type_t<T, L>& lp) {
61+
if (value_of_rec(lb) == NEGATIVE_INFTY) {
62+
return identity_constrain(x, lb);
63+
} else {
64+
lp += x;
65+
return add(exp(x), lb);
66+
}
67+
}
68+
69+
/**
70+
* Specialization of `lb_constrain` to apply a scalar lower bound elementwise
71+
* to each input.
72+
*
73+
* @tparam T A type inheriting from `EigenBase`.
74+
* @tparam L Scalar.
75+
* @param[in] x unconstrained input
76+
* @param[in] lb lower bound on output
77+
* @return lower-bound constrained value corresponding to inputs
78+
*/
79+
template <typename T, typename L, require_eigen_t<T>* = nullptr,
80+
require_stan_scalar_t<L>* = nullptr,
81+
require_all_not_st_var<T, L>* = nullptr>
82+
inline auto lb_constrain(T&& x, L&& lb) {
83+
return eval(x.unaryExpr([lb](auto&& x) { return lb_constrain(x, lb); }));
84+
}
85+
86+
/**
87+
* Specialization of `lb_constrain` to apply a scalar lower bound elementwise
88+
* to each input.
89+
*
90+
* @tparam T A type inheriting from `EigenBase`.
91+
* @tparam L Scalar.
92+
* @param[in] x unconstrained input
93+
* @param[in] lb lower bound on output
94+
* @param[in,out] lp reference to log probability to increment
95+
* @return lower-bound constrained value corresponding to inputs
96+
*/
97+
template <typename T, typename L, require_eigen_t<T>* = nullptr,
98+
require_stan_scalar_t<L>* = nullptr,
99+
require_all_not_st_var<T, L>* = nullptr>
100+
inline auto lb_constrain(const T& x, const L& lb, return_type_t<T, L>& lp) {
101+
return eval(
102+
x.unaryExpr([lb, &lp](auto&& xx) { return lb_constrain(xx, lb, lp); }));
103+
}
104+
105+
/**
106+
* Specialization of `lb_constrain` to apply a matrix of lower bounds
107+
* elementwise to each input element.
108+
*
109+
* @tparam T A type inheriting from `EigenBase`.
110+
* @tparam L A type inheriting from `EigenBase`.
111+
* @param[in] x unconstrained input
112+
* @param[in] lb lower bound on output
113+
* @return lower-bound constrained value corresponding to inputs
114+
*/
115+
template <typename T, typename L, require_all_eigen_t<T, L>* = nullptr,
116+
require_all_not_st_var<T, L>* = nullptr>
117+
inline auto lb_constrain(T&& x, L&& lb) {
118+
check_matching_dims("lb_constrain", "x", x, "lb", lb);
119+
return eval(x.binaryExpr(
120+
lb, [](auto&& x, auto&& lb) { return lb_constrain(x, lb); }));
121+
}
122+
123+
/**
124+
* Specialization of `lb_constrain` to apply a matrix of lower bounds
125+
* elementwise to each input element.
126+
*
127+
* @tparam T A type inheriting from `EigenBase`.
128+
* @tparam L A type inheriting from `EigenBase`.
129+
* @param[in] x unconstrained input
130+
* @param[in] lb lower bound on output
131+
* @param[in,out] lp reference to log probability to increment
132+
* @return lower-bound constrained value corresponding to inputs
133+
*/
134+
template <typename T, typename L, require_all_eigen_t<T, L>* = nullptr,
135+
require_all_not_st_var<T, L>* = nullptr>
53136
inline auto lb_constrain(const T& x, const L& lb, return_type_t<T, L>& lp) {
54-
auto& x_ref = to_ref(x);
55-
auto& lb_ref = to_ref(lb);
56-
check_finite("lb_constrain", "lb", value_of(lb_ref));
57-
lp += sum(x_ref);
58-
return eval(add(exp(x_ref), lb_ref));
137+
check_matching_dims("lb_constrain", "x", x, "lb", lb);
138+
return eval(x.binaryExpr(
139+
lb, [&lp](auto&& xx, auto&& lbb) { return lb_constrain(xx, lbb, lp); }));
140+
}
141+
142+
/**
143+
* Specialization of `lb_constrain` to apply a container of lower bounds
144+
* elementwise to each input element.
145+
*
146+
* @tparam T A Any type with a Scalar `scalar_type`.
147+
* @tparam L A type inheriting from `EigenBase` or a scalar.
148+
* @param[in] x unconstrained input
149+
* @param[in] lb lower bound on output
150+
* @return lower-bound constrained value corresponding to inputs
151+
*/
152+
template <typename T, typename L, require_not_std_vector_t<L>* = nullptr>
153+
inline auto lb_constrain(const std::vector<T>& x, const L& lb) {
154+
std::vector<plain_type_t<decltype(lb_constrain(x[0], lb))>> ret(x.size());
155+
for (size_t i = 0; i < x.size(); ++i) {
156+
ret[i] = lb_constrain(x[i], lb);
157+
}
158+
return ret;
159+
}
160+
161+
/**
162+
* Specialization of `lb_constrain` to apply a container of lower bounds
163+
* elementwise to each input element.
164+
*
165+
* @tparam T A Any type with a Scalar `scalar_type`.
166+
* @tparam L A type inheriting from `EigenBase` or a standard vector.
167+
* @param[in] x unconstrained input
168+
* @param[in] lb lower bound on output
169+
* @param[in,out] lp reference to log probability to increment
170+
* @return lower-bound constrained value corresponding to inputs
171+
*/
172+
template <typename T, typename L, require_not_std_vector_t<L>* = nullptr>
173+
inline auto lb_constrain(const std::vector<T>& x, const L& lb,
174+
return_type_t<T, L>& lp) {
175+
std::vector<plain_type_t<decltype(lb_constrain(x[0], lb))>> ret(x.size());
176+
for (size_t i = 0; i < x.size(); ++i) {
177+
ret[i] = lb_constrain(x[i], lb, lp);
178+
}
179+
return ret;
180+
}
181+
182+
/**
183+
* Specialization of `lb_constrain` to apply a container of lower bounds
184+
* elementwise to each input element.
185+
*
186+
* @tparam T A Any type with a Scalar `scalar_type`.
187+
* @tparam L A type inheriting from `EigenBase` or a standard vector.
188+
* @param[in] x unconstrained input
189+
* @param[in] lb lower bound on output
190+
* @return lower-bound constrained value corresponding to inputs
191+
*/
192+
template <typename T, typename L>
193+
inline auto lb_constrain(const std::vector<T>& x, const std::vector<L>& lb) {
194+
check_matching_dims("lb_constrain", "x", x, "lb", lb);
195+
std::vector<plain_type_t<decltype(lb_constrain(x[0], lb[0]))>> ret(x.size());
196+
for (size_t i = 0; i < x.size(); ++i) {
197+
ret[i] = lb_constrain(x[i], lb[i]);
198+
}
199+
return ret;
200+
}
201+
202+
/**
203+
* Specialization of `lb_constrain` to apply a container of lower bounds
204+
* elementwise to each input element.
205+
*
206+
* @tparam T A Any type with a Scalar `scalar_type`.
207+
* @tparam L A type inheriting from `EigenBase` or a standard vector.
208+
* @param[in] x unconstrained input
209+
* @param[in] lb lower bound on output
210+
* @param[in,out] lp reference to log probability to increment
211+
* @return lower-bound constrained value corresponding to inputs
212+
*/
213+
template <typename T, typename L>
214+
inline auto lb_constrain(const std::vector<T>& x, const std::vector<L>& lb,
215+
return_type_t<T, L>& lp) {
216+
check_matching_dims("lb_constrain", "x", x, "lb", lb);
217+
std::vector<plain_type_t<decltype(lb_constrain(x[0], lb[0]))>> ret(x.size());
218+
for (size_t i = 0; i < x.size(); ++i) {
219+
ret[i] = lb_constrain(x[i], lb[i], lp);
220+
}
221+
return ret;
59222
}
60223

61224
} // namespace math

0 commit comments

Comments
 (0)