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}