MathML

MathML.MathMLModule

MathML

A parser for the MathML XML standard.

Uses Symbolics.jl under the hood for defining equations and uses EzXML.jl for XML parsing.

MathML Specification: https://www.w3.org/TR/MathML3/

Examples:

using MathML, EzXML, Symbolics, AbstractTrees
xml = xml"""<math xmlns="http://www.w3.org/1998/Math/MathML">
   <apply>
      <times />
      <ci>compartment</ci>
      <ci>k1</ci>
      <ci>S1</ci>
   </apply>
</math>"""

num = parse_node(xml)
# 1-element Vector{Num}:
#  S1*compartment*k1

# to pretty print the tree use `print_tree`
print_tree(xml)
# math
# └─ apply
#    ├─ times
#    ├─ ci
#    ├─ ci
#    └─ ci

# you can also just go directly from EzXML.Document or String
str = "<apply><power/><ci>x</ci><cn>3</cn></apply>"
MathML.parse_str(str)
# x^3

# derivatives also work!
str = """
<apply><diff/>
  <bvar><ci>x</ci><degree><cn>2</cn></degree></bvar>
  <apply><power/><ci>x</ci><cn>4</cn></apply>
</apply>
"""
expand_derivatives(MathML.parse_str(str))
# 12(x^2)

# there is also a macro @MathML_str to directly call `parse_str`
ml = MathML"""
<apply><diff/>
  <bvar><ci>x</ci><degree><cn>2</cn></degree></bvar>
  <apply><power/><ci>x</ci><cn>4</cn></apply>
</apply>
"""
expand_derivatives(ml)
# 12(x^2)

Check the tests in test/parse.jl to see a more exaustive list of what is covered.

TODO:

  • calculus:
    • ivars fix, make ODESystem(parse_node(readxml("lorenz.xml").root)) work
    • partial derivatives partialdiff tags
    • integration int tags
    • eq nodes sometimes needs to be ~ and sometimes needs to be =
      • often a var like dPidt is assigned to Differential(time)(Pi) where dPidt is refered to after this \<eq> (I think solution is Symbolics.diff2term)
    • diffs with no independent variable: like <apply><diff/><ci>f</ci></apply>
  • piecewise tags: make heaviside test work
  • fix undefined namespacing issues https://github.com/JuliaIO/EzXML.jl/issues/156
  • fix sep tags in cis, take type attribute into account
  • to_mathml: julia expr -> mathml. round tripping

DONE:

  • nested apply
  • fix sep/ tags in cn, take type attribute into account
    • rational, e-notation, complex, complex polar
  • basic diff handling
  • bound variables like bvar, might be lingering issues though
source
MathML.check_ivsMethod

ensure theres only one independent variable, returns false if more than one iv

source
MathML.extract_mathmlFunction
extract_mathml()

given a filename, EzXML.Document, or EzXML.Node returns all of the MathML nodes.

source
MathML.mathml_to_numsFunction
mathml_to_nums()

given a filename or an EzXML.Document or EzXML.Node, finds all of the <ci>s and defines them as Symbolics.jl Nums returns a Vector{Num}. Note, the root namespace needs to be MathML

source
MathML.parse_applyMethod
parse_apply(node)

parse an <apply> node into Symbolics form

how to deal w apply within apply, need to ensure we've hit bottom

source
MathML.parse_cn_w_sepMethod
parse_cn_w_sep(node)

parse a <cn type=".."> node

where type ∈ ["e-notation", "rational", "complex-cartesian", "complex-polar"]

source
MathML.parse_lambdaMethod
parse_lambda(node)

parse a <lambda> node

<lambda>
  <bvar> x1 </bvar><bvar> xn </bvar>
   expression-in-x1-xn
</lambda>
source