Engauge Digitizer  2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
TestFitting.cpp
Go to the documentation of this file.
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;
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
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,
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;
120 
121  // Create the points according to y = 0 + 1 * (x + 1) (x + 2) ... (x + order), with y=0 for order=0
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,
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 {
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 }
const bool NO_GNUPLOT_LOG_FILES
Definition: TestExport.cpp:29
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.
const int MAX_POLYNOMIAL_ORDER
QList< QPointF > FittingPointsConvenient
Array of (x,y) points in graph coordinates.
const bool NO_REGRESSION_IMPORT
Definition: TestExport.cpp:30
const int NOMINAL_SIGNIFICANT_DIGITS
Definition: TestFitting.cpp:14
const int NOMINAL_ORDER
Definition: TestFitting.cpp:13
const QString NO_EXTRACT_IMAGE_EXTENSION
Definition: TestExport.cpp:34
void initializeLogging(const QString &name, const QString &filename, bool isDebug)
Definition: Logger.cpp:21
const QStringList NO_LOAD_STARTUP_FILES
Definition: TestExport.cpp:36
const QString NO_REGRESSION_OPEN_FILE
Definition: TestExport.cpp:28
const bool NO_EXPORT_ONLY
Definition: TestExport.cpp:32
const QStringList NO_COMMAND_LINE
Definition: TestExport.cpp:37
const bool NO_DROP_REGRESSION
Definition: TestExport.cpp:24
const double EPSILON
QVector< double > FittingCurveCoefficients
Coefficients x0, x1, ... in y = a0 + a1 * x + a2 * x^2 + ...
const QString NO_ERROR_REPORT_LOG_FILE
Definition: TestExport.cpp:27
const bool DEBUG_FLAG
Definition: TestExport.cpp:35
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
const bool NO_EXTRACT_IMAGE_ONLY
Definition: TestExport.cpp:33