Parser Design for Noncommutative Algebra
Topic:
parser.noncommutative_design
Design documentation for MathHook's type-aware LaTeX parser that automatically infers symbol types. Enables seamless support for noncommutative algebra without explicit type annotations in mathematical expressions.
Parser Design for Noncommutative Algebra
Design documentation for MathHook's type-aware LaTeX parser that automatically infers symbol types.
Overview
The parser implements automatic type inference from LaTeX notation, enabling seamless support for noncommutative algebra without explicit type annotations in mathematical expressions.
Key Innovation: LaTeX notation implicitly encodes symbol types:
\mathbf{A}→ Matrix (noncommutative)\hat{p}→ Operator (noncommutative)x→ Scalar (commutative, default)
Design Rationale
Why LaTeX Notation?
- Universal Standard: LaTeX is the de facto standard for mathematical typesetting
- Rich Semantics: Notation conventions already encode meaning (bold for matrices, hat for operators)
- User Familiarity: Mathematicians and physicists already know these conventions
- Minimal Overhead: No separate type annotation syntax needed
Advantages Over Explicit Typing
With Type Inference (our approach):
\mathbf{A}\mathbf{X} = \mathbf{B}
Without Type Inference (alternative):
matrix A * matrix X = matrix B
Benefits:
- Cleaner syntax
- Standard mathematical notation
- No learning curve for users
- Automatic type propagation
Type Inference Rules
Matrix Type
Trigger: \mathbf{identifier}
Rationale: Mathematical convention uses bold for matrices and vectors
Examples:
\mathbf{A} → Matrix symbol A
\mathbf{B} → Matrix symbol B
\mathbf{x} → Matrix symbol x (vector)
Implementation:
- Parser detects
\mathbf{...}pattern - Creates symbol with
SymbolType::Matrix - Preserves identifier name inside braces
Operator Type
Trigger: \hat{identifier}
Rationale: Quantum mechanics convention uses hat notation for operators
Examples:
\hat{p} → Operator symbol p (momentum)
\hat{x} → Operator symbol x (position)
\hat{H} → Operator symbol H (Hamiltonian)
Implementation:
- Parser detects
\hat{...}pattern - Creates symbol with
SymbolType::Operator - Preserves identifier name inside braces
Scalar Type (Default)
Trigger: Plain identifier (no special notation)
Rationale: Standard variables are commutative by default
Examples:
x → Scalar symbol x
y → Scalar symbol y
\theta → Scalar symbol theta
Type System Integration
Symbol Type Enum
#![allow(unused)] fn main() { pub enum SymbolType { Scalar, // Commutative (default) Matrix, // Noncommutative Operator, // Noncommutative Quaternion, // Noncommutative } }
Commutativity Propagation
Rule: Expression is noncommutative if any operand is noncommutative
Implementation:
#![allow(unused)] fn main() { fn commutativity(expr: &Expression) -> Commutativity { match expr { Expression::Symbol(sym) => sym.commutativity(), Expression::Mul(factors) => { if factors.iter().any(|f| f.is_noncommutative()) { Commutativity::Noncommutative } else { Commutativity::Commutative } } // ... similar for other operations } } }
Type Preservation
Guarantee: Symbol types preserved through all operations
Implementation Challenges
Challenge 1: Parser State Management
Problem: LALRPOP is stateless; cannot maintain type context
Solution: Encode types in syntax tree structure (symbol metadata)
Result: Type information flows through AST naturally
Challenge 2: Backward Compatibility
Problem: Existing code assumes all symbols are scalars
Solution: Default to scalar type; noncommutative types opt-in via notation
Result: Zero breaking changes to existing code
Challenge 3: Performance
Problem: Type checking on every operation could be expensive
Solution: Cache type information in symbol itself (O(1) lookup)
Result: No performance regression
Testing Strategy
Unit Tests
Test individual type inference rules:
\mathbf{A}→ Matrix\hat{p}→ Operatorx→ Scalar- Mixed expressions preserve types
Integration Tests
Test end-to-end workflows:
- Parse → Solve → Format
- Type preservation through operations
- Correct LaTeX output formatting
Edge Case Tests
Test boundary conditions:
- Nested notation
- Malformed LaTeX
- Mixed notation precedence
- Empty identifiers
- Special characters
Examples
Matrix Type Inference
LaTeX bold notation creates matrix symbols
Rust
#![allow(unused)] fn main() { use mathhook::parser::latex::parse_latex; // Bold notation → Matrix symbols let expr = parse_latex(r"\mathbf{A}\mathbf{B} \neq \mathbf{B}\mathbf{A}")?; // A and B are noncommutative matrices // A*B ≠ B*A in general }
Python
from mathhook.parser import parse_latex
# Bold notation → Matrix symbols
expr = parse_latex(r"\mathbf{A}\mathbf{B} \neq \mathbf{B}\mathbf{A}")
# A and B are noncommutative matrices
# A*B ≠ B*A in general
JavaScript
const { parseLatex } = require('mathhook');
// Bold notation → Matrix symbols
const expr = parseLatex(String.raw`\mathbf{A}\mathbf{B} \neq \mathbf{B}\mathbf{A}`);
// A and B are noncommutative matrices
// A*B ≠ B*A in general
Operator Type Inference
LaTeX hat notation creates operator symbols
Rust
#![allow(unused)] fn main() { use mathhook::parser::latex::parse_latex; // Hat notation → Operator symbols let expr = parse_latex(r"[\hat{x}, \hat{p}] = i\hbar")?; // Canonical commutation relation // x and p are noncommutative operators }
Python
from mathhook.parser import parse_latex
# Hat notation → Operator symbols
expr = parse_latex(r"[\hat{x}, \hat{p}] = i\hbar")
# Canonical commutation relation
# x and p are noncommutative operators
JavaScript
const { parseLatex } = require('mathhook');
// Hat notation → Operator symbols
const expr = parseLatex(String.raw`[\hat{x}, \hat{p}] = i\hbar`);
// Canonical commutation relation
// x and p are noncommutative operators
Mixed Type Expression
Different symbol types in same expression
Rust
#![allow(unused)] fn main() { use mathhook::parser::latex::parse_latex; // Quantum mechanics: scalar + operators + matrix let expr = parse_latex(r"\hbar \omega \hat{a}^\dagger \hat{a} + \mathbf{H}_0")?; // ℏ and ω: scalars (commutative) // â†, â: operators (noncommutative) // H₀: matrix (noncommutative) }
Python
from mathhook.parser import parse_latex
# Quantum mechanics: scalar + operators + matrix
expr = parse_latex(r"\hbar \omega \hat{a}^\dagger \hat{a} + \mathbf{H}_0")
# ℏ and ω: scalars (commutative)
# â†, â: operators (noncommutative)
# H₀: matrix (noncommutative)
JavaScript
const { parseLatex } = require('mathhook');
// Quantum mechanics: scalar + operators + matrix
const expr = parseLatex(String.raw`\hbar \omega \hat{a}^\dagger \hat{a} + \mathbf{H}_0`);
// ℏ and ω: scalars (commutative)
// â†, â: operators (noncommutative)
// H₀: matrix (noncommutative)
Performance
Time Complexity: O(1) - Type stored in symbol metadata
API Reference
- Rust:
mathhook_core::parser::type_inference - Python:
mathhook.parser.type_inference - JavaScript:
mathhook.parser.typeInference