Skip to main content

Vector

Struct Vector 

Source
pub struct Vector<const D: usize> { /* private fields */ }
Expand description

Finite fixed-size vector of length D, stored inline.

Public construction rejects NaN and infinity through try_new, and the storage field is private, so a Vector value carries the invariant that every stored entry is finite. Algorithms therefore do not re-scan stored entries at every use; user-visible non-finite errors come from construction boundaries or from values computed during arithmetic, such as overflowed accumulators.

Direct field construction is intentionally unavailable to downstream callers:

use la_stack::Vector;

let _ = Vector::<2> {
    data: [1.0, f64::NAN],
};

Implementations§

Source§

impl<const D: usize> Vector<D>

Source

pub const fn try_new(data: [f64; D]) -> Result<Self, LaError>

Try to create a finite vector from a backing array.

This is the public raw-storage boundary for vectors. Successful construction makes the returned Vector a finite-storage proof.

§Examples
use la_stack::prelude::*;

let v = Vector::<3>::try_new([1.0, 2.0, 3.0])?;
assert_eq!(v.into_array(), [1.0, 2.0, 3.0]);
§Errors

Returns LaError::NonFinite with the first offending entry index when data contains NaN or infinity.

Source

pub const fn zero() -> Self

All-zeros finite vector.

§Examples
use la_stack::prelude::*;

let z = Vector::<2>::zero();
assert_eq!(z.into_array(), [0.0, 0.0]);
Source

pub const fn as_array(&self) -> &[f64; D]

Borrow the finite backing array.

§Examples
use la_stack::prelude::*;

let v = Vector::<2>::try_new([1.0, -2.0])?;
assert_eq!(v.as_array(), &[1.0, -2.0]);
Source

pub const fn into_array(self) -> [f64; D]

Consume and return the finite backing array.

§Examples
use la_stack::prelude::*;

let v = Vector::<2>::try_new([1.0, 2.0])?;
let a = v.into_array();
assert_eq!(a, [1.0, 2.0]);
Source

pub const fn dot(&self, other: &Self) -> Result<f64, LaError>

Dot product.

Terms are accumulated in f64 using f64::mul_add at each index. Intermediate rounding occurs, and this method does not provide a certified absolute rounding bound for the returned dot product. Raw Vector values are finite by construction, so this method only checks whether the accumulation overflows to NaN or infinity.

§Examples
use la_stack::prelude::*;

let a = Vector::<3>::try_new([1.0, 2.0, 3.0])?;
let b = Vector::<3>::try_new([-2.0, 0.5, 4.0])?;
assert!((a.dot(&b)? - 11.0).abs() <= 1e-12);
§Errors

Returns LaError::NonFinite when the accumulated dot product overflows to NaN or infinity.

Source

pub const fn dot_with_errbound( &self, other: &Self, ) -> Result<Option<ScalarWithErrorBound>, LaError>

Dot product with a certified absolute roundoff bound.

The estimate uses the deterministic left-to-right recurrence s[0] = 0 and s[i + 1] = self[i].mul_add(other[i], s[i]). When the relative-error model is valid, the returned certificate bounds the difference between s[D] and the exact-real expression Σᵢ self[i] × other[i] over the stored binary64 inputs.

The bound is gamma_D × Σᵢ |self[i] × other[i]|, where gamma_D = D u / (1 - D u) and u = 2^-53. The magnitude sum and the published bound are rounded upward. See REFERENCES.md [9-11].

Ok(None) means no certificate is available because a nonzero product or FMA result entered the subnormal range, the reduction dimension made gamma_D invalid, or a proof-only magnitude/bound calculation exhausted the finite binary64 range. It does not mean the exact dot product is zero. Unlike a user-selected tolerance, a returned error bound describes rounding in this specific arithmetic tree.

§Examples
use la_stack::prelude::*;

let left = Vector::<3>::try_new([1.0, 2.0, 3.0])?;
let right = Vector::<3>::try_new([4.0, 5.0, 6.0])?;
let positive = left.dot_with_errbound(&right)?.and_then(|bounded| {
    if bounded.lower_bound() > 0.0 {
        Some(true)
    } else if bounded.upper_bound() <= 0.0 {
        Some(false)
    } else {
        None // The enclosure cannot establish whether the result is positive.
    }
});
assert_eq!(positive, Some(true));

// Finite inputs can also lack a certificate; use an exact fallback
// before deciding the sign in this case.
let tiny = Vector::<2>::try_new([1e-200, 1e-200])?;
assert_eq!(tiny.dot_with_errbound(&tiny)?, None);
§Errors

Returns LaError::NonFinite with the first failing reduction index and ArithmeticOperation::VectorDotProduct when an FMA estimate becomes non-finite.

Source

pub const fn dot_difference_with_errbound( &self, left: &Self, right: &Self, ) -> Result<Option<ScalarWithErrorBound>, LaError>

Certified dot product with an unrounded vector difference.

This evaluates the exact-real expression Σᵢ self[i] × (left[i] - right[i]) without first rounding left - right into a Vector. Its deterministic arithmetic tree is

s[0]       = 0
s[2i + 1]  = self[i].mul_add(left[i], s[2i])
s[2i + 2]  = (-self[i]).mul_add(right[i], s[2i + 1]).

A returned certificate therefore includes all 2D FMA rounding events in that tree and bounds the intended expression over the original binary64 coordinates. When available, its absolute bound is gamma_2D × Σᵢ (|self[i] × left[i]| + |self[i] × right[i]|), where gamma_2D = 2D u / (1 - 2D u) and u = 2^-53; every magnitude and the final bound are rounded upward. Its lower_bound and upper_bound can certify a sign or separation from a caller’s threshold. An overlapping endpoint range remains inconclusive and should trigger the caller’s exact fallback.

Ok(None) has the same proof-unavailable meaning as in dot_with_errbound, including gradual underflow and proof-only range exhaustion.

§Examples
use la_stack::prelude::*;

let axis = Vector::<2>::try_new([2.0, -1.0])?;
let left = Vector::<2>::try_new([4.0, 1.0])?;
let right = Vector::<2>::try_new([1.0, 3.0])?;
let separated = axis.dot_difference_with_errbound(&left, &right)?.and_then(|bounded| {
    if bounded.lower_bound() > 1.0 {
        Some(true)
    } else if bounded.upper_bound() <= 1.0 {
        Some(false)
    } else {
        None // An exact fallback is needed to decide this threshold test.
    }
});
// An unavailable certificate also remains None through and_then.
assert_eq!(separated, Some(true));
§Errors

Returns LaError::NonFinite with the first failing coordinate index and ArithmeticOperation::VectorDotDifference when either FMA for that coordinate produces a non-finite estimate.

Source

pub const fn norm_squared(&self) -> Result<f64, LaError>

Squared Euclidean norm.

This is computed as dot(self, self), so norm_squared has the same f64 mul_add accumulation behavior as dot. Intermediate rounding occurs, and this method does not provide a certified absolute rounding bound for the returned squared norm. Vector values are finite by construction, so this method only checks whether the accumulation overflows to NaN or infinity.

§Examples
use la_stack::prelude::*;

let v = Vector::<3>::try_new([1.0, 2.0, 3.0])?;
assert!((v.norm_squared()? - 14.0).abs() <= 1e-12);
§Errors

Returns LaError::NonFinite when the accumulated norm overflows to NaN or infinity.

Source

pub fn norm(&self) -> Result<f64, LaError>

Overflow- and underflow-safe Euclidean norm.

This computes sqrt(Σᵢ self[i]²) with a deterministic left-to-right scaled sum-of-squares recurrence. Each non-zero magnitude is divided by the largest magnitude seen so far before it is squared, so intermediate squares cannot overflow and an all-subnormal vector is scaled into the normal range. See REFERENCES.md [15].

The divisions, fused multiply-adds, square root, and final rescaling are rounded in binary64. This method does not claim correct rounding or provide a certified absolute error bound. Because Vector entries are finite by construction, it returns a finite non-negative result unless the exact Euclidean norm rounds outside the finite binary64 range. Near that boundary, a fixed-size stack accumulator sums the coordinate squares exactly and compares squared rounding midpoints. This fallback prevents accumulated roundoff from causing or hiding overflow and does not require the exact feature.

Unlike norm_squared, this method does not require the squared norm to be representable. For example, the norm of [1.0e200, 1.0e200] is finite even though its squared norm is not.

§Examples
use la_stack::prelude::*;

let ordinary = Vector::<2>::try_new([3.0, 4.0])?;
assert_eq!(ordinary.norm()?, 5.0);
assert_eq!(ordinary.norm_squared()?, 25.0);

let large = Vector::<2>::try_new([1.0e200, 1.0e200])?;
assert!(large.norm()?.is_finite());
assert_eq!(
    large.norm_squared(),
    Err(LaError::non_finite_computation_step(ArithmeticOperation::VectorSquaredNorm, 0)),
);
§Errors

Returns LaError::NonFinite with ArithmeticOperation::VectorNorm when the exact Euclidean norm rounds to infinity under round-to-nearest, ties-to-even.

Trait Implementations§

Source§

impl<const D: usize> Clone for Vector<D>

Source§

fn clone(&self) -> Vector<D>

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<const D: usize> Copy for Vector<D>

Source§

impl<const D: usize> Debug for Vector<D>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<const D: usize> Default for Vector<D>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<const D: usize> PartialEq for Vector<D>

Source§

fn eq(&self, other: &Vector<D>) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl<const D: usize> StructuralPartialEq for Vector<D>

Auto Trait Implementations§

§

impl<const D: usize> Freeze for Vector<D>
where [f64; D]: Freeze,

§

impl<const D: usize> RefUnwindSafe for Vector<D>
where [f64; D]: RefUnwindSafe,

§

impl<const D: usize> Send for Vector<D>
where [f64; D]: Send,

§

impl<const D: usize> Sync for Vector<D>
where [f64; D]: Sync,

§

impl<const D: usize> Unpin for Vector<D>
where [f64; D]: Unpin,

§

impl<const D: usize> UnsafeUnpin for Vector<D>
where [f64; D]: UnsafeUnpin,

§

impl<const D: usize> UnwindSafe for Vector<D>
where [f64; D]: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.