Files
pip/libs/main/math/pievaluator.h
2026-03-20 16:31:30 +03:00

430 lines
13 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.
//! \~\file pievaluator.h
//! \~\ingroup Math
//! \~\brief
//! \~english Mathematical expression evaluator
//! \~russian Вычислитель математических выражений
//! \~\details
//! \~english
//! Declares evaluator types, expression storage, and the evaluator that
//! prepares an expression once and then reuses compiled instructions.
//! \~russian
//! Объявляет типы вычислителя, контейнер выражения и вычислитель,
//! который один раз подготавливает выражение и затем повторно использует
//! скомпилированные инструкции.
/*
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 {
typedef std::function<complexd(void *, int, complexd *)> FuncHanlder;
enum eType {
etNumber,
etOperator,
etVariable,
etFunction
};
enum Operation {
oNone,
oAdd,
oSubtract,
oMultiply,
oDivide,
oResidue,
oPower,
oEqual,
oNotEqual,
oGreater,
oSmaller,
oGreaterEqual,
oSmallerEqual,
oAnd,
oOr,
oFunction
};
enum BaseFunctions {
bfUnknown,
bfSin,
bfCos,
bfTg,
bfCtg,
bfArcsin,
bfArccos,
bfArctg,
bfArcctg,
bfExp,
bfRandom,
bfRandomn,
bfSh,
bfCh,
bfTh,
bfCth,
bfSqrt,
bfSqr,
bfPow,
bfAbs,
bfLn,
bfLg,
bfLog,
bfSign,
bfIm,
bfRe,
bfArg,
bfLen,
bfConj,
bfRad,
bfDeg,
bfJ0,
bfJ1,
bfJN,
bfY0,
bfY1,
bfYN,
bfMin,
bfMax,
bfClamp,
bfStep,
bfMix,
bfDefined,
bfRound,
bfCustom = 0xFFFF
};
struct PIP_EXPORT Instruction {
Instruction() {
out = -1;
function = -1;
operation = oNone;
}
Instruction(Operation oper, PIVector<short> opers, short out_ind, short func = -1) {
operation = oper;
operators = opers;
out = out_ind;
function = func;
}
Operation operation;
short out;
short function;
PIVector<short> operators;
};
struct PIP_EXPORT Element {
Element() {
num = 0;
var_num = -1;
type = etNumber;
}
Element(eType new_type, short new_num, short new_var_num = -1) { set(new_type, new_num, new_var_num); }
void set(eType new_type, short new_num, short new_var_num = -1) {
type = new_type;
num = new_num;
var_num = new_var_num;
}
eType type;
short num;
short var_num;
};
struct PIP_EXPORT Function {
Function() {
arguments = 0;
type = bfUnknown;
handler = nullptr;
}
Function(const PIString & name, short args, BaseFunctions ftype) {
identifier = name;
arguments = args;
type = ftype;
handler = nullptr;
}
Function(const PIString & name, short args, FuncHanlder h) {
identifier = name;
arguments = args;
type = bfCustom;
handler = std::move(h);
}
PIString identifier;
BaseFunctions type;
FuncHanlder handler;
short arguments;
};
struct PIP_EXPORT Variable {
Variable() { value = 0.; }
Variable(const PIString & var_name, complexd val) {
name = var_name;
value = val;
}
PIString name;
complexd value;
};
} // namespace PIEvaluatorTypes
/*
≠ :
≥ }
≤ {
⋀ &
|
*/
class PIP_EXPORT PIEvaluatorContent {
friend class PIEvaluator;
BINARY_STREAM_FRIEND(PIEvaluatorContent);
public:
PIEvaluatorContent();
~PIEvaluatorContent() { ; }
void addFunction(const PIString & name, int args = 1);
int addVariable(const PIString & name, const complexd & val = 0.);
void addCustomFunction(const PIString & name, int args_count, PIEvaluatorTypes::FuncHanlder func);
int functionsCount() const { return functions.size(); }
int variablesCount() const { return variables.size(); }
int customVariablesCount() const;
int findFunction(const PIString & name) const;
int findVariable(const PIString & var_name) const;
PIEvaluatorTypes::Function function(int index);
PIEvaluatorTypes::Variable variable(int index);
PIEvaluatorTypes::Function function(const PIString & name) { return function(findFunction(name)); }
PIEvaluatorTypes::Variable variable(const PIString & name) { return variable(findVariable(name)); }
PIEvaluatorTypes::Variable customVariable(int index);
bool setVariableValue(int index, complexd new_value);
bool setVariableValue(const PIString & var_name, const complexd & new_value) {
return setVariableValue(findVariable(var_name), new_value);
}
bool setVariableName(int index, const PIString & new_name);
bool setVariableName(const PIString & var_name, const PIString & new_name) { return setVariableName(findVariable(var_name), new_name); }
void clearCustomVariables();
PIEvaluatorTypes::BaseFunctions getBaseFunction(const PIString & name);
void dump();
private:
PIVector<PIEvaluatorTypes::Function> functions;
PIVector<PIEvaluatorTypes::Variable> variables;
int cv_count;
};
//! \~\ingroup Math
//! \~\brief
//! \~english Expression evaluator with reusable compiled instructions.
//! \~russian Вычислитель выражений с повторно используемыми скомпилированными инструкциями.
//!
//! \~\details
//! \~english
//! The evaluator prepares an expression with \a check(), keeps the processed
//! form and instruction list, and then reevaluates it after variable updates.
//! Built-in constants include \c i, \c pi, and \c e.
//! \~russian
//! Вычислитель подготавливает выражение через \a check(), сохраняет
//! обработанную форму и список инструкций, а затем повторно вычисляет его
//! после обновления переменных. Встроенные константы: \c i, \c pi и \c e.
class PIP_EXPORT PIEvaluator {
public:
//! \~english Constructs an empty evaluator.
//! \~russian Создает пустой вычислитель.
PIEvaluator() {
correct = false;
data_ = 0;
}
//! \~english Destroys the evaluator.
//! \~russian Уничтожает вычислитель.
~PIEvaluator() { ; }
//! \~english Returns custom user data passed to callback functions.
//! \~russian Возвращает пользовательские данные, передаваемые в callback-функции.
void * data() { return data_; }
//! \~english Sets custom user data for callback functions.
//! \~russian Устанавливает пользовательские данные для callback-функций.
void setData(void * _data) { data_ = _data; }
//! \~english Checks and compiles an expression.
//! \~russian Проверяет и компилирует выражение.
bool check(const PIString & string);
//! \~english Returns true if the last \a check() succeeded.
//! \~russian Возвращает true, если последний вызов \a check() завершился успешно.
bool isCorrect() const { return correct; }
//! \~english Sets a named variable and creates it if needed.
//! \~russian Устанавливает именованную переменную и создает ее при необходимости.
int setVariable(const PIString & name, complexd value = complexd(0.));
//! \~english Sets a variable by index.
//! \~russian Устанавливает переменную по индексу.
void setVariable(int index, complexd value = 0.);
//! \~english Evaluates the last successfully compiled expression.
//! \~russian Вычисляет последнее успешно скомпилированное выражение.
complexd evaluate();
//! \~english Removes user-added variables and keeps built-in constants.
//! \~russian Удаляет добавленные пользователем переменные и сохраняет встроенные константы.
void clearCustomVariables() { content.clearCustomVariables(); }
//! \~english Returns variable index by name, or -1.
//! \~russian Возвращает индекс переменной по имени или -1.
int variableIndex(const PIString & name) const { return content.findVariable(name); }
//! \~english Returns unknown variables found during the last \a check().
//! \~russian Возвращает неизвестные переменные, найденные при последнем \a check().
const PIStringList & unknownVariables() const { return unknownVars; }
//! \~english Returns variables used in the last checked expression.
//! \~russian Возвращает переменные, использованные в последнем проверенном выражении.
const PIStringList & usedVariables() const { return usedVars; }
//! \~english Returns the normalized form of the last checked expression.
//! \~russian Возвращает нормализованную форму последнего проверенного выражения.
const PIString & expression() const { return currentString; }
//! \~english Returns the last status or error text from \a check().
//! \~russian Возвращает последний статус или текст ошибки из \a check().
const PIString & error() const { return lastError; }
//! \~english Returns the last evaluation result.
//! \~russian Возвращает последний результат вычисления.
const complexd & lastResult() const { return out; }
//! \~english Serializes evaluator state.
//! \~russian Сериализует состояние вычислителя.
PIByteArray save() const;
//! \~english Restores evaluator state from serialized data.
//! \~russian Восстанавливает состояние вычислителя из сериализованных данных.
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