harness_algebra/tensors/dynamic/
vector.rs

1//! # Dynamic Vector Module
2//!
3//! This module provides a flexible implementation of vectors with dynamically determined
4//! dimensions.
5//!
6//! ## Mathematical Background
7//!
8//! A vector space $V$ over a field $F$ is a set equipped with operations of addition and scalar
9//! multiplication that satisfy the vector space axioms. This implementation represents elements of
10//! $V$ as an ordered collection 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//! ## Zero Vector Handling
19//!
20//! This implementation represents the zero vector as an empty vector with no components.
21//! Any vector with all components equal to zero is also considered a zero vector.
22//!
23//! ## Features
24//!
25//! - Generic implementation that works with any field type
26//! - Support for vector arithmetic operations (+, -, *, scalar multiplication)
27//! - Efficient component access and modification
28//! - Implements algebraic traits like `Zero`, `Group`, and `VectorSpace`
29//!
30//! ## Examples
31//!
32//! ```
33//! use harness_algebra::{prelude::*, tensors::dynamic::vector::DynamicVector};
34//!
35//! // Create a vector with components [1, 2, 3]
36//! let vec1 = DynamicVector::<f64>::from([1.0, 2.0, 3.0]);
37//!
38//! // Create the zero vector
39//! let zero = DynamicVector::<f64>::zero();
40//!
41//! // Vector addition
42//! let vec2 = DynamicVector::<f64>::from([4.0, 5.0, 6.0]);
43//! let sum = vec1.clone() + vec2;
44//!
45//! // Scalar multiplication
46//! let scaled = vec1 * 2.0;
47//! ```
48
49// TODO (autoparallel): We could use `MaybeUninit` to avoid the `Vec` allocation especially in the
50// zero case.
51
52// TODO (autoparallel): We could also have this be generic over an inner vector too and use
53// `smallvec` and `tinyvec` if need be.
54
55use std::fmt;
56
57use super::*;
58use crate::category::Category;
59
60/// # Dynamic Vector
61///
62/// A dynamically-sized vector implementation for n-dimensional vector spaces.
63///
64/// ## Mathematical Background
65///
66/// A vector space $V$ over a field $F$ is a set equipped with operations of addition and scalar
67/// multiplication that satisfy the vector space axioms. This implementation represents elements of
68/// $V$ as an ordered collection of components from the field $F$.
69///
70/// For any two vectors $\mathbf{u}, \mathbf{v} \in V$ and scalar $\alpha \in F$:
71///
72/// - Vector addition: $\mathbf{u} + \mathbf{v} = (u_1 + v_1, u_2 + v_2, \ldots, u_n + v_n)$
73/// - Scalar multiplication: $\alpha\mathbf{v} = (\alpha v_1, \alpha v_2, \ldots, \alpha v_n)$
74/// - Additive inverse (negation): $-\mathbf{v} = (-v_1, -v_2, \ldots, -v_n)$
75///
76/// ## Zero Vector Handling
77///
78/// This implementation represents the zero vector as an empty vector with no components.
79/// Any vector with all components equal to zero is also considered a zero vector.
80///
81/// ## Examples
82///
83/// ```
84/// use harness_algebra::{prelude::*, tensors::dynamic::vector::DynamicVector};
85///
86/// // Create a vector with components [1, 2, 3]
87/// let vec1 = DynamicVector::<f64>::from([1.0, 2.0, 3.0]);
88///
89/// // Create the zero vector
90/// let zero = DynamicVector::<f64>::zero();
91///
92/// // Vector addition
93/// let vec2 = DynamicVector::<f64>::from([4.0, 5.0, 6.0]);
94/// let sum = vec1.clone() + vec2;
95///
96/// // Scalar multiplication
97/// let scaled = vec1 * 2.0;
98/// ```
99#[derive(Default, Clone, Debug, PartialEq, Eq, Hash)]
100pub struct DynamicVector<F> {
101  /// The components of the vector.
102  pub components: Vec<F>,
103}
104
105impl<F> DynamicVector<F> {
106  /// Creates a new `DynamicVector` from a vector of components.
107  ///
108  /// # Arguments
109  ///
110  /// * `components` - A vector containing the components of the dynamic vector
111  ///
112  /// # Returns
113  ///
114  /// A new `DynamicVector` instance with the given components
115  pub const fn new(components: Vec<F>) -> Self { Self { components } }
116
117  /// Returns the dimension (number of components) of the vector.
118  ///
119  /// For the zero vector (empty components), the dimension is 0.
120  pub const fn dimension(&self) -> usize { self.components.len() }
121
122  /// Returns a reference to the components of the vector.
123  ///
124  /// This allows read-only access to the underlying data.
125  pub fn components(&self) -> &[F] { &self.components }
126
127  /// Returns a mutable reference to the components of the vector.
128  ///
129  /// This allows direct modification of the underlying data.
130  pub const fn components_mut(&mut self) -> &mut Vec<F> { &mut self.components }
131
132  /// Gets a reference to the component at the specified index.
133  ///
134  /// # Arguments
135  ///
136  /// * `index` - The index of the component to retrieve
137  ///
138  /// # Returns
139  ///
140  /// A reference to the component at the specified index
141  ///
142  /// # Panics
143  ///
144  /// Panics if the index is out of bounds.
145  pub fn get_component(&self, index: usize) -> &F { &self.components[index] }
146
147  /// Sets the component at the specified index to the given value.
148  ///
149  /// # Arguments
150  ///
151  /// * `index` - The index of the component to set
152  /// * `value` - The value to set at the specified index
153  ///
154  /// # Panics
155  ///
156  /// Panics if the index is out of bounds.
157  pub fn set_component(&mut self, index: usize, value: F) { self.components[index] = value }
158
159  /// Appends a value to the end of the vector, increasing its dimension by 1.
160  ///
161  /// # Arguments
162  ///
163  /// * `value` - The value to append to the vector
164  pub fn append(&mut self, value: F) { self.components.push(value) }
165
166  /// Removes the last component from the vector and returns it.
167  ///
168  /// # Returns
169  ///
170  /// The last component of the vector wrapped in `Some`, or `None` if the vector is empty.
171  pub fn pop(&mut self) -> Option<F> { self.components.pop() }
172
173  /// Returns a vector of zeros with the same dimension as the vector.
174  pub fn zeros(dimension: usize) -> Self
175  where F: Zero + Copy {
176    Self { components: vec![F::zero(); dimension] }
177  }
178}
179
180impl<F: Field> From<Vec<F>> for DynamicVector<F> {
181  /// Creates a new `DynamicVector` from a `Vec<F>`.
182  ///
183  /// # Arguments
184  ///
185  /// * `components` - A vector containing the components
186  fn from(components: Vec<F>) -> Self { Self { components } }
187}
188
189impl<const M: usize, F: Field + Copy> From<[F; M]> for DynamicVector<F> {
190  /// Creates a new `DynamicVector` from a fixed-size array of components.
191  ///
192  /// # Arguments
193  ///
194  /// * `components` - An array of components
195  fn from(components: [F; M]) -> Self { Self { components: components.to_vec() } }
196}
197
198impl<F: Field + Clone> From<&[F]> for DynamicVector<F> {
199  /// Creates a new `DynamicVector` from a slice of components.
200  ///
201  /// # Arguments
202  ///
203  /// * `components` - A slice of components
204  fn from(components: &[F]) -> Self { Self { components: components.to_vec() } }
205}
206
207impl<F: Field + Copy> Category for DynamicVector<F> {
208  type Morphism = DynamicDenseMatrix<F, RowMajor>;
209
210  fn compose(f: Self::Morphism, g: Self::Morphism) -> Self::Morphism { f * g }
211
212  fn identity(a: Self) -> Self::Morphism {
213    let mut mat = DynamicDenseMatrix::<F, RowMajor>::new();
214    for i in 0..a.dimension() {
215      let mut col = Self::from(vec![F::zero(); a.dimension()]);
216      col.components[i] = F::one();
217      mat.append_column(&col);
218    }
219    mat
220  }
221
222  fn apply(f: Self::Morphism, x: Self) -> Self { f * x }
223}
224
225// TODO (autoparallel): This does handle the zero case but this is clunky as fuck and I hate it.
226impl<F: Field + Copy> Add for DynamicVector<F> {
227  type Output = Self;
228
229  /// Adds two vectors component-wise.
230  ///
231  /// # Arguments
232  ///
233  /// * `other` - The vector to add to this vector
234  ///
235  /// # Returns
236  ///
237  /// A new vector representing the sum of the two vectors
238  ///
239  /// # Panics
240  ///
241  /// Panics if the vectors have different dimensions.
242  fn add(self, other: Self) -> Self::Output {
243    assert_eq!(self.components.len(), other.components.len());
244    let mut sum = Self { components: vec![F::zero(); self.components.len()] };
245    for i in 0..self.components.len() {
246      sum.components[i] = self.components[i] + other.components[i];
247    }
248    sum
249  }
250}
251
252impl<F: Field + Copy> AddAssign for DynamicVector<F> {
253  /// Adds another vector to this vector in-place.
254  ///
255  /// # Arguments
256  ///
257  /// * `rhs` - The vector to add to this vector
258  ///
259  /// # Panics
260  ///
261  /// Panics if the vectors have different dimensions.
262  fn add_assign(&mut self, rhs: Self) { *self = self.clone() + rhs }
263}
264
265impl<F: Field + Copy> Neg for DynamicVector<F> {
266  type Output = Self;
267
268  /// Negates this vector, returning a vector with all components negated.
269  ///
270  /// # Returns
271  ///
272  /// A new vector representing the negation of this vector
273  fn neg(self) -> Self::Output {
274    let mut neg = Self { components: vec![F::zero(); self.components.len()] };
275    for i in 0..self.components.len() {
276      neg.components[i] = -self.components[i];
277    }
278    neg
279  }
280}
281
282impl<F: Field + Copy> Mul<F> for DynamicVector<F> {
283  type Output = Self;
284
285  /// Multiplies this vector by a scalar.
286  ///
287  /// # Arguments
288  ///
289  /// * `scalar` - The scalar to multiply by
290  ///
291  /// # Returns
292  ///
293  /// A new vector representing the product of this vector and the scalar
294  fn mul(self, scalar: F) -> Self::Output {
295    let mut scalar_multiple = Self { components: vec![F::zero(); self.components.len()] };
296    for i in 0..self.components.len() {
297      scalar_multiple.components[i] = scalar * self.components[i];
298    }
299    scalar_multiple
300  }
301}
302
303impl<F: Field + Copy> Sub for DynamicVector<F> {
304  type Output = Self;
305
306  /// Subtracts another vector from this vector.
307  ///
308  /// # Arguments
309  ///
310  /// * `other` - The vector to subtract from this vector
311  ///
312  /// # Returns
313  ///
314  /// A new vector representing the difference between the two vectors
315  ///
316  /// # Panics
317  ///
318  /// Panics if the vectors have different dimensions.
319  fn sub(self, other: Self) -> Self::Output { self + -other }
320}
321
322impl<F: Field + Copy> SubAssign for DynamicVector<F> {
323  /// Subtracts another vector from this vector in-place.
324  ///
325  /// # Arguments
326  ///
327  /// * `rhs` - The vector to subtract from this vector
328  ///
329  /// # Panics
330  ///
331  /// Panics if the vectors have different dimensions.
332  fn sub_assign(&mut self, rhs: Self) { *self = self.clone() - rhs }
333}
334
335impl<F: Field + Copy> Additive for DynamicVector<F> {}
336
337impl<F: Field + Copy> Group for DynamicVector<F> {
338  /// Returns the identity element for vector addition (the zero vector).
339  fn identity() -> Self { Self::zero() }
340
341  /// Returns the additive inverse of this vector.
342  fn inverse(&self) -> Self { -self.clone() }
343}
344
345impl<F: Field + Copy> Zero for DynamicVector<F> {
346  /// Returns the zero vector (empty vector with no components).
347  fn zero() -> Self { Self { components: vec![] } }
348
349  /// Checks if this vector is the zero vector.
350  ///
351  /// A vector is considered zero if either:
352  /// 1. It has no components (empty vector)
353  /// 2. All of its components are equal to the zero element of the field
354  fn is_zero(&self) -> bool {
355    self.components.iter().all(|x| *x == F::zero()) || self.components.is_empty()
356  }
357}
358
359impl<F: Field + Copy> AbelianGroup for DynamicVector<F> {}
360
361impl<F: Field + Copy + Mul<Self>> LeftModule for DynamicVector<F> {
362  type Ring = F;
363}
364
365impl<F: Field + Copy + Mul<Self>> RightModule for DynamicVector<F> {
366  type Ring = F;
367}
368
369impl<F: Field + Copy + Mul<Self>> TwoSidedModule for DynamicVector<F> {
370  type Ring = F;
371}
372
373impl<F: Field + Copy + Mul<Self>> VectorSpace for DynamicVector<F> {}
374
375impl<F> Iterator for DynamicVector<F> {
376  type Item = F;
377
378  fn next(&mut self) -> Option<Self::Item> { self.components.pop() }
379}
380
381impl<F: Field + Copy + fmt::Display> fmt::Display for DynamicVector<F> {
382  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
383    if self.components.is_empty() {
384      return write!(f, "( )");
385    }
386
387    if self.components.len() == 1 {
388      // Single element: use simple parentheses
389      return write!(f, "( {} )", self.components[0]);
390    }
391
392    // Calculate the width needed for proper alignment
393    let mut max_width = 0;
394    for component in &self.components {
395      let component_str = format!("{component}");
396      max_width = max_width.max(component_str.len());
397    }
398
399    // Multi-element: use tall parentheses
400    for (i, component) in self.components.iter().enumerate() {
401      if i == 0 {
402        writeln!(f, "⎛ {component:>max_width$} ⎞")?;
403      } else if i == self.components.len() - 1 {
404        write!(f, "⎝ {component:>max_width$} ⎠")?;
405      } else {
406        writeln!(f, "⎜ {component:>max_width$} ⎟")?;
407      }
408    }
409
410    Ok(())
411  }
412}
413
414#[cfg(test)]
415mod tests {
416  use fixtures::Mod7;
417
418  use super::*;
419
420  #[test]
421  fn test_zero_vector() {
422    let zero_vec: DynamicVector<Mod7> = DynamicVector::zero();
423    assert!(zero_vec.is_zero());
424    assert_eq!(zero_vec.components.len(), 0, "Default zero vector should have 0 components");
425
426    let non_zero_vec = DynamicVector::<Mod7>::from([Mod7::from(1), Mod7::from(0)]);
427    assert!(!non_zero_vec.is_zero());
428
429    let zero_vec_explicit_empty: DynamicVector<Mod7> = DynamicVector::from([]);
430    assert!(zero_vec_explicit_empty.is_zero());
431    assert_eq!(
432      zero_vec_explicit_empty.components.len(),
433      0,
434      "Explicit empty vector should have 0 components"
435    );
436  }
437
438  #[test]
439  fn test_is_zero_for_non_empty_vector_with_all_zeros() {
440    let vec_all_zeros: DynamicVector<Mod7> =
441      DynamicVector::from([Mod7::from(0), Mod7::from(0), Mod7::from(0)]);
442    assert!(vec_all_zeros.is_zero());
443  }
444
445  #[test]
446  fn test_addition_zero_vectors() {
447    let vec1: DynamicVector<Mod7> = DynamicVector::zero();
448    let vec2: DynamicVector<Mod7> = DynamicVector::zero();
449    let sum = vec1 + vec2;
450    assert!(sum.is_zero());
451    assert_eq!(
452      sum.components.len(),
453      0,
454      "Sum of two default zero vectors should be a zero vector with 0 components"
455    );
456  }
457
458  #[test]
459  fn test_addition_same_dimension() {
460    let vec1 = DynamicVector::<Mod7>::from([Mod7::from(1), Mod7::from(0)]);
461    let vec2 = DynamicVector::<Mod7>::from([Mod7::from(1), Mod7::from(1)]);
462    let sum = vec1 + vec2;
463    assert_eq!(sum.components, vec![Mod7::from(2), Mod7::from(1)]);
464  }
465
466  #[test]
467  #[should_panic(expected = "assertion `left == right` failed\n  left: 2\n right: 0")]
468  fn test_addition_with_zero_vector_implicit_panics() {
469    let vec1 = DynamicVector::<Mod7>::from([Mod7::from(1), Mod7::from(0)]);
470    let zero_vec: DynamicVector<Mod7> = DynamicVector::zero();
471    let _ = vec1 + zero_vec; // Panics because vec1.len (2) != zero_vec.len (0)
472  }
473
474  #[test]
475  #[should_panic(expected = "assertion `left == right` failed\n  left: 2\n right: 3")]
476  fn test_addition_different_dimensions_panic() {
477    let vec1 = DynamicVector::<Mod7>::from([Mod7::from(1), Mod7::from(0)]);
478    let vec2 = DynamicVector::<Mod7>::from([Mod7::from(1), Mod7::from(1), Mod7::from(1)]);
479    let _ = vec1 + vec2; // Should panic
480  }
481
482  #[test]
483  fn test_negation() {
484    let vec = DynamicVector::<Mod7>::from([Mod7::from(1), Mod7::from(0)]);
485    let neg_vec = -vec;
486    assert_eq!(neg_vec.components, vec![Mod7::from(6), Mod7::from(0)]);
487  }
488
489  #[test]
490  fn test_scalar_multiplication() {
491    let vec = DynamicVector::<Mod7>::from([Mod7::from(1), Mod7::from(0), Mod7::from(1)]);
492    let scalar_one = Mod7::from(1);
493    let scalar_zero = Mod7::from(0);
494
495    let mul_one = vec.clone() * scalar_one;
496    assert_eq!(mul_one.components, vec![
497      Mod7::from(1) * scalar_one,
498      Mod7::from(0) * scalar_one,
499      Mod7::from(1) * scalar_one
500    ]);
501
502    let mul_zero = vec * scalar_zero;
503    assert_eq!(mul_zero.components, vec![Mod7::from(0), Mod7::from(0), Mod7::from(0)]);
504  }
505
506  #[test]
507  fn test_subtraction_same_dimension() {
508    let vec1 = DynamicVector::<Mod7>::from([Mod7::from(1), Mod7::from(1)]);
509    let vec2 = DynamicVector::<Mod7>::from([Mod7::from(0), Mod7::from(1)]);
510    let diff = vec1 + (-vec2);
511    assert_eq!(diff.components, vec![Mod7::from(1), Mod7::from(0)]);
512  }
513
514  #[test]
515  #[should_panic(expected = "assertion `left == right` failed\n  left: 2\n right: 1")]
516  fn test_subtraction_different_dimensions_panic() {
517    let vec1 = DynamicVector::<Mod7>::from([Mod7::from(1), Mod7::from(0)]);
518    let vec2 = DynamicVector::<Mod7>::from([Mod7::from(1)]);
519    let _ = vec1 - vec2;
520  }
521
522  #[test]
523  fn test_add_assign_same_dimension() {
524    let mut vec1 = DynamicVector::<Mod7>::from([Mod7::from(1), Mod7::from(0)]);
525    let vec2 = DynamicVector::<Mod7>::from([Mod7::from(1), Mod7::from(1)]);
526    vec1 += vec2;
527    assert_eq!(vec1.components, vec![Mod7::from(2), Mod7::from(1)]);
528  }
529
530  #[test]
531  #[should_panic(expected = "assertion `left == right` failed\n  left: 2\n right: 1")]
532  fn test_add_assign_different_dimensions_panic() {
533    let mut vec1 = DynamicVector::<Mod7>::from([Mod7::from(1), Mod7::from(0)]);
534    let vec2 = DynamicVector::<Mod7>::from([Mod7::from(1)]);
535    vec1 += vec2; // Should panic
536  }
537
538  #[test]
539  fn test_sub_assign_same_dimension() {
540    let mut vec1 = DynamicVector::<Mod7>::from([Mod7::from(1), Mod7::from(1)]);
541    let vec2 = DynamicVector::<Mod7>::from([Mod7::from(0), Mod7::from(1)]);
542    vec1 -= vec2;
543    assert_eq!(vec1.components, vec![Mod7::from(1), Mod7::from(0)]);
544  }
545
546  #[test]
547  #[should_panic(expected = "assertion `left == right` failed\n  left: 2\n right: 1")]
548  fn test_sub_assign_different_dimensions_panic() {
549    let mut vec1 = DynamicVector::<Mod7>::from([Mod7::from(1), Mod7::from(0)]);
550    let vec2 = DynamicVector::<Mod7>::from([Mod7::from(1)]);
551    vec1 -= vec2; // Should panic
552  }
553
554  #[test]
555  fn test_zeros() {
556    let zero_vec = DynamicVector::<Mod7>::zeros(3);
557    assert_eq!(zero_vec.components, vec![Mod7::from(0), Mod7::from(0), Mod7::from(0)]);
558  }
559
560  #[test]
561  fn test_display_formatting() {
562    // Test empty vector
563    let empty: DynamicVector<f64> = DynamicVector::new(vec![]);
564    println!("Empty vector: \n{empty}");
565
566    // Test single element
567    let single = DynamicVector::from([42.0]);
568    println!("Single element: \n{single}");
569
570    // Test multiple elements
571    let multi = DynamicVector::from([1.0, 2.5, -3.7, 0.0]);
572    println!("Multiple elements: \n{multi}");
573  }
574}