harness_space/
cloud.rs

1//! # Cloud - Vector Set in N-dimensional Space
2//!
3//! This module defines the `Cloud` struct and its implementations, representing a collection
4//! of points (vectors) in an `N-`dimensional space.
5//!
6//! ## Overview
7//!
8//! A [`Cloud<N, F>`] is essentially a set of N-dimensional vectors with elements from a field `F`.
9//! The module provides:
10//!
11//! - Basic collection operations ([`Collection::contains`], [`Collection::is_empty`])
12//! - Metric space capabilities ([`MetricSpace::distance`])
13//! - Normed space functionality ([`NormedSpace::norm`])
14//!
15//! ## Example
16//!
17//! ```
18//! use harness_algebra::tensors::fixed::FixedVector;
19//! use harness_space::{cloud::Cloud, prelude::*};
20//!
21//! // Create two 2D vectors
22//! let v1 = FixedVector([1.0, 2.0]);
23//! let v2 = FixedVector([3.0, 4.0]);
24//!
25//! // Create a cloud containing these vectors
26//! let cloud = Cloud::new(vec![v1, v2]);
27//!
28//! // Check if the cloud contains a vector
29//! assert!(cloud.contains(&v1));
30//!
31//! // Calculate distance between vectors
32//! let distance = Cloud::<2, f64>::distance(v1, v2);
33//! ```
34//!
35//! ## Implementation Details
36//!
37//! The `Cloud` implements several traits:
38//! - `Collection` - Basic set operations
39//! - `MetricSpace` - Distance calculations
40//! - `NormedSpace` - Norm calculations (Euclidean norm)
41
42use std::iter::Sum;
43
44use harness_algebra::{rings::Field, tensors::fixed::FixedVector};
45
46use crate::{
47  definitions::{MetricSpace, NormedSpace},
48  set::Collection,
49};
50
51/// Defines the [`Cloud`] struct, representing a collection of points (vectors)
52/// in an N-dimensional space.
53///
54/// This module provides the `Cloud` type, which can be used to store and
55/// manage a set of points. It implements traits for basic collection operations,
56/// as well as for metric and normed space concepts, allowing for calculations
57/// like distance and norm.
58///
59/// A `Cloud` is essentially a set of vectors, providing basic [`Collection`] operations
60/// as well as metric and normed space functionalities.
61#[derive(Debug, Clone)]
62pub struct Cloud<const N: usize, F: Field> {
63  points: Vec<FixedVector<N, F>>,
64}
65
66impl<F: Field, const N: usize> Cloud<N, F> {
67  /// Creates a new `Cloud` from a given set of points.
68  ///
69  /// # Arguments
70  ///
71  /// * `points`: A `HashSet` of `Vector<N, F>` representing the points in the cloud.
72  pub const fn new(points: Vec<FixedVector<N, F>>) -> Self { Self { points } }
73
74  /// Returns a reference to the points in the cloud.
75  pub const fn points_ref(&self) -> &Vec<FixedVector<N, F>> { &self.points }
76}
77
78impl<const N: usize, F: Field + Copy + Sum<F>> Collection for Cloud<N, F> {
79  type Item = FixedVector<N, F>;
80
81  fn contains(&self, point: &Self::Item) -> bool { self.points.contains(point) }
82
83  fn is_empty(&self) -> bool { self.points.is_empty() }
84}
85
86impl<const N: usize, F: Field + Copy + Sum<F>> MetricSpace for Cloud<N, F> {
87  type Distance = F;
88
89  /// Calculates the distance between two points in the cloud.
90  ///
91  /// The distance is defined as the norm of the difference between the two points.
92  fn distance(point_a: Self::Item, point_b: Self::Item) -> Self::Distance {
93    <Self as NormedSpace>::norm(point_a - point_b)
94  }
95}
96
97impl<const N: usize, F: Field + Copy + Sum<F>> NormedSpace for Cloud<N, F> {
98  type Norm = F;
99
100  /// Calculates the norm of a point.
101  ///
102  /// The norm is defined as the sum of the squares of its components (Euclidean norm).
103  fn norm(point: Self::Item) -> Self::Norm { point.0.iter().map(|p| *p * *p).sum() }
104}
105
106#[cfg(test)]
107mod tests {
108  #![allow(clippy::float_cmp)]
109
110  use super::*;
111
112  fn create_test_vector1() -> FixedVector<2, f64> { FixedVector([1.0, 2.0]) }
113
114  fn create_test_vector2() -> FixedVector<2, f64> { FixedVector([3.0, 4.0]) }
115
116  #[test]
117  fn test_new_cloud() {
118    let points = vec![create_test_vector1()];
119    let cloud = Cloud::new(points.clone());
120    assert_eq!(cloud.points, points);
121  }
122
123  #[test]
124  fn test_contains_point() {
125    let points = vec![create_test_vector1()];
126    let cloud = Cloud::new(points);
127    assert!(cloud.contains(&create_test_vector1()));
128    assert!(!cloud.contains(&create_test_vector2()));
129  }
130
131  #[test]
132  fn test_is_empty() {
133    let points: Vec<FixedVector<2, f64>> = Vec::new();
134    let cloud = Cloud::new(points);
135    assert!(cloud.is_empty());
136
137    let points_non_empty = vec![create_test_vector1()];
138    let cloud_non_empty = Cloud::new(points_non_empty);
139    assert!(!cloud_non_empty.is_empty());
140  }
141
142  #[test]
143  fn test_norm() {
144    let v1 = create_test_vector1(); // [1.0, 2.0]
145                                    // 1.0*1.0 + 2.0*2.0 = 1.0 + 4.0 = 5.0
146    assert_eq!(Cloud::<2, f64>::norm(v1), 5.0);
147
148    let v2 = create_test_vector2(); // [3.0, 4.0]
149                                    // 3.0*3.0 + 4.0*4.0 = 9.0 + 16.0 = 25.0
150    assert_eq!(Cloud::<2, f64>::norm(v2), 25.0);
151  }
152
153  #[test]
154  fn test_distance() {
155    let v1 = create_test_vector1(); // [1.0, 2.0]
156    let v2 = create_test_vector2(); // [3.0, 4.0]
157                                    // v1 - v2 = [-2.0, -2.0]
158                                    // norm([-2.0, -2.0]) = (-2.0)*(-2.0) + (-2.0)*(-2.0) = 4.0 + 4.0 = 8.0
159    assert_eq!(Cloud::<2, f64>::distance(v1, v2), 8.0);
160  }
161}