mini_matrix/operations.rs
1//! # mini_matrix
2//!
3//! A mini linear algebra library implemented in Rust.
4//!
5use num::{Float, Num};
6use std::iter::Sum;
7use std::ops::{Add, AddAssign, Mul};
8
9use super::Vector;
10
11/* ***************************** */
12/* Linear Combination */
13/* *************************** */
14
15/// Computes the linear combination of a set of vectors.
16///
17/// A linear combination is the sum of scalar multiples of vectors.
18///
19/// # Arguments
20///
21/// * `vectors` - A mutable slice of vectors to be combined
22/// * `scalars` - A slice of scalar values to multiply with each vector
23///
24/// # Returns
25///
26/// A new `Vector<T, N>` representing the linear combination of the input vectors.
27///
28/// # Examples
29///
30/// ```
31/// use mini_matrix::{Vector, linear_combination};
32///
33/// let mut v1 = Vector::from([1.0, 2.0, 3.0]);
34/// let mut v2 = Vector::from([4.0, 5.0, 6.0]);
35/// let scalars = [2.0, 3.0];
36///
37/// let result = linear_combination(&mut [v1, v2], &scalars);
38/// assert_eq!(result, Vector::from([14.0, 19.0, 24.0]));
39/// ```
40///
41/// # Panics
42///
43/// This function will panic if:
44/// - The number of vectors and scalars are not equal
45/// - The vector slice is empty
46
47// O(n)
48
49pub fn linear_combination<T, const N: usize>(
50 vectors: &[Vector<T, N>],
51 scalars: &[T],
52) -> Vector<T, N>
53where
54 T: Num + Copy + Clone + Default + PartialOrd + AddAssign + Mul<T>,
55{
56 assert_eq!(
57 vectors.len(),
58 scalars.len(),
59 "The number of vectors and scalars must be the same"
60 );
61
62 if vectors.is_empty() {
63 panic!("The number of vectors must be greater than 0");
64 }
65
66 let mut result = Vector::zero();
67 for (v, s) in vectors.iter().zip(scalars.iter()) {
68 result += *v * *s;
69 }
70 result
71}
72
73/// Computes the linear interpolation between two vectors.
74///
75/// Linear interpolation (lerp) finds a point that is between two vectors, based on a given parameter `t`.
76/// It computes a weighted average of the vectors where `t` determines the weight of the second vector.
77///
78/// # Arguments
79///
80/// * `u` - The starting vector.
81/// * `v` - The ending vector.
82/// * `t` - A scalar parameter between 0.0 and 1.0 that determines the interpolation point.
83/// If `t` is 0.0, the result is `u`. If `t` is 1.0, the result is `v`.
84/// For values between 0.0 and 1.0, the result is a point between `u` and `v`.
85///
86/// # Returns
87///
88/// A new vector that represents the interpolated result between `u` and `v`.
89///
90/// # Examples
91///
92/// ```
93/// use mini_matrix::{Vector, lerp};
94///
95/// let u = Vector::from([1.0, 2.0, 3.0]);
96/// let v = Vector::from([4.0, 5.0, 6.0]);
97///
98/// let result = lerp(u, v, 0.5);
99/// assert_eq!(result, Vector::from([2.5, 3.5, 4.5]));
100/// ```
101///
102/// # Panics
103///
104/// This function will panic if:
105/// - The type `V` does not implement the required traits (`Add`, `Mul`).
106///
107/// # Notes
108///
109/// - This function assumes `t` is a floating-point number (`f32`) and works with vectors where the `Add`
110/// and `Mul` traits are implemented.
111pub fn lerp<V>(u: V, v: V, t: f32) -> V
112where
113 V: Add<V, Output = V> + Mul<f32, Output = V>,
114{
115 u * (1.0 - t) + v * t
116}
117
118/* *********************** */
119/* Cosine Angle */
120/* *********************** */
121
122/// Calculates the cosine of the angle between two vectors.
123///
124/// For vectors a and b, the cosine of the angle θ between them is:
125/// cos(θ) = (a · b) / (||a|| ||b||)
126/// Where (a · b) is the dot product and ||a|| and ||b|| are the magnitudes of the vectors.
127///
128/// # Arguments
129/// * `u` - A reference to the first vector
130/// * `v` - A reference to the second vector
131///
132/// # Returns
133/// The cosine of the angle between the two vectors as a value of type `T`.
134///
135/// # Type Parameters
136/// * `T` - The floating-point type of the vector components
137/// * `N` - The dimensionality of the vectors
138///
139/// # Type Constraints
140/// * `T: Float` - The component type must be a floating-point type
141/// * `T: Sum` - The component type must support summation
142pub fn angle_cos<T, const N: usize>(u: &Vector<T, N>, v: &Vector<T, N>) -> T
143where
144 T: Float,
145 T: Sum,
146{
147 let dot_product = u.dot(v);
148 let norm_u = u.norm();
149 let norm_v = v.norm();
150 dot_product / (norm_u * norm_v)
151}
152
153/// Computes the cross product of two 3-dimensional vectors.
154///
155/// The cross product u × v is defined for 3D vectors as:
156/// u × v = [u2v3 - u3v2, u3v1 - u1v3, u1v2 - u2v1]
157///
158/// # Arguments
159/// * `u` - A reference to the first 3D vector
160/// * `v` - A reference to the second 3D vector
161///
162/// # Returns
163/// A new `Vector<T, 3>` representing the cross product of `u` and `v`.
164///
165/// # Type Parameters
166/// * `T` - The floating-point type of the vector components
167/// * `N` - The dimensionality of the vectors (should be 3)
168///
169/// # Panics
170/// This function will panic if the input vectors are not 3-dimensional.
171///
172pub fn cross_product<T, const N: usize>(u: &Vector<T, N>, v: &Vector<T, N>) -> Vector<T, 3>
173where
174 T: Float + Default,
175{
176 assert_eq!(N, 3, "Cross product is only defined for 3D vectors");
177
178 Vector::from([
179 u[1] * v[2] - u[2] * v[1],
180 u[2] * v[0] - u[0] * v[2],
181 u[0] * v[1] - u[1] * v[0],
182 ])
183}