annotate maths/Polyfit.h @ 204:214b31ec7e1a clapack-included

Minor build fixes
author Chris Cannam
date Fri, 30 Sep 2016 16:23:10 +0100
parents be1fc3a6b901
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