mathlex 0.4.1

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

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.4.1] - 2026-05-02

### Fixed

- Un-ignored 3 previously skipped tests: `test_implicit_mult_parens_parens`
  (parser limitation resolved), `test_number_set_in_membership` (`\mathbb{R}`
  after `\in` now works), and `test_implicit_mult_mixed_with_explicit`
  (corrected test expectation — implicit and explicit multiplication share
  precedence and left-associate).

## [0.4.0] - 2026-05-01

### Breaking Changes

- **`Expression` type restructured.** The public `Expression` type is now a
  struct with two fields — `kind: ExprKind` and `annotations: AnnotationSet`
  — rather than a flat enum. All match arms that previously destructured
  `Expression::Variant { ... }` must be updated to `ExprKind::Variant { ... }`
  and applied to `expr.kind`. Convenience constructors on `Expression`
  (`Expression::integer`, `Expression::variable`, etc.) remain available.

- **Serde format changed to adjacently-tagged.** The JSON wire format now uses
  `{ "kind": "VariantName", "value": <payload> }` throughout. The previous
  externally-tagged format (`{ "VariantName": <payload> }`) and bare-string
  unit variants (e.g. `"Nabla"`) are no longer emitted or accepted. Any stored
  JSON or hardcoded deserializers must be updated. See `docs/WIRE-FORMAT.md`
  and the migration guide below.

### Added

- **`AnnotationSet` substrate.** Each `Expression` node now carries an
  `AnnotationSet` — an ordered string-to-string metadata map. The field is
  omitted from JSON when empty and defaults to empty on deserialization, so
  existing documents round-trip without modification. The substrate is passed
  through unchanged by thales v0.9.0; semantic consumption is planned for
  thales v0.10.0.

- **Golden fixtures and variant stability tests.** `tests/fixtures/serde/`
  contains one canonical JSON file per `ExprKind` variant (53 total) plus a
  `variant_manifest.txt`. CI verifies that round-tripping each fixture produces
  bit-identical output, locking the wire format against accidental drift.

- **`docs/WIRE-FORMAT.md`.** Normative wire-format reference covering all 53
  variants, the `AnnotationSet` field, all nested enum kind values, and the
  stability guarantee.

### Migration Guide

**Rust match arms.** Replace `Expression::Add { left, right }` with:

```rust
// before
match expr {
    Expression::Binary { op, left, right } => { ... }
    Expression::Nabla => { ... }
}

// after
match expr.kind {
    ExprKind::Binary { op, left, right } => { ... }
    ExprKind::Nabla => { ... }
}
```

**JSON format.** Every node that previously serialized as
`{ "VariantName": payload }` now serializes as
`{ "kind": "VariantName", "value": payload }`. Unit variants that previously
serialized as the bare string `"Nabla"` now serialize as `{ "kind": "Nabla" }`.

```json
// before (externally tagged)
{ "Binary": { "op": "Add", "left": { "Integer": 1 }, "right": { "Integer": 2 } } }

// after (adjacently tagged)
{
  "kind": "Binary",
  "value": {
    "op":    { "kind": "Add" },
    "left":  { "kind": "Integer", "value": 1 },
    "right": { "kind": "Integer", "value": 2 }
  }
}
```

Swift consumers that decoded the JSON via hand-written `Decodable` structs must
update their `CodingKeys` and decoding logic to match the new shape. See
`docs/WIRE-FORMAT.md` for the new adjacently-tagged layout.

## [0.3.4] - 2026-04-09

### Added

- **Plain text integral notation**: `integrate(expr, var)` and `integrate(expr, var, lower, upper)` producing `Expression::Integral`. Aliases: `integral`, `int`. Variable accepts `dx` or bare `x` form.
- **Plain text summation**: `sum(expr, var, lower, upper)` producing `Expression::Sum`. Aliases: `summation`, `Sum`.
- **Plain text product**: `product(expr, var, lower, upper)` producing `Expression::Product`. Aliases: `prod`, `Product`.
- **Plain text limit**: `limit(expr, var, point)` with optional direction (`+`, `-`, `left`, `right`) producing `Expression::Limit`. Aliases: `lim`, `Limit`.
- **Operator-form derivative**: `d(expr)/dx` and `d(expr)/d(var)` producing `Expression::Derivative`.
- **Special function recognition**: `gamma`, `beta`, `erf`, `erfc`, `zeta`, `bessel_j`, `bessel_y`, `bessel_i`, `bessel_k` added to known-functions list for typo suggestions.
- **Transform functions**: `laplace`, `fourier`, `ilaplace`, `ifourier` recognized as known functions.
- **Unicode logic/set tokens**: `` (and), `` (or), `¬` (not), `` (implies), `` (iff), `` (union), `` (intersect), `` (in), `` (notin) recognized by text tokenizer.
- **Cross-parser round-trip tests**: 47 tests verifying text→LaTeX→text and LaTeX→text→LaTeX paths.
- **Plain text syntax reference**: Comprehensive `docs/plain-text-syntax.md` documenting all supported notation with LaTeX equivalents.

## [0.3.3] - 2026-04-09

### Added

- **Gradient plain text notation**: `nabla(f)` as alias for `grad(f)`, and Unicode `∇f` for gradient expressions
- **Parenthesis-optional vector calculus**: `grad f`, `∇f`, `div f`, `curl f`, `laplacian f` now work without parentheses (parsing the next primary expression as the argument)

### Documentation

- Updated README to document all plain text derivative, partial derivative, and gradient notations

## [0.3.2] - 2026-04-09

### Added

- **Plain text derivative parsing**: Leibniz notation (`dy/dx`, `d2y/dx2`, `d3y/dx3`), prime notation (`y'`, `y''`, `y'''`), and functional notation (`diff(expr, var)`, `diff(expr, var, order)`) all produce `Expression::Derivative`
- **Plain text partial derivative parsing**: functional notation `partial(f, x)`, `partial(f, x, 2)` for higher-order, and `partial(f, x, y)` for mixed partials producing nested `Expression::PartialDerivative`
- **Apostrophe token**: tokenizer recognizes `'` for prime derivative notation

## [0.3.1] - 2026-04-06

### Added

- **New functions**: `trunc`, `clamp`, `lerp`, `rad`, `deg` added to both plain text and LaTeX parsers
- **NaN constant**: `MathConstant::NaN` variant; parseable from `nan`/`NaN` in plain text and `\text{NaN}`/`\mathrm{NaN}` in LaTeX
- **JSON serialization**: `toJSON()` and `toJSONPretty()` methods on `MathExpression` in both the Rust FFI layer and the Swift wrapper; requires the `serde` feature
- **JSON AST schema**: `docs/json-ast-schema.md` documents the complete JSON representation of every AST node
- **NumericSwift integration example**: `examples/numericswift-integration/` demonstrates decoding the JSON AST into Swift `Decodable` types and evaluating expressions numerically
- **Swift integration tests**: 14 new XCTest cases covering JSON serialization round-trips
- **FFI test coverage**: expanded FFI test suite from 12 to 45 tests, covering all JSON serialization paths

### Fixed

- **Swift CI**: `serde` feature flag added to the Swift CI workflow and XCFramework build so JSON serialization is available in packaged builds

## [0.3.0] - 2026-04-06

### Added

- **Equation system parsing**: `parse_equation_system()` and `parse_latex_equation_system()` for parsing semicolon-delimited equations into `Vec<Expression>`
- **Function name aliases**: plain text parser recognizes `asin`/`acos`/`atan` as `arcsin`/`arccos`/`arctan`, `sign` as `sgn`, `log2` as `lg`
- **Additional functions**: `atan2`, `cbrt`, `round`, `pow` parse as named functions; added to known-functions list for typo suggestions
- **Tree traversal**: `Expression::map()` for bottom-up tree transformation
- **Tree reduction**: `Expression::fold()` for generic tree accumulation
- **Variable lookup**: `Expression::contains_variable()` with early-exit semantics
- **FFI**: equation system parsing wrappers for Swift bindings
- **Serde**: comprehensive round-trip tests for all Expression variants

### Documentation

- Added guidance for extending `Equation` with tracking IDs
- Added guidance for attaching variable metadata (dimensions, units)
- Updated utility module documentation to list all available methods

## [0.2.0] - 2026-04-03

### Added

- **Vector calculus**: gradient (`\nabla f`), divergence (`\nabla \cdot F`), curl (`\nabla \times F`), Laplacian (`\nabla^2 f`) in both AST and LaTeX parser
- **Vector notation**: bold (`\mathbf{v}`), arrow (`\vec{v}`), hat (`\hat{n}`), underline parsing; dot, cross, and outer product operators
- **Multiple integrals**: double (`\iint`), triple (`\iiint`), and quadruple (`\iiiint`) integrals with optional region bounds and multiple differential variables
- **Closed integrals**: line (`\oint`), surface (`\oiint`), and volume (`\oiiint`) integrals
- **Set theory**: union (`\cup`), intersection (`\cap`), difference (`\setminus`); membership (`\in`, `\notin`); subset/superset relations; empty set (`\emptyset`); power set (`\mathcal{P}`); number sets (`\mathbb{N}` through `\mathbb{H}`)
- **Quantifiers**: universal (`\forall`) and existential (`\exists`) with optional domains
- **Logical connectives**: `\land`, `\lor`, `\lnot`, `\implies`, `\iff` with correct precedence hierarchy
- **Quaternions**: `Expression::Quaternion` variant; basis vectors `J` and `K` in `MathConstant`; parsing via `\mathrm{j}`, `\mathrm{k}`, `\mathbf{j}`, `\mathbf{k}`
- **Tensor notation**: Einstein index notation (`T^{ij}_{kl}`), Kronecker delta (`\delta^i_j`), Levi-Civita symbol (`\varepsilon_{ijk}`)
- **Linear algebra operations**: `\det`, `\tr`, `\rank`, conjugate transpose (`A^\dagger`), matrix inverse (`A^{-1}`), transpose (`A^T`, `A^\top`)
- **Context-aware constants**: `e` and `i` are parsed as `MathConstant::E` and `MathConstant::I` by default in LaTeX, with scope-aware fallback to variables when bound in `\sum`/`\prod`; explicit markers via `\mathrm{e}`, `\mathrm{i}`, `\imath`, `\jmath`
- **NegInfinity folding**: `-\infty` (LaTeX) and `-inf`/`-∞` (plain text) parse directly as `Constant(NegInfinity)` instead of `Unary(Neg, Constant(Infinity))`
- **Expression subscripts**: `x_{i+1}`, `a_{n-1}` in LaTeX parser (flattened to variable names)
- **Plain text subscripts**: `x_1`, `x_i` in plain text parser
- **Plain text extensions**: vector operations (`dot`, `cross`), vector calculus (`grad`, `div`, `curl`, `laplacian`), quantifiers (`forall`, `exists`), set operations (`union`, `intersect`, `in`, `notin`), logical operators (`and`, `or`, `not`, `implies`, `iff`)
- **Expression context engine**: `ExpressionContext` for tracking variable types, binding scopes, and number systems across multiple expressions; `parse_system()` for multi-expression parsing
- **Expression metadata**: type inference foundation for expression analysis
- **Function signatures**: `f: A \to B` notation and relation parsing in LaTeX
- **Error suggestions**: helpful hints for common parse mistakes
- **Comprehensive benchmarks**: Criterion benchmarks for all parser features
- **Fuzz testing**: cargo-fuzz infrastructure for both text and LaTeX parsers
- **Property-based tests**: LaTeX parser property tests; serialization precedence tests
- **Integration tests**: vector calculus, set theory, and real-world expression test suites
- **Swift CI**: GitHub Actions workflow for Swift package testing

### Fixed

- **ToLatex precedence**: parentheses around unary prefix operators in power expressions and additive expressions in product operators, ensuring round-trip safety
- **Round-trip tests**: LaTeX round-trip tests now fail on unparsable output instead of printing warnings
- **Swift bindings**: generated bindings are copied into `Sources/MathLexRust`; simplified import structure
- **Tokenizer**: removed duplicate code from malformed merge

### Changed

- Removed unused `chumsky` dependency

## [0.1.1] - 2026-01-17

### Fixed

- Move DocC catalog into MathLex target for Swift Package Index compatibility
- Resolve clippy warnings and formatting issues in CI
- Add write permissions for release workflows

## [0.1.0] - 2026-01-17

### Added

- Initial release
- LaTeX parser: arithmetic, fractions, roots, trigonometric/logarithmic functions, derivatives, integrals, limits, sums, products, matrices, vectors
- Plain text parser: arithmetic, functions, implicit multiplication, configurable options
- AST with 19+ expression variants covering algebra, calculus, and linear algebra
- `Display` trait for human-readable output
- `ToLatex` trait for LaTeX serialization
- AST utilities: `find_variables`, `find_functions`, `find_constants`, `depth`, `node_count`, `substitute`, `substitute_all`
- Optional `serde` feature for AST serialization
- Swift bindings via `swift-bridge` (behind `ffi` feature flag)
- XCFramework build script for iOS/macOS distribution
- GitHub Actions CI/CD with release automation
- Comprehensive unit test suite (700+ tests)

[Unreleased]: https://github.com/ChrisGVE/mathlex/compare/v0.4.1...HEAD
[0.4.1]: https://github.com/ChrisGVE/mathlex/compare/v0.4.0...v0.4.1
[0.4.0]: https://github.com/ChrisGVE/mathlex/compare/v0.3.4...v0.4.0
[0.3.4]: https://github.com/ChrisGVE/mathlex/compare/v0.3.3...v0.3.4
[0.3.3]: https://github.com/ChrisGVE/mathlex/compare/v0.3.2...v0.3.3
[0.3.2]: https://github.com/ChrisGVE/mathlex/compare/v0.3.1...v0.3.2
[0.3.1]: https://github.com/ChrisGVE/mathlex/compare/v0.3.0...v0.3.1
[0.3.0]: https://github.com/ChrisGVE/mathlex/compare/v0.2.0...v0.3.0
[0.2.0]: https://github.com/ChrisGVE/mathlex/compare/v0.1.1...v0.2.0
[0.1.1]: https://github.com/ChrisGVE/mathlex/compare/v0.1.0...v0.1.1
[0.1.0]: https://github.com/ChrisGVE/mathlex/releases/tag/v0.1.0