7 #include <stan/math/fwd/scal.hpp>
13 template<
typename EstimatorType>
14 Eigen::VectorXd muq::SamplingAlgorithms::Diagnostics::Rhat(std::vector<std::shared_ptr<EstimatorType>>
const& collections,
15 boost::property_tree::ptree options)
17 std::vector<std::shared_ptr<SampleEstimator>> chains;
20 auto samplePtr = std::dynamic_pointer_cast<SampleCollection>(collections.at(0));
24 std::vector<std::shared_ptr<SampleCollection>> newCollections(collections.size());
25 for(
unsigned int i=0; i<collections.size(); ++i)
26 newCollections.at(i) = std::dynamic_pointer_cast<SampleCollection>(collections.at(i));
29 if(options.get(
"Split",
true))
30 newCollections = SplitChains(newCollections);
32 if(options.get(
"Transform",
false))
33 newCollections = TransformChains(newCollections);
36 chains.resize(newCollections.size());
37 for(
unsigned int chainInd=0; chainInd<newCollections.size(); ++chainInd)
38 chains.at(chainInd) = std::dynamic_pointer_cast<SampleEstimator>(newCollections.at(chainInd));
42 chains.resize(collections.size());
43 for(
unsigned int chainInd=0; chainInd<collections.size(); ++chainInd)
44 chains.at(chainInd) = std::dynamic_pointer_cast<SampleEstimator>(collections.at(chainInd));
48 if(options.get(
"Multivariate",
false)){
49 return BasicMPSRF(chains) * Eigen::VectorXd::Ones(1);
51 return BasicRhat(chains);
55 template Eigen::VectorXd muq::SamplingAlgorithms::Diagnostics::Rhat(std::vector<std::shared_ptr<MarkovChain>>
const& collections,
56 boost::property_tree::ptree options);
57 template Eigen::VectorXd muq::SamplingAlgorithms::Diagnostics::Rhat(std::vector<std::shared_ptr<MultiIndexEstimator>>
const& collections,
58 boost::property_tree::ptree options);
59 template Eigen::VectorXd muq::SamplingAlgorithms::Diagnostics::Rhat(std::vector<std::shared_ptr<SampleCollection>>
const& collections,
60 boost::property_tree::ptree options);
63 std::vector<std::shared_ptr<SampleCollection>> muq::SamplingAlgorithms::Diagnostics::SplitChains(std::vector<std::shared_ptr<SampleCollection>>
const& origChains,
64 unsigned int numSegments)
66 std::vector<std::shared_ptr<const SampleCollection>> constChains;
67 for(
int i=0; i<origChains.size(); ++i)
68 constChains.push_back(std::const_pointer_cast<const SampleCollection>(origChains.at(i)));
70 return SplitChains(constChains,numSegments);
73 std::vector<std::shared_ptr<SampleCollection>> muq::SamplingAlgorithms::Diagnostics::SplitChains(std::vector<std::shared_ptr<const SampleCollection>>
const& origChains,
74 unsigned int numSegments)
76 std::vector<std::shared_ptr<SampleCollection>> chains;
78 double fraction = 1.0/double(numSegments);
81 unsigned int chainLength = std::floor(fraction*origChains.at(0)->size());
82 unsigned int numChains = numSegments*origChains.size();
83 const unsigned int dim = origChains.at(0)->at(0)->TotalDim();
85 chains.resize(numChains);
88 for(
int i=0; i<origChains.size();++i){
89 for(
int j=0; j<numSegments; ++j){
90 chains.at(numSegments*i+j) = origChains.at(i)->segment(j*chainLength, chainLength);
98 std::vector<std::shared_ptr<SampleCollection>> muq::SamplingAlgorithms::Diagnostics::TransformChains(std::vector<std::shared_ptr<SampleCollection>>
const& origChains)
100 const unsigned int dim = origChains.at(0)->at(0)->TotalDim();
102 unsigned int numChains = origChains.size();
103 unsigned int chainLength = origChains.at(0)->size();
104 const unsigned int totalSamps = numChains*chainLength;
106 std::vector<std::shared_ptr<SampleCollection>> chains;
107 chains.insert(chains.begin(), origChains.begin(), origChains.end());
109 for(
unsigned int i=0; i<dim; ++i){
112 std::vector<Eigen::VectorXd> ranks = ComputeRanks(chains,i);
115 for(
unsigned int chainInd=0; chainInd<ranks.size(); ++chainInd){
116 ranks.at(chainInd) = ( (ranks.at(chainInd).array()+0.625)/(totalSamps + 0.25) ).unaryExpr([](
double v){
return stan::math::inv_Phi(
v);});
118 for(
unsigned int sampInd=0; sampInd<chains.at(chainInd)->size(); ++sampInd)
119 chains.at(chainInd)->at(sampInd)->StateValue(i) = ranks.at(chainInd)(sampInd);
127 double muq::SamplingAlgorithms::Diagnostics::BasicMPSRF(std::vector<std::shared_ptr<SampleEstimator>>
const& chains)
129 const unsigned int numChains = chains.size();
130 const unsigned int dim = chains.at(0)->BlockSize(-1);
132 double lengthScale = 1.0;
135 auto cast = std::dynamic_pointer_cast<SampleCollection>(chains.at(0));
137 lengthScale = (cast->size() - 1.0)/cast->size();
140 Eigen::MatrixXd chainMeans(dim,numChains);
143 std::vector<Eigen::MatrixXd> chainCovs(numChains);
146 for(
int i=0; i<numChains; ++i){
147 chainMeans.col(i) = chains.at(i)->Mean();
148 chainCovs.at(i) = chains.at(i)->Covariance();
152 Eigen::VectorXd globalMean = chainMeans.rowwise().mean();
154 Eigen::MatrixXd W = Eigen::MatrixXd::Zero(chainCovs.at(0).rows(), chainCovs.at(0).cols());
155 for(
auto& cov : chainCovs)
158 W /= chainCovs.size();
161 Eigen::MatrixXd diff = chainMeans.colwise()-globalMean;
162 Eigen::MatrixXd B = (1.0/(numChains-1)) * diff * diff.transpose();
164 Eigen::MatrixXd Vhat = lengthScale * W + (1.0 + 1.0/numChains)*B;
166 Eigen::VectorXd lambdas = Eigen::GeneralizedSelfAdjointEigenSolver<Eigen::MatrixXd>(B,W,Eigen::EigenvaluesOnly).eigenvalues();
168 if(lambdas.size()==1)
169 return std::sqrt( lengthScale + lambdas(0)*(numChains+1)/numChains );
171 if(lambdas(1)>lambdas(0)){
173 return std::sqrt( lengthScale + lambdas(lambdas.size()-1)*(numChains+1)/numChains );
175 return std::sqrt( lengthScale + lambdas(0)*(numChains+1)/numChains );
179 Eigen::VectorXd muq::SamplingAlgorithms::Diagnostics::BasicRhat(std::vector<std::shared_ptr<SampleEstimator>>
const& chains)
184 const unsigned int numChains = chains.size();
185 const unsigned int dim = chains.at(0)->BlockSize(-1);
187 Eigen::MatrixXd mus(dim, numChains);
188 Eigen::MatrixXd sbjs(dim, numChains);
189 Eigen::MatrixXd vars(dim,numChains);
191 for(
unsigned int i=0; i<numChains; ++i){
192 mus.col(i) = chains.at(i)->Mean();
193 sbjs.col(i) = chains.at(i)->CentralMoment(2,mus.col(i));
194 vars.col(i) = chains.at(i)->Variance(mus.col(i));
197 Eigen::VectorXd mumu = mus.rowwise().mean();
198 Eigen::VectorXd muVar = (mus.colwise()-mumu).
array().square().rowwise().sum() / (numChains-1.0);
200 Eigen::VectorXd varEst = sbjs.rowwise().mean() + muVar;
201 Eigen::VectorXd W = vars.rowwise().mean();
203 return (varEst.array() / W.array()).
array().sqrt();
208 std::vector<Eigen::VectorXd> muq::SamplingAlgorithms::Diagnostics::ComputeRanks(std::vector<std::shared_ptr<SampleCollection>>
const& collections,
213 std::vector<std::pair<unsigned int, unsigned int>> sampInds;
215 for(
unsigned int chainInd=0; chainInd<collections.size(); ++chainInd){
216 for(
unsigned int sampInd=0; sampInd<collections.at(chainInd)->size(); ++sampInd)
217 sampInds.push_back(std::make_pair(chainInd,sampInd));
221 auto compLambda = [&collections, dim](std::pair<unsigned int, unsigned int>
const& p1, std::pair<unsigned int, unsigned int>
const& p2) {
222 return collections.at(p1.first)->at(p1.second)->StateValue(dim) < collections.at(p2.first)->at(p2.second)->StateValue(dim);
225 std::stable_sort(sampInds.begin(), sampInds.end(), compLambda);
228 std::vector<Eigen::VectorXd> ranks(collections.size());
229 for(
unsigned int i=0; i<ranks.size(); ++i)
230 ranks.at(i).resize(collections.at(i)->size());
233 unsigned int rawRank = 0;
234 double currVal, nextVal;
235 unsigned int numRepeat, chainInd, sampInd;
237 while(rawRank < sampInds.size()){
238 std::tie(chainInd, sampInd) = sampInds.at(rawRank);
239 currVal = collections.at(chainInd)->at(sampInd)->StateValue(dim);
243 for(numRepeat=1; numRepeat<sampInds.size()-rawRank; ++numRepeat){
244 std::tie(chainInd, sampInd) = sampInds.at(rawRank+numRepeat);
245 nextVal = collections.at(chainInd)->at(sampInd)->StateValue(dim);
247 if(std::abs(currVal-nextVal)>1
e-15){
253 double avgRank = 0.5*(rawRank + rawRank+numRepeat-1);
256 for(
int i=rawRank; i<rawRank+numRepeat; ++i){
257 std::tie(chainInd, sampInd) = sampInds.at(i);
258 ranks.at(chainInd)(sampInd) = avgRank;
262 rawRank += numRepeat;
@ array
array (ordered collection of values)