-
-
Notifications
You must be signed in to change notification settings - Fork 372
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/3299 improved ess rhat #3312
Changes from all commits
44f8004
b8342cd
439d5f5
a954edc
4a70110
1355de8
c184c9e
a5fe9d2
1ebd1e2
f67a142
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
#ifndef STAN_ANALYZE_MCMC_CHECK_CHAINS_HPP | ||
#define STAN_ANALYZE_MCMC_CHECK_CHAINS_HPP | ||
|
||
#include <stan/math/prim.hpp> | ||
#include <cmath> | ||
#include <cstdlib> | ||
#include <limits> | ||
#include <utility> | ||
#include <vector> | ||
|
||
namespace stan { | ||
namespace analyze { | ||
|
||
/** | ||
* Checks that values across all matrix columns finite and non-identical. | ||
* | ||
* @param chains matrix of draws, one column per chain | ||
* @return bool true if OK, false otherwise | ||
*/ | ||
inline bool is_finite_and_varies(const Eigen::MatrixXd chains) { | ||
size_t num_chains = chains.cols(); | ||
size_t num_samples = chains.rows(); | ||
Eigen::VectorXd first_draws = Eigen::VectorXd::Zero(num_chains); | ||
for (std::size_t i = 0; i < num_chains; ++i) { | ||
first_draws(i) = chains.col(i)(0); | ||
for (int j = 0; j < num_samples; ++j) { | ||
if (!std::isfinite(chains.col(i)(j))) | ||
return false; | ||
} | ||
if (chains.col(i).isApproxToConstant(first_draws(i))) { | ||
return false; | ||
} | ||
} | ||
if (num_chains > 1 && first_draws.isApproxToConstant(first_draws(0))) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
} // namespace analyze | ||
} // namespace stan | ||
|
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
#ifndef STAN_ANALYZE_MCMC_RANK_NORMALIZATION_HPP | ||
#define STAN_ANALYZE_MCMC_RANK_NORMALIZATION_HPP | ||
|
||
#include <stan/math/prim.hpp> | ||
#include <boost/math/distributions/normal.hpp> | ||
#include <algorithm> | ||
#include <cmath> | ||
#include <vector> | ||
#include <limits> | ||
|
||
namespace stan { | ||
namespace analyze { | ||
|
||
/** | ||
* Computes normalized average ranks for pooled draws. Normal scores computed | ||
* using inverse normal transformation and a fractional offset. Based on paper | ||
* https://arxiv.org/abs/1903.08008 | ||
* | ||
* @param chains matrix of draws, one column per chain | ||
* @return normal scores for average ranks of draws | ||
*/ | ||
inline Eigen::MatrixXd rank_transform(const Eigen::MatrixXd& chains) { | ||
const Eigen::Index rows = chains.rows(); | ||
const Eigen::Index cols = chains.cols(); | ||
const Eigen::Index size = rows * cols; | ||
|
||
std::vector<std::pair<double, int>> value_with_index(size); | ||
for (Eigen::Index i = 0; i < size; ++i) { | ||
value_with_index[i] = {chains(i), i}; | ||
} | ||
|
||
std::sort(value_with_index.begin(), value_with_index.end()); | ||
Eigen::MatrixXd rank_matrix = Eigen::MatrixXd::Zero(rows, cols); | ||
// Assigning average ranks | ||
for (Eigen::Index i = 0; i < size; ++i) { | ||
// Handle ties by averaging ranks | ||
Eigen::Index j = i + 1; | ||
double sum_ranks = j; | ||
Eigen::Index count = 1; | ||
|
||
while (j < size && value_with_index[j].first == value_with_index[i].first) { | ||
sum_ranks += j + 1; // Rank starts from 1 | ||
++j; | ||
++count; | ||
} | ||
double avg_rank = sum_ranks / count; | ||
boost::math::normal_distribution<double> dist; | ||
for (std::size_t k = i; k < j; ++k) { | ||
double p = (avg_rank - 0.375) / (size + 0.25); | ||
const Eigen::Index index = value_with_index[k].second; | ||
rank_matrix(index) = boost::math::quantile(dist, p); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. am I correct that this is I know this is just moving code around, but if so that's probably worth calling instead There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure - this is a question for @aleksgorica or @avehtari There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @WardBrian, can you clarify the question? I'm not certain to which part you refer to be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're computing rank[index] by using the boost::math::quantile function where this |
||
} | ||
i = j - 1; // Skip over tied elements | ||
} | ||
return rank_matrix; | ||
} | ||
|
||
} // namespace analyze | ||
} // namespace stan | ||
|
||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function moved to file
rank_normalization.hpp