annotate maths/Polyfit.h @ 209:ccd2019190bf msvc

Some MSVC fixes, including (temporarily, probably) renaming the FFT source file to avoid getting it mixed up with the Vamp SDK one in our object dir
author Chris Cannam
date Thu, 01 Feb 2018 16:34:08 +0000
parents 214b31ec7e1a
children
rev   line source
cannam@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@0 2 //---------------------------------------------------------------------------
cannam@0 3
cannam@0 4 #ifndef PolyfitHPP
cannam@0 5 #define PolyfitHPP
cannam@0 6 //---------------------------------------------------------------------------
cannam@0 7 // Least-squares curve fitting class for arbitrary data types
cannam@0 8 /*
cannam@0 9
cannam@0 10 { ******************************************
cannam@0 11 **** Scientific Subroutine Library ****
cannam@0 12 **** for C++ Builder ****
cannam@0 13 ******************************************
cannam@0 14
cannam@0 15 The following programs were written by Allen Miller and appear in the
cannam@0 16 book entitled "Pascal Programs For Scientists And Engineers" which is
cannam@0 17 published by Sybex, 1981.
cannam@0 18 They were originally typed and submitted to MTPUG in Oct. 1982
cannam@0 19 Juergen Loewner
cannam@0 20 Hoher Heckenweg 3
cannam@0 21 D-4400 Muenster
cannam@0 22 They have had minor corrections and adaptations for Turbo Pascal by
cannam@0 23 Jeff Weiss
cannam@0 24 1572 Peacock Ave.
cannam@0 25 Sunnyvale, CA 94087.
cannam@0 26
cannam@0 27
cannam@0 28 2000 Oct 28 Updated for Delphi 4, open array parameters.
cannam@0 29 This allows the routine to be generalised so that it is no longer
cannam@0 30 hard-coded to make a specific order of best fit or work with a
cannam@0 31 specific number of points.
cannam@0 32 2001 Jan 07 Update Web site address
cannam@0 33
cannam@0 34 Copyright © David J Taylor, Edinburgh and others listed above
cannam@0 35 Web site: www.satsignal.net
cannam@0 36 E-mail: davidtaylor@writeme.com
cannam@0 37 }*/
cannam@0 38
cannam@0 39 ///////////////////////////////////////////////////////////////////////////////
cannam@0 40 // Modified by CLandone for VC6 Aug 2004
cannam@0 41 ///////////////////////////////////////////////////////////////////////////////
cannam@0 42
cannam@43 43 #include <iostream>
cannam@0 44
cannam@0 45 using std::vector;
cannam@0 46
cannam@0 47 class TPolyFit
cannam@0 48 {
cannam@0 49 typedef vector<vector<double> > Matrix;
cannam@0 50 public:
cannam@0 51
cannam@0 52 static double PolyFit2 (const vector<double> &x, // does the work
cannam@0 53 const vector<double> &y,
cannam@0 54 vector<double> &coef);
cannam@0 55
cannam@0 56
cannam@0 57 private:
cannam@0 58 TPolyFit &operator = (const TPolyFit &); // disable assignment
cannam@0 59 TPolyFit(); // and instantiation
cannam@0 60 TPolyFit(const TPolyFit&); // and copying
cannam@0 61
cannam@0 62
cannam@0 63 static void Square (const Matrix &x, // Matrix multiplication routine
cannam@0 64 const vector<double> &y,
cannam@0 65 Matrix &a, // A = transpose X times X
cannam@0 66 vector<double> &g, // G = Y times X
cannam@0 67 const int nrow, const int ncol);
cannam@0 68 // Forms square coefficient matrix
cannam@0 69
cannam@0 70 static bool GaussJordan (Matrix &b, // square matrix of coefficients
cannam@0 71 const vector<double> &y, // constant vector
cannam@0 72 vector<double> &coef); // solution vector
cannam@0 73 // returns false if matrix singular
cannam@0 74
cannam@0 75 static bool GaussJordan2(Matrix &b,
cannam@0 76 const vector<double> &y,
cannam@0 77 Matrix &w,
cannam@0 78 vector<vector<int> > &index);
cannam@0 79 };
cannam@0 80
cannam@0 81 // some utility functions
cannam@0 82
Chris@196 83 struct NSUtility
cannam@0 84 {
Chris@196 85 static void swap(double &a, double &b) {double t = a; a = b; b = t;}
Chris@196 86 // fills a vector with zeros.
Chris@196 87 static void zeroise(vector<double> &array, int n) {
Chris@196 88 array.clear();
Chris@196 89 for(int j = 0; j < n; ++j) array.push_back(0);
Chris@196 90 }
Chris@196 91 // fills a vector with zeros.
Chris@196 92 static void zeroise(vector<int> &array, int n) {
Chris@196 93 array.clear();
Chris@196 94 for(int j = 0; j < n; ++j) array.push_back(0);
Chris@196 95 }
Chris@196 96 // fills a (m by n) matrix with zeros.
Chris@196 97 static void zeroise(vector<vector<double> > &matrix, int m, int n) {
Chris@196 98 vector<double> zero;
Chris@196 99 zeroise(zero, n);
Chris@196 100 matrix.clear();
Chris@196 101 for(int j = 0; j < m; ++j) matrix.push_back(zero);
Chris@196 102 }
Chris@196 103 // fills a (m by n) matrix with zeros.
Chris@196 104 static void zeroise(vector<vector<int> > &matrix, int m, int n) {
Chris@196 105 vector<int> zero;
Chris@196 106 zeroise(zero, n);
Chris@196 107 matrix.clear();
Chris@196 108 for(int j = 0; j < m; ++j) matrix.push_back(zero);
Chris@196 109 }
Chris@196 110 static double sqr(const double &x) {return x * x;}
cannam@0 111 };
cannam@0 112
cannam@0 113
cannam@0 114 // main PolyFit routine
cannam@0 115
cannam@0 116 double TPolyFit::PolyFit2 (const vector<double> &x,
cannam@0 117 const vector<double> &y,
cannam@0 118 vector<double> &coefs)
cannam@0 119 // nterms = coefs.size()
cannam@0 120 // npoints = x.size()
cannam@0 121 {
cannam@0 122 int i, j;
cannam@0 123 double xi, yi, yc, srs, sum_y, sum_y2;
cannam@0 124 Matrix xmatr; // Data matrix
cannam@0 125 Matrix a;
cannam@0 126 vector<double> g; // Constant vector
cannam@0 127 const int npoints(x.size());
cannam@0 128 const int nterms(coefs.size());
cannam@0 129 double correl_coef;
Chris@196 130 NSUtility::zeroise(g, nterms);
Chris@196 131 NSUtility::zeroise(a, nterms, nterms);
Chris@196 132 NSUtility::zeroise(xmatr, npoints, nterms);
cannam@43 133 if (nterms < 1) {
cannam@43 134 std::cerr << "ERROR: PolyFit called with less than one term" << std::endl;
cannam@43 135 return 0;
cannam@43 136 }
cannam@43 137 if(npoints < 2) {
cannam@43 138 std::cerr << "ERROR: PolyFit called with less than two points" << std::endl;
cannam@43 139 return 0;
cannam@43 140 }
Chris@102 141 if(npoints != (int)y.size()) {
cannam@43 142 std::cerr << "ERROR: PolyFit called with x and y of unequal size" << std::endl;
cannam@43 143 return 0;
cannam@43 144 }
cannam@0 145 for(i = 0; i < npoints; ++i)
cannam@0 146 {
cannam@0 147 // { setup x matrix }
cannam@0 148 xi = x[i];
cannam@0 149 xmatr[i][0] = 1.0; // { first column }
cannam@0 150 for(j = 1; j < nterms; ++j)
cannam@0 151 xmatr[i][j] = xmatr [i][j - 1] * xi;
cannam@0 152 }
cannam@0 153 Square (xmatr, y, a, g, npoints, nterms);
cannam@0 154 if(!GaussJordan (a, g, coefs))
cannam@0 155 return -1;
cannam@0 156 sum_y = 0.0;
cannam@0 157 sum_y2 = 0.0;
cannam@0 158 srs = 0.0;
cannam@0 159 for(i = 0; i < npoints; ++i)
cannam@0 160 {
cannam@0 161 yi = y[i];
cannam@0 162 yc = 0.0;
cannam@0 163 for(j = 0; j < nterms; ++j)
cannam@0 164 yc += coefs [j] * xmatr [i][j];
Chris@196 165 srs += NSUtility::sqr (yc - yi);
cannam@0 166 sum_y += yi;
cannam@0 167 sum_y2 += yi * yi;
cannam@0 168 }
cannam@0 169
cannam@0 170 // If all Y values are the same, avoid dividing by zero
Chris@196 171 correl_coef = sum_y2 - NSUtility::sqr (sum_y) / npoints;
cannam@0 172 // Either return 0 or the correct value of correlation coefficient
cannam@0 173 if (correl_coef != 0)
cannam@0 174 correl_coef = srs / correl_coef;
cannam@0 175 if (correl_coef >= 1)
cannam@0 176 correl_coef = 0.0;
cannam@0 177 else
cannam@0 178 correl_coef = sqrt (1.0 - correl_coef);
cannam@0 179 return correl_coef;
cannam@0 180 }
cannam@0 181
cannam@0 182
cannam@0 183 //------------------------------------------------------------------------
cannam@0 184
cannam@0 185 // Matrix multiplication routine
cannam@0 186 // A = transpose X times X
cannam@0 187 // G = Y times X
cannam@0 188
cannam@0 189 // Form square coefficient matrix
cannam@0 190
cannam@0 191 void TPolyFit::Square (const Matrix &x,
cannam@0 192 const vector<double> &y,
cannam@0 193 Matrix &a,
cannam@0 194 vector<double> &g,
cannam@0 195 const int nrow,
cannam@0 196 const int ncol)
cannam@0 197 {
cannam@0 198 int i, k, l;
cannam@0 199 for(k = 0; k < ncol; ++k)
cannam@0 200 {
cannam@0 201 for(l = 0; l < k + 1; ++l)
cannam@0 202 {
cannam@0 203 a [k][l] = 0.0;
cannam@0 204 for(i = 0; i < nrow; ++i)
cannam@0 205 {
cannam@0 206 a[k][l] += x[i][l] * x [i][k];
cannam@0 207 if(k != l)
cannam@0 208 a[l][k] = a[k][l];
cannam@0 209 }
cannam@0 210 }
cannam@0 211 g[k] = 0.0;
cannam@0 212 for(i = 0; i < nrow; ++i)
cannam@0 213 g[k] += y[i] * x[i][k];
cannam@0 214 }
cannam@0 215 }
cannam@0 216 //---------------------------------------------------------------------------------
cannam@0 217
cannam@0 218
cannam@0 219 bool TPolyFit::GaussJordan (Matrix &b,
cannam@0 220 const vector<double> &y,
cannam@0 221 vector<double> &coef)
cannam@0 222 //b square matrix of coefficients
cannam@0 223 //y constant vector
cannam@0 224 //coef solution vector
cannam@0 225 //ncol order of matrix got from b.size()
cannam@0 226
cannam@0 227
cannam@0 228 {
cannam@0 229 /*
cannam@0 230 { Gauss Jordan matrix inversion and solution }
cannam@0 231
cannam@0 232 { B (n, n) coefficient matrix becomes inverse }
cannam@0 233 { Y (n) original constant vector }
cannam@0 234 { W (n, m) constant vector(s) become solution vector }
cannam@0 235 { DETERM is the determinant }
cannam@0 236 { ERROR = 1 if singular }
cannam@0 237 { INDEX (n, 3) }
cannam@0 238 { NV is number of constant vectors }
cannam@0 239 */
cannam@0 240
cannam@0 241 int ncol(b.size());
cannam@0 242 int irow, icol;
cannam@0 243 vector<vector<int> >index;
cannam@0 244 Matrix w;
cannam@0 245
Chris@196 246 NSUtility::zeroise(w, ncol, ncol);
Chris@196 247 NSUtility::zeroise(index, ncol, 3);
cannam@0 248
cannam@0 249 if(!GaussJordan2(b, y, w, index))
cannam@0 250 return false;
cannam@0 251
cannam@0 252 // Interchange columns
cannam@0 253 int m;
cannam@0 254 for (int i = 0; i < ncol; ++i)
cannam@0 255 {
cannam@0 256 m = ncol - i - 1;
cannam@0 257 if(index [m][0] != index [m][1])
cannam@0 258 {
cannam@0 259 irow = index [m][0];
cannam@0 260 icol = index [m][1];
cannam@0 261 for(int k = 0; k < ncol; ++k)
cannam@0 262 swap (b[k][irow], b[k][icol]);
cannam@0 263 }
cannam@0 264 }
cannam@0 265
cannam@0 266 for(int k = 0; k < ncol; ++k)
cannam@0 267 {
cannam@0 268 if(index [k][2] != 0)
cannam@0 269 {
cannam@43 270 std::cerr << "ERROR: Error in PolyFit::GaussJordan: matrix is singular" << std::endl;
cannam@43 271 return false;
cannam@0 272 }
cannam@0 273 }
cannam@0 274
cannam@0 275 for( int i = 0; i < ncol; ++i)
cannam@0 276 coef[i] = w[i][0];
cannam@0 277
cannam@0 278
cannam@0 279 return true;
cannam@0 280 } // end; { procedure GaussJordan }
cannam@0 281 //----------------------------------------------------------------------------------------------
cannam@0 282
cannam@0 283
cannam@0 284 bool TPolyFit::GaussJordan2(Matrix &b,
cannam@0 285 const vector<double> &y,
cannam@0 286 Matrix &w,
cannam@0 287 vector<vector<int> > &index)
cannam@0 288 {
cannam@0 289 //GaussJordan2; // first half of GaussJordan
cannam@0 290 // actual start of gaussj
cannam@0 291
cannam@0 292 double big, t;
cannam@0 293 double pivot;
cannam@0 294 double determ;
Chris@204 295 int irow = 0, icol = 0;
cannam@0 296 int ncol(b.size());
cannam@0 297 int nv = 1; // single constant vector
cannam@0 298 for(int i = 0; i < ncol; ++i)
cannam@0 299 {
cannam@0 300 w[i][0] = y[i]; // copy constant vector
cannam@0 301 index[i][2] = -1;
cannam@0 302 }
cannam@0 303 determ = 1.0;
cannam@0 304 for(int i = 0; i < ncol; ++i)
cannam@0 305 {
cannam@0 306 // Search for largest element
cannam@0 307 big = 0.0;
cannam@0 308 for(int j = 0; j < ncol; ++j)
cannam@0 309 {
cannam@0 310 if(index[j][2] != 0)
cannam@0 311 {
cannam@0 312 for(int k = 0; k < ncol; ++k)
cannam@0 313 {
cannam@43 314 if(index[k][2] > 0) {
cannam@43 315 std::cerr << "ERROR: Error in PolyFit::GaussJordan2: matrix is singular" << std::endl;
cannam@43 316 return false;
cannam@43 317 }
cannam@0 318
cannam@0 319 if(index[k][2] < 0 && fabs(b[j][k]) > big)
cannam@0 320 {
cannam@0 321 irow = j;
cannam@0 322 icol = k;
cannam@0 323 big = fabs(b[j][k]);
cannam@0 324 }
cannam@0 325 } // { k-loop }
cannam@0 326 }
cannam@0 327 } // { j-loop }
cannam@0 328 index [icol][2] = index [icol][2] + 1;
cannam@0 329 index [i][0] = irow;
cannam@0 330 index [i][1] = icol;
cannam@0 331
cannam@0 332 // Interchange rows to put pivot on diagonal
cannam@0 333 // GJ3
cannam@0 334 if(irow != icol)
cannam@0 335 {
cannam@0 336 determ = -determ;
cannam@0 337 for(int m = 0; m < ncol; ++m)
cannam@0 338 swap (b [irow][m], b[icol][m]);
cannam@0 339 if (nv > 0)
cannam@0 340 for (int m = 0; m < nv; ++m)
cannam@0 341 swap (w[irow][m], w[icol][m]);
cannam@0 342 } // end GJ3
cannam@0 343
cannam@0 344 // divide pivot row by pivot column
cannam@0 345 pivot = b[icol][icol];
cannam@0 346 determ *= pivot;
cannam@0 347 b[icol][icol] = 1.0;
cannam@0 348
cannam@0 349 for(int m = 0; m < ncol; ++m)
cannam@0 350 b[icol][m] /= pivot;
cannam@0 351 if(nv > 0)
cannam@0 352 for(int m = 0; m < nv; ++m)
cannam@0 353 w[icol][m] /= pivot;
cannam@0 354
cannam@0 355 // Reduce nonpivot rows
cannam@0 356 for(int n = 0; n < ncol; ++n)
cannam@0 357 {
cannam@0 358 if(n != icol)
cannam@0 359 {
cannam@0 360 t = b[n][icol];
cannam@0 361 b[n][icol] = 0.0;
cannam@0 362 for(int m = 0; m < ncol; ++m)
cannam@0 363 b[n][m] -= b[icol][m] * t;
cannam@0 364 if(nv > 0)
cannam@0 365 for(int m = 0; m < nv; ++m)
cannam@0 366 w[n][m] -= w[icol][m] * t;
cannam@0 367 }
cannam@0 368 }
cannam@0 369 } // { i-loop }
cannam@0 370 return true;
cannam@0 371 }
cannam@0 372
cannam@0 373 #endif
cannam@0 374