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 unsigned int npoints(x.size());
114 const unsigned 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 != 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
284 int nv = 1; // single constant vector
285 for(int i = 0; i < ncol; ++i)
287 w[i][0] = y[i]; // copy constant vector
291 for(int i = 0; i < ncol; ++i)
293 // Search for largest element
295 for(int j = 0; j < ncol; ++j)
299 for(int k = 0; k < ncol; ++k)
301 if(index[k][2] > 0) {
302 std::cerr << "ERROR: Error in PolyFit::GaussJordan2: matrix is singular" << std::endl;
306 if(index[k][2] < 0 && fabs(b[j][k]) > big)
315 index [icol][2] = index [icol][2] + 1;
319 // Interchange rows to put pivot on diagonal
324 for(int m = 0; m < ncol; ++m)
325 swap (b [irow][m], b[icol][m]);
327 for (int m = 0; m < nv; ++m)
328 swap (w[irow][m], w[icol][m]);
331 // divide pivot row by pivot column
332 pivot = b[icol][icol];
336 for(int m = 0; m < ncol; ++m)
339 for(int m = 0; m < nv; ++m)
342 // Reduce nonpivot rows
343 for(int n = 0; n < ncol; ++n)
349 for(int m = 0; m < ncol; ++m)
350 b[n][m] -= b[icol][m] * t;
352 for(int m = 0; m < nv; ++m)
353 w[n][m] -= w[icol][m] * t;
359 //----------------------------------------------------------------------------------------------
361 //------------------------------------------------------------------------------------
364 //--------------------------------------------------------------------------
366 // fills a vector with zeros.
367 void NSUtility::zeroise(vector<double> &array, int n)
370 for(int j = 0; j < n; ++j)
373 //--------------------------------------------------------------------------
375 // fills a vector with zeros.
376 void NSUtility::zeroise(vector<int> &array, int n)
379 for(int j = 0; j < n; ++j)
382 //--------------------------------------------------------------------------
384 // fills a (m by n) matrix with zeros.
385 void NSUtility::zeroise(vector<vector<double> > &matrix, int m, int n)
390 for(int j = 0; j < m; ++j)
391 matrix.push_back(zero);
393 //--------------------------------------------------------------------------
395 // fills a (m by n) matrix with zeros.
396 void NSUtility::zeroise(vector<vector<int> > &matrix, int m, int n)
401 for(int j = 0; j < m; ++j)
402 matrix.push_back(zero);
404 //--------------------------------------------------------------------------