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}