Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1,556 changes: 366 additions & 1,190 deletions CHANGELOG.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ cff-version: 1.2.0
message: "If you use this software, please cite it as below."
type: software
title: "la-stack: Fast, stack-allocated linear algebra for fixed dimensions in Rust"
version: 0.4.6
date-released: 2026-09-08
version: 0.5.0
date-released: 2026-10-17
url: "https://github.com/acgetchell/la-stack"
repository-code: "https://github.com/acgetchell/la-stack"
doi: "10.5281/zenodo.18158926"
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "la-stack"
version = "0.4.6"
version = "0.5.0"
edition = "2024"
rust-version = "1.99.0"
autobenches = false
Expand Down
51 changes: 33 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ Add this to your `Cargo.toml`:

```toml
[dependencies]
la-stack = "0.4.6"
la-stack = "0.5.0"
```

### Solve a 5×5 system
Expand Down Expand Up @@ -259,7 +259,7 @@ Enable exact determinant signs, determinant values, and solves:

```toml
[dependencies]
la-stack = { version = "0.4.6", features = ["exact"] }
la-stack = { version = "0.5.0", features = ["exact"] }
```

`Matrix` / `Vector` exact methods preserve stored `f64` values;
Expand Down Expand Up @@ -442,14 +442,14 @@ cargo run --example solve_5x5
![LU solve (factor + solve): median time vs dimension][lu-solve-benchmark]

Raw data:
[docs/assets/bench/vs_linalg_lu_solve_median.csv](https://github.com/acgetchell/la-stack/blob/v0.4.6/docs/assets/bench/vs_linalg_lu_solve_median.csv)
[docs/assets/bench/vs_linalg_lu_solve_median.csv](https://github.com/acgetchell/la-stack/blob/v0.5.0/docs/assets/bench/vs_linalg_lu_solve_median.csv)
Measurement provenance:
[docs/assets/bench/vs_linalg_lu_solve_median.provenance.json][benchmark-provenance]

Representative benchmark: `lu_solve` factors the matrix and solves one
right-hand side. Median time is lower-is-better, and the “la-stack vs
nalgebra/faer” columns show the % time reduction relative to each baseline
(positive means the recorded la-stack median is lower). These are descriptive
right-hand side. Median time is lower-is-better, and the “Speedup vs
nalgebra/faer” columns divide each peer's median by the la-stack median
(above 1× means the recorded la-stack median is lower). These are descriptive
point-estimate ratios, not statistical significance claims or an aggregate score
across operations.

Expand Down Expand Up @@ -486,16 +486,31 @@ expectations are validated outside the timed closures.

<!-- BENCH_TABLE:lu_solve:median:new:BEGIN -->

| D | la-stack median (ns) | nalgebra median (ns) | faer median (ns) | reduction vs nalgebra (point est.) | reduction vs faer (point est.) |
|---:|--------------------:|--------------------:|----------------:|---------------------:|----------------:|
| 2 | 2.021 | 4.479 | 182.532 | +54.9% | +98.9% |
| 3 | 9.977 | 22.795 | 217.567 | +56.2% | +95.4% |
| 4 | 22.101 | 51.739 | 241.525 | +57.3% | +90.8% |
| 5 | 46.070 | 69.003 | 326.848 | +33.2% | +85.9% |
| 8 | 128.364 | 165.933 | 401.400 | +22.6% | +68.0% |
| 16 | 643.532 | 569.446 | 903.140 | -13.0% | +28.7% |
| 32 | 2,755.773 | 2,710.235 | 2,919.290 | -1.7% | +5.6% |
| 64 | 17,518.634 | 14,313.979 | 12,108.783 | -22.4% | -44.7% |
Run: `634bc9527c2caf0a431a9bdfac082c190e1094f0b29eb6e3f28c4b96961cdec5`. Statistic: median. Unit: ns.

- la-stack (v0.5.0): current phase, v0.5.0, revision 51868ea4725c1a4790bba4c59341d2113b18b2bb.
- nalgebra (0.35.0): baseline phase, v0.4.6, revision 0215e65763f8eecb4bcad8bf29de4aca67531aa1.
- faer (0.24.4): baseline phase, v0.4.6, revision 0215e65763f8eecb4bcad8bf29de4aca67531aa1.

| Dimension | la-stack | nalgebra | faer | Speedup vs nalgebra | Speedup vs faer |
| --- | --- | --- | --- | --- | --- |
| 2 | 2.10359<br>[2.08908, 2.11912] | 4.53894<br>[4.53141, 4.54661] | 154.45<br>[153.658, 155.846] | 2.15771× | 73.4219× |
| 3 | 9.93879<br>[9.92881, 9.95117] | 32.9342<br>[32.8554, 33.057] | 191.85<br>[191.206, 192.814] | 3.3137× | 19.3032× |
| 4 | 21.7341<br>[21.7035, 21.776] | 55.0106<br>[54.9217, 55.0615] | 221.887<br>[221.678, 222.673] | 2.53107× | 10.2091× |
| 5 | 49.1031<br>[49.0318, 49.1659] | 74.629<br>[74.3476, 74.9906] | 272.864<br>[272.009, 273.512] | 1.51984× | 5.55695× |
| 8 | 133.665<br>[133.426, 133.861] | 166.317<br>[166.02, 166.604] | 374.912<br>[372.746, 376.096] | 1.24429× | 2.80487× |
| 16 | 750.027<br>[649.969, 761.453] | 589.011<br>[586.474, 592.341] | 938.943<br>[932.02, 944.127] | 0.78532× | 1.25188× |
| 32 | 2829.62<br>[2819.66, 2837.22] | 2722.74<br>[2720.98, 2729.21] | 3023.87<br>[3017.73, 3030.19] | 0.962229× | 1.06865× |
| 64 | 18280.4<br>[18138, 18489.9] | 13835.1<br>[13822.9, 13852.2] | 12678.8<br>[12660.2, 12699.3] | 0.756828× | 0.693573× |

Median time in ns; brackets show the lower and upper bounds of the **95% confidence interval**.
Speedups are ratios of point estimates; no ratio intervals or significance claims are inferred.

Selection coverage:

- la-stack (v0.5.0): 8 selected; 0 unavailable rows; 437 phase cases omitted. Complete evidence is retained independently.
- nalgebra (0.35.0): 8 selected; 0 unavailable rows; 789 phase cases omitted. Complete evidence is retained independently.
- faer (0.24.4): 8 selected; 0 unavailable rows; 789 phase cases omitted. Complete evidence is retained independently.

<!-- BENCH_TABLE:lu_solve:median:new:END -->

Expand Down Expand Up @@ -533,7 +548,7 @@ BSD 3-Clause License. See [LICENSE](https://github.com/acgetchell/la-stack/blob/

[audit-badge]: https://github.com/acgetchell/la-stack/actions/workflows/audit.yml/badge.svg
[audit-workflow]: https://github.com/acgetchell/la-stack/actions/workflows/audit.yml
[benchmark-provenance]: https://github.com/acgetchell/la-stack/blob/v0.4.6/docs/assets/bench/vs_linalg_lu_solve_median.provenance.json
[benchmark-provenance]: https://github.com/acgetchell/la-stack/blob/v0.5.0/docs/assets/bench/vs_linalg_lu_solve_median.provenance.json
[benchmarks-badge]: https://github.com/acgetchell/la-stack/actions/workflows/benchmarks.yml/badge.svg
[benchmarks-workflow]: https://github.com/acgetchell/la-stack/actions/workflows/benchmarks.yml
[clippy-badge]: https://github.com/acgetchell/la-stack/actions/workflows/rust-clippy.yml/badge.svg
Expand All @@ -544,7 +559,7 @@ BSD 3-Clause License. See [LICENSE](https://github.com/acgetchell/la-stack/blob/
[coverage-workflow]: https://github.com/acgetchell/la-stack/actions/workflows/codecov.yml
[dependabot-badge]: https://github.com/acgetchell/la-stack/actions/workflows/dependabot-auto-merge.yml/badge.svg
[dependabot-workflow]: https://github.com/acgetchell/la-stack/actions/workflows/dependabot-auto-merge.yml
[lu-solve-benchmark]: https://raw.githubusercontent.com/acgetchell/la-stack/v0.4.6/docs/assets/bench/vs_linalg_lu_solve_median.svg
[lu-solve-benchmark]: https://raw.githubusercontent.com/acgetchell/la-stack/v0.5.0/docs/assets/bench/vs_linalg_lu_solve_median.svg
[refs-det-bound]: https://github.com/acgetchell/la-stack/blob/main/REFERENCES.md#absolute-error-bound-for-closed-form-determinants
[refs-exact-sign]: https://github.com/acgetchell/la-stack/blob/main/REFERENCES.md#exact-determinant-sign-adaptive-precision-integer-arithmetic
[refs-exact-solve]: https://github.com/acgetchell/la-stack/blob/main/REFERENCES.md#exact-linear-system-solve-hybrid-bareiss--bigrational
Expand Down
18 changes: 14 additions & 4 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,19 @@ assignment in that file. Other assignments and paths remain checked.
Semgrep 1.180.0 accepts `pyjwt[crypto]>=2.15.0,<3`, so the older security override
is retired. `tooling/semgrep/uv.lock` retains patched PyJWT 2.15.1 and its crypto
dependencies. Validate native Semgrep scans when changing the scanner or lock.
`just audit` includes both Python lockfiles, and Dependabot monitors both
environments. The isolated scanner remains on Python 3.14 while its wheels
exclude Python 3.15; support scripts run on Python 3.15.

Semgrep 1.180.0 pins MCP 1.29.0, which is affected by
[GHSA-84m7-p3x7-pcfv](https://github.com/advisories/GHSA-84m7-p3x7-pcfv).
The isolated environment overrides that pin with `mcp>=1.30.0,<2`, retaining
the patched 1.x API. Remove the override when a released Semgrep dependency
accepts a patched MCP version. The root support environment has no MCP dependency.

`just audit` includes both Python lockfiles, and Dependabot is configured for both
environments. Its [root graph job](https://github.com/acgetchell/la-stack/actions/runs/38871146224)
currently rejects Python 3.15, so the root dependency alerts can be stale; use
`just audit` to check the current inventory until upstream supports Python 3.15.
The isolated scanner remains on Python 3.14 while its wheels exclude Python 3.15;
support scripts run on Python 3.15.

### Numerical logging false positives

Expand All @@ -141,7 +151,7 @@ Review new alerts on their own data flow.

### Benchmark dependency maintenance

As of October 1, 2026, `paste` 1.0.15 enters through the development dependency
As of October 16, 2026, `paste` 1.0.15 enters through the development dependency
`faer` 0.24.4, via `gemm` 0.19.0 and `pulp` 0.22.3. Those are the latest
published upstream versions checked on that date. Repository-owned Rust code
already uses `pastey`; changing that direct dependency cannot replace upstream
Expand Down
9 changes: 9 additions & 0 deletions docs/BENCHMARKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,9 @@ source and harness inventories/digests, dependency resolution, complete peer
coverage, and recorded phase provenance before writing. The derived sidecar
records the run identity and the actual current/baseline origins of each series.
Historical CSV/JSON evidence remains frozen with its original provenance.
The README table shows median times in nanoseconds, with lower and upper 95%
confidence bounds below each timing. Its compact comparison columns show
speedup ratios; the confidence level is stated once in the table legend.
Missing, stale, or inconsistent input aborts publication atomically.
An existing local release tag must contain the exact selected asset bytes.
A future release tag may be absent during release preparation.
Expand Down Expand Up @@ -353,6 +356,12 @@ from `Cargo.toml` and discovers the previous stable published release. During
release preparation, passing both tags explicitly removes ambiguity.

This command uses the shared common-harness engine in isolated worktrees.
The native driver resolves `CRITERION_HOME` from each checkout root before
Cargo launches the benchmarks, keeping comparison-member and root-package
measurements in one output tree.
Each timing command has a four-hour timeout because `baseline-all` combines both
full suites. This accommodates the combined 150-minute comparison and 90-minute
exact-suite budgets described under [Hosted Release Runtime Budget](#hosted-release-runtime-budget).
The native Criterion inventory declares every expected semantic ID, including
diagnostics outside the selected report. Each case requires 100 raw samples,
both mean and median estimates, and complete 95% intervals in nanoseconds.
Expand Down
38 changes: 29 additions & 9 deletions docs/RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ release process does not require a temporary local tag.

Release recipes are content-idempotent where their inputs permit it. Repeating
`update-version` on the same UTC date or repeating `performance-readme` for the
same retained bundle produces no file changes. Crossing UTC midnight
intentionally advances the release date, and repeated `performance-release`
runs can produce different measurements.
same retained bundle produces no file changes. Rerunning `update-version` on a
later UTC date intentionally advances the declared release date. Crossing
midnight alone requires no update: the `declared` date policy allows preparation
and tagging on different UTC days when citation and changelog dates agree.
Repeated `performance-release` runs can produce different measurements.

## Prepare the environment

Expand Down Expand Up @@ -80,8 +82,10 @@ just update-version "$TAG"
The recipe requires a stable `vX.Y.Z` target that is not older than any
published stable GitHub release and that has at least one earlier published
stable release. It infers the previous release from GitHub and updates the Rust
and Python package metadata and lockfiles, `CITATION.cff`, and README dependency
metadata. Active navigation stays on `main`; measured artifact links retain their
package metadata and `Cargo.lock`, `CITATION.cff`, and README dependency metadata.
The dependency-only Python environment retains its own project and lockfile
version independently of the Rust release.
Active navigation stays on `main`; measured artifact links retain their
recorded revision. `date-released` uses the
current UTC date; if the target changelog section already exists, its date is
updated in the same transaction. `CITATION.cff` retains the Zenodo all-versions
Expand All @@ -101,16 +105,28 @@ just changelog-unreleased "$TAG" "$RELEASE_DATE"
This generates `CHANGELOG.md` as though the target tag already existed, archives
completed minor series under `docs/archives/changelog/`, and uses the explicit
ISO release date. Verify that `RELEASE_DATE` equals the date recorded in
`CITATION.cff` by metadata preparation; if preparation crossed UTC midnight,
rerun `just update-version "$TAG"` first. Generation preserves existing release
dates and does not update package or citation metadata.
`CITATION.cff` by metadata preparation. If preparation crossed UTC midnight,
either reuse that declared date or deliberately advance it by rerunning
`just update-version "$TAG"` first. Generation preserves existing release dates
and does not update package or citation metadata.
Use `just changelog-preview --tag "$TAG" --date "$RELEASE_DATE"` for a read-only
preview, and `just changelog-check` to validate the root and every archive.
Review the generated changelog and any archive changes. The
[Scripts guide](../scripts/README.md#changelog-and-release-tooling) explains
the supported `dependency-bodies = "preserve"` policy in `pyproject.toml`, which
preserves authored dependency-note links, text, and code without a local template.

If generation reports `conflicting retained release`, compare the regenerated
section with the retained archive and its original tagged commit history. Both
versions already pass through the same formatter before comparison, so this
error can indicate a content-policy change rather than whitespace differences.
For example, adopting `dependency-bodies = "preserve"` can restore original
Dependabot release-note and comparison links omitted by an older template.
Generate an archive candidate in a disposable directory with the published CLI,
review the policy migration, and replace only the affected generated archive.
Preserve release dates, commit identities, and authored notes, then rerun the
original command and `just changelog-check`.

### 4. Generate the release performance comparison

Run this after the package version has been updated:
Expand Down Expand Up @@ -142,6 +158,10 @@ This consumes the complete-run payload and evidence envelope retained by
updates the table and tag-pinned benchmark links in `README.md` with the CSV,
SVG, and provenance JSON under `docs/assets/bench/`. Until it succeeds, those
README links continue to reference the previous published artifacts.
After regeneration, the new tag-pinned image and data links become available
when the release tag is pushed. Before then, preview the SVG directly from
`docs/assets/bench/`; a failed image load in the README does not imply that
generation failed.
If scratch inputs were cleaned, it uses the validated
`docs/performance-runs/latest.json` run. Existing
partial or corrupt scratch inputs remain errors and never trigger a fallback.
Expand Down Expand Up @@ -184,7 +204,7 @@ git --no-pager diff --cached
git commit -m "chore(release): release $TAG

- Bump version to $TAG
- Update citation and utility package metadata
- Update citation and README release metadata
- Generate the release changelog
- Update benchmark and performance artifacts
- Update release documentation"
Expand Down
11 changes: 11 additions & 0 deletions docs/archives/changelog/0.2.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,19 @@
### Dependencies

- Bump actions/setup-node from 6.2.0 to 6.3.0 [`0f2fc34`](https://github.com/acgetchell/la-stack/commit/0f2fc348b06d72476610821c77945c265207ad05)

Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6.2.0 to 6.3.0.

- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/6044e13b5dc448c55e2357c09f80417699197238...53b83947a5a98c8d113130e565377fae1a50d02f)
- Bump taiki-e/install-action from 2.68.20 to 2.68.22 [`c3e49bd`](https://github.com/acgetchell/la-stack/commit/c3e49bdd75e3ca26117942da243dac1ee59eb7a1)

Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.68.20 to 2.68.22.

- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/install-action/compare/4a136ceac97fe29b942ff3b6c749a46c7950d853...5faf876256ccfc7ba64a4f87314c3457cc374b98)

## [0.2.1] - 2026-03-08

### ⚠️ Breaking Changes
Expand Down
Loading
Loading