pub struct IntervalMatrix<const D: usize> { /* private fields */ }Expand description
Fixed-size square matrix of outward-rounded Interval entries.
Storage is the inline array [[Interval; D]; D]. Determinants use a
division-free Leibniz subset DP through D=7, so zero-containing pivot
intervals never require a special case and no heap allocation occurs.
solve uses interval Gaussian elimination with row pivoting
and explicitly reports inconclusive pivots. It has no determinant dimension
limit, uses O(D²) stack storage, and is intended for small systems.
§Examples
use la_stack::prelude::*;
let matrix = IntervalMatrix::<3>::try_from_point_rows([
[0.0, 1.0, 0.0],
[1.0, 0.0, 0.0],
[0.0, 0.0, 1.0],
])?;
assert_eq!(matrix.det_sign()?, IntervalDeterminantSign::Negative);Implementations§
Source§impl<const D: usize> IntervalMatrix<D>
impl<const D: usize> IntervalMatrix<D>
Sourcepub const fn from_rows(rows: [[Interval; D]; D]) -> Self
pub const fn from_rows(rows: [[Interval; D]; D]) -> Self
Construct an interval matrix from already-validated interval rows.
See det for an example with non-point entries.
Sourcepub const fn try_from_point_rows(rows: [[f64; D]; D]) -> Result<Self, LaError>
pub const fn try_from_point_rows(rows: [[f64; D]; D]) -> Result<Self, LaError>
Lift finite binary64 rows into point intervals.
This preserves the stored binary64 values exactly; it does not recover
uncertainty from arithmetic performed before this call.
See IntervalMatrix for a determinant-sign example using this constructor.
§Errors
Returns LaError::NonFinite with matrix coordinates for the first NaN
or infinity in row-major order.
Sourcepub const fn from_matrix(matrix: &Matrix<D>) -> Self
pub const fn from_matrix(matrix: &Matrix<D>) -> Self
Lift a finite Matrix into point intervals.
Earlier rounded expression construction is not enclosed; use interval operations while constructing derived coefficients when that uncertainty belongs in the proof.
§Examples
use la_stack::prelude::*;
let matrix = Matrix::<2>::try_from_rows([[2.0, 0.0], [0.0, 3.0]])?;
let intervals = IntervalMatrix::from_matrix(&matrix);
assert_eq!(intervals.det()?, Interval::point(6.0)?);Sourcepub const fn into_rows(self) -> [[Interval; D]; D]
pub const fn into_rows(self) -> [[Interval; D]; D]
Consume this matrix and return its row-major interval storage.
Sourcepub const fn get(&self, row: usize, column: usize) -> Option<Interval>
pub const fn get(&self, row: usize, column: usize) -> Option<Interval>
Get an interval entry with bounds checking.
Sourcepub const fn try_get(
&self,
row: usize,
column: usize,
) -> Result<Interval, LaError>
pub const fn try_get( &self, row: usize, column: usize, ) -> Result<Interval, LaError>
Get an interval entry while preserving index context on failure.
See set for an example of mutation and checked access.
§Errors
Returns LaError::IndexOutOfBounds when either index is not < D.
Sourcepub const fn set(
&mut self,
row: usize,
column: usize,
value: Interval,
) -> Result<(), LaError>
pub const fn set( &mut self, row: usize, column: usize, value: Interval, ) -> Result<(), LaError>
Set an interval entry with bounds checking.
Validation is unnecessary for the value because Interval already
carries the finite ordered-bound proof. An invalid index leaves the
matrix unchanged.
§Examples
use core::assert_matches;
use la_stack::prelude::*;
let mut matrix = IntervalMatrix::<2>::identity();
let range = Interval::try_new(2.0, 3.0)?;
matrix.set(0, 0, range)?;
assert_eq!(matrix.try_get(0, 0)?, range);
let before = matrix;
assert_matches!(
matrix.set(2, 0, Interval::ZERO),
Err(LaError::IndexOutOfBounds { row: 2, col: 0, dim: 2, .. })
);
assert_eq!(matrix, before);§Errors
Returns LaError::IndexOutOfBounds when either index is not < D.
Sourcepub const fn solve(&self, rhs: &[Interval; D]) -> Result<[Interval; D], LaError>
pub const fn solve(&self, rhs: &[Interval; D]) -> Result<[Interval; D], LaError>
Enclose the solution of every real system A x = b admitted by these
coefficient intervals and rhs.
On success every admitted A is nonsingular and the unique exact-real
solution satisfies x[i] ∈ result[i]. Entries vary independently; any
correlations introduced during expression assembly are safely widened.
The enclosure need not be tight. Wide intervals and ill-conditioning
can prevent certification even when every admitted matrix is invertible.
Uses outward-rounded Gaussian elimination and back substitution, with
row pivots maximizing their minimum distance from zero (first row wins
ties). No tolerance admits a zero-containing pivot. See REFERENCES.md
[20] and the
enclosure proof.
Both shapes are fixed by D. All const dimensions are supported, with
O(D³) work and O(D²) inline scratch space intended for small systems;
D=0 returns the empty solution. Inputs are unchanged on all outcomes.
This operation is available without the exact feature.
§Examples
use la_stack::prelude::*;
let matrix = IntervalMatrix::try_from_point_rows([[0.0, 2.0], [3.0, 1.0]])?;
let rhs = [Interval::point(4.0)?, Interval::point(5.0)?];
let x = matrix.solve(&rhs)?;
assert!(x[0].contains(1.0) && x[1].contains(2.0));§Errors
Returns LaError::IntervalSolveInconclusive at the first column whose
remaining pivot intervals all contain zero, including the final column.
This never establishes singularity, even for point inputs or [0, 0]
pivots; this method never returns LaError::Singular.
Returns LaError::IntervalRangeExhausted with
ArithmeticOperation::IntervalSolve if an intermediate or result has
no finite enclosure. Both outcomes require the caller’s fallback when a
certified answer is needed. Invalid raw endpoints are rejected by the
interval constructors before this method can be called.
Sourcepub const fn det(&self) -> Result<Interval, LaError>
pub const fn det(&self) -> Result<Interval, LaError>
Enclose the determinant with division-free subset dynamic programming.
For each column subset, the DP stores the determinant interval of the
leading rows and those columns. This evaluates the Leibniz expansion in
D × 2^(D-1) products and additions without choosing or dividing by a
pivot. The returned interval therefore encloses every exact-real
determinant represented by the input intervals, subject only to an
explicit range failure.
The D=0 determinant follows the empty-product convention and is [1, 1].
Use det_sign when only sign evidence is needed.
§Examples
use la_stack::prelude::*;
// Every represented diagonal matrix has a determinant in [8, 15].
let matrix = IntervalMatrix::<2>::from_rows([
[Interval::try_new(2.0, 3.0)?, Interval::ZERO],
[Interval::ZERO, Interval::try_new(4.0, 5.0)?],
]);
assert_eq!(matrix.det()?, Interval::try_new(8.0, 15.0)?);§Errors
Returns LaError::UnsupportedDimension for D>7. Returns
LaError::IntervalRangeExhausted with interval-determinant provenance
when an exact intermediate has no finite binary64 enclosure; callers can
then proceed to an exact or higher-range fallback.
Sourcepub const fn det_sign(&self) -> Result<IntervalDeterminantSign, LaError>
pub const fn det_sign(&self) -> Result<IntervalDeterminantSign, LaError>
Return proof-bearing determinant sign evidence.
An interval strictly on one side of zero proves that sign. Only the
singleton interval [0, 0] proves Zero; every other overlap with zero
is IntervalDeterminantSign::Inconclusive.
§Examples
use la_stack::prelude::*;
let mut matrix = IntervalMatrix::<2>::identity();
assert_eq!(matrix.det_sign()?, IntervalDeterminantSign::Positive);
matrix.set(0, 0, Interval::try_new(-1.0, 1.0)?)?;
// This range includes nonsingular matrices of both signs; a caller
// needs tighter or exact input before it can decide singularity.
assert_eq!(matrix.det_sign()?, IntervalDeterminantSign::Inconclusive);
matrix.set(0, 0, Interval::ZERO)?;
assert_eq!(matrix.det_sign()?, IntervalDeterminantSign::Zero);§Errors
Propagates the dimension and arithmetic range failures from
det.