LATEX math,
resolved.

TeXForm parses, edits and normalizes LaTeX formulas as syntax trees.

Open source, with packages for Python, JavaScript and Rust.

Get started pip install texform
Specimen
i / v
Input23 chars · live
Structure · hover a node
Canonical · corpusconsistent training labels
\frac{a}{b}+\sqrt{x^2}
RenderedMathJax, from the canonical output
Fig. 0. {a \over b}+\sqrt {x^2} under corpus, precomputed by texform 0.10.1 until the live engine loads. Hover a character, node or token to trace it. Tinted marks show what changes.
Open in Playground (opens in new tab)

§1Parse. Edit. Transform.

Parse a formula once, then edit and transform the same tree.

1.1Parse

The parser turns LaTeX source into a syntax tree. It looks up each command in the knowledge base to find its arguments.

1.2Edit

The Document API finds, builds and replaces nodes, then writes the tree back to LaTeX.

1.3Transform

The transform engine rewrites the tree into a canonical form. A profile sets how much it changes.

Parsei / iiitexform 0.10.1
Pythonthe same steps with the Document API
engine = texform.TransformEngine(profile="corpus")
doc = engine.parse(src)["document"]
[sqrt] = doc.find_commands("sqrt")
doc.set_arg(sqrt, 1, "x^2+y^2")
engine.transform(doc)
doc.to_latex()
Fig. 1. The formula from Fig. 0 through all three steps: parsed, one argument replaced through the Document API, then normalized under corpus. Scroll to step through.

1.1Parse

The parser turns LaTeX source into a syntax tree. It looks up each command in the knowledge base to find its arguments.

engine = texform.TransformEngine(profile="corpus")
doc = engine.parse(src)["document"]
[sqrt] = doc.find_commands("sqrt")
doc.set_arg(sqrt, 1, "x^2+y^2")
engine.transform(doc)
doc.to_latex()
Fig. 1a. The parsed tree.

1.2Edit

The Document API finds, builds and replaces nodes, then writes the tree back to LaTeX.

engine = texform.TransformEngine(profile="corpus")
doc = engine.parse(src)["document"]
[sqrt] = doc.find_commands("sqrt")
doc.set_arg(sqrt, 1, "x^2+y^2")
engine.transform(doc)
doc.to_latex()
Fig. 1b. One argument replaced through the Document API.

1.3Transform

The transform engine rewrites the tree into a canonical form. A profile sets how much it changes.

engine = texform.TransformEngine(profile="corpus")
doc = engine.parse(src)["document"]
[sqrt] = doc.find_commands("sqrt")
doc.set_arg(sqrt, 1, "x^2+y^2")
engine.transform(doc)
doc.to_latex()
Fig. 1c. The tree normalized under corpus.

§2Normalization

LaTeX lets the same formula be written in many ways. Normalization rewrites these variants into one form: aliases unified, convenience macros expanded, redundant braces removed. Most rewrites are named rules, and each profile enables the rules suited to one use.

LowerAttributesRewriteLowerAttributesFinalizeAstFlattenGroups↺again✓ check
\sum\limits_i\big(\dfrac{1}{x_i}\big)^2\neq\mathbf{y}
✓
Fixed pointNo phase changes the tree any more, after the phases ran twice. 2 rules fired; the eliminated-form check passes.
\sum\limits_i\big(\dfrac{1}{x_i}\big)^2\neq\mathbf{y}
Fig. 2. \sum\limits_{i}\bigl(\dfrac{1}{x_i}\bigr)^{{2}} \not{=} {\bf y} under corpus. Flattening \not{=} creates a match for Rewrite, so the earlier phases run again. Tinted nodes are about to be replaced or were just added. Phase states are replayed from texform 0.10.1; rule order within a Rewrite pass is reconstructed.
Fired in Fig. 2
2in the order they fired
Fig. 3. The rewrite rules that fired in Fig. 2. Each tile shows a form and what it becomes. Profiles are cumulative: each adds one level of rules. Hover a rule for details; click to replay its test case in Fig. 2. Browse the rules

§3Knowledge base

The knowledge base records the syntax of LaTeX commands and environments: their arguments, modes and packages. The parser and the Document API both rely on it. Every entry is tested in three renderers and has its own reference page.

Arrange by
renderers with full supportall threetwoonenone
base277
physics183
textmacros78
ams63
bboldx12
braket11
color5
boldsymbol1
Fig. 4. Commands and environments in the knowledge base, one cell per entry and package. Shade shows how many of the three renderers support it fully. Hover for details; click to open its reference page.
Renderer
0%25%50%75%100%
Full
Fig. 5. Share of entries each renderer supports fully, from compiling generated test cases. Select a renderer to filter Fig. 4. Renderer support
MeasureValue
Formulas checked1,226,617
Formulas TeXForm cannot represent1,584
Lenient parse failure rate0.13%
Eliminated-form contract violations0
Configured exceptions0
Table 1. Parsing and normalization over real-world formulas. The contract check flags any form that an enabled rule should have removed. Method and full tables

§4Get started in Python, JavaScript, Rust or the CLI

The same API in Python, JavaScript and Rust, built on a shared Rust core. The JavaScript package runs as WebAssembly, in the browser or in Node.js. The CLI brings the same normalization to the command line.

Pythonpip install texform
import texform
src = r"{a \over b}+\sqrt {x^2}"
engine = texform.TransformEngine(
    profile="corpus")
engine.normalize(src)
→\frac { a } { b } + \sqrt { x ^ { 2 } }
JavaScriptnpm install texform
import { TransformEngine } from "texform";
const src = String.raw`{a \over b}+\sqrt {x^2}`;
const engine = new TransformEngine({
  profile: "corpus" });
engine.normalize(src);
→\frac { a } { b } + \sqrt { x ^ { 2 } }
Rustcargo add texform
use texform::{Profile, TransformEngine};
let src = r"{a \over b}+\sqrt {x^2}";
let engine = TransformEngine::builder()
    .profile(Profile::Corpus).build()?;
let out = engine.normalize(src)?;
→\frac { a } { b } + \sqrt { x ^ { 2 } }
CLIuv tool install texform
texform normalize --profile corpus '{a \over b}+\sqrt {x^2}'
→\frac { a } { b } + \sqrt { x ^ { 2 } }
Listing 1. The same normalization in Python, JavaScript, Rust and the CLI. The JavaScript package also runs Fig. 0. With --lines, the CLI reads one formula per line. Command-line reference

§5Applications

Pipelines that store, compare or render LaTeX math need it in a predictable form. Tools that edit it need its structure. TeXForm provides both.

imagelabel{a \over b}\frac { a } { b }\frac{a}{b}\frac { a } { b }\frac ab\frac { a } { b }
distinct labels 31corpus
(a) Training data. Labels are normalized, so each formula is written one way across the dataset.
pred{\bf v}^2_iref\mathbf{v}_{i}^{2}corpuspred\mathbf { v } _ { i } ^ { 2 }ref\mathbf { v } _ { i } ^ { 2 }
exact match 01corpus
(b) Evaluation. Predictions and references are normalized before comparison, removing many spelling-only mismatches.
notes.html\dv{f}{x}Undefined control sequence: \dvsrc\dv{f}{x}\frac { \mathrm { d } f } { \mathrm { d } x }
render errors 10faithful
(c) Web rendering. Package-specific commands are expanded into forms that common web renderers support.
editor\sqrt[·]{·}x3n\sqrt [ ] { x }3n
doc.set_arg(sqrt, 0, "n")
(d) Editing tools. Editors and authoring tools read and change formulas through the syntax tree.
Fig. 6. Every LaTeX string in (a)–(d) is an input or output of texform 0.10.1; the tags under (a)–(c) name the profile used.

References

Build on a foundation you can cite.

Open source under Apache-2.0, including its knowledge base and rewrite rules.

A paper describing TeXForm is coming soon. Until then, please cite the software.

BibTeX
@software{texform,
author = {TeXForm contributors},
title = {TeXForm: Parsing, Editing,
and Normalizing LaTeX Math},
url = {https://texform.dev},
version = {0.10.1},
year = {2026},
}
Typesetas it appears in your bibliography
[1]

TeXForm contributors. TeXForm: Parsing, Editing, and Normalizing LaTeX Math. Version 0.10.1, 2026. https://texform.dev