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 bool NO_DROP_REGRESSION = false;
156  const QString NO_ERROR_REPORT_LOG_FILE;
157  const QString NO_REGRESSION_OPEN_FILE;
158  const bool NO_GNUPLOT_LOG_FILES = false;
159  const bool NO_REGRESSION_IMPORT = false;
160  const bool NO_RESET = false;
161  const bool NO_EXPORT_ONLY = false;
162  const bool NO_EXTRACT_IMAGE_ONLY = false;
163  const QString NO_EXTRACT_IMAGE_EXTENSION;
164  const bool DEBUG_FLAG = false;
165  const QStringList NO_LOAD_STARTUP_FILES;
166  const QStringList NO_COMMAND_LINE;
167 
168  initializeLogging ("engauge_test",
169  "engauge_test.log",
170  DEBUG_FLAG);
171 
172  MainWindow w (NO_ERROR_REPORT_LOG_FILE,
173  NO_REGRESSION_OPEN_FILE,
174  NO_DROP_REGRESSION,
175  NO_REGRESSION_IMPORT,
176  NO_GNUPLOT_LOG_FILES,
177  NO_RESET,
178  NO_EXPORT_ONLY,
179  NO_EXTRACT_IMAGE_ONLY,
180  NO_EXTRACT_IMAGE_EXTENSION,
181  NO_LOAD_STARTUP_FILES,
182  NO_COMMAND_LINE);
183  w.show ();
184 }
185 
186 int TestFitting::orderReducedVersusOrderAndSignificantDigits (int order,
187  int significantDigits) const
188 {
189  FittingPointsConvenient points;
190  FittingCurveCoefficients coefficients (MAX_POLYNOMIAL_ORDER + 1);
191 
192  // Hyperbola points
193  FittingStatistics fittingStatistics;
194  for (double x = 1; x <= 10; x += 1) {
195  double y = 100.0 / x;
196  points.append (QPointF (x, y));
197  }
198 
199  fittingStatistics.calculateCurveFit (order,
200  points,
201  coefficients,
202  significantDigits);
203 
204  // Find first nonzero coefficient. Two cases for 0th order are y<>0 (not all coefficients are zero)
205  // and y=0 (all coefficients are zero). In all other cases the order is the highest nonzero coefficient
206  int orderReduced;
207  for (orderReduced = MAX_POLYNOMIAL_ORDER; orderReduced > 0; orderReduced--) {
208  if (coefficients [orderReduced] != 0) {
209  return orderReduced;
210  }
211  }
212 
213  return orderReduced;
214 }
215 
216 void TestFitting::testFunctionExactFit01 ()
217 {
218  QVERIFY (generalFunctionTest (0, 1));
219 }
220 
221 void TestFitting::testFunctionExactFit12 ()
222 {
223  QVERIFY (generalFunctionTest (1, 2));
224 }
225 
226 void TestFitting::testFunctionExactFit23 ()
227 {
228  QVERIFY (generalFunctionTest (2, 3));
229 }
230 
231 void TestFitting::testFunctionExactFit34 ()
232 {
233  QVERIFY (generalFunctionTest (3, 4));
234 }
235 
236 void TestFitting::testFunctionOverfit11 ()
237 {
238  QVERIFY (generalFunctionTest (1, 1));
239 }
240 
241 void TestFitting::testFunctionOverfit22 ()
242 {
243  QVERIFY (generalFunctionTest (2, 2));
244 }
245 
246 void TestFitting::testFunctionOverfit33 ()
247 {
248  QVERIFY (generalFunctionTest (3, 3));
249 }
250 
251 void TestFitting::testFunctionOverfit44 ()
252 {
253  QVERIFY (generalFunctionTest (4, 4));
254 }
255 
256 void TestFitting::testFunctionUnderfit02 ()
257 {
258  QVERIFY (generalFunctionTest (0, 2));
259 }
260 
261 void TestFitting::testFunctionUnderfit13 ()
262 {
263  QVERIFY (generalFunctionTest (1, 3));
264 }
265 
266 void TestFitting::testFunctionUnderfit24 ()
267 {
268  QVERIFY (generalFunctionTest (2, 4));
269 }
270 
271 void TestFitting::testFunctionUnderfit35 ()
272 {
273  QVERIFY (generalFunctionTest (3, 5));
274 }
275 
276 void TestFitting::testNonFunction ()
277 {
278  QVERIFY (generalNonFunctionTest ());
279 }
280 
281 void TestFitting::testOrderReduced3 ()
282 {
283  QVERIFY (orderReducedVersusOrderAndSignificantDigits (3, NOMINAL_SIGNIFICANT_DIGITS) == 3);
284 }
285 
286 void TestFitting::testOrderReduced4 ()
287 {
288  QVERIFY (orderReducedVersusOrderAndSignificantDigits (4, NOMINAL_SIGNIFICANT_DIGITS) == 4);
289 }
290 
291 void TestFitting::testOrderReduced5 ()
292 {
293  QVERIFY (orderReducedVersusOrderAndSignificantDigits (5, NOMINAL_SIGNIFICANT_DIGITS) == 5);
294 }
295 
296 void TestFitting::testOrderReduced6 ()
297 {
298  QVERIFY (orderReducedVersusOrderAndSignificantDigits (6, NOMINAL_SIGNIFICANT_DIGITS) == 6);
299 }
300 
301 void TestFitting::testSignificantDigits3 ()
302 {
303  QVERIFY (orderReducedVersusOrderAndSignificantDigits (NOMINAL_ORDER, 3) == NOMINAL_ORDER);
304 }
305 
306 void TestFitting::testSignificantDigits4 ()
307 {
308  QVERIFY (orderReducedVersusOrderAndSignificantDigits (NOMINAL_ORDER, 4) == NOMINAL_ORDER);
309 }
310 
311 void TestFitting::testSignificantDigits5 ()
312 {
313  QVERIFY (orderReducedVersusOrderAndSignificantDigits (NOMINAL_ORDER, 5) == NOMINAL_ORDER);
314 }
315 
316 void TestFitting::testSignificantDigits6 ()
317 {
318  QVERIFY (orderReducedVersusOrderAndSignificantDigits (NOMINAL_ORDER, 6) == NOMINAL_ORDER);
319 }
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