mathlex 0.2.0

Mathematical expression parser for LaTeX and plain text notation, producing a language-agnostic AST
Documentation

mathlex

License GitHub Release CI Crates.io Rust Version docs.rs Swift Package Index Swift Platform

A mathematical expression parser for LaTeX and plain text notation, producing a language-agnostic Abstract Syntax Tree (AST).

Features

  • LaTeX Parsing - Parse mathematical LaTeX notation (\frac{1}{2}, \int_0^1, \sum_{i=1}^n)
  • Plain Text Parsing - Parse standard math notation (2*x + 3, sin(x))
  • Rich AST - Comprehensive AST supporting:
    • Algebra and calculus expressions
    • Linear algebra (vectors and matrices)
    • Vector calculus (gradient, divergence, curl, Laplacian)
    • Set theory (unions, intersections, quantifiers)
    • Logic (connectives, quantifiers)
    • Multiple integrals (double, triple, closed path)
    • Quaternion algebra
  • Vector Notation - Multiple styles: bold (\mathbf{v}), arrow (\vec{v}), hat (\hat{n})
  • Context-Aware - Smart handling of e, i, j, k based on number system context
  • No Evaluation - Pure parsing library, interpretation is client responsibility
  • Cross-Platform - Native support for Rust and Swift (iOS/macOS)

Installation

Rust

Add to your Cargo.toml:

[dependencies]
mathlex = "0.2.0"

Swift

Add to your Package.swift:

dependencies: [
    .package(url: "https://github.com/ChrisGVE/mathlex.git", from: "0.2.0")
]

Or in Xcode: File → Add Package Dependencies → Enter https://github.com/ChrisGVE/mathlex.git

Quick Start

Rust

Parse Plain Text

use mathlex::{parse, Expression};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let expr = parse("2*x + sin(y)")?;

    // Find all variables
    let vars = expr.find_variables();
    println!("Variables: {:?}", vars); // {"x", "y"}

    // Convert back to string
    println!("{}", expr); // "2 * x + sin(y)"

    Ok(())
}

Parse LaTeX

use mathlex::{parse_latex, Expression};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let expr = parse_latex(r"\frac{1}{2} + \sqrt{x}")?;

    // Convert to LaTeX string
    println!("{}", expr.to_latex()); // "\frac{1}{2} + \sqrt{x}"

    Ok(())
}

Swift

import MathLex

do {
    // Parse plain text
    let expr = try MathExpression.parse("2*x + sin(y)")
    print(expr.variables) // ["x", "y"]
    print(expr.description) // "2 * x + sin(y)"

    // Parse LaTeX
    let latex = try MathExpression.parseLatex(#"\frac{1}{2}"#)
    print(latex.latex) // "\frac{1}{2}"
} catch {
    print("Parse error: \(error)")
}

Supported Notation

Literals

  • Integers: 42, -17
  • Floats: 3.14, 2.5e-3
  • Rationals: LaTeX \frac{1}{2}
  • Complex: via construction
  • Quaternions: via construction with basis vectors i, j, k

Symbols

  • Variables: x, y, theta
  • Greek letters: \alpha, \beta, \Gamma
  • Constants: \pi (π), e, \infty (∞)
  • Imaginary/quaternion units: i, j, k (context-aware)

Operations

  • Binary: +, -, *, /, ^, **, %, \pm, \mp
  • Unary: -x, x!
  • Functions: sin, cos, tan, log, ln, exp, sqrt, abs, floor, ceil, det
  • Vector products: \cdot (dot), \times (cross)

Calculus (Representation Only)

  • Derivatives:
    • Standard notation: \frac{d}{dx}f, \frac{\partial}{\partial x}f (operator followed by expression)
    • With explicit multiplication: \frac{d}{d*x}f, \frac{\partial}{\partial*x}f (when variable needs marker)
    • Higher order: \frac{d^2}{dx^2}f, \frac{\partial^2}{\partial x^2}f
  • Integrals: \int, \int_a^b
  • Multiple integrals: \iint (double), \iiint (triple)
  • Closed integrals: \oint (line), \oiint (surface)
  • Limits: \lim_{x \to a}
  • Sums: \sum_{i=1}^{n}
  • Products: \prod_{i=1}^{n}
  • Subscripts: Supports expression subscripts like x_{i+1}, a_{n-1} (flattened to variable names)

Vector Calculus

  • Gradient: \nabla f
  • Divergence: \nabla \cdot \mathbf{F}
  • Curl: \nabla \times \mathbf{F}
  • Laplacian: \nabla^2 f
  • Vector notation styles:
    • Bold: \mathbf{v}
    • Arrow: \vec{v}
    • Hat (unit vectors): \hat{n}

Set Theory

  • Operations: \cup (union), \cap (intersection), \setminus (difference)
  • Relations: \in, \notin, \subset, \subseteq, \supset, \supseteq
  • Special sets: \emptyset or \varnothing (empty set)
  • Number sets: \mathbb{N}, \mathbb{Z}, \mathbb{Q}, \mathbb{R}, \mathbb{C}, \mathbb{H} (quaternions)
  • Power set: \mathcal{P}(A)
  • Quantifiers: \forall (for all), \exists (there exists)

Logic

  • Connectives: \land (and), \lor (or), \lnot (not)
  • Implications: \implies, \iff (if and only if)

Structures

  • Vectors: \begin{pmatrix} a \\ b \end{pmatrix}
  • Matrices: \begin{bmatrix} a & b \\ c & d \end{bmatrix}
  • Equations: x = y
  • Inequalities: x < y, \leq, \geq, \neq

Advanced Examples

Vector Calculus

use mathlex::parse_latex;

// Maxwell's equations components
let gauss = parse_latex(r"\nabla \cdot \mathbf{E}").unwrap();
let faraday = parse_latex(r"\nabla \times \mathbf{E}").unwrap();

// Laplacian operator
let poisson = parse_latex(r"\nabla^2 \phi").unwrap();

// Vector identities
let div_curl = parse_latex(r"\nabla \cdot (\nabla \times \mathbf{F})").unwrap();
let curl_grad = parse_latex(r"\nabla \times (\nabla f)").unwrap();

Multiple Integrals

use mathlex::parse_latex;

// Surface area integral
let surface = parse_latex(r"\iint_R f(x,y) dA").unwrap();

// Volume integral
let volume = parse_latex(r"\iiint_V \rho dV").unwrap();

// Closed line integral (circulation)
let circulation = parse_latex(r"\oint_C \mathbf{F} \cdot d\mathbf{r}").unwrap();

Set Theory and Logic

use mathlex::parse_latex;

// Set operations
let union = parse_latex(r"A \cup B \cap C").unwrap();
let membership = parse_latex(r"x \in A \cup B").unwrap();

// Logical statements
let forall = parse_latex(r"\forall x \in \mathbb{R} (x^2 \geq 0)").unwrap();
let exists = parse_latex(r"\exists x (P(x) \land Q(x))").unwrap();
let implication = parse_latex(r"P \implies Q").unwrap();

Quaternions

use mathlex::{Expression, MathConstant};

// Quaternion basis vectors satisfy:
// i² = j² = k² = ijk = -1
// ij = k, jk = i, ki = j
// ji = -k, kj = -i, ik = -j

let quaternion = Expression::Quaternion {
    real: Box::new(Expression::Integer(1)),
    i: Box::new(Expression::Integer(2)),
    j: Box::new(Expression::Integer(3)),
    k: Box::new(Expression::Integer(4)),
};

Context-Aware Parsing

use mathlex::{parse_latex, Expression, MathConstant};

// 'e' is parsed as Euler's constant
let euler = parse_latex(r"e^x").unwrap();

// 'i' requires explicit marking to be treated as imaginary unit
let complex = parse_latex(r"3 + 4\mathrm{i}").unwrap();

// Quaternion basis vectors (when marked)
let quat = parse_latex(r"\mathbf{i} + \mathbf{j} + \mathbf{k}").unwrap();

Design Philosophy

mathlex is a pure parsing library. It converts text to AST and back - nothing more.

  • No evaluation - mathlex does not compute values
  • No simplification - mathlex does not transform expressions
  • No dependencies on consumers - can be used by any library

This design allows different libraries to interpret the AST according to their capabilities:

  • A CAS library can perform symbolic differentiation on Derivative nodes
  • A numerical library can evaluate Function nodes numerically
  • An educational tool can render step-by-step explanations

Optional Features

Rust

[dependencies]
mathlex = { version = "0.1.1", features = ["serde"] }
  • serde - Enable serialization/deserialization of AST types
  • ffi - Enable Swift FFI bindings (for building XCFramework)

Documentation

License

MIT License - see LICENSE for details.

Links