Files
pip/libs/main/math/pievaluator.h

618 lines
31 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! \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 <http://www.gnu.org/licenses/>.
*/
#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<complexd(void *, int, complexd *)> 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<short> 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<short> 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<PIEvaluatorTypes::Function> functions;
PIVector<PIEvaluatorTypes::Variable> 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<PIEvaluatorTypes::Operation> & 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<PIEvaluatorTypes::Element> elements;
PIVector<PIEvaluatorTypes::Variable> currentVariables, variables, tmpvars;
PIVector<PIEvaluatorTypes::Instruction> 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