base/chainBundle.hpp
00001 #ifndef _BETA_CHAINBUNDLE_
00002 
00003 #include <vector>
00004 #include <RandomLib/Random.hpp>
00005 
00006 using std::vector;
00007 using RandomLib::Random;
00008                                            
00019 
00020 template <typename T>
00021 class chainBundle
00022 {
00023     
00024     public:
00025         
00026         explicit chainBundle(Random &random);
00027         ~chainBundle();
00028         
00030         //                   Accessors                  //
00032         
00033         int nChains() { return (int)mChains.size(); }                  
00034         T* chain(const int i) { return mChains.at(i); }                
00035     
00036         double stepSize() { return mStepSize; }                        
00037         double nLeapfrog() { return mNumLeapfrog; }                    
00038     
00039         double ESS(int i) { return mESS(i); }                          
00040         double minESS() { return mESS.minCoeff(); }                    
00041         
00042         vector<VectorXd>& samples() { return mSamples; }               
00043     
00045         //                   Mutators                   //
00047         
00052         void setVerbosity(const unsigned int v) { mVerbosity = v; }
00053         
00054         void setNumSubsample(const int n) { mNumSubsample = n; }        
00055         void setNumLeapfrog(const int n) { mNumLeapfrog = n; }          
00056         void setWindowSize(const int n);                                //   Requires warning, see cpp
00057         
00058         void setStepSize(const double s) { mStepSize = s; }             
00059         void setStepSizeJitter(const double j);                         //   Requires warning, see cpp
00060         void setStepSizeJerk(const double j);                           //   Requires warning, see cpp
00061         void setProbStepSizeJerk(const double p);                       //   Requires warning, see cpp
00062 
00063         void setTemperAlpha(const double a) { mTemperAlpha = a; }       
00064         
00065         void setAdaptIntTime(double t) { mAdaptIntTime = t; }           
00066         void setAdaptTargetAccept(double a) { mAdaptTargetAccept = a; } 
00067         void setAdaptMaxLeapfrog(int n) { mAdaptMaxLeapfrog = n; }      
00068         
00069         void storeSamples(const bool store = true) { mStoreSamples = store; }  
00070         
00071         void setMaxLagDisplay(int n) { mMaxLagDisplay = n; } 
00072         void setMaxLagCalc(int n) { mMaxLagCalc = n; }       
00073                               
00074         void useExternalMoments(VectorXd& mean, VectorXd& var) { mUseExternalMoments = true; mExternalMean = &mean; mExternalVar = &var; }
00075     
00077         void addChain(T* object) { mChains.push_back(object); }
00078         
00080         //              Auxiliary Functions             //
00082         
00083         void evolve(T* chain, const double epsilon);
00084         void verboseEvolve(T* chain, const double epsilon);
00085 
00086         void engageAdaptation() { mAdaptStepSize = true; }     
00087         void disengageAdaptation() { mAdaptStepSize = false; } 
00088         
00089         void initAdaptation();
00090         void updateAdaptation(double metropolisProb);
00091     
00092         void transition();
00093         void transition(int i);
00094         bool transition(T* chain);
00095     
00096         void saveTrajectory(std::ofstream& outputFile, const int i = 0);
00097     
00098         void checkIntError(const int i, const int N, const int f = 1);
00099         
00100         void seed(const double min, const double max);
00101         void seed(const int i, const double min, const double max);
00102         void burn(const int nBurn = 100, const int nCheck = 100, const double minR = 1.1, const bool verbose = true);
00103         
00104         void clearSamples();
00105         void computeSummaryStats(const int b, const bool verbose = true, std::ofstream* outputFile = NULL);
00106         
00107     protected:
00108         
00109         // Flags
00110         bool mStoreSamples;       
00111         bool mAdaptStepSize;      
00112         bool mRefStats;           
00113         bool mChar;               
00114         bool mConstraint;         
00115         bool mUseExternalMoments; 
00116         
00117         // Switches
00118         unsigned int mVerbosity;  
00119         
00120         // Random number generator
00121         Random mRandom;           
00122         
00123         // Hamiltonian Monte Carlo parameters
00124         int mNumSubsample;        
00125         int mNumLeapfrog;         
00126         int mWindowSize;          
00127         
00128         double mStepSize;         
00129         double mStepSizeJitter;   
00130         double mStepSizeJerk;     
00131         double mProbStepSizeJerk; 
00132         
00133         int mNumFixedPoint;       
00134         
00135         double mTemperAlpha;      
00136     
00137         double mAdaptTargetAccept; 
00138         double mAdaptIntTime;      
00139         int mAdaptMaxLeapfrog;     
00140         double mAdaptMu;           
00141         double mAdaptLogEpsBar;    
00142         double mAdaptHBar;         
00143         double mAdaptCounter;      
00144         double mAdaptGamma;        
00145         double mAdaptKappa;        
00146         double mAdaptT0;           
00147         
00148         // Sample parameters
00149         int mNumSamples;             
00150         vector<VectorXd> mSamples;   
00151         vector<double> mSampleE;     
00152 
00153         int mMaxLagDisplay;          
00154         int mMaxLagCalc;             
00155     
00157         VectorXd mESS;           
00158     
00159         VectorXd* mExternalMean;     
00160         VectorXd* mExternalVar;      
00161 
00162         // Chain containers
00163         vector<T*> mChains;       
00164         typename vector<T*>::iterator mIt; 
00165         
00166         // Private functions
00167     
00169         virtual bool fConstraint(T* chain) { return !(chain->supportViolated()); }
00170         
00172         virtual const VectorXd& fNormal(T* chain) { return chain->supportNormal(); }
00173      
00174         double fLogSumExp(double a, double b);
00175     
00176 };
00177 
00178 // C++ standard libraries
00179 #include "math.h"
00180 #include <iostream>
00181 #include <iomanip>
00182 #include <fstream>
00183 
00184 using std::cout;
00185 using std::endl;
00186 using std::flush;
00187 
00191 template <typename T>
00192 chainBundle<T>::chainBundle(Random& random): 
00193 mRandom(random),
00194 mESS(VectorXd::Zero(1))
00195 {
00196     
00197     mStoreSamples = true;
00198     mAdaptStepSize = false;
00199     mRefStats = false;
00200     mChar = false;
00201     mConstraint = true;
00202     mUseExternalMoments = false;
00203     
00204     mVerbosity = 0;
00205     
00206     mNumSubsample = 1;
00207     mNumLeapfrog = 150;
00208     mWindowSize = 10;
00209     
00210     mStepSize = 0.1;
00211     mStepSizeJitter = 0.05;
00212     mStepSizeJerk = 0.1;
00213     mProbStepSizeJerk = 0.0;
00214     
00215     mTemperAlpha = 0.0;
00216     
00217     mAdaptTargetAccept = 0.65;
00218     mAdaptIntTime = 10;
00219     mAdaptMaxLeapfrog = 1000;
00220     mAdaptMu = 0;
00221     mAdaptLogEpsBar = 0;
00222     mAdaptHBar = 0;
00223     mAdaptCounter = 0;
00224     mAdaptGamma = 0.05;
00225     mAdaptKappa = 0.75;
00226     mAdaptT0 = 10;   
00227     
00228     mNumSamples = 0;
00229     
00230     mMaxLagDisplay = 10;
00231     mMaxLagCalc = 50;
00232 
00233     mExternalMean = 0;
00234     mExternalVar = 0;
00235     
00236 }
00237 
00238 
00241 
00242 template <typename T>
00243 chainBundle<T>::~chainBundle()
00244 {
00245     for(mIt = mChains.begin(); mIt != mChains.end(); ++mIt) delete *mIt;
00246     mChains.clear();
00247     
00248     clearSamples();
00249     
00250 }
00251 
00253 
00254 template <typename T>
00255 void chainBundle<T>::setWindowSize(const int n)
00256 {
00257     
00258     if(n > 0.5 * mNumLeapfrog)
00259     {
00260         cout << "chainBundle::setWindowSize() - Reject/Accept window must not be larger"
00261         << " than half of the total leapfrog steps!" << endl;
00262         return;
00263     }
00264     
00265     if(n < 2)
00266     {
00267         //cout << "chainBundle::setWindowSize() - Reject/Accept window should be larger than two"
00268         //     << " to avoid proposed windows in violation of the defined constraints!" << endl; 
00269         //return;
00270     }
00271     
00272     mWindowSize = n;
00273     
00274 }
00275 
00277 
00278 template <typename T>
00279 void chainBundle<T>::setStepSizeJitter(const double j)
00280 {
00281     
00282     if(j < 0 || j > 1)
00283     {
00284         cout << "chainBundle::setStepSizeJitter() - Step size jitter must lie between 0 and 1!" << endl;
00285         return;
00286     }
00287     
00288     mStepSizeJitter = j;
00289     
00290 }
00291 
00293 
00294 template <typename T>
00295 void chainBundle<T>::setStepSizeJerk(const double j)
00296 {
00297     
00298     if(j < 0)
00299     {
00300         cout << "chainBundle::setStepSizeJerk() - Step size jerk cannot be negative!" << endl;
00301         return;
00302     }
00303     
00304     mStepSizeJitter = j;
00305     
00306 }
00307 
00309 
00310 template <typename T>
00311 void chainBundle<T>::setProbStepSizeJerk(const double p)
00312 {
00313     
00314     if(p < 0 || p > 1)
00315     {
00316         cout << "chainBundle::setProbStepSizeJerk() - Step size jerk probability must lie between 0 and 1!" << endl;
00317         return;
00318     }
00319     
00320     mProbStepSizeJerk = p;
00321     
00322 }
00323 
00325 
00326 template <typename T>
00327 void chainBundle<T>::clearSamples()
00328 {
00329     mSamples.clear();
00330     mSampleE.clear();
00331     for(mIt = mChains.begin(); mIt != mChains.end(); ++mIt) (*mIt)->clearHistory();
00332     
00333 }
00334 
00347 
00348 template <typename T>
00349 void chainBundle<T>::computeSummaryStats(const int b, const bool verbose, std::ofstream* outputFile)
00350 {
00351     
00352     cout.precision(6);
00353     int acceptWidth = 14;
00354     
00355     if(mSamples.size() == 0)
00356     {
00357         cout << "Cannot compute summary stats without any samples!" << endl;
00358         return;
00359     }
00360     
00361     if(verbose)
00362     {
00363         
00364         cout << "Displaying summary statistics..." << endl << endl;
00365         
00366         cout << "    " << std::setw(5 * acceptWidth / 2) << std::setfill('-') << "" << std::setfill(' ') << endl;
00367         cout << "    "
00368              << std::setw(acceptWidth / 2) << std::left << "Chain" 
00369              << std::setw(acceptWidth) << std::left << "Global"
00370              << std::setw(acceptWidth) << std::left << "Local"
00371              << std::endl;
00372         cout << "    "
00373              << std::setw(acceptWidth / 2) << std::left << "" 
00374              << std::setw(acceptWidth) << std::left << "Accept Rate"
00375              << std::setw(acceptWidth) << std::left << "Accept Rate"
00376              << std::endl;
00377         cout << "    " << std::setw(5 * acceptWidth / 2) << std::setfill('-') << "" << std::setfill(' ') << endl;
00378         
00379         for(int i = 0; i < mChains.size(); ++i)
00380         {
00381             cout << "    "
00382                  << std::setw(acceptWidth / 2) << std::left << i 
00383                  << std::setw(acceptWidth) << std::left << (mChains.at(i))->acceptRate()
00384                  << std::setw(acceptWidth) << std::left << (mChains.at(i))->movingAcceptRate()
00385                  << endl;
00386         }
00387         cout << "    " << std::setw(5 * acceptWidth / 2) << std::setfill('-') << "" << std::setfill(' ') << endl;
00388         cout << endl;
00389         
00390     }
00391     
00392     int nSamples = (int)mSamples.size();
00393     int nBatch = nSamples / b;
00394     int nLag = nBatch / 2;
00395     
00396     nLag = nLag > mMaxLagCalc ? mMaxLagDisplay : nLag;
00397     int nLagDisplay = nLag > mMaxLagDisplay ? mMaxLagDisplay : nLag;
00398     
00399     if(verbose)
00400     {
00401         cout << "\tUsing " << nBatch << " batches of " << b << " samples"
00402         << " (" << nSamples % b << " samples clipped)" << endl << endl;
00403     }
00404     
00405     // Loop over samples
00406     double batchPotential;
00407     double sumPotential = 0;
00408     double sumPotential2 = 0;
00409     
00410     long dim = chain(0)->dim();
00411     if(outputFile) *outputFile << "DIM " << dim << endl << endl;
00412     
00413     VectorXd batchSample(dim);
00414     VectorXd sum(VectorXd::Zero(dim));
00415     VectorXd sum2(VectorXd::Zero(dim));
00416     
00417     MatrixXd autoCorr = MatrixXd::Zero(dim, nLag);
00418     mESS.resize(dim);
00419     
00420     vector<VectorXd> batchSamples;
00421     
00422     vector<double>::const_iterator eIt = mSampleE.begin();
00423     vector<VectorXd>::const_iterator it = mSamples.begin();
00424     
00425     // Compute batch expectations
00426     if(outputFile) *outputFile << "BEGINSAMPLES" << endl;
00427     
00428     for(int n = 0; n < nBatch; ++n)
00429     {
00430         
00431         batchPotential = 0;
00432         batchSample.setZero();
00433         
00434         // Loop over intra-batch samples
00435         for(int m = 0; m < b; ++m, ++eIt, ++it)
00436         {
00437             
00438             // Increment sums
00439             batchPotential += *eIt;
00440             batchSample += (*it);
00441             
00442             // Write to output file, if desired
00443             if(outputFile)
00444             {
00445                 *outputFile << n * b + m << "\t" << *eIt << flush;
00446                 for(int i = 0; i < dim; ++i)
00447                 {
00448                     *outputFile << "\t" << (*it)(i) << flush;
00449                 }
00450                 *outputFile << endl;
00451             }
00452         }
00453         
00454         // Normalize
00455         batchPotential /= b;
00456         sumPotential += batchPotential;
00457         sumPotential2 += batchPotential * batchPotential;
00458         
00459         batchSample /= (double)b;
00460         batchSamples.push_back(VectorXd(batchSample));
00461         
00462         sum += batchSample;
00463         sum2 += batchSample.array().square().matrix();
00464         
00465     }
00466     
00467     if(outputFile) *outputFile << "ENDSAMPLES" << endl << endl;
00468     
00469     // Normalize batch expectations
00470     sumPotential /= (double)nBatch;
00471     sumPotential2 = sumPotential2 / (double)nBatch - sumPotential * sumPotential;
00472     
00473     sum /= (double)nBatch;
00474     
00475     sum2 /= (double)nBatch; 
00476     sum2 -= sum.array().square().matrix();
00477     sum2 *= b / nSamples; // Correct asymptotic batch variance to asymptotic chain variance
00478     
00479     // Compute autocorrelations
00480     VectorXd gamma(dim);
00481     VectorXd one(dim);
00482     VectorXd two(dim);
00483     
00484     if(!mUseExternalMoments) mExternalMean = &sum;
00485     
00486     for(int k = 0; k < nLag; ++k)
00487     {
00488         
00489         gamma = autoCorr.col(k);
00490         
00491         vector<VectorXd>::iterator itOne = batchSamples.begin();
00492         
00493         vector<VectorXd>::iterator itTwo = itOne;
00494         for(int j = 0; j < k; ++j) ++itTwo;
00495         
00496         for(int n = 0; n < nBatch - k; ++n, ++itOne, ++itTwo)
00497         {
00498             one = *itOne - *mExternalMean;
00499             two = *itTwo - *mExternalMean;
00500             gamma += one.cwiseProduct(two);
00501         }
00502         
00503         gamma /= (double)nBatch;
00504         
00505         // Compute autocorrelation
00506         if(k == 0) 
00507         {
00508             for(int i = 0; i < dim; ++i) autoCorr(i, k) = gamma(i);
00509             continue;
00510         }
00511         
00512         one = gamma.cwiseQuotient(autoCorr.col(0));
00513         
00514         if(mUseExternalMoments) one = gamma.cwiseQuotient(*mExternalVar);
00515         else                    one = gamma.cwiseQuotient(autoCorr.col(0));
00516      
00517         for(int i = 0; i < dim; ++i) autoCorr(i, k) = one(i);
00518         
00519     }
00520     
00521     autoCorr.col(0).setOnes();
00522     
00523     // Compute effective sample size for each variable
00524     for(int i = 0; i < dim; ++i)
00525     {
00526         
00527         mESS(i) = 0;
00528         
00529         double gamma = 0;
00530         double Gamma = 0;
00531         double oldGamma = 1;
00532         
00533         for(int k = 1; k < nLag; ++k)
00534         {
00535             
00536             gamma = autoCorr(i, k);
00537             
00538             // Even k, finish computation of Gamma
00539             if(k % 2 == 0)
00540             {
00541                 
00542                 Gamma += gamma;
00543                 
00544                 // Convert to initial monotone sequence (IMS)
00545                 if(Gamma > oldGamma) Gamma = oldGamma;
00546                 
00547                 oldGamma = Gamma;
00548                 
00549                 // Terminate if necessary
00550                 if(Gamma <= 0) break;
00551                 
00552                 // Increment autocorrelation sum
00553                 mESS(i) += Gamma;
00554                 
00555             }
00556             // Odd k, begin computation of Gamma
00557             else
00558             {
00559                 Gamma = gamma;   
00560             }
00561             
00562             //ess(i) += (1.0 - (double)k / (double)nBatch) * (*(autoCorr[k]))[i];
00563             
00564         }
00565         
00566         mESS(i) = (double)nBatch / (1.0 + 2 * mESS(i) );
00567         
00568     }
00569     
00570     // Display results
00571     if(verbose)
00572     {
00573         cout << "\tV ~ " << sumPotential << " +/- " << sqrt(sumPotential2) << endl;
00574         cout << "\tSmallest Effective Sample Size is " << minESS() << endl << endl;
00575     }
00576     
00577     double whiteNoise = 2.0 / sqrt((double)nBatch);
00578     
00579     if(outputFile) 
00580     {
00581         
00582         *outputFile << "WHITENOISE " << whiteNoise << endl << endl;
00583         *outputFile << "BEGINAUTOCORR" << endl;
00584         
00585         for(int k = 0; k < nLag; ++k)
00586         {
00587             
00588             *outputFile << k << flush;
00589             
00590             for(int i = 0; i < dim; ++i)
00591             {
00592                 *outputFile << "\t" << autoCorr(i, k) << flush;
00593             }
00594             
00595             *outputFile << endl;
00596             
00597         }
00598         
00599         *outputFile << "ENDAUTOCORR" << endl;
00600         
00601     }
00602     
00603     if(verbose)
00604     {
00605         
00606         for(int i = 0; i < dim; ++i)
00607         {
00608             
00609             cout << "\t" << std::setw(4 * acceptWidth) << std::setfill('-') << "" << std::setfill(' ') << endl;
00610             cout << "\tVariable " << i << endl;
00611             cout << "\t" << std::setw(4 * acceptWidth) << std::setfill('-') << "" << std::setfill(' ') << endl;
00612             cout << endl;
00613             
00614             cout << "\t\tMean = " << sum[i] << endl;
00615             cout << "\t\tMonte Carlo Standard Error = " << sqrt(sum2[i]) << endl;
00616             cout << "\t\tEffective Sample Size = " << mESS(i) << endl << endl;
00617             
00618             cout << endl << "\t\tAutocorrelation:" << endl;
00619             cout << "\t\t\tWhite noise correlation = " << whiteNoise << endl << endl;
00620             
00621             
00622             for(int k = 0; k < nLagDisplay; ++k)
00623             {
00624                 double g = autoCorr(i, k);
00625                 cout << "\t\t\tgamma_{" << k << "} = " << g << flush;
00626                 if(g > whiteNoise && k > 0) cout << " (Larger than expected fluctuation from white noise!)" << flush;
00627                 cout << endl;
00628             }
00629             
00630             cout << endl;
00631             
00632         }
00633         
00634         cout << "\t" << std::setw(4 * acceptWidth) << std::setfill('-') << "" << std::setfill(' ') << endl;
00635         
00636     }
00637     
00638     // Clean up
00639     batchSamples.clear();
00640     
00641     return;
00642     
00643 }
00644 
00659 
00660 template <typename T>
00661 void chainBundle<T>::evolve(T* chain, const double epsilon)
00662 {
00663     
00664     // Initial half momentum evolution
00665     if(mConstraint) chain->beginEvolveP(0.5 * epsilon);
00666     
00667     // Full spatial evolution
00668     chain->evolveQ(epsilon);
00669     
00670     // Check constraint
00671     mConstraint = fConstraint(chain);
00672     
00673     // Final half momentum evolution
00674     if(mConstraint)  chain->finishEvolveP(0.5 * epsilon);
00675     else             chain->bounceP(fNormal(chain));
00676     
00677 }
00678 
00684 
00685 template <typename T>
00686 void chainBundle<T>::verboseEvolve(T* chain, const double epsilon)
00687 {
00688     
00689     //cout << "----------------------------------------------------" << endl;
00690     
00691     std::cout.precision(6);
00692     int width = 14;
00693     int nColumn = 4;
00694     
00695     std::cout << "Verbose Hamiltonian Evolution, Step Size = " << epsilon << ":" << std::endl;
00696     std::cout << "    " << std::setw(nColumn * width) << std::setfill('-') << "" << std::setfill(' ') << std::endl;
00697     std::cout << "    "
00698     << std::setw(width) << std::left << "Poisson"
00699     << std::setw(width) << std::left << "Initial" 
00700     << std::setw(width) << std::left << "Current"
00701     << std::setw(width) << std::left << "DeltaH"
00702     << std::endl;
00703     std::cout << "    "
00704     << std::setw(width) << std::left << "Operator"
00705     << std::setw(width) << std::left << "Hamiltonian" 
00706     << std::setw(width) << std::left << "Hamiltonian"
00707     << std::setw(width) << std::left << "/ Stepsize^{2}"
00708     << std::endl;
00709     std::cout << "    " << std::setw(nColumn * width) << std::setfill('-') << "" << std::setfill(' ') << std::endl;
00710     
00711     double H0 = chain->H();
00712     
00713     // Initial half momentum evolution
00714     if(mConstraint) chain->beginEvolveP(0.5 * epsilon);
00715     
00716     double H1 = chain->H();
00717     
00718     std::cout << "    "
00719     << std::setw(width) << std::left << "hat{V}/2"
00720     << std::setw(width) << std::left << H0
00721     << std::setw(width) << std::left << H1
00722     << std::setw(width) << std::left << (H1 - H0) / (epsilon * epsilon)
00723     << std::endl;
00724     
00725     // Full spatial evolution
00726     chain->evolveQ(epsilon);
00727     
00728     double H2 = chain->H();
00729     
00730     std::cout << "    "
00731     << std::setw(width) << std::left << "hat{T}"
00732     << std::setw(width) << std::left << H0
00733     << std::setw(width) << std::left << H2
00734     << std::setw(width) << std::left << (H2 - H0) / (epsilon * epsilon)
00735     << std::endl;
00736     
00737     // Check constraint
00738     mConstraint = fConstraint(chain);
00739     
00740     // Final half momentum evolution
00741     if(mConstraint)  chain->finishEvolveP(0.5 * epsilon);
00742     else             chain->bounceP(fNormal(chain));
00743     
00744     double H3 = chain->H();
00745     
00746     std::cout << "    "
00747     << std::setw(width) << std::left << "hat{V}/2"
00748     << std::setw(width) << std::left << H0
00749     << std::setw(width) << std::left << H3
00750     << std::setw(width) << std::left << (H3 - H0) / (epsilon * epsilon)
00751     << std::endl;
00752     
00753     std::cout << "    " << std::setw(nColumn * width) << std::setfill('-') << "" << std::setfill(' ') << std::endl;
00754     
00755 }
00756 
00759 
00760 template <typename T>
00761 void chainBundle<T>::initAdaptation()
00762 {
00763     
00764     mAdaptMu = log(mStepSize / (1 - mStepSize) );
00765     mAdaptLogEpsBar = log(mStepSize / (1 - mStepSize) );
00766     
00767     mAdaptHBar = 0;
00768     mAdaptCounter = 0;
00769     
00770     mNumLeapfrog = (int)(mAdaptIntTime / mStepSize);
00771     mNumLeapfrog = mNumLeapfrog < 1 ? 1 : mNumLeapfrog;
00772     mNumLeapfrog = mNumLeapfrog > mAdaptMaxLeapfrog ? mAdaptMaxLeapfrog : mNumLeapfrog;
00773     
00774 }
00775 
00778 
00779 template <typename T>
00780 void chainBundle<T>::updateAdaptation(double metropolisProb)
00781 {
00782     
00783     metropolisProb = metropolisProb > 1 ? 1 : metropolisProb;
00784     
00785     // Update averaging parameters
00786     ++mAdaptCounter;
00787     
00788     double delta = 1.0 / (mAdaptCounter + mAdaptT0);
00789     
00790     mAdaptHBar = (1.0 - delta) * mAdaptHBar + delta * (mAdaptTargetAccept - metropolisProb);
00791     
00792     double logEps = mAdaptMu - mAdaptHBar * sqrt(mAdaptCounter) / mAdaptGamma;
00793     delta = exp( - mAdaptKappa * log( mAdaptCounter ) );
00794     
00795     mAdaptLogEpsBar = (1.0 - delta) * mAdaptLogEpsBar + delta * logEps;
00796     
00797     // Then the stepsize
00798     mStepSize = 1.0 / ( 1.0 + exp(-mAdaptLogEpsBar) );
00799     
00800     // And the number of leapfrog steps to maintain a constant integration time
00801     mNumLeapfrog = (int)(mAdaptIntTime / mStepSize);
00802     mNumLeapfrog = mNumLeapfrog < 1 ? 1 : mNumLeapfrog;
00803     mNumLeapfrog = mNumLeapfrog > mAdaptMaxLeapfrog ? mAdaptMaxLeapfrog : mNumLeapfrog;
00804     
00805 }
00806 
00808 
00809 template <typename T>
00810 void chainBundle<T>::transition()
00811 {
00812     for(mIt = mChains.begin(); mIt != mChains.end(); ++mIt) transition(*mIt);
00813 }
00814 
00817 
00818 template <typename T>
00819 void chainBundle<T>::transition(int i)
00820 {
00821     
00822     if(i < 0 || i >= mChains.size())
00823     {
00824         cout << "chainBundle::transition() - Bad chain index " << i << "!" << endl;
00825         return;
00826     }
00827     
00828     transition(mChains.at(i));
00829     
00830     return;
00831     
00832 }
00833 
00838 
00839 template <typename T>
00840 void chainBundle<T>::saveTrajectory(std::ofstream& outputFile, const int i)
00841 {
00842     
00843     outputFile << mStepSize << "\t" << mNumLeapfrog << endl << endl;
00844     
00845     chain(i)->prepareEvolution();
00846     chain(i)->sampleP(mRandom);
00847     
00848     outputFile << 0 << "\t" << chain(i)->H() << "\t" << chain(i)->T() << "\t" << chain(i)->V() << flush;
00849     
00850     for(int j = 0; j < chain(i)->dim(); ++j) outputFile << "\t" << chain(i)->q()(j) << flush;
00851     for(int j = 0; j < chain(i)->dim(); ++j) outputFile << "\t" << chain(i)->p()(j) << flush;  
00852     outputFile << endl;
00853     
00854     for(int n = 0; n < mNumLeapfrog; ++n) 
00855     {
00856         
00857         evolve(chain(i), mStepSize);
00858         
00859         outputFile << n + 1 << "\t" << chain(i)->H() << "\t" << chain(i)->T() << "\t" << chain(i)->V() << flush;
00860         
00861         for(int j = 0; j < chain(i)->dim(); ++j) outputFile << "\t" << chain(i)->q()(j) << flush;
00862         for(int j = 0; j < chain(i)->dim(); ++j) outputFile << "\t" << chain(i)->p()(j) << flush;  
00863         outputFile << endl;
00864         
00865     }
00866     
00867     outputFile.close();
00868     
00869     return;
00870     
00871 }
00872 
00881 
00882 template <typename T>
00883 bool chainBundle<T>::transition(T* chain)
00884 {
00885     
00886     // Check that the chain was properly seeded
00887     if(mNumSamples == 0)
00888     {
00889         
00890         mConstraint = fConstraint(chain);
00891         
00892         if(!mConstraint)
00893         {
00894             cout << "chainBundle::transition() - Initial chain parameters in violation "
00895             << "of constraints, aborting the transition!" << endl;
00896             return false;
00897         }
00898         
00899     }
00900     
00901     bool accept = true;
00902     
00903     for(int n = 0; n < mNumSubsample; ++n)
00904     {
00905         
00906         // Add random jitter to the step size to avoid closed loops, and
00907         // an occassional jerk to allow the chain to move through narrow valleys
00908         double stepSize = mStepSize;
00909         
00910         if(mRandom.Prob<double>(mProbStepSizeJerk)) 
00911         {
00912             stepSize *= mStepSizeJerk;
00913         }
00914         else
00915         {
00916             stepSize *= 1.0 + mStepSizeJitter * (2.0 * mRandom.FloatU() - 1.0);
00917         }
00918         
00919         // Prepare the chain
00920         chain->prepareEvolution();
00921         
00922         // Sample momenta conditioned on the current position of the chain
00923         chain->sampleP(mRandom);
00924         
00926         //        Sample from the reject window         //
00928         
00929         // Immediately accept initial point as current sample
00930         chain->saveAsRejectSample();
00931         double logSumRejectProb = -chain->H();
00932         
00933         if(mWindowSize > 0)
00934         {
00935             
00936             // Backwards evolution
00937             stepSize *= -1;
00938             
00939             chain->saveCurrentPoint();
00940             int s = mRandom.Integer(mWindowSize);
00941             
00942             for(int t = 0; t < s; ++t)
00943             {
00944                 
00945                 evolve(chain, stepSize);
00946                 
00947                 // Accept or reject updating the sample, with constraint violations immediately rejected 
00948                 if(mConstraint) 
00949                 {
00950                     double Hplus = chain->H();
00951                     logSumRejectProb = fLogSumExp(logSumRejectProb, -Hplus);
00952                     if( mRandom.Prob<double>( exp(-Hplus - logSumRejectProb) ) ) chain->saveAsRejectSample();
00953                 }
00954                 
00955             }
00956             
00957             // Forwards evolution
00958             stepSize *= -1;
00959             
00960             chain->restoreStoredPoint();
00961             
00962             for(int t = 0; t < mWindowSize - s - 1; ++t)
00963             {
00964                 
00965                 evolve(chain, stepSize);
00966                 
00967                 // Accept or reject updating the sample, with constraint violations immediately rejected 
00968                 if(mConstraint) 
00969                 {
00970                     double Hplus = chain->H();
00971                     logSumRejectProb = fLogSumExp(logSumRejectProb, -Hplus);
00972                     if( mRandom.Prob<double>( exp(-Hplus - logSumRejectProb) ) ) chain->saveAsRejectSample();
00973                 }
00974                 
00975             }
00976             
00977         }
00978         
00980         //       Evolve for mNumLeapfrog iterations     //
00982         
00983         if(mVerbosity >= 2)
00984         {
00985             cout << "Beginning leapfrog:" << endl;
00986             cout << endl;
00987             chain->displayState();
00988             cout << endl;
00989         }
00990         
00991         if(mTemperAlpha) chain->p() *= sqrt(mTemperAlpha);
00992         
00993         
00994         double m = 0.5 * (mNumLeapfrog - 2 * mWindowSize);
00995         
00996         for(unsigned int t = 0; t < mNumLeapfrog - 2 * mWindowSize; ++t)
00997         {
00998             
00999             // Immediately reject if a NaN shows up
01000             if(chain->isNaN()) 
01001             {
01002                 if(mVerbosity >= 1) cout << "Immediately rejecting a NaN state..." << endl;
01003                 break;
01004             }
01005             
01006             // Evolve one step
01007             evolve(chain, stepSize);
01008             
01009             // Temper the momenta
01010             if(mTemperAlpha)
01011             {
01012                 if(t < m)       chain->p() *= sqrt(mTemperAlpha);
01013                 else if(t >= m) chain->p() /= sqrt(mTemperAlpha);
01014             }
01015             
01016         }
01017         
01018         if(mVerbosity >= 2)
01019         {
01020             cout << "Ending leapfrog:" << endl;
01021             cout << endl;
01022             chain->displayState();
01023             cout << endl;
01024         }
01025         
01027         //        Sample from the accept window         //
01029         
01030         double logSumAcceptProb = 0;
01031         bool goodAcceptSample = false;
01032         
01033         if(!chain->isNaN())
01034         {
01035             
01036             // Immediately accept current point, provided the constraint is not violated            
01037             if(mConstraint) 
01038             {
01039                 chain->saveAsAcceptSample();
01040                 logSumAcceptProb = -chain->H();
01041                 goodAcceptSample = true;
01042             }
01043             
01044             if(mWindowSize > 0)
01045             {
01046                 
01047                 for(int t = 0; t < mWindowSize - 1; ++t)
01048                 {
01049                     
01050                     evolve(chain, stepSize);
01051                     
01052                     // Accept or reject updating the sample, with constraint violations immediately rejected 
01053                     if(mConstraint) 
01054                     {
01055                         
01056                         // Immediately reject if a NaN shows up
01057                         if(chain->isNaN()) 
01058                         {
01059                             if(mVerbosity >= 1) cout << "Immediately rejecting a NaN state..." << endl;
01060                             break;
01061                         }
01062                         
01063                         double Hplus = chain->H();
01064                         
01065                         // Immediately accept if no sample has yet been accepted
01066                         if(!goodAcceptSample)
01067                         {
01068                             logSumAcceptProb = -Hplus;
01069                             chain->saveAsAcceptSample();
01070                             goodAcceptSample = true;
01071                         }
01072                         else
01073                         {
01074                             logSumAcceptProb = fLogSumExp(logSumAcceptProb, -Hplus);
01075                             if( mRandom.Prob<double>( exp(-Hplus - logSumRejectProb) ) ) chain->saveAsAcceptSample();
01076                         }
01077                         
01078                     }
01079                     
01080                 }
01081                 
01082             }
01083             else
01084             {
01085                 
01086                 if(!mConstraint)
01087                 {
01088                     chain->saveAsAcceptSample();
01089                     goodAcceptSample = false;
01090                 }
01091                 
01092             }
01093             
01094         }
01095         
01097         //   Sample between reject and accept windows   //
01099         
01100         double metropolisProb = 0;
01101         if(goodAcceptSample) metropolisProb = exp(logSumAcceptProb - logSumRejectProb);
01102         if(metropolisProb != metropolisProb) metropolisProb = 0;
01103         
01104         if(metropolisProb > 1) accept = true;
01105         else                   accept = mRandom.Prob<double>(metropolisProb);
01106         
01107         chain->sampleWindows(accept);
01108         
01109         if(mVerbosity >= 2)
01110         {
01111             if(accept) cout << "Accepting proposed sample with" << endl;
01112             else       cout << "Rejecting proposed sample with" << endl;
01113             
01114             cout << "    log(p_{accept window}) = " << logSumAcceptProb << endl;
01115             cout << "    log(p_{reject window}) = " << logSumRejectProb << endl;
01116             cout << "    p(accept window) = " << metropolisProb << endl << endl;
01117             
01118         }
01119         
01120         chain->updateMetroStats(accept, metropolisProb > 1 ? 1.0 : metropolisProb);
01121         
01122         if(mAdaptStepSize) updateAdaptation(metropolisProb);
01123         
01124     }
01125     
01126     // Store sample if desired
01127     if(mStoreSamples) 
01128     {
01129         mSamples.push_back(VectorXd(chain->q()));
01130         mSampleE.push_back(chain->V());
01131     }
01132     
01133     ++mNumSamples;
01134     
01135     return accept;
01136     
01137 }
01138 
01145 
01146 template <typename T>
01147 void chainBundle<T>::checkIntError(int i, int N, int f)
01148 {
01149     
01150     if(i < 0 || i >= mChains.size())
01151     {
01152         cout << "chainBundle::checkIntError() - Bad chain index " << i << "!" << endl;
01153         return;
01154     }
01155     
01156     // Prepare chain
01157     mChains.at(i)->prepareEvolution();
01158     mChains.at(i)->sampleP(mRandom);
01159     
01160     mChains.at(i)->displayState();
01161     
01162     double initH = mChains.at(i)->H();
01163     
01164     // Display Header
01165     std::cout.precision(6);
01166     int width = 12;
01167     int nColumn = 4;
01168     
01169     std::cout << "Displaying the integration error of chain " << i << ":" << std::endl;
01170     std::cout << "    " << std::setw(nColumn * width) << std::setfill('-') << "" << std::setfill(' ') << std::endl;
01171     std::cout << "    "
01172     << std::setw(width) << std::left << "Step" 
01173     << std::setw(width) << std::left << "H_{0}"
01174     << std::setw(width) << std::left << "H_{i}"
01175     << std::setw(width) << std::left << "H_{0} - H_{i}"
01176     << std::endl;
01177     std::cout << "    " << std::setw(nColumn * width) << std::setfill('-') << "" << std::setfill(' ') << std::endl;
01178     
01179     // Evolve and display results
01180     for(int n = 0; n < N; ++n)
01181     {
01182         
01183         evolve(mChains.at(i), mStepSize);
01184         
01185         if(!(n % f))
01186         {
01187             std::cout << "    "
01188             << std::setw(width) << std::left << n
01189             << std::setw(width) << std::left << initH
01190             << std::setw(width) << std::left << mChains.at(i)->H()
01191             << std::setw(width) << std::left << initH -  mChains.at(i)->H()
01192             << std::endl;
01193         }
01194         
01195     }
01196     
01197     std::cout << "    " << std::setw(nColumn * width) << std::setfill('-') << "" << std::setfill(' ') << std::endl;
01198     std::cout << std::endl;
01199     
01200 }
01201 
01205 
01206 template <typename T>
01207 void chainBundle<T>::seed(const double min, const double max)
01208 {
01209     for(int i = 0; i < mChains.at(0)->dim(); ++i) seed(i, min, max);
01210 }
01211 
01216 
01217 template <typename T>
01218 void chainBundle<T>::seed(const int i, const double min, const double max)
01219 {
01220     
01221     if(i < 0 || i >= mChains.at(0)->dim())
01222     {
01223         cout << "chainBundle::seed() - Bad parameter index!" << endl;
01224         return;
01225     }
01226     
01227     for(mIt = mChains.begin(); mIt != mChains.end(); ++mIt) 
01228     {
01229         (*mIt)->q()(i) = (max - min) * mRandom.FloatU<double>() + min;
01230     }
01231     
01232 }
01233 
01245 
01246 template <typename T>
01247 void chainBundle<T>::burn(const int nBurn, const int nCheck, const double minR, const bool verbose)
01248 {
01249     
01250     // Convergence storage
01251     long dim = mChains.at(0)->dim();
01252     double m = (double)mChains.size();
01253     double n = (double)nCheck;
01254     
01255     VectorXd R(dim);   // Gelman-Rubin statistics
01256     
01257     VectorXd* chainSum[(int)m];
01258     for(int i = 0; i < m; ++i) chainSum[i] = new VectorXd(dim);
01259     VectorXd ensembleSum(dim);
01260     VectorXd ensembleSum2(dim);
01261     VectorXd chainSum2(dim);
01262     
01263     bool burning = true;
01264     
01265     int nPerLine = 5;
01266     int nLines = (int)dim / nPerLine;
01267     
01268     cout.precision(6);
01269     int width = 12;
01270     int totalWidth = width + 8;
01271     int borderWidth = ((int)dim < nPerLine ? (int)dim : nPerLine) * totalWidth + 4;
01272     
01273     int acceptWidth = 14;
01274     
01276     //              Burn in Markov Chain            //
01278     
01279     // Temporarily store samples
01280     bool sampleFlag = mStoreSamples;
01281     mStoreSamples = false;
01282     
01283     // Burn through initial samples
01284     if(verbose) cout << endl << "Burn, baby, burn" << flush;
01285     
01286     for(int i = 0; i < nBurn; ++i) 
01287     {
01288         transition();
01289         if(verbose) if(i % 10 == 0) cout << "." << flush;
01290     }
01291     
01292     if(verbose) cout << endl << endl;
01293     if(verbose) cout << "Computing diagnostics:" << endl;
01294     if(verbose) cout << "    " << std::setw(borderWidth) << std::setfill('-') << "" << std::setfill(' ') << endl;
01295     
01296     while(burning)
01297     {
01298         
01299         ensembleSum.setZero();
01300         ensembleSum2.setZero();
01301         for(int i = 0; i < m; ++i) (chainSum[i])->setZero();
01302         chainSum2.setZero();
01303         
01304         // Burn through diagnostic samples
01305         for(int i = 0; i < nCheck; ++i) 
01306         {
01307             
01308             transition();
01309             
01310             mIt = mChains.begin();
01311             for(int j = 0; j < m; ++j, ++mIt)
01312             {
01313                 
01314                 VectorXd& q = (*mIt)->q();
01315                 
01316                 ensembleSum += q;
01317                 ensembleSum2 += q.cwiseAbs2();
01318                 
01319                 *(chainSum[j]) += q;
01320                 
01321             }
01322             
01323         }
01324         
01325         // Compute Gelman-Rubin statistic for each parameter
01326         double a = (n - 1) / n;
01327         double b = m / (m - 1);
01328         
01329         for(int j = 0; j < m; ++j)
01330         {
01331             chainSum2 += (chainSum[j])->cwiseAbs2();
01332         }
01333         
01334         ensembleSum = ensembleSum.cwiseAbs2();
01335         ensembleSum = ensembleSum.cwiseQuotient(chainSum2);
01336         ensembleSum /= m;
01337         ensembleSum = VectorXd::Ones(dim) - ensembleSum;
01338         
01339         ensembleSum2 = ensembleSum2.cwiseQuotient(chainSum2);
01340         ensembleSum2 *= n;
01341         ensembleSum2 = VectorXd::Ones(dim) - ensembleSum2;
01342         
01343         R = a * (VectorXd::Ones(dim) - b * ensembleSum.cwiseQuotient(ensembleSum2));
01344         
01345         burning = false;
01346         for(int i = 0; i < dim; ++i) burning |= (R[i] > minR);
01347         
01348         // Failure output
01349         if(verbose && burning)
01350         {
01351             cout << "    Diagnostic test failed," << endl;
01352             
01353             int k = 0;
01354             for(int i = 0; i < nLines; ++i)
01355             {
01356                 
01357                 cout << "        " << flush;
01358                 for(int j = 0; j < nPerLine; ++j, ++k)
01359                 {
01360                     cout << "R_{" << k << "} = " << std::setw(width) << std::left << R[k] << flush;
01361                 }
01362                 
01363                 cout << endl;
01364                 
01365             }
01366             
01367             if(dim % nPerLine > 0)
01368             {
01369                 
01370                 cout << "        " << flush;
01371                 for(int i = 0; i < dim % nPerLine; ++i, ++k)
01372                 {
01373                     cout << "R_{" << k << "} = " << std::setw(width) << std::left << R[k] << flush;
01374                 }
01375                 cout << endl;
01376                 
01377             }
01378             
01379             cout << "    " << std::setw(borderWidth) << std::setfill('-') << "" << std::setfill(' ') << endl;
01380             
01381         }
01382         
01383     }
01384     
01385     // Display convergence details if desired
01386     if(verbose)
01387     {
01388         
01389         cout << "    Markov chains converged with" << endl;
01390         
01391         int k = 0;
01392         for(int i = 0; i < nLines; ++i)
01393         {
01394             
01395             cout << "        " << flush;
01396             for(int j = 0; j < nPerLine; ++j, ++k)
01397             {
01398                 cout << "R_{" << k << "} = " << std::setw(width) << std::left << R[k] << flush;
01399             }
01400             
01401             cout << endl;
01402             
01403         }
01404         
01405         if(dim % nPerLine > 0)
01406         {
01407             
01408             cout << "        " << flush;
01409             for(int i = 0; i < dim % nPerLine; ++i, ++k)
01410             {
01411                 cout << "R_{" << k << "} = " << std::setw(width) << std::left << R[k] << flush;
01412             }
01413             cout << endl;
01414             
01415         }
01416         
01417         cout << "    " << std::setw(borderWidth) << std::setfill('-') << "" << std::setfill(' ') << endl;
01418         
01419         cout << endl;
01420         
01421         cout << "    " << std::setw(5 * acceptWidth / 2) << std::setfill('-') << "" << std::setfill(' ') << endl;
01422         cout << "    "
01423         << std::setw(acceptWidth / 2) << std::left << "Chain" 
01424         << std::setw(acceptWidth) << std::left << "Global"
01425         << std::setw(acceptWidth) << std::left << "Local"
01426         << std::endl;
01427         cout << "    "
01428         << std::setw(acceptWidth / 2) << std::left << "" 
01429         << std::setw(acceptWidth) << std::left << "Accept Rate"
01430         << std::setw(acceptWidth) << std::left << "Accept Rate"
01431         << std::endl;
01432         cout << "    " << std::setw(5 * acceptWidth / 2) << std::setfill('-') << "" << std::setfill(' ') << endl;
01433         
01434         for(int i = 0; i < mChains.size(); ++i)
01435         {
01436             cout << "    "
01437             << std::setw(acceptWidth / 2) << std::left << i 
01438             << std::setw(acceptWidth) << std::left << (mChains.at(i))->acceptRate()
01439             << std::setw(acceptWidth) << std::left << (mChains.at(i))->movingAcceptRate()
01440             << endl;
01441         }
01442         cout << "    " << std::setw(5 * acceptWidth / 2) << std::setfill('-') << "" << std::setfill(' ') << endl;
01443         cout << endl;
01444         
01445     }
01446     
01447     mChar = true;
01448     
01449     // Return sample flag
01450     mStoreSamples = sampleFlag;
01451     
01452     return;
01453     
01454 }
01455 
01461 
01462 template <typename T>
01463 double chainBundle<T>::fLogSumExp(double a, double b)
01464 {
01465     
01466     if(a > b) 
01467     {
01468         return a + log( 1.0 + exp(b - a) );
01469     }
01470     else
01471     {      
01472         return b + log( 1.0 + exp(a - b) );
01473     }
01474     
01475 }
01476 
01477 #define _BETA_CHAINBUNDLE_
01478 #endif
 All Classes Functions Variables