![]() |
Object-oriented Scientific Computing Library: Version 0.910
|
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
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).