Engauge Digitizer  2
 All Classes Functions Variables Typedefs Enumerations Friends Pages
TestFitting.cpp
1 #include "FittingStatistics.h"
2 #include "Logger.h"
3 #include "MainWindow.h"
4 #include <qmath.h>
5 #include <QPointF>
6 #include <QtTest/QtTest>
7 #include "Test/TestFitting.h"
8 
9 QTEST_MAIN (TestFitting)
10 
11 using namespace std;
12 
13 const int NOMINAL_ORDER = 6;
14 const int NOMINAL_SIGNIFICANT_DIGITS = 7;
15 
16 TestFitting::TestFitting(QObject *parent) :
17  QObject(parent)
18 {
19 }
20 
21 void TestFitting::cleanupTestCase ()
22 {
23 
24 }
25 
26 bool TestFitting::generalFunctionTest (int order,
27  int numPoints) const
28 {
29  int orderReduced = qMin (order, numPoints - 1);
30 
31  const double EPSILON = 0.0001;
32  FittingStatistics fitting;
33  double mse, rms, rSquared;
34  FittingCurveCoefficients coefficientsGot (MAX_POLYNOMIAL_ORDER + 1);
35 
36  // Overfitting or underfitting?
37  bool isOverfitting = (order >= numPoints - 1);
38 
39  // Create the points according to y = 0 + 1 * (x + 1) (x + 2) ... (x + order), with y=0 for order=0
40  FittingPointsConvenient points;
41  for (int iPoint = 0; iPoint < numPoints; iPoint++) {
42  double x = iPoint; // Pick arbitrary x values that are near the zeros
43  double y = 0;
44  if (orderReduced > 0) {
45  y = 1; // Multiply this by successive terms
46  for (int ord = 0; ord < orderReduced; ord++) {
47  y *= (x + ord + 1);
48  }
49  }
50 
51  points.append (QPointF (x, y));
52  }
53 
54  fitting.calculateCurveFitAndStatistics (order,
55  points,
56  coefficientsGot,
57  mse,
58  rms,
59  rSquared,
60  NOMINAL_SIGNIFICANT_DIGITS);
61 
62  bool success = true;
63 
64  // Expected coefficients are hardcoded
65  FittingCurveCoefficients coefficientsExpected (orderReduced + 1);
66  switch (orderReduced)
67  {
68  case 0: // y=0
69  coefficientsExpected [0] = 0;
70  break;
71  case 1: // y=(x+1)
72  coefficientsExpected [0] = 1;
73  coefficientsExpected [1] = 1;
74  break;
75  case 2: // y=(x+1)(x+2)
76  coefficientsExpected [0] = 2;
77  coefficientsExpected [1] = 3;
78  coefficientsExpected [2] = 1;
79  break;
80  case 3: // y=(x+1)(x+2)(x+3)
81  coefficientsExpected [0] = 6;
82  coefficientsExpected [1] = 11;
83  coefficientsExpected [2] = 6;
84  coefficientsExpected [3] = 1;
85  break;
86  case 4: // y=(x+1)(x+2)(x+3)(x+4)
87  coefficientsExpected [0] = 24;
88  coefficientsExpected [1] = 50;
89  coefficientsExpected [2] = 35;
90  coefficientsExpected [3] = 10;
91  coefficientsExpected [4] = 1;
92  break;
93  }
94 
95  for (int coef = 0; coef < order + 1; coef++) {
96  double coefGot = coefficientsGot [coef];
97 
98  double coefExpected = 0;
99  if (coef <= orderReduced) {
100  coefExpected = coefficientsExpected [coef];
101  }
102 
103  success = (success && ((qAbs (coefGot - coefExpected) < EPSILON)));
104  }
105 
106  if (isOverfitting) {
107  // Overfitting case should always have an error of zero
108  success = (success && ((qAbs (mse) < EPSILON)));
109  }
110 
111  return success;
112 }
113 
114 bool TestFitting::generalNonFunctionTest () const
115 {
116  const double EPSILON = 0.0001;
117  FittingStatistics fitting;
118  double mse, rms, rSquared;
119  FittingCurveCoefficients coefficientsGot (MAX_POLYNOMIAL_ORDER);
120 
121  // Create the points according to y = 0 + 1 * (x + 1) (x + 2) ... (x + order), with y=0 for order=0
122  FittingPointsConvenient points;
123  const double Y1 = 1, Y2 = 2;
124  points.append (QPointF (1, Y1));
125  points.append (QPointF (1, Y2));
126 
128  points,
129  coefficientsGot,
130  mse,
131  rms,
132  rSquared,
133  NOMINAL_SIGNIFICANT_DIGITS);
134 
135  bool success = true;
136 
137  // Expected coefficients are hardcoded
138  FittingCurveCoefficients coefficientsExpected (2);
139  coefficientsExpected [0] = (Y1 + Y2) / 2.0;
140  coefficientsExpected [1] = 0;
141 
142  for (int coef = 0; coef < 2; coef++) {
143  double coefGot = coefficientsGot [coef];
144 
145  double coefExpected = coefficientsExpected [coef];
146 
147  success = (success && ((qAbs (coefGot - coefExpected) < EPSILON)));
148  }
149 
150  return success;
151 }
152 
153 void TestFitting::initTestCase ()
154 {
155  const QString NO_ERROR_REPORT_LOG_FILE;
156  const QString NO_REGRESSION_OPEN_FILE;
157  const bool NO_GNUPLOT_LOG_FILES = false;
158  const bool NO_REGRESSION_IMPORT = false;
159  const bool NO_RESET = false;
160  const bool NO_EXPORT_ONLY = false;
161  const bool NO_EXTRACT_IMAGE_ONLY = false;
162  const QString NO_EXTRACT_IMAGE_EXTENSION;
163  const bool DEBUG_FLAG = false;
164  const QStringList NO_LOAD_STARTUP_FILES;
165  const QStringList NO_COMMAND_LINE;
166 
167  initializeLogging ("engauge_test",
168  "engauge_test.log",
169  DEBUG_FLAG);
170 
171  MainWindow w (NO_ERROR_REPORT_LOG_FILE,
172  NO_REGRESSION_OPEN_FILE,
173  NO_REGRESSION_IMPORT,
174  NO_GNUPLOT_LOG_FILES,
175  NO_RESET,
176  NO_EXPORT_ONLY,
177  NO_EXTRACT_IMAGE_ONLY,
178  NO_EXTRACT_IMAGE_EXTENSION,
179  NO_LOAD_STARTUP_FILES,
180  NO_COMMAND_LINE);
181  w.show ();
182 }
183 
184 int TestFitting::orderReducedVersusOrderAndSignificantDigits (int order,
185  int significantDigits) const
186 {
187  FittingPointsConvenient points;
188  FittingCurveCoefficients coefficients (MAX_POLYNOMIAL_ORDER + 1);
189 
190  // Hyperbola points
191  FittingStatistics fittingStatistics;
192  for (double x = 1; x <= 10; x += 1) {
193  double y = 100.0 / x;
194  points.append (QPointF (x, y));
195  }
196 
197  fittingStatistics.calculateCurveFit (order,
198  points,
199  coefficients,
200  significantDigits);
201 
202  // Find first nonzero coefficient. Two cases for 0th order are y<>0 (not all coefficients are zero)
203  // and y=0 (all coefficients are zero). In all other cases the order is the highest nonzero coefficient
204  int orderReduced;
205  for (orderReduced = MAX_POLYNOMIAL_ORDER; orderReduced > 0; orderReduced--) {
206  if (coefficients [orderReduced] != 0) {
207  return orderReduced;
208  }
209  }
210 
211  return orderReduced;
212 }
213 
214 void TestFitting::testFunctionExactFit01 ()
215 {
216  QVERIFY (generalFunctionTest (0, 1));
217 }
218 
219 void TestFitting::testFunctionExactFit12 ()
220 {
221  QVERIFY (generalFunctionTest (1, 2));
222 }
223 
224 void TestFitting::testFunctionExactFit23 ()
225 {
226  QVERIFY (generalFunctionTest (2, 3));
227 }
228 
229 void TestFitting::testFunctionExactFit34 ()
230 {
231  QVERIFY (generalFunctionTest (3, 4));
232 }
233 
234 void TestFitting::testFunctionOverfit11 ()
235 {
236  QVERIFY (generalFunctionTest (1, 1));
237 }
238 
239 void TestFitting::testFunctionOverfit22 ()
240 {
241  QVERIFY (generalFunctionTest (2, 2));
242 }
243 
244 void TestFitting::testFunctionOverfit33 ()
245 {
246  QVERIFY (generalFunctionTest (3, 3));
247 }
248 
249 void TestFitting::testFunctionOverfit44 ()
250 {
251  QVERIFY (generalFunctionTest (4, 4));
252 }
253 
254 void TestFitting::testFunctionUnderfit02 ()
255 {
256  QVERIFY (generalFunctionTest (0, 2));
257 }
258 
259 void TestFitting::testFunctionUnderfit13 ()
260 {
261  QVERIFY (generalFunctionTest (1, 3));
262 }
263 
264 void TestFitting::testFunctionUnderfit24 ()
265 {
266  QVERIFY (generalFunctionTest (2, 4));
267 }
268 
269 void TestFitting::testFunctionUnderfit35 ()
270 {
271  QVERIFY (generalFunctionTest (3, 5));
272 }
273 
274 void TestFitting::testNonFunction ()
275 {
276  QVERIFY (generalNonFunctionTest ());
277 }
278 
279 void TestFitting::testOrderReduced3 ()
280 {
281  QVERIFY (orderReducedVersusOrderAndSignificantDigits (3, NOMINAL_SIGNIFICANT_DIGITS) == 3);
282 }
283 
284 void TestFitting::testOrderReduced4 ()
285 {
286  QVERIFY (orderReducedVersusOrderAndSignificantDigits (4, NOMINAL_SIGNIFICANT_DIGITS) == 4);
287 }
288 
289 void TestFitting::testOrderReduced5 ()
290 {
291  QVERIFY (orderReducedVersusOrderAndSignificantDigits (5, NOMINAL_SIGNIFICANT_DIGITS) == 5);
292 }
293 
294 void TestFitting::testOrderReduced6 ()
295 {
296  QVERIFY (orderReducedVersusOrderAndSignificantDigits (6, NOMINAL_SIGNIFICANT_DIGITS) == 6);
297 }
298 
299 void TestFitting::testSignificantDigits3 ()
300 {
301  QVERIFY (orderReducedVersusOrderAndSignificantDigits (NOMINAL_ORDER, 3) == NOMINAL_ORDER);
302 }
303 
304 void TestFitting::testSignificantDigits4 ()
305 {
306  QVERIFY (orderReducedVersusOrderAndSignificantDigits (NOMINAL_ORDER, 4) == NOMINAL_ORDER);
307 }
308 
309 void TestFitting::testSignificantDigits5 ()
310 {
311  QVERIFY (orderReducedVersusOrderAndSignificantDigits (NOMINAL_ORDER, 5) == NOMINAL_ORDER);
312 }
313 
314 void TestFitting::testSignificantDigits6 ()
315 {
316  QVERIFY (orderReducedVersusOrderAndSignificantDigits (NOMINAL_ORDER, 6) == NOMINAL_ORDER);
317 }
Unit test of Fitting classes.
Definition: TestFitting.h:7
void calculateCurveFitAndStatistics(unsigned int order, const FittingPointsConvenient &pointsConvenient, FittingCurveCoefficients &coefficients, double &mse, double &rms, double &rSquared, int significantDigits)
Compute the curve fit and the statistics for that curve fit.
This class does the math to compute statistics for FittingWindow.
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
Definition: MainWindow.h:91