1 //============================================================================== 2 // 3 // This file is part of GPSTk, the GPS Toolkit. 4 // 5 // The GPSTk is free software; you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published 7 // by the Free Software Foundation; either version 3.0 of the License, or 8 // any later version. 9 // 10 // The GPSTk is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public 16 // License along with GPSTk; if not, write to the Free Software Foundation, 17 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 18 // 19 // This software was developed by Applied Research Laboratories at the 20 // University of Texas at Austin. 21 // Copyright 2004-2020, The Board of Regents of The University of Texas System 22 // 23 //============================================================================== 24 25 //============================================================================== 26 // 27 // This software was developed by Applied Research Laboratories at the 28 // University of Texas at Austin, under contract to an agency or agencies 29 // within the U.S. Department of Defense. The U.S. Government retains all 30 // rights to use, duplicate, distribute, disclose, or release this software. 31 // 32 // Pursuant to DoD Directive 523024 33 // 34 // DISTRIBUTION STATEMENT A: This software has been approved for public 35 // release, distribution is unlimited. 36 // 37 //============================================================================== 38 39 /// @file Stats.hpp 40 /// Conventional, sequential and weighted one-sample, and two-sample statistics 41 42 #ifndef INCLUDE_GPSTK_STATS_INCLUDE 43 #define INCLUDE_GPSTK_STATS_INCLUDE 44 45 #include <string> 46 #include <sstream> 47 #include <vector> 48 #include <algorithm> 49 #include "Exception.hpp" 50 #include "MiscMath.hpp" 51 #include "Vector.hpp" 52 53 namespace gpstk 54 { 55 /** @addtogroup math */ 56 //@{ 57 58 /// Compute the median of a gpstk::Vector median(const Vector<T> & v)59 template <class T> inline T median(const Vector<T>& v) 60 { 61 const int n(v.size()); 62 if(n==0) return T(); 63 if(n==1) return v(0); 64 if(n==2) return (v(0)+v(1))/T(2); 65 // insert sort 66 int i,j; 67 T x; 68 Vector<T> w(v); 69 for(i=0; i<n; i++) { 70 x = w[i] = v(i); 71 j = i-1; 72 while(j>=0 && x<w[j]) { 73 w[j+1] = w[j]; 74 j--; 75 } 76 w[j+1] = x; 77 } 78 79 if(n % 2) return (w[(n+1)/2-1]); 80 return ((w[n/2-1]+w[n/2])/T(2)); 81 82 } // end median(Vector) 83 84 /// median absolute deviation of a gpstk::Vector mad(const gpstk::Vector<T> & v)85 template <class T> inline T mad(const gpstk::Vector<T>& v) 86 { 87 if (v.size() < 2) return T(); 88 89 double med = gpstk::median(v); 90 gpstk::Vector<T> w(v); 91 for(size_t i=0; i < w.size(); i++) 92 w[i] = std::abs(w[i]- med); 93 94 return gpstk::median(w); 95 } // end mad(Vector) 96 97 /// Compute the median of a std::vector median(const std::vector<T> & v)98 template <class T> inline T median(const std::vector<T>& v) 99 { 100 const unsigned int n(v.size()); 101 if(n==0) return T(); 102 103 std::vector<T> w(v); 104 std::sort(w.begin(), w.end()); 105 106 if (n % 2) return w[(n+1)/2-1]; 107 return ((w[n/2-1]+w[n/2])/T(2)); 108 } // end median(vector) 109 110 /// median absolute deviation of a std::vector mad(const std::vector<T> & v)111 template <class T> inline T mad(const std::vector<T>& v) 112 { 113 if (v.size() < 2) return T(); 114 115 double med = gpstk::median(v); 116 std::vector<T> w(v); 117 for(size_t i=0; i < w.size(); i++) 118 w[i] = std::abs(w[i]- med); 119 120 return gpstk::median(w); 121 } // end mad(vector) 122 123 //--------------------------------------------------------------------------- 124 //--------------------------------------------------------------------------- 125 // forward declaration 126 template <class T> class TwoSampleStats; 127 128 //--------------------------------------------------------------------------- 129 /// Conventional statistics for one sample, with scaling to improve numerical 130 /// error in cases of very large numbers. Constructor does the same as Reset(); 131 /// use it when starting a new series of input samples. 132 /// Results are available at any time by calling N(), Minimum(), Maximum(), 133 /// Average(), Variance() and StdDev(). Also the scale is available in Scale(). 134 /// NB. Variance is normalized with 1/(N-1) and StdDev is sqrt(Variance). 135 /// NB. This class is not intended to be used with non-floating types, 136 /// for which it may yield incorrect results. 137 template <class T> class Stats 138 { 139 public: 140 friend class TwoSampleStats<T>; 141 142 /// constructor Stats()143 Stats() { Reset(); } 144 145 /// reset, i.e. ignore earlier data and restart sampling Reset(void)146 inline void Reset(void) 147 { 148 n = 0; 149 setScale = false; 150 scale = T(1); 151 sum = sum2 = min = max = T(); 152 } 153 154 // add and subtract --------------------------------------------------- 155 156 /// add a single sample to the computation of statistics 157 /// NB this is the fundamental Add routine; all other Add's call this Add(const T & x)158 void Add(const T& x) // Stats 159 { 160 if(n == 0) { 161 sum = sum2 = T(); 162 min = max = x; 163 scale = T(1); 164 setScale = false; 165 } 166 if(!setScale && x!=T()) { scale=::fabs(x); setScale = true; } 167 sum += x/scale; 168 sum2 += (x/scale)*(x/scale); 169 if(x < min) min=x; 170 if(x > max) max=x; 171 n++; 172 } 173 174 /// remove a sample from the computation of statistics. 175 /// NB this is the fundamental Subtract routine; all others call this 176 /// NB. Assumes that this sample was previously added. 177 /// NB. Minimum() and Maximum() may no longer be valid. Subtract(const T & x)178 void Subtract(const T& x) // Stats 179 { 180 if(n < 1) return; // TD throw 181 if(n == 1) { n = 0; return; } 182 T sx(x/scale); 183 sum -= sx; 184 sum2 -= sx*sx; 185 n--; 186 } 187 188 /// Add gpstk::Vector<T> of data to the statistics Add(const Vector<T> & X)189 void Add(const Vector<T>& X) // Stats 190 { 191 for(size_t i=0; i < X.size(); i++) Add(X(i)); 192 } 193 194 /// add a std::vector<T> of samples to the computation of statistics Add(std::vector<T> & X)195 inline void Add(std::vector<T>& X) // Stats 196 { 197 for(size_t i=0; i<X.size(); i++) Add(X[i]); 198 } 199 200 /// Subtract gpstk::Vector<T> of data to the statistics 201 /// NB. Assumes that these samples were previously added. 202 /// NB. Minimum() and Maximum() may no longer be valid. Subtract(const Vector<T> & X)203 void Subtract(const Vector<T>& X) // Stats 204 { 205 for(size_t i=0; i < X.size(); i++) Subtract(X(i)); 206 } 207 208 /// remove a std::vector<T> of samples to the computation of statistics 209 /// NB. Assumes that these samples were previously added. 210 /// NB. Minimum() and Maximum() may no longer be valid. Subtract(std::vector<T> & X)211 inline void Subtract(std::vector<T>& X) // Stats 212 { 213 for(size_t i=0; i<X.size(); i++) Subtract(X[i]); 214 } 215 216 // combine two Stats objects ------------------------------------- 217 218 /// combine two Stats (assumed taken from the same or equivalent ensembles) operator +=(const Stats<T> & S)219 Stats<T>& operator+=(const Stats<T>& S) 220 { 221 if(S.n == 0) 222 return *this; 223 if(!setScale) { setScale=true; scale = S.scale; } 224 // TD what if both have !setScale? 225 if((n == 0) || (S.min < min)) min=S.min; 226 if((n == 0) || (S.max > max)) max=S.max; 227 sum += S.scale*S.sum/scale; 228 sum2 += (S.scale/scale)*(S.scale/scale)*S.sum2; 229 n += S.n; 230 return *this; 231 } 232 233 /// remove one Stats from another, assumed to be taken from the same or 234 /// equivalent ensembles. 235 /// NB. Assumes that these samples were previously added. 236 /// NB. Minimum() and Maximum() may no longer be valid. operator -=(const Stats<T> & S)237 Stats<T>& operator-=(const Stats<T>& S) 238 { 239 if(n <= S.n) { Reset(); return *this; } 240 sum -= S.scale*S.sum/scale; 241 sum2 -= (S.scale/scale)*(S.scale/scale)*S.sum2; 242 n -= S.n; 243 return *this; 244 } 245 246 // dump and reload ----------------------------------------------- 247 248 /// Dump Stats private members directly; 249 /// useful in saving an object (e.g. to a file); reload with Load(). 250 /// @param vuint output vector<unsigned int> of length 2, input of Load() 251 /// @param vT output vector<T> of length 5, input of Load() Dump(std::vector<unsigned int> & vuint,std::vector<T> & vT)252 void Dump(std::vector<unsigned int>& vuint, std::vector<T>& vT) 253 { 254 vuint.clear(); 255 vuint.push_back(n); vuint.push_back(setScale ? 1:0); 256 257 vT.clear(); 258 vT.push_back(setScale ? scale : T(0)); 259 vT.push_back(min); vT.push_back(max); 260 vT.push_back(sum); vT.push_back(sum2); 261 } 262 263 /// Define Stats private members directly; useful in continuing 264 /// with an object that was earlier saved (e.g. to a file) using Dump(). 265 /// @param vuint input vector<unsigned int> of length 2, output of Dump() 266 /// @param vT input vector<T> of length 5, output of Dump() 267 /// NB no checking at all - caller has burden of validity 268 /// NB zero-fill rather than throwing Load(const std::vector<unsigned int> & vuint,const std::vector<T> & vT)269 void Load(const std::vector<unsigned int>& vuint, const std::vector<T>& vT) 270 { 271 if(vuint.size() < 2 || vT.size() < 4) { 272 n = 0; 273 setScale = false; 274 scale = T(0); 275 min = T(0); max = T(0); 276 sum = T(0); sum2 = T(0); 277 } 278 else { 279 n = vuint[0]; 280 setScale = (vuint[1] != 0); 281 scale = vT[0]; 282 min = vT[1]; max = vT[2]; 283 sum = vT[3]; sum2 = vT[4]; 284 } 285 } 286 287 // output --------------------------------------------------- 288 289 /// Write Stats to a single-line string asString(std::string msg=std::string (),int w=7,int p=4) const290 std::string asString(std::string msg=std::string(), int w=7, int p=4) const 291 { 292 std::ostringstream oss; 293 //static const int p=4, w=7; 294 oss << "stats(con):" << (msg.empty() ? "" : " "+msg) 295 << " N " << std::setw(w) << N() << std::fixed << std::setprecision(p) 296 << " Ave " << std::setw(w) << Average() 297 << " Std " << std::setw(w) << StdDev() 298 << " Var " << std::setw(w) << Variance() 299 << " Min " << std::setw(w) << Minimum() 300 << " Max " << std::setw(w) << Maximum() 301 << " P2P " << std::setw(w) << Maximum()-Minimum(); 302 return oss.str(); 303 } 304 305 /// Write Stats N,ave,sig to a short single-line string asShortString(std::string msg=std::string (),int w=0,int p=3) const306 std::string asShortString(std::string msg=std::string(), int w=0, int p=3) const 307 { 308 std::ostringstream oss; 309 oss << msg << std::fixed << std::setprecision(p) 310 << " N " << std::setw(w) << N() 311 << " Ave " << std::setw(w) << Average() 312 << " Std " << std::setw(w) << StdDev(); 313 return oss.str(); 314 } 315 316 // the rest are just accessors -------------------------------------- 317 /// return the sample size N(void) const318 inline unsigned int N(void) const { return n; } 319 320 /// return minimum value Minimum(void) const321 inline T Minimum(void) const 322 { if(n) return min; else return T(); } 323 324 /// return maximum value Maximum(void) const325 inline T Maximum(void) const 326 { if(n) return max; else return T(); } 327 328 /// return the average Average(void) const329 inline T Average(void) const // Stats 330 { 331 if(n>0) 332 return (scale*sum/T(n)); 333 else 334 return T(); 335 } 336 337 /// return computed variance Variance(void) const338 inline T Variance(void) const // Stats 339 { 340 if(n>1) 341 return scale*scale*(sum2-sum*sum/T(n))/T(n-1); 342 else 343 return T(); 344 } 345 346 /// return computed standard deviation StdDev(void) const347 inline T StdDev(void) const 348 { if(n <= 1) return T(); return SQRT(Variance()); } 349 350 /// return the scale Scale(void) const351 inline T Scale(void) const 352 { if(n) return scale; else return T(); } 353 354 protected: 355 unsigned int n; ///< number of samples added to the statistics 356 bool setScale; ///< scale has been set to non-zero 357 T scale; ///< scale 358 T min; ///< Minimum value 359 T max; ///< Maximum value 360 T sum; ///< sum of x 361 T sum2; ///< sum of x squared 362 363 }; // end class Stats 364 365 /// Output operator for Stats class operator <<(std::ostream & s,const Stats<T> & ST)366 template <class T> std::ostream& operator<<(std::ostream& s, const Stats<T>& ST) 367 { 368 std::ofstream savefmt; 369 savefmt.copyfmt(s); 370 s << " N = " << ST.N() << " (1-sample statistics)\n"; 371 s << " Minimum = "; s.copyfmt(savefmt); s << ST.Minimum(); 372 s << " Maximum = "; s.copyfmt(savefmt); s << ST.Maximum() << "\n"; 373 s << " Average = "; s.copyfmt(savefmt); s << ST.Average(); 374 s << " Std Dev = "; s.copyfmt(savefmt); s << ST.StdDev(); 375 s << " Variance = "; s.copyfmt(savefmt); s << ST.Variance(); // temp 376 return s; 377 } 378 379 //--------------------------------------------------------------------------- 380 //--------------------------------------------------------------------------- 381 /// Sequential conventional statistics for one sample; gives results identical 382 /// to class Stats except there is no scaling. This class maintains a current 383 /// average and variance with each Add(); thus it is more efficient when results 384 /// at each step are accessed - use this class when stats are to be accessed often, 385 /// e.g. after each Add(). 386 /// Class Stats holds sum(x) and sum(x squared) and computes ave, sig etc on call. 387 /// NB. class WtdStats (weighted stats) derives from this class. 388 template <class T> class SeqStats 389 { 390 public: 391 /// constructor SeqStats()392 SeqStats() : n(0) { } 393 394 /// reset, i.e. ignore earlier data and restart sampling Reset(void)395 inline void Reset(void) { n=0; } 396 397 /// constructor given a gpstk::Vector<T> of data SeqStats(Vector<T> & X)398 SeqStats(Vector<T>& X) { n = 0; Add(X); } 399 400 // add and subtract --------------------------------------------------- 401 402 /// add a single sample to the computation of statistics) 403 /// NB this is the fundamental Add routine; all other Add's call this Add(const T & x)404 void Add(const T& x) // SeqStats 405 { 406 if(n == 0) { 407 min = max = ave = x; 408 var = T(); 409 } 410 else { 411 if(x < min) min=x; 412 if(x > max) max=x; 413 } 414 415 ave += (x-ave)/T(n + 1); 416 if(n > 0) var = T(n)*var/T(n + 1) + (x-ave)*(x-ave)/T(n); 417 418 n++; 419 } 420 421 /// remove a sample from the computation of statistics 422 /// NB this is the fundamental Subtract routine; all others call this 423 /// NB. Assumes that this sample was previously added. 424 /// NB. Minimum() and Maximum() may no longer be valid. Subtract(const T x)425 void Subtract(const T x) // SeqStats 426 { 427 if(n == 0) return; 428 if(n > 1) 429 var = (var - (x-ave)*(x-ave)/T(n-1))*T(n)/(T(n)-T(1)); 430 else 431 var = T(); 432 ave = T(n)*(ave - x/T(n))/(T(n)-T(1)); 433 n--; 434 } 435 436 /// add a gpstk::Vector<T> of samples to the computation of statistics Add(Vector<T> & X)437 inline void Add(Vector<T>& X) // SeqStats 438 { 439 for(size_t i=0; i<X.size(); i++) Add(X(i)); 440 } 441 442 /// add a std::vector<T> of samples to the computation of statistics Add(std::vector<T> & X)443 inline void Add(std::vector<T>& X) // SeqStats 444 { 445 for(size_t i=0; i<X.size(); i++) Add(X[i]); 446 } 447 448 /// remove a gpstk::Vector<T> of samples to the computation of statistics 449 /// NB. Assumes that these samples were previously added. 450 /// NB. Minimum() and Maximum() may no longer be valid. Subtract(Vector<T> & X)451 inline void Subtract(Vector<T>& X) // SeqStats 452 { 453 for(size_t i=0; i<X.size(); i++) Subtract(X(i)); 454 } 455 456 /// remove a std::vector<T> of samples to the computation of statistics 457 /// NB. Assumes that these samples were previously added. 458 /// NB. Minimum() and Maximum() may no longer be valid. Subtract(std::vector<T> & X)459 inline void Subtract(std::vector<T>& X) // SeqStats 460 { 461 for(size_t i=0; i<X.size(); i++) Subtract(X[i]); 462 } 463 464 // combine two Stats objects ------------------------------------- 465 466 /// combine two SeqStats (assumed taken from the same or equivalent ensembles); operator +=(const SeqStats<T> & S)467 SeqStats<T>& operator+=(const SeqStats<T>& S) 468 { 469 if(S.n == 0) return *this; 470 if(n==0) { *this = S; return *this; } 471 472 if(S.min < min) min=S.min; 473 if(S.max > max) max=S.max; 474 475 T newave = T(n)*ave + T(S.n)*S.ave; 476 T newvar = T(n)*var + T(S.n)*S.var + T(n)*ave*ave + T(S.n)*S.ave*S.ave; 477 ave = newave/T(n+S.n); 478 var = newvar/T(n+S.n) - ave*ave; 479 n += S.n; 480 481 return *this; 482 } // end SeqStats operator+= 483 484 /// remove one SeqStats from another, assumed to be taken from the same or 485 /// equivalent ensembles. 486 /// NB. Assumes that these samples were previously added. 487 /// NB. Minimum() and Maximum() may no longer be valid. operator -=(const SeqStats<T> & S)488 SeqStats<T>& operator-=(const SeqStats<T>& S) 489 { 490 if(n <= S.n) { n=0; return *this; } 491 492 T newave = T(n)*ave - T(S.n)*S.ave; 493 T newvar = T(n)*var - T(S.n)*S.var + T(n)*ave*ave - T(S.n)*S.ave*S.ave; 494 ave = newave/T(n-S.n); 495 var = newvar/T(n-S.n) - ave*ave; 496 n -= S.n; 497 498 return *this; 499 } // end SeqStats operator-= 500 501 // dump and reload ----------------------------------------------- 502 503 /// Dump SeqStats private members directly; 504 /// useful in saving an object (e.g. to a file); reload with Load(). 505 /// @param vuint output vector<unsigned int> of length 1, input of Load() 506 /// @param vT output vector<T> of length 4, input of Load() Dump(std::vector<unsigned int> & vuint,std::vector<T> & vT)507 void Dump(std::vector<unsigned int>& vuint, std::vector<T>& vT) 508 { 509 vuint.clear(); 510 vuint.push_back(n); 511 512 vT.clear(); 513 vT.push_back(min); vT.push_back(max); 514 vT.push_back(ave); vT.push_back(var); 515 } 516 517 /// Define SeqStats private members directly; useful in continuing 518 /// with an object that was earlier saved (e.g. to a file) using Dump(). 519 /// @param vuint input vector<unsigned int> of length 1, output of Dump() 520 /// @param vT input vector<T> of length 4, output of Dump() 521 /// NB no checking at all - caller has burden of validity 522 /// NB zero-fill rather than throwing Load(const std::vector<unsigned int> & vuint,const std::vector<T> & vT)523 void Load(const std::vector<unsigned int>& vuint, const std::vector<T>& vT) 524 { 525 if(vuint.size() < 1 || vT.size() < 4) { 526 n = 0; 527 min = T(0); max = T(0); 528 ave = T(0); var = T(0); 529 } 530 else { 531 n = vuint[0]; 532 min = vT[0]; max = vT[1]; 533 ave = vT[2]; var = vT[3]; 534 } 535 } 536 537 // output --------------------------------------------------- 538 539 /// Write SeqStats to a single-line string asString(std::string msg=std::string (),int w=7,int p=4) const540 std::string asString(std::string msg=std::string(), int w=7, int p=4) const 541 { 542 std::ostringstream oss; 543 //static const int p=4, w=7; 544 oss << "stats(seq):" << (msg.empty() ? "" : " "+msg) 545 << " N " << std::setw(w) << N() << std::fixed << std::setprecision(p) 546 << " Ave " << std::setw(w) << Average() 547 << " Std " << std::setw(w) << StdDev() 548 << " Var " << std::setw(w) << Variance() 549 << " Min " << std::setw(w) << Minimum() 550 << " Max " << std::setw(w) << Maximum() 551 << " P2P " << std::setw(w) << Maximum()-Minimum(); 552 return oss.str(); 553 } 554 555 /// Write SeqStats N,ave,sig to a short single-line string asShortString(std::string msg=std::string (),int w=0,int p=3) const556 std::string asShortString(std::string msg=std::string(), int w=0, int p=3) const 557 { 558 std::ostringstream oss; 559 oss << msg << std::fixed << std::setprecision(p) 560 << " N " << std::setw(w) << N() 561 << " Ave " << std::setw(w) << Average() 562 << " Std " << std::setw(w) << StdDev(); 563 return oss.str(); 564 } 565 566 // accessors ------------------------------------------------------- 567 /// return the sample size N(void) const568 inline unsigned int N(void) const { return n; } 569 570 /// return minimum value Minimum(void) const571 inline T Minimum(void) const { if(n) return min; else return T(); } 572 573 /// return maximum value Maximum(void) const574 inline T Maximum(void) const { if(n) return max; else return T(); } 575 576 /// return computed average Average(void) const577 inline T Average(void) const { if(n == 0) return T(); return ave; } 578 579 /// return computed variance Variance(void) const580 inline T Variance(void) const // SeqStats 581 { 582 if(n <= 1) return T(); 583 return (T(n)*var/T(n-1)); 584 } 585 586 /// return computed standard deviation StdDev(void) const587 inline T StdDev(void) const // SeqStats 588 { 589 if(n <= 1) return T(); 590 return SQRT(Variance()); 591 } 592 593 protected: 594 unsigned int n; ///< number of samples added to the statistics 595 T min; ///< Minimum value 596 T max; ///< Maximum value 597 T ave; ///< Average value 598 T var; ///< Variance (square of the standard deviation) 599 600 }; // end class SeqStats 601 602 /// Output operator for SeqStats class operator <<(std::ostream & s,const SeqStats<T> & ST)603 template <class T> std::ostream& operator<<(std::ostream& s, const SeqStats<T>& ST) 604 { 605 std::ofstream savefmt; 606 savefmt.copyfmt(s); 607 s << " N = " << ST.N() << " (1-sample stats, seq.impl.)\n"; 608 s << " Minimum = "; s.copyfmt(savefmt); s << ST.Minimum(); 609 s << " Maximum = "; s.copyfmt(savefmt); s << ST.Maximum() << "\n"; 610 s << " Average = "; s.copyfmt(savefmt); s << ST.Average(); 611 s << " Std Dev = "; s.copyfmt(savefmt); s << ST.StdDev(); 612 s << " Variance = "; s.copyfmt(savefmt); s << ST.Variance(); // temp 613 return s; 614 } 615 616 //--------------------------------------------------------------------------- 617 //--------------------------------------------------------------------------- 618 /// Weighted conventional statistics for one sample. Derived from SeqStats<T> 619 /// Weights must not be zero; zero weight causes the sample to be ignored. 620 template <class T> class WtdStats : public SeqStats<T> 621 { 622 public: 623 /// constructor WtdStats()624 WtdStats() { } 625 626 /// constructor given a gpstk::Vector<T> of data, with weights WtdStats(Vector<T> & X,Vector<T> & W)627 WtdStats(Vector<T>& X, Vector<T>& W) 628 { 629 SeqStats<T>::n = 0; 630 Add(X,W); 631 } 632 633 // add and subtract ------------------------------------- 634 635 /// add a single sample to the computation of statistics 636 /// NB this is the fundamental Add routine; all other Add's call this 637 /// NB input of zero weight causes the sample x to be ignored. Add(const T & x,const T & wt_in)638 void Add(const T& x, const T& wt_in) // WtdStats 639 { 640 T wt(::fabs(wt_in)); 641 if(wt == T()) return; // Don't add with zero weight 642 643 if(SeqStats<T>::n == 0) { 644 SeqStats<T>::min = SeqStats<T>::max = SeqStats<T>::ave = x; 645 SeqStats<T>::var = T(); 646 WtNorm = T(); 647 } 648 else { 649 if(x < SeqStats<T>::min) SeqStats<T>::min=x; 650 if(x > SeqStats<T>::max) SeqStats<T>::max=x; 651 } 652 653 SeqStats<T>::ave += (x-SeqStats<T>::ave)*(wt/(WtNorm+wt)); 654 if(SeqStats<T>::n > 0) 655 SeqStats<T>::var = (WtNorm/(WtNorm+wt))*SeqStats<T>::var 656 + (x-SeqStats<T>::ave)*(x-SeqStats<T>::ave)*(wt/WtNorm); 657 WtNorm += wt; 658 659 SeqStats<T>::n++; 660 } 661 662 /// remove a sample from the computation of statistics 663 /// NB input of zero weight causes the sample x to be ignored. 664 /// NB this is the fundamental Subtract routine; all others call this 665 /// NB. Assumes that this sample was previously added. 666 /// NB. Minimum() and Maximum() may no longer be valid. Subtract(const T & x,const T & wt_in)667 void Subtract(const T& x, const T& wt_in) // WtdStats 668 { 669 if(SeqStats<T>::n == 0) return; 670 T wt(::fabs(wt_in)); 671 if(wt == T()) return; // Don't add with zero weight 672 673 T newave = WtNorm*SeqStats<T>::ave - wt*x; 674 T newvar = WtNorm*SeqStats<T>::var 675 + WtNorm * SeqStats<T>::ave * SeqStats<T>::ave - wt*x*x; 676 WtNorm -= wt; 677 SeqStats<T>::ave = newave/WtNorm; 678 SeqStats<T>::var = newvar/WtNorm - SeqStats<T>::ave * SeqStats<T>::ave; 679 SeqStats<T>::n--; 680 } 681 682 /// add a gpstk::Vector<T> of samples, with weights Add(Vector<T> & X,Vector<T> & W)683 inline void Add(Vector<T>& X, Vector<T>& W) // WtdStats 684 { 685 for(size_t i=0; i<(X.size()>W.size() ? W.size():X.size()); i++) 686 Add(X(i),W(i)); 687 } 688 689 /// add a std::vector<T> of samples, with weights Add(std::vector<T> & X,std::vector<T> & W)690 inline void Add(std::vector<T>& X, std::vector<T>& W) // WtdStats 691 { 692 for(size_t i=0; i<(X.size()>W.size() ? W.size():X.size()); i++) 693 Add(X(i),W(i)); 694 } 695 696 /// remove a gpstk::Vector<T> of samples, with weights 697 /// NB input of zero weight causes the sample x to be ignored. 698 /// NB. Assumes that this sample was previously added. 699 /// NB. Minimum() and Maximum() may no longer be valid. Subtract(Vector<T> & X,Vector<T> & W)700 inline void Subtract(Vector<T>& X, Vector<T>& W) // WtdStats 701 { 702 size_t i, nn(X.size() > W.size() ? W.size() : X.size()); 703 for(i=0; i<nn; i++) Subtract(X(i),W(i)); 704 } 705 706 /// remove a std::vector<T> of samples, with weights 707 /// NB input of zero weight causes the sample x to be ignored. 708 /// NB. Assumes that this sample was previously added. 709 /// NB. Minimum() and Maximum() may no longer be valid. Subtract(std::vector<T> & X,std::vector<T> & W)710 inline void Subtract(std::vector<T>& X, std::vector<T>& W) // WtdStats 711 { 712 size_t i, nn(X.size() > W.size() ? W.size() : X.size()); 713 for(i=0; i<nn; i++) Subtract(X(i),W(i)); 714 } 715 716 // combine two objects ------------------------------------------- 717 718 /// combine two WtdStats (assumed taken from the same or equivalent ensembles); operator +=(const WtdStats<T> & S)719 WtdStats<T>& operator+=(const WtdStats<T>& S) 720 { 721 if(S.n == 0) 722 return *this; 723 if(SeqStats<T>::n == 0) 724 { *this = S; return *this; } 725 726 //if(S.min < SeqStats<T>::min) SeqStats<T>::min = S.min; // gcc why!?!? 727 if(SeqStats<T>::min > S.min) SeqStats<T>::min = S.min; 728 if(S.max > SeqStats<T>::max) SeqStats<T>::max = S.max; 729 730 T newave = WtNorm*SeqStats<T>::ave + S.WtNorm*S.ave; 731 T newvar = WtNorm*SeqStats<T>::var + S.WtNorm*S.var 732 + WtNorm*SeqStats<T>::ave*SeqStats<T>::ave + S.WtNorm*S.ave*S.ave; 733 WtNorm += S.WtNorm; 734 SeqStats<T>::ave = newave/WtNorm; 735 SeqStats<T>::var = newvar/WtNorm - SeqStats<T>::ave*SeqStats<T>::ave; 736 SeqStats<T>::n += S.n; 737 738 return *this; 739 } 740 741 /// remove one WtdStats from another, assumed to be taken from the same or 742 /// equivalent ensembles. 743 /// NB. Assumes that this sample was previously added. 744 /// NB. Minimum() and Maximum() may no longer be valid. operator -=(const WtdStats<T> & S)745 WtdStats<T>& operator-=(const WtdStats<T>& S) 746 { 747 if(SeqStats<T>::n <= S.n) { SeqStats<T>::n=0; return *this; } 748 749 T newave = WtNorm*SeqStats<T>::ave - S.WtNorm*S.ave; 750 T newvar = WtNorm*SeqStats<T>::var-S.WtNorm*S.var 751 + WtNorm*SeqStats<T>::ave*SeqStats<T>::ave - S.WtNorm*S.ave*S.ave; 752 WtNorm -= S.WtNorm; 753 SeqStats<T>::ave = newave/WtNorm; 754 SeqStats<T>::var = newvar/WtNorm - SeqStats<T>::ave*SeqStats<T>::ave; 755 SeqStats<T>::n -= S.n; 756 757 return *this; 758 759 } // end WtdStats operator-= 760 761 // dump and reload ----------------------------------------------- 762 763 /// Dump WtdStats private members directly; 764 /// useful in saving an object (e.g. to a file); reload with Load(). 765 /// @param vuint output vector<unsigned int> of length 1, input of Load() 766 /// @param vT output vector<T> of length 5, input of Load() Dump(std::vector<unsigned int> & vuint,std::vector<T> & vT)767 void Dump(std::vector<unsigned int>& vuint, std::vector<T>& vT) // WtdStats 768 { 769 SeqStats<T>::Dump(vuint,vT); 770 vT.push_back(WtNorm); 771 } 772 773 /// Define WtdStats private members directly; useful in continuing 774 /// with an object that was earlier saved (e.g. to a file) using Dump(). 775 /// @param vuint input vector<unsigned int> of length 1, output of Dump() 776 /// @param vT input vector<T> of length 5, output of Dump() 777 /// NB no checking at all - caller has burden of validity 778 /// NB zero-fill rather than throwing Load(std::vector<unsigned int> & vuint,std::vector<T> & vT)779 void Load(std::vector<unsigned int>& vuint, std::vector<T>& vT) // WtdStats 780 { 781 if(vuint.size() < 1 || vT.size() < 5) { 782 vuint.clear(); 783 vuint.push_back(0); 784 vT.clear(); 785 for(size_t i=0; i<5; i++) vT.push_back(T(0)); 786 } 787 SeqStats<T>::Load(vuint,vT); 788 WtNorm = vT[4]; 789 } 790 791 // output ---------------------------------------------------------- 792 793 /// Write WtdStats to a single-line string asString(std::string msg=std::string (),int w=7,int p=4) const794 std::string asString(std::string msg=std::string(), int w=7, int p=4) const 795 { 796 std::ostringstream oss; 797 oss << "stats(wtd):" << (msg.empty() ? "" : " "+msg) 798 << " N " << std::setw(w) << SeqStats<T>::N() 799 << std::fixed << std::setprecision(p) 800 << " Ave " << std::setw(w) << SeqStats<T>::Average() 801 << " Std " << std::setw(w) << SeqStats<T>::StdDev() 802 << " Var " << std::setw(w) << SeqStats<T>::Variance() 803 << " Min " << std::setw(w) << SeqStats<T>::Minimum() 804 << " Max " << std::setw(w) << SeqStats<T>::Maximum() 805 << " P2P " << std::setw(w) 806 << SeqStats<T>::Maximum()-SeqStats<T>::Minimum() 807 << " Wts " << std::setw(w) << WtsSum(); 808 return oss.str(); 809 } 810 811 /// Write WtdStats N,ave,sig to a short single-line string asShortString(std::string msg=std::string (),int w=0,int p=3) const812 std::string asShortString(std::string msg=std::string(), int w=0, int p=3) const 813 { 814 std::ostringstream oss; 815 oss << msg << std::fixed << std::setprecision(p) 816 << " N " << std::setw(w) << SeqStats<T>::N() 817 << " Ave " << std::setw(w) << SeqStats<T>::Average() 818 << " Std " << std::setw(w) << SeqStats<T>::StdDev(); 819 return oss.str(); 820 } 821 822 /// return normalization = sum of weights WtsSum(void) const823 inline T WtsSum(void) const { return WtNorm; } // WtdStats 824 825 protected: 826 T WtNorm; ///< Normalization constant = sum weights 827 828 }; // end class WtdStats 829 830 /// Output operator for WtdStats class operator <<(std::ostream & s,const WtdStats<T> & ST)831 template <class T> std::ostream& operator<<(std::ostream& s, const WtdStats<T>& ST) 832 { 833 std::ofstream savefmt; 834 savefmt.copyfmt(s); 835 s << " N = " << ST.N() << " (weighted 1-sample stats)\n"; 836 s << " Minimum = "; s.copyfmt(savefmt); s << ST.Minimum(); 837 s << " Maximum = "; s.copyfmt(savefmt); s << ST.Maximum() << "\n"; 838 s << " Average = "; s.copyfmt(savefmt); s << ST.Average(); 839 s << " Std Dev = "; s.copyfmt(savefmt); s << ST.StdDev(); 840 s << " Variance = "; s.copyfmt(savefmt); s << ST.Variance() << "\n"; 841 s << " SumWts = "; s.copyfmt(savefmt); s << ST.WtsSum(); 842 return s; 843 } 844 845 //--------------------------------------------------------------------------- 846 //--------------------------------------------------------------------------- 847 /// Conventional statistics for two samples. Also uses a pair of Stats<T> for 848 /// the each of the two samples. 849 template <class T> class TwoSampleStats 850 { 851 public: 852 /// constructor TwoSampleStats()853 TwoSampleStats() : n(0), sumxy(T(0)) {} 854 855 /// reset, i.e. ignore earlier data and restart sampling Reset(void)856 inline void Reset(void) { n=0; SX.Reset(); SY.Reset(); sumxy = T(0); } 857 858 /// constructor given two gpstk::Vector<T>s of data - must be parallel TwoSampleStats(Vector<T> & X,Vector<T> & Y)859 TwoSampleStats(Vector<T>& X, Vector<T>& Y) 860 { 861 Reset(); 862 Add(X,Y); 863 } 864 865 /// Add data to the statistics 866 /// NB this is the fundamental Add routine; all other Add's call this Add(const T & x,const T & y)867 void Add(const T& x, const T& y) // TwoSampleStats 868 { 869 SX.Add(x); 870 SY.Add(y); 871 sumxy += (x/SX.scale)*(y/SY.scale); 872 n++; 873 } 874 875 /// Subtract data from the statistics 876 /// NB this is the fundamental Subtract routine; all others call this 877 /// NB. Assumes that these samples were previously added. 878 /// NB. Minimum() and Maximum() may no longer be valid. Subtract(const T & x,const T & y)879 void Subtract(const T& x, const T& y) // TwoSampleStats 880 { 881 if(n < 1) return; // TD throw 882 if(n == 1) { Reset(); return; } 883 SX.Subtract(x); 884 SY.Subtract(y); 885 sumxy -= (x/SX.scale)*(y/SY.scale); 886 n--; 887 } 888 889 /// Add two gpstk::Vector<T>s of data to the statistics Add(const Vector<T> & X,const Vector<T> & Y)890 void Add(const Vector<T>& X, const Vector<T>& Y) // TwoSampleStats 891 { 892 for(size_t i=0; i<(X.size()<Y.size() ? X.size():Y.size()); i++) 893 Add(X(i),Y(i)); 894 } 895 896 /// Add two std::vectors of data to the statistics Add(const std::vector<T> & X,const std::vector<T> & Y)897 void Add(const std::vector<T>& X, const std::vector<T>& Y) // TwoSampleStats 898 { 899 for(size_t i=0; i<(X.size()<Y.size() ? X.size():Y.size()); i++) 900 Add(X[i],Y[i]); 901 } 902 903 /// Subtract two gpstk::Vector<T>s of data from the statistics Subtract(const Vector<T> & X,const Vector<T> & Y)904 void Subtract(const Vector<T>& X, const Vector<T>& Y) // TwoSampleStats 905 { 906 for(size_t i=0; i<(X.size()<Y.size() ? X.size():Y.size()); i++) 907 Subtract(X(i),Y(i)); 908 } 909 910 /// Subtract two std::vectors of data from the statistics Subtract(const std::vector<T> & X,const std::vector<T> & Y)911 void Subtract(const std::vector<T>& X, const std::vector<T>& Y) 912 { 913 for(size_t i=0; i<(X.size()<Y.size() ? X.size():Y.size()); i++) 914 Subtract(X[i],Y[i]); 915 } 916 917 // combine two objects --------------------------------------------- 918 919 /// combine two TwoSampleStats (assumed to be taken from the same or 920 /// equivalent ensembles) operator +=(TwoSampleStats<T> & TSS)921 TwoSampleStats<T>& operator+=(TwoSampleStats<T>& TSS) 922 { 923 if(n + TSS.n == 0) return *this; 924 SX += TSS.SX; 925 SY += TSS.SY; 926 sumxy += (TSS.SX.scale/SX.scale)*(TSS.SY.scale/SY.scale)*TSS.sumxy; 927 n += TSS.n; 928 return *this; 929 } // end TwoSampleStats operator+= 930 931 /// remove one WtdStats from another, assumed to be taken from the same or 932 /// equivalent ensembles. 933 /// NB. Assumes that these samples were previously added. 934 /// NB. Minimum() and Maximum() may no longer be valid. operator -=(TwoSampleStats<T> & TSS)935 TwoSampleStats<T>& operator-=(TwoSampleStats<T>& TSS) 936 { 937 if(n <= TSS.n) { Reset(); return *this; } 938 SX -= TSS.SX; 939 SY -= TSS.SY; 940 sumxy -= (TSS.SX.scale/SX.scale)*(TSS.SY.scale/SY.scale)*TSS.sumxy; 941 n -= TSS.n; 942 return *this; 943 } // end TwoSampleStats operator-= 944 945 // dump and reload -------------------------------------------- 946 947 /// Dump TwoSampleStats private members directly; 948 /// useful in saving an object (e.g. to a file); reload with Load(). 949 /// @param vuint output vector<unsigned int> of length 5, input of Load() 950 /// @param vT output vector<T> of length 11, input of Load() Dump(std::vector<unsigned int> & vuint,std::vector<T> & vT)951 void Dump(std::vector<unsigned int>& vuint, std::vector<T>& vT) // TSS 952 { 953 size_t i; 954 std::vector<unsigned int> vi; 955 std::vector<T> vt; 956 957 vuint.clear(); vT.clear(); 958 959 SX.Dump(vi,vt); 960 for(i=0; i<2; i++) vuint.push_back(vi[i]); 961 for(i=0; i<5; i++) vT.push_back(vt[i]); 962 963 SY.Dump(vi,vt); // this will clear vi,vt first 964 for(i=0; i<2; i++) vuint.push_back(vi[i]); 965 for(i=0; i<5; i++) vT.push_back(vt[i]); 966 967 vuint.push_back(n); 968 vT.push_back(sumxy); 969 } 970 971 /// Define TwoSampleStats private members directly; useful in continuing 972 /// with an object that was earlier saved (e.g. to a file) using Dump(). 973 /// @param vuint input vector<unsigned int> of length 5, output of Dump() 974 /// @param vT input vector<T> of length 11, output of Dump() 975 /// NB no checking at all - caller has burden of validity 976 /// NB zero-fill rather than throwing Load(std::vector<unsigned int> & vuint,std::vector<T> & vT)977 void Load(std::vector<unsigned int>& vuint, std::vector<T>& vT) // TSS 978 { 979 size_t i; 980 std::vector<unsigned int> vi2; 981 std::vector<double> vt2; 982 if(vuint.size() < 5 || vT.size() < 11) { 983 vuint.clear(); 984 for(i=0; i<5; i++) vT.push_back(T(0)); 985 vT.clear(); 986 for(i=0; i<11; i++) vT.push_back(T(0)); 987 } 988 SX.Load(vuint,vT); 989 990 for(i=0; i<2; i++) vi2.push_back(vuint[i+2]); 991 for(i=0; i<5; i++) vt2.push_back(vT[i+5]); 992 SY.Load(vi2,vt2); 993 994 n = vuint[4]; 995 sumxy = vT[10]; 996 } 997 998 // output ----------------------------------------------------------- 999 1000 /// Write TwoSampleStats to a three-line string asString(std::string msg=std::string (),int w=7,int p=4) const1001 std::string asString(std::string msg=std::string(), int w=7, int p=4) const 1002 { 1003 std::ostringstream oss; 1004 //static const int p=4, w=7; 1005 oss << SX.asString(msg,w,p) << " (X)" << std::endl 1006 << SY.asString(msg,w,p) << " (Y)" << std::endl 1007 << "stats(tss):" << (msg.empty() ? "" : " "+msg) 1008 << " N " << std::setw(w) << N() << std::fixed << std::setprecision(p) 1009 << " Int " << std::setw(w) << Intercept() 1010 << " Slp " << std::setw(w) << Slope() 1011 << " +- " << std::setw(w) << SigmaSlope() 1012 << " CSig " << std::setw(w) << SigmaYX() 1013 << " Corr " << std::setw(w) << Correlation(); 1014 return oss.str(); 1015 } 1016 1017 /// Write TwoSampleStats as a short 1-line string asShortString(std::string msg=std::string (),int w=0,int p=3) const1018 std::string asShortString(std::string msg=std::string(), int w=0, int p=3) const 1019 { 1020 std::ostringstream oss; 1021 oss << SX.asShortString(msg,w,p) << " (X);" 1022 << SY.asShortString(msg,w,p) << " (Y);" 1023 << msg << std::fixed << std::setprecision(p) 1024 << std::fixed << std::setprecision(p) 1025 << " Int " << std::setw(w) << Intercept() 1026 << " Slp " << std::setw(w) << Slope() 1027 << " +- " << std::setw(w) << SigmaSlope() 1028 << " CSig " << std::setw(w) << SigmaYX() 1029 << " Corr " << std::setw(w) << Correlation(); 1030 return oss.str(); 1031 } 1032 1033 // accessors ------------------------------------------------------- 1034 1035 /// access the sample size 1036 /// NB. n should match SX.N() and SY.N() at all times N(void) const1037 inline unsigned int N(void) const { return n; } 1038 /// return minimum X value MinimumX(void) const1039 inline T MinimumX(void) const { return SX.Minimum(); } 1040 /// return maximum X value MaximumX(void) const1041 inline T MaximumX(void) const { return SX.Maximum(); } 1042 /// return minimum Y value MinimumY(void) const1043 inline T MinimumY(void) const { return SY.Minimum(); } 1044 /// return maximum Y value MaximumY(void) const1045 inline T MaximumY(void) const { return SY.Maximum(); } 1046 /// return computed X average AverageX(void) const1047 inline T AverageX(void) const { return SX.Average(); } 1048 /// return computed Y average AverageY(void) const1049 inline T AverageY(void) const { return SY.Average(); } 1050 /// return computed X variance VarianceX(void) const1051 inline T VarianceX(void) const { return SX.Variance(); } 1052 /// return computed Y variance VarianceY(void) const1053 inline T VarianceY(void) const { return SY.Variance(); } 1054 /// return computed X standard deviation StdDevX(void) const1055 inline T StdDevX(void) const { return SX.StdDev(); } 1056 /// return computed Y standard deviation StdDevY(void) const1057 inline T StdDevY(void) const { return SY.StdDev(); } 1058 1059 /// return slope of best-fit line Y=slope*X + intercept Slope(void) const1060 inline T Slope(void) const 1061 { 1062 if(n > 0) { 1063 T den(SX.sum2-SX.sum*SX.sum/T(n)); 1064 if(den == T()) return T(); // throw? 1065 return ( (SY.scale/SX.scale) * (sumxy-SX.sum*SY.sum/T(n)) / den ); 1066 } 1067 else 1068 return T(); 1069 } 1070 1071 /// return intercept of best-fit line Y=slope*X + intercept Intercept(void) const1072 inline T Intercept(void) const 1073 { 1074 if(n > 0) 1075 return (AverageY()-Slope()*AverageX()); 1076 else 1077 return T(); 1078 } 1079 1080 /// return uncertainty in slope SigmaSlope(void) const1081 inline T SigmaSlope(void) const 1082 { 1083 if(n > 2) { 1084 T den(StdDevX()*SQRT(T(n-1))); 1085 if(den == T()) return T(); // throw? 1086 return (SigmaYX()/den); 1087 } 1088 else 1089 return T(); 1090 } 1091 1092 /// return correlation Correlation(void) const1093 inline T Correlation(void) const 1094 { 1095 if(n>1) { 1096 T den(StdDevX()*StdDevY()*T(n-1)); 1097 if(den == T()) return T(); // throw? 1098 return ( SX.scale*SY.scale*(sumxy-SX.sum*SY.sum/T(n)) / den); 1099 } 1100 else 1101 return T(); 1102 } 1103 1104 /// return conditional uncertainty = uncertainty y given x SigmaYX(void) const1105 inline T SigmaYX(void) const 1106 { 1107 return SQRT(VarianceYX()); 1108 } 1109 1110 /// return conditional variance = (uncertainty y given x)^2 VarianceYX(void) const1111 inline T VarianceYX(void) const 1112 { 1113 if(n > 2) { 1114 return (VarianceY() * (T(n-1)/T(n-2)) 1115 * (T(1)-Correlation()*Correlation())); 1116 } 1117 else return T(); 1118 } 1119 1120 /// return the predicted Y at the given X, using Slope and Intercept Evaluate(T x) const1121 inline T Evaluate(T x) const 1122 { 1123 return (Slope()*x + Intercept()); 1124 } 1125 1126 protected: 1127 Stats<T> SX; ///< conventional 1-sample stats for first sample x 1128 Stats<T> SY; ///< conventional 1-sample stats for second sample y 1129 unsigned int n; ///< number of samples added to the statistics 1130 T sumxy; ///< sum of x*y 1131 1132 }; // end class TwoSampleStats 1133 1134 /// Output operator for TwoSampleStats class 1135 template <class T> operator <<(std::ostream & s,const TwoSampleStats<T> & TSS)1136 std::ostream& operator<<(std::ostream& s, const TwoSampleStats<T>& TSS) 1137 { 1138 std::ofstream savefmt; 1139 savefmt.copyfmt(s); 1140 s << " N = " << TSS.N() << " (two-sample-statistics)\n"; 1141 s << " Minimum: X = "; s.copyfmt(savefmt); s << TSS.MinimumX(); 1142 s << " Y = "; s.copyfmt(savefmt); s << TSS.MinimumY() << "\n"; 1143 s << " Maximum: X = "; s.copyfmt(savefmt); s << TSS.MaximumX(); 1144 s << " Y = "; s.copyfmt(savefmt); s << TSS.MaximumY() << "\n"; 1145 s << " Average: X = "; s.copyfmt(savefmt); s << TSS.AverageX(); 1146 s << " Y = "; s.copyfmt(savefmt); s << TSS.AverageY() << "\n"; 1147 s << " Std Dev: X = "; s.copyfmt(savefmt); s << TSS.StdDevX(); 1148 s << " Y = "; s.copyfmt(savefmt); s << TSS.StdDevY() << "\n"; 1149 s << " Variance: X = "; s.copyfmt(savefmt); s << TSS.VarianceX(); 1150 s << " Y = "; s.copyfmt(savefmt); s << TSS.VarianceY() << "\n"; 1151 1152 bool bad(TSS.VarianceYX() == T()); 1153 std::string badmsg("undef"); 1154 s << " Intercept = "; s.copyfmt(savefmt); 1155 if(bad) s << badmsg; else s << TSS.Intercept(); 1156 s << " Slope = "; s.copyfmt(savefmt); 1157 if(bad) s << badmsg; else s << TSS.Slope(); 1158 s << " with uncertainty = "; s.copyfmt(savefmt); 1159 if(bad) s << badmsg; else s << TSS.SigmaSlope(); 1160 s << "\n Conditional uncertainty (sigma Y given X) = "; s.copyfmt(savefmt); 1161 if(bad) s << badmsg; else s << TSS.SigmaYX(); 1162 s << " Correlation = "; s.copyfmt(savefmt); 1163 if(bad) s << badmsg; else s << TSS.Correlation(); 1164 1165 return s; 1166 } 1167 1168 //@} 1169 1170 } // namespace 1171 1172 #endif // INCLUDE_GPSTK_STATS_INCLUDE 1173