SymPy is a computer algebra system for Python. This blog post will talk about how to use SymPy with Dexy to get automated mathematical LaTeX in your documents.
With SymPy you can calculate things like this derivative table:
$$\frac{d}{d x}\left(\frac{\cos{\left (x \right )}}{\sin{\left (x \right )} + 1}\right) = – \frac{\sin{\left (x \right )}}{\sin{\left (x \right )} + 1} – \frac{\cos^{2}{\left (x \right )}}{\left(\sin{\left (x \right )} + 1\right)^{2}}$$
$$\frac{d}{d x}\left(\frac{\cos{\left (x \right )}}{\sin^{2}{\left (x \right )} + 1}\right) = – \frac{\sin{\left (x \right )}}{\sin^{2}{\left (x \right )} + 1} – \frac{2 \sin{\left (x \right )} \cos^{2}{\left (x \right )}}{\left(\sin^{2}{\left (x \right )} + 1\right)^{2}}$$
$$\frac{d}{d x}\left(\frac{\cos{\left (x \right )}}{\sin^{3}{\left (x \right )} + 1}\right) = – \frac{\sin{\left (x \right )}}{\sin^{3}{\left (x \right )} + 1} – \frac{3 \sin^{2}{\left (x \right )} \cos^{2}{\left (x \right )}}{\left(\sin^{3}{\left (x \right )} + 1\right)^{2}}$$
$$\frac{d}{d x}\left(\frac{\cos{\left (x \right )}}{\sin^{4}{\left (x \right )} + 1}\right) = – \frac{\sin{\left (x \right )}}{\sin^{4}{\left (x \right )} + 1} – \frac{4 \sin^{3}{\left (x \right )} \cos^{2}{\left (x \right )}}{\left(\sin^{4}{\left (x \right )} + 1\right)^{2}}$$
or this integral table:
$$\int x e^{x}\, dx = \left(x – 1\right) e^{x}$$
$$\int x^{2} e^{2 x}\, dx = \frac{e^{2 x}}{4} \left(2 x^{2} – 2 x + 1\right)$$
$$\int x^{3} e^{3 x}\, dx = \frac{e^{3 x}}{27} \left(9 x^{3} – 9 x^{2} + 6 x – 2\right)$$
$$\int x^{4} e^{4 x}\, dx = \frac{e^{4 x}}{128} \left(32 x^{4} – 32 x^{3} + 24 x^{2} – 12 x + 3\right)$$
To generate these tables, we modify this example from the Sympy wiki.
Here’s the imports for this script:
>>> from sympy import Eq, Derivative, Integral
>>> from sympy import diff, integrate
>>> from sympy import cos, sin, exp
>>> from sympy import latex
>>> from sympy.abc import x
>>> import json
We start by defining functions which return equality objects relating the derivative or integral to its calculated expression:
>>> def derivative_eqn(f, x):
... return Eq(Derivative(f, x), diff(f, x))
...
>>> def integral_eqn(f, x):
... return Eq(Integral(f, x), integrate(f, x))
...
Here’s a simple example of what this function returns:
Here’s another:
Then, we define functions which return the LaTeX representation of that equality:
>>> def derivative_eqn_latex(f, x):
... return latex(derivative_eqn(f, x))
...
>>> def integral_eqn_latex(f, x):
... return latex(integral_eqn(f, x))
...
Here’s what these functions return:
So, it’s very simple to generate the LaTeX we want, now we just need a way of displaying that LaTeX in a dexy document. A recommended way of sharing content between dexy documents is to use JSON. JSON is widely available and is human readable for debugging. JSON objects map nicely to Python dictionaries, and dexy defines a from_json()
method which you can use to easily parse JSON into their corresponding Python objects (dictionaries, lists, or whatever the JSON happens to map to).
So, in our Python script, let’s define a simple dict which contains the latex we want, referenced by a memorable name, and save this to a JSON file:
>>> example_dict = {
... 'derivative' : derivative_eqn_latex(x**2, x),
... 'integral' : integral_eqn_latex(x**2, x)
... }
>>>
>>> with open("example-latex.json", "w") as f:
... json.dump(example_dict, f)
...
Then in a Markdown-formatted document, we can do something like this:
{% set example_latex = d['example-latex.json'].from_json() -%} Here is the derivative example: $${{ example_latex.derivative }}$$ And here is the integral example: $${{ example_latex.integral }}$$
And the result looks like this:
Here is the derivative example:
$$\frac{d}{d x} x^{2} = 2 x$$
And here is the integral example:
$$\int x^{2}\, dx = \frac{x^{3}}{3}$$
Now, we want to see how to generate the derivative and integral tables we started with. Instead of a dictionary letting us pick out individual examples, we’ll generate a list and store this list in JSON, then iterate over and display each element in the list in order.
We use two list comprehensions, the first generates a list of functions, the second returns the LaTeX for the expressions:
>>> functions = [cos(x)/(1 + sin(x)**i) for i in range(1, 5)]
>>> derivatives_latex = [derivative_eqn_latex(f, x) for f in functions]
>>>
>>> with open("derivatives.json", "w") as f:
... json.dump(derivatives_latex, f)
...
And here is how we load the JSON saved to derivatives.json
and iterate over each entry, to generate the table:
{% for deriv_latex in d['derivatives.json'].from_json() %} $${{ deriv_latex }}$$ {% endfor %}
Here’s the table again:
$$\frac{d}{d x}\left(\frac{\cos{\left (x \right )}}{\sin{\left (x \right )} + 1}\right) = – \frac{\sin{\left (x \right )}}{\sin{\left (x \right )} + 1} – \frac{\cos^{2}{\left (x \right )}}{\left(\sin{\left (x \right )} + 1\right)^{2}}$$
$$\frac{d}{d x}\left(\frac{\cos{\left (x \right )}}{\sin^{2}{\left (x \right )} + 1}\right) = – \frac{\sin{\left (x \right )}}{\sin^{2}{\left (x \right )} + 1} – \frac{2 \sin{\left (x \right )} \cos^{2}{\left (x \right )}}{\left(\sin^{2}{\left (x \right )} + 1\right)^{2}}$$
$$\frac{d}{d x}\left(\frac{\cos{\left (x \right )}}{\sin^{3}{\left (x \right )} + 1}\right) = – \frac{\sin{\left (x \right )}}{\sin^{3}{\left (x \right )} + 1} – \frac{3 \sin^{2}{\left (x \right )} \cos^{2}{\left (x \right )}}{\left(\sin^{3}{\left (x \right )} + 1\right)^{2}}$$
$$\frac{d}{d x}\left(\frac{\cos{\left (x \right )}}{\sin^{4}{\left (x \right )} + 1}\right) = – \frac{\sin{\left (x \right )}}{\sin^{4}{\left (x \right )} + 1} – \frac{4 \sin^{3}{\left (x \right )} \cos^{2}{\left (x \right )}}{\left(\sin^{4}{\left (x \right )} + 1\right)^{2}}$$
We do much the same for the integrals table, here’s the Python which generates the JSON:
>>> functions = [x**i * exp(i*x) for i in range(1, 5)]
>>> integrals_latex = [integral_eqn_latex(f, x) for f in functions]
>>>
>>> with open("integrals.json", "w") as f:
... json.dump(integrals_latex, f)
...
And here is how we load the JSON and generate the table:
{% for integral_latex in d['integrals.json'].from_json() %} $${{ integral_latex }}$$ {% endfor %}
Here’s the table again:
$$\int x e^{x}\, dx = \left(x – 1\right) e^{x}$$
$$\int x^{2} e^{2 x}\, dx = \frac{e^{2 x}}{4} \left(2 x^{2} – 2 x + 1\right)$$
$$\int x^{3} e^{3 x}\, dx = \frac{e^{3 x}}{27} \left(9 x^{3} – 9 x^{2} + 6 x – 2\right)$$
$$\int x^{4} e^{4 x}\, dx = \frac{e^{4 x}}{128} \left(32 x^{4} – 32 x^{3} + 24 x^{2} – 12 x + 3\right)$$
That’s how you can use SymPy, JSON and Dexy to get automated math into your documents. We’ve been displaying the LaTeX within a HTML document and using MathJax to render it, but of course you can just insert the LaTeX content into a .tex file and render it to a PDF.
Another option, besides using JSON, is to print the LaTeX content to STDOUT within your python scripts and then use dexy to insert the output into a document directly. For example:
Here is how we could insert this into a document:
$${{ d['example.py|py'] }}$$
And here’s what it looks like:
$$\frac{x^{3}}{3}
$$
This is simpler, although using JSON is more flexible and robust.