forked from StrafesNET/strafe-project
rename fixed_wide_vectors to linear_ops
This commit is contained in:
1
linear_ops/.gitignore
vendored
Normal file
1
linear_ops/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
37
linear_ops/Cargo.lock
generated
Normal file
37
linear_ops/Cargo.lock
generated
Normal file
@ -0,0 +1,37 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "bnum"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790"
|
||||
|
||||
[[package]]
|
||||
name = "fixed_wide"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bnum",
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lin_ops"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"fixed_wide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
11
linear_ops/Cargo.toml
Normal file
11
linear_ops/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "linear_ops"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
default=["named-fields"]
|
||||
named-fields=[]
|
||||
|
||||
[dev-dependencies]
|
||||
fixed_wide = { version = "0.1.0", path = "../fixed_wide" }
|
10
linear_ops/src/lib.rs
Normal file
10
linear_ops/src/lib.rs
Normal file
@ -0,0 +1,10 @@
|
||||
mod macros;
|
||||
pub mod types;
|
||||
pub mod vector;
|
||||
pub mod matrix;
|
||||
|
||||
#[cfg(feature="named-fields")]
|
||||
mod named;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
1
linear_ops/src/macros/common.rs
Normal file
1
linear_ops/src/macros/common.rs
Normal file
@ -0,0 +1 @@
|
||||
|
219
linear_ops/src/macros/matrix.rs
Normal file
219
linear_ops/src/macros/matrix.rs
Normal file
@ -0,0 +1,219 @@
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_matrix {
|
||||
() => {
|
||||
impl<const X:usize,const Y:usize,T> Matrix<X,Y,T>{
|
||||
#[inline(always)]
|
||||
pub const fn new(array:[[T;X];Y])->Self{
|
||||
Self{array}
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn to_array(self)->[[T;X];Y]{
|
||||
self.array
|
||||
}
|
||||
#[inline]
|
||||
pub fn map<F,U>(self,f:F)->Matrix<X,Y,U>
|
||||
where
|
||||
F:Fn(T)->U
|
||||
{
|
||||
Matrix::new(
|
||||
self.array.map(|inner|inner.map(&f)),
|
||||
)
|
||||
}
|
||||
#[inline]
|
||||
pub fn transpose(self)->Matrix<Y,X,T>{
|
||||
//how did I think of this
|
||||
let mut array_of_iterators=self.array.map(|axis|axis.into_iter());
|
||||
Matrix::new(
|
||||
core::array::from_fn(|_|
|
||||
array_of_iterators.each_mut().map(|iter|
|
||||
iter.next().unwrap()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
#[inline]
|
||||
// MatY<VecX>.MatX<VecZ> = MatY<VecZ>
|
||||
pub fn dot<const Z:usize,U,V>(self,rhs:Matrix<Z,X,U>)->Matrix<Z,Y,V>
|
||||
where
|
||||
T:core::ops::Mul<U,Output=V>+Copy,
|
||||
V:core::iter::Sum,
|
||||
U:Copy,
|
||||
{
|
||||
let mut array_of_iterators=rhs.array.map(|axis|axis.into_iter().cycle());
|
||||
Matrix::new(
|
||||
self.array.map(|axis|
|
||||
core::array::from_fn(|_|
|
||||
// axis dot product with transposed rhs array
|
||||
axis.iter().zip(
|
||||
array_of_iterators.iter_mut()
|
||||
).map(|(&lhs_value,rhs_iter)|
|
||||
lhs_value*rhs_iter.next().unwrap()
|
||||
).sum()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
#[inline]
|
||||
// MatY<VecX>.VecX = VecY
|
||||
pub fn transform_vector<U,V>(self,rhs:Vector<X,U>)->Vector<Y,V>
|
||||
where
|
||||
T:core::ops::Mul<U,Output=V>,
|
||||
V:core::iter::Sum,
|
||||
U:Copy,
|
||||
{
|
||||
Vector::new(
|
||||
self.array.map(|axis|
|
||||
Vector::new(axis).dot(rhs)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
impl<const X:usize,const Y:usize,T> Matrix<X,Y,T>
|
||||
where
|
||||
T:Copy
|
||||
{
|
||||
#[inline(always)]
|
||||
pub const fn from_value(value:T)->Self{
|
||||
Self::new([[value;X];Y])
|
||||
}
|
||||
}
|
||||
|
||||
impl<const X:usize,const Y:usize,T:Default> Default for Matrix<X,Y,T>{
|
||||
#[inline]
|
||||
fn default()->Self{
|
||||
Self::new(
|
||||
core::array::from_fn(|_|core::array::from_fn(|_|Default::default()))
|
||||
)
|
||||
}
|
||||
}
|
||||
impl<const X:usize,const Y:usize,const Z:usize,T,U,V> core::ops::Mul<Matrix<Z,X,U>> for Matrix<X,Y,T>
|
||||
where
|
||||
T:core::ops::Mul<U,Output=V>+Copy,
|
||||
V:core::iter::Sum,
|
||||
U:Copy,
|
||||
{
|
||||
type Output=Matrix<Z,Y,V>;
|
||||
#[inline]
|
||||
fn mul(self,rhs:Matrix<Z,X,U>)->Self::Output{
|
||||
self.dot(rhs)
|
||||
}
|
||||
}
|
||||
impl<const X:usize,const Y:usize,T,U,V> core::ops::Mul<Vector<X,U>> for Matrix<X,Y,T>
|
||||
where
|
||||
T:core::ops::Mul<U,Output=V>,
|
||||
V:core::iter::Sum,
|
||||
U:Copy,
|
||||
{
|
||||
type Output=Vector<Y,V>;
|
||||
#[inline]
|
||||
fn mul(self,rhs:Vector<X,U>)->Self::Output{
|
||||
self.transform_vector(rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_matrix_extend {
|
||||
( $x: expr, $y: expr ) => {
|
||||
impl<T> Matrix<$x,$y,T>{
|
||||
#[inline]
|
||||
pub fn extend_row(self,value:Vector<$x,T>)->Matrix<$x,{$y+1},T>{
|
||||
let mut iter=self.array.into_iter().chain(core::iter::once(value.array));
|
||||
Matrix::new(
|
||||
core::array::from_fn(|_|iter.next().unwrap()),
|
||||
)
|
||||
}
|
||||
#[inline]
|
||||
pub fn extend_column(self,value:Vector<$y,T>)->Matrix<{$x+1},$y,T>{
|
||||
let mut iter_rows=value.array.into_iter();
|
||||
Matrix::new(
|
||||
self.array.map(|axis|{
|
||||
let mut elements_iter=axis.into_iter().chain(core::iter::once(iter_rows.next().unwrap()));
|
||||
core::array::from_fn(|_|elements_iter.next().unwrap())
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_matrix_named_fields_shape {
|
||||
(
|
||||
($struct_outer:ident, $size_outer: expr),
|
||||
($size_inner: expr)
|
||||
) => {
|
||||
impl<T> core::ops::Deref for Matrix<$size_outer,$size_inner,T>{
|
||||
type Target=$struct_outer<Vector<$size_inner,T>>;
|
||||
#[inline]
|
||||
fn deref(&self)->&Self::Target{
|
||||
unsafe{core::mem::transmute(&self.array)}
|
||||
}
|
||||
}
|
||||
impl<T> core::ops::DerefMut for Matrix<$size_outer,$size_inner,T>{
|
||||
#[inline]
|
||||
fn deref_mut(&mut self)->&mut Self::Target{
|
||||
unsafe{core::mem::transmute(&mut self.array)}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_matrix_named_fields_shape_shim {
|
||||
(
|
||||
($($vector_info:tt),+),
|
||||
$matrix_info:tt
|
||||
) => {
|
||||
$crate::macro_repeated!(impl_matrix_named_fields_shape,$matrix_info,$($vector_info),+);
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_matrix_named_fields {
|
||||
(
|
||||
($($matrix_info:tt),+),
|
||||
$vector_infos:tt
|
||||
) => {
|
||||
$crate::macro_repeated!(impl_matrix_named_fields_shape_shim,$vector_infos,$($matrix_info),+);
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_matrix_3x3 {
|
||||
()=>{
|
||||
impl<T,T2,T3> Matrix<3,3,T>
|
||||
where
|
||||
//cross
|
||||
T:core::ops::Mul<T,Output=T2>+Copy,
|
||||
T2:core::ops::Sub,
|
||||
//dot
|
||||
T:core::ops::Mul<<T2 as core::ops::Sub>::Output,Output=T3>,
|
||||
T3:core::iter::Sum,
|
||||
{
|
||||
pub fn det(self)->T3{
|
||||
self.x_axis.dot(self.y_axis.cross(self.z_axis))
|
||||
}
|
||||
}
|
||||
impl<T,T2> Matrix<3,3,T>
|
||||
where
|
||||
T:core::ops::Mul<T,Output=T2>+Copy,
|
||||
T2:core::ops::Sub,
|
||||
{
|
||||
pub fn adjugate(self)->Matrix<3,3,<T2 as core::ops::Sub>::Output>{
|
||||
Matrix::new([
|
||||
[self.y_axis.y*self.z_axis.z-self.y_axis.z*self.z_axis.y,self.x_axis.z*self.z_axis.y-self.x_axis.y*self.z_axis.z,self.x_axis.y*self.y_axis.z-self.x_axis.z*self.y_axis.y],
|
||||
[self.y_axis.z*self.z_axis.x-self.y_axis.x*self.z_axis.z,self.x_axis.x*self.z_axis.z-self.x_axis.z*self.z_axis.x,self.x_axis.z*self.y_axis.x-self.x_axis.x*self.y_axis.z],
|
||||
[self.y_axis.x*self.z_axis.y-self.y_axis.y*self.z_axis.x,self.x_axis.y*self.z_axis.x-self.x_axis.x*self.z_axis.y,self.x_axis.x*self.y_axis.y-self.x_axis.y*self.y_axis.x],
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
17
linear_ops/src/macros/mod.rs
Normal file
17
linear_ops/src/macros/mod.rs
Normal file
@ -0,0 +1,17 @@
|
||||
pub mod common;
|
||||
pub mod vector;
|
||||
pub mod matrix;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! macro_repeated{
|
||||
(
|
||||
$macro:ident,
|
||||
$any:tt,
|
||||
$($repeated:tt),*
|
||||
)=>{
|
||||
$(
|
||||
$crate::$macro!($any, $repeated);
|
||||
)*
|
||||
};
|
||||
}
|
244
linear_ops/src/macros/vector.rs
Normal file
244
linear_ops/src/macros/vector.rs
Normal file
@ -0,0 +1,244 @@
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_vector {
|
||||
() => {
|
||||
impl<const N:usize,T> Vector<N,T>{
|
||||
#[inline(always)]
|
||||
pub const fn new(array:[T;N])->Self{
|
||||
Self{array}
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn to_array(self)->[T;N]{
|
||||
self.array
|
||||
}
|
||||
#[inline]
|
||||
pub fn map<F,U>(self,f:F)->Vector<N,U>
|
||||
where
|
||||
F:Fn(T)->U
|
||||
{
|
||||
Vector::new(
|
||||
self.array.map(f)
|
||||
)
|
||||
}
|
||||
#[inline]
|
||||
pub fn map_zip<F,U,V>(self,other:Vector<N,U>,f:F)->Vector<N,V>
|
||||
where
|
||||
F:Fn((T,U))->V,
|
||||
{
|
||||
let mut iter=self.array.into_iter().zip(other.array);
|
||||
Vector::new(
|
||||
core::array::from_fn(|_|f(iter.next().unwrap())),
|
||||
)
|
||||
}
|
||||
}
|
||||
impl<const N:usize,T:Copy> Vector<N,T>{
|
||||
#[inline(always)]
|
||||
pub const fn from_value(value:T)->Self{
|
||||
Self::new([value;N])
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N:usize,T:Default> Default for Vector<N,T>{
|
||||
#[inline]
|
||||
fn default()->Self{
|
||||
Self::new(
|
||||
core::array::from_fn(|_|Default::default())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N:usize,T:Ord> Vector<N,T>{
|
||||
#[inline]
|
||||
pub fn min(self,rhs:Self)->Self{
|
||||
self.map_zip(rhs,|(a,b)|a.min(b))
|
||||
}
|
||||
#[inline]
|
||||
pub fn max(self,rhs:Self)->Self{
|
||||
self.map_zip(rhs,|(a,b)|a.max(b))
|
||||
}
|
||||
#[inline]
|
||||
pub fn cmp(self,rhs:Self)->Vector<N,core::cmp::Ordering>{
|
||||
self.map_zip(rhs,|(a,b)|a.cmp(&b))
|
||||
}
|
||||
#[inline]
|
||||
pub fn lt(self,rhs:Self)->Vector<N,bool>{
|
||||
self.map_zip(rhs,|(a,b)|a.lt(&b))
|
||||
}
|
||||
#[inline]
|
||||
pub fn gt(self,rhs:Self)->Vector<N,bool>{
|
||||
self.map_zip(rhs,|(a,b)|a.gt(&b))
|
||||
}
|
||||
#[inline]
|
||||
pub fn ge(self,rhs:Self)->Vector<N,bool>{
|
||||
self.map_zip(rhs,|(a,b)|a.ge(&b))
|
||||
}
|
||||
#[inline]
|
||||
pub fn le(self,rhs:Self)->Vector<N,bool>{
|
||||
self.map_zip(rhs,|(a,b)|a.le(&b))
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N:usize> Vector<N,bool>{
|
||||
#[inline]
|
||||
pub fn all(&self)->bool{
|
||||
self.array==[true;N]
|
||||
}
|
||||
#[inline]
|
||||
pub fn any(&self)->bool{
|
||||
self.array!=[false;N]
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N:usize,T:core::ops::Neg<Output=V>,V> core::ops::Neg for Vector<N,T>{
|
||||
type Output=Vector<N,V>;
|
||||
#[inline]
|
||||
fn neg(self)->Self::Output{
|
||||
Vector::new(
|
||||
self.array.map(|t|-t)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N:usize,T> Vector<N,T>
|
||||
{
|
||||
#[inline]
|
||||
pub fn dot<U,V>(self,rhs:Vector<N,U>)->V
|
||||
where
|
||||
T:core::ops::Mul<U,Output=V>,
|
||||
V:core::iter::Sum,
|
||||
{
|
||||
self.array.into_iter().zip(rhs.array).map(|(a,b)|a*b).sum()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N:usize,T,V> Vector<N,T>
|
||||
where
|
||||
T:core::ops::Mul<Output=V>+Copy,
|
||||
V:core::iter::Sum,
|
||||
{
|
||||
#[inline]
|
||||
pub fn length_squared(self)->V{
|
||||
self.array.into_iter().map(|t|t*t).sum()
|
||||
}
|
||||
}
|
||||
|
||||
// Impl arithmetic operators
|
||||
$crate::impl_vector_assign_operator!(AddAssign, add_assign );
|
||||
$crate::impl_vector_operator!(Add, add );
|
||||
$crate::impl_vector_assign_operator!(SubAssign, sub_assign );
|
||||
$crate::impl_vector_operator!(Sub, sub );
|
||||
$crate::impl_vector_assign_operator!(MulAssign, mul_assign );
|
||||
$crate::impl_vector_operator!(Mul, mul );
|
||||
$crate::impl_vector_assign_operator!(DivAssign, div_assign );
|
||||
$crate::impl_vector_operator!(Div, div );
|
||||
$crate::impl_vector_assign_operator!(RemAssign, rem_assign );
|
||||
$crate::impl_vector_operator!(Rem, rem );
|
||||
|
||||
// Impl bitwise operators
|
||||
$crate::impl_vector_assign_operator!(BitAndAssign, bitand_assign );
|
||||
$crate::impl_vector_operator!(BitAnd, bitand );
|
||||
$crate::impl_vector_assign_operator!(BitOrAssign, bitor_assign );
|
||||
$crate::impl_vector_operator!(BitOr, bitor );
|
||||
$crate::impl_vector_assign_operator!(BitXorAssign, bitxor_assign );
|
||||
$crate::impl_vector_operator!(BitXor, bitxor );
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_vector_operator {
|
||||
($trait: ident, $method: ident ) => {
|
||||
impl<const N:usize,T:core::ops::$trait<U,Output=V>,U,V> core::ops::$trait<Vector<N,U>> for Vector<N,T>{
|
||||
type Output=Vector<N,V>;
|
||||
#[inline]
|
||||
fn $method(self,rhs:Vector<N,U>)->Self::Output{
|
||||
self.map_zip(rhs,|(a,b)|a.$method(b))
|
||||
}
|
||||
}
|
||||
impl<const N:usize,T:core::ops::$trait<i64,Output=T>> core::ops::$trait<i64> for Vector<N,T>{
|
||||
type Output=Self;
|
||||
#[inline]
|
||||
fn $method(self,rhs:i64)->Self::Output{
|
||||
self.map(|t|t.$method(rhs))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_vector_assign_operator {
|
||||
($trait: ident, $method: ident ) => {
|
||||
impl<const N:usize,T:core::ops::$trait<U>,U> core::ops::$trait<Vector<N,U>> for Vector<N,T>{
|
||||
#[inline]
|
||||
fn $method(&mut self,rhs:Vector<N,U>){
|
||||
self.array.iter_mut().zip(rhs.array)
|
||||
.for_each(|(a,b)|a.$method(b))
|
||||
}
|
||||
}
|
||||
impl<const N:usize,T:core::ops::$trait<i64>> core::ops::$trait<i64> for Vector<N,T>{
|
||||
#[inline]
|
||||
fn $method(&mut self,rhs:i64){
|
||||
self.array.iter_mut()
|
||||
.for_each(|t|t.$method(rhs))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_vector_extend {
|
||||
( $size: expr ) => {
|
||||
impl<T> Vector<$size,T>{
|
||||
#[inline]
|
||||
pub fn extend(self,value:T)->Vector<{$size+1},T>{
|
||||
let mut iter=self.array.into_iter().chain(core::iter::once(value));
|
||||
Vector::new(
|
||||
core::array::from_fn(|_|iter.next().unwrap()),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_vector_named_fields {
|
||||
( $struct:ident, $size: expr ) => {
|
||||
impl<T> core::ops::Deref for Vector<$size,T>{
|
||||
type Target=$struct<T>;
|
||||
#[inline]
|
||||
fn deref(&self)->&Self::Target{
|
||||
unsafe{core::mem::transmute(&self.array)}
|
||||
}
|
||||
}
|
||||
impl<T> core::ops::DerefMut for Vector<$size,T>{
|
||||
#[inline]
|
||||
fn deref_mut(&mut self)->&mut Self::Target{
|
||||
unsafe{core::mem::transmute(&mut self.array)}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_vector_3 {
|
||||
()=>{
|
||||
impl<T> Vector<3,T>
|
||||
{
|
||||
#[inline]
|
||||
pub fn cross<U,V>(self,rhs:Vector<3,U>)->Vector<3,<V as core::ops::Sub>::Output>
|
||||
where
|
||||
T:core::ops::Mul<U,Output=V>+Copy,
|
||||
U:Copy,
|
||||
V:core::ops::Sub,
|
||||
{
|
||||
Vector::new([
|
||||
self.y*rhs.z-self.z*rhs.y,
|
||||
self.z*rhs.x-self.x*rhs.z,
|
||||
self.x*rhs.y-self.y*rhs.x,
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
17
linear_ops/src/matrix.rs
Normal file
17
linear_ops/src/matrix.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use crate::vector::Vector;
|
||||
|
||||
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
|
||||
pub struct Matrix<const X:usize,const Y:usize,T>{
|
||||
pub(crate) array:[[T;X];Y],
|
||||
}
|
||||
|
||||
crate::impl_matrix!();
|
||||
|
||||
crate::impl_matrix_extend!(2,2);
|
||||
crate::impl_matrix_extend!(2,3);
|
||||
crate::impl_matrix_extend!(3,2);
|
||||
crate::impl_matrix_extend!(3,3);
|
||||
|
||||
//Special case 3x3 matrix operations because I cba to write macros for the arbitrary cases
|
||||
#[cfg(feature="named-fields")]
|
||||
crate::impl_matrix_3x3!();
|
59
linear_ops/src/named.rs
Normal file
59
linear_ops/src/named.rs
Normal file
@ -0,0 +1,59 @@
|
||||
use crate::vector::Vector;
|
||||
use crate::matrix::Matrix;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Vector2<T> {
|
||||
pub x: T,
|
||||
pub y: T,
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct Vector3<T> {
|
||||
pub x: T,
|
||||
pub y: T,
|
||||
pub z: T,
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct Vector4<T> {
|
||||
pub x: T,
|
||||
pub y: T,
|
||||
pub z: T,
|
||||
pub w: T,
|
||||
}
|
||||
|
||||
crate::impl_vector_named_fields!(Vector2, 2);
|
||||
crate::impl_vector_named_fields!(Vector3, 3);
|
||||
crate::impl_vector_named_fields!(Vector4, 4);
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Matrix2<T> {
|
||||
pub x_axis: T,
|
||||
pub y_axis: T,
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct Matrix3<T> {
|
||||
pub x_axis: T,
|
||||
pub y_axis: T,
|
||||
pub z_axis: T,
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct Matrix4<T> {
|
||||
pub x_axis: T,
|
||||
pub y_axis: T,
|
||||
pub z_axis: T,
|
||||
pub w_axis: T,
|
||||
}
|
||||
|
||||
crate::impl_matrix_named_fields!(
|
||||
//outer struct
|
||||
(
|
||||
(Matrix2, 2),
|
||||
(Matrix3, 3),
|
||||
(Matrix4, 4)
|
||||
),
|
||||
//inner struct
|
||||
(
|
||||
(2),
|
||||
(3),
|
||||
(4)
|
||||
)
|
||||
);
|
96
linear_ops/src/tests/fixed_wide.rs
Normal file
96
linear_ops/src/tests/fixed_wide.rs
Normal file
@ -0,0 +1,96 @@
|
||||
use crate::types::{Matrix3,Matrix2x3,Matrix4x3,Matrix2x4,Vector3};
|
||||
|
||||
type Planar64=fixed_wide::types::I32F32;
|
||||
type Planar64Wide1=fixed_wide::types::I64F64;
|
||||
//type Planar64Wide2=fixed_wide::types::I128F128;
|
||||
type Planar64Wide3=fixed_wide::types::I256F256;
|
||||
|
||||
#[test]
|
||||
fn wide_vec3(){
|
||||
let v=Vector3::from_value(Planar64::from(3));
|
||||
let v1=v*v;
|
||||
let v2=v1*v1;
|
||||
let v3=v2*v2;
|
||||
|
||||
assert_eq!(v3.array,Vector3::from_value(Planar64Wide3::from(3i128.pow(8))).array);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_vec3_dot(){
|
||||
let v=Vector3::from_value(Planar64::from(3));
|
||||
let v1=v*v;
|
||||
let v2=v1*v1;
|
||||
let v3=v2.dot(v2);
|
||||
|
||||
assert_eq!(v3,Planar64Wide3::from(3i128.pow(8)*3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_vec3_length_squared(){
|
||||
let v=Vector3::from_value(Planar64::from(3));
|
||||
let v1=v*v;
|
||||
let v2=v1*v1;
|
||||
let v3=v2.length_squared();
|
||||
|
||||
assert_eq!(v3,Planar64Wide3::from(3i128.pow(8)*3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_matrix_dot(){
|
||||
let lhs=Matrix4x3::new([
|
||||
[Planar64::from(1),Planar64::from(2),Planar64::from(3),Planar64::from(4)],
|
||||
[Planar64::from(5),Planar64::from(6),Planar64::from(7),Planar64::from(8)],
|
||||
[Planar64::from(9),Planar64::from(10),Planar64::from(11),Planar64::from(12)],
|
||||
]);
|
||||
let rhs=Matrix2x4::new([
|
||||
[Planar64::from(1),Planar64::from(2)],
|
||||
[Planar64::from(3),Planar64::from(4)],
|
||||
[Planar64::from(5),Planar64::from(6)],
|
||||
[Planar64::from(7),Planar64::from(8)],
|
||||
]);
|
||||
// Mat3<Vec4>.dot(Mat4<Vec2>) -> Mat3<Vec2>
|
||||
let m_dot=lhs*rhs;
|
||||
//In[1]:= {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}} . {{1, 2}, {3, 4}, {5, 6}, {7, 8}}
|
||||
//Out[1]= {{50, 60}, {114, 140}, {178, 220}}
|
||||
assert_eq!(
|
||||
m_dot.array,
|
||||
Matrix2x3::new([
|
||||
[Planar64Wide1::from(50),Planar64Wide1::from(60)],
|
||||
[Planar64Wide1::from(114),Planar64Wide1::from(140)],
|
||||
[Planar64Wide1::from(178),Planar64Wide1::from(220)],
|
||||
]).array
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature="named-fields")]
|
||||
fn wide_matrix_det(){
|
||||
let m=Matrix3::new([
|
||||
[Planar64::from(1),Planar64::from(2),Planar64::from(3)],
|
||||
[Planar64::from(4),Planar64::from(5),Planar64::from(7)],
|
||||
[Planar64::from(6),Planar64::from(8),Planar64::from(9)],
|
||||
]);
|
||||
// In[2]:= Det[{{1, 2, 3}, {4, 5, 7}, {6, 8, 9}}]
|
||||
// Out[2]= 7
|
||||
assert_eq!(m.det(),fixed_wide::fixed::Fixed::<3,96>::from(7));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature="named-fields")]
|
||||
fn wide_matrix_adjugate(){
|
||||
let m=Matrix3::new([
|
||||
[Planar64::from(1),Planar64::from(2),Planar64::from(3)],
|
||||
[Planar64::from(4),Planar64::from(5),Planar64::from(7)],
|
||||
[Planar64::from(6),Planar64::from(8),Planar64::from(9)],
|
||||
]);
|
||||
// In[6]:= Adjugate[{{1, 2, 3}, {4, 5, 7}, {6, 8, 9}}]
|
||||
// Out[6]= {{-11, 6, -1}, {6, -9, 5}, {2, 4, -3}}
|
||||
assert_eq!(
|
||||
m.adjugate().array,
|
||||
Matrix3::new([
|
||||
[Planar64Wide1::from(-11),Planar64Wide1::from(6),Planar64Wide1::from(-1)],
|
||||
[Planar64Wide1::from(6),Planar64Wide1::from(-9),Planar64Wide1::from(5)],
|
||||
[Planar64Wide1::from(2),Planar64Wide1::from(4),Planar64Wide1::from(-3)],
|
||||
]).array
|
||||
);
|
||||
}
|
6
linear_ops/src/tests/mod.rs
Normal file
6
linear_ops/src/tests/mod.rs
Normal file
@ -0,0 +1,6 @@
|
||||
mod tests;
|
||||
|
||||
#[cfg(feature="named-fields")]
|
||||
mod named;
|
||||
|
||||
mod fixed_wide;
|
30
linear_ops/src/tests/named.rs
Normal file
30
linear_ops/src/tests/named.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use crate::types::{Vector3,Matrix3};
|
||||
|
||||
#[test]
|
||||
fn test_vector(){
|
||||
let mut v=Vector3::new([1,2,3]);
|
||||
assert_eq!(v.x,1);
|
||||
assert_eq!(v.y,2);
|
||||
assert_eq!(v.z,3);
|
||||
|
||||
v.x=5;
|
||||
assert_eq!(v.x,5);
|
||||
|
||||
v.y*=v.x;
|
||||
assert_eq!(v.y,10);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_matrix(){
|
||||
let mut v=Matrix3::from_value(2);
|
||||
assert_eq!(v.x_axis.x,2);
|
||||
assert_eq!(v.y_axis.y,2);
|
||||
assert_eq!(v.z_axis.z,2);
|
||||
|
||||
v.x_axis.x=5;
|
||||
assert_eq!(v.x_axis.x,5);
|
||||
|
||||
v.y_axis.z*=v.x_axis.x;
|
||||
assert_eq!(v.y_axis.z,10);
|
||||
}
|
59
linear_ops/src/tests/tests.rs
Normal file
59
linear_ops/src/tests/tests.rs
Normal file
@ -0,0 +1,59 @@
|
||||
use crate::types::{Vector2,Vector3,Matrix4x3,Matrix2x4,Matrix2x3,Matrix3x2};
|
||||
|
||||
#[test]
|
||||
fn test_bool(){
|
||||
assert_eq!(Vector3::new([false,false,false]).any(),false);
|
||||
assert_eq!(Vector3::new([false,false,true]).any(),true);
|
||||
assert_eq!(Vector3::new([false,false,true]).all(),false);
|
||||
assert_eq!(Vector3::new([true,true,true]).all(),true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_length_squared(){
|
||||
assert_eq!(Vector3::new([1,2,3]).length_squared(),14);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arithmetic(){
|
||||
let a=Vector3::new([1,2,3]);
|
||||
assert_eq!((a+a*2).array,Vector3::new([1*3,2*3,3*3]).array);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matrix_transform_vector(){
|
||||
let m=Matrix3x2::new([
|
||||
[1,2,3],
|
||||
[4,5,6],
|
||||
]);
|
||||
let v=Vector3::new([1,2,3]);
|
||||
let transformed=m*v;
|
||||
assert_eq!(transformed.array,Vector2::new([14,32]).array);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matrix_dot(){
|
||||
|
||||
let rhs=Matrix2x4::new([
|
||||
[ 1.0, 2.0],
|
||||
[ 3.0, 4.0],
|
||||
[ 5.0, 6.0],
|
||||
[ 7.0, 8.0],
|
||||
]); // | | |
|
||||
let lhs=Matrix4x3::new([ // | | |
|
||||
[1.0, 2.0, 3.0, 4.0],// [ 50.0, 60.0],
|
||||
[5.0, 6.0, 7.0, 8.0],// [114.0,140.0],
|
||||
[9.0,10.0,11.0,12.0],// [178.0,220.0],
|
||||
]);
|
||||
// Mat3<Vec4>.dot(Mat4<Vec2>) -> Mat3<Vec2>
|
||||
let m_dot=lhs*rhs;
|
||||
//In[1]:= {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}} . {{1, 2}, {3, 4}, {5, 6}, {7, 8}}
|
||||
//Out[1]= {{50, 60}, {114, 140}, {178, 220}}
|
||||
assert_eq!(
|
||||
m_dot.array,
|
||||
Matrix2x3::new([
|
||||
[50.0,60.0],
|
||||
[114.0,140.0],
|
||||
[178.0,220.0],
|
||||
]).array
|
||||
);
|
||||
}
|
18
linear_ops/src/types.rs
Normal file
18
linear_ops/src/types.rs
Normal file
@ -0,0 +1,18 @@
|
||||
use crate::vector::Vector;
|
||||
use crate::matrix::Matrix;
|
||||
|
||||
pub type Vector2<T>=Vector<2,T>;
|
||||
pub type Vector3<T>=Vector<3,T>;
|
||||
pub type Vector4<T>=Vector<4,T>;
|
||||
|
||||
pub type Matrix2<T>=Matrix<2,2,T>;
|
||||
pub type Matrix2x3<T>=Matrix<2,3,T>;
|
||||
pub type Matrix2x4<T>=Matrix<2,4,T>;
|
||||
|
||||
pub type Matrix3x2<T>=Matrix<3,2,T>;
|
||||
pub type Matrix3<T>=Matrix<3,3,T>;
|
||||
pub type Matrix3x4<T>=Matrix<3,4,T>;
|
||||
|
||||
pub type Matrix4x2<T>=Matrix<4,2,T>;
|
||||
pub type Matrix4x3<T>=Matrix<4,3,T>;
|
||||
pub type Matrix4<T>=Matrix<4,4,T>;
|
19
linear_ops/src/vector.rs
Normal file
19
linear_ops/src/vector.rs
Normal file
@ -0,0 +1,19 @@
|
||||
/// An array-backed vector type. Named fields are made accessible via the Deref/DerefMut traits which are implmented for 2-4 dimensions.
|
||||
/// let mut v = Vector::new([1.0,2.0,3.0]);
|
||||
/// v.x += v.z;
|
||||
/// println!("v.x={}",v.x);
|
||||
|
||||
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
|
||||
pub struct Vector<const N:usize,T>{
|
||||
pub(crate) array:[T;N],
|
||||
}
|
||||
|
||||
crate::impl_vector!();
|
||||
|
||||
// Needs const generics for generic case
|
||||
crate::impl_vector_extend!(2);
|
||||
crate::impl_vector_extend!(3);
|
||||
|
||||
//cross product
|
||||
#[cfg(feature="named-fields")]
|
||||
crate::impl_vector_3!();
|
Reference in New Issue
Block a user