File indexing completed on 2024-05-12 03:41:59

0001 /*************************************************************************************
0002  *  Copyright (C) 2007-2011 by Aleix Pol <aleixpol@kde.org>                          *
0003  *                                                                                   *
0004  *  This program is free software; you can redistribute it and/or                    *
0005  *  modify it under the terms of the GNU General Public License                      *
0006  *  as published by the Free Software Foundation; either version 2                   *
0007  *  of the License, or (at your option) any later version.                           *
0008  *                                                                                   *
0009  *  This program is distributed in the hope that it will be useful,                  *
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *
0012  *  GNU General Public License for more details.                                     *
0013  *                                                                                   *
0014  *  You should have received a copy of the GNU General Public License                *
0015  *  along with this program; if not, write to the Free Software                      *
0016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
0017  *************************************************************************************/
0018 
0019 #include "analitzatest.h"
0020 #include "analyzer.h"
0021 #include <cmath>
0022 
0023 #include "apply.h"
0024 #include "container.h"
0025 #include "variables.h"
0026 #include "vector.h"
0027 #include "value.h"
0028 #include <variable.h>
0029 #include <analitzautils.h>
0030 #include <QTest>
0031 //#include <operations.h>
0032 
0033 using namespace std;
0034 using Analitza::Cn;
0035 using Analitza::Ci;
0036 using Analitza::Vector;
0037 using Analitza::Object;
0038 using Analitza::Operator;
0039 using Analitza::Container;
0040 using Analitza::Expression;
0041 
0042 QTEST_MAIN( AnalitzaTest )
0043 
0044 namespace QTest {
0045 
0046 template <> char *toString(const Analitza::Cn &cn)
0047 { return qstrdup(QStringLiteral("Cn(%1)").arg(cn.toString()).toLatin1().constData()); }
0048 
0049 }
0050 
0051 Q_DECLARE_METATYPE(Cn)
0052 
0053 AnalitzaTest::AnalitzaTest(QObject *parent)
0054  : QObject(parent)
0055 {}
0056 
0057 AnalitzaTest::~AnalitzaTest()
0058 {}
0059 
0060 void AnalitzaTest::initTestCase()
0061 {
0062     a=new Analitza::Analyzer;
0063 }
0064 
0065 void AnalitzaTest::cleanupTestCase()
0066 {
0067     delete a;
0068 }
0069 
0070 void AnalitzaTest::testTrivialCalculate_data()
0071 {
0072     QTest::addColumn<QString>("expression");
0073     QTest::addColumn<Cn>("result");
0074 
0075     QTest::newRow("a value") << "2" << Cn(2.);
0076     QTest::newRow("val.e0") << "12.0e-02" << Cn(12e-2);
0077     QTest::newRow("vale") << "12e-2" << Cn(12e-2);
0078     QTest::newRow("val") << "12e2" << Cn(12e2);
0079 
0080     QTest::newRow("factorial5") << "factorial(5)" << Cn(120);
0081     QTest::newRow("factorial12") << "factorial(12)" << Cn(12*11*10*9*8*7*6*5*4*3*2*1);
0082     
0083     QTest::newRow("simple addition") << "2+2" << Cn(4.);
0084     QTest::newRow("simple power") << "2**99" << Cn(pow(2., 99.));
0085     QTest::newRow("simple multiplication") << "3*3" << Cn(9.);
0086     QTest::newRow("sinus") << "sin(3*3)" << Cn(sin(9.));
0087     QTest::newRow("declare") << "x:=3" << Cn(3.);
0088     QTest::newRow("sum") << "sum(x : x=1..99)" << Cn(4950.);
0089     QTest::newRow("diff") << "(diff(x:x))(1)" << Cn(1.);
0090     QTest::newRow("diffz") <<"(diff(z:z))(1)" << Cn(1.);
0091     
0092     QTest::newRow("product") << "product(n : n=1..5)" << Cn(120.);
0093     QTest::newRow("factorial") << "factorial(5)" << Cn(120.);
0094     
0095     QTest::newRow("simple piecewise") << "piecewise { pi=0? 3, pi=pi?33 }" << Cn(33.);
0096     QTest::newRow("simple piecewise with otherwise") << "piecewise { pi=0? 3, ?33 }" << Cn(33.);
0097     QTest::newRow("boolean and") << "and(true,false)" << Cn(false);
0098     QTest::newRow("boolean or") << "or(false,true)" << Cn(true);
0099     QTest::newRow("boolean not") << "not(false)" << Cn(true);
0100     QTest::newRow("lambda")  << "(x->x+2)(2)" << Cn(4.);
0101     QTest::newRow("lambda2") << "(x->3*x^2)(1)" << Cn(3.);
0102     QTest::newRow("lambda3") << "(x->x*sum(t:t=0..3))(2)" << Cn(12.);
0103     QTest::newRow("imaginarypow") << "(-4)^(1/4)" << Cn(1, 1);
0104     QTest::newRow("imaginaryroot") << "root(-4, 4)" << Cn(1.);
0105     QTest::newRow("squareroot-1") << "(-1)^(1/2)" << Cn(0, 1);
0106 
0107     //comprehension
0108     QTest::newRow("sum.2bvars") << "sum(x*y : (x, y)=1..3)" << Cn(36.);
0109     QTest::newRow("sum.list") << "sum(x : x@list{1,5,44})" << Cn(50.);
0110 
0111     QTest::newRow("sum.sum") << "sum(sum(x : x=0..i) : i=0..10)" << Cn(220.);
0112 
0113     QTest::newRow("exists") << "exists(x : x@list{true,true,false})" << Cn(true);
0114     QTest::newRow("forall") << "forall(x : x@list{true,true,false})" << Cn(false);
0115 //     QTest::newRow("emptysum") << "sum(x : x@list{})" << 0.;
0116     
0117     QTest::newRow("lambdacall") << "f:=x->f(x)" << Cn(0.);
0118     QTest::newRow("cpx1") << "i" << Cn(0, 1);
0119     QTest::newRow("cpx2") << "i*i" << Cn(-1);
0120     QTest::newRow("cpx3") << "2+i*i" << Cn(1);
0121     QTest::newRow("complex number") << "3+4*(5-6*i)" << Cn(23, -24);
0122 }
0123 
0124 void AnalitzaTest::testTrivialCalculate()
0125 {
0126     QFETCH(QString, expression);
0127     QFETCH(Cn, result);
0128     Expression e(expression, false);
0129     if(!e.isCorrect()) qDebug() << "error: " << e.error();
0130     QCOMPARE(e.isCorrect(), true);
0131     
0132     a->setExpression(e);
0133     
0134     if(!a->isCorrect()) qDebug() << "error: " << a->errors();
0135     QVERIFY(a->isCorrect());
0136     QCOMPARE(a->evaluate().toReal(), result);
0137     QVERIFY(a->isCorrect());
0138     Expression ee=a->calculate();
0139     if(!a->isCorrect()) qDebug() << "error: " << a->errors();
0140     QVERIFY(a->isCorrect());
0141     QCOMPARE(ee.toReal(), result);
0142     QVERIFY(a->isCorrect());
0143 }
0144 
0145 void AnalitzaTest::testTrivialEvaluate_data()
0146 {
0147     QTest::addColumn<QString>("expression");
0148     QTest::addColumn<QString>("result");
0149     
0150     QTest::newRow("simple value") << "2" << "2";
0151     QTest::newRow("complex") << "i*5" << "5*i";
0152     QTest::newRow("simple complex value") << "6*(2+i)" << "12+6*i";
0153     QTest::newRow("complex irreductibility") << "i" << "i";
0154     QTest::newRow("from complex value") << "i*i" << "-1";
0155     QTest::newRow("from power complex") << "power(i, 2)" << "-1";
0156     QTest::newRow("sin complex") << "sin(i)" << "1.17520119364*i";
0157     QTest::newRow("cos complex") << "cos(5-9*i)" << "1149.26926545-3885.12187972*i";
0158     QTest::newRow("complex*complex") << "(5.3-9.8*i)*(-6.2+3.7*i)" << "3.4+80.37*i";
0159     QTest::newRow("simple complex/complex") << "i/i" << "1";
0160     QTest::newRow("complex/complex") << "(9.3-5.4*i)/(3.6-9.5*i)" << "0.82143203178+0.667667861641*i";
0161     QTest::newRow("simple complex conjugate") << "conjugate(i)" << "-i";
0162     QTest::newRow("complex conjugate") << "conjugate(-9.3+5.87*i)" << "-9.3-5.87*i";
0163     QTest::newRow("complex arg") << "arg(i)" << "1.57079632679";
0164     QTest::newRow("complex real part") << "real(45-9*i)" << "45";
0165     QTest::newRow("complex imag part") << "imaginary(45-9*i)" << "-9";
0166     QTest::newRow("simply complex mod") << "abs(i)" << "1";
0167     QTest::newRow("complex mod") << "abs(8-9*i)" << "12.0415945788";
0168     QTest::newRow("simple addition") << "2+2" << "4";
0169     QTest::newRow("simple addition with var") << "2+x" << "x+2";
0170     QTest::newRow("minus irreductibility") << "-x" << "-x";
0171     QTest::newRow("minus0") << "x-y" << "x-y";
0172     QTest::newRow("minus1") << "minus(x, y, x)" << "-y";
0173     QTest::newRow("minus2") << "x-y-y-y-x" << "-3*y";
0174     QTest::newRow("minus2.1") << "minus(x,y,y,y,x)" << "-3*y";
0175     QTest::newRow("minus3") << "x-x-x-x-x-x" << "-4*x";
0176     QTest::newRow("minus3.1") << "x-x-x-x" << "-2*x";
0177     QTest::newRow("minus3.2") << "minus(x,x,x,x,x,x)" << "-4*x";
0178     QTest::newRow("addition") << "x+x" << "2*x";
0179     QTest::newRow("simple polynomial") << "x+x+x**2+x**2" << "2*x+2*x^2";
0180     QTest::newRow("simplification of unary minus in times") << "x*(-x)" << "-x^2";
0181     QTest::newRow("strange") << "0*x-1*1" << "-1";
0182     QTest::newRow("strange2") << "x-x" << "0";
0183     QTest::newRow("old leak") << "x^1" << "x";
0184     QTest::newRow("declare") << "wockawocka:=3" << "3";
0185     QTest::newRow("nested multiplication") << "x*(x+x)" << "2*x^2";
0186     QTest::newRow("multiplication") << "x*x" << "x^2";
0187     QTest::newRow("undefined function call") << "f(2)" << "f(2)";
0188     QTest::newRow("--simplification") << "-(-x)" << "x";
0189     QTest::newRow("unneeded --simplification") << "-(x-x)" << "0";
0190     QTest::newRow("minus order") << "1-x" << "-x--1";
0191     QTest::newRow("minus order2") << "x-1" << "x-1";
0192     QTest::newRow("after simp(minus) --simplification") << "-(x-x-x)" << "x";
0193     QTest::newRow("and") << "and(6>5, 4<5)" << "true";
0194     QTest::newRow("or") << "or(6>5, 6<5)" << "true";
0195     
0196     QTest::newRow("sum") << "sum(n : n=1..99)" << "4950";
0197     QTest::newRow("sum times") << "x*sum(n : n=0..99)" << "4950*x";
0198     QTest::newRow("unrelated sum") << "sum(x : n=0..99)" << "100*x";
0199     
0200     QTest::newRow("product") << "product(n : n=1..5)" << "120";
0201     QTest::newRow("factorial") << "factorial(5)" << "120";
0202     
0203     QTest::newRow("simple piecewise") << "piecewise { eq(pi,0)? 3, eq(pi, pi)?33}" << "33";
0204     QTest::newRow("simple piecewise with otherwise") << "piecewise { eq(pi,0)? 3, ?33}" << "33";
0205     
0206     QTest::newRow("lambda") << "f:=q->2" << "q->2";
0207 //     QTest::newRow("selector lambda") << "selector(2, vector{x->x, x->x+2})" << "x->x+2";
0208 //     QTest::newRow("boolean and") << "and(x,0)" << "false";
0209 
0210     QTest::newRow("irreductible vector") << "vector { x, y, z }" << "vector { x, y, z }";
0211     QTest::newRow("in-vector operations") << "vector { x+x, y+y, z-z }" << "vector { 2*x, 2*y, 0 }";
0212     
0213     QTest::newRow("vect+vect") << "x+vector { 2, 3, 4 }+vector { 4, 3, 2 }" << "x+vector { 6, 6, 6 }";
0214     QTest::newRow("vect+2vect") << "2*vector { x, y, z }+vector{x,y,z}" << "3*vector { x, y, z }";
0215     QTest::newRow("vect+null") << "vector { x, y, z }+vector{0,0,0}" << "vector { x, y, z }";
0216     QTest::newRow("card") << "card(vector { x, y, z })" << "3";
0217     QTest::newRow("card+var") << "card(x)" << "card(x)";
0218     
0219     QTest::newRow("selector+idx") << "selector(1, vector{x,y,z})" << "x";
0220     QTest::newRow("selector+var") << "(vector { x, y, z })[x]" << "vector { x, y, z }[x]";
0221     QTest::newRow("selector+impossible") << "v[1]" << "v[1]";
0222     
0223     QTest::newRow("in lists") << "list{w+w}" << "list { 2*w }";
0224     QTest::newRow("lists") << "union(list{w}, list{x}, list{y,z})" << "list { w, x, y, z }";
0225     QTest::newRow("lists2") << "union(list{w}, x, list{y}, list{z})" << "union(list { w }, x, list { y, z })";
0226     
0227     QTest::newRow("sum.2bvars") << "sum(x*w : (x, y)=1..3)" << "18*w";
0228     QTest::newRow("sum.list") << "sum(x+y : x@list{x,y,z})" << "x+4*y+z";
0229     
0230     QTest::newRow("forall") << "forall(x : x@list{x,true,true})" << "forall(x:x@list { x, true, true })";
0231     QTest::newRow("exists") << "exists(x : x@list{x,false,false})" << "exists(x:x@list { x, false, false })";
0232     
0233     QTest::newRow("map") << "map(x->x**2, list {1,2,3})" << "list { 1, 4, 9 }";
0234     QTest::newRow("filter") << "filter(x->x>5, list {3,4,5,6,7})" << "list { 6, 7 }";
0235     
0236     QTest::newRow("forall1") << "forall(a<w:a@list { 2 })" << "2<w";
0237     
0238     QTest::newRow("matrix") << "matrix { matrixrow { 1, 2 } }" << "matrix { matrixrow { 1, 2 } }";
0239     QTest::newRow("matrix+") << "matrix { matrixrow { 1, 2 } }+matrix{ matrixrow { 1, 2 } }" << "matrix { matrixrow { 2, 4 } }";
0240     QTest::newRow("matrix++") << "matrix { matrixrow { 5, 6 }, matrixrow { 4, 0 }}+matrix { matrixrow { 2, 3 }, matrixrow { 4, 0 }}" << "matrix { matrixrow { 7, 9 }, matrixrow { 8, 0 } }";
0241     //TODO aucahuasi: we support only matrix and vector over a scalar field (numbers), but I think we could have matrix/vector over other structures too (e.g. functions, vectors, etc.)
0242     //QTest::newRow("matrix+++") << "matrix { matrixrow { vector { 1, 2 } } }+matrix { matrixrow { vector { 1.8, 2.4 } } }" << "matrix { matrixrow { vector { 2.8, 4.4 } } }";
0243     QTest::newRow("matrix@") << "selector(1, matrix { matrixrow { 1, 2 } })" << "vector { 1, 2 }";
0244     QTest::newRow("matrix@@") << "selector(1, selector(1, matrix { matrixrow { 1, 2 } }))" << "1";
0245     QTest::newRow("scalar multiplication of matrix") << "3*matrix { matrixrow { 5, 6 }, matrixrow { 4, 0 }}" << "matrix { matrixrow { 15, 18 }, matrixrow { 12, 0 } }";
0246     QTest::newRow("transpose vector") << "transpose(vector{12,45})" << "matrix { matrixrow { 12, 45 } }";
0247     QTest::newRow("row x column") << "matrix { matrixrow { 1, 2 } }*matrix { matrixrow { 3 }, matrixrow { 5 } }" << "matrix { matrixrow { 13 } }";
0248     QTest::newRow("column x row") << "matrix { matrixrow { 3 }, matrixrow { 5 } }*matrix { matrixrow { 1, 2 } }" << "matrix { matrixrow { 3, 6 }, matrixrow { 5, 10 } }";
0249     QTest::newRow("row x vector") << "matrix { matrixrow { 1, 2 } }*vector{ 3, 5 }" << "vector { 13 }";
0250     QTest::newRow("vector x row") << "vector{ 3, 5 }*matrix { matrixrow { 1, 2 } }" << "matrix { matrixrow { 3, 6 }, matrixrow { 5, 10 } }";
0251     QTest::newRow("vector x transpose(vector)") << "vector{ 3, 5 }*transpose(vector{1,2})" << "matrix { matrixrow { 3, 6 }, matrixrow { 5, 10 } }";
0252     QTest::newRow("matrix x vector") << "matrix { matrixrow { 3, 3 }, matrixrow { 2, 2 }, matrixrow { 3, 4 } }*vector{ 1, 2 }" << "vector { 9, 6, 11 }";
0253     QTest::newRow("matrix x matrix") << "matrix { matrixrow { 3, 3 }, matrixrow { 2, 2 }, matrixrow { 3, 4 } }*matrix { matrixrow{3, 3, 4, 5, 6}, matrixrow{2, 4, 5, 6, 2} }" << "matrix { matrixrow { 15, 21, 27, 33, 24 }, matrixrow { 10, 14, 18, 22, 16 }, matrixrow { 17, 25, 32, 39, 26 } }";
0254     QTest::newRow("matrix^0") << "power(matrix { matrixrow { 3, 3 }, matrixrow { 2, 2 } }, 0)" << "matrix { matrixrow { 1, 0 }, matrixrow { 0, 1 } }";
0255     QTest::newRow("matrix^1") << "power(matrix { matrixrow { 3, 3 }, matrixrow { 2, 2 } }, 1)" << "matrix { matrixrow { 3, 3 }, matrixrow { 2, 2 } }";
0256     QTest::newRow("matrix^2") << "power(matrix { matrixrow { 3, 3 }, matrixrow { 2, 2 } }, 2)" << "matrix { matrixrow { 15, 15 }, matrixrow { 10, 10 } }";
0257     QTest::newRow("matrix^64") << "power(matrix { matrixrow { 1.63, 2.4}, matrixrow { -0.36,7.128 } }, 64)" << "matrix { matrixrow { -2.79721542669e+52, 4.14615974023e+53 }, matrixrow { -6.21923961035e+52, 9.21843939558e+53 } }";
0258     QTest::newRow("matrix^6464") << "power(matrix { matrixrow { 1.0019 } }, 6464)"  << "matrix { matrixrow { 213191.74219 } }";
0259 }
0260 
0261 void AnalitzaTest::testTrivialEvaluate()
0262 {
0263     QFETCH(QString, expression);
0264     QFETCH(QString, result);
0265     
0266     Expression e(expression, false);
0267     a->setExpression(e);
0268     if(!a->isCorrect())
0269         qDebug() << "errors:" << a->errors();
0270     
0271     qDeleteAll(*a->variables());
0272     a->variables()->clear();
0273     a->variables()->initializeConstants();
0274     
0275     QVERIFY(a->isCorrect());
0276     QCOMPARE(a->evaluate().toString(), result);
0277 }
0278 
0279 void AnalitzaTest::testDerivativeSimple_data()
0280 {
0281     QTest::addColumn<QString>("expression");
0282     QTest::addColumn<QString>("result");
0283     
0284     QTest::newRow("dumb") << "x" << "1";
0285     QTest::newRow("simple polynomial") << "x^3+1" << "3*x^2";
0286     QTest::newRow("power and sinus") << "x^2+sin(x)" << "2*x+cos(x)";
0287     QTest::newRow("power") << "x^2" << "2*x";
0288     QTest::newRow("division") << "1/x" << "-1/x^2";
0289     QTest::newRow("logarithm") << "ln x" << "1/x";
0290     QTest::newRow("times") << "x*y" << "y";
0291     QTest::newRow("powere") << "e^x" << "e^x"; // power derivative and logarithm simplification
0292     QTest::newRow("chain rule") << "sin(x**2)" << "2*x*cos(x^2)";
0293     QTest::newRow("tangent") << "tan(x**2)" << "(2*x)/cos(x^2)^2";
0294     QTest::newRow("piecewise") << "piecewise { x<0 ? x**2, ? x } " << "piecewise { x<0 ? 2*x, ? 1 }";
0295     QTest::newRow("lambda") << "x->3" << "0";
0296     QTest::newRow("timesminus") << "1-x*sin(x)" << "-sin(x)-x*cos(x)";
0297     QTest::newRow("timesminus2") << "cos(x)-x*sin(x)" << "-2*sin(x)-x*cos(x)";
0298     QTest::newRow("log") << "log(x)" << "1/(2.30258509299*x)";
0299     QTest::newRow("vector") << "vector { x, x^2 }" << "vector { 1, 2*x }";
0300     QTest::newRow("exp") << "exp(x**2)" << "2*x*exp(x^2)";
0301     QTest::newRow("halfx") << "(1/2)*x" << "0.5";
0302     QTest::newRow("halfx2") << "1/2 x" << "-2/(2*x)^2"; //TODO: could improve the simplification
0303 }
0304 
0305 void AnalitzaTest::testDerivativeSimple()
0306 {
0307     QFETCH(QString, expression);
0308     QFETCH(QString, result);
0309     
0310     qDeleteAll(*a->variables());
0311     a->variables()->clear();
0312     a->variables()->initializeConstants();
0313     
0314     Expression e(expression, false);
0315     a->setExpression(e);
0316     QVERIFY(a->isCorrect());
0317     a->setExpression(a->derivative(QStringLiteral("x")));
0318     a->simplify();
0319     Expression deriv=a->expression();
0320     QCOMPARE(deriv.toString(), QString(QStringLiteral("x->")+result));
0321     if(!a->isCorrect()) qDebug() << "errors: " << a->errors();
0322     QVERIFY(a->isCorrect());
0323     
0324     double val=1.;
0325     QVector<Object*> vars;
0326     vars.append(new Cn(val));
0327     
0328     a->setExpression(Expression("x->"+expression, false));
0329     double valCalc=a->derivative(vars);
0330     qDeleteAll(vars);
0331     
0332     if(a->isCorrect()) {
0333         Expression ee(QStringLiteral("(x->%1)(%2)").arg(result).arg(val));
0334         a->setExpression(ee);
0335         QVERIFY(a->isCorrect());
0336         
0337         Expression r=a->calculate();
0338         
0339         if(a->isCorrect())
0340             QCOMPARE(QString::number(valCalc).left(5), QString::number(r.toReal().value()).left(5));
0341     }
0342     a->setExpression(Expression("diff("+expression+":x)", false));
0343     a->simplify();
0344     QVERIFY(a->isCorrect());
0345     deriv=a->evaluate();
0346     
0347     QCOMPARE(deriv.toString(), QString(QStringLiteral("x->")+result));
0348     QVERIFY(a->isCorrect());
0349 }
0350 
0351 void AnalitzaTest::testCorrection_data()
0352 {
0353     QTest::addColumn<QStringList>("expression");
0354     QTest::addColumn<QString>("result");
0355     
0356     QStringList script;
0357     
0358     script.clear();
0359     script << QStringLiteral("f:=y->y*y");
0360     script << QStringLiteral("f(i)");
0361     QTest::newRow("from complex function") << script << "-1";
0362     
0363     script.clear();
0364     script << QStringLiteral("n:=2");
0365     script << QStringLiteral("n+1");
0366     QTest::newRow("simple") << script << "3";
0367     
0368     script.clear();
0369     script << QStringLiteral("f:=x->x+2");
0370     script << QStringLiteral("f(1)");
0371     QTest::newRow("simple func") << script << "3";
0372     
0373 //     script.clear();
0374 //     script << "t:=(c, c1, c2, t1, t2)->(t2-t1)/(c2-c1)*(c-c1)+t1";
0375 //     script << "t(1,2,3,4,5)";
0376 //     QTest::newRow("long func") << script << "3";
0377     
0378     script.clear();
0379     script << QStringLiteral("fact:=n->piecewise { n=1?1, ? n*fact(n-1) }");
0380     script << QStringLiteral("fact(5)");
0381     QTest::newRow("piecewise factorial") << script << "120";
0382     
0383     script.clear();
0384     script << QStringLiteral("fib:=n->piecewise { n=0?0, n=1?1, ?fib(n-1)+fib(n-2) }");
0385     script << QStringLiteral("fib(6)");
0386     QTest::newRow("piecewise fibonacci") << script << "8";
0387     
0388     script.clear();
0389     script << QStringLiteral("n:=vector{1}");
0390     script << QStringLiteral("func:=n->n+1");
0391     script << QStringLiteral("func(5)");
0392     QTest::newRow("simple function, shadowed parameter") << script << "6";
0393     
0394     script.clear();
0395     script << QStringLiteral("x:=3");
0396     script << QStringLiteral("x*sum(x : x=0..99)");
0397     QTest::newRow("bounded scope") << script << "14850";
0398     
0399     script.clear();
0400     script << QStringLiteral("f:=diff(x^2:x)");
0401     script << QStringLiteral("f(3)");
0402     QTest::newRow("diff function") << script << "6";
0403     
0404     script.clear();
0405     script << QStringLiteral("fv:=vector{x->x, x->x+2}");
0406     script << QStringLiteral("(selector(1, fv))(1)");
0407     script << QStringLiteral("(selector(1, fv))(1)+(selector(2, fv))(2)");
0408     QTest::newRow("selector+lambda") << script << "5";
0409     
0410     QTest::newRow("lists") << QStringList(QStringLiteral("union(list{0}, list{1}, list{2,3})")) << "list { 0, 1, 2, 3 }";
0411     
0412     script.clear();
0413     script <<    QStringLiteral("valueTableRec := (func, antimages, i) ->"
0414                 "piecewise { i=0 ? list{}, "
0415                     "? union(list{func(selector(i, antimages))}, valueTableRec(func, antimages, i-1))"
0416                 " }")
0417             << QStringLiteral("valueTableRec(x->x**2, list{1,2,3}, 3)");
0418     QTest::newRow("yay") << script << "list { 9, 4, 1 }";
0419     
0420     script.clear();
0421     script << QStringLiteral("f:=ff->(y->ff(y))");
0422 //     script << "f(x->x**2)";
0423     script << QStringLiteral("(f(x->x**2))(2)");
0424     QTest::newRow("yay2") << script << "4";
0425     
0426     script.clear();
0427     script <<    QStringLiteral("findroot:=(der, dee)->piecewise { dee>1 ?"
0428                 "piecewise { rem(der, dee)=0 ? true, ? findroot(der, dee-1)  }, ? false }");
0429     script << QStringLiteral("isprime:=n->not(findroot(n, floor(root(n, 2))))");
0430     script << QStringLiteral("primes:=(from, to)->piecewise { or(from<0, to<0, from>=to)? list{},"
0431                 " isprime(from)? union(list{from}, primes(from+1, to)), ? primes(from+1, to)}");
0432     script << QStringLiteral("primes(1, 25)");
0433     QTest::newRow("primes") << script << "list { 1, 2, 3, 5, 7, 11, 13, 17, 19, 23 }";
0434     
0435     script.clear();
0436     script << QStringLiteral("f:=v->sum(i**2 : i@v)");
0437     script << QStringLiteral("f(list{1,2,3})");
0438     script << QStringLiteral("f(vector{1,2,3})");
0439     QTest::newRow("sum.list") << script << "14";
0440     
0441     script.clear();
0442     script << QStringLiteral("f:=o->vector { x->x+o, x->x*o }");
0443     script << QStringLiteral("vector { selector(1, f(3)), selector(1, f(4)) }");
0444     QTest::newRow("lambda") << script << "vector { x->x+3, x->x+4 }";
0445     
0446     script.clear();
0447     script << QStringLiteral("comb:=(n, i)->factorial(n)/(factorial(i)*factorial(n-i))")
0448            << QStringLiteral("p:=10^-2")
0449            << QStringLiteral("pu:=n->sum(  comb(n,i)*p^(n-i)*(1-p)*sum(x:x=0..i)  :i=0..(floor((n-1)/2)))")
0450            << QStringLiteral("pu(5)");
0451     
0452     QTest::newRow("bug241047") << script << "2.97495e-05";
0453     
0454     script.clear();
0455     script << QStringLiteral("comb:=(n, i)->factorial(n)/(factorial(i)*factorial(n-i))")
0456            << QStringLiteral("probability:=(place, case, totalprobability,"
0457                     "positive, negative)->(comb(place,"
0458                     "case)*(positive/totalprobability)^case)*(negative/totalprobability)^(place-case)")
0459            << QStringLiteral("sum(probability(5, t, 6, 1, 5):t=0..5)");
0460     
0461     QTest::newRow("probabilities") << script << "1";
0462     
0463     script.clear();
0464     script
0465             << QStringLiteral("rtail:=(elems,i)->piecewise { card(elems)>=i ? union(list{elems[i]}, rtail(elems, i+1)), ? list{} }")
0466             << QStringLiteral("tail:=elems->rtail(elems,2)")
0467             << QStringLiteral("foldr:=(f,z,elems)->piecewise {card(elems)=0 ? z, ? f(elems[1], foldr(f, z, tail(elems))) }")
0468             << QStringLiteral("sumsum:=elems->foldr((x,y)->x+y, 0, elems)")
0469             << QStringLiteral("sumsum(list{1,2,3})");
0470     QTest::newRow("sumsum") << script << "6";
0471     
0472     script.clear();
0473     script
0474             << QStringLiteral("rtail:=(elems,i)->piecewise { card(elems)>=i ? union(list{elems[i]}, rtail(elems, i+1)), ? list{} }")
0475             << QStringLiteral("tail:=elems->rtail(elems,2)")
0476             << QStringLiteral("foldr:=(f,z,elems)->piecewise {card(elems)=0 ? z, ? f(elems[1], foldr(f, z, tail(elems))) }")
0477             << QStringLiteral("cfilter:=(condition,elems)->foldr((v,pred)->piecewise{ condition(v) ? union(list{v}, pred), ? pred }, list{}, elems)")
0478             
0479             << QStringLiteral("cfilter(x->x>3, list{1,2,3,4,5})");
0480     QTest::newRow("custom filter") << script << "list { 4, 5 }";
0481     
0482     script.clear();
0483     script
0484             << QStringLiteral("pmap:=(func, list, i)->piecewise { i>=card(list)+1 ? list {}, ? union(list { func(selector(i, list)) }, pmap(func, list, i+1)) }")
0485             << QStringLiteral("cmap:=(func, list)->pmap(func, list, 1)")
0486             << QStringLiteral("refImport:=x->x>3")
0487             << QStringLiteral("importedRef:=imports->cmap(refImport, imports)")
0488             
0489             << QStringLiteral("importedRef(list{1,2,3,4,5})");
0490     QTest::newRow("custom map") << script << "list { false, false, false, true, true }";
0491     
0492     script.clear();
0493     script
0494             << QStringLiteral("f:=v->sum(i**2 : i@v)")
0495             << QStringLiteral("g:=(u, v)->f(u)+f(v)")
0496             << QStringLiteral("g(vector{1,2}, vector{3,4})");
0497     QTest::newRow("aaa") << script << "30";
0498 
0499     script.clear();
0500     script << QStringLiteral("f := (w,zz) -> list{zz} | acs->forall(a<w : a@acs)");
0501     script << QStringLiteral("f(2,3)");
0502     QTest::newRow("lambda1") << script << "false";
0503 
0504     script.clear();
0505     script << QStringLiteral("f := x -> matrix { matrixrow { x, x } }");
0506     script << QStringLiteral("f(90)");
0507     QTest::newRow("matrix-f") << script << "matrix { matrixrow { 90, 90 } }";
0508 
0509     script.clear();
0510     script << QStringLiteral("rotate := angle -> matrix { matrixrow { cos(angle), -sin(angle) }, matrixrow { sin(angle), cos(angle) } }");
0511     script << QStringLiteral("rotate(90) * vector { 20, 20 }");
0512     QTest::newRow("rotate-vector") << script << "vector { -26.8414055946, 8.91846094943 }";
0513 }
0514 
0515 //testCalculate
0516 void AnalitzaTest::testCorrection()
0517 {
0518     QFETCH(QStringList, expression);
0519     QFETCH(QString, result);
0520     
0521     Expression last;
0522     Analitza::Analyzer b1;
0523     foreach(const QString &exp, expression) {
0524         Expression e(exp, false);
0525         if(!e.isCorrect()) qDebug() << "error:" << e.error();
0526         QVERIFY(e.isCorrect());
0527         
0528         b1.setExpression(e);
0529         
0530         if(!b1.isCorrect()) qDebug() << "errors: " << b1.errors();
0531         QVERIFY(b1.isCorrect());
0532         last = b1.calculate();
0533         if(!b1.isCorrect()) qDebug() << "errors:" << e.toString() << b1.errors();
0534         QVERIFY(b1.isCorrect());
0535     }
0536     QCOMPARE(last.toString(), result);
0537     
0538     Analitza::Analyzer b;
0539     Expression evalResult;
0540     foreach(const QString &exp, expression) {
0541         Expression e(exp, false);
0542         QVERIFY(e.isCorrect());
0543         
0544         b.setExpression(e);
0545         QVERIFY(b.isCorrect());
0546         evalResult=b.evaluate();
0547         QVERIFY(b.isCorrect());
0548     }
0549     QCOMPARE(evalResult.toString(), result);
0550 
0551     QString script = expression.join(QStringLiteral("\n"));
0552     script+=QLatin1String("\n\n\n");
0553     QTextStream stream(&script);
0554     a->importScript(&stream);
0555     QVERIFY(a->isCorrect());
0556 }
0557 
0558 void AnalitzaTest::testTypeUncorrection()
0559 {
0560     QFETCH(QStringList, expression);
0561     
0562     bool correct=false;
0563     Analitza::Analyzer b;
0564     
0565     foreach(const QString &exp, expression) {
0566         Expression e(exp, false);
0567         b.setExpression(e);
0568         correct=b.isCorrect();
0569         
0570         if(correct)
0571             b.calculate().toReal().value();
0572         
0573         if(!correct || !b.isCorrect())
0574             break;
0575     }
0576     QVERIFY(!correct);
0577 }
0578 
0579 void AnalitzaTest::testTypeUncorrection_data()
0580 {
0581     QTest::addColumn<QStringList>("expression");
0582     QTest::newRow("vect+sin") << QStringList(QStringLiteral("3+sin(vector{3,4,2})"));
0583     QTest::newRow("scalar+card") << QStringList(QStringLiteral("card(3)"));
0584     QTest::newRow("wrong operation") << QStringList(QStringLiteral("lcm(vector{0}, vector{0})"));
0585     
0586     QStringList script;
0587     script << QStringLiteral("x:=3");
0588     script << QStringLiteral("x(3)");
0589     QTest::newRow("value call") << script;
0590     
0591     script.clear();
0592     script << QStringLiteral("f:=(x,y)->x*y");
0593     script << QStringLiteral("f(3)");
0594     QTest::newRow("call missing parameter") << script;
0595 }
0596 
0597 void AnalitzaTest::testUncorrection_data()
0598 {
0599     QTest::addColumn<QStringList>("expression");
0600     QTest::newRow("summatory with uncorrect downlimit1") << QStringList(QStringLiteral("sum(x : x=y..3)"));
0601     QTest::newRow("summatory with uncorrect downlimit2") << QStringList(QStringLiteral("sum(x : x=x..3)"));
0602     QTest::newRow("wrong sum") << QStringList(QStringLiteral("sum(x : x=10..0)"));
0603     
0604     QStringList script;
0605     script << QStringLiteral("a:=b");
0606     script << QStringLiteral("b:=a");
0607     QTest::newRow("var dependency cycle") << script;
0608     
0609     
0610     QTest::newRow("unsupported diff") << QStringList(QStringLiteral("diff(arccos(x):x)"));
0611 }
0612 
0613 void AnalitzaTest::testUncorrection()
0614 {
0615     QFETCH(QStringList, expression);
0616     
0617     bool correct=false;
0618     Analitza::Analyzer b;
0619     foreach(const QString &exp, expression) {
0620         Expression e(exp, false);
0621         correct=e.isCorrect();
0622         
0623         if(correct) {
0624             b.setExpression(e);
0625             Expression res=b.evaluate();
0626             correct=b.isCorrect();
0627         }
0628 //         qDebug() << "cycle" << b.isCorrect() << e.toString() << b.errors();
0629         if(!correct) break;
0630     }
0631 //     QVERIFY(!correct);
0632     
0633     foreach(const QString &exp, expression) {
0634         Expression e(exp, false);
0635         correct=e.isCorrect();
0636         b.setExpression(e);
0637         
0638         if(correct) {
0639             /*double val=*/b.calculate().toReal().value();
0640             correct=b.isCorrect();
0641 //             qDebug() << "aaaaaaaaagh"  << b.errors() << val << correct;
0642         }
0643         if(!correct) break;
0644     }
0645     QVERIFY(!correct);
0646 }
0647 
0648 void AnalitzaTest::testSimplify_data()
0649 {
0650     QTest::addColumn<QString>("expression");
0651     QTest::addColumn<QString>("result");
0652     
0653     QTest::newRow("identity") << "1*x" << "x";
0654     QTest::newRow("minus") << "x-x-x" << "-x";
0655     QTest::newRow("minus1") << "x-1" << "x-1";
0656     QTest::newRow("minus2") << "x-2*x" << "-x";
0657     QTest::newRow("compensation") << "-(4*x)+3*x" << "-x";
0658     QTest::newRow("compensation1") << "(-(4*x))+3*x" << "-x";
0659     QTest::newRow("compensation2") << "((-4)*x)+3*x" << "-x";
0660     QTest::newRow("compensation*") << "-(x^4)*x^3" << "-x^7";
0661     QTest::newRow("powers") << "3**x*5**x" << "3^x*5^x";
0662     QTest::newRow("poli1") << "x-1+2" << "x+1";
0663     QTest::newRow("poli2") << "(x+y)-z" << "x--y-z";
0664     QTest::newRow("poli3") << "2-13-(x+1)" << "-x-12";
0665     QTest::newRow("poli4") << "-x-1-2-4" << "-x-7";
0666     QTest::newRow("poli4.0") << "-x-y-z" << "-x-y-z";
0667     QTest::newRow("poli4.1") << "minus(-x, 1, 2, 4)" << "-x-7";
0668     QTest::newRow("poli5") << "y+3*(x-1)" << "y+3*(x-1)";
0669 //     QTest::newRow("powerscomb") << "3**x*3**x" << "9^x";
0670     QTest::newRow("no var") << "2+2" << "4";
0671     QTest::newRow("simple") << "x+x" << "2*x";
0672     QTest::newRow("lambda") << "(x->x+1)(2)" << "3";
0673     QTest::newRow("lambda1") << "(x->x+1)(y)" << "y+1";
0674     QTest::newRow("lambda2") << "(x->x+1)(x+1)" << "x+2";
0675     QTest::newRow("lambda3") << "zz->(x->card(x)>0)(list{zz})" << "zz->card(list { zz })>0";
0676     QTest::newRow("lambda4") << "f(3) | a-> (g(a) | b-> useForIndex(a, b))" << "(a->(b->useForIndex(a, b))(g(a)))(f(3))";
0677 //     QTest::newRow("lambda3")<< "(x->x+x)(y)" << "2*y";
0678     QTest::newRow("diff") << "diff(x^2:x)" << "x->2*x";
0679     QTest::newRow("sum times") << "sum(n*x : n=0..99)" << "4950*x";
0680     QTest::newRow("levelout") << "-y-(x+y)" << "-2*y-x";
0681     QTest::newRow("sum") << "n->sum((s+n) * s : s=0..9)" << "n->sum((s+n)*s:s=0..9)";
0682     QTest::newRow("sum.sum") << "k->sum(sum(x:x=0..s):s=0..k)" << "k->sum(sum(x:x=0..s):s=0..k)";
0683     QTest::newRow("unrelated sum") << "sum(x : n=0..99)" << "100*x";
0684     QTest::newRow("ln") << "ln(x)" << "ln(x)";
0685     
0686     QTest::newRow("piecewise1") << "piecewise { 1=2 ? 4, ? 3}" << "3";
0687     QTest::newRow("piecewise2") << "piecewise { x=2 ? 4, ? 3}" << "piecewise { x=2 ? 4, ? 3 }";
0688     QTest::newRow("piecewise3") << "piecewise { 2=2 ? 4, ? 3}" << "4";
0689     
0690     QTest::newRow("sum.dlul") << "w->sum(x : x=(floor(2.5)+w)..(ceiling(2.5)))" << "w->sum(x:x=w+2..3)";
0691     QTest::newRow("sum.times") << "sum(2*x : x=0..y)" << "2*sum(x:x=0..y)";
0692     QTest::newRow("trig") << "sin(x)/cos(x)" << "sin(x)/cos(x)";
0693     
0694     QTest::newRow("mono") << "2*x*y+3*x*y" << "5*x*y";
0695     QTest::newRow("mono1") << "2*y+y" << "3*y";
0696     QTest::newRow("mono2") << "-y+1" << "-y+1";
0697     
0698     QTest::newRow("matrix") << "matrix { matrixrow { x, y, z } }" << "matrix { matrixrow { x, y, z } }";
0699     
0700     //equations
0701     QTest::newRow("eqminus") << "x-3=0" << "x=3";
0702     QTest::newRow("eqplus") << "x+3=0" << "x=-3";
0703     QTest::newRow("eqtimes") << "3x=0" << "x=0";
0704     QTest::newRow("eqtimes1") << "(x-3)*(x-2)=0" << "or(x=3, x=2)";
0705     QTest::newRow("eqdiv") << "x/2=0" << "x=0";
0706     QTest::newRow("eqdiv1") << "(x-1)/2=0" << "x=1";
0707     QTest::newRow("eqdiv2") << "(x*(x-1))/x=0" << "x=1";
0708     QTest::newRow("eqdiv3") << "(x*(x-1))/(x+3)=0" << "or(x=0, x=1)";
0709     QTest::newRow("eqsin") << "sin(x)=0" << "x=0";
0710     QTest::newRow("eqcos") << "cos(x)=1" << "x=0";
0711     QTest::newRow("eqmin") << "x=3-2" << "x=1";
0712     QTest::newRow("different") << "x+3=x+2" << "false";
0713 }
0714 
0715 void AnalitzaTest::testSimplify()
0716 {
0717     QFETCH(QString, expression);
0718     QFETCH(QString, result);
0719     
0720     a->setExpression(Expression(expression, false));
0721     if(!a->isCorrect()) qDebug() << "error:" << a->errors();
0722     QVERIFY(a->isCorrect());
0723     a->simplify();
0724     QCOMPARE(a->expression().toString(), result);
0725 }
0726 
0727 void AnalitzaTest::testEvaluate_data()
0728 {
0729     QTest::addColumn<QStringList>("expression");
0730     QTest::addColumn<QString>("result");
0731     
0732     QStringList script;
0733     script << QStringLiteral("f:=x->x");
0734     script << QStringLiteral("f(x)");
0735     QTest::newRow("function parameter") << script << "x";
0736     
0737     script.clear();
0738     script << QStringLiteral("pu:=n->sum(p**i:i=0..floor(n))");
0739     script << QStringLiteral("pu(3)");
0740     QTest::newRow("calls") << script << "sum(p^i:i=0..3)";
0741 }
0742 
0743 void AnalitzaTest::testEvaluate()
0744 {
0745     QFETCH(QStringList, expression);
0746     QFETCH(QString, result);
0747     
0748     Analitza::Analyzer b;
0749     Expression res;
0750     foreach(const QString &exp, expression) {
0751         Expression e(exp, false);
0752         if(!e.isCorrect()) qDebug() << "XXXX" << e.error();
0753         QVERIFY(e.isCorrect());
0754         
0755         b.setExpression(e);
0756         if(!b.isCorrect()) qDebug() << "XXXX" << b.errors();
0757         QVERIFY(b.isCorrect());
0758         res=b.evaluate();
0759         
0760         if(!b.isCorrect()) qDebug() << "XXXX" << b.errors();
0761         QVERIFY(b.isCorrect());
0762 //         b.calculate(); //we can do that just if we know that all variables doesn't have dependencies
0763     }
0764     QCOMPARE(res.toString(), result);
0765 }
0766 
0767 void AnalitzaTest::testVector()
0768 {
0769     QFETCH(QString, expression);
0770     QFETCH(QString, result);
0771     Expression e(expression, false);
0772     QCOMPARE(e.isCorrect(), true);
0773     
0774     a->setExpression(e);
0775     if(!a->isCorrect()) qDebug() << "error:" << a->errors();
0776     QVERIFY(a->isCorrect());
0777     QCOMPARE(a->calculate().toString(), result);
0778     QCOMPARE(a->evaluate().toString(), result);
0779 }
0780 
0781 void AnalitzaTest::testVector_data()
0782 {
0783     QTest::addColumn<QString>("expression");
0784     QTest::addColumn<QString>("result");
0785 
0786     QTest::newRow("avector") << "vector { 1, 2, 3 }" << "vector { 1, 2, 3 }";
0787     QTest::newRow("card(vect)") << "card(vector { 1, 2, 3 })" << "3";
0788     QTest::newRow("in-vector operations") << "vector { 2+2, 3*3, 3^3 }" << "vector { 4, 9, 27 }";
0789     
0790     QTest::newRow("vect+vect") << "vector { 1, 2, 3 }+vector { 3, 2, 1 }" << "vector { 4, 4, 4 }";
0791     QTest::newRow("vect+vect2") << "vector { 1, 2, 3 }+vector { 3, 2, sin(pi/2) }" << "vector { 4, 4, 4 }";
0792     QTest::newRow("vect*scalar") << "vector { 1, 2, 3 }*3" << "vector { 3, 6, 9 }";
0793     QTest::newRow("scalar*vect") << "3*vector { 1, 2, 3 }" << "vector { 3, 6, 9 }";
0794     
0795     QTest::newRow("sum") << "sum(vector {x,x,x} : x=1..99)" << "vector { 4950, 4950, 4950 }";
0796     QTest::newRow("product") << "product(vector {x,x,x} : x=1..5)" << "vector { 120, 120, 120 }";
0797     
0798     QTest::newRow("selector1+vector") << "selector(1, vector{1,2,3})" << "1";
0799     QTest::newRow("selector2+vector") << "selector(2, vector{1,2,3})" << "2";
0800     QTest::newRow("selector3+vector") << "selector(3, vector{1,2,3})" << "3";
0801     
0802     QTest::newRow("selector1+list") << "selector(1, list{1,2,3})" << "1";
0803     QTest::newRow("selector2+list") << "selector(2, list{1,2,3})" << "2";
0804     QTest::newRow("selector3+list") << "selector(3, union(list{1,2}, list{3}))" << "3";
0805     QTest::newRow("union") << "union(list{1,2}, list{3})" << "list { 1, 2, 3 }";
0806 }
0807 
0808 void AnalitzaTest::testCrash_data()
0809 {
0810     QTest::addColumn<QString>("expression");
0811     
0812     QTest::newRow("undefined variable") << "x";
0813     QTest::newRow("selector overflow") << "selector(9, vector{1,2})";
0814     QTest::newRow("selector underflow") << "selector(0, vector{1,2})";
0815     QTest::newRow("simple piecewise") << "piecewise { pi=0? 3, eq(pi, pi)?33 }";
0816     QTest::newRow("oscarmartinez piecewise") << "piecewise { gt(x,23)?a }";
0817     QTest::newRow("vector+ovf") << "selector(2, vector{x})";
0818     QTest::newRow("wrong func") << "xsin(x)";
0819     QTest::newRow("scalarprod") << "scalarproduct(vector{0}, vector{x,0})";
0820     QTest::newRow("power") << "list{}**2";
0821     QTest::newRow("unary-nested-error") << "-(2/0)";
0822 }
0823 
0824 void AnalitzaTest::testCrash()
0825 {
0826     QFETCH(QString, expression);
0827     Expression e(expression, Expression::isMathML(expression));
0828     QVERIFY(e.isCorrect());
0829     
0830     a->setExpression(e);
0831     a->evaluate();
0832     a->calculate();
0833     
0834     //We don't want it to crash, so we try to
0835     for(int i=0; i<expression.size(); i++)
0836     {
0837         QString aux=expression.left(i);
0838         QString aux1=expression.right(i);
0839         
0840         Expression e1(aux, false);
0841         Expression e2(aux, true);
0842         
0843         Expression e3(aux1, false);
0844         Expression e4(aux1, true);
0845     }
0846 }
0847 
0848 void AnalitzaTest::testOperators_data()
0849 {
0850     QTest::addColumn<int>("i");
0851     
0852     for(int i=Operator::none+1; i<Operator::nOfOps; i++) {
0853         QTest::newRow( Operator::words[i] ) << i;
0854     }
0855 }
0856 
0857 void AnalitzaTest::testOperators()
0858 {
0859     QFETCH(int, i);
0860     Operator o(static_cast<Operator::OperatorType>(i));
0861     QVERIFY(o.nparams()>=-1);
0862     if(!o.isCorrect())
0863         qDebug() << o.toString();
0864     QVERIFY(o.isCorrect());
0865     QCOMPARE(static_cast<Operator::OperatorType>(i), o.operatorType());
0866     QCOMPARE(Operator::toOperatorType(o.toString()), o.operatorType());
0867     
0868     if(o.operatorType()==Operator::function)
0869         return;
0870     
0871 //     QVERIFY(!Analitza::Operations::infer(o.operatorType()).isEmpty() || !Analitza::Operations::inferUnary(o.operatorType()).isEmpty());
0872     
0873     Vector* v=new Vector(3);
0874     v->appendBranch(new Cn(0.));
0875     v->appendBranch(new Cn(1.));
0876     v->appendBranch(new Cn(2.));
0877     
0878     QList<Object*> values=QList<Object*>()    << new Cn(0.)
0879                                             << new Cn(0.5)
0880                                             << new Cn(1.)
0881                                             << new Cn(-1.)
0882                                             << new Cn(-.5)
0883                                             << new Ci(QStringLiteral("x"))
0884                                             << v; //lets try to make it crash
0885     QList<int> params;
0886     if(o.nparams()<0)
0887         params /*<< 0 << 1 << 2*/ << 3;
0888     else
0889         params << o.nparams();
0890     
0891 #ifdef Q_CC_GNU
0892     #warning improve the test for bounded operations
0893 #endif    
0894     if(o.operatorType()==Operator::sum || o.operatorType()==Operator::product) 
0895         return;
0896     
0897     foreach(Object* obj, values) {
0898         foreach(int paramCnt, params) {
0899             Analitza::Apply* apply=new Analitza::Apply;
0900             apply->appendBranch(new Operator(o));
0901             for(; paramCnt>0; paramCnt--)  {
0902                 apply->appendBranch(obj->copy());
0903             }
0904             
0905             if(o.isBounded()) {
0906                 Container *bvar=new Container(Container::bvar);
0907                 apply->appendBranch(bvar);
0908                 
0909                 QList<Object*> bvarValues=QList<Object*>() << new Ci(QStringLiteral("x"));
0910                 foreach(Object* obvar, bvarValues) {
0911                     Analitza::Apply* cc=(Analitza::Apply*) apply->copy();
0912                     Container* bvar=(Container*) cc->bvarCi().at(0);
0913                     bvar->appendBranch(obvar->copy());
0914                     
0915                     Expression e1(cc);
0916                     a->setExpression(e1);
0917                     
0918                     a->calculate();
0919                     a->evaluate();
0920                     a->derivative(QStringLiteral("x"));
0921                 }
0922                 qDeleteAll(bvarValues);
0923             } else {
0924                 Expression e(apply);
0925                 a->setExpression(e);
0926                 a->calculate();
0927                 a->evaluate();
0928                 a->derivative(QStringLiteral("x"));
0929             }
0930         }
0931     }
0932     qDeleteAll(values);
0933     
0934     QList<double> diffValues = QList<double>() << 0. << 0.5 << -0.5 << 1. << -1.;
0935     QString bvar('x');
0936     foreach(double v, diffValues) {
0937         foreach(int paramCnt, params) {
0938             Analitza::Apply *diffApply=new Analitza::Apply;
0939             diffApply->appendBranch(new Operator(Operator::diff));
0940             Container* diffBVar=new Container(Container::bvar);
0941             diffBVar->appendBranch(new Ci(bvar));
0942             diffApply->appendBranch(diffBVar);
0943             
0944             Analitza::Apply* apply=new Analitza::Apply;
0945             apply->appendBranch(new Operator(o));
0946             diffApply->appendBranch(apply);
0947             
0948             for(; paramCnt>0; paramCnt--)
0949                 apply->appendBranch(new Ci(bvar));
0950             
0951             Expression e(diffApply);
0952             a->setExpression(e);
0953             a->calculate();
0954             a->evaluate();
0955             a->simplify();
0956             a->derivative(QStringLiteral("x"));
0957             
0958             Cn* vv = new Cn(v);
0959             QVector<Object*> stack;
0960             stack += vv;
0961             a->derivative(stack);
0962             delete vv;
0963         }
0964     }
0965 }
0966 
0967 
0968 
0969 #include "moc_analitzatest.cpp"