Get startedQuick start

Quick start

Normalize your first formula, pick a profile, and look at the document tree underneath — in 10 minutes.

This walks the core TeXForm path in about ten minutes: normalize a formula, choose the profile that controls how aggressive normalization is, and look at the document tree that sits underneath. Every step shows the output and one line on what just happened.

Install#

Install TeXForm for your language. See Installation for supported versions and verification.

pip install texform
npm install texform
cargo add texform

Normalize your first formula#

Build a TransformEngine with the corpus profile and normalize a physics-package derivative. physics is not in the default package set, so the engine gets a knowledge base that names the packages it loads. The convenience macro \dv{f}{x} expands into the universal \frac form that renders on any plain MathJax or KaTeX deployment.

import texform

kb = texform.KnowledgeBase(packages=["base", "ams", "physics"])
engine = texform.TransformEngine(profile="corpus", knowledge_base=kb)
print(engine.normalize(r"\dv{f}{x}"))
Output
\frac { \mathrm { d } f } { \mathrm { d } x }
import { KnowledgeBase, TransformEngine } from 'texform';

const knowledgeBase = new KnowledgeBase({ packages: ['base', 'ams', 'physics'] });
const engine = new TransformEngine({ profile: 'corpus', knowledgeBase });
console.log(engine.normalize('\\dv{f}{x}'));
Output
\frac { \mathrm { d } f } { \mathrm { d } x }
use texform::{KnowledgeBase, Profile, TransformEngine};

let kb = KnowledgeBase::builder().packages(&["base", "ams", "physics"]).build()?;
let engine = TransformEngine::builder()
    .knowledge_base(kb)
    .profile(Profile::Corpus)
    .build()?;
let result = engine.normalize(r"\dv{f}{x}")?;
println!("{}", result);
Output
\frac { \mathrm { d } f } { \mathrm { d } x }

What just happened: the engine parsed \dv{f}{x}, recognized it as a physics derivative macro, and rewrote it into a form that no longer depends on the physics package. The default serialized style is spaced, which is why braces and operators are separated.

Pick a profile#

The profile is the core decision: it names your downstream use and selects how far normalization goes. Run the same input through the authoring profile and compare.

import texform

kb = texform.KnowledgeBase(packages=["base", "ams", "physics"])
corpus = texform.TransformEngine(profile="corpus", knowledge_base=kb)
authoring = texform.TransformEngine(profile="authoring", knowledge_base=kb)
print(corpus.normalize(r"\dv{f}{x}"))
print(authoring.normalize(r"\dv{f}{x}"))
Output
\frac { \mathrm { d } f } { \mathrm { d } x }
\dv { f } { x }
import { KnowledgeBase, TransformEngine } from 'texform';

const knowledgeBase = new KnowledgeBase({ packages: ['base', 'ams', 'physics'] });
const corpus = new TransformEngine({ profile: 'corpus', knowledgeBase });
const authoring = new TransformEngine({ profile: 'authoring', knowledgeBase });
console.log(corpus.normalize('\\dv{f}{x}'));
console.log(authoring.normalize('\\dv{f}{x}'));
Output
\frac { \mathrm { d } f } { \mathrm { d } x }
\dv { f } { x }
use texform::{KnowledgeBase, Profile, TransformEngine};

let kb = KnowledgeBase::builder().packages(&["base", "ams", "physics"]).build()?;
let corpus = TransformEngine::builder().knowledge_base(kb.clone()).profile(Profile::Corpus).build()?;
let authoring = TransformEngine::builder().knowledge_base(kb).profile(Profile::Authoring).build()?;
println!("{}", corpus.normalize(r"\dv{f}{x}")?);
println!("{}", authoring.normalize(r"\dv{f}{x}")?);
Output
\frac { \mathrm { d } f } { \mathrm { d } x }
\dv { f } { x }

What just happened: corpus expanded the macro because a training corpus should not depend on the physics package, while authoring kept the author's shorthand. Same input, different target, different output — no profile is "better", only fitter for a downstream use. The four profiles and the rules behind them are covered in Transforms.

Look under the hood#

Beneath normalize there is a tree you can use any time. Parse a formula directly, check that the parse is clean, and serialize it back to LaTeX.

import texform

result = texform.Parser().parse(r"\frac{x}{y}")
document = result["document"]
print(document.has_errors())
print(document.to_latex())
Output
False
\frac { x } { y }
import { Parser } from 'texform';

const result = new Parser().parse('\\frac{x}{y}');
const document = result.document;
console.log(document.hasErrors());
console.log(document.toLatex());
Output
false
\frac { x } { y }
use texform::Parser;

let parser = Parser::builder().build()?;
let parsed = parser.parse(r"\frac{x}{y}");
if let Some(document) = parsed.document() {
    println!("{}", document.has_errors());
    println!("{}", document.to_latex()?);
}
Output
false
\frac { x } { y }

What just happened: parse returned a Document — the editable working tree. has_errors() confirms the parse is complete (a tree with holes would be read-only and could not be normalized), and to_latex() serializes it back. Normalization is this same tree with a rule pipeline applied; you can also walk and edit it directly.

Last updated