diff --git a/src/backend/gsl/ExpressionParser.cpp b/src/backend/gsl/ExpressionParser.cpp index cfafd4963..84177c2c4 100644 --- a/src/backend/gsl/ExpressionParser.cpp +++ b/src/backend/gsl/ExpressionParser.cpp @@ -1,1566 +1,1567 @@ /*************************************************************************** File : ExpressionParser.cpp Project : LabPlot -------------------------------------------------------------------- Copyright : (C) 2014 Alexander Semke (alexander.semke@web.de) Copyright : (C) 2014-2017 Stefan Gerlach (stefan.gerlach@uni.kn) Description : C++ wrapper for the bison generated parser. ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #include "backend/lib/macros.h" #include "backend/gsl/ExpressionParser.h" #include #include #include extern "C" { #include #include #include #include #include #include "backend/gsl/parser.h" } ExpressionParser* ExpressionParser::instance = NULL; ExpressionParser::ExpressionParser() { init_table(); initFunctions(); initConstants(); } void ExpressionParser::initFunctions() { //functions (sync with functions.h!) for (int i = 0; _functions[i].name != 0; i++) m_functions << _functions[i].name; m_functionsGroups << i18n("Standard Mathematical functions"); //http://www.gnu.org/software/gsl/manual/html_node/Special-Functions.html m_functionsGroups << i18n("Airy Functions and Derivatives"); m_functionsGroups << i18n("Bessel Functions"); m_functionsGroups << i18n("Clausen Functions"); m_functionsGroups << i18n("Coulomb Functions"); // m_functionsGroups << i18n("Coupling Coefficients"); m_functionsGroups << i18n("Dawson Function"); m_functionsGroups << i18n("Debye Functions"); m_functionsGroups << i18n("Dilogarithm"); // m_functionsGroups << i18n("Elementary Operations"); m_functionsGroups << i18n("Elliptic Integrals"); // m_functionsGroups << i18n("Elliptic Functions (Jacobi)"); m_functionsGroups << i18n("Error Functions"); m_functionsGroups << i18n("Exponential Functions"); m_functionsGroups << i18n("Exponential Integrals"); m_functionsGroups << i18n("Fermi-Dirac Function"); m_functionsGroups << i18n("Gamma and Beta Functions"); m_functionsGroups << i18n("Gegenbauer Functions"); #if (GSL_MAJOR_VERSION > 2) || (GSL_MAJOR_VERSION == 2) && (GSL_MINOR_VERSION >= 4) m_functionsGroups << i18n("Hermite Polynomials and Functions"); #endif m_functionsGroups << i18n("Hypergeometric Functions"); m_functionsGroups << i18n("Laguerre Functions"); m_functionsGroups << i18n("Lambert W Functions"); m_functionsGroups << i18n("Legendre Functions and Spherical Harmonics"); m_functionsGroups << i18n("Logarithm and Related Functions"); // m_functionsGroups << i18n("Mathieu Functions"); m_functionsGroups << i18n("Power Function"); m_functionsGroups << i18n("Psi (Digamma) Function"); m_functionsGroups << i18n("Synchrotron Functions"); m_functionsGroups << i18n("Transport Functions"); m_functionsGroups << i18n("Trigonometric Functions"); m_functionsGroups << i18n("Zeta Functions"); // GSL random distribution functions m_functionsGroups << i18n("Gaussian Distribution"); m_functionsGroups << i18n("Exponential Distribution"); m_functionsGroups << i18n("Laplace Distribution"); m_functionsGroups << i18n("Exponential Power Distribution"); m_functionsGroups << i18n("Cauchy Distribution"); m_functionsGroups << i18n("Rayleigh Distribution"); m_functionsGroups << i18n("Landau Distribution"); m_functionsGroups << i18n("Gamma Distribution"); m_functionsGroups << i18n("Flat (Uniform) Distribution"); m_functionsGroups << i18n("Lognormal Distribution"); m_functionsGroups << i18n("Chi-squared Distribution"); m_functionsGroups << i18n("F-distribution"); m_functionsGroups << i18n("t-distribution"); m_functionsGroups << i18n("Beta Distribution"); m_functionsGroups << i18n("Logistic Distribution"); m_functionsGroups << i18n("Pareto Distribution"); m_functionsGroups << i18n("Weibull Distribution"); m_functionsGroups << i18n("Gumbel Distribution"); m_functionsGroups << i18n("Poisson Distribution"); m_functionsGroups << i18n("Bernoulli Distribution"); m_functionsGroups << i18n("Binomial Distribution"); m_functionsGroups << i18n("Pascal Distribution"); m_functionsGroups << i18n("Geometric Distribution"); m_functionsGroups << i18n("Hypergeometric Distribution"); m_functionsGroups << i18n("Logarithmic Distribution"); int index = 0; // Standard mathematical functions m_functionsNames << i18n("pseudo-random integer [0,RAND_MAX]"); m_functionsNames << i18n("nonlinear additive feedback rng [0,RAND_MAX]"); m_functionsNames << i18n("nonlinear additive feedback rng [0,1]"); m_functionsNames << i18n("Smallest integral value not less"); m_functionsNames << i18n("Absolute value"); m_functionsNames << i18n("Base 10 logarithm"); m_functionsNames << i18n("Power function [x^y]"); m_functionsNames << i18n("Nonnegative square root"); m_functionsNames << i18n("Sign function"); m_functionsNames << i18n("Heavyside theta function"); #ifndef HAVE_WINDOWS m_functionsNames << i18n("Cube root"); m_functionsNames << i18n("Extract the exponent"); m_functionsNames << i18n("Round to an integer value"); m_functionsNames << i18n("Round to the nearest integer"); m_functionsNames << i18n("Round to the nearest integer"); #endif m_functionsNames << QString("log(1+x)"); m_functionsNames << QString("x * 2^e"); m_functionsNames << QString("x^n"); m_functionsNames << QString("x^2"); m_functionsNames << QString("x^3"); m_functionsNames << QString("x^4"); m_functionsNames << QString("x^5"); m_functionsNames << QString("x^6"); m_functionsNames << QString("x^7"); m_functionsNames << QString("x^8"); m_functionsNames << QString("x^9"); #ifndef HAVE_WINDOWS for (int i = 0; i < 26; i++) #else for (int i = 0; i < 21; i++) #endif m_functionsGroupIndex << index; // Airy Functions and Derivatives m_functionsNames << i18n("Airy function of the first kind"); m_functionsNames << i18n("Airy function of the second kind"); m_functionsNames << i18n("Scaled Airy function of the first kind"); m_functionsNames << i18n("Scaled Airy function of the second kind"); m_functionsNames << i18n("Airy function derivative of the first kind"); m_functionsNames << i18n("Airy function derivative of the second kind"); m_functionsNames << i18n("Scaled Airy function derivative of the first kind"); m_functionsNames << i18n("Scaled Airy function derivative of the second kind"); m_functionsNames << i18n("n-th zero of the Airy function of the first kind"); m_functionsNames << i18n("n-th zero of the Airy function of the second kind"); m_functionsNames << i18n("n-th zero of the Airy function derivative of the first kind"); m_functionsNames << i18n("n-th zero of the Airy function derivative of the second kind"); index++; for (int i = 0; i < 12; i++) m_functionsGroupIndex << index; // Bessel Functions m_functionsNames << i18n("Regular cylindrical Bessel function of zeroth order"); m_functionsNames << i18n("Regular cylindrical Bessel function of first order"); m_functionsNames << i18n("Regular cylindrical Bessel function of order n"); m_functionsNames << i18n("Irregular cylindrical Bessel function of zeroth order"); m_functionsNames << i18n("Irregular cylindrical Bessel function of first order"); m_functionsNames << i18n("Irregular cylindrical Bessel function of order n"); m_functionsNames << i18n("Regular modified cylindrical Bessel function of zeroth order"); m_functionsNames << i18n("Regular modified cylindrical Bessel function of first order"); m_functionsNames << i18n("Regular modified cylindrical Bessel function of order n"); m_functionsNames << i18n("Scaled regular modified cylindrical Bessel function of zeroth order exp(-|x|) I0(x)"); m_functionsNames << i18n("Scaled regular modified cylindrical Bessel function of first order exp(-|x|) I1(x)"); m_functionsNames << i18n("Scaled regular modified cylindrical Bessel function of order n exp(-|x|) In(x)"); m_functionsNames << i18n("Irregular modified cylindrical Bessel function of zeroth order"); m_functionsNames << i18n("Irregular modified cylindrical Bessel function of first order"); m_functionsNames << i18n("Irregular modified cylindrical Bessel function of order n"); m_functionsNames << i18n("Scaled irregular modified cylindrical Bessel function of zeroth order exp(x) K0(x)"); m_functionsNames << i18n("Scaled irregular modified cylindrical Bessel function of first order exp(x) K1(x)"); m_functionsNames << i18n("Scaled irregular modified cylindrical Bessel function of order n exp(x) Kn(x)"); m_functionsNames << i18n("Regular spherical Bessel function of zeroth order"); m_functionsNames << i18n("Regular spherical Bessel function of first order"); m_functionsNames << i18n("Regular spherical Bessel function of second order"); m_functionsNames << i18n("Regular spherical Bessel function of order l"); m_functionsNames << i18n("Irregular spherical Bessel function of zeroth order"); m_functionsNames << i18n("Irregular spherical Bessel function of first order"); m_functionsNames << i18n("Irregular spherical Bessel function of second order"); m_functionsNames << i18n("Irregular spherical Bessel function of order l"); m_functionsNames << i18n("Scaled regular modified spherical Bessel function of zeroth order, exp(-|x|) i0(x)"); m_functionsNames << i18n("Scaled regular modified spherical Bessel function of first order, exp(-|x|) i1(x)"); m_functionsNames << i18n("Scaled regular modified spherical Bessel function of second order, exp(-|x|) i2(x)"); m_functionsNames << i18n("Scaled regular modified spherical Bessel function of order l, exp(-|x|) il(x)"); m_functionsNames << i18n("Scaled irregular modified spherical Bessel function of zeroth order, exp(x) k0(x)"); m_functionsNames << i18n("Scaled irregular modified spherical Bessel function of first order, exp(-|x|) k1(x)"); m_functionsNames << i18n("Scaled irregular modified spherical Bessel function of second order, exp(-|x|) k2(x)"); m_functionsNames << i18n("Scaled irregular modified spherical Bessel function of order l, exp(-|x|) kl(x)"); m_functionsNames << i18n("Regular cylindrical Bessel function of fractional order"); m_functionsNames << i18n("Irregular cylindrical Bessel function of fractional order"); m_functionsNames << i18n("Regular modified Bessel function of fractional order"); m_functionsNames << i18n("Scaled regular modified Bessel function of fractional order"); m_functionsNames << i18n("Irregular modified Bessel function of fractional order"); m_functionsNames << i18n("Logarithm of irregular modified Bessel function of fractional order"); m_functionsNames << i18n("Scaled irregular modified Bessel function of fractional order"); m_functionsNames << i18n("n-th positive zero of the Bessel function J0"); m_functionsNames << i18n("n-th positive zero of the Bessel function J1"); m_functionsNames << i18n("n-th positive zero of the Bessel function Jnu"); index++; for (int i = 0; i < 44; i++) m_functionsGroupIndex << index; // Clausen Functions m_functionsNames << i18n("Clausen function"); index++; m_functionsGroupIndex << index; // Coulomb Functions m_functionsNames << i18n("Lowest-order normalized hydrogenic bound state radial wavefunction"); m_functionsNames << i18n("n-th normalized hydrogenic bound state radial wavefunction"); index++; for (int i = 0; i < 2; i++) m_functionsGroupIndex << index; // Dawson Function m_functionsNames << i18n("Dawson integral"); index++; m_functionsGroupIndex << index; // Debye Functions m_functionsNames << i18n("First-order Debye function"); m_functionsNames << i18n("Second-order Debye function"); m_functionsNames << i18n("Third-order Debye function"); m_functionsNames << i18n("Fourth-order Debye function"); m_functionsNames << i18n("Fifth-order Debye function"); m_functionsNames << i18n("Sixth-order Debye function"); index++; for (int i = 0; i < 6; i++) m_functionsGroupIndex << index; // Dilogarithm m_functionsNames << i18n("Dilogarithm for a real argument"); index++; m_functionsGroupIndex << index; // Elliptic Integrals m_functionsNames << i18n("Legendre form of complete elliptic integral K"); m_functionsNames << i18n("Legendre form of complete elliptic integral E"); m_functionsNames << i18n("Legendre form of complete elliptic integral Pi"); m_functionsNames << i18n("Legendre form of incomplete elliptic integral F"); m_functionsNames << i18n("Legendre form of incomplete elliptic integral E"); m_functionsNames << i18n("Legendre form of incomplete elliptic integral P"); m_functionsNames << i18n("Legendre form of incomplete elliptic integral D"); m_functionsNames << i18n("Carlson form of incomplete elliptic integral RC"); m_functionsNames << i18n("Carlson form of incomplete elliptic integral RD"); m_functionsNames << i18n("Carlson form of incomplete elliptic integral RF"); m_functionsNames << i18n("Carlson form of incomplete elliptic integral RJ"); index++; for (int i = 0; i < 11; i++) m_functionsGroupIndex << index; // Error Functions m_functionsNames << i18n("Error function"); m_functionsNames << i18n("Complementary error function"); m_functionsNames << i18n("Logarithm of complementary error function"); m_functionsNames << i18n("Gaussian probability density function Z"); m_functionsNames << i18n("Upper tail of the Gaussian probability function Q"); m_functionsNames << i18n("Hazard function for the normal distribution Z/Q"); index++; for (int i = 0; i < 6; i++) m_functionsGroupIndex << index; // Exponential Functions m_functionsNames << i18n("Exponential function"); m_functionsNames << i18n("exponentiate x and multiply by y"); m_functionsNames << QString("exp(x) - 1"); m_functionsNames << QString("(exp(x)-1)/x"); m_functionsNames << QString("2(exp(x)-1-x)/x^2"); m_functionsNames << i18n("n-relative exponential"); index++; for (int i = 0; i < 6; i++) m_functionsGroupIndex << index; // Exponential Integrals m_functionsNames << i18n("Exponential integral"); m_functionsNames << i18n("Second order exponential integral"); m_functionsNames << i18n("Exponential integral of order n"); m_functionsNames << i18n("Exponential integral Ei"); m_functionsNames << i18n("Hyperbolic integral Shi"); m_functionsNames << i18n("Hyperbolic integral Chi"); m_functionsNames << i18n("Third-order exponential integral"); m_functionsNames << i18n("Sine integral"); m_functionsNames << i18n("Cosine integral"); m_functionsNames << i18n("Arctangent integral"); index++; for (int i = 0; i < 10; i++) m_functionsGroupIndex << index; // Fermi-Dirac Function m_functionsNames << i18n("Complete Fermi-Dirac integral with index -1"); m_functionsNames << i18n("Complete Fermi-Dirac integral with index 0"); m_functionsNames << i18n("Complete Fermi-Dirac integral with index 1"); m_functionsNames << i18n("Complete Fermi-Dirac integral with index 2"); m_functionsNames << i18n("Complete Fermi-Dirac integral with integer index j"); m_functionsNames << i18n("Complete Fermi-Dirac integral with index -1/2"); m_functionsNames << i18n("Complete Fermi-Dirac integral with index 1/2"); m_functionsNames << i18n("Complete Fermi-Dirac integral with index 3/2"); m_functionsNames << i18n("Incomplete Fermi-Dirac integral with index zero"); index++; for (int i = 0; i < 9; i++) m_functionsGroupIndex << index; // Gamma and Beta Functions m_functionsNames << i18n("Gamma function"); m_functionsNames << i18n("Gamma function"); m_functionsNames << i18n("Logarithm of the gamma function"); m_functionsNames << i18n("Logarithm of the gamma function"); m_functionsNames << i18n("Regulated gamma function"); m_functionsNames << i18n("Reciprocal of the gamma function"); m_functionsNames << i18n("Factorial n!"); m_functionsNames << i18n("Double factorial n!!"); m_functionsNames << i18n("Logarithm of the factorial"); m_functionsNames << i18n("Logarithm of the double factorial"); m_functionsNames << i18n("Combinatorial factor"); m_functionsNames << i18n("Logarithm of the combinatorial factor"); m_functionsNames << i18n("Taylor coefficient"); m_functionsNames << i18n("Pochhammer symbol"); m_functionsNames << i18n("Logarithm of the Pochhammer symbol"); m_functionsNames << i18n("Relative Pochhammer symbol"); m_functionsNames << i18n("Unnormalized incomplete gamma function"); m_functionsNames << i18n("Normalized incomplete gamma function"); m_functionsNames << i18n("Complementary normalized incomplete gamma function"); m_functionsNames << i18n("Beta function"); m_functionsNames << i18n("Logarithm of the beta function"); m_functionsNames << i18n("Normalized incomplete beta function"); index++; for (int i = 0; i < 22; i++) m_functionsGroupIndex << index; // Gegenbauer Functions m_functionsNames << i18n("Gegenbauer polynomial C_1"); m_functionsNames << i18n("Gegenbauer polynomial C_2"); m_functionsNames << i18n("Gegenbauer polynomial C_3"); m_functionsNames << i18n("Gegenbauer polynomial C_n"); index++; for (int i = 0; i < 4; i++) m_functionsGroupIndex << index; #if (GSL_MAJOR_VERSION > 2) || (GSL_MAJOR_VERSION == 2) && (GSL_MINOR_VERSION >= 4) // Hermite Polynomials and Functions m_functionsNames << i18n("Hermite polynomials physicists version"); m_functionsNames << i18n("Hermite polynomials probabilists version"); m_functionsNames << i18n("Hermite functions"); m_functionsNames << i18n("Derivatives of Hermite polynomials physicists version"); m_functionsNames << i18n("Derivatives of Hermite polynomials probabilists version"); m_functionsNames << i18n("Derivatives of Hermite functions"); index++; for (int i = 0; i < 6; i++) m_functionsGroupIndex << index; #endif // Hypergeometric Functions m_functionsNames << i18n("Hypergeometric function 0F1"); m_functionsNames << i18n("Confluent hypergeometric function 1F1 for integer parameters"); m_functionsNames << i18n("Confluent hypergeometric function 1F1 for general parameters"); m_functionsNames << i18n("Confluent hypergeometric function U for integer parameters"); m_functionsNames << i18n("Confluent hypergeometric function U"); m_functionsNames << i18n("Gauss hypergeometric function 2F1"); m_functionsNames << i18n("Gauss hypergeometric function 2F1 with complex parameters"); m_functionsNames << i18n("Renormalized Gauss hypergeometric function 2F1"); m_functionsNames << i18n("Renormalized Gauss hypergeometric function 2F1 with complex parameters"); m_functionsNames << i18n("Hypergeometric function 2F0"); index++; for (int i = 0; i < 10; i++) m_functionsGroupIndex << index; // Laguerre Functions m_functionsNames << i18n("generalized Laguerre polynomials L_1"); m_functionsNames << i18n("generalized Laguerre polynomials L_2"); m_functionsNames << i18n("generalized Laguerre polynomials L_3"); index++; for (int i = 0; i < 3; i++) m_functionsGroupIndex << index; // Lambert W Functions m_functionsNames << i18n("Principal branch of the Lambert W function"); m_functionsNames << i18n("Secondary real-valued branch of the Lambert W function"); index++; for (int i = 0; i < 2; i++) m_functionsGroupIndex << index; // Legendre Functions and Spherical Harmonics m_functionsNames << i18n("Legendre polynomial P_1"); m_functionsNames << i18n("Legendre polynomial P_2"); m_functionsNames << i18n("Legendre polynomial P_3"); m_functionsNames << i18n("Legendre polynomial P_l"); m_functionsNames << i18n("Legendre function Q_0"); m_functionsNames << i18n("Legendre function Q_1"); m_functionsNames << i18n("Legendre function Q_l"); m_functionsNames << i18n("Associated Legendre polynomial"); m_functionsNames << i18n("Normalized associated Legendre polynomial"); m_functionsNames << i18n("Irregular spherical conical function P^1/2"); m_functionsNames << i18n("Regular spherical conical function P^(-1/2)"); m_functionsNames << i18n("Conical function P^0"); m_functionsNames << i18n("Conical function P^1"); m_functionsNames << i18n("Regular spherical conical function P^(-1/2-l)"); m_functionsNames << i18n("Regular cylindrical conical function P^(-m)"); m_functionsNames << i18n("Zeroth radial eigenfunction of the Laplacian on the 3-dimensional hyperbolic space"); m_functionsNames << i18n("First radial eigenfunction of the Laplacian on the 3-dimensional hyperbolic space"); m_functionsNames << i18n("l-th radial eigenfunction of the Laplacian on the 3-dimensional hyperbolic space"); index++; for (int i = 0; i < 18; i++) m_functionsGroupIndex << index; // Logarithm and Related Functions m_functionsNames << i18n("Logarithm"); m_functionsNames << i18n("Logarithm of the magnitude"); m_functionsNames << QString("log(1+x)"); m_functionsNames << QString("log(1+x) - x"); index++; for (int i = 0; i < 4; i++) m_functionsGroupIndex << index; // Power Function m_functionsNames << i18n("x^n for integer n with an error estimate"); index++; m_functionsGroupIndex << index; // Psi (Digamma) Function m_functionsNames << i18n("Digamma function for positive integer n"); m_functionsNames << i18n("Digamma function"); m_functionsNames << i18n("Real part of the digamma function on the line 1+i y"); m_functionsNames << i18n("Trigamma function psi' for positive integer n"); m_functionsNames << i18n("Trigamma function psi'"); m_functionsNames << i18n("Polygamma function psi^(n)"); index++; for (int i = 0; i < 6; i++) m_functionsGroupIndex << index; // Synchrotron Functions m_functionsNames << i18n("First synchrotron function"); m_functionsNames << i18n("Second synchrotron function"); index++; for (int i = 0; i < 2; i++) m_functionsGroupIndex << index; // Transport Functions m_functionsNames << i18n("Transport function"); m_functionsNames << i18n("Transport function"); m_functionsNames << i18n("Transport function"); m_functionsNames << i18n("Transport function"); index++; for (int i = 0; i < 4; i++) m_functionsGroupIndex << index; // Trigonometric Functions m_functionsNames << i18n("Sine"); m_functionsNames << i18n("Cosine"); m_functionsNames << i18n("Tangent"); m_functionsNames << i18n("Inverse sine"); m_functionsNames << i18n("Inverse cosine"); m_functionsNames << i18n("Inverse tangent"); m_functionsNames << i18n("Inverse tangent using sign"); m_functionsNames << i18n("Hyperbolic sine"); m_functionsNames << i18n("Hyperbolic cosine"); m_functionsNames << i18n("Hyperbolic tangent"); m_functionsNames << i18n("Inverse hyperbolic cosine"); m_functionsNames << i18n("Inverse hyperbolic sine"); m_functionsNames << i18n("Inverse hyperbolic tangent"); m_functionsNames << i18n("Secant"); m_functionsNames << i18n("Cosecant"); m_functionsNames << i18n("Cotangent"); m_functionsNames << i18n("Inverse secant"); m_functionsNames << i18n("Inverse cosecant"); m_functionsNames << i18n("Inverse cotangent"); m_functionsNames << i18n("Hyperbolic secant"); m_functionsNames << i18n("Hyperbolic cosecant"); m_functionsNames << i18n("Hyperbolic cotangent"); m_functionsNames << i18n("Inverse hyperbolic secant"); m_functionsNames << i18n("Inverse hyperbolic cosecant"); m_functionsNames << i18n("Inverse hyperbolic cotangent"); m_functionsNames << i18n("Sinc function sin(x)/x"); m_functionsNames << QString("log(sinh(x))"); m_functionsNames << QString("log(cosh(x))"); m_functionsNames << i18n("Hypotenuse function"); m_functionsNames << i18n("Three component hypotenuse function"); m_functionsNames << i18n("restrict to [-pi,pi]"); m_functionsNames << i18n("restrict to [0,2 pi]"); index++; for (int i = 0; i < 32; i++) m_functionsGroupIndex << index; // Zeta Functions m_functionsNames << i18n("Riemann zeta function for integer n"); m_functionsNames << i18n("Riemann zeta function"); m_functionsNames << i18n("zeta(n)-1 for integer n"); m_functionsNames << i18n("zeta(x)-1"); m_functionsNames << i18n("Hurwitz zeta function"); m_functionsNames << i18n("Eta function for integer n"); m_functionsNames << i18n("Eta function"); index++; for (int i = 0; i < 7; i++) m_functionsGroupIndex << index; // GSL Random Number Distributions: see http://www.gnu.org/software/gsl/manual/html_node/Random-Number-Distributions.html // Gaussian Distribution m_functionsNames << i18n("Probability density for a Gaussian distribution"); m_functionsNames << i18n("Probability density for a unit Gaussian distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); m_functionsNames << i18n("Inverse cumulative distribution function P"); m_functionsNames << i18n("Inverse cumulative distribution function Q"); m_functionsNames << i18n("Cumulative unit distribution function P"); m_functionsNames << i18n("Cumulative unit distribution function Q"); m_functionsNames << i18n("Inverse cumulative unit distribution function P"); m_functionsNames << i18n("Inverse cumulative unit distribution function Q"); m_functionsNames << i18n("Probability density for Gaussian tail distribution"); m_functionsNames << i18n("Probability density for unit Gaussian tail distribution"); m_functionsNames << i18n("Probability density for a bivariate Gaussian distribution"); index++; for (int i = 0; i < 13; i++) m_functionsGroupIndex << index; // Exponential Distribution m_functionsNames << i18n("Probability density for an exponential distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); m_functionsNames << i18n("Inverse cumulative distribution function P"); m_functionsNames << i18n("Inverse cumulative distribution function Q"); index++; for (int i = 0; i < 5; i++) m_functionsGroupIndex << index; // Laplace Distribution m_functionsNames << i18n("Probability density for a Laplace distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); m_functionsNames << i18n("Inverse cumulative distribution function P"); m_functionsNames << i18n("Inverse cumulative distribution function Q"); index++; for (int i = 0; i < 5; i++) m_functionsGroupIndex << index; // Exponential Power Distribution m_functionsNames << i18n("Probability density for an exponential power distribution"); m_functionsNames << i18n("cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); index++; for (int i = 0; i < 3; i++) m_functionsGroupIndex << index; // Cauchy Distribution m_functionsNames << i18n("Probability density for a Cauchy distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); m_functionsNames << i18n("Inverse cumulative distribution function P"); m_functionsNames << i18n("Inverse cumulative distribution function Q"); index++; for (int i = 0; i < 5; i++) m_functionsGroupIndex << index; // Rayleigh Distribution m_functionsNames << i18n("Probability density for a Rayleigh distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); m_functionsNames << i18n("Inverse cumulative distribution function P"); m_functionsNames << i18n("Inverse cumulative distribution function Q"); m_functionsNames << i18n("Probability density for a Rayleigh tail distribution"); index++; for (int i = 0; i < 6; i++) m_functionsGroupIndex << index; // Landau Distribution m_functionsNames << i18n("Probability density for a Landau distribution"); index++; m_functionsGroupIndex << index; // Gamma Distribution m_functionsNames << i18n("Probability density for a gamma distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); m_functionsNames << i18n("Inverse cumulative distribution function P"); m_functionsNames << i18n("Inverse cumulative distribution function Q"); index++; for (int i = 0; i < 5; i++) m_functionsGroupIndex << index; // Flat (Uniform) Distribution m_functionsNames << i18n("Probability density for a uniform distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); m_functionsNames << i18n("Inverse cumulative distribution function P"); m_functionsNames << i18n("Inverse cumulative distribution function Q"); index++; for (int i = 0; i < 5; i++) m_functionsGroupIndex << index; // Lognormal Distribution m_functionsNames << i18n("Probability density for a lognormal distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); m_functionsNames << i18n("Inverse cumulative distribution function P"); m_functionsNames << i18n("Inverse cumulative distribution function Q"); index++; for (int i = 0; i < 5; i++) m_functionsGroupIndex << index; // Chi-squared Distribution m_functionsNames << i18n("Probability density for a chi squared distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); m_functionsNames << i18n("Inverse cumulative distribution function P"); m_functionsNames << i18n("Inverse cumulative distribution function Q"); index++; for (int i = 0; i < 5; i++) m_functionsGroupIndex << index; // F-distribution m_functionsNames << i18n("Probability density for a F-distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); m_functionsNames << i18n("Inverse cumulative distribution function P"); m_functionsNames << i18n("Inverse cumulative distribution function Q"); index++; for (int i = 0; i < 5; i++) m_functionsGroupIndex << index; // t-distribution m_functionsNames << i18n("Probability density for a t-distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); m_functionsNames << i18n("Inverse cumulative distribution function P"); m_functionsNames << i18n("Inverse cumulative distribution function Q"); index++; for (int i = 0; i < 5; i++) m_functionsGroupIndex << index; // Beta Distribution m_functionsNames << i18n("Probability density for a beta distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); m_functionsNames << i18n("Inverse cumulative distribution function P"); m_functionsNames << i18n("Inverse cumulative distribution function Q"); index++; for (int i = 0; i < 5; i++) m_functionsGroupIndex << index; // Logistic Distribution m_functionsNames << i18n("Probability density for a logistic distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); m_functionsNames << i18n("Inverse cumulative distribution function P"); m_functionsNames << i18n("Inverse cumulative distribution function Q"); index++; for (int i = 0; i < 5; i++) m_functionsGroupIndex << index; // Pareto Distribution m_functionsNames << i18n("Probability density for a Pareto distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); m_functionsNames << i18n("Inverse cumulative distribution function P"); m_functionsNames << i18n("Inverse cumulative distribution function Q"); index++; for (int i = 0; i < 5; i++) m_functionsGroupIndex << index; // Weibull Distribution m_functionsNames << i18n("Probability density for a Weibull distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); m_functionsNames << i18n("Inverse cumulative distribution function P"); m_functionsNames << i18n("Inverse cumulative distribution function Q"); index++; for (int i = 0; i < 5; i++) m_functionsGroupIndex << index; // Gumbel Distribution m_functionsNames << i18n("Probability density for a Type-1 Gumbel distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); m_functionsNames << i18n("Inverse cumulative distribution function P"); m_functionsNames << i18n("Inverse cumulative distribution function Q"); m_functionsNames << i18n("Probability density for a Type-2 Gumbel distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); m_functionsNames << i18n("Inverse cumulative distribution function P"); m_functionsNames << i18n("Inverse cumulative distribution function Q"); index++; for (int i = 0; i < 10; i++) m_functionsGroupIndex << index; // Poisson Distribution m_functionsNames << i18n("Probability density for a Poisson distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); index++; for (int i = 0; i < 3; i++) m_functionsGroupIndex << index; // Bernoulli Distribution m_functionsNames << i18n("Probability density for a Bernoulli distribution"); index++; m_functionsGroupIndex << index; // Binomial Distribution m_functionsNames << i18n("Probability density for a binomial distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); m_functionsNames << i18n("Probability density for a negative binomial distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); index++; for (int i = 0; i < 6; i++) m_functionsGroupIndex << index; // Pascal Distribution m_functionsNames << i18n("Probability density for a Pascal distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); index++; for (int i = 0; i < 3; i++) m_functionsGroupIndex << index; // Geometric Distribution m_functionsNames << i18n("Probability density for a geometric distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); index++; for (int i = 0; i < 3; i++) m_functionsGroupIndex << index; // Hypergeometric Distribution m_functionsNames << i18n("Probability density for a hypergeometric distribution"); m_functionsNames << i18n("Cumulative distribution function P"); m_functionsNames << i18n("Cumulative distribution function Q"); index++; for (int i = 0; i < 3; i++) m_functionsGroupIndex << index; // Logarithmic Distribution m_functionsNames << i18n("Probability density for a logarithmic distribution"); index++; m_functionsGroupIndex << index; } //TODO: decide whether we want to have i18n here in the backend part of the code void ExpressionParser::initConstants() { for (int i = 0; _constants[i].name != 0; i++) m_constants << _constants[i].name; //groups m_constantsGroups << i18n("Mathematical constants"); m_constantsGroups << i18n("Fundamental constants"); m_constantsGroups << i18n("Astronomy and Astrophysics"); m_constantsGroups << i18n("Atomic and Nuclear Physics"); m_constantsGroups << i18n("Measurement of Time"); m_constantsGroups << i18n("Imperial Units"); m_constantsGroups << i18n("Speed and Nautical Units"); m_constantsGroups << i18n("Printers Units"); m_constantsGroups << i18n("Volume, Area and Length"); m_constantsGroups << i18n("Mass and Weight"); m_constantsGroups << i18n("Thermal Energy and Power"); m_constantsGroups << i18n("Pressure"); m_constantsGroups << i18n("Viscosity"); m_constantsGroups << i18n("Light and Illumination"); m_constantsGroups << i18n("Radioactivity"); m_constantsGroups << i18n("Force and Energy"); //Mathematical constants m_constantsNames << i18n("Euler constant"); m_constantsValues << QString::number(M_E,'g',15); m_constantsUnits << ""; m_constantsNames << i18n("Pi"); m_constantsValues << QString::number(M_PI,'g',15); m_constantsUnits << ""; for (int i = 0; i < 2; i++) m_constantsGroupIndex << 0; //Fundamental constants m_constantsNames << i18n("Speed of light"); m_constantsValues << QString::number(GSL_CONST_MKSA_SPEED_OF_LIGHT,'g',15); m_constantsUnits << "m / s"; m_constantsNames << i18n("Vacuum permeability"); m_constantsValues << QString::number(GSL_CONST_MKSA_VACUUM_PERMEABILITY,'g',15); m_constantsUnits << "kg m / A^2 s^2"; m_constantsNames << i18n("Vacuum permittivity"); m_constantsValues << QString::number(GSL_CONST_MKSA_VACUUM_PERMITTIVITY,'g',15); m_constantsUnits << "A^2 s^4 / kg m^3"; m_constantsNames << i18n("Planck constant"); m_constantsValues << QString::number(GSL_CONST_MKSA_PLANCKS_CONSTANT_H,'g',15); m_constantsUnits << "kg m^2 / s"; m_constantsNames << i18n("Reduced Planck constant"); m_constantsValues << QString::number(GSL_CONST_MKSA_PLANCKS_CONSTANT_HBAR,'g',15); m_constantsUnits << "kg m^2 / s"; m_constantsNames << i18n("Avogadro constant"); m_constantsValues << QString::number(GSL_CONST_NUM_AVOGADRO,'g',15); m_constantsUnits << "1 / mol"; m_constantsNames << i18n("Faraday"); m_constantsValues << QString::number(GSL_CONST_MKSA_FARADAY,'g',15); m_constantsUnits << "A s / mol"; m_constantsNames << i18n("Boltzmann constant"); m_constantsValues << QString::number(GSL_CONST_MKSA_BOLTZMANN,'g',15); m_constantsUnits << "kg m^2 / K s^2"; m_constantsNames << i18n("Molar gas"); m_constantsValues << QString::number(GSL_CONST_MKSA_MOLAR_GAS,'g',15); m_constantsUnits << "kg m^2 / K mol s^2"; m_constantsNames << i18n("Standard gas volume"); m_constantsValues << QString::number(GSL_CONST_MKSA_STANDARD_GAS_VOLUME,'g',15); m_constantsUnits << "m^3 / mol"; m_constantsNames << i18n("Stefan-Boltzmann constant"); m_constantsValues << QString::number(GSL_CONST_MKSA_STEFAN_BOLTZMANN_CONSTANT,'g',15); m_constantsUnits << "kg / K^4 s^3"; m_constantsNames << i18n("Gauss"); m_constantsValues << QString::number(GSL_CONST_MKSA_GAUSS,'g',15); m_constantsUnits << "kg / A s^2"; for (int i = 0; i < 12; i++) m_constantsGroupIndex << 1; // Astronomy and Astrophysics m_constantsNames << i18n("Astronomical unit"); m_constantsValues << QString::number(GSL_CONST_MKSA_ASTRONOMICAL_UNIT,'g',15); m_constantsUnits << "m"; m_constantsNames << i18n("Gravitational constant"); m_constantsValues << QString::number(GSL_CONST_MKSA_GRAVITATIONAL_CONSTANT,'g',15); m_constantsUnits << "m^3 / kg s^2"; m_constantsNames << i18n("Light year"); m_constantsValues << QString::number(GSL_CONST_MKSA_LIGHT_YEAR,'g',15); m_constantsUnits << "m"; m_constantsNames << i18n("Parsec"); m_constantsValues << QString::number(GSL_CONST_MKSA_PARSEC,'g',15); m_constantsUnits << "m"; m_constantsNames << i18n("Gravitational acceleration"); m_constantsValues << QString::number(GSL_CONST_MKSA_GRAV_ACCEL,'g',15); m_constantsUnits << "m / s^2"; m_constantsNames << i18n("Solar mass"); m_constantsValues << QString::number(GSL_CONST_MKSA_SOLAR_MASS,'g',15); m_constantsUnits << "kg"; for (int i = 0; i < 6; i++) m_constantsGroupIndex << 2; // Atomic and Nuclear Physics; m_constantsNames << i18n("Charge of the electron"); m_constantsValues << QString::number(GSL_CONST_MKSA_ELECTRON_CHARGE,'g',15); m_constantsUnits << "A s"; m_constantsNames << i18n("Energy of 1 electron volt"); m_constantsValues << QString::number(GSL_CONST_MKSA_ELECTRON_VOLT,'g',15); m_constantsUnits << "kg m^2 / s^2"; m_constantsNames << i18n("Unified atomic mass"); m_constantsValues << QString::number(GSL_CONST_MKSA_UNIFIED_ATOMIC_MASS,'g',15); m_constantsUnits << "kg"; m_constantsNames << i18n("Mass of the electron"); m_constantsValues << QString::number(GSL_CONST_MKSA_MASS_ELECTRON,'g',15); m_constantsUnits << "kg"; m_constantsNames << i18n("Mass of the muon"); m_constantsValues << QString::number(GSL_CONST_MKSA_MASS_MUON,'g',15); m_constantsUnits << "kg"; m_constantsNames << i18n("Mass of the proton"); m_constantsValues << QString::number(GSL_CONST_MKSA_MASS_PROTON,'g',15); m_constantsUnits << "kg"; m_constantsNames << i18n("Mass of the neutron"); m_constantsValues << QString::number(GSL_CONST_MKSA_MASS_NEUTRON,'g',15); m_constantsUnits << "kg"; m_constantsNames << i18n("Electromagnetic fine structure constant"); m_constantsValues << QString::number(GSL_CONST_NUM_FINE_STRUCTURE,'g',15); m_constantsUnits << ""; m_constantsNames << i18n("Rydberg constant"); m_constantsValues << QString::number(GSL_CONST_MKSA_RYDBERG,'g',15); m_constantsUnits << "kg m^2 / s^2"; m_constantsNames << i18n("Bohr radius"); m_constantsValues << QString::number(GSL_CONST_MKSA_BOHR_RADIUS,'g',15); m_constantsUnits << "m"; m_constantsNames << i18n("Length of 1 angstrom"); m_constantsValues << QString::number(GSL_CONST_MKSA_ANGSTROM,'g',15); m_constantsUnits << "m"; m_constantsNames << i18n("Area of 1 barn"); m_constantsValues << QString::number(GSL_CONST_MKSA_BARN,'g',15); m_constantsUnits << "m^2"; m_constantsNames << i18n("Bohr Magneton"); m_constantsValues << QString::number(GSL_CONST_MKSA_BOHR_MAGNETON,'g',15); m_constantsUnits << "A m^2"; m_constantsNames << i18n("Nuclear Magneton"); m_constantsValues << QString::number(GSL_CONST_MKSA_NUCLEAR_MAGNETON,'g',15); m_constantsUnits << "A m^2"; m_constantsNames << i18n("Magnetic moment of the electron [absolute value]"); m_constantsValues << QString::number(GSL_CONST_MKSA_ELECTRON_MAGNETIC_MOMENT,'g',15); m_constantsUnits << "A m^2"; m_constantsNames << i18n("Magnetic moment of the proton"); m_constantsValues << QString::number(GSL_CONST_MKSA_PROTON_MAGNETIC_MOMENT,'g',15); m_constantsUnits << "A m^2"; m_constantsNames << i18n("Thomson cross section"); m_constantsValues << QString::number(GSL_CONST_MKSA_THOMSON_CROSS_SECTION,'g',15); m_constantsUnits << "m^2"; m_constantsNames << i18n("Electric dipole moment of 1 Debye"); m_constantsValues << QString::number(GSL_CONST_MKSA_DEBYE,'g',15); m_constantsUnits << "A s^2 / m^2"; for (int i = 0; i < 18; i++) m_constantsGroupIndex << 3; // Measurement of Time m_constantsNames << i18n("Number of seconds in 1 minute"); m_constantsValues << QString::number(GSL_CONST_MKSA_MINUTE,'g',15); m_constantsUnits << "s"; m_constantsNames << i18n("Number of seconds in 1 hour"); m_constantsValues << QString::number(GSL_CONST_MKSA_HOUR,'g',15); m_constantsUnits << "s"; m_constantsNames << i18n("Number of seconds in 1 day"); m_constantsValues << QString::number(GSL_CONST_MKSA_DAY,'g',15); m_constantsUnits << "s"; m_constantsNames << i18n("Number of seconds in 1 week"); m_constantsValues << QString::number(GSL_CONST_MKSA_WEEK,'g',15); m_constantsUnits << "s"; for (int i = 0; i < 4; i++) m_constantsGroupIndex << 4; // Imperial Units m_constantsNames << i18n("Length of 1 inch"); m_constantsValues << QString::number(GSL_CONST_MKSA_INCH,'g',15); m_constantsUnits << "m"; m_constantsNames << i18n("Length of 1 foot"); m_constantsValues << QString::number(GSL_CONST_MKSA_FOOT,'g',15); m_constantsUnits << "m"; m_constantsNames << i18n("Length of 1 yard"); m_constantsValues << QString::number(GSL_CONST_MKSA_YARD,'g',15); m_constantsUnits << "m"; m_constantsNames << i18n("Length of 1 mile"); m_constantsValues << QString::number(GSL_CONST_MKSA_MILE,'g',15); m_constantsUnits << "m"; m_constantsNames << i18n("Length of 1/1000th of an inch"); m_constantsValues << QString::number(GSL_CONST_MKSA_MIL,'g',15); m_constantsUnits << "m"; for (int i = 0; i < 5; i++) m_constantsGroupIndex << 5; // Speed and Nautical Units m_constantsNames << i18n("Speed of 1 kilometer per hour"); m_constantsValues << QString::number(GSL_CONST_MKSA_KILOMETERS_PER_HOUR,'g',15); m_constantsUnits << "m / s"; m_constantsNames << i18n("Speed of 1 mile per hour"); m_constantsValues << QString::number(GSL_CONST_MKSA_MILES_PER_HOUR,'g',15); m_constantsUnits << "m / s"; m_constantsNames << i18n("Length of 1 nautical mile"); m_constantsValues << QString::number(GSL_CONST_MKSA_NAUTICAL_MILE,'g',15); m_constantsUnits << "m"; m_constantsNames << i18n("Length of 1 fathom"); m_constantsValues << QString::number(GSL_CONST_MKSA_FATHOM,'g',15); m_constantsUnits << "m"; m_constantsNames << i18n("Speed of 1 knot"); m_constantsValues << QString::number(GSL_CONST_MKSA_KNOT,'g',15); m_constantsUnits << "m / s"; for (int i = 0; i < 5; i++) m_constantsGroupIndex << 6; // Printers Units m_constantsNames << i18n("length of 1 printer's point [1/72 inch]"); m_constantsValues << QString::number(GSL_CONST_MKSA_POINT,'g',15); m_constantsUnits << "m"; m_constantsNames << i18n("length of 1 TeX point [1/72.27 inch]"); m_constantsValues << QString::number(GSL_CONST_MKSA_TEXPOINT,'g',15); m_constantsUnits << "m"; for (int i = 0; i < 2; i++) m_constantsGroupIndex << 7; // Volume, Area and Length m_constantsNames << i18n("Length of 1 micron"); m_constantsValues << QString::number(GSL_CONST_MKSA_MICRON,'g',15); m_constantsUnits << "m"; m_constantsNames << i18n("Area of 1 hectare"); m_constantsValues << QString::number(GSL_CONST_MKSA_HECTARE,'g',15); m_constantsUnits << "m^2"; m_constantsNames << i18n("Area of 1 acre"); m_constantsValues << QString::number(GSL_CONST_MKSA_ACRE,'g',15); m_constantsUnits << "m^2"; m_constantsNames << i18n("Volume of 1 liter"); m_constantsValues << QString::number(GSL_CONST_MKSA_LITER,'g',15); m_constantsUnits << "m^3"; m_constantsNames << i18n("Volume of 1 US gallon"); m_constantsValues << QString::number(GSL_CONST_MKSA_US_GALLON,'g',15); m_constantsUnits << "m^3"; m_constantsNames << i18n("Volume of 1 Canadian gallon"); m_constantsValues << QString::number(GSL_CONST_MKSA_CANADIAN_GALLON,'g',15); m_constantsUnits << "m^3"; m_constantsNames << i18n("Volume of 1 UK gallon"); m_constantsValues << QString::number(GSL_CONST_MKSA_UK_GALLON,'g',15); m_constantsUnits << "m^3"; m_constantsNames << i18n("Volume of 1 quart"); m_constantsValues << QString::number(GSL_CONST_MKSA_QUART,'g',15); m_constantsUnits << "m^3"; m_constantsNames << i18n("Volume of 1 pint"); m_constantsValues << QString::number(GSL_CONST_MKSA_PINT,'g',15); m_constantsUnits << "m^3"; for (int i = 0; i < 9; i++) m_constantsGroupIndex << 8; // Mass and Weight m_constantsNames << i18n("Mass of 1 pound"); m_constantsValues << QString::number(GSL_CONST_MKSA_POUND_MASS,'g',15); m_constantsUnits << "kg"; m_constantsNames << i18n("Mass of 1 ounce"); m_constantsValues << QString::number(GSL_CONST_MKSA_OUNCE_MASS,'g',15); m_constantsUnits << "kg"; m_constantsNames << i18n("Mass of 1 ton"); m_constantsValues << QString::number(GSL_CONST_MKSA_TON,'g',15); m_constantsUnits << "kg"; m_constantsNames << i18n("Mass of 1 metric ton [1000 kg]"); m_constantsValues << QString::number(GSL_CONST_MKSA_METRIC_TON,'g',15); m_constantsUnits << "kg"; m_constantsNames << i18n("Mass of 1 UK ton"); m_constantsValues << QString::number(GSL_CONST_MKSA_UK_TON,'g',15); m_constantsUnits << "kg"; m_constantsNames << i18n("Mass of 1 troy ounce"); m_constantsValues << QString::number(GSL_CONST_MKSA_TROY_OUNCE,'g',15); m_constantsUnits << "kg"; m_constantsNames << i18n("Mass of 1 carat"); m_constantsValues << QString::number(GSL_CONST_MKSA_CARAT,'g',15); m_constantsUnits << "kg"; m_constantsNames << i18n("Force of 1 gram weight"); m_constantsValues << QString::number(GSL_CONST_MKSA_GRAM_FORCE,'g',15); m_constantsUnits << "kg m / s^2"; m_constantsNames << i18n("Force of 1 pound weight"); m_constantsValues << QString::number(GSL_CONST_MKSA_POUND_FORCE,'g',15); m_constantsUnits << "kg m / s^2"; m_constantsNames << i18n("Force of 1 kilopound weight"); m_constantsValues << QString::number(GSL_CONST_MKSA_KILOPOUND_FORCE,'g',15); m_constantsUnits << "kg m / s^2"; m_constantsNames << i18n("Force of 1 poundal"); m_constantsValues << QString::number(GSL_CONST_MKSA_POUNDAL,'g',15); m_constantsUnits << "kg m / s^2"; for (int i = 0; i < 11; i++) m_constantsGroupIndex << 9; // Thermal Energy and Power m_constantsNames << i18n("Energy of 1 calorie"); m_constantsValues << QString::number(GSL_CONST_MKSA_CALORIE,'g',15); m_constantsUnits << "kg m^2 / s^2"; m_constantsNames << i18n("Energy of 1 British Thermal Unit"); m_constantsValues << QString::number(GSL_CONST_MKSA_BTU,'g',15); m_constantsUnits << "kg m^2 / s^2"; m_constantsNames << i18n("Energy of 1 Therm"); m_constantsValues << QString::number(GSL_CONST_MKSA_THERM,'g',15); m_constantsUnits << "kg m^2 / s^2"; m_constantsNames << i18n("Power of 1 horsepower"); m_constantsValues << QString::number(GSL_CONST_MKSA_HORSEPOWER,'g',15); m_constantsUnits << "kg m^2 / s^3"; for (int i = 0; i < 4; i++) m_constantsGroupIndex << 10; // Pressure m_constantsNames << i18n("Pressure of 1 bar"); m_constantsValues << QString::number(GSL_CONST_MKSA_BAR,'g',15); m_constantsUnits << "kg / m s^2"; m_constantsNames << i18n("Pressure of 1 standard atmosphere"); m_constantsValues << QString::number(GSL_CONST_MKSA_STD_ATMOSPHERE,'g',15); m_constantsUnits << "kg / m s^2"; m_constantsNames << i18n("Pressure of 1 torr"); m_constantsValues << QString::number(GSL_CONST_MKSA_TORR,'g',15); m_constantsUnits << "kg / m s^2"; m_constantsNames << i18n("Pressure of 1 meter of mercury"); m_constantsValues << QString::number(GSL_CONST_MKSA_METER_OF_MERCURY,'g',15); m_constantsUnits << "kg / m s^2"; m_constantsNames << i18n("Pressure of 1 inch of mercury"); m_constantsValues << QString::number(GSL_CONST_MKSA_INCH_OF_MERCURY,'g',15); m_constantsUnits << "kg / m s^2"; m_constantsNames << i18n("Pressure of 1 inch of water"); m_constantsValues << QString::number(GSL_CONST_MKSA_INCH_OF_WATER,'g',15); m_constantsUnits << "kg / m s^2"; m_constantsNames << i18n("Pressure of 1 pound per square inch"); m_constantsValues << QString::number(GSL_CONST_MKSA_PSI,'g',15); m_constantsUnits << "kg / m s^2"; for (int i = 0; i < 7; i++) m_constantsGroupIndex << 11; // Viscosity m_constantsNames << i18n("Dynamic viscosity of 1 poise"); m_constantsValues << QString::number(GSL_CONST_MKSA_POISE,'g',15); m_constantsUnits << "kg / m s"; m_constantsNames << i18n("Kinematic viscosity of 1 stokes"); m_constantsValues << QString::number(GSL_CONST_MKSA_STOKES,'g',15); m_constantsUnits << "m^2 / s"; for (int i = 0; i < 2; i++) m_constantsGroupIndex << 12; // Light and Illumination m_constantsNames << i18n("Luminance of 1 stilb"); m_constantsValues << QString::number(GSL_CONST_MKSA_STILB,'g',15); m_constantsUnits << "cd / m^2"; m_constantsNames << i18n("Luminous flux of 1 lumen"); m_constantsValues << QString::number(GSL_CONST_MKSA_LUMEN,'g',15); m_constantsUnits << "cd sr"; m_constantsNames << i18n("Illuminance of 1 lux"); m_constantsValues << QString::number(GSL_CONST_MKSA_LUX,'g',15); m_constantsUnits << "cd sr / m^2"; m_constantsNames << i18n("Illuminance of 1 phot"); m_constantsValues << QString::number(GSL_CONST_MKSA_PHOT,'g',15); m_constantsUnits << "cd sr / m^2"; m_constantsNames << i18n("Illuminance of 1 footcandle"); m_constantsValues << QString::number(GSL_CONST_MKSA_FOOTCANDLE,'g',15); m_constantsUnits << "cd sr / m^2"; m_constantsNames << i18n("Luminance of 1 lambert"); m_constantsValues << QString::number(GSL_CONST_MKSA_LAMBERT,'g',15); m_constantsUnits << "cd sr / m^2"; m_constantsNames << i18n("Luminance of 1 footlambert"); m_constantsValues << QString::number(GSL_CONST_MKSA_FOOTLAMBERT,'g',15); m_constantsUnits << "cd sr / m^2"; for (int i = 0; i < 7; i++) m_constantsGroupIndex << 13; // Radioactivity m_constantsNames << i18n("Activity of 1 curie"); m_constantsValues << QString::number(GSL_CONST_MKSA_CURIE,'g',15); m_constantsUnits << "1 / s"; m_constantsNames << i18n("Exposure of 1 roentgen"); m_constantsValues << QString::number(GSL_CONST_MKSA_ROENTGEN,'g',15); m_constantsUnits << "A s / kg"; m_constantsNames << i18n("Absorbed dose of 1 rad"); m_constantsValues << QString::number(GSL_CONST_MKSA_RAD,'g',15); m_constantsUnits << "m^2 / s^2"; for (int i = 0; i < 3; i++) m_constantsGroupIndex << 14; // Force and Energy m_constantsNames << i18n("SI unit of force"); m_constantsValues << QString::number(GSL_CONST_MKSA_NEWTON,'g',15); m_constantsUnits << "kg m / s^2"; m_constantsNames << i18n("Force of 1 Dyne"); m_constantsValues << QString::number(GSL_CONST_MKSA_DYNE,'g',15); m_constantsUnits << "kg m / s^2"; m_constantsNames << i18n("SI unit of energy"); m_constantsValues << QString::number(GSL_CONST_MKSA_JOULE,'g',15); m_constantsUnits << "kg m^2 / s^2"; m_constantsNames << i18n("Energy 1 erg"); m_constantsValues << QString::number(GSL_CONST_MKSA_ERG,'g',15); m_constantsUnits << "kg m^2 / s^2"; for (int i = 0; i < 4; i++) m_constantsGroupIndex << 15; } ExpressionParser::~ExpressionParser() { delete_table(); } ExpressionParser* ExpressionParser::getInstance() { if (!instance) instance = new ExpressionParser(); return instance; } const QStringList& ExpressionParser::functions() { return m_functions; } const QStringList& ExpressionParser::functionsGroups() { return m_functionsGroups; } const QStringList& ExpressionParser::functionsNames() { return m_functionsNames; } const QVector& ExpressionParser::functionsGroupIndices() { return m_functionsGroupIndex; } const QStringList& ExpressionParser::constants() { return m_constants; } const QStringList& ExpressionParser::constantsGroups() { return m_constantsGroups; } const QStringList& ExpressionParser::constantsNames() { return m_constantsNames; } const QStringList& ExpressionParser::constantsValues() { return m_constantsValues; } const QStringList& ExpressionParser::constantsUnits() { return m_constantsUnits; } const QVector& ExpressionParser::constantsGroupIndices() { return m_constantsGroupIndex; } bool ExpressionParser::isValid(const QString& expr, const QStringList& vars) { for (int i = 0; i < vars.size(); ++i) { QByteArray varba = vars.at(i).toLatin1(); assign_variable(varba.constData(), 0); } QByteArray funcba = expr.toLatin1(); const char* data = funcba.constData(); gsl_set_error_handler_off(); parse(data); return !(parse_errors() > 0); } QStringList ExpressionParser::getParameter(const QString& expr, const QStringList& vars) { + DEBUG("ExpressionParser::getParameter()"); QDEBUG("variables:" << vars); QStringList parameters; QStringList strings = expr.split(QRegExp("\\W+"), QString::SkipEmptyParts); QDEBUG("found strings:" << strings); for (int i = 0; i < strings.size(); ++i) { // check if token is not a known constant/function/variable or number if (constants().indexOf(strings[i]) == -1 && functions().indexOf(strings[i]) == -1 && vars.indexOf(strings[i]) == -1 && QRegExp("[0-9]*").exactMatch(strings[i]) == 0) parameters << strings[i]; else QDEBUG(strings[i] << ':' << constants().indexOf(strings[i]) << ' ' << functions().indexOf(strings[i]) << ' ' << vars.indexOf(strings[i]) << ' ' << QRegExp("[0-9]*").exactMatch(strings[i])); } parameters.removeDuplicates(); QDEBUG("parameters found:" << parameters); return parameters; } bool ExpressionParser::evaluateCartesian(const QString& expr, const QString& min, const QString& max, int count, QVector* xVector, QVector* yVector, const QStringList& paramNames, const QVector& paramValues) { QByteArray xminba = min.toLatin1(); const double xMin = parse(xminba.constData()); QByteArray xmaxba = max.toLatin1(); const double xMax = parse(xmaxba.constData()); const double step = (xMax - xMin)/(double)(count - 1); QByteArray funcba = expr.toLatin1(); const char* func = funcba.constData(); double x, y; gsl_set_error_handler_off(); for (int i = 0; i < paramNames.size(); ++i) { QByteArray paramba = paramNames.at(i).toLatin1(); assign_variable(paramba.constData(), paramValues.at(i)); } for (int i = 0; i < count; i++) { x = xMin + step * i; assign_variable("x", x); y = parse(func); if (parse_errors() > 0) return false; (*xVector)[i] = x; if (std::isfinite(y)) (*yVector)[i] = y; else (*yVector)[i] = NAN; } return true; } bool ExpressionParser::evaluateCartesian(const QString& expr, const QString& min, const QString& max, int count, QVector* xVector, QVector* yVector) { QByteArray xminba = min.toLatin1(); const double xMin = parse(xminba.constData()); QByteArray xmaxba = max.toLatin1(); const double xMax = parse(xmaxba.constData()); const double step = (xMax - xMin)/(double)(count - 1); QByteArray funcba = expr.toLatin1(); const char* func = funcba.constData(); double x, y; gsl_set_error_handler_off(); for (int i = 0; i < count; i++) { x = xMin + step*i; assign_variable("x", x); y = parse(func); if (parse_errors() > 0) return false; (*xVector)[i] = x; if (std::isfinite(y)) (*yVector)[i] = y; else (*yVector)[i] = NAN; } return true; } bool ExpressionParser::evaluateCartesian(const QString& expr, QVector* xVector, QVector* yVector) { QByteArray funcba = expr.toLatin1(); const char* func = funcba.constData(); double x, y; gsl_set_error_handler_off(); for (int i = 0; i < xVector->count(); i++) { x = xVector->at(i); assign_variable("x", x); y = parse(func); if (parse_errors() > 0) return false; if (std::isfinite(y)) (*yVector)[i] = y; else (*yVector)[i] = NAN; } return true; } bool ExpressionParser::evaluateCartesian(const QString& expr, QVector* xVector, QVector* yVector, const QStringList& paramNames, const QVector& paramValues) { QByteArray funcba = expr.toLatin1(); const char* func = funcba.constData(); double x, y; gsl_set_error_handler_off(); for (int i = 0; i < paramNames.size(); ++i) { QByteArray paramba = paramNames.at(i).toLatin1(); assign_variable(paramba.constData(), paramValues.at(i)); } for (int i = 0; i < xVector->count(); i++) { x = xVector->at(i); assign_variable("x", x); y = parse(func); if (parse_errors() > 0) return false; if (std::isfinite(y)) (*yVector)[i] = y; else (*yVector)[i] = NAN; } return true; } /*! evaluates multivariate function y=f(x_1, x_2, ...). Variable names (x_1, x_2, ...) are stored in \c vars. Data is stored in \c dataVectors. */ bool ExpressionParser::evaluateCartesian(const QString& expr, const QStringList& vars, const QVector*>& xVectors, QVector* yVector) { Q_ASSERT(vars.size() == xVectors.size()); QByteArray funcba = expr.toLatin1(); const char* func = funcba.constData(); double y, varValue; QString varName; gsl_set_error_handler_off(); bool stop = false; for (int i = 0; i < yVector->size(); i++) { //stop iterating over i if one of the x-vectors has no elements anymore. for (int n = 0; n < xVectors.size(); ++n) { if (i == xVectors.at(n)->size()) { stop = true; break; } } if (stop) break; for (int n = 0; n < vars.size(); ++n) { varName = vars.at(n); varValue = xVectors.at(n)->at(i); QByteArray varba = varName.toLatin1(); assign_variable(varba.constData(), varValue); } y = parse(func); if (parse_errors() > 0) return false; if (std::isfinite(y)) (*yVector)[i] = y; else (*yVector)[i] = NAN; } return true; } bool ExpressionParser::evaluatePolar(const QString& expr, const QString& min, const QString& max, int count, QVector* xVector, QVector* yVector) { QByteArray minba = min.toLatin1(); const double minValue = parse(minba.constData()); QByteArray maxba = max.toLatin1(); const double maxValue = parse(maxba.constData()); const double step = (maxValue - minValue)/(double)(count - 1); QByteArray funcba = expr.toLatin1(); const char* func = funcba.constData(); double r, phi; gsl_set_error_handler_off(); for (int i = 0; i < count; i++) { phi = minValue + step * i; assign_variable("phi", phi); r = parse(func); if (parse_errors() > 0) return false; if (std::isfinite(r)) { (*xVector)[i] = r*cos(phi); (*yVector)[i] = r*sin(phi); } else { (*xVector)[i] = NAN; (*yVector)[i] = NAN; } } return true; } bool ExpressionParser::evaluateParametric(const QString& expr1, const QString& expr2, const QString& min, const QString& max, int count, QVector* xVector, QVector* yVector) { QByteArray minba = min.toLatin1(); const double minValue = parse(minba.constData()); QByteArray maxba = max.toLatin1(); const double maxValue = parse(maxba.constData()); const double step = (maxValue - minValue)/(double)(count - 1); QByteArray xfuncba = expr1.toLatin1(); const char* xFunc = xfuncba.constData(); QByteArray yfuncba = expr2.toLatin1(); const char* yFunc = yfuncba.constData(); double x, y, t; gsl_set_error_handler_off(); for (int i = 0; i < count; i++) { t = minValue + step*i; assign_variable("t", t); x = parse(xFunc); if (parse_errors() > 0) return false; if (std::isfinite(x)) (*xVector)[i] = x; else (*xVector)[i] = NAN; y = parse(yFunc); if (parse_errors() > 0) return false; if (std::isfinite(y)) (*yVector)[i] = y; else (*yVector)[i] = NAN; } return true; } diff --git a/src/kdefrontend/dockwidgets/XYFitCurveDock.cpp b/src/kdefrontend/dockwidgets/XYFitCurveDock.cpp index 381aee291..83a3d5e88 100644 --- a/src/kdefrontend/dockwidgets/XYFitCurveDock.cpp +++ b/src/kdefrontend/dockwidgets/XYFitCurveDock.cpp @@ -1,1146 +1,1163 @@ /*************************************************************************** File : XYFitCurveDock.cpp Project : LabPlot -------------------------------------------------------------------- Copyright : (C) 2014-2017 Alexander Semke (alexander.semke@web.de) Copyright : (C) 2016-2018 Stefan Gerlach (stefan.gerlach@uni.kn) Description : widget for editing properties of fit curves ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #include "XYFitCurveDock.h" #include "backend/core/AspectTreeModel.h" #include "backend/core/Project.h" #include "backend/lib/macros.h" #include "backend/gsl/ExpressionParser.h" #include "commonfrontend/widgets/TreeViewComboBox.h" #include "kdefrontend/widgets/ConstantsWidget.h" #include "kdefrontend/widgets/FunctionsWidget.h" #include "kdefrontend/widgets/FitOptionsWidget.h" #include "kdefrontend/widgets/FitParametersWidget.h" #include #include #include #include #include #include extern "C" { #include "backend/nsl/nsl_sf_stats.h" } /*! \class XYFitCurveDock \brief Provides a widget for editing the properties of the XYFitCurves (2D-curves defined by a fit model) currently selected in the project explorer. If more then one curves are set, the properties of the first column are shown. The changes of the properties are applied to all curves. The exclusions are the name, the comment and the datasets (columns) of the curves - these properties can only be changed if there is only one single curve. \ingroup kdefrontend */ XYFitCurveDock::XYFitCurveDock(QWidget* parent) : XYCurveDock(parent), cbDataSourceCurve(0), cbXDataColumn(0), cbYDataColumn(0), cbXErrorColumn(0), cbYErrorColumn(0), m_fitCurve(0) { //remove the tab "Error bars" ui.tabWidget->removeTab(5); } /*! * // Tab "General" */ void XYFitCurveDock::setupGeneral() { QWidget* generalTab = new QWidget(ui.tabGeneral); uiGeneralTab.setupUi(generalTab); QGridLayout* gridLayout = qobject_cast(generalTab->layout()); if (gridLayout) { gridLayout->setContentsMargins(2, 2, 2, 2); gridLayout->setHorizontalSpacing(2); gridLayout->setVerticalSpacing(2); } uiGeneralTab.cbDataSourceType->addItem(i18n("Spreadsheet")); uiGeneralTab.cbDataSourceType->addItem(i18n("XY-Curve")); cbDataSourceCurve = new TreeViewComboBox(generalTab); gridLayout->addWidget(cbDataSourceCurve, 6, 4, 1, 4); cbXDataColumn = new TreeViewComboBox(generalTab); gridLayout->addWidget(cbXDataColumn, 7, 4, 1, 4); cbXErrorColumn = new TreeViewComboBox(generalTab); cbXErrorColumn->setEnabled(false); uiGeneralTab.hlXError->addWidget(cbXErrorColumn); cbYDataColumn = new TreeViewComboBox(generalTab); gridLayout->addWidget(cbYDataColumn, 8, 4, 1, 4); cbYErrorColumn = new TreeViewComboBox(generalTab); cbYErrorColumn->setEnabled(false); uiGeneralTab.hlYWeight->addWidget(cbYErrorColumn); //X-Error/Y-Weight for(int i = 0; i < NSL_FIT_ERROR_TYPE_COUNT; i++) uiGeneralTab.cbXError->addItem(nsl_fit_error_type_name[i]); uiGeneralTab.cbXError->setCurrentIndex(nsl_fit_error_no); for(int i = 0; i < NSL_FIT_WEIGHT_TYPE_COUNT; i++) uiGeneralTab.cbYWeight->addItem(nsl_fit_weight_type_name[i]); uiGeneralTab.cbYWeight->setCurrentIndex(nsl_fit_weight_no); for(int i = 0; i < NSL_FIT_MODEL_CATEGORY_COUNT; i++) uiGeneralTab.cbCategory->addItem(nsl_fit_model_category_name[i]); //show the fit-model category for the currently selected default (first) fit-model category categoryChanged(uiGeneralTab.cbCategory->currentIndex()); uiGeneralTab.teEquation->setMaximumHeight(uiGeneralTab.leName->sizeHint().height() * 2); //use white background in the preview label QPalette p; p.setColor(QPalette::Window, Qt::white); uiGeneralTab.lFuncPic->setAutoFillBackground(true); uiGeneralTab.lFuncPic->setPalette(p); uiGeneralTab.tbConstants->setIcon(QIcon::fromTheme("labplot-format-text-symbol")); uiGeneralTab.tbFunctions->setIcon(QIcon::fromTheme("preferences-desktop-font")); uiGeneralTab.pbRecalculate->setIcon(QIcon::fromTheme("run-build")); uiGeneralTab.twLog->setEditTriggers(QAbstractItemView::NoEditTriggers); uiGeneralTab.twParameters->setEditTriggers(QAbstractItemView::NoEditTriggers); uiGeneralTab.twGoodness->setEditTriggers(QAbstractItemView::NoEditTriggers); //don't allow word wrapping in the log-table for the multi-line iterations string uiGeneralTab.twLog->setWordWrap(false); // context menus uiGeneralTab.twParameters->setContextMenuPolicy(Qt::CustomContextMenu); uiGeneralTab.twGoodness->setContextMenuPolicy(Qt::CustomContextMenu); uiGeneralTab.twLog->setContextMenuPolicy(Qt::CustomContextMenu); connect(uiGeneralTab.twParameters, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(resultParametersContextMenuRequest(const QPoint &)) ); connect(uiGeneralTab.twGoodness, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(resultGoodnessContextMenuRequest(const QPoint &)) ); connect(uiGeneralTab.twLog, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(resultLogContextMenuRequest(const QPoint &)) ); uiGeneralTab.twLog->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents); uiGeneralTab.twGoodness->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents); uiGeneralTab.twGoodness->item(0, 1)->setText(UTF8_QSTRING("χ²")); uiGeneralTab.twGoodness->item(1, 1)->setText(i18n("reduced") + " " + UTF8_QSTRING("χ²") + " (" + UTF8_QSTRING("χ²") + "/dof)"); uiGeneralTab.twGoodness->item(3, 1)->setText(UTF8_QSTRING("R²")); uiGeneralTab.twGoodness->item(4, 1)->setText(UTF8_QSTRING("R̄²")); uiGeneralTab.twGoodness->item(5, 0)->setText(UTF8_QSTRING("χ²") + ' ' + i18n("test")); uiGeneralTab.twGoodness->item(5, 1)->setText("P > " + UTF8_QSTRING("χ²")); QHBoxLayout* layout = new QHBoxLayout(ui.tabGeneral); layout->setMargin(0); layout->addWidget(generalTab); //Slots connect(uiGeneralTab.leName, SIGNAL(returnPressed()), this, SLOT(nameChanged())); connect(uiGeneralTab.leComment, SIGNAL(returnPressed()), this, SLOT(commentChanged())); connect(uiGeneralTab.chkVisible, SIGNAL(clicked(bool)), this, SLOT(visibilityChanged(bool))); connect(uiGeneralTab.cbDataSourceType, SIGNAL(currentIndexChanged(int)), this, SLOT(dataSourceTypeChanged(int))); connect(uiGeneralTab.cbXError, SIGNAL(currentIndexChanged(int)), this, SLOT(xErrorChanged(int))); connect(uiGeneralTab.cbYWeight, SIGNAL(currentIndexChanged(int)), this, SLOT(yWeightChanged(int))); connect(uiGeneralTab.cbCategory, SIGNAL(currentIndexChanged(int)), this, SLOT(categoryChanged(int))); connect(uiGeneralTab.cbModel, SIGNAL(currentIndexChanged(int)), this, SLOT(modelTypeChanged(int))); connect(uiGeneralTab.sbDegree, SIGNAL(valueChanged(int)), this, SLOT(updateModelEquation())); - connect(uiGeneralTab.teEquation, SIGNAL(expressionChanged()), this, SLOT(enableRecalculate())); + connect(uiGeneralTab.teEquation, SIGNAL(expressionChanged()), this, SLOT(expressionChanged())); connect(uiGeneralTab.tbConstants, SIGNAL(clicked()), this, SLOT(showConstants())); connect(uiGeneralTab.tbFunctions, SIGNAL(clicked()), this, SLOT(showFunctions())); connect(uiGeneralTab.pbParameters, SIGNAL(clicked()), this, SLOT(showParameters())); connect(uiGeneralTab.pbOptions, SIGNAL(clicked()), this, SLOT(showOptions())); connect(uiGeneralTab.pbRecalculate, SIGNAL(clicked()), this, SLOT(recalculateClicked())); connect(cbDataSourceCurve, SIGNAL(currentModelIndexChanged(QModelIndex)), this, SLOT(dataSourceCurveChanged(QModelIndex))); connect(cbXDataColumn, SIGNAL(currentModelIndexChanged(QModelIndex)), this, SLOT(xDataColumnChanged(QModelIndex))); connect(cbYDataColumn, SIGNAL(currentModelIndexChanged(QModelIndex)), this, SLOT(yDataColumnChanged(QModelIndex))); connect(cbXErrorColumn, SIGNAL(currentModelIndexChanged(QModelIndex)), this, SLOT(xErrorColumnChanged(QModelIndex))); connect(cbYErrorColumn, SIGNAL(currentModelIndexChanged(QModelIndex)), this, SLOT(yErrorColumnChanged(QModelIndex))); } void XYFitCurveDock::initGeneralTab() { //if there are more then one curve in the list, disable the tab "general" if (m_curvesList.size() == 1) { uiGeneralTab.lName->setEnabled(true); uiGeneralTab.leName->setEnabled(true); uiGeneralTab.lComment->setEnabled(true); uiGeneralTab.leComment->setEnabled(true); uiGeneralTab.leName->setText(m_curve->name()); uiGeneralTab.leComment->setText(m_curve->comment()); } else { uiGeneralTab.lName->setEnabled(false); uiGeneralTab.leName->setEnabled(false); uiGeneralTab.lComment->setEnabled(false); uiGeneralTab.leComment->setEnabled(false); uiGeneralTab.leName->setText(""); uiGeneralTab.leComment->setText(""); } //show the properties of the first curve m_fitCurve = dynamic_cast(m_curve); uiGeneralTab.cbDataSourceType->setCurrentIndex(m_fitCurve->dataSourceType()); this->dataSourceTypeChanged(uiGeneralTab.cbDataSourceType->currentIndex()); XYCurveDock::setModelIndexFromAspect(cbDataSourceCurve, m_fitCurve->dataSourceCurve()); XYCurveDock::setModelIndexFromAspect(cbXDataColumn, m_fitCurve->xDataColumn()); XYCurveDock::setModelIndexFromAspect(cbYDataColumn, m_fitCurve->yDataColumn()); XYCurveDock::setModelIndexFromAspect(cbXErrorColumn, m_fitCurve->xErrorColumn()); XYCurveDock::setModelIndexFromAspect(cbYErrorColumn, m_fitCurve->yErrorColumn()); int tmpModelType = m_fitData.modelType; // save type because it's reset when category changes if (m_fitData.modelCategory == nsl_fit_model_custom) uiGeneralTab.cbCategory->setCurrentIndex(uiGeneralTab.cbCategory->count() - 1); else uiGeneralTab.cbCategory->setCurrentIndex(m_fitData.modelCategory); m_fitData.modelType = tmpModelType; if (m_fitData.modelCategory != nsl_fit_model_custom) uiGeneralTab.cbModel->setCurrentIndex(m_fitData.modelType); uiGeneralTab.cbXError->setCurrentIndex(m_fitData.xErrorsType); uiGeneralTab.cbYWeight->setCurrentIndex(m_fitData.yWeightsType); uiGeneralTab.sbDegree->setValue(m_fitData.degree); updateModelEquation(); this->showFitResult(); uiGeneralTab.chkVisible->setChecked(m_curve->isVisible()); //Slots connect(m_fitCurve, SIGNAL(aspectDescriptionChanged(const AbstractAspect*)), this, SLOT(curveDescriptionChanged(const AbstractAspect*))); connect(m_fitCurve, SIGNAL(dataSourceTypeChanged(XYAnalysisCurve::DataSourceType)), this, SLOT(curveDataSourceTypeChanged(XYAnalysisCurve::DataSourceType))); connect(m_fitCurve, SIGNAL(dataSourceCurveChanged(const XYCurve*)), this, SLOT(curveDataSourceCurveChanged(const XYCurve*))); connect(m_fitCurve, SIGNAL(xDataColumnChanged(const AbstractColumn*)), this, SLOT(curveXDataColumnChanged(const AbstractColumn*))); connect(m_fitCurve, SIGNAL(yDataColumnChanged(const AbstractColumn*)), this, SLOT(curveYDataColumnChanged(const AbstractColumn*))); connect(m_fitCurve, SIGNAL(xErrorColumnChanged(const AbstractColumn*)), this, SLOT(curveXErrorColumnChanged(const AbstractColumn*))); connect(m_fitCurve, SIGNAL(yErrorColumnChanged(const AbstractColumn*)), this, SLOT(curveYErrorColumnChanged(const AbstractColumn*))); connect(m_fitCurve, SIGNAL(fitDataChanged(XYFitCurve::FitData)), this, SLOT(curveFitDataChanged(XYFitCurve::FitData))); connect(m_fitCurve, SIGNAL(sourceDataChanged()), this, SLOT(enableRecalculate())); } void XYFitCurveDock::setModel() { QList list; list << "Folder" << "Datapicker" << "Worksheet" << "CartesianPlot" << "XYCurve"; cbDataSourceCurve->setTopLevelClasses(list); QList hiddenAspects; for (auto* curve : m_curvesList) hiddenAspects << curve; cbDataSourceCurve->setHiddenAspects(hiddenAspects); list.clear(); list << "Folder" << "Workbook" << "Spreadsheet" << "FileDataSource" << "Column" << "CantorWorksheet" << "Datapicker"; cbXDataColumn->setTopLevelClasses(list); cbYDataColumn->setTopLevelClasses(list); cbXErrorColumn->setTopLevelClasses(list); cbYErrorColumn->setTopLevelClasses(list); cbDataSourceCurve->setModel(m_aspectTreeModel); cbXDataColumn->setModel(m_aspectTreeModel); cbYDataColumn->setModel(m_aspectTreeModel); cbXErrorColumn->setModel(m_aspectTreeModel); cbYErrorColumn->setModel(m_aspectTreeModel); XYCurveDock::setModel(); } /*! sets the curves. The properties of the curves in the list \c list can be edited in this widget. */ void XYFitCurveDock::setCurves(QList list) { m_initializing = true; m_curvesList = list; m_curve = list.first(); m_fitCurve = dynamic_cast(m_curve); m_aspectTreeModel = new AspectTreeModel(m_curve->project()); this->setModel(); m_fitData = m_fitCurve->fitData(); initGeneralTab(); initTabs(); m_initializing = false; } //************************************************************* //**** SLOTs for changes triggered in XYFitCurveDock ***** //************************************************************* void XYFitCurveDock::nameChanged() { if (m_initializing) return; m_curve->setName(uiGeneralTab.leName->text()); } void XYFitCurveDock::commentChanged() { if (m_initializing) return; m_curve->setComment(uiGeneralTab.leComment->text()); } void XYFitCurveDock::dataSourceTypeChanged(int index) { const XYAnalysisCurve::DataSourceType type = (XYAnalysisCurve::DataSourceType)index; if (type == XYAnalysisCurve::DataSourceSpreadsheet) { uiGeneralTab.lDataSourceCurve->hide(); cbDataSourceCurve->hide(); uiGeneralTab.lXColumn->show(); cbXDataColumn->show(); uiGeneralTab.lYColumn->show(); cbYDataColumn->show(); } else { uiGeneralTab.lDataSourceCurve->show(); cbDataSourceCurve->show(); uiGeneralTab.lXColumn->hide(); cbXDataColumn->hide(); uiGeneralTab.lYColumn->hide(); cbYDataColumn->hide(); } if (m_initializing) return; for (auto* curve : m_curvesList) dynamic_cast(curve)->setDataSourceType(type); } void XYFitCurveDock::dataSourceCurveChanged(const QModelIndex& index) { AbstractAspect* aspect = static_cast(index.internalPointer()); XYCurve* dataSourceCurve = dynamic_cast(aspect); if (m_initializing) return; for (auto* curve : m_curvesList) dynamic_cast(curve)->setDataSourceCurve(dataSourceCurve); } void XYFitCurveDock::xDataColumnChanged(const QModelIndex& index) { DEBUG("XYFitCurveDock::xDataColumnChanged()"); if (m_initializing) return; AbstractAspect* aspect = static_cast(index.internalPointer()); AbstractColumn* column = dynamic_cast(aspect); for (auto* curve : m_curvesList) dynamic_cast(curve)->setXDataColumn(column); // set model dependent start values from new data XYFitCurve::initStartValues(m_fitData, m_curve); } void XYFitCurveDock::yDataColumnChanged(const QModelIndex& index) { DEBUG("XYFitCurveDock::yDataColumnChanged()"); if (m_initializing) return; AbstractAspect* aspect = static_cast(index.internalPointer()); AbstractColumn* column = dynamic_cast(aspect); for (auto* curve : m_curvesList) dynamic_cast(curve)->setYDataColumn(column); // set model dependent start values from new data XYFitCurve::initStartValues(m_fitData, m_curve); } void XYFitCurveDock::xErrorColumnChanged(const QModelIndex& index) { if (m_initializing) return; AbstractAspect* aspect = static_cast(index.internalPointer()); AbstractColumn* column = dynamic_cast(aspect); for (auto* curve : m_curvesList) dynamic_cast(curve)->setXErrorColumn(column); } void XYFitCurveDock::yErrorColumnChanged(const QModelIndex& index) { if (m_initializing) return; AbstractAspect* aspect = static_cast(index.internalPointer()); AbstractColumn* column = dynamic_cast(aspect); for (auto* curve : m_curvesList) dynamic_cast(curve)->setYErrorColumn(column); } void XYFitCurveDock::xErrorChanged(int index) { DEBUG("xErrorChanged() error = " << nsl_fit_error_type_name[index]); m_fitData.xErrorsType = (nsl_fit_error_type)index; // enable/disable weight column switch ((nsl_fit_error_type)index) { case nsl_fit_error_no: cbXErrorColumn->setEnabled(false); uiGeneralTab.lXErrorCol->setEnabled(false); break; case nsl_fit_error_direct: case nsl_fit_error_inverse: cbXErrorColumn->setEnabled(true); uiGeneralTab.lXErrorCol->setEnabled(true); break; } enableRecalculate(); } void XYFitCurveDock::yWeightChanged(int index) { DEBUG("yWeightChanged() weight = " << nsl_fit_weight_type_name[index]); m_fitData.yWeightsType = (nsl_fit_weight_type)index; // enable/disable weight column switch ((nsl_fit_weight_type)index) { case nsl_fit_weight_no: case nsl_fit_weight_statistical: case nsl_fit_weight_statistical_fit: case nsl_fit_weight_relative: case nsl_fit_weight_relative_fit: cbYErrorColumn->setEnabled(false); uiGeneralTab.lYErrorCol->setEnabled(false); break; case nsl_fit_weight_instrumental: case nsl_fit_weight_direct: case nsl_fit_weight_inverse: cbYErrorColumn->setEnabled(true); uiGeneralTab.lYErrorCol->setEnabled(true); break; } enableRecalculate(); } /*! * called when the fit model category (basic functions, peak functions etc.) was changed. * In the combobox for the model type shows the model types for the current category \index and calls \c modelTypeChanged() * to update the model type dependent widgets in the general-tab. */ void XYFitCurveDock::categoryChanged(int index) { if (index == nsl_fit_model_custom) { DEBUG("categoryChanged() category = \"nsl_fit_model_custom\""); } else { DEBUG("categoryChanged() category = \"" << nsl_fit_model_category_name[index] << "\""); } if (uiGeneralTab.cbCategory->currentIndex() == uiGeneralTab.cbCategory->count() - 1) m_fitData.modelCategory = nsl_fit_model_custom; else m_fitData.modelCategory = (nsl_fit_model_category)index; m_initializing = true; uiGeneralTab.cbModel->clear(); uiGeneralTab.cbModel->show(); uiGeneralTab.lModel->show(); switch (m_fitData.modelCategory) { case nsl_fit_model_basic: for(int i = 0; i < NSL_FIT_MODEL_BASIC_COUNT; i++) uiGeneralTab.cbModel->addItem(nsl_fit_model_basic_name[i]); break; case nsl_fit_model_peak: for(int i = 0; i < NSL_FIT_MODEL_PEAK_COUNT; i++) uiGeneralTab.cbModel->addItem(nsl_fit_model_peak_name[i]); break; case nsl_fit_model_growth: for(int i = 0; i < NSL_FIT_MODEL_GROWTH_COUNT; i++) uiGeneralTab.cbModel->addItem(nsl_fit_model_growth_name[i]); break; case nsl_fit_model_distribution: { for(int i = 0; i < NSL_SF_STATS_DISTRIBUTION_COUNT; i++) uiGeneralTab.cbModel->addItem(nsl_sf_stats_distribution_name[i]); // not-used items are disabled here const QStandardItemModel* model = qobject_cast(uiGeneralTab.cbModel->model()); for(int i = 1; i < NSL_SF_STATS_DISTRIBUTION_COUNT; i++) { // unused distributions if (i == nsl_sf_stats_levy_alpha_stable || i == nsl_sf_stats_levy_skew_alpha_stable || i == nsl_sf_stats_bernoulli) { QStandardItem* item = model->item(i); item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled)); } } break; } case nsl_fit_model_custom: uiGeneralTab.cbModel->addItem(i18n("Custom")); uiGeneralTab.cbModel->hide(); uiGeneralTab.lModel->hide(); } //show the fit-model for the currently selected default (first) fit-model m_fitData.modelType = 0; uiGeneralTab.cbModel->setCurrentIndex(m_fitData.modelType); modelTypeChanged(m_fitData.modelType); m_initializing = false; enableRecalculate(); } /*! * called when the fit model type (polynomial, power, etc.) was changed. * Updates the model type dependent widgets in the general-tab and calls \c updateModelEquation() to update the preview pixmap. */ void XYFitCurveDock::modelTypeChanged(int index) { DEBUG("modelTypeChanged() type = " << index << ", initializing = " << m_initializing); // leave if there is no selection if(index == -1) return; unsigned int type = 0; bool custom = false; if (m_fitData.modelCategory == nsl_fit_model_custom) custom = true; else type = (unsigned int)index; m_fitData.modelType = type; uiGeneralTab.teEquation->setReadOnly(!custom); uiGeneralTab.tbFunctions->setVisible(custom); uiGeneralTab.tbConstants->setVisible(custom); // default settings uiGeneralTab.lDegree->setText(i18n("Degree")); switch (m_fitData.modelCategory) { case nsl_fit_model_basic: switch (type) { case nsl_fit_model_polynomial: case nsl_fit_model_fourier: uiGeneralTab.lDegree->setVisible(true); uiGeneralTab.sbDegree->setVisible(true); uiGeneralTab.sbDegree->setMaximum(10); uiGeneralTab.sbDegree->setValue(1); break; case nsl_fit_model_power: uiGeneralTab.lDegree->setVisible(true); uiGeneralTab.sbDegree->setVisible(true); uiGeneralTab.sbDegree->setMaximum(2); uiGeneralTab.sbDegree->setValue(1); break; case nsl_fit_model_exponential: uiGeneralTab.lDegree->setVisible(true); uiGeneralTab.sbDegree->setVisible(true); uiGeneralTab.sbDegree->setMaximum(10); uiGeneralTab.sbDegree->setValue(1); break; default: uiGeneralTab.lDegree->setVisible(false); uiGeneralTab.sbDegree->setVisible(false); } break; case nsl_fit_model_peak: // all models support multiple peaks uiGeneralTab.lDegree->setText(i18n("Number of peaks")); uiGeneralTab.lDegree->setVisible(true); uiGeneralTab.sbDegree->setVisible(true); uiGeneralTab.sbDegree->setMaximum(9); uiGeneralTab.sbDegree->setValue(1); break; case nsl_fit_model_growth: case nsl_fit_model_distribution: case nsl_fit_model_custom: uiGeneralTab.lDegree->setVisible(false); uiGeneralTab.sbDegree->setVisible(false); } this->updateModelEquation(); + enableRecalculate(); } /*! * Show the preview pixmap of the fit model expression for the current model category and type. * Called when the model type or the degree of the model were changed. */ void XYFitCurveDock::updateModelEquation() { if (m_fitData.modelCategory == nsl_fit_model_custom) { DEBUG("XYFitCurveDock::updateModelEquation() category = nsl_fit_model_custom, type = " << m_fitData.modelType); } else { DEBUG("XYFitCurveDock::updateModelEquation() category = " << nsl_fit_model_category_name[m_fitData.modelCategory] << ", type = " << m_fitData.modelType); } //this function can also be called when the value for the degree was changed -> update the fit data structure int degree = uiGeneralTab.sbDegree->value(); m_fitData.degree = degree; XYFitCurve::initFitData(m_fitData); // set model dependent start values from curve data XYFitCurve::initStartValues(m_fitData, m_curve); // variables/parameter that are known QStringList vars = {"x"}; vars << m_fitData.paramNames; uiGeneralTab.teEquation->setVariables(vars); // set formula picture uiGeneralTab.lEquation->setText(QLatin1String("f(x) =")); QString file; switch (m_fitData.modelCategory) { case nsl_fit_model_basic: { // formula pic depends on degree QString numSuffix = QString::number(degree); if (degree > 4) numSuffix = "4"; if ((nsl_fit_model_type_basic)m_fitData.modelType == nsl_fit_model_power && degree > 2) numSuffix = "2"; file = QStandardPaths::locate(QStandardPaths::AppDataLocation, "pics/fit_models/" + QString(nsl_fit_model_basic_pic_name[m_fitData.modelType]) + numSuffix + ".png"); break; } case nsl_fit_model_peak: { // formula pic depends on number of peaks QString numSuffix = QString::number(degree); if (degree > 4) numSuffix = "4"; file = QStandardPaths::locate(QStandardPaths::AppDataLocation, "pics/fit_models/" + QString(nsl_fit_model_peak_pic_name[m_fitData.modelType]) + numSuffix + ".png"); break; } case nsl_fit_model_growth: file = QStandardPaths::locate(QStandardPaths::AppDataLocation, "pics/fit_models/" + QString(nsl_fit_model_growth_pic_name[m_fitData.modelType]) + ".png"); break; case nsl_fit_model_distribution: file = QStandardPaths::locate(QStandardPaths::AppDataLocation, "pics/gsl_distributions/" + QString(nsl_sf_stats_distribution_pic_name[m_fitData.modelType]) + ".png"); // change label if (m_fitData.modelType == nsl_sf_stats_poisson) uiGeneralTab.lEquation->setText(QLatin1String("f(k)/A =")); else uiGeneralTab.lEquation->setText(QLatin1String("f(x)/A =")); break; case nsl_fit_model_custom: uiGeneralTab.teEquation->show(); uiGeneralTab.teEquation->clear(); uiGeneralTab.teEquation->insertPlainText(m_fitData.model); uiGeneralTab.lFuncPic->hide(); } if (m_fitData.modelCategory != nsl_fit_model_custom) { DEBUG("Model pixmap path = " << file.toStdString()); uiGeneralTab.lFuncPic->setPixmap(file); uiGeneralTab.lFuncPic->show(); uiGeneralTab.teEquation->hide(); } } void XYFitCurveDock::showConstants() { QMenu menu; ConstantsWidget constants(&menu); connect(&constants, SIGNAL(constantSelected(QString)), this, SLOT(insertConstant(QString))); connect(&constants, SIGNAL(constantSelected(QString)), &menu, SLOT(close())); connect(&constants, SIGNAL(canceled()), &menu, SLOT(close())); QWidgetAction* widgetAction = new QWidgetAction(this); widgetAction->setDefaultWidget(&constants); menu.addAction(widgetAction); QPoint pos(-menu.sizeHint().width() + uiGeneralTab.tbConstants->width(), -menu.sizeHint().height()); menu.exec(uiGeneralTab.tbConstants->mapToGlobal(pos)); } void XYFitCurveDock::showFunctions() { QMenu menu; FunctionsWidget functions(&menu); connect(&functions, SIGNAL(functionSelected(QString)), this, SLOT(insertFunction(QString))); connect(&functions, SIGNAL(functionSelected(QString)), &menu, SLOT(close())); connect(&functions, SIGNAL(canceled()), &menu, SLOT(close())); QWidgetAction* widgetAction = new QWidgetAction(this); widgetAction->setDefaultWidget(&functions); menu.addAction(widgetAction); QPoint pos(-menu.sizeHint().width() + uiGeneralTab.tbFunctions->width(), -menu.sizeHint().height()); menu.exec(uiGeneralTab.tbFunctions->mapToGlobal(pos)); } void XYFitCurveDock::updateParameterList() { + DEBUG("XYFitCurveDock::updateParameterList()"); // use current model function m_fitData.model = uiGeneralTab.teEquation->toPlainText(); ExpressionParser* parser = ExpressionParser::getInstance(); QStringList vars; // variables that are known vars << "x"; //TODO: others? m_fitData.paramNames = m_fitData.paramNamesUtf8 = parser->getParameter(m_fitData.model, vars); // if number of parameter changed bool moreParameter = false; if (m_fitData.paramNames.size() > m_fitData.paramStartValues.size()) moreParameter = true; if (m_fitData.paramNames.size() != m_fitData.paramStartValues.size()) { m_fitData.paramStartValues.resize(m_fitData.paramNames.size()); m_fitData.paramFixed.resize(m_fitData.paramNames.size()); m_fitData.paramLowerLimits.resize(m_fitData.paramNames.size()); m_fitData.paramUpperLimits.resize(m_fitData.paramNames.size()); } if (moreParameter) { for (int i = m_fitData.paramStartValues.size() - 1; i < m_fitData.paramNames.size(); ++i) { m_fitData.paramStartValues[i] = 1.0; m_fitData.paramFixed[i] = false; m_fitData.paramLowerLimits[i] = -std::numeric_limits::max(); m_fitData.paramUpperLimits[i] = std::numeric_limits::max(); } } parametersChanged(); } void XYFitCurveDock::showParameters() { if (m_fitData.modelCategory == nsl_fit_model_custom) updateParameterList(); QMenu menu; FitParametersWidget w(&menu, &m_fitData); connect(&w, SIGNAL(finished()), &menu, SLOT(close())); connect(&w, SIGNAL(parametersChanged()), this, SLOT(parametersChanged())); QWidgetAction* widgetAction = new QWidgetAction(this); widgetAction->setDefaultWidget(&w); menu.addAction(widgetAction); menu.setMinimumWidth(w.width()); menu.setTearOffEnabled(true); //menu.setWindowFlags(menu.windowFlags() & Qt::MSWindowsFixedSizeDialogHint); QPoint pos(-menu.sizeHint().width() + uiGeneralTab.pbParameters->width(), 0); menu.exec(uiGeneralTab.pbParameters->mapToGlobal(pos)); } /*! * called when parameter names and/or start values for the custom model were changed */ void XYFitCurveDock::parametersChanged() { + DEBUG("XYFitCurveDock::parametersChanged()"); //parameter names were (probably) changed -> set the new names in EquationTextEdit uiGeneralTab.teEquation->setVariables(m_fitData.paramNames); enableRecalculate(); } void XYFitCurveDock::showOptions() { QMenu menu; FitOptionsWidget w(&menu, &m_fitData, m_fitCurve); connect(&w, SIGNAL(finished()), &menu, SLOT(close())); connect(&w, SIGNAL(optionsChanged()), this, SLOT(enableRecalculate())); QWidgetAction* widgetAction = new QWidgetAction(this); widgetAction->setDefaultWidget(&w); menu.addAction(widgetAction); menu.setTearOffEnabled(true); //menu.setWindowFlags(menu.windowFlags() & Qt::MSWindowsFixedSizeDialogHint); QPoint pos(-menu.sizeHint().width() + uiGeneralTab.pbParameters->width(), 0); menu.exec(uiGeneralTab.pbOptions->mapToGlobal(pos)); } void XYFitCurveDock::insertFunction(const QString& str) const { + //TODO: not all function have only one argument! uiGeneralTab.teEquation->insertPlainText(str + "(x)"); } void XYFitCurveDock::insertConstant(const QString& str) const { uiGeneralTab.teEquation->insertPlainText(str); } void XYFitCurveDock::recalculateClicked() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); m_fitData.degree = uiGeneralTab.sbDegree->value(); if (m_fitData.modelCategory == nsl_fit_model_custom) updateParameterList(); for (XYCurve* curve: m_curvesList) dynamic_cast(curve)->setFitData(m_fitData); this->showFitResult(); uiGeneralTab.pbRecalculate->setEnabled(false); emit info(i18n("Fit status: ") + m_fitCurve->fitResult().status); QApplication::restoreOverrideCursor(); } +void XYFitCurveDock::expressionChanged() { + DEBUG("XYFitCurveDock::expressionChanged()"); + if (m_initializing) + return; + + // update parameter list for custom model + if (m_fitData.modelCategory == nsl_fit_model_custom) + updateParameterList(); + + enableRecalculate(); +} + void XYFitCurveDock::enableRecalculate() const { + DEBUG("XYFitCurveDock::enableRecalculate()"); if (m_initializing || m_fitCurve == nullptr) return; //no fitting possible without the x- and y-data bool hasSourceData = false; if (m_fitCurve->dataSourceType() == XYAnalysisCurve::DataSourceSpreadsheet) { AbstractAspect* aspectX = static_cast(cbXDataColumn->currentModelIndex().internalPointer()); AbstractAspect* aspectY = static_cast(cbYDataColumn->currentModelIndex().internalPointer()); hasSourceData = (aspectX != 0 && aspectY != 0); } else { hasSourceData = (m_fitCurve->dataSourceCurve() != nullptr); } uiGeneralTab.pbRecalculate->setEnabled(hasSourceData); } void XYFitCurveDock::resultCopySelection() { QTableWidget* tw = nullptr; int currentTab = uiGeneralTab.twResults->currentIndex(); DEBUG("current tab = " << currentTab); if (currentTab == 0) tw = uiGeneralTab.twParameters; else if (currentTab == 1) tw = uiGeneralTab.twGoodness; else if (currentTab == 2) tw = uiGeneralTab.twLog; else return; QTableWidgetSelectionRange range = tw->selectedRanges().first(); QString str; for (int i = 0; i < range.rowCount(); ++i) { if (i > 0) str += "\n"; for (int j = 0; j < range.columnCount(); ++j) { if (j > 0) str += "\t"; str += tw->item(range.topRow() + i, range.leftColumn() + j)->text(); } } str += "\n"; QApplication::clipboard()->setText(str); DEBUG(QApplication::clipboard()->text().toStdString()); } void XYFitCurveDock::resultCopyAll() { const XYFitCurve::FitResult& fitResult = m_fitCurve->fitResult(); int currentTab = uiGeneralTab.twResults->currentIndex(); QString str; if (currentTab == 0) { str = i18n("Parameters:") + "\n"; const int np = fitResult.paramValues.size(); for (int i = 0; i < np; i++) { if (m_fitData.paramFixed.at(i)) str += m_fitData.paramNamesUtf8.at(i) + QString(" = ") + QString::number(fitResult.paramValues.at(i)) + "\n"; else { str += m_fitData.paramNamesUtf8.at(i) + QString(" = ") + QString::number(fitResult.paramValues.at(i)) + UTF8_QSTRING("±") + QString::number(fitResult.errorValues.at(i)) + " (" + QString::number(100.*fitResult.errorValues.at(i)/std::abs(fitResult.paramValues.at(i)), 'g', 3) + " %)\n"; const double margin = fitResult.tdist_marginValues.at(i); QString tdistValueString; if (fitResult.tdist_tValues.at(i) < std::numeric_limits::max()) tdistValueString = QString::number(fitResult.tdist_tValues.at(i), 'g', 3); else tdistValueString = UTF8_QSTRING("∞"); str += " (" + i18n("t statistic:") + ' ' + tdistValueString + ", " + i18n("p value:") + ' ' + QString::number(fitResult.tdist_pValues.at(i), 'g', 3) + ", " + i18n("conf. interval:") + ' '; if (std::abs(fitResult.tdist_tValues.at(i)) < 1.e6) { str += QString::number(fitResult.paramValues.at(i) - margin) + " .. " + QString::number(fitResult.paramValues.at(i) + margin) + ")\n"; } else { str += i18n("too small"); } } } } else if (currentTab == 1) { str = i18n("Goodness of fit:") + "\n"; str += i18n("sum of squared residuals") + " (" + UTF8_QSTRING("χ²") + "): " + QString::number(fitResult.sse) + "\n"; if (fitResult.dof != 0) { str += i18n("reduced") + ' ' + UTF8_QSTRING("χ²") + ": " + QString::number(fitResult.rms) + '\n'; str += i18n("root mean square error") + " (RMSE): " + QString::number(fitResult.rsd) + "\n"; str += i18n("coefficient of determination") + " (" + UTF8_QSTRING("R²") + "): " + QString::number(fitResult.rsquare, 'g', 15) + '\n'; str += i18n("adj. coefficient of determination")+ " (" + UTF8_QSTRING("R̄²") + "): " + QString::number(fitResult.rsquareAdj, 'g', 15) + "\n\n"; str += i18n("P > ") + UTF8_QSTRING("χ²") + ": " + QString::number(fitResult.chisq_p, 'g', 3) + '\n'; str += i18n("F statistic") + ": " + QString::number(fitResult.fdist_F, 'g', 3) + '\n'; str += i18n("P > F") + ": " + QString::number(fitResult.fdist_p, 'g', 3) + '\n'; } str += i18n("mean absolute error:") + ' ' + QString::number(fitResult.mae) + '\n'; str += i18n("Akaike information criterion:") + ' ' + QString::number(fitResult.aic) + '\n'; str += i18n("Bayesian information criterion:") + ' ' + QString::number(fitResult.bic) + '\n'; } else if (currentTab == 2) { str = i18n("status:") + ' ' + fitResult.status + '\n'; str += i18n("iterations:") + ' ' + QString::number(fitResult.iterations) + '\n'; str += i18n("tolerance:") + ' ' + QString::number(m_fitData.eps) + '\n'; if (fitResult.elapsedTime > 1000) str += i18n("calculation time: %1 s", fitResult.elapsedTime/1000) + '\n'; else str += i18n("calculation time: %1 ms", fitResult.elapsedTime) + '\n'; str += i18n("degrees of freedom:") + ' ' + QString::number(fitResult.dof) + '\n'; str += i18n("number of parameters:") + ' ' + QString::number(fitResult.paramValues.size()) + '\n'; str += i18n("X range:") + ' ' + QString::number(m_fitData.xRange.first()) + " .. " + QString::number(m_fitData.xRange.last()) + '\n'; str += i18n("Iterations:") + '\n'; for (const auto &s: m_fitData.paramNamesUtf8) str += s + '\t'; str += UTF8_QSTRING("χ²"); const QStringList iterations = fitResult.solverOutput.split(';'); for (const auto &s: iterations) if (!s.isEmpty()) str += '\n' + s; } QApplication::clipboard()->setText(str); DEBUG(QApplication::clipboard()->text().toStdString()); } void XYFitCurveDock::resultParametersContextMenuRequest(const QPoint &pos) { QMenu *contextMenu = new QMenu; contextMenu->addAction("Copy selection", this, SLOT(resultCopySelection())); contextMenu->addAction("Copy all", this, SLOT(resultCopyAll())); contextMenu->exec(uiGeneralTab.twParameters->mapToGlobal(pos)); } void XYFitCurveDock::resultGoodnessContextMenuRequest(const QPoint &pos) { QMenu *contextMenu = new QMenu; contextMenu->addAction("Copy selection", this, SLOT(resultCopySelection())); contextMenu->addAction("Copy all", this, SLOT(resultCopyAll())); contextMenu->exec(uiGeneralTab.twGoodness->mapToGlobal(pos)); } void XYFitCurveDock::resultLogContextMenuRequest(const QPoint &pos) { QMenu *contextMenu = new QMenu; contextMenu->addAction("Copy selection", this, SLOT(resultCopySelection())); contextMenu->addAction("Copy all", this, SLOT(resultCopyAll())); contextMenu->exec(uiGeneralTab.twLog->mapToGlobal(pos)); } /*! * show the result and details of fit */ void XYFitCurveDock::showFitResult() { DEBUG("XYFitCurveDock::showFitResult()"); //clear the previous result uiGeneralTab.twParameters->setRowCount(0); for (int row = 0; row < uiGeneralTab.twGoodness->rowCount(); ++row) uiGeneralTab.twGoodness->item(row, 2)->setText(""); for (int row = 0; row < uiGeneralTab.twLog->rowCount(); ++row) uiGeneralTab.twLog->item(row, 1)->setText(""); const XYFitCurve::FitResult& fitResult = m_fitCurve->fitResult(); if (!fitResult.available) { DEBUG("fit result not available"); return; } // Log uiGeneralTab.twLog->item(0, 1)->setText(fitResult.status); if (!fitResult.valid) { DEBUG("fit result not valid"); return; } uiGeneralTab.twLog->item(1, 1)->setText(QString::number(fitResult.iterations)); uiGeneralTab.twLog->item(2, 1)->setText(QString::number(m_fitData.eps)); if (fitResult.elapsedTime > 1000) uiGeneralTab.twLog->item(3, 1)->setText(QString::number(fitResult.elapsedTime/1000) + " s"); else uiGeneralTab.twLog->item(3, 1)->setText(QString::number(fitResult.elapsedTime) + " ms"); uiGeneralTab.twLog->item(4, 1)->setText(QString::number(fitResult.dof)); uiGeneralTab.twLog->item(5, 1)->setText(QString::number(fitResult.paramValues.size())); uiGeneralTab.twLog->item(6, 1)->setText(QString::number(m_fitData.xRange.first()) + " .. " + QString::number(m_fitData.xRange.last()) ); // show all iterations QString str; for (const auto &s: m_fitData.paramNamesUtf8) str += s + '\t'; str += UTF8_QSTRING("χ²"); const QStringList iterations = fitResult.solverOutput.split(';'); for (const auto &s: iterations) if (!s.isEmpty()) str += '\n' + s; uiGeneralTab.twLog->item(7, 1)->setText(str); uiGeneralTab.twLog->resizeRowsToContents(); // Parameters const int np = m_fitData.paramNames.size(); uiGeneralTab.twParameters->setRowCount(np); QStringList headerLabels; headerLabels << i18n("Name") << i18n("Value") << i18n("Error") << i18n("Error, %") << i18n("t statistic") << QLatin1String("P > |t|") << i18n("Conf. Interval"); uiGeneralTab.twParameters->setHorizontalHeaderLabels(headerLabels); for (int i = 0; i < np; i++) { const double paramValue = fitResult.paramValues.at(i); const double errorValue = fitResult.errorValues.at(i); QTableWidgetItem* item = new QTableWidgetItem(m_fitData.paramNamesUtf8.at(i)); item->setBackground(QApplication::palette().color(QPalette::Window)); uiGeneralTab.twParameters->setItem(i, 0, item); item = new QTableWidgetItem(QString::number(paramValue)); uiGeneralTab.twParameters->setItem(i, 1, item); if (!m_fitData.paramFixed.at(i)) { if (!std::isnan(errorValue)) { item = new QTableWidgetItem(QString::number(errorValue, 'g', 6)); uiGeneralTab.twParameters->setItem(i, 2, item); item = new QTableWidgetItem(QString::number(100.*errorValue/std::abs(paramValue), 'g', 3)); uiGeneralTab.twParameters->setItem(i, 3, item); } else { item = new QTableWidgetItem(UTF8_QSTRING("∞")); uiGeneralTab.twParameters->setItem(i, 2, item); item = new QTableWidgetItem(UTF8_QSTRING("∞")); uiGeneralTab.twParameters->setItem(i, 3, item); } // t values QString tdistValueString; if (fitResult.tdist_tValues.at(i) < std::numeric_limits::max()) tdistValueString = QString::number(fitResult.tdist_tValues.at(i), 'g', 3); else tdistValueString = UTF8_QSTRING("∞"); item = new QTableWidgetItem(tdistValueString); uiGeneralTab.twParameters->setItem(i, 4, item); // p values const double p = fitResult.tdist_pValues.at(i); item = new QTableWidgetItem(QString::number(p, 'g', 3)); // color p values depending on value if (p > 0.05) item->setTextColor(QApplication::palette().color(QPalette::LinkVisited)); else if (p > 0.01) item->setTextColor(Qt::darkGreen); else if (p > 0.001) item->setTextColor(Qt::darkCyan); else if (p > 0.0001) item->setTextColor(QApplication::palette().color(QPalette::Link)); else item->setTextColor(QApplication::palette().color(QPalette::Highlight)); uiGeneralTab.twParameters->setItem(i, 5, item); // Conf. interval if (!std::isnan(errorValue)) { const double margin = fitResult.tdist_marginValues.at(i); if (fitResult.tdist_tValues.at(i) < 1.e6) item = new QTableWidgetItem(QString::number(paramValue - margin) + QLatin1String(" .. ") + QString::number(paramValue + margin)); else item = new QTableWidgetItem(i18n("too small")); uiGeneralTab.twParameters->setItem(i, 6, item); } } } // Goodness of fit uiGeneralTab.twGoodness->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); uiGeneralTab.twGoodness->item(0, 2)->setText(QString::number(fitResult.sse)); if (fitResult.dof != 0) { uiGeneralTab.twGoodness->item(1, 2)->setText(QString::number(fitResult.rms)); uiGeneralTab.twGoodness->item(2, 2)->setText(QString::number(fitResult.rsd)); uiGeneralTab.twGoodness->item(3, 2)->setText(QString::number(fitResult.rsquare, 'g', 15)); uiGeneralTab.twGoodness->item(4, 2)->setText(QString::number(fitResult.rsquareAdj, 'g', 15)); // chi^2 and F test p-values uiGeneralTab.twGoodness->item(5, 2)->setText(QString::number(fitResult.chisq_p, 'g', 3)); uiGeneralTab.twGoodness->item(6, 2)->setText(QString::number(fitResult.fdist_F, 'g', 3)); uiGeneralTab.twGoodness->item(7, 2)->setText(QString::number(fitResult.fdist_p, 'g', 3)); uiGeneralTab.twGoodness->item(9, 2)->setText(QString::number(fitResult.aic, 'g', 3)); uiGeneralTab.twGoodness->item(10, 2)->setText(QString::number(fitResult.bic, 'g', 3)); } uiGeneralTab.twGoodness->item(8, 2)->setText(QString::number(fitResult.mae)); //resize the table headers to fit the new content uiGeneralTab.twLog->resizeColumnsToContents(); uiGeneralTab.twParameters->resizeColumnsToContents(); //twGoodness doesn't have any header -> resize sections uiGeneralTab.twGoodness->resizeColumnToContents(0); uiGeneralTab.twGoodness->resizeColumnToContents(1); uiGeneralTab.twGoodness->resizeColumnToContents(2); //enable the "recalculate"-button if the source data was changed since the last fit uiGeneralTab.pbRecalculate->setEnabled(m_fitCurve->isSourceDataChangedSinceLastRecalc()); } //************************************************************* //*********** SLOTs for changes triggered in XYCurve ********** //************************************************************* //General-Tab void XYFitCurveDock::curveDescriptionChanged(const AbstractAspect* aspect) { if (m_curve != aspect) return; m_initializing = true; if (aspect->name() != uiGeneralTab.leName->text()) uiGeneralTab.leName->setText(aspect->name()); else if (aspect->comment() != uiGeneralTab.leComment->text()) uiGeneralTab.leComment->setText(aspect->comment()); m_initializing = false; } void XYFitCurveDock::curveDataSourceTypeChanged(XYAnalysisCurve::DataSourceType type) { m_initializing = true; uiGeneralTab.cbDataSourceType->setCurrentIndex(type); m_initializing = false; } void XYFitCurveDock::curveDataSourceCurveChanged(const XYCurve* curve) { m_initializing = true; XYCurveDock::setModelIndexFromAspect(cbDataSourceCurve, curve); m_initializing = false; } void XYFitCurveDock::curveXDataColumnChanged(const AbstractColumn* column) { m_initializing = true; XYCurveDock::setModelIndexFromAspect(cbXDataColumn, column); m_initializing = false; } void XYFitCurveDock::curveYDataColumnChanged(const AbstractColumn* column) { m_initializing = true; XYCurveDock::setModelIndexFromAspect(cbYDataColumn, column); m_initializing = false; } void XYFitCurveDock::curveXErrorColumnChanged(const AbstractColumn* column) { m_initializing = true; XYCurveDock::setModelIndexFromAspect(cbXErrorColumn, column); m_initializing = false; } void XYFitCurveDock::curveYErrorColumnChanged(const AbstractColumn* column) { m_initializing = true; XYCurveDock::setModelIndexFromAspect(cbYErrorColumn, column); m_initializing = false; } void XYFitCurveDock::curveFitDataChanged(const XYFitCurve::FitData& fitData) { m_initializing = true; m_fitData = fitData; if (m_fitData.modelCategory == nsl_fit_model_custom) uiGeneralTab.teEquation->setPlainText(m_fitData.model); else uiGeneralTab.cbModel->setCurrentIndex(m_fitData.modelType); uiGeneralTab.sbDegree->setValue(m_fitData.degree); this->showFitResult(); m_initializing = false; } void XYFitCurveDock::dataChanged() { this->enableRecalculate(); } diff --git a/src/kdefrontend/dockwidgets/XYFitCurveDock.h b/src/kdefrontend/dockwidgets/XYFitCurveDock.h index 48437d027..1a3ac561d 100644 --- a/src/kdefrontend/dockwidgets/XYFitCurveDock.h +++ b/src/kdefrontend/dockwidgets/XYFitCurveDock.h @@ -1,113 +1,114 @@ /*************************************************************************** File : XYFitCurveDock.h Project : LabPlot -------------------------------------------------------------------- Copyright : (C) 2014 Alexander Semke (alexander.semke@web.de) Copyright : (C) 2017 Stefan Gerlach (stefan.gerlach@uni.kn) Description : widget for editing properties of equation curves ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #ifndef XYFITCURVEDOCK_H #define XYFITCURVEDOCK_H #include "kdefrontend/dockwidgets/XYCurveDock.h" #include "backend/worksheet/plots/cartesian/XYFitCurve.h" #include "ui_xyfitcurvedockgeneraltab.h" class TreeViewComboBox; class XYFitCurveDock: public XYCurveDock { Q_OBJECT public: explicit XYFitCurveDock(QWidget* parent); void setCurves(QList); virtual void setupGeneral(); private: virtual void initGeneralTab(); void showFitResult(); void updateSettings(const AbstractColumn*); Ui::XYFitCurveDockGeneralTab uiGeneralTab; TreeViewComboBox* cbDataSourceCurve; TreeViewComboBox* cbXDataColumn; TreeViewComboBox* cbYDataColumn; TreeViewComboBox* cbXErrorColumn; TreeViewComboBox* cbYErrorColumn; XYFitCurve* m_fitCurve; XYFitCurve::FitData m_fitData; QList parameters; QList parameterValues; protected: virtual void setModel(); private slots: //SLOTs for changes triggered in XYFitCurveDock //general tab void nameChanged(); void commentChanged(); void dataSourceTypeChanged(int); void dataSourceCurveChanged(const QModelIndex&); void xErrorChanged(int); void yWeightChanged(int); void categoryChanged(int); void modelTypeChanged(int); void xDataColumnChanged(const QModelIndex&); void yDataColumnChanged(const QModelIndex&); void xErrorColumnChanged(const QModelIndex&); void yErrorColumnChanged(const QModelIndex&); void showConstants(); void showFunctions(); void updateParameterList(); void showParameters(); void parametersChanged(); void showOptions(); void insertFunction(const QString&) const; void insertConstant(const QString&) const; void recalculateClicked(); void updateModelEquation(); + void expressionChanged(); void enableRecalculate() const; void resultParametersContextMenuRequest(const QPoint &); void resultGoodnessContextMenuRequest(const QPoint &); void resultLogContextMenuRequest(const QPoint &); void resultCopySelection(); void resultCopyAll(); //SLOTs for changes triggered in XYCurve //General-Tab void curveDescriptionChanged(const AbstractAspect*); void curveDataSourceTypeChanged(XYAnalysisCurve::DataSourceType); void curveDataSourceCurveChanged(const XYCurve*); void curveXDataColumnChanged(const AbstractColumn*); void curveYDataColumnChanged(const AbstractColumn*); void curveXErrorColumnChanged(const AbstractColumn*); void curveYErrorColumnChanged(const AbstractColumn*); void curveFitDataChanged(const XYFitCurve::FitData&); void dataChanged(); }; #endif diff --git a/src/kdefrontend/widgets/ExpressionTextEdit.cpp b/src/kdefrontend/widgets/ExpressionTextEdit.cpp index 661621dc1..930e20089 100644 --- a/src/kdefrontend/widgets/ExpressionTextEdit.cpp +++ b/src/kdefrontend/widgets/ExpressionTextEdit.cpp @@ -1,251 +1,254 @@ /*************************************************************************** File : ExpressionTextEdit.cpp Project : LabPlot -------------------------------------------------------------------- Copyright : (C) 2014-2017 Alexander Semke (alexander.semke@web.de) Description : widget for defining mathematical expressions modified version of http://qt-project.org/doc/qt-4.8/tools-customcompleter.html ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ /**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "ExpressionTextEdit.h" #include "backend/gsl/ExpressionParser.h" #include "tools/EquationHighlighter.h" #include #include #include #include /*! \class ExpressionTextEdit \brief Provides a widget for defining mathematical expressions Supports syntax-highlighting and completion. Modified version of http://qt-project.org/doc/qt-4.8/tools-customcompleter.html \ingroup kdefrontend */ ExpressionTextEdit::ExpressionTextEdit(QWidget* parent) : KTextEdit(parent), m_highlighter(new EquationHighlighter(this)), m_expressionType(XYEquationCurve::Neutral), m_isValid(false) { QStringList list = ExpressionParser::getInstance()->functions(); list.append(ExpressionParser::getInstance()->constants()); setTabChangesFocus(true); m_completer = new QCompleter(list, this); m_completer->setWidget(this); m_completer->setCompletionMode(QCompleter::PopupCompletion); m_completer->setCaseSensitivity(Qt::CaseInsensitive); connect(m_completer, static_cast(&QCompleter::activated),this, &ExpressionTextEdit::insertCompletion); connect(this, SIGNAL(textChanged()), this, SLOT(validateExpression()) ); connect(this, SIGNAL(cursorPositionChanged()), m_highlighter, SLOT(rehighlight()) ); } EquationHighlighter* ExpressionTextEdit::highlighter() { return m_highlighter; } bool ExpressionTextEdit::isValid() const { return (!document()->toPlainText().trimmed().isEmpty() && m_isValid); } void ExpressionTextEdit::setExpressionType(XYEquationCurve::EquationType type) { m_expressionType = type; m_variables.clear(); if (type==XYEquationCurve::Cartesian) m_variables<<"x"; else if (type==XYEquationCurve::Polar) m_variables<<"phi"; else if (type==XYEquationCurve::Parametric) m_variables<<"t"; else if (type==XYEquationCurve::Implicit) m_variables<<"x"<<"y"; m_highlighter->setVariables(m_variables); } void ExpressionTextEdit::setVariables(const QStringList& vars) { m_variables = vars; m_highlighter->setVariables(m_variables); validateExpression(true); } void ExpressionTextEdit::insertCompletion(const QString& completion) { QTextCursor tc = textCursor(); int extra = completion.length() - m_completer->completionPrefix().length(); tc.movePosition(QTextCursor::Left); tc.movePosition(QTextCursor::EndOfWord); tc.insertText(completion.right(extra)); setTextCursor(tc); } /*! * \brief Validates the current expression if the text was changed and highlights the text field red if the expression is invalid. * \param force forces the validation and highlighting when no text changes were made, used when new parameters/variables were provided */ void ExpressionTextEdit::validateExpression(bool force) { //check whether the expression was changed or only the formating QString text = toPlainText(); - if (text != m_currentExpression || force) { + bool textChanged = (text != m_currentExpression) ? true : false; + + if (textChanged || force) { m_isValid = ExpressionParser::getInstance()->isValid(text, m_variables); if (!m_isValid) setStyleSheet("QTextEdit{background: red;}"); else setStyleSheet(""); m_currentExpression = text; - emit expressionChanged(); } + if (textChanged) + emit expressionChanged(); } //############################################################################## //#################################### Events ############################### //############################################################################## void ExpressionTextEdit::focusInEvent(QFocusEvent* e) { m_completer->setWidget(this); QTextEdit::focusInEvent(e); } void ExpressionTextEdit::focusOutEvent(QFocusEvent* e) { //when loosing focus, rehighlight to remove potential highlighting of openning and closing brackets m_highlighter->rehighlight(); QTextEdit::focusOutEvent(e); } void ExpressionTextEdit::keyPressEvent(QKeyEvent* e) { switch (e->key()) { case Qt::Key_Enter: case Qt::Key_Return: e->ignore(); return; default: break; } bool isShortcut = ((e->modifiers() & Qt::ControlModifier) && e->key() == Qt::Key_E); // CTRL+E if (!isShortcut) // do not process the shortcut when we have a completer QTextEdit::keyPressEvent(e); const bool ctrlOrShift = e->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier); if ((ctrlOrShift && e->text().isEmpty())) return; static QString eow("~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-="); // end of word bool hasModifier = (e->modifiers() != Qt::NoModifier) && !ctrlOrShift; QTextCursor tc = textCursor(); tc.select(QTextCursor::WordUnderCursor); const QString& completionPrefix = tc.selectedText(); if (!isShortcut && (hasModifier || e->text().isEmpty()|| completionPrefix.length() < 1 || eow.contains(e->text().right(1)))) { m_completer->popup()->hide(); return; } if (completionPrefix != m_completer->completionPrefix()) { m_completer->setCompletionPrefix(completionPrefix); m_completer->popup()->setCurrentIndex(m_completer->completionModel()->index(0, 0)); } QRect cr = cursorRect(); cr.setWidth(m_completer->popup()->sizeHintForColumn(0) + m_completer->popup()->verticalScrollBar()->sizeHint().width()); m_completer->complete(cr); // popup it up! } void ExpressionTextEdit::mouseMoveEvent(QMouseEvent* e) { QTextCursor tc = cursorForPosition(e->pos()); tc.select(QTextCursor::WordUnderCursor); const QString& token = tc.selectedText(); if (token.isEmpty()) { setToolTip(""); return; } //try to find the token under the mouse cursor in the list of constants first static const QStringList& constants = ExpressionParser::getInstance()->constants(); int index = constants.indexOf(token); if (index != -1) { static const QStringList& names = ExpressionParser::getInstance()->constantsNames(); static const QStringList& values = ExpressionParser::getInstance()->constantsValues(); static const QStringList& units = ExpressionParser::getInstance()->constantsUnits(); setToolTip(names.at(index) + ": " + constants.at(index) + " = " + values.at(index) + " " + units.at(index)); } else { //text token was not found in the list of constants -> check functions as next static const QStringList& functions = ExpressionParser::getInstance()->functions(); index = functions.indexOf(token); if (index != -1) { static const QStringList& names = ExpressionParser::getInstance()->functionsNames(); setToolTip(functions.at(index) + " - " + names.at(index)); } else setToolTip(""); } KTextEdit::mouseMoveEvent(e); } diff --git a/tests/analysis/fit/FitTest.cpp b/tests/analysis/fit/FitTest.cpp index 6883d8a1c..cba374efc 100644 --- a/tests/analysis/fit/FitTest.cpp +++ b/tests/analysis/fit/FitTest.cpp @@ -1,2037 +1,2037 @@ /*************************************************************************** File : FitTest.cpp Project : LabPlot Description : Tests for data fitting -------------------------------------------------------------------- Copyright : (C) 2017 Alexander Semke (alexander.semke@web.de) Copyright : (C) 2018 Stefan Gerlach (stefan.gerlach@uni.kn) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #include "FitTest.h" #include "backend/core/column/Column.h" #include "backend/worksheet/plots/cartesian/XYFitCurve.h" extern "C" { #include "backend/nsl/nsl_sf_stats.h" #include "backend/nsl/nsl_stats.h" } void FitTest::initTestCase() { // needed in order to have the signals triggered by SignallingUndoCommand, see LabPlot.cpp //TODO: redesign/remove this qRegisterMetaType("const AbstractAspect*"); qRegisterMetaType("const AbstractColumn*"); } //############################################################################## //################# linear regression with NIST datasets ###################### //############################################################################## void FitTest::testLinearNorris() { //NIST data for Norris dataset QVector 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,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}; QVector 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,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}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_basic; fitData.modelType = nsl_fit_model_polynomial; fitData.degree = 1; XYFitCurve::initFitData(fitData); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); const int np = fitData.paramNames.size(); QCOMPARE(np, 2); QCOMPARE(fitResult.paramValues.at(0), -0.262323073774029); QCOMPARE(fitResult.errorValues.at(0), 0.232818234301152); QCOMPARE(fitResult.paramValues.at(1), 1.00211681802045); QCOMPARE(fitResult.errorValues.at(1), 0.429796848199937e-3); QCOMPARE(fitResult.rsd, 0.884796396144373); QCOMPARE(fitResult.rsquare, 0.999993745883712); QCOMPARE(fitResult.sse, 26.6173985294224); QCOMPARE(fitResult.rms, 0.782864662630069); DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 5436419.54079774 FuzzyCompare(fitResult.fdist_F, 5436385.54079785, 1.e-5); } void FitTest::testLinearPontius() { //NIST data for Pontius dataset QVector xData = {150000,300000,450000,600000,750000,900000,1050000,1200000,1350000,1500000,1650000,1800000,1950000,2100000, 2250000,2400000,2550000,2700000,2850000,3000000,150000,300000,450000,600000,750000,900000,1050000,1200000,1350000,1500000, 1650000,1800000,1950000,2100000,2250000,2400000,2550000,2700000,2850000,3000000}; QVector yData = {.11019,.21956,.32949,.43899,.54803,.65694,.76562,.87487,.98292,1.09146,1.20001,1.30822,1.41599,1.52399, 1.63194,1.73947,1.84646,1.95392,2.06128,2.16844,.11052,.22018,.32939,.43886,.54798,.65739,.76596,.87474, .98300,1.09150,1.20004,1.30818,1.41613,1.52408,1.63159,1.73965,1.84696,1.95445,2.06177,2.16829}; //data source columns Column xDataColumn("x", AbstractColumn::Integer); xDataColumn.replaceInteger(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_basic; fitData.modelType = nsl_fit_model_polynomial; fitData.degree = 2; XYFitCurve::initFitData(fitData); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); const int np = fitData.paramNames.size(); QCOMPARE(np, 3); QCOMPARE(fitResult.paramValues.at(0), 0.673565789473684e-3); QCOMPARE(fitResult.errorValues.at(0), 0.107938612033077e-3); QCOMPARE(fitResult.paramValues.at(1), 0.732059160401003e-6); QCOMPARE(fitResult.errorValues.at(1), 0.157817399981659e-9); QCOMPARE(fitResult.paramValues.at(2), -0.316081871345029e-14); QCOMPARE(fitResult.errorValues.at(2), 0.486652849992036e-16); QCOMPARE(fitResult.rsd, 0.205177424076185e-3); QCOMPARE(fitResult.rsquare, 0.999999900178537); QCOMPARE(fitResult.sse, 0.155761768796992e-5); QCOMPARE(fitResult.rms, 0.420977753505385e-7); DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 185330884.495776 FuzzyCompare(fitResult.fdist_F, 185330865.995752, 1.e-7); } void FitTest::testLinearNoInt1() { //NIST data for NoInt1 dataset QVector xData = {60,61,62,63,64,65,66,67,68,69,70}; QVector yData = {130,131,132,133,134,135,136,137,138,139,140}; //data source columns Column xDataColumn("x", AbstractColumn::Integer); xDataColumn.replaceInteger(0, xData); Column yDataColumn("y", AbstractColumn::Integer); yDataColumn.replaceInteger(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*x"; fitData.paramNames << "b1"; const int np = fitData.paramNames.size(); fitData.paramStartValues << 1.; fitData.paramLowerLimits << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max(); //fitData.eps = 1.e-15; fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 1); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 2.07438016513166 FuzzyCompare(fitResult.paramValues.at(0), 2.07438016528926, 1.e-9); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 0.0165289256079047 FuzzyCompare(fitResult.errorValues.at(0), 0.165289256198347e-1, 1.e-9); QCOMPARE(fitResult.rsd, 3.56753034006338); QCOMPARE(fitResult.sse, 127.272727272727); QCOMPARE(fitResult.rms, 12.7272727272727); QCOMPARE(fitResult.rsquare, 0.999365492298663); DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 15760.25 FuzzyCompare(fitResult.fdist_F, 15750.25, 1.e-3); } void FitTest::testLinearNoInt1_2() { //NIST data for NoInt1 dataset QVector xData = {60,61,62,63,64,65,66,67,68,69,70}; QVector yData = {130,131,132,133,134,135,136,137,138,139,140}; //data source columns Column xDataColumn("x", AbstractColumn::Integer); xDataColumn.replaceInteger(0, xData); Column yDataColumn("y", AbstractColumn::Integer); yDataColumn.replaceInteger(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_basic; fitData.modelType = nsl_fit_model_polynomial; fitData.degree = 1; XYFitCurve::initFitData(fitData); fitData.paramStartValues[0] = 0; fitData.paramFixed[0] = true; fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); const int np = fitData.paramNames.size(); QCOMPARE(np, 2); QCOMPARE(fitResult.paramValues.at(0), 0.); QCOMPARE(fitResult.paramValues.at(1), 2.07438016528926); QCOMPARE(fitResult.errorValues.at(1), 0.165289256198347e-1); QCOMPARE(fitResult.rsd, 3.56753034006338); QCOMPARE(fitResult.sse, 127.272727272727); QCOMPARE(fitResult.rms, 12.7272727272727); QCOMPARE(fitResult.rsquare, 0.999365492298663); DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 15760.25 FuzzyCompare(fitResult.fdist_F, 15750.25, 1.e-3); } void FitTest::testLinearNoInt2() { //NIST data for NoInt2 dataset QVector xData = {4,5,6}; QVector yData = {3,4,4}; //data source columns Column xDataColumn("x", AbstractColumn::Integer); xDataColumn.replaceInteger(0, xData); Column yDataColumn("y", AbstractColumn::Integer); yDataColumn.replaceInteger(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "c * x"; fitData.paramNames << "c"; const int np = fitData.paramNames.size(); fitData.paramStartValues << 1.; fitData.paramLowerLimits << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max(); //fitData.eps = 1.e-15; fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 1); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 0.727272727152573 FuzzyCompare(fitResult.paramValues.at(0), 0.727272727272727, 1.e-9); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 0.0420827316561797 FuzzyCompare(fitResult.errorValues.at(0), 0.420827318078432E-01, 1.e-8); QCOMPARE(fitResult.rsd, 0.369274472937998); QCOMPARE(fitResult.sse, 0.272727272727273); QCOMPARE(fitResult.rms, 0.136363636363636); // can not detect that intercept is zero for a custom linear model DEBUG(std::setprecision(15) << fitResult.rsquare); // result: 0.590909090909091 // QCOMPARE(fitResult.rsquare, 0.993348115299335); DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 4.88888888888889 // FuzzyCompare(fitResult.fdist_F, 298.666666666667, 1.); } void FitTest::testLinearNoInt2_2() { //NIST data for NoInt2 dataset QVector xData = {4,5,6}; QVector yData = {3,4,4}; //data source columns Column xDataColumn("x", AbstractColumn::Integer); xDataColumn.replaceInteger(0, xData); Column yDataColumn("y", AbstractColumn::Integer); yDataColumn.replaceInteger(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_basic; fitData.modelType = nsl_fit_model_polynomial; fitData.degree = 1; XYFitCurve::initFitData(fitData); fitData.paramStartValues[0] = 0; fitData.paramFixed[0] = true; fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); const int np = fitData.paramNames.size(); QCOMPARE(np, 2); QCOMPARE(fitResult.paramValues.at(0), 0.); QCOMPARE(fitResult.paramValues.at(1), 0.727272727272727); QCOMPARE(fitResult.errorValues.at(1), 0.420827318078432e-1); QCOMPARE(fitResult.rsd, 0.369274472937998); QCOMPARE(fitResult.sse, 0.272727272727273); QCOMPARE(fitResult.rms, 0.136363636363636); QCOMPARE(fitResult.rsquare, 0.993348115299335); DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 300.666666666667 FuzzyCompare(fitResult.fdist_F, 298.666666666667, 1.e-2); } void FitTest::testLinearFilip() { //NIST data for Filip dataset QVector xData = {-6.860120914,-4.324130045,-4.358625055,-4.358426747,-6.955852379,-6.661145254,-6.355462942,-6.118102026, -7.115148017,-6.815308569,-6.519993057,-6.204119983,-5.853871964,-6.109523091,-5.79832982,-5.482672118,-5.171791386,-4.851705903, -4.517126416,-4.143573228,-3.709075441,-3.499489089,-6.300769497,-5.953504836,-5.642065153,-5.031376979,-4.680685696,-4.329846955, -3.928486195,-8.56735134,-8.363211311,-8.107682739,-7.823908741,-7.522878745,-7.218819279,-6.920818754,-6.628932138,-6.323946875, -5.991399828,-8.781464495,-8.663140179,-8.473531488,-8.247337057,-7.971428747,-7.676129393,-7.352812702,-7.072065318,-6.774174009, -6.478861916,-6.159517513,-6.835647144,-6.53165267,-6.224098421,-5.910094889,-5.598599459,-5.290645224,-4.974284616,-4.64454848, -4.290560426,-3.885055584,-3.408378962,-3.13200249,-8.726767166,-8.66695597,-8.511026475,-8.165388579,-7.886056648,-7.588043762, -7.283412422,-6.995678626,-6.691862621,-6.392544977,-6.067374056,-6.684029655,-6.378719832,-6.065855188,-5.752272167,-5.132414673, -4.811352704,-4.098269308,-3.66174277,-3.2644011}; QVector 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,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,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,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,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,0.8253,0.8602, 0.8809,0.8301,0.8664,0.8834,0.8898,0.8964,0.8963,0.9074,0.9119,0.9228}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_basic; fitData.modelType = nsl_fit_model_polynomial; fitData.degree = 10; XYFitCurve::initFitData(fitData); const int np = fitData.paramNames.size(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 11); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: -1467.48962615175 FuzzyCompare(fitResult.paramValues.at(0), -1467.48961422980, 1.e-7); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 298.084524514884 FuzzyCompare(fitResult.errorValues.at(0), 298.084530995537, 1.e-7); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: -2772.1796150428 FuzzyCompare(fitResult.paramValues.at(1), -2772.17959193342, 1.e-7); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 559.779853249694 FuzzyCompare(fitResult.errorValues.at(1), 559.779865474950, 1.e-7); DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: -2316.37110148409 FuzzyCompare(fitResult.paramValues.at(2), -2316.37108160893, 1.e-7); DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: 466.477561928144 FuzzyCompare(fitResult.errorValues.at(2), 466.477572127796, 1.e-7); DEBUG(std::setprecision(15) << fitResult.paramValues.at(3)); // result: -1127.97395097195 FuzzyCompare(fitResult.paramValues.at(3), -1127.97394098372, 1.e-7); DEBUG(std::setprecision(15) << fitResult.errorValues.at(3)); // result: 227.204269523115 FuzzyCompare(fitResult.errorValues.at(3), 227.204274477751, 1.e-7); DEBUG(std::setprecision(15) << fitResult.paramValues.at(4)); // result: -354.478236951913 FuzzyCompare(fitResult.paramValues.at(4), -354.478233703349, 1.e-7); DEBUG(std::setprecision(15) << fitResult.errorValues.at(4)); // result: 71.6478645361214 FuzzyCompare(fitResult.errorValues.at(4), 71.6478660875927, 1.e-7); DEBUG(std::setprecision(15) << fitResult.paramValues.at(5)); // result: -75.1242024539908 FuzzyCompare(fitResult.paramValues.at(5), -75.1242017393757, 1.e-7); DEBUG(std::setprecision(15) << fitResult.errorValues.at(5)); // result: 15.289717547564 FuzzyCompare(fitResult.errorValues.at(5), 15.2897178747400, 1.e-7); DEBUG(std::setprecision(15) << fitResult.paramValues.at(6)); // result: -10.875318143236 FuzzyCompare(fitResult.paramValues.at(6), -10.8753180355343, 1.e-7); DEBUG(std::setprecision(15) << fitResult.errorValues.at(6)); // result: 2.23691155110776 FuzzyCompare(fitResult.errorValues.at(6), 2.23691159816033, 1.e-7); DEBUG(std::setprecision(15) << fitResult.paramValues.at(7)); // result: -1.06221499687347 FuzzyCompare(fitResult.paramValues.at(7), -1.06221498588947, 1.e-7); DEBUG(std::setprecision(15) << fitResult.errorValues.at(7)); // result: 0.221624317377432 FuzzyCompare(fitResult.errorValues.at(7), 0.221624321934227, 1.e-7); DEBUG(std::setprecision(15) << fitResult.paramValues.at(8)); // result: -0.0670191161850038 FuzzyCompare(fitResult.paramValues.at(8), -0.670191154593408E-01, 1.e-7); DEBUG(std::setprecision(15) << fitResult.errorValues.at(8)); // result: 0.0142363760310402 FuzzyCompare(fitResult.errorValues.at(8), 0.142363763154724E-01, 1.e-7); DEBUG(std::setprecision(15) << fitResult.paramValues.at(9)); // result: -0.00246781081080665 FuzzyCompare(fitResult.paramValues.at(9), -0.246781078275479E-02, 1.e-7); DEBUG(std::setprecision(15) << fitResult.errorValues.at(9)); // result: 0.000535617398555022 FuzzyCompare(fitResult.errorValues.at(9), 0.535617408889821E-03, 1.e-7); DEBUG(std::setprecision(15) << fitResult.paramValues.at(10)); // result: -4.02962529900222e-05 FuzzyCompare(fitResult.paramValues.at(10), -0.402962525080404E-04, 1.e-7); DEBUG(std::setprecision(15) << fitResult.errorValues.at(10)); // result: 8.96632820770946e-06 FuzzyCompare(fitResult.errorValues.at(10), 0.896632837373868E-05, 1.e-7); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.00334801050105949 FuzzyCompare(fitResult.rsd, 0.334801051324544E-02, 1.e-8); DEBUG(std::setprecision(15) << fitResult.rsquare); // result: 0.996727416209443 FuzzyCompare(fitResult.rsquare, 0.996727416185620, 1.e-9); DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.00079585137637953 FuzzyCompare(fitResult.sse, 0.795851382172941E-03, 1.e-7); DEBUG(std::setprecision(15) << fitResult.rms); // result: 1.12091743152047e-05 FuzzyCompare(fitResult.rms, 0.112091743968020E-04, 1.e-7); DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 2169.53956090808 FuzzyCompare(fitResult.fdist_F, 2162.43954511489, 1.e-2); } void FitTest::testLinearWampler1() { //NIST data for Wampler1 dataset QVector xData = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; QVector yData = {1,6,63,364,1365,3906,9331,19608,37449,66430,111111, 177156,271453,402234,579195,813616,1118481,1508598,2000719,2613660,3368421}; //data source columns Column xDataColumn("x", AbstractColumn::Integer); xDataColumn.replaceInteger(0, xData); Column yDataColumn("y", AbstractColumn::Integer); yDataColumn.replaceInteger(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_basic; fitData.modelType = nsl_fit_model_polynomial; fitData.degree = 5; XYFitCurve::initFitData(fitData); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); const int np = fitData.paramNames.size(); QCOMPARE(np, 6); for (int i = 0; i < np; i++) { const double paramValue = fitResult.paramValues.at(i); const double errorValue = fitResult.errorValues.at(i); QCOMPARE(paramValue, 1.0); QCOMPARE(errorValue, 0.0); } QCOMPARE(fitResult.rsd, 0.0); QCOMPARE(fitResult.rsquare, 1.0); QCOMPARE(fitResult.sse, 0.0); QCOMPARE(fitResult.rms, 0.0); QVERIFY(std::isinf(fitResult.fdist_F)); } void FitTest::testLinearWampler2() { //NIST data for Wampler2 dataset QVector xData = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; QVector yData = {1.00000,1.11111,1.24992,1.42753,1.65984,1.96875,2.38336,2.94117,3.68928,4.68559, 6.00000,7.71561,9.92992,12.75603,16.32384,20.78125,26.29536,33.05367,41.26528,51.16209,63.00000}; //data source columns Column xDataColumn("x", AbstractColumn::Integer); xDataColumn.replaceInteger(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_basic; fitData.modelType = nsl_fit_model_polynomial; fitData.degree = 5; XYFitCurve::initFitData(fitData); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results qDebug() << "STATUS " << fitResult.status; QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); const int np = fitData.paramNames.size(); QCOMPARE(np, 6); QCOMPARE(fitResult.paramValues.at(0), 1.0); QCOMPARE(fitResult.paramValues.at(1), 0.1); QCOMPARE(fitResult.paramValues.at(2), 0.01); QCOMPARE(fitResult.paramValues.at(3), 0.001); QCOMPARE(fitResult.paramValues.at(4), 0.0001); QCOMPARE(fitResult.paramValues.at(5), 0.00001); for (int i = 0; i < np; i++) { const double errorValue = fitResult.errorValues.at(i); FuzzyCompare(errorValue, 0., 1.); } DEBUG(std::setprecision(15) << fitResult.rsd); // result: 2.32458538254974e-15 FuzzyCompare(fitResult.rsd, 0., 1.); QCOMPARE(fitResult.rsquare, 1.); DEBUG(std::setprecision(15) << fitResult.sse); // result: 8.1055458011459e-29 FuzzyCompare(fitResult.sse, 0., 1.); DEBUG(std::setprecision(15) << fitResult.rms); // result: 5.40369720076393e-30 FuzzyCompare(fitResult.rms, 0., 1.); DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 2.44385217688297e+32 QVERIFY(fitResult.fdist_F > 2.e+32); } void FitTest::testLinearWampler3() { //NIST data for Wampler3 dataset QVector xData = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; QVector yData = {760.,-2042.,2111.,-1684.,3888.,1858.,11379.,17560.,39287.,64382.,113159., 175108.,273291.,400186.,581243.,811568.,1121004.,1506550.,2002767.,2611612.,3369180.}; //data source columns Column xDataColumn("x", AbstractColumn::Integer); xDataColumn.replaceInteger(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_basic; fitData.modelType = nsl_fit_model_polynomial; fitData.degree = 5; XYFitCurve::initFitData(fitData); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); const int np = fitData.paramNames.size(); QCOMPARE(np, 6); for (int i = 0; i < np; i++) { const double paramValue = fitResult.paramValues.at(i); QCOMPARE(paramValue, 1.0); } QCOMPARE(fitResult.errorValues.at(0), 2152.32624678170); QCOMPARE(fitResult.errorValues.at(1), 2363.55173469681); QCOMPARE(fitResult.errorValues.at(2), 779.343524331583); QCOMPARE(fitResult.errorValues.at(3), 101.475507550350); QCOMPARE(fitResult.errorValues.at(4), 5.64566512170752); QCOMPARE(fitResult.errorValues.at(5), 0.112324854679312); QCOMPARE(fitResult.rsd, 2360.14502379268); QCOMPARE(fitResult.rsquare, 0.999995559025820); QCOMPARE(fitResult.sse, 83554268.0000000); QCOMPARE(fitResult.rms, 5570284.53333333); DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 675527.458240122 FuzzyCompare(fitResult.fdist_F, 675524.458240122, 1.e-5); } void FitTest::testLinearWampler4() { //NIST data for Wampler4 dataset QVector xData = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; QVector yData = {75901,-204794,204863,-204436,253665,-200894,214131,-185192,221249,-138370, 315911,-27644,455253,197434,783995,608816,1370781,1303798,2205519,2408860,3444321}; //data source columns Column xDataColumn("x", AbstractColumn::Integer); xDataColumn.replaceInteger(0, xData); Column yDataColumn("y", AbstractColumn::Integer); yDataColumn.replaceInteger(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_basic; fitData.modelType = nsl_fit_model_polynomial; fitData.degree = 5; XYFitCurve::initFitData(fitData); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); const int np = fitData.paramNames.size(); QCOMPARE(np, 6); for (int i = 0; i < np; i++) { const double paramValue = fitResult.paramValues.at(i); QCOMPARE(paramValue, 1.0); } QCOMPARE(fitResult.errorValues.at(0), 215232.624678170); QCOMPARE(fitResult.errorValues.at(1), 236355.173469681); QCOMPARE(fitResult.errorValues.at(2), 77934.3524331583); QCOMPARE(fitResult.errorValues.at(3), 10147.5507550350); QCOMPARE(fitResult.errorValues.at(4), 564.566512170752); QCOMPARE(fitResult.errorValues.at(5), 11.2324854679312); QCOMPARE(fitResult.rsd, 236014.502379268); QCOMPARE(fitResult.rsquare, 0.957478440825662); QCOMPARE(fitResult.sse, 835542680000.000); QCOMPARE(fitResult.rms, 55702845333.3333); DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 70.5524458240122 FuzzyCompare(fitResult.fdist_F, 67.5524458240122, 5.e-2); } void FitTest::testLinearWampler5() { //NIST data for Wampler5 dataset QVector xData = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; QVector yData = {7590001,-20479994,20480063,-20479636,25231365,-20476094,20489331,-20460392,18417449,-20413570, 20591111,-20302844,18651453,-20077766,21059195,-19666384,26348481,-18971402,22480719,-17866340,10958421}; //data source columns Column xDataColumn("x", AbstractColumn::Integer); xDataColumn.replaceInteger(0, xData); Column yDataColumn("y", AbstractColumn::Integer); yDataColumn.replaceInteger(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_basic; fitData.modelType = nsl_fit_model_polynomial; fitData.degree = 5; XYFitCurve::initFitData(fitData); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); const int np = fitData.paramNames.size(); QCOMPARE(np, 6); for (int i = 0; i < np; i++) { const double paramValue = fitResult.paramValues.at(i); QCOMPARE(paramValue, 1.0); } QCOMPARE(fitResult.errorValues.at(0), 21523262.4678170); QCOMPARE(fitResult.errorValues.at(1), 23635517.3469681); QCOMPARE(fitResult.errorValues.at(2), 7793435.24331583); QCOMPARE(fitResult.errorValues.at(3), 1014755.07550350); QCOMPARE(fitResult.errorValues.at(4), 56456.6512170752); QCOMPARE(fitResult.errorValues.at(5), 1123.24854679312); QCOMPARE(fitResult.rsd, 23601450.2379268); QCOMPARE(fitResult.rsquare, 0.224668921574940E-02); QCOMPARE(fitResult.sse, 0.835542680000000E+16); QCOMPARE(fitResult.rms, 557028453333333.); DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 3.0067552445824 //TODO FuzzyCompare(fitResult.fdist_F, 0.675524458240122E-02, 1.e-6); } // taken from https://en.wikipedia.org/wiki/Ordinary_least_squares void FitTest::testLinearWP_OLS() { //data from The World Almanac and Book of Facts, 1975 QVector 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}; QVector 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}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_basic; fitData.modelType = nsl_fit_model_polynomial; fitData.degree = 2; XYFitCurve::initFitData(fitData); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); const int np = fitData.paramNames.size(); QCOMPARE(np, 3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 128.812803578436 FuzzyCompare(fitResult.paramValues.at(0), 128.8128, 1.e-7); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 16.3082821390367 FuzzyCompare(fitResult.errorValues.at(0), 16.3083, 1.e-5); DEBUG(std::setprecision(15) << fitResult.tdist_tValues.at(0)); // result: 7.89861264848368 FuzzyCompare(fitResult.tdist_tValues.at(0), 7.8986, 1.e-5); DEBUG(std::setprecision(15) << fitResult.tdist_pValues.at(0)); // result: 4.28330815316414e-06 FuzzyCompare(fitResult.tdist_pValues.at(0), 0.0, 1.); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: -143.16202286476 FuzzyCompare(fitResult.paramValues.at(1), -143.1620, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 19.8331710430895 FuzzyCompare(fitResult.errorValues.at(1), 19.8332, 1.e-5); DEBUG(std::setprecision(15) << fitResult.tdist_tValues.at(1)); // result: -7.21831231897945 FuzzyCompare(fitResult.tdist_tValues.at(1), -7.2183, 1.e-5); DEBUG(std::setprecision(15) << fitResult.tdist_pValues.at(1)); // result: 1.05970640905074e-05 FuzzyCompare(fitResult.tdist_pValues.at(1), 0.0, 1.); DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: 61.9603254424724 FuzzyCompare(fitResult.paramValues.at(2), 61.9603, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: 6.00842899301227 FuzzyCompare(fitResult.errorValues.at(2), 6.0084, 1.e-5); DEBUG(std::setprecision(15) << fitResult.tdist_tValues.at(2)); // result: 10.3122339490958 FuzzyCompare(fitResult.tdist_tValues.at(2), 10.3122, 1.e-5); DEBUG(std::setprecision(15) << fitResult.tdist_pValues.at(2)); // result: 2.56647515320682e-07 FuzzyCompare(fitResult.tdist_pValues.at(2), 0.0, 1.); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.25158650082898 FuzzyCompare(fitResult.rsd, 0.2516, 1.e-4); DEBUG(std::setprecision(15) << fitResult.rsquare); // result: 0.998904558436583 FuzzyCompare(fitResult.rsquare, 0.9989, 1.e-5); DEBUG(std::setprecision(15) << fitResult.rsquareAdj); // result: 0.99860580164656 FuzzyCompare(fitResult.rsquareAdj, 0.9987, 1.e-4); DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.759549208792447 FuzzyCompare(fitResult.sse, 0.7595, 1.e-4); -// QCOMPARE(fitResult.rms, ); // result: 0.0632958 +// QCOMPARE(fitResult.rms, ???); // result: 0.0632958 DEBUG(std::setprecision(15) << fitResult.chisq_p); // result: 0.999996987409119 -//TODO FuzzyCompare(fitResult.chisq_p, 1.0890, 1.e-8); // == Log-likelihood ? +//TODO FuzzyCompare(fitResult.chisq_p, ???, 1.e-8); // Log-likelihood = 1.0890 DEBUG(std::setprecision(15) << fitResult.fdist_F); // result: 5477.24333307392 FuzzyCompare(fitResult.fdist_F, 5471.2, 2.e-3); QCOMPARE(fitResult.fdist_p, 0.0); DEBUG(std::setprecision(15) << fitResult.aic); // result: -36.5643873548404 //TODO FuzzyCompare(fitResult.aic, 0.2548, 2.e-6); DEBUG(std::setprecision(15) << fitResult.bic); // result: -36.6220549333519 //TODO FuzzyCompare(fitResult.bic, 0.3964, 2.e-6); } //############################################################################## //############# non-linear regression with NIST datasets ##################### //############################################################################## void FitTest::testNonLinearMisra1a() { //NIST data for Misra1a dataset QVector 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}; QVector 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}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*(1.-exp(-b2*x))"; fitData.paramNames << "b1" << "b2"; fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 500. << 0.0001; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 2); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 238.942305251573 FuzzyCompare(fitResult.paramValues.at(0), 2.3894212918E+02, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 2.70651225218243 FuzzyCompare(fitResult.errorValues.at(0), 2.7070075241E+00, 1.e-3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000550155958419367 FuzzyCompare(fitResult.paramValues.at(1), 5.5015643181E-04, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 7.26565480949189e-06 FuzzyCompare(fitResult.errorValues.at(1), 7.2668688436E-06, 1.e-3); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.101878763320394 FuzzyCompare(fitResult.rsd, 1.0187876330E-01, 1.e-9); DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.124551388988316 FuzzyCompare(fitResult.sse, 1.2455138894E-01, 1.e-9); } void FitTest::testNonLinearMisra1a_2() { //NIST data for Misra1a dataset QVector 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}; QVector 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}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*(1.-exp(-b2*x))"; fitData.paramNames << "b1" << "b2"; fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 250. << 5.e-4; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 2); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 238.942305251573 FuzzyCompare(fitResult.paramValues.at(0), 2.3894212918E+02, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 2.70651225218243 FuzzyCompare(fitResult.errorValues.at(0), 2.7070075241E+00, 1.e-3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000550155958419367 FuzzyCompare(fitResult.paramValues.at(1), 5.5015643181E-04, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 7.26565480949189e-06 FuzzyCompare(fitResult.errorValues.at(1), 7.2668688436E-06, 1.e-3); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.101878763320394 FuzzyCompare(fitResult.rsd, 1.0187876330E-01, 1.e-9); DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.124551388988316 FuzzyCompare(fitResult.sse, 1.2455138894E-01, 1.e-9); } void FitTest::testNonLinearMisra1a_3() { //NIST data for Misra1a dataset QVector 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}; QVector 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}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*(1.-exp(-b2*x))"; fitData.paramNames << "b1" << "b2"; fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 2.3894212918E+02 << 5.5015643181E-04; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 2); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 238.942305251573 FuzzyCompare(fitResult.paramValues.at(0), 2.3894212918E+02, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 2.70651225218243 FuzzyCompare(fitResult.errorValues.at(0), 2.7070075241E+00, 1.e-3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000550155958419367 FuzzyCompare(fitResult.paramValues.at(1), 5.5015643181E-04, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 7.26565480949189e-06 FuzzyCompare(fitResult.errorValues.at(1), 7.2668688436E-06, 1.e-3); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.101878763320394 FuzzyCompare(fitResult.rsd, 1.0187876330E-01, 1.e-9); DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.124551388988316 FuzzyCompare(fitResult.sse, 1.2455138894E-01, 1.e-9); } void FitTest::testNonLinearMisra1b() { //NIST data for Misra1b dataset QVector 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}; QVector 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}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*(1.-1./(1.+b2*x/2)^2)"; fitData.paramNames << "b1" << "b2"; fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 500. << 0.0001; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 2); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 337.99775062098 FuzzyCompare(fitResult.paramValues.at(0), 3.3799746163E+02, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 3.16358581006192 FuzzyCompare(fitResult.errorValues.at(0), 3.1643950207E+00, 1.e-3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000390390523934039 FuzzyCompare(fitResult.paramValues.at(1), 3.9039091287E-04, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 4.25373670682006e-06 FuzzyCompare(fitResult.errorValues.at(1), 4.2547321834E-06, 1.e-3); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.0793014720259488 FuzzyCompare(fitResult.rsd, 7.9301471998E-02, 1.e-9); DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.0754646815857881 FuzzyCompare(fitResult.sse, 7.5464681533E-02, 1.e-9); } void FitTest::testNonLinearMisra1b_2() { //NIST data for Misra1b dataset QVector 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}; QVector 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}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*(1.-1./(1.+b2*x/2)^2)"; fitData.paramNames << "b1" << "b2"; fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 300. << 2.e-4; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 2); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 337.99775062098 FuzzyCompare(fitResult.paramValues.at(0), 3.3799746163E+02, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 3.16358581006192 FuzzyCompare(fitResult.errorValues.at(0), 3.1643950207E+00, 1.e-3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000390390523934039 FuzzyCompare(fitResult.paramValues.at(1), 3.9039091287E-04, 1.e-5); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 4.25373670682006e-06 FuzzyCompare(fitResult.errorValues.at(1), 4.2547321834E-06, 1.e-3); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.0793014720259488 FuzzyCompare(fitResult.rsd, 7.9301471998E-02, 1.e-9); DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.0754646815857881 FuzzyCompare(fitResult.sse, 7.5464681533E-02, 1.e-9); } void FitTest::testNonLinearMisra1b_3() { //NIST data for Misra1b dataset QVector 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}; QVector 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}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*(1.-1./(1.+b2*x/2)^2)"; fitData.paramNames << "b1" << "b2"; fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 3.3799746163E+02 << 3.9039091287E-04; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 2); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 337.99775062098 FuzzyCompare(fitResult.paramValues.at(0), 3.3799746163E+02, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 3.16358581006192 FuzzyCompare(fitResult.errorValues.at(0), 3.1643950207E+00, 1.e-3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000390390523934039 FuzzyCompare(fitResult.paramValues.at(1), 3.9039091287E-04, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 4.25373670682006e-06 FuzzyCompare(fitResult.errorValues.at(1), 4.2547321834E-06, 1.e-3); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.0793014720259488 FuzzyCompare(fitResult.rsd, 7.9301471998E-02, 1.e-9); DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.0754646815857881 FuzzyCompare(fitResult.sse, 7.5464681533E-02, 1.e-9); } void FitTest::testNonLinearMisra1c() { //NIST data for Misra1c dataset QVector 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}; QVector 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}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*(1.-1./sqrt(1.+2.*b2*x))"; fitData.paramNames << "b1" << "b2"; fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 500. << 0.0001; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 2); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 636.427904767969 FuzzyCompare(fitResult.paramValues.at(0), 6.3642725809E+02, 1.e-5); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 4.66168062054875 FuzzyCompare(fitResult.errorValues.at(0), 4.6638326572E+00, 1.e-3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000208136026420746 FuzzyCompare(fitResult.paramValues.at(1), 2.0813627256E-04, 1.e-5); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 1.77209416674174e-06 FuzzyCompare(fitResult.errorValues.at(1), 1.7728423155E-06, 1.e-3); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.0584286153041661 FuzzyCompare(fitResult.rsd, 5.8428615257E-02, 1.e-9); DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.0409668370363468 FuzzyCompare(fitResult.sse, 4.0966836971E-02, 1.e-8); } void FitTest::testNonLinearMisra1c_2() { //NIST data for Misra1c dataset QVector 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}; QVector 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}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*(1.-1./sqrt(1.+2.*b2*x))"; fitData.paramNames << "b1" << "b2"; fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 600. << 2.e-4; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 2); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 636.427904767969 FuzzyCompare(fitResult.paramValues.at(0), 6.3642725809E+02, 1.e-5); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 4.66168062054875 FuzzyCompare(fitResult.errorValues.at(0), 4.6638326572E+00, 1.e-3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000208136026420746 FuzzyCompare(fitResult.paramValues.at(1), 2.0813627256E-04, 1.e-5); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 1.77209416674174e-06 FuzzyCompare(fitResult.errorValues.at(1), 1.7728423155E-06, 1.e-3); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.0584286153041661 FuzzyCompare(fitResult.rsd, 5.8428615257E-02, 1.e-9); DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.0409668370363468 FuzzyCompare(fitResult.sse, 4.0966836971E-02, 1.e-8); } void FitTest::testNonLinearMisra1c_3() { //NIST data for Misra1c dataset QVector 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}; QVector 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}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*(1.-1./sqrt(1.+2.*b2*x))"; fitData.paramNames << "b1" << "b2"; fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 6.3642725809E+02 << 2.0813627256E-04; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 2); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 636.427904767969 FuzzyCompare(fitResult.paramValues.at(0), 6.3642725809E+02, 1.e-5); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 4.66168062054875 FuzzyCompare(fitResult.errorValues.at(0), 4.6638326572E+00, 1.e-3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000208136026420746 FuzzyCompare(fitResult.paramValues.at(1), 2.0813627256E-04, 1.e-5); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 1.77209416674174e-06 FuzzyCompare(fitResult.errorValues.at(1), 1.7728423155E-06, 1.e-3); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.0584286153041661 FuzzyCompare(fitResult.rsd, 5.8428615257E-02, 1.e-9); DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.0409668370363468 FuzzyCompare(fitResult.sse, 4.0966836971E-02, 1.e-8); } void FitTest::testNonLinearMisra1d() { //NIST data for Misra1d dataset QVector 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}; QVector 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}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*b2*x/(1.+b2*x)"; fitData.paramNames << "b1" << "b2"; fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 500. << 0.0001; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 2); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 437.370039987725 FuzzyCompare(fitResult.paramValues.at(0), 4.3736970754E+02, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 3.64772833062694 FuzzyCompare(fitResult.errorValues.at(0), 3.6489174345E+00, 1.e-3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000302272976784709 FuzzyCompare(fitResult.paramValues.at(1), 3.0227324449E-04, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 2.93256059733558e-06 FuzzyCompare(fitResult.errorValues.at(1), 2.9334354479E-06, 1.e-3); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.068568272134244 FuzzyCompare(fitResult.rsd, 6.8568272111E-02, 1.e-9); DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.056419295321709 FuzzyCompare(fitResult.sse, 5.6419295283E-02, 1.e-9); } void FitTest::testNonLinearMisra1d_2() { //NIST data for Misra1d dataset QVector 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}; QVector 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}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*b2*x/(1.+b2*x)"; fitData.paramNames << "b1" << "b2"; fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 450. << 3.e-4; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 2); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 437.370039987725 FuzzyCompare(fitResult.paramValues.at(0), 4.3736970754E+02, 1.e-5); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 3.64772833062694 FuzzyCompare(fitResult.errorValues.at(0), 3.6489174345E+00, 1.e-3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000302272976784709 FuzzyCompare(fitResult.paramValues.at(1), 3.0227324449E-04, 1.e-5); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 2.93256059733558e-06 FuzzyCompare(fitResult.errorValues.at(1), 2.9334354479E-06, 1.e-3); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.068568272134244 FuzzyCompare(fitResult.rsd, 6.8568272111E-02, 1.e-9); DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.056419295321709 FuzzyCompare(fitResult.sse, 5.6419295283E-02, 1.e-8); } void FitTest::testNonLinearMisra1d_3() { //NIST data for Misra1d dataset QVector 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}; QVector 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}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*b2*x/(1.+b2*x)"; fitData.paramNames << "b1" << "b2"; fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 4.3736970754E+02 << 3.0227324449E-04; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 2); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 437.370039987725 FuzzyCompare(fitResult.paramValues.at(0), 4.3736970754E+02, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 3.64772833062694 FuzzyCompare(fitResult.errorValues.at(0), 3.6489174345E+00, 1.e-3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 0.000302272976784709 FuzzyCompare(fitResult.paramValues.at(1), 3.0227324449E-04, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 2.93256059733558e-06 FuzzyCompare(fitResult.errorValues.at(1), 2.9334354479E-06, 1.e-3); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 0.068568272134244 FuzzyCompare(fitResult.rsd, 6.8568272111E-02, 1.e-9); DEBUG(std::setprecision(15) << fitResult.sse); // result: 0.056419295321709 FuzzyCompare(fitResult.sse, 5.6419295283E-02, 1.e-9); } void FitTest::testNonLinearMGH09() { //NIST data for MGH09 dataset QVector xData = {4.000000E+00,2.000000E+00,1.000000E+00,5.000000E-01,2.500000E-01,1.670000E-01,1.250000E-01,1.000000E-01, 8.330000E-02,7.140000E-02,6.250000E-02}; QVector yData = {1.957000E-01,1.947000E-01,1.735000E-01,1.600000E-01,8.440000E-02,6.270000E-02,4.560000E-02,3.420000E-02, 3.230000E-02,2.350000E-02,2.460000E-02}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*(x^2 + b2*x)/(x^2 + x*b3 + b4)"; fitData.paramNames << "b1" << "b2" << "b3" << "b4"; //fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 2.5000000000E+01 << 3.9000000000E+01 << 4.1500000000E+01 << 3.9000000000E+01; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max() << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max() << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 4); // TODO: fit does not find global minimum /* DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: FuzzyCompare(fitResult.paramValues.at(0), 1.9280693458E-01, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: FuzzyCompare(fitResult.errorValues.at(0), 1.1435312227E-02, 1.e-3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: FuzzyCompare(fitResult.paramValues.at(1), 1.9128232873E-01, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: FuzzyCompare(fitResult.errorValues.at(1), 1.9633220911E-01, 1.e-3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: FuzzyCompare(fitResult.paramValues.at(2), 1.2305650693E-01, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: FuzzyCompare(fitResult.errorValues.at(2), 8.0842031232E-02, 1.e-3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(3)); // result: FuzzyCompare(fitResult.paramValues.at(3), 1.3606233068E-01, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(3)); // result: FuzzyCompare(fitResult.errorValues.at(3), 9.0025542308E-02, 1.e-3); DEBUG(std::setprecision(15) << fitResult.rsd); // result: FuzzyCompare(fitResult.rsd, 6.6279236551E-03, 1.e-9); DEBUG(std::setprecision(15) << fitResult.sse); // result: FuzzyCompare(fitResult.sse, 3.0750560385E-04, 1.e-9); */ } void FitTest::testNonLinearMGH09_2() { //NIST data for MGH09 dataset QVector xData = {4.000000E+00,2.000000E+00,1.000000E+00,5.000000E-01,2.500000E-01,1.670000E-01,1.250000E-01,1.000000E-01, 8.330000E-02,7.140000E-02,6.250000E-02}; QVector yData = {1.957000E-01,1.947000E-01,1.735000E-01,1.600000E-01,8.440000E-02,6.270000E-02,4.560000E-02,3.420000E-02, 3.230000E-02,2.350000E-02,2.460000E-02}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*(x^2 + b2*x)/(x^2 + x*b3 + b4)"; fitData.paramNames << "b1" << "b2" << "b3" << "b4"; //fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 2.5000000000E-01 << 3.9000000000E-01 << 4.1500000000E-01 << 3.9000000000E-01; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max() << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max() << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 4); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: FuzzyCompare(fitResult.paramValues.at(0), 1.9280693458E-01, 1.e-5); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: FuzzyCompare(fitResult.errorValues.at(0), 1.1435312227E-02, 1.e-4); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: FuzzyCompare(fitResult.paramValues.at(1), 1.9128232873E-01, 1.e-3); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: FuzzyCompare(fitResult.errorValues.at(1), 1.9633220911E-01, 1.e-4); DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: FuzzyCompare(fitResult.paramValues.at(2), 1.2305650693E-01, 1.e-4); DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: FuzzyCompare(fitResult.errorValues.at(2), 8.0842031232E-02, 1.e-4); DEBUG(std::setprecision(15) << fitResult.paramValues.at(3)); // result: FuzzyCompare(fitResult.paramValues.at(3), 1.3606233068E-01, 1.e-4); DEBUG(std::setprecision(15) << fitResult.errorValues.at(3)); // result: FuzzyCompare(fitResult.errorValues.at(3), 9.0025542308E-02, 1.e-4); DEBUG(std::setprecision(15) << fitResult.rsd); // result: FuzzyCompare(fitResult.rsd, 6.6279236551E-03, 1.e-8); DEBUG(std::setprecision(15) << fitResult.sse); // result: FuzzyCompare(fitResult.sse, 3.0750560385E-04, 1.e-8); } void FitTest::testNonLinearMGH09_3() { //NIST data for MGH09 dataset QVector xData = {4.000000E+00,2.000000E+00,1.000000E+00,5.000000E-01,2.500000E-01,1.670000E-01,1.250000E-01,1.000000E-01, 8.330000E-02,7.140000E-02,6.250000E-02}; QVector yData = {1.957000E-01,1.947000E-01,1.735000E-01,1.600000E-01,8.440000E-02,6.270000E-02,4.560000E-02,3.420000E-02, 3.230000E-02,2.350000E-02,2.460000E-02}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*(x^2 + b2*x)/(x^2 + x*b3 + b4)"; fitData.paramNames << "b1" << "b2" << "b3" << "b4"; //fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 1.9280693458E-01 << 1.9128232873E-01 << 1.2305650693E-01 << 1.3606233068E-01; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max() << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max() << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 4); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: FuzzyCompare(fitResult.paramValues.at(0), 1.9280693458E-01, 1.e-9); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: FuzzyCompare(fitResult.errorValues.at(0), 1.1435312227E-02, 1.e-5); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: FuzzyCompare(fitResult.paramValues.at(1), 1.9128232873E-01, 1.e-9); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: FuzzyCompare(fitResult.errorValues.at(1), 1.9633220911E-01, 1.e-5); DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: FuzzyCompare(fitResult.paramValues.at(2), 1.2305650693E-01, 1.e-9); DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: FuzzyCompare(fitResult.errorValues.at(2), 8.0842031232E-02, 1.e-5); DEBUG(std::setprecision(15) << fitResult.paramValues.at(3)); // result: FuzzyCompare(fitResult.paramValues.at(3), 1.3606233068E-01, 1.e-9); DEBUG(std::setprecision(15) << fitResult.errorValues.at(3)); // result: FuzzyCompare(fitResult.errorValues.at(3), 9.0025542308E-02, 1.e-5); DEBUG(std::setprecision(15) << fitResult.rsd); // result: FuzzyCompare(fitResult.rsd, 6.6279236551E-03, 1.e-9); DEBUG(std::setprecision(15) << fitResult.sse); // result: FuzzyCompare(fitResult.sse, 3.0750560385E-04, 1.e-9); } void FitTest::testNonLinearMGH10() { //NIST data for MGH10 dataset QVector xData = {5.000000E+01,5.500000E+01,6.000000E+01,6.500000E+01,7.000000E+01,7.500000E+01,8.000000E+01,8.500000E+01,9.000000E+01, 9.500000E+01,1.000000E+02,1.050000E+02,1.100000E+02,1.150000E+02,1.200000E+02,1.250000E+02}; QVector yData = {3.478000E+04,2.861000E+04,2.365000E+04,1.963000E+04,1.637000E+04,1.372000E+04,1.154000E+04,9.744000E+03,8.261000E+03, 7.030000E+03,6.005000E+03,5.147000E+03,4.427000E+03,3.820000E+03,3.307000E+03,2.872000E+03}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*exp(b2/(x+b3))"; fitData.paramNames << "b1" << "b2" << "b3"; //fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 2.0000000000E+00 << 4.0000000000E+05 << 2.5000000000E+04; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 0.00560963848336205 (Windows: 0.00560964247264364) FuzzyCompare(fitResult.paramValues.at(0), 5.6096364710E-03, 1.e-5); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 0.000156888682057687 FuzzyCompare(fitResult.errorValues.at(0), 1.5687892471E-04, 1.e-4); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 6181.34604697191 (Windows: 6181.34545410281) FuzzyCompare(fitResult.paramValues.at(1), 6.1813463463E+03, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 23.3105479190063 FuzzyCompare(fitResult.errorValues.at(1), 2.3309021107E+01, 1.e-4); DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: 345.223624540718 FuzzyCompare(fitResult.paramValues.at(2), 3.4522363462E+02, 1.e-7); DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: 0.784915645388214 FuzzyCompare(fitResult.errorValues.at(2), 7.8486103508E-01, 1.e-4); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 2.6009740064923 (Windows: 2.60097400662837) FuzzyCompare(fitResult.rsd, 2.6009740065E+00, 1.e-10); DEBUG(std::setprecision(15) << fitResult.sse); // result: 87.9458551718321 (FreeBSD: 87.9458551726946, Windows: 87.9458551810338) FuzzyCompare(fitResult.sse, 8.7945855171E+01, 1.e-9); } void FitTest::testNonLinearMGH10_2() { //NIST data for MGH10 dataset QVector xData = {5.000000E+01,5.500000E+01,6.000000E+01,6.500000E+01,7.000000E+01,7.500000E+01,8.000000E+01,8.500000E+01,9.000000E+01, 9.500000E+01,1.000000E+02,1.050000E+02,1.100000E+02,1.150000E+02,1.200000E+02,1.250000E+02}; QVector yData = {3.478000E+04,2.861000E+04,2.365000E+04,1.963000E+04,1.637000E+04,1.372000E+04,1.154000E+04,9.744000E+03,8.261000E+03, 7.030000E+03,6.005000E+03,5.147000E+03,4.427000E+03,3.820000E+03,3.307000E+03,2.872000E+03}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*exp(b2/(x+b3))"; fitData.paramNames << "b1" << "b2" << "b3"; //fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 2.0000000000E-02 << 4.0000000000E+03 << 2.5000000000E+02; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 0.00560963848336205 FuzzyCompare(fitResult.paramValues.at(0), 5.6096364710E-03, 1.e-5); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 0.000156888586677272 FuzzyCompare(fitResult.errorValues.at(0), 1.5687892471E-04, 1.e-4); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 6181.34604697191 FuzzyCompare(fitResult.paramValues.at(1), 6.1813463463E+03, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 23.3105167849511 FuzzyCompare(fitResult.errorValues.at(1), 2.3309021107E+01, 1.e-4); DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: 345.223624540718 FuzzyCompare(fitResult.paramValues.at(2), 3.4522363462E+02, 1.e-7); DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: 0.784914752553929 FuzzyCompare(fitResult.errorValues.at(2), 7.8486103508E-01, 1.e-4); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 2.6009740064923 FuzzyCompare(fitResult.rsd, 2.6009740065E+00, 1.e-10); DEBUG(std::setprecision(15) << fitResult.sse); // result: 87.9458551718321 FuzzyCompare(fitResult.sse, 8.7945855171E+01, 1.e-9); } void FitTest::testNonLinearMGH10_3() { //NIST data for MGH10 dataset QVector xData = {5.000000E+01,5.500000E+01,6.000000E+01,6.500000E+01,7.000000E+01,7.500000E+01,8.000000E+01,8.500000E+01,9.000000E+01, 9.500000E+01,1.000000E+02,1.050000E+02,1.100000E+02,1.150000E+02,1.200000E+02,1.250000E+02}; QVector yData = {3.478000E+04,2.861000E+04,2.365000E+04,1.963000E+04,1.637000E+04,1.372000E+04,1.154000E+04,9.744000E+03,8.261000E+03, 7.030000E+03,6.005000E+03,5.147000E+03,4.427000E+03,3.820000E+03,3.307000E+03,2.872000E+03}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1*exp(b2/(x+b3))"; fitData.paramNames << "b1" << "b2" << "b3"; //fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 5.6096364710E-03 << 6.1813463463E+03 << 3.4522363462E+02; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 3); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 0.00560963848336205 FuzzyCompare(fitResult.paramValues.at(0), 5.6096364710E-03, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 0.000156888348998521 FuzzyCompare(fitResult.errorValues.at(0), 1.5687892471E-04, 1.e-4); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 6181.34604697191 FuzzyCompare(fitResult.paramValues.at(1), 6.1813463463E+03, 1.e-7); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 23.310508065631 FuzzyCompare(fitResult.errorValues.at(1), 2.3309021107E+01, 1.e-4); DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: 345.223624540718 FuzzyCompare(fitResult.paramValues.at(2), 3.4522363462E+02, 1.e-7); DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: 0.784914424350028 FuzzyCompare(fitResult.errorValues.at(2), 7.8486103508E-01, 1.e-4); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 2.6009740064923 FuzzyCompare(fitResult.rsd, 2.6009740065E+00, 1.e-11); DEBUG(std::setprecision(15) << fitResult.sse); // result: 87.9458551718321 FuzzyCompare(fitResult.sse, 8.7945855171E+01, 1.e-11); } void FitTest::testNonLinearRat43() { //NIST data for Rat43 dataset QVector 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}; QVector yData = {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}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1/pow(1. + exp(b2-b3*x), 1/b4)"; fitData.paramNames << "b1" << "b2" << "b3" << "b4"; //fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 1.0000000000E+02 << 1.0000000000E+01 << 1.0000000000E+00 << 1.0000000000E+00; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max() << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max() << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 4); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 699.641340982193 FuzzyCompare(fitResult.paramValues.at(0), 6.9964151270E+02, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 16.3022524293302 FuzzyCompare(fitResult.errorValues.at(0), 1.6302297817E+01, 1.e-5); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 5.2771555758844 FuzzyCompare(fitResult.paramValues.at(1), 5.2771253025E+00, 1.e-5); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 2.08290034908325 FuzzyCompare(fitResult.errorValues.at(1), 2.0828735829E+00, 1.e-4); DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: 0.759632366113637 FuzzyCompare(fitResult.paramValues.at(2), 7.5962938329E-01, 1.e-5); DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: 0.195664372178938 FuzzyCompare(fitResult.errorValues.at(2), 1.9566123451E-01, 1.e-4); DEBUG(std::setprecision(15) << fitResult.paramValues.at(3)); // result: 1.27925748993867 FuzzyCompare(fitResult.paramValues.at(3), 1.2792483859E+00, 1.e-5); DEBUG(std::setprecision(15) << fitResult.errorValues.at(3)); // result: 0.687627478905195 FuzzyCompare(fitResult.errorValues.at(3), 6.8761936385E-01, 1.e-4); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 28.2624146626284 FuzzyCompare(fitResult.rsd, 2.8262414662E+01, 1.e-10); DEBUG(std::setprecision(15) << fitResult.sse); // result: 8786.4049081859 FuzzyCompare(fitResult.sse, 8.7864049080E+03, 1.e-10); } void FitTest::testNonLinearRat43_2() { //NIST data for Rat43 dataset QVector 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}; QVector yData = {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}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1/pow(1. + exp(b2-b3*x), 1/b4)"; fitData.paramNames << "b1" << "b2" << "b3" << "b4"; //fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 7.0000000000E+02 << 5.0000000000E+00 << 7.5000000000E-01 << 1.3000000000E+00; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max() << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max() << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 4); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 699.641340982193 FuzzyCompare(fitResult.paramValues.at(0), 6.9964151270E+02, 1.e-6); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 16.3023134145464 (FreeBSD: 16.3023141645004) FuzzyCompare(fitResult.errorValues.at(0), 1.6302297817E+01, 1.e-5); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 5.2771555758844 FuzzyCompare(fitResult.paramValues.at(1), 5.2771253025E+00, 1.e-5); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 2.08288970703906 FuzzyCompare(fitResult.errorValues.at(1), 2.0828735829E+00, 1.e-5); DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: 0.759632366113637 FuzzyCompare(fitResult.paramValues.at(2), 7.5962938329E-01, 1.e-5); DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: 0.195662802156063 FuzzyCompare(fitResult.errorValues.at(2), 1.9566123451E-01, 1.e-5); DEBUG(std::setprecision(15) << fitResult.paramValues.at(3)); // result: 1.27925748993867 FuzzyCompare(fitResult.paramValues.at(3), 1.2792483859E+00, 1.e-5); DEBUG(std::setprecision(15) << fitResult.errorValues.at(3)); // result: 0.687623222160242 FuzzyCompare(fitResult.errorValues.at(3), 6.8761936385E-01, 1.e-5); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 28.2624146626284 FuzzyCompare(fitResult.rsd, 2.8262414662E+01, 1.e-10); DEBUG(std::setprecision(15) << fitResult.sse); // result: 8786.4049081859 FuzzyCompare(fitResult.sse, 8.7864049080E+03, 1.e-11); } void FitTest::testNonLinearRat43_3() { //NIST data for Rat43 dataset QVector 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}; QVector yData = {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}; //data source columns Column xDataColumn("x", AbstractColumn::Numeric); xDataColumn.replaceValues(0, xData); Column yDataColumn("y", AbstractColumn::Numeric); yDataColumn.replaceValues(0, yData); XYFitCurve fitCurve("fit"); fitCurve.setXDataColumn(&xDataColumn); fitCurve.setYDataColumn(&yDataColumn); //prepare the fit XYFitCurve::FitData fitData = fitCurve.fitData(); fitData.modelCategory = nsl_fit_model_custom; XYFitCurve::initFitData(fitData); fitData.model = "b1/pow(1. + exp(b2-b3*x), 1/b4)"; fitData.paramNames << "b1" << "b2" << "b3" << "b4"; //fitData.eps = 1.e-12; const int np = fitData.paramNames.size(); fitData.paramStartValues << 6.9964151270E+02 << 5.2771253025E+00 << 7.5962938329E-01 << 1.2792483859E+00; fitData.paramLowerLimits << -std::numeric_limits::max() << -std::numeric_limits::max() << -std::numeric_limits::max() << -std::numeric_limits::max(); fitData.paramUpperLimits << std::numeric_limits::max() << std::numeric_limits::max() << std::numeric_limits::max() << std::numeric_limits::max(); fitCurve.setFitData(fitData); //perform the fit fitCurve.recalculate(); const XYFitCurve::FitResult& fitResult = fitCurve.fitResult(); //check the results QCOMPARE(fitResult.available, true); QCOMPARE(fitResult.valid, true); QCOMPARE(np, 4); DEBUG(std::setprecision(15) << fitResult.paramValues.at(0)); // result: 699.641340982193 FuzzyCompare(fitResult.paramValues.at(0), 6.9964151270E+02, 1.e-8); DEBUG(std::setprecision(15) << fitResult.errorValues.at(0)); // result: 16.3022905400761 FuzzyCompare(fitResult.errorValues.at(0), 1.6302297817E+01, 1.e-6); DEBUG(std::setprecision(15) << fitResult.paramValues.at(1)); // result: 5.2771555758844 FuzzyCompare(fitResult.paramValues.at(1), 5.2771253025E+00, 1.e-8); DEBUG(std::setprecision(15) << fitResult.errorValues.at(1)); // result: 2.08289316520407 FuzzyCompare(fitResult.errorValues.at(1), 2.0828735829E+00, 1.e-5); DEBUG(std::setprecision(15) << fitResult.paramValues.at(2)); // result: 0.759632366113637 FuzzyCompare(fitResult.paramValues.at(2), 7.5962938329E-01, 1.e-8); DEBUG(std::setprecision(15) << fitResult.errorValues.at(2)); // result: 0.195663312668779 FuzzyCompare(fitResult.errorValues.at(2), 1.9566123451E-01, 1.e-4); DEBUG(std::setprecision(15) << fitResult.paramValues.at(3)); // result: 1.27925748993867 FuzzyCompare(fitResult.paramValues.at(3), 1.2792483859E+00, 1.e-8); DEBUG(std::setprecision(15) << fitResult.errorValues.at(3)); // result: 0.687624541478887 FuzzyCompare(fitResult.errorValues.at(3), 6.8761936385E-01, 1.e-5); DEBUG(std::setprecision(15) << fitResult.rsd); // result: 28.2624146626284 FuzzyCompare(fitResult.rsd, 2.8262414662E+01, 1.e-11); DEBUG(std::setprecision(15) << fitResult.sse); // result: 8786.4049081859 FuzzyCompare(fitResult.sse, 8.7864049080E+03, 1.e-11); } //TODO: more tests //############################################################################## //######################### Fits with weights ################################# //############################################################################## //TODO: add tests QTEST_MAIN(FitTest)