Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
/cobertura.xml
.DS_Store

# Generated benchmark results (machine-specific)
docs/PERFORMANCE.md

# Python / uv
**/__pycache__/
*.egg-info/
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Move error and tolerance contracts into first-class modules with prelude exports
- Update exact benchmarks to distinguish strict Result paths from rounded f64 paths
- Document and exercise the rounded fallback pattern for RequiresRounding errors
- [**breaking**] Make exact f64 conversions strict [`89f3720`](https://github.com/acgetchell/la-stack/commit/89f3720ecde9f12d7a0f42e79394836615e8fd97)
- Make Matrix and Vector the finite-by-construction public types for exact arithmetic.
- Add rounded exact-to-f64 APIs for determinant and solve callers that want explicit lossy conversion.
- Return typed Unrepresentable reasons when strict exact-to-f64 conversion would round or become non-finite.
- Specialize D4 exact determinants and keep determinant/error-bound zero coefficients from evaluating overflowing absent terms.
- Update exact benchmark comparison reporting to compare strict and rounded APIs against legacy v0.4.2 rows.

### Changed

Expand Down Expand Up @@ -72,6 +78,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
Use a literal regex pattern for the malformed Criterion JSON diagnostic so
Windows paths with backslashes do not break pytest's match expression.
- Align ty with Python 3.13 [`b9e0ba0`](https://github.com/acgetchell/la-stack/commit/b9e0ba08e54a15d8eddd5c5c53edc37bbc03939a)
- Preserve coordinates for overflowed accumulators [`1d976b3`](https://github.com/acgetchell/la-stack/commit/1d976b346172ad4eca37c68a3ec31817eeca8529)

- Return matrix-cell metadata when inf-norm row sums or symmetry tolerance scaling overflow.
- Avoid reparsing finite-by-construction RHS vectors in LU and LDLT solves.

## [0.4.2] - 2026-06-04

Expand Down
14 changes: 14 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@ to an explicit allowlist, and kept with readable version comments for review.
CI runs `just ci` on Ubuntu, macOS, and Windows to keep platform coverage
aligned with the local comprehensive validation path.

## Performance checks

Performance-sensitive changes should compare the current tree against the
latest published release:

```bash
just performance-local
```

This writes `target/bench-reports/performance.md` without changing committed
release docs. Regressions are worth treating as design feedback: if a slowdown
is intentional, document the correctness, API clarity, or composability benefit
that justifies it.

For coverage commands and report locations, see [`docs/COVERAGE.md`](docs/COVERAGE.md).
For benchmark methodology, see [`docs/BENCHMARKING.md`](docs/BENCHMARKING.md).
For the full set of developer commands, run `just --list`.
Expand Down
66 changes: 40 additions & 26 deletions docs/BENCHMARKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,40 +151,28 @@ benchmarks on every iteration.
### Workflow

```bash
# 1. Check out the old release and save its full baseline
git checkout v0.2.0
just bench-save-baseline v0.2.0
# Current in-tree code vs latest published release, all measured locally
just performance-local

# 2. Switch to current code and run latest la-stack measurements
git checkout main # or your feature branch
just bench-latest # populates target/criterion/*/new/

# 3. Generate a local comparison report
just bench-compare v0.2.0
# Stored GitHub Actions release assets, no local cargo runs
just performance-github-assets
```

You can save multiple baselines and compare against any of them.
`performance-local` creates isolated temporary worktrees, generates the latest
published release baseline locally, then benchmarks the current in-tree code on
the same machine. It uses the current checkout's Rust toolchain for both sides
unless `RUSTUP_TOOLCHAIN` is already set. `performance-github-assets` compares
stored GitHub Actions release artifacts and does not run cargo locally.

If the release baseline is already present in `target/criterion/`, skip the
checkout step and compare directly. For example, to compare current code against
the saved `v0.4.2` release baseline:
For local scratch comparisons, you can save multiple baselines and compare
against any of them. If the release baseline is already present in
`target/criterion/`, compare directly:

```bash
just bench-latest # gather latest la-stack measurements
just bench-compare v0.4.2 # compare latest measurements against v0.4.2
```

If the release baseline is not present locally, download and restore the release
asset first:

```bash
gh release download v0.4.2 --pattern "la-stack-v0.4.2-criterion-baseline.tar.gz" # fetch archived release baseline
mkdir -p target # ensure Criterion parent directory exists
tar -C target -xzf la-stack-v0.4.2-criterion-baseline.tar.gz # restore target/criterion baseline data
just bench-latest # gather latest la-stack measurements
just bench-compare v0.4.2 # compare latest measurements against v0.4.2
```

### Output

`just bench-compare` writes `target/bench-reports/performance.md` by
Expand All @@ -193,6 +181,31 @@ local. The report includes per-dimension tables showing median times,
percent change, speedup, and last-release nalgebra/faer context where a
matching `vs_linalg` peer exists.

Release PRs promote one curated comparison into committed docs:

```bash
just performance-release
```

This infers the current release tag from `Cargo.toml`, discovers the previous
stable published release, generates both sides locally in temporary worktrees,
copies the finished report to `docs/PERFORMANCE.md`, and archives the previous
committed report under `docs/archive/performance/`. Archive filenames are
release-pair names such as `v0.4.2-vs-v0.4.1.md`, so the directory and generated
index stay lexicographically sorted. For explicit release repair, pass both
tags: `just performance-release v0.4.3 v0.4.2`.

To compare the latest stored GitHub Actions release assets without touching the
current checkout:

```bash
just performance-github-assets
```

The recipe discovers the latest stable published GitHub release and its previous
stable release automatically. For explicit historical repair, pass both tags:
`just performance-github-assets v0.4.2 v0.4.1`.

For exact-arithmetic comparisons against v0.4.2 or older baselines, rows such
as `det_exact_rounded_f64 (vs det_exact_f64)` mean the current rounded API is
being compared to the historical lossy `*_exact_f64` benchmark. Rows such as
Expand Down Expand Up @@ -234,11 +247,12 @@ See `scripts/criterion_dim_plot.py --help` for options.
At release time, save a local baseline so future work can compare against it:

```bash
just bench-save-baseline $TAG
just bench-save-baseline <tag>
just bench-save-last
```

When the GitHub Release is published, `.github/workflows/release-benchmarks.yml`
saves a full release baseline and attaches
`la-stack-$TAG-criterion-baseline.tar.gz` to the release as the durable archive.
See `docs/RELEASING.md` step 5 for where this fits in the release process.
See the `just performance-release` step in `docs/RELEASING.md` for where the
curated `docs/PERFORMANCE.md` comparison fits in the release process.
117 changes: 117 additions & 0 deletions docs/PERFORMANCE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Exact Arithmetic Performance

**la-stack** v0.4.2 · `7e11f93` (HEAD) · 2026-06-08 20:39:03 UTC
**Statistic**: median

## Benchmark Results

Comparison against baseline **v0.4.1**:

Negative change = faster. Speedup > 1.00x = improvement.

### D=2

| Benchmark | v0.4.1 | Current | Change | Speedup |
|-----------|-------:|--------:|-------:|--------:|
| det | 0.6 ns | 0.9 ns | +61.1% | 0.62x |
| det_direct | 0.7 ns | 1.0 ns | +44.7% | 0.69x |
| det_exact | 315.5 ns | 318.4 ns | +0.9% | 0.99x |
| det_exact_f64 | 555.7 ns | 555.7 ns | -0.0% | 1.00x |
| det_sign_exact | 0.7 ns | 1.5 ns | +128.2% | 0.44x |
| solve_exact | 7.05 µs | 7.06 µs | +0.2% | 1.00x |
| solve_exact_f64 | 7.50 µs | 7.67 µs | +2.3% | 0.98x |

### D=3

| Benchmark | v0.4.1 | Current | Change | Speedup |
|-----------|-------:|--------:|-------:|--------:|
| det | 1.3 ns | 1.8 ns | +36.3% | 0.73x |
| det_direct | 4.7 ns | 2.2 ns | **-51.9%** | 2.08x |
| det_exact | 936.9 ns | 924.3 ns | **-1.3%** | 1.01x |
| det_exact_f64 | 1.18 µs | 1.19 µs | +1.1% | 0.99x |
| det_sign_exact | 2.4 ns | 4.2 ns | +78.1% | 0.56x |
| solve_exact | 27.02 µs | 27.41 µs | +1.5% | 0.99x |
| solve_exact_f64 | 28.06 µs | 27.98 µs | -0.3% | 1.00x |

### D=4

| Benchmark | v0.4.1 | Current | Change | Speedup |
|-----------|-------:|--------:|-------:|--------:|
| det | 2.4 ns | 3.3 ns | +36.8% | 0.73x |
| det_direct | 2.4 ns | 4.1 ns | +70.2% | 0.59x |
| det_exact | 2.33 µs | 2.33 µs | -0.0% | 1.00x |
| det_exact_f64 | 2.59 µs | 2.58 µs | -0.7% | 1.01x |
| det_sign_exact | 5.3 ns | 6.9 ns | +30.5% | 0.77x |
| solve_exact | 67.14 µs | 67.99 µs | +1.3% | 0.99x |
| solve_exact_f64 | 67.86 µs | 68.51 µs | +1.0% | 0.99x |

### D=5

| Benchmark | v0.4.1 | Current | Change | Speedup |
|-----------|-------:|--------:|-------:|--------:|
| det | 21.6 ns | 24.5 ns | +13.7% | 0.88x |
| det_direct | 2.3 ns | 4.7 ns | +104.8% | 0.49x |
| det_exact | 5.04 µs | 4.99 µs | -1.0% | 1.01x |
| det_exact_f64 | 5.32 µs | 5.31 µs | -0.1% | 1.00x |
| det_sign_exact | 4.97 µs | 4.99 µs | +0.3% | 1.00x |
| solve_exact | 134.99 µs | 136.04 µs | +0.8% | 0.99x |
| solve_exact_f64 | 137.11 µs | 138.97 µs | +1.4% | 0.99x |

### Near-singular 3x3

| Benchmark | v0.4.1 | Current | Change | Speedup |
|-----------|-------:|--------:|-------:|--------:|
| det_sign_exact | 871.8 ns | 877.6 ns | +0.7% | 0.99x |
| det_exact | 907.3 ns | 904.4 ns | -0.3% | 1.00x |
| solve_exact | 4.31 µs | 4.25 µs | **-1.5%** | 1.02x |
| solve_exact_f64 | 4.29 µs | 4.32 µs | +0.7% | 0.99x |

### Large entries 3x3

| Benchmark | v0.4.1 | Current | Change | Speedup |
|-----------|-------:|--------:|-------:|--------:|
| det_sign_exact | 3.14 µs | 3.09 µs | **-1.3%** | 1.01x |
| det_exact | 3.19 µs | 3.11 µs | **-2.3%** | 1.02x |
| solve_exact | 84.77 µs | 83.89 µs | **-1.0%** | 1.01x |
| solve_exact_f64 | 84.62 µs | 83.92 µs | -0.8% | 1.01x |

### Hilbert 4x4

| Benchmark | v0.4.1 | Current | Change | Speedup |
|-----------|-------:|--------:|-------:|--------:|
| det_sign_exact | 5.3 ns | 6.9 ns | +30.4% | 0.77x |
| det_exact | 2.39 µs | 2.31 µs | **-3.2%** | 1.03x |
| solve_exact | 51.69 µs | 52.27 µs | +1.1% | 0.99x |
| solve_exact_f64 | 52.90 µs | 53.26 µs | +0.7% | 0.99x |

### Hilbert 5x5

| Benchmark | v0.4.1 | Current | Change | Speedup |
|-----------|-------:|--------:|-------:|--------:|
| det_sign_exact | 5.03 µs | 4.88 µs | **-2.9%** | 1.03x |
| det_exact | 5.07 µs | 4.96 µs | **-2.1%** | 1.02x |
| solve_exact | 105.35 µs | 102.72 µs | **-2.5%** | 1.03x |
| solve_exact_f64 | 104.99 µs | 103.94 µs | -1.0% | 1.01x |

## How to Update

Local performance reports are generated in isolated temporary worktrees:

```bash
# Local development: compare the current tree with the latest release
just performance-local

# Release PR: update docs/PERFORMANCE.md and archive the previous report
just performance-release

# GitHub Actions release assets
just performance-github-assets

# Explicit repair
just performance-release <current-tag> <previous-tag>
```

`just performance-local` writes `target/bench-reports/performance.md`.
`just performance-github-assets` writes `target/bench-reports/github-assets-performance.md`.

See `docs/BENCHMARKING.md` for the full comparison workflow.
28 changes: 23 additions & 5 deletions docs/RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Set these variables to avoid repeating the version string:
# tag has the leading v, version does not
TAG=vX.Y.Z
VERSION=${TAG#v}
PREVIOUS_TAG=vA.B.C
```

Verify your git remotes:
Expand Down Expand Up @@ -100,7 +101,24 @@ just plot-vs-linalg-readme
Review the updated table in `README.md` and the plot in `docs/assets/` for
accuracy.

5. Save benchmark baselines for this release
5. Update the release performance comparison

```bash
# Infers TAG from Cargo.toml, compares it against the previous stable published
# release, writes docs/PERFORMANCE.md, and archives the previous docs/PERFORMANCE.md
# under docs/archive/performance/.
just performance-release
```

Review `docs/PERFORMANCE.md` for the latest release-to-release comparison. Older
committed comparisons are archived under `docs/archive/performance/` with
lexicographically sorted filenames such as `v0.4.2-vs-v0.4.1.md`. Iterative
local reports still live under `target/bench-reports/`. For an explicit release
repair, run `just performance-release <current-tag> <previous-tag>`. To compare
the stored GitHub Actions release assets instead of running cargo locally, use
`just performance-github-assets`.

6. Save benchmark baselines for this release

Comment thread
coderabbitai[bot] marked this conversation as resolved.
```bash
# Save a named full baseline for this release
Expand All @@ -125,15 +143,15 @@ uploads a short-lived Actions artifact for debugging the run.

See `docs/BENCHMARKING.md` for the full comparison workflow.

6. Validate the release branch
7. Validate the release branch

```bash
just ci
just citation-check
cargo publish --locked --dry-run
```

7. Stage and commit release artifacts
8. Stage and commit release artifacts

```bash
git add Cargo.toml Cargo.lock CITATION.cff pyproject.toml CHANGELOG.md README.md docs/
Expand All @@ -143,11 +161,11 @@ git commit -m "chore(release): release $TAG
- Bump version to $TAG
- Update citation and utility package metadata
- Update changelog with latest changes
- Update benchmark comparison table
- Update benchmark comparison table and release performance report
- Update documentation for release"
```

8. Push the branch and open a PR
9. Push the branch and open a PR

```bash
git push -u origin "release/$TAG"
Expand Down
6 changes: 6 additions & 0 deletions docs/archive/performance/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Archived Performance Reports

Older release-to-release benchmark comparisons are archived here.
`docs/PERFORMANCE.md` contains the latest curated comparison.

- [v0.4.1-vs-v0.4.0](v0.4.1-vs-v0.4.0.md)
Loading
Loading