Crates.io | slut |
lib.rs | slut |
version | |
source | src |
created_at | 2025-04-08 12:02:18.819499+00 |
updated_at | 2025-04-11 07:28:40.507978+00 |
description | Static Linear Untiful Tensors. Library for Vectors and Matrices with Physical Dimensions. Basically `uom` but in a vector space. |
homepage | |
repository | |
max_upload_size | |
id | 1625398 |
Cargo.toml error: | TOML parse error at line 17, column 1 | 17 | autolib = false | ^^^^^^^ unknown field `autolib`, expected one of `name`, `version`, `edition`, `authors`, `description`, `readme`, `license`, `repository`, `homepage`, `documentation`, `build`, `resolver`, `links`, `default-run`, `default_dash_run`, `rust-version`, `rust_dash_version`, `rust_version`, `license-file`, `license_dash_file`, `license_file`, `licenseFile`, `license_capital_file`, `forced-target`, `forced_dash_target`, `autobins`, `autotests`, `autoexamples`, `autobenches`, `publish`, `metadata`, `keywords`, `categories`, `exclude`, `include` |
size | 0 |
This is a small lib I made for my thermodynamics simulation project. I was fed up with implementing vectors in uom
. It's very bug prone, experimental but does the job quite well. Inspired by Terry Tao's post and yuouom.
It's very useful for a lot of things like physics simulation, linear algebra, and could even be used as a theorem prover for dimensional analysis. Don't forget to include the experimental headers and use cargo nightly.
#![feature(generic_const_exprs)]
#![feature(trivial_bounds)]
#![feature(generic_arg_infer)]
You can cargo add the library from this repository. You can find all the structures in slut::tensor
units in slut::units
and all the dimensions in slut::dimension
. You can create tensors of any dimension and any unit. You can also perform operations on tensors like addition, subtraction, scaling, dot product, cross product, matrix multiplication, etc.
// Tensor of lengths
let mass = (10.0).scalar::<Kilogram>();
let force = Vec2::<f64,Force>::new::<Newton>([1.0, 2.0]);
//let error = mass + force; // error (expected)
let mass = mass + Scalar::<f64,Mass>::from::<Gram>(5.0); // works
println!("{}", mass);
/*
Tensor [1x1x1]: M^1
-- Layer 0 --
( 10.005 )
*/
let acc = force.scale(mass.inv()); // works
println!("{}", acc);
/*
Tensor [1x2x1]: L^1 * T^-2
-- Layer 0 --
( 0.09995002498750624 )
( 0.19990004997501248 )
*/
let time = Scalar::<f64,Time>::new::<Second>([1.0]);
let vel1 = Vec2::<f64,Velocity>::new::<MetersPerSecond>([10.0, 20.0]);
let vel2 = vel1 + acc.scale(time); // works
println!("{:?}", vel2.get::<MetersPerSecond>());
/*
[10.099950024987507, 20.199900049975014]
*/
// try to transpose a tensor
let tensor = Tensor::<c64,Dimensionless, 1,1, 6>::new::<Unitless>([1.0, 2.0, 3.0, 4.0, 5.0, 6.0].complex());
let tensor_transposed = tensor.transpose();
println!("{}", tensor);
println!("{}", tensor_transposed);
/*
Tensor [1x1x6]: Dimensionless
-- Layer 0 --
( 1 2 3 4 5 6 )
Tensor [1x6x1]: Dimensionless
-- Layer 0 --
( 1 )
( 2 )
( 3 )
( 4 )
( 5 )
( 6 )
*/
let length = Vec2::<f64,Length>::new::<Meter>([10.0, 20.0]);
// now try and dot product length and force
let dot_product = dot!(length, force);
println!("{}", dot_product);
/*
Tensor [1x1x1]: L^2 * M^1 * T^-2
-- Layer 0 --
( 50 )
*/
assert_dimension!(dot_product, Energy); // works
//assert_dimension!(dot_product, Force); // error (expected)
let m1 = Matrix::<f64,Length, 2, 3>::new::<Meter>([1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
let m2 = Matrix::<f64,Length, 3, 2>::new::<Meter>([1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
let m3 = m1.matmul(m2);
println!("{}", m3);
/*
Tensor [1x2x2]: L^2
-- Layer 0 --
( 22 28 )
( 49 64 )
*/
// test openrators
if (vel1 == vel2) {
println!("Equal");
} else {
println!("Not equal");
}
let mass2 = Scalar::<f64,Mass>::from::<Kilogram>(10.0);
if (mass == mass2) {
println!("Equal");
} else {
if mass < mass2 {
println!("Less than");
} else {
println!("Greater than");
}
}
/*
Not equal
Greater than
*/
let inv = Scalar::<f64,dim_inv!(Time)>::from::<unit_inv!(Second)>(1.0);
let mul = Scalar::<f64,dim_div!(Energy,Temperature)>::new::<unit_div!(Joule, Kelvin)>([1.0]);
assert_dimension!(mul, Entropy); // works
assert_dimension!(inv, Frequency); // works
println!("{}", inv);
println!("{}", mul);
/*
Tensor [1x1x1]: T^-1
-- Layer 0 --
( 1 )
Tensor [1x1x1]: L^2 * M^1 * T^-2 * Θ^-1
-- Layer 0 --
( 1 )
*/
// test dot product
let a = Vec2::<f64,Length>::new::<Meter>([1.0, 2.0]);
let b = Vec2::<f64,Length>::new::<Meter>([3.0, 4.0]);
let c = dot!(a, b);
println!("{}", c);
/*
Tensor [1x1x1]: L^2
-- Layer 0 --
( 11 )
*/
// invert
let d = c.inv();
println!("{}", d);
I also implemented some physics/linald features I use for prototyping quantum sims and other stuff. You can use the cvec!
macro to create complex vectors and matrices. You can also use the ip!
macro to calculate the inner product of two vectors (hilbert on complex ones).
let a = cvec!((2,4), (3,5)); // [2+4i, 3+5i]
let a_h = a.conjugate_transpose();
println!("{}", a);
println!("{}", a_h);
/*
Tensor [1x2x1]: Dimensionless
-- Layer 0 --
( 2 + 4i )
( 3 + 5i )
Tensor [1x1x2]: Dimensionless
-- Layer 0 --
( 2 - 4i 3 - 5i )
*/
assert_eq!(a_h.get_at(0,0,0).raw(), c64::new(2.0, -4.0));
assert_eq!(a_h.get_at(0,0,1).raw(), c64::new(3.0, -5.0));
let a = cvec!((2,4), (3,5));
let b = cvec!((1,2), (3,4));
println!("a:\n{}", a);
println!("b:\n{}", b);
println!("a†:\n{}", a.conjugate_transpose());
println!("a† × b:\n{}", a.conjugate_transpose().matmul(b));
/*
a:
Tensor [1x2x1]: Dimensionless
-- Layer 0 --
( 2 + 4i )
( 3 + 5i )
b:
Tensor [1x2x1]: Dimensionless
-- Layer 0 --
( 1 + 2i )
( 3 + 4i )
a†:
Tensor [1x1x2]: Dimensionless
-- Layer 0 --
( 2 - 4i 3 - 5i )
a† × b:
Tensor [1x1x1]: Dimensionless
-- Layer 0 --
( 39 - 3i )
*/
let c = ip!(a,b);
println!("c: {}",c);
/*
c: Tensor [1x1x1]: Dimensionless
-- Layer 0 --
( 39 - 3i )
*/
let c_ = dless!((39.0, -3.0).complex());
println!("c_: {}",c_);
/*
c_: Tensor [1x1x1]: Dimensionless
-- Layer 0 --
( 39 - 3i )
*/
// The result should be -17 - 7i
assert_approx_eq!(c, c_);
// Test conjugate symmetry
assert_approx_eq!(ip!(a,b).conjugate(), ip!(b,a));
// Test linearity
let d = cvec!((1,1), (2,2));
let alpha = dless!((2.0, 1.0).complex());
// (a, αb + d) = α(a,b) + (a,d)
assert_approx_eq!(
ip!(a,(b.scale(alpha) + d)),
ip!(a,b).scale(alpha) + ip!(a,d)
);
// Test positive definiteness
assert!(ip!(a,a).raw().re() >= 0.0);