Skip to main content

cova_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`] is essentially a set of N-dimensional vectors with elements [`f64`].
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 cova_algebra::tensors::SVector;
19//! use cova_space::{cloud::Cloud, prelude::*};
20//!
21//! // Create two 2D vectors
22//! let v1 = SVector::from([1.0, 2.0]);
23//! let v2 = SVector::from([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>::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 cova_algebra::tensors::SVector;
43
44use crate::{
45  definitions::{MetricSpace, NormedSpace},
46  set::Collection,
47};
48
49/// Defines the [`Cloud`] struct, representing a collection of points (vectors)
50/// in an N-dimensional space.
51///
52/// This module provides the `Cloud` type, which can be used to store and
53/// manage a set of points. It implements traits for basic collection operations,
54/// as well as for metric and normed space concepts, allowing for calculations
55/// like distance and norm.
56///
57/// A `Cloud` is essentially a set of vectors, providing basic [`Collection`] operations
58/// as well as metric and normed space functionalities.
59#[derive(Debug, Clone)]
60pub struct Cloud<const N: usize> {
61  points: Vec<SVector<f64, N>>,
62}
63
64impl<const N: usize> Cloud<N> {
65  /// Creates a new `Cloud` from a given set of points.
66  ///
67  /// # Arguments
68  ///
69  /// * `points`: A `HashSet` of `Vector<N, F>` representing the points in the cloud.
70  pub const fn new(points: Vec<SVector<f64, N>>) -> Self { Self { points } }
71
72  /// Returns a reference to the points in the cloud.
73  pub const fn points_ref(&self) -> &Vec<SVector<f64, N>> { &self.points }
74}
75
76impl<const N: usize> Collection for Cloud<N> {
77  type Item = SVector<f64, N>;
78
79  fn contains(&self, point: &Self::Item) -> bool { self.points.contains(point) }
80
81  fn is_empty(&self) -> bool { self.points.is_empty() }
82}
83
84impl<const N: usize> MetricSpace for Cloud<N> {
85  type Distance = f64;
86
87  /// Calculates the distance between two points in the cloud.
88  ///
89  /// The distance is defined as the norm of the difference between the two points.
90  fn distance(point_a: Self::Item, point_b: Self::Item) -> Self::Distance {
91    <Self as NormedSpace>::norm(point_a - point_b)
92  }
93}
94
95impl<const N: usize> NormedSpace for Cloud<N> {
96  type Norm = f64;
97
98  /// Calculates the norm of a point.
99  ///
100  /// The norm is defined as the sum of the squares of its components (Euclidean norm).
101  fn norm(point: Self::Item) -> Self::Norm { point.iter().map(|p| *p * *p).sum::<f64>().sqrt() }
102}
103
104#[cfg(test)]
105mod tests {
106  #![allow(clippy::float_cmp)]
107
108  use super::*;
109
110  fn create_test_vector1() -> SVector<f64, 2> { SVector::from([1.0, 2.0]) }
111
112  fn create_test_vector2() -> SVector<f64, 2> { SVector::from([3.0, 4.0]) }
113
114  #[test]
115  fn test_new_cloud() {
116    let points = vec![create_test_vector1()];
117    let cloud = Cloud::new(points.clone());
118    assert_eq!(cloud.points, points);
119  }
120
121  #[test]
122  fn test_contains_point() {
123    let points = vec![create_test_vector1()];
124    let cloud = Cloud::new(points);
125    assert!(cloud.contains(&create_test_vector1()));
126    assert!(!cloud.contains(&create_test_vector2()));
127  }
128
129  #[test]
130  fn test_is_empty() {
131    let points: Vec<SVector<f64, 2>> = Vec::new();
132    let cloud = Cloud::new(points);
133    assert!(cloud.is_empty());
134
135    let points_non_empty = vec![create_test_vector1()];
136    let cloud_non_empty = Cloud::new(points_non_empty);
137    assert!(!cloud_non_empty.is_empty());
138  }
139
140  #[test]
141  fn test_norm() {
142    let v1 = create_test_vector1(); // [1.0, 2.0]
143    // 1.0*1.0 + 2.0*2.0 = 1.0 + 4.0 = 5.0
144    assert_eq!(Cloud::<2>::norm(v1), 5.0_f64.sqrt());
145
146    let v2 = create_test_vector2(); // [3.0, 4.0]
147    // 3.0*3.0 + 4.0*4.0 = 9.0 + 16.0 = 25.0
148    assert_eq!(Cloud::<2>::norm(v2), 25.0_f64.sqrt());
149  }
150
151  #[test]
152  fn test_distance() {
153    let v1 = create_test_vector1(); // [1.0, 2.0]
154    let v2 = create_test_vector2(); // [3.0, 4.0]
155    // v1 - v2 = [-2.0, -2.0]
156    // norm([-2.0, -2.0]) = (-2.0)*(-2.0) + (-2.0)*(-2.0) = 4.0 + 4.0 = 8.0
157    assert_eq!(Cloud::<2>::distance(v1, v2), 8.0_f64.sqrt());
158  }
159}