MUQ  0.4.3
MarkovChain.cpp
Go to the documentation of this file.
2 
3 #include <unsupported/Eigen/FFT>
4 
5 using namespace muq::SamplingAlgorithms;
6 
7 Eigen::VectorXd MarkovChain::ESS(int blockInd, std::string const& method) const
8 {
9  if(method=="Wolff"){
10  return WolffESS(blockInd);
11  }else if(method=="Batch"){
12  return BatchESS(blockInd);
13  }else if(method=="MultiBatch"){
14  return MultiBatchESS(blockInd)*Eigen::VectorXd::Ones(1);
15  }else{
16  std::stringstream msg;
17  msg << "Invalid method (" << method << ") passed to MarkovChain::ESS. Valid options include \"Wolff\", \"Batch\", and \"MultiBatch\".";
18  throw std::runtime_error(msg.str());
19  return Eigen::VectorXd();
20  }
21 }
22 
23 
24 Eigen::VectorXd MarkovChain::StandardError(int blockInd, std::string const& method) const
25 {
26  if(method=="Wolff"){
27  return WolffError(blockInd);
28  }else if(method=="Batch"){
29  return BatchError(blockInd);
30  }else if(method=="MultiBatch"){
31  return MultiBatchError(blockInd)*Eigen::VectorXd::Ones(1);
32  }else{
33  std::stringstream msg;
34  msg << "Invalid method (" << method << ") passed to MarkovChain::StandardError. Valid options include \"Wolff\", \"Batch\", and \"MultiBatch\".";
35  throw std::runtime_error(msg.str());
36  return Eigen::VectorXd();
37  }
38 }
39 
40 Eigen::VectorXd MarkovChain::WolffError(int blockDim) const
41 {
42  Eigen::VectorXd ess = WolffESS(blockDim);
43 
44  return (Variance(blockDim).array() / ess.array()).sqrt();
45 }
46 
47 Eigen::VectorXd MarkovChain::WolffESS(int blockDim) const
48 {
49  Eigen::MatrixXd sampMat = AsMatrix(blockDim);
50 
51  Eigen::VectorXd ess(sampMat.rows());
52  for(int row=0; row<sampMat.rows(); ++row)
53  ess(row) = SingleComponentWolffESS(sampMat.row(row));
54 
55  return ess;
56 }
57 
58 double MarkovChain::SingleComponentWolffESS(Eigen::Ref<const Eigen::VectorXd> const& trace)
59 {
60  int size = trace.size();
61  // must have a positive number of samples
62  assert( size>=0 );
63 
64  // ESS needs at least 2 samples; just return ESS=0.0 if there aren't enough
65  if( size<2 ) {
66  return 0.0;
67  }
68 
69  double traceMean = trace.mean();
70 
71  Eigen::FFT<double> fft;
72 
73  int tmax = floor(0.5*size);
74  double Stau = 1.5;
75 
76  Eigen::Matrix<std::complex<double>, Eigen::Dynamic, 1> freqVec;
77  Eigen::Matrix<std::complex<double>, Eigen::Dynamic,
78  1> timeVec = Eigen::Matrix<std::complex<double>, Eigen::Dynamic, 1>::Zero(size + tmax);
79  for (int i = 0; i < size; ++i) {
80  timeVec(i) = std::complex<double>(trace(i) - traceMean, 0.0);
81  }
82 
83 
84  fft.fwd(freqVec, timeVec);
85 
86 
87  // compute out1*conj(out2) and store in out1 (x+yi)*(x-yi)
88  double real;
89 
90  for (int i = 0; i < size + tmax; ++i) {
91  real = freqVec(i).real() * freqVec(i).real() + freqVec(i).imag() * freqVec(i).imag();
92  freqVec(i) = std::complex<double>(real, 0.0);
93  }
94 
95  // now compute the inverse fft to get the autocorrelation (stored in timeVec)
96  fft.inv(timeVec, freqVec);
97 
98  for (int i = 0; i < tmax + 1; ++i) {
99  timeVec(i) = std::complex<double>(timeVec(i).real() / double(size - i), 0.0);
100  }
101 
102  // the following loop uses ideas from "Monte Carlo errors with less errors." by Ulli Wolff to figure out how far we
103  // need to integrate
104  //int MaxLag = 0;
105  double Gint = 0;
106  int Wopt = 0;
107  for (int i = 1; i < tmax + 1; ++i) {
108  Gint += timeVec(i).real() / timeVec(0).real(); // in1[i][0] /= scale;
109 
110  double tauW;
111  if (Gint <= 0) {
112  tauW = 1.0e-15;
113  } else {
114  tauW = Stau / log((Gint + 1) / Gint);
115  }
116  double gW = exp(-double(i) / tauW) - tauW / sqrt(double(i) * size);
117 
118  if (gW < 0) {
119  Wopt = i;
120  tmax = std::min(tmax, 2 * i);
121  break;
122  }
123  }
124 
125 
126  // correct for bias
127  double CFbbopt = timeVec(0).real();
128  for (int i = 0; i < Wopt + 1; ++i) {
129  CFbbopt += 2 * timeVec(i + 1).real();
130  }
131 
132  CFbbopt = CFbbopt / size;
133 
134  for (int i = 0; i < tmax + 1; ++i) {
135  timeVec(i) += std::complex<double>(CFbbopt, 0.0);
136  }
137 
138  // compute the normalized autocorrelation
139  double scale = timeVec(0).real();
140  for (int i = 0; i < Wopt; ++i) {
141  timeVec(i) = std::complex<double>(timeVec(i).real() / scale, 0.0);
142  }
143 
144  double tauint = 0;
145  for (int i = 0; i < Wopt; ++i) {
146  tauint += timeVec(i).real();
147  }
148 
149  tauint -= 0.5;
150 
151  // return the effective sample size
152  double frac = 1.0 / (2.0 * tauint);
153  frac = fmin(1.0, frac);
154  return size * frac;
155 }
156 
157 
158 std::shared_ptr<SampleCollection> MarkovChain::segment(unsigned int startInd, unsigned int length, unsigned int skipBy) const
159 {
160  assert(startInd<size());
161  assert(startInd+length<=size());
162 
163  std::shared_ptr<SampleCollection> output = std::make_shared<MarkovChain>();
164  for(unsigned int i=startInd; i<startInd+length; i+=skipBy)
165  output->Add(at(i));
166 
167  return output;
168 }
virtual Eigen::VectorXd StandardError(std::string const &method="Batch") const override
Definition: MarkovChain.h:59
Eigen::VectorXd WolffError(int blockDim) const
Definition: MarkovChain.cpp:40
static double SingleComponentWolffESS(Eigen::Ref< const Eigen::VectorXd > const &trace)
Definition: MarkovChain.cpp:58
Eigen::VectorXd WolffESS(int blockDim) const
Definition: MarkovChain.cpp:47
virtual std::shared_ptr< SampleCollection > segment(unsigned int startInd, unsigned int length, unsigned int skipBy=1) const override
virtual Eigen::VectorXd ESS(std::string const &method="Batch") const override
Definition: MarkovChain.h:41
virtual std::shared_ptr< SamplingState > at(unsigned i)
double MultiBatchESS(int blockInd=-1, int batchSize=-1, int overlap=-1) const
virtual Eigen::VectorXd MultiBatchError(int blockInd=-1, int batchSize=-1, int overlap=-1) const
virtual Eigen::MatrixXd AsMatrix(int blockDim=-1) const
Eigen::VectorXd BatchESS(int blockInd=-1, int batchSize=-1, int overlap=-1) const
virtual Eigen::VectorXd BatchError(int blockInd=-1, int batchSize=-1, int overlap=-1) const
virtual Eigen::VectorXd Variance(int blockInd=-1) const