Skip to content

Commit 5a7715e

Browse files
authored
Merge pull request #555 from stan-dev/CODOLS
use COD to create sufficient statistic
2 parents aca291c + 9d481ee commit 5a7715e

4 files changed

Lines changed: 46 additions & 7 deletions

File tree

inst/include/CODOLS.hpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#ifndef RSTANARM__CODOLS_HPP
2+
#define RSTANARM__CODOLS_HPP
3+
4+
/*
5+
* Compute ordinary least squares coefficients,
6+
* even in the situation where X is rank deficient
7+
* See https://eigen.tuxfamily.org/dox/classEigen_1_1CompleteOrthogonalDecomposition.html
8+
*/
9+
10+
template <typename T2__, typename T3__>
11+
inline
12+
Eigen::Matrix<typename boost::math::tools::promote_args<T2__, T3__>::type,
13+
Eigen::Dynamic, 1>
14+
CODOLS(const Eigen::Matrix<T2__, Eigen::Dynamic, Eigen::Dynamic>& X,
15+
const Eigen::Matrix<T3__, Eigen::Dynamic, 1>& y,
16+
std::ostream* pstream__) {
17+
typename boost::math::tools::promote_args<T2__, T3__>::type T1__;
18+
using namespace Eigen;
19+
CompleteOrthogonalDecomposition<MatrixXd> cod(X);
20+
return cod.solve(y);
21+
}
22+
#endif
23+

inst/include/meta_header.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
#define RSTANARM__META_HEADER_HPP
33

44
#include "csr_matrix_times_vector2.hpp"
5+
#include "CODOLS.hpp"
56
#endif

src/stan_files/continuous.stan

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ functions {
2424
- N * (log(sigma) + log(sqrt(2 * pi())));
2525
}
2626

27+
vector CODOLS(matrix X, vector y); // implemented in C++
28+
2729
/**
2830
* test function for csr_matrix_times_vector
2931
*
@@ -94,13 +96,9 @@ transformed data {
9496
matrix[N, has_intercept + K + K_smooth ] X_ = has_intercept ? append_col(rep_vector(1.0, N),
9597
(K_smooth > 0 ? append_col(X[1], S) : X[1])) :
9698
(K_smooth > 0 ? append_col(X[1], S) : X[1]);
97-
matrix[cols(X_), cols(X_)] R = qr_thin_R(X_);
98-
if (tail(diagonal(R), 1)[1] > 1e-16) {
99-
matrix[N, cols(R)] Q = qr_thin_Q(X_);
100-
XtX = crossprod(X_);
101-
OLS = mdivide_right_tri_low(y' * Q, R')';
102-
SSR = dot_self(y - X_ * OLS);
103-
} else can_do_OLS = 0;
99+
XtX = crossprod(X_);
100+
OLS = CODOLS(X_, y);
101+
SSR = dot_self(y - X_ * OLS);
104102
}
105103
if (can_do_normalidglm) {
106104
XS = K_smooth > 0 ? append_col(X[1], S) : X[1];

tests/testthat/test_stan_glm.R

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,3 +447,20 @@ test_that("contrasts attribute isn't dropped", {
447447
chains = 1, refresh = 0))
448448
expect_equal(fit$contrasts, contrasts)
449449
})
450+
451+
test_that("returns something with collinear predictors", {
452+
N <- 100
453+
y <- rnorm(N)
454+
z <- sample(c(0,1), N, replace=TRUE)
455+
x1 <- rnorm(N)
456+
x2 <- 2*x1
457+
458+
fit_1 <- stan_glm(
459+
y ~ z * (x1 + x2),
460+
data = data.frame(y, z, x1, x2),
461+
prior = normal(location = 0, scale = 0.1),
462+
prior_intercept = normal(location = 0, scale = 0.1),
463+
chains = CHAINS, iter = ITER, refresh = REFRESH
464+
)
465+
expect_stanreg(fit_1)
466+
})

0 commit comments

Comments
 (0)