/* PIP - Platform Independent Primitives Evaluator designed for stream computing Copyright (C) 2013 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 . */ #include "pievaluator.h" /*! \class PIEvaluator * \brief This class provide mathematical evaluations of custom expression * * \section PIEvaluator_sec0 Synopsis * %PIEvaluator developed for stream evaluations of once set expression. * It`s create internal list of instructions on function \a check() and * executes very fast on function \a evaluate(). Once given expression * can be evaluated any times with different variable values. Evaluator * supports many common mathematic functions described below. Also it`s * automatic puts unnecessarily signs and bracets. Processed expression * can be obtains with function \a expression(). If there is an error * in expression you can get it with function \a error(). Last evaluated * result you can get with function \a lastResult(). * \section PIEvaluator_sec1 Using * First you should set your variables with function \a setVariable(). * Next give your expression with function \a check() and check for error * with functions \a isCorrect() and \a error(). If expression is correct * you can get processed expression with function \a expression() and * evaluate it with function \a evaluate(). You can change variable values * without rechecking expression. * * \section PIEvaluator_sec2 Functions * %PIEvaluator supports arithmetical operations with complex numbers, this * is their list in priority order: * * ^ (power) * * * (multiply) * * / (divide) * * % (residue) * * + (add) * * - (subtract) * * In addition there are compare and logical operations: * * == (equal) * * != (not equal) * * > (greater) * * < (smaller) * * >= (greater or equal) * * <= (smaller or equal) * * && (and) * * || (or) * * Compare and logical functions works with real operators part and returns 0 or 1. * * Mathematical functions: * * sin(x) - sine * * cos(x) - cosine * * tg(x) - tangent * * ctg(x) - cotangent * * arcsin(x) - arcsine * * arccos(x) - arccosine * * arctg(x) -arccotangent * * arcctg(x) - arctangent * * sh(x) - hyperbolical sine * * ch(x) - hyperbolical cosine * * th(x) - hyperbolical tangent * * cth(x) - hyperbolical cotangent * * sqr(x) - square * * sqrt(x) - square root * * abs(x) - absolute value * * sign(x) - sign of real part (-1 or 1) * * exp(x) - exponent * * pow(x, p) - x in power p * * ln(x) - natural logarithm * * lg(x) - decimal logarithm * * log(x, b) - logarithm of x with base b * * im(x) - imaginary part of complex number * * re(x) - real part of complex number * * arg(x) - argument of complex number * * len(x) - length of complex number * * conj(x) - length of complex number * * rad(x) - convert degrees to radians * * deg(x) - convert radians to degrees * * j0(x) - Bessel function first kind order 0 * * j1(x) - Bessel function first kind order 1 * * jn(x, n) - Bessel function first kind order n * * y0(x) - Bessel function second kind order 0 * * y1(x) - Bessel function second kind order 1 * * yn(x, n) - Bessel function second kind order n * * random(s, f) - regular random number in range [s, f] * * min(x0, x1, ...) - minimum of x0, x1, ... * * max(x0, x1, ...) - maximum of x0, x1, ... * * clamp(x, a, b) - trim x on range [a, b] * * step(x, s) - 0 if x < s, else 1 * * mix(x, a, b) - interpolate between a and b linear for x (a * (1 - x) + b * x) * * There are some built-in constans: * * i (imaginary 1) * * e * * pi * * All trigonometric functions takes angle in radians. * * \section PIEvaluator_sec3 Example * \snippet pievaluator.cpp main */ PIEvaluatorContent::PIEvaluatorContent() { addFunction("arcsin", 1); addFunction("arccos", 1); addFunction("arctg", 1); addFunction("arcctg", 1); addFunction("random", 2); addFunction("sin", 1); addFunction("cos", 1); addFunction("ctg", 1); addFunction("tg", 1); addFunction("exp", 1); addFunction("cth", 1); addFunction("sh", 1); addFunction("ch", 1); addFunction("th", 1); addFunction("sqrt", 1); addFunction("sqr", 1); addFunction("pow", 2); addFunction("abs", 1); addFunction("ln", 1); addFunction("lg", 1); addFunction("log", 2); addFunction("im", 1); addFunction("re", 1); addFunction("arg", 1); addFunction("len", 1); addFunction("conj", 1); addFunction("sign", 1); addFunction("rad", 1); addFunction("deg", 1); addFunction("j0", 1); addFunction("j1", 1); addFunction("jn", 2); addFunction("y0", 1); addFunction("y1", 1); addFunction("yn", 2); addFunction("min", -2); // (x0,x1,...) addFunction("max", -2); // (x0,x1,...) addFunction("clamp", 3); // (x,a,b) = x < a ? a : (x > b ? b : x) addFunction("step", 2); // (x,s) = x >= s ? 1. : 0. (1 if 'x' >= 's', else 0) addFunction("mix", 3); // (x,a,b) = a*(1.-x) + b*x (interpolate between 'a' and 'b' linear for 'x') clearCustomVariables(); //addVariable("n", 0.); //addVariable("x1", 123); } bool PIEvaluatorContent::setVariableValue(int index, complexd new_value) { if (index < 0 || index >= variables.size_s()) return false; variables[index].value = new_value; return true; } bool PIEvaluatorContent::setVariableName(int index, const PIString & new_name) { if (index < 0 || index >= variables.size_s()) return false; variables[index].name = new_name; return true; } void PIEvaluatorContent::clearCustomVariables() { variables.clear(); addVariable("i", complexd_i); addVariable("pi", atan(1.) * 4.); addVariable("e", exp(1.)); cv_count = variables.size(); } void PIEvaluatorContent::sortVariables() { PIEvaluatorTypes::Variable tv; for (uint i = 0; i < variables.size(); i++) { for (uint j = variables.size() - 1; j > i; j--) { if (variables[j].name.length() <= variables[i].name.length()) continue; piSwap(variables[i], variables[j]); } } /* * qDebug() << "---"; * for (int i = 0; i < variables.size(); i++) { * qDebug() << variables[i].name; } */ } PIEvaluatorTypes::BaseFunctions PIEvaluatorContent::getBaseFunction(const PIString & name) { if (name == "sin") return PIEvaluatorTypes::bfSin; if (name == "cos") return PIEvaluatorTypes::bfCos; if (name == "tg") return PIEvaluatorTypes::bfTg; if (name == "ctg") return PIEvaluatorTypes::bfCtg; if (name == "arcsin") return PIEvaluatorTypes::bfArcsin; if (name == "arccos") return PIEvaluatorTypes::bfArccos; if (name == "arctg") return PIEvaluatorTypes::bfArctg; if (name == "arcctg") return PIEvaluatorTypes::bfArcctg; if (name == "exp") return PIEvaluatorTypes::bfExp; if (name == "random") return PIEvaluatorTypes::bfRandom; if (name == "sh") return PIEvaluatorTypes::bfSh; if (name == "ch") return PIEvaluatorTypes::bfCh; if (name == "th") return PIEvaluatorTypes::bfTh; if (name == "cth") return PIEvaluatorTypes::bfCth; if (name == "sqrt") return PIEvaluatorTypes::bfSqrt; if (name == "sqr") return PIEvaluatorTypes::bfSqr; if (name == "pow") return PIEvaluatorTypes::bfPow; if (name == "abs") return PIEvaluatorTypes::bfAbs; if (name == "ln") return PIEvaluatorTypes::bfLn; if (name == "lg") return PIEvaluatorTypes::bfLg; if (name == "log") return PIEvaluatorTypes::bfLog; if (name == "im") return PIEvaluatorTypes::bfIm; if (name == "re") return PIEvaluatorTypes::bfRe; if (name == "arg") return PIEvaluatorTypes::bfArg; if (name == "len") return PIEvaluatorTypes::bfLen; if (name == "conj") return PIEvaluatorTypes::bfConj; if (name == "sign") return PIEvaluatorTypes::bfSign; if (name == "rad") return PIEvaluatorTypes::bfRad; if (name == "deg") return PIEvaluatorTypes::bfDeg; if (name == "j0") return PIEvaluatorTypes::bfJ0; if (name == "j1") return PIEvaluatorTypes::bfJ1; if (name == "jn") return PIEvaluatorTypes::bfJN; if (name == "y0") return PIEvaluatorTypes::bfY0; if (name == "y1") return PIEvaluatorTypes::bfY1; if (name == "yn") return PIEvaluatorTypes::bfYN; if (name == "min") return PIEvaluatorTypes::bfMin; if (name == "max") return PIEvaluatorTypes::bfMax; if (name == "clamp") return PIEvaluatorTypes::bfClamp; if (name == "step") return PIEvaluatorTypes::bfStep; if (name == "mix") return PIEvaluatorTypes::bfMix; return PIEvaluatorTypes::bfUnknown; } const PIString & PIEvaluator::prepare(const PIString & string) { currentString = string.trimmed(); if (currentString.isEmpty()) currentString = "0"; replaceOperators(); removeSpaces(); checkBrackets(); while (fillElements()) checkBrackets(); while (setSignes()) fillElements(); removeJunk(); findUnknownVariables(); return currentString; } void PIEvaluator::removeSpaces() { PIString tmps = currentString; for (int i = 0; i < tmps.length(); i++) { if (tmps[i] == ' ' || tmps[i] == '\t') { tmps.remove(i, 1); i--; } } currentString = tmps; } void PIEvaluator::removeJunk() { PIChar cc; bool junk = true; int bcnt; while (junk) { if (currentString.left(1) != "(" || currentString.right(1) != ")") return; bcnt = 1; junk = false; for (int i = 1; i < currentString.length(); i++) { cc = currentString[i]; if (cc == '(') bcnt++; if (cc == ')') bcnt--; if (bcnt == 0) { if (i == currentString.length() - 1) { currentString = currentString.mid(1, currentString.length() - 2); elements.pop_front(); elements.pop_back(); junk = true; break; } else break; } } } } void PIEvaluator::replaceOperators() { currentString.replaceAll("==", "="); currentString.replaceAll("!=", ":"); currentString.replaceAll(">=", "}"); currentString.replaceAll("<=", "{"); currentString.replaceAll("&&", "&"); currentString.replaceAll("||", "|"); } void PIEvaluator::makeOutput(PIString & string) { string.replaceAll(":", "≠"); string.replaceAll("}", "≥"); string.replaceAll("{", "≤"); string.replaceAll("&", "⋀"); string.replaceAll("|", "⋁"); } void PIEvaluator::findUnknownVariables() { PIString cvar; unknownVars.clear(); for (int i = 0; i < currentString.length(); i++) { if (elements[i].var_num == -666) cvar += currentString[i]; else { if (cvar.length() == 0) continue; unknownVars << cvar; cvar = ""; } } if (cvar.length() > 0) unknownVars << cvar; unknownVars.removeDuplicates(); } bool PIEvaluator::isSign(const PIChar & ch) { return ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%' || ch == '^' || ch == '=' || ch == ':' || ch == '>' || ch == '<' || ch == '}' || ch == '{' || ch == '&' || ch == '|'; } void PIEvaluator::checkBrackets() { PIString tmps = currentString; PIChar fc, sc; int bcnt = 0, bpos = 0, inserted = 0; currentString = tmps; for (int i = 0; i < tmps.length(); i++) { if (tmps[i] == '(') { if (bcnt == 0) bpos = i; bcnt++; } if (tmps[i] == ')') { if (bcnt == 0) { currentString.insert(bpos + inserted, "("); inserted++; } else bcnt--; } } if (bcnt > 0) currentString += PIString(bcnt, ')'); tmps = currentString; for (int i = 0; i < tmps.length() - 1; i++) { fc = tmps[i].toLower(); sc = tmps[i + 1].toLower(); if ((fc == ')' && sc == '(') || (fc == ')' && sc >= '0' && sc <= '9') || (fc == ')' && sc >= 'a' && sc <= 'z') ) tmps.insert(++i, '*'); } currentString = tmps; } bool PIEvaluator::fillElements() { int fstart, flen, cnum = 0, cpart = 0, cfunc; PIChar cc, nc, pc, fc = '!'; bool numFound = false; PIString curfind, tmps = currentString; elements.resize(tmps.length()); for (uint i = 0; i < elements.size(); i++) { elements[i].type = PIEvaluatorTypes::etVariable; elements[i].var_num = -666; } currentVariables.clear(); //qDebug().nospace() << "search for functions ..."; for (int i = 0; i < content.functionsCount(); i++) { curfind = content.function(i).identifier; cfunc = i; //(int)content.function(i).type; flen = curfind.length(); fstart = 0; while (fstart >= 0) { fstart = tmps.find(curfind, fstart); if (fstart < 0) break; if (tmps[fstart + flen] != '(') { currentString.insert(fstart + flen, "("); return true; } for (int j = fstart; j < fstart + flen; j++) { elements[j].set(PIEvaluatorTypes::etFunction, cnum, cfunc); tmps.replace(j, 1, fc); } cnum++; } } cnum = 0; //qDebug().nospace() << "search for variables ..."; for (int i = 0; i < content.variablesCount(); i++) { curfind = content.variable(i).name; flen = curfind.length(); fstart = 0; while (fstart >= 0) { fstart = tmps.find(curfind, fstart); if (fstart < 0) break; for (int j = fstart; j < fstart + flen; j++) { elements[j].set(PIEvaluatorTypes::etVariable, cnum, i); tmps.replace(j, 1, fc); } cnum++; } } curfind = ""; cnum = 1; //qDebug().nospace() << "search for numbers ..."; for (int i = 0; i < tmps.length(); i++) { cc = tmps[i]; /*if (cc == " " || cc == "(" || cc == ")") { curfind = ""; cpart = 0; numFound = false; continue; }*/ switch (cpart) { case 0: if ((cc >= '0' && cc <= '9')) {// || cc == '-' || cc == '+') { curfind += cc; cpart = 1; continue; } if (cc == '.') { curfind += cc; cpart = 2; continue; } if (cc == 'E') { curfind += cc; cpart = 3; continue; } break; case 1: if (cc >= '0' && cc <= '9') { curfind += cc; continue; } if (cc == '.') { curfind += cc; cpart = 2; continue; } if (cc == 'E') { curfind += cc; cpart = 3; continue; } numFound = true; break; case 2: if (cc >= '0' && cc <= '9') { curfind += cc; continue; } if (cc == 'E') { curfind += cc; cpart = 3; continue; } numFound = true; break; case 3: if ((cc >= '0' && cc <= '9') || cc == '-' || cc == '+') { curfind += cc; cpart = 4; continue; } numFound = true; break; case 4: if (cc >= '0' && cc <= '9') { curfind += cc; continue; } numFound = true; break; } if (numFound) { //qDebug().nospace() << "add " << cnum << ": " << curfind << " = " << curfind.toDouble(); currentVariables.push_back(PIEvaluatorTypes::Variable("tmp" + PIString::fromNumber(cnum), curfind.toDouble())); for (int j = i - curfind.length(); j < i; j++) { elements[j].set(PIEvaluatorTypes::etNumber, cnum, -cnum); tmps.replace(j, 1, fc); } curfind = ""; cnum++; cpart = 0; numFound = false; } } if (cpart > 0) { //qDebug().nospace() << "add " << cnum << ": " << curfind << " = " << curfind.toDouble(); currentVariables.push_back(PIEvaluatorTypes::Variable("tmp" + PIString::fromNumber(cnum), curfind.toDouble())); for (int j = tmps.length() - curfind.length(); j < tmps.length(); j++) { elements[j].set(PIEvaluatorTypes::etNumber, cnum, -cnum); tmps.replace(j, 1, fc); } } cc = nc = fc; //qDebug().nospace() << "search for signes ..."; for (int i = 0; i < tmps.length(); i++) { cc = tmps[i]; if (i > 0) pc = tmps[i - 1]; else pc = fc; if (i < tmps.length() - 1) nc = tmps[i + 1]; else nc = fc; if (cc == '(' || cc == ')' || cc == ',') { elements[i].set(PIEvaluatorTypes::etOperator, -1); continue; } if (cc == '-' || cc == '+') { elements[i].set(PIEvaluatorTypes::etOperator, -1); if (i < tmps.length() - 1) if (elements[i + 1].type == PIEvaluatorTypes::etVariable || elements[i + 1].type == PIEvaluatorTypes::etFunction) continue; if ((pc == '(' || isSign(pc) || i == 0) && i < tmps.length() - 1) { if (elements[i + 1].type != PIEvaluatorTypes::etOperator) { cnum = elements[i + 1].num; elements[i].set(PIEvaluatorTypes::etNumber, cnum); tmps.replace(i, 1, fc); ///cout << "found sign " << cc << " :" << cnum - 1 << endl; if (cc == '-' && currentVariables.size_s() >= cnum) currentVariables[cnum - 1].value = -currentVariables[cnum - 1].value; //i++; continue; } } } if (isSign(cc)) { elements[i].set(PIEvaluatorTypes::etOperator, -1); continue; } } /* qDebug().nospace() << tmps; cout << " "; for (int i = 0; i < elements.size(); i++) { switch (elements[i].type) { case etFunction: cout << "f"; break; case etNumber: cout << "n"; break; case etOperator: cout << "o"; break; case etVariable: cout << "v"; break; } } cout << endl; */ return false; //for (int i = 0; i < currentVariables.size(); i++) qDebug() << "var " << i << ": " << currentVariables[i].value.real(); } bool PIEvaluator::setSignes() { int inserted = 0, ni, pi = 0, needInsert = 0; PIChar fc, sc, pc; PIString tmps = currentString; for (int i = 0; i < tmps.length() - 1; i++) { needInsert = 0; ni = i + 1; if (i > 0) pi = i - 1; fc = tmps[i].toLower(); sc = tmps[ni].toLower(); pc = tmps[pi].toLower(); //if (elements[i].type == etOperator || elements[ni].type == etVariable) continue; if (fc == ',' || sc == ',') continue; if (elements[i].type == PIEvaluatorTypes::etOperator && elements[ni].type == PIEvaluatorTypes::etOperator) continue; if (fc == ')' && (elements[ni].type == PIEvaluatorTypes::etNumber || elements[ni].type == PIEvaluatorTypes::etVariable || elements[ni].type == PIEvaluatorTypes::etFunction)) needInsert = 1; if (sc == '(' && (elements[i].type == PIEvaluatorTypes::etNumber || elements[i].type == PIEvaluatorTypes::etVariable)) needInsert = 1; if (elements[i].type == PIEvaluatorTypes::etNumber && elements[ni].type == PIEvaluatorTypes::etNumber && elements[i].num != elements[ni].num) needInsert = 1; if (elements[i].type == PIEvaluatorTypes::etVariable && elements[ni].type == PIEvaluatorTypes::etVariable && elements[i].num != elements[ni].num) needInsert = 1; if ((elements[i].type == PIEvaluatorTypes::etNumber && elements[ni].type == PIEvaluatorTypes::etVariable) || (elements[i].type == PIEvaluatorTypes::etVariable && elements[ni].type == PIEvaluatorTypes::etNumber)) needInsert = 1; if ((elements[i].type == PIEvaluatorTypes::etNumber || elements[i].type == PIEvaluatorTypes::etVariable) && elements[ni].type == PIEvaluatorTypes::etFunction) needInsert = 1; if (elements[i].type == PIEvaluatorTypes::etFunction && elements[ni].type == PIEvaluatorTypes::etFunction && elements[i].num != elements[ni].num) needInsert = 2; if (elements[i].type == PIEvaluatorTypes::etFunction && elements[ni].type != PIEvaluatorTypes::etFunction && sc != '(') needInsert = 2; if (elements[pi].type == PIEvaluatorTypes::etOperator && (elements[ni].type == PIEvaluatorTypes::etFunction || elements[ni].type == PIEvaluatorTypes::etVariable) && fc == '-') needInsert = 3; switch (needInsert) { case 1: currentString.insert(ni + inserted, "*"); elements.insert(ni + inserted, PIEvaluatorTypes::Element(PIEvaluatorTypes::etOperator, -1)); //inserted++; //i++; return true; /*case 2: currentString.insert(ni + inserted, ")"); currentString.insert(ni + inserted, "("); elements.insert(ni + inserted, Element(etOperator, -1)); elements.insert(ni + inserted, Element(etOperator, -1)); inserted++; i++; return true;*/ case 3: currentString.insert(ni + inserted, "1*"); elements.insert(ni + inserted, PIEvaluatorTypes::Element(PIEvaluatorTypes::etOperator, -1)); //inserted; //i++; return true; } } /*if (elements[tmps.length() - 1].type == etFunction) { currentString.insert(tmps.length() + inserted, ")"); currentString.insert(tmps.length() + inserted, "("); elements.insert(tmps.length() + inserted, Element(etOperator, -1)); elements.insert(tmps.length() + inserted, Element(etOperator, -1)); return true; }*/ return false; } void PIEvaluator::convert() { int j; PIEvaluatorTypes::Element ce, pe; for (int i = 0; i < currentString.length(); i++) { pe = elements[i]; if (pe.type != PIEvaluatorTypes::etFunction) continue; j = i + 1; while (j < currentString.length()) { ce = elements[j]; if (ce != pe) break; j++; } currentString.replace(i, j - i, " "); for (int k = i + 1; k < j; k++) elements.remove(i); //i++; } for (int i = 0; i < currentString.length(); i++) { pe = elements[i]; if (pe.type != PIEvaluatorTypes::etNumber) continue; j = i + 1; while (j < currentString.length()) { ce = elements[j]; if (ce != pe) break; j++; } currentString.replace(i, j - i, " "); for (int k = i + 1; k < j; k++) elements.remove(i); //i++; } for (int i = 0; i < currentString.length(); i++) { pe = elements[i]; if (pe.type != PIEvaluatorTypes::etVariable) continue; j = i + 1; while (j < currentString.length()) { ce = elements[j]; if (ce != pe) break; j++; } currentString.replace(i, j - i, " "); for (int k = i + 1; k < j; k++) elements.remove(i); //i++; } /*qDebug().nospace() << currentString; cout << " "; for (int i = 0; i < elements.size(); i++) { switch (elements[i].type) { case etFunction: cout << "f"; break; case etNumber: cout << "n"; break; case etOperator: cout << "o"; break; case etVariable: cout << "v"; break; } } cout << endl;*/ } const PIString & PIEvaluator::preprocess(const PIString & string) { static PIString ret; int lind; ret = prepare(string); convert(); instructions.clear(); //qDebug() << preproc->currentString; variables = currentVariables; lind = parse(currentString); if (instructions.size() == 0) { variables.push_back(PIEvaluatorTypes::Variable()); instructions.push_back(PIEvaluatorTypes::Instruction(PIEvaluatorTypes::oNone, PIVector(1, lind), -variables.size_s())); } kvars = &(content.variables); /* cout << endl << "variables:" << endl; for (int i = 0; i < variables.size(); i++) cout << i << " value = " << variables[i].value << endl; cout << endl << "instructions:" << endl; for (int i = 0; i < instructions.size(); i++) { cout << i << endl; cout << " operation " << instructions[i].operation << endl; cout << " operators: "; for (int j = 0; j < instructions[i].operators.size(); j++) cout << instructions[i].operators[j] << "; "; cout << endl << " function " << instructions[i].function << endl; cout << " out " << instructions[i].out << endl; } */ makeOutput(ret); return ret; } PIEvaluatorTypes::Operation PIEvaluator::operationInOrder(const int & index) { switch (index) { case 0: return PIEvaluatorTypes::oPower; case 1: return PIEvaluatorTypes::oMultiply; case 2: return PIEvaluatorTypes::oDivide; case 3: return PIEvaluatorTypes::oResidue; case 4: return PIEvaluatorTypes::oAdd; case 5: return PIEvaluatorTypes::oSubtract; case 6: return PIEvaluatorTypes::oEqual; case 7: return PIEvaluatorTypes::oNotEqual; case 8: return PIEvaluatorTypes::oGreaterEqual; case 9: return PIEvaluatorTypes::oSmallerEqual; case 10: return PIEvaluatorTypes::oGreater; case 11: return PIEvaluatorTypes::oSmaller; case 12: return PIEvaluatorTypes::oAnd; case 13: return PIEvaluatorTypes::oOr; default: return PIEvaluatorTypes::oNone; } } int PIEvaluator::parse(const PIString & string, int offset) { int slen = string.length(), /*facnt,*/ farg, bcnt, k; PIChar cc; PIEvaluatorTypes::Element ce; PIEvaluatorTypes::Function cfunc; PIEvaluatorTypes::Operation coper; PIString sbrackets, carg; PIVector args, atmp; PIVector opers; ///qDebug() << "to parse :" + string; ///cout << " "; for (int i = 0; i < slen; i++) cout << preproc->elements[i + offset].type; cout << endl; for (int i = 0; i < slen; i++) { ce = elements[i + offset]; cc = string[i]; switch (ce.type) { case PIEvaluatorTypes::etNumber: args.push_back(ce.var_num); continue; case PIEvaluatorTypes::etVariable: args.push_back(ce.var_num); continue; case PIEvaluatorTypes::etFunction: i++; cfunc = content.function(ce.var_num); //facnt = cfunc.arguments; atmp.clear(); bcnt = farg = 1; ///qDebug() << "function: " + cfunc.identifier; //for (int k = 0; k < facnt; k++) { bcnt = 1; carg = ""; k = i + 1; //if (string.size_s() <= k || k < 0) return -666; while (bcnt > 0) { //if (k < facnt - 1) fcomma = string.indexOf(',', j); cc = string[k]; switch (cc.toAscii()) { case '(': bcnt++; break; case ')': bcnt--; if (bcnt == 0) { ///qDebug() << "arument: " << carg; atmp.push_back(parse(carg, k + offset - carg.length())); k++; carg = ""; if (atmp.size_s() > 0) if (atmp.back() < 0 && farg > 0) farg = atmp.back(); continue; } break; case ',': if (bcnt == 1) { ///qDebug() << "arument: " << carg; atmp.push_back(parse(carg, k + offset - carg.length())); k++; carg = ""; if (atmp.size_s() > 0) if (atmp.back() < 0 && farg > 0) farg = atmp.back(); continue; } break; } carg += cc; k++; } i = k - 1; if (farg > 0) { variables.push_back(PIEvaluatorTypes::Variable()); farg = -variables.size_s(); } instructions.push_back(PIEvaluatorTypes::Instruction(PIEvaluatorTypes::oFunction, atmp, farg, ce.var_num)); args.push_back(farg); //for (int i = 0; i < args.size_s(); i++) cout << preproc->currentVariables[-args[i]].value << endl; //i = j + 1; continue; case PIEvaluatorTypes::etOperator: //qDebug() << "operator: " << cc; if (cc == '(') { sbrackets = inBrackets(string.right(slen - i)); args.push_back(parse(sbrackets, i + offset + 1)); i += sbrackets.length() + 1; continue; } if (cc == '+') {opers.push_back(PIEvaluatorTypes::oAdd); continue;} if (cc == '-') {opers.push_back(PIEvaluatorTypes::oSubtract); continue;} if (cc == '*') {opers.push_back(PIEvaluatorTypes::oMultiply); continue;} if (cc == '/') {opers.push_back(PIEvaluatorTypes::oDivide); continue;} if (cc == '%') {opers.push_back(PIEvaluatorTypes::oResidue); continue;} if (cc == '^') {opers.push_back(PIEvaluatorTypes::oPower); continue;} if (cc == '=') {opers.push_back(PIEvaluatorTypes::oEqual); continue;} if (cc == ':') {opers.push_back(PIEvaluatorTypes::oNotEqual); continue;} if (cc == '}') {opers.push_back(PIEvaluatorTypes::oGreaterEqual); continue;} if (cc == '{') {opers.push_back(PIEvaluatorTypes::oSmallerEqual); continue;} if (cc == '>') {opers.push_back(PIEvaluatorTypes::oGreater); continue;} if (cc == '<') {opers.push_back(PIEvaluatorTypes::oSmaller); continue;} if (cc == '&') {opers.push_back(PIEvaluatorTypes::oAnd); continue;} if (cc == '|') {opers.push_back(PIEvaluatorTypes::oOr); continue;} } } /* cout << "stack: " << endl << "args: "; for (int i = 0; i < args.size_s(); i++) cout << args[i] << ", "; cout << endl << "opers: "; for (int i = 0; i < opers.size_s(); i++) cout << opers[i] << ", "; */ if (opers.size_s() == 0) { if (args.size_s() > 0) return args.back(); else return -666; } for (int i = 0; i < PIEvaluatorTypes::operationCount; i++) { coper = operationInOrder(i); for (int j = 0; j < opers.size_s(); j++) { if (coper == PIEvaluatorTypes::oDivide || coper == PIEvaluatorTypes::oMultiply) { if (opers[j] != PIEvaluatorTypes::oDivide && opers[j] != PIEvaluatorTypes::oMultiply) continue; } else { if (opers[j] != coper) continue; } atmp.clear(); if (j < args.size_s() && j >= 0) atmp.push_back(args[j]); else atmp.push_back(-666); if (j + 1 < args.size_s() && j >= -1) atmp.push_back(args[j + 1]); else atmp.push_back(-666); farg = 1; if (atmp[0] < 0) farg = atmp[0]; else { if (atmp[1] < 0) farg = atmp[1]; else { variables.push_back(PIEvaluatorTypes::Variable()); farg = -variables.size_s(); } } instructions.push_back(PIEvaluatorTypes::Instruction(opers[j], atmp, farg)); if (j >= 0 && j < args.size_s()) { args.remove(j); if (j < args.size_s()) args[j] = farg; } opers.remove(j); j--; } } return instructions.back().out; ///cout << endl; } bool PIEvaluator::check() { PIEvaluatorTypes::Instruction ci; bool error; if (unknownVars.size_s() > 0) { lastError = "Unknown variables: \"" + unknownVars.join("\", \"") + "\""; return false; } for (int i = 0; i < instructions.size_s(); i++) { error = false; ci = instructions[i]; PIEvaluatorTypes::Function cf; int fac, gac; switch (ci.operation) { case PIEvaluatorTypes::oNone: break; case PIEvaluatorTypes::oFunction: cf = content.function(ci.function); fac = cf.arguments; gac = ci.operators.size_s(); for (int j = 0; j < ci.operators.size_s(); j++) { if (ci.operators[j] == -666) { //(ci.operators[j] < -variables.size_s() || ci.operators[j] >= kvars->size()) { error = true; gac--; } } if (fac > 0) { if (gac != fac) { lastError = "Invalid arguments count for function \"" + cf.identifier + "\", expected " + PIString::fromNumber(fac) + " but " + PIString::fromNumber(gac) + " given"; return false; } if (error) { lastError = "Invalid at least one of function \"" + cf.identifier + "\" argument"; return false; } } if (fac < 0) { if (gac < -fac) { lastError = "Invalid arguments count for function \"" + cf.identifier + "\", expected at least " + PIString::fromNumber(-fac) + " but " + PIString::fromNumber(gac) + " given"; return false; } if (error) { lastError = "Invalid at least one of function \"" + cf.identifier + "\" argument"; return false; } } break; default: if (ci.operators[0] == -666 || ci.operators[1] == -666) error = true; if (ci.operators.size_s() != 2 || error) { lastError = "Invalid arguments count for operation \" " + operationChar(ci.operation) + " \""; return false; } break; } if (ci.out < -variables.size_s()) { lastError = "Invalid variable index \"" + PIString::fromNumber(ci.out) + "\""; return false; } for (int j = 0; j < ci.operators.size_s(); j++) { if (ci.operators[j] < -variables.size_s() || ci.operators[j] >= kvars->size_s()) { lastError = "Invalid variable index \"" + PIString::fromNumber(ci.operators[j]) + "\""; return false; } } } return true; } PIString PIEvaluator::inBrackets(const PIString & string) { int slen = string.length(), bcnt = 0; PIChar cc; for (int i = 0; i < slen; i++) { cc = string[i]; if (cc == '(') bcnt++; if (cc == ')') { bcnt--; if (bcnt == 0) return string.mid(1, i - 1); } } return PIString(); } PIString PIEvaluator::operationChar(const PIEvaluatorTypes::Operation & operation) { switch (operation) { case PIEvaluatorTypes::oAdd: return "+"; case PIEvaluatorTypes::oSubtract: return "-"; case PIEvaluatorTypes::oMultiply: return "*"; case PIEvaluatorTypes::oDivide: return "/"; case PIEvaluatorTypes::oPower: return "^"; case PIEvaluatorTypes::oResidue: return "%"; case PIEvaluatorTypes::oEqual: return "="; case PIEvaluatorTypes::oNotEqual: return ("≠"); case PIEvaluatorTypes::oGreaterEqual: return ("≥"); case PIEvaluatorTypes::oSmallerEqual: return ("≤"); case PIEvaluatorTypes::oGreater: return ">"; case PIEvaluatorTypes::oSmaller: return "<"; case PIEvaluatorTypes::oAnd: return ("⋀"); case PIEvaluatorTypes::oOr: return ("⋁"); default: return "???"; } } inline complexd PIEvaluator::residue(const complexd & f, const complexd & s) { complexd ret; if (s.real() != 0.) ret = complexd(f.real() - ((int)(f.real() / s.real())) * s.real(), 0.); if (s.imag() != 0.) ret = complexd(ret.real(), f.imag() - ((int)(f.imag() / s.imag())) * s.imag()); return ret; } inline void PIEvaluator::execFunction(const PIEvaluatorTypes::Instruction & ci) { PIEvaluatorTypes::Function cfunc = content.function(ci.function); int oi = -ci.out - 1; complexd tmp, stmp, ttmp; //qDebug() << "function " << (int)cfunc.type; switch (cfunc.type) { case PIEvaluatorTypes::bfSin: tmpvars[oi].value = sin(value(ci.operators[0])); break; case PIEvaluatorTypes::bfCos: tmpvars[oi].value = cos(value(ci.operators[0])); break; case PIEvaluatorTypes::bfTg: tmpvars[oi].value = tan(value(ci.operators[0])); break; case PIEvaluatorTypes::bfCtg: tmp = tan(value(ci.operators[0])); if (tmp == complexd_0) tmpvars[oi].value = 0.; else tmpvars[oi].value = complexd_1 / tmp; break; case PIEvaluatorTypes::bfArcsin: tmpvars[oi].value = asinc(value(ci.operators[0])); break; case PIEvaluatorTypes::bfArccos: tmpvars[oi].value = acosc(value(ci.operators[0])); break; case PIEvaluatorTypes::bfArctg: tmpvars[oi].value = atanc(value(ci.operators[0])); break; case PIEvaluatorTypes::bfArcctg: tmp = atanc(value(ci.operators[0])); if (tmp == complexd_0) tmpvars[oi].value = 0.; else tmpvars[oi].value = complexd_1 / tmp; break; case PIEvaluatorTypes::bfSh: tmpvars[oi].value = sinh(value(ci.operators[0])); break; case PIEvaluatorTypes::bfCh: tmpvars[oi].value = cosh(value(ci.operators[0])); break; case PIEvaluatorTypes::bfTh: tmpvars[oi].value = tanh(value(ci.operators[0])); break; case PIEvaluatorTypes::bfCth: tmp = tanh(value(ci.operators[0])); if (tmp == complexd_0) tmpvars[oi].value = 0.; else tmpvars[oi].value = complexd_1 / tmp; break; case PIEvaluatorTypes::bfAbs: tmpvars[oi].value = abs(value(ci.operators[0])); break; case PIEvaluatorTypes::bfSqrt: tmpvars[oi].value = sqrt(value(ci.operators[0])); break; case PIEvaluatorTypes::bfSqr: tmpvars[oi].value = value(ci.operators[0]) * value(ci.operators[0]); break; case PIEvaluatorTypes::bfExp: tmpvars[oi].value = exp(value(ci.operators[0])); break; case PIEvaluatorTypes::bfPow: tmpvars[oi].value = pow(value(ci.operators[0]), value(ci.operators[1])); break; case PIEvaluatorTypes::bfLn: tmpvars[oi].value = log(value(ci.operators[0])); break; case PIEvaluatorTypes::bfLg: tmpvars[oi].value = log10(value(ci.operators[0])); break; case PIEvaluatorTypes::bfLog: tmp = log(value(ci.operators[1])); if (tmp == complexd_0) tmpvars[oi].value = 0.; else tmpvars[oi].value = log(value(ci.operators[0])) / tmp; break; case PIEvaluatorTypes::bfRe: tmpvars[oi].value = value(ci.operators[0]).real(); break; case PIEvaluatorTypes::bfIm: tmpvars[oi].value = value(ci.operators[0]).imag(); break; case PIEvaluatorTypes::bfArg: tmpvars[oi].value = arg(value(ci.operators[0])); break; case PIEvaluatorTypes::bfLen: tmpvars[oi].value = abs(value(ci.operators[0])); break; case PIEvaluatorTypes::bfConj: tmpvars[oi].value = conj(value(ci.operators[0])); break; case PIEvaluatorTypes::bfSign: tmpvars[oi].value = value(ci.operators[0]).real() >= 0. ? complexd_1 : -complexd_1; break; case PIEvaluatorTypes::bfRad: tmpvars[oi].value = value(ci.operators[0]) * complexd(deg2rad, 0.); break; case PIEvaluatorTypes::bfDeg: tmpvars[oi].value = value(ci.operators[0]) * complexd(rad2deg, 0.); break; case PIEvaluatorTypes::bfJ0: tmpvars[oi].value = piJ0(value(ci.operators[0]).real()); break; case PIEvaluatorTypes::bfJ1: tmpvars[oi].value = piJ1(value(ci.operators[0]).real()); break; case PIEvaluatorTypes::bfJN: tmpvars[oi].value = piJn(piRoundd(value(ci.operators[1]).real()), value(ci.operators[0]).real()); break; case PIEvaluatorTypes::bfY0: tmpvars[oi].value = piY0(value(ci.operators[0]).real()); break; case PIEvaluatorTypes::bfY1: tmpvars[oi].value = piY1(value(ci.operators[0]).real()); break; case PIEvaluatorTypes::bfYN: tmpvars[oi].value = piYn(piRoundd(value(ci.operators[1]).real()), value(ci.operators[0]).real()); break; case PIEvaluatorTypes::bfMin: tmp = value(ci.operators[0]); for (int i = 1; i < ci.operators.size_s(); ++i) { stmp = value(ci.operators[i]); tmp = complexd(piMind(tmp.real(), stmp.real()), piMind(tmp.imag(), stmp.imag())); } tmpvars[oi].value = tmp; break; case PIEvaluatorTypes::bfMax: tmp = value(ci.operators[0]); for (int i = 1; i < ci.operators.size_s(); ++i) { stmp = value(ci.operators[i]); tmp = complexd(piMaxd(tmp.real(), stmp.real()), piMaxd(tmp.imag(), stmp.imag())); } tmpvars[oi].value = tmp; break; case PIEvaluatorTypes::bfClamp: tmp = value(ci.operators[0]); stmp = value(ci.operators[1]); ttmp = value(ci.operators[2]); tmpvars[oi].value = complexd(piClampd(tmp.real(), stmp.real(), ttmp.real()), piClampd(tmp.imag(), stmp.imag(), ttmp.imag())); break; case PIEvaluatorTypes::bfStep: tmpvars[oi].value = complexd(value(ci.operators[0]).real() >= value(ci.operators[1]).real() ? complexld_1 : complexld_0); break; case PIEvaluatorTypes::bfMix: tmp = value(ci.operators[0]); stmp = value(ci.operators[1]); ttmp = value(ci.operators[2]); tmpvars[oi].value = stmp.real() * (1. - tmp.real()) + ttmp.real() * tmp.real(); break; case PIEvaluatorTypes::bfRandom: tmp = static_cast(rand()) / RAND_MAX; stmp = value(ci.operators[1]) - value(ci.operators[0]); tmpvars[oi].value = value(ci.operators[0]) + tmp * stmp; break; default: break; } } inline bool PIEvaluator::execInstructions() { PIEvaluatorTypes::Instruction ci; int oi; complexd tmp; tmpvars = variables; //cout << "var count " << tmpvars.size_s() << endl; for (int i = 0; i < instructions.size_s(); i++) { ci = instructions[i]; oi = -ci.out - 1; //cout << value(ci.operators[0]) << operationChar(ci.operation) << value(ci.operators[1]) << ", " << oi << endl; switch (ci.operation) { case PIEvaluatorTypes::oAdd: tmpvars[oi].value = value(ci.operators[0]) + value(ci.operators[1]); break; case PIEvaluatorTypes::oSubtract: tmpvars[oi].value = value(ci.operators[0]) - value(ci.operators[1]); break; case PIEvaluatorTypes::oMultiply: tmpvars[oi].value = value(ci.operators[0]) * value(ci.operators[1]); break; case PIEvaluatorTypes::oDivide: tmp = value(ci.operators[1]); if (tmp == complexd(0., 0.)) tmpvars[oi].value = 0.; else tmpvars[oi].value = value(ci.operators[0]) / tmp; break; case PIEvaluatorTypes::oResidue: tmpvars[oi].value = residue(value(ci.operators[0]), value(ci.operators[1])); break; case PIEvaluatorTypes::oPower: tmpvars[oi].value = pow(value(ci.operators[0]), value(ci.operators[1])); break; case PIEvaluatorTypes::oEqual: tmpvars[oi].value = value(ci.operators[0]) == value(ci.operators[1]); break; case PIEvaluatorTypes::oNotEqual: tmpvars[oi].value = value(ci.operators[0]) != value(ci.operators[1]); break; case PIEvaluatorTypes::oGreaterEqual: tmpvars[oi].value = value(ci.operators[0]).real() >= value(ci.operators[1]).real(); break; case PIEvaluatorTypes::oSmallerEqual: tmpvars[oi].value = value(ci.operators[0]).real() <= value(ci.operators[1]).real(); break; case PIEvaluatorTypes::oGreater: tmpvars[oi].value = value(ci.operators[0]).real() > value(ci.operators[1]).real(); break; case PIEvaluatorTypes::oSmaller: tmpvars[oi].value = value(ci.operators[0]).real() < value(ci.operators[1]).real(); break; case PIEvaluatorTypes::oAnd: tmpvars[oi].value = value(ci.operators[0]).real() > 0. && value(ci.operators[1]).real() > 0.; break; case PIEvaluatorTypes::oOr: tmpvars[oi].value = value(ci.operators[0]).real() > 0. || value(ci.operators[1]).real() > 0.; break; case PIEvaluatorTypes::oFunction: execFunction(ci); break; case PIEvaluatorTypes::oNone: tmpvars[oi].value = value(ci.operators[0]); break; } } if (!instructions.isEmpty()) out = value(instructions.back().out); return true; } bool PIEvaluator::check(const PIString & string) { currentString = preprocess(string); correct = check(); if (!correct) { instructions.clear(); return false; } lastError = "Correct"; return true; } complexd PIEvaluator::evaluate() { if (!execInstructions()) out = 0.; if (fabs(out.real()) < 1E-300) out = complexd(0., out.imag()); if (fabs(out.imag()) < 1E-300) out = complexd(out.real(), 0.); return out; }