la-stack 0.5.2

Fast, stack-allocated linear algebra for fixed dimensions
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
# la-stack

<!-- Keep the three compact badge rows; allow their explicit line breaks. -->
<!-- markdownlint-disable MD033 -->
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.18158926.svg)](https://doi.org/10.5281/zenodo.18158926)
[![Crates.io](https://badgen.net/crates/v/la-stack)](https://crates.io/crates/la-stack)
[![Downloads](https://badgen.net/crates/d/la-stack)](https://crates.io/crates/la-stack)
[![License](https://badgen.net/github/license/acgetchell/la-stack)](https://github.com/acgetchell/la-stack/blob/main/LICENSE)
[![Docs.rs](https://docs.rs/la-stack/badge.svg)](https://docs.rs/la-stack)<br>
[![CI][ci-badge]][ci-workflow]
[![Clippy][clippy-badge]][clippy-workflow]
[![codecov](https://codecov.io/gh/acgetchell/la-stack/graph/badge.svg?token=4eKXa5QjuZ)](https://codecov.io/gh/acgetchell/la-stack)<br>
[![CodeQL][codeql-badge]][codeql-workflow]
[![Audit dependencies][audit-badge]][audit-workflow]
[![zizmor][zizmor-badge]][zizmor-workflow]
[![Repository Rule SARIF][semgrep-badge]][semgrep-workflow]
<!-- markdownlint-enable MD033 -->

![la-stack](https://raw.githubusercontent.com/acgetchell/la-stack/main/docs/assets/la-stack.jpg)

Fast, stack-allocated linear algebra for fixed dimensions in Rust.

This crate grew from the need to support [`delaunay`](https://crates.io/crates/delaunay) with fast, stack-allocated linear algebra primitives and algorithms
while keeping the API intentionally small and explicit.

## Contents

- [Introduction]#-introduction
- [Use this crate when]#-use-this-crate-when
- [Quickstart]#-quickstart
- [Scalar and bounded-value types]#-scalar-and-bounded-value-types
- [API at a glance]#-api-at-a-glance
- [Features]#-features
  - [Adaptive determinant filtering (D ≤ 4)]#adaptive-determinant-filtering-d--4
  - [Certified dot products and affine differences]#certified-dot-products-and-affine-differences
  - [Compile-time determinants (D ≤ 4)]#compile-time-determinants-d--4
  - [Exact arithmetic]#exact-arithmetic-exact-feature
  - [LDLT determinant]#ldlt-determinant
  - [LU solve]#lu-solve
  - [Outward-rounded interval determinants]#outward-rounded-interval-determinants
  - [Overflow-safe Euclidean norms]#overflow-safe-euclidean-norms
  - [Unsigned vector angles]#unsigned-vector-angles
- [Mathematical basis]#-mathematical-basis
- [Design goals]#-design-goals
- [Anti-goals]#-anti-goals
- [Documentation Map]#documentation-map
- [Examples]#-examples
- [Benchmarks]#-benchmarks-vs-nalgebrafaer
- [Contributing]#-contributing
- [Citation]#-citation
- [References]#-references
- [AI Agents]#-ai-agents
- [License]#-license

## 📐 Introduction

`la-stack` provides const-generic linear algebra and focused exact-arithmetic
kernels. Its floating-point core uses stack-backed storage; arbitrary-precision
values and sparse polynomials use heap allocation.

- `column_basis(&[[f64; C]; R], tolerance)` for rectangular column selection
  with explicit absolute tolerance and a provisional numerical rank;
  exact certification of the selected basis remains the caller's responsibility
- `gram_matrix(&[Vector<N>; M])` for allocation-free `Matrix<M>` construction
  from pairwise vector inner products, with bit-for-bit symmetry. Gram matrices
  encode lengths and angles and support simplex/facet volume calculations; see
  [Gram matrices and geometric measures][refs-gram].
  Each independent dot product is checked once;
  rounding has no certified error bound. Positive definiteness or affine
  independence requires independent proof from the caller; successful
  floating-point factorization is not a certificate.
- `Interval` and `IntervalMatrix<const D: usize>` for outward-rounded,
  proof-bearing arithmetic, including division and reciprocals for zero-free
  divisors, linear solution enclosures, and determinant filters through D=7.
  Inconclusive solves and finite-range failures require caller fallback
- `Ldlt<const D: usize>` for no-pivot factorization intended for exactly
  symmetric positive-definite matrices (solve + det; typed pivot diagnostics)
- `Lu<const D: usize>` for LU factorization with partial pivoting (solve + det)
- `Matrix<const D: usize>` for fixed-size square `f64` matrices backed by `[[f64; D]; D]`
- `RationalVector<const D: usize>` and `RationalMatrix<const D: usize>` for
  exact rational inputs behind the optional `"exact"` feature; vector `dot`
  and the checked `rational_dot` slice adapter preserve exact products at any length
- `ScalarWithErrorBound` for proof-bearing fixed-vector dot products and
  affine differences over finite `f64` inputs
- `SparsePolynomial` and `polynomial_determinant` for exact sparse rational
  polynomial determinants through order eight behind `"exact"`, with explicit
  work budgets and caller-owned perturbation encodings
- `Vector<const D: usize>` for fixed-length `f64` vectors backed by `[f64; D]`
- `VectorAngle::angle` on coordinate slices and `Vector::angle` for allocation-free,
  unsigned vector angles with arbitrary finite nonzero magnitudes

## ✅ Use this crate when

- Robust predicates matter for geometry-style workloads near degeneracy
- Stack allocation and `Copy` value semantics fit your data flow
- You need a certified sign or threshold comparison for a fixed-vector dot
  product or `axis · (left - right)` expression
- You need a cheap, sound interval filter for determinant expressions assembled
  from rounded binary64 operations
- You need exact determinants, exact determinant signs, or exact linear solves
  for fixed-size systems
- You need exact dot products of rational vectors or borrowed slices without
  an intermediate `f64` conversion
- You need exact sparse polynomial determinants through order eight, with
  explicit work budgets and caller-defined perturbation encodings
- You need interval solution enclosures for small fixed-size linear systems,
  with explicit inconclusive outcomes for fallback
- You need provisional column selection for a rectangular matrix before
  independently certifying the selected basis
- You prefer a default build with no runtime dependencies
- You want explicit LU / LDLT / determinant APIs rather than a broad algebra toolkit
- Your matrices and vectors have small, fixed dimensions known at compile time

## 🚀 Quickstart

The minimum supported Rust version (MSRV) is 1.99.1.

Add this to your `Cargo.toml`:

```toml
[dependencies]
la-stack = "0.5.2"
```

### Solve a 5×5 system

This system has solution `[1, 2, 3, 4, 5]` and requires partial pivoting:

```rust
use la_stack::prelude::*;

fn main() -> Result<(), LaError> {
    // The zero leading entry requires LU pivoting.
    let a = Matrix::<5>::try_from_rows([
        [0.0, 2.0, -1.0, 1.0, 3.0],
        [4.0, -1.0, 2.0, 0.0, 1.0],
        [1.0, 3.0, 5.0, -2.0, 0.0],
        [2.0, 0.0, -1.0, 4.0, 1.0],
        [-1.0, 2.0, 0.0, 1.0, 6.0],
    ])?;
    let b = Vector::try_new([20.0, 13.0, 14.0, 20.0, 37.0])?;
    let lu = a.lu(DEFAULT_SINGULAR_TOL)?;
    let x = lu.solve(b)?;

    for (&actual, expected) in x.as_array().iter().zip([1.0, 2.0, 3.0, 4.0, 5.0]) {
        assert!((actual - expected).abs() <= 1e-12);
    }
    Ok(())
}
```

The assertion tolerance is suitable for this known example; LU does not
provide a certified solution error bound.

### Feature flags

- `bench`: repository-development gate used only by benchmark targets and
  benchmark-input tests; application crates should not enable it
- `default`: no runtime dependencies; includes outward-rounded `Interval` and
  `IntervalMatrix` APIs
- `exact`: exact determinant signs, determinant values, and solves over stored
  `f64` values or caller-supplied `BigRational` inputs

### Run the repository examples

After the [prerequisite setup][contributor-setup], discover commands and run
the complete examples, including exact determinants and solves:

```bash
just
just examples
```

To run the pivoted solve above individually:

```bash
cargo run --locked --example solve_5x5
```

[contributor-setup]: https://github.com/acgetchell/la-stack/blob/main/CONTRIBUTING.md#getting-started

## 🔢 Scalar and bounded-value types

The public point-value scalar model deliberately has two input domains:

- arbitrary-precision `BigRational` through `RationalMatrix<D>` and
  `RationalVector<D>` behind the optional `"exact"` feature;
- finite `f64` through `Matrix<D>` and `Vector<D>` for floating-point work.

`Interval` is a separate bounded-value layer over finite `f64` endpoints. It
encloses exact-real values during a small set of outward-rounded operations,
including division by intervals that exclude zero, and feeds `IntervalMatrix<D>`
determinant proofs and linear solution enclosures. It does not make `Matrix`
generic over alternate scalars or provide a general interval package.

With `exact`, `SparsePolynomial` supplies rational coefficients keyed by `u128`
exponents for bounded polynomial determinants through order eight. Its first
nonzero term uses increasing exponent order; callers own perturbation encoding
and work limits. This focused kernel retains cancellation exactly.

This is not a generic scalar-parameterized API. Exact support intentionally
covers determinant signs and values, linear solves, rational dot products,
and bounded sparse polynomial determinants. Rational results support explicit
strict or rounded conversion when an `f64` result is required. It does not promise a
`BigRational` counterpart for every floating-point helper or factorization.

Lower-precision `f32` / `f16` throughput-oriented workloads are outside the
crate's scope; they usually indicate large-matrix or accelerator-oriented use
cases better served by broader linear-algebra libraries.

## 🧩 API at a glance

Start with the capability you need; the [API reference][api-reference] lists
the complete public surface, and the [worked examples][api-guide] show how
to combine operations.

| Capability | Main entry points |
|---|---|
| Certified dot, affine-difference, and determinant estimates | [`ScalarWithErrorBound`][api-scalar-bound], [`DeterminantWithErrorBound`][api-det-bound] |
| Exact rational dot products for fixed vectors or runtime-length slices¹ | [`RationalVector::dot`][api-rational-dot], [`rational_dot`][api-rational-dot-slice] |
| Exact signs, determinants, solves, and output conversion¹ | [Exact arithmetic examples][api-exact] |
| Exact sparse polynomial determinants through order eight¹ | [`polynomial_determinant`][api-polynomial], [`SparsePolynomial`][api-sparse-polynomial], [`PolynomialDeterminantBudget`][api-polynomial-budget] |
| Floating-point determinants and solves | [`Matrix<D>`][api-matrix], [`Lu<D>`][api-lu], [`Ldlt<D>`][api-ldlt] |
| Gram matrix construction | [`gram_matrix`][api-gram] |
| Interval arithmetic, division, and reciprocals | [`Interval`][api-interval], [`Interval::try_div`][api-interval-division], [`Interval::try_recip`][api-interval-reciprocal] |
| Interval determinant signs | [`IntervalMatrix<D>`][api-interval-matrix] |
| Interval linear solution enclosures | [`IntervalMatrix::solve`][api-interval-solve] |
| Provisional rectangular column basis and numerical rank | [`column_basis`][api-column-basis] |
| Runtime selection of a const-generic matrix dimension | [Dimension dispatch examples][api-dispatch] |
| Unsigned vector angles in radians | [`VectorAngle::angle`][api-angle], [`Vector::angle`][api-vector-angle] |
| Vector operations and norms | [`Vector<D>`][api-vector] |

[`Tolerance`][api-tolerance] validates numerical rejection thresholds.
[`LaError`][api-error] and its reason/location enums preserve structured
failure details; match non-exhaustive enums with a wildcard and struct-style
variants with `..`. See the [storage, access, and error guide][api-contracts]
for the full contracts.

¹ Requires `features = ["exact"]`.

For tested usage examples, see [exact dot products and column selection][guide-exact-reductions],
[interval division and solution enclosures][guide-intervals], and the runnable
[polynomial determinant example][example-polynomial].

[api-reference]: https://docs.rs/la-stack/latest/la_stack/
[api-guide]: https://docs.rs/la-stack/latest/la_stack/guide/index.html
[api-vector]: https://docs.rs/la-stack/latest/la_stack/struct.Vector.html
[api-angle]: https://docs.rs/la-stack/latest/la_stack/trait.VectorAngle.html#tymethod.angle
[api-vector-angle]: https://docs.rs/la-stack/latest/la_stack/struct.Vector.html#method.angle
[api-matrix]: https://docs.rs/la-stack/latest/la_stack/struct.Matrix.html
[api-lu]: https://docs.rs/la-stack/latest/la_stack/struct.Lu.html
[api-ldlt]: https://docs.rs/la-stack/latest/la_stack/struct.Ldlt.html
[api-gram]: https://docs.rs/la-stack/latest/la_stack/fn.gram_matrix.html
[api-scalar-bound]: https://docs.rs/la-stack/latest/la_stack/struct.ScalarWithErrorBound.html
[api-det-bound]: https://docs.rs/la-stack/latest/la_stack/struct.DeterminantWithErrorBound.html
[api-interval]: https://docs.rs/la-stack/latest/la_stack/struct.Interval.html
[api-interval-division]: https://docs.rs/la-stack/latest/la_stack/struct.Interval.html#method.try_div
[api-interval-reciprocal]: https://docs.rs/la-stack/latest/la_stack/struct.Interval.html#method.try_recip
[api-interval-matrix]: https://docs.rs/la-stack/latest/la_stack/struct.IntervalMatrix.html
[api-interval-solve]: https://docs.rs/la-stack/latest/la_stack/struct.IntervalMatrix.html#method.solve
[api-exact]: https://docs.rs/la-stack/latest/la_stack/guide/exact/index.html
[api-dispatch]: https://docs.rs/la-stack/latest/la_stack/guide/index.html#dimension-dispatch
[api-tolerance]: https://docs.rs/la-stack/latest/la_stack/struct.Tolerance.html
[api-error]: https://docs.rs/la-stack/latest/la_stack/enum.LaError.html
[api-contracts]: https://docs.rs/la-stack/latest/la_stack/guide/index.html#storage-access-and-errors
[guide-exact-reductions]: https://docs.rs/la-stack/latest/la_stack/guide/exact/index.html#exact-reductions-and-provisional-column-selection

## ✨ Features

### Adaptive determinant filtering (D ≤ 4)

`det_direct_with_errbound()` pairs a determinant with its certified absolute
bound, without optional dependencies. Resolve the sign when `|det| > bound`;
otherwise an exact fallback is needed. With `exact`, `det_sign_exact()` handles
filtering and fallback automatically.
[Worked examples: the floating-point filter and exact fallback][guide-adaptive].

### Certified dot products and affine differences

`dot_with_errbound()` and `dot_difference_with_errbound()` return certified
bounds for dot products and `axis · (left - right)` over the original stored
coordinates. Their endpoints support sign and threshold proofs; a bound that
straddles the threshold or an unavailable certificate is inconclusive.
[Worked examples: dot-product signs and affine threshold tests][guide-certified].

### Compile-time determinants (D ≤ 4)

`det_direct()` evaluates closed-form determinants in `const` contexts through
D=4. `det()` selects those formulas automatically and uses zero-tolerance LU
for larger dimensions; a failed numerical pivot remains `LaError::Singular`.
[Compile-time example and dimension contracts][guide-compile-time].

### Exact arithmetic (`"exact"` feature)

Enable exact determinant signs, determinant values, and solves:

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

`Matrix` / `Vector` exact methods preserve stored `f64` values;
`RationalMatrix` / `RationalVector` also preserve rational expressions before
any `f64` rounding. Keep exact results or explicitly choose strict versus
rounded conversion with `ExactF64Conversion`.
[Worked examples: rational inputs, exact solves, and output conversion][api-exact].

### LDLT determinant

`Matrix::ldlt()` provides a square-root-free factorization for exactly symmetric
positive-definite matrices, supporting determinants and solves without pivoting.
Approximate symmetry is not sufficient, and floating-point success is not an
exact positive-definiteness certificate.
[Worked example and typed pivot diagnostics][guide-ldlt].

### LU solve

`Matrix::lu()` uses partial pivoting for general square systems. Reuse one
`Lu` factorization for multiple right-hand sides or a determinant; pivot
tolerances control rejection, not solution accuracy.
[Worked example: solving and reusing factors][guide-lu].

### Outward-rounded interval determinants

`Interval` preserves bounds while assembling differences, squares, and other
expressions, including division by zero-free intervals. `IntervalMatrix::solve()`
encloses every admitted exact-real solution, with explicit inconclusive-pivot
and finite-range failures for caller fallback. `IntervalMatrix::det_sign()`
certifies determinant signs through D=7: an enclosure separated from zero proves
its sign, and `[0, 0]` proves
exact zero. Other overlaps with zero are inconclusive and may need exact fallback.
[Worked example: lifted coordinates, range errors, and fallback][guide-intervals].

### Overflow-safe Euclidean norms

`Vector::norm()` avoids unnecessary overflow and underflow from squaring
coordinates. `norm_squared()` computes the squared norm and can overflow even
when the norm is finite. Both results remain approximate, without a certified
error bound.
[Worked example and range contracts][guide-norms].

**v0.4.6 migration:** `Vector::norm2_sq()` is renamed to `Vector::norm_squared()`,
the unreleased `Vector::norm2()` API is named `Vector::norm()`, and
`Matrix::inf_norm()` is renamed to `Matrix::norm_inf()`. The old method names
are removed; their numerical behavior and error contracts are unchanged by
the renames. `Matrix::norm_inf()` remains the maximum absolute row sum.

### Unsigned vector angles

Import `VectorAngle` directly or through `la_stack::prelude::*` to call
`left.angle(right)` on borrowed coordinate slices. `Vector::angle` uses finite
fixed-size storage. Both return radians in `[0, π]`, with no
allocation or matrix dispatch limit. Independent magnitude scaling supports
overflowing input norms and subnormal separations. Empty, zero, unequal-length,
and non-finite inputs have typed errors. Results are rounded, without a certified
error bound; see the [angle contract and derivation][math-angles].
The runnable [`vector_angles` example][example-vector-angles] demonstrates both
APIs, very different input magnitudes, and a subnormal separation.

[math-angles]: https://github.com/acgetchell/la-stack/blob/main/docs/mathematical_basis.md#unsigned-vector-angles
[guide-lu]: https://docs.rs/la-stack/latest/la_stack/guide/index.html#solving-and-reusing-factors
[guide-ldlt]: https://docs.rs/la-stack/latest/la_stack/guide/ldlt/index.html
[guide-compile-time]: https://docs.rs/la-stack/latest/la_stack/guide/compile_time/index.html
[guide-intervals]: https://docs.rs/la-stack/latest/la_stack/guide/intervals/index.html
[guide-norms]: https://docs.rs/la-stack/latest/la_stack/guide/norms/index.html
[guide-certified]: https://docs.rs/la-stack/latest/la_stack/guide/certified/index.html
[guide-adaptive]: https://docs.rs/la-stack/latest/la_stack/guide/adaptive/index.html

## 🧮 Mathematical basis

`la-stack` operates on finite IEEE 754 binary64 values in small, fixed
dimensions. Its floating-point paths use [LU with partial pivoting][refs-lu],
[LDLT without pivoting][refs-ldlt] for exactly symmetric positive-definite matrices, and closed-form
determinants through D=4. These results remain subject to conditioning and
binary64 rounding;
factorization tolerances are rejection thresholds, not accuracy guarantees. For
D≤4, direct determinants can be paired with a
[conservative absolute roundoff bound][refs-det-bound] when its range
preconditions hold. [Fixed-vector dot products and direct affine differences][refs-reductions]
can likewise return a paired estimate and certified absolute
roundoff bound without enabling arbitrary-precision dependencies.

Derived binary64 expressions can instead be assembled with `Interval`
subtraction, addition, multiplication, negation, and square. The resulting
`IntervalMatrix<D>` [determinant sign][refs-interval] is certified through D=7 when its enclosure
separates zero; the singleton `[0, 0]` also certifies exact zero. Every other
overlap with zero is explicitly inconclusive. This default-feature surface is
distinct from arbitrary-precision exact arithmetic.

With `features = ["exact"]`, callers can either lift stored binary64 inputs
losslessly or supply already-exact rational inputs for
[exact determinant signs][refs-exact-sign], determinant values, and
[solves][refs-exact-solve]. Exactness over binary64 input starts at the
stored values and cannot recover information rounded away before construction.
See the
[mathematical basis](https://github.com/acgetchell/la-stack/blob/main/docs/mathematical_basis.md)
for the algorithms, validity boundaries, and supporting references.

## 🎯 Design goals

- ✅ `const fn` where possible (compile-time evaluation of determinants, dot products, etc.)
- ✅ Const-generic storage (no dynamically sized matrix or vector representation)
- ✅ `Copy` types where possible
- ✅ Defined binary64 arithmetic semantics: Rust's `f64::algebraic_*`
  operations are forbidden because their unspecified reassociation, precision,
  and special-value behavior is incompatible with the crate's error bounds,
  non-finite classification, exact fallbacks, and reproducibility contract;
  deliberate `f64::mul_add` remains allowed for its defined single-rounding
  semantics
- ✅ Error-bounded f64 dot, affine-difference, and determinant filtering plus
  optional exact signs (`dot_with_errbound`, `dot_difference_with_errbound`,
  `det_errbound`, `det_sign_exact`)
- ✅ Exact determinant values and linear solves via optional arbitrary-precision
  arithmetic (`det_exact`, `solve_exact`, strict/rounded f64 conversions)
- ✅ Explicit algorithms (LU, solve, determinant)
- ✅ Inline, stack-backed storage for core types; optional arbitrary-precision
  exact values allocate as required
- ✅ No runtime dependencies by default (optional features may add deps)
- ✅ Outward-rounded interval expressions and division-free determinant signs
  through D=7, with explicit inconclusive evidence
- ✅ Overflow- and underflow-safe Euclidean vector norms (`norm`)
- ✅ `unsafe` forbidden

See [CHANGELOG.md](https://github.com/acgetchell/la-stack/blob/main/CHANGELOG.md)
for release history and
[docs/roadmap.md](https://github.com/acgetchell/la-stack/blob/main/docs/roadmap.md)
for current release planning.

## 🚫 Anti-goals

- Alternate scalar families: `la-stack` deliberately supports finite `f64` and
  optional exact `BigRational` input domains, not `f32`, `f16`, complex, or
  generic scalar APIs
- Bare-metal performance: use [`blas`]https://crates.io/crates/blas or
  [`lapack`]https://crates.io/crates/lapack with a native backend selected
  through [`blas-src`]https://crates.io/crates/blas-src,
  [`lapack-src`]https://crates.io/crates/lapack-src, or
  [`openblas-src`]https://crates.io/crates/openblas-src
- Broad general-purpose linear algebra: use [`nalgebra`]https://crates.io/crates/nalgebra
- Large matrices/dimensions with parallelism: use [`faer`]https://crates.io/crates/faer

<a name="documentation-map"></a>

## 🗺️ Documentation Map

- [API guide][api-guide] — worked examples, API selection, storage, and error contracts.
- [Architecture]https://github.com/acgetchell/la-stack/blob/main/docs/code_organization.md — module, feature, file, and documentation ownership.
- [Benchmarking]https://github.com/acgetchell/la-stack/blob/main/docs/BENCHMARKING.md — benchmark suites, comparison workflows, and measurement methodology.
- [Coverage]https://github.com/acgetchell/la-stack/blob/main/docs/MEASURING_COVERAGE.md — local and CI coverage commands and report locations.
- [Mathematical basis]https://github.com/acgetchell/la-stack/blob/main/docs/mathematical_basis.md — algorithms, numerical guarantees, and limitations.
- [Performance reports]https://github.com/acgetchell/la-stack/blob/main/docs/performance.md — release-to-release measurement results and provenance.
- [Releasing]https://github.com/acgetchell/la-stack/blob/main/docs/RELEASING.md — release preparation, validation, and publication.
- [Roadmap]https://github.com/acgetchell/la-stack/blob/main/docs/roadmap.md — release planning, future directions, and non-goals.
- [Validation records]https://github.com/acgetchell/la-stack/blob/main/docs/validation/README.md — numerical contracts, evidence, and decisions.

## 📋 Examples

The `examples/` directory contains small, runnable programs:

- **[`const_det_4x4`][example-const-det]** — compile-time 4×4 determinant via `det_direct()`
- **[`det_5x5`][example-det]** — determinant of a 5×5 matrix via LU
- **[`exact_det_3x3`][example-exact-det]** — exact determinant value of a near-singular 3×3 matrix (requires `exact` feature)
- **[`exact_sign_3x3`][example-exact-sign]** — exact determinant sign of a near-singular 3×3 matrix (requires `exact` feature)
- **[`exact_solve_3x3`][example-exact-solve]** — exact solve of a near-singular 3×3 system vs f64 LU (requires `exact` feature)
- **[`ldlt_solve_3x3`][example-ldlt-solve]** — solve a 3×3 symmetric positive definite system via LDLT
- **[`polynomial_determinant`][example-polynomial]** — exact cancellation, leading coefficients, and explicit work limits (requires `exact` feature)
- **[`rational_input_5x5`][example-rational-input]** — exact rational solve of a 5×5 system that becomes singular as f64 (requires `exact` feature)
- **[`solve_5x5`][example-solve]** — solve a 5×5 system via LU with partial pivoting
- **[`vector_angles`][example-vector-angles]** — unsigned angles for fixed vectors and borrowed slices, including extreme magnitudes and subnormal separations

[example-const-det]: https://github.com/acgetchell/la-stack/blob/main/examples/const_det_4x4.rs
[example-det]: https://github.com/acgetchell/la-stack/blob/main/examples/det_5x5.rs
[example-exact-det]: https://github.com/acgetchell/la-stack/blob/main/examples/exact_det_3x3.rs
[example-exact-sign]: https://github.com/acgetchell/la-stack/blob/main/examples/exact_sign_3x3.rs
[example-exact-solve]: https://github.com/acgetchell/la-stack/blob/main/examples/exact_solve_3x3.rs
[example-ldlt-solve]: https://github.com/acgetchell/la-stack/blob/main/examples/ldlt_solve_3x3.rs
[example-polynomial]: https://github.com/acgetchell/la-stack/blob/main/examples/polynomial_determinant.rs
[example-rational-input]: https://github.com/acgetchell/la-stack/blob/main/examples/rational_input_5x5.rs
[example-solve]: https://github.com/acgetchell/la-stack/blob/main/examples/solve_5x5.rs
[example-vector-angles]: https://github.com/acgetchell/la-stack/blob/main/examples/vector_angles.rs

```bash
just examples
# or individually:
cargo run --example const_det_4x4
cargo run --example det_5x5
cargo run --features exact --example exact_det_3x3
cargo run --features exact --example exact_sign_3x3
cargo run --features exact --example exact_solve_3x3
cargo run --example ldlt_solve_3x3
cargo run --features exact --example rational_input_5x5
cargo run --example solve_5x5
cargo run --locked --example vector_angles
```

## 📈 Benchmarks (vs nalgebra/faer)

<!-- BENCHMARKS:BEGIN -->

![LU solve (factor + solve): median time vs dimension](https://raw.githubusercontent.com/acgetchell/la-stack/v0.5.2/docs/assets/bench/vs_linalg_lu_solve_median_log.svg)

Run: `5af2e5bf8a3aa22f12f45efad18280cebd2b4be31a0612901374306d4a7eb652`. Statistic: median. Unit: ns. Confidence level: 95%.

- la-stack v0.5.2: current phase, v0.5.2 working-tree snapshot based on commit
  `b5156e222add90fc62191db55dcccb40875a5e41`; measured source SHA-256
  `80e684f9e40f0b89417aa4a8317b22e37e0f594aef8043b250656f2c6cb3990f`.
- nalgebra 0.35.0: baseline phase, v0.5.1, revision 80a67d598b8f5788c2c8ffc12a0e8677c306909e.
- faer 0.24.4: baseline phase, v0.5.1, revision 80a67d598b8f5788c2c8ffc12a0e8677c306909e.

| Dimension | la-stack v0.5.2 | nalgebra 0.35.0 | faer 0.24.4 | Speedup vs nalgebra | Speedup vs faer |
| --- | --- | --- | --- | --- | --- |
| 2 | 2.06256<br>[2.04953, 2.09431] | 4.52663<br>[4.51758, 4.53267] | 128.125<br>[127.445, 128.545] | 2.19467× | 62.1194× |
| 3 | 9.98278<br>[9.96279, 10.0083] | 32.5058<br>[32.3949, 32.6237] | 156.551<br>[156.195, 157.093] | 3.25619× | 15.6821× |
| 4 | 23.7355<br>[23.6905, 23.7801] | 52.8361<br>[52.7137, 52.9963] | 183.09<br>[182.58, 183.503] | 2.22603× | 7.71373× |
| 5 | 47.0332<br>[46.9411, 47.2694] | 74.3705<br>[74.1427, 74.7764] | 250.816<br>[250.442, 251.241] | 1.58123× | 5.33275× |
| 8 | 132.096<br>[131.87, 132.513] | 166.8<br>[166.498, 167.23] | 342.479<br>[340.695, 343.771] | 1.26272× | 2.59266× |
| 16 | 631.9<br>[628.777, 638.18] | 589.967<br>[588.536, 591.405] | 900.746<br>[897.01, 902.971] | 0.933639× | 1.42546× |
| 32 | 2772.06<br>[2766.99, 2779.6] | 2499.64<br>[2493.29, 2506.42] | 2998.91<br>[2995.26, 3003.01] | 0.901726× | 1.08183× |
| 64 | 17505.6<br>[17263.4, 17749.8] | 14495.6<br>[14481, 14519.4] | 12840.2<br>[12828.6, 12881.9] | 0.828057× | 0.733493× |

Intervals are recorded marginal timing intervals; ratios are point estimates, with no ratio intervals or significance claims.
Ratio is numerator time / denominator time; greater than one means less denominator time.

- Speedup vs nalgebra: ratio; numerator = nalgebra 0.35.0; denominator = la-stack v0.5.2.
- Speedup vs faer: ratio; numerator = faer 0.24.4; denominator = la-stack v0.5.2.

Selection coverage:

- la-stack v0.5.2: 8 selected; 0 unavailable rows; 1395 phase cases omitted. Complete evidence is retained independently.
- nalgebra 0.35.0: 8 selected; 0 unavailable rows; 1262 phase cases omitted. Complete evidence is retained independently.
- faer 0.24.4: 8 selected; 0 unavailable rows; 1262 phase cases omitted. Complete evidence is retained independently.
- [Complete run evidence]https://github.com/acgetchell/la-stack/blob/v0.5.2/docs/performance-runs/runs/5af2e5bf8a3aa22f12f45efad18280cebd2b4be31a0612901374306d4a7eb652/run.json
- [Evidence envelope]https://github.com/acgetchell/la-stack/blob/v0.5.2/docs/performance-runs/runs/5af2e5bf8a3aa22f12f45efad18280cebd2b4be31a0612901374306d4a7eb652/evidence.json
- [Selected timings CSV]https://github.com/acgetchell/la-stack/blob/v0.5.2/docs/assets/bench/vs_linalg_lu_solve_median_log.csv

<!-- BENCHMARKS:END -->

Representative benchmark: `lu_solve` factors the matrix and solves one
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.

Timings count only when the implementation preserves the documented
correctness guarantees and invariants. Performance claims require comparable
before-and-after evidence using the same inputs, configuration, and environment.
This snapshot records the measured source state, available CPU model, operating system, Rust
toolchain, dependency lock and harness digests, Criterion command, and
correctness-gate result in the linked evidence. The publication workflow
requires complete canonical-dimension coverage and publishes the CSV, SVG,
README table, and evidence links together. Original plot-provenance sidecars
remain available as frozen records.

For the full per-kernel comparison methodology, algorithm citations, input
construction, and release-comparison workflow details, see
[docs/BENCHMARKING.md](https://github.com/acgetchell/la-stack/blob/main/docs/BENCHMARKING.md).
For the current release-to-release performance snapshot, see
[docs/performance.md](https://github.com/acgetchell/la-stack/blob/main/docs/performance.md).
The exact release suite includes the already-exact rational-input groups for
D=2 through D=8. Those rows report `RationalMatrix::det_sign`, `det`, and
`solve` alongside straightforward `BigRational` Gaussian determinant and solve
references. Releases produced with the rational-input harness include Criterion
point estimates and confidence intervals for these rows; comparisons against a
pre-API baseline retain them as explicit current-only measurements.

The focused `interval` Criterion suite covers conclusive and inconclusive
relative-coordinate lifted determinant signs at D=4 and the maximum supported
D=7 workload. Run it with `just bench-interval`; fixture validation stays
outside the timed closures.

The focused `linear_form` Criterion suite compares plain and certified dot
products and covers both well-separated and inconclusive dot/affine-difference
filters at D=4. Run it with `just bench-linear-form`; exact small-integer fixture
expectations are validated outside the timed closures.

## 🤝 Contributing

See [CONTRIBUTING.md](https://github.com/acgetchell/la-stack/blob/main/CONTRIBUTING.md)
for prerequisite setup, checks and fixes, tests, security scans, and PR preparation.
Coverage execution belongs in
[Measuring coverage](https://github.com/acgetchell/la-stack/blob/main/docs/MEASURING_COVERAGE.md).

## 📚 Citation

If you use this library in academic work, please cite it using
[CITATION.cff](https://github.com/acgetchell/la-stack/blob/main/CITATION.cff)
(or GitHub's "Cite this repository" feature). Tagged releases are archived on
Zenodo under the
[all-versions concept DOI](https://doi.org/10.5281/zenodo.18158926).

## 🔎 References

For canonical references to the algorithms used by this crate, see
[REFERENCES.md](https://github.com/acgetchell/la-stack/blob/main/REFERENCES.md).

## 🤖 AI Agents

AI coding assistants should read
[AGENTS.md](https://github.com/acgetchell/la-stack/blob/main/AGENTS.md)
before proposing or applying changes. See
[CONTRIBUTING.md](https://github.com/acgetchell/la-stack/blob/main/CONTRIBUTING.md)
for the repository's AI-assisted development note.

## 📜 License

BSD 3-Clause License. See [LICENSE](https://github.com/acgetchell/la-stack/blob/main/LICENSE).

[audit-badge]: https://github.com/acgetchell/la-stack/actions/workflows/audit.yml/badge.svg?branch=main
[api-column-basis]: https://docs.rs/la-stack/latest/la_stack/fn.column_basis.html
[api-polynomial]: https://docs.rs/la-stack/latest/la_stack/fn.polynomial_determinant.html
[api-polynomial-budget]: https://docs.rs/la-stack/latest/la_stack/struct.PolynomialDeterminantBudget.html
[api-sparse-polynomial]: https://docs.rs/la-stack/latest/la_stack/struct.SparsePolynomial.html
[api-rational-dot]: https://docs.rs/la-stack/latest/la_stack/struct.RationalVector.html#method.dot
[api-rational-dot-slice]: https://docs.rs/la-stack/latest/la_stack/fn.rational_dot.html
[audit-workflow]: https://github.com/acgetchell/la-stack/actions/workflows/audit.yml
[ci-badge]: https://github.com/acgetchell/la-stack/actions/workflows/ci.yml/badge.svg?branch=main
[ci-workflow]: https://github.com/acgetchell/la-stack/actions/workflows/ci.yml
[clippy-badge]: https://github.com/acgetchell/la-stack/actions/workflows/rust-clippy.yml/badge.svg?branch=main
[clippy-workflow]: https://github.com/acgetchell/la-stack/actions/workflows/rust-clippy.yml
[codeql-badge]: https://github.com/acgetchell/la-stack/actions/workflows/codeql.yml/badge.svg?branch=main
[codeql-workflow]: https://github.com/acgetchell/la-stack/actions/workflows/codeql.yml
[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
[refs-gram]: https://github.com/acgetchell/la-stack/blob/main/REFERENCES.md#gram-matrices-and-geometric-measures
[refs-interval]: https://github.com/acgetchell/la-stack/blob/main/REFERENCES.md#outward-rounded-interval-determinant-sign
[refs-ldlt]: https://github.com/acgetchell/la-stack/blob/main/REFERENCES.md#ldlᵀ-factorization-exactly-symmetric-positive-definite-inputs
[refs-lu]: https://github.com/acgetchell/la-stack/blob/main/REFERENCES.md#lu-decomposition-gaussian-elimination-with-partial-pivoting
[refs-reductions]: https://github.com/acgetchell/la-stack/blob/main/REFERENCES.md#certified-fixed-vector-reductions
[semgrep-badge]: https://github.com/acgetchell/la-stack/actions/workflows/semgrep-sarif.yml/badge.svg?branch=main
[semgrep-workflow]: https://github.com/acgetchell/la-stack/actions/workflows/semgrep-sarif.yml
[zizmor-badge]: https://github.com/acgetchell/la-stack/actions/workflows/zizmor.yml/badge.svg?branch=main
[zizmor-workflow]: https://github.com/acgetchell/la-stack/actions/workflows/zizmor.yml