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>ⅇ</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("∑") : 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="<", *gt=">", *_not="¬";
151 const char* leq="≤", *geq="≥", *neq="≠", *approx="≈";
152 const char* implies="⇒", *_and="∧", *_or="∨", *_xor="⊕";
153 const char* mabs="|", *factorial="!";
154 const char *lfloor="⌊", *rfloor="⌋";
155 const char *lceil="⌈", *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>ⅇ</mn></msub>";
158 }
159
160 MathMLPresentationExpressionWriter::operatorToString
161 MathMLPresentationExpressionWriter::m_operatorToPresentation[] = { nullptr,
162 joinOp<&plus>, joinOp<×>,
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<<>, joinOp<>>,
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>→</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><</mo>")+convertElements(var->constBegin(), var->constEnd(), this).join(QStringLiteral("<mo>,</mo>"))+"<mo>></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> ⁡ </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