use crate::ALMOST_ZERO;
use rand::Rng;
#[derive(Debug)]
pub struct Vector4D {
pub x: f64,
pub y: f64,
pub z: f64,
pub t: f64,
}
pub const E_X: Vector4D = Vector4D {
x: 1.0,
y: 0.0,
z: 0.0,
t: 0.0,
};
pub const E_Y: Vector4D = Vector4D {
x: 0.0,
y: 1.0,
z: 0.0,
t: 0.0,
};
pub const E_Z: Vector4D = Vector4D {
x: 0.0,
y: 0.0,
z: 1.0,
t: 0.0,
};
pub const E_T: Vector4D = Vector4D {
x: 0.0,
y: 0.0,
z: 0.0,
t: 1.0,
};
impl Vector4D {
pub fn new(x: f64, y: f64, z: f64, t: f64) -> Vector4D {
Vector4D { x, y, z, t }
}
pub fn length_l1(&self) -> f64 {
vec![self.x, self.y, self.z, self.t]
.iter()
.map(|i| i.abs())
.reduce(f64::max)
.unwrap()
}
pub fn is_close_to_zero(self: &Vector4D) -> bool {
self.length_l1() < ALMOST_ZERO
}
pub fn plus(self: &Vector4D, a: &Vector4D) -> Vector4D {
Vector4D {
x: self.x + a.x,
y: self.y + a.y,
z: self.z + a.z,
t: self.t + a.t,
}
}
pub fn minus(self: &Vector4D, a: &Vector4D) -> Vector4D {
Vector4D {
x: self.x - a.x,
y: self.y - a.y,
z: self.z - a.z,
t: self.t - a.t,
}
}
pub fn almost_equals(self: &Vector4D, a: &Vector4D) -> bool {
self.minus(a).is_close_to_zero()
}
pub fn revert(&self) -> Vector4D {
Vector4D {
x: -self.x,
y: -self.y,
z: -self.z,
t: -self.t,
}
}
pub fn generate_random_vectors(n: usize) -> Vec<Vector4D> {
(0..n).map(|_| Self::random_vector()).collect()
}
pub fn random_vector() -> Vector4D {
let mut rng = rand::rng();
Vector4D::new(
rng.random_range(-1.0..=1.0),
rng.random_range(-1.0..=1.0),
rng.random_range(-1.0..=1.0),
rng.random_range(-1.0..=1.0),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn plus_and_minus_are_opposite() {
let a = Vector4D::random_vector();
let b = Vector4D::random_vector();
let c = a.plus(&b).minus(&b);
assert!(c.almost_equals(&a));
}
#[test]
fn minus_and_revert() {
let a = Vector4D::random_vector();
let b = Vector4D::random_vector();
let c = a.minus(&(b.revert()));
assert!(a.plus(&b).almost_equals(&c));
}
}