Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
62 changes: 37 additions & 25 deletions docs/BENCHMARKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,40 +151,27 @@ 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
# Latest published release vs previous stable release
just performance-archive-published

# 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
# Explicit historical repair
just performance-archive-published v0.4.2 v0.4.1
```

You can save multiple baselines and compare against any of them.
These recipes create isolated temporary worktrees, restore release baselines
from GitHub Release assets when available, and fall back to generating a missing
baseline in a second temporary worktree. They do not require changing the current
checkout.

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 +180,30 @@ 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 v0.4.3 v0.4.2
```

This runs the release-signal benchmark set, renders the comparison into
an isolated temporary worktree, 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.

To regenerate and archive the latest published release comparison without
touching the current checkout:

```bash
just performance-archive-published
```

The recipe discovers the latest stable published GitHub release and its previous
stable release automatically. For explicit historical repair, pass both tags:
`just performance-archive-published 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 @@ -241,4 +252,5 @@ 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.
114 changes: 114 additions & 0 deletions docs/PERFORMANCE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# 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

Release performance docs are generated in isolated temporary worktrees:

```bash
# Release PR: update docs/PERFORMANCE.md and archive the previous report
just performance-release <current-tag> <previous-tag>

# Historical published comparison
just performance-archive-published

# Explicit historical repair
just performance-archive-published <current-tag> <previous-tag>
```

For local scratch comparisons, use `just bench-latest` and `just bench-compare`.
Those write `target/bench-reports/performance.md`.

See `docs/BENCHMARKING.md` for the full comparison workflow.
29 changes: 24 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,25 @@ 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
# Runs the release-signal benchmark set in a temporary worktree, compares TAG
# against PREVIOUS_TAG, writes docs/PERFORMANCE.md, and archives the previous
# docs/PERFORMANCE.md under docs/archive/performance/.
just performance-release "$TAG" "$PREVIOUS_TAG"
```

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/`. To regenerate the
latest published release comparison, use `just performance-archive-published`;
it discovers the latest stable published GitHub release and its previous stable
release automatically, then runs inside a temporary worktree. For explicit
historical repair, pass both tags.

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 +144,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 +162,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)
85 changes: 85 additions & 0 deletions docs/archive/performance/v0.4.1-vs-v0.4.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Exact Arithmetic Performance

**la-stack** v0.4.1 · `c6e04fd` (main) · 2026-04-21 22:30:49 UTC
**Statistic**: median

## Benchmark Results

Comparison against baseline **v0.4.0**:

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

### D=2

| Benchmark | v0.4.0 | Current | Change | Speedup |
|-----------|-------:|--------:|-------:|--------:|
| det | 0.6 ns | 0.6 ns | +0.9% | 0.99x |
| det_direct | 0.7 ns | 0.7 ns | +0.6% | 0.99x |
| det_exact | 250.3 ns | 250.0 ns | -0.1% | 1.00x |
| det_exact_f64 | 434.2 ns | 421.7 ns | **-2.9%** | 1.03x |
| det_sign_exact | 1.1 ns | 0.7 ns | **-39.6%** | 1.66x |
| solve_exact | 15.74 µs | 6.51 µs | **-58.7%** | 2.42x |
| solve_exact_f64 | 16.76 µs | 7.06 µs | **-57.9%** | 2.38x |

### D=3

| Benchmark | v0.4.0 | Current | Change | Speedup |
|-----------|-------:|--------:|-------:|--------:|
| det | 1.4 ns | 1.3 ns | **-3.0%** | 1.03x |
| det_direct | 4.7 ns | 4.6 ns | **-2.3%** | 1.02x |
| det_exact | 719.2 ns | 741.2 ns | +3.1% | 0.97x |
| det_exact_f64 | 942.0 ns | 933.1 ns | -0.9% | 1.01x |
| det_sign_exact | 4.1 ns | 2.3 ns | **-43.3%** | 1.76x |
| solve_exact | 51.03 µs | 25.19 µs | **-50.6%** | 2.03x |
| solve_exact_f64 | 53.31 µs | 26.64 µs | **-50.0%** | 2.00x |

### D=4

| Benchmark | v0.4.0 | Current | Change | Speedup |
|-----------|-------:|--------:|-------:|--------:|
| det | 2.4 ns | 2.4 ns | **-2.6%** | 1.03x |
| det_direct | 2.4 ns | 2.4 ns | -0.6% | 1.01x |
| det_exact | 1.89 µs | 1.88 µs | -0.3% | 1.00x |
| det_exact_f64 | 2.09 µs | 2.09 µs | +0.2% | 1.00x |
| det_sign_exact | 6.4 ns | 5.4 ns | **-15.7%** | 1.19x |
| solve_exact | 147.18 µs | 64.62 µs | **-56.1%** | 2.28x |
| solve_exact_f64 | 147.75 µs | 64.03 µs | **-56.7%** | 2.31x |

### D=5

| Benchmark | v0.4.0 | Current | Change | Speedup |
|-----------|-------:|--------:|-------:|--------:|
| det | 26.3 ns | 24.4 ns | **-7.5%** | 1.08x |
| det_direct | 2.3 ns | 2.3 ns | **-1.7%** | 1.02x |
| det_exact | 4.24 µs | 4.13 µs | **-2.6%** | 1.03x |
| det_exact_f64 | 4.40 µs | 4.48 µs | +1.9% | 0.98x |
| det_sign_exact | 4.19 µs | 4.08 µs | **-2.7%** | 1.03x |
| solve_exact | 339.25 µs | 132.55 µs | **-60.9%** | 2.56x |
| solve_exact_f64 | 340.14 µs | 135.75 µs | **-60.1%** | 2.51x |

### Near-singular 3x3

| Benchmark | v0.4.0 | Current | Change | Speedup |
|-----------|-------:|--------:|-------:|--------:|
| det_sign_exact | 909.2 ns | 705.9 ns | **-22.4%** | 1.29x |
| det_exact | 929.6 ns | 729.8 ns | **-21.5%** | 1.27x |

## How to Update

Release performance docs are generated in isolated temporary worktrees:

```bash
# Release PR: update docs/PERFORMANCE.md and archive the previous report
just performance-release <current-tag> <previous-tag>

# Historical published comparison
just performance-archive-published

# Explicit historical repair
just performance-archive-published <current-tag> <previous-tag>
```

For local scratch comparisons, use `just bench-latest` and `just bench-compare`.
Those write `target/bench-reports/performance.md`.

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