//! \addtogroup Math //! \{ //! \file pievaluator.h //! \brief Mathematical expressions evaluator //! \~english Mathematical expressions evaluator for parsing and calculating math expressions //! \~russian Вычислитель математических выражений для разбора и вычисления математических выражений //! \details //! \~english PIEvaluator provides functionality to parse and evaluate mathematical expressions. It supports variables, functions (both //! built-in and custom), and various operators including arithmetic, comparison, and logical operations. //! \~russian PIEvaluator предоставляет функциональность для разбора и вычисления математических выражений. Поддерживаются переменные, //! функции (как встроенные, так и пользовательские), а также различные операторы: арифметические, сравнения и логические. //! \} /* PIP - Platform Independent Primitives Evaluator designed for stream calculations Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef PIEVALUATOR_H #define PIEVALUATOR_H #include "pimathcomplex.h" #include "pistringlist.h" namespace PIEvaluatorTypes { //! \~english Handler function type for custom functions //! \~russian Тип обработчика для пользовательских функций typedef std::function FuncHanlder; //! \~english Type of evaluator element //! \~russian Тип элемента вычислителя enum eType { etNumber, //! \~english Number value //! \~russian Числовое значение etOperator, //! \~english Operator symbol //! \~russian Символ оператора etVariable, //! \~english Variable reference //! \~russian Ссылка на переменную etFunction //! \~english Function call //! \~russian Вызов функции }; //! \~english Operation types supported by evaluator //! \~russian Типы операций, поддерживаемые вычислителем enum Operation { oNone, //! \~english No operation //! \~russian Нет операции oAdd, //! \~english Addition operator (+) //! \~russian Оператор сложения (+) oSubtract, //! \~english Subtraction operator (-) //! \~russian Оператор вычитания (-) oMultiply, //! \~english Multiplication operator (*) //! \~russian Оператор умножения (*) oDivide, //! \~english Division operator (/) //! \~russian Оператор деления (/) oResidue, //! \~english Residue operator //! \~russian Оператор остатка oPower, //! \~english Power operator (^) //! \~russian Оператор возведения в степень (^) oEqual, //! \~english Equal comparison operator (=) //! \~russian Оператор равенства (=) oNotEqual, //! \~english Not equal comparison operator (<>) //! \~russian Оператор неравенства (<>) oGreater, //! \~english Greater than comparison operator (>) //! \~russian Оператор больше (>) oSmaller, //! \~english Smaller than comparison operator (<) //! \~russian Оператор меньше (<) oGreaterEqual, //! \~english Greater or equal comparison operator (>=) //! \~russian Оператор больше или равно (>=) oSmallerEqual, //! \~english Smaller or equal comparison operator (<=) //! \~russian Оператор меньше или равно (<=) oAnd, //! \~english Logical AND operator //! \~russian Логический оператор И oOr, //! \~english Logical OR operator //! \~russian Логический оператор ИЛИ oFunction //! \~english Function call //! \~russian Вызов функции }; //! \~english Built-in base functions supported by evaluator //! \~russian Встроенные базовые функции, поддерживаемые вычислителем enum BaseFunctions { bfUnknown, //! \~english Unknown function //! \~russian Неизвестная функция bfSin, //! \~english Sine function //! \~russian Синус bfCos, //! \~english Cosine function //! \~russian Косинус bfTg, //! \~english Tangent function //! \~russian Тангенс bfCtg, //! \~english Cotangent function //! \~russian Котангенс bfArcsin, //! \~english Arcsine function //! \~russian Арксинус bfArccos, //! \~english Arccosine function //! \~russian Арккосинус bfArctg, //! \~english Arctangent function //! \~russian Арктангенс bfArcctg, //! \~english Arccotangent function //! \~russian Арккотангенс bfExp, //! \~english Exponential function (e^x) //! \~russian Экспонента (e^x) bfRandom, //! \~english Random number generator [0,1] //! \~russian Генератор случайных чисел [0,1] bfRandomn, //! \~english Normal distribution random number //! \~russian Случайное число с нормальным распределением bfSh, //! \~english Hyperbolic sine //! \~russian Гиперболический синус bfCh, //! \~english Hyperbolic cosine //! \~russian Гиперболический косинус bfTh, //! \~english Hyperbolic tangent //! \~russian Гиперболический тангенс bfCth, //! \~english Hyperbolic cotangent //! \~russian Гиперболический котангенс bfSqrt, //! \~english Square root //! \~russian Квадратный корень bfSqr, //! \~english Square function (x^2) //! \~russian Возведение в квадрат (x^2) bfPow, //! \~english Power function //! \~russian Возведение в степень bfAbs, //! \~english Absolute value //! \~russian Модуль (абсолютное значение) bfLn, //! \~english Natural logarithm //! \~russian Натуральный логарифм bfLg, //! \~english Base-10 logarithm //! \~russian Десятичный логарифм bfLog, //! \~english Base-N logarithm //! \~russian Логарифм по основанию N bfSign, //! \~english Sign function //! \~russian Знак числа bfIm, //! \~english Imaginary part of complex number //! \~russian Мнимая часть комплексного числа bfRe, //! \~english Real part of complex number //! \~russian Действительная часть комплексного числа bfArg, //! \~english Argument (phase) of complex number //! \~russian Аргумент (фаза) комплексного числа bfLen, //! \~english Length (magnitude) of complex number //! \~russian Модуль (длина) комплексного числа bfConj, //! \~english Complex conjugate //! \~russian Комплексно-сопряженное bfRad, //! \~english Convert degrees to radians //! \~russian Перевод градусов в радианы bfDeg, //! \~english Convert radians to degrees //! \~russian Перевод радианов в градусы bfJ0, //! \~english Bessel function J0 //! \~russian Функция Бесселя J0 bfJ1, //! \~english Bessel function J1 //! \~russian Функция Бесселя J1 bfJN, //! \~english Bessel function Jn //! \~russian Функция Бесселя Jn bfY0, //! \~english Bessel function Y0 //! \~russian Функция Бесселя Y0 bfY1, //! \~english Bessel function Y1 //! \~russian Функция Бесселя Y1 bfYN, //! \~english Bessel function Yn //! \~russian Функция Бесселя Yn bfMin, //! \~english Minimum of two values //! \~russian Минимум из двух значений bfMax, //! \~english Maximum of two values //! \~russian Максимум из двух значений bfClamp, //! \~english Clamp value to range //! \~russian Ограничение значения диапазоном bfStep, //! \~english Step function //! \~russian Ступенчатая функция bfMix, //! \~english Mix/interpolation function //! \~russian Смешивание/интерполяция bfDefined, //! \~english Check if variable is defined //! \~russian Проверка определена ли переменная bfRound, //! \~english Round to nearest integer //! \~russian Округление до ближайшего целого bfCustom = 0xFFFF //! \~english Custom user-defined function //! \~russian Пользовательская функция }; //! \~english Instruction for evaluator - contains operation, output index, function index and operator indices //! \~russian Инструкция для вычислителя - содержит операцию, индекс вывода, индекс функции и индексы операторов struct PIP_EXPORT Instruction { //! \~english Constructs empty instruction with default values //! \~russian Создает пустую инструкцию со значениями по умолчанию Instruction() { out = -1; function = -1; operation = oNone; } //! \~english Constructs instruction with operation, operators, output index and optional function index //! \~russian Создает инструкцию с указанной операцией, операторами, индексом вывода и опционально индексом функции Instruction(Operation oper, PIVector opers, short out_ind, short func = -1) { operation = oper; operators = opers; out = out_ind; function = func; } //! \~english Operation to perform //! \~russian Операция для выполнения Operation operation; //! \~english Output variable index //! \~russian Индекс переменной вывода short out; //! \~english Function index (if operation is function call) //! \~russian Индекс функции (если операция - вызов функции) short function; //! \~english Input operator indices //! \~russian Индексы входных операторов PIVector operators; }; //! \~english Evaluator element representing a number, variable, operator or function //! \~russian Элемент вычислителя, представляющий число, переменную, оператор или функцию struct PIP_EXPORT Element { //! \~english Constructs empty element (number type with value 0) //! \~russian Создает пустой элемент (тип число со значением 0) Element() { num = 0; var_num = -1; type = etNumber; } //! \~english Constructs element with specified type and numeric/variable indices //! \~russian Создает элемент с указанным типом и числовыми/переменными индексами Element(eType new_type, short new_num, short new_var_num = -1) { set(new_type, new_num, new_var_num); } //! \~english Sets element type and numeric/variable indices //! \~russian Устанавливает тип элемента и числовые/переменные индексы void set(eType new_type, short new_num, short new_var_num = -1) { type = new_type; num = new_num; var_num = new_var_num; } //! \~english Element type (number, operator, variable or function) //! \~russian Тип элемента (число, оператор, переменная или функция) eType type; //! Numeric value or operator index //! \~english Numeric value or operator index //! \~russian Числовое значение или индекс оператора short num; //! Variable index (for variables) //! \~english Variable index (for variables) //! \~russian Индекс переменной (для переменных) short var_num; }; //! \~english Function definition with name, type and handler //! \~russian Определение функции с именем, типом и обработчиком struct PIP_EXPORT Function { //! \~english Constructs unknown function with 0 arguments //! \~russian Создает неизвестную функцию с 0 аргументами Function() { arguments = 0; type = bfUnknown; handler = nullptr; } //! \~english Constructs built-in function with name, argument count and base function type //! \~russian Создает встроенную функцию с именем, количеством аргументов и типом базовой функции Function(const PIString & name, short args, BaseFunctions ftype) { identifier = name; arguments = args; type = ftype; handler = nullptr; } //! \~english Constructs custom function with name, argument count and handler function //! \~russian Создает пользовательскую функцию с именем, количеством аргументов и обработчиком Function(const PIString & name, short args, FuncHanlder h) { identifier = name; arguments = args; type = bfCustom; handler = h; } //! \~english Function identifier (name) //! \~russian Идентификатор функции (имя) PIString identifier; //! \~english Function type (built-in or custom) //! \~russian Тип функции (встроенная или пользовательская) BaseFunctions type; //! \~english Handler function for custom functions //! \~russian Обработчик для пользовательских функций FuncHanlder handler; //! \~english Number of arguments //! \~russian Количество аргументов short arguments; }; //! \~english Variable definition with name and value //! \~russian Определение переменной с именем и значением struct PIP_EXPORT Variable { //! \~english Constructs variable with value 0 //! \~russian Создает переменную со значением 0 Variable() { value = 0.; } //! \~english Constructs variable with name and value //! \~russian Создает переменную с именем и значением Variable(const PIString & var_name, complexd val) { name = var_name; value = val; } //! \~english Variable name //! \~russian Имя переменной PIString name; //! \~english Variable value //! \~russian Значение переменной complexd value; }; } // namespace PIEvaluatorTypes //! \~english Evaluator types namespace containing enums, structs and types for PIEvaluator //! \~russian Пространство имен типов вычислителя, содержащее перечисления, структуры и типы для PIEvaluator /* ≠ : ≥ } ≤ { ⋀ & ⋁ | */ //! Content container for variables and functions //! \~english Container for variables and functions of the evaluator //! \~russian Контейнер для переменных и функций вычислителя //! \details //! \~english PIEvaluatorContent manages variables and functions for the evaluator. It provides methods to add, find, //! and retrieve functions and variables. //! \~russian PIEvaluatorContent управляет переменными и функциями вычислителя. Он предоставляет методы для добавления, //! поиска и получения функций и переменных. class PIP_EXPORT PIEvaluatorContent { friend class PIEvaluator; BINARY_STREAM_FRIEND(PIEvaluatorContent); public: //! \~english Constructs an empty evaluator content //! \~russian Создает пустой контент вычислителя PIEvaluatorContent(); ~PIEvaluatorContent() { ; } //! \~english Add function with name and default 1 argument //! \~russian Добавить функцию с указанным именем и количеством аргументов (по умолчанию 1) void addFunction(const PIString & name, int args = 1); //! \~english Add variable with name and optional value, returns variable index //! \~russian Добавить переменную с указанным именем и значением, возвращает индекс переменной int addVariable(const PIString & name, const complexd & val = 0.); //! \~english Add custom function with name, argument count and handler function //! \~russian Добавить пользовательскую функцию с обработчиком void addCustomFunction(const PIString & name, int args_count, PIEvaluatorTypes::FuncHanlder func); //! \~english Returns number of registered functions //! \~russian Возвращает количество зарегистрированных функций int functionsCount() const { return functions.size(); } //! \~english Returns number of registered variables //! \~russian Возвращает количество зарегистрированных переменных int variablesCount() const { return variables.size(); } //! \~english Returns number of custom variables //! \~russian Возвращает количество пользовательских переменных int customVariablesCount() const; //! \~english Finds function index by name, returns -1 if not found //! \~russian Находит индекс функции по имени, возвращает -1 если не найдена int findFunction(const PIString & name) const; //! \~english Finds variable index by name, returns -1 if not found //! \~russian Находит индекс переменной по имени, возвращает -1 если не найдена int findVariable(const PIString & var_name) const; //! \~english Returns function by index //! \~russian Возвращает функцию по индексу PIEvaluatorTypes::Function function(int index); //! \~english Returns variable by index //! \~russian Возвращает переменную по индексу PIEvaluatorTypes::Variable variable(int index); //! \~english Returns function by name, convenience wrapper //! \~russian Возвращает функцию по имени, удобная обертка PIEvaluatorTypes::Function function(const PIString & name) { return function(findFunction(name)); } //! \~english Returns variable by name, convenience wrapper //! \~russian Возвращает переменную по имени, удобная обертка PIEvaluatorTypes::Variable variable(const PIString & name) { return variable(findVariable(name)); } //! \~english Returns custom variable by index //! \~russian Возвращает пользовательскую переменную по индексу PIEvaluatorTypes::Variable customVariable(int index); //! \~english Set variable value by index, returns true on success //! \~russian Установить значение переменной по индексу, возвращает true при успехе bool setVariableValue(int index, complexd new_value); //! \~english Set variable value by name, returns true on success //! \~russian Установить значение переменной по имени, возвращает true при успехе bool setVariableValue(const PIString & var_name, const complexd & new_value) { return setVariableValue(findVariable(var_name), new_value); } //! \~english Set variable name by index //! \~russian Установить имя переменной по индексу bool setVariableName(int index, const PIString & new_name); //! \~english Set variable name by name, convenience wrapper //! \~russian Установить имя переменной по имени, удобная обертка bool setVariableName(const PIString & var_name, const PIString & new_name) { return setVariableName(findVariable(var_name), new_name); } //! \~english Clears all custom variables //! \~russian Очищает все пользовательские переменные void clearCustomVariables(); //! \~english Returns base function type by name //! \~russian Возвращает тип базовой функции по имени PIEvaluatorTypes::BaseFunctions getBaseFunction(const PIString & name); //! \~english Print all functions and variables to console //! \~russian Вывести все функции и переменные в консоль void dump(); private: PIVector functions; PIVector variables; int cv_count; }; //! Main evaluator class for parsing and calculating mathematical expressions //! \~english Main class for parsing and evaluating mathematical expressions //! \~russian Главный класс для разбора и вычисления математических выражений //! \details //! \~english PIEvaluator provides functionality to parse and evaluate mathematical expressions. It supports variables, functions (both //! built-in and custom), and various operators including arithmetic, comparison, and logical operations. //! \~russian PIEvaluator предоставляет функциональность для разбора и вычисления математических выражений. Поддерживаются переменные, //! функции (как встроенные, так и пользовательские), а также различные операторы: арифметические, сравнения и логические. class PIP_EXPORT PIEvaluator { public: //! \~english Constructs an empty evaluator //! \~russian Создает пустой вычислитель PIEvaluator() { correct = false; data_ = 0; } ~PIEvaluator() { ; } //! \~english Returns custom data pointer //! \~russian Возвращает указатель на пользовательские данные void * data() { return data_; } //! \~english Sets custom data pointer to "_data" //! \~russian Устанавливает указатель на пользовательские данные в "_data" void setData(void * _data) { data_ = _data; } //! \~english Checks mathematical expression and parses it to list of instructions //! \~russian Проверяет математическое выражение и разбирает его в список инструкций bool check(const PIString & string); //! \~english Returns true if expression was checked successfully //! \~russian Возвращает true если выражение было успешно проверено bool isCorrect() const { return correct; } //! \~english Set variable value by name, adds variable if it does not exist, returns variable index //! \~russian Устанавливает значение переменной по имени, добавляет переменную если она не существует, возвращает индекс переменной int setVariable(const PIString & name, complexd value = complexd(0.)); //! \~english Set variable value by index, does not add variable if it does not exist //! \~russian Устанавливает значение переменной по индексу, не добавляет переменную если она не существует void setVariable(int index, complexd value = 0.); //! \~english Evaluates the last successfully checked expression and returns result //! \~russian Вычисляет последнее успешно проверенное выражение и возвращает результат complexd evaluate(); //! \~english Removes all manually added variables //! \~russian Удаляет все вручную добавленные переменные void clearCustomVariables() { content.clearCustomVariables(); } //! \~english Returns index of variable by name //! \~russian Возвращает индекс переменной по имени int variableIndex(const PIString & name) const { return content.findVariable(name); } //! \~english Returns list of unknown variables found in the last expression passed to check() //! \~russian Возвращает список неизвестных переменных, найденных в последнем выражении, переданном в check() const PIStringList & unknownVariables() const { return unknownVars; } //! \~english Returns list of used variables found in the last expression passed to check() //! \~russian Возвращает список используемых переменных, найденных в последнем выражении, переданном в check() const PIStringList & usedVariables() const { return usedVars; } //! \~english Returns the last expression passed to check() //! \~russian Возвращает последнее выражение, переданное в check() const PIString & expression() const { return currentString; } //! \~english Returns last error description from check() function //! \~russian Возвращает описание последней ошибки из функции check() const PIString & error() const { return lastError; } //! \~english Returns last result of evaluate() //! \~russian Возвращает последний результат evaluate() const complexd & lastResult() const { return out; } //! \~english Saves evaluator state to PIByteArray (expression, variables, errors, compiled instructions) //! \~russian Сохраняет состояние вычислителя в PIByteArray (выражение, переменные, ошибки, скомпилированные инструкции) PIByteArray save() const; //! \~english Restores evaluator state from PIByteArray (expression, variables, errors, compiled instructions) //! \~russian Восстанавливает состояние вычислителя из PIByteArray (выражение, переменные, ошибки, скомпилированные инструкции) void load(PIByteArray ba); private: const PIString & prepare(const PIString & string); PIString preprocess(const PIString & string); int parse(const PIString & string, int offset = 0); void convert(); void checkBrackets(); void removeSpaces(); void findUnknownVariables(); void removeJunk(); void replaceOperators(); void makeOutput(PIString & string); bool fillElements(); bool setSignes(); bool isSign(const PIChar & ch); PIString inverse(const PIString & string) { int len = string.length(); PIString s; for (int i = 0; i < len; i++) s += string[len - i - 1]; return s; } bool check(); bool execInstructions(); PIString inBrackets(const PIString & string); PIString operationChar(const PIEvaluatorTypes::Operation & operation); void operationsByPriority(int p, PIVector & ret); complexd value(const int & index) { if (index < 0) return tmpvars[-index - 1].value; else return content.variables[index].value; } inline complexd residue(const complexd & f, const complexd & s); inline void execFunction(const PIEvaluatorTypes::Instruction & ci); PIEvaluatorContent content; PIDeque elements; PIVector currentVariables, variables, tmpvars; PIVector instructions; PIStringList unknownVars, usedVars; PIString currentString, lastError; complexd out; bool correct; void * data_; }; inline bool operator==(PIEvaluatorTypes::Element e1, PIEvaluatorTypes::Element e2) { return (e1.type == e2.type && e1.num == e2.num); } inline bool operator!=(PIEvaluatorTypes::Element e1, PIEvaluatorTypes::Element e2) { return (e1.type != e2.type || e1.num != e2.num); } BINARY_STREAM_WRITE(PIEvaluatorTypes::Instruction) { s << PIMemoryBlock(&v, sizeof(v) - sizeof(v.operators)) << v.operators; return s; } BINARY_STREAM_READ(PIEvaluatorTypes::Instruction) { s >> PIMemoryBlock(&v, sizeof(v) - sizeof(v.operators)) >> v.operators; return s; } BINARY_STREAM_WRITE(PIEvaluatorTypes::Element) { s << createMemoryBlock(&v); return s; } BINARY_STREAM_READ(PIEvaluatorTypes::Element) { s >> createMemoryBlock(&v); return s; } BINARY_STREAM_WRITE(PIEvaluatorTypes::Variable) { s << v.name << v.value; return s; } BINARY_STREAM_READ(PIEvaluatorTypes::Variable) { s >> v.name >> v.value; return s; } BINARY_STREAM_WRITE(PIEvaluatorContent) { s << v.variables << v.cv_count; return s; } BINARY_STREAM_READ(PIEvaluatorContent) { s >> v.variables >> v.cv_count; return s; } #endif // PIEVALUATOR_H