Object-oriented Scientific Computing Library: Version 0.910
expect_val.h
00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2011-2012 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 EXPECT_VAL_H
00024 #define EXPECT_VAL_H
00025 
00026 #include <o2scl/uvector_tlate.h>
00027 #include <o2scl/umatrix_tlate.h>
00028 #include <o2scl/vec_stats.h>
00029 
00030 #ifndef DOXYGENP
00031 namespace o2scl {
00032 #endif
00033   
00034   /** \brief Expectation value base class
00035       
00036       This class is experimental.
00037       
00038       This is a base class for a set of classes useful for recording
00039       the outputs of several iterations of a numerical simulation, and
00040       summarizing the average, standard deviation, and error in the
00041       average over all iterations. After each iteration, some
00042       measurement is performed, and that measurement is added to the
00043       class with an <tt>add()</tt> functions (e.g. \ref
00044       scalar_ev::add() ). Autocorrelations are common in numerical
00045       simulations, and to handle this difficulty the measurements may
00046       be demarcated into 'blocks'. These blocks may have a variable or
00047       fixed number of measurements in each block.
00048 
00049       The constructor needs as input the number of blocks to record
00050       (at least one) and the number of measurements per block. The
00051       number of measurements per block can be zero to indicate an
00052       unspecified number of blocks to record.
00053 
00054       If the number of measurements per block is greater than zero,
00055       then blocks are filled one by one, moving to the next block when
00056       the requested of measurements (<tt>n_per_block</tt>) in the
00057       previous block has been provided. If the number of measurements
00058       per block is zero, then the blocks are filled evenly.
00059 
00060       Current averages are always reported, though not all data is
00061       always used if there are incomplete blocks or the blocks have
00062       not yet been filled evenly. Two functions <tt>current_avg()</tt>
00063       and <tt>current_avg_stats()</tt> are provided in children. The
00064       latter provides the number of blocks and number of measurements
00065       per block used in the currently reported statistics. If only one
00066       block or one measurement is available, the standard deviation is
00067       reported as zero. If no data is available, then calls to
00068       <tt>current_avg()</tt> will call the error handler. See, e.g.
00069       \ref scalar_ev::current_avg() and \ref
00070       scalar_ev::current_avg_stats().
00071 
00072       If <tt>n_per_block</tt> is nonzero, then children call the error
00073       handler if they get more than <tt>n_per_block</tt> times
00074       <tt>n_blocks</tt> measurements.
00075 
00076       \future If \c n_per_block is nonzero and the user adds more
00077       than \c n_blocks times \c n_per_block data, set \c n_per_block
00078       to zero, allocate the \c last structure and fall back to the 
00079       variable block size method. 
00080   */
00081   class expect_val {
00082 
00083   protected:
00084 
00085     /// Index denoting the current block number
00086     size_t iblock;
00087     
00088     /// Index for the number of values in the current block (or blocks)
00089     size_t i;
00090 
00091     /** \brief Total number of blocks (default 1)
00092         
00093         This should never be zero.
00094     */
00095     size_t nblocks;
00096     
00097     /** \brief Number of measurements per block (default 0)
00098 
00099         This is zero to indicate blocks of unspecified size
00100     */
00101     size_t nperblock;
00102 
00103   public:
00104 
00105     /// Create with one block of unspecified size
00106     expect_val();
00107 
00108     /// Copy constructor
00109     expect_val(const expect_val &ev);
00110 
00111     /// Copy constructor
00112     expect_val &operator=(const expect_val &ev);
00113 
00114     /** \brief Create with \c n_blocks blocks and \c n_per_block points
00115         per block
00116 
00117         If this is called with a value of zero for \c n_blocks, then
00118         the error handler is called.
00119     */
00120     expect_val(size_t n_blocks, size_t n_per_block);
00121 
00122     virtual ~expect_val();
00123     
00124     /// The name of the expectation value
00125     std::string name;
00126     
00127     /// The shortened name
00128     std::string short_name;
00129 
00130     /** \brief Reset for \c n_blocks blocks and \c n_per_block points
00131         per block
00132 
00133         This function resets the currently stored data to zero
00134         by calling \ref reset(). If this is called with a value
00135         of zero for \c n_blocks, then the value 1 is assumed.
00136     */
00137     virtual void set_blocks(size_t n_blocks, size_t n_per_block);
00138 
00139     /** \brief Get the number of blocks and the number of points per
00140         block
00141     */
00142     virtual void get_blocks(size_t &n_blocks, size_t &n_per_block) const;
00143     
00144     /// Free allocated data
00145     virtual void free();
00146 
00147     /// Clear all the data
00148     virtual void reset();
00149 
00150     /** \brief Get the block index and the index within the current block
00151      */
00152     virtual void get_block_indices(size_t &i_block, 
00153                                    size_t &i_curr_block) const;
00154 
00155     /** \brief Returns true if all blocks have been stored
00156 
00157         If \c n_per_block is greater than zero, then this reports true
00158         only when all \c n_blocks times \c n_per_block data points
00159         have been added.
00160 
00161         Otherwise, this reports true whenever the last addition of
00162         data filled up the last block.
00163     */
00164     virtual bool finished() const;
00165 
00166     /** \brief Report progress as a fraction between zero to one 
00167         (inclusive)
00168         
00169         When \c n_per_block is zero, this reports the progress in
00170         having filled a round of blocks (i.e. whenever the last
00171         addition of data filled up the last block). This reports zero
00172         if no data has been added.
00173 
00174         When \c n_per_block is nonzero, this reports the total
00175         progress on all blocks, reporting \c 1.0 only when all \c
00176         n_blocks times \c n_per_block data points have been added.
00177     */
00178     virtual double progress() const;
00179 
00180   };
00181   
00182   /** \brief Scalar expectation value
00183 
00184       See \ref expect_val for some general notes on 
00185       this and related classes. 
00186 
00187       This class is experimental.
00188 
00189       \hline
00190       <b>Implementation notes</b>
00191 
00192       In the case where <tt>nperblock</tt> is zero, the vector \ref
00193       last is used to store the most recent measurements, copying the
00194       results to \ref vals only when <tt>nblocks</tt> measurements are
00195       stored in \ref last. The variable <tt>i</tt> is only incremented
00196       when the vector \ref last is full and the information is copied
00197       over to \ref vals. This ensures that \ref vals always contains
00198       averages with an equal number of measurements. The information
00199       in \ref last is never used by \ref reblock_avg().
00200   */
00201   class scalar_ev : public expect_val {
00202     
00203   protected:
00204     
00205     /** \brief The average for each block
00206         
00207         This is a vector of length \c nblocks.
00208     */
00209     uvector vals;
00210 
00211     /// The current rolling average
00212     double current;
00213 
00214     /** \brief The most recent values for each block
00215         
00216         This is a vector of length \c nblocks used for when
00217         \c n_per_block is set to zero.
00218     */
00219     uvector last;
00220 
00221   public:
00222     
00223     /// Create with one unspecified block
00224     scalar_ev();
00225     
00226     /** \brief Create with \c n_blocks blocks and \c n_per_block points
00227         block
00228     */
00229     scalar_ev(size_t n_blocks, size_t n_per_block);
00230 
00231     virtual ~scalar_ev();
00232     
00233     /// Copy constructor
00234     scalar_ev(const scalar_ev &ev);
00235 
00236     /// Copy constructor
00237     scalar_ev &operator=(const scalar_ev &ev);
00238 
00239     /** \brief Reset for \c n_blocks blocks and \c n_per_block points
00240         block
00241     */
00242     virtual void set_blocks(size_t n_blocks, size_t n_per_block);
00243 
00244     /// Free allocated data
00245     virtual void free();
00246 
00247     /// Clear all the data
00248     virtual void reset();
00249 
00250     /// Add measurement of value \c val
00251     virtual void add(double val);
00252 
00253     /// \name Report statistics
00254     //@{
00255     /** \brief Report current average, standard deviation, and 
00256         the error in the average and include block information
00257     */
00258     virtual void current_avg_stats(double &avg, double &std_dev, 
00259                                    double &avg_err, size_t &m_block,
00260                                    size_t &m_per_block) const;
00261 
00262     /** \brief Report current average, standard deviation, and 
00263         the error in the average
00264     */
00265     virtual void current_avg(double &avg, double &std_dev, 
00266                              double &avg_err) const;
00267     
00268     /** \brief Report average, standard deviation, and 
00269         the error in the average assuming a new block size
00270 
00271         \future Use recurrence relation for averages here
00272         rather than dividing at the end.
00273     */
00274     virtual void reblock_avg_stats(size_t new_blocks, double &avg, 
00275                                    double &std_dev, double &avg_err,
00276                                    size_t &m_per_block) const;
00277 
00278     /** \brief Report average, standard deviation, and 
00279         the error in the average assuming a new block size
00280     */
00281     virtual void reblock_avg(size_t new_blocks, double &avg, 
00282                              double &std_dev, double &avg_err) const;
00283     //@}
00284 
00285     /// \name Direct manipulation of the stored data 
00286     //@{
00287     /// Return the current data for all blocks
00288     const uvector &get_data() const;
00289 
00290     /// Return the current data for block with index \c i_block
00291     const double &operator[](size_t i_block) const;
00292 
00293     /// Return the current data for block with index \c i_block
00294     double &operator[](size_t i_block);
00295 
00296     /// Set the data for all blocks
00297     template<class vec_t> void set_data(vec_t &v) {
00298       for(size_t ib=0;ib<nblocks;ib++) {
00299         vals[ib]=v[ib];
00300       }
00301       return;
00302     }
00303     //@}
00304 
00305   };
00306 
00307   /** \brief Vector expectation value
00308 
00309       See \ref expect_val for some general notes on 
00310       this and related classes. 
00311 
00312       This class is experimental.
00313 
00314       This is a similar to \ref scalar_ev, except that it allows
00315       updating and statistics for a set of scalars en masse. The data
00316       is stored internally in \ref uvector and \ref umatrix objects,
00317       but the public member functions operate with template types
00318       which are compatible with any vector class which provides
00319       <tt>double &operator[]</tt>.
00320 
00321       Internally, data is stored in matrices designating the first
00322       (row) index as the user-specified vector index and designating
00323       the second (column) index as the block index.
00324   */
00325   class vector_ev : public expect_val {
00326     
00327   protected:
00328     
00329     /** \brief The most recent values for each block
00330      */
00331     umatrix last;
00332 
00333     /** \brief The average for each block
00334      */
00335     umatrix vals;
00336     
00337     /// The current rolling average
00338     uvector current;
00339 
00340     /// The size of the vector
00341     size_t nvec;
00342 
00343   public:
00344     
00345     /// Create for a vector of size \c n with no blocking
00346     vector_ev(size_t n);
00347 
00348     /** \brief Create for a vector of size \c n with \c n_blocks
00349         blocks and \c n_per_block points block
00350     */
00351     vector_ev(size_t n, size_t n_blocks, size_t n_per_block);
00352 
00353     /** \brief Set for a vector of size \c n with \c n_blocks blocks
00354         and \c n_per_block points block
00355     */
00356     virtual void set_blocks(size_t n, size_t n_blocks, size_t n_per_block);
00357 
00358     virtual ~vector_ev();
00359 
00360     /// Copy constructor
00361     vector_ev(const vector_ev &ev);
00362 
00363     /// Copy constructor
00364     vector_ev &operator=(const vector_ev &ev);
00365 
00366     /// Free allocated data
00367     virtual void free();
00368 
00369     /// Clear all the data
00370     virtual void reset();
00371 
00372     /// Add measurement of value \c val
00373     template<class vec_t> void add(vec_t &v) {
00374 
00375       // Handle varable block size case separately
00376       if (nperblock==0) {
00377 
00378         // Store in last vector and increment block index
00379         for(size_t iv=0;iv<nvec;iv++) {
00380           last[iv][iblock]=v[iv];
00381         }
00382         iblock++;
00383 
00384         // If last vector is full, add to vals, increment index,
00385         // and reset block counter
00386         if (iblock==nblocks) {
00387           for(size_t j=0;j<nblocks;j++) {
00388             for(size_t k=0;k<nvec;k++) {
00389               vals[k][j]+=(last[k][j]-vals[k][j])/(i+1);
00390             }
00391           }
00392           i++;
00393           iblock=0;
00394         }
00395 
00396         return;
00397       }
00398 
00399       if (iblock==nblocks) {
00400         O2SCL_ERR("Too much data provided in scalar_ev::add().",
00401                   gsl_einval);
00402       }
00403 
00404       // Keep track of the rolling average and increment the index
00405       for(size_t k=0;k<nvec;k++) {
00406         current[k]+=(v[k]-current[k])/(i+1);
00407       }
00408       i++;
00409 
00410       // If the block is full, store the average and move to the next block
00411       if (i==nperblock) {
00412         for(size_t iv=0;iv<nvec;iv++) {
00413           vals[iv][iblock]=current[iv];
00414         }
00415         iblock++;
00416         for(size_t k=0;k<nvec;k++) {
00417           current[k]=0.0;
00418         }
00419         i=0;
00420       }
00421 
00422       return;
00423     }
00424 
00425     /// \name Report statistics
00426     //@{
00427     /** \brief Report current average, standard deviation, and 
00428         the error in the average and include block information
00429     */
00430     template<class vec_t, class vec2_t, class vec3_t> 
00431       void current_avg_stats(vec_t &avg, vec2_t &std_dev, 
00432                              vec3_t &avg_err, size_t &m_block,
00433                              size_t &m_per_block) const {
00434       
00435       if (nperblock==0) {
00436 
00437         // Unspecified block size
00438 
00439         if (i<1) {
00440 
00441           if (iblock==0) {
00442 
00443             // No data
00444             O2SCL_ERR("No data in scalar_ev::current_avg_stats().",
00445                       gsl_einval);
00446 
00447           } else if (iblock==1) {
00448 
00449             // Only one data point
00450             m_block=1;
00451             m_per_block=1;
00452             for(size_t k=0;k<nvec;k++) {
00453               avg[k]=last[k][0];
00454               std_dev[k]=0.0;
00455               avg_err[k]=0.0;
00456             }
00457 
00458             return;
00459           }
00460           
00461           // Only one data point for some of the blocks
00462           m_block=iblock;
00463           m_per_block=1;
00464           for(size_t k=0;k<nvec;k++) {
00465             avg[k]=vector_mean(iblock,last[k]);
00466             std_dev[k]=vector_stddev(iblock,last[k]);
00467             avg_err[k]=std_dev[k]/sqrt(((double)iblock));
00468           }
00469 
00470           return;
00471         }
00472 
00473         // General case
00474         m_block=nblocks;
00475         m_per_block=i;
00476         for(size_t k=0;k<nvec;k++) {
00477           avg[k]=vector_mean(nblocks,vals[k]);
00478           std_dev[k]=vector_stddev(nblocks,vals[k]);
00479           avg_err[k]=std_dev[k]/sqrt(((double)nblocks));
00480         }
00481 
00482         return;
00483 
00484       } else if (iblock==0) {
00485 
00486         // We're blocking, but don't have any full blocks
00487         m_block=1;
00488         m_per_block=i;
00489         for(size_t k=0;k<nvec;k++) {
00490           avg[k]=current[k];
00491           std_dev[k]=0.0;
00492           avg_err[k]=0.0;
00493         }
00494 
00495         return;
00496       } else if (iblock==1) {
00497 
00498         // We're blocking, but have only one full block so far
00499         m_block=1;
00500         m_per_block=nperblock;
00501         for(size_t k=0;k<nvec;k++) {
00502           avg[k]=vals[k][0];
00503           std_dev[k]=0.0;
00504           avg_err[k]=0.0;
00505         }
00506 
00507         return;
00508       }
00509 
00510       // In the blocking case, report the average and std. dev.
00511       // for all the blocks which have been finished
00512       m_block=iblock;
00513       m_per_block=nperblock;
00514       for(size_t k=0;k<nvec;k++) {
00515         avg[k]=vector_mean(iblock,vals[k]);
00516         std_dev[k]=vector_stddev(iblock,vals[k]);
00517         avg_err[k]=std_dev[k]/sqrt(((double)iblock));
00518       }
00519       
00520       return;
00521     }
00522 
00523     /** \brief Report current average, standard deviation, and 
00524         the error in the average
00525     */
00526     template<class vec_t, class vec2_t, class vec3_t> 
00527       void current_avg(vec_t &avg, vec2_t &std_dev, vec3_t &avg_err) const {
00528       size_t m_per_block, m_block;
00529       return current_avg_stats(avg,std_dev,avg_err,m_block,m_per_block);
00530     }
00531 
00532     /** \brief Report average, standard deviation, and 
00533         the error in the average assuming a new block size
00534     */
00535     template<class vec_t, class vec2_t, class vec3_t> 
00536       void reblock_avg_stats(size_t new_blocks, vec_t &avg, 
00537                              vec2_t &std_dev, vec3_t &avg_err,
00538                              size_t &m_per_block) const {
00539 
00540       if (new_blocks==0) {
00541         O2SCL_ERR2("Requested zero blocks in ",
00542                    "vector_ev::reblock_avg_stats().",gsl_einval);
00543       }
00544       
00545       umatrix dat(nvec,new_blocks);
00546       dat.set_all(0.0);
00547       
00548       // If 'i==0' and 'nperblock==0', then not all of the blocks have
00549       // data yet, and we use the information from 'last' instead of
00550       // 'vals'.
00551       
00552       // The ratio of the old to new block size
00553       size_t fact=nblocks/new_blocks;
00554       if (i==0 && nperblock==0) fact=iblock/new_blocks;
00555       if (fact==0) {
00556         O2SCL_ERR2("Not enough data for reblocking ",
00557                    "in scalar_ev::reblock_avg_stats().",gsl_einval);
00558       }
00559       size_t iblock2=0;
00560       // Compute the sum
00561       for(size_t j=0;j<fact;j++) {
00562         for(size_t k=0;k<new_blocks;k++) {
00563           if (i==0 && nperblock==0) {
00564             for(size_t iv=0;iv<nvec;iv++) {
00565               dat[iv][k]+=last[iv][iblock2];
00566             }
00567           } else {
00568             for(size_t iv=0;iv<nvec;iv++) {
00569               dat[iv][k]+=vals[iv][iblock2];
00570             }
00571           }
00572           iblock2++;
00573         }
00574       }
00575       // Now divide to get averages
00576       for(size_t k=0;k<new_blocks;k++) {
00577         for(size_t iv=0;iv<nvec;iv++) {
00578           dat[iv][k]/=((double)fact);
00579         }
00580       }
00581       for(size_t iv=0;iv<nvec;iv++) {
00582         avg[iv]=vector_mean(new_blocks,dat[iv]);
00583         if (new_blocks>1) {
00584           std_dev[iv]=vector_stddev(new_blocks,dat[iv]);
00585           avg_err[iv]=std_dev[iv]/sqrt(((double)new_blocks));
00586         } else {
00587           std_dev[iv]=0.0;
00588           avg_err[iv]=0.0;
00589         }
00590       }
00591       
00592       if (i==0 && nperblock==0) m_per_block=fact;
00593       else if (nperblock==0) m_per_block=fact*i;
00594       else m_per_block=fact*nperblock;
00595       
00596       return;
00597     }
00598     
00599     /** \brief Report average, standard deviation, and 
00600         the error in the average assuming a new block size
00601     */
00602     template<class vec_t, class vec2_t, class vec3_t> 
00603       void reblock_avg(size_t new_blocks, vec_t &avg, 
00604                        vec2_t &std_dev, vec3_t &avg_err) const {
00605       size_t m_per_block;
00606       return reblock_avg_stats(new_blocks,avg,std_dev,avg_err,
00607                                m_per_block);
00608     }
00609     //@}
00610 
00611   };
00612 
00613 }
00614 
00615 #endif
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.