File indexing completed on 2024-05-12 03:47:44

0001 /*
0002     File             : ExpressionParser.cpp
0003     Project          : LabPlot
0004     Description      : C++ wrapper for the bison generated parser.
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2014 Alexander Semke <alexander.semke@web.de>
0007     SPDX-FileCopyrightText: 2014-2022 Stefan Gerlach <stefan.gerlach@uni.kn>
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "backend/gsl/ExpressionParser.h"
0012 #include "backend/lib/macros.h"
0013 #include "backend/lib/trace.h"
0014 
0015 #include <KLocalizedString>
0016 
0017 #include <QRegularExpression>
0018 
0019 #include <gsl/gsl_const_mksa.h>
0020 #include <gsl/gsl_const_num.h>
0021 #include <gsl/gsl_errno.h>
0022 #include <gsl/gsl_math.h>
0023 #include <gsl/gsl_version.h>
0024 
0025 ExpressionParser* ExpressionParser::m_instance{nullptr};
0026 
0027 ExpressionParser::ExpressionParser() {
0028     init_table();
0029     initFunctions();
0030     initConstants();
0031 }
0032 
0033 // initialize function list (sync with functions.h and FunctionsWidget.cpp!)
0034 void ExpressionParser::initFunctions() {
0035     for (int i = 0; i < _number_functions; i++) {
0036         const auto& function = _functions[i];
0037         m_functionsDescription << function.description();
0038         m_functions << QLatin1String(function.name);
0039         m_functionsGroupIndex << function.group;
0040     }
0041     for (int i = 0; i < _number_specialfunctions; i++) {
0042         const auto& function = _special_functions[i];
0043         m_functionsDescription << function.description();
0044         m_functions << QLatin1String(function.name);
0045         m_functionsGroupIndex << function.group;
0046     }
0047 }
0048 
0049 // TODO: decide whether we want to have i18n here in the backend part of the code
0050 void ExpressionParser::initConstants() {
0051     for (int i = 0; i < _number_constants; i++) {
0052         const auto& constant = _constants[i];
0053         m_constantsDescription << constant.description();
0054         m_constants << QLatin1String(constant.name);
0055         m_constantsValues << QString::number(constant.value, 'g', 15);
0056         m_constantsUnits << QLatin1String(constant.unit);
0057         m_constantsGroupIndex << constant.group;
0058     }
0059 }
0060 
0061 /**********************************************************************************/
0062 
0063 ExpressionParser::~ExpressionParser() {
0064     delete_table();
0065 }
0066 
0067 ExpressionParser* ExpressionParser::getInstance() {
0068     if (!m_instance)
0069         m_instance = new ExpressionParser();
0070 
0071     return m_instance;
0072 }
0073 
0074 const QStringList& ExpressionParser::functions() {
0075     return m_functions;
0076 }
0077 
0078 const QStringList& ExpressionParser::functionsGroups() {
0079     return m_functionsGroups;
0080 }
0081 
0082 const QStringList& ExpressionParser::functionsDescriptions() {
0083     return m_functionsDescription;
0084 }
0085 
0086 const QVector<FunctionGroups>& ExpressionParser::functionsGroupIndices() {
0087     return m_functionsGroupIndex;
0088 }
0089 
0090 /* another idea:
0091  * https://stackoverflow.com/questions/36797770/get-function-parameters-count
0092  * but this does not work since all function pointer have zero args in the struct
0093  */
0094 int ExpressionParser::functionArgumentCount(const QString& functionName) {
0095     for (int i = 0; i < _number_functions; i++) {
0096         if (functionName == QLatin1String(_functions[i].name))
0097             return _functions[i].argc;
0098     }
0099     for (int i = 0; i < _number_specialfunctions; i++) {
0100         if (functionName == QLatin1String(_special_functions[i].name))
0101             return _special_functions[i].argc;
0102     }
0103 
0104     // DEBUG(Q_FUNC_INFO << ", Found function " << STDSTRING(functionName) << " at index " << index);
0105     // DEBUG(Q_FUNC_INFO << ", function " << STDSTRING(functionName) << " has " << _functions[index].argc << " arguments");
0106     return 0;
0107 }
0108 
0109 QString ExpressionParser::parameters(const QString& functionName) {
0110     for (int i = 0; i < _number_functions; i++) {
0111         if (functionName == QLatin1String(_functions[i].name)) {
0112             int count = _functions[i].argc;
0113             const auto parameterFunction = _functions[i].parameterFunction;
0114 
0115             if (parameterFunction == nullptr)
0116                 return QStringLiteral("");
0117 
0118             if (count == 0)
0119                 return QStringLiteral("()");
0120 
0121             QString parameter = QStringLiteral("(");
0122             for (int p = 0; p < count - 1; p++)
0123                 parameter += parameterFunction(p) + QStringLiteral("; ");
0124             parameter += parameterFunction(count - 1);
0125             parameter += QStringLiteral(")");
0126             return parameter;
0127         }
0128         // DEBUG(Q_FUNC_INFO << ", Found function " << STDSTRING(functionName) << " at index " << index);
0129         // DEBUG(Q_FUNC_INFO << ", function " << STDSTRING(functionName) << " has " << _functions[index].argc << " arguments");
0130     }
0131     for (int i = 0; i < _number_specialfunctions; i++) {
0132         if (functionName == QLatin1String(_special_functions[i].name)) {
0133             int count = _special_functions[i].argc;
0134             const auto parameterFunction = _special_functions[i].parameterFunction;
0135 
0136             if (parameterFunction == nullptr)
0137                 return QStringLiteral("");
0138 
0139             if (count == 0)
0140                 return QStringLiteral("()");
0141 
0142             QString parameter = QStringLiteral("(");
0143             for (int p = 0; p < count - 1; p++)
0144                 parameter += parameterFunction(p) + QStringLiteral("; ");
0145             parameter += parameterFunction(count - 1);
0146             parameter += QStringLiteral(")");
0147             return parameter;
0148         }
0149         // DEBUG(Q_FUNC_INFO << ", Found function " << STDSTRING(functionName) << " at index " << index);
0150         // DEBUG(Q_FUNC_INFO << ", function " << STDSTRING(functionName) << " has " << _functions[index].argc << " arguments");
0151     }
0152     return QStringLiteral("");
0153 }
0154 
0155 QString ExpressionParser::functionArgumentString(const QString& functionName, const XYEquationCurve::EquationType type) {
0156     QString p = parameters(functionName);
0157     if (!p.isEmpty())
0158         return p;
0159 
0160     // Default parameters
0161     switch (functionArgumentCount(functionName)) {
0162     case 0:
0163         return QStringLiteral("()");
0164     case 1:
0165         switch (type) {
0166         case XYEquationCurve::EquationType::Cartesian:
0167             return QStringLiteral("(x)");
0168         case XYEquationCurve::EquationType::Polar:
0169             return QStringLiteral("(phi)");
0170         case XYEquationCurve::EquationType::Parametric:
0171             return QStringLiteral("(t)");
0172         case XYEquationCurve::EquationType::Implicit:
0173         case XYEquationCurve::EquationType::Neutral:
0174             return QStringLiteral("(x)");
0175         }
0176         break;
0177     case 2:
0178         switch (type) {
0179         case XYEquationCurve::EquationType::Cartesian:
0180             return QStringLiteral("(x; y)");
0181         case XYEquationCurve::EquationType::Polar:
0182             return QStringLiteral("(phi; theta)");
0183         case XYEquationCurve::EquationType::Parametric:
0184             return QStringLiteral("(u; v)");
0185         case XYEquationCurve::EquationType::Implicit:
0186         case XYEquationCurve::EquationType::Neutral:
0187             return QStringLiteral("(x; y)");
0188         }
0189         break;
0190     case 3:
0191         switch (type) {
0192         case XYEquationCurve::EquationType::Cartesian:
0193             return QStringLiteral("(x; y; z)");
0194         case XYEquationCurve::EquationType::Polar:
0195             return QStringLiteral("(alpha; beta; gamma)");
0196         case XYEquationCurve::EquationType::Parametric:
0197             return QStringLiteral("(u; v; w)");
0198         case XYEquationCurve::EquationType::Implicit:
0199         case XYEquationCurve::EquationType::Neutral:
0200             return QStringLiteral("(x; y; z)");
0201         }
0202         break;
0203     case 4:
0204         switch (type) {
0205         case XYEquationCurve::EquationType::Cartesian:
0206             return QStringLiteral("(a; b; c; d)");
0207         case XYEquationCurve::EquationType::Polar:
0208             return QStringLiteral("(alpha; beta; gamma; delta)");
0209         case XYEquationCurve::EquationType::Parametric:
0210             return QStringLiteral("(a; b; c; d)");
0211         case XYEquationCurve::EquationType::Implicit:
0212         case XYEquationCurve::EquationType::Neutral:
0213             return QStringLiteral("(a; b; c; d)");
0214         }
0215         break;
0216     }
0217 
0218     return QStringLiteral("(...)");
0219 }
0220 
0221 QString ExpressionParser::functionDescription(const QString& function) {
0222     for (int index = 0; index < _number_functions; index++) {
0223         if (function == QLatin1String(_functions[index].name))
0224             return _functions[index].description();
0225     }
0226     for (int index = 0; index < _number_specialfunctions; index++) {
0227         if (function == QLatin1String(_special_functions[index].name))
0228             return _special_functions[index].description();
0229     }
0230     return QStringLiteral("");
0231 }
0232 QString ExpressionParser::constantDescription(const QString& constant) {
0233     for (int index = 0; index < _number_constants; index++) {
0234         if (constant == QLatin1String(_constants[index].name))
0235             return QStringLiteral("%1 (%2 %3)").arg(_constants[index].description()).arg(_constants[index].value).arg(QLatin1String(_constants[index].unit));
0236     }
0237     return QStringLiteral("");
0238 }
0239 
0240 const QStringList& ExpressionParser::constants() {
0241     return m_constants;
0242 }
0243 
0244 const QStringList& ExpressionParser::constantsGroups() {
0245     return m_constantsGroups;
0246 }
0247 
0248 const QStringList& ExpressionParser::constantsNames() {
0249     return m_constantsDescription;
0250 }
0251 
0252 const QStringList& ExpressionParser::constantsValues() {
0253     return m_constantsValues;
0254 }
0255 
0256 const QStringList& ExpressionParser::constantsUnits() {
0257     return m_constantsUnits;
0258 }
0259 
0260 const QVector<ConstantGroups>& ExpressionParser::constantsGroupIndices() {
0261     return m_constantsGroupIndex;
0262 }
0263 
0264 bool ExpressionParser::isValid(const QString& expr, const QStringList& vars) {
0265     QDEBUG(Q_FUNC_INFO << ", expr:" << expr << ", vars:" << vars);
0266     gsl_set_error_handler_off();
0267 
0268     Lock l(skipSpecialFunctionEvaluation);
0269 
0270     for (const auto& var : vars)
0271         assign_symbol(qPrintable(var), 0);
0272 
0273     // Row index
0274     assign_symbol("i", 0);
0275 
0276     const auto numberLocale = QLocale();
0277     DEBUG(Q_FUNC_INFO << ", number locale: " << STDSTRING(numberLocale.name()))
0278     parse(qPrintable(expr), qPrintable(numberLocale.name()));
0279 
0280     // if parsing with number locale fails, try default locale
0281     if (parse_errors() > 0) {
0282         DEBUG(Q_FUNC_INFO << ", WARNING: failed parsing expr \"" << STDSTRING(expr) << "\" with locale " << numberLocale.name().toStdString()
0283                           << ", errors = " << parse_errors())
0284         parse(qPrintable(expr), "en_US");
0285         if (parse_errors() > 0)
0286             DEBUG(Q_FUNC_INFO << ", ERROR: parsing FAILED, errors = " << parse_errors())
0287     }
0288 
0289     /* remove temporarily defined symbols */
0290     for (const auto& var : vars)
0291         remove_symbol(qPrintable(var));
0292 
0293     return !(parse_errors() > 0);
0294 }
0295 
0296 QStringList ExpressionParser::getParameter(const QString& expr, const QStringList& vars) {
0297     QDEBUG(Q_FUNC_INFO << ", variables:" << vars);
0298     QStringList parameters;
0299 
0300 #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
0301     QStringList strings = expr.split(QRegularExpression(QStringLiteral("\\W+")), Qt::SkipEmptyParts);
0302 #else
0303     QStringList strings = expr.split(QRegularExpression(QStringLiteral("\\W+")), QString::SkipEmptyParts);
0304 #endif
0305     QDEBUG(Q_FUNC_INFO << ", found strings:" << strings);
0306     // RE for any number
0307     const QRegularExpression re(QRegularExpression::anchoredPattern(QStringLiteral("[0-9]*")));
0308     for (const QString& string : strings) {
0309         QDEBUG(string << ':' << constants().indexOf(string) << ' ' << functions().indexOf(string) << ' ' << vars.indexOf(string) << ' '
0310                       << re.match(string).hasMatch());
0311         // check if token is not a known constant/function/variable or number
0312         if (constants().indexOf(string) == -1 && functions().indexOf(string) == -1 && vars.indexOf(string) == -1 && re.match(string).hasMatch() == false)
0313             parameters << string;
0314     }
0315     parameters.removeDuplicates();
0316     QDEBUG(Q_FUNC_INFO << ", parameters found:" << parameters);
0317 
0318     return parameters;
0319 }
0320 
0321 /*
0322  * Evaluate cartesian expression returning true on success and false if parsing fails
0323  * using given range
0324  */
0325 bool ExpressionParser::evaluateCartesian(const QString& expr,
0326                                          const Range<double> range,
0327                                          int count,
0328                                          QVector<double>* xVector,
0329                                          QVector<double>* yVector,
0330                                          const QStringList& paramNames,
0331                                          const QVector<double>& paramValues) {
0332     DEBUG(Q_FUNC_INFO << ", v0: range = " << range.toStdString())
0333     const double step = range.stepSize(count);
0334     DEBUG(Q_FUNC_INFO << ", range = " << range.toStdString() << ", step = " << step)
0335 
0336     for (int i = 0; i < paramNames.size(); ++i)
0337         assign_symbol(qPrintable(paramNames.at(i)), paramValues.at(i));
0338 
0339     const auto numberLocale = QLocale();
0340     gsl_set_error_handler_off();
0341     for (int i = 0; i < count; i++) {
0342         const double x{range.start() + step * i};
0343         assign_symbol("x", x);
0344 
0345         double y = parse(qPrintable(expr), qPrintable(numberLocale.name()));
0346         if (parse_errors() > 0) // try default locale if failing
0347             y = parse(qPrintable(expr), "en_US");
0348         if (parse_errors() > 0)
0349             return false;
0350 
0351         if (std::isnan(y))
0352             WARN(Q_FUNC_INFO << ", WARNING: expression " << STDSTRING(expr) << " evaluated @ " << x << " is NAN")
0353 
0354         (*xVector)[i] = x;
0355         (*yVector)[i] = y;
0356     }
0357 
0358     return true;
0359 }
0360 /*
0361  * Evaluate cartesian expression returning true on success and false if parsing fails
0362  * min and max are localized strings which are parsed to support expressions like "pi + 1.5"
0363  */
0364 bool ExpressionParser::evaluateCartesian(const QString& expr,
0365                                          const QString& min,
0366                                          const QString& max,
0367                                          int count,
0368                                          QVector<double>* xVector,
0369                                          QVector<double>* yVector,
0370                                          const QStringList& paramNames,
0371                                          const QVector<double>& paramValues) {
0372     DEBUG(Q_FUNC_INFO << ", v1: range = " << STDSTRING(min) << " .. " << STDSTRING(max))
0373 
0374     const Range<double> range{min, max};
0375     return evaluateCartesian(expr, range, count, xVector, yVector, paramNames, paramValues);
0376 }
0377 
0378 bool ExpressionParser::evaluateCartesian(const QString& expr,
0379                                          const QString& min,
0380                                          const QString& max,
0381                                          int count,
0382                                          QVector<double>* xVector,
0383                                          QVector<double>* yVector) {
0384     DEBUG(Q_FUNC_INFO << ", v2")
0385     gsl_set_error_handler_off();
0386 
0387     const Range<double> range{min, max};
0388     const double step = range.stepSize(count);
0389 
0390     const auto numberLocale = QLocale();
0391     for (int i = 0; i < count; i++) {
0392         const double x{range.start() + step * i};
0393         assign_symbol("x", x);
0394 
0395         double y = parse(qPrintable(expr), qPrintable(numberLocale.name()));
0396         if (parse_errors() > 0) { // try default locale if failing
0397             y = parse(qPrintable(expr), "en_US");
0398             // DEBUG(Q_FUNC_INFO << ", WARNING: PARSER failed, trying default locale: y = " << y)
0399         }
0400         if (parse_errors() > 0)
0401             return false;
0402 
0403         if (std::isnan(y))
0404             WARN(Q_FUNC_INFO << ", WARNING: expression " << STDSTRING(expr) << " evaluated @ " << x << " is NAN")
0405 
0406         (*xVector)[i] = x;
0407         (*yVector)[i] = y;
0408     }
0409 
0410     return true;
0411 }
0412 
0413 bool ExpressionParser::evaluateCartesian(const QString& expr, QVector<double>* xVector, QVector<double>* yVector) {
0414     DEBUG(Q_FUNC_INFO << ", v3")
0415     gsl_set_error_handler_off();
0416 
0417     const auto numberLocale = QLocale();
0418     for (int i = 0; i < xVector->count(); i++) {
0419         assign_symbol("x", xVector->at(i));
0420         double y = parse(qPrintable(expr), qPrintable(numberLocale.name()));
0421         if (parse_errors() > 0) // try default locale if failing
0422             y = parse(qPrintable(expr), "en_US");
0423         if (parse_errors() > 0)
0424             return false;
0425 
0426         if (std::isnan(y))
0427             WARN(Q_FUNC_INFO << ", WARNING: expression " << STDSTRING(expr) << " evaluated @ " << xVector->at(i) << " is NAN")
0428 
0429         (*yVector)[i] = y;
0430     }
0431 
0432     return true;
0433 }
0434 
0435 bool ExpressionParser::evaluateCartesian(const QString& expr,
0436                                          const QVector<double>* xVector,
0437                                          QVector<double>* yVector,
0438                                          const QStringList& paramNames,
0439                                          const QVector<double>& paramValues) {
0440     DEBUG(Q_FUNC_INFO << ", v4")
0441     gsl_set_error_handler_off();
0442 
0443     for (int i = 0; i < paramNames.size(); ++i)
0444         assign_symbol(qPrintable(paramNames.at(i)), paramValues.at(i));
0445 
0446     const auto numberLocale = QLocale();
0447     for (int i = 0; i < xVector->count(); i++) {
0448         assign_symbol("x", xVector->at(i));
0449 
0450         double y = parse(qPrintable(expr), qPrintable(numberLocale.name()));
0451         if (parse_errors() > 0) // try default locale if failing
0452             y = parse(qPrintable(expr), "en_US");
0453         if (parse_errors() > 0)
0454             return false;
0455 
0456         if (std::isnan(y))
0457             WARN(Q_FUNC_INFO << ", WARNING: expression " << STDSTRING(expr) << " evaluated @ " << xVector->at(i) << " is NAN")
0458 
0459         (*yVector)[i] = y;
0460     }
0461 
0462     return true;
0463 }
0464 
0465 struct PayloadExpressionParser : public Payload {
0466     PayloadExpressionParser() {
0467     }
0468     PayloadExpressionParser(const QStringList* vars, const QVector<QVector<double>*>* xVectors, bool constant = false)
0469         : Payload(constant)
0470         , vars(vars)
0471         , row(0)
0472         , xVectors(xVectors) {
0473     }
0474     const QStringList* vars;
0475     int row;
0476     const QVector<QVector<double>*>* xVectors;
0477 };
0478 
0479 double cell(double x, const char* variable, const std::weak_ptr<Payload> payload) {
0480     const auto p = std::dynamic_pointer_cast<PayloadExpressionParser>(payload.lock());
0481     if (!p) {
0482         assert(p); // Debug build
0483         return NAN;
0484     }
0485 
0486     const int index = (int)x - 1;
0487     for (int i = 0; i < p->vars->length(); i++) {
0488         if (p->vars->at(i).compare(QLatin1String(variable)) == 0) {
0489             if (index >= 0 && index < p->xVectors->at(i)->length())
0490                 return p->xVectors->at(i)->at(index);
0491             else
0492                 break;
0493         }
0494     }
0495 
0496     return NAN;
0497 }
0498 
0499 double ma(const char* variable, const std::weak_ptr<Payload> payload) {
0500     const auto p = std::dynamic_pointer_cast<PayloadExpressionParser>(payload.lock());
0501     if (!p) {
0502         assert(p); // Debug build
0503         return NAN;
0504     }
0505     return (cell(p->row, variable, payload) + cell(p->row + 1, variable, payload)) / 2.;
0506 }
0507 
0508 double mr(const char* variable, const std::weak_ptr<Payload> payload) {
0509     const auto p = std::dynamic_pointer_cast<PayloadExpressionParser>(payload.lock());
0510     if (!p) {
0511         assert(p); // Debug build
0512         return NAN;
0513     }
0514     return fabs(cell(p->row + 1, variable, payload) - cell(p->row + 1 - 1, variable, payload));
0515 }
0516 
0517 double smmin(double x, const char* variable, const std::weak_ptr<Payload> payload) {
0518     const auto p = std::dynamic_pointer_cast<PayloadExpressionParser>(payload.lock());
0519     if (!p) {
0520         assert(p); // Debug build
0521         return NAN;
0522     }
0523 
0524     for (int i = 0; i < p->vars->length(); i++) {
0525         if (p->vars->at(i).compare(QLatin1String(variable)) == 0) {
0526             const int N = x;
0527             DEBUG("N = " << N)
0528             if (N < 1)
0529                 break;
0530             // calculate min of last n points
0531             double min = INFINITY;
0532             const int row = p->row;
0533             for (int index = std::max(0, row - N + 1); index <= row; index++) {
0534                 const double v = p->xVectors->at(i)->at(index);
0535                 if (v < min)
0536                     min = v;
0537             }
0538             return min;
0539         }
0540     }
0541     return NAN;
0542 }
0543 
0544 double smmax(double x, const char* variable, const std::weak_ptr<Payload> payload) {
0545     const auto p = std::dynamic_pointer_cast<PayloadExpressionParser>(payload.lock());
0546     if (!p) {
0547         assert(p); // Debug build
0548         return NAN;
0549     }
0550 
0551     for (int i = 0; i < p->vars->length(); i++) {
0552         if (p->vars->at(i).compare(QLatin1String(variable)) == 0) {
0553             const int N = x;
0554             DEBUG("N = " << N)
0555             if (N < 1)
0556                 break;
0557             // calculate max of last n points
0558             double max = -INFINITY;
0559             const int row = p->row;
0560             for (int index = std::max(0, row - N + 1); index <= row; index++) {
0561                 const double v = p->xVectors->at(i)->at(index);
0562                 if (v > max)
0563                     max = v;
0564             }
0565             return max;
0566         }
0567     }
0568     return NAN;
0569 }
0570 
0571 double sma(double x, const char* variable, const std::weak_ptr<Payload> payload) {
0572     const auto p = std::dynamic_pointer_cast<PayloadExpressionParser>(payload.lock());
0573     if (!p) {
0574         assert(p); // Debug build
0575         return NAN;
0576     }
0577 
0578     for (int i = 0; i < p->vars->length(); i++) {
0579         if (p->vars->at(i).compare(QLatin1String(variable)) == 0) {
0580             const int N = x;
0581             DEBUG("N = " << N)
0582             if (N < 1)
0583                 break;
0584             // calculate max of last n points
0585             double sum = 0.;
0586             const int row = p->row;
0587             for (int index = std::max(0, row - N + 1); index <= row; index++)
0588                 sum += p->xVectors->at(i)->at(index);
0589             return sum / N;
0590         }
0591     }
0592     return NAN;
0593 }
0594 
0595 double smr(double x, const char* variable, const std::weak_ptr<Payload> payload) {
0596     return smmax(x, variable, payload) - smmin(x, variable, payload);
0597 }
0598 
0599 void ExpressionParser::setSpecialFunction1(const char* function_name, func_t1Payload funct, std::shared_ptr<Payload> payload) {
0600     set_specialfunction1(function_name, funct, payload);
0601 }
0602 
0603 void ExpressionParser::setSpecialFunction2(const char* function_name, func_t2Payload funct, std::shared_ptr<Payload> payload) {
0604     set_specialfunction2(function_name, funct, payload);
0605 }
0606 
0607 /*!
0608     evaluates multivariate function y=f(x_1, x_2, ...).
0609     Variable names (x_1, x_2, ...) are stored in \c vars.
0610     Data is stored in \c xVectors.
0611  */
0612 bool ExpressionParser::evaluateCartesian(const QString& expr, const QStringList& vars, const QVector<QVector<double>*>& xVectors, QVector<double>* yVector) {
0613 #if PERFTRACE_EXPRESSION_PARSER
0614     PERFTRACE(QLatin1String(Q_FUNC_INFO));
0615 #endif
0616     DEBUG(Q_FUNC_INFO << ", v5")
0617     Q_ASSERT(vars.size() == xVectors.size());
0618     gsl_set_error_handler_off();
0619 
0620     // determine the minimal size of involved vectors
0621     int minSize{std::numeric_limits<int>::max()};
0622     for (auto* xVector : xVectors) {
0623         if (xVector->size() < minSize)
0624             minSize = xVector->size();
0625     }
0626     if (yVector->size() < minSize)
0627         minSize = yVector->size();
0628 
0629     // calculate values
0630     const auto numberLocale = QLocale();
0631     DEBUG("Parsing with locale " << qPrintable(numberLocale.name()))
0632 
0633     const auto payload = std::make_shared<PayloadExpressionParser>(&vars, &xVectors);
0634     const auto payloadConst = std::make_shared<PayloadExpressionParser>(&vars, &xVectors, true);
0635 
0636     set_specialfunction2(specialfun_cell, cell, payloadConst);
0637     set_specialfunction1(specialfun_ma, ma, payload);
0638     set_specialfunction1(specialfun_mr, mr, payload);
0639     set_specialfunction2(specialfun_smmin, smmin, payload);
0640     set_specialfunction2(specialfun_smmax, smmax, payload);
0641     set_specialfunction2(specialfun_sma, sma, payload);
0642     set_specialfunction2(specialfun_smr, smr, payload);
0643 
0644     bool constExpression = false;
0645     for (int i = 0; i < minSize || (constExpression && i < yVector->size()); i++) {
0646         QString tmpExpr = expr;
0647 
0648         payload->row = i; // all special functions contain pointer to payload so they get this information
0649         assign_symbol("i", i + 1);
0650 
0651         for (int n = 0; n < vars.size(); ++n) {
0652             if (!constExpression)
0653                 assign_symbol(qPrintable(vars.at(n)), xVectors.at(n)->at(i));
0654         }
0655 
0656         double y = parse(qPrintable(tmpExpr), qPrintable(numberLocale.name()));
0657         if (parse_errors() > 0) { // try default locale if failing
0658             // DEBUG("Parsing with locale failed. Using en_US.")
0659             y = parse(qPrintable(tmpExpr), "en_US");
0660         }
0661 
0662         if (parse_errors() == 0)
0663             constExpression = variablesCounter() == 0;
0664         // continue with next value
0665         // if (parse_errors() > 0)
0666         //  return false;
0667 
0668         if (std::isnan(y))
0669             WARN(Q_FUNC_INFO << ", WARNING: expression " << STDSTRING(tmpExpr) << " evaluated to NAN")
0670 
0671         (*yVector)[i] = y;
0672     }
0673 
0674     // if the y-vector is longer than the x-vector(s), set all exceeding elements to NaN
0675     if (!constExpression) {
0676         for (int i = minSize; i < yVector->size(); ++i)
0677             (*yVector)[i] = NAN;
0678     }
0679 
0680     return true;
0681 }
0682 
0683 bool ExpressionParser::evaluatePolar(const QString& expr,
0684                                      const QString& min,
0685                                      const QString& max,
0686                                      int count,
0687                                      QVector<double>* xVector,
0688                                      QVector<double>* yVector) {
0689     gsl_set_error_handler_off();
0690 
0691     const Range<double> range{min, max};
0692     const double step = range.stepSize(count);
0693 
0694     const auto numberLocale = QLocale();
0695     for (int i = 0; i < count; i++) {
0696         const double phi = range.start() + step * i;
0697         assign_symbol("phi", phi);
0698 
0699         double r = parse(qPrintable(expr), qPrintable(numberLocale.name()));
0700         if (parse_errors() > 0) // try default locale if failing
0701             r = parse(qPrintable(expr), "en_US");
0702         if (parse_errors() > 0)
0703             return false;
0704 
0705         if (std::isnan(r))
0706             WARN(Q_FUNC_INFO << ", WARNING: expression " << STDSTRING(expr) << " evaluated @ " << phi << " is NAN")
0707 
0708         (*xVector)[i] = r * cos(phi);
0709         (*yVector)[i] = r * sin(phi);
0710     }
0711 
0712     return true;
0713 }
0714 
0715 bool ExpressionParser::evaluateParametric(const QString& xexpr,
0716                                           const QString& yexpr,
0717                                           const QString& min,
0718                                           const QString& max,
0719                                           int count,
0720                                           QVector<double>* xVector,
0721                                           QVector<double>* yVector) {
0722     gsl_set_error_handler_off();
0723 
0724     const Range<double> range{min, max};
0725     const double step = range.stepSize(count);
0726 
0727     const auto numberLocale = QLocale();
0728     for (int i = 0; i < count; i++) {
0729         assign_symbol("t", range.start() + step * i);
0730 
0731         double x = parse(qPrintable(xexpr), qPrintable(numberLocale.name()));
0732         if (parse_errors() > 0) // try default locale if failing
0733             x = parse(qPrintable(xexpr), "en_US");
0734         if (parse_errors() > 0)
0735             return false;
0736 
0737         double y = parse(qPrintable(yexpr), qPrintable(numberLocale.name()));
0738         if (parse_errors() > 0) // try default locale if failing
0739             y = parse(qPrintable(yexpr), "en_US");
0740         if (parse_errors() > 0)
0741             return false;
0742 
0743         if (std::isnan(x))
0744             WARN(Q_FUNC_INFO << ", WARNING: X expression " << STDSTRING(xexpr) << " evaluated @ " << range.start() + step * i << " is NAN")
0745         if (std::isnan(y))
0746             WARN(Q_FUNC_INFO << ", WARNING: Y expression " << STDSTRING(yexpr) << " evaluated @ " << range.start() + step * i << " is NAN")
0747 
0748         (*xVector)[i] = x;
0749         (*yVector)[i] = y;
0750     }
0751 
0752     return true;
0753 }
0754 
0755 QString ExpressionParser::errorMessage() const {
0756     return QLatin1String(lastErrorMessage());
0757 }