# SaneTeX

Using `SageTex`

in larger articles in a sane way.

## Introduction

I've recently been using
SageTex in my
research writing.
There's been ups and downs, benefits but also multiple drawbacks to my
workflows until I finally settled on how to do things in a *sane* way to
overcome the limitations in the naive approaches you may have after getting to work immediately after looking at the
official tutorials.
After lessons learnt, I've come up with some **top tips** for using sagetex in
larger projects.
I'll be starting with short, easily-actionable tips that aren't present in the
official tutorials, and then finishing with a couple larger pieces advice around
overall project structure.

To set the expectations, let me clarify my personal reasons for including SageMath code into my document building:

### 1) Programmatically generate LaTeX expressions to avoid errors

(TODO add tiny example)

At the point when I decided to start using SageTex, I was frequently making
mistakes in the expressions I was deriving. Particularly when specializing
expressions to different contexts, where there are different coefficients
involved which were easily mixed up. Sometimes the expressions were just long.
Having a CAS do these calculations added an extra degree of certainty to my
work. Furthermore, including the code inside the project (as opposed to doing
it separately) just keeps the calculation steps *on record* easily checked in
case I worry I had done something incorrectly.

### 2) Include plot creation into the document build

(TODO add tiny example)

Instead of generating plots programmatically inside the LaTeX document, most people use separate tools to create diagrams. Idealogically, this impacts reproducibility of the research. But via SageTex, it's also easier to use the same expressions to generate LaTeX formulae, as creating a plot.

## TIP 1: SageMath plot sizing

Although, not present in the official tutorials, the
official example
shows some invaluable options for the `\sageplot`

function to adjust sizing
among other things.
The most common usages I have are:

```
\sageplot[width=\textwidth]{...}
```

```
\sageplot[width=\linewidth]{...}
```

If you have trouble sizing plots correctly, especially in subfigures, this might be your solution.

Another takeaway here is to have a look at the official example to come across more advanced usage of SageTex than the minor snippets in the tutorial page. The rest of the tips here however, is not in the official material.

## TIP 2: Cut down on manual steps in document build

### Problem: annoying compilation steps

The default way of compiling a document `main.tex`

using `sagetex`

is to:

- Attempt the compilation once (with say
`pdflatex`

) - Watch it fail because it cannot find the
`main.sagetex.sout`

file. But be prompted to run the generated SageMath script. - Run
`sage`

on said generated SageMath script, creating the`main.sagetex.sout`

file required - Run the LaTeX compiler (however many times necessary for references, etc...), but successfully this time

If you were to script this, it would look something like:

```
pdflatex main.tex
sage main.sagetex.sage
pdflatex main.tex # possibly repeated a few times
```

Furthermore, if you were to be using `latexmk`

, either directly, or via you editor, then that first step may involve extra unnecessary compilation attemtps.

### Solution: latexmk + Makefile

Firstly, using `latexmk`

is generally useful. If you aren't using it, maybe check out my other post about it. Also, `make`

is standard CLI tool for specifying how to build a project, you may already have, or can easily install.

One neat feature that you can enable in `latexmk`

, by either

- invoking it with the
`-use-make`

flag (`latexmk -use-make ...`

) - or by add the line
`$use_make_for_missing_files = 1;`

to the`latexmkrc`

file for the project

... is to have `latexmk`

invoke `make <filename>`

whenever the LaTeX compiler complains about a file `<filename>`

being missing, before the subsequent calls to `pdf/lualatex`

. If we use it in our scenario, then `make main.sagetex.sout`

would be invoked after the first time `latexmk`

calls `pdf/lualatex`

.

To have `make main.sagetex.sout`

actually create the file required, add a `Makefile`

file in your project with the following:

```
# This may need to be adjusted to your filename, jobname, aux file location etc...
main.sagetex.sout: main.sagetex.sage
sage main.sagetex.sage
# possibly add other dependencies after the colon you
# may want for running your sagescript
# (such as notebook.py seen later in
# section "Solution: Jupyter notebooks")
```

With this ^ `Makefile`

created, you can open the project and run in the terminal:

```
# -use-make ommitable if setting already in latexmkrc
latexmk -use-make -pvc
```

... to build your document and watch to rebuild on any changes to the `.tex`

files.
The same can be achieved in LaTeX editors if set up to use `latexmk`

in the appropriate way.

#### Caveat

`latexmk`

will only call `make main.sagetex.sout`

if it is not present. If you make changes to any of the SageMath code after the first compile, you would need to run `make main.sagetex.sout`

yourself. The upside is that if you use `latexmk -pvc`

, then this will trigger a rebuild of the project automatically.

This isn't necessarily a bad thing, and could allow you to isolate your tasks without worrying about the main document braking on any given change.

## TIP 3: Use dmath environment for long expressions

When generating long latex expressions into equation environments, you may run into the equations extending into the margins, or even off the page.

```
% demonstrate coefficients of particularly long binomial expansion
\begin{sagesilent}
var("x y") # declare symbols for 'x' and 'y'
\end{sagesilent}
\begin{equation}
\sage{expand((x+y)^10)}
\end{equation}
```

(TODO mini example)

The easy fix for this is to use the `dmath`

environment from the `breqn`

package. This environent behaves very similarly to the `equation`

environment,
however it breaks the equation over multiple lines appropriately.

```
% in preamble:
\usepackage{breqn}
% ... in document body
\begin{sagesilent}
var("x y") # declare symbols for 'x' and 'y'
\end{sagesilent}
% demonstrate coefficients of particularly long binomial expansion
\begin{dmath}
\sage{expand((x+y)^10)}
\end{dmath}
```

(TODO show render)

## TIP 4: Don't put everything into sagesilent

### Problem: Bad SageMath experience inside LaTeX

The path of least resistance when writing Sage Code to be used by SageTex in a
latex document, is to write it into `sagesilent`

or `sageblock`

environments.

```
\begin{sagesilent}
# long calculations:
# ...
final_expression = ...
illustrative_plot = ...
\end{sagesilent}
\begin{equation}
\sage{final_expression}
\end{equation}
\sageplot{illustrative_plot}
```

But when iterating on the code to do the correct thing (especially so for creating plots), the feedback loop is very slow (run latex, run sage on generated script, ... then run latex again...). Furthermore, any syntax error will make the second step (running the generated SageMath script) fail completely, making you repeat the first two steps again. As the document gets larger, it gets even slower and irritating. SageMath provides a brilliant Jupyter Notebook experience, especially with the cells which you can run individually to make small adjustments on the fly when creating the code. It's natural to do the initial development in notebook and copy-paste into the SageTex environments, however you may decide to develop on the code some more but will now find yourself in a more difficult environent. My tip here is to never copy-paste the code into SageTex environments and hence never leave the Jupyter notebook.

There are also a few extra knacks which I have with developing in the SageTex environments, but these are more likely to be noticed by people with more general software experience:

- Syntax highlighting is poor/non-existant in some editors
- No language intelligence i.e. no find-references, rename-symbol (this is available for SageMath notebooks opened in VSCode)
- No debugger (again available for notebooks in VSCode)

### Solution: Jupyter Notebooks

As mentioned above, I recommend writing most of the SageMath code in Jupyter notebooks, and create well-labeled variables for the expressions and plots to be used in the LaTeX document.

An object, say `final_expression`

, can be imported from a Python script
(but not a SageMath script), say `notebook.py`

as follows:

```
\begin{sagesilent}
from notebook import final_expression
\end{sagesilent}
\begin{equation}
\sage{final_expression}
\end{equation}
```

But I just said to do your SageMath work in a notebook, not a Python script...

Suppose, we have a SageMath notebook `notebook.ipynb`

defining
`final_expression`

instead, we need to create a corresponding Python script
`notebook.py`

.

The following steps in a unix-style shell would do this (including SageMath shell on Windows):

- From the notebook, create a SageMath script with
`jupyter nbconvert --to script characteristic_curves.ipynb`

(with erroneous`.py`

extension) - Correct
`.py`

extension to`.sage`

with`mv notebook.py notebook.sage`

- Remove the ipython call generated by
`%display latex`

which would crash normal Python/Sage with`sed -e "/get_ipython/d" -i notebook.sage`

- Convert SageMath script to valid Python with
`sage --preparse notebook.sage`

(creating file named`notebook.sage.py`

) - Rename to required filename with
`mv notebook.sage.py notebook.py`

There's multiple steps here but this can be scripted.
Furthermore the `make`

utility is available in most environments where
SageMath is installed, so we can conveniently add rules to a Makefile which
recreates the required Python script whenever the notebook changes.
Have a look at the example repository that comes with this blog post (TODO)
to see this in action.

```
notebook.py: notebook.ipynb
jupyter nbconvert --to script characteristic_curves.ipynb
mv notebook.py notebook.sage
sed -e "/get_ipython/d" -i notebook.sage
sage --preparse notebook.sage
mv notebook.sage.py notebook.py
```

**p.s.** don't forget to include `%display latex`

to the first cell of the
notebook.

## TIP 5: Make use of the latex_name named argument for var

### Problem: LaTeX Representations

A big limitation of using the `\sage`

function to generate formulae in a latex
document, is that symbols in SageMath, unlike in
SymPy, must be valid Python
identifiers (i.e. can be a variable name).
The LaTeX representations are then derived from the variable name.
Typically, the latex representation is precisely the identifier, such as:
`x`

is displayed $x$ (with latex `x`

), and `a_t`

would be displayed $a_t$
(with latex `a_t`

).
Although the backslash `\`

is disallowed in Python identifiers, certain latex
command names are recognised and treated appropriately, for example:
`Phi_t`

is displayed $\Phi_t$ (with latex `\Phi_t`

).

```
sage: # var() creates SageMath variables so need to give valid var names
sage: var("x_2 Phi")
(x_2, Phi)
sage: latex(x_2) # latex generally matches variable name
x_{2}
sage: latex(Phi) # exceptions are made for common latex commands
\Phi
```

In particular, the caret symbol `^`

is disallowed in Python identifiers
(it's an operator),
making it impossible to create symbols which display with superscripts.
But also, the `-`

symbol is also disallowed, making it impossible, for
example, to create a SageMath symbol for $\beta_{-}$.

```
sage: var("a^t")
ValueError: The name "a^t" is not a valid Python identifier.
sage: var("beta_{-}")
ValueError: The name "beta_{-}" is not a valid Python identifier.
```

On the face of it, this limits the expressiveness of the expressions that can be generated with SageMath into LaTeX documents. But there are ways around this.

### Solution: latex_name

Turns out `var`

takes a named argument `latex_name`

to provide a LaTeX representation as a string. A tip here is to use "raw" strings (`r"..."`

) to avoid having to escape all the backslashes you are likely using.

For the last examples:

```
sage: var("a_to_the_t", latex_name="a^t")
a_to_the_t
sage: var("beta_min", latex_name=r"\beta_{-}")
beta_min
sage: latex(beta_min) # in a notebook with %display latex, the following latex would be rendered
{\beta_{-}}
```

### Chaotic Solution

Another way of getting round this, at the cost of potential chaotic hackery, is to
make use of commands in (La)Tex such as `\let`

, `\def`

, and `\renewcommand`

to
move the responsibility of displaying the symbols the way you want, onto the
main LaTeX document, instead of SageMath. For some cases, this might be the more desirable solution.

Suppose you want to create an expression from SageMath involving $\beta^{n}*{-}$.
In the SageMath code, you could just define a symbol for beta (displayed as
$\beta$).
However, with the following latex code, you can redefine the \beta command,
generated by SageMath to instead produce $\beta^{n}*{-}$:

```
\let\originalbeta\beta
\renewcommand\beta{{\originalbeta^{n}_{-}}}
\begin{sagesilent}
var("beta")
\end{sagesilent}
\begin{equation*}
\sage{ (beta + 1)^2 }
\end{equation*}
```

This will render to the following: $$(\beta^n_- + 1)^2$$

#### Limiting the bad stuff

Redefining default values for things is inherently ugly, so here are a couple of ways of mitigating the harm.

We can tweak the above example to limit the scope of the redefinition for the
`\beta`

command with `\begingroup`

and `\endgroup`

, removing possible
unintended consequences in other parts of the document:

```
\begingroup % beginning of scope redefining \beta
\let\originalbeta\beta
\renewcommand\beta{{\originalbeta^{n}_{-}}}
...
\begin{equation*}
\sage{ (beta + 1)^2 }
\end{equation*}
\endgroup % end of scope redefining \beta
```

In this example, $\beta$ is redefined to be a relatively similar $\beta^n_-$.
The variable name in the Sage code is still `beta`

, but happens to still fit
quite well.
However, you may want to create a symbol which displays to something very
different to any standard symbol in SageMath, say $\mathrm{ch}_2^\beta(v)$, in
which case the variable name will not match very well.
In such an example, it would make sense to redefine a symbol you are unlikely
to use, and store it to an appropriate variable name in the SageMath code:

```
\begingroup % beginning of scope redefining \kappa (second_twisted_chern)
\let\originalkappa\kappa
\renewcommand\kappa{{\mathrm{ch}_2^\beta(v)}}
\begin{sagesilent}
# Create symbol for kappa (to display in the latex differently)
# But store it with a variable name better suited the intended mathematical
# meaning
second_twisted_chern = var("kappa")
\end{sagesilent}
\begin{equation*}
\sage{ (second_twisted_chern + 1)^2 }
\end{equation*}
\endgroup % end of scope redefining \kappa (second_twisted_chern)
```

This would render to: $$\left(\mathrm{ch}_2^\beta(v) + 1\right)^2$$