Skip to content

Commit b5958e6

Browse files
committed
Merge branch 'develop' into ilr-simplex
2 parents 9a934dc + c2d7422 commit b5958e6

File tree

6 files changed

+89
-33
lines changed

6 files changed

+89
-33
lines changed

.github/workflows/main.yml

+20-6
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,20 @@ jobs:
4141
with:
4242
python-version: '3.x'
4343

44-
- name: Download and install Rtools45
44+
- name: Download and Install Rtools45
4545
if: runner.os == 'Windows'
4646
run: |
4747
$ARCH = if ('${{ matrix.os }}' -eq 'windows-11-arm') { 'aarch64' } else { 'x86_64' }
4848
$RTOOLS = if ('${{ matrix.os }}' -eq 'windows-11-arm') { "rtools45-$ARCH" } else { 'rtools45' }
49-
Invoke-WebRequest -Uri https://github.com/r-hub/rtools45/releases/download/latest/$RTOOLS.exe -OutFile "$RTOOLS.exe"
50-
Start-Process -FilePath "$RTOOLS.exe" -ArgumentList "/install /norestart /verysilent /SUPPRESSMSGBOXES" -NoNewWindow -Wait
49+
50+
# Installation will hang if the toolchain is already installed
51+
if (-Not $(Test-Path -Path "C:/$RTOOLS")) {
52+
Invoke-WebRequest `
53+
-Uri https://github.com/r-hub/rtools45/releases/download/latest/$RTOOLS.exe `
54+
-OutFile "$RTOOLS.exe"
55+
Start-Process -FilePath "$RTOOLS.exe" -ArgumentList "/INSTALL /VERYSILENT /SUPPRESSMSGBOXES" -Wait
56+
}
57+
5158
echo "C:/$RTOOLS/usr/bin;C:/$RTOOLS/$ARCH-w64-mingw32.static.posix/bin" | Out-File -Append -FilePath $env:GITHUB_PATH -Encoding utf8
5259
echo "$(pwd)/lib/tbb" | Out-File -Append -FilePath $env:GITHUB_PATH -Encoding utf8
5360
@@ -85,13 +92,20 @@ jobs:
8592
with:
8693
python-version: '3.x'
8794

88-
- name: Download and install Rtools45
95+
- name: Download and Install Rtools45
8996
if: runner.os == 'Windows'
9097
run: |
9198
$ARCH = if ('${{ matrix.os }}' -eq 'windows-11-arm') { 'aarch64' } else { 'x86_64' }
9299
$RTOOLS = if ('${{ matrix.os }}' -eq 'windows-11-arm') { "rtools45-$ARCH" } else { 'rtools45' }
93-
Invoke-WebRequest -Uri https://github.com/r-hub/rtools45/releases/download/latest/$RTOOLS.exe -OutFile "$RTOOLS.exe"
94-
Start-Process -FilePath "$RTOOLS.exe" -ArgumentList "/install /norestart /verysilent /SUPPRESSMSGBOXES" -NoNewWindow -Wait
100+
101+
# Installation will hang if the toolchain is already installed
102+
if (-Not $(Test-Path -Path "C:/$RTOOLS")) {
103+
Invoke-WebRequest `
104+
-Uri https://github.com/r-hub/rtools45/releases/download/latest/$RTOOLS.exe `
105+
-OutFile "$RTOOLS.exe"
106+
Start-Process -FilePath "$RTOOLS.exe" -ArgumentList "/INSTALL /VERYSILENT /SUPPRESSMSGBOXES" -Wait
107+
}
108+
95109
echo "C:/$RTOOLS/usr/bin;C:/$RTOOLS/$ARCH-w64-mingw32.static.posix/bin" | Out-File -Append -FilePath $env:GITHUB_PATH -Encoding utf8
96110
echo "$(pwd)/lib/tbb" | Out-File -Append -FilePath $env:GITHUB_PATH -Encoding utf8
97111

stan/math/prim/fun/poisson_binomial_log_probs.hpp

+10-9
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <stan/math/prim/fun/log.hpp>
66
#include <stan/math/prim/fun/log1m.hpp>
77
#include <stan/math/prim/fun/log_sum_exp.hpp>
8+
#include <stan/math/prim/fun/log_mix.hpp>
89
#include <stan/math/prim/fun/max_size.hpp>
910
#include <stan/math/prim/fun/vector_seq_view.hpp>
1011

@@ -22,34 +23,34 @@ namespace math {
2223
* @return the last row of the computed log probability matrix
2324
*/
2425
template <typename T_theta, typename T_scalar = scalar_type_t<T_theta>,
25-
require_eigen_vector_t<T_theta>* = nullptr>
26-
plain_type_t<T_theta> poisson_binomial_log_probs(int y, const T_theta& theta) {
26+
require_vector_t<T_theta>* = nullptr>
27+
Eigen::Matrix<T_scalar, -1, 1> poisson_binomial_log_probs(
28+
int y, const T_theta& theta) {
2729
int size_theta = theta.size();
2830
plain_type_t<T_theta> log_theta = log(theta);
2931
plain_type_t<T_theta> log1m_theta = log1m(theta);
3032

31-
Eigen::Matrix<T_scalar, Eigen::Dynamic, Eigen::Dynamic> alpha(size_theta + 1,
32-
y + 1);
33+
Eigen::Matrix<T_scalar, Eigen::Dynamic, Eigen::Dynamic> alpha(y + 1,
34+
size_theta + 1);
3335

3436
// alpha[i, j] = log prob of j successes in first i trials
3537
alpha(0, 0) = 0.0;
3638
for (int i = 0; i < size_theta; ++i) {
3739
// no success in i trials
38-
alpha(i + 1, 0) = alpha(i, 0) + log1m_theta[i];
40+
alpha(0, i + 1) = alpha(0, i) + log1m_theta[i];
3941

4042
// 0 < j < i successes in i trials
4143
for (int j = 0; j < std::min(y, i); ++j) {
42-
alpha(i + 1, j + 1) = log_sum_exp(alpha(i, j) + log_theta[i],
43-
alpha(i, j + 1) + log1m_theta[i]);
44+
alpha(j + 1, i + 1) = log_mix(theta[i], alpha(j, i), alpha(j + 1, i));
4445
}
4546

4647
// i successes in i trials
4748
if (i < y) {
48-
alpha(i + 1, i + 1) = alpha(i, i) + log_theta(i);
49+
alpha(i + 1, i + 1) = alpha(i, i) + log_theta[i];
4950
}
5051
}
5152

52-
return alpha.row(size_theta);
53+
return alpha.col(size_theta);
5354
}
5455

5556
template <typename T_y, typename T_theta, require_vt_integral<T_y>* = nullptr>

stan/math/prim/fun/size_mvt.hpp

+10
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ int64_t size_mvt(const ScalarT& /* unused */) {
2626
throw std::invalid_argument("size_mvt passed to an unrecognized type.");
2727
}
2828

29+
template <typename ScalarT, require_stan_scalar_t<ScalarT>* = nullptr>
30+
int64_t size_mvt(const std::vector<ScalarT>& /* unused */) {
31+
return 1;
32+
}
33+
2934
template <typename MatrixT, require_matrix_t<MatrixT>* = nullptr>
3035
int64_t size_mvt(const MatrixT& /* unused */) {
3136
return 1;
@@ -36,6 +41,11 @@ int64_t size_mvt(const std::vector<MatrixT>& x) {
3641
return x.size();
3742
}
3843

44+
template <typename StdVectorT, require_std_vector_t<StdVectorT>* = nullptr>
45+
int64_t size_mvt(const std::vector<StdVectorT>& x) {
46+
return x.size();
47+
}
48+
3949
} // namespace math
4050
} // namespace stan
4151
#endif

stan/math/prim/fun/vector_seq_view.hpp

+12-8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@
66
#include <vector>
77

88
namespace stan {
9+
namespace internal {
10+
template <typename T>
11+
using is_matrix_or_std_vector
12+
= math::disjunction<is_matrix<T>, is_std_vector<T>>;
13+
14+
template <typename T>
15+
using is_scalar_container = math::disjunction<
16+
is_matrix<T>,
17+
math::conjunction<is_std_vector<T>, is_stan_scalar<value_type_t<T>>>>;
18+
} // namespace internal
919

1020
/**
1121
* This class provides a low-cost wrapper for situations where you either need
@@ -33,7 +43,7 @@ class vector_seq_view;
3343
* @tparam T the type of the underlying Vector
3444
*/
3545
template <typename T>
36-
class vector_seq_view<T, require_matrix_t<T>> {
46+
class vector_seq_view<T, require_t<internal::is_scalar_container<T>>> {
3747
public:
3848
explicit vector_seq_view(const T& m) : m_(m) {}
3949
static constexpr auto size() { return 1; }
@@ -46,19 +56,13 @@ class vector_seq_view<T, require_matrix_t<T>> {
4656

4757
template <typename C = T, require_st_autodiff<C>* = nullptr>
4858
inline auto val(size_t /* i */) const noexcept {
49-
return m_.val();
59+
return value_of(m_);
5060
}
5161

5262
private:
5363
const ref_type_t<T> m_;
5464
};
5565

56-
namespace internal {
57-
template <typename T>
58-
using is_matrix_or_std_vector
59-
= math::disjunction<is_matrix<T>, is_std_vector<T>>;
60-
}
61-
6266
/**
6367
* This class provides a low-cost wrapper for situations where you either need
6468
* an Eigen Vector or RowVector or a std::vector of them and you want to be

stan/math/prim/prob/poisson_binomial_rng.hpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,17 @@ namespace math {
2121
* @return a Poisson binomial distribution random variable
2222
* @throw std::domain_error if theta is not a valid probability
2323
*/
24-
template <typename T_theta, typename RNG,
25-
require_eigen_vt<std::is_arithmetic, T_theta>* = nullptr>
24+
template <typename T_theta, typename RNG>
2625
inline int poisson_binomial_rng(const T_theta& theta, RNG& rng) {
2726
static constexpr const char* function = "poisson_binomial_rng";
28-
check_finite(function, "Probability parameters", theta);
29-
check_bounded(function, "Probability parameters", value_of(theta), 0.0, 1.0);
27+
ref_type_t<T_theta> theta_ref = theta;
28+
check_finite(function, "Probability parameters", theta_ref);
29+
check_bounded(function, "Probability parameters", theta_ref, 0.0, 1.0);
3030

3131
int y = 0;
3232
for (size_t i = 0; i < theta.size(); ++i) {
3333
boost::variate_generator<RNG&, boost::bernoulli_distribution<> >
34-
bernoulli_rng(rng, boost::bernoulli_distribution<>(theta(i)));
34+
bernoulli_rng(rng, boost::bernoulli_distribution<>(theta_ref[i]));
3535
y += bernoulli_rng();
3636
}
3737

test/unit/math/prim/prob/poisson_binomial_test.cpp

+32-5
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,41 @@
66
#include <vector>
77

88
TEST(ProbDistributionsPoissonBinomial, lpmf_length_0_length_1) {
9+
using stan::math::poisson_binomial_lpmf;
10+
using stan::math::to_array_1d;
11+
using stan::math::to_row_vector;
12+
913
Eigen::VectorXd v0(0);
1014
Eigen::VectorXd v1(1);
1115
v1 << 0.4;
1216

13-
EXPECT_FLOAT_EQ(stan::math::poisson_binomial_lpmf(0, v0), 0.0);
14-
EXPECT_FLOAT_EQ(stan::math::poisson_binomial_lpmf(1, v1), std::log(0.4));
17+
EXPECT_FLOAT_EQ(poisson_binomial_lpmf(0, v0), 0.0);
18+
EXPECT_FLOAT_EQ(poisson_binomial_lpmf(0, to_row_vector(v0)), 0.0);
19+
EXPECT_FLOAT_EQ(poisson_binomial_lpmf(0, to_array_1d(v0)), 0.0);
20+
EXPECT_FLOAT_EQ(poisson_binomial_lpmf(1, v1), std::log(0.4));
21+
EXPECT_FLOAT_EQ(poisson_binomial_lpmf(1, to_row_vector(v1)), std::log(0.4));
22+
EXPECT_FLOAT_EQ(poisson_binomial_lpmf(1, to_array_1d(v1)), std::log(0.4));
1523
}
16-
1724
TEST(ProbDistributionsPoissonBinomial, lpmf_length_0_length_1_vectorial_y) {
25+
using stan::math::poisson_binomial_lpmf;
26+
using stan::math::to_array_1d;
27+
using stan::math::to_row_vector;
28+
1829
Eigen::VectorXd v0(0);
1930
Eigen::VectorXd v1(1);
2031
v1 << 0.4;
2132

2233
std::vector<int> y0{0, 0};
2334
std::vector<int> y1{1, 1};
2435

25-
EXPECT_FLOAT_EQ(stan::math::poisson_binomial_lpmf(y0, v0), 0.0);
26-
EXPECT_FLOAT_EQ(stan::math::poisson_binomial_lpmf(y1, v1), std::log(0.4) * 2);
36+
EXPECT_FLOAT_EQ(poisson_binomial_lpmf(y0, v0), 0.0);
37+
EXPECT_FLOAT_EQ(poisson_binomial_lpmf(y0, to_row_vector(v0)), 0.0);
38+
EXPECT_FLOAT_EQ(poisson_binomial_lpmf(y0, to_array_1d(v0)), 0.0);
39+
EXPECT_FLOAT_EQ(poisson_binomial_lpmf(y1, v1), std::log(0.4) * 2);
40+
EXPECT_FLOAT_EQ(poisson_binomial_lpmf(y1, to_row_vector(v1)),
41+
std::log(0.4) * 2);
42+
EXPECT_FLOAT_EQ(poisson_binomial_lpmf(y1, to_array_1d(v1)),
43+
std::log(0.4) * 2);
2744
}
2845

2946
TEST(ProbDistributionsPoissonBinomial, lpmf_works_on_scalar_arguments) {
@@ -41,25 +58,35 @@ TEST(ProbDistributionsPoissonBinomial, lpmf_works_on_scalar_arguments) {
4158

4259
TEST(ProbDistributionsPoissonBinomial, lpmf_works_on_vectorial_y) {
4360
using stan::math::poisson_binomial_lpmf;
61+
using stan::math::to_array_1d;
62+
using stan::math::to_row_vector;
4463
using vec = Eigen::Matrix<double, Eigen::Dynamic, 1>;
4564

4665
vec p(3, 1);
4766
p << 0.5, 0.2, 0.7;
4867
std::vector<int> y{2, 2};
4968

5069
EXPECT_NEAR(-0.967584 * 2, poisson_binomial_lpmf(y, p), 1e-6);
70+
EXPECT_NEAR(-0.967584 * 2, poisson_binomial_lpmf(y, to_row_vector(p)), 1e-6);
71+
EXPECT_NEAR(-0.967584 * 2, poisson_binomial_lpmf(y, to_array_1d(p)), 1e-6);
5172
}
5273

5374
TEST(ProbDistributionsPoissonBinomial, lpmf_works_on_vectorial_y_and_theta) {
5475
using stan::math::poisson_binomial_lpmf;
76+
using stan::math::to_array_1d;
77+
using stan::math::to_row_vector;
5578
using vec = Eigen::Matrix<double, Eigen::Dynamic, 1>;
5679

5780
vec p(3, 1);
5881
p << 0.5, 0.2, 0.7;
5982
std::vector<int> y{2, 0};
6083
std::vector<vec> ps{p, p};
84+
std::vector<Eigen::RowVectorXd> ps_rv{to_row_vector(p), to_row_vector(p)};
85+
std::vector<std::vector<double>> ps_std{to_array_1d(p), to_array_1d(p)};
6186

6287
EXPECT_NEAR(-0.967584 - 2.12026, poisson_binomial_lpmf(y, ps), 1e-5);
88+
EXPECT_NEAR(-0.967584 - 2.12026, poisson_binomial_lpmf(y, ps_rv), 1e-5);
89+
EXPECT_NEAR(-0.967584 - 2.12026, poisson_binomial_lpmf(y, ps_std), 1e-5);
6390
}
6491

6592
TEST(ProbDistributionsPoissonBinomial,

0 commit comments

Comments
 (0)