annotate maths/Polyfit.h @ 261:2e8518f08648

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