Core Expression System
Topic:
api.core.expressions
The Expression type is the foundation of MathHook. Expressions are immutable, 32-byte cache-optimized structures representing mathematical constructs from numbers to complex symbolic operations.
Core Expression System
Overview
The Expression type is MathHook's core data structure, designed for:
- Immutability: Thread-safe, predictable behavior
- Performance: 32-byte size for cache optimization (2 per cache line)
- Canonical Forms: Automatic normalization for equality checking
Expression Structure
Expressions use Rust enums for type-safe mathematical constructs:
- Numbers: Integer, Rational, Float, Complex
- Variables: Symbol
- Operations: Add, Mul, Pow
- Functions: Function calls (sin, cos, log, etc.)
- Constants: π, e, i, φ, γ
- Matrices: Matrix (noncommutative)
- Relations: Equation, Inequality
Design Decisions
Why 32 Bytes?
- Modern CPUs have 64-byte cache lines
- Two expressions fit perfectly in one cache line
- 3-5x faster operations in hot loops
- Critical for CAS workloads with millions of expression traversals
Why Immutable?
- Thread safety without locks
- No hidden mutation surprises
- Compiler optimizations
- Traceable expression history
Why Canonical Forms?
- Structural equality: y + x → x + y
- Flattening: (a + b) + c → Add(a, b, c)
- Identity removal: x + 0 → x
- Rational reduction: 6/4 → 3/2
Examples
Creating Expressions with Macros
Use expr!() and symbol!() macros for ergonomic expression creation
Rust
#![allow(unused)] fn main() { use mathhook::prelude::*; let x = symbol!(x); let y = symbol!(y); // Basic arithmetic let sum = expr!(x + y); let product = expr!(x * y); let power = expr!(x ^ 2); // Complex nested expressions let complex = expr!(sin(x ^ 2) + cos(y ^ 2)); }
Python
from mathhook import symbol, expr
x = symbol('x')
y = symbol('y')
# Basic arithmetic
sum_expr = x + y
product = x * y
power = x**2
# Complex nested expressions
from mathhook import sin, cos
complex_expr = sin(x**2) + cos(y**2)
JavaScript
import { symbol, parse } from 'mathhook';
const x = symbol('x');
const y = symbol('y');
// Parse expressions
const sum = parse('x + y');
const product = parse('x * y');
const power = parse('x^2');
// Complex nested expressions
const complex = parse('sin(x^2) + cos(y^2)');
Immutability and Operations
All operations return new expressions, original unchanged
Rust
#![allow(unused)] fn main() { let expr = expr!(x + 1); let doubled = expr.mul(&expr!(2)); // Returns new expression // `expr` is unchanged - still x + 1 // Safe to use in multiple threads use std::sync::Arc; let expr_arc = Arc::new(expr!(x ^ 2)); let clone = Arc::clone(&expr_arc); }
Python
expr = x + 1
doubled = expr * 2 # Returns new expression
# expr is unchanged - still x + 1
# Safe for concurrent use
import threading
shared_expr = x**2
JavaScript
const expr = parse('x + 1');
const doubled = expr.mul(2); // Returns new expression
// expr is unchanged - still x + 1
// Immutable - safe for concurrent access
Canonical Forms and Equality
Automatic normalization ensures equivalent expressions are equal
Rust
#![allow(unused)] fn main() { let expr1 = expr!(x + y); let expr2 = expr!(y + x); assert_eq!(expr1, expr2); // True - both normalized to x + y // Flattening let nested = expr!((x + y) + z); // Automatically flattened to Add(x, y, z) // Identity removal let identity = expr!(x + 0); assert_eq!(identity.simplify(), expr!(x)); }
Python
expr1 = x + y
expr2 = y + x
assert expr1 == expr2 # True - both normalized to x + y
# Flattening and identity removal
nested = (x + y) + z
identity = x + 0
assert identity.simplify() == x
JavaScript
const expr1 = parse('x + y');
const expr2 = parse('y + x');
// Both normalized to x + y
// Identity removal
const identity = parse('x + 0');
const simplified = identity.simplify();
// Result: x
Pattern Matching and Structure
Work with expression structure using pattern matching
Rust
#![allow(unused)] fn main() { use mathhook::Expression; match expr { Expression::Add(terms) => { println!("Sum with {} terms", terms.len()); } Expression::Mul(factors) => { println!("Product with {} factors", factors.len()); } Expression::Pow(base, exp) => { println!("Power: {} ^ {}", base, exp); } Expression::Function(name, args) => { println!("Function {} with {} args", name, args.len()); } _ => {} } }
Python
from mathhook import Expression
# Python uses method introspection
if expr.is_add():
terms = expr.get_terms()
print(f"Sum with {len(terms)} terms")
elif expr.is_mul():
factors = expr.get_factors()
print(f"Product with {len(factors)} factors")
elif expr.is_pow():
base, exp = expr.get_base_exp()
print(f"Power: {base} ^ {exp}")
JavaScript
import { Expression } from 'mathhook';
// Node.js uses type checking methods
if (expr.isAdd()) {
const terms = expr.getTerms();
console.log(`Sum with ${terms.length} terms`);
} else if (expr.isMul()) {
const factors = expr.getFactors();
console.log(`Product with ${factors.length} factors`);
} else if (expr.isPow()) {
const [base, exp] = expr.getBaseExp();
console.log(`Power: ${base} ^ ${exp}`);
}
Performance
Time Complexity: O(1) construction, O(n) operations for n-node trees
API Reference
- Rust:
mathhook_core::expression::Expression - Python:
mathhook.Expression - JavaScript:
mathhook.Expression