Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help



Expression Formatting

Topic: parser.formatting

Format mathematical expressions for display in multiple notations. Supports LaTeX, Unicode, Wolfram, and custom formatters for different output targets.

Expression Formatting

Format mathematical expressions for display in multiple notations.

Understanding Expression Formatting

What is Expression Formatting?

Expression formatting converts internal Expression structures to human-readable or machine-parseable strings. MathHook provides multiple output formats:

  • LaTeX: Academic papers, presentations, web rendering (MathJax/KaTeX)
  • Unicode: Pretty terminal output, notebooks, readable display
  • Wolfram: Mathematica/Wolfram Language compatibility
  • String: Rust Debug format for debugging

How It Works (Architecture)

Formatter Trait:

#![allow(unused)]
fn main() {
pub trait Formatter {
    fn format(&self, expr: &Expression) -> String;
}
}

Implementations:

  • LaTeXFormatter - Recursive descent with LaTeX command generation
  • UnicodeFormatter - Unicode mathematical symbols (superscripts, subscripts)
  • WolframFormatter - Wolfram Language bracket notation
  • Type-aware formatting for noncommutative symbols

Format Comparison

ExpressionLaTeXUnicodeWolfram
x² + 2x + 1x^{2} + 2 \cdot x + 1x² + 2·x + 1x^2 + 2*x + 1
sin(x)\sin(x)sin(x)Sin[x]
√2\sqrt{2}√2Sqrt[2]
π·r²\pi \cdot r^{2}π·r²Pi*r^2

Unicode Mathematical Symbols

Supported Unicode ranges:

  • Superscripts: ⁰¹²³⁴⁵⁶⁷⁸⁹
  • Subscripts: ₀₁₂₃₄₅₆₇₈₉
  • Greek: α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ σ τ υ φ χ ψ ω
  • Operators: · × ÷ ± ∓ ≤ ≥ ≠ ≈ ∞
  • Roots: √ ∛ ∜
  • Set theory: ∈ ∉ ⊂ ⊃ ⊆ ⊇ ∪ ∩ ∅

Examples

Basic Formatting

Format expressions in different notations

Rust
#![allow(unused)]
fn main() {
use mathhook::prelude::*;
use mathhook::formatter::{LatexFormatter, UnicodeFormatter, WolframFormatter};

let x = symbol!(x);
let expr = expr!(x^2 + 2*x + 1);

// LaTeX
let latex = LatexFormatter::new().format(&expr);
println!("{}", latex);   // x^{2} + 2 \cdot x + 1

// Unicode (pretty-print)
let unicode = UnicodeFormatter::new().format(&expr);
println!("{}", unicode); // x² + 2·x + 1

// Wolfram
let wolfram = WolframFormatter::new().format(&expr);
println!("{}", wolfram); // x^2 + 2*x + 1

}
Python
from mathhook import symbol, expr
from mathhook.formatter import LatexFormatter, UnicodeFormatter, WolframFormatter

x = symbol('x')
expr_obj = expr('x^2 + 2*x + 1')

# LaTeX
latex = LatexFormatter().format(expr_obj)
print(latex)   # x^{2} + 2 \cdot x + 1

# Unicode (pretty-print)
unicode = UnicodeFormatter().format(expr_obj)
print(unicode) # x² + 2·x + 1

# Wolfram
wolfram = WolframFormatter().format(expr_obj)
print(wolfram) # x^2 + 2*x + 1

JavaScript
const { symbol, expr } = require('mathhook');
const { LatexFormatter, UnicodeFormatter, WolframFormatter } = require('mathhook');

const x = symbol('x');
const exprObj = expr('x^2 + 2*x + 1');

// LaTeX
const latex = new LatexFormatter().format(exprObj);
console.log(latex);   // x^{2} + 2 \cdot x + 1

// Unicode (pretty-print)
const unicode = new UnicodeFormatter().format(exprObj);
console.log(unicode); // x² + 2·x + 1

// Wolfram
const wolfram = new WolframFormatter().format(exprObj);
console.log(wolfram); // x^2 + 2*x + 1

Type-Aware Formatting

Noncommutative symbols formatted correctly

Rust
#![allow(unused)]
fn main() {
use mathhook::prelude::*;
use mathhook::formatter::latex::LatexFormatter;

// Matrix symbols (bold)
let A = symbol!(A; matrix);
let B = symbol!(B; matrix);
let matrix_expr = expr!(A * B);

let formatter = LatexFormatter::new();
println!("{}", formatter.format(&matrix_expr));
// Output: \mathbf{A}\mathbf{B}

// Operator symbols (hat)
let p = symbol!(p; operator);
let x = symbol!(x; operator);
let op_expr = expr!(p * x);

println!("{}", formatter.format(&op_expr));
// Output: \hat{p}\hat{x}

}
Python
from mathhook import symbol, expr
from mathhook.formatter import LatexFormatter

# Matrix symbols (bold)
A = symbol('A', type='matrix')
B = symbol('B', type='matrix')
matrix_expr = expr('A * B')

formatter = LatexFormatter()
print(formatter.format(matrix_expr))
# Output: \mathbf{A}\mathbf{B}

# Operator symbols (hat)
p = symbol('p', type='operator')
x = symbol('x', type='operator')
op_expr = expr('p * x')

print(formatter.format(op_expr))
# Output: \hat{p}\hat{x}

JavaScript
const { symbol, expr } = require('mathhook');
const { LatexFormatter } = require('mathhook');

// Matrix symbols (bold)
const A = symbol('A', { type: 'matrix' });
const B = symbol('B', { type: 'matrix' });
const matrixExpr = expr('A * B');

const formatter = new LatexFormatter();
console.log(formatter.format(matrixExpr));
// Output: \mathbf{A}\mathbf{B}

// Operator symbols (hat)
const p = symbol('p', { type: 'operator' });
const x = symbol('x', { type: 'operator' });
const opExpr = expr('p * x');

console.log(formatter.format(opExpr));
// Output: \hat{p}\hat{x}

Customized LaTeX Output

Configure formatter behavior

Rust
#![allow(unused)]
fn main() {
use mathhook::prelude::*;
use mathhook::formatter::latex::LatexFormatter;

// Configure formatter
let formatter = LatexFormatter::new()
    .with_precision(6)           // Float precision
    .with_explicit_multiplication(true)  // Show all * as \cdot
    .with_compact_fractions(false);      // Use \frac always

let expr = expr!(2*x / 3);
println!("{}", formatter.format(&expr));
// Output: \frac{2 \cdot x}{3}

}
Python
from mathhook import symbol, expr
from mathhook.formatter import LatexFormatter

# Configure formatter
formatter = LatexFormatter(
    precision=6,
    explicit_multiplication=True,
    compact_fractions=False
)

expr_obj = expr('2*x / 3')
print(formatter.format(expr_obj))
# Output: \frac{2 \cdot x}{3}

JavaScript
const { symbol, expr } = require('mathhook');
const { LatexFormatter } = require('mathhook');

// Configure formatter
const formatter = new LatexFormatter({
    precision: 6,
    explicitMultiplication: true,
    compactFractions: false
});

const exprObj = expr('2*x / 3');
console.log(formatter.format(exprObj));
// Output: \frac{2 \cdot x}{3}

Educational Step Formatting

Format step-by-step explanations

Rust
#![allow(unused)]
fn main() {
use mathhook::prelude::*;
use mathhook::formatter::latex::LatexFormatter;

let x = symbol!(x);
let expr = expr!(x^2 + 2*x + 1);

// Generate step-by-step LaTeX
let formatter = LatexFormatter::new();

println!("Step 1: Start with {}", formatter.format(&expr));
let factored = expr.factor();  // (x+1)^2
println!("Step 2: Factor as {}", formatter.format(&factored));

}
Python
from mathhook import symbol, expr
from mathhook.formatter import LatexFormatter

x = symbol('x')
expr_obj = expr('x^2 + 2*x + 1')

# Generate step-by-step LaTeX
formatter = LatexFormatter()

print(f"Step 1: Start with {formatter.format(expr_obj)}")
factored = expr_obj.factor()  # (x+1)^2
print(f"Step 2: Factor as {formatter.format(factored)}")

JavaScript
const { symbol, expr } = require('mathhook');
const { LatexFormatter } = require('mathhook');

const x = symbol('x');
const exprObj = expr('x^2 + 2*x + 1');

// Generate step-by-step LaTeX
const formatter = new LatexFormatter();

console.log(`Step 1: Start with ${formatter.format(exprObj)}`);
const factored = exprObj.factor();  // (x+1)^2
console.log(`Step 2: Factor as ${formatter.format(factored)}`);

Performance

Time Complexity: O(n) where n = expression tree size

API Reference

  • Rust: mathhook_core::formatter
  • Python: mathhook.formatter
  • JavaScript: mathhook.formatter

See Also