File indexing completed on 2024-04-28 03:40:45

0001 /*************************************************************************************
0002  *  Copyright (C) 2007 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 "operations.h"
0020 
0021 #include <math.h>
0022 
0023 #include <cmath>
0024 #include <complex>
0025 #include <QCoreApplication>
0026 
0027 #include "value.h"
0028 #include "vector.h"
0029 #include "expression.h"
0030 #include "list.h"
0031 #include "expressiontypechecker.h"
0032 #include "customobject.h"
0033 #include "matrix.h"
0034 #include "container.h"
0035 #include "additionchains.h"
0036 
0037 using namespace std;
0038 using namespace Analitza;
0039 
0040 Object* reduceRealReal(enum Operator::OperatorType op, Cn *oper, double a, double b, QString** correct)
0041 {
0042     Object *ret = oper;
0043     switch(op) {
0044         case Operator::plus:
0045             oper->setValue(a+b);
0046             break;
0047         case Operator::times:
0048             oper->setValue(a*b);
0049             break;
0050         case Operator::divide:
0051             if(Q_LIKELY(b!=0.))
0052                 oper->setValue(a / b);
0053             else {
0054                 *correct=new QString(QCoreApplication::tr("Cannot divide by 0."));
0055                 ret=new None();
0056             }
0057             break;
0058         case Operator::minus:
0059             oper->setValue(a - b);
0060             break;
0061         case Operator::power:
0062             if (b<1 && b>-1 && a<0) {
0063                 oper->setValue(pow(complex<double>(a), complex<double>(b)));
0064             } else {
0065                 oper->setValue(b==2 ? a*a : pow(a, b));
0066             }
0067             break;
0068         case Operator::rem:
0069             if(Q_LIKELY(floor(b)!=0.))
0070                 oper->setValue(int(remainder(a, b)));
0071             else {
0072                 *correct=new QString(QCoreApplication::tr("Cannot calculate the remainder on 0."));
0073                 ret=new None();
0074             }
0075             break;
0076         case Operator::quotient:
0077             oper->setValue(int(floor(a / b)));
0078             break;
0079         case Operator::factorof: {
0080             int fb = int(floor(b));
0081             if(Q_LIKELY(fb!=0))
0082                 oper->setValue((int(floor(a)) % fb)==0);
0083             else {
0084                 *correct=new QString(QCoreApplication::tr("Cannot calculate the factor on 0."));
0085                 ret=new None();
0086             }
0087         }    break;
0088         case Operator::min:
0089             oper->setValue(a < b? a : b);
0090             break;
0091         case Operator::max:
0092             oper->setValue(a > b? a : b);
0093             break;
0094         case Operator::gt:
0095             oper->setValue(a > b);
0096             break;
0097         case Operator::lt:
0098             oper->setValue(a < b);
0099             break;
0100         case Operator::eq:
0101             oper->setValue(a == b);
0102             break;
0103         case Operator::approx:
0104             oper->setValue(fabs(a-b)<0.001);
0105             break;
0106         case Operator::neq:
0107             oper->setValue(a != b);
0108             break;
0109         case Operator::geq:
0110             oper->setValue(a >= b);
0111             break;
0112         case Operator::leq:
0113             oper->setValue(a <= b);
0114             break;
0115         case Operator::_and:
0116             oper->setValue(a && b);
0117             break;
0118         case Operator::_or:
0119             oper->setValue(a || b);
0120             break;
0121         case Operator::_xor:
0122             oper->setValue((a || b) && !(a&&b));
0123             break;
0124         case Operator::implies:
0125             oper->setValue(a || !b);
0126             break;
0127         case Operator::gcd:  {
0128             //code by michael cane aka kiko :)
0129             int ia=floor(a), ib=floor(b);
0130             while (ib > 0) {
0131                 int residu = ia % ib;
0132                 ia = ib;
0133                 ib = residu;
0134             }
0135             oper->setValue(ia);
0136         }    break;
0137         case Operator::lcm:
0138             //code by michael cane aka kiko :)
0139             if(Q_UNLIKELY(floor(a)==0. || floor(b)==0.)) {
0140                 *correct=new QString(QCoreApplication::tr("Cannot calculate the lcm of 0."));
0141                 ret=new None();
0142             }
0143             else {
0144                 int ia=floor(a), ib=floor(b);
0145                 int ic=ia*ib;
0146                 while (ib > 0) {
0147                     int residu = ia % ib;
0148                     ia = ib;
0149                     ib = residu;
0150                 }
0151                 ia=ic/ia;
0152                 oper->setValue(ia);
0153             }
0154             break;
0155         case Operator::root:
0156             oper->setValue(              b==2.0 ? sqrt(a)
0157             : (b>1 || b<-1) && a<0 ? pow(complex<double>(a), complex<double>(1./b)).real()
0158             : pow(a, 1.0/b));
0159             break;
0160         default:
0161             break;
0162     }
0163     return ret;
0164 }
0165 
0166 static bool operator<(complex<double> a, complex<double> b)
0167 { return a.real() < b.real() || (a.real() == b.real() && a.imag()<b.imag()); }
0168 
0169 static bool operator>(complex<double> a, complex<double> b)
0170 { return a.real() > b.real() || (a.real() == b.real() && a.imag()>b.imag()); }
0171 
0172 static bool operator<=(complex<double> a, complex<double> b)
0173 { return a.real() <= b.real() || (a.real() == b.real() && a.imag()<=b.imag()); }
0174 
0175 static bool operator>=(complex<double> a, complex<double> b)
0176 { return a.real() >= b.real() || (a.real() == b.real() && a.imag()>=b.imag()); }
0177 
0178 Cn* reduceComplexComplex(enum Operator::OperatorType op, Cn *oper, complex<double> a, complex<double> b, QString** correct)
0179 {
0180     switch(op) {
0181         case Operator::plus:
0182             oper->setValue(a+b);
0183             break;
0184         case Operator::times:
0185             oper->setValue(a*b);
0186             break;
0187         case Operator::divide:
0188             if(Q_LIKELY(b.real()!=0. || b.imag()!=0.))
0189                 oper->setValue(a / b);
0190             else
0191                 *correct=new QString(QCoreApplication::tr("Cannot divide by 0."));
0192             break;
0193         case Operator::minus:
0194             oper->setValue(a - b);
0195             break;
0196         case Operator::power:
0197             oper->setValue(pow(a, b));
0198             break;
0199         case Operator::rem:
0200             if(Q_LIKELY(floor(b.real())!=0.))
0201                 oper->setValue(int(remainder(a.real(), b.real())));
0202             else
0203                 *correct=new QString(QCoreApplication::tr("Cannot calculate the remainder on 0."));
0204             break;
0205         case Operator::quotient:
0206             oper->setValue(int(floor((a / b).real())));
0207             break;
0208         case Operator::factorof: {
0209             int fb = int(floor(b.real()));
0210             if(Q_LIKELY(fb!=0))
0211                 oper->setValue((int(floor(a.real())) % fb)==0);
0212             else
0213                 *correct=new QString(QCoreApplication::tr("Cannot calculate the factor on 0."));
0214         }    break;
0215         case Operator::min:
0216             oper->setValue(a < b ? a : b);
0217             break;
0218         case Operator::max:
0219             oper->setValue(a > b? a : b);
0220             break;
0221         case Operator::gt:
0222             oper->setValue(a > b);
0223             break;
0224         case Operator::lt:
0225             oper->setValue(a < b);
0226             break;
0227         case Operator::eq:
0228             oper->setValue(a == b);
0229             break;
0230         case Operator::approx:
0231             oper->setValue(fabs(a.real()-b.real())+fabs(a.imag()-b.imag())<0.001);
0232             break;
0233         case Operator::neq:
0234             oper->setValue(a != b);
0235             break;
0236         case Operator::geq:
0237             oper->setValue(a >= b);
0238             break;
0239         case Operator::leq:
0240             oper->setValue(a <= b);
0241             break;
0242         case Operator::_and:
0243         case Operator::_or:
0244         case Operator::_xor:
0245         case Operator::implies:
0246             *correct = new QString(QCoreApplication::tr("Boolean operations on complex numbers not available"));
0247             break;
0248         case Operator::gcd:  {
0249             //code by michael cane aka kiko :)
0250             int ia=floor(a.real()), ib=floor(b.real());
0251             while (ib > 0) {
0252                 int residu = ia % ib;
0253                 ia = ib;
0254                 ib = residu;
0255             }
0256             oper->setValue(ia);
0257         }    break;
0258         case Operator::lcm:
0259             //code by michael cane aka kiko :)
0260             if(Q_UNLIKELY(floor(a.real())==0. || floor(b.real())==0.))
0261                 *correct=new QString(QCoreApplication::tr("Cannot calculate the lcm of 0."));
0262             else {
0263                 int ia=floor(a.real()), ib=floor(b.real());
0264                 int ic=ia*ib;
0265                 while (ib > 0) {
0266                     int residu = ia % ib;
0267                     ia = ib;
0268                     ib = residu;
0269                 }
0270                 ia=ic/ia;
0271                 oper->setValue(ia);
0272             }
0273             break;
0274         case Operator::root:
0275             if(b.real()!=2.0 && b.imag()==0)
0276                 *correct = new QString(QCoreApplication::tr("Only square root implemented for complex numbers"));
0277             else
0278                 oper->setValue(sqrt(a));
0279             break;
0280         default:
0281             break;
0282     }
0283     return oper;
0284 }
0285 
0286 Object* Operations::reduceValueValue(enum Operator::OperatorType op, Cn *oper, const Cn *oper1, QString** correct)
0287 {
0288     if(Q_UNLIKELY(oper->isComplex() || oper1->isComplex())) {
0289         const complex<double> a=oper->complexValue(), b=oper1->complexValue();
0290         return reduceComplexComplex(op, oper, a, b, correct);
0291     } else {
0292         const double a=oper->value(), b=oper1->value();
0293         return reduceRealReal(op, oper, a, b, correct);
0294     }
0295 }
0296 
0297 Cn* reduceUnaryComplex(Operator::OperatorType op, Cn* oper, QString** correct)
0298 {
0299     const complex<double> a=oper->complexValue();
0300 
0301     switch(op) {
0302         case Operator::minus:
0303                  oper->setValue(-a);
0304             break;
0305         case Operator::sin:
0306                  oper->setValue(sin(a));
0307             break;
0308         case Operator::cos:
0309                  oper->setValue(cos(a));
0310             break;
0311         case Operator::tan:
0312                  oper->setValue(tan(a));
0313             break;
0314         case Operator::sinh:
0315                  oper->setValue(sinh(a));
0316             break;
0317         case Operator::cosh:
0318                  oper->setValue(cosh(a));
0319             break;
0320         case Operator::tanh:
0321                  oper->setValue(tanh(a));
0322             break;
0323         case Operator::coth:
0324                  oper->setValue(cosh(a)/sinh(a));
0325             break;
0326         case Operator::exp:
0327                  oper->setValue(exp(a));
0328             break;
0329         case Operator::ln:
0330                  oper->setValue(log(a));
0331             break;
0332         case Operator::log:
0333                  oper->setValue(log10(a));
0334             break;
0335         case Operator::abs:
0336                  oper->setValue(std::abs(a));
0337             break;
0338         case Operator::conjugate:
0339                  oper->setValue(std::conj(a));
0340             break;
0341             case Operator::arg:
0342                     oper->setValue(std::arg(a));
0343             break;
0344             case Operator::real:
0345                     oper->setValue(a.real());
0346             break;
0347             case Operator::imaginary:
0348                     oper->setValue(a.imag());
0349             break;
0350         default:
0351             *correct=new QString(QCoreApplication::tr("Could not calculate a value %1").arg(Operator(op).toString()));
0352     }
0353     return oper;
0354 }
0355 
0356 Cn* reduceUnaryReal(Operator::OperatorType op, Cn* oper, QString** correct)
0357 {
0358     const double a=oper->value();
0359     
0360     switch(op) {
0361         case Operator::minus:
0362                  oper->setValue(-a);
0363             break;
0364         case Operator::factorial: {
0365             //Use gamma from math.h?
0366             uint res=1;
0367             for(int i=a; i>1.; i--) {
0368                 res*=floor(i);
0369             }
0370                  oper->setValue(res);
0371         }    break;
0372         case Operator::sin:
0373                  oper->setValue(sin(a));
0374             break;
0375         case Operator::cos:
0376                  oper->setValue(cos(a));
0377             break;
0378         case Operator::tan:
0379                  oper->setValue(tan(a));
0380             break;
0381         case Operator::sec:
0382                  oper->setValue(1./cos(a));
0383             break;
0384         case Operator::csc:
0385                  oper->setValue(1./sin(a));
0386             break;
0387         case Operator::cot:
0388                  oper->setValue(1./tan(a));
0389             break;
0390         case Operator::sinh:
0391                  oper->setValue(sinh(a));
0392             break;
0393         case Operator::cosh:
0394                  oper->setValue(cosh(a));
0395             break;
0396         case Operator::tanh:
0397                  oper->setValue(tanh(a));
0398             break;
0399         case Operator::sech:
0400                  oper->setValue(1.0/cosh(a));
0401             break;
0402         case Operator::csch:
0403                  oper->setValue(1.0/sinh(a));
0404             break;
0405         case Operator::coth:
0406                  oper->setValue(cosh(a)/sinh(a));
0407             break;
0408         case Operator::arcsin:
0409                  oper->setValue(asin(a));
0410             break;
0411         case Operator::arccos:
0412                  oper->setValue(acos(a));
0413             break;
0414         case Operator::arctan:
0415                  oper->setValue(atan(a));
0416             break;
0417         case Operator::arccot:
0418                  oper->setValue(log(a+pow(a*a+1., 0.5)));
0419             break;
0420         case Operator::arcsinh: //see https://en.wikipedia.org/wiki/Inverse_hyperbolic_function
0421                  oper->setValue(asinh(a));
0422             break;
0423         case Operator::arccosh:
0424                  oper->setValue(acosh(a));
0425             break;
0426         case Operator::arccsc:
0427                  oper->setValue(1/asin(a));
0428             break;
0429         case Operator::arccsch:
0430                  oper->setValue(log(1/a+sqrt(1/(a*a)+1)));
0431             break;
0432         case Operator::arcsec:
0433                  oper->setValue(1/(acos(a)));
0434             break;
0435         case Operator::arcsech:
0436                  oper->setValue(log(1/a+sqrt(1/a+1)*sqrt(1/a-1)));
0437             break;
0438         case Operator::arctanh:
0439                  oper->setValue(atanh(a));
0440             break;
0441         case Operator::exp:
0442                  oper->setValue(exp(a));
0443             break;
0444         case Operator::ln:
0445                  oper->setValue(log(a));
0446             break;
0447         case Operator::log:
0448                  oper->setValue(log10(a));
0449             break;
0450         case Operator::abs:
0451                  oper->setValue(a>=0. ? a : -a);
0452             break;
0453         case Operator::floor:
0454                  oper->setValue(floor(a));
0455             break;
0456         case Operator::ceiling:
0457                  oper->setValue(ceil(a));
0458             break;
0459         case Operator::_not:
0460                  oper->setValue(!a);
0461             break;
0462         default:
0463             *correct=new QString(QCoreApplication::tr("Could not calculate a value %1").arg(Operator(op).toString()));
0464             break;
0465     }
0466     return oper;
0467 }
0468 
0469 Object* Operations::reduceUnaryValue(Operator::OperatorType op, Cn* oper, QString** correct)
0470 {
0471     if(Q_UNLIKELY(oper->isComplex()))
0472         return reduceUnaryComplex(op, oper, correct);
0473     else
0474         return reduceUnaryReal(op, oper, correct);
0475 }
0476 
0477 Object* Operations::reduceNoneValue(Operator::OperatorType op, None*, Cn*, QString** correct)
0478 {
0479     return errorCase(QCoreApplication::tr("Cannot calculate %1 between a value and an error type").arg(Operator(op).name()), correct);
0480 }
0481 
0482 Object* Operations::reduceValueNone(Operator::OperatorType op, Cn* oper, None* cntr, QString** correct)
0483 {
0484     return reduceNoneValue(op, cntr, oper, correct);
0485 }
0486 
0487 Object * Operations::reduceValueVector(Operator::OperatorType op, Cn * oper, Vector * v1, QString** correct)
0488 {
0489     switch(op) {
0490         case Operator::selector: {
0491             int select=oper->intValue();
0492             delete oper;
0493             Object* ret=nullptr;
0494             if(select<1 || (select-1) >= v1->size()) {
0495                 *correct=new QString(QCoreApplication::tr("Invalid index for a container"));
0496                 ret=new None();
0497             } else {
0498                 ret=v1->at(select-1)->copy();
0499             }
0500             return ret;
0501         }    break;
0502         default: {
0503             Vector *ret = v1->copy();
0504             for(Vector::iterator it=ret->begin(); it!=ret->end(); ++it)
0505             {
0506                 *it=reduce(op, new Cn(*oper), *it, correct);
0507             }
0508             
0509             delete oper;
0510             return ret;
0511         }
0512     }
0513 }
0514 
0515 Object * Operations::reduceVectorValue(Operator::OperatorType op, Vector * v1, Cn * oper, QString** correct)
0516 {
0517     for(Vector::iterator it=v1->begin(); it!=v1->end(); ++it)
0518     {
0519         *it=reduce(op, *it, new Cn(*oper), correct);
0520     }
0521     return v1;
0522 }
0523 
0524 Object * Operations::reduceVectorVector(Operator::OperatorType op, Vector * v1, Vector * v2, QString** correct)
0525 {
0526     if(v1->size()!=v2->size()) { //FIXME: unneeded? ... aucahuasi: I think is needed ...
0527         *correct=new QString(QCoreApplication::tr("Cannot operate '%1' on different sized vectors.").arg(Operator(op).name()));
0528         return new None();
0529     }
0530     
0531     if(op==Operator::scalarproduct)
0532         op=Operator::times;
0533     Vector::iterator it2=v2->begin();
0534     for(Vector::iterator it1=v1->begin(); it1!=v1->end(); ++it1, ++it2)
0535     {
0536         *it1=reduce(op, *it1, *it2, correct);
0537     }
0538     return v1;
0539 }
0540 
0541 Object* Operations::reduceMatrixVector(Operator::OperatorType op, Matrix* matrix, Vector* vector, QString** correct)
0542 {
0543     Object* ret = nullptr;
0544     if (op == Operator::times) {
0545         if (matrix->hasOnlyNumbers() && vector->hasOnlyNumbers()) {
0546             const int maxk = matrix->columnCount();
0547             
0548             if (maxk == vector->size()) {
0549                 const int m = matrix->rowCount();
0550                 
0551                 Vector *newvec = new Vector(m);
0552                 
0553                 for (int i = 0; i < m; ++i) {
0554                     std::complex<double> sum = 0.;
0555                     for (int k = 0; k < maxk; ++k)
0556                         sum += static_cast<const Cn*>(reduceValueValue(op, (Cn*)matrix->at(i,k), (Cn*)vector->at(k), correct))->complexValue();
0557                     
0558                     if (sum.imag() == 0)
0559                         newvec->appendBranch(new Cn(sum.real()));
0560                     else
0561                         newvec->appendBranch(new Cn(sum.real(), sum.imag()));
0562                 }
0563                 
0564                 ret = newvec;
0565             } else {
0566                 *correct=new QString(QCoreApplication::tr("Multiplication between a matrix and a vector is allowed provided that the number of columns of the matrix equals the size of the vector"));
0567                 ret=new None();
0568             }
0569         } else {
0570             *correct=new QString(QCoreApplication::tr("Matrix and vector entries must be numbers"));
0571             ret=new None();
0572         }
0573     }
0574     
0575     return ret;
0576 }
0577 
0578 Object* Operations::reduceUnaryVector(Operator::OperatorType op, Vector* c, QString** correct)
0579 {
0580     Object *ret=nullptr;
0581     switch(op) {
0582         case Operator::card:
0583             ret=new Cn(c->size());
0584             break;
0585         case Operator::transpose: {
0586             const int n = c->size();
0587             
0588             Matrix* mret = new Matrix;
0589             MatrixRow* row = new MatrixRow(n);
0590             for(int j=0; j<n; ++j) {
0591                 row->appendBranch(c->at(j)->copy());
0592             }
0593             
0594             mret->appendBranch(row);
0595             ret = mret;
0596         }    break;
0597         default:
0598             //Should be dealt by typechecker. not necessary
0599             *correct=new QString(QCoreApplication::tr("Could not calculate a vector's %1").arg(Operator(op).toString()));
0600             ret=new None();
0601             break;
0602     }
0603     delete c;
0604     return ret;
0605 }
0606 
0607 Object* Operations::reduceListList(Operator::OperatorType op, List* l1, List* l2, QString** correct)
0608 {
0609     Object* ret=nullptr;
0610     switch(op) {
0611         case Operator::_union: {
0612             List::iterator itEnd=l2->end();
0613             for(List::iterator it=l2->begin(); it!=itEnd; ++it) {
0614                 l1->appendBranch((*it)->copy());
0615             }
0616             
0617             ret=l1;
0618         }    break;
0619         default:
0620             //Should be dealt by typechecker. not necessary
0621             *correct=new QString(QCoreApplication::tr("Could not calculate a list's %1").arg(Operator(op).toString()));
0622             delete l1;
0623             ret=new None();
0624             break;
0625     }
0626     return ret;
0627 }
0628 
0629 Object* Operations::reduceUnaryList(Operator::OperatorType op, List* l, QString** correct)
0630 {
0631     Object *ret=nullptr;
0632     switch(op) {
0633         case Operator::card:
0634             ret=new Cn(l->size());
0635             break;
0636         default:
0637             *correct=new QString(QCoreApplication::tr("Could not calculate a list's %1").arg(Operator(op).toString()));
0638             ret=new None();
0639             break;
0640     }
0641     delete l;
0642     return ret;
0643 }
0644 
0645 Object* Operations::reduceValueList(Operator::OperatorType op, Cn* oper, List* v1, QString** correct)
0646 {
0647     switch(op) {
0648         case Operator::selector: {
0649             int select=oper->intValue();
0650             Object* ret=nullptr;
0651             if(select<1 || (select-1) >= v1->size()) {
0652                 *correct=new QString(QCoreApplication::tr("Invalid index for a container"));
0653                 ret=new None();
0654             } else {
0655                 ret=v1->at(select-1);
0656                 v1->setAt(select-1, nullptr);
0657             }
0658             delete oper;
0659             return ret;
0660         }    break;
0661         default:
0662             break;
0663     }
0664     return nullptr;
0665 }
0666 
0667 Object* Operations::reduceCustomCustom(Operator::OperatorType op, CustomObject* v1, CustomObject* v2, QString** )
0668 {
0669     switch(op) {
0670         case Operator::neq:
0671             return new Cn(v1->value()!=v2->value());
0672         case Operator::eq:
0673             return new Cn(v1->value()==v2->value());
0674         default:
0675             break;
0676     }
0677     
0678     Q_ASSERT(false && "not implemented, please report");
0679     return nullptr;
0680 }
0681 
0682 Object* Operations::reduceVectorMatrix(Operator::OperatorType op, Vector* vector, Matrix* matrix, QString** correct)
0683 {
0684     Object* ret = nullptr;
0685     if (op == Operator::times) {
0686         if (vector->hasOnlyNumbers() && matrix->hasOnlyNumbers()) {
0687             if (1 == matrix->rowCount()) {
0688                 const int m = vector->size();
0689                 const int n = matrix->columnCount();
0690                 
0691                 Matrix *newmat = new Matrix();
0692                 
0693                 for (int i = 0; i < m; ++i) {
0694                     MatrixRow *row = new MatrixRow(n);
0695                     for (int j = 0; j < n; ++j)
0696                         row->appendBranch(reduceValueValue(op, (Cn*)vector->at(i), (Cn*)matrix->at(0,j), correct)->copy());
0697                     
0698                     newmat->appendBranch(row);
0699                 }
0700                 
0701                 ret = newmat;
0702             } else {
0703                 *correct=new QString(QCoreApplication::tr("Multiplication between a vector and a matrix is allowed provided that the matrix has only one matrixrow element"));
0704                 ret=new None();
0705             }
0706         } else {
0707             *correct=new QString(QCoreApplication::tr("Matrix and vector entries must be numbers"));
0708             ret=new None();
0709         }
0710     }
0711     
0712     return ret;
0713 }
0714 
0715 Object* Operations::reduceMatrixMatrix(Operator::OperatorType op, Matrix* m1, Matrix* m2, QString** correct)
0716 {
0717     Object* ret = nullptr;
0718     switch(op) {
0719         //TODO see if we can use here and or xor for matrix too
0720         case Operator::plus:
0721         case Operator::minus: {
0722             if(m1->rowCount() == m2->rowCount() && m1->columnCount() == m2->columnCount()) {
0723                 Matrix::iterator it2=m2->begin();
0724                 for(Matrix::iterator it1=m1->begin(); it1!=m1->end(); ++it1, ++it2)
0725                 {
0726                     *it1 = static_cast<MatrixRow*>(reduceVectorVector(op, *it1, *it2, correct));
0727                 }
0728                 ret = m1;
0729             } else {
0730                 *correct=new QString(QCoreApplication::tr("Addition of two matrices is allowed provided that both matrices have the same number of rows and the same number of columns"));
0731                 ret=new None();
0732             }
0733         }    break;
0734         case Operator::times: {
0735             if (m1->hasOnlyNumbers() && m2->hasOnlyNumbers()) {
0736                 const int maxk = m1->columnCount();
0737                 if (maxk == m2->rowCount()) {
0738                     const int m = m1->rowCount();
0739                     const int n = m2->columnCount();
0740                     
0741                     Matrix *matrix = new Matrix();
0742                     
0743                     for (int i = 0; i < m; ++i) {
0744                         MatrixRow *row = new MatrixRow(n);
0745                         for (int j = 0; j < n; ++j) {
0746                             std::complex<double> sum = 0;
0747                             for (int k = 0; k < maxk; ++k) {
0748                                 sum += static_cast<const Cn*>(reduceValueValue(op, (Cn*)m1->at(i,k)->copy(), (Cn*)m2->at(k,j)->copy(), correct))->complexValue();
0749                             }
0750                             
0751                             if (sum.imag() == 0)
0752                                 row->appendBranch(new Cn(sum.real()));
0753                             else
0754                                 row->appendBranch(new Cn(sum.real(), sum.imag()));
0755                         }
0756                         
0757                         matrix->appendBranch(row);
0758                     }
0759                     
0760                     ret = matrix;
0761                 } else {
0762                     *correct=new QString(QCoreApplication::tr("Multiplication of two matrices is allowed provided that the number of columns of the first matrix equals the number of rows of the second matrix"));
0763                     ret=new None();
0764                 }
0765             } else {
0766                 *correct=new QString(QCoreApplication::tr("Matrix entries must be numbers"));
0767                 ret=new None();
0768             }
0769         }    break;
0770         default:
0771             break;
0772     }
0773     
0774     return ret;
0775 }
0776 
0777 Object* Operations::reduceValueMatrix(Operator::OperatorType op, Cn* v, Matrix* m1, QString** correct)
0778 {
0779     Object* ret = nullptr;
0780     switch(op) {
0781         case Operator::selector: {
0782             int select=v->intValue();
0783             if(select<1 || (select-1) >= m1->rowCount()) {
0784                 *correct=new QString(QCoreApplication::tr("Invalid index for a container"));
0785                 ret=new None();
0786             } else {
0787                 MatrixRow* row = static_cast<MatrixRow*>(m1->rows().at(select-1));
0788                 Vector* nv = new Vector(row->size());
0789                 for(Vector::iterator it=row->begin(); it!=row->end(); ++it) {
0790                     nv->appendBranch((*it));
0791                     *it = nullptr;
0792                 }
0793                 ret = nv;
0794             }
0795             delete v;
0796         }    break;
0797         case Operator::times: {
0798             if (m1->hasOnlyNumbers()) {
0799                 Matrix *nm = new Matrix();
0800                 for(Matrix::iterator it=m1->begin(); it!=m1->end(); ++it)
0801                     nm->appendBranch(static_cast<MatrixRow*>(reduceValueVector(op, static_cast<Cn*>(v->copy()), static_cast<MatrixRow*>(*it), correct)));
0802                 ret = nm;
0803             } else {
0804                 *correct=new QString(QCoreApplication::tr("Matrix entries must be numbers"));
0805                 ret=new None();
0806             }
0807         }    break;
0808         default:
0809             break;
0810     }
0811     return ret;
0812 }
0813 
0814 Object* Operations::reduceMatrixValue(Operator::OperatorType op, Matrix* matrix, Cn* value, QString** correct)
0815 {
0816     Object* ret = nullptr;
0817     switch(op) {
0818         case Operator::power: {
0819             if (matrix->hasOnlyNumbers()) {
0820                 if (matrix->isSquare()) {
0821                     if (value->isInteger()) {
0822                         const int exp = qAbs(value->intValue());
0823                         
0824                         switch(exp) {
0825                             case 0: ret = Matrix::identity(matrix->rowCount()); break;
0826                             case 1: ret = matrix; break;
0827                             default: {
0828                                 //base = value->intValue() < 0? invert(matrix) : matrix;//TODO negative exponents
0829                                 Matrix *base = matrix;
0830                                 
0831                                 if (exp <= MAX_EXPONENT) { // then: use Addition-chain exponentiation
0832                                     const int len = additionChains[exp][0];
0833                                     int i, j, k;
0834                                     QVector<Matrix*> products(len+1);
0835                                     products[0] = base;
0836                                     
0837                                     if (exp>1)
0838                                         products[1] = static_cast<Matrix*>(reduceMatrixMatrix(Operator::times, matrix, matrix, correct));
0839                                     
0840                                     //NOTE see https://rosettacode.org/wiki/Addition-chain_exponentiation#C for more details
0841                                     for (i = 2; i <= len; ++i) 
0842                                         for (j = i - 1; j; --j) 
0843                                             for (k = j; k >= 0; --k) 
0844                                             {
0845                                                 if (additionChains[exp][k+1] + additionChains[exp][j+1] < additionChains[exp][i+1]) break;
0846                                                 if (additionChains[exp][k+1] + additionChains[exp][j+1] > additionChains[exp][i+1]) continue;
0847                                                 products[i] = static_cast<Matrix*>(reduceMatrixMatrix(Operator::times, products[j], products[k], correct));
0848                                                 j = 1;
0849                                                 break;
0850                                             }
0851                                     ret = products[len];
0852                                     
0853                                     //NOTE free the memory, except products[len]
0854                                     for (i = 0; i < len; ++i)
0855                                         delete products[i];
0856                                 } else { // else: use Exponentiation by squaring
0857                                     Matrix *product = Matrix::identity(base->rowCount());
0858                                     Matrix *newbase = base->copy();
0859                                     int n = exp;
0860                                     
0861                                     while (n != 0) {
0862                                         if (n % 2 != 0) {
0863                                             Matrix *oldproduct = product;
0864                                             product = static_cast<Matrix*>(reduceMatrixMatrix(Operator::times, product, newbase, correct));
0865                                             delete oldproduct;
0866                                             --n;
0867                                         }
0868                                         Matrix *oldbase = newbase;
0869                                         newbase = static_cast<Matrix*>(reduceMatrixMatrix(Operator::times, newbase, newbase, correct));
0870                                         delete oldbase;
0871                                         n /= 2;
0872                                     }
0873                                     
0874                                     ret = product;
0875                                 }
0876                             }    break;
0877                         }
0878                     } else {
0879                         *correct=new QString(QCoreApplication::tr("The exponent of 'power' must be some integer number"));
0880                         ret=new None();
0881                     }
0882                 } else {
0883                     *correct=new QString(QCoreApplication::tr("Cannot compute 'power' for non square matrix"));
0884                     ret=new None();
0885                 }
0886             } else {
0887                 *correct=new QString(QCoreApplication::tr("Matrix entries must be numbers"));
0888                 ret=new None();
0889             }
0890         }    break;
0891         //TODO root
0892         default:
0893             break;
0894     }
0895     return ret;
0896 }
0897 
0898 Object* Operations::reduceUnaryMatrix(Operator::OperatorType op, Matrix* m, QString** )
0899 {
0900     Object* ret = nullptr;
0901     switch(op) {
0902         case Operator::transpose: {
0903             int sizeA = m->rowCount(), sizeB = static_cast<MatrixRow*>(*m->constBegin())->size();
0904             Matrix* mret = new Matrix;
0905             for(int i=0; i<sizeB; ++i) {
0906                 MatrixRow* row = new MatrixRow(sizeA);
0907                 for(int j=0; j<sizeA; ++j) {
0908                     row->appendBranch(m->at(j, i)->copy());
0909                 }
0910                 mret->appendBranch(row);
0911             }
0912             ret = mret;
0913         }    break;
0914         default:
0915             break;
0916     }
0917     return ret;
0918 }
0919 
0920 Object* Operations::reduceMatrixNone(Operator::OperatorType op, Matrix*, None*, QString** correct)
0921 {
0922     return errorCase(QCoreApplication::tr("Cannot calculate %1 between a matrix and an error type").arg(Operator(op).name()), correct);
0923 }
0924 
0925 Object* Operations::reduceNoneMatrix(Operator::OperatorType op, None* cntr, Matrix* m, QString** correct)
0926 {
0927     return reduceMatrixNone(op, m, cntr, correct);
0928 }
0929 
0930 ExpressionType TypeTriplet(const ExpressionType& a,const ExpressionType& b,const ExpressionType& c) { return ExpressionType(ExpressionType::Lambda).addParameter(a).addParameter(b).addParameter(c); }
0931 
0932 //TODO: test that there's one output per input
0933 QList<ExpressionType> Operations::infer(Operator::OperatorType op)
0934 {
0935     QList<ExpressionType> ret;
0936     
0937     switch(op) {
0938         case Operator::plus:
0939         case Operator::minus:
0940             ret << TypeTriplet(ExpressionType(ExpressionType::Value), ExpressionType(ExpressionType::Value), ExpressionType(ExpressionType::Value));
0941             ret << TypeTriplet(ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1),
0942                                ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1),
0943                                ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1));
0944             ret << TypeTriplet(ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -2), -1),
0945                                ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -2), -1),
0946                                ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -2), -1));
0947             break;
0948         case Operator::divide:
0949             ret << TypeTriplet(ExpressionType(ExpressionType::Value), ExpressionType(ExpressionType::Value), ExpressionType(ExpressionType::Value));
0950             ret << TypeTriplet(ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1),
0951                                ExpressionType(ExpressionType::Value),
0952                                ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1));
0953             ret << TypeTriplet(ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1),
0954                                ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1),
0955                                ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1));
0956             break;
0957         case Operator::times:
0958             ret << TypeTriplet(ExpressionType(ExpressionType::Value), ExpressionType(ExpressionType::Value), ExpressionType(ExpressionType::Value));
0959             ret << TypeTriplet(ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1),
0960                                ExpressionType(ExpressionType::Value),
0961                                ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1));
0962             ret << TypeTriplet(ExpressionType(ExpressionType::Value),
0963                                ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1),
0964                                ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1));
0965             ret << TypeTriplet(ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1),
0966                                ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1),
0967                                ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1));
0968             ret << TypeTriplet(ExpressionType(ExpressionType::Value),
0969                                ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -2), -1),
0970                                ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -2), -1));
0971             ret << TypeTriplet(ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -2), -1),
0972                                ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -2), -1),
0973                                ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -2), -1));
0974             ret << TypeTriplet(ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -2), -1),
0975                                ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -2),
0976                                ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1));
0977             ret << TypeTriplet(ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1),
0978                                ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -2), 1),
0979                                ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -2), -1));
0980             break;
0981         case Operator::eq:
0982         case Operator::neq:
0983             ret << TypeTriplet(ExpressionType(ExpressionType::Any, 1),
0984                                ExpressionType(ExpressionType::Any, 1),
0985                                ExpressionType(ExpressionType::Bool));
0986             break;
0987         case Operator::scalarproduct:
0988             ret << TypeTriplet(
0989                                 ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1),
0990                                 ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1),
0991                                 ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1));
0992             break;
0993         case Operator::power:
0994             ret << TypeTriplet(ExpressionType(ExpressionType::Value), ExpressionType(ExpressionType::Value), ExpressionType(ExpressionType::Value));
0995             ret << TypeTriplet(ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1), -1),
0996                                ExpressionType(ExpressionType::Value),
0997                                ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1), -1));
0998             break;
0999         case Operator::rem:
1000         case Operator::quotient:
1001         case Operator::factorof:
1002         case Operator::min:
1003         case Operator::max:
1004         case Operator::gcd:
1005         case Operator::lcm:
1006         case Operator::root:
1007             ret << TypeTriplet(ExpressionType(ExpressionType::Value), ExpressionType(ExpressionType::Value), ExpressionType(ExpressionType::Value));
1008             break;
1009         case Operator::gt:
1010         case Operator::lt:
1011         case Operator::approx:
1012         case Operator::geq:
1013         case Operator::leq:
1014             ret << TypeTriplet(ExpressionType(ExpressionType::Value), ExpressionType(ExpressionType::Value), ExpressionType(ExpressionType::Bool));
1015             break;
1016         case Operator::_and:
1017         case Operator::_or:
1018         case Operator::_xor:
1019         case Operator::implies:
1020             ret << TypeTriplet(ExpressionType(ExpressionType::Bool), ExpressionType(ExpressionType::Bool), ExpressionType(ExpressionType::Bool));
1021             break;
1022         case Operator::selector:
1023             ret << TypeTriplet(ExpressionType(ExpressionType::Value),
1024                                ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Any, 1), -1),
1025                                ExpressionType(ExpressionType::Any, 1));
1026             ret << TypeTriplet(ExpressionType(ExpressionType::Value),
1027                                ExpressionType(ExpressionType::List, ExpressionType(ExpressionType::Any, 1)),
1028                                ExpressionType(ExpressionType::Any, 1));
1029             ret << TypeTriplet(ExpressionType(ExpressionType::Value),
1030                                ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Any, 1), -1), -2),
1031                                ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Any, 1), -1));
1032             break;
1033         case Operator::_union:
1034             ret << TypeTriplet(ExpressionType(ExpressionType::List, ExpressionType(ExpressionType::Any, 1)),
1035                                ExpressionType(ExpressionType::List, ExpressionType(ExpressionType::Any, 1)),
1036                                ExpressionType(ExpressionType::List, ExpressionType(ExpressionType::Any, 1)));
1037             break;
1038         case Operator::map:
1039             ret << TypeTriplet(ExpressionType(ExpressionType::Lambda).addParameter(ExpressionType(ExpressionType::Any, 1)).addParameter(ExpressionType(ExpressionType::Any, 2)),
1040                                ExpressionType(ExpressionType::List, ExpressionType(ExpressionType::Any, 1)),
1041                                ExpressionType(ExpressionType::List, ExpressionType(ExpressionType::Any, 2)));
1042             break;
1043         case Operator::filter:
1044             ret << TypeTriplet(ExpressionType(ExpressionType::Lambda).addParameter(ExpressionType(ExpressionType::Any, 1)).addParameter(ExpressionType::Bool),
1045                                ExpressionType(ExpressionType::List, ExpressionType(ExpressionType::Any, 1)),
1046                                ExpressionType(ExpressionType::List, ExpressionType(ExpressionType::Any, 1)));
1047             break;
1048         default:
1049             break;
1050     }
1051     return ret;
1052 }
1053 
1054 ExpressionType TypePair(const ExpressionType& a, const ExpressionType& b) { return ExpressionType(ExpressionType::Lambda).addParameter(a).addParameter(b); }
1055 
1056 QList<ExpressionType> Operations::inferUnary(Operator::OperatorType op)
1057 {
1058     QList<ExpressionType> ret;
1059     switch(op) {
1060         case Operator::minus:
1061             ret << TypePair(ExpressionType(ExpressionType::Value), ExpressionType(ExpressionType::Value));
1062             ret << TypePair(ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Any, 1), -1), ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Any, 1), -1));
1063             break;
1064         case Operator::card:
1065             ret << TypePair(ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Any, 1), -1), ExpressionType(ExpressionType::Value));
1066             ret << TypePair(ExpressionType(ExpressionType::List, ExpressionType(ExpressionType::Any, 1)), ExpressionType(ExpressionType::Value));
1067             break;
1068         case Operator::sum:
1069         case Operator::product:
1070             ret << TypePair(ExpressionType(ExpressionType::Value), ExpressionType(ExpressionType::Value));
1071             ret << TypePair(ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Any, 1), -1), ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Any, 1), -1));
1072             break;
1073         case Operator::transpose:
1074             ret << TypePair(ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -2), -1),
1075                             ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1), -2));
1076             ret << TypePair(ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1),
1077                             ExpressionType(ExpressionType::Matrix, ExpressionType(ExpressionType::Vector, ExpressionType(ExpressionType::Value), -1), 1));
1078             break;
1079         case Operator::factorial:
1080         case Operator::sin:
1081         case Operator::cos:
1082         case Operator::tan:
1083         case Operator::sec:
1084         case Operator::csc:
1085         case Operator::cot:
1086         case Operator::sinh:
1087         case Operator::cosh:
1088         case Operator::tanh:
1089         case Operator::sech:
1090         case Operator::csch:
1091         case Operator::coth:
1092         case Operator::arcsin:
1093         case Operator::arccos:
1094         case Operator::arctan:
1095         case Operator::arccot:
1096         case Operator::arcsinh:
1097         case Operator::arccosh:
1098         case Operator::arccsc:
1099         case Operator::arccsch:
1100         case Operator::arcsec:
1101         case Operator::arcsech:
1102         case Operator::arctanh:
1103         case Operator::exp:
1104         case Operator::ln:
1105         case Operator::log:
1106         case Operator::abs:
1107         case Operator::conjugate:
1108         case Operator::arg:
1109         case Operator::real:
1110         case Operator::imaginary:
1111         case Operator::floor:
1112         case Operator::ceiling:
1113             ret << TypePair(ExpressionType(ExpressionType::Value), ExpressionType(ExpressionType::Value));
1114             break;
1115         case Operator::_not:
1116         case Operator::exists:
1117         case Operator::forall:
1118             ret << TypePair(ExpressionType(ExpressionType::Bool), ExpressionType(ExpressionType::Bool));
1119             break;
1120         default:
1121             break;
1122     }
1123     return ret;
1124 }
1125 
1126 Operations::BinaryOp Operations::opsBinary[Object::custom+1][Object::custom+1] = {
1127     {nullptr,(Operations::BinaryOp) reduceNoneValue,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,(Operations::BinaryOp) reduceNoneMatrix,nullptr,nullptr},
1128     {(Operations::BinaryOp) reduceValueNone, (Operations::BinaryOp) reduceValueValue, nullptr, (Operations::BinaryOp) reduceValueVector, (Operations::BinaryOp) reduceValueList,nullptr,nullptr,nullptr,(Operations::BinaryOp) reduceValueMatrix,nullptr},
1129     {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr},
1130     {nullptr, (Operations::BinaryOp) reduceVectorValue, nullptr, (Operations::BinaryOp) reduceVectorVector, nullptr,nullptr,nullptr,nullptr,(Operations::BinaryOp) reduceVectorMatrix,nullptr,nullptr},
1131     {nullptr, nullptr, nullptr,nullptr, (Operations::BinaryOp) reduceListList, nullptr,nullptr,nullptr,nullptr,nullptr},
1132     {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr},
1133     {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr},
1134     {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr},
1135     {(Operations::BinaryOp) reduceMatrixNone, (Operations::BinaryOp) reduceMatrixValue,nullptr, (Operations::BinaryOp) reduceMatrixVector,nullptr,nullptr,nullptr,nullptr, (Operations::BinaryOp) reduceMatrixMatrix,nullptr,nullptr},
1136     {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr},
1137     {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,(Operations::BinaryOp) reduceCustomCustom}
1138 };
1139 
1140 Object * Operations::reduce(Operator::OperatorType op, Object * val1, Object * val2, QString** correct)
1141 {
1142     Object::ObjectType t1=val1->type(), t2=val2->type();
1143     
1144     BinaryOp f=opsBinary[t1][t2];
1145     Q_ASSERT(f);
1146     return f(op, val1, val2, correct);
1147 }
1148 
1149 Operations::UnaryOp Operations::opsUnary[] = {
1150     nullptr,
1151     (Operations::UnaryOp) Operations::reduceUnaryValue,
1152     nullptr, //variable
1153     (Operations::UnaryOp) Operations::reduceUnaryVector,
1154     (Operations::UnaryOp) Operations::reduceUnaryList,
1155     nullptr, //apply
1156     nullptr, //oper
1157     nullptr, //container
1158     (Operations::UnaryOp) Operations::reduceUnaryMatrix
1159 };
1160 
1161 Object * Operations::reduceUnary(Operator::OperatorType op, Object * val, QString** correct)
1162 {
1163     Q_ASSERT(val->type()<=Operator::matrix);
1164     UnaryOp f=opsUnary[val->type()];
1165     
1166     Q_ASSERT(f && "using reduceUnary in a wrong way");
1167     return f(op, val, correct);
1168 }
1169 
1170 Object* Operations::errorCase(const QString& error, QString** correct)
1171 {
1172     *correct = new QString(error);
1173     return new None;
1174 }