1 /*************************************************************************************
2  *  Copyright (C) 2008 by Aleix Pol <aleixpol@kde.org>                               *
3  *                                                                                   *
4  *  This program is free software; you can redistribute it and/or                    *
5  *  modify it under the terms of the GNU General Public License                      *
6  *  as published by the Free Software Foundation; either version 2                   *
7  *  of the License, or (at your option) any later version.                           *
8  *                                                                                   *
9  *  This program is distributed in the hope that it will be useful,                  *
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *
12  *  GNU General Public License for more details.                                     *
13  *                                                                                   *
14  *  You should have received a copy of the GNU General Public License                *
15  *  along with this program; if not, write to the Free Software                      *
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
17  *************************************************************************************/
18 
19 #include "mathmlpresentationexpressionwriter.h"
20 #include "value.h"
21 #include "container.h"
22 #include <QStringList>
23 #include "vector.h"
24 #include "list.h"
25 #include "variable.h"
26 #include "apply.h"
27 #include <analitza/analitzautils.h>
28 #include "matrix.h"
29 
30 using namespace Analitza;
31 
32 namespace
33 {
34 
35 template <class T>
convertElements(T it,const T & itEnd,MathMLPresentationExpressionWriter * w)36 QStringList convertElements(T it, const T& itEnd, MathMLPresentationExpressionWriter* w)
37 {
38     QStringList elems;
39     for(; it!=itEnd; ++it) {
40         elems += (*it)->accept(w).toString();
41     }
42     return elems;
43 }
44 
45 template <const char **C>
joinOp(const Apply * c,MathMLPresentationExpressionWriter * w)46 static QString joinOp(const Apply* c, MathMLPresentationExpressionWriter* w)
47 {
48     QString op=QStringLiteral("<mo>%1</mo>").arg(*C);
49     return convertElements<Apply::const_iterator>(c->firstValue(), c->constEnd(), w).join(op);
50 }
51 
52 template <const char **C, const char **D>
infix(const Apply * c,MathMLPresentationExpressionWriter * w)53 static QString infix(const Apply* c, MathMLPresentationExpressionWriter* w)
54 {
55     QString exp=QStringLiteral("<mrow><mo>%1</mo>%2<mo>%3</mo></mrow>").arg(*C)
56         .arg(convertElements<Apply::const_iterator>(c->firstValue(), c->constEnd(), w).join(QString())).arg(*D);
57     return exp;
58 }
59 
60 template <const char **C>
prefix(const Apply * c,MathMLPresentationExpressionWriter * w)61 static QString prefix(const Apply* c, MathMLPresentationExpressionWriter* w)
62 {
63     return QStringLiteral("<mo>%1</mo>").arg(*C)+convertElements(c->firstValue(), c->constEnd(), w).join(QString());
64 }
65 
66 template <const char **C>
prefixOp(const Apply * c,MathMLPresentationExpressionWriter * w)67 static QString prefixOp(const Apply* c, MathMLPresentationExpressionWriter* w)
68 {
69     return QString(*C)+convertElements(c->firstValue(), c->constEnd(), w).join(QString());
70 }
71 
72 template <const char **C>
postfix(const Apply * c,MathMLPresentationExpressionWriter * w)73 static QString postfix(const Apply* c, MathMLPresentationExpressionWriter* w)
74 {
75     return convertElements(c->firstValue(), c->constEnd(), w).join(QString())+QStringLiteral("<mo>%1</mo>").arg(*C);
76 }
77 
minus(const Apply * c,MathMLPresentationExpressionWriter * w)78 QString minus(const Apply* c, MathMLPresentationExpressionWriter* w)
79 {
80     QStringList e=convertElements(c->firstValue(), c->constEnd(), w);
81     if(e.count()==1)
82         return "<mo>-</mo>"+e[0];
83     else
84         return e.join(QStringLiteral("<mo>-</mo>"));
85 }
86 
power(const Apply * c,MathMLPresentationExpressionWriter * w)87 QString power(const Apply* c, MathMLPresentationExpressionWriter* w)
88 {    return "<msup>"+convertElements(c->firstValue(), c->constEnd(), w).join(QString())+"</msup>"; }
89 
divide(const Apply * c,MathMLPresentationExpressionWriter * w)90 QString divide(const Apply* c, MathMLPresentationExpressionWriter* w)
91 {    return "<mfrac><mrow>"+convertElements(c->firstValue(), c->constEnd(), w).join(QStringLiteral("</mrow><mrow>"))+"</mrow></mfrac>"; }
92 
quotient(const Apply * c,MathMLPresentationExpressionWriter * w)93 QString quotient(const Apply* c, MathMLPresentationExpressionWriter* w)
94 {    return divide(c, w); }
95 
root(const Apply * c,MathMLPresentationExpressionWriter * w)96 QString root(const Apply* c, MathMLPresentationExpressionWriter* w)
97 {
98     Cn two(2);
99     if(AnalitzaUtils::equalTree(c->values().at(1), &two))
100         return "<msqrt>"+(*c->firstValue())->accept(w).toString()+"</msqrt>";
101     else
102         return "<mroot>"+convertElements<Apply::const_iterator>(c->firstValue(), c->constEnd(), w).join(QString())+"</mroot>";
103 }
104 
diff(const Apply * c,MathMLPresentationExpressionWriter * w)105 QString diff(const Apply* c, MathMLPresentationExpressionWriter* w)
106 {
107     QStringList bv=c->bvarStrings();
108     return "<msubsup><mfenced>"+convertElements<Apply::const_iterator>(c->firstValue(), c->constEnd(), w).join(QString())+"</mfenced>"
109             "<mrow>"+bv.join(QStringLiteral("<mo>,</mo>"))+"</mrow><mo>'</mo></msubsup>";
110 }
111 
exp(const Apply * c,MathMLPresentationExpressionWriter * w)112 QString exp(const Apply* c, MathMLPresentationExpressionWriter* w)
113 {
114     return "<msup><mn>&ExponentialE;</mn>"+convertElements<Apply::const_iterator>(c->firstValue(), c->constEnd(), w).at(0)+"</msup>";
115 }
116 
iterative(Operator::OperatorType t,const Apply * c,MathMLPresentationExpressionWriter * w)117 QString iterative(Operator::OperatorType t, const Apply* c, MathMLPresentationExpressionWriter* w)
118 {
119     QString op= t==Operator::sum ? QStringLiteral("&Sum;") : QStringLiteral("&Prod;");
120     QString ul="<mrow>"+c->ulimit()->toString()+"</mrow>";
121     QString dl="<mrow>"+c->bvarStrings().join(QStringLiteral(", "))+"<mo>=</mo>"+c->dlimit()->toString()+"</mrow>";
122 
123     return "<mrow><msubsup><mo>"+op+"</mo>"+dl+ul+"</msubsup>"+convertElements(c->firstValue(), c->constEnd(), w).join(QString())+"</mrow>";
124 }
125 
sum(const Apply * c,MathMLPresentationExpressionWriter * w)126 QString sum(const Apply* c, MathMLPresentationExpressionWriter* w)
127 { return iterative(Operator::sum, c, w); }
128 
product(const Apply * c,MathMLPresentationExpressionWriter * w)129 QString product(const Apply* c, MathMLPresentationExpressionWriter* w)
130 { return iterative(Operator::product, c, w); }
131 
selector(const Apply * c,MathMLPresentationExpressionWriter * w)132 QString selector(const Apply* c, MathMLPresentationExpressionWriter* w)
133 {
134     QStringList el=convertElements(c->firstValue(), c->constEnd(), w);
135     return "<msub><mrow>"+el.last()+"</mrow><mrow>"+el.first()+"</mrow></msub>";
136 }
137 
function(const Apply * c,MathMLPresentationExpressionWriter * w)138 QString function(const Apply* c, MathMLPresentationExpressionWriter* w)
139 {
140     QString ret=QStringLiteral("<mrow>");
141     foreach(const Ci* bvar, c->bvarCi())
142         ret+=bvar->accept(w).toString();
143     foreach(const Object* o, c->values())
144         ret+=o->accept(w).toString();
145     ret+=QLatin1String("</mrow>");
146     return ret;
147 }
148 
149 const char* plus="+", *times="*", *equal="=";
150 const char* lt="&lt;", *gt="&gt;", *_not="&not;";
151 const char* leq="&leq;", *geq="&geq;", *neq="&NotEqual;", *approx="&asymp;";
152 const char* implies="&DoubleRightArrow;", *_and="&and;", *_or="&or;", *_xor="&CirclePlus;";
153 const char* mabs="|", *factorial="!";
154 const char *lfloor="&lfloor;", *rfloor="&rfloor;";
155 const char *lceil="&lceil;", *rceil="&rceil;";
156 const char *cardinal="#", *scalarproduct="X";
157 const char *_log10="<msub><mo>log</mo><mn>10</mn></msub>", *logE="<msub><mo>log</mo><mn>&ExponentialE;</mn></msub>";
158 }
159 
160 MathMLPresentationExpressionWriter::operatorToString
161     MathMLPresentationExpressionWriter::m_operatorToPresentation[] = { nullptr,
162             joinOp<&plus>, joinOp<&times>,
163             minus, divide, quotient,
164             power, root, postfix<&factorial>,
165             joinOp<&_and>,joinOp<&_or>,joinOp<&_xor>, prefix<&_not>,
166             nullptr,nullptr,nullptr,nullptr,//gcd, lcm, rem, factorof,
167             nullptr,nullptr,//max, min,
168             joinOp<&lt>, joinOp<&gt>,
169             joinOp<&equal>,
170             joinOp<&neq>, joinOp<&leq>, joinOp<&geq>, joinOp<&implies>,
171             joinOp<&approx>, infix<&mabs, &mabs>, infix<&lfloor, &rfloor>, infix<&lceil, &rceil>,
172             // approx, abs, floor, ceiling,
173             nullptr,nullptr,nullptr,// sin, cos, tan,
174             nullptr,nullptr,nullptr,// sec, csc, cot,
175             nullptr,nullptr,nullptr,// sinh, cosh, tanh,
176             nullptr,nullptr,nullptr,// sech, csch, coth,
177             nullptr,nullptr,nullptr,// arcsin, arccos, arctan,
178             nullptr,// arccot,// arccoth,
179             nullptr,nullptr,nullptr,// arccosh, arccsc, arccsch,
180             nullptr,nullptr,nullptr,nullptr,// arcsec, arcsech, arcsinh, arctanh,
181             exp, prefixOp<&_log10>, prefixOp<&logE>,// exp, ln, log,
182             nullptr,nullptr,nullptr,nullptr,// //             conjugate, arg, real, imaginary,
183             sum, product, diff,// sum, product, diff,
184             prefix<&cardinal>, joinOp<&scalarproduct>, selector, nullptr,
185             function // function
186     };
187 
MathMLPresentationExpressionWriter(const Object * o)188 MathMLPresentationExpressionWriter::MathMLPresentationExpressionWriter(const Object* o)
189 {
190     m_result=o->accept(this);
191 }
192 
visit(const Ci * var)193 QVariant MathMLPresentationExpressionWriter::visit(const Ci* var)
194 {
195     return QVariant::fromValue<QString>(QStringLiteral("<mi>") + var->name() + QStringLiteral("</mi>"));
196 }
197 
visit(const Operator * op)198 QVariant MathMLPresentationExpressionWriter::visit(const Operator* op)
199 {
200     return op->name();
201 }
202 
visit(const Cn * val)203 QVariant MathMLPresentationExpressionWriter::visit(const Cn* val)
204 {
205     if(val->isBoolean()) {
206         if(val->isTrue())
207             return "<mo>true</mo>";
208         else
209             return "<mo>false</mo>";
210     } else
211         return QStringLiteral("<mn>%1</mn>").arg(val->value(), 0, 'g', 12);
212 
213 }
214 
piecewise(const Container * c,MathMLPresentationExpressionWriter * w)215 QString piecewise(const Container* c, MathMLPresentationExpressionWriter* w)
216 {
217     QString ret=QStringLiteral("<mrow>"
218     "<mo stretchy='true'> { </mo>"
219     "<mtable columnalign='left left'>");
220     for(Container::const_iterator it=c->constBegin(); it!=c->constEnd(); ++it) {
221         Q_ASSERT((*it)->type()==Object::container);
222         Container *piece=static_cast<Container*>(*it);
223         if(piece->containerType()==Container::piece) {
224             ret += "<mtr>"
225             "<mtd>"
226                 +piece->m_params.first()->accept(w).toString()+
227             "</mtd>"
228             "<mtd>"
229                 "<mtext>if </mtext>"
230                 +piece->m_params.last()->accept(w).toString()+
231             "</mtd>"
232             "</mtr>";
233         } else {
234             ret += "<mtr>"
235             "<mtd>"
236                 +piece->m_params.first()->accept(w).toString()+
237             "</mtd>"
238             "<mtd>"
239                 "<mtext>otherwise</mtext>"
240             "</mtd>"
241             "</mtr>";
242         }
243     }
244 
245     ret+=QLatin1String("</mtable></mrow>");
246     return ret;
247 }
248 
lambda(const Container * c,MathMLPresentationExpressionWriter * w)249 QString lambda(const Container* c, MathMLPresentationExpressionWriter* w)
250 {
251     QString ret=QStringLiteral("<mrow>");
252     foreach(const Ci* bvar, c->bvarCi())
253         ret+=bvar->accept(w).toString();
254     ret+=QLatin1String("<mo>&RightArrow;</mo>");
255     ret+=c->m_params.last()->accept(w).toString();
256     ret+=QLatin1String("</mrow>");
257     return ret;
258 }
259 
visit(const Container * c)260 QVariant MathMLPresentationExpressionWriter::visit(const Container* c)
261 {
262     QString ret;
263 //     objectWalker(c);
264 //     qDebug() << "ttttttttttt" << m_operatorToPresentation << op.operatorType()
265 //              << m_operatorToPresentation[op.operatorType()] << op.name();
266 
267     switch(c->containerType()) {
268         case Container::math:
269             ret="<math><mrow>"+convertElements(c->constBegin(), c->constEnd(), this).join(QString())+"</mrow></math>";
270             break;
271         case Container::piecewise:
272             ret=piecewise(c, this);
273             break;
274         case Container::lambda:
275             ret=lambda(c, this);
276             break;
277         case Container::otherwise:
278         case Container::piece:
279         case Container::bvar:
280         case Container::uplimit:
281         case Container::downlimit:
282         case Container::declare:
283         case Container::domainofapplication:
284         case Container::none:
285             qDebug() << "error" << c->tagName();
286             Q_ASSERT(false);
287             break;
288     }
289 
290     return ret;
291 }
292 
visit(const Vector * var)293 QVariant MathMLPresentationExpressionWriter::visit(const Vector* var)
294 {
295     return QVariant::fromValue<QString>(QStringLiteral("<mrow><mo>&lt;</mo>")+convertElements(var->constBegin(), var->constEnd(), this).join(QStringLiteral("<mo>,</mo>"))+"<mo>&gt;</mo></mrow>");
296 }
297 
visit(const List * var)298 QVariant MathMLPresentationExpressionWriter::visit(const List* var)
299 {
300     return QVariant::fromValue<QString>(QStringLiteral("<mrow><mo>[</mo>")+convertElements(var->constBegin(), var->constEnd(), this).join(QStringLiteral("<mo>,</mo>"))+"<mo>]</mo></mrow>");
301 }
302 
visit(const Matrix * m)303 QVariant MathMLPresentationExpressionWriter::visit(const Matrix* m)
304 {
305     return QVariant::fromValue<QString>(QStringLiteral("<mrow><mo>[</mo>")+convertElements(m->constBegin(), m->constEnd(), this).join(QStringLiteral("<mo>,</mo>"))+"<mo>]</mo></mrow>");
306 }
307 
visit(const MatrixRow * m)308 QVariant MathMLPresentationExpressionWriter::visit(const MatrixRow* m)
309 {
310     return QVariant::fromValue<QString>(QStringLiteral("<mrow><mo>[</mo>")+convertElements(m->constBegin(), m->constEnd(), this).join(QStringLiteral("<mo>,</mo>"))+"<mo>]</mo></mrow>");
311 }
312 
visit(const Analitza::Apply * a)313 QVariant Analitza::MathMLPresentationExpressionWriter::visit(const Analitza::Apply* a)
314 {
315     QString ret;
316     Operator op=a->firstOperator();
317 
318     operatorToString call=m_operatorToPresentation[op.operatorType()];
319 
320     if(call!=nullptr) {
321         ret = call(a, this);
322     } else if(op.operatorType()!=0) {
323         QString bvars;
324         if(!a->bvarStrings().isEmpty()) {
325             bvars=a->bvarStrings().join(QString());
326             if(a->bvarStrings().size()>1)
327                 bvars="<mfenced>"+bvars+"</mfenced>";
328             const Object *ul=a->ulimit(), *dl=a->dlimit();
329             if(ul || dl) {
330                 bvars += QLatin1String("<mo>=</mo>");
331                 if(dl) bvars += dl->accept(this).toString();
332                 bvars += QLatin1String("<mo>..</mo>");
333                 if(ul) bvars += ul->accept(this).toString();
334             } else if(a->domain())
335                 bvars += "<mo>@</mo>" + a->domain()->accept(this).toString();
336             bvars="<mo>:</mo>"+bvars;
337         }
338 
339         ret="<mi>"+op.name()+"</mi>"
340             "<mo> &ApplyFunction; </mo>"
341             "<mfenced>"
342             +convertElements(a->firstValue(), a->constEnd(), this).join(QString())
343             +bvars
344             +"</mfenced>";
345     }
346     return ret;
347 }
348 
visit(const CustomObject *)349 QVariant MathMLPresentationExpressionWriter::visit(const CustomObject*)
350 {
351     return QStringLiteral("<!-- custom object -->");
352 }
353 
visit(const None *)354 QVariant MathMLPresentationExpressionWriter::visit(const None* )
355 {
356     return QString();
357 }
358 
359