14 unstable releases (3 breaking)
✓ Uses Rust 2018 edition
|0.4.1||Sep 19, 2019|
|0.4.0||Sep 19, 2019|
|0.3.2||Aug 29, 2019|
|0.3.1||Jul 30, 2019|
|0.1.0||Jun 21, 2019|
#26 in Math
193 downloads per month
An experimental n-dimensional linear algebra and mathematics library for the Rust programming language that makes extensive use of unstable Rust features.
aljabar supports Vectors and Matrices of any size and will provide implementations for any mathematic operations that are supported by their scalars. Additionally, aljabar can leverage Rust's type system to ensure that operations are only applied to values that are the correct size.
aljabar relies heavily on unstable Rust features such as const generics and thus requires nightly to build.
Currently, aljabar supports only
Matrix types. Over the long
term aljabar is intended to be feature compliant with cgmath.
Vectors can be constructed from arrays of any type and size. Use the
macro to easily construct a vector:
let a = vector![ 0u32, 1, 2, 3 ]; assert_eq!( a, Vector::<u32, 4>::from([ 0u32, 1, 2, 3 ]) );
Neg will be properly implemented for any
for any respective implementation of such operations for
are only implemented for vectors of equal sizes.
let b = Vector::<f32, 7>::from([ 0.0f32, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, ]); let c = Vector::<f32, 7>::from([ 1.0f32, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, ]) * 0.5; assert_eq!( b + c, Vector::<f32, 7>::from([ 0.5f32, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5 ]) );
If the scalar type implements
Mul as well, then the Vector will be an
InnerSpace and have the
dot product defined for it, as well as the ability
to find the squared distance between two vectors (implements
the squared magnitude of a vector. If the scalar type is a real number then the
distance between two vectors and the magnitude of a vector can be found in
let a = vector!(1i32, 1); let b = vector!(5i32, 5); assert_eq!(a.distance2(b), 32); // distance method not implemented. assert_eq!((b - a).magnitude2(), 32); // magnitude method not implemented. let a = vector!(1.0f32, 1.0); let b = vector!(5.0f32, 5.0); const close: f32 = 5.65685424949; assert_eq!(a.distance(b), close); // distance is implemented. assert_eq!((b - a).magnitude(), close); // magnitude is implemented. // Vector normalization is also supported for floating point scalars. assert_eq!( vector!(0.0f32, 20.0, 0.0) .normalize(), vector!(0.0f32, 1.0, 0.0) );
is supported for both the
rgba conventions. All possible combinations
of the first four elements of a vector are supported. Single-element swizzle
functions return scalar results, multi-element swizzle functions return vector
results of the appropriate size based on the number of selected elements.
let a = vector!(0.0f32, 1.0, 2.0, 3.0); // A single element is returned as a scalar. assert_eq!(1.0, a.y()); // Multiple elements are returned as a vector. assert_eq!(vector!(2.0, 0.0, 3.0), a.zxw()); // The same element can be selected more than once. assert_eq!(vector!(0.0f32, 0.0), a.rr());
rgba swizzle conventions is not allowed.
let a = vector!(0.0f32, 1.0, 2.0, 3.0); let b = a.rgzw(); // Does not compile.
Swizzling is supported on vectors of length less than 4. Attempting to access elements past the length of the vector is a compile error.
let a = vector!(0.0f32, 1.0, 2.0); let b = a.xyz(); // OK, only accesses the first 3 elements. let c = a.rgba(); // Compile error, attempts to access missing 4th element.
Matrices can be created from arrays of vectors of any size and scalar type.
Matrices are column-major and constructing a matrix from a raw array reflects
matrix! macro can be used to construct a matrix in row-major order:
let a = Matrix::<f32, 3, 3>::from( [ vector!(1.0, 0.0, 0.0), vector!(0.0, 1.0, 0.0), vector!(0.0, 0.0, 1.0), ] ); let b: Matrix::<i32, 3, 3> = matrix![ [ 0, -3, 5 ], [ 6, 1, -4 ], [ 2, 3, -2 ] ];
All operations performed on matrices produce fixed-size outputs. For example,
transpose of a non-square matrix will produce a matrix with the
width and height swapped:
assert_eq!( Matrix::<i32, 1, 2>::from( [ vec1( 1 ), vec1( 2 ) ] ) .transpose(), Matrix::<i32, 2, 1>::from( [ vec2( 1, 2 ) ] ) );
As with Vectors, if the underlying scalar type supports the appropriate
Matrix will implement element-wise
Sub for matrices
of equal size:
let a = mat1x1( 1u32 ); let b = mat1x1( 2u32 ); let c = mat1x1( 3u32 ); assert_eq!(a + b, c);
And this is true for any type that implements
Add, so therefore the following
is possible as well:
let a = mat1x1(mat1x1(1u32)); let b = mat1x1(mat1x1(2u32)); let c = mat1x1(mat1x1(3u32)); assert_eq!(a + b, c);
For a given type
T: Clone and
Vector<T, _> is an
multiplication is defined for
Matrix<T, N, M> * Matrix<T, M, P>. The result is
Matrix<T, N, P>:
let a: Matrix::<i32, 3, 3> = matrix![ [ 0, -3, 5 ], [ 6, 1, -4 ], [ 2, 3, -2 ], ]; let b: Matrix::<i32, 3, 3> = matrix![ [ -1, 0, -3 ], [ 4, 5, 1 ], [ 2, 6, -2 ], ]; let c: Matrix::<i32, 3, 3> = matrix![ [ -2, 15, -13 ], [ -10, -19, -9 ], [ 6, 3, 1 ], ]; assert_eq!( a * b, c );
It is important to note that this implementation is not necessarily commutative.
That is because matrices only need to share one dimension in order to be
multiplied together in one direction. From this fact a somewhat pleasant trait
bound appears: matrices that satisfy
Mul<Self> must be square matrices. This
is reflected by a matrix's trait bounds; if a Matrix is square, you are able to
extract a diagonal vector from it:
assert_eq!( matrix![ [ 1i32, 0, 0 ], [ 0, 2, 0 ], [ 0, 0, 3 ], ].diagonal(), vector!(1i32, 2, 3) ); assert_eq!( matrix![ [ 1i32, 0, 0, 0 ], [ 0, 2, 0, 0 ], [ 0, 0, 3, 0 ], [ 0, 0, 0, 4 ], ].diagonal(), vector!(1i32, 2, 3, 4) );
Matrices can be indexed by either their native column major storage or by
the more natural row major method. In order to use row-major indexing, call
.index_mut on the matrix with a pair of indices. Calling
.index with a single index will produce a Vector representing the
appropriate column of the matrix.
let m: Matrix::<i32, 2, 2> = matrix![ [ 0, 2 ], [ 1, 3 ], ]; // Column-major indexing: assert_eq!(m, 0); assert_eq!(m, 1); assert_eq!(m, 2); assert_eq!(m, 3); // Row-major indexing: assert_eq!(m[(0, 0)], 0); assert_eq!(m[(1, 0)], 1); assert_eq!(m[(0, 1)], 2); assert_eq!(m[(1, 1)], 3);
Defines the additive and multiplicative identity respectively.
vectors and matrices filled with zeroes, while
one returns the unit matrix
and is unimplemented vectors.
As far as aljabar is considered, a
Real is a value that has
By default this is implemented for
Sub and its scalar implements
Div, then that vector is part of a
If two scalars have a distance squared, then vectors of that scalar type
If a vector is a
MetricSpace and its scalar is a real number, then
.distance() is defined as an alias for
If a vector is a
MetricSpace, and its scalar implements
Clone, then it is also an
InnerSpace and has the inner product defined for
it. The inner product is known as the
dot product and its respective method
in aljabar takes that spelling.
A vector that is an
InnerSpace also has
.magnitude2() implemented, which is
defined as the length of the vector squared.
If a vector is an
InnerSpace and its scalar is a real number then it inherits
a number of convenience methods:
.magnitude(): returns the length of the vector.
.normalize(): returns a vector with the same direction and a length of one.
.normalize_to(magnitude): returns a vector with the same direction and a length of
.project_on(other): returns the vector projection of the current inner space onto the given argument.
Matrix that implements
Mul<Self>. Square matrices have the following
methods defined for them:
.diagonal(): returns the diaganol vector of the matrix.
.determinant(): returns the determinant of the matrix. currently only supported for matrices of
N <= 3
.invert(): returns the inverse of the matrix if one exists. currently only supported for matrices of
N <= 2
Individual component access isn't implemented for vectors and most likely will
not be as simple as a public field access when it is. For now, manually
destructure the vector or use
let a = Vector1::<u32>::from([ 5 ]); assert_eq!(a, 5); let mut b = Vector2::<u32>::from([ 1, 2 ]); b += 3; assert_eq!(b, 5);
Truncation must be performed by manually destructuring as well, but this is due to a limitation of the current compiler.
Please feel free to submit pull requests of any nature.
There is a lot of work that needs to be done on aljabar before it can be considered stable or non-experimental.
Vectorops to SIMD implementations.
- Add more tests and get code coverage to 100%.
- Implement faster matrix multiplication algorithms.