Files
pip/libs/main/math/pievaluator.h
2022-07-25 11:18:09 +03:00

244 lines
9.1 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 Mathematic expressions calculator
* \~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 "pistringlist.h"
#include "pimathcomplex.h"
typedef complexd (*FuncFunc)(void * , int, complexd * );
namespace PIEvaluatorTypes {
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 = 0;}
Function(const PIString & name, short args, BaseFunctions ftype) {identifier = name; arguments = args; type = ftype; handler = 0;}
Function(const PIString & name, short args, FuncFunc h) {identifier = name; arguments = args; type = bfCustom; handler = h;}
PIString identifier;
BaseFunctions type;
FuncFunc 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;
};
}
/*
≠ :
≥ }
≤ {
⋀ &
|
*/
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, FuncFunc 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;
};
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