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

415 lines
12 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
//! \~english Mathematic expressions calculator
//! \~russian Вычислитель математических выражений
//! \details
//! \~english Evaluator for parsing and calculating mathematical expressions
//! \~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 = 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
/*
≠ :
≥ }
≤ {
⋀ &
|
*/
//! Content container for variables and functions
//! \~\english Container for variables and functions of the evaluator
//! \~russian Контейнер для переменных и функций вычислителя
class PIP_EXPORT PIEvaluatorContent {
friend class PIEvaluator;
BINARY_STREAM_FRIEND(PIEvaluatorContent);
public:
//! Constructs an empty evaluator content
PIEvaluatorContent();
~PIEvaluatorContent() { ; }
//! Add function with specified name and argument count
//! \~english Add function with name and default 1 argument
//! \~russian Добавить функцию с указанным именем и количеством аргументов (по умолчанию 1)
void addFunction(const PIString & name, int args = 1);
//! Add variable with specified name and value
//! \~english Add variable with name and optional value, returns variable index
//! \~russian Добавить переменную с указанным именем и значением, возвращает индекс переменной
int addVariable(const PIString & name, const complexd & val = 0.);
//! Add custom function with handler
//! \~english Add custom function with name, argument count and handler function
//! \~russian Добавить пользовательскую функцию с обработчиком
void addCustomFunction(const PIString & name, int args_count, PIEvaluatorTypes::FuncHanlder func);
//! Get number of functions
int functionsCount() const { return functions.size(); }
//! Get number of variables
int variablesCount() const { return variables.size(); }
//! Get number of custom variables
int customVariablesCount() const;
//! Find function index by name
int findFunction(const PIString & name) const;
//! Find variable index by name
int findVariable(const PIString & var_name) const;
//! Get function by index
PIEvaluatorTypes::Function function(int index);
//! Get variable by index
PIEvaluatorTypes::Variable variable(int index);
//! Get function by name
PIEvaluatorTypes::Function function(const PIString & name) { return function(findFunction(name)); }
//! Get variable by name
PIEvaluatorTypes::Variable variable(const PIString & name) { return variable(findVariable(name)); }
//! Get custom variable by index
PIEvaluatorTypes::Variable customVariable(int index);
//! Set variable value by index
//! \~english Set variable value by index, returns true on success
//! \~russian Установить значение переменной по индексу, возвращает true при успехе
bool setVariableValue(int index, complexd new_value);
//! Set variable value by name
//! \~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);
}
//! Set variable name by index
bool setVariableName(int index, const PIString & new_name);
//! Set variable name by name
bool setVariableName(const PIString & var_name, const PIString & new_name) { return setVariableName(findVariable(var_name), new_name); }
//! Clear all custom variables
void clearCustomVariables();
//! Get base function type by name
PIEvaluatorTypes::BaseFunctions getBaseFunction(const PIString & name);
//! Dump content to console for debugging
//! \~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 Главный класс для разбора и вычисления математических выражений
class PIP_EXPORT PIEvaluator {
public:
//! Constructs an empty evaluator
PIEvaluator() {
correct = false;
data_ = 0;
}
~PIEvaluator() { ; }
//! Returns custom data
void * data() { return data_; }
//! Set custom data to "_data"
void setData(void * _data) { data_ = _data; }
//! Check mathematical expression and parse it to list of instructions
bool check(const PIString & string);
//! Returns true if expression was checked succesfully
bool isCorrect() const { return correct; }
//! Set variable value with name "name" to value "value". Add variable if it doesn`t exists
int setVariable(const PIString & name, complexd value = complexd(0.));
//! Set variable value with index "index" to value "value". Don`t add variable if it doesn`t exists
void setVariable(int index, complexd value = 0.);
//! Evaluate last successfully checked with function \a check() expression and returns result
complexd evaluate();
//! Remove all manually added variables
void clearCustomVariables() { content.clearCustomVariables(); }
//! Returns index of variable with name "name"
int variableIndex(const PIString & name) const { return content.findVariable(name); }
//! Returns all unknown variables founded in last expression passed to \a check() function
const PIStringList & unknownVariables() const { return unknownVars; }
//! Returns all used variables founded in last expression passed to \a check() function
const PIStringList & usedVariables() const { return usedVars; }
//! Returns processed last expression passed to \a check() function
const PIString & expression() const { return currentString; }
//! Returns last error description occured in \a check() function
const PIString & error() const { return lastError; }
//! Returns last result of \a evaluate()
const complexd & lastResult() const { return out; }
//! Save to %PIByteArray evaluator state (expression, variables, errors, compiled instructions)
PIByteArray save() const;
//! Restore from %PIByteArray evaluator state (expression, variables, errors, compiled instructions)
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