1 #ifndef STAN_MATH_PRIM_FUN_ORDERED_CONSTRAIN_HPP
2 #define STAN_MATH_PRIM_FUN_ORDERED_CONSTRAIN_HPP
3 
4 #include <stan/math/prim/meta.hpp>
5 #include <stan/math/prim/fun/Eigen.hpp>
6 #include <stan/math/prim/fun/exp.hpp>
7 #include <stan/math/prim/fun/sum.hpp>
8 #include <stan/math/prim/fun/to_ref.hpp>
9 #include <cmath>
10 
11 namespace stan {
12 namespace math {
13 
14 /**
15  * Return an increasing ordered vector derived from the specified
16  * free vector.  The returned constrained vector will have the
17  * same dimensionality as the specified free vector.
18  *
19  * @tparam T type of the vector
20  * @param x Free vector of scalars.
21  * @return Positive, increasing ordered vector.
22  * @tparam T Type of scalar.
23  */
24 template <typename EigVec, require_eigen_col_vector_t<EigVec>* = nullptr,
25           require_not_st_var<EigVec>* = nullptr>
ordered_constrain(const EigVec & x)26 inline plain_type_t<EigVec> ordered_constrain(const EigVec& x) {
27   using std::exp;
28   Eigen::Index k = x.size();
29   plain_type_t<EigVec> y(k);
30   const auto& x_ref = to_ref(x);
31   if (unlikely(k == 0)) {
32     return y;
33   }
34   y[0] = x_ref[0];
35   for (Eigen::Index i = 1; i < k; ++i) {
36     y.coeffRef(i) = y.coeff(i - 1) + exp(x_ref.coeff(i));
37   }
38   return y;
39 }
40 
41 /**
42  * Return a positive valued, increasing ordered vector derived
43  * from the specified free vector and increment the specified log
44  * probability reference with the log absolute Jacobian determinant
45  * of the transform.  The returned constrained vector
46  * will have the same dimensionality as the specified free vector.
47  *
48  * @tparam T type of the vector
49  * @param x Free vector of scalars.
50  * @param lp Log probability reference.
51  * @return Positive, increasing ordered vector.
52  */
53 template <typename EigVec, require_eigen_col_vector_t<EigVec>* = nullptr>
ordered_constrain(const EigVec & x,value_type_t<EigVec> & lp)54 inline auto ordered_constrain(const EigVec& x, value_type_t<EigVec>& lp) {
55   const auto& x_ref = to_ref(x);
56   if (likely(x.size() > 1)) {
57     lp += sum(x_ref.tail(x.size() - 1));
58   }
59   return ordered_constrain(x_ref);
60 }
61 
62 /**
63  * Return a positive valued, increasing ordered vector derived from the
64  * specified free vector. The returned constrained vector will have the same
65  * dimensionality as the specified free vector. If the `Jacobian` parameter is
66  * `true`, the log density accumulator is incremented with the log absolute
67  * Jacobian determinant of the transform. All of the transforms are specified
68  * with their Jacobians in the *Stan Reference Manual* chapter Constraint
69  * Transforms.
70  *
71  * @tparam Jacobian if `true`, increment log density accumulator with log
72  * absolute Jacobian determinant of constraining transform
73  * @tparam T A type inheriting from `Eigen::DenseBase` or a `var_value` with
74  *  inner type inheriting from `Eigen::DenseBase` with compile time dynamic rows
75  *  and 1 column
76  * @param x Free vector of scalars
77  * @param[in, out] lp log density accumulator
78  * @return Positive, increasing ordered vector.
79  */
80 template <bool Jacobian, typename T, require_not_std_vector_t<T>* = nullptr>
ordered_constrain(const T & x,return_type_t<T> & lp)81 inline auto ordered_constrain(const T& x, return_type_t<T>& lp) {
82   if (Jacobian) {
83     return ordered_constrain(x, lp);
84   } else {
85     return ordered_constrain(x);
86   }
87 }
88 
89 /**
90  * Return a positive valued, increasing ordered vector derived from the
91  * specified free vector. The returned constrained vector will have the same
92  * dimensionality as the specified free vector. If the `Jacobian` parameter is
93  * `true`, the log density accumulator is incremented with the log absolute
94  * Jacobian determinant of the transform. All of the transforms are specified
95  * with their Jacobians in the *Stan Reference Manual* chapter Constraint
96  * Transforms.
97  *
98  * @tparam Jacobian if `true`, increment log density accumulator with log
99  * absolute Jacobian determinant of constraining transform
100  * @tparam T A standard vector with inner type inheriting from
101  * `Eigen::DenseBase` or a `var_value` with inner type inheriting from
102  * `Eigen::DenseBase` with compile time dynamic rows and 1 column
103  * @param x Free vector of scalars
104  * @param[in, out] lp log density accumulator
105  * @return Positive, increasing ordered vector.
106  */
107 template <bool Jacobian, typename T, require_std_vector_t<T>* = nullptr>
ordered_constrain(const T & x,return_type_t<T> & lp)108 inline auto ordered_constrain(const T& x, return_type_t<T>& lp) {
109   return apply_vector_unary<T>::apply(
110       x, [&lp](auto&& v) { return ordered_constrain<Jacobian>(v, lp); });
111 }
112 
113 }  // namespace math
114 }  // namespace stan
115 
116 #endif
117