File indexing completed on 2022-11-22 17:48:13

0001 /*************************************************************************************
0002  *  Copyright (C) 2007-2008 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 "operatorsmodel.h"
0020 #include <analitza/operator.h>
0021 #include <analitza/variables.h>
0022 #include <QFont>
0023 #include <QCoreApplication>
0024 
0025 using Analitza::Operator;
0026 
0027 OperatorsModel::OperatorsModel(QObject *parent) : QAbstractTableModel(parent), m_vars(nullptr)
0028 {
0029 }
0030 
0031 QHash<int, QByteArray> OperatorsModel::roleNames() const
0032 {
0033     auto ret = QAbstractTableModel::roleNames();
0034     ret.insert(IsVariableRole, "isVariable");
0035     ret.insert(DescriptionRole, "description");
0036     return ret;
0037 }
0038 
0039 QVariant OperatorsModel::data(const QModelIndex & index, int role) const
0040 {
0041     QVariant ret;
0042     if(role==Qt::DisplayRole) {
0043         if(index.row()<Analitza::Operator::nOfOps-2) {
0044             Analitza::Operator oper((Analitza::Operator::OperatorType) (index.row()+1));
0045             
0046             switch(index.column()) {
0047                 case 0:
0048                     ret=oper.toString();
0049                     break;
0050                 case 1:
0051                     ret=description(oper);
0052                     break;
0053                 case 2:
0054                     ret=sample(oper);
0055                     break;
0056                 case 3:
0057                     ret=example(oper);
0058                     break;
0059             }
0060         } else if(m_vars) {
0061             int var=index.row()-Analitza::Operator::nOfOps+2;
0062             QString key=m_vars->keys()[var];
0063             switch(index.column()) {
0064                 case 0:
0065                     ret=key;
0066                     break;
0067                 case 1:
0068                     ret=m_vars->value(key)->toString();
0069                     break;
0070             }
0071         }
0072     } else if(role==Qt::FontRole && index.column()==1) {
0073         QFont f;
0074         f.setItalic(true);
0075         ret=f;
0076     } else if(role==DescriptionRole && index.column()==0) {
0077         Analitza::Operator oper((Analitza::Operator::OperatorType) (index.row()+1));
0078         switch(index.column()) {
0079             case 0:
0080                 ret=description(oper);
0081                 break;
0082         }
0083     } else if(role==IsVariableRole && index.column()==0) {
0084         ret=index.row()<Analitza::Operator::nOfOps-2;
0085     }
0086     return ret;
0087 }
0088 
0089 QVariant OperatorsModel::headerData(int section, Qt::Orientation orientation, int role) const
0090 {
0091     QVariant ret;
0092     if(role==Qt::DisplayRole && orientation==Qt::Horizontal) {
0093         switch(section) {
0094             case 0:
0095                 ret=QCoreApplication::translate("@title:column", "Name");
0096                 break;
0097             case 1:
0098                 ret=QCoreApplication::translate("@title:column", "Description");
0099                 break;
0100             case 2:
0101                 ret=QCoreApplication::translate("@title:column", "Parameters");
0102                 break;
0103             case 3:
0104                 ret=QCoreApplication::translate("@title:column", "Example");
0105                 break;
0106         }
0107     }
0108     return ret;
0109 }
0110 
0111 int OperatorsModel::rowCount(const QModelIndex &) const
0112 {
0113     int count=Analitza::Operator::nOfOps;
0114     if(m_vars)
0115         count+=m_vars->count();
0116     return count-2;
0117 }
0118 
0119 int OperatorsModel::columnCount(const QModelIndex &) const
0120 {
0121     return 4;
0122 }
0123 
0124 void OperatorsModel::updateInformation()
0125 {
0126     beginResetModel();
0127     endResetModel();
0128 }
0129 
0130 QString OperatorsModel::sample(const Analitza::Operator& oper)
0131 {
0132     QString funcname=oper.toString();
0133     QString bounds;
0134     if(oper.isBounded()) {
0135         bounds=QCoreApplication::translate("Syntax for function bounding", " : var");
0136         if(oper.operatorType()==Operator::sum || oper.operatorType()==Operator::product)
0137             bounds += QCoreApplication::translate("Syntax for function bounding values", "=from..to");
0138     }
0139     
0140     QString sample = QCoreApplication::tr("%1(").arg(funcname);
0141     
0142     if(oper.nparams()<0) {
0143         return QCoreApplication::tr("%1... parameters, ...%2)").arg(sample, bounds);
0144     } else {
0145         for(int i=0; i<oper.nparams(); ++i) {
0146             sample += QCoreApplication::tr("par%1").arg(i+1);
0147             if(i<oper.nparams()-1)
0148                 sample += QLatin1String(", ");
0149         }
0150         return sample+bounds+')';
0151     }
0152 }
0153 
0154 QString OperatorsModel::description(const Analitza::Operator& o)
0155 {
0156     QString s;
0157     switch(o.operatorType()) {
0158         case Operator::plus:
0159             s = QCoreApplication::tr("Addition");
0160             break;
0161         case Operator::times:
0162             s = QCoreApplication::tr("Multiplication");
0163             break;
0164         case Operator::divide:
0165             s = QCoreApplication::tr("Division");
0166             break;
0167         case Operator::minus:
0168             s = QCoreApplication::tr("Subtraction. Will remove all values from the first one.");
0169             break;
0170         case Operator::power:
0171             s = QCoreApplication::tr("Power");
0172             break;
0173         case Operator::rem:
0174             s = QCoreApplication::tr("Remainder");
0175             break;
0176         case Operator::quotient:
0177             s = QCoreApplication::tr("Quotient");
0178             break;
0179         case Operator::factorof:
0180             s = QCoreApplication::tr("The factor of");
0181             break;
0182         case Operator::factorial:
0183             s = QCoreApplication::tr("Factorial. factorial(n)=n!");
0184             break;
0185         case Operator::sin:
0186             s = QCoreApplication::tr("Function to calculate the sine of a given angle");
0187             break;
0188         case Operator::cos:
0189             s = QCoreApplication::tr("Function to calculate the cosine of a given angle");
0190             break;
0191         case Operator::tan:
0192             s = QCoreApplication::tr("Function to calculate the tangent of a given angle");
0193             break;
0194         case Operator::sec:
0195             s = QCoreApplication::tr("Secant");
0196             break;
0197         case Operator::csc:
0198             s = QCoreApplication::tr("Cosecant");
0199             break;
0200         case Operator::cot:
0201             s = QCoreApplication::tr("Cotangent");
0202             break;
0203         case Operator::sinh:
0204             s = QCoreApplication::tr("Hyperbolic sine");
0205             break;
0206         case Operator::cosh:
0207             s = QCoreApplication::tr("Hyperbolic cosine");
0208             break;
0209         case Operator::tanh:
0210             s = QCoreApplication::tr("Hyperbolic tangent");
0211             break;
0212         case Operator::sech:
0213             s = QCoreApplication::tr("Hyperbolic secant");
0214             break;
0215         case Operator::csch:
0216             s = QCoreApplication::tr("Hyperbolic cosecant");
0217             break;
0218         case Operator::coth:
0219             s = QCoreApplication::tr("Hyperbolic cotangent");
0220             break;
0221         case Operator::arcsin:
0222             s = QCoreApplication::tr("Arc sine");
0223             break;
0224         case Operator::arccos:
0225             s = QCoreApplication::tr("Arc cosine");
0226             break;
0227         case Operator::arctan:
0228             s = QCoreApplication::tr("Arc tangent");
0229             break;
0230         case Operator::arccot:
0231             s = QCoreApplication::tr("Arc cotangent");
0232             break;
0233 //         case Operator::arccoth:
0234 //             s = QCoreApplication::tr("Hyperbolic arc cotangent");
0235 //             break;
0236         case Operator::arctanh:
0237             s = QCoreApplication::tr("Hyperbolic arc tangent");
0238             break;
0239         case Operator::sum:
0240             s = QCoreApplication::tr("Summatory");
0241             break;
0242         case Operator::product:
0243             s = QCoreApplication::tr("Productory");
0244             break;
0245         case Operator::forall:
0246             s = QCoreApplication::tr("For all");
0247             break;
0248         case Operator::exists:
0249             s = QCoreApplication::tr("Exists");
0250             break;
0251         case Operator::diff:
0252             s = QCoreApplication::tr("Differentiation");
0253             break;
0254         case Operator::arcsinh:
0255             s = QCoreApplication::tr("Hyperbolic arc sine");
0256             break;
0257         case Operator::arccosh:
0258             s = QCoreApplication::tr("Hyperbolic arc cosine");
0259             break;
0260         case Operator::arccsc:
0261             s = QCoreApplication::tr("Arc cosecant");
0262             break;
0263         case Operator::arccsch:
0264             s = QCoreApplication::tr("Hyperbolic arc cosecant");
0265             break;
0266         case Operator::arcsec:
0267             s = QCoreApplication::tr("Arc secant");
0268             break;
0269         case Operator::arcsech:
0270             s = QCoreApplication::tr("Hyperbolic arc secant");
0271             break;
0272         case Operator::exp:
0273             s = QCoreApplication::tr("Exponent (e^x)");
0274             break;
0275         case Operator::ln:
0276             s = QCoreApplication::tr("Base-e logarithm");
0277             break;
0278         case Operator::log:
0279             s = QCoreApplication::tr("Base-10 logarithm");
0280             break;
0281         case Operator::abs:
0282             s = QCoreApplication::tr("Absolute value. abs(n)=|n|");
0283             break;
0284         case Operator::conjugate:
0285             s = QCoreApplication::tr("Conjugate");
0286             break;
0287         case Operator::arg:
0288             s = QCoreApplication::tr("Arg");
0289             break;
0290         case Operator::real:
0291             s = QCoreApplication::tr("Real");
0292             break;
0293         case Operator::imaginary:
0294             s = QCoreApplication::tr("Imaginary");
0295             break;
0296         case Operator::floor:
0297             s = QCoreApplication::tr("Floor value. floor(n)=⌊n⌋");
0298             break;
0299         case Operator::ceiling:
0300             s = QCoreApplication::tr("Ceil value. ceil(n)=⌈n⌉");
0301             break;
0302         case Operator::min:
0303             s = QCoreApplication::tr("Minimum");
0304             break;
0305         case Operator::max:
0306             s = QCoreApplication::tr("Maximum");
0307             break;
0308         case Operator::gt:
0309             s = QCoreApplication::tr("Greater than. gt(a,b)=a>b");
0310             break;
0311         case Operator::lt:
0312             s = QCoreApplication::tr("Less than. lt(a,b)=a<b");
0313             break;
0314         case Operator::eq:
0315             s = QCoreApplication::tr("Equal. eq(a,b) = a=b");
0316             break;
0317         case Operator::approx:
0318             s = QCoreApplication::tr("Approximation. approx(a)=a±n");
0319             break;
0320         case Operator::neq:
0321             s = QCoreApplication::tr("Not equal. neq(a,b)=a≠b");
0322             break;
0323         case Operator::geq:
0324             s = QCoreApplication::tr("Greater or equal. geq(a,b)=a≥b");
0325             break;
0326         case Operator::leq:
0327             s = QCoreApplication::tr("Less or equal. leq(a,b)=a≤b");
0328             break;
0329         case Operator::_and:
0330             s = QCoreApplication::tr("Boolean and");
0331             break;
0332         case Operator::_not:
0333             s = QCoreApplication::tr("Boolean not");
0334             break;
0335         case Operator::_or:
0336             s = QCoreApplication::tr("Boolean or");
0337             break;
0338         case Operator::_xor:
0339             s = QCoreApplication::tr("Boolean xor");
0340             break;
0341         case Operator::implies:
0342             s = QCoreApplication::tr("Boolean implication");
0343             break;
0344         case Operator::gcd:
0345             s = QCoreApplication::tr("Greatest common divisor");
0346             break;
0347         case Operator::lcm:
0348             s = QCoreApplication::tr("Least common multiple");
0349             break;
0350         case Operator::root:
0351             s = QCoreApplication::tr("Root");
0352             break;
0353         case Operator::card:
0354             s = QCoreApplication::tr("Cardinal");
0355             break;
0356         case Operator::scalarproduct:
0357             s = QCoreApplication::tr("Scalar product");
0358             break;
0359         case Operator::selector:
0360             s = QCoreApplication::tr("Select the par1-th element of par2 list or vector");
0361             break;
0362         case Operator::_union:
0363             s = QCoreApplication::tr("Joins several items of the same type");
0364             break;
0365         case Operator::map:
0366             s = QCoreApplication::tr("Applies a function to every element in a list");
0367             break;
0368         case Operator::filter:
0369             s = QCoreApplication::tr("Removes all elements that don't fit a condition");
0370             break;
0371         case Operator::transpose:
0372             s = QCoreApplication::tr("Transpose");
0373             break;
0374         case Operator::function:
0375         case Operator::nOfOps:
0376         case Operator::none:
0377             break;
0378     }
0379     return s;
0380 }
0381 
0382 QString OperatorsModel::example(const Analitza::Operator& o)
0383 {
0384     QString s;
0385     
0386     switch(o.operatorType()) {
0387         case Operator::plus:
0388             s=QStringLiteral("x+2");
0389             break;
0390         case Operator::times:
0391             s=QStringLiteral("x*2");
0392             break;
0393         case Operator::divide:
0394             s=QStringLiteral("x/2");
0395             break;
0396         case Operator::minus:
0397             s=QStringLiteral("x-2");
0398             break;
0399         case Operator::power:
0400             s=QStringLiteral("x^2");
0401             break;
0402         case Operator::rem:
0403             s=QStringLiteral("rem(x, 5)");
0404             break;
0405         case Operator::quotient:
0406             s=QStringLiteral("quotient(x, 2)");
0407             break;
0408         case Operator::factorof:
0409             s=QStringLiteral("factorof(x, 3)");
0410             break;
0411         case Operator::min:
0412             s=QStringLiteral("min(x, 4)");
0413             break;
0414         case Operator::max:
0415             s=QStringLiteral("max(x, 4)");
0416             break;
0417         case Operator::gt:
0418             s=QStringLiteral("piecewise { x>4 ? 1, ? 0 }");
0419             break;
0420         case Operator::lt:
0421             s=QStringLiteral("piecewise { x<4 ? 1, ? 0 }");
0422             break;
0423         case Operator::eq:
0424             s=QStringLiteral("piecewise { x=4 ? 1, ? 0 }");
0425             break;
0426         case Operator::approx:
0427             s=QStringLiteral("piecewise { approx(x, 4) ? 1, ? 0 }");
0428             break;
0429         case Operator::neq:
0430             s=QStringLiteral("piecewise { x!=4 ? 1, ? 0 }");
0431             break;
0432         case Operator::geq:
0433             s=QStringLiteral("piecewise { x>=4 ? 1, ? 0 }");
0434             break;
0435         case Operator::leq:
0436             s=QStringLiteral("piecewise { x<=4 ? 1, ? 0 }");
0437             break;
0438         case Operator::_and:
0439             s=QStringLiteral("piecewise { and(x>-2, x<2) ? 1, ? 0 }");
0440             break;
0441         case Operator::_or:
0442             s=QStringLiteral("piecewise { or(x>2, x>-2) ? 1, ? 0 }");
0443             break;
0444         case Operator::_xor:
0445             s=QStringLiteral("piecewise { xor(x>0, x<3) ? 1, ? 0 }");
0446             break;
0447         case Operator::implies:
0448             s=QStringLiteral("piecewise { implies(x<0, x<3) ? 1, ? 0 }");
0449             break;
0450         case Operator::forall:
0451             s=QStringLiteral("piecewise { forall(t:t@list { true, false, false }) ? 1, ? 0 }");
0452             break;
0453         case Operator::exists:
0454             s=QStringLiteral("piecewise { exists(t:t@list { true, false, false }) ? 1, ? 0 }");
0455             break;
0456         case Operator::_not:
0457             s=QStringLiteral("piecewise { not(x>0) ? 1, ? 0 }");
0458             break;
0459         case Operator::gcd:
0460             s=QStringLiteral("gcd(x, 3)");
0461             break;
0462         case Operator::lcm:
0463             s=QStringLiteral("lcm(x, 4)");
0464             break;
0465         case Operator::root:
0466             s=QStringLiteral("root(x, 2)");
0467             break;
0468         case Operator::selector:
0469             s=QStringLiteral("scalarproduct(vector { 0, x }, vector { x, 0 })[1]");
0470             break;
0471         case Operator::sum:
0472             s=QStringLiteral("x*sum(t*t:t=0..3)");
0473             break;
0474         case Operator::product:
0475             s=QStringLiteral("product(t+t:t=1..3)");
0476             break;
0477         case Operator::card:
0478             s=QStringLiteral("card(vector { x, 1, 2 })");
0479             break;
0480         case Operator::scalarproduct:
0481             s=QStringLiteral("scalarproduct(vector { 0, x }, vector { x, 0 })[1]");
0482             break;
0483         case Operator::diff:
0484             s=QStringLiteral("(diff(x^2:x))(x)");
0485             break;
0486         case Operator::_union:
0487             s=QStringLiteral("union(list { 1, 2, 3 }, list { 4, 5, 6 })[rem(floor(x), 5)+3]");
0488             break;
0489         case Operator::map:
0490             s=QStringLiteral("map(x->x+x, list { 1, 2, 3, 4, 5, 6 })[rem(floor(x), 5)+3]");
0491             break;
0492         case Operator::filter:
0493             s=QStringLiteral("filter(u->rem(u, 2)=0, list { 2, 4, 3, 4, 8, 6 })[rem(floor(x), 5)+3]");
0494             break;
0495         case Operator::transpose:
0496             s = QStringLiteral("transpose(matrix { matrixrow { 1, 2, 3, 4, 5, 6 } })[rem(floor(x), 5)+3][1]");
0497             break;
0498         case Operator::real:
0499             s = QStringLiteral("real(x*i)");
0500             break;
0501         case Operator::conjugate:
0502             s = QStringLiteral("conjugate(x*i)");
0503             break;
0504         case Operator::arg:
0505             s = QStringLiteral("arg(x*i)");
0506             break;
0507         case Operator::imaginary:
0508             s = QStringLiteral("imaginary(x*i)");
0509             break;
0510         case Operator::factorial:
0511         case Operator::arcsech:
0512         case Operator::arcsec:
0513         case Operator::arccsch:
0514         case Operator::arccsc:
0515 //         case Operator::arccoth:
0516         case Operator::sin:
0517         case Operator::cos:
0518         case Operator::tan:
0519         case Operator::sec:
0520         case Operator::csc:
0521         case Operator::cot:
0522         case Operator::sinh:
0523         case Operator::cosh:
0524         case Operator::tanh:
0525         case Operator::sech:
0526         case Operator::csch:
0527         case Operator::coth:
0528         case Operator::arcsin:
0529         case Operator::arccos:
0530         case Operator::arctan:
0531         case Operator::arccot:
0532         case Operator::arcsinh:
0533         case Operator::arccosh:
0534 //         case Operator::arccsc:
0535 //         case Operator::arccsch:
0536 //         case Operator::arcsec:
0537 //         case Operator::arcsech:
0538         case Operator::arctanh:
0539         case Operator::exp:
0540         case Operator::ln:
0541         case Operator::log:
0542         case Operator::abs:
0543         case Operator::floor:
0544         case Operator::ceiling:
0545             s=QStringLiteral("%1(x)").arg(o.toString());
0546             break;
0547         case Operator::nOfOps:
0548         case Operator::none:
0549         case Operator::function:
0550             break;
0551     }
0552     return "x->"+s;
0553 }
0554 
0555 QModelIndex OperatorsModel::indexForOperatorName(const QString& id) const
0556 {
0557     Operator::OperatorType opt=Analitza::Operator::toOperatorType(id);
0558     if(opt==Operator::none)
0559         return QModelIndex();
0560     else
0561         return index(opt-1, 0);
0562 }
0563 
0564 QString OperatorsModel::parameterHelp(const QModelIndex& index, int param, bool inbounds) const
0565 {
0566     Q_ASSERT(index.isValid());
0567     QString ret;
0568     Analitza::Operator oper((Analitza::Operator::OperatorType) (index.row()+1));
0569     QString funcname = oper.toString();
0570     const int op=oper.nparams();
0571     if(op == -1) {
0572         ret=QCoreApplication::translate("n-ary function prototype", "<em>%1</em>(..., <b>par%2</b>, ...)").arg(funcname).arg(param+1);
0573     } else {
0574         ret=standardFunctionCallHelp(funcname, param, op, inbounds, oper.isBounded());
0575     }
0576     return ret;
0577 }
0578 
0579 QString OperatorsModel::standardFunctionCallHelp(const QString& funcname, int param, int paramcount, bool inbounds, bool isbounded)
0580 {
0581     QString sample = (param < paramcount || (inbounds && isbounded)) ?
0582         QCoreApplication::translate("Function name in function prototype", "<em>%1</em>(").arg(funcname) :
0583         QCoreApplication::translate("Uncorrect function name in function prototype", "<em style='color:red'><b>%1</b></em>(").arg(funcname);
0584         
0585     for(int i=0; i<paramcount; ++i) {
0586         QString current=QCoreApplication::translate("Parameter in function prototype", "par%1").arg(i+1);
0587         
0588         if(i==param)
0589             current=QCoreApplication::translate("Current parameter in function prototype", "<b>%1</b>").arg(current);
0590         sample += current;
0591         if(i<paramcount-1)
0592             sample += QCoreApplication::translate("Function parameter separator", ", ");
0593     }
0594     
0595     if(isbounded) {
0596         static QString bounds=QCoreApplication::translate("Current parameter is the bounding", " : bounds");
0597         QString p=bounds;
0598         if(inbounds)
0599             p=QCoreApplication::translate("Current parameter in function prototype", "<b>%1</b>").arg(p);
0600         sample += p;
0601     }
0602     
0603     return sample+')';
0604 
0605 }
0606 
0607 QString OperatorsModel::lastWord(int pos, const QString& exp)
0608 {
0609     int act=pos-1;
0610     for(; act>=0 && exp[act].isLetter(); act--) {}
0611 
0612     return exp.mid(act+1, pos-act-1);
0613 }
0614 
0615 /*QString OperatorsModel::operToString(const Operator& op) const
0616 {
0617     QStandardItem *it;
0618     
0619     for(int i=0; i<KEYWORDNUM; i++) {
0620         it=item(i,2);
0621         if(it!=NULL && it->data(Qt::EditRole).toInt()==op.operatorType()) {
0622             return item(i,0)->data(Qt::EditRole).toString();
0623 }
0624 }
0625     return QString();
0626 }*/
0627 
0628