File indexing completed on 2024-04-28 03:48:04

0001 /*
0002     File                 : FitTest.cpp
0003     Project              : LabPlot
0004     Description          : Tests for data fitting
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2017 Alexander Semke <alexander.semke@web.de>
0007     SPDX-FileCopyrightText: 2018-2022 Stefan Gerlach <stefan.gerlach@uni.kn>
0008 
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 
0012 #include "FitTest.h"
0013 #include "backend/core/AbstractAspect.h"
0014 #include "backend/core/AbstractColumn.h"
0015 #include "backend/core/Project.h"
0016 #include "backend/core/column/Column.h"
0017 #include "backend/datasources/filters/AsciiFilter.h"
0018 #include "backend/spreadsheet/Spreadsheet.h"
0019 #include "backend/worksheet/Worksheet.h"
0020 #include "backend/worksheet/plots/cartesian/Histogram.h"
0021 #include "backend/worksheet/plots/cartesian/XYFitCurve.h"
0022 
0023 #include "backend/nsl/nsl_sf_stats.h"
0024 #include "backend/nsl/nsl_stats.h"
0025 
0026 // ##############################################################################
0027 // #################  linear regression with NIST datasets ######################
0028 // ##############################################################################
0029 void FitTest::testLinearNorris() {
0030     // NIST data for Norris dataset
0031     QVector<double> xData = {0.2,   337.4, 118.2, 884.6, 10.1,  226.5, 666.3, 996.3, 448.6, 777.0, 558.2, 0.4,   0.6,  775.5, 666.9, 338.0, 447.5, 11.6,
0032                              556.0, 228.1, 995.8, 887.6, 120.2, 0.3,   0.3,   556.8, 339.1, 887.2, 999.0, 779.0, 11.1, 118.3, 229.2, 669.1, 448.9, 0.5};
0033     QVector<double> yData = {0.1,   338.8, 118.1, 888.0, 9.2,   228.1, 668.5, 998.5, 449.1, 778.9, 559.2, 0.3,   0.1,  778.1, 668.8, 339.3, 448.9, 10.8,
0034                              557.7, 228.3, 998.0, 888.8, 119.6, 0.3,   0.6,   557.6, 339.3, 888.0, 998.5, 778.9, 10.2, 117.6, 228.9, 668.4, 449.2, 0.2};
0035 
0036     // data source columns
0037     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
0038     xDataColumn.replaceValues(0, xData);
0039 
0040     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
0041     yDataColumn.replaceValues(0, yData);
0042 
0043     XYFitCurve fitCurve(QStringLiteral("fit"));
0044     fitCurve.setXDataColumn(&xDataColumn);
0045     fitCurve.setYDataColumn(&yDataColumn);
0046 
0047     // prepare the fit
0048     XYFitCurve::FitData fitData = fitCurve.fitData();
0049     fitData.modelCategory = nsl_fit_model_basic;
0050     fitData.modelType = nsl_fit_model_polynomial;
0051     fitData.degree = 1;
0052     XYFitCurve::initFitData(fitData);
0053     fitCurve.setFitData(fitData);
0054 
0055     // perform the fit
0056     fitCurve.recalculate();
0057     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
0058 
0059     // check the results
0060     QCOMPARE(fitResult.available, true);
0061     QCOMPARE(fitResult.valid, true);
0062 
0063     const int np = fitData.paramNames.size();
0064     QCOMPARE(np, 2);
0065 
0066     QCOMPARE(fitResult.paramValues.at(0), -0.262323073774029);
0067     QCOMPARE(fitResult.errorValues.at(0), 0.232818234301152);
0068     QCOMPARE(fitResult.paramValues.at(1), 1.00211681802045);
0069     QCOMPARE(fitResult.errorValues.at(1), 0.429796848199937e-3);
0070 
0071     QCOMPARE(fitResult.rsd, 0.884796396144373);
0072     QCOMPARE(fitResult.rsquare, 0.999993745883712);
0073     QCOMPARE(fitResult.sse, 26.6173985294224);
0074     QCOMPARE(fitResult.rms, 0.782864662630069);
0075     DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 5436385.54083098
0076     FuzzyCompare(fitResult.fdist_F, 5436385.54079785, 1.e-9);
0077 }
0078 
0079 void FitTest::testLinearPontius() {
0080     // NIST data for Pontius dataset
0081     QVector<int> xData = {150000,  300000,  450000,  600000,  750000,  900000,  1050000, 1200000, 1350000, 1500000, 1650000, 1800000, 1950000, 2100000,
0082                           2250000, 2400000, 2550000, 2700000, 2850000, 3000000, 150000,  300000,  450000,  600000,  750000,  900000,  1050000, 1200000,
0083                           1350000, 1500000, 1650000, 1800000, 1950000, 2100000, 2250000, 2400000, 2550000, 2700000, 2850000, 3000000};
0084     QVector<double> yData = {.11019,  .21956,  .32949,  .43899,  .54803,  .65694,  .76562,  .87487,  .98292,  1.09146, 1.20001, 1.30822, 1.41599, 1.52399,
0085                              1.63194, 1.73947, 1.84646, 1.95392, 2.06128, 2.16844, .11052,  .22018,  .32939,  .43886,  .54798,  .65739,  .76596,  .87474,
0086                              .98300,  1.09150, 1.20004, 1.30818, 1.41613, 1.52408, 1.63159, 1.73965, 1.84696, 1.95445, 2.06177, 2.16829};
0087 
0088     // data source columns
0089     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Integer);
0090     xDataColumn.replaceInteger(0, xData);
0091 
0092     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
0093     yDataColumn.replaceValues(0, yData);
0094 
0095     XYFitCurve fitCurve(QStringLiteral("fit"));
0096     fitCurve.setXDataColumn(&xDataColumn);
0097     fitCurve.setYDataColumn(&yDataColumn);
0098 
0099     // prepare the fit
0100     XYFitCurve::FitData fitData = fitCurve.fitData();
0101     fitData.modelCategory = nsl_fit_model_basic;
0102     fitData.modelType = nsl_fit_model_polynomial;
0103     fitData.degree = 2;
0104     XYFitCurve::initFitData(fitData);
0105     fitCurve.setFitData(fitData);
0106 
0107     // perform the fit
0108     fitCurve.recalculate();
0109     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
0110 
0111     // check the results
0112     QCOMPARE(fitResult.available, true);
0113     QCOMPARE(fitResult.valid, true);
0114 
0115     const int np = fitData.paramNames.size();
0116     QCOMPARE(np, 3);
0117 
0118     QCOMPARE(fitResult.paramValues.at(0), 0.673565789473684e-3);
0119     QCOMPARE(fitResult.errorValues.at(0), 0.107938612033077e-3);
0120     QCOMPARE(fitResult.paramValues.at(1), 0.732059160401003e-6);
0121     QCOMPARE(fitResult.errorValues.at(1), 0.157817399981659e-9);
0122     QCOMPARE(fitResult.paramValues.at(2), -0.316081871345029e-14);
0123     QCOMPARE(fitResult.errorValues.at(2), 0.486652849992036e-16);
0124 
0125     QCOMPARE(fitResult.rsd, 0.205177424076185e-3);
0126     QCOMPARE(fitResult.rsquare, 0.999999900178537);
0127     QCOMPARE(fitResult.sse, 0.155761768796992e-5);
0128     QCOMPARE(fitResult.rms, 0.420977753505385e-7);
0129     DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 185330865.884471
0130     FuzzyCompare(fitResult.fdist_F, 185330865.995752, 1.e-9);
0131 }
0132 
0133 void FitTest::testLinearNoInt1() {
0134     // NIST data for NoInt1 dataset
0135     QVector<int> xData = {60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70};
0136     QVector<int> yData = {130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140};
0137 
0138     // data source columns
0139     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Integer);
0140     xDataColumn.replaceInteger(0, xData);
0141 
0142     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Integer);
0143     yDataColumn.replaceInteger(0, yData);
0144 
0145     XYFitCurve fitCurve(QStringLiteral("fit"));
0146     fitCurve.setXDataColumn(&xDataColumn);
0147     fitCurve.setYDataColumn(&yDataColumn);
0148 
0149     // prepare the fit
0150     XYFitCurve::FitData fitData = fitCurve.fitData();
0151     fitData.modelCategory = nsl_fit_model_custom;
0152     XYFitCurve::initFitData(fitData);
0153     fitData.model = QStringLiteral("b1*x");
0154     fitData.paramNames << QStringLiteral("b1");
0155     const int np = fitData.paramNames.size();
0156     fitData.paramStartValues << 1.;
0157     fitData.paramLowerLimits << -std::numeric_limits<double>::max();
0158     fitData.paramUpperLimits << std::numeric_limits<double>::max();
0159     // fitData.eps = 1.e-15;
0160     fitCurve.setFitData(fitData);
0161 
0162     // perform the fit
0163     fitCurve.recalculate();
0164     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
0165 
0166     // check the results
0167     QCOMPARE(fitResult.available, true);
0168     QCOMPARE(fitResult.valid, true);
0169 
0170     QCOMPARE(np, 1);
0171 
0172     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 2.07438016513166
0173     FuzzyCompare(fitResult.paramValues.at(0), 2.07438016528926, 1.e-9);
0174     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 0.0165289256079047
0175     FuzzyCompare(fitResult.errorValues.at(0), 0.165289256198347e-1, 1.e-9);
0176 
0177     QCOMPARE(fitResult.rsd, 3.56753034006338);
0178     QCOMPARE(fitResult.sse, 127.272727272727);
0179     QCOMPARE(fitResult.rms, 12.7272727272727);
0180     QCOMPARE(fitResult.rsquare, 0.999365492298663);
0181     DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 15750.2500000027
0182     QCOMPARE(fitResult.fdist_F, 15750.25);
0183 }
0184 
0185 void FitTest::testLinearNoInt1_2() {
0186     // NIST data for NoInt1 dataset
0187     QVector<int> xData = {60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70};
0188     QVector<int> yData = {130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140};
0189 
0190     // data source columns
0191     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Integer);
0192     xDataColumn.replaceInteger(0, xData);
0193 
0194     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Integer);
0195     yDataColumn.replaceInteger(0, yData);
0196 
0197     XYFitCurve fitCurve(QStringLiteral("fit"));
0198     fitCurve.setXDataColumn(&xDataColumn);
0199     fitCurve.setYDataColumn(&yDataColumn);
0200 
0201     // prepare the fit
0202     XYFitCurve::FitData fitData = fitCurve.fitData();
0203     fitData.modelCategory = nsl_fit_model_basic;
0204     fitData.modelType = nsl_fit_model_polynomial;
0205     fitData.degree = 1;
0206     XYFitCurve::initFitData(fitData);
0207     fitData.paramStartValues[0] = 0;
0208     fitData.paramFixed[0] = true;
0209     fitCurve.setFitData(fitData);
0210 
0211     // perform the fit
0212     fitCurve.recalculate();
0213     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
0214 
0215     // check the results
0216     QCOMPARE(fitResult.available, true);
0217     QCOMPARE(fitResult.valid, true);
0218 
0219     const int np = fitData.paramNames.size();
0220     QCOMPARE(np, 2);
0221 
0222     QCOMPARE(fitResult.paramValues.at(0), 0.);
0223     QCOMPARE(fitResult.paramValues.at(1), 2.07438016528926);
0224     QCOMPARE(fitResult.errorValues.at(1), 0.165289256198347e-1);
0225 
0226     QCOMPARE(fitResult.rsd, 3.56753034006338);
0227     QCOMPARE(fitResult.sse, 127.272727272727);
0228     QCOMPARE(fitResult.rms, 12.7272727272727);
0229     QCOMPARE(fitResult.rsquare, 0.999365492298663);
0230     DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 15760.25
0231     QCOMPARE(fitResult.fdist_F, 15750.25);
0232 }
0233 
0234 void FitTest::testLinearNoInt2() {
0235     // NIST data for NoInt2 dataset
0236     QVector<int> xData = {4, 5, 6};
0237     QVector<int> yData = {3, 4, 4};
0238 
0239     // data source columns
0240     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Integer);
0241     xDataColumn.replaceInteger(0, xData);
0242 
0243     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Integer);
0244     yDataColumn.replaceInteger(0, yData);
0245 
0246     XYFitCurve fitCurve(QStringLiteral("fit"));
0247     fitCurve.setXDataColumn(&xDataColumn);
0248     fitCurve.setYDataColumn(&yDataColumn);
0249 
0250     // prepare the fit
0251     XYFitCurve::FitData fitData = fitCurve.fitData();
0252     fitData.modelCategory = nsl_fit_model_custom;
0253     XYFitCurve::initFitData(fitData);
0254     fitData.model = QStringLiteral("c * x");
0255     fitData.paramNames << QStringLiteral("c");
0256     const int np = fitData.paramNames.size();
0257     fitData.paramStartValues << 1.;
0258     fitData.paramLowerLimits << -std::numeric_limits<double>::max();
0259     fitData.paramUpperLimits << std::numeric_limits<double>::max();
0260     // fitData.eps = 1.e-15;
0261     fitCurve.setFitData(fitData);
0262 
0263     // perform the fit
0264     fitCurve.recalculate();
0265     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
0266 
0267     // check the results
0268     QCOMPARE(fitResult.available, true);
0269     QCOMPARE(fitResult.valid, true);
0270 
0271     QCOMPARE(np, 1);
0272 
0273     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 0.727272727152573
0274     FuzzyCompare(fitResult.paramValues.at(0), 0.727272727272727, 1.e-9);
0275     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 0.0420827316561797
0276     FuzzyCompare(fitResult.errorValues.at(0), 0.420827318078432E-01, 1.e-8);
0277 
0278     QCOMPARE(fitResult.rsd, 0.369274472937998);
0279     QCOMPARE(fitResult.sse, 0.272727272727273);
0280     QCOMPARE(fitResult.rms, 0.136363636363636);
0281     // can not detect that intercept is zero for a custom linear model
0282     DEBUG(std::setprecision(15) << fitResult.rsquare); // result: 0.590909090909091
0283     //  QCOMPARE(fitResult.rsquare, 0.993348115299335);
0284     DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 2.88888888888889
0285     //  FuzzyCompare(fitResult.fdist_F, 298.666666666667, 1.);
0286 }
0287 
0288 void FitTest::testLinearNoInt2_2() {
0289     // NIST data for NoInt2 dataset
0290     QVector<int> xData = {4, 5, 6};
0291     QVector<int> yData = {3, 4, 4};
0292 
0293     // data source columns
0294     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Integer);
0295     xDataColumn.replaceInteger(0, xData);
0296 
0297     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Integer);
0298     yDataColumn.replaceInteger(0, yData);
0299 
0300     XYFitCurve fitCurve(QStringLiteral("fit"));
0301     fitCurve.setXDataColumn(&xDataColumn);
0302     fitCurve.setYDataColumn(&yDataColumn);
0303 
0304     // prepare the fit
0305     XYFitCurve::FitData fitData = fitCurve.fitData();
0306     fitData.modelCategory = nsl_fit_model_basic;
0307     fitData.modelType = nsl_fit_model_polynomial;
0308     fitData.degree = 1;
0309     XYFitCurve::initFitData(fitData);
0310     fitData.paramStartValues[0] = 0;
0311     fitData.paramFixed[0] = true;
0312     fitCurve.setFitData(fitData);
0313 
0314     // perform the fit
0315     fitCurve.recalculate();
0316     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
0317 
0318     // check the results
0319     QCOMPARE(fitResult.available, true);
0320     QCOMPARE(fitResult.valid, true);
0321 
0322     const int np = fitData.paramNames.size();
0323     QCOMPARE(np, 2);
0324 
0325     QCOMPARE(fitResult.paramValues.at(0), 0.);
0326     QCOMPARE(fitResult.paramValues.at(1), 0.727272727272727);
0327     QCOMPARE(fitResult.errorValues.at(1), 0.420827318078432e-1);
0328 
0329     QCOMPARE(fitResult.rsd, 0.369274472937998);
0330     QCOMPARE(fitResult.sse, 0.272727272727273);
0331     QCOMPARE(fitResult.rms, 0.136363636363636);
0332     QCOMPARE(fitResult.rsquare, 0.993348115299335);
0333     DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 300.666666666667
0334     QCOMPARE(fitResult.fdist_F, 298.666666666667);
0335 }
0336 
0337 void FitTest::testLinearFilip() {
0338     // NIST data for Filip dataset
0339     QVector<double> xData = {-6.860120914, -4.324130045, -4.358625055, -4.358426747, -6.955852379, -6.661145254, -6.355462942, -6.118102026, -7.115148017,
0340                              -6.815308569, -6.519993057, -6.204119983, -5.853871964, -6.109523091, -5.79832982,  -5.482672118, -5.171791386, -4.851705903,
0341                              -4.517126416, -4.143573228, -3.709075441, -3.499489089, -6.300769497, -5.953504836, -5.642065153, -5.031376979, -4.680685696,
0342                              -4.329846955, -3.928486195, -8.56735134,  -8.363211311, -8.107682739, -7.823908741, -7.522878745, -7.218819279, -6.920818754,
0343                              -6.628932138, -6.323946875, -5.991399828, -8.781464495, -8.663140179, -8.473531488, -8.247337057, -7.971428747, -7.676129393,
0344                              -7.352812702, -7.072065318, -6.774174009, -6.478861916, -6.159517513, -6.835647144, -6.53165267,  -6.224098421, -5.910094889,
0345                              -5.598599459, -5.290645224, -4.974284616, -4.64454848,  -4.290560426, -3.885055584, -3.408378962, -3.13200249,  -8.726767166,
0346                              -8.66695597,  -8.511026475, -8.165388579, -7.886056648, -7.588043762, -7.283412422, -6.995678626, -6.691862621, -6.392544977,
0347                              -6.067374056, -6.684029655, -6.378719832, -6.065855188, -5.752272167, -5.132414673, -4.811352704, -4.098269308, -3.66174277,
0348                              -3.2644011};
0349     QVector<double> yData = {0.8116, 0.9072, 0.9052, 0.9039, 0.8053, 0.8377, 0.8667, 0.8809, 0.7975, 0.8162, 0.8515, 0.8766, 0.8885, 0.8859,
0350                              0.8959, 0.8913, 0.8959, 0.8971, 0.9021, 0.909,  0.9139, 0.9199, 0.8692, 0.8872, 0.89,   0.891,  0.8977, 0.9035,
0351                              0.9078, 0.7675, 0.7705, 0.7713, 0.7736, 0.7775, 0.7841, 0.7971, 0.8329, 0.8641, 0.8804, 0.7668, 0.7633, 0.7678,
0352                              0.7697, 0.77,   0.7749, 0.7796, 0.7897, 0.8131, 0.8498, 0.8741, 0.8061, 0.846,  0.8751, 0.8856, 0.8919, 0.8934,
0353                              0.894,  0.8957, 0.9047, 0.9129, 0.9209, 0.9219, 0.7739, 0.7681, 0.7665, 0.7703, 0.7702, 0.7761, 0.7809, 0.7961,
0354                              0.8253, 0.8602, 0.8809, 0.8301, 0.8664, 0.8834, 0.8898, 0.8964, 0.8963, 0.9074, 0.9119, 0.9228};
0355 
0356     // data source columns
0357     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
0358     xDataColumn.replaceValues(0, xData);
0359 
0360     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
0361     yDataColumn.replaceValues(0, yData);
0362 
0363     XYFitCurve fitCurve(QStringLiteral("fit"));
0364     fitCurve.setXDataColumn(&xDataColumn);
0365     fitCurve.setYDataColumn(&yDataColumn);
0366 
0367     // prepare the fit
0368     XYFitCurve::FitData fitData = fitCurve.fitData();
0369     fitData.modelCategory = nsl_fit_model_basic;
0370     fitData.modelType = nsl_fit_model_polynomial;
0371     fitData.degree = 10;
0372     fitData.eps = 1.e-8;
0373     XYFitCurve::initFitData(fitData);
0374     const int np = fitData.paramNames.size();
0375     fitCurve.setFitData(fitData);
0376 
0377     // perform the fit
0378     fitCurve.recalculate();
0379     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
0380 
0381     // check the results
0382     QCOMPARE(fitResult.available, true);
0383     QCOMPARE(fitResult.valid, true);
0384 
0385     QCOMPARE(np, 11);
0386 
0387     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: -1467.48962615175
0388     FuzzyCompare(fitResult.paramValues.at(0), -1467.48961422980, 2.e-5);
0389     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 298.084524514884
0390     FuzzyCompare(fitResult.errorValues.at(0), 298.084530995537, 1.e-7);
0391     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: -2772.1796150428
0392     FuzzyCompare(fitResult.paramValues.at(1), -2772.17959193342, 2.e-5);
0393     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 559.779853249694
0394     FuzzyCompare(fitResult.errorValues.at(1), 559.779865474950, 1.e-7);
0395     DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: -2316.37110148409
0396     FuzzyCompare(fitResult.paramValues.at(2), -2316.37108160893, 2.e-5);
0397     DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: 466.477561928144
0398     FuzzyCompare(fitResult.errorValues.at(2), 466.477572127796, 1.e-7);
0399     DEBUG(std::setprecision(15) << fitResult.paramValues.at(3)); // result: -1127.97395097195
0400     FuzzyCompare(fitResult.paramValues.at(3), -1127.97394098372, 2.e-5);
0401     DEBUG(std::setprecision(15) << fitResult.errorValues.at(3)); // result: 227.204269523115
0402     FuzzyCompare(fitResult.errorValues.at(3), 227.204274477751, 1.e-6);
0403     DEBUG(std::setprecision(15) << fitResult.paramValues.at(4)); // result: -354.478236951913
0404     FuzzyCompare(fitResult.paramValues.at(4), -354.478233703349, 2.e-5);
0405     DEBUG(std::setprecision(15) << fitResult.errorValues.at(4)); // result: 71.6478645361214
0406     FuzzyCompare(fitResult.errorValues.at(4), 71.6478660875927, 1.e-7);
0407     DEBUG(std::setprecision(15) << fitResult.paramValues.at(5)); // result: -75.1242024539908
0408     FuzzyCompare(fitResult.paramValues.at(5), -75.1242017393757, 2.e-5);
0409     DEBUG(std::setprecision(15) << fitResult.errorValues.at(5)); // result: 15.289717547564
0410     FuzzyCompare(fitResult.errorValues.at(5), 15.2897178747400, 1.e-7);
0411     DEBUG(std::setprecision(15) << fitResult.paramValues.at(6)); // result: -10.875318143236
0412     FuzzyCompare(fitResult.paramValues.at(6), -10.8753180355343, 2.e-5);
0413     DEBUG(std::setprecision(15) << fitResult.errorValues.at(6)); // result: 2.23691155110776
0414     FuzzyCompare(fitResult.errorValues.at(6), 2.23691159816033, 1.e-7);
0415     DEBUG(std::setprecision(15) << fitResult.paramValues.at(7)); // result: -1.06221499687347
0416     FuzzyCompare(fitResult.paramValues.at(7), -1.06221498588947, 2.e-5);
0417     DEBUG(std::setprecision(15) << fitResult.errorValues.at(7)); // result: 0.221624317377432
0418     FuzzyCompare(fitResult.errorValues.at(7), 0.221624321934227, 1.e-7);
0419     DEBUG(std::setprecision(15) << fitResult.paramValues.at(8)); // result: -0.0670191161850038
0420     FuzzyCompare(fitResult.paramValues.at(8), -0.670191154593408E-01, 2.e-5);
0421     DEBUG(std::setprecision(15) << fitResult.errorValues.at(8)); // result: 0.0142363760310402
0422     FuzzyCompare(fitResult.errorValues.at(8), 0.142363763154724E-01, 1.e-7);
0423     DEBUG(std::setprecision(15) << fitResult.paramValues.at(9)); // result: -0.00246781081080665
0424     FuzzyCompare(fitResult.paramValues.at(9), -0.246781078275479E-02, 2.e-5);
0425     DEBUG(std::setprecision(15) << fitResult.errorValues.at(9)); // result: 0.000535617398555022
0426     FuzzyCompare(fitResult.errorValues.at(9), 0.535617408889821E-03, 1.e-7);
0427     DEBUG(std::setprecision(15) << fitResult.paramValues.at(10)); // result: -4.02962529900222e-05
0428     FuzzyCompare(fitResult.paramValues.at(10), -0.402962525080404E-04, 2.e-5);
0429     DEBUG(std::setprecision(15) << fitResult.errorValues.at(10)); // result: 8.96632820770946e-06
0430     FuzzyCompare(fitResult.errorValues.at(10), 0.896632837373868E-05, 1.e-7);
0431 
0432     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.00334801050105949
0433     FuzzyCompare(fitResult.rsd, 0.334801051324544E-02, 1.e-7);
0434     DEBUG(std::setprecision(15) << fitResult.rsquare); // result: 0.996727416209443
0435     FuzzyCompare(fitResult.rsquare, 0.996727416185620, 1.e-9);
0436     DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.00079585137637953
0437     FuzzyCompare(fitResult.sse, 0.795851382172941E-03, 1.e-7);
0438     DEBUG(std::setprecision(15) << fitResult.rms); // result: 1.12091743152047e-05
0439     FuzzyCompare(fitResult.rms, 0.112091743968020E-04, 1.e-7);
0440     DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 2162.43960297897
0441     FuzzyCompare(fitResult.fdist_F, 2162.43954511489, 1.e-7);
0442 }
0443 
0444 void FitTest::testLinearWampler1() {
0445     // NIST data for Wampler1 dataset
0446     QVector<int> xData = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
0447     QVector<int> yData = {1,      6,      63,     364,    1365,   3906,    9331,    19608,   37449,   66430,  111111,
0448                           177156, 271453, 402234, 579195, 813616, 1118481, 1508598, 2000719, 2613660, 3368421};
0449 
0450     // data source columns
0451     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Integer);
0452     xDataColumn.replaceInteger(0, xData);
0453 
0454     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Integer);
0455     yDataColumn.replaceInteger(0, yData);
0456 
0457     XYFitCurve fitCurve(QStringLiteral("fit"));
0458     fitCurve.setXDataColumn(&xDataColumn);
0459     fitCurve.setYDataColumn(&yDataColumn);
0460 
0461     // prepare the fit
0462     XYFitCurve::FitData fitData = fitCurve.fitData();
0463     fitData.modelCategory = nsl_fit_model_basic;
0464     fitData.modelType = nsl_fit_model_polynomial;
0465     fitData.degree = 5;
0466     XYFitCurve::initFitData(fitData);
0467     fitCurve.setFitData(fitData);
0468 
0469     // perform the fit
0470     fitCurve.recalculate();
0471     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
0472 
0473     // check the results
0474     QCOMPARE(fitResult.available, true);
0475     QCOMPARE(fitResult.valid, true);
0476 
0477     const int np = fitData.paramNames.size();
0478     QCOMPARE(np, 6);
0479 
0480     for (int i = 0; i < np; i++) {
0481         const double paramValue = fitResult.paramValues.at(i);
0482         const double errorValue = fitResult.errorValues.at(i);
0483         QCOMPARE(paramValue, 1.0);
0484         QCOMPARE(errorValue, 0.0);
0485     }
0486 
0487     QCOMPARE(fitResult.rsd, 0.0);
0488     QCOMPARE(fitResult.rsquare, 1.0);
0489     QCOMPARE(fitResult.sse, 0.0);
0490     QCOMPARE(fitResult.rms, 0.0);
0491     QVERIFY(std::isinf(fitResult.fdist_F));
0492 }
0493 
0494 void FitTest::testLinearWampler2() {
0495     // NIST data for Wampler2 dataset
0496     QVector<int> xData = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
0497     QVector<double> yData = {1.00000, 1.11111, 1.24992,  1.42753,  1.65984,  1.96875,  2.38336,  2.94117,  3.68928,  4.68559, 6.00000,
0498                              7.71561, 9.92992, 12.75603, 16.32384, 20.78125, 26.29536, 33.05367, 41.26528, 51.16209, 63.00000};
0499 
0500     // data source columns
0501     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Integer);
0502     xDataColumn.replaceInteger(0, xData);
0503 
0504     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
0505     yDataColumn.replaceValues(0, yData);
0506 
0507     XYFitCurve fitCurve(QStringLiteral("fit"));
0508     fitCurve.setXDataColumn(&xDataColumn);
0509     fitCurve.setYDataColumn(&yDataColumn);
0510 
0511     // prepare the fit
0512     XYFitCurve::FitData fitData = fitCurve.fitData();
0513     fitData.modelCategory = nsl_fit_model_basic;
0514     fitData.modelType = nsl_fit_model_polynomial;
0515     fitData.degree = 5;
0516     XYFitCurve::initFitData(fitData);
0517     fitCurve.setFitData(fitData);
0518 
0519     // perform the fit
0520     fitCurve.recalculate();
0521     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
0522 
0523     // check the results
0524     qDebug() << "STATUS " << fitResult.status;
0525     QCOMPARE(fitResult.available, true);
0526     QCOMPARE(fitResult.valid, true);
0527 
0528     const int np = fitData.paramNames.size();
0529     QCOMPARE(np, 6);
0530 
0531     for (int i = 0; i < np; i++) {
0532         DEBUG(std::setprecision(15) << fitResult.paramValues.at(i));
0533     }
0534     QCOMPARE(fitResult.paramValues.at(0), 1.0);
0535     QCOMPARE(fitResult.paramValues.at(1), 0.1);
0536     QCOMPARE(fitResult.paramValues.at(2), 0.01);
0537     QCOMPARE(fitResult.paramValues.at(3), 0.001);
0538     QCOMPARE(fitResult.paramValues.at(4), 0.0001);
0539     QCOMPARE(fitResult.paramValues.at(5), 0.00001);
0540     for (int i = 0; i < np; i++) {
0541         const double errorValue = fitResult.errorValues.at(i);
0542         DEBUG(std::setprecision(15) << errorValue); // max. result: 2.32794076549904e-15
0543         FuzzyCompare(errorValue, 0., 1.e-14);
0544     }
0545 
0546     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 2.32458538254974e-15
0547     FuzzyCompare(fitResult.rsd, 0., 1.e-14);
0548     QCOMPARE(fitResult.rsquare, 1.);
0549     DEBUG(std::setprecision(15) << fitResult.sse); // result: 8.1055458011459e-29
0550     FuzzyCompare(fitResult.sse, 0., 1.e-15);
0551     DEBUG(std::setprecision(15) << fitResult.rms); // result: 5.40369720076393e-30
0552     FuzzyCompare(fitResult.rms, 0., 1.e-15);
0553     DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 2.44385217688297e+32
0554     QVERIFY(fitResult.fdist_F > 1.e+32);
0555 }
0556 
0557 void FitTest::testLinearWampler3() {
0558     // NIST data for Wampler3 dataset
0559     QVector<int> xData = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
0560     QVector<double> yData = {760.,    -2042.,  2111.,   -1684.,  3888.,   1858.,    11379.,   17560.,   39287.,   64382.,  113159.,
0561                              175108., 273291., 400186., 581243., 811568., 1121004., 1506550., 2002767., 2611612., 3369180.};
0562 
0563     // data source columns
0564     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Integer);
0565     xDataColumn.replaceInteger(0, xData);
0566 
0567     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
0568     yDataColumn.replaceValues(0, yData);
0569 
0570     XYFitCurve fitCurve(QStringLiteral("fit"));
0571     fitCurve.setXDataColumn(&xDataColumn);
0572     fitCurve.setYDataColumn(&yDataColumn);
0573 
0574     // prepare the fit
0575     XYFitCurve::FitData fitData = fitCurve.fitData();
0576     fitData.modelCategory = nsl_fit_model_basic;
0577     fitData.modelType = nsl_fit_model_polynomial;
0578     fitData.degree = 5;
0579     XYFitCurve::initFitData(fitData);
0580     fitCurve.setFitData(fitData);
0581 
0582     // perform the fit
0583     fitCurve.recalculate();
0584     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
0585 
0586     // check the results
0587     QCOMPARE(fitResult.available, true);
0588     QCOMPARE(fitResult.valid, true);
0589 
0590     const int np = fitData.paramNames.size();
0591     QCOMPARE(np, 6);
0592 
0593     for (int i = 0; i < np; i++) {
0594         const double paramValue = fitResult.paramValues.at(i);
0595         QCOMPARE(paramValue, 1.0);
0596     }
0597     QCOMPARE(fitResult.errorValues.at(0), 2152.32624678170);
0598     QCOMPARE(fitResult.errorValues.at(1), 2363.55173469681);
0599     QCOMPARE(fitResult.errorValues.at(2), 779.343524331583);
0600     QCOMPARE(fitResult.errorValues.at(3), 101.475507550350);
0601     QCOMPARE(fitResult.errorValues.at(4), 5.64566512170752);
0602     QCOMPARE(fitResult.errorValues.at(5), 0.112324854679312);
0603 
0604     QCOMPARE(fitResult.rsd, 2360.14502379268);
0605     QCOMPARE(fitResult.rsquare, 0.999995559025820);
0606     QCOMPARE(fitResult.sse, 83554268.0000000);
0607     QCOMPARE(fitResult.rms, 5570284.53333333);
0608     DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 675524.458247789
0609     FuzzyCompare(fitResult.fdist_F, 675524.458240122, 1.e-7);
0610 }
0611 
0612 void FitTest::testLinearWampler4() {
0613     // NIST data for Wampler4 dataset
0614     QVector<int> xData = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
0615     QVector<int> yData = {75901,  -204794, 204863, -204436, 253665, -200894, 214131,  -185192, 221249,  -138370, 315911,
0616                           -27644, 455253,  197434, 783995,  608816, 1370781, 1303798, 2205519, 2408860, 3444321};
0617 
0618     // data source columns
0619     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Integer);
0620     xDataColumn.replaceInteger(0, xData);
0621 
0622     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Integer);
0623     yDataColumn.replaceInteger(0, yData);
0624 
0625     XYFitCurve fitCurve(QStringLiteral("fit"));
0626     fitCurve.setXDataColumn(&xDataColumn);
0627     fitCurve.setYDataColumn(&yDataColumn);
0628 
0629     // prepare the fit
0630     XYFitCurve::FitData fitData = fitCurve.fitData();
0631     fitData.modelCategory = nsl_fit_model_basic;
0632     fitData.modelType = nsl_fit_model_polynomial;
0633     fitData.degree = 5;
0634     XYFitCurve::initFitData(fitData);
0635     fitCurve.setFitData(fitData);
0636 
0637     // perform the fit
0638     fitCurve.recalculate();
0639     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
0640 
0641     // check the results
0642     QCOMPARE(fitResult.available, true);
0643     QCOMPARE(fitResult.valid, true);
0644 
0645     const int np = fitData.paramNames.size();
0646     QCOMPARE(np, 6);
0647 
0648     FuzzyCompare(fitResult.paramValues.at(0), 1.0, 3.e-9); // i386: 1.00000000223515
0649     FuzzyCompare(fitResult.paramValues.at(1), 1.0, 5.e-9); // i386: 0.999999995021441
0650     FuzzyCompare(fitResult.paramValues.at(2), 1.0, 2.e-9); // i386: 1.00000000188395
0651     FuzzyCompare(fitResult.paramValues.at(3), 1.0, 1.e-9); // i386: 0.999999999743725
0652     FuzzyCompare(fitResult.paramValues.at(4), 1.0, 2.e-11); // i386: 1.00000000001441
0653     FuzzyCompare(fitResult.paramValues.at(5), 1.0); // i386: 0.999999999999714
0654 
0655     QCOMPARE(fitResult.errorValues.at(0), 215232.624678170);
0656     QCOMPARE(fitResult.errorValues.at(1), 236355.173469681);
0657     QCOMPARE(fitResult.errorValues.at(2), 77934.3524331583);
0658     QCOMPARE(fitResult.errorValues.at(3), 10147.5507550350);
0659     QCOMPARE(fitResult.errorValues.at(4), 564.566512170752);
0660     QCOMPARE(fitResult.errorValues.at(5), 11.2324854679312);
0661 
0662     QCOMPARE(fitResult.rsd, 236014.502379268);
0663     QCOMPARE(fitResult.rsquare, 0.957478440825662);
0664     QCOMPARE(fitResult.sse, 835542680000.000);
0665     QCOMPARE(fitResult.rms, 55702845333.3333);
0666     DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 67.5524458240122
0667     QCOMPARE(fitResult.fdist_F, 67.5524458240122);
0668 }
0669 
0670 void FitTest::testLinearWampler5() {
0671     // NIST data for Wampler5 dataset
0672     QVector<int> xData = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
0673     QVector<int> yData = {7590001,   -20479994, 20480063,  -20479636, 25231365,  -20476094, 20489331,  -20460392, 18417449,  -20413570, 20591111,
0674                           -20302844, 18651453,  -20077766, 21059195,  -19666384, 26348481,  -18971402, 22480719,  -17866340, 10958421};
0675 
0676     // data source columns
0677     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Integer);
0678     xDataColumn.replaceInteger(0, xData);
0679 
0680     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Integer);
0681     yDataColumn.replaceInteger(0, yData);
0682 
0683     XYFitCurve fitCurve(QStringLiteral("fit"));
0684     fitCurve.setXDataColumn(&xDataColumn);
0685     fitCurve.setYDataColumn(&yDataColumn);
0686 
0687     // prepare the fit
0688     XYFitCurve::FitData fitData = fitCurve.fitData();
0689     fitData.modelCategory = nsl_fit_model_basic;
0690     fitData.modelType = nsl_fit_model_polynomial;
0691     fitData.degree = 5;
0692     XYFitCurve::initFitData(fitData);
0693     fitCurve.setFitData(fitData);
0694 
0695     // perform the fit
0696     fitCurve.recalculate();
0697     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
0698 
0699     // check the results
0700     QCOMPARE(fitResult.available, true);
0701     QCOMPARE(fitResult.valid, true);
0702 
0703     const int np = fitData.paramNames.size();
0704     QCOMPARE(np, 6);
0705 
0706     for (int i = 0; i < np; i++) {
0707         const double paramValue = fitResult.paramValues.at(i);
0708         DEBUG(std::setprecision(15) << paramValue);
0709         FuzzyCompare(paramValue, 1.0, 3.e-7);
0710     }
0711     QCOMPARE(fitResult.errorValues.at(0), 21523262.4678170);
0712     QCOMPARE(fitResult.errorValues.at(1), 23635517.3469681);
0713     QCOMPARE(fitResult.errorValues.at(2), 7793435.24331583);
0714     QCOMPARE(fitResult.errorValues.at(3), 1014755.07550350);
0715     QCOMPARE(fitResult.errorValues.at(4), 56456.6512170752);
0716     QCOMPARE(fitResult.errorValues.at(5), 1123.24854679312);
0717 
0718     QCOMPARE(fitResult.rsd, 23601450.2379268);
0719     QCOMPARE(fitResult.rsquare, 0.224668921574940E-02);
0720     QCOMPARE(fitResult.sse, 0.835542680000000E+16);
0721     QCOMPARE(fitResult.rms, 557028453333333.);
0722     DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 0.00675524458240069
0723     QCOMPARE(fitResult.fdist_F, 0.675524458240122E-02);
0724 }
0725 
0726 // taken from https://en.wikipedia.org/wiki/Ordinary_least_squares
0727 void FitTest::testLinearWP_OLS() {
0728     // data from  The World Almanac and Book of Facts, 1975
0729     QVector<double> xData = {1.47, 1.50, 1.52, 1.55, 1.57, 1.60, 1.63, 1.65, 1.68, 1.70, 1.73, 1.75, 1.78, 1.80, 1.83};
0730     QVector<double> yData = {52.21, 53.12, 54.48, 55.84, 57.20, 58.57, 59.93, 61.29, 63.11, 64.47, 66.28, 68.10, 69.92, 72.19, 74.46};
0731 
0732     // data source columns
0733     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
0734     xDataColumn.replaceValues(0, xData);
0735 
0736     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
0737     yDataColumn.replaceValues(0, yData);
0738 
0739     XYFitCurve fitCurve(QStringLiteral("fit"));
0740     fitCurve.setXDataColumn(&xDataColumn);
0741     fitCurve.setYDataColumn(&yDataColumn);
0742 
0743     // prepare the fit
0744     XYFitCurve::FitData fitData = fitCurve.fitData();
0745     fitData.modelCategory = nsl_fit_model_basic;
0746     fitData.modelType = nsl_fit_model_polynomial;
0747     fitData.degree = 2;
0748     XYFitCurve::initFitData(fitData);
0749     fitCurve.setFitData(fitData);
0750 
0751     // perform the fit
0752     fitCurve.recalculate();
0753     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
0754 
0755     // check the results
0756     QCOMPARE(fitResult.available, true);
0757     QCOMPARE(fitResult.valid, true);
0758 
0759     const int np = fitData.paramNames.size();
0760     QCOMPARE(np, 3);
0761 
0762     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 128.812803578436
0763     FuzzyCompare(fitResult.paramValues.at(0), 128.8128, 1.e-7);
0764     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 16.3082821390367
0765     FuzzyCompare(fitResult.errorValues.at(0), 16.3083, 1.e-5);
0766     DEBUG(std::setprecision(15) << fitResult.tdist_tValues.at(0)); // result: 7.89861264848368
0767     FuzzyCompare(fitResult.tdist_tValues.at(0), 7.8986, 1.e-5);
0768     DEBUG(std::setprecision(15) << fitResult.tdist_pValues.at(0)); // result: 4.28330815316414e-06
0769     FuzzyCompare(fitResult.tdist_pValues.at(0), 0., 1.e-5);
0770     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: -143.16202286476
0771     FuzzyCompare(fitResult.paramValues.at(1), -143.1620, 1.e-6);
0772     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 19.8331710430895
0773     FuzzyCompare(fitResult.errorValues.at(1), 19.8332, 1.e-5);
0774     DEBUG(std::setprecision(15) << fitResult.tdist_tValues.at(1)); // result: -7.21831231897945
0775     FuzzyCompare(fitResult.tdist_tValues.at(1), -7.2183, 1.e-5);
0776     DEBUG(std::setprecision(15) << fitResult.tdist_pValues.at(1)); // result: 1.05970640905074e-05
0777     FuzzyCompare(fitResult.tdist_pValues.at(1), 0., 2.e-5);
0778     DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: 61.9603254424724
0779     FuzzyCompare(fitResult.paramValues.at(2), 61.9603, 1.e-6);
0780     DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: 6.00842899301227
0781     FuzzyCompare(fitResult.errorValues.at(2), 6.0084, 1.e-5);
0782     DEBUG(std::setprecision(15) << fitResult.tdist_tValues.at(2)); // result: 10.3122339490958
0783     FuzzyCompare(fitResult.tdist_tValues.at(2), 10.3122, 1.e-5);
0784     DEBUG(std::setprecision(15) << fitResult.tdist_pValues.at(2)); // result: 2.56647515320682e-07
0785     FuzzyCompare(fitResult.tdist_pValues.at(2), 0., 1.e-6);
0786 
0787     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.25158650082898
0788     FuzzyCompare(fitResult.rsd, 0.2516, 1.e-4);
0789     DEBUG(std::setprecision(15) << fitResult.rsquare); // result: 0.998904558436583
0790     FuzzyCompare(fitResult.rsquare, 0.9989, 1.e-5);
0791     DEBUG(std::setprecision(15) << fitResult.rsquareAdj); // result: 0.99860580164656
0792     FuzzyCompare(fitResult.rsquareAdj, 0.9987, 1.e-4);
0793     DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.759549208792447
0794     FuzzyCompare(fitResult.sse, 0.7595, 1.e-4);
0795     //  QCOMPARE(fitResult.rms, ???);   // result: 0.0632958
0796     DEBUG(std::setprecision(15) << fitResult.chisq_p); // result: 0.999996987409119
0797     //  FuzzyCompare(fitResult.chisq_p, ???, 1.e-8);
0798     DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 5471.2433330734
0799     FuzzyCompare(fitResult.fdist_F, 5471.2, 1.e-5);
0800     DEBUG(std::setprecision(15) << fitResult.fdist_p); // result: 0.0
0801     QCOMPARE(fitResult.fdist_p, 0.0);
0802     DEBUG(std::setprecision(15) << fitResult.logLik); // result: 1.0890247702592
0803     FuzzyCompare(fitResult.logLik, 1.0890, 3.e-5);
0804     DEBUG(std::setprecision(15) << fitResult.aic); // result: 5.82195045948161
0805     // not reproducable
0806     //  FuzzyCompare(fitResult.aic, 0.2548, 2.e-6);
0807     DEBUG(std::setprecision(15) << fitResult.bic); // result: 8.65415126389045
0808     // not reproducable
0809     //  FuzzyCompare(fitResult.bic, 0.3964, 2.e-6);
0810 }
0811 
0812 // from http://sia.webpopix.org/polynomialRegression1.html
0813 void FitTest::testLinearR_lm2() {
0814     QVector<int> xData = {4,  4,  7,  7,  8,  9,  10, 10, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15,
0815                           15, 16, 16, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 20, 20, 20, 20, 20, 22, 23, 24, 24, 24, 24, 25};
0816     QVector<int> yData = {2,  10, 4,  22, 16, 10, 18, 26, 34, 17, 28, 14, 20, 24, 28, 26, 34, 34, 46, 26, 36, 60, 80, 20,  26,
0817                           54, 32, 40, 32, 40, 50, 42, 56, 76, 84, 36, 46, 68, 32, 48, 52, 56, 64, 66, 54, 70, 92, 93, 120, 85};
0818 
0819     // data source columns
0820     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Integer);
0821     xDataColumn.replaceInteger(0, xData);
0822 
0823     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Integer);
0824     yDataColumn.replaceInteger(0, yData);
0825 
0826     XYFitCurve fitCurve(QStringLiteral("fit"));
0827     fitCurve.setXDataColumn(&xDataColumn);
0828     fitCurve.setYDataColumn(&yDataColumn);
0829 
0830     // prepare the fit
0831     XYFitCurve::FitData fitData = fitCurve.fitData();
0832     fitData.modelCategory = nsl_fit_model_basic;
0833     fitData.modelType = nsl_fit_model_polynomial;
0834     fitData.degree = 2;
0835     XYFitCurve::initFitData(fitData);
0836     fitCurve.setFitData(fitData);
0837 
0838     // perform the fit
0839     fitCurve.recalculate();
0840     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
0841 
0842     // check the results
0843     QCOMPARE(fitResult.available, true);
0844     QCOMPARE(fitResult.valid, true);
0845 
0846     const int np = fitData.paramNames.size();
0847     QCOMPARE(np, 3);
0848 
0849     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 2.47013778506623
0850     FuzzyCompare(fitResult.paramValues.at(0), 2.47014, 1.e-6);
0851     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 14.8171647250237
0852     FuzzyCompare(fitResult.errorValues.at(0), 14.81716, 1.e-6);
0853     DEBUG(std::setprecision(15) << fitResult.tdist_tValues.at(0)); // result: 0.16670785746848
0854     FuzzyCompare(fitResult.tdist_tValues.at(0), 0.167, 2.e-3);
0855     DEBUG(std::setprecision(15) << fitResult.tdist_pValues.at(0)); // result: 0.868315075848582
0856     FuzzyCompare(fitResult.tdist_pValues.at(0), 0.868, 1.e-3);
0857     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.913287614242592
0858     FuzzyCompare(fitResult.paramValues.at(1), 0.91329, 1.e-5);
0859     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 2.03422044231195
0860     FuzzyCompare(fitResult.errorValues.at(1), 2.03422, 1.e-6);
0861     DEBUG(std::setprecision(15) << fitResult.tdist_tValues.at(1)); // result: 0.448961968548804
0862     FuzzyCompare(fitResult.tdist_tValues.at(1), 0.449, 1.e-4);
0863     DEBUG(std::setprecision(15) << fitResult.tdist_pValues.at(1)); // result: 0.655522449402813
0864     FuzzyCompare(fitResult.tdist_pValues.at(1), 0.656, 1.e-3);
0865     DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: 0.0999593020698437
0866     FuzzyCompare(fitResult.paramValues.at(2), 0.09996, 1.e-5);
0867     DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: 0.0659682106823392
0868     FuzzyCompare(fitResult.errorValues.at(2), 0.06597, 1.e-4);
0869     DEBUG(std::setprecision(15) << fitResult.tdist_tValues.at(2)); // result: 1.5152647166858
0870     FuzzyCompare(fitResult.tdist_tValues.at(2), 1.515, 1.e-3);
0871     DEBUG(std::setprecision(15) << fitResult.tdist_pValues.at(2)); // result: 0.136402432803739
0872     FuzzyCompare(fitResult.tdist_pValues.at(2), 0.136, 3.e-3);
0873 
0874     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 15.1760701243277
0875     FuzzyCompare(fitResult.rsd, 15.18, 1.e-3);
0876     DEBUG(std::setprecision(15) << fitResult.rsquare); // result: 0.66733081652621
0877     FuzzyCompare(fitResult.rsquare, 0.6673, 1.e-4);
0878     DEBUG(std::setprecision(15) << fitResult.rsquareAdj); // result: 0.645635000212702
0879     DEBUG(std::setprecision(15) << 1. - (1. - fitResult.rsquare) * (50. - 1.) / (50. - np)); // result: 0.65317468105924
0880     // reference calculates 1-(1-R^2)(n-1)/(n-p)
0881     FuzzyCompare(1. - (1. - fitResult.rsquare) * (50. - 1.) / (50. - np), 0.6532, 1.e-4);
0882     DEBUG(std::setprecision(15) << fitResult.sse); // result: 10824.71590767
0883     FuzzyCompare(fitResult.sse, 10825, 1.e-4);
0884     DEBUG(std::setprecision(15) << fitResult.rms); // result: 230.313104418511
0885     //  QCOMPARE(fitResult.rms, ???);
0886     DEBUG(std::setprecision(15) << fitResult.logLik); // result: -205.386034235309
0887     FuzzyCompare(fitResult.logLik, -205.386, 1.e-6);
0888     DEBUG(std::setprecision(15) << fitResult.chisq_p); // result:
0889     //  FuzzyCompare(fitResult.chisq_p, ???, 1.e-8);
0890     DEBUG(std::setprecision(15) << fitResult.fdist_F); // result:
0891     // reference calculates sst/rms/np
0892     DEBUG(std::setprecision(15) << fitResult.sst / fitResult.rms / np); // result: 47.0938320858956
0893     FuzzyCompare(fitResult.sst / fitResult.rms / np, 47.14, 1.e-3);
0894     DEBUG(std::setprecision(15) << fitResult.fdist_p); // result: 0
0895     QCOMPARE(fitResult.fdist_p, 0.); // exact: 5.852e-12
0896     DEBUG(std::setprecision(15) << fitResult.aic); // result: 418.772068470618
0897     FuzzyCompare(fitResult.aic, 418.7721, 1.e-7);
0898     DEBUG(std::setprecision(15) << fitResult.bic); // result: 426.42016049233
0899     FuzzyCompare(fitResult.bic, 426.4202, 1.e-7);
0900 }
0901 
0902 // ##############################################################################
0903 // #############  non-linear regression with NIST datasets  #####################
0904 // ##############################################################################
0905 
0906 void FitTest::testNonLinearMisra1a() {
0907     // NIST data for Misra1a dataset
0908     QVector<double> xData = {77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0};
0909     QVector<double> yData = {10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0};
0910 
0911     // data source columns
0912     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
0913     xDataColumn.replaceValues(0, xData);
0914 
0915     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
0916     yDataColumn.replaceValues(0, yData);
0917 
0918     XYFitCurve fitCurve(QStringLiteral("fit"));
0919     fitCurve.setXDataColumn(&xDataColumn);
0920     fitCurve.setYDataColumn(&yDataColumn);
0921 
0922     // prepare the fit
0923     XYFitCurve::FitData fitData = fitCurve.fitData();
0924     fitData.modelCategory = nsl_fit_model_custom;
0925     XYFitCurve::initFitData(fitData);
0926     fitData.model = QStringLiteral("b1*(1-exp(-b2*x))");
0927     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2");
0928     fitData.eps = 1.e-12;
0929     const int np = fitData.paramNames.size();
0930     fitData.paramStartValues << 500. << 0.0001;
0931     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max();
0932     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max();
0933     fitCurve.setFitData(fitData);
0934 
0935     // perform the fit
0936     fitCurve.recalculate();
0937     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
0938 
0939     // check the results
0940     QCOMPARE(fitResult.available, true);
0941     QCOMPARE(fitResult.valid, true);
0942 
0943     QCOMPARE(np, 2);
0944 
0945     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 238.942305251573
0946     FuzzyCompare(fitResult.paramValues.at(0), 2.3894212918E+02, 1.e-6);
0947     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 2.70651225218243
0948     FuzzyCompare(fitResult.errorValues.at(0), 2.7070075241E+00, 1.e-3);
0949     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000550155958419367
0950     FuzzyCompare(fitResult.paramValues.at(1), 5.5015643181E-04, 1.e-6);
0951     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 7.26565480949189e-06
0952     FuzzyCompare(fitResult.errorValues.at(1), 7.2668688436E-06, 1.e-3);
0953 
0954     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.101878763320394
0955     FuzzyCompare(fitResult.rsd, 1.0187876330E-01, 1.e-9);
0956     DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.124551388988316
0957     FuzzyCompare(fitResult.sse, 1.2455138894E-01, 1.e-9);
0958 }
0959 
0960 void FitTest::testNonLinearMisra1a_2() {
0961     // NIST data for Misra1a dataset
0962     QVector<double> xData = {77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0};
0963     QVector<double> yData = {10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0};
0964 
0965     // data source columns
0966     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
0967     xDataColumn.replaceValues(0, xData);
0968 
0969     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
0970     yDataColumn.replaceValues(0, yData);
0971 
0972     XYFitCurve fitCurve(QStringLiteral("fit"));
0973     fitCurve.setXDataColumn(&xDataColumn);
0974     fitCurve.setYDataColumn(&yDataColumn);
0975 
0976     // prepare the fit
0977     XYFitCurve::FitData fitData = fitCurve.fitData();
0978     fitData.modelCategory = nsl_fit_model_custom;
0979     XYFitCurve::initFitData(fitData);
0980     fitData.model = QStringLiteral("b1*(1-exp(-b2*x))");
0981     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2");
0982     fitData.eps = 1.e-12;
0983     const int np = fitData.paramNames.size();
0984     fitData.paramStartValues << 250. << 5.e-4;
0985     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max();
0986     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max();
0987     fitCurve.setFitData(fitData);
0988 
0989     // perform the fit
0990     fitCurve.recalculate();
0991     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
0992 
0993     // check the results
0994     QCOMPARE(fitResult.available, true);
0995     QCOMPARE(fitResult.valid, true);
0996 
0997     QCOMPARE(np, 2);
0998 
0999     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 238.942305251573
1000     FuzzyCompare(fitResult.paramValues.at(0), 2.3894212918E+02, 1.e-6);
1001     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 2.70651225218243
1002     FuzzyCompare(fitResult.errorValues.at(0), 2.7070075241E+00, 1.e-3);
1003     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000550155958419367
1004     FuzzyCompare(fitResult.paramValues.at(1), 5.5015643181E-04, 1.e-6);
1005     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 7.26565480949189e-06
1006     FuzzyCompare(fitResult.errorValues.at(1), 7.2668688436E-06, 1.e-3);
1007 
1008     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.101878763320394
1009     FuzzyCompare(fitResult.rsd, 1.0187876330E-01, 1.e-9);
1010     DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.124551388988316
1011     FuzzyCompare(fitResult.sse, 1.2455138894E-01, 1.e-9);
1012 }
1013 
1014 void FitTest::testNonLinearMisra1a_3() {
1015     // NIST data for Misra1a dataset
1016     QVector<double> xData = {77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0};
1017     QVector<double> yData = {10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0};
1018 
1019     // data source columns
1020     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
1021     xDataColumn.replaceValues(0, xData);
1022 
1023     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
1024     yDataColumn.replaceValues(0, yData);
1025 
1026     XYFitCurve fitCurve(QStringLiteral("fit"));
1027     fitCurve.setXDataColumn(&xDataColumn);
1028     fitCurve.setYDataColumn(&yDataColumn);
1029 
1030     // prepare the fit
1031     XYFitCurve::FitData fitData = fitCurve.fitData();
1032     fitData.modelCategory = nsl_fit_model_custom;
1033     XYFitCurve::initFitData(fitData);
1034     fitData.model = QStringLiteral("b1*(1-exp(-b2*x))");
1035     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2");
1036     fitData.eps = 1.e-12;
1037     const int np = fitData.paramNames.size();
1038     fitData.paramStartValues << 2.3894212918E+02 << 5.5015643181E-04;
1039     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max();
1040     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max();
1041     fitCurve.setFitData(fitData);
1042 
1043     // perform the fit
1044     fitCurve.recalculate();
1045     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
1046 
1047     // check the results
1048     QCOMPARE(fitResult.available, true);
1049     QCOMPARE(fitResult.valid, true);
1050 
1051     QCOMPARE(np, 2);
1052 
1053     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 238.942305251573
1054     FuzzyCompare(fitResult.paramValues.at(0), 2.3894212918E+02, 1.e-6);
1055     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 2.70651225218243
1056     FuzzyCompare(fitResult.errorValues.at(0), 2.7070075241E+00, 1.e-3);
1057     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000550155958419367
1058     FuzzyCompare(fitResult.paramValues.at(1), 5.5015643181E-04, 1.e-6);
1059     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 7.26565480949189e-06
1060     FuzzyCompare(fitResult.errorValues.at(1), 7.2668688436E-06, 1.e-3);
1061 
1062     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.101878763320394
1063     FuzzyCompare(fitResult.rsd, 1.0187876330E-01, 1.e-9);
1064     DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.124551388988316
1065     FuzzyCompare(fitResult.sse, 1.2455138894E-01, 1.e-9);
1066 }
1067 
1068 void FitTest::testNonLinearMisra1b() {
1069     // NIST data for Misra1b dataset
1070     QVector<double> xData = {77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0};
1071     QVector<double> yData = {10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0};
1072 
1073     // data source columns
1074     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
1075     xDataColumn.replaceValues(0, xData);
1076 
1077     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
1078     yDataColumn.replaceValues(0, yData);
1079 
1080     XYFitCurve fitCurve(QStringLiteral("fit"));
1081     fitCurve.setXDataColumn(&xDataColumn);
1082     fitCurve.setYDataColumn(&yDataColumn);
1083 
1084     // prepare the fit
1085     XYFitCurve::FitData fitData = fitCurve.fitData();
1086     fitData.modelCategory = nsl_fit_model_custom;
1087     XYFitCurve::initFitData(fitData);
1088     fitData.model = QStringLiteral("b1*(1-1/(1+b2*x/2)^2)");
1089     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2");
1090     fitData.eps = 1.e-12;
1091     const int np = fitData.paramNames.size();
1092     fitData.paramStartValues << 500. << 0.0001;
1093     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max();
1094     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max();
1095     fitCurve.setFitData(fitData);
1096 
1097     // perform the fit
1098     fitCurve.recalculate();
1099     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
1100 
1101     // check the results
1102     QCOMPARE(fitResult.available, true);
1103     QCOMPARE(fitResult.valid, true);
1104 
1105     QCOMPARE(np, 2);
1106 
1107     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 337.99775062098
1108     FuzzyCompare(fitResult.paramValues.at(0), 3.3799746163E+02, 1.e-6);
1109     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 3.16358581006192
1110     FuzzyCompare(fitResult.errorValues.at(0), 3.1643950207E+00, 1.e-3);
1111     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000390390523934039
1112     FuzzyCompare(fitResult.paramValues.at(1), 3.9039091287E-04, 1.e-6);
1113     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 4.25373670682006e-06
1114     FuzzyCompare(fitResult.errorValues.at(1), 4.2547321834E-06, 1.e-3);
1115 
1116     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.0793014720259488
1117     FuzzyCompare(fitResult.rsd, 7.9301471998E-02, 1.e-9);
1118     DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.0754646815857881
1119     FuzzyCompare(fitResult.sse, 7.5464681533E-02, 1.e-9);
1120 }
1121 
1122 void FitTest::testNonLinearMisra1b_2() {
1123     // NIST data for Misra1b dataset
1124     QVector<double> xData = {77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0};
1125     QVector<double> yData = {10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0};
1126 
1127     // data source columns
1128     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
1129     xDataColumn.replaceValues(0, xData);
1130 
1131     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
1132     yDataColumn.replaceValues(0, yData);
1133 
1134     XYFitCurve fitCurve(QStringLiteral("fit"));
1135     fitCurve.setXDataColumn(&xDataColumn);
1136     fitCurve.setYDataColumn(&yDataColumn);
1137 
1138     // prepare the fit
1139     XYFitCurve::FitData fitData = fitCurve.fitData();
1140     fitData.modelCategory = nsl_fit_model_custom;
1141     XYFitCurve::initFitData(fitData);
1142     fitData.model = QStringLiteral("b1*(1-1/(1+b2*x/2)^2)");
1143     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2");
1144     fitData.eps = 1.e-12;
1145     const int np = fitData.paramNames.size();
1146     fitData.paramStartValues << 300. << 2.e-4;
1147     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max();
1148     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max();
1149     fitCurve.setFitData(fitData);
1150 
1151     // perform the fit
1152     fitCurve.recalculate();
1153     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
1154 
1155     // check the results
1156     QCOMPARE(fitResult.available, true);
1157     QCOMPARE(fitResult.valid, true);
1158 
1159     QCOMPARE(np, 2);
1160 
1161     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 337.99775062098
1162     FuzzyCompare(fitResult.paramValues.at(0), 3.3799746163E+02, 1.e-6);
1163     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 3.16358581006192
1164     FuzzyCompare(fitResult.errorValues.at(0), 3.1643950207E+00, 1.e-3);
1165     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000390390523934039
1166     FuzzyCompare(fitResult.paramValues.at(1), 3.9039091287E-04, 1.e-5);
1167     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 4.25373670682006e-06
1168     FuzzyCompare(fitResult.errorValues.at(1), 4.2547321834E-06, 1.e-3);
1169 
1170     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.0793014720259488
1171     FuzzyCompare(fitResult.rsd, 7.9301471998E-02, 1.e-9);
1172     DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.0754646815857881
1173     FuzzyCompare(fitResult.sse, 7.5464681533E-02, 1.e-9);
1174 }
1175 
1176 void FitTest::testNonLinearMisra1b_3() {
1177     // NIST data for Misra1b dataset
1178     QVector<double> xData = {77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0};
1179     QVector<double> yData = {10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0};
1180 
1181     // data source columns
1182     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
1183     xDataColumn.replaceValues(0, xData);
1184 
1185     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
1186     yDataColumn.replaceValues(0, yData);
1187 
1188     XYFitCurve fitCurve(QStringLiteral("fit"));
1189     fitCurve.setXDataColumn(&xDataColumn);
1190     fitCurve.setYDataColumn(&yDataColumn);
1191 
1192     // prepare the fit
1193     XYFitCurve::FitData fitData = fitCurve.fitData();
1194     fitData.modelCategory = nsl_fit_model_custom;
1195     XYFitCurve::initFitData(fitData);
1196     fitData.model = QStringLiteral("b1*(1-1/(1+b2*x/2)^2)");
1197     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2");
1198     fitData.eps = 1.e-12;
1199     const int np = fitData.paramNames.size();
1200     fitData.paramStartValues << 3.3799746163E+02 << 3.9039091287E-04;
1201     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max();
1202     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max();
1203     fitCurve.setFitData(fitData);
1204 
1205     // perform the fit
1206     fitCurve.recalculate();
1207     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
1208 
1209     // check the results
1210     QCOMPARE(fitResult.available, true);
1211     QCOMPARE(fitResult.valid, true);
1212 
1213     QCOMPARE(np, 2);
1214 
1215     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 337.99775062098
1216     FuzzyCompare(fitResult.paramValues.at(0), 3.3799746163E+02, 1.e-6);
1217     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 3.16358581006192
1218     FuzzyCompare(fitResult.errorValues.at(0), 3.1643950207E+00, 1.e-3);
1219     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000390390523934039
1220     FuzzyCompare(fitResult.paramValues.at(1), 3.9039091287E-04, 1.e-6);
1221     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 4.25373670682006e-06
1222     FuzzyCompare(fitResult.errorValues.at(1), 4.2547321834E-06, 1.e-3);
1223 
1224     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.0793014720259488
1225     FuzzyCompare(fitResult.rsd, 7.9301471998E-02, 1.e-9);
1226     DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.0754646815857881
1227     FuzzyCompare(fitResult.sse, 7.5464681533E-02, 1.e-9);
1228 }
1229 
1230 void FitTest::testNonLinearMisra1c() {
1231     // NIST data for Misra1c dataset
1232     QVector<double> xData = {77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0};
1233     QVector<double> yData = {10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0};
1234 
1235     // data source columns
1236     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
1237     xDataColumn.replaceValues(0, xData);
1238 
1239     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
1240     yDataColumn.replaceValues(0, yData);
1241 
1242     XYFitCurve fitCurve(QStringLiteral("fit"));
1243     fitCurve.setXDataColumn(&xDataColumn);
1244     fitCurve.setYDataColumn(&yDataColumn);
1245 
1246     // prepare the fit
1247     XYFitCurve::FitData fitData = fitCurve.fitData();
1248     fitData.modelCategory = nsl_fit_model_custom;
1249     XYFitCurve::initFitData(fitData);
1250     fitData.model = QStringLiteral("b1*(1-1/sqrt(1+2*b2*x))");
1251     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2");
1252     fitData.eps = 1.e-12;
1253     const int np = fitData.paramNames.size();
1254     fitData.paramStartValues << 500. << 0.0001;
1255     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max();
1256     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max();
1257     fitCurve.setFitData(fitData);
1258 
1259     // perform the fit
1260     fitCurve.recalculate();
1261     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
1262 
1263     // check the results
1264     QCOMPARE(fitResult.available, true);
1265     QCOMPARE(fitResult.valid, true);
1266 
1267     QCOMPARE(np, 2);
1268 
1269     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 636.427904767969
1270     FuzzyCompare(fitResult.paramValues.at(0), 6.3642725809E+02, 1.e-5);
1271     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 4.66168062054875
1272     FuzzyCompare(fitResult.errorValues.at(0), 4.6638326572E+00, 1.e-3);
1273     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000208136026420746
1274     FuzzyCompare(fitResult.paramValues.at(1), 2.0813627256E-04, 1.e-5);
1275     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 1.77209416674174e-06
1276     FuzzyCompare(fitResult.errorValues.at(1), 1.7728423155E-06, 1.e-3);
1277 
1278     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.0584286153041661
1279     FuzzyCompare(fitResult.rsd, 5.8428615257E-02, 1.e-9);
1280     DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.0409668370363468
1281     FuzzyCompare(fitResult.sse, 4.0966836971E-02, 1.e-8);
1282 }
1283 
1284 void FitTest::testNonLinearMisra1c_2() {
1285     // NIST data for Misra1c dataset
1286     QVector<double> xData = {77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0};
1287     QVector<double> yData = {10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0};
1288 
1289     // data source columns
1290     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
1291     xDataColumn.replaceValues(0, xData);
1292 
1293     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
1294     yDataColumn.replaceValues(0, yData);
1295 
1296     XYFitCurve fitCurve(QStringLiteral("fit"));
1297     fitCurve.setXDataColumn(&xDataColumn);
1298     fitCurve.setYDataColumn(&yDataColumn);
1299 
1300     // prepare the fit
1301     XYFitCurve::FitData fitData = fitCurve.fitData();
1302     fitData.modelCategory = nsl_fit_model_custom;
1303     XYFitCurve::initFitData(fitData);
1304     fitData.model = QStringLiteral("b1*(1-1/sqrt(1+2*b2*x))");
1305     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2");
1306     fitData.eps = 1.e-12;
1307     const int np = fitData.paramNames.size();
1308     fitData.paramStartValues << 600. << 2.e-4;
1309     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max();
1310     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max();
1311     fitCurve.setFitData(fitData);
1312 
1313     // perform the fit
1314     fitCurve.recalculate();
1315     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
1316 
1317     // check the results
1318     QCOMPARE(fitResult.available, true);
1319     QCOMPARE(fitResult.valid, true);
1320 
1321     QCOMPARE(np, 2);
1322 
1323     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 636.427904767969
1324     FuzzyCompare(fitResult.paramValues.at(0), 6.3642725809E+02, 1.e-5);
1325     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 4.66168062054875
1326     FuzzyCompare(fitResult.errorValues.at(0), 4.6638326572E+00, 1.e-3);
1327     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000208136026420746
1328     FuzzyCompare(fitResult.paramValues.at(1), 2.0813627256E-04, 1.e-5);
1329     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 1.77209416674174e-06
1330     FuzzyCompare(fitResult.errorValues.at(1), 1.7728423155E-06, 1.e-3);
1331 
1332     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.0584286153041661    (WIN: 0.0584286153252961)
1333     FuzzyCompare(fitResult.rsd, 5.8428615257E-02, 1.e-8);
1334     DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.0409668370363468
1335     FuzzyCompare(fitResult.sse, 4.0966836971E-02, 1.e-8);
1336 }
1337 
1338 void FitTest::testNonLinearMisra1c_3() {
1339     // NIST data for Misra1c dataset
1340     QVector<double> xData = {77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0};
1341     QVector<double> yData = {10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0};
1342 
1343     // data source columns
1344     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
1345     xDataColumn.replaceValues(0, xData);
1346 
1347     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
1348     yDataColumn.replaceValues(0, yData);
1349 
1350     XYFitCurve fitCurve(QStringLiteral("fit"));
1351     fitCurve.setXDataColumn(&xDataColumn);
1352     fitCurve.setYDataColumn(&yDataColumn);
1353 
1354     // prepare the fit
1355     XYFitCurve::FitData fitData = fitCurve.fitData();
1356     fitData.modelCategory = nsl_fit_model_custom;
1357     XYFitCurve::initFitData(fitData);
1358     fitData.model = QStringLiteral("b1*(1-1/sqrt(1+2*b2*x))");
1359     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2");
1360     fitData.eps = 1.e-12;
1361     const int np = fitData.paramNames.size();
1362     fitData.paramStartValues << 6.3642725809E+02 << 2.0813627256E-04;
1363     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max();
1364     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max();
1365     fitCurve.setFitData(fitData);
1366 
1367     // perform the fit
1368     fitCurve.recalculate();
1369     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
1370 
1371     // check the results
1372     QCOMPARE(fitResult.available, true);
1373     QCOMPARE(fitResult.valid, true);
1374 
1375     QCOMPARE(np, 2);
1376 
1377     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 636.427904767969
1378     FuzzyCompare(fitResult.paramValues.at(0), 6.3642725809E+02, 1.e-5);
1379     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 4.66168062054875
1380     FuzzyCompare(fitResult.errorValues.at(0), 4.6638326572E+00, 1.e-3);
1381     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000208136026420746
1382     FuzzyCompare(fitResult.paramValues.at(1), 2.0813627256E-04, 1.e-5);
1383     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 1.77209416674174e-06
1384     FuzzyCompare(fitResult.errorValues.at(1), 1.7728423155E-06, 1.e-3);
1385 
1386     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.0584286153041661
1387     FuzzyCompare(fitResult.rsd, 5.8428615257E-02, 1.e-9);
1388     DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.0409668370363468
1389     FuzzyCompare(fitResult.sse, 4.0966836971E-02, 1.e-8);
1390 }
1391 
1392 void FitTest::testNonLinearMisra1d() {
1393     // NIST data for Misra1d dataset
1394     QVector<double> xData = {77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0};
1395     QVector<double> yData = {10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0};
1396 
1397     // data source columns
1398     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
1399     xDataColumn.replaceValues(0, xData);
1400 
1401     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
1402     yDataColumn.replaceValues(0, yData);
1403 
1404     XYFitCurve fitCurve(QStringLiteral("fit"));
1405     fitCurve.setXDataColumn(&xDataColumn);
1406     fitCurve.setYDataColumn(&yDataColumn);
1407 
1408     // prepare the fit
1409     XYFitCurve::FitData fitData = fitCurve.fitData();
1410     fitData.modelCategory = nsl_fit_model_custom;
1411     XYFitCurve::initFitData(fitData);
1412     fitData.model = QStringLiteral("b1*b2*x/(1+b2*x)");
1413     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2");
1414     fitData.eps = 1.e-12;
1415     const int np = fitData.paramNames.size();
1416     fitData.paramStartValues << 500. << 0.0001;
1417     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max();
1418     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max();
1419     fitCurve.setFitData(fitData);
1420 
1421     // perform the fit
1422     fitCurve.recalculate();
1423     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
1424 
1425     // check the results
1426     QCOMPARE(fitResult.available, true);
1427     QCOMPARE(fitResult.valid, true);
1428 
1429     QCOMPARE(np, 2);
1430 
1431     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 437.370039987725
1432     FuzzyCompare(fitResult.paramValues.at(0), 4.3736970754E+02, 1.e-6);
1433     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 3.64772833062694
1434     FuzzyCompare(fitResult.errorValues.at(0), 3.6489174345E+00, 1.e-3);
1435     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000302272976784709
1436     FuzzyCompare(fitResult.paramValues.at(1), 3.0227324449E-04, 1.e-6);
1437     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 2.93256059733558e-06
1438     FuzzyCompare(fitResult.errorValues.at(1), 2.9334354479E-06, 1.e-3);
1439 
1440     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.068568272134244
1441     FuzzyCompare(fitResult.rsd, 6.8568272111E-02, 1.e-9);
1442     DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.056419295321709 (new: 0.0564192953613416)
1443     FuzzyCompare(fitResult.sse, 5.6419295283E-02, 1.e-8);
1444 }
1445 
1446 void FitTest::testNonLinearMisra1d_2() {
1447     // NIST data for Misra1d dataset
1448     QVector<double> xData = {77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0};
1449     QVector<double> yData = {10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0};
1450 
1451     // data source columns
1452     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
1453     xDataColumn.replaceValues(0, xData);
1454 
1455     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
1456     yDataColumn.replaceValues(0, yData);
1457 
1458     XYFitCurve fitCurve(QStringLiteral("fit"));
1459     fitCurve.setXDataColumn(&xDataColumn);
1460     fitCurve.setYDataColumn(&yDataColumn);
1461 
1462     // prepare the fit
1463     XYFitCurve::FitData fitData = fitCurve.fitData();
1464     fitData.modelCategory = nsl_fit_model_custom;
1465     XYFitCurve::initFitData(fitData);
1466     fitData.model = QStringLiteral("b1*b2*x/(1+b2*x)");
1467     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2");
1468     fitData.eps = 1.e-12;
1469     const int np = fitData.paramNames.size();
1470     fitData.paramStartValues << 450. << 3.e-4;
1471     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max();
1472     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max();
1473     fitCurve.setFitData(fitData);
1474 
1475     // perform the fit
1476     fitCurve.recalculate();
1477     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
1478 
1479     // check the results
1480     QCOMPARE(fitResult.available, true);
1481     QCOMPARE(fitResult.valid, true);
1482 
1483     QCOMPARE(np, 2);
1484 
1485     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 437.370039987725
1486     FuzzyCompare(fitResult.paramValues.at(0), 4.3736970754E+02, 1.e-5);
1487     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 3.64772833062694
1488     FuzzyCompare(fitResult.errorValues.at(0), 3.6489174345E+00, 1.e-3);
1489     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000302272976784709
1490     FuzzyCompare(fitResult.paramValues.at(1), 3.0227324449E-04, 1.e-5);
1491     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 2.93256059733558e-06
1492     FuzzyCompare(fitResult.errorValues.at(1), 2.9334354479E-06, 1.e-3);
1493 
1494     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.068568272134244
1495     FuzzyCompare(fitResult.rsd, 6.8568272111E-02, 1.e-9);
1496     DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.056419295321709
1497     FuzzyCompare(fitResult.sse, 5.6419295283E-02, 1.e-8);
1498 }
1499 
1500 void FitTest::testNonLinearMisra1d_3() {
1501     // NIST data for Misra1d dataset
1502     QVector<double> xData = {77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0};
1503     QVector<double> yData = {10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0};
1504 
1505     // data source columns
1506     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
1507     xDataColumn.replaceValues(0, xData);
1508 
1509     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
1510     yDataColumn.replaceValues(0, yData);
1511 
1512     XYFitCurve fitCurve(QStringLiteral("fit"));
1513     fitCurve.setXDataColumn(&xDataColumn);
1514     fitCurve.setYDataColumn(&yDataColumn);
1515 
1516     // prepare the fit
1517     XYFitCurve::FitData fitData = fitCurve.fitData();
1518     fitData.modelCategory = nsl_fit_model_custom;
1519     XYFitCurve::initFitData(fitData);
1520     fitData.model = QStringLiteral("b1*b2*x/(1+b2*x)");
1521     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2");
1522     fitData.eps = 1.e-12;
1523     const int np = fitData.paramNames.size();
1524     fitData.paramStartValues << 4.3736970754E+02 << 3.0227324449E-04;
1525     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max();
1526     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max();
1527     fitCurve.setFitData(fitData);
1528 
1529     // perform the fit
1530     fitCurve.recalculate();
1531     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
1532 
1533     // check the results
1534     QCOMPARE(fitResult.available, true);
1535     QCOMPARE(fitResult.valid, true);
1536 
1537     QCOMPARE(np, 2);
1538 
1539     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 437.370039987725
1540     FuzzyCompare(fitResult.paramValues.at(0), 4.3736970754E+02, 1.e-6);
1541     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 3.64772833062694
1542     FuzzyCompare(fitResult.errorValues.at(0), 3.6489174345E+00, 1.e-3);
1543     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000302272976784709
1544     FuzzyCompare(fitResult.paramValues.at(1), 3.0227324449E-04, 1.e-6);
1545     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 2.93256059733558e-06
1546     FuzzyCompare(fitResult.errorValues.at(1), 2.9334354479E-06, 1.e-3);
1547 
1548     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.068568272134244
1549     FuzzyCompare(fitResult.rsd, 6.8568272111E-02, 1.e-9);
1550     DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.056419295321709
1551     FuzzyCompare(fitResult.sse, 5.6419295283E-02, 1.e-9);
1552 }
1553 
1554 void FitTest::testNonLinearMGH09() {
1555     // NIST data for MGH09 dataset
1556     QVector<double> xData = {4.000000E+00,
1557                              2.000000E+00,
1558                              1.000000E+00,
1559                              5.000000E-01,
1560                              2.500000E-01,
1561                              1.670000E-01,
1562                              1.250000E-01,
1563                              1.000000E-01,
1564                              8.330000E-02,
1565                              7.140000E-02,
1566                              6.250000E-02};
1567     QVector<double> yData = {1.957000E-01,
1568                              1.947000E-01,
1569                              1.735000E-01,
1570                              1.600000E-01,
1571                              8.440000E-02,
1572                              6.270000E-02,
1573                              4.560000E-02,
1574                              3.420000E-02,
1575                              3.230000E-02,
1576                              2.350000E-02,
1577                              2.460000E-02};
1578 
1579     // data source columns
1580     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
1581     xDataColumn.replaceValues(0, xData);
1582 
1583     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
1584     yDataColumn.replaceValues(0, yData);
1585 
1586     XYFitCurve fitCurve(QStringLiteral("fit"));
1587     fitCurve.setXDataColumn(&xDataColumn);
1588     fitCurve.setYDataColumn(&yDataColumn);
1589 
1590     // prepare the fit
1591     XYFitCurve::FitData fitData = fitCurve.fitData();
1592     fitData.modelCategory = nsl_fit_model_custom;
1593     XYFitCurve::initFitData(fitData);
1594     fitData.model = QStringLiteral("b1*(x^2 + b2*x)/(x^2 + x*b3 + b4)");
1595     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2") << QStringLiteral("b3") << QStringLiteral("b4");
1596     // fitData.eps = 1.e-12;
1597     const int np = fitData.paramNames.size();
1598     fitData.paramStartValues << 2.5000000000E+01 << 3.9000000000E+01 << 4.1500000000E+01 << 3.9000000000E+01;
1599     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max()
1600                              << -std::numeric_limits<double>::max();
1601     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max() << std::numeric_limits<double>::max()
1602                              << std::numeric_limits<double>::max();
1603     fitCurve.setFitData(fitData);
1604 
1605     // perform the fit
1606     fitCurve.recalculate();
1607     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
1608 
1609     // check the results
1610     QCOMPARE(fitResult.available, true);
1611     QCOMPARE(fitResult.valid, true);
1612 
1613     QCOMPARE(np, 4);
1614 
1615     // TODO: fit does not find global minimum
1616     /*  DEBUG(std::setprecision(15) << fitResult.paramValues.at(0));    // result:
1617         FuzzyCompare(fitResult.paramValues.at(0), 1.9280693458E-01, 1.e-6);
1618         DEBUG(std::setprecision(15) << fitResult.errorValues.at(0));    // result:
1619         FuzzyCompare(fitResult.errorValues.at(0), 1.1435312227E-02, 1.e-3);
1620         DEBUG(std::setprecision(15) << fitResult.paramValues.at(1));    // result:
1621         FuzzyCompare(fitResult.paramValues.at(1), 1.9128232873E-01, 1.e-6);
1622         DEBUG(std::setprecision(15) << fitResult.errorValues.at(1));    // result:
1623         FuzzyCompare(fitResult.errorValues.at(1), 1.9633220911E-01, 1.e-3);
1624         DEBUG(std::setprecision(15) << fitResult.paramValues.at(2));    // result:
1625         FuzzyCompare(fitResult.paramValues.at(2), 1.2305650693E-01, 1.e-6);
1626         DEBUG(std::setprecision(15) << fitResult.errorValues.at(2));    // result:
1627         FuzzyCompare(fitResult.errorValues.at(2), 8.0842031232E-02, 1.e-3);
1628         DEBUG(std::setprecision(15) << fitResult.paramValues.at(3));    // result:
1629         FuzzyCompare(fitResult.paramValues.at(3), 1.3606233068E-01, 1.e-6);
1630         DEBUG(std::setprecision(15) << fitResult.errorValues.at(3));    // result:
1631         FuzzyCompare(fitResult.errorValues.at(3), 9.0025542308E-02, 1.e-3);
1632 
1633         DEBUG(std::setprecision(15) << fitResult.rsd);  // result:
1634         FuzzyCompare(fitResult.rsd, 6.6279236551E-03, 1.e-9);
1635         DEBUG(std::setprecision(15) << fitResult.sse);  // result:
1636         FuzzyCompare(fitResult.sse, 3.0750560385E-04, 1.e-9);
1637     */
1638 }
1639 
1640 void FitTest::testNonLinearMGH09_2() {
1641     // NIST data for MGH09 dataset
1642     QVector<double> xData = {4.000000E+00,
1643                              2.000000E+00,
1644                              1.000000E+00,
1645                              5.000000E-01,
1646                              2.500000E-01,
1647                              1.670000E-01,
1648                              1.250000E-01,
1649                              1.000000E-01,
1650                              8.330000E-02,
1651                              7.140000E-02,
1652                              6.250000E-02};
1653     QVector<double> yData = {1.957000E-01,
1654                              1.947000E-01,
1655                              1.735000E-01,
1656                              1.600000E-01,
1657                              8.440000E-02,
1658                              6.270000E-02,
1659                              4.560000E-02,
1660                              3.420000E-02,
1661                              3.230000E-02,
1662                              2.350000E-02,
1663                              2.460000E-02};
1664 
1665     // data source columns
1666     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
1667     xDataColumn.replaceValues(0, xData);
1668 
1669     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
1670     yDataColumn.replaceValues(0, yData);
1671 
1672     XYFitCurve fitCurve(QStringLiteral("fit"));
1673     fitCurve.setXDataColumn(&xDataColumn);
1674     fitCurve.setYDataColumn(&yDataColumn);
1675 
1676     // prepare the fit
1677     XYFitCurve::FitData fitData = fitCurve.fitData();
1678     fitData.modelCategory = nsl_fit_model_custom;
1679     XYFitCurve::initFitData(fitData);
1680     fitData.model = QStringLiteral("b1*(x^2 + b2*x)/(x^2 + x*b3 + b4)");
1681     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2") << QStringLiteral("b3") << QStringLiteral("b4");
1682     // fitData.eps = 1.e-12;
1683     const int np = fitData.paramNames.size();
1684     fitData.paramStartValues << 2.5000000000E-01 << 3.9000000000E-01 << 4.1500000000E-01 << 3.9000000000E-01;
1685     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max()
1686                              << -std::numeric_limits<double>::max();
1687     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max() << std::numeric_limits<double>::max()
1688                              << std::numeric_limits<double>::max();
1689     fitCurve.setFitData(fitData);
1690 
1691     // perform the fit
1692     fitCurve.recalculate();
1693     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
1694 
1695     // check the results
1696     QCOMPARE(fitResult.available, true);
1697     QCOMPARE(fitResult.valid, true);
1698 
1699     QCOMPARE(np, 4);
1700 
1701     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result:
1702     FuzzyCompare(fitResult.paramValues.at(0), 1.9280693458E-01, 1.e-5);
1703     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result:
1704     FuzzyCompare(fitResult.errorValues.at(0), 1.1435312227E-02, 1.e-4);
1705     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result:
1706     FuzzyCompare(fitResult.paramValues.at(1), 1.9128232873E-01, 1.e-3);
1707     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: (new: 0.196361378435283)
1708     FuzzyCompare(fitResult.errorValues.at(1), 1.9633220911E-01, 1.e-3);
1709     DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result:
1710     FuzzyCompare(fitResult.paramValues.at(2), 1.2305650693E-01, 1.e-4);
1711     DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result:
1712     FuzzyCompare(fitResult.errorValues.at(2), 8.0842031232E-02, 1.e-4);
1713     DEBUG(std::setprecision(15) << fitResult.paramValues.at(3)); // result:
1714     FuzzyCompare(fitResult.paramValues.at(3), 1.3606233068E-01, 1.e-4);
1715     DEBUG(std::setprecision(15) << fitResult.errorValues.at(3)); // result:
1716     FuzzyCompare(fitResult.errorValues.at(3), 9.0025542308E-02, 1.e-4);
1717 
1718     DEBUG(std::setprecision(15) << fitResult.rsd); // result:
1719     FuzzyCompare(fitResult.rsd, 6.6279236551E-03, 1.e-8);
1720     DEBUG(std::setprecision(15) << fitResult.sse); // result:
1721     FuzzyCompare(fitResult.sse, 3.0750560385E-04, 1.e-8);
1722 }
1723 
1724 void FitTest::testNonLinearMGH09_3() {
1725     // NIST data for MGH09 dataset
1726     QVector<double> xData = {4.000000E+00,
1727                              2.000000E+00,
1728                              1.000000E+00,
1729                              5.000000E-01,
1730                              2.500000E-01,
1731                              1.670000E-01,
1732                              1.250000E-01,
1733                              1.000000E-01,
1734                              8.330000E-02,
1735                              7.140000E-02,
1736                              6.250000E-02};
1737     QVector<double> yData = {1.957000E-01,
1738                              1.947000E-01,
1739                              1.735000E-01,
1740                              1.600000E-01,
1741                              8.440000E-02,
1742                              6.270000E-02,
1743                              4.560000E-02,
1744                              3.420000E-02,
1745                              3.230000E-02,
1746                              2.350000E-02,
1747                              2.460000E-02};
1748 
1749     // data source columns
1750     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
1751     xDataColumn.replaceValues(0, xData);
1752 
1753     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
1754     yDataColumn.replaceValues(0, yData);
1755 
1756     XYFitCurve fitCurve(QStringLiteral("fit"));
1757     fitCurve.setXDataColumn(&xDataColumn);
1758     fitCurve.setYDataColumn(&yDataColumn);
1759 
1760     // prepare the fit
1761     XYFitCurve::FitData fitData = fitCurve.fitData();
1762     fitData.modelCategory = nsl_fit_model_custom;
1763     XYFitCurve::initFitData(fitData);
1764     fitData.model = QStringLiteral("b1*(x^2 + b2*x)/(x^2 + x*b3 + b4)");
1765     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2") << QStringLiteral("b3") << QStringLiteral("b4");
1766     // fitData.eps = 1.e-12;
1767     const int np = fitData.paramNames.size();
1768     fitData.paramStartValues << 1.9280693458E-01 << 1.9128232873E-01 << 1.2305650693E-01 << 1.3606233068E-01;
1769     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max()
1770                              << -std::numeric_limits<double>::max();
1771     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max() << std::numeric_limits<double>::max()
1772                              << std::numeric_limits<double>::max();
1773     fitCurve.setFitData(fitData);
1774 
1775     // perform the fit
1776     fitCurve.recalculate();
1777     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
1778 
1779     // check the results
1780     QCOMPARE(fitResult.available, true);
1781     QCOMPARE(fitResult.valid, true);
1782 
1783     QCOMPARE(np, 4);
1784 
1785     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result:
1786     FuzzyCompare(fitResult.paramValues.at(0), 1.9280693458E-01, 1.e-9);
1787     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result:
1788     FuzzyCompare(fitResult.errorValues.at(0), 1.1435312227E-02, 1.e-5);
1789     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result:
1790     FuzzyCompare(fitResult.paramValues.at(1), 1.9128232873E-01, 1.e-9);
1791     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result:
1792     FuzzyCompare(fitResult.errorValues.at(1), 1.9633220911E-01, 1.e-5);
1793     DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result:
1794     FuzzyCompare(fitResult.paramValues.at(2), 1.2305650693E-01, 1.e-9);
1795     DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result:
1796     FuzzyCompare(fitResult.errorValues.at(2), 8.0842031232E-02, 1.e-5);
1797     DEBUG(std::setprecision(15) << fitResult.paramValues.at(3)); // result:
1798     FuzzyCompare(fitResult.paramValues.at(3), 1.3606233068E-01, 1.e-9);
1799     DEBUG(std::setprecision(15) << fitResult.errorValues.at(3)); // result:
1800     FuzzyCompare(fitResult.errorValues.at(3), 9.0025542308E-02, 1.e-5);
1801 
1802     DEBUG(std::setprecision(15) << fitResult.rsd); // result:
1803     FuzzyCompare(fitResult.rsd, 6.6279236551E-03, 1.e-9);
1804     DEBUG(std::setprecision(15) << fitResult.sse); // result:
1805     FuzzyCompare(fitResult.sse, 3.0750560385E-04, 1.e-9);
1806 }
1807 
1808 void FitTest::testNonLinearMGH10() {
1809     // NIST data for MGH10 dataset
1810     QVector<double> xData = {5.000000E+01,
1811                              5.500000E+01,
1812                              6.000000E+01,
1813                              6.500000E+01,
1814                              7.000000E+01,
1815                              7.500000E+01,
1816                              8.000000E+01,
1817                              8.500000E+01,
1818                              9.000000E+01,
1819                              9.500000E+01,
1820                              1.000000E+02,
1821                              1.050000E+02,
1822                              1.100000E+02,
1823                              1.150000E+02,
1824                              1.200000E+02,
1825                              1.250000E+02};
1826     QVector<double> yData = {3.478000E+04,
1827                              2.861000E+04,
1828                              2.365000E+04,
1829                              1.963000E+04,
1830                              1.637000E+04,
1831                              1.372000E+04,
1832                              1.154000E+04,
1833                              9.744000E+03,
1834                              8.261000E+03,
1835                              7.030000E+03,
1836                              6.005000E+03,
1837                              5.147000E+03,
1838                              4.427000E+03,
1839                              3.820000E+03,
1840                              3.307000E+03,
1841                              2.872000E+03};
1842 
1843     // data source columns
1844     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
1845     xDataColumn.replaceValues(0, xData);
1846 
1847     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
1848     yDataColumn.replaceValues(0, yData);
1849 
1850     XYFitCurve fitCurve(QStringLiteral("fit"));
1851     fitCurve.setXDataColumn(&xDataColumn);
1852     fitCurve.setYDataColumn(&yDataColumn);
1853 
1854     // prepare the fit
1855     XYFitCurve::FitData fitData = fitCurve.fitData();
1856     fitData.modelCategory = nsl_fit_model_custom;
1857     XYFitCurve::initFitData(fitData);
1858     fitData.model = QStringLiteral("b1*exp(b2/(x+b3))");
1859     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2") << QStringLiteral("b3");
1860     // fitData.eps = 1.e-12;
1861     const int np = fitData.paramNames.size();
1862     fitData.paramStartValues << 2.0000000000E+00 << 4.0000000000E+05 << 2.5000000000E+04;
1863     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max();
1864     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max() << std::numeric_limits<double>::max();
1865     fitCurve.setFitData(fitData);
1866 
1867     // perform the fit
1868     fitCurve.recalculate();
1869     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
1870 
1871     // check the results
1872     QCOMPARE(fitResult.available, true);
1873     QCOMPARE(fitResult.valid, true);
1874 
1875     QCOMPARE(np, 3);
1876 
1877     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 0.00560963848336205 (Windows: 0.00560964247264364)
1878     FuzzyCompare(fitResult.paramValues.at(0), 5.6096364710E-03, 1.e-5);
1879     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 0.000156888682057687
1880     FuzzyCompare(fitResult.errorValues.at(0), 1.5687892471E-04, 1.e-4);
1881     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 6181.34604697191 (Windows: 6181.34545410281)
1882     FuzzyCompare(fitResult.paramValues.at(1), 6.1813463463E+03, 1.e-6);
1883     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 23.3105479190063
1884     FuzzyCompare(fitResult.errorValues.at(1), 2.3309021107E+01, 1.e-4);
1885     DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: 345.223624540718 (Windows: 345.223579103645)
1886     FuzzyCompare(fitResult.paramValues.at(2), 3.4522363462E+02, 1.e-6);
1887     DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: 0.784915645388214
1888     FuzzyCompare(fitResult.errorValues.at(2), 7.8486103508E-01, 1.e-4);
1889 
1890     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 2.6009740064923   (Windows: 2.60097400662837, 2.60097400697918)
1891     FuzzyCompare(fitResult.rsd, 2.6009740065E+00, 1.e-9);
1892     DEBUG(std::setprecision(15) << fitResult.sse); // result: 87.9458551718321  (FreeBSD: 87.9458551726946, Windows: 87.9458551810338)
1893     FuzzyCompare(fitResult.sse, 8.7945855171E+01, 1.e-9);
1894 }
1895 
1896 void FitTest::testNonLinearMGH10_2() {
1897     // NIST data for MGH10 dataset
1898     QVector<double> xData = {5.000000E+01,
1899                              5.500000E+01,
1900                              6.000000E+01,
1901                              6.500000E+01,
1902                              7.000000E+01,
1903                              7.500000E+01,
1904                              8.000000E+01,
1905                              8.500000E+01,
1906                              9.000000E+01,
1907                              9.500000E+01,
1908                              1.000000E+02,
1909                              1.050000E+02,
1910                              1.100000E+02,
1911                              1.150000E+02,
1912                              1.200000E+02,
1913                              1.250000E+02};
1914     QVector<double> yData = {3.478000E+04,
1915                              2.861000E+04,
1916                              2.365000E+04,
1917                              1.963000E+04,
1918                              1.637000E+04,
1919                              1.372000E+04,
1920                              1.154000E+04,
1921                              9.744000E+03,
1922                              8.261000E+03,
1923                              7.030000E+03,
1924                              6.005000E+03,
1925                              5.147000E+03,
1926                              4.427000E+03,
1927                              3.820000E+03,
1928                              3.307000E+03,
1929                              2.872000E+03};
1930 
1931     // data source columns
1932     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
1933     xDataColumn.replaceValues(0, xData);
1934 
1935     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
1936     yDataColumn.replaceValues(0, yData);
1937 
1938     XYFitCurve fitCurve(QStringLiteral("fit"));
1939     fitCurve.setXDataColumn(&xDataColumn);
1940     fitCurve.setYDataColumn(&yDataColumn);
1941 
1942     // prepare the fit
1943     XYFitCurve::FitData fitData = fitCurve.fitData();
1944     fitData.modelCategory = nsl_fit_model_custom;
1945     XYFitCurve::initFitData(fitData);
1946     fitData.model = QStringLiteral("b1*exp(b2/(x+b3))");
1947     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2") << QStringLiteral("b3");
1948     // fitData.eps = 1.e-12;
1949     const int np = fitData.paramNames.size();
1950     fitData.paramStartValues << 2.0000000000E-02 << 4.0000000000E+03 << 2.5000000000E+02;
1951     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max();
1952     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max() << std::numeric_limits<double>::max();
1953     fitCurve.setFitData(fitData);
1954 
1955     // perform the fit
1956     fitCurve.recalculate();
1957     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
1958 
1959     // check the results
1960     QCOMPARE(fitResult.available, true);
1961     QCOMPARE(fitResult.valid, true);
1962 
1963     QCOMPARE(np, 3);
1964 
1965     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 0.00560963848336205
1966     FuzzyCompare(fitResult.paramValues.at(0), 5.6096364710E-03, 1.e-5);
1967     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 0.000156888586677272
1968     FuzzyCompare(fitResult.errorValues.at(0), 1.5687892471E-04, 1.e-4);
1969     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 6181.34604697191
1970     FuzzyCompare(fitResult.paramValues.at(1), 6.1813463463E+03, 1.e-6);
1971     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 23.3105167849511
1972     FuzzyCompare(fitResult.errorValues.at(1), 2.3309021107E+01, 1.e-4);
1973     DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: 345.223624540718
1974     FuzzyCompare(fitResult.paramValues.at(2), 3.4522363462E+02, 2.e-7);
1975     DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: 0.784914752553929
1976     FuzzyCompare(fitResult.errorValues.at(2), 7.8486103508E-01, 1.e-4);
1977 
1978     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 2.6009740064923
1979     FuzzyCompare(fitResult.rsd, 2.6009740065E+00, 2.e-10);
1980     DEBUG(std::setprecision(15) << fitResult.sse); // result: 87.9458551718321
1981     FuzzyCompare(fitResult.sse, 8.7945855171E+01, 1.e-9);
1982 }
1983 
1984 void FitTest::testNonLinearMGH10_3() {
1985     // NIST data for MGH10 dataset
1986     QVector<double> xData = {5.000000E+01,
1987                              5.500000E+01,
1988                              6.000000E+01,
1989                              6.500000E+01,
1990                              7.000000E+01,
1991                              7.500000E+01,
1992                              8.000000E+01,
1993                              8.500000E+01,
1994                              9.000000E+01,
1995                              9.500000E+01,
1996                              1.000000E+02,
1997                              1.050000E+02,
1998                              1.100000E+02,
1999                              1.150000E+02,
2000                              1.200000E+02,
2001                              1.250000E+02};
2002     QVector<double> yData = {3.478000E+04,
2003                              2.861000E+04,
2004                              2.365000E+04,
2005                              1.963000E+04,
2006                              1.637000E+04,
2007                              1.372000E+04,
2008                              1.154000E+04,
2009                              9.744000E+03,
2010                              8.261000E+03,
2011                              7.030000E+03,
2012                              6.005000E+03,
2013                              5.147000E+03,
2014                              4.427000E+03,
2015                              3.820000E+03,
2016                              3.307000E+03,
2017                              2.872000E+03};
2018 
2019     // data source columns
2020     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
2021     xDataColumn.replaceValues(0, xData);
2022 
2023     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
2024     yDataColumn.replaceValues(0, yData);
2025 
2026     XYFitCurve fitCurve(QStringLiteral("fit"));
2027     fitCurve.setXDataColumn(&xDataColumn);
2028     fitCurve.setYDataColumn(&yDataColumn);
2029 
2030     // prepare the fit
2031     XYFitCurve::FitData fitData = fitCurve.fitData();
2032     fitData.modelCategory = nsl_fit_model_custom;
2033     XYFitCurve::initFitData(fitData);
2034     fitData.model = QStringLiteral("b1*exp(b2/(x+b3))");
2035     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2") << QStringLiteral("b3");
2036     // fitData.eps = 1.e-12;
2037     const int np = fitData.paramNames.size();
2038     fitData.paramStartValues << 5.6096364710E-03 << 6.1813463463E+03 << 3.4522363462E+02;
2039     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max();
2040     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max() << std::numeric_limits<double>::max();
2041     fitCurve.setFitData(fitData);
2042 
2043     // perform the fit
2044     fitCurve.recalculate();
2045     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
2046 
2047     // check the results
2048     QCOMPARE(fitResult.available, true);
2049     QCOMPARE(fitResult.valid, true);
2050 
2051     QCOMPARE(np, 3);
2052 
2053     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 0.00560963848336205
2054     FuzzyCompare(fitResult.paramValues.at(0), 5.6096364710E-03, 1.e-6);
2055     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 0.000156888348998521
2056     FuzzyCompare(fitResult.errorValues.at(0), 1.5687892471E-04, 1.e-4);
2057     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 6181.34604697191
2058     FuzzyCompare(fitResult.paramValues.at(1), 6.1813463463E+03, 1.e-7);
2059     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 23.310508065631
2060     FuzzyCompare(fitResult.errorValues.at(1), 2.3309021107E+01, 1.e-4);
2061     DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: 345.223624540718
2062     FuzzyCompare(fitResult.paramValues.at(2), 3.4522363462E+02, 1.e-7);
2063     DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: 0.784914424350028
2064     FuzzyCompare(fitResult.errorValues.at(2), 7.8486103508E-01, 1.e-4);
2065 
2066     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 2.6009740064923
2067     FuzzyCompare(fitResult.rsd, 2.6009740065E+00, 1.e-11);
2068     DEBUG(std::setprecision(15) << fitResult.sse); // result: 87.9458551718321
2069     FuzzyCompare(fitResult.sse, 8.7945855171E+01, 1.e-11);
2070 }
2071 
2072 void FitTest::testNonLinearRat43() {
2073     // NIST data for Rat43 dataset
2074     QVector<double> xData = {1.0E0, 2.0E0, 3.0E0, 4.0E0, 5.0E0, 6.0E0, 7.0E0, 8.0E0, 9.0E0, 10.0E0, 11.0E0, 12.0E0, 13.0E0, 14.0E0, 15.0E0};
2075     QVector<double> yData =
2076         {16.08E0, 33.83E0, 65.80E0, 97.20E0, 191.55E0, 326.20E0, 386.87E0, 520.53E0, 590.03E0, 651.92E0, 724.93E0, 699.56E0, 689.96E0, 637.56E0, 717.41E0};
2077 
2078     // data source columns
2079     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
2080     xDataColumn.replaceValues(0, xData);
2081 
2082     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
2083     yDataColumn.replaceValues(0, yData);
2084 
2085     XYFitCurve fitCurve(QStringLiteral("fit"));
2086     fitCurve.setXDataColumn(&xDataColumn);
2087     fitCurve.setYDataColumn(&yDataColumn);
2088 
2089     // prepare the fit
2090     XYFitCurve::FitData fitData = fitCurve.fitData();
2091     fitData.modelCategory = nsl_fit_model_custom;
2092     XYFitCurve::initFitData(fitData);
2093     fitData.model = QStringLiteral("b1/pow(1 + exp(b2-b3*x); 1/b4)");
2094     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2") << QStringLiteral("b3") << QStringLiteral("b4");
2095     fitData.eps = 1.e-9;
2096     const int np = fitData.paramNames.size();
2097     fitData.paramStartValues << 1.0000000000E+02 << 1.0000000000E+01 << 1.0000000000E+00 << 1.0000000000E+00;
2098     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max()
2099                              << -std::numeric_limits<double>::max();
2100     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max() << std::numeric_limits<double>::max()
2101                              << std::numeric_limits<double>::max();
2102     fitCurve.setFitData(fitData);
2103 
2104     // perform the fit
2105     fitCurve.recalculate();
2106     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
2107 
2108     // check the results
2109     QCOMPARE(fitResult.available, true);
2110     QCOMPARE(fitResult.valid, true);
2111 
2112     QCOMPARE(np, 4);
2113 
2114     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 699.641340982193
2115     FuzzyCompare(fitResult.paramValues.at(0), 6.9964151270E+02, 1.e-6);
2116     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 16.3022524293302
2117     FuzzyCompare(fitResult.errorValues.at(0), 1.6302297817E+01, 1.e-5);
2118     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 5.2771555758844
2119     FuzzyCompare(fitResult.paramValues.at(1), 5.2771253025E+00, 1.e-5);
2120     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 2.08290034908325
2121     FuzzyCompare(fitResult.errorValues.at(1), 2.0828735829E+00, 1.e-4);
2122     DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: 0.759632366113637
2123     FuzzyCompare(fitResult.paramValues.at(2), 7.5962938329E-01, 1.e-5);
2124     DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: 0.195664372178938
2125     FuzzyCompare(fitResult.errorValues.at(2), 1.9566123451E-01, 1.e-4);
2126     DEBUG(std::setprecision(15) << fitResult.paramValues.at(3)); // result: 1.27925748993867
2127     FuzzyCompare(fitResult.paramValues.at(3), 1.2792483859E+00, 1.e-5);
2128     DEBUG(std::setprecision(15) << fitResult.errorValues.at(3)); // result: 0.687627478905195
2129     FuzzyCompare(fitResult.errorValues.at(3), 6.8761936385E-01, 1.e-4);
2130 
2131     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 28.2624146626284
2132     FuzzyCompare(fitResult.rsd, 2.8262414662E+01, 1.e-10);
2133     DEBUG(std::setprecision(15) << fitResult.sse); // result: 8786.4049081859
2134     FuzzyCompare(fitResult.sse, 8.7864049080E+03, 1.e-10);
2135 }
2136 
2137 void FitTest::testNonLinearRat43_2() {
2138     // NIST data for Rat43 dataset
2139     QVector<double> xData = {1.0E0, 2.0E0, 3.0E0, 4.0E0, 5.0E0, 6.0E0, 7.0E0, 8.0E0, 9.0E0, 10.0E0, 11.0E0, 12.0E0, 13.0E0, 14.0E0, 15.0E0};
2140     QVector<double> yData =
2141         {16.08E0, 33.83E0, 65.80E0, 97.20E0, 191.55E0, 326.20E0, 386.87E0, 520.53E0, 590.03E0, 651.92E0, 724.93E0, 699.56E0, 689.96E0, 637.56E0, 717.41E0};
2142 
2143     // data source columns
2144     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
2145     xDataColumn.replaceValues(0, xData);
2146 
2147     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
2148     yDataColumn.replaceValues(0, yData);
2149 
2150     XYFitCurve fitCurve(QStringLiteral("fit"));
2151     fitCurve.setXDataColumn(&xDataColumn);
2152     fitCurve.setYDataColumn(&yDataColumn);
2153 
2154     // prepare the fit
2155     XYFitCurve::FitData fitData = fitCurve.fitData();
2156     fitData.modelCategory = nsl_fit_model_custom;
2157     XYFitCurve::initFitData(fitData);
2158     fitData.model = QStringLiteral("b1/pow(1 + exp(b2-b3*x); 1/b4)");
2159     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2") << QStringLiteral("b3") << QStringLiteral("b4");
2160     fitData.eps = 1.e-10;
2161     const int np = fitData.paramNames.size();
2162     fitData.paramStartValues << 7.0000000000E+02 << 5.0000000000E+00 << 7.5000000000E-01 << 1.3000000000E+00;
2163     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max()
2164                              << -std::numeric_limits<double>::max();
2165     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max() << std::numeric_limits<double>::max()
2166                              << std::numeric_limits<double>::max();
2167     fitCurve.setFitData(fitData);
2168 
2169     // perform the fit
2170     fitCurve.recalculate();
2171     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
2172 
2173     // check the results
2174     QCOMPARE(fitResult.available, true);
2175     QCOMPARE(fitResult.valid, true);
2176 
2177     QCOMPARE(np, 4);
2178 
2179     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 699.641340982193
2180     FuzzyCompare(fitResult.paramValues.at(0), 6.9964151270E+02, 1.e-6);
2181     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 16.3023134145464 (FreeBSD: 16.3023141645004)
2182     FuzzyCompare(fitResult.errorValues.at(0), 1.6302297817E+01, 1.e-5);
2183     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 5.2771555758844
2184     FuzzyCompare(fitResult.paramValues.at(1), 5.2771253025E+00, 1.e-5);
2185     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 2.08288970703906
2186     FuzzyCompare(fitResult.errorValues.at(1), 2.0828735829E+00, 1.e-5);
2187     DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: 0.759632366113637
2188     FuzzyCompare(fitResult.paramValues.at(2), 7.5962938329E-01, 1.e-5);
2189     DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: 0.195662802156063
2190     FuzzyCompare(fitResult.errorValues.at(2), 1.9566123451E-01, 1.e-5);
2191     DEBUG(std::setprecision(15) << fitResult.paramValues.at(3)); // result: 1.27925748993867
2192     FuzzyCompare(fitResult.paramValues.at(3), 1.2792483859E+00, 1.e-5);
2193     DEBUG(std::setprecision(15) << fitResult.errorValues.at(3)); // result: 0.687623222160242
2194     FuzzyCompare(fitResult.errorValues.at(3), 6.8761936385E-01, 1.e-5);
2195 
2196     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 28.2624146626284
2197     FuzzyCompare(fitResult.rsd, 2.8262414662E+01, 1.e-10);
2198     DEBUG(std::setprecision(15) << fitResult.sse); // result: 8786.4049081859
2199     FuzzyCompare(fitResult.sse, 8.7864049080E+03, 1.e-11);
2200 }
2201 
2202 void FitTest::testNonLinearRat43_3() {
2203     // NIST data for Rat43 dataset
2204     QVector<double> xData = {1.0E0, 2.0E0, 3.0E0, 4.0E0, 5.0E0, 6.0E0, 7.0E0, 8.0E0, 9.0E0, 10.0E0, 11.0E0, 12.0E0, 13.0E0, 14.0E0, 15.0E0};
2205     QVector<double> yData =
2206         {16.08E0, 33.83E0, 65.80E0, 97.20E0, 191.55E0, 326.20E0, 386.87E0, 520.53E0, 590.03E0, 651.92E0, 724.93E0, 699.56E0, 689.96E0, 637.56E0, 717.41E0};
2207 
2208     // data source columns
2209     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
2210     xDataColumn.replaceValues(0, xData);
2211 
2212     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
2213     yDataColumn.replaceValues(0, yData);
2214 
2215     XYFitCurve fitCurve(QStringLiteral("fit"));
2216     fitCurve.setXDataColumn(&xDataColumn);
2217     fitCurve.setYDataColumn(&yDataColumn);
2218 
2219     // prepare the fit
2220     XYFitCurve::FitData fitData = fitCurve.fitData();
2221     fitData.modelCategory = nsl_fit_model_custom;
2222     XYFitCurve::initFitData(fitData);
2223     fitData.model = QStringLiteral("b1/pow(1 + exp(b2-b3*x); 1/b4)");
2224     fitData.paramNames << QStringLiteral("b1") << QStringLiteral("b2") << QStringLiteral("b3") << QStringLiteral("b4");
2225     // fitData.eps = 1.e-12;
2226     const int np = fitData.paramNames.size();
2227     fitData.paramStartValues << 6.9964151270E+02 << 5.2771253025E+00 << 7.5962938329E-01 << 1.2792483859E+00;
2228     fitData.paramLowerLimits << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max() << -std::numeric_limits<double>::max()
2229                              << -std::numeric_limits<double>::max();
2230     fitData.paramUpperLimits << std::numeric_limits<double>::max() << std::numeric_limits<double>::max() << std::numeric_limits<double>::max()
2231                              << std::numeric_limits<double>::max();
2232     fitCurve.setFitData(fitData);
2233 
2234     // perform the fit
2235     fitCurve.recalculate();
2236     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
2237 
2238     // check the results
2239     QCOMPARE(fitResult.available, true);
2240     QCOMPARE(fitResult.valid, true);
2241 
2242     QCOMPARE(np, 4);
2243 
2244     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 699.641340982193
2245     FuzzyCompare(fitResult.paramValues.at(0), 6.9964151270E+02, 1.e-8);
2246     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 16.3022905400761
2247     FuzzyCompare(fitResult.errorValues.at(0), 1.6302297817E+01, 1.e-6);
2248     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 5.2771555758844
2249     FuzzyCompare(fitResult.paramValues.at(1), 5.2771253025E+00, 1.e-8);
2250     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 2.08289316520407
2251     FuzzyCompare(fitResult.errorValues.at(1), 2.0828735829E+00, 1.e-5);
2252     DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: 0.759632366113637
2253     FuzzyCompare(fitResult.paramValues.at(2), 7.5962938329E-01, 1.e-8);
2254     DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: 0.195663312668779
2255     FuzzyCompare(fitResult.errorValues.at(2), 1.9566123451E-01, 1.e-4);
2256     DEBUG(std::setprecision(15) << fitResult.paramValues.at(3)); // result: 1.27925748993867
2257     FuzzyCompare(fitResult.paramValues.at(3), 1.2792483859E+00, 1.e-8);
2258     DEBUG(std::setprecision(15) << fitResult.errorValues.at(3)); // result: 0.687624541478887
2259     FuzzyCompare(fitResult.errorValues.at(3), 6.8761936385E-01, 1.e-5);
2260 
2261     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 28.2624146626284
2262     FuzzyCompare(fitResult.rsd, 2.8262414662E+01, 1.e-11);
2263     DEBUG(std::setprecision(15) << fitResult.sse); // result: 8786.4049081859
2264     FuzzyCompare(fitResult.sse, 8.7864049080E+03, 1.e-11);
2265 }
2266 
2267 // https://bugs.kde.org/show_bug.cgi?id=393213
2268 void FitTest::testNonLinearMichaelis_Menten() {
2269     // generic data
2270     QVector<double> xData = {0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0};
2271     QVector<double> yData = {0.0, 0.6, 0.65, 0.7, 0.75, 0.75, 0.8, 0.9, 0.85, 0.95, 0.9};
2272 
2273     // data source columns
2274     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
2275     xDataColumn.replaceValues(0, xData);
2276 
2277     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
2278     yDataColumn.replaceValues(0, yData);
2279 
2280     XYFitCurve fitCurve(QStringLiteral("fit"));
2281     fitCurve.setXDataColumn(&xDataColumn);
2282     fitCurve.setYDataColumn(&yDataColumn);
2283 
2284     // prepare the fit
2285     XYFitCurve::FitData fitData = fitCurve.fitData();
2286     fitData.modelCategory = nsl_fit_model_custom;
2287     XYFitCurve::initFitData(fitData);
2288     fitData.model = QStringLiteral("Vm * x/(Km + x)");
2289     fitData.paramNames << QStringLiteral("Vm") << QStringLiteral("Km");
2290     fitData.eps = 1.e-12;
2291     const int np = fitData.paramNames.size();
2292     fitData.paramStartValues << 1.0 << 1.0;
2293     for (int i = 0; i < np; i++) {
2294         fitData.paramLowerLimits << -std::numeric_limits<double>::max();
2295         fitData.paramUpperLimits << std::numeric_limits<double>::max();
2296     }
2297     fitCurve.setFitData(fitData);
2298 
2299     // perform the fit
2300     fitCurve.recalculate();
2301     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
2302 
2303     // check the results
2304     QCOMPARE(fitResult.available, true);
2305     QCOMPARE(fitResult.valid, true);
2306 
2307     QCOMPARE(np, 2);
2308 
2309     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 0.945561082955744
2310     FuzzyCompare(fitResult.paramValues.at(0), 0.94556434933256, 1.e-5);
2311     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 0.0388724403232334
2312     FuzzyCompare(fitResult.errorValues.at(0), 0.0388803714011844, 3.e-4);
2313     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.159396945453528
2314     FuzzyCompare(fitResult.paramValues.at(1), 0.159400761666661, 3.e-5);
2315     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 0.0388244491752518
2316     FuzzyCompare(fitResult.errorValues.at(1), 0.0388429738447119, 5.e-4);
2317 
2318     DEBUG(std::setprecision(15) << fitResult.rms); // result: 0.00280486748619082
2319     FuzzyCompare(fitResult.rms, 0.00280486748877263, 1.e-9);
2320     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.0529609996713697
2321     FuzzyCompare(fitResult.rsd, 0.0529609996957444, 1.e-9);
2322     DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.0252438073757174
2323     FuzzyCompare(fitResult.sse, 0.0252438073989537, 1.e-9);
2324 }
2325 // ##############################################################################
2326 // #########################  Fits with weights #################################
2327 // ##############################################################################
2328 
2329 // see http://gnuplot.sourceforge.net/demo_5.2/fit.html
2330 void FitTest::testNonLinearGP_lcdemo() {
2331     // data from https://github.com/gnuplot/gnuplot/blob/master/demo/lcdemo.dat
2332     QVector<double> xData = {39.471, 40.091, 40.602, 41.058, 41.438, 41.880, 42.437, 42.836, 43.209, 43.599, 43.997, 44.313, 44.908,
2333                              45.169, 45.594, 45.743, 45.796, 45.816, 45.841, 45.876, 45.908, 45.959, 46.008, 46.040, 46.060, 46.096,
2334                              46.126, 46.149, 46.372, 46.625, 46.945, 47.326, 47.708, 48.095, 48.540, 48.927, 49.314};
2335     QVector<double> yData = {1.03307, 1.03246, 1.03197, 1.03153, 1.03117, 1.03074, 1.03021, 1.02982, 1.02946, 1.02907, 1.02867, 1.02833, 1.02765,
2336                              1.02735, 1.02683, 1.02661, 1.02650, 1.02644, 1.02634, 1.02623, 1.02611, 1.02592, 1.02561, 1.02526, 1.02506, 1.02500,
2337                              1.02496, 1.02494, 1.02474, 1.02452, 1.02425, 1.02393, 1.02361, 1.02329, 1.02293, 1.02262, 1.02231};
2338     QVector<double> yError = {0.010, 0.010, 0.010, 0.010, 0.010, 0.010, 0.010, 0.010, 0.010, 0.010, 0.010, 0.010, 0.010,
2339                               0.010, 0.010, 0.010, 0.010, 0.010, 0.010, 0.010, 0.010, 0.010, 0.001, 0.001, 0.001, 0.001,
2340                               0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001};
2341 
2342     // data source columns
2343     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
2344     xDataColumn.replaceValues(0, xData);
2345 
2346     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
2347     yDataColumn.replaceValues(0, yData);
2348 
2349     Column yErrorColumn(QStringLiteral("yerr"), AbstractColumn::ColumnMode::Double);
2350     yErrorColumn.replaceValues(0, yError);
2351 
2352     XYFitCurve fitCurve(QStringLiteral("fit"));
2353     fitCurve.setXDataColumn(&xDataColumn);
2354     fitCurve.setYDataColumn(&yDataColumn);
2355     fitCurve.setYErrorColumn(&yErrorColumn);
2356 
2357     // prepare the fit
2358     XYFitCurve::FitData fitData = fitCurve.fitData();
2359     fitData.modelCategory = nsl_fit_model_custom;
2360     XYFitCurve::initFitData(fitData);
2361     // x > Tc : d + mh(x-Tc)
2362     // x < Tc : d + ml(x-Tc) + b tanh(g(Tc-x))
2363     fitData.model = QStringLiteral("d + theta(x-Tc)*mh*(x-Tc) + theta(Tc-x)*(ml*(x-Tc)+b*tanh(g*(Tc-x)))");
2364     fitData.paramNames << QStringLiteral("d") << QStringLiteral("Tc") << QStringLiteral("mh") << QStringLiteral("ml") << QStringLiteral("b")
2365                        << QStringLiteral("g");
2366     fitData.eps = 1.e-12;
2367     const int np = fitData.paramNames.size();
2368     fitData.paramStartValues << 1.02 << 45. << -0.0005 << -0.0005 << 0.01002 << 1.0;
2369     for (int i = 0; i < np; i++) {
2370         fitData.paramLowerLimits << -std::numeric_limits<double>::max();
2371         fitData.paramUpperLimits << std::numeric_limits<double>::max();
2372     }
2373     fitData.yWeightsType = nsl_fit_weight_instrumental;
2374     fitCurve.setFitData(fitData);
2375 
2376     // perform the fit
2377     fitCurve.recalculate();
2378     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
2379 
2380     // check the results
2381     QCOMPARE(fitResult.available, true);
2382     QCOMPARE(fitResult.valid, true);
2383 
2384     QCOMPARE(np, 6);
2385 
2386     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 1.02499979307627 (Windows: 1.02561781433026)
2387     FuzzyCompare(fitResult.paramValues.at(0), 1.02499621370905, 1.e-3);
2388     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 4.81672854812941e-06
2389     // TODO FuzzyCompare(fitResult.errorValues.at(0), 7.27819513635249e-06, 1.e-6);
2390     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 46.0647953740441 (Windows: 45.4871250830364)
2391     FuzzyCompare(fitResult.paramValues.at(1), 46.0665367045608, 2.e-2);
2392     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 9.90288940612482
2393     // TODO FuzzyCompare(fitResult.errorValues.at(1), 0.00159887430059728, 1.e-6);
2394     DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result:  -0.000835023995828296 (Windows: -0.000883960665773456)
2395     FuzzyCompare(fitResult.paramValues.at(2), -0.0008340717673769, 1.e-1);
2396     DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result:
2397     // TODO FuzzyCompare(fitResult.errorValues.at(2), , 1.e-6);
2398     DEBUG(std::setprecision(15) << fitResult.paramValues.at(3)); // result: -0.000987547207638997
2399     FuzzyCompare(fitResult.paramValues.at(3), -0.00103152542276233, 1.e-1);
2400     DEBUG(std::setprecision(15) << fitResult.errorValues.at(3)); // result:
2401     // TODO FuzzyCompare(fitResult.errorValues.at(3), , 1.e-6);
2402     DEBUG(std::setprecision(15) << fitResult.paramValues.at(4)); // result: 0.00158880319355268
2403     FuzzyCompare(fitResult.paramValues.at(4), 0.00139548391000006, 1.5e-1);
2404     DEBUG(std::setprecision(15) << fitResult.errorValues.at(4)); // result:
2405     // TODO FuzzyCompare(fitResult.errorValues.at(4), , 1.e-6);
2406     DEBUG(std::setprecision(15) << fitResult.paramValues.at(5)); // result: 6.34254053273612 (Windows: 4.45482397068125)
2407     //  FuzzyCompare(fitResult.paramValues.at(5), 6.92493866108287, 1.e-1);
2408     DEBUG(std::setprecision(15) << fitResult.errorValues.at(5)); // result:
2409     // TODO FuzzyCompare(fitResult.errorValues.at(5), , 1.e-6);
2410 
2411     DEBUG(std::setprecision(15) << fitResult.rms); // result: 98.0672185899393
2412     //  FuzzyCompare(fitResult.rms, 0.000188776, 1.e-11);
2413     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 9.90288940612482
2414     //  FuzzyCompare(fitResult.rsd, 0.0137395924378767, 1.e-11);
2415     DEBUG(std::setprecision(15) << fitResult.sse); // result: 3040.08377628812
2416     //  FuzzyCompare(fitResult.sse, 0.00585206841112775, 1.e-11);
2417 }
2418 
2419 // see http://gnuplot.sourceforge.net/demo_5.2/fit.html
2420 void FitTest::testLinearGP_PY_noerror() {
2421     // Pearson's data and York's weights
2422     QVector<double> xData = {0.0, 0.9, 1.8, 2.6, 3.3, 4.4, 5.2, 6.1, 6.5, 7.4};
2423     QVector<double> yData = {5.9, 5.4, 4.4, 4.6, 3.5, 3.7, 2.8, 2.8, 2.4, 1.5};
2424     //  QVector<double> xError = {1000.,1000.,500.,800.,200.,80.,60.,20.,1.8,1.0};
2425     //  QVector<double> yError = {1.0,1.8,4.,8.,20.,20.,70.,70.,100.,500.};
2426 
2427     // data source columns
2428     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
2429     xDataColumn.replaceValues(0, xData);
2430 
2431     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
2432     yDataColumn.replaceValues(0, yData);
2433 
2434     //  Column yErrorColumn(QStringLiteral("yerr"), AbstractColumn::ColumnMode::Double);
2435     //  yErrorColumn.replaceValues(0, yError);
2436 
2437     XYFitCurve fitCurve(QStringLiteral("fit"));
2438     fitCurve.setXDataColumn(&xDataColumn);
2439     fitCurve.setYDataColumn(&yDataColumn);
2440     //  fitCurve.setYErrorColumn(&yErrorColumn);
2441 
2442     // prepare the fit
2443     XYFitCurve::FitData fitData = fitCurve.fitData();
2444     fitData.modelCategory = nsl_fit_model_custom;
2445     XYFitCurve::initFitData(fitData);
2446     fitData.model = QStringLiteral("a1 + a2 * x");
2447     fitData.paramNames << QStringLiteral("a1") << QStringLiteral("a2");
2448     fitData.eps = 1.e-9;
2449     const int np = fitData.paramNames.size();
2450     fitData.paramStartValues << 5. << -0.5;
2451     for (int i = 0; i < np; i++) {
2452         fitData.paramLowerLimits << -std::numeric_limits<double>::max();
2453         fitData.paramUpperLimits << std::numeric_limits<double>::max();
2454     }
2455     //  fitData.yWeightsType = nsl_fit_weight_instrumental;
2456     fitCurve.setFitData(fitData);
2457 
2458     // perform the fit
2459     fitCurve.recalculate();
2460     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
2461 
2462     // check the results
2463     QCOMPARE(fitResult.available, true);
2464     QCOMPARE(fitResult.valid, true);
2465 
2466     QCOMPARE(np, 2);
2467 
2468     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 5.76118518568804
2469     FuzzyCompare(fitResult.paramValues.at(0), 5.76118519043878, 1.e-9);
2470     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 0.189485192391863
2471     FuzzyCompare(fitResult.errorValues.at(0), 0.189485195921141, 1.e-7);
2472     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: -0.539577274076964
2473     FuzzyCompare(fitResult.paramValues.at(1), -0.539577274983977, 1.e-8);
2474     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 0.0421265487265946
2475     FuzzyCompare(fitResult.errorValues.at(1), 0.0421265483886995, 1.e-8);
2476 
2477     DEBUG(std::setprecision(15) << fitResult.rms); // result: 0.100082940279452
2478     QCOMPARE(fitResult.rms, 0.100082940279452);
2479     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.316358878932538
2480     QCOMPARE(fitResult.rsd, 0.316358878932538);
2481     DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.800663522235619
2482     QCOMPARE(fitResult.sse, 0.800663522235619);
2483 }
2484 
2485 // see http://gnuplot.sourceforge.net/demo_5.2/fit.html
2486 void FitTest::testLinearGP_PY_yerror_polynomial() {
2487     // Pearson's data and York's weights
2488     QVector<double> xData = {0.0, 0.9, 1.8, 2.6, 3.3, 4.4, 5.2, 6.1, 6.5, 7.4};
2489     QVector<double> yData = {5.9, 5.4, 4.4, 4.6, 3.5, 3.7, 2.8, 2.8, 2.4, 1.5};
2490     //  QVector<double> xError = {1000.,1000.,500.,800.,200.,80.,60.,20.,1.8,1.0};
2491     QVector<double> yError = {1.0, 1.8, 4., 8., 20., 20., 70., 70., 100., 500.};
2492 
2493     // data source columns
2494     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
2495     xDataColumn.replaceValues(0, xData);
2496 
2497     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
2498     yDataColumn.replaceValues(0, yData);
2499 
2500     Column yErrorColumn(QStringLiteral("yerr"), AbstractColumn::ColumnMode::Double);
2501     yErrorColumn.replaceValues(0, yError);
2502 
2503     XYFitCurve fitCurve(QStringLiteral("fit"));
2504     fitCurve.setXDataColumn(&xDataColumn);
2505     fitCurve.setYDataColumn(&yDataColumn);
2506     fitCurve.setYErrorColumn(&yErrorColumn);
2507 
2508     // prepare the fit
2509     XYFitCurve::FitData fitData = fitCurve.fitData();
2510     fitData.modelCategory = nsl_fit_model_basic;
2511     fitData.modelType = nsl_fit_model_polynomial;
2512     fitData.degree = 1;
2513     XYFitCurve::initFitData(fitData);
2514     //  fitData.eps = 1.e-12;
2515     const int np = fitData.paramNames.size();
2516     fitData.paramStartValues << 5. << -0.5;
2517     fitData.yWeightsType = nsl_fit_weight_direct;
2518     fitCurve.setFitData(fitData);
2519 
2520     // perform the fit
2521     fitCurve.recalculate();
2522     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
2523 
2524     // check the results
2525     QCOMPARE(fitResult.available, true);
2526     QCOMPARE(fitResult.valid, true);
2527 
2528     QCOMPARE(np, 2);
2529 
2530     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 6.10010931666575
2531     FuzzyCompare(fitResult.paramValues.at(0), 6.10010931635002, 1.e-10);
2532     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 0.424059452104775, i386: 0.424059429083679
2533     FuzzyCompare(fitResult.errorValues.at(0), 0.424059452104785, 1.e-10);
2534     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: -0.610812956583933, i386: -0.610812954591566
2535     FuzzyCompare(fitResult.paramValues.at(1), -0.610812956537254, 1.e-9);
2536     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 0.0623409539388997, i386: 0.0623409508171503
2537     FuzzyCompare(fitResult.errorValues.at(1), 0.0623409539389024, 1.e-10);
2538 
2539     QCOMPARE(fitResult.rms, 4.29315093729054);
2540     QCOMPARE(fitResult.rsd, 2.07199202153158);
2541     QCOMPARE(fitResult.sse, 34.3452074983243);
2542     DEBUG(std::setprecision(15) << fitResult.fdist_p); // result: 0.000101015996328551
2543     // TODO QCOMPARE(fitResult.fdist_p, 3.51725605201025e-05);
2544 }
2545 
2546 // see http://gnuplot.sourceforge.net/demo_5.2/fit.html
2547 void FitTest::testLinearGP_PY_yerror_custom() {
2548     // Pearson's data and York's weights
2549     QVector<double> xData = {0.0, 0.9, 1.8, 2.6, 3.3, 4.4, 5.2, 6.1, 6.5, 7.4};
2550     QVector<double> yData = {5.9, 5.4, 4.4, 4.6, 3.5, 3.7, 2.8, 2.8, 2.4, 1.5};
2551     //  QVector<double> xError = {1000.,1000.,500.,800.,200.,80.,60.,20.,1.8,1.0};
2552     QVector<double> yError = {1.0, 1.8, 4., 8., 20., 20., 70., 70., 100., 500.};
2553 
2554     // data source columns
2555     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
2556     xDataColumn.replaceValues(0, xData);
2557 
2558     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
2559     yDataColumn.replaceValues(0, yData);
2560 
2561     Column yErrorColumn(QStringLiteral("yerr"), AbstractColumn::ColumnMode::Double);
2562     yErrorColumn.replaceValues(0, yError);
2563 
2564     XYFitCurve fitCurve(QStringLiteral("fit"));
2565     fitCurve.setXDataColumn(&xDataColumn);
2566     fitCurve.setYDataColumn(&yDataColumn);
2567     fitCurve.setYErrorColumn(&yErrorColumn);
2568 
2569     // prepare the fit
2570     XYFitCurve::FitData fitData = fitCurve.fitData();
2571     fitData.modelCategory = nsl_fit_model_custom;
2572     XYFitCurve::initFitData(fitData);
2573     fitData.model = QStringLiteral("a1 + a2 * x");
2574     fitData.paramNames << QStringLiteral("a1") << QStringLiteral("a2");
2575     fitData.eps = 1.e-9;
2576     const int np = fitData.paramNames.size();
2577     fitData.paramStartValues << 5. << -0.5;
2578     for (int i = 0; i < np; i++) {
2579         fitData.paramLowerLimits << -std::numeric_limits<double>::max();
2580         fitData.paramUpperLimits << std::numeric_limits<double>::max();
2581     }
2582 
2583     fitData.yWeightsType = nsl_fit_weight_direct;
2584     fitCurve.setFitData(fitData);
2585 
2586     // perform the fit
2587     fitCurve.recalculate();
2588     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
2589 
2590     // check the results
2591     QCOMPARE(fitResult.available, true);
2592     QCOMPARE(fitResult.valid, true);
2593 
2594     QCOMPARE(np, 2);
2595 
2596     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 6.10010932451396
2597     FuzzyCompare(fitResult.paramValues.at(0), 6.10010931635002, 1.e-8);
2598     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 0.424059453530443 (new: 0.424059492144904)
2599     FuzzyCompare(fitResult.errorValues.at(0), 0.424059452104785, 1.e-7);
2600     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: -0.610812957040808 (new: -0.610812955065274)
2601     FuzzyCompare(fitResult.paramValues.at(1), -0.610812956537254, 1.e-8);
2602     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 0.0623409543258892 (new: 0.0623409596911536)
2603     FuzzyCompare(fitResult.errorValues.at(1), 0.0623409539389024, 1.e-7);
2604 
2605     QCOMPARE(fitResult.rms, 4.29315093729054);
2606     QCOMPARE(fitResult.rsd, 2.07199202153158);
2607     QCOMPARE(fitResult.sse, 34.3452074983243);
2608     DEBUG(std::setprecision(15) << fitResult.fdist_p); // result: 0.000101015996328551
2609     // TODO QCOMPARE(fitResult.fdist_p, 3.51725605201025e-05);
2610 }
2611 
2612 // see http://gnuplot.sourceforge.net/demo_5.2/fit.html
2613 void FitTest::testLinearGP_PY_xyerror_polynomial() {
2614     // Pearson's data and York's weights
2615     QVector<double> xData = {0.0, 0.9, 1.8, 2.6, 3.3, 4.4, 5.2, 6.1, 6.5, 7.4};
2616     QVector<double> yData = {5.9, 5.4, 4.4, 4.6, 3.5, 3.7, 2.8, 2.8, 2.4, 1.5};
2617     QVector<double> xError = {1000., 1000., 500., 800., 200., 80., 60., 20., 1.8, 1.0};
2618     QVector<double> yError = {1.0, 1.8, 4., 8., 20., 20., 70., 70., 100., 500.};
2619 
2620     // data source columns
2621     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
2622     xDataColumn.replaceValues(0, xData);
2623 
2624     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
2625     yDataColumn.replaceValues(0, yData);
2626 
2627     Column xErrorColumn(QStringLiteral("xerr"), AbstractColumn::ColumnMode::Double);
2628     xErrorColumn.replaceValues(0, xError);
2629 
2630     Column yErrorColumn(QStringLiteral("yerr"), AbstractColumn::ColumnMode::Double);
2631     yErrorColumn.replaceValues(0, yError);
2632 
2633     XYFitCurve fitCurve(QStringLiteral("fit"));
2634     fitCurve.setXDataColumn(&xDataColumn);
2635     fitCurve.setYDataColumn(&yDataColumn);
2636     fitCurve.setXErrorColumn(&xErrorColumn);
2637     fitCurve.setYErrorColumn(&yErrorColumn);
2638 
2639     // prepare the fit
2640     XYFitCurve::FitData fitData = fitCurve.fitData();
2641     fitData.modelCategory = nsl_fit_model_basic;
2642     fitData.modelType = nsl_fit_model_polynomial;
2643     fitData.degree = 1;
2644     XYFitCurve::initFitData(fitData);
2645     fitData.eps = 1.e-12;
2646     const int np = fitData.paramNames.size();
2647     fitData.paramStartValues << 5. << -0.5;
2648     fitData.xWeightsType = nsl_fit_weight_direct;
2649     fitData.yWeightsType = nsl_fit_weight_direct;
2650     fitCurve.setFitData(fitData);
2651 
2652     // perform the fit
2653     fitCurve.recalculate();
2654     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
2655 
2656     // check the results
2657     QCOMPARE(fitResult.available, true);
2658     QCOMPARE(fitResult.valid, true);
2659 
2660     QCOMPARE(np, 2);
2661 
2662     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 5.3960522989993
2663     FuzzyCompare(fitResult.paramValues.at(0), 5.39749958415886, 3.e-4); // gnuplot result ("effective variance" method)
2664     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 0.361458387983792
2665     FuzzyCompare(fitResult.errorValues.at(0), 0.361439886824914, 1.e-4); // -""-
2666     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: -0.463448925094435
2667     FuzzyCompare(fitResult.paramValues.at(1), -0.463744669606207, 1.e-3); // -""-
2668     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 0.0706627287153768
2669     FuzzyCompare(fitResult.errorValues.at(1), 0.0706637562101211, 1.e-4); // -""-
2670 
2671     DEBUG(std::setprecision(15) << fitResult.rms); // result: 1.49455608152396
2672     FuzzyCompare(fitResult.rms, 1.49417194665446, 1.e-3); // gnuplot result ("effective variance" method)
2673     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 1.22252038082151
2674     FuzzyCompare(fitResult.rsd, 1.22236326296828, 1.e-3); // -""-
2675     DEBUG(std::setprecision(15) << fitResult.sse); // result: 11.9564486521917
2676     FuzzyCompare(fitResult.sse, 11.9533755732357, 1.e-3); // -""-
2677     DEBUG(std::setprecision(15) << fitResult.fdist_p); // result: 0.00441031749154456
2678     // TODO QCOMPARE(fitResult.fdist_p, 0.153296328355244);
2679 }
2680 
2681 // see http://gnuplot.sourceforge.net/demo_5.2/fit.html
2682 void FitTest::testLinearGP_PY_xyerror_custom() {
2683     // Pearson's data and York's weights
2684     QVector<double> xData = {0.0, 0.9, 1.8, 2.6, 3.3, 4.4, 5.2, 6.1, 6.5, 7.4};
2685     QVector<double> yData = {5.9, 5.4, 4.4, 4.6, 3.5, 3.7, 2.8, 2.8, 2.4, 1.5};
2686     QVector<double> xError = {1000., 1000., 500., 800., 200., 80., 60., 20., 1.8, 1.0};
2687     QVector<double> yError = {1.0, 1.8, 4., 8., 20., 20., 70., 70., 100., 500.};
2688 
2689     // data source columns
2690     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
2691     xDataColumn.replaceValues(0, xData);
2692 
2693     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
2694     yDataColumn.replaceValues(0, yData);
2695 
2696     Column xErrorColumn(QStringLiteral("xerr"), AbstractColumn::ColumnMode::Double);
2697     xErrorColumn.replaceValues(0, xError);
2698 
2699     Column yErrorColumn(QStringLiteral("yerr"), AbstractColumn::ColumnMode::Double);
2700     yErrorColumn.replaceValues(0, yError);
2701 
2702     XYFitCurve fitCurve(QStringLiteral("fit"));
2703     fitCurve.setXDataColumn(&xDataColumn);
2704     fitCurve.setYDataColumn(&yDataColumn);
2705     fitCurve.setXErrorColumn(&xErrorColumn);
2706     fitCurve.setYErrorColumn(&yErrorColumn);
2707 
2708     // prepare the fit
2709     XYFitCurve::FitData fitData = fitCurve.fitData();
2710     fitData.modelCategory = nsl_fit_model_custom;
2711     XYFitCurve::initFitData(fitData);
2712     fitData.model = QStringLiteral("a1 + a2 * x");
2713     fitData.paramNames << QStringLiteral("a1") << QStringLiteral("a2");
2714     fitData.eps = 1.e-12;
2715     const int np = fitData.paramNames.size();
2716     fitData.paramStartValues << 5. << -0.5;
2717     for (int i = 0; i < np; i++) {
2718         fitData.paramLowerLimits << -std::numeric_limits<double>::max();
2719         fitData.paramUpperLimits << std::numeric_limits<double>::max();
2720     }
2721 
2722     fitData.xWeightsType = nsl_fit_weight_direct;
2723     fitData.yWeightsType = nsl_fit_weight_direct;
2724     fitCurve.setFitData(fitData);
2725 
2726     // perform the fit
2727     fitCurve.recalculate();
2728     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
2729 
2730     // check the results
2731     QCOMPARE(fitResult.available, true);
2732     QCOMPARE(fitResult.valid, true);
2733 
2734     QCOMPARE(np, 2);
2735 
2736     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 5.39605223831693
2737     FuzzyCompare(fitResult.paramValues.at(0), 5.39749958415886, 3.e-4); // gnuplot result ("effective variance" method)
2738     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 0.361458369696386
2739     FuzzyCompare(fitResult.errorValues.at(0), 0.361439886824914, 1.e-4); // -""-
2740     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: -0.463448913528306
2741     FuzzyCompare(fitResult.paramValues.at(1), -0.463744669606207, 1.e-3); // -""-
2742     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 0.0706627257036884
2743     FuzzyCompare(fitResult.errorValues.at(1), 0.0706637562101211, 1.e-4); // -""-
2744 
2745     DEBUG(std::setprecision(15) << fitResult.rms); // result: 1.49455596317092
2746     FuzzyCompare(fitResult.rms, 1.49417194665446, 1.e-3); // gnuplot result ("effective variance" method)
2747     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 1.22252033241616
2748     FuzzyCompare(fitResult.rsd, 1.22236326296828, 1.e-3); // -""-
2749     DEBUG(std::setprecision(15) << fitResult.sse); // result: 11.9564477053674
2750     FuzzyCompare(fitResult.sse, 11.9533755732357, 1.e-3); // -""-
2751     DEBUG(std::setprecision(15) << fitResult.fdist_p); // result: 0.00441031645455255
2752     // TODO QCOMPARE(fitResult.fdist_p, 0.153296328355244);
2753 }
2754 
2755 // see http://gnuplot.sourceforge.net/demo_5.2/fit.html
2756 void FitTest::testLinearGP_PY_xyerror_custom_instrumental_weight() {
2757     // Pearson's data and York's weights
2758     QVector<double> xData = {0.0, 0.9, 1.8, 2.6, 3.3, 4.4, 5.2, 6.1, 6.5, 7.4};
2759     QVector<double> yData = {5.9, 5.4, 4.4, 4.6, 3.5, 3.7, 2.8, 2.8, 2.4, 1.5};
2760     QVector<double> xError = {1000., 1000., 500., 800., 200., 80., 60., 20., 1.8, 1.0};
2761     QVector<double> yError = {1.0, 1.8, 4., 8., 20., 20., 70., 70., 100., 500.};
2762 
2763     // w_i -> s_i
2764     for (int i = 0; i < xError.size(); i++) {
2765         xError[i] = 1. / sqrt(xError[i]);
2766         yError[i] = 1. / sqrt(yError[i]);
2767     }
2768 
2769     // data source columns
2770     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
2771     xDataColumn.replaceValues(0, xData);
2772 
2773     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
2774     yDataColumn.replaceValues(0, yData);
2775 
2776     Column xErrorColumn(QStringLiteral("xerr"), AbstractColumn::ColumnMode::Double);
2777     xErrorColumn.replaceValues(0, xError);
2778 
2779     Column yErrorColumn(QStringLiteral("yerr"), AbstractColumn::ColumnMode::Double);
2780     yErrorColumn.replaceValues(0, yError);
2781 
2782     XYFitCurve fitCurve(QStringLiteral("fit"));
2783     fitCurve.setXDataColumn(&xDataColumn);
2784     fitCurve.setYDataColumn(&yDataColumn);
2785     fitCurve.setXErrorColumn(&xErrorColumn);
2786     fitCurve.setYErrorColumn(&yErrorColumn);
2787 
2788     // prepare the fit
2789     XYFitCurve::FitData fitData = fitCurve.fitData();
2790     fitData.modelCategory = nsl_fit_model_custom;
2791     XYFitCurve::initFitData(fitData);
2792     fitData.model = QStringLiteral("a1 + a2 * x");
2793     fitData.paramNames << QStringLiteral("a1") << QStringLiteral("a2");
2794     //  fitData.eps = 1.e-12;
2795     const int np = fitData.paramNames.size();
2796     fitData.paramStartValues << 5. << -0.5;
2797     for (int i = 0; i < np; i++) {
2798         fitData.paramLowerLimits << -std::numeric_limits<double>::max();
2799         fitData.paramUpperLimits << std::numeric_limits<double>::max();
2800     }
2801 
2802     fitData.xWeightsType = nsl_fit_weight_instrumental;
2803     fitData.yWeightsType = nsl_fit_weight_instrumental;
2804     fitCurve.setFitData(fitData);
2805 
2806     // perform the fit
2807     fitCurve.recalculate();
2808     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
2809 
2810     // check the results
2811     QCOMPARE(fitResult.available, true);
2812     QCOMPARE(fitResult.valid, true);
2813 
2814     QCOMPARE(np, 2);
2815 
2816     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 5.3960521880058
2817     FuzzyCompare(fitResult.paramValues.at(0), 5.39749958415886, 3.e-4); // gnuplot result ("effective variance" method)
2818     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 0.361458367406729
2819     FuzzyCompare(fitResult.errorValues.at(0), 0.361439886824914, 1.e-4); // -""-
2820     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: -0.463448904801834
2821     FuzzyCompare(fitResult.paramValues.at(1), -0.463744669606207, 1.e-3); // -""-
2822     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 0.0706627229337577
2823     FuzzyCompare(fitResult.errorValues.at(1), 0.0706637562101211, 1.e-4); // -""-
2824 
2825     DEBUG(std::setprecision(15) << fitResult.rms); // result: 1.49455610878403
2826     FuzzyCompare(fitResult.rms, 1.49417194665446, 1.e-3); // gnuplot result ("effective variance" method)
2827     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 1.22252039197063
2828     FuzzyCompare(fitResult.rsd, 1.22236326296828, 1.e-3); // -""-
2829     DEBUG(std::setprecision(15) << fitResult.sse); // result: 11.9564488702722
2830     FuzzyCompare(fitResult.sse, 11.9533755732357, 1.e-3); // -""-
2831     DEBUG(std::setprecision(15) << fitResult.fdist_p); // result: 0.00441031773039329
2832     // TODO QCOMPARE(fitResult.fdist_p, 0.153296328355244);
2833 }
2834 
2835 // see http://gnuplot.sourceforge.net/demo_5.2/fit.html
2836 void FitTest::testLinearGP_PY_xyerror_custom_inverse_weight() {
2837     // Pearson's data and York's weights
2838     QVector<double> xData = {0.0, 0.9, 1.8, 2.6, 3.3, 4.4, 5.2, 6.1, 6.5, 7.4};
2839     QVector<double> yData = {5.9, 5.4, 4.4, 4.6, 3.5, 3.7, 2.8, 2.8, 2.4, 1.5};
2840     QVector<double> xError = {1000., 1000., 500., 800., 200., 80., 60., 20., 1.8, 1.0};
2841     QVector<double> yError = {1.0, 1.8, 4., 8., 20., 20., 70., 70., 100., 500.};
2842 
2843     // w_i -> 1/w_i
2844     for (int i = 0; i < xError.size(); i++) {
2845         xError[i] = 1. / xError[i];
2846         yError[i] = 1. / yError[i];
2847     }
2848 
2849     // data source columns
2850     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
2851     xDataColumn.replaceValues(0, xData);
2852 
2853     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
2854     yDataColumn.replaceValues(0, yData);
2855 
2856     Column xErrorColumn(QStringLiteral("xerr"), AbstractColumn::ColumnMode::Double);
2857     xErrorColumn.replaceValues(0, xError);
2858 
2859     Column yErrorColumn(QStringLiteral("yerr"), AbstractColumn::ColumnMode::Double);
2860     yErrorColumn.replaceValues(0, yError);
2861 
2862     XYFitCurve fitCurve(QStringLiteral("fit"));
2863     fitCurve.setXDataColumn(&xDataColumn);
2864     fitCurve.setYDataColumn(&yDataColumn);
2865     fitCurve.setXErrorColumn(&xErrorColumn);
2866     fitCurve.setYErrorColumn(&yErrorColumn);
2867 
2868     // prepare the fit
2869     XYFitCurve::FitData fitData = fitCurve.fitData();
2870     fitData.modelCategory = nsl_fit_model_custom;
2871     XYFitCurve::initFitData(fitData);
2872     fitData.model = QStringLiteral("a1 + a2 * x");
2873     fitData.paramNames << QStringLiteral("a1") << QStringLiteral("a2");
2874     //  fitData.eps = 1.e-12;
2875     const int np = fitData.paramNames.size();
2876     fitData.paramStartValues << 5. << -0.5;
2877     for (int i = 0; i < np; i++) {
2878         fitData.paramLowerLimits << -std::numeric_limits<double>::max();
2879         fitData.paramUpperLimits << std::numeric_limits<double>::max();
2880     }
2881 
2882     fitData.xWeightsType = nsl_fit_weight_inverse;
2883     fitData.yWeightsType = nsl_fit_weight_inverse;
2884     fitCurve.setFitData(fitData);
2885 
2886     // perform the fit
2887     fitCurve.recalculate();
2888     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
2889 
2890     // check the results
2891     QCOMPARE(fitResult.available, true);
2892     QCOMPARE(fitResult.valid, true);
2893 
2894     QCOMPARE(np, 2);
2895 
2896     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 5.39605219384715
2897     FuzzyCompare(fitResult.paramValues.at(0), 5.39749958415886, 3.e-4); // gnuplot result ("effective variance" method)
2898     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 0.361458367208767
2899     FuzzyCompare(fitResult.errorValues.at(0), 0.361439886824914, 1.e-4); // -""-
2900     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: -0.463448906090293
2901     FuzzyCompare(fitResult.paramValues.at(1), -0.463744669606207, 1.e-3); // -""-
2902     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 0.0706627222052917
2903     FuzzyCompare(fitResult.errorValues.at(1), 0.0706637562101211, 1.e-4); // -""-
2904 
2905     DEBUG(std::setprecision(15) << fitResult.rms); // result: 1.49455610679827
2906     FuzzyCompare(fitResult.rms, 1.49417194665446, 1.e-3); // gnuplot result ("effective variance" method)
2907     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 1.22252039115847
2908     FuzzyCompare(fitResult.rsd, 1.22236326296828, 1.e-3); // -""-
2909     DEBUG(std::setprecision(15) << fitResult.sse); // result: 11.9564488543861
2910     FuzzyCompare(fitResult.sse, 11.9533755732357, 1.e-3); // -""-
2911     DEBUG(std::setprecision(15) << fitResult.fdist_p); // result: 0.00441031771299435
2912     // TODO QCOMPARE(fitResult.fdist_p, 0.153296328355244);
2913 }
2914 
2915 // see https://bugs.kde.org/show_bug.cgi?id=408535
2916 void FitTest::testNonLinear_yerror_zero_bug408535() {
2917     QVector<double> xData = {0.0,  320., 320., 360., 360., 400., 400., 440., 440., 480., 480., 520., 520., 560.,  560.,  600.,  600., 640.,
2918                              640., 680., 680., 720., 720., 760., 760., 800., 800., 840., 840., 880., 880., 1200., 1200., 1200., 1200.};
2919     QVector<double> yData = {0.0,  160., 120., 190., 120., 210., 140., 220., 170., 230., 190., 240., 210., 250., 230., 270., 240., 260.,
2920                              270., 290., 240., 310., 270., 320., 290., 330., 290., 320., 300., 330., 310., 370., 390., 390., 400.};
2921     QVector<double> yError = {0.0, 15., 15., 15., 15., 15., 15., 15., 15., 15., 15., 15., 15., 15., 15., 15., 15., 15.,
2922                               15., 15., 15., 15., 15., 15., 15., 15., 15., 15., 15., 15., 15., 15., 15., 15., 15.};
2923 
2924     // data source columns
2925     Column xDataColumn(QStringLiteral("x"), AbstractColumn::ColumnMode::Double);
2926     xDataColumn.replaceValues(0, xData);
2927 
2928     Column yDataColumn(QStringLiteral("y"), AbstractColumn::ColumnMode::Double);
2929     yDataColumn.replaceValues(0, yData);
2930 
2931     Column yErrorColumn(QStringLiteral("yerr"), AbstractColumn::ColumnMode::Double);
2932     yErrorColumn.replaceValues(0, yError);
2933 
2934     XYFitCurve fitCurve(QStringLiteral("fit"));
2935     fitCurve.setXDataColumn(&xDataColumn);
2936     fitCurve.setYDataColumn(&yDataColumn);
2937     fitCurve.setYErrorColumn(&yErrorColumn);
2938 
2939     // prepare the fit
2940     XYFitCurve::FitData fitData = fitCurve.fitData();
2941     fitData.modelCategory = nsl_fit_model_custom;
2942     XYFitCurve::initFitData(fitData);
2943     fitData.model = QStringLiteral("A*exp(-B/x)");
2944     fitData.paramNames << QStringLiteral("A") << QStringLiteral("B");
2945     //  fitData.eps = 1.e-12;
2946     const int np = fitData.paramNames.size();
2947     fitData.paramStartValues << 100. << 100.;
2948     for (int i = 0; i < np; i++) {
2949         fitData.paramLowerLimits << -std::numeric_limits<double>::max();
2950         fitData.paramUpperLimits << std::numeric_limits<double>::max();
2951     }
2952 
2953     fitData.yWeightsType = nsl_fit_weight_instrumental;
2954     fitCurve.setFitData(fitData);
2955 
2956     // perform the fit
2957     fitCurve.recalculate();
2958     const XYFitCurve::FitResult& fitResult = fitCurve.fitResult();
2959 
2960     // check the results
2961     QCOMPARE(fitResult.available, true);
2962     QCOMPARE(fitResult.valid, true);
2963 
2964     QCOMPARE(np, 2);
2965 
2966     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 557.463875234563, Win: 557.463888957409
2967     FuzzyCompare(fitResult.paramValues.at(0), 557.463875234563, 1.e-7);
2968     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 22.0490332546127, FreeBSD: 22.0490429285665
2969     FuzzyCompare(fitResult.errorValues.at(0), 22.0490332546127, 1.e-6);
2970     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 468.319724706721, Win: 468.319742522772
2971     FuzzyCompare(fitResult.paramValues.at(1), 468.319724706721, 1.e-7);
2972     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 26.5105791274139, FreeBSD: 26.510591238283
2973     FuzzyCompare(fitResult.errorValues.at(1), 26.5105791274139, 1.e-6);
2974 
2975     DEBUG(std::setprecision(15) << fitResult.rms); // result: 1.96172656494138
2976     FuzzyCompare(fitResult.rms, 1.96172656494138, 1.e-9);
2977     DEBUG(std::setprecision(15) << fitResult.rsd); // result: 1.4006164945985
2978     FuzzyCompare(fitResult.rsd, 1.4006164945985, 1.e-9);
2979     DEBUG(std::setprecision(15) << fitResult.sse); // result: 64.7369766430654
2980     FuzzyCompare(fitResult.sse, 64.7369766430654, 1.e-9);
2981     DEBUG(std::setprecision(15) << fitResult.rsquare); // result: 0.999740417228134
2982     FuzzyCompare(fitResult.rsquare, 0.999740417228134, 1.e-9);
2983     DEBUG(std::setprecision(15) << fitResult.rsquareAdj); // result: 0.999724193304893
2984     FuzzyCompare(fitResult.rsquareAdj, 0.999724193304893, 1.e-9);
2985 }
2986 
2987 void FitTest::testHistogramFit() {
2988     Project project;
2989     project.load(QFINDTESTDATA(QLatin1String("data/TestHistogramFit.lml")));
2990 
2991     auto* aspect = project.child<AbstractAspect>(0);
2992     QVERIFY(aspect != nullptr);
2993     QCOMPARE(aspect->name(), QLatin1String("Spreadsheet"));
2994     QVERIFY(aspect->type() == AspectType::Spreadsheet);
2995     aspect = project.child<AbstractAspect>(1);
2996     QVERIFY(aspect != nullptr);
2997 
2998     QCOMPARE(aspect->name(), QLatin1String("Worksheet - Spreadsheet"));
2999     QVERIFY(aspect->type() == AspectType::Worksheet);
3000     auto w = dynamic_cast<Worksheet*>(aspect);
3001     if (!w)
3002         return;
3003 
3004     auto plot = dynamic_cast<CartesianPlot*>(aspect->child<CartesianPlot>(0));
3005     QVERIFY(plot != nullptr);
3006 
3007     QCOMPARE(plot->name(), QLatin1String("Plot - Spreadsheet"));
3008     auto hist = dynamic_cast<Histogram*>(plot->child<Histogram>(0));
3009     QVERIFY(hist != nullptr);
3010 
3011     QCOMPARE(hist->name(), QLatin1String("2"));
3012     // Do the fit
3013     plot->addHistogramFit(hist, nsl_sf_stats_gaussian);
3014 
3015     auto fit = dynamic_cast<XYFitCurve*>(plot->child<XYFitCurve>(0));
3016     QVERIFY(fit != nullptr);
3017 
3018     QCOMPARE(fit->name(), QLatin1String("Distribution Fit to '2'"));
3019     // get results
3020     const XYFitCurve::FitResult& fitResult = fit->fitResult();
3021 
3022     QCOMPARE(fitResult.available, true);
3023     QCOMPARE(fitResult.valid, true);
3024 
3025     // ML results
3026     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0));
3027     QCOMPARE(fitResult.paramValues.at(0), 1.);
3028     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1));
3029     QCOMPARE(fitResult.paramValues.at(1), 0.999776858937);
3030     DEBUG(std::setprecision(15) << fitResult.paramValues.at(2));
3031     QCOMPARE(fitResult.paramValues.at(2), -0.0294045302042);
3032 
3033     /* LM results
3034     DEBUG(std::setprecision(15) << fitResult.paramValues.at(0));
3035     QCOMPARE(fitResult.paramValues.at(0), 0.999829585605626);
3036     DEBUG(std::setprecision(15) << fitResult.errorValues.at(0));
3037     QCOMPARE(fitResult.errorValues.at(0), 0.0313884775124071);
3038     DEBUG(std::setprecision(15) << fitResult.paramValues.at(1));
3039     QCOMPARE(fitResult.paramValues.at(1), 0.988871409810129);
3040     DEBUG(std::setprecision(15) << fitResult.errorValues.at(1));
3041     QCOMPARE(fitResult.errorValues.at(1), 0.0358652107488108);
3042     DEBUG(std::setprecision(15) << fitResult.paramValues.at(2));
3043     QCOMPARE(fitResult.paramValues.at(2), -0.138053471452345);
3044     DEBUG(std::setprecision(15) << fitResult.errorValues.at(2));
3045     QCOMPARE(fitResult.errorValues.at(2), 0.0358379697268546);
3046 
3047     DEBUG(std::setprecision(15) << fitResult.rms); // result:
3048     QCOMPARE(fitResult.rms, 0.000890023253844838);
3049     DEBUG(std::setprecision(15) << fitResult.rsd); // result:
3050     QCOMPARE(fitResult.rsd, 0.0298332575131318);
3051     DEBUG(std::setprecision(15) << fitResult.sse); // result:
3052     QCOMPARE(fitResult.sse, 0.0249206511076555);
3053     DEBUG(std::setprecision(15) << fitResult.rsquare); // result:
3054     QCOMPARE(fitResult.rsquare, 0.961753741845289);
3055     DEBUG(std::setprecision(15) << fitResult.rsquareAdj); // result:
3056     QCOMPARE(fitResult.rsquareAdj, 0.957504157605876);
3057     */
3058 }
3059 
3060 void FitTest::testHistogramGaussianML() {
3061     Spreadsheet spreadsheet(QStringLiteral("test"), false);
3062     AsciiFilter filter;
3063 
3064     const QString& fileName = QFINDTESTDATA(QLatin1String("data/Gaussian.dat"));
3065 
3066     filter.setHeaderEnabled(false);
3067     filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace);
3068 
3069     QCOMPARE(spreadsheet.rowCount(), 1000);
3070     QCOMPARE(spreadsheet.columnCount(), 1);
3071 
3072     Worksheet worksheet(QStringLiteral("test"), false);
3073     auto* plot = new CartesianPlot(QStringLiteral("plot"));
3074     worksheet.addChild(plot);
3075 
3076     auto* hist = new Histogram(QStringLiteral("Histogram"));
3077     plot->addChild(hist);
3078     hist->setDataColumn(spreadsheet.column(0));
3079 
3080     // Do the fit
3081     plot->addHistogramFit(hist, nsl_sf_stats_gaussian);
3082 
3083     auto fit = dynamic_cast<XYFitCurve*>(plot->child<XYFitCurve>(0));
3084     QVERIFY(fit != nullptr);
3085 
3086     QCOMPARE(fit->name(), QLatin1String("Distribution Fit to 'Histogram'"));
3087     // get results
3088     const XYFitCurve::FitResult& fitResult = fit->fitResult();
3089 
3090     QCOMPARE(fitResult.available, true);
3091     QCOMPARE(fitResult.valid, true);
3092 
3093     WARN(std::setprecision(15) << fitResult.paramValues.at(0));
3094     QCOMPARE(fitResult.paramValues.at(0), 210.380459328);
3095     WARN(std::setprecision(15) << fitResult.paramValues.at(1));
3096     QCOMPARE(fitResult.paramValues.at(1), 0.999776858937);
3097     WARN(std::setprecision(15) << fitResult.errorValues.at(1));
3098     QCOMPARE(fitResult.errorValues.at(1), 0.0223507017166885);
3099     WARN(std::setprecision(15) << fitResult.paramValues.at(1) - fitResult.marginValues.at(1));
3100     QCOMPARE(fitResult.paramValues.at(1) - fitResult.marginValues.at(1), 0.955917043549699);
3101     WARN(std::setprecision(15) << fitResult.paramValues.at(1) + fitResult.marginValues.at(1));
3102     QCOMPARE(fitResult.paramValues.at(1) + fitResult.marginValues.at(1), 1.0436366743251);
3103 
3104     WARN(std::setprecision(15) << fitResult.paramValues.at(2));
3105     QCOMPARE(fitResult.paramValues.at(2), -0.0294045302042);
3106     WARN(std::setprecision(15) << fitResult.errorValues.at(2));
3107     QCOMPARE(fitResult.errorValues.at(2), 0.0316157202617);
3108     WARN(std::setprecision(15) << fitResult.paramValues.at(2) - fitResult.marginValues.at(2));
3109     QCOMPARE(fitResult.paramValues.at(2) - fitResult.marginValues.at(2), -0.0914455198610062);
3110     WARN(std::setprecision(15) << fitResult.paramValues.at(2) + fitResult.marginValues.at(2));
3111     QCOMPARE(fitResult.paramValues.at(2) + fitResult.marginValues.at(2), 0.0326364594526431);
3112 }
3113 
3114 void FitTest::testHistogramExponentialML() {
3115     Spreadsheet spreadsheet(QStringLiteral("test"), false);
3116     AsciiFilter filter;
3117 
3118     const QString& fileName = QFINDTESTDATA(QLatin1String("data/Exponential.dat"));
3119 
3120     filter.setHeaderEnabled(false);
3121     filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace);
3122 
3123     QCOMPARE(spreadsheet.rowCount(), 100);
3124     QCOMPARE(spreadsheet.columnCount(), 1);
3125 
3126     Worksheet worksheet(QStringLiteral("test"), false);
3127     auto* plot = new CartesianPlot(QStringLiteral("plot"));
3128     worksheet.addChild(plot);
3129 
3130     auto* hist = new Histogram(QStringLiteral("Histogram"));
3131     plot->addChild(hist);
3132     hist->setDataColumn(spreadsheet.column(0));
3133 
3134     // Do the fit
3135     plot->addHistogramFit(hist, nsl_sf_stats_exponential);
3136 
3137     auto fit = dynamic_cast<XYFitCurve*>(plot->child<XYFitCurve>(0));
3138     QVERIFY(fit != nullptr);
3139 
3140     QCOMPARE(fit->name(), QLatin1String("Distribution Fit to 'Histogram'"));
3141     // get results
3142     const XYFitCurve::FitResult& fitResult = fit->fitResult();
3143 
3144     QCOMPARE(fitResult.available, true);
3145     QCOMPARE(fitResult.valid, true);
3146 
3147     WARN(std::setprecision(15) << fitResult.paramValues.at(0));
3148     QCOMPARE(fitResult.paramValues.at(0), 41.6543778722);
3149     WARN(std::setprecision(15) << fitResult.paramValues.at(1));
3150     QCOMPARE(fitResult.paramValues.at(1), 1.93906050400681);
3151     WARN(std::setprecision(15) << fitResult.errorValues.at(1));
3152     QCOMPARE(fitResult.errorValues.at(1), 0.195884683568035);
3153     WARN(std::setprecision(15) << fitResult.paramValues.at(1) - fitResult.marginValues.at(1));
3154     QCOMPARE(fitResult.paramValues.at(1) - fitResult.marginValues.at(1), 1.5740096363284);
3155     WARN(std::setprecision(15) << fitResult.paramValues.at(1) + fitResult.margin2Values.at(1));
3156     QCOMPARE(fitResult.paramValues.at(1) + fitResult.margin2Values.at(1), 2.34119114746796);
3157     WARN(std::setprecision(15) << fitResult.paramValues.at(2));
3158     QCOMPARE(fitResult.paramValues.at(2), 5.01032231564491);
3159 }
3160 
3161 void FitTest::testHistogramLaplaceML() {
3162     Spreadsheet spreadsheet(QStringLiteral("test"), false);
3163     AsciiFilter filter;
3164 
3165     const QString& fileName = QFINDTESTDATA(QLatin1String("data/Laplace.dat"));
3166 
3167     filter.setHeaderEnabled(false);
3168     filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace);
3169 
3170     QCOMPARE(spreadsheet.rowCount(), 100);
3171     QCOMPARE(spreadsheet.columnCount(), 1);
3172 
3173     Worksheet worksheet(QStringLiteral("test"), false);
3174     auto* plot = new CartesianPlot(QStringLiteral("plot"));
3175     worksheet.addChild(plot);
3176 
3177     auto* hist = new Histogram(QStringLiteral("Histogram"));
3178     plot->addChild(hist);
3179     hist->setDataColumn(spreadsheet.column(0));
3180 
3181     // Do the fit
3182     plot->addHistogramFit(hist, nsl_sf_stats_laplace);
3183 
3184     auto fit = dynamic_cast<XYFitCurve*>(plot->child<XYFitCurve>(0));
3185     QVERIFY(fit != nullptr);
3186 
3187     QCOMPARE(fit->name(), QLatin1String("Distribution Fit to 'Histogram'"));
3188     // get results
3189     const XYFitCurve::FitResult& fitResult = fit->fitResult();
3190 
3191     QCOMPARE(fitResult.available, true);
3192     QCOMPARE(fitResult.valid, true);
3193 
3194     WARN(std::setprecision(15) << fitResult.paramValues.at(0));
3195     QCOMPARE(fitResult.paramValues.at(0), 145.64147805241);
3196     WARN(std::setprecision(15) << fitResult.paramValues.at(1));
3197     QCOMPARE(fitResult.paramValues.at(1), 1.99538835213796);
3198     WARN(std::setprecision(15) << fitResult.paramValues.at(2));
3199     QCOMPARE(fitResult.paramValues.at(2), 4.95890340967321);
3200 }
3201 
3202 void FitTest::testHistogramCauchyML() {
3203     Spreadsheet spreadsheet(QStringLiteral("test"), false);
3204     AsciiFilter filter;
3205 
3206     const QString& fileName = QFINDTESTDATA(QLatin1String("data/Cauchy.dat"));
3207 
3208     filter.setHeaderEnabled(false);
3209     filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace);
3210 
3211     QCOMPARE(spreadsheet.rowCount(), 1000);
3212     QCOMPARE(spreadsheet.columnCount(), 1);
3213 
3214     Worksheet worksheet(QStringLiteral("test"), false);
3215     auto* plot = new CartesianPlot(QStringLiteral("plot"));
3216     worksheet.addChild(plot);
3217 
3218     auto* hist = new Histogram(QStringLiteral("Histogram"));
3219     plot->addChild(hist);
3220     hist->setDataColumn(spreadsheet.column(0));
3221 
3222     // Do the fit
3223     plot->addHistogramFit(hist, nsl_sf_stats_cauchy_lorentz);
3224 
3225     auto fit = dynamic_cast<XYFitCurve*>(plot->child<XYFitCurve>(0));
3226     QVERIFY(fit != nullptr);
3227 
3228     QCOMPARE(fit->name(), QLatin1String("Distribution Fit to 'Histogram'"));
3229     // get results
3230     const XYFitCurve::FitResult& fitResult = fit->fitResult();
3231 
3232     QCOMPARE(fitResult.available, true);
3233     QCOMPARE(fitResult.valid, true);
3234 
3235     WARN(std::setprecision(15) << fitResult.paramValues.at(0));
3236     QCOMPARE(fitResult.paramValues.at(0), 34973.659700564);
3237     WARN(std::setprecision(15) << fitResult.paramValues.at(1));
3238     QCOMPARE(fitResult.paramValues.at(1), 1.87876026823743);
3239     WARN(std::setprecision(15) << fitResult.paramValues.at(2));
3240     QCOMPARE(fitResult.paramValues.at(2), 5.09155507540282);
3241 }
3242 
3243 void FitTest::testHistogramLognormalML() {
3244     Spreadsheet spreadsheet(QStringLiteral("test"), false);
3245     AsciiFilter filter;
3246 
3247     const QString& fileName = QFINDTESTDATA(QLatin1String("data/Lognormal.dat"));
3248 
3249     filter.setHeaderEnabled(false);
3250     filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace);
3251 
3252     QCOMPARE(spreadsheet.rowCount(), 1000);
3253     QCOMPARE(spreadsheet.columnCount(), 1);
3254 
3255     Worksheet worksheet(QStringLiteral("test"), false);
3256     auto* plot = new CartesianPlot(QStringLiteral("plot"));
3257     worksheet.addChild(plot);
3258 
3259     auto* hist = new Histogram(QStringLiteral("Histogram"));
3260     plot->addChild(hist);
3261     hist->setDataColumn(spreadsheet.column(0));
3262 
3263     // Do the fit
3264     plot->addHistogramFit(hist, nsl_sf_stats_lognormal);
3265 
3266     auto fit = dynamic_cast<XYFitCurve*>(plot->child<XYFitCurve>(0));
3267     QVERIFY(fit != nullptr);
3268 
3269     QCOMPARE(fit->name(), QLatin1String("Distribution Fit to 'Histogram'"));
3270     // get results
3271     const XYFitCurve::FitResult& fitResult = fit->fitResult();
3272 
3273     QCOMPARE(fitResult.available, true);
3274     QCOMPARE(fitResult.valid, true);
3275 
3276     WARN(std::setprecision(15) << fitResult.paramValues.at(0));
3277     QCOMPARE(fitResult.paramValues.at(0), 4714813.91602);
3278     WARN(std::setprecision(15) << fitResult.paramValues.at(1));
3279     QCOMPARE(fitResult.paramValues.at(1), 2.07876791650682);
3280     WARN(std::setprecision(15) << fitResult.paramValues.at(2));
3281     QCOMPARE(fitResult.paramValues.at(2), 5.01070949852617);
3282 }
3283 
3284 void FitTest::testHistogramPoissonML() {
3285     Spreadsheet spreadsheet(QStringLiteral("test"), false);
3286     AsciiFilter filter;
3287 
3288     const QString& fileName = QFINDTESTDATA(QLatin1String("data/Poisson.dat"));
3289 
3290     filter.setHeaderEnabled(false);
3291     filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace);
3292 
3293     QCOMPARE(spreadsheet.rowCount(), 100);
3294     QCOMPARE(spreadsheet.columnCount(), 1);
3295 
3296     Worksheet worksheet(QStringLiteral("test"), false);
3297     auto* plot = new CartesianPlot(QStringLiteral("plot"));
3298     worksheet.addChild(plot);
3299 
3300     auto* hist = new Histogram(QStringLiteral("Histogram"));
3301     plot->addChild(hist);
3302     hist->setDataColumn(spreadsheet.column(0));
3303 
3304     // Do the fit
3305     plot->addHistogramFit(hist, nsl_sf_stats_poisson);
3306 
3307     auto fit = dynamic_cast<XYFitCurve*>(plot->child<XYFitCurve>(0));
3308     QVERIFY(fit != nullptr);
3309 
3310     QCOMPARE(fit->name(), QLatin1String("Distribution Fit to 'Histogram'"));
3311     // get results
3312     const XYFitCurve::FitResult& fitResult = fit->fitResult();
3313 
3314     QCOMPARE(fitResult.available, true);
3315     QCOMPARE(fitResult.valid, true);
3316 
3317     WARN(std::setprecision(15) << fitResult.paramValues.at(0));
3318     QCOMPARE(fitResult.paramValues.at(0), 150.);
3319     WARN(std::setprecision(15) << fitResult.paramValues.at(1));
3320     QCOMPARE(fitResult.paramValues.at(1), 9.55);
3321     WARN(std::setprecision(15) << fitResult.errorValues.at(1));
3322     QCOMPARE(fitResult.errorValues.at(1), 0.309030742807249);
3323     WARN(std::setprecision(15) << fitResult.paramValues.at(1) - fitResult.marginValues.at(1));
3324     QCOMPARE(fitResult.paramValues.at(1) - fitResult.marginValues.at(1), 8.95383732390823);
3325     WARN(std::setprecision(15) << fitResult.paramValues.at(1) + fitResult.margin2Values.at(1));
3326     QCOMPARE(fitResult.paramValues.at(1) + fitResult.margin2Values.at(1), 10.1754213697868);
3327 }
3328 
3329 void FitTest::testHistogramBinomialML() {
3330     Spreadsheet spreadsheet(QStringLiteral("test"), false);
3331     AsciiFilter filter;
3332 
3333     const QString& fileName = QFINDTESTDATA(QLatin1String("data/Binomial.dat"));
3334 
3335     filter.setHeaderEnabled(false);
3336     filter.readDataFromFile(fileName, &spreadsheet, AbstractFileFilter::ImportMode::Replace);
3337 
3338     QCOMPARE(spreadsheet.rowCount(), 100);
3339     QCOMPARE(spreadsheet.columnCount(), 1);
3340 
3341     Worksheet worksheet(QStringLiteral("test"), false);
3342     auto* plot = new CartesianPlot(QStringLiteral("plot"));
3343     worksheet.addChild(plot);
3344 
3345     auto* hist = new Histogram(QStringLiteral("Histogram"));
3346     plot->addChild(hist);
3347     hist->setDataColumn(spreadsheet.column(0));
3348 
3349     // Do the fit
3350     plot->addHistogramFit(hist, nsl_sf_stats_binomial);
3351 
3352     auto fit = dynamic_cast<XYFitCurve*>(plot->child<XYFitCurve>(0));
3353     QVERIFY(fit != nullptr);
3354 
3355     QCOMPARE(fit->name(), QLatin1String("Distribution Fit to 'Histogram'"));
3356     // get results
3357     const XYFitCurve::FitResult& fitResult = fit->fitResult();
3358 
3359     QCOMPARE(fitResult.available, true);
3360     QCOMPARE(fitResult.valid, true);
3361 
3362     WARN(std::setprecision(15) << fitResult.paramValues.at(0));
3363     QCOMPARE(fitResult.paramValues.at(0), 270.);
3364     WARN(std::setprecision(15) << fitResult.paramValues.at(1));
3365     QCOMPARE(fitResult.paramValues.at(1), 0.4931);
3366     WARN(std::setprecision(15) << fitResult.errorValues.at(1));
3367     QCOMPARE(fitResult.errorValues.at(1), 0.0499952387733072);
3368     WARN(std::setprecision(15) << fitResult.paramValues.at(1) - fitResult.marginValues.at(1));
3369     QCOMPARE(fitResult.paramValues.at(1) - fitResult.marginValues.at(1), 0.482953993308348);
3370     WARN(std::setprecision(15) << fitResult.paramValues.at(1) + fitResult.margin2Values.at(1));
3371     QCOMPARE(fitResult.paramValues.at(1) + fitResult.margin2Values.at(1), 0.503287947118723);
3372 
3373     QCOMPARE(fitResult.paramValues.at(2), spreadsheet.rowCount());
3374 }
3375 
3376 QTEST_MAIN(FitTest)