Skip to content

Commit 7635348

Browse files
committed
Merge remote-tracking branch 'origin/develop' into fix/sparse-vari-impl
2 parents 0656caa + b010193 commit 7635348

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+4987
-549
lines changed

stan/math/fwd/fun/sqrt.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ namespace math {
1616
template <typename T>
1717
inline fvar<T> sqrt(const fvar<T>& x) {
1818
using std::sqrt;
19+
if (value_of_rec(x.val_) == 0.0) {
20+
return fvar<T>(sqrt(x.val_), 0.0 * x.d_);
21+
}
1922
return fvar<T>(sqrt(x.val_), 0.5 * x.d_ * inv_sqrt(x.val_));
2023
}
2124

stan/math/prim/fun.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,10 @@
334334
#include <stan/math/prim/fun/squared_distance.hpp>
335335
#include <stan/math/prim/fun/stan_print.hpp>
336336
#include <stan/math/prim/fun/step.hpp>
337+
#include <stan/math/prim/fun/stochastic_column_constrain.hpp>
338+
#include <stan/math/prim/fun/stochastic_column_free.hpp>
339+
#include <stan/math/prim/fun/stochastic_row_constrain.hpp>
340+
#include <stan/math/prim/fun/stochastic_row_free.hpp>
337341
#include <stan/math/prim/fun/sub_col.hpp>
338342
#include <stan/math/prim/fun/sub_row.hpp>
339343
#include <stan/math/prim/fun/subtract.hpp>

stan/math/prim/fun/simplex_constrain.hpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ namespace math {
2424
* @param y Free vector input of dimensionality K - 1.
2525
* @return Simplex of dimensionality K.
2626
*/
27-
template <typename Vec, require_eigen_col_vector_t<Vec>* = nullptr,
27+
template <typename Vec, require_eigen_vector_t<Vec>* = nullptr,
2828
require_not_st_var<Vec>* = nullptr>
29-
inline auto simplex_constrain(const Vec& y) {
29+
inline plain_type_t<Vec> simplex_constrain(const Vec& y) {
3030
// cut & paste simplex_constrain(Eigen::Matrix, T) w/o Jacobian
3131
using std::log;
3232
using T = value_type_t<Vec>;
@@ -56,9 +56,10 @@ inline auto simplex_constrain(const Vec& y) {
5656
* @param lp Log probability reference to increment.
5757
* @return Simplex of dimensionality K.
5858
*/
59-
template <typename Vec, require_eigen_col_vector_t<Vec>* = nullptr,
59+
template <typename Vec, require_eigen_vector_t<Vec>* = nullptr,
6060
require_not_st_var<Vec>* = nullptr>
61-
inline auto simplex_constrain(const Vec& y, value_type_t<Vec>& lp) {
61+
inline plain_type_t<Vec> simplex_constrain(const Vec& y,
62+
value_type_t<Vec>& lp) {
6263
using Eigen::Dynamic;
6364
using Eigen::Matrix;
6465
using std::log;
@@ -98,7 +99,8 @@ inline auto simplex_constrain(const Vec& y, value_type_t<Vec>& lp) {
9899
* @return simplex of dimensionality one greater than `y`
99100
*/
100101
template <bool Jacobian, typename Vec, require_not_std_vector_t<Vec>* = nullptr>
101-
auto simplex_constrain(const Vec& y, return_type_t<Vec>& lp) {
102+
inline plain_type_t<Vec> simplex_constrain(const Vec& y,
103+
return_type_t<Vec>& lp) {
102104
if (Jacobian) {
103105
return simplex_constrain(y, lp);
104106
} else {

stan/math/prim/fun/simplex_free.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@ namespace math {
2626
* the simplex.
2727
* @throw std::domain_error if x is not a valid simplex
2828
*/
29-
template <typename Vec, require_eigen_col_vector_t<Vec>* = nullptr>
30-
auto simplex_free(const Vec& x) {
29+
template <typename Vec, require_eigen_vector_t<Vec>* = nullptr>
30+
inline plain_type_t<Vec> simplex_free(const Vec& x) {
3131
using std::log;
3232
using T = value_type_t<Vec>;
3333

3434
const auto& x_ref = to_ref(x);
3535
check_simplex("stan::math::simplex_free", "Simplex variable", x_ref);
36-
int Km1 = x_ref.size() - 1;
36+
Eigen::Index Km1 = x_ref.size() - 1;
3737
plain_type_t<Vec> y(Km1);
3838
T stick_len = x_ref.coeff(Km1);
3939
for (Eigen::Index k = Km1; --k >= 0;) {
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#ifndef STAN_MATH_PRIM_FUN_SIMPLEX_COLUMN_CONSTRAIN_HPP
2+
#define STAN_MATH_PRIM_FUN_SIMPLEX_COLUMN_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 <stan/math/prim/fun/simplex_constrain.hpp>
11+
#include <cmath>
12+
13+
namespace stan {
14+
namespace math {
15+
16+
/**
17+
* Return a column stochastic matrix.
18+
*
19+
* The transform is based on a centered stick-breaking process.
20+
*
21+
* @tparam Mat type of the Matrix
22+
* @param y Free Matrix input of dimensionality (K - 1, M)
23+
* @return Matrix with simplex columns of dimensionality (K, M)
24+
*/
25+
template <typename Mat, require_eigen_matrix_dynamic_t<Mat>* = nullptr,
26+
require_not_st_var<Mat>* = nullptr>
27+
inline plain_type_t<Mat> stochastic_column_constrain(const Mat& y) {
28+
auto&& y_ref = to_ref(y);
29+
const Eigen::Index M = y_ref.cols();
30+
plain_type_t<Mat> ret(y_ref.rows() + 1, M);
31+
for (Eigen::Index i = 0; i < M; ++i) {
32+
ret.col(i) = simplex_constrain(y_ref.col(i));
33+
}
34+
return ret;
35+
}
36+
37+
/**
38+
* Return a column stochastic matrix
39+
* and increment the specified log probability reference with
40+
* the log absolute Jacobian determinant of the transform.
41+
*
42+
* The simplex transform is defined through a centered
43+
* stick-breaking process.
44+
*
45+
* @tparam Mat type of the Matrix
46+
* @param y Free Matrix input of dimensionality (K - 1, M)
47+
* @param lp Log probability reference to increment.
48+
* @return Matrix with stochastic columns of dimensionality (K, M)
49+
*/
50+
template <typename Mat, require_eigen_matrix_dynamic_t<Mat>* = nullptr,
51+
require_not_st_var<Mat>* = nullptr>
52+
inline plain_type_t<Mat> stochastic_column_constrain(const Mat& y,
53+
value_type_t<Mat>& lp) {
54+
auto&& y_ref = to_ref(y);
55+
const Eigen::Index M = y_ref.cols();
56+
plain_type_t<Mat> ret(y_ref.rows() + 1, M);
57+
for (Eigen::Index i = 0; i < M; ++i) {
58+
ret.col(i) = simplex_constrain(y_ref.col(i), lp);
59+
}
60+
return ret;
61+
}
62+
63+
/**
64+
* Return a column stochastic matrix. If the
65+
* `Jacobian` parameter is `true`, the log density accumulator is incremented
66+
* with the log absolute Jacobian determinant of the transform. All of the
67+
* transforms are specified with their Jacobians in the *Stan Reference Manual*
68+
* chapter Constraint Transforms.
69+
*
70+
* @tparam Jacobian if `true`, increment log density accumulator with log
71+
* absolute Jacobian determinant of constraining transform
72+
* @tparam Mat type of the Matrix
73+
* @param y Free Matrix input of dimensionality (K - 1, M).
74+
* @param[in, out] lp log density accumulator
75+
* @return Matrix with simplex columns of dimensionality (K, M).
76+
*/
77+
template <bool Jacobian, typename Mat, require_not_std_vector_t<Mat>* = nullptr>
78+
inline plain_type_t<Mat> stochastic_column_constrain(const Mat& y,
79+
return_type_t<Mat>& lp) {
80+
if (Jacobian) {
81+
return stochastic_column_constrain(y, lp);
82+
} else {
83+
return stochastic_column_constrain(y);
84+
}
85+
}
86+
87+
/**
88+
* Return a vector of column stochastic matrices. If the
89+
* `Jacobian` parameter is `true`, the log density accumulator is incremented
90+
* with the log absolute Jacobian determinant of the transform. All of the
91+
* transforms are specified with their Jacobians in the *Stan Reference Manual*
92+
* chapter Constraint Transforms.
93+
*
94+
* @tparam Jacobian if `true`, increment log density accumulator with log
95+
* absolute Jacobian determinant of constraining transform
96+
* @tparam T A standard vector with inner type inheriting from
97+
* `Eigen::DenseBase` or a `var_value` with inner type inheriting from
98+
* `Eigen::DenseBase` with compile time dynamic rows and dynamic columns
99+
* @param[in] y free vector
100+
* @param[in, out] lp log density accumulator
101+
* @return Standard vector containing matrices with simplex columns of
102+
* dimensionality (K, M).
103+
*/
104+
template <bool Jacobian, typename T, require_std_vector_t<T>* = nullptr>
105+
inline auto stochastic_column_constrain(const T& y, return_type_t<T>& lp) {
106+
return apply_vector_unary<T>::apply(y, [&lp](auto&& v) {
107+
return stochastic_column_constrain<Jacobian>(v, lp);
108+
});
109+
}
110+
111+
} // namespace math
112+
} // namespace stan
113+
114+
#endif
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#ifndef STAN_MATH_PRIM_FUN_STOCHASTIC_COLUMN_FREE_HPP
2+
#define STAN_MATH_PRIM_FUN_STOCHASTIC_COLUMN_FREE_HPP
3+
4+
#include <stan/math/prim/meta.hpp>
5+
#include <stan/math/prim/fun/Eigen.hpp>
6+
#include <stan/math/prim/fun/simplex_free.hpp>
7+
8+
namespace stan {
9+
namespace math {
10+
11+
/**
12+
* Return an unconstrained matrix that when transformed produces
13+
* the specified columnwise stochastic matrix. It applies to a stochastic
14+
* matrix of dimensionality (N, K) and produces an unconstrained vector of
15+
* dimensionality (N - 1, K).
16+
*
17+
* @tparam Mat type of the Matrix
18+
* @param y Columnwise stochastic matrix input of dimensionality (N, K)
19+
*/
20+
template <typename Mat, require_eigen_matrix_dynamic_t<Mat>* = nullptr,
21+
require_not_st_var<Mat>* = nullptr>
22+
inline plain_type_t<Mat> stochastic_column_free(const Mat& y) {
23+
auto&& y_ref = to_ref(y);
24+
const Eigen::Index M = y_ref.cols();
25+
plain_type_t<Mat> ret(y_ref.rows() - 1, M);
26+
for (Eigen::Index i = 0; i < M; ++i) {
27+
ret.col(i) = simplex_free(y_ref.col(i));
28+
}
29+
return ret;
30+
}
31+
32+
/**
33+
* Overload that untransforms each Eigen matrix in a standard vector.
34+
*
35+
* @tparam T A standard vector with inner type inheriting from
36+
* `Eigen::DenseBase` with compile time dynamic rows and dynamic rows
37+
* @param[in] y vector of columnwise stochastic matrix of size (N, K)
38+
*/
39+
template <typename T, require_std_vector_t<T>* = nullptr>
40+
inline auto stochastic_column_free(const T& y) {
41+
return apply_vector_unary<T>::apply(
42+
y, [](auto&& v) { return stochastic_column_free(v); });
43+
}
44+
45+
} // namespace math
46+
} // namespace stan
47+
48+
#endif
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#ifndef STAN_MATH_PRIM_FUN_STOCHASTIC_ROW_CONSTRAIN_HPP
2+
#define STAN_MATH_PRIM_FUN_STOCHASTIC_ROW_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 <stan/math/prim/fun/simplex_constrain.hpp>
11+
#include <cmath>
12+
13+
namespace stan {
14+
namespace math {
15+
16+
/**
17+
* Return a row stochastic matrix.
18+
*
19+
* The transform is based on a centered stick-breaking process.
20+
*
21+
* @tparam Mat type of the Matrix
22+
* @param y Free Matrix input of dimensionality (N, K - 1).
23+
* @return Matrix with simplexes along the rows of dimensionality (N, K).
24+
*/
25+
template <typename Mat, require_eigen_matrix_dynamic_t<Mat>* = nullptr,
26+
require_not_st_var<Mat>* = nullptr>
27+
inline plain_type_t<Mat> stochastic_row_constrain(const Mat& y) {
28+
auto&& y_ref = to_ref(y);
29+
const Eigen::Index N = y_ref.rows();
30+
int Km1 = y_ref.cols();
31+
plain_type_t<Mat> x(N, Km1 + 1);
32+
using eigen_arr = Eigen::Array<scalar_type_t<Mat>, -1, 1>;
33+
eigen_arr stick_len = eigen_arr::Constant(N, 1.0);
34+
for (Eigen::Index k = 0; k < Km1; ++k) {
35+
auto z_k = inv_logit(y_ref.array().col(k) - log(Km1 - k));
36+
x.array().col(k) = stick_len * z_k;
37+
stick_len -= x.array().col(k);
38+
}
39+
x.array().col(Km1) = stick_len;
40+
return x;
41+
}
42+
43+
/**
44+
* Return a row stochastic matrix.
45+
* The simplex transform is defined through a centered
46+
* stick-breaking process.
47+
*
48+
* @tparam Mat type of the matrix
49+
* @param y Free matrix input of dimensionality (N, K - 1).
50+
* @param lp Log probability reference to increment.
51+
* @return Matrix with simplexes along the rows of dimensionality (N, K).
52+
*/
53+
template <typename Mat, require_eigen_matrix_dynamic_t<Mat>* = nullptr,
54+
require_not_st_var<Mat>* = nullptr>
55+
inline plain_type_t<Mat> stochastic_row_constrain(const Mat& y,
56+
value_type_t<Mat>& lp) {
57+
auto&& y_ref = to_ref(y);
58+
const Eigen::Index N = y_ref.rows();
59+
Eigen::Index Km1 = y_ref.cols();
60+
plain_type_t<Mat> x(N, Km1 + 1);
61+
Eigen::Array<scalar_type_t<Mat>, -1, 1> stick_len
62+
= Eigen::Array<scalar_type_t<Mat>, -1, 1>::Constant(N, 1.0);
63+
for (Eigen::Index k = 0; k < Km1; ++k) {
64+
const auto eq_share = -log(Km1 - k); // = logit(1.0/(Km1 + 1 - k));
65+
auto adj_y_k = (y_ref.array().col(k) + eq_share).eval();
66+
auto z_k = inv_logit(adj_y_k);
67+
x.array().col(k) = stick_len * z_k;
68+
lp += -sum(log1p_exp(adj_y_k)) - sum(log1p_exp(-adj_y_k))
69+
+ sum(log(stick_len));
70+
stick_len -= x.array().col(k); // equivalently *= (1 - z_k);
71+
}
72+
x.col(Km1).array() = stick_len;
73+
return x;
74+
}
75+
76+
/**
77+
* Return a row stochastic matrix.
78+
* If the `Jacobian` parameter is `true`, the log density accumulator is
79+
* incremented with the log absolute Jacobian determinant of the transform. All
80+
* of the transforms are specified with their Jacobians in the *Stan Reference
81+
* Manual* chapter Constraint Transforms.
82+
*
83+
* @tparam Jacobian if `true`, increment log density accumulator with log
84+
* absolute Jacobian determinant of constraining transform
85+
* @tparam Mat A type inheriting from `Eigen::DenseBase` or a `var_value` with
86+
* inner type inheriting from `Eigen::DenseBase` with compile time dynamic rows
87+
* and dynamic columns
88+
* @param[in] y free matrix
89+
* @param[in, out] lp log density accumulator
90+
* @return Matrix with simplexes along the rows of dimensionality (N, K).
91+
*/
92+
template <bool Jacobian, typename Mat, require_not_std_vector_t<Mat>* = nullptr>
93+
inline plain_type_t<Mat> stochastic_row_constrain(const Mat& y,
94+
return_type_t<Mat>& lp) {
95+
if (Jacobian) {
96+
return stochastic_row_constrain(y, lp);
97+
} else {
98+
return stochastic_row_constrain(y);
99+
}
100+
}
101+
102+
/**
103+
* Return a row stochastic matrix.
104+
* If the `Jacobian` parameter is `true`, the log density accumulator is
105+
* incremented with the log absolute Jacobian determinant of the transform. All
106+
* of the transforms are specified with their Jacobians in the *Stan Reference
107+
* Manual* chapter Constraint Transforms.
108+
*
109+
* @tparam Jacobian if `true`, increment log density accumulator with log
110+
* absolute Jacobian determinant of constraining transform
111+
* @tparam T A standard vector with inner type inheriting from
112+
* `Eigen::DenseBase` or a `var_value` with inner type inheriting from
113+
* `Eigen::DenseBase` with compile time dynamic rows and dynamic columns
114+
* @param[in] y free vector with matrices of size (N, K - 1)
115+
* @param[in, out] lp log density accumulator
116+
* @return vector of matrices with simplex rows of dimensionality (N, K)
117+
*/
118+
template <bool Jacobian, typename T, require_std_vector_t<T>* = nullptr>
119+
inline auto stochastic_row_constrain(const T& y, return_type_t<T>& lp) {
120+
return apply_vector_unary<T>::apply(
121+
y, [&lp](auto&& v) { return stochastic_row_constrain<Jacobian>(v, lp); });
122+
}
123+
124+
} // namespace math
125+
} // namespace stan
126+
127+
#endif

0 commit comments

Comments
 (0)