File indexing completed on 2024-05-12 15:19:51
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"