1 /***************************************************************************
2     File                 : PolynomialFit.cpp
3     Project              : QtiPlot
4     --------------------------------------------------------------------
5     Copyright            : (C) 2006 by Ion Vasilief
6     Email (use @ for *)  : ion_vasilief*yahoo.fr
7     Description          : Polynomial Fit and Linear Fit classes
8 
9  ***************************************************************************/
10 
11 /***************************************************************************
12  *                                                                         *
13  *  This program is free software; you can redistribute it and/or modify   *
14  *  it under the terms of the GNU General Public License as published by   *
15  *  the Free Software Foundation; either version 2 of the License, or      *
16  *  (at your option) any later version.                                    *
17  *                                                                         *
18  *  This program is distributed in the hope that it will be useful,        *
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
21  *  GNU General Public License for more details.                           *
22  *                                                                         *
23  *   You should have received a copy of the GNU General Public License     *
24  *   along with this program; if not, write to the Free Software           *
25  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
26  *   Boston, MA  02110-1301  USA                                           *
27  *                                                                         *
28  ***************************************************************************/
29 #include "PolynomialFit.h"
30 
31 #include <QMessageBox>
32 #include <QLocale>
33 
34 #include <gsl/gsl_multifit.h>
35 #include <gsl/gsl_fit.h>
36 
PolynomialFit(ApplicationWindow * parent,Graph * g,int order,bool legend)37 PolynomialFit::PolynomialFit(ApplicationWindow *parent, Graph *g, int order, bool legend)
38 : Fit(parent, g), d_order(order), show_legend(legend)
39 {
40 	init();
41 }
42 
PolynomialFit(ApplicationWindow * parent,QwtPlotCurve * c,int order,bool legend)43 PolynomialFit::PolynomialFit(ApplicationWindow *parent, QwtPlotCurve *c, int order, bool legend)
44 : Fit(parent, c), d_order(order), show_legend(legend)
45 {
46 	init();
47 	setDataFromCurve(c);
48 }
49 
PolynomialFit(ApplicationWindow * parent,QwtPlotCurve * c,double start,double end,int order,bool legend)50 PolynomialFit::PolynomialFit(ApplicationWindow *parent, QwtPlotCurve *c, double start, double end, int order, bool legend)
51 : Fit(parent, c), d_order(order), show_legend(legend)
52 {
53 	init();
54 	setDataFromCurve(c, start, end);
55 }
56 
PolynomialFit(ApplicationWindow * parent,Graph * g,QString & curveTitle,int order,bool legend)57 PolynomialFit::PolynomialFit(ApplicationWindow *parent, Graph *g, QString& curveTitle, int order, bool legend)
58 : Fit(parent, g), d_order(order), show_legend(legend)
59 {
60 	init();
61 	setDataFromCurve(curveTitle);
62 }
63 
PolynomialFit(ApplicationWindow * parent,Graph * g,QString & curveTitle,double start,double end,int order,bool legend)64 PolynomialFit::PolynomialFit(ApplicationWindow *parent, Graph *g, QString& curveTitle, double start, double end, int order, bool legend)
65 : Fit(parent, g), d_order(order), show_legend(legend)
66 {
67 	init();
68 	setDataFromCurve(curveTitle, start, end);
69 }
70 
PolynomialFit(ApplicationWindow * parent,Table * t,const QString & xCol,const QString & yCol,int startRow,int endRow,int order,bool legend)71 PolynomialFit::PolynomialFit(ApplicationWindow *parent, Table *t, const QString& xCol, const QString& yCol, int startRow, int endRow, int order, bool legend)
72 : Fit(parent, t), d_order(order), show_legend(legend)
73 {
74 	init();
75 	setDataFromTable(t, xCol, yCol, startRow, endRow);
76 }
77 
init()78 void PolynomialFit::init()
79 {
80 	setObjectName(tr("Polynomial"));
81 	is_non_linear = false;
82 	d_explanation = tr("Polynomial Fit");
83 	setOrder(d_order);
84 	d_scale_errors = false;
85 }
86 
setOrder(int order)87 void PolynomialFit::setOrder(int order)
88 {
89 	d_order = order;
90 	d_p = d_order + 1;
91 
92 	freeWorkspace();
93 	initWorkspace(d_p);
94 
95 	d_formula = generateFormula(d_order);
96 	d_param_names = generateParameterList(d_order);
97 
98 	d_param_explain.clear();
99 	for (int i=0; i<d_p; i++)
100 		d_param_explain << "";
101 }
102 
generateFormula(int order)103 QString PolynomialFit::generateFormula(int order)
104 {
105 	QString formula = QString::null;
106 	for (int i = 0; i < order+1; i++){
107 		QString par = "a" + QString::number(i);
108 		formula += par;
109 		if (i>0)
110 			formula +="*x";
111 		if (i>1)
112 			formula += "^"+QString::number(i);
113 		if (i != order)
114 			formula += "+";
115 	}
116 	return formula;
117 }
118 
generateParameterList(int order)119 QStringList PolynomialFit::generateParameterList(int order)
120 {
121 	QStringList lst;
122 	for (int i = 0; i < order+1; i++)
123 		lst << "a" + QString::number(i);
124 	return lst;
125 }
126 
calculateFitCurveData(double * X,double * Y)127 void PolynomialFit::calculateFitCurveData(double *X, double *Y)
128 {
129 	if (d_gen_function){
130 		double X0 = d_x[0];
131 		double step = (d_x[d_n-1]-X0)/(d_points-1);
132 		for (int i=0; i<d_points; i++){
133 		    double x = X0+i*step;
134 			X[i] = x;
135 			double 	yi = 0.0;
136 			for (int j=0; j<d_p;j++)
137 				yi += d_results[j]*pow(x, j);
138 			Y[i] = yi;
139 		}
140 	} else {
141 		for (int i=0; i<d_points; i++) {
142 		    double x = d_x[i];
143 			X[i] = x;
144 			double 	yi = 0.0;
145 			for (int j=0; j<d_p; j++)
146 				yi += d_results[j]*pow(x, j);
147 			Y[i] = yi;
148 		}
149 	}
150 }
151 
eval(double * par,double x)152 double PolynomialFit::eval(double *par, double x)
153 {
154 	double 	y = 0.0;
155 	for (int j=0; j<d_p; j++)
156 		y += par[j]*pow(x, j);
157 	return y;
158 }
159 
fit()160 void PolynomialFit::fit()
161 {
162     if (d_init_err)
163         return;
164 
165 	if (d_p > d_n){
166   		QMessageBox::critical((ApplicationWindow *)parent(), tr("QtiPlot - Fit Error"),
167   	    tr("You need at least %1 data points for this fit operation. Operation aborted!").arg(d_p));
168   		return;
169   	}
170 
171 	gsl_matrix *X = gsl_matrix_alloc (d_n, d_p);
172 
173 	for (int i = 0; i <d_n; i++){
174 		for (int j= 0; j < d_p; j++)
175 			gsl_matrix_set (X, i, j, pow(d_x[i],j));
176 	}
177 
178 	gsl_vector_view y = gsl_vector_view_array (d_y, d_n);
179 	gsl_vector_view w = gsl_vector_view_array (d_w, d_n);
180 	gsl_multifit_linear_workspace * work = gsl_multifit_linear_alloc (d_n, d_p);
181 
182 	if (d_weighting == NoWeighting)
183 		gsl_multifit_linear (X, &y.vector, d_param_init, covar, &chi_2, work);
184 	else
185 		gsl_multifit_wlinear (X, &w.vector, &y.vector, d_param_init, covar, &chi_2, work);
186 
187 	for (int i = 0; i < d_p; i++)
188 		d_results[i] = gsl_vector_get(d_param_init, i);
189 
190 	gsl_multifit_linear_free (work);
191 	gsl_matrix_free (X);
192 
193 	generateFitCurve();
194 
195 	if (show_legend)
196 		showLegend();
197 
198 	ApplicationWindow *app = (ApplicationWindow *)parent();
199 	if (app->writeFitResultsToLog)
200 		app->updateLog(logFitInfo(0, 0));
201 }
202 
legendInfo()203 QString PolynomialFit::legendInfo()
204 {
205     ApplicationWindow *app = (ApplicationWindow *)parent();
206     QLocale locale = app->locale();
207 	QString legend = "Y=" + locale.toString(d_results[0], 'g', d_prec);
208 	for (int j = 1; j < d_p; j++){
209 		double cj = d_results[j];
210 		if (cj>0 && !legend.isEmpty())
211 			legend += "+";
212 
213 		QString s;
214 		s.sprintf("%.5f",cj);
215 		if (s != "1.00000")
216 			legend += locale.toString(cj, 'g', d_prec);
217 
218 		legend += "X";
219 		if (j>1)
220 			legend += "<sup>" + QString::number(j) + "</sup>";
221 	}
222 	return legend;
223 }
224 
225 /*****************************************************************************
226  *
227  * Class LinearFit
228  *
229  *****************************************************************************/
230 
LinearFit(ApplicationWindow * parent,QwtPlotCurve * c)231 LinearFit::LinearFit(ApplicationWindow *parent, QwtPlotCurve *c)
232 : Fit(parent, c)
233 {
234 	init();
235 	setDataFromCurve(c);
236 }
237 
LinearFit(ApplicationWindow * parent,QwtPlotCurve * c,double start,double end)238 LinearFit::LinearFit(ApplicationWindow *parent, QwtPlotCurve *c, double start, double end)
239 : Fit(parent, c)
240 {
241 	init();
242 	setDataFromCurve(c, start, end);
243 }
244 
LinearFit(ApplicationWindow * parent,Graph * g)245 LinearFit::LinearFit(ApplicationWindow *parent, Graph *g)
246 : Fit(parent, g)
247 {
248 	init();
249 }
250 
LinearFit(ApplicationWindow * parent,Graph * g,const QString & curveTitle)251 LinearFit::LinearFit(ApplicationWindow *parent, Graph *g, const QString& curveTitle)
252 : Fit(parent, g)
253 {
254 	init();
255 	setDataFromCurve(curveTitle);
256 }
257 
LinearFit(ApplicationWindow * parent,Graph * g,const QString & curveTitle,double start,double end)258 LinearFit::LinearFit(ApplicationWindow *parent, Graph *g, const QString& curveTitle, double start, double end)
259 : Fit(parent, g)
260 {
261 	init();
262 	setDataFromCurve(curveTitle, start, end);
263 }
264 
LinearFit(ApplicationWindow * parent,Table * t,const QString & xCol,const QString & yCol,int startRow,int endRow)265 LinearFit::LinearFit(ApplicationWindow *parent, Table *t, const QString& xCol, const QString& yCol, int startRow, int endRow)
266 : Fit(parent, t)
267 {
268 	init();
269 	setDataFromTable(t, xCol, yCol, startRow, endRow);
270 }
271 
init()272 void LinearFit::init()
273 {
274 	d_scale_errors = false;
275 
276 	d_p = 2;
277     d_min_points = d_p;
278 
279 	covar = gsl_matrix_alloc (d_p, d_p);
280 	d_results = new double[d_p];
281 
282     d_param_init = gsl_vector_alloc(d_p);
283 	gsl_vector_set_all (d_param_init, 1.0);
284 
285 	is_non_linear = false;
286 	d_formula = "A*x+B";
287 	d_param_names << "B" << "A";
288 	d_param_explain << "y-intercept" << "slope";
289 	d_explanation = tr("Linear Regression");
290 	setObjectName(tr("Linear"));
291 }
292 
fit()293 void LinearFit::fit()
294 {
295     if (d_init_err)
296         return;
297 
298 	if (d_p > d_n){
299   		QMessageBox::critical((ApplicationWindow *)parent(), tr("QtiPlot - Fit Error"),
300   	    tr("You need at least %1 data points for this fit operation. Operation aborted!").arg(d_p));
301   		return;
302   	}
303 
304 	double c0, c1, cov00, cov01, cov11;
305 	if (d_weighting == NoWeighting)
306 		gsl_fit_linear(d_x, 1, d_y, 1, d_n, &c0, &c1, &cov00, &cov01, &cov11, &chi_2);
307 	else
308 		gsl_fit_wlinear(d_x, 1, d_w, 1, d_y, 1, d_n, &c0, &c1, &cov00, &cov01, &cov11, &chi_2);
309 
310 	d_results[0] = c0;
311 	d_results[1] = c1;
312 
313 	gsl_matrix_set(covar, 0, 0, cov00);
314 	gsl_matrix_set(covar, 0, 1, cov01);
315 	gsl_matrix_set(covar, 1, 1, cov11);
316 	gsl_matrix_set(covar, 1, 0, cov01);
317 
318 	generateFitCurve();
319 
320 	ApplicationWindow *app = (ApplicationWindow *)parent();
321 	if (app->writeFitResultsToLog)
322 		app->updateLog(logFitInfo(0, 0));
323 }
324 
calculateFitCurveData(double * X,double * Y)325 void LinearFit::calculateFitCurveData(double *X, double *Y)
326 {
327 	if (d_gen_function){
328 		double X0 = d_x[0];
329 		double step = (d_x[d_n-1]-X0)/(d_points-1);
330 		for (int i=0; i<d_points; i++){
331 		    double x = X0+i*step;
332 			X[i] = x;
333 			Y[i] = d_results[0] + d_results[1]*x;
334 		}
335 	} else {
336 		for (int i=0; i<d_points; i++) {
337 		    double x = d_x[i];
338 			X[i] = x;
339 			Y[i] = d_results[0] + d_results[1]*x;
340 		}
341 	}
342 }
343 
344 
345 /*****************************************************************************
346  *
347  * Class LinearSlopeFit
348  *
349  *****************************************************************************/
350 
LinearSlopeFit(ApplicationWindow * parent,Graph * g)351 LinearSlopeFit::LinearSlopeFit(ApplicationWindow *parent, Graph *g)
352 : Fit(parent, g)
353 {
354 	init();
355 }
356 
LinearSlopeFit(ApplicationWindow * parent,Graph * g,const QString & curveTitle)357 LinearSlopeFit::LinearSlopeFit(ApplicationWindow *parent, Graph *g, const QString& curveTitle)
358 : Fit(parent, g)
359 {
360 	init();
361 	setDataFromCurve(curveTitle);
362 }
363 
LinearSlopeFit(ApplicationWindow * parent,Graph * g,const QString & curveTitle,double start,double end)364 LinearSlopeFit::LinearSlopeFit(ApplicationWindow *parent, Graph *g, const QString& curveTitle, double start, double end)
365 : Fit(parent, g)
366 {
367 	init();
368 	setDataFromCurve(curveTitle, start, end);
369 }
370 
LinearSlopeFit(ApplicationWindow * parent,Table * t,const QString & xCol,const QString & yCol,int startRow,int endRow)371 LinearSlopeFit::LinearSlopeFit(ApplicationWindow *parent, Table *t, const QString& xCol, const QString& yCol, int startRow, int endRow)
372 : Fit(parent, t)
373 {
374 	init();
375 	setDataFromTable(t, xCol, yCol, startRow, endRow);
376 }
377 
init()378 void LinearSlopeFit::init()
379 {
380 	d_scale_errors = false;
381 
382 	d_p = 1;
383     d_min_points = d_p;
384 
385 	covar = gsl_matrix_alloc (d_p, d_p);
386 	d_results = new double[d_p];
387 
388     d_param_init = gsl_vector_alloc(d_p);
389 	gsl_vector_set_all (d_param_init, 1.0);
390 
391 	is_non_linear = false;
392 	d_formula = "A*x";
393 	d_param_names << "A";
394 	d_param_explain << "slope";
395 	d_explanation = tr("Linear Regression");
396 	setObjectName(tr("LinearSlope"));
397 }
398 
fit()399 void LinearSlopeFit::fit()
400 {
401     if (d_init_err)
402         return;
403 
404 	if (d_p > d_n){
405   		QMessageBox::critical((ApplicationWindow *)parent(), tr("QtiPlot - Fit Error"),
406   	    tr("You need at least %1 data points for this fit operation. Operation aborted!").arg(d_p));
407   		return;
408   	}
409 
410 	double c1, cov11;
411 	if (d_weighting == NoWeighting)
412 		gsl_fit_mul(d_x, 1, d_y, 1, d_n, &c1, &cov11, &chi_2);
413 	else
414 		gsl_fit_wmul(d_x, 1, d_w, 1, d_y, 1, d_n, &c1, &cov11, &chi_2);
415 
416 	d_results[0] = c1;
417 
418 	gsl_matrix_set(covar, 0, 0, cov11);
419 	generateFitCurve();
420 
421 	ApplicationWindow *app = (ApplicationWindow *)parent();
422 	if (app->writeFitResultsToLog)
423 		app->updateLog(logFitInfo(0, 0));
424 }
425 
calculateFitCurveData(double * X,double * Y)426 void LinearSlopeFit::calculateFitCurveData(double *X, double *Y)
427 {
428 	if (d_gen_function){
429 		double X0 = d_x[0];
430 		double step = (d_x[d_n-1] - X0)/(d_points - 1);
431 		for (int i=0; i<d_points; i++){
432 		    double x = X0 + i*step;
433 			X[i] = x;
434 			Y[i] = d_results[0]*x;
435 		}
436 	} else {
437 		for (int i=0; i<d_points; i++) {
438 		    double x = d_x[i];
439 			X[i] = x;
440 			Y[i] = d_results[0]*x;
441 		}
442 	}
443 }
444