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

0001 /*************************************************************************************
0002  *  Copyright (C) 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 "mathmlpresentationexpressionwriter.h"
0020 #include "value.h"
0021 #include "container.h"
0022 #include <QStringList>
0023 #include "vector.h"
0024 #include "list.h"
0025 #include "variable.h"
0026 #include "apply.h"
0027 #include <analitza/analitzautils.h>
0028 #include "matrix.h"
0029 
0030 using namespace Analitza;
0031 
0032 namespace
0033 {
0034 
0035 template <class T>
0036 QStringList convertElements(T it, const T& itEnd, MathMLPresentationExpressionWriter* w)
0037 {
0038     QStringList elems;
0039     for(; it!=itEnd; ++it) {
0040         elems += (*it)->accept(w).toString();
0041     }
0042     return elems;
0043 }
0044 
0045 template <const char **C>
0046 static QString joinOp(const Apply* c, MathMLPresentationExpressionWriter* w)
0047 {
0048     QString op=QStringLiteral("<mo>%1</mo>").arg(*C);
0049     return convertElements<Apply::const_iterator>(c->firstValue(), c->constEnd(), w).join(op);
0050 }
0051 
0052 template <const char **C, const char **D>
0053 static QString infix(const Apply* c, MathMLPresentationExpressionWriter* w)
0054 {
0055     QString exp=QStringLiteral("<mrow><mo>%1</mo>%2<mo>%3</mo></mrow>").arg(*C)
0056         .arg(convertElements<Apply::const_iterator>(c->firstValue(), c->constEnd(), w).join(QString())).arg(*D);
0057     return exp;
0058 }
0059 
0060 template <const char **C>
0061 static QString prefix(const Apply* c, MathMLPresentationExpressionWriter* w)
0062 {
0063     return QStringLiteral("<mo>%1</mo>").arg(*C)+convertElements(c->firstValue(), c->constEnd(), w).join(QString());
0064 }
0065 
0066 template <const char **C>
0067 static QString prefixOp(const Apply* c, MathMLPresentationExpressionWriter* w)
0068 {
0069     return QString(*C)+convertElements(c->firstValue(), c->constEnd(), w).join(QString());
0070 }
0071 
0072 template <const char **C>
0073 static QString postfix(const Apply* c, MathMLPresentationExpressionWriter* w)
0074 {
0075     return convertElements(c->firstValue(), c->constEnd(), w).join(QString())+QStringLiteral("<mo>%1</mo>").arg(*C);
0076 }
0077 
0078 QString minus(const Apply* c, MathMLPresentationExpressionWriter* w)
0079 {
0080     QStringList e=convertElements(c->firstValue(), c->constEnd(), w);
0081     if(e.count()==1)
0082         return "<mo>-</mo>"+e[0];
0083     else
0084         return e.join(QStringLiteral("<mo>-</mo>"));
0085 }
0086 
0087 QString power(const Apply* c, MathMLPresentationExpressionWriter* w)
0088 {    return "<msup>"+convertElements(c->firstValue(), c->constEnd(), w).join(QString())+"</msup>"; }
0089 
0090 QString divide(const Apply* c, MathMLPresentationExpressionWriter* w)
0091 {    return "<mfrac><mrow>"+convertElements(c->firstValue(), c->constEnd(), w).join(QStringLiteral("</mrow><mrow>"))+"</mrow></mfrac>"; }
0092 
0093 QString quotient(const Apply* c, MathMLPresentationExpressionWriter* w)
0094 {    return divide(c, w); }
0095 
0096 QString root(const Apply* c, MathMLPresentationExpressionWriter* w)
0097 {
0098     Cn two(2);
0099     if(AnalitzaUtils::equalTree(c->values().at(1), &two))
0100         return "<msqrt>"+(*c->firstValue())->accept(w).toString()+"</msqrt>";
0101     else
0102         return "<mroot>"+convertElements<Apply::const_iterator>(c->firstValue(), c->constEnd(), w).join(QString())+"</mroot>";
0103 }
0104 
0105 QString diff(const Apply* c, MathMLPresentationExpressionWriter* w)
0106 {
0107     QStringList bv=c->bvarStrings();
0108     return "<msubsup><mfenced>"+convertElements<Apply::const_iterator>(c->firstValue(), c->constEnd(), w).join(QString())+"</mfenced>"
0109             "<mrow>"+bv.join(QStringLiteral("<mo>,</mo>"))+"</mrow><mo>'</mo></msubsup>";
0110 }
0111 
0112 QString exp(const Apply* c, MathMLPresentationExpressionWriter* w)
0113 {
0114     return "<msup><mn>&ExponentialE;</mn>"+convertElements<Apply::const_iterator>(c->firstValue(), c->constEnd(), w).at(0)+"</msup>";
0115 }
0116 
0117 QString iterative(Operator::OperatorType t, const Apply* c, MathMLPresentationExpressionWriter* w)
0118 {
0119     QString op= t==Operator::sum ? QStringLiteral("&Sum;") : QStringLiteral("&Prod;");
0120     QString ul="<mrow>"+c->ulimit()->toString()+"</mrow>";
0121     QString dl="<mrow>"+c->bvarStrings().join(QStringLiteral(", "))+"<mo>=</mo>"+c->dlimit()->toString()+"</mrow>";
0122     
0123     return "<mrow><msubsup><mo>"+op+"</mo>"+dl+ul+"</msubsup>"+convertElements(c->firstValue(), c->constEnd(), w).join(QString())+"</mrow>";
0124 }
0125 
0126 QString sum(const Apply* c, MathMLPresentationExpressionWriter* w)
0127 { return iterative(Operator::sum, c, w); }
0128 
0129 QString product(const Apply* c, MathMLPresentationExpressionWriter* w)
0130 { return iterative(Operator::product, c, w); }
0131 
0132 QString selector(const Apply* c, MathMLPresentationExpressionWriter* w)
0133 {
0134     QStringList el=convertElements(c->firstValue(), c->constEnd(), w);
0135     return "<msub><mrow>"+el.last()+"</mrow><mrow>"+el.first()+"</mrow></msub>";
0136 }
0137 
0138 QString function(const Apply* c, MathMLPresentationExpressionWriter* w)
0139 {
0140     QString ret=QStringLiteral("<mrow>");
0141     foreach(const Ci* bvar, c->bvarCi())
0142         ret+=bvar->accept(w).toString();
0143     foreach(const Object* o, c->values())
0144         ret+=o->accept(w).toString();
0145     ret+=QLatin1String("</mrow>");
0146     return ret;
0147 }
0148 
0149 const char* plus="+", *times="*", *equal="=";
0150 const char* lt="&lt;", *gt="&gt;", *_not="&not;";
0151 const char* leq="&leq;", *geq="&geq;", *neq="&NotEqual;", *approx="&asymp;";
0152 const char* implies="&DoubleRightArrow;", *_and="&and;", *_or="&or;", *_xor="&CirclePlus;";
0153 const char* mabs="|", *factorial="!";
0154 const char *lfloor="&lfloor;", *rfloor="&rfloor;";
0155 const char *lceil="&lceil;", *rceil="&rceil;";
0156 const char *cardinal="#", *scalarproduct="X";
0157 const char *_log10="<msub><mo>log</mo><mn>10</mn></msub>", *logE="<msub><mo>log</mo><mn>&ExponentialE;</mn></msub>";
0158 }
0159 
0160 MathMLPresentationExpressionWriter::operatorToString
0161     MathMLPresentationExpressionWriter::m_operatorToPresentation[] = { nullptr,
0162             joinOp<&plus>, joinOp<&times>,
0163             minus, divide, quotient,
0164             power, root, postfix<&factorial>,
0165             joinOp<&_and>,joinOp<&_or>,joinOp<&_xor>, prefix<&_not>,
0166             nullptr,nullptr,nullptr,nullptr,//gcd, lcm, rem, factorof,
0167             nullptr,nullptr,//max, min,
0168             joinOp<&lt>, joinOp<&gt>,
0169             joinOp<&equal>,
0170             joinOp<&neq>, joinOp<&leq>, joinOp<&geq>, joinOp<&implies>,
0171             joinOp<&approx>, infix<&mabs, &mabs>, infix<&lfloor, &rfloor>, infix<&lceil, &rceil>,
0172             // approx, abs, floor, ceiling,
0173             nullptr,nullptr,nullptr,// sin, cos, tan,
0174             nullptr,nullptr,nullptr,// sec, csc, cot,
0175             nullptr,nullptr,nullptr,// sinh, cosh, tanh,
0176             nullptr,nullptr,nullptr,// sech, csch, coth,
0177             nullptr,nullptr,nullptr,// arcsin, arccos, arctan,
0178             nullptr,// arccot,// arccoth,
0179             nullptr,nullptr,nullptr,// arccosh, arccsc, arccsch,
0180             nullptr,nullptr,nullptr,nullptr,// arcsec, arcsech, arcsinh, arctanh,
0181             exp, prefixOp<&_log10>, prefixOp<&logE>,// exp, ln, log,
0182             nullptr,nullptr,nullptr,nullptr,// //             conjugate, arg, real, imaginary,
0183             sum, product, diff,// sum, product, diff,
0184             prefix<&cardinal>, joinOp<&scalarproduct>, selector, nullptr,
0185             function // function
0186     };
0187 
0188 MathMLPresentationExpressionWriter::MathMLPresentationExpressionWriter(const Object* o)
0189 {
0190     m_result=o->accept(this);
0191 }
0192 
0193 QVariant MathMLPresentationExpressionWriter::visit(const Ci* var)
0194 {
0195     return QVariant::fromValue<QString>(QStringLiteral("<mi>") + var->name() + QStringLiteral("</mi>"));
0196 }
0197 
0198 QVariant MathMLPresentationExpressionWriter::visit(const Operator* op)
0199 {
0200     return op->name();
0201 }
0202 
0203 QVariant MathMLPresentationExpressionWriter::visit(const Cn* val)
0204 {
0205     if(val->isBoolean()) {
0206         if(val->isTrue())
0207             return "<mo>true</mo>";
0208         else
0209             return "<mo>false</mo>";
0210     } else
0211         return QStringLiteral("<mn>%1</mn>").arg(val->value(), 0, 'g', 12);
0212 
0213 }
0214 
0215 QString piecewise(const Container* c, MathMLPresentationExpressionWriter* w)
0216 {
0217     QString ret=QStringLiteral("<mrow>"
0218     "<mo stretchy='true'> { </mo>"
0219     "<mtable columnalign='left left'>");
0220     for(Container::const_iterator it=c->constBegin(); it!=c->constEnd(); ++it) {
0221         Q_ASSERT((*it)->type()==Object::container);
0222         Container *piece=static_cast<Container*>(*it);
0223         if(piece->containerType()==Container::piece) {
0224             ret += "<mtr>"
0225             "<mtd>"
0226                 +piece->m_params.first()->accept(w).toString()+
0227             "</mtd>"
0228             "<mtd>"
0229                 "<mtext>if </mtext>"
0230                 +piece->m_params.last()->accept(w).toString()+
0231             "</mtd>"
0232             "</mtr>";
0233         } else {
0234             ret += "<mtr>"
0235             "<mtd>"
0236                 +piece->m_params.first()->accept(w).toString()+
0237             "</mtd>"
0238             "<mtd>"
0239                 "<mtext>otherwise</mtext>"
0240             "</mtd>"
0241             "</mtr>";
0242         }
0243     }
0244     
0245     ret+=QLatin1String("</mtable></mrow>");
0246     return ret;
0247 }
0248 
0249 QString lambda(const Container* c, MathMLPresentationExpressionWriter* w)
0250 {
0251     QString ret=QStringLiteral("<mrow>");
0252     foreach(const Ci* bvar, c->bvarCi())
0253         ret+=bvar->accept(w).toString();
0254     ret+=QLatin1String("<mo>&RightArrow;</mo>");
0255     ret+=c->m_params.last()->accept(w).toString();
0256     ret+=QLatin1String("</mrow>");
0257     return ret;
0258 }
0259 
0260 QVariant MathMLPresentationExpressionWriter::visit(const Container* c)
0261 {
0262     QString ret;
0263 //     objectWalker(c);
0264 //     qDebug() << "ttttttttttt" << m_operatorToPresentation << op.operatorType()
0265 //              << m_operatorToPresentation[op.operatorType()] << op.name();
0266     
0267     switch(c->containerType()) {
0268         case Container::math:
0269             ret="<math><mrow>"+convertElements(c->constBegin(), c->constEnd(), this).join(QString())+"</mrow></math>";
0270             break;
0271         case Container::piecewise:
0272             ret=piecewise(c, this);
0273             break;
0274         case Container::lambda:
0275             ret=lambda(c, this);
0276             break;
0277         case Container::otherwise:
0278         case Container::piece:
0279         case Container::bvar:
0280         case Container::uplimit:
0281         case Container::downlimit:
0282         case Container::declare:
0283         case Container::domainofapplication:
0284         case Container::none:
0285             qDebug() << "error" << c->tagName();
0286             Q_ASSERT(false);
0287             break;
0288     }
0289     
0290     return ret;
0291 }
0292 
0293 QVariant MathMLPresentationExpressionWriter::visit(const Vector* var)
0294 {
0295     return QVariant::fromValue<QString>(QStringLiteral("<mrow><mo>&lt;</mo>")+convertElements(var->constBegin(), var->constEnd(), this).join(QStringLiteral("<mo>,</mo>"))+"<mo>&gt;</mo></mrow>");
0296 }
0297 
0298 QVariant MathMLPresentationExpressionWriter::visit(const List* var)
0299 {
0300     return QVariant::fromValue<QString>(QStringLiteral("<mrow><mo>[</mo>")+convertElements(var->constBegin(), var->constEnd(), this).join(QStringLiteral("<mo>,</mo>"))+"<mo>]</mo></mrow>");
0301 }
0302 
0303 QVariant MathMLPresentationExpressionWriter::visit(const Matrix* m)
0304 {
0305     return QVariant::fromValue<QString>(QStringLiteral("<mrow><mo>[</mo>")+convertElements(m->constBegin(), m->constEnd(), this).join(QStringLiteral("<mo>,</mo>"))+"<mo>]</mo></mrow>");
0306 }
0307 
0308 QVariant MathMLPresentationExpressionWriter::visit(const MatrixRow* m)
0309 {
0310     return QVariant::fromValue<QString>(QStringLiteral("<mrow><mo>[</mo>")+convertElements(m->constBegin(), m->constEnd(), this).join(QStringLiteral("<mo>,</mo>"))+"<mo>]</mo></mrow>");
0311 }
0312 
0313 QVariant Analitza::MathMLPresentationExpressionWriter::visit(const Analitza::Apply* a)
0314 {
0315     QString ret;
0316     Operator op=a->firstOperator();
0317     
0318     operatorToString call=m_operatorToPresentation[op.operatorType()];
0319     
0320     if(call!=nullptr) {
0321         ret = call(a, this);
0322     } else if(op.operatorType()!=0) {
0323         QString bvars;
0324         if(!a->bvarStrings().isEmpty()) {
0325             bvars=a->bvarStrings().join(QString());
0326             if(a->bvarStrings().size()>1)
0327                 bvars="<mfenced>"+bvars+"</mfenced>";
0328             const Object *ul=a->ulimit(), *dl=a->dlimit();
0329             if(ul || dl) {
0330                 bvars += QLatin1String("<mo>=</mo>");
0331                 if(dl) bvars += dl->accept(this).toString();
0332                 bvars += QLatin1String("<mo>..</mo>");
0333                 if(ul) bvars += ul->accept(this).toString();
0334             } else if(a->domain())
0335                 bvars += "<mo>@</mo>" + a->domain()->accept(this).toString();
0336             bvars="<mo>:</mo>"+bvars;
0337         }
0338         
0339         ret="<mi>"+op.name()+"</mi>"
0340             "<mo> &ApplyFunction; </mo>"
0341             "<mfenced>"
0342             +convertElements(a->firstValue(), a->constEnd(), this).join(QString())
0343             +bvars
0344             +"</mfenced>";
0345     }
0346     return ret;
0347 }
0348 
0349 QVariant MathMLPresentationExpressionWriter::visit(const CustomObject*)
0350 {
0351     return QStringLiteral("<!-- custom object -->");
0352 }
0353 
0354 QVariant MathMLPresentationExpressionWriter::visit(const None* )
0355 {
0356     return QString();
0357 }
0358