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