1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 //---------------------------------------------------------------------------
6 //---------------------------------------------------------------------------
7 // Least-squares curve fitting class for arbitrary data types
10 { ******************************************
11 **** Scientific Subroutine Library ****
12 **** for C++ Builder ****
13 ******************************************
15 The following programs were written by Allen Miller and appear in the
16 book entitled "Pascal Programs For Scientists And Engineers" which is
17 published by Sybex, 1981.
18 They were originally typed and submitted to MTPUG in Oct. 1982
22 They have had minor corrections and adaptations for Turbo Pascal by
28 2000 Oct 28 Updated for Delphi 4, open array parameters.
29 This allows the routine to be generalised so that it is no longer
30 hard-coded to make a specific order of best fit or work with a
31 specific number of points.
32 2001 Jan 07 Update Web site address
34 Copyright � David J Taylor, Edinburgh and others listed above
35 Web site: www.satsignal.net
36 E-mail: davidtaylor@writeme.com
39 ///////////////////////////////////////////////////////////////////////////////
40 // Modified by CLandone for VC6 Aug 2004
41 ///////////////////////////////////////////////////////////////////////////////
49 typedef vector<vector<double> > Matrix;
52 static double PolyFit2 (const vector<double> &x, // does the work
53 const vector<double> &y,
54 vector<double> &coef);
58 TPolyFit &operator = (const TPolyFit &); // disable assignment
59 TPolyFit(); // and instantiation
60 TPolyFit(const TPolyFit&); // and copying
63 static void Square (const Matrix &x, // Matrix multiplication routine
64 const vector<double> &y,
65 Matrix &a, // A = transpose X times X
66 vector<double> &g, // G = Y times X
67 const int nrow, const int ncol);
68 // Forms square coefficient matrix
70 static bool GaussJordan (Matrix &b, // square matrix of coefficients
71 const vector<double> &y, // constant vector
72 vector<double> &coef); // solution vector
73 // returns false if matrix singular
75 static bool GaussJordan2(Matrix &b,
76 const vector<double> &y,
78 vector<vector<int> > &index);
81 // some utility functions
85 inline void swap(double &a, double &b) {double t = a; a = b; b = t;}
86 void zeroise(vector<double> &array, int n);
87 void zeroise(vector<int> &array, int n);
88 void zeroise(vector<vector<double> > &matrix, int m, int n);
89 void zeroise(vector<vector<int> > &matrix, int m, int n);
90 inline double sqr(const double &x) {return x * x;}
93 //---------------------------------------------------------------------------
95 //---------------------------------------------------------------------------
96 using namespace NSUtility;
97 //------------------------------------------------------------------------------------------
100 // main PolyFit routine
102 double TPolyFit::PolyFit2 (const vector<double> &x,
103 const vector<double> &y,
104 vector<double> &coefs)
105 // nterms = coefs.size()
106 // npoints = x.size()
109 double xi, yi, yc, srs, sum_y, sum_y2;
110 Matrix xmatr; // Data matrix
112 vector<double> g; // Constant vector
113 const int npoints(x.size());
114 const int nterms(coefs.size());
117 zeroise(a, nterms, nterms);
118 zeroise(xmatr, npoints, nterms);
120 std::cerr << "ERROR: PolyFit called with less than one term" << std::endl;
124 std::cerr << "ERROR: PolyFit called with less than two points" << std::endl;
127 if(npoints != (int)y.size()) {
128 std::cerr << "ERROR: PolyFit called with x and y of unequal size" << std::endl;
131 for(i = 0; i < npoints; ++i)
133 // { setup x matrix }
135 xmatr[i][0] = 1.0; // { first column }
136 for(j = 1; j < nterms; ++j)
137 xmatr[i][j] = xmatr [i][j - 1] * xi;
139 Square (xmatr, y, a, g, npoints, nterms);
140 if(!GaussJordan (a, g, coefs))
145 for(i = 0; i < npoints; ++i)
149 for(j = 0; j < nterms; ++j)
150 yc += coefs [j] * xmatr [i][j];
151 srs += sqr (yc - yi);
156 // If all Y values are the same, avoid dividing by zero
157 correl_coef = sum_y2 - sqr (sum_y) / npoints;
158 // Either return 0 or the correct value of correlation coefficient
159 if (correl_coef != 0)
160 correl_coef = srs / correl_coef;
161 if (correl_coef >= 1)
164 correl_coef = sqrt (1.0 - correl_coef);
169 //------------------------------------------------------------------------
171 // Matrix multiplication routine
172 // A = transpose X times X
175 // Form square coefficient matrix
177 void TPolyFit::Square (const Matrix &x,
178 const vector<double> &y,
185 for(k = 0; k < ncol; ++k)
187 for(l = 0; l < k + 1; ++l)
190 for(i = 0; i < nrow; ++i)
192 a[k][l] += x[i][l] * x [i][k];
198 for(i = 0; i < nrow; ++i)
199 g[k] += y[i] * x[i][k];
202 //---------------------------------------------------------------------------------
205 bool TPolyFit::GaussJordan (Matrix &b,
206 const vector<double> &y,
207 vector<double> &coef)
208 //b square matrix of coefficients
210 //coef solution vector
211 //ncol order of matrix got from b.size()
216 { Gauss Jordan matrix inversion and solution }
218 { B (n, n) coefficient matrix becomes inverse }
219 { Y (n) original constant vector }
220 { W (n, m) constant vector(s) become solution vector }
221 { DETERM is the determinant }
222 { ERROR = 1 if singular }
224 { NV is number of constant vectors }
229 vector<vector<int> >index;
232 zeroise(w, ncol, ncol);
233 zeroise(index, ncol, 3);
235 if(!GaussJordan2(b, y, w, index))
238 // Interchange columns
240 for (int i = 0; i < ncol; ++i)
243 if(index [m][0] != index [m][1])
247 for(int k = 0; k < ncol; ++k)
248 swap (b[k][irow], b[k][icol]);
252 for(int k = 0; k < ncol; ++k)
254 if(index [k][2] != 0)
256 std::cerr << "ERROR: Error in PolyFit::GaussJordan: matrix is singular" << std::endl;
261 for( int i = 0; i < ncol; ++i)
266 } // end; { procedure GaussJordan }
267 //----------------------------------------------------------------------------------------------
270 bool TPolyFit::GaussJordan2(Matrix &b,
271 const vector<double> &y,
273 vector<vector<int> > &index)
275 //GaussJordan2; // first half of GaussJordan
276 // actual start of gaussj
283 int nv = 1; // single constant vector
284 for(int i = 0; i < ncol; ++i)
286 w[i][0] = y[i]; // copy constant vector
290 for(int i = 0; i < ncol; ++i)
292 // Search for largest element
294 for(int j = 0; j < ncol; ++j)
298 for(int k = 0; k < ncol; ++k)
300 if(index[k][2] > 0) {
301 std::cerr << "ERROR: Error in PolyFit::GaussJordan2: matrix is singular" << std::endl;
305 if(index[k][2] < 0 && fabs(b[j][k]) > big)
314 index [icol][2] = index [icol][2] + 1;
318 // Interchange rows to put pivot on diagonal
323 for(int m = 0; m < ncol; ++m)
324 swap (b [irow][m], b[icol][m]);
326 for (int m = 0; m < nv; ++m)
327 swap (w[irow][m], w[icol][m]);
330 // divide pivot row by pivot column
331 pivot = b[icol][icol];
335 for(int m = 0; m < ncol; ++m)
338 for(int m = 0; m < nv; ++m)
341 // Reduce nonpivot rows
342 for(int n = 0; n < ncol; ++n)
348 for(int m = 0; m < ncol; ++m)
349 b[n][m] -= b[icol][m] * t;
351 for(int m = 0; m < nv; ++m)
352 w[n][m] -= w[icol][m] * t;
358 //----------------------------------------------------------------------------------------------
360 //------------------------------------------------------------------------------------
363 //--------------------------------------------------------------------------
365 // fills a vector with zeros.
366 void NSUtility::zeroise(vector<double> &array, int n)
369 for(int j = 0; j < n; ++j)
372 //--------------------------------------------------------------------------
374 // fills a vector with zeros.
375 void NSUtility::zeroise(vector<int> &array, int n)
378 for(int j = 0; j < n; ++j)
381 //--------------------------------------------------------------------------
383 // fills a (m by n) matrix with zeros.
384 void NSUtility::zeroise(vector<vector<double> > &matrix, int m, int n)
389 for(int j = 0; j < m; ++j)
390 matrix.push_back(zero);
392 //--------------------------------------------------------------------------
394 // fills a (m by n) matrix with zeros.
395 void NSUtility::zeroise(vector<vector<int> > &matrix, int m, int n)
400 for(int j = 0; j < m; ++j)
401 matrix.push_back(zero);
403 //--------------------------------------------------------------------------