[{"data":1,"prerenderedAt":4},["ShallowReactive",2],{"awUWPlgd84":3},"\u003Ch1 align=\"center\">Eig3x3\u003C/h1>\n\n\u003Cp align=\"center\">\n  \u003Ca href=\"https://opensource.org/licenses/Apache-2.0\">\u003Cimg src=\"https://img.shields.io/badge/license-Apache%202.0-blue.svg\" alt=\"Licence - Apache 2.0\">\u003C/a>\n  \u003Ca href=\"https://israelflores8789.github.io/eig3x3-lean\">\u003Cimg src=\"https://img.shields.io/badge/docs-Lean%20v4.34.0--rc2-blue.svg\">\u003C/a>\n  \u003Ca href=\"https://github.com/israelflores8789/eig3x3-lean/releases\">\u003Cimg src=\"https://img.shields.io/github/v/release/israelflores8789/eig3x3-lean\" alt=\"Latest Release\">\u003C/a>\n  \u003C!-- \u003Ca href=\"https://reservoir.lean-lang.org/@israelflores8789/Eig3x3\">\u003Cimg src=\"https://reservoir.lean-lang.org/badge/@israelflores8789/Eig3x3.svg\" alt=\"Reservoir\">\u003C/a> -->\n  \u003Ca href =\"https://github.com/israelflores8789/eig3x3-lean/actions\">\u003Cimg src=\"https://github.com/israelflores8789/eig3x3-lean/actions/workflows/ci.yml/badge.svg\" alt=\"Build Status\">\u003C/a>\n\u003C/p>\n\nA high-performance, pure **Lean 4** library for the closed-form eigendecomposition of $3 \\times 3$ real symmetric matrices over IEEE 754 64-bit floating point (`Float`).\n\n**Eig3x3** delivers machine-precision eigenvalues and eigenvectors without external C/FFI bindings and Mathlib dependencies.\n\n## Table of Contents\n\n- [Overview & Highlights](#overview--highlights)\n- [Motivation](#motivation)\n- [Installation](#installation)\n  - [Supported Toolchains & Downstream Compatibility](#supported-toolchains--downstream-compatibility)\n- [Quick Start](#quick-start)\n- [Matrix Algebra Notation & Operators](#matrix-algebra-notation--operators)\n- [Accuracy & Numerical Stability](#accuracy--numerical-stability)\n- [Performance Benchmarks](#performance-benchmarks)\n- [Core Architecture & Numerical Methods](#core-architecture--numerical-methods)\n- [Runtime Certificates](#runtime-certificates)\n- [Verification & Testing](#verification--testing)\n  - [Lean Test Suite](#lean-test-suite)\n  - [Python Parity & Differential Suite](#python-parity--differential-suite)\n- [Citation](#citation)\n- [Credits](#credits)\n\n## Overview & Highlights\n\n- **Pure Lean 4 / Zero Dependencies**: No C/FFI toolchain dependencies, no Mathlib dependency. Fully self-contained and ready as a drop-in Lake package.\n- **Numerically Stabilized Closed-Form**: Combines the invariant-based eigenvalue algorithm of **Habera & Zilian (2025)** with the robust null-space eigenvector construction of **Eberly (2014)**.\n- **Deterministic Sub-Microsecond Speed**: Closed-form computation eliminates loop branches and iterative convergence checks, achieving $\\sim 0.35\\,\\mu\\text{s}$ per decomposition ($\\sim 2.8\\times 10^6$ matrices/sec).\n- **Bit-Transparent Preconditioning**: Employs `Float.frExp` power-of-two scaling to guard against underflow/overflow over 600 orders of magnitude ($10^{-300}$ to $10^{300}$) with zero mantissa rounding distortion.\n- **Runtime Error Certificates**: Built-in verification module (`certify`) computing per-instance residual, orthonormality, and reconstruction errors.\n- **Mathlib-Consistent Operator Layer**: Opt-in Unicode notation for floating-point vector (`Vec3`) and matrix (`Mat3`) operations (`open scoped Eig3x3`) providing `Qᵀ`, `M⁻¹`, `u ⬝ᵥ v`, `A ⬝ₘ B`, `u ⊗ᵥ v`, `u ⨯₃ v`, `s • v`, `u ⊙ v`, `‖v‖`, `|x|`, and fast natural powers `x ^ⁿ n`.\n\n## Motivation\n\nI was using Lean to both prove properties of a custom density model I wrote and compute parity figures to validate implementations of that density model in other applications (e.g. my Python-based Jupyter notebook research). The inspiration for this came from [Amazon's own use of Lean](https://aws.amazon.com/blogs/opensource/lean-into-verified-software-development/) as their parity source-of-truth for their Cedar DSL written in Rust. Fitting my model requires Newton's method, and I needed a floating-point eigensolver for ill-conditioned Hessian management on the parity part of my Lean work. The research I found while solving this problem for myself was exciting, and I chose to make it open-source when I saw how useful it could be for others in the Lean community.\n\nEigendecomposition of $3 \\times 3$ symmetric matrices is a core operation across scientific computing, geometric processing, robotics, physics, and more. Classical closed-form solutions, like Cardano/Viète, suffer catastrophic floating-point cancellation near degenerate eigenvalues. Standard workflows typically bind via FFI to more numerically robust but iterative LAPACK routines (e.g., `dsyev`). For anything $n \\le 5$, iterative routines such as LAPACK can be inefficient and suffer their own consequences, such as:\n1. Imposing external C build dependencies and FFI overhead.\n2. Suffering variable execution times dependent on convergence criteria.\n3. Complicating deployment across pure-Lean environments, embedded contexts, and web/Wasm targets.\n\n**Eig3x3** combines recent 2025 advancements eigenvalue computation from [Michal Habera and Andreas Zilian](https://doi.org/10.48550/arXiv.2511.00292) at the University of Luxembourg with David Eberly's industry standard [Geometric Tools](https://www.geometrictools.com/Documentation/RobustEigenSymmetric3x3.pdf) algorithms for eigenvectors as a numerically stable closed-form solver to the Lean 4 ecosystem, providing a lightweight, robust and pure Lean solution for the scientific computing community.\n\n## Installation\n\n### Using Lean Reservoir / `lakefile.toml` (Recommended)\n\nAdd `Eig3x3` to your project's `lakefile.toml`:\n\n```toml\n[[require]]\nname = \"Eig3x3\"\nscope = \"israelflores8789\"\nversion = \">= 1.0.0\"\n```\n\n*Alternatively, require directly from Git:*\n\n```toml\n[[require]]\nname = \"Eig3x3\"\ngit = \"https://github.com/israelflores8789/eig3x3-lean\"\nrev = \"v1.0.0\"\n```\n\n### Using `lakefile.lean`\n\n```lean\nrequire «Eig3x3» from \"israelflores8789\" / \"eig3x3-lean\"\n-- or from git:\nrequire «Eig3x3» from git\n  \"https://github.com/israelflores8789/eig3x3-lean\" @ \"v1.0.0\"\n```\n\nThen run `lake update` and `lake build`.\n\n### Supported Toolchains & Downstream Compatibility\n\n> [!NOTE]\n> When `Eig3x3` is consumed as a Lake dependency in your project, its internal `lean-toolchain` file is **ignored** by Lake — your root project's toolchain governs the entire workspace. The **minimum supported toolchain** is `v4.27.0`.\n\n`Eig3x3` has significant backwards compatibility and is built and continuously tested across the following active stable and candidate Lean 4 releases:\n- `v4.27.0`\n- `v4.30.0`\n- `v4.34.0-rc2`\n\n## Quick Start\n\n```lean\nimport Eig3x3\n\nopen scoped Eig3x3\n\ndef main : IO Unit := do\n  -- 1. Define a symmetric 3×3 matrix via its 6 unique entries:\n  --    [[2.0, 1.0, 0.0],\n  --     [1.0, 2.0, 1.0],\n  --     [0.0, 1.0, 2.0]]\n  let A : Eig3x3.SymmMat3 := ⟨2.0, 2.0, 2.0, 1.0, 0.0, 1.0⟩\n\n  -- 2. Compute the full eigendecomposition: A = Q Λ Qᵀ\n  let decomp := Eig3x3.eigendecomp A\n  let e := decomp.eigvals  -- Ordered: l₀ ≤ l₁ ≤ l₂\n  let Q := decomp.eigvecs  -- Right-handed orthonormal matrix (det Q = 1)\n\n  IO.println s!\"Eigenvalues: [{e.l₀}, {e.l₁}, {e.l₂}]\"\n  -- Expected: [0.5857864376269049, 2.0, 3.414213562373095]\n\n  -- 3. Verify numerical quality with runtime certificates:\n  let certs := Eig3x3.certify A decomp\n  IO.println s!\"Max Residual ‖Av - λv‖∞: {certs.maxResidual}\"\n  IO.println s!\"Orthogonality Error:     {certs.orthogonality}\"\n  IO.println s!\"Reconstruction Error:    {certs.reconstruction}\"\n  -- Errors are typically ≈ 1e-16 to 1e-15\n\n  -- 4. Convenient vector & matrix arithmetic:\n  let v : Eig3x3.Vec3 := ⟨1.0, 0.0, 0.0⟩\n  let transformed := Q * v\n  let norm := ‖transformed‖\n  IO.println s!\"Transformed vector norm: {norm}\"\n```\n\n## Matrix Algebra Notation & Operators\n\n`import Eig3x3` includes a complete, standalone 3D linear algebra toolkit with `Float`-type structures `Vec3` and `Mat3` for a 3-element vector and 3-column matrix, respectively, without Mathlib dependencies. Eigenvalues are returned as an ordered `Eigval3` structure which coerces to `Vec3` for vector algebra, and eigenvectors are returned as a `Mat3` structure. Activating `open scoped Eig3x3` enables the following mathematical notations with Mathlib conventions:\n\n| Notation | Operation | Lean Declaration | Precedence / Associativity |\n| :--- | :--- | :--- | :--- |\n| `u + v` / `A + B` | Addition | `HAdd.hAdd` | `infixl:65` |\n| `u - v` / `A - B` | Subtraction | `HSub.hSub` | `infixl:65` |\n| `-v` / `-A` | Negation | `Neg.neg` | Prefix |\n| `A * B` | Matrix product | `HMul.hMul` | `infixl:70` |\n| `A * v` | Matrix-vector product | `HMul.hMul` | `infixl:70` |\n| `v * A` | Row-vector matrix product ($v^T A$) | `HMul.hMul` | `infixl:70` |\n| `v / s` / `A / s` | Scalar division | `HDiv.hDiv` | `infixl:70` |\n| `u ⊗ᵥ v` | Vector outer product ($u v^T$) | `Vec3.outer` | `infixl:70` |\n| `u ⬝ᵥ v` | Vector dot product | `Vec3.dot` | `infixl:72` |\n| `A ⬝ₘ B` | Matrix Frobenius inner product | `Mat3.dot` | `infixl:72` |\n| `s • v` / `s • A` | Scalar multiplication | `HSMul.hSMul` | `infixr:73` |\n| `u ⨯₃ v` | Vector cross product ($\\mathbb{R}^3$) | `Vec3.cross` | `infixl:74` |\n| `x ^ⁿ n` / `A ^ⁿ n`| Fast natural power (repeated mul / squaring) | `PowNat.powNat`| `infixr:80` |\n| `u ⊙ v` / `A ⊙ B` | Hadamard (entrywise) product | `Hadamard.hadamard`| `infixl:100` |\n| `\\|x\\|` / `\\|v\\|` / `\\|A\\|` | Absolute value / entrywise magnitude | `Abs.abs` | Delimited (`\\|v\\|`) |\n| `‖v‖` / `‖A‖` | Euclidean (vector) / Frobenius (matrix) norm | `Norm.norm` | Delimited (`‖v‖`) |\n| `‖v‖²` / `‖A‖²` | Squared norm | `NormSq.normSq` | Delimited (`‖v‖²`) |\n| `Aᵀ` | Matrix transpose | `Mat3.transpose` | `postfix:max` |\n| `A⁻¹` | Matrix inverse (via cofactors) | `Inv.inv` | `postfix:max` |\n\n\n## Accuracy & Numerical Stability\n\nMax residual error ($\\|Av - \\lambda v\\|_\\infty / \\|A\\|_\\infty$) across characteristic problem regimes in double precision (`Float` / `float64`):\n\n| Test Regime | Naive Cardano / Viète | NumPy / LAPACK (`dsyev`) | `Eig3x3` (Lean 4) | Status / Notes |\n| :--- | :---: | :---: | :---: | :--- |\n| **Uniform Random** ($A_{ij} \\in [-1, 1]$) | $\\sim 10^{-15}$ | $\\sim 10^{-16}$ | $\\mathbf{\\sim 10^{-16}}$ | Machine precision across all solvers |\n| **Near-Double Eigenvalues** ($\\delta = 10^{-8}$) | $\\approx 3.6 \\times 10^{-9}$ | $\\approx 2.2 \\times 10^{-16}$ | $\\mathbf{\\approx 2.2 \\times 10^{-16}}$ | Naive loses ~8 digits; Eig3x3 matches LAPACK |\n| **Near-Triple Eigenvalues** ($\\delta = 10^{-8}$) | $\\approx 1.5 \\times 10^{-8}$ | $\\approx 2.2 \\times 10^{-16}$ | $\\mathbf{\\approx 2.2 \\times 10^{-16}}$ | $J_2 \\to 0$ stabilized via diagonal differences |\n| **Scaled Identity** ($cI$) | $\\sim 10^{-15}$ | $0.0$ | $\\mathbf{0.0}$ | Exact zero fast path ($J_2 = 0$) |\n| **Dynamic Range** ($10^{-300}$ to $10^{300}$) | Overflow / Underflow | Fails / Subnormal | $\\mathbf{\\sim 10^{-16}}$ | Bit-transparent `Float.frExp` scaling |\n\n## Performance Benchmarks\n\nBenchmarks measured on $n = 20{,}000$ random symmetric matrices comparing in-process Lean 4 native execution against optimized NumPy/LAPACK (`dgeev`/`dsyev`):\n\n| Implementation / Workload | Latency (µs / matrix) | Throughput (matrices / sec) | Speedup vs. Single LAPACK |\n| :--- | :---: | :---: | :---: |\n| **`Eig3x3` (Lean in-process)** | **0.35 µs** | **~2,850,000 / s** | **~35× faster** |\n| **`Eig3x3` + `certify` (Lean in-process)** | **0.44 µs** | **~2,270,000 / s** | **~28× faster** |\n| `numpy.linalg.eigh` (single-matrix loop) | 12.90 µs | ~77,500 / s | 1.0× (baseline) |\n| `numpy.linalg.eigh` (vectorized batch) | 1.55 µs | ~645,000 / s | ~8.3× faster |\n| `Eig3x3` CLI (end-to-end JSON IPC) | 6.22 µs | ~160,000 / s | ~2.1× faster |\n\n## Core Architecture & Numerical Methods\n\nThe calculation of eigenvectors is fundamentally a null-space computation of $(A - \\lambda I)$ that directly consumes the computed eigenvalues $\\lambda$. Consequently, eigenvalue accuracy dictates the stability of the entire pipeline.\n\n```\n                  ┌─────────────────────────────────────────┐\n                  │          Input SymmMat3 (A)             │\n                  └────────────────────┬────────────────────┘\n                                       │\n                         [Float.frExp Preconditioning]\n                                       │\n                  ┌────────────────────▼────────────────────┐\n                  │    1. Habera–Zilian (2025) Pipeline     │\n                  │   - Trace recentering (I₁)              │\n                  │   - Deviatoric invariants (J₂, J₃)      │\n                  │   - Sum-of-squares discriminant (Δ)     │\n                  │   - Quadrant-safe atan2 angle (φ)       │\n                  │   - 3-element permutation sort guard    │\n                  └────────────────────┬────────────────────┘\n                                       │ Ordered Eigenvalues (l₀ ≤ l₁ ≤ l₂)\n                  ┌────────────────────▼────────────────────┐\n                  │    2. Eberly (2014) Eigenvector Engine  │\n                  │   - Spectral gap comparison             │\n                  │   - Cross-product null-space (isolated) │\n                  │   - 2×2 planar orthogonal complement    │\n                  │   - Right-handed completion (c₁ ⨯₃ c₂)  │\n                  └────────────────────┬────────────────────┘\n                                       │\n                            [Power-of-2 Rescaling]\n                                       │\n                  ┌────────────────────▼────────────────────┐\n                  │    Decomposition { eigvals, eigvecs }   │\n                  │      + Optional Runtime Certify         │\n                  └─────────────────────────────────────────┘\n```\n\n### Key Algorithmic Improvements & Fixes\n\n1. **Sum-of-Squares Discriminant ($\\Delta$)**: Uses Habera–Zilian Algorithm 8 sum-of-squares formulation ($\\Delta = 4J_2^3 - 27J_3^2$) rather than subtractive cubics, preventing catastrophic cancellation when eigenvalues are close. Includes the verified $r_{10}$ correction (`+ q·r·d₂`).\n2. **Quadrant-Safe $\\text{atan2}$ Angle Formulation**: Replaces the classical $\\arccos$ formulation with $\\varphi = \\text{atan2}(\\sqrt{27\\Delta}, 27J_3)$, maintaining forward stability across the full domain.\n3. **Ordering Contract Guard**: While Habera–Zilian guarantees $\\lambda_0 \\le \\lambda_1 \\le \\lambda_2$ in exact arithmetic, floating-point evaluation of transcendental $\\cos$ at degenerate angles can vary by $\\sim 1\\text{ ULP}$. A final 3-element compare-exchange sort enforces the strict ordering contract.\n4. **Spectral Gap Isolation**: Compares $(\\lambda_1 - \\lambda_0)$ vs $(\\lambda_2 - \\lambda_1)$ to construct the isolated eigenvector first from the longest row cross-product, completing the remaining eigenvectors via 2D planar reduction and cross product.\n\n## Runtime Certificates\n\nBecause mathematical proofs over IEEE 754 `Float` are inherently empirical without interval arithmetic, `Eig3x3.certify` provides runtime numerical validation:\n\n```lean\nlet certs := Eig3x3.certify A decomp\n```\n\n- **`maxResidual`**: $\\max_i \\|A v_i - \\lambda_i v_i\\|_\\infty$ (checks eigenpair validity).\n- **`orthogonality`**: $\\max_{i,j} |c_i \\cdot c_j - \\delta_{ij}|$ (checks orthonormality of $Q$).\n- **`reconstruction`**: $\\max_{i,j} |(Q \\Lambda Q^T)_{ij} - A_{ij}|$ (checks spectral synthesis).\n\n### Scale-Aware Quality Standard\n\nAll decompositions satisfy strict machine-epsilon gates ($\\varepsilon = 2^{-52} \\approx 2.22 \\times 10^{-16}$):\n- $\\text{Residual} \\le 64\\varepsilon \\cdot \\max_{ij} |A_{ij}|$\n- $\\text{Reconstruction} \\le 64\\varepsilon \\cdot \\max_{ij} |A_{ij}|$\n- $\\text{Orthogonality} \\le 16\\varepsilon$ (dimensionless)\n\n## Verification & Testing\n\nCloning the repository offers various tests that validate the eigensolver's computation. This repo uses [`just`](https://github.com/casey/just) as the command runner.\n\n### Lean Test Suite\n\nRun the full native Lean verification suite with `just test` or `lake test`:\n\n```bash\njust test\n# or\nlake test\n```\n\nThe Lean test harness executes:\n- **`KnownAnswer`**: Exact-arithmetic validation for vectors, matrices, operators, and special matrices (zero matrix, scaled identity, textbook cases).\n- **`Golden`**: Bit-exact verification against 50-digit `mpmath` reference vectors (loaded via dyadic pairs $[sig, exp]$ to prevent decimal parser rounding).\n- **`Properties`**: 5,000 deterministic pseudo-random matrices (via splitmix64 PRNG) testing trace invariants, determinant identities, right-handedness ($\\det Q = 1$), and scale invariance.\n- **`Regression`**: Pinned historical boundary cases including the Habera–Zilian $r_{10}$ discriminant check and clustered perturbation paths.\n- **`Certificates`**: Runtime error assertions on the curated case zoo under the $64\\varepsilon / 16\\varepsilon$ standard.\n\n### Python Parity & Differential Suite\n\nA comprehensive differential test harness validates the Lean CLI binary against NumPy/LAPACK and 50-digit `mpmath` references.\n\n```bash\n# Run the full parity suite (default n=1000, seed=42)\njust parity\n\n# Run in parallel across all CPU cores (pytest-xdist) (useful for large n)\njust parity-parallel\n\n# Run granular sub-suites\njust parity zoo          # 7 curated edge cases\njust parity random       # Uniform random symmetric matrices A_ij ∈ [-1, 1]\njust parity logscale     # Matrices spanning 600 orders of magnitude (10^-300 to 10^300)\njust parity paths        # Adversarial perturbation paths (diag(-1,1,1+δ), diag(1,1,1+δ))\njust parity smallscale   # Vanishing scale double eigenvalues (s, s, 2s)\njust parity frontier     # Extreme dynamic range cases (2^±997)\njust parity golden       # 50-digit mpmath golden cases\n\n# Generate CI JUnit XML report\njust parity-ci\n```\n\n## Citation\n\nIf you use `Eig3x3` in your academic research or software project, please include the [`NOTICE.md`](https://github.com/israelflores8789/eig3x3-lean/blob/main/NOTICE.md) and cite:\n\n```bibtex\n@software{FloresArbolay_Eig3x3_2026,\n  author       = {Israel D. Flores-Arbolay},\n  title        = {Eig3x3: Pure Lean 4 Closed-Form 3x3 Symmetric Eigensolver},\n  year         = {2026},\n  publisher    = {GitHub},\n  url          = {https://github.com/israelflores8789/eig3x3-lean},\n  license      = {Apache-2.0}\n}\n```\n\n## Credits\n\n**This library is an implementation of the algorithms defined in the following scholarly articles and publishings:**\n\nDavid H. Eberly, \"A Robust Eigensolver for 3x3 Symmetric Matrices,\" Geometric Tools,\nLLC, 2014. \u003Chttps://www.geometrictools.com/Documentation/RobustEigenSymmetric3x3.pdf>\n\nMichal Habera and Andreas Zilian, \"Numerically stable evaluation of closed-form\nexpressions for eigenvalues of 3×3 matrices,\" arXiv:2511.00292 [math.NA], 2025.\n\u003Chttps://doi.org/10.48550/arXiv.2511.00292>\n\nMichal Habera and Andreas Zilian, \"Symbolic spectral decomposition of 3x3 matrices,\"\narXiv:2111.02117 [math.NA], 2021. \u003Chttps://doi.org/10.48550/arXiv.2111.02117>\n\n**While not referenced directly, each author maintains C implementations of their work which can be found on their GitHub here:**\n\nDavid Eberly's C implementation of their 2014 paper at Geometric Tools: [`davideberly/GeometricTools`](https://github.com/davideberly/GeometricTools)\n\nMichal Habera and Andreas Zilian's C implementation of their 2025 paper: [`michalhabera/eig3x3`](https://github.com/michalhabera/eig3x3)\n\n**Please give them your support!**\n",1791085040525]