>From 0b4da32a6d037c324bb20145f39a1180d59f9be5 Mon Sep 17 00:00:00 2001
From: Thomas Sidoti <tsid...@gmail.com>
Date: Sun, 24 May 2009 00:21:54 -0400
Subject: [PATCH 1/1] MathML: trig functions, order of terms, roots, and
constants

---
 sympy/printing/mathml.py            |  144
+++++++++++++++++++++++++++++++++--
 sympy/printing/tests/test_mathml.py |   67 ++++++++++++++++-
 2 files changed, 203 insertions(+), 8 deletions(-)

diff --git a/sympy/printing/mathml.py b/sympy/printing/mathml.py
index 3bc1ae2..d057b03 100644
--- a/sympy/printing/mathml.py
+++ b/sympy/printing/mathml.py
@@ -2,8 +2,11 @@
 A MathML printer.
 """

-from sympy import Basic, sympify
+from sympy import Basic, sympify, C, S
+from sympy.simplify import fraction
 from printer import Printer
+from xml.sax import saxutils
+

 class MathMLPrinter(Printer):
     """Prints an expression to the MathML markup language
@@ -20,7 +23,8 @@ class MathMLPrinter(Printer):
         self.dom = Document()

     def doprint(self, e):
-        return self._print(e).toxml()
+        mathML = Printer.doprint(self,expr)
+        return mathML.toxml()

     def mathml_tag(self, e):
         """Returns the MathML tag for an expression."""
@@ -32,18 +36,91 @@ class MathMLPrinter(Printer):
             'int': 'cn',
             'Pow': 'power',
             'Symbol': 'ci',
-            'Integral': 'int'
+            'Integral': 'int',
+            'sin': 'sin',
+            'cos': 'cos',
+            'tan': 'tan',
+            'cot': 'cot',
+            'asin': 'arcsin',
+            'asinh': 'arcsinh',
+            'acos': 'arccos',
+            'acosh': 'arccosh',
+            'atan': 'arctan',
+            'atanh': 'arctanh',
+            'acot': 'arccot',
+            'atan2': 'arctan',
+            'log': 'ln'
         }

         for cls in e.__class__.__mro__:
             n = cls.__name__
             if n in translate:
                 return translate[n]
-
         # Not found in the MRO set
         n = e.__class__.__name__
         return n.lower()

+    def _print_Mul(self, expr):
+        coeff, terms  = expr.as_coeff_terms()
+
+        if coeff.is_negative:
+            x = self.dom.createElement('apply')
+            x.appendChild(self.dom.createElement('minus'))
+            x.appendChild(self._print_Mul(-expr))
+            return x
+
+        numer, denom = fraction(expr)
+
+        if not denom is S.One:
+            x = self.dom.createElement('apply')
+            x.appendChild(self.dom.createElement('divide'))
+            x.appendChild(self._print(numer))
+            x.appendChild(self._print(denom))
+            return x
+
+        if coeff == 1 and len(terms) == 1:
+            return self._print(terms[0])
+        x = self.dom.createElement('apply')
+        x.appendChild(self.dom.createElement('times'))
+        if(coeff != 1):
+            x.appendChild(self._print(coeff))
+        for term in terms:
+            x.appendChild(self._print(term))
+        return x
+
+    """This is complicated because we attempt to order then results in
order of Basic._compare_pretty and use minus instaed of negative"""
+    def _print_Add(self, e):
+        args = list(e.args)
+        args.sort(Basic._compare_pretty)
+        lastProcessed = self._print(args[0])
+        args.pop(0)
+        plusNodes = list()
+        for i in range(0,len(args)):
+            arg = args[i]
+            coeff, terms = arg.as_coeff_terms()
+            if(coeff.is_negative):
+                """use minus"""
+                x = self.dom.createElement('apply')
+                x.appendChild(self.dom.createElement('minus'))
+                x.appendChild(lastProcessed)
+                x.appendChild(self._print(-arg))
+                """invert expression  since this is now minused"""
+                lastProcessed = x;
+                if(arg == args[-1]):
+                    plusNodes.append(lastProcessed)
+            else:
+                plusNodes.append(lastProcessed)
+                lastProcessed = self._print(arg)
+                if(arg == args[-1]):
+                    plusNodes.append(self._print(arg))
+        if len(plusNodes) == 1:
+            return lastProcessed
+        x = self.dom.createElement('apply')
+        x.appendChild(self.dom.createElement('plus'))
+        while len(plusNodes) > 0:
+            x.appendChild(plusNodes.pop(0))
+        return x
+
     def _print_Matrix(self, m):
         x = self.dom.createElement('matrix')
         for i in range(m.lines):
@@ -53,6 +130,24 @@ class MathMLPrinter(Printer):
             x.appendChild(x_r)
         return x

+    def _print_Rational(self, e):
+        if e.q == 1:
+            """don't divide"""
+            x = self.dom.createElement('cn')
+            x.appendChild(self.dom.createTextNode(str(e.p)))
+            return x
+        x = self.dom.createElement('apply')
+        x.appendChild(self.dom.createElement('divide'))
+        """numerator"""
+        xnum = self.dom.createElement('cn')
+        xnum.appendChild(self.dom.createTextNode(str(e.p)))
+        """denomenator"""
+        xdenom = self.dom.createElement('cn')
+        xdenom.appendChild(self.dom.createTextNode(str(e.q)))
+        x.appendChild(xnum)
+        x.appendChild(xdenom)
+        return x
+
     def _print_Limit(self, e):
         x = self.dom.createElement('apply')
         x.appendChild(self.dom.createElement(self.mathml_tag(e)))
@@ -65,9 +160,31 @@ class MathMLPrinter(Printer):
         x.appendChild(x_1)
         x.appendChild(x_2)
         x.appendChild(self._print(e.args[0]))
-
         return x

+    def _print_ImaginaryUnit(self,e):
+        return self.dom.createElement('imaginaryi')
+
+    def _print_GoldenRatio(self,e):
+        x = self.dom.createElement('cn')
+        """This is an html phi"""
+        x.appendChild(self.dom.createTextNode('&#981;'))
+        return x;
+
+    def _print_Exp1(self,e):
+        return self.dom.createElement('exponentiale')
+
+    def _print_Pi(self, e):
+        return self.dom.createElement('pi')
+
+    def _print_Infinity(self, e):
+        return self.dom.createElement('infinity')
+
+    def _print_Negative_Infinity(self,e):
+        x = self.dom.createElement('apply')
+        x.appendChild(self.dom.createElement('minus'))
+        x.appendChild(self.dom.createElement('infinity'))
+        return x

     def _print_Integral(self, e):
         def lime_recur(limits):
@@ -100,6 +217,19 @@ class MathMLPrinter(Printer):
         return x

     def _print_Pow(self, e):
+        """Here we use root instead of power if the exponent is the
reciprocal of an integer"""
+        if e.exp.is_Rational and e.exp.p == 1:
+            x = self.dom.createElement('apply')
+            x.appendChild(self.dom.createElement('root'))
+            if e.exp.q != 2:
+                xmldeg = self.dom.createElement('degree')
+                xmlci = self.dom.createElement('ci')
+                xmlci.appendChild(self.dom.createTextNode(str(e.exp.q)))
+                xmldeg.appendChild(xmlci)
+                x.appendChild(xmldeg)
+            x.appendChild(self._print(e.base))
+            return x
+
         x = self.dom.createElement('apply')
         x_1 = self.dom.createElement(self.mathml_tag(e))
         x.appendChild(x_1)
@@ -161,7 +291,7 @@ class MathMLPrinter(Printer):
 def mathml(expr):
     """Returns the MathML representation of expr"""
     s = MathMLPrinter()
-    return s.doprint(sympify(expr))
+    return saxutils.unescape(s._print(sympify(expr)).toprettyxml())

 def print_mathml(expr):
     """
@@ -182,4 +312,4 @@ def print_mathml(expr):
     </apply>
     """
     s = MathMLPrinter()
-    print s._print(sympify(expr)).toprettyxml()
+    print saxutils.unescape(s._print(sympify(expr)).toprettyxml())
diff --git a/sympy/printing/tests/test_mathml.py
b/sympy/printing/tests/test_mathml.py
index f5aab5b..52aea8a 100644
--- a/sympy/printing/tests/test_mathml.py
+++ b/sympy/printing/tests/test_mathml.py
@@ -1,4 +1,4 @@
-from sympy import diff, Integral, Limit, sin, Symbol, Integer
+from sympy import diff, Integral, Limit, sin, Symbol, Integer, Rational,
cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh, E, I, oo,
pi
 from sympy.printing.mathml import mathml, MathMLPrinter
 from xml.dom.minidom import parseString

@@ -82,6 +82,71 @@ def test_mathml_tuples():
 def test_mathml_matrices():
     pass #TODO

+def test_mathml_add():
+    mml = mp._print(x**5 - x**4 + x)
+    assert mml.childNodes[0].nodeName == 'plus'
+    assert mml.childNodes[1].childNodes[0].nodeName == 'minus'
+    assert mml.childNodes[1].childNodes[1].nodeName == 'ci'
+    assert mml.childNodes[2].childNodes[0].nodeName == 'power'
+
+def test_mathml_Rational():
+    mml_1 = mp._print(Rational(1,1))
+    """should just return a number"""
+    assert mml_1.nodeName == 'cn'
+
+    mml_2 = mp._print(Rational(2,5))
+    assert mml_2.childNodes[0].nodeName == 'divide'
+
+def test_mathml_constants():
+    mml = mp._print(I)
+    assert mml.nodeName == 'imaginaryi'
+
+    mml = mp._print(E)
+    assert mml.nodeName == 'exponentiale'
+
+    mml = mp._print(oo)
+    assert mml.nodeName == 'infinity'
+
+    mml = mp._print(pi)
+    assert mml.nodeName == 'pi'
+
+def test_mathml_trig():
+    mml = mp._print(sin(x))
+    assert mml.childNodes[0].nodeName == 'sin'
+
+    mml = mp._print(cos(x))
+    assert mml.childNodes[0].nodeName == 'cos'
+
+    mml = mp._print(tan(x))
+    assert mml.childNodes[0].nodeName == 'tan'
+
+    mml = mp._print(asin(x))
+    assert mml.childNodes[0].nodeName == 'arcsin'
+
+    mml = mp._print(acos(x))
+    assert mml.childNodes[0].nodeName == 'arccos'
+
+    mml = mp._print(atan(x))
+    assert mml.childNodes[0].nodeName == 'arctan'
+
+    mml = mp._print(sinh(x))
+    assert mml.childNodes[0].nodeName == 'sinh'
+
+    mml = mp._print(cosh(x))
+    assert mml.childNodes[0].nodeName == 'cosh'
+
+    mml = mp._print(tanh(x))
+    assert mml.childNodes[0].nodeName == 'tanh'
+
+    mml = mp._print(asinh(x))
+    assert mml.childNodes[0].nodeName == 'arcsinh'
+
+    mml = mp._print(atanh(x))
+    assert mml.childNodes[0].nodeName == 'arctanh'
+
+    mml = mp._print(acosh(x))
+    assert mml.childNodes[0].nodeName == 'arccosh'
+
 def test_c2p():
     """This tests some optional routines that depend on libxslt1 (which is
optional)"""
     try:
-- 
1.5.6.5

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sympy-patches" group.
To post to this group, send email to sympy-patches@googlegroups.com
To unsubscribe from this group, send email to 
sympy-patches+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/sympy-patches?hl=en
-~----------~----~----~----~------~----~------~--~---

Attachment: 0001-MathML-trig-functions-order-of-terms-roots-and-c.patch
Description: Binary data

Reply via email to