harness_algebra/tensors/
fixed.rs

1//! # Fixed Vector Module
2//!
3//! This module provides a compile-time fixed-size vector implementation over
4//! arbitrary fields.
5//!
6//! ## Mathematical Background
7//!
8//! A vector space $V$ over a field $F$ is a set equipped with operations of addition
9//! and scalar multiplication that satisfy the vector space axioms. This implementation
10//! represents elements of $V$ as fixed-length arrays of components from the field $F$.
11//!
12//! For any two vectors $\mathbf{u}, \mathbf{v} \in V$ and scalar $\alpha \in F$:
13//!
14//! - Vector addition: $\mathbf{u} + \mathbf{v} = (u_1 + v_1, u_2 + v_2, \ldots, u_n + v_n)$
15//! - Scalar multiplication: $\alpha\mathbf{v} = (\alpha v_1, \alpha v_2, \ldots, \alpha v_n)$
16//! - Additive inverse (negation): $-\mathbf{v} = (-v_1, -v_2, \ldots, -v_n)$
17//!
18//! ## Features
19//!
20//! - Dimension determined at compile-time using const generics
21//! - Efficient memory layout with stack allocation
22//! - Support for vector arithmetic operations (+, -, *, scalar multiplication)
23//! - Implements algebraic traits like `Zero`, `Group`, and `VectorSpace`
24//! - Automatic bounds checking prevention through fixed-size arrays
25//!
26//! ## Examples
27//!
28//! ```
29//! use harness_algebra::{prelude::*, tensors::fixed::FixedVector};
30//!
31//! // Create a 3D vector with f64 components
32//! let v = FixedVector::<3, f64>([1.0, 2.0, 3.0]);
33//!
34//! // Create another vector
35//! let w = FixedVector::<3, f64>([4.0, 5.0, 6.0]);
36//!
37//! // Vector addition
38//! let sum = v + w;
39//!
40//! // Scalar multiplication
41//! let scaled = v * 2.0;
42//!
43//! // Create a zero vector
44//! let zero = FixedVector::<3, f64>::zero();
45//! ```
46
47use super::*;
48
49/// A fixed-size vector over a field.
50///
51/// This is a concrete implementation of a vector space, where vectors have
52/// a fixed number of components and the scalars come from a field.
53///
54/// ```
55/// use harness_algebra::{rings::Field, tensors::fixed::FixedVector};
56///
57/// let v = FixedVector::<3, f64>([1.0, 2.0, 3.0]);
58/// let w = FixedVector::<3, f64>([4.0, 5.0, 6.0]);
59/// let sum = v + w;
60/// ```
61#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
62pub struct FixedVector<const M: usize, F>(pub [F; M]);
63
64impl<const M: usize, F: Field + Copy> Default for FixedVector<M, F> {
65  fn default() -> Self { Self([F::zero(); M]) }
66}
67
68impl<const M: usize, F: Field + Copy> Add for FixedVector<M, F> {
69  type Output = Self;
70
71  fn add(self, other: Self) -> Self::Output {
72    let mut sum = Self::zero();
73    for i in 0..M {
74      sum.0[i] = self.0[i] + other.0[i];
75    }
76    sum
77  }
78}
79
80impl<const M: usize, F: Field + Copy> AddAssign for FixedVector<M, F> {
81  fn add_assign(&mut self, rhs: Self) { *self = *self + rhs }
82}
83
84impl<const M: usize, F: Field + Copy> Neg for FixedVector<M, F> {
85  type Output = Self;
86
87  fn neg(self) -> Self::Output {
88    let mut neg = Self::zero();
89    for i in 0..M {
90      neg.0[i] = -self.0[i];
91    }
92    neg
93  }
94}
95
96impl<const M: usize, F: Field + Copy> Mul<F> for FixedVector<M, F> {
97  type Output = Self;
98
99  fn mul(self, scalar: F) -> Self::Output {
100    let mut scalar_multiple = Self::zero();
101    for i in 0..M {
102      scalar_multiple.0[i] = scalar * self.0[i];
103    }
104    scalar_multiple
105  }
106}
107
108impl<const M: usize, F: Field + Copy> Sub for FixedVector<M, F> {
109  type Output = Self;
110
111  fn sub(self, other: Self) -> Self::Output { self + -other }
112}
113
114impl<const M: usize, F: Field + Copy> SubAssign for FixedVector<M, F> {
115  fn sub_assign(&mut self, rhs: Self) { *self = *self - rhs }
116}
117
118impl<const M: usize, F: Field + Copy> Additive for FixedVector<M, F> {}
119
120impl<const M: usize, F: Field + Copy> Group for FixedVector<M, F> {
121  fn identity() -> Self { Self::zero() }
122
123  fn inverse(&self) -> Self { -*self }
124}
125
126impl<const M: usize, F: Field + Copy> Zero for FixedVector<M, F> {
127  fn zero() -> Self { Self([F::zero(); M]) }
128
129  fn is_zero(&self) -> bool { self.0.iter().all(|x| *x == F::zero()) }
130}
131
132impl<const M: usize, F: Field + Copy> AbelianGroup for FixedVector<M, F> {}
133
134impl<const M: usize, F: Field + Copy + Mul<Self>> LeftModule for FixedVector<M, F> {
135  type Ring = F;
136}
137
138impl<const M: usize, F: Field + Copy + Mul<Self>> RightModule for FixedVector<M, F> {
139  type Ring = F;
140}
141
142impl<const M: usize, F: Field + Copy + Mul<Self>> TwoSidedModule for FixedVector<M, F> {
143  type Ring = F;
144}
145
146impl<const M: usize, F: Field + Copy + Mul<Self>> VectorSpace for FixedVector<M, F> {}
147
148impl<const M: usize, F: Field> From<[F; M]> for FixedVector<M, F> {
149  fn from(components: [F; M]) -> Self { Self(components) }
150}
151
152impl<const M: usize, F: Field + Copy> From<&[F; M]> for FixedVector<M, F> {
153  fn from(components: &[F; M]) -> Self { Self(*components) }
154}
155
156#[cfg(test)]
157mod tests {
158  use super::*;
159  use crate::fixtures::Mod7;
160
161  #[test]
162  fn test_zero_vector() {
163    let zero_vec: FixedVector<3, Mod7> = FixedVector::zero();
164    assert!(zero_vec.is_zero());
165    assert_eq!(zero_vec.0, [Mod7::zero(), Mod7::zero(), Mod7::zero()]);
166
167    let zero_vec_default: FixedVector<3, Mod7> = FixedVector::default();
168    assert!(zero_vec_default.is_zero());
169    assert_eq!(zero_vec_default.0, [Mod7::zero(), Mod7::zero(), Mod7::zero()]);
170
171    let non_zero_vec = FixedVector::from([Mod7::from(1), Mod7::zero(), Mod7::from(2)]);
172    assert!(!non_zero_vec.is_zero());
173  }
174
175  #[test]
176  fn test_is_zero_all_components_zero() {
177    let vec: FixedVector<2, Mod7> = FixedVector::from([Mod7::zero(), Mod7::zero()]);
178    assert!(vec.is_zero());
179  }
180
181  #[test]
182  fn test_from_array() {
183    let arr = [Mod7::from(1), Mod7::from(2), Mod7::from(3)];
184    let vec: FixedVector<3, Mod7> = FixedVector::from(arr);
185    assert_eq!(vec.0, arr);
186  }
187
188  #[test]
189  fn test_addition() {
190    let vec1 = FixedVector::from([Mod7::from(1), Mod7::from(2)]);
191    let vec2 = FixedVector::from([Mod7::from(3), Mod7::from(4)]);
192    let sum = vec1 + vec2;
193    assert_eq!(sum.0, [Mod7::from(4), Mod7::from(6)]);
194  }
195
196  #[test]
197  fn test_add_assign() {
198    let mut vec1 = FixedVector::from([Mod7::from(1), Mod7::from(2)]);
199    let vec2 = FixedVector::from([Mod7::from(3), Mod7::from(4)]);
200    vec1 += vec2;
201    assert_eq!(vec1.0, [Mod7::from(4), Mod7::from(6)]);
202  }
203
204  #[test]
205  fn test_negation() {
206    let vec = FixedVector::from([Mod7::from(1), Mod7::from(0), Mod7::from(6)]);
207    let neg_vec = -vec;
208    assert_eq!(neg_vec.0, [Mod7::from(6), Mod7::from(0), Mod7::from(1)]);
209  }
210
211  #[test]
212  fn test_scalar_multiplication() {
213    let vec = FixedVector::from([Mod7::from(1), Mod7::from(2), Mod7::from(3)]);
214    let scalar = Mod7::from(2);
215    let product = vec * scalar;
216    assert_eq!(product.0, [Mod7::from(2), Mod7::from(4), Mod7::from(6)]);
217
218    let scalar_zero = Mod7::zero();
219    let product_zero = vec * scalar_zero;
220    assert_eq!(product_zero.0, [Mod7::zero(), Mod7::zero(), Mod7::zero()]);
221  }
222
223  #[test]
224  fn test_subtraction() {
225    let vec1 = FixedVector::from([Mod7::from(5), Mod7::from(3)]);
226    let vec2 = FixedVector::from([Mod7::from(1), Mod7::from(4)]);
227    let diff = vec1 - vec2;
228    // vec1 + (-vec2) = [5,3] + [-1,-4] = [5,3] + [6,3] = [11,6] = [4,6]
229    assert_eq!(diff.0, [Mod7::from(4), Mod7::from(6)]);
230  }
231
232  #[test]
233  fn test_sub_assign() {
234    let mut vec1 = FixedVector::from([Mod7::from(5), Mod7::from(3)]);
235    let vec2 = FixedVector::from([Mod7::from(1), Mod7::from(4)]);
236    vec1 -= vec2;
237    assert_eq!(vec1.0, [Mod7::from(4), Mod7::from(6)]);
238  }
239}