/*! \file pievaluator.h * \brief Mathematic expressions calculator */ /* PIP - Platform Independent Primitives Evaluator designed for stream computing Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PIEVALUATOR_H #define PIEVALUATOR_H #include "pistring.h" #include "pimath.h" typedef complexd (*FuncFunc)(void * , int, complexd * ); namespace PIEvaluatorTypes { static const int operationCount = 14; 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, 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, bfCustom = 0xFFFF }; struct Instruction { Instruction() {;} Instruction(Operation oper, PIVector opers, int out_ind, int func = -1) { operation = oper; operators = opers; out = out_ind; function = func;} Operation operation; PIVector operators; int out; int function; }; struct Element { Element() {;} Element(eType new_type, int new_num, int new_var_num = -1) {set(new_type, new_num, new_var_num);} void set(eType new_type, int new_num, int new_var_num = -1) {type = new_type; num = new_num; var_num = new_var_num;} eType type; int num; int var_num; }; struct Function { Function() {arguments = 0; type = bfUnknown; handler = 0;} Function(const PIString & name, int args, BaseFunctions ftype) {identifier = name; arguments = args; type = ftype; handler = 0;} Function(const PIString & name, int args, FuncFunc h) {identifier = name; arguments = args; type = bfCustom; handler = h;} PIString identifier; BaseFunctions type; FuncFunc handler; int arguments; }; struct 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; public: PIEvaluatorContent(); ~PIEvaluatorContent() {;} void addFunction(const PIString & name, int args = 1) {functions.push_back(PIEvaluatorTypes::Function(name, args, getBaseFunction(name)));} void addVariable(const PIString & name, const complexd & val = 0.) {variables.push_back(PIEvaluatorTypes::Variable(name, val)); sortVariables();} void addCustomFunction(const PIString & name, int args_count, FuncFunc func) {functions << PIEvaluatorTypes::Function(name, args_count, func);} int functionsCount() const {return functions.size();} int variablesCount() const {return variables.size();} int customVariablesCount() const {return variables.size() - cv_count;} int findFunction(const PIString & name) const {for (uint i = 0; i < functions.size(); i++) if (functions[i].identifier == name) return i; return -1;} int findVariable(const PIString & var_name) const {for (uint i = 0; i < variables.size(); i++) if (variables[i].name == var_name) return i; return -1;} PIEvaluatorTypes::Function function(int index) {if (index < 0 || index >= functions.size_s()) return PIEvaluatorTypes::Function(); return functions[index];} PIEvaluatorTypes::Variable variable(int index) {if (index < 0 || index >= variables.size_s()) return PIEvaluatorTypes::Variable(); return variables[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) {if (index < cv_count || index >= variables.size_s() + cv_count) return PIEvaluatorTypes::Variable(); return variables[index + cv_count];} bool setVariableValue(int index, complexd new_value); bool setVariableName(int index, const PIString & new_name); bool setVariableValue(const PIString & var_name, const complexd & new_value) {return setVariableValue(findVariable(var_name), new_value);} bool setVariableName(const PIString & var_name, const PIString & new_name) {return setVariableName(findVariable(var_name), new_name);} void removeVariable(int index) {variables.remove(index);} void removeVariable(const PIString & var_name) {removeVariable(findVariable(var_name));} void clearCustomVariables(); void sortVariables(); PIEvaluatorTypes::BaseFunctions getBaseFunction(const PIString & name); 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 = 0.) {if (content.findVariable(name) < 0) content.addVariable(name, value); else content.setVariableValue(name, value); return content.findVariable(name);} //! 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.) {if (index >= 0 && index < content.variablesCount()) content.setVariableValue(index, value);} void setCustomVariableValue(int index, complexd value = 0.) {content.variables[index + content.cv_count].value = value;} /* //! Add function "name" with arguments count "args_count" and handler "func". Three arguments will be passed to handler: \a data(), "args_count" and array of input values. void addFunction(const PIString & name, int args_count, FuncFunc func) {content.addCustomFunction(name, args_count, func);} */ //! Evaluate last successfully checked with function \a check() expression and returns result complexd evaluate(); //! Remove variable with name "name" void removeVariable(const PIString & name) {content.removeVariable(name);} //! 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 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;} PIEvaluatorContent content; private: const PIString & prepare(const PIString & string); const 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); PIEvaluatorTypes::Operation operationInOrder(const int & index); complexd value(const int & index) {if (index < 0) return tmpvars[-index - 1].value; else return kvars->at(index).value;} inline complexd residue(const complexd & f, const complexd & s); inline void execFunction(const PIEvaluatorTypes::Instruction & ci); PIVector elements; PIVector currentVariables, variables, tmpvars, * kvars; PIVector instructions; PIStringList unknownVars; 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);} #endif // PIEVALUATOR_H