Expand description
§algea
Portable, SIMD-accelerated vectors and matrices.
algea provides small fixed-size algebra types whose storage and operations
are selected for the target. It supports f32, f64, i32, i64, u32, and
u64 elements, with vector dimensions and matrix row and column counts from one
through four. Both row_major and column_major matrix storage are
supported.
Implementations pursue target-specific performance, so floating-point results are not guaranteed to be bit-for-bit identical; see Floating-point reproducibility.
§Stability
Documented public APIs follow Semantic Versioning.
The __internal module is public solely to support implementation details that
must remain reachable across crate boundaries, including bounds on public APIs.
It is not a supported public API and may be changed, moved, or removed in any
release. Downstream crates must not refer to it directly.
§Examples
Vectors provide lane-wise arithmetic and common geometric operations:
use algea::vector;
let a = vector![1.0_f32, 2.0, 3.0];
let b = vector![4.0_f32, 5.0, 6.0];
assert_eq!(a + b, vector![5.0, 7.0, 9.0]);
assert_eq!(a.dot(b), 32.0);Row-major matrices are constructed from rows:
use algea::row_major::Matrix;
let a = Matrix::<f32, 2, 2>::from_rows([[1.0, 2.0], [3.0, 4.0]]);
let b = Matrix::<f32, 2, 2>::from_rows([[5.0, 6.0], [7.0, 8.0]]);
assert_eq!((a * b).to_rows(), [[19.0, 22.0], [43.0, 50.0]]);Column-major matrices represent the same operations but are constructed from columns:
use algea::column_major::Matrix;
let a = Matrix::<f32, 2, 2>::from_columns([[1.0, 3.0], [2.0, 4.0]]);
let b = Matrix::<f32, 2, 2>::from_columns([[5.0, 7.0], [6.0, 8.0]]);
assert_eq!((a * b).to_columns(), [[19.0, 43.0], [22.0, 50.0]]);Elements convert between types with cast:
use algea::vector;
let v = vector![1.5_f64, -2.5, 3.5];
assert_eq!(v.cast::<i32>(), vector![1_i32, -2, 3]);§Generic code
The Element family of traits expresses which element types and dimensions
are available. Generic code can state that requirement in either of the
following equivalent forms:
use algea::{Element, Vector};
fn by_parameter<T: Element<D>, const D: usize>(value: Vector<T, D>) {
let _ = value;
}
fn by_where_clause<const D: usize>(value: Vector<f32, D>)
where
f32: Element<D>,
{
let _ = value;
}§Arithmetic semantics
Operations follow std::simd::Simd, not the scalar operators, wherever the two
differ. Integer addition, subtraction, multiplication, and negation therefore
wrap in both debug and release builds; integer division by zero panics; and
dividing the most negative value by -1 wraps back to that value. SIMD padding
lanes do not participate in public operations or panic checks.
Casting an element follows Rust’s as conversion, as std::simd::Simd::cast
does, for every pair of supported types. That includes saturation at the
destination’s limits and NaN becoming zero when a floating-point value becomes
an integer, and the sign of zero when a floating-point value changes width. The
bit pattern of a NaN result is not specified.
§Floating-point reproducibility
A floating-point result is not guaranteed to be the same everywhere. What varies, and why:
- Between targets. Each backend picks the order of additions and whether to use fused multiply-add from what the target offers, so the same expression can round differently on x86-64, aarch64 and WebAssembly.
- Between target-feature sets of one target. Enabling FMA on x86-64, or
relaxed-simdon WebAssembly, changes how many roundings an expression takes. - Between runtimes, on WebAssembly with
relaxed-simd. Those instructions leave fusing to the runtime, so one binary can round differently under two engines.wasmtime -W relaxed-simd-deterministic=ypins it to the unfused behaviour. - Between versions of this crate. A release may change the shape of a kernel, and with it the order of additions.
Integer results, comparisons, and casts are exact, so none of this applies to them.
§Layout
Note: The layouts documented below describe the current implementation only. This crate does not guarantee that memory layout, size, alignment, padding, or element placement remains unchanged across crate versions, platforms, or selected backends. These details may change; do not rely on them for serialization, persistent data, FFI, or reinterpreting memory.
When the SIMD backend is selected, vectors have the following layouts. Sizes and
alignments are in bytes. In both tables, a 32-bit T is f32, i32, or u32,
and a 64-bit T is f64, i64, or u64.
| Type | Size (32-bit) | Alignment (32-bit) | Size (64-bit) | Alignment (64-bit) |
|---|---|---|---|---|
Vector<T, 1> | 4 | 4 | 8 | 8 |
Vector<T, 2> | 8 | 8 | 16 | 16 |
Vector<T, 3> | 16 | 16 | 32 | 32 |
Vector<T, 4> | 16 | 16 | 32 | 32 |
SIMD-backed matrices have the following layouts. Each column-major matrix and the transposed row-major shape shown beside it use the same storage layout.
| Type | Size (32-bit) | Alignment (32-bit) | Size (64-bit) | Alignment (64-bit) |
|---|---|---|---|---|
column_major::Matrix<T, 1, 1> / row_major::Matrix<T, 1, 1> | 4 | 4 | 8 | 8 |
column_major::Matrix<T, 2, 1> / row_major::Matrix<T, 1, 2> | 8 | 8 | 16 | 16 |
column_major::Matrix<T, 3, 1> / row_major::Matrix<T, 1, 3> | 16 | 16 | 32 | 32 |
column_major::Matrix<T, 4, 1> / row_major::Matrix<T, 1, 4> | 16 | 16 | 32 | 32 |
column_major::Matrix<T, 1, 2> / row_major::Matrix<T, 2, 1> | 8 | 8 | 16 | 16 |
column_major::Matrix<T, 2, 2> / row_major::Matrix<T, 2, 2> | 16 | 16 | 32 | 32 |
column_major::Matrix<T, 3, 2> / row_major::Matrix<T, 2, 3> | 32 | 16 | 64 | 32 |
column_major::Matrix<T, 4, 2> / row_major::Matrix<T, 2, 4> | 32 | 16 | 64 | 32 |
column_major::Matrix<T, 1, 3> / row_major::Matrix<T, 3, 1> | 16 | 16 | 32 | 32 |
column_major::Matrix<T, 2, 3> / row_major::Matrix<T, 3, 2> | 32 | 16 | 48 or 64 | 16 or 32 |
column_major::Matrix<T, 3, 3> / row_major::Matrix<T, 3, 3> | 48 | 16 | 96 | 32 |
column_major::Matrix<T, 4, 3> / row_major::Matrix<T, 3, 4> | 48 | 16 | 96 | 32 |
column_major::Matrix<T, 1, 4> / row_major::Matrix<T, 4, 1> | 16 | 16 | 32 | 32 |
column_major::Matrix<T, 2, 4> / row_major::Matrix<T, 4, 2> | 32 | 16 | 64 | 32 |
column_major::Matrix<T, 3, 4> / row_major::Matrix<T, 4, 3> | 64 | 16 | 128 | 32 |
column_major::Matrix<T, 4, 4> / row_major::Matrix<T, 4, 4> | 64 | 16 | 128 | 32 |
The 2x3 shape is the one whose 64-bit storage depends on the target: three two-lane units, 48 bytes with alignment 16, unless a four-lane 64-bit value occupies one register, where it is two four-lane units, 64 bytes with alignment 32.
When the non-SIMD backend is selected, storage uses scalar arrays instead. A
Vector<T, D> then has the size of D elements and the alignment of one, and a
matrix has the size of R * C elements with the same alignment. The SIMD tables
above therefore do not describe non-SIMD layouts.
§Comparison and alternatives
algea focuses on portable, target-selected SIMD implementations of small
fixed-size vectors and matrices, with explicit row-major and column-major
storage. Depending on the application, another crate may be a better fit.
✅ supported, ⚠️ conditional or partial, see the footnote, ❌ not supported.
| Crate | x86 SIMD | ARM NEON | Wasm SIMD | no_std | Generic element | Generic size | Integer vectors | Lane-wise vector * | Non-square matrices | Column-major | Row-major | Same results across targets | Three-lane vector | 4x4 matrix |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
algea | ✅ | ✅ | ✅ | ❌ | ✅ | ⚠️ 1 | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ 2 | Vector<f32, 3> | Matrix<f32, 4, 4> |
glam 0.33 | ✅ 3 | ✅ 3 | ✅ 3 | ✅ 4 | ❌ 5 | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ 6 | Vec3, Vec3A 3 | Mat4 |
nalgebra 0.35 | ⚠️ 7 | ⚠️ 7 | ⚠️ 7 | ✅ 4 | ✅ | ✅ 8 | ✅ | ❌ 9 | ✅ | ✅ | ❌ | ✅ 10 | Matrix<f32, U3, U1, ArrayStorage<f32, 3, 1>> 11 | Matrix<f32, U4, U4, ArrayStorage<f32, 4, 4>> 11 |
cgmath 0.18 | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ 12 | ❌ | ✅ | ❌ | ✅ 10 | Vector3<f32> | Matrix4<f32> |
euclid 0.22 | ❌ | ❌ | ❌ | ✅ | ✅ 13 | ❌ | ✅ | ❌ 14 | ❌ | ✅ | ❌ | ✅ 10 | Vector3D<f32, U> | Transform3D<f32, S, D> |
ultraviolet 0.9 | ⚠️ 15 | ⚠️ 15 | ⚠️ 15 | ❌ | ❌ 5 | ❌ | ⚠️ 16 | ✅ | ❌ | ✅ | ❌ | ⚠️ 15 | Vec3 | Mat4 |
vek 0.17 | ⚠️ 17 | ⚠️ 17 | ⚠️ 17 | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ 18 | ✅ 10 | Vec3<f32> | Mat4<f32> 18 |
pathfinder_geometry 0.5 | ✅ | ⚠️ 19 | ❌ | ❌ | ❌ 5 | ❌ | ⚠️ 20 | ✅ | ❌ | ✅ | ❌ | ❌ | Vector3F | Transform4F |
§License
Licensed under either of Apache License, Version 2.0 or the MIT license, at your option.
Vector dimensions and matrix row and column counts are generic parameters, but only one through four are implemented. ↩
See Floating-point reproducibility for what varies and why. Whether the other crates hold their arithmetic fixed from one version to the next is not stated here either way. ↩
On by default and used for
Vec3A,Mat4and the other 16-byte-aligned types; thescalar-mathfeature turns it off andcore-simdswaps it forstd::simd. ↩ 1 2 3 4With
default-features = false, and alibmfeature for the floating-point functions. ↩ 1 2Separate concrete types per element type rather than one generic type. ↩ 1 2 3
Documented as the default, with the
fast-mathfeature as the opt-out that allows platform-specific optimizations. ↩SIMD comes from
simba’s SIMD element types, which put several matrices in the lanes of one value rather than the lanes of one matrix. The crate itself has no target-specific code paths. ↩ 1 2 3Also
SMatrix<f32, R, C>for any static size, dimensions beyond four, dynamically sized matrices, and decompositions. ↩*is the matrix product, and a vector is a one-column matrix, sov * wdoes not compile. The element-wise product is thecomponent_mulmethod. ↩Follows from having no target-specific code paths, rather than from a documented guarantee. ↩ 1 2 3 4
Usually written through the aliases
Vector3<f32>andMatrix4<f32>. ↩ 1 2*multiplies by a scalar. The element-wise product isElementWise::mul_element_wise. ↩Also generic over a unit marker, so lengths in different spaces do not mix. ↩
*multiplies by a scalar or applies a transform. The element-wise product is thecomponent_mulmethod. ↩In the wide types,
Vec3x4andMat4x4for example. Each of those holds four or eight separate vectors or matrices, one per lane, and followswide’s per-target paths; a loneVec3orMat4is plain scalar code. ↩ 1 2 3 4Needs the
intfeature, which is not enabled by default. ↩The
repr_simdfeature unlocks SIMD variants of the types, and needs a nightly compiler. ↩ 1 2 3Mat4<f32>is the column-major type; the row-major one isvek::mat::repr_c::row_major::Mat4<f32>. ↩ 1 2Only on a nightly compiler. ↩
Vector2Ionly. ↩
Re-exports§
pub use support::Element;pub use support::FloatElement;pub use support::IntElement;pub use support::MaskElement;pub use support::SintElement;pub use support::UintElement;
Modules§
- column_
major - Column-major matrices and their multiplication traits.
- marker
- Marker traits describing scalar lane capabilities.
- row_
major - Row-major matrices and their multiplication traits.
- support
- Dimension-dependent traits used to express supported vector and matrix types.
Macros§
- vector
- Constructs a vector by concatenating scalar and vector expressions.
Structs§
- Mask
- A lane mask represented by signed integer lanes.
- Vector
- A fixed-size, orientation-independent vector.