/*! \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 .
*/
#ifndef PIEVALUATOR_H
#define PIEVALUATOR_H
#include "pimathcomplex.h"
#include "pistringlist.h"
namespace PIEvaluatorTypes {
typedef std::function 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 opers, short out_ind, short func = -1) {
operation = oper;
operators = opers;
out = out_ind;
function = func;
}
Operation operation;
short out;
short function;
PIVector 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
/*
≠ :
≥ }
≤ {
⋀ &
⋁ |
*/
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 functions;
PIVector 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 & 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