1 /*************************************************************************************
2 * Copyright (C) 2007-2011 by Aleix Pol <aleixpol@kde.org> *
3 * *
4 * This program is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU General Public License *
6 * as published by the Free Software Foundation; either version 2 *
7 * of the License, or (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA *
17 *************************************************************************************/
18
19 #include "analitzatest.h"
20 #include "analyzer.h"
21 #include <cmath>
22
23 #include "apply.h"
24 #include "container.h"
25 #include "variables.h"
26 #include "vector.h"
27 #include "value.h"
28 #include <variable.h>
29 #include <analitzautils.h>
30 #include <QTest>
31 //#include <operations.h>
32
33 using namespace std;
34 using Analitza::Cn;
35 using Analitza::Ci;
36 using Analitza::Vector;
37 using Analitza::Object;
38 using Analitza::Operator;
39 using Analitza::Container;
40 using Analitza::Expression;
41
42 QTEST_MAIN( AnalitzaTest )
43
44 namespace QTest {
45
toString(const Analitza::Cn & cn)46 template <> char *toString(const Analitza::Cn &cn)
47 { return qstrdup(QStringLiteral("Cn(%1)").arg(cn.toString()).toLatin1().constData()); }
48
49 }
50
Q_DECLARE_METATYPE(Cn)51 Q_DECLARE_METATYPE(Cn)
52
53 AnalitzaTest::AnalitzaTest(QObject *parent)
54 : QObject(parent)
55 {}
56
~AnalitzaTest()57 AnalitzaTest::~AnalitzaTest()
58 {}
59
initTestCase()60 void AnalitzaTest::initTestCase()
61 {
62 a=new Analitza::Analyzer;
63 }
64
cleanupTestCase()65 void AnalitzaTest::cleanupTestCase()
66 {
67 delete a;
68 }
69
testTrivialCalculate_data()70 void AnalitzaTest::testTrivialCalculate_data()
71 {
72 QTest::addColumn<QString>("expression");
73 QTest::addColumn<Cn>("result");
74
75 QTest::newRow("a value") << "2" << Cn(2.);
76 QTest::newRow("val.e0") << "12.0e-02" << Cn(12e-2);
77 QTest::newRow("vale") << "12e-2" << Cn(12e-2);
78 QTest::newRow("val") << "12e2" << Cn(12e2);
79
80 QTest::newRow("factorial5") << "factorial(5)" << Cn(120);
81 QTest::newRow("factorial12") << "factorial(12)" << Cn(12*11*10*9*8*7*6*5*4*3*2*1);
82
83 QTest::newRow("simple addition") << "2+2" << Cn(4.);
84 QTest::newRow("simple power") << "2**99" << Cn(pow(2., 99.));
85 QTest::newRow("simple multiplication") << "3*3" << Cn(9.);
86 QTest::newRow("sinus") << "sin(3*3)" << Cn(sin(9.));
87 QTest::newRow("declare") << "x:=3" << Cn(3.);
88 QTest::newRow("sum") << "sum(x : x=1..99)" << Cn(4950.);
89 QTest::newRow("diff") << "(diff(x:x))(1)" << Cn(1.);
90 QTest::newRow("diffz") <<"(diff(z:z))(1)" << Cn(1.);
91
92 QTest::newRow("product") << "product(n : n=1..5)" << Cn(120.);
93 QTest::newRow("factorial") << "factorial(5)" << Cn(120.);
94
95 QTest::newRow("simple piecewise") << "piecewise { pi=0? 3, pi=pi?33 }" << Cn(33.);
96 QTest::newRow("simple piecewise with otherwise") << "piecewise { pi=0? 3, ?33 }" << Cn(33.);
97 QTest::newRow("boolean and") << "and(true,false)" << Cn(false);
98 QTest::newRow("boolean or") << "or(false,true)" << Cn(true);
99 QTest::newRow("boolean not") << "not(false)" << Cn(true);
100 QTest::newRow("lambda") << "(x->x+2)(2)" << Cn(4.);
101 QTest::newRow("lambda2") << "(x->3*x^2)(1)" << Cn(3.);
102 QTest::newRow("lambda3") << "(x->x*sum(t:t=0..3))(2)" << Cn(12.);
103 QTest::newRow("imaginarypow") << "(-4)^(1/4)" << Cn(1, 1);
104 QTest::newRow("imaginaryroot") << "root(-4, 4)" << Cn(1.);
105 QTest::newRow("squareroot-1") << "(-1)^(1/2)" << Cn(0, 1);
106
107 //comprehension
108 QTest::newRow("sum.2bvars") << "sum(x*y : (x, y)=1..3)" << Cn(36.);
109 QTest::newRow("sum.list") << "sum(x : x@list{1,5,44})" << Cn(50.);
110
111 QTest::newRow("sum.sum") << "sum(sum(x : x=0..i) : i=0..10)" << Cn(220.);
112
113 QTest::newRow("exists") << "exists(x : x@list{true,true,false})" << Cn(true);
114 QTest::newRow("forall") << "forall(x : x@list{true,true,false})" << Cn(false);
115 // QTest::newRow("emptysum") << "sum(x : x@list{})" << 0.;
116
117 QTest::newRow("lambdacall") << "f:=x->f(x)" << Cn(0.);
118 QTest::newRow("cpx1") << "i" << Cn(0, 1);
119 QTest::newRow("cpx2") << "i*i" << Cn(-1);
120 QTest::newRow("cpx3") << "2+i*i" << Cn(1);
121 QTest::newRow("complex number") << "3+4*(5-6*i)" << Cn(23, -24);
122 }
123
testTrivialCalculate()124 void AnalitzaTest::testTrivialCalculate()
125 {
126 QFETCH(QString, expression);
127 QFETCH(Cn, result);
128 Expression e(expression, false);
129 if(!e.isCorrect()) qDebug() << "error: " << e.error();
130 QCOMPARE(e.isCorrect(), true);
131
132 a->setExpression(e);
133
134 if(!a->isCorrect()) qDebug() << "error: " << a->errors();
135 QVERIFY(a->isCorrect());
136 QCOMPARE(a->evaluate().toReal(), result);
137 QVERIFY(a->isCorrect());
138 Expression ee=a->calculate();
139 if(!a->isCorrect()) qDebug() << "error: " << a->errors();
140 QVERIFY(a->isCorrect());
141 QCOMPARE(ee.toReal(), result);
142 QVERIFY(a->isCorrect());
143 }
144
testTrivialEvaluate_data()145 void AnalitzaTest::testTrivialEvaluate_data()
146 {
147 QTest::addColumn<QString>("expression");
148 QTest::addColumn<QString>("result");
149
150 QTest::newRow("simple value") << "2" << "2";
151 QTest::newRow("complex") << "i*5" << "5*i";
152 QTest::newRow("simple complex value") << "6*(2+i)" << "12+6*i";
153 QTest::newRow("complex irreductibility") << "i" << "i";
154 QTest::newRow("from complex value") << "i*i" << "-1";
155 QTest::newRow("from power complex") << "power(i, 2)" << "-1";
156 QTest::newRow("sin complex") << "sin(i)" << "1.17520119364*i";
157 QTest::newRow("cos complex") << "cos(5-9*i)" << "1149.26926545-3885.12187972*i";
158 QTest::newRow("complex*complex") << "(5.3-9.8*i)*(-6.2+3.7*i)" << "3.4+80.37*i";
159 QTest::newRow("simple complex/complex") << "i/i" << "1";
160 QTest::newRow("complex/complex") << "(9.3-5.4*i)/(3.6-9.5*i)" << "0.82143203178+0.667667861641*i";
161 QTest::newRow("simple complex conjugate") << "conjugate(i)" << "-i";
162 QTest::newRow("complex conjugate") << "conjugate(-9.3+5.87*i)" << "-9.3-5.87*i";
163 QTest::newRow("complex arg") << "arg(i)" << "1.57079632679";
164 QTest::newRow("complex real part") << "real(45-9*i)" << "45";
165 QTest::newRow("complex imag part") << "imaginary(45-9*i)" << "-9";
166 QTest::newRow("simply complex mod") << "abs(i)" << "1";
167 QTest::newRow("complex mod") << "abs(8-9*i)" << "12.0415945788";
168 QTest::newRow("simple addition") << "2+2" << "4";
169 QTest::newRow("simple addition with var") << "2+x" << "x+2";
170 QTest::newRow("minus irreductibility") << "-x" << "-x";
171 QTest::newRow("minus0") << "x-y" << "x-y";
172 QTest::newRow("minus1") << "minus(x, y, x)" << "-y";
173 QTest::newRow("minus2") << "x-y-y-y-x" << "-3*y";
174 QTest::newRow("minus2.1") << "minus(x,y,y,y,x)" << "-3*y";
175 QTest::newRow("minus3") << "x-x-x-x-x-x" << "-4*x";
176 QTest::newRow("minus3.1") << "x-x-x-x" << "-2*x";
177 QTest::newRow("minus3.2") << "minus(x,x,x,x,x,x)" << "-4*x";
178 QTest::newRow("addition") << "x+x" << "2*x";
179 QTest::newRow("simple polynomial") << "x+x+x**2+x**2" << "2*x+2*x^2";
180 QTest::newRow("simplification of unary minus in times") << "x*(-x)" << "-x^2";
181 QTest::newRow("strange") << "0*x-1*1" << "-1";
182 QTest::newRow("strange2") << "x-x" << "0";
183 QTest::newRow("old leak") << "x^1" << "x";
184 QTest::newRow("declare") << "wockawocka:=3" << "3";
185 QTest::newRow("nested multiplication") << "x*(x+x)" << "2*x^2";
186 QTest::newRow("multiplication") << "x*x" << "x^2";
187 QTest::newRow("undefined function call") << "f(2)" << "f(2)";
188 QTest::newRow("--simplification") << "-(-x)" << "x";
189 QTest::newRow("unneeded --simplification") << "-(x-x)" << "0";
190 QTest::newRow("minus order") << "1-x" << "-x--1";
191 QTest::newRow("minus order2") << "x-1" << "x-1";
192 QTest::newRow("after simp(minus) --simplification") << "-(x-x-x)" << "x";
193 QTest::newRow("and") << "and(6>5, 4<5)" << "true";
194 QTest::newRow("or") << "or(6>5, 6<5)" << "true";
195
196 QTest::newRow("sum") << "sum(n : n=1..99)" << "4950";
197 QTest::newRow("sum times") << "x*sum(n : n=0..99)" << "4950*x";
198 QTest::newRow("unrelated sum") << "sum(x : n=0..99)" << "100*x";
199
200 QTest::newRow("product") << "product(n : n=1..5)" << "120";
201 QTest::newRow("factorial") << "factorial(5)" << "120";
202
203 QTest::newRow("simple piecewise") << "piecewise { eq(pi,0)? 3, eq(pi, pi)?33}" << "33";
204 QTest::newRow("simple piecewise with otherwise") << "piecewise { eq(pi,0)? 3, ?33}" << "33";
205
206 QTest::newRow("lambda") << "f:=q->2" << "q->2";
207 // QTest::newRow("selector lambda") << "selector(2, vector{x->x, x->x+2})" << "x->x+2";
208 // QTest::newRow("boolean and") << "and(x,0)" << "false";
209
210 QTest::newRow("irreductible vector") << "vector { x, y, z }" << "vector { x, y, z }";
211 QTest::newRow("in-vector operations") << "vector { x+x, y+y, z-z }" << "vector { 2*x, 2*y, 0 }";
212
213 QTest::newRow("vect+vect") << "x+vector { 2, 3, 4 }+vector { 4, 3, 2 }" << "x+vector { 6, 6, 6 }";
214 QTest::newRow("vect+2vect") << "2*vector { x, y, z }+vector{x,y,z}" << "3*vector { x, y, z }";
215 QTest::newRow("vect+null") << "vector { x, y, z }+vector{0,0,0}" << "vector { x, y, z }";
216 QTest::newRow("card") << "card(vector { x, y, z })" << "3";
217 QTest::newRow("card+var") << "card(x)" << "card(x)";
218
219 QTest::newRow("selector+idx") << "selector(1, vector{x,y,z})" << "x";
220 QTest::newRow("selector+var") << "(vector { x, y, z })[x]" << "vector { x, y, z }[x]";
221 QTest::newRow("selector+impossible") << "v[1]" << "v[1]";
222
223 QTest::newRow("in lists") << "list{w+w}" << "list { 2*w }";
224 QTest::newRow("lists") << "union(list{w}, list{x}, list{y,z})" << "list { w, x, y, z }";
225 QTest::newRow("lists2") << "union(list{w}, x, list{y}, list{z})" << "union(list { w }, x, list { y, z })";
226
227 QTest::newRow("sum.2bvars") << "sum(x*w : (x, y)=1..3)" << "18*w";
228 QTest::newRow("sum.list") << "sum(x+y : x@list{x,y,z})" << "x+4*y+z";
229
230 QTest::newRow("forall") << "forall(x : x@list{x,true,true})" << "forall(x:x@list { x, true, true })";
231 QTest::newRow("exists") << "exists(x : x@list{x,false,false})" << "exists(x:x@list { x, false, false })";
232
233 QTest::newRow("map") << "map(x->x**2, list {1,2,3})" << "list { 1, 4, 9 }";
234 QTest::newRow("filter") << "filter(x->x>5, list {3,4,5,6,7})" << "list { 6, 7 }";
235
236 QTest::newRow("forall1") << "forall(a<w:a@list { 2 })" << "2<w";
237
238 QTest::newRow("matrix") << "matrix { matrixrow { 1, 2 } }" << "matrix { matrixrow { 1, 2 } }";
239 QTest::newRow("matrix+") << "matrix { matrixrow { 1, 2 } }+matrix{ matrixrow { 1, 2 } }" << "matrix { matrixrow { 2, 4 } }";
240 QTest::newRow("matrix++") << "matrix { matrixrow { 5, 6 }, matrixrow { 4, 0 }}+matrix { matrixrow { 2, 3 }, matrixrow { 4, 0 }}" << "matrix { matrixrow { 7, 9 }, matrixrow { 8, 0 } }";
241 //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.)
242 //QTest::newRow("matrix+++") << "matrix { matrixrow { vector { 1, 2 } } }+matrix { matrixrow { vector { 1.8, 2.4 } } }" << "matrix { matrixrow { vector { 2.8, 4.4 } } }";
243 QTest::newRow("matrix@") << "selector(1, matrix { matrixrow { 1, 2 } })" << "vector { 1, 2 }";
244 QTest::newRow("matrix@@") << "selector(1, selector(1, matrix { matrixrow { 1, 2 } }))" << "1";
245 QTest::newRow("scalar multiplication of matrix") << "3*matrix { matrixrow { 5, 6 }, matrixrow { 4, 0 }}" << "matrix { matrixrow { 15, 18 }, matrixrow { 12, 0 } }";
246 QTest::newRow("transpose vector") << "transpose(vector{12,45})" << "matrix { matrixrow { 12, 45 } }";
247 QTest::newRow("row x column") << "matrix { matrixrow { 1, 2 } }*matrix { matrixrow { 3 }, matrixrow { 5 } }" << "matrix { matrixrow { 13 } }";
248 QTest::newRow("column x row") << "matrix { matrixrow { 3 }, matrixrow { 5 } }*matrix { matrixrow { 1, 2 } }" << "matrix { matrixrow { 3, 6 }, matrixrow { 5, 10 } }";
249 QTest::newRow("row x vector") << "matrix { matrixrow { 1, 2 } }*vector{ 3, 5 }" << "vector { 13 }";
250 QTest::newRow("vector x row") << "vector{ 3, 5 }*matrix { matrixrow { 1, 2 } }" << "matrix { matrixrow { 3, 6 }, matrixrow { 5, 10 } }";
251 QTest::newRow("vector x transpose(vector)") << "vector{ 3, 5 }*transpose(vector{1,2})" << "matrix { matrixrow { 3, 6 }, matrixrow { 5, 10 } }";
252 QTest::newRow("matrix x vector") << "matrix { matrixrow { 3, 3 }, matrixrow { 2, 2 }, matrixrow { 3, 4 } }*vector{ 1, 2 }" << "vector { 9, 6, 11 }";
253 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 } }";
254 QTest::newRow("matrix^0") << "power(matrix { matrixrow { 3, 3 }, matrixrow { 2, 2 } }, 0)" << "matrix { matrixrow { 1, 0 }, matrixrow { 0, 1 } }";
255 QTest::newRow("matrix^1") << "power(matrix { matrixrow { 3, 3 }, matrixrow { 2, 2 } }, 1)" << "matrix { matrixrow { 3, 3 }, matrixrow { 2, 2 } }";
256 QTest::newRow("matrix^2") << "power(matrix { matrixrow { 3, 3 }, matrixrow { 2, 2 } }, 2)" << "matrix { matrixrow { 15, 15 }, matrixrow { 10, 10 } }";
257 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 } }";
258 QTest::newRow("matrix^6464") << "power(matrix { matrixrow { 1.0019 } }, 6464)" << "matrix { matrixrow { 213191.74219 } }";
259 }
260
testTrivialEvaluate()261 void AnalitzaTest::testTrivialEvaluate()
262 {
263 QFETCH(QString, expression);
264 QFETCH(QString, result);
265
266 Expression e(expression, false);
267 a->setExpression(e);
268 if(!a->isCorrect())
269 qDebug() << "errors:" << a->errors();
270
271 qDeleteAll(*a->variables());
272 a->variables()->clear();
273 a->variables()->initializeConstants();
274
275 QVERIFY(a->isCorrect());
276 QCOMPARE(a->evaluate().toString(), result);
277 }
278
testDerivativeSimple_data()279 void AnalitzaTest::testDerivativeSimple_data()
280 {
281 QTest::addColumn<QString>("expression");
282 QTest::addColumn<QString>("result");
283
284 QTest::newRow("dumb") << "x" << "1";
285 QTest::newRow("simple polynomial") << "x^3+1" << "3*x^2";
286 QTest::newRow("power and sinus") << "x^2+sin(x)" << "2*x+cos(x)";
287 QTest::newRow("power") << "x^2" << "2*x";
288 QTest::newRow("division") << "1/x" << "-1/x^2";
289 QTest::newRow("logarithm") << "ln x" << "1/x";
290 QTest::newRow("times") << "x*y" << "y";
291 QTest::newRow("powere") << "e^x" << "e^x"; // power derivative and logarithm simplification
292 QTest::newRow("chain rule") << "sin(x**2)" << "2*x*cos(x^2)";
293 QTest::newRow("tangent") << "tan(x**2)" << "(2*x)/cos(x^2)^2";
294 QTest::newRow("piecewise") << "piecewise { x<0 ? x**2, ? x } " << "piecewise { x<0 ? 2*x, ? 1 }";
295 QTest::newRow("lambda") << "x->3" << "0";
296 QTest::newRow("timesminus") << "1-x*sin(x)" << "-sin(x)-x*cos(x)";
297 QTest::newRow("timesminus2") << "cos(x)-x*sin(x)" << "-2*sin(x)-x*cos(x)";
298 QTest::newRow("log") << "log(x)" << "1/(2.30258509299*x)";
299 QTest::newRow("vector") << "vector { x, x^2 }" << "vector { 1, 2*x }";
300 QTest::newRow("exp") << "exp(x**2)" << "2*x*exp(x^2)";
301 QTest::newRow("halfx") << "(1/2)*x" << "0.5";
302 QTest::newRow("halfx2") << "1/2 x" << "-2/(2*x)^2"; //TODO: could improve the simplification
303 }
304
testDerivativeSimple()305 void AnalitzaTest::testDerivativeSimple()
306 {
307 QFETCH(QString, expression);
308 QFETCH(QString, result);
309
310 qDeleteAll(*a->variables());
311 a->variables()->clear();
312 a->variables()->initializeConstants();
313
314 Expression e(expression, false);
315 a->setExpression(e);
316 QVERIFY(a->isCorrect());
317 a->setExpression(a->derivative(QStringLiteral("x")));
318 a->simplify();
319 Expression deriv=a->expression();
320 QCOMPARE(deriv.toString(), QString(QStringLiteral("x->")+result));
321 if(!a->isCorrect()) qDebug() << "errors: " << a->errors();
322 QVERIFY(a->isCorrect());
323
324 double val=1.;
325 QVector<Object*> vars;
326 vars.append(new Cn(val));
327
328 a->setExpression(Expression("x->"+expression, false));
329 double valCalc=a->derivative(vars);
330 qDeleteAll(vars);
331
332 if(a->isCorrect()) {
333 Expression ee(QStringLiteral("(x->%1)(%2)").arg(result).arg(val));
334 a->setExpression(ee);
335 QVERIFY(a->isCorrect());
336
337 Expression r=a->calculate();
338
339 if(a->isCorrect())
340 QCOMPARE(QString::number(valCalc).left(5), QString::number(r.toReal().value()).left(5));
341 }
342 a->setExpression(Expression("diff("+expression+":x)", false));
343 a->simplify();
344 QVERIFY(a->isCorrect());
345 deriv=a->evaluate();
346
347 QCOMPARE(deriv.toString(), QString(QStringLiteral("x->")+result));
348 QVERIFY(a->isCorrect());
349 }
350
testCorrection_data()351 void AnalitzaTest::testCorrection_data()
352 {
353 QTest::addColumn<QStringList>("expression");
354 QTest::addColumn<QString>("result");
355
356 QStringList script;
357
358 script.clear();
359 script << QStringLiteral("f:=y->y*y");
360 script << QStringLiteral("f(i)");
361 QTest::newRow("from complex function") << script << "-1";
362
363 script.clear();
364 script << QStringLiteral("n:=2");
365 script << QStringLiteral("n+1");
366 QTest::newRow("simple") << script << "3";
367
368 script.clear();
369 script << QStringLiteral("f:=x->x+2");
370 script << QStringLiteral("f(1)");
371 QTest::newRow("simple func") << script << "3";
372
373 // script.clear();
374 // script << "t:=(c, c1, c2, t1, t2)->(t2-t1)/(c2-c1)*(c-c1)+t1";
375 // script << "t(1,2,3,4,5)";
376 // QTest::newRow("long func") << script << "3";
377
378 script.clear();
379 script << QStringLiteral("fact:=n->piecewise { n=1?1, ? n*fact(n-1) }");
380 script << QStringLiteral("fact(5)");
381 QTest::newRow("piecewise factorial") << script << "120";
382
383 script.clear();
384 script << QStringLiteral("fib:=n->piecewise { n=0?0, n=1?1, ?fib(n-1)+fib(n-2) }");
385 script << QStringLiteral("fib(6)");
386 QTest::newRow("piecewise fibonacci") << script << "8";
387
388 script.clear();
389 script << QStringLiteral("n:=vector{1}");
390 script << QStringLiteral("func:=n->n+1");
391 script << QStringLiteral("func(5)");
392 QTest::newRow("simple function, shadowed parameter") << script << "6";
393
394 script.clear();
395 script << QStringLiteral("x:=3");
396 script << QStringLiteral("x*sum(x : x=0..99)");
397 QTest::newRow("bounded scope") << script << "14850";
398
399 script.clear();
400 script << QStringLiteral("f:=diff(x^2:x)");
401 script << QStringLiteral("f(3)");
402 QTest::newRow("diff function") << script << "6";
403
404 script.clear();
405 script << QStringLiteral("fv:=vector{x->x, x->x+2}");
406 script << QStringLiteral("(selector(1, fv))(1)");
407 script << QStringLiteral("(selector(1, fv))(1)+(selector(2, fv))(2)");
408 QTest::newRow("selector+lambda") << script << "5";
409
410 QTest::newRow("lists") << QStringList(QStringLiteral("union(list{0}, list{1}, list{2,3})")) << "list { 0, 1, 2, 3 }";
411
412 script.clear();
413 script << QStringLiteral("valueTableRec := (func, antimages, i) ->"
414 "piecewise { i=0 ? list{}, "
415 "? union(list{func(selector(i, antimages))}, valueTableRec(func, antimages, i-1))"
416 " }")
417 << QStringLiteral("valueTableRec(x->x**2, list{1,2,3}, 3)");
418 QTest::newRow("yay") << script << "list { 9, 4, 1 }";
419
420 script.clear();
421 script << QStringLiteral("f:=ff->(y->ff(y))");
422 // script << "f(x->x**2)";
423 script << QStringLiteral("(f(x->x**2))(2)");
424 QTest::newRow("yay2") << script << "4";
425
426 script.clear();
427 script << QStringLiteral("findroot:=(der, dee)->piecewise { dee>1 ?"
428 "piecewise { rem(der, dee)=0 ? true, ? findroot(der, dee-1) }, ? false }");
429 script << QStringLiteral("isprime:=n->not(findroot(n, floor(root(n, 2))))");
430 script << QStringLiteral("primes:=(from, to)->piecewise { or(from<0, to<0, from>=to)? list{},"
431 " isprime(from)? union(list{from}, primes(from+1, to)), ? primes(from+1, to)}");
432 script << QStringLiteral("primes(1, 25)");
433 QTest::newRow("primes") << script << "list { 1, 2, 3, 5, 7, 11, 13, 17, 19, 23 }";
434
435 script.clear();
436 script << QStringLiteral("f:=v->sum(i**2 : i@v)");
437 script << QStringLiteral("f(list{1,2,3})");
438 script << QStringLiteral("f(vector{1,2,3})");
439 QTest::newRow("sum.list") << script << "14";
440
441 script.clear();
442 script << QStringLiteral("f:=o->vector { x->x+o, x->x*o }");
443 script << QStringLiteral("vector { selector(1, f(3)), selector(1, f(4)) }");
444 QTest::newRow("lambda") << script << "vector { x->x+3, x->x+4 }";
445
446 script.clear();
447 script << QStringLiteral("comb:=(n, i)->factorial(n)/(factorial(i)*factorial(n-i))")
448 << QStringLiteral("p:=10^-2")
449 << QStringLiteral("pu:=n->sum( comb(n,i)*p^(n-i)*(1-p)*sum(x:x=0..i) :i=0..(floor((n-1)/2)))")
450 << QStringLiteral("pu(5)");
451
452 #if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) && QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
453 QTest::newRow("bug241047") << script << "2.97495e-5";
454 #else
455 QTest::newRow("bug241047") << script << "2.97495e-05";
456 #endif
457
458 script.clear();
459 script << QStringLiteral("comb:=(n, i)->factorial(n)/(factorial(i)*factorial(n-i))")
460 << QStringLiteral("probability:=(place, case, totalprobability,"
461 "positive, negative)->(comb(place,"
462 "case)*(positive/totalprobability)^case)*(negative/totalprobability)^(place-case)")
463 << QStringLiteral("sum(probability(5, t, 6, 1, 5):t=0..5)");
464
465 QTest::newRow("probabilities") << script << "1";
466
467 script.clear();
468 script
469 << QStringLiteral("rtail:=(elems,i)->piecewise { card(elems)>=i ? union(list{elems[i]}, rtail(elems, i+1)), ? list{} }")
470 << QStringLiteral("tail:=elems->rtail(elems,2)")
471 << QStringLiteral("foldr:=(f,z,elems)->piecewise {card(elems)=0 ? z, ? f(elems[1], foldr(f, z, tail(elems))) }")
472 << QStringLiteral("sumsum:=elems->foldr((x,y)->x+y, 0, elems)")
473 << QStringLiteral("sumsum(list{1,2,3})");
474 QTest::newRow("sumsum") << script << "6";
475
476 script.clear();
477 script
478 << QStringLiteral("rtail:=(elems,i)->piecewise { card(elems)>=i ? union(list{elems[i]}, rtail(elems, i+1)), ? list{} }")
479 << QStringLiteral("tail:=elems->rtail(elems,2)")
480 << QStringLiteral("foldr:=(f,z,elems)->piecewise {card(elems)=0 ? z, ? f(elems[1], foldr(f, z, tail(elems))) }")
481 << QStringLiteral("cfilter:=(condition,elems)->foldr((v,pred)->piecewise{ condition(v) ? union(list{v}, pred), ? pred }, list{}, elems)")
482
483 << QStringLiteral("cfilter(x->x>3, list{1,2,3,4,5})");
484 QTest::newRow("custom filter") << script << "list { 4, 5 }";
485
486 script.clear();
487 script
488 << QStringLiteral("pmap:=(func, list, i)->piecewise { i>=card(list)+1 ? list {}, ? union(list { func(selector(i, list)) }, pmap(func, list, i+1)) }")
489 << QStringLiteral("cmap:=(func, list)->pmap(func, list, 1)")
490 << QStringLiteral("refImport:=x->x>3")
491 << QStringLiteral("importedRef:=imports->cmap(refImport, imports)")
492
493 << QStringLiteral("importedRef(list{1,2,3,4,5})");
494 QTest::newRow("custom map") << script << "list { false, false, false, true, true }";
495
496 script.clear();
497 script
498 << QStringLiteral("f:=v->sum(i**2 : i@v)")
499 << QStringLiteral("g:=(u, v)->f(u)+f(v)")
500 << QStringLiteral("g(vector{1,2}, vector{3,4})");
501 QTest::newRow("aaa") << script << "30";
502
503 script.clear();
504 script << QStringLiteral("f := (w,zz) -> list{zz} | acs->forall(a<w : a@acs)");
505 script << QStringLiteral("f(2,3)");
506 QTest::newRow("lambda1") << script << "false";
507
508 script.clear();
509 script << QStringLiteral("f := x -> matrix { matrixrow { x, x } }");
510 script << QStringLiteral("f(90)");
511 QTest::newRow("matrix-f") << script << "matrix { matrixrow { 90, 90 } }";
512
513 script.clear();
514 script << QStringLiteral("rotate := angle -> matrix { matrixrow { cos(angle), -sin(angle) }, matrixrow { sin(angle), cos(angle) } }");
515 script << QStringLiteral("rotate(90) * vector { 20, 20 }");
516 QTest::newRow("rotate-vector") << script << "vector { -26.8414055946, 8.91846094943 }";
517 }
518
519 //testCalculate
testCorrection()520 void AnalitzaTest::testCorrection()
521 {
522 QFETCH(QStringList, expression);
523 QFETCH(QString, result);
524
525 Expression last;
526 Analitza::Analyzer b1;
527 foreach(const QString &exp, expression) {
528 Expression e(exp, false);
529 if(!e.isCorrect()) qDebug() << "error:" << e.error();
530 QVERIFY(e.isCorrect());
531
532 b1.setExpression(e);
533
534 if(!b1.isCorrect()) qDebug() << "errors: " << b1.errors();
535 QVERIFY(b1.isCorrect());
536 last = b1.calculate();
537 if(!b1.isCorrect()) qDebug() << "errors:" << e.toString() << b1.errors();
538 QVERIFY(b1.isCorrect());
539 }
540 QCOMPARE(last.toString(), result);
541
542 Analitza::Analyzer b;
543 Expression evalResult;
544 foreach(const QString &exp, expression) {
545 Expression e(exp, false);
546 QVERIFY(e.isCorrect());
547
548 b.setExpression(e);
549 QVERIFY(b.isCorrect());
550 evalResult=b.evaluate();
551 QVERIFY(b.isCorrect());
552 }
553 QCOMPARE(evalResult.toString(), result);
554
555 QString script = expression.join(QStringLiteral("\n"));
556 script+=QLatin1String("\n\n\n");
557 QTextStream stream(&script);
558 a->importScript(&stream);
559 QVERIFY(a->isCorrect());
560 }
561
testTypeUncorrection()562 void AnalitzaTest::testTypeUncorrection()
563 {
564 QFETCH(QStringList, expression);
565
566 bool correct=false;
567 Analitza::Analyzer b;
568
569 foreach(const QString &exp, expression) {
570 Expression e(exp, false);
571 b.setExpression(e);
572 correct=b.isCorrect();
573
574 if(correct)
575 b.calculate().toReal().value();
576
577 if(!correct || !b.isCorrect())
578 break;
579 }
580 QVERIFY(!correct);
581 }
582
testTypeUncorrection_data()583 void AnalitzaTest::testTypeUncorrection_data()
584 {
585 QTest::addColumn<QStringList>("expression");
586 QTest::newRow("vect+sin") << QStringList(QStringLiteral("3+sin(vector{3,4,2})"));
587 QTest::newRow("scalar+card") << QStringList(QStringLiteral("card(3)"));
588 QTest::newRow("wrong operation") << QStringList(QStringLiteral("lcm(vector{0}, vector{0})"));
589
590 QStringList script;
591 script << QStringLiteral("x:=3");
592 script << QStringLiteral("x(3)");
593 QTest::newRow("value call") << script;
594
595 script.clear();
596 script << QStringLiteral("f:=(x,y)->x*y");
597 script << QStringLiteral("f(3)");
598 QTest::newRow("call missing parameter") << script;
599 }
600
testUncorrection_data()601 void AnalitzaTest::testUncorrection_data()
602 {
603 QTest::addColumn<QStringList>("expression");
604 QTest::newRow("summatory with uncorrect downlimit1") << QStringList(QStringLiteral("sum(x : x=y..3)"));
605 QTest::newRow("summatory with uncorrect downlimit2") << QStringList(QStringLiteral("sum(x : x=x..3)"));
606 QTest::newRow("wrong sum") << QStringList(QStringLiteral("sum(x : x=10..0)"));
607
608 QStringList script;
609 script << QStringLiteral("a:=b");
610 script << QStringLiteral("b:=a");
611 QTest::newRow("var dependency cycle") << script;
612
613
614 QTest::newRow("unsupported diff") << QStringList(QStringLiteral("diff(arccos(x):x)"));
615 }
616
testUncorrection()617 void AnalitzaTest::testUncorrection()
618 {
619 QFETCH(QStringList, expression);
620
621 bool correct=false;
622 Analitza::Analyzer b;
623 foreach(const QString &exp, expression) {
624 Expression e(exp, false);
625 correct=e.isCorrect();
626
627 if(correct) {
628 b.setExpression(e);
629 Expression res=b.evaluate();
630 correct=b.isCorrect();
631 }
632 // qDebug() << "cycle" << b.isCorrect() << e.toString() << b.errors();
633 if(!correct) break;
634 }
635 // QVERIFY(!correct);
636
637 foreach(const QString &exp, expression) {
638 Expression e(exp, false);
639 correct=e.isCorrect();
640 b.setExpression(e);
641
642 if(correct) {
643 /*double val=*/b.calculate().toReal().value();
644 correct=b.isCorrect();
645 // qDebug() << "aaaaaaaaagh" << b.errors() << val << correct;
646 }
647 if(!correct) break;
648 }
649 QVERIFY(!correct);
650 }
651
testSimplify_data()652 void AnalitzaTest::testSimplify_data()
653 {
654 QTest::addColumn<QString>("expression");
655 QTest::addColumn<QString>("result");
656
657 QTest::newRow("identity") << "1*x" << "x";
658 QTest::newRow("minus") << "x-x-x" << "-x";
659 QTest::newRow("minus1") << "x-1" << "x-1";
660 QTest::newRow("minus2") << "x-2*x" << "-x";
661 QTest::newRow("compensation") << "-(4*x)+3*x" << "-x";
662 QTest::newRow("compensation1") << "(-(4*x))+3*x" << "-x";
663 QTest::newRow("compensation2") << "((-4)*x)+3*x" << "-x";
664 QTest::newRow("compensation*") << "-(x^4)*x^3" << "-x^7";
665 QTest::newRow("powers") << "3**x*5**x" << "3^x*5^x";
666 QTest::newRow("poli1") << "x-1+2" << "x+1";
667 QTest::newRow("poli2") << "(x+y)-z" << "x--y-z";
668 QTest::newRow("poli3") << "2-13-(x+1)" << "-x-12";
669 QTest::newRow("poli4") << "-x-1-2-4" << "-x-7";
670 QTest::newRow("poli4.0") << "-x-y-z" << "-x-y-z";
671 QTest::newRow("poli4.1") << "minus(-x, 1, 2, 4)" << "-x-7";
672 QTest::newRow("poli5") << "y+3*(x-1)" << "y+3*(x-1)";
673 // QTest::newRow("powerscomb") << "3**x*3**x" << "9^x";
674 QTest::newRow("no var") << "2+2" << "4";
675 QTest::newRow("simple") << "x+x" << "2*x";
676 QTest::newRow("lambda") << "(x->x+1)(2)" << "3";
677 QTest::newRow("lambda1") << "(x->x+1)(y)" << "y+1";
678 QTest::newRow("lambda2") << "(x->x+1)(x+1)" << "x+2";
679 QTest::newRow("lambda3") << "zz->(x->card(x)>0)(list{zz})" << "zz->card(list { zz })>0";
680 QTest::newRow("lambda4") << "f(3) | a-> (g(a) | b-> useForIndex(a, b))" << "(a->(b->useForIndex(a, b))(g(a)))(f(3))";
681 // QTest::newRow("lambda3")<< "(x->x+x)(y)" << "2*y";
682 QTest::newRow("diff") << "diff(x^2:x)" << "x->2*x";
683 QTest::newRow("sum times") << "sum(n*x : n=0..99)" << "4950*x";
684 QTest::newRow("levelout") << "-y-(x+y)" << "-2*y-x";
685 QTest::newRow("sum") << "n->sum((s+n) * s : s=0..9)" << "n->sum((s+n)*s:s=0..9)";
686 QTest::newRow("sum.sum") << "k->sum(sum(x:x=0..s):s=0..k)" << "k->sum(sum(x:x=0..s):s=0..k)";
687 QTest::newRow("unrelated sum") << "sum(x : n=0..99)" << "100*x";
688 QTest::newRow("ln") << "ln(x)" << "ln(x)";
689
690 QTest::newRow("piecewise1") << "piecewise { 1=2 ? 4, ? 3}" << "3";
691 QTest::newRow("piecewise2") << "piecewise { x=2 ? 4, ? 3}" << "piecewise { x=2 ? 4, ? 3 }";
692 QTest::newRow("piecewise3") << "piecewise { 2=2 ? 4, ? 3}" << "4";
693
694 QTest::newRow("sum.dlul") << "w->sum(x : x=(floor(2.5)+w)..(ceiling(2.5)))" << "w->sum(x:x=w+2..3)";
695 QTest::newRow("sum.times") << "sum(2*x : x=0..y)" << "2*sum(x:x=0..y)";
696 QTest::newRow("trig") << "sin(x)/cos(x)" << "sin(x)/cos(x)";
697
698 QTest::newRow("mono") << "2*x*y+3*x*y" << "5*x*y";
699 QTest::newRow("mono1") << "2*y+y" << "3*y";
700 QTest::newRow("mono2") << "-y+1" << "-y+1";
701
702 QTest::newRow("matrix") << "matrix { matrixrow { x, y, z } }" << "matrix { matrixrow { x, y, z } }";
703
704 //equations
705 QTest::newRow("eqminus") << "x-3=0" << "x=3";
706 QTest::newRow("eqplus") << "x+3=0" << "x=-3";
707 QTest::newRow("eqtimes") << "3x=0" << "x=0";
708 QTest::newRow("eqtimes1") << "(x-3)*(x-2)=0" << "or(x=3, x=2)";
709 QTest::newRow("eqdiv") << "x/2=0" << "x=0";
710 QTest::newRow("eqdiv1") << "(x-1)/2=0" << "x=1";
711 QTest::newRow("eqdiv2") << "(x*(x-1))/x=0" << "x=1";
712 QTest::newRow("eqdiv3") << "(x*(x-1))/(x+3)=0" << "or(x=0, x=1)";
713 QTest::newRow("eqsin") << "sin(x)=0" << "x=0";
714 QTest::newRow("eqcos") << "cos(x)=1" << "x=0";
715 QTest::newRow("eqmin") << "x=3-2" << "x=1";
716 QTest::newRow("different") << "x+3=x+2" << "false";
717 }
718
testSimplify()719 void AnalitzaTest::testSimplify()
720 {
721 QFETCH(QString, expression);
722 QFETCH(QString, result);
723
724 a->setExpression(Expression(expression, false));
725 if(!a->isCorrect()) qDebug() << "error:" << a->errors();
726 QVERIFY(a->isCorrect());
727 a->simplify();
728 QCOMPARE(a->expression().toString(), result);
729 }
730
testEvaluate_data()731 void AnalitzaTest::testEvaluate_data()
732 {
733 QTest::addColumn<QStringList>("expression");
734 QTest::addColumn<QString>("result");
735
736 QStringList script;
737 script << QStringLiteral("f:=x->x");
738 script << QStringLiteral("f(x)");
739 QTest::newRow("function parameter") << script << "x";
740
741 script.clear();
742 script << QStringLiteral("pu:=n->sum(p**i:i=0..floor(n))");
743 script << QStringLiteral("pu(3)");
744 QTest::newRow("calls") << script << "sum(p^i:i=0..3)";
745 }
746
testEvaluate()747 void AnalitzaTest::testEvaluate()
748 {
749 QFETCH(QStringList, expression);
750 QFETCH(QString, result);
751
752 Analitza::Analyzer b;
753 Expression res;
754 foreach(const QString &exp, expression) {
755 Expression e(exp, false);
756 if(!e.isCorrect()) qDebug() << "XXXX" << e.error();
757 QVERIFY(e.isCorrect());
758
759 b.setExpression(e);
760 if(!b.isCorrect()) qDebug() << "XXXX" << b.errors();
761 QVERIFY(b.isCorrect());
762 res=b.evaluate();
763
764 if(!b.isCorrect()) qDebug() << "XXXX" << b.errors();
765 QVERIFY(b.isCorrect());
766 // b.calculate(); //we can do that just if we know that all variables doesn't have dependencies
767 }
768 QCOMPARE(res.toString(), result);
769 }
770
testVector()771 void AnalitzaTest::testVector()
772 {
773 QFETCH(QString, expression);
774 QFETCH(QString, result);
775 Expression e(expression, false);
776 QCOMPARE(e.isCorrect(), true);
777
778 a->setExpression(e);
779 if(!a->isCorrect()) qDebug() << "error:" << a->errors();
780 QVERIFY(a->isCorrect());
781 QCOMPARE(a->calculate().toString(), result);
782 QCOMPARE(a->evaluate().toString(), result);
783 }
784
testVector_data()785 void AnalitzaTest::testVector_data()
786 {
787 QTest::addColumn<QString>("expression");
788 QTest::addColumn<QString>("result");
789
790 QTest::newRow("avector") << "vector { 1, 2, 3 }" << "vector { 1, 2, 3 }";
791 QTest::newRow("card(vect)") << "card(vector { 1, 2, 3 })" << "3";
792 QTest::newRow("in-vector operations") << "vector { 2+2, 3*3, 3^3 }" << "vector { 4, 9, 27 }";
793
794 QTest::newRow("vect+vect") << "vector { 1, 2, 3 }+vector { 3, 2, 1 }" << "vector { 4, 4, 4 }";
795 QTest::newRow("vect+vect2") << "vector { 1, 2, 3 }+vector { 3, 2, sin(pi/2) }" << "vector { 4, 4, 4 }";
796 QTest::newRow("vect*scalar") << "vector { 1, 2, 3 }*3" << "vector { 3, 6, 9 }";
797 QTest::newRow("scalar*vect") << "3*vector { 1, 2, 3 }" << "vector { 3, 6, 9 }";
798
799 QTest::newRow("sum") << "sum(vector {x,x,x} : x=1..99)" << "vector { 4950, 4950, 4950 }";
800 QTest::newRow("product") << "product(vector {x,x,x} : x=1..5)" << "vector { 120, 120, 120 }";
801
802 QTest::newRow("selector1+vector") << "selector(1, vector{1,2,3})" << "1";
803 QTest::newRow("selector2+vector") << "selector(2, vector{1,2,3})" << "2";
804 QTest::newRow("selector3+vector") << "selector(3, vector{1,2,3})" << "3";
805
806 QTest::newRow("selector1+list") << "selector(1, list{1,2,3})" << "1";
807 QTest::newRow("selector2+list") << "selector(2, list{1,2,3})" << "2";
808 QTest::newRow("selector3+list") << "selector(3, union(list{1,2}, list{3}))" << "3";
809 QTest::newRow("union") << "union(list{1,2}, list{3})" << "list { 1, 2, 3 }";
810 }
811
testCrash_data()812 void AnalitzaTest::testCrash_data()
813 {
814 QTest::addColumn<QString>("expression");
815
816 QTest::newRow("undefined variable") << "x";
817 QTest::newRow("selector overflow") << "selector(9, vector{1,2})";
818 QTest::newRow("selector underflow") << "selector(0, vector{1,2})";
819 QTest::newRow("simple piecewise") << "piecewise { pi=0? 3, eq(pi, pi)?33 }";
820 QTest::newRow("oscarmartinez piecewise") << "piecewise { gt(x,23)?a }";
821 QTest::newRow("vector+ovf") << "selector(2, vector{x})";
822 QTest::newRow("wrong func") << "xsin(x)";
823 QTest::newRow("scalarprod") << "scalarproduct(vector{0}, vector{x,0})";
824 QTest::newRow("power") << "list{}**2";
825 QTest::newRow("unary-nested-error") << "-(2/0)";
826 }
827
testCrash()828 void AnalitzaTest::testCrash()
829 {
830 QFETCH(QString, expression);
831 Expression e(expression, Expression::isMathML(expression));
832 QVERIFY(e.isCorrect());
833
834 a->setExpression(e);
835 a->evaluate();
836 a->calculate();
837
838 //We don't want it to crash, so we try to
839 for(int i=0; i<expression.size(); i++)
840 {
841 QString aux=expression.left(i);
842 QString aux1=expression.right(i);
843
844 Expression e1(aux, false);
845 Expression e2(aux, true);
846
847 Expression e3(aux1, false);
848 Expression e4(aux1, true);
849 }
850 }
851
testOperators_data()852 void AnalitzaTest::testOperators_data()
853 {
854 QTest::addColumn<int>("i");
855
856 for(int i=Operator::none+1; i<Operator::nOfOps; i++) {
857 QTest::newRow( Operator::words[i] ) << i;
858 }
859 }
860
testOperators()861 void AnalitzaTest::testOperators()
862 {
863 QFETCH(int, i);
864 Operator o(static_cast<Operator::OperatorType>(i));
865 QVERIFY(o.nparams()>=-1);
866 if(!o.isCorrect())
867 qDebug() << o.toString();
868 QVERIFY(o.isCorrect());
869 QCOMPARE(static_cast<Operator::OperatorType>(i), o.operatorType());
870 QCOMPARE(Operator::toOperatorType(o.toString()), o.operatorType());
871
872 if(o.operatorType()==Operator::function)
873 return;
874
875 // QVERIFY(!Analitza::Operations::infer(o.operatorType()).isEmpty() || !Analitza::Operations::inferUnary(o.operatorType()).isEmpty());
876
877 Vector* v=new Vector(3);
878 v->appendBranch(new Cn(0.));
879 v->appendBranch(new Cn(1.));
880 v->appendBranch(new Cn(2.));
881
882 QList<Object*> values=QList<Object*>() << new Cn(0.)
883 << new Cn(0.5)
884 << new Cn(1.)
885 << new Cn(-1.)
886 << new Cn(-.5)
887 << new Ci(QStringLiteral("x"))
888 << v; //lets try to make it crash
889 QList<int> params;
890 if(o.nparams()<0)
891 params /*<< 0 << 1 << 2*/ << 3;
892 else
893 params << o.nparams();
894
895 #ifdef Q_CC_GNU
896 #warning improve the test for bounded operations
897 #endif
898 if(o.operatorType()==Operator::sum || o.operatorType()==Operator::product)
899 return;
900
901 foreach(Object* obj, values) {
902 foreach(int paramCnt, params) {
903 Analitza::Apply* apply=new Analitza::Apply;
904 apply->appendBranch(new Operator(o));
905 for(; paramCnt>0; paramCnt--) {
906 apply->appendBranch(obj->copy());
907 }
908
909 if(o.isBounded()) {
910 Container *bvar=new Container(Container::bvar);
911 apply->appendBranch(bvar);
912
913 QList<Object*> bvarValues=QList<Object*>() << new Ci(QStringLiteral("x"));
914 foreach(Object* obvar, bvarValues) {
915 Analitza::Apply* cc=(Analitza::Apply*) apply->copy();
916 Container* bvar=(Container*) cc->bvarCi().at(0);
917 bvar->appendBranch(obvar->copy());
918
919 Expression e1(cc);
920 a->setExpression(e1);
921
922 a->calculate();
923 a->evaluate();
924 a->derivative(QStringLiteral("x"));
925 }
926 qDeleteAll(bvarValues);
927 } else {
928 Expression e(apply);
929 a->setExpression(e);
930 a->calculate();
931 a->evaluate();
932 a->derivative(QStringLiteral("x"));
933 }
934 }
935 }
936 qDeleteAll(values);
937
938 QList<double> diffValues = QList<double>() << 0. << 0.5 << -0.5 << 1. << -1.;
939 QString bvar('x');
940 foreach(double v, diffValues) {
941 foreach(int paramCnt, params) {
942 Analitza::Apply *diffApply=new Analitza::Apply;
943 diffApply->appendBranch(new Operator(Operator::diff));
944 Container* diffBVar=new Container(Container::bvar);
945 diffBVar->appendBranch(new Ci(bvar));
946 diffApply->appendBranch(diffBVar);
947
948 Analitza::Apply* apply=new Analitza::Apply;
949 apply->appendBranch(new Operator(o));
950 diffApply->appendBranch(apply);
951
952 for(; paramCnt>0; paramCnt--)
953 apply->appendBranch(new Ci(bvar));
954
955 Expression e(diffApply);
956 a->setExpression(e);
957 a->calculate();
958 a->evaluate();
959 a->simplify();
960 a->derivative(QStringLiteral("x"));
961
962 Cn* vv = new Cn(v);
963 QVector<Object*> stack;
964 stack += vv;
965 a->derivative(stack);
966 delete vv;
967 }
968 }
969 }
970
971
972