naive_metropolis.h

00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006, 2007, Andrew W. Steiner
00005   
00006   This file is part of O2scl.
00007   
00008   O2scl is free software; you can redistribute it and/or modify
00009   it under the terms of the GNU General Public License as published by
00010   the Free Software Foundation; either version 3 of the License, or
00011   (at your option) any later version.
00012   
00013   O2scl is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016   GNU General Public License for more details.
00017   
00018   You should have received a copy of the GNU General Public License
00019   along with O2scl. If not, see <http://www.gnu.org/licenses/>.
00020 
00021   -------------------------------------------------------------------
00022 */
00023 #ifndef O2SCL_NAIVE_METROPOLIS_H
00024 #define O2SCL_NAIVE_METROPOLIS_H
00025 
00026 #include <iostream>
00027 #include <o2scl/collection.h>
00028 #include <o2scl/funct.h>
00029 #include <o2scl/mcarlo_inte.h>
00030 #include <o2scl/gsl_rnga.h>
00031 
00032 #ifndef DOXYGENP
00033 namespace o2scl {
00034 #endif
00035 
00036   /** 
00037       \brief Naive metropolis monte carlo integration
00038 
00039       Very experimental.
00040       
00041       This returns the ratio of n-dimensional integrals
00042       \f[
00043       I = \frac{\int f(\vec{x}) \exp\left[-\beta~w(\vec{x})\right] d \vec{x}}
00044       {\int \exp\left[-\beta~w(\vec{x})\right] d \vec{x}}
00045       \f]
00046       for function  \f$ f \f$  specified in \c func and  \f$ w \f$ 
00047       specified in \c weight. 
00048 
00049       A "Metropolis step" (or simply a "step") is defined by 
00050       the following procedure: The step \f$ \vec{x}_0 \rightarrow 
00051       \vec{x}_1 \f$ is accepted if
00052       \f[
00053       w(\vec{x}_1)<w_(\vec{x}_0)
00054       \f]
00055       or if 
00056       \f[
00057       e^{-\beta \left[w(\vec{x}_1)-w_(\vec{x}_0)\right]}>r
00058       \f]
00059       where  \f$ r \f$  is a uniform random number  \f$ [0,1) \f$  newly
00060       generated for each step.
00061 
00062       \ref nstart steps are taken initially to ensure the first point
00063       is created with the correct probability. Afterwards, the
00064       average value of the function is stored over \ref niter steps.
00065       This average value is computed \ref nblock times to get
00066       an overall average and an estimate of the uncertainity.
00067 
00068       \todo Talk about how accurate this is with \f$ \beta \f$ .
00069       \todo Redo statistics, talk about how many times the integral
00070       is evaluated. 
00071       \todo Offer an option of giving more results 
00072       than just the final averange and error?
00073       
00074       \b Minimization
00075 
00076       There is a connection between integration over functions of this
00077       type and minimization. The expression
00078       \f[
00079       \lim_{T \rightarrow 0} 
00080       \frac{\int_{x=a}^{x=b} f(x) e^{-f(x)/T}}
00081       {\int_{x=a}^{x=b} e^{-f(x)/T}}
00082       \f]
00083       gives the minimum of the function  \f$ f(x) \f$  in the region
00084        \f$ x \in (a,b) \f$ .
00085 
00086   */
00087   template<class param_t, class func_t, class rng_t,
00088     class vec_t, class alloc_vec_t> class naive_metropolis :
00089     public mcarlo_inte<param_t,func_t,rng_t,vec_t>
00090 
00091     {
00092     public:
00093 
00094       rng_t rng;
00095       
00096       naive_metropolis() {
00097         nblock=10;
00098         niter=10000;
00099         nstart=1000;
00100       }
00101       
00102       virtual ~naive_metropolis() {}
00103     
00104       /** 
00105           \brief Calculate the integral returning result in \c value
00106 
00107           Calculates the integral given the functions \c func and \c weight
00108           over the region specified by \c a and \c b, both of side \c ndim.
00109           The value of  \f$ \beta \f$  is specified in \c beta, and the
00110           result is returned in \c value, with the uncertainty given
00111           in \c err.
00112       */
00113       virtual int minteg_err(func_t &func, func_t &energy, size_t ndim, 
00114                              const vec_t &a, const vec_t &b, 
00115                              const double beta, double &value, double &err, 
00116                              param_t &pa) 
00117         {
00118           double value2=0.0, bvalue;
00119           alloc_vec_t x, xnew;
00120           
00121           value=0.0;
00122           
00123           // Choose a random starting point
00124           for(size_t i=0;i<ndim;i++) {
00125             x[i]=rng.random()*(b[i]-a[i])+a[i];
00126           }
00127 
00128           // Take several steps to ensure independence
00129           // from the starting point
00130           for(size_t n=0;n<nstart;n++) {
00131 
00132             // Pick a new point
00133             for(size_t i=0;i<ndim;i++) {
00134               xnew[i]=rng.random()*(b[i]-a[i])+a[i];
00135             }
00136 
00137             // Take a step
00138             double dw=energy(ndim,xnew,pa)-energy(ndim,x,pa);
00139             if (dw<0 || exp(-beta*dw)>rng.random()) {
00140               for(size_t i=0;i<ndim;i++) {
00141                 x[i]=xnew[i];
00142               }
00143             }
00144 
00145           }
00146 
00147           for(unsigned long int ib=0;ib<nblock;ib++) {
00148 
00149             bvalue=0.0;
00150 
00151             // Integrate the function
00152             for(size_t n=0;n<niter;n++) {
00153               double t=func(ndim,x,pa);
00154               bvalue+=t;
00155       
00156               // Pick a new point
00157               for(size_t i=0;i<ndim;i++) {
00158                 xnew[i]=rng.random()*(b[i]-a[i])+a[i];
00159               }
00160       
00161               // Decide to accept or reject
00162               double dw=energy(ndim,xnew,pa)-energy(ndim,x,pa);
00163               if (dw<0 || exp(-beta*dw)>rng.random()) {
00164                 for(size_t i=0;i<ndim;i++) {
00165                   x[i]=xnew[i];
00166                 }
00167               }
00168             }
00169     
00170             bvalue/=((double)niter);
00171             value+=bvalue;
00172             value2+=bvalue*bvalue;
00173 
00174           }
00175 
00176           value/=((double)nblock);
00177           value2/=((double)nblock);
00178           err=sqrt(fabs(value2-value*value));
00179 
00180           return 0;
00181         }
00182 
00183       /** 
00184           \brief Calculate the integral returning result in \c value
00185 
00186           Calculates the integral given the functions \c func and \c weight
00187           over the region specified by \c a and \c b, both of side \c ndim.
00188           The value of  \f$ \beta \f$  is specified in \c beta, and the
00189           result is returned in \c value, with the uncertainty given
00190           in \c err.
00191       */
00192       virtual int minteg_array(func_t &func, func_t &energy, size_t ndim, 
00193                                const vec_t &a, const vec_t &b, 
00194                                const double beta, vec_t &results, param_t &pa) 
00195         {
00196           double value2=0.0, bvalue;
00197           alloc_vec_t x, xnew;
00198 
00199           unsigned long int ix=0;
00200 
00201           // Choose a random starting point
00202           for(size_t i=0;i<ndim;i++) {
00203             x[i]=rng.random()*(b[i]-a[i])+a[i];
00204           }
00205 
00206           // Take several steps to ensure independence
00207           // from the starting point
00208           for(size_t n=0;n<nstart;n++) {
00209 
00210             // Pick a new point
00211             for(size_t i=0;i<ndim;i++) {
00212               xnew[i]=rng.random()*(b[i]-a[i])+a[i];
00213             }
00214 
00215             // Take a step
00216             double dw=energy(ndim,xnew,pa)-energy(ndim,x,pa);
00217             if (dw<0 || exp(-beta*dw)>rng.random()) {
00218               for(size_t i=0;i<ndim;i++) {
00219                 x[i]=xnew[i];
00220               }
00221             }
00222 
00223           }
00224 
00225           for(unsigned long int ib=0;ib<nblock;ib++) {
00226 
00227             bvalue=0.0;
00228 
00229             // Integrate the function
00230             for(size_t n=0;n<niter;n++) {
00231               double t=func(ndim,x,pa);
00232               bvalue+=t;
00233       
00234               // Pick a new point
00235               for(size_t i=0;i<ndim;i++) {
00236                 xnew[i]=rng.random()*(b[i]-a[i])+a[i];
00237               }
00238       
00239               // Decide to accept or reject
00240               double dw=energy(ndim,xnew,pa)-energy(ndim,x,pa);
00241               if (dw<0 || exp(-beta*dw)>rng.random()) {
00242                 for(size_t i=0;i<ndim;i++) {
00243                   x[i]=xnew[i];
00244                 }
00245               }
00246             }
00247 
00248             results[ix]=bvalue;
00249             ix++;
00250 
00251           }
00252           
00253           return 0;
00254         }
00255     
00256       /// The number of iterations (default 10000)
00257       unsigned long int niter;
00258 
00259       /// The number of warm-up iterations (default 1000)
00260       unsigned long int nstart;
00261 
00262       /// Number of blocks (default 10)
00263       unsigned long int nblock;
00264     };
00265 
00266 #ifndef DOXYGENP
00267 }
00268 #endif
00269 
00270 #endif
00271 
00272 
00273 
00274 
00275 
00276 

Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.

Project hosting provided by SourceForge.net Logo, O2scl Sourceforge Project Page