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>ⅇ</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("∑") : 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="<", *gt=">", *_not="¬"; 0151 const char* leq="≤", *geq="≥", *neq="≠", *approx="≈"; 0152 const char* implies="⇒", *_and="∧", *_or="∨", *_xor="⊕"; 0153 const char* mabs="|", *factorial="!"; 0154 const char *lfloor="⌊", *rfloor="⌋"; 0155 const char *lceil="⌈", *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>ⅇ</mn></msub>"; 0158 } 0159 0160 MathMLPresentationExpressionWriter::operatorToString 0161 MathMLPresentationExpressionWriter::m_operatorToPresentation[] = { nullptr, 0162 joinOp<&plus>, joinOp<×>, 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<<>, joinOp<>>, 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>→</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><</mo>")+convertElements(var->constBegin(), var->constEnd(), this).join(QStringLiteral("<mo>,</mo>"))+"<mo>></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> ⁡ </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