1 #ifndef STAN_MATH_PRIM_FUN_SIMPLEX_CONSTRAIN_HPP
2 #define STAN_MATH_PRIM_FUN_SIMPLEX_CONSTRAIN_HPP
3
4 #include <stan/math/prim/meta.hpp>
5 #include <stan/math/prim/fun/Eigen.hpp>
6 #include <stan/math/prim/fun/inv_logit.hpp>
7 #include <stan/math/prim/fun/log.hpp>
8 #include <stan/math/prim/fun/log1p_exp.hpp>
9 #include <stan/math/prim/fun/logit.hpp>
10 #include <cmath>
11
12 namespace stan {
13 namespace math {
14
15 /**
16 * Return the simplex corresponding to the specified free vector.
17 * A simplex is a vector containing values greater than or equal
18 * to 0 that sum to 1. A vector with (K-1) unconstrained values
19 * will produce a simplex of size K.
20 *
21 * The transform is based on a centered stick-breaking process.
22 *
23 * @tparam Vec type of the vector
24 * @param y Free vector input of dimensionality K - 1.
25 * @return Simplex of dimensionality K.
26 */
27 template <typename Vec, require_eigen_col_vector_t<Vec>* = nullptr,
28 require_not_st_var<Vec>* = nullptr>
simplex_constrain(const Vec & y)29 inline auto simplex_constrain(const Vec& y) {
30 // cut & paste simplex_constrain(Eigen::Matrix, T) w/o Jacobian
31 using std::log;
32 using T = value_type_t<Vec>;
33
34 int Km1 = y.size();
35 plain_type_t<Vec> x(Km1 + 1);
36 T stick_len(1.0);
37 for (Eigen::Index k = 0; k < Km1; ++k) {
38 T z_k = inv_logit(y.coeff(k) - log(Km1 - k));
39 x.coeffRef(k) = stick_len * z_k;
40 stick_len -= x.coeff(k);
41 }
42 x.coeffRef(Km1) = stick_len;
43 return x;
44 }
45
46 /**
47 * Return the simplex corresponding to the specified free vector
48 * and increment the specified log probability reference with
49 * the log absolute Jacobian determinant of the transform.
50 *
51 * The simplex transform is defined through a centered
52 * stick-breaking process.
53 *
54 * @tparam Vec type of the vector
55 * @param y Free vector input of dimensionality K - 1.
56 * @param lp Log probability reference to increment.
57 * @return Simplex of dimensionality K.
58 */
59 template <typename Vec, require_eigen_col_vector_t<Vec>* = nullptr,
60 require_not_st_var<Vec>* = nullptr>
simplex_constrain(const Vec & y,value_type_t<Vec> & lp)61 inline auto simplex_constrain(const Vec& y, value_type_t<Vec>& lp) {
62 using Eigen::Dynamic;
63 using Eigen::Matrix;
64 using std::log;
65 using T = value_type_t<Vec>;
66
67 int Km1 = y.size(); // K = Km1 + 1
68 plain_type_t<Vec> x(Km1 + 1);
69 T stick_len(1.0);
70 for (Eigen::Index k = 0; k < Km1; ++k) {
71 double eq_share = -log(Km1 - k); // = logit(1.0/(Km1 + 1 - k));
72 T adj_y_k = y.coeff(k) + eq_share;
73 T z_k = inv_logit(adj_y_k);
74 x.coeffRef(k) = stick_len * z_k;
75 lp += log(stick_len);
76 lp -= log1p_exp(-adj_y_k);
77 lp -= log1p_exp(adj_y_k);
78 stick_len -= x.coeff(k); // equivalently *= (1 - z_k);
79 }
80 x.coeffRef(Km1) = stick_len; // no Jacobian contrib for last dim
81 return x;
82 }
83
84 /**
85 * Return the simplex corresponding to the specified free vector. If the
86 * `Jacobian` parameter is `true`, the log density accumulator is incremented
87 * with the log absolute Jacobian determinant of the transform. All of the
88 * transforms are specified with their Jacobians in the *Stan Reference Manual*
89 * chapter Constraint Transforms.
90 *
91 * @tparam Jacobian if `true`, increment log density accumulator with log
92 * absolute Jacobian determinant of constraining transform
93 * @tparam Vec A type inheriting from `Eigen::DenseBase` or a `var_value` with
94 * inner type inheriting from `Eigen::DenseBase` with compile time dynamic rows
95 * and 1 column
96 * @param[in] y free vector
97 * @param[in, out] lp log density accumulator
98 * @return simplex of dimensionality one greater than `y`
99 */
100 template <bool Jacobian, typename Vec, require_not_std_vector_t<Vec>* = nullptr>
simplex_constrain(const Vec & y,return_type_t<Vec> & lp)101 auto simplex_constrain(const Vec& y, return_type_t<Vec>& lp) {
102 if (Jacobian) {
103 return simplex_constrain(y, lp);
104 } else {
105 return simplex_constrain(y);
106 }
107 }
108
109 /**
110 * Return the simplex corresponding to the specified free vector. If the
111 * `Jacobian` parameter is `true`, the log density accumulator is incremented
112 * with the log absolute Jacobian determinant of the transform. All of the
113 * transforms are specified with their Jacobians in the *Stan Reference Manual*
114 * chapter Constraint Transforms.
115 *
116 * @tparam Jacobian if `true`, increment log density accumulator with log
117 * absolute Jacobian determinant of constraining transform
118 * @tparam Vec A standard vector with inner type inheriting from
119 * `Eigen::DenseBase` or a `var_value` with inner type inheriting from
120 * `Eigen::DenseBase` with compile time dynamic rows and 1 column
121 * @param[in] y free vector
122 * @param[in, out] lp log density accumulator
123 * @return simplex of dimensionality one greater than `y`
124 */
125 template <bool Jacobian, typename T, require_std_vector_t<T>* = nullptr>
simplex_constrain(const T & y,return_type_t<T> & lp)126 inline auto simplex_constrain(const T& y, return_type_t<T>& lp) {
127 return apply_vector_unary<T>::apply(
128 y, [&lp](auto&& v) { return simplex_constrain<Jacobian>(v, lp); });
129 }
130
131 } // namespace math
132 } // namespace stan
133
134 #endif
135