//! \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