1use crate::error::Result;
7use crate::phantom::{Complete, CompletenessProperty};
8use core::marker::PhantomData;
9
10pub trait VectorSpace<V, S = f64> {
20 fn add(&self, x: &V, y: &V) -> V;
22
23 fn sub(&self, x: &V, y: &V) -> V;
25
26 fn scale(&self, scalar: S, x: &V) -> V;
28
29 fn zero(&self) -> V;
31
32 fn dimension(&self) -> Option<usize>;
34}
35
36pub trait NormedSpace<V, S = f64>: VectorSpace<V, S> {
48 fn norm(&self, x: &V) -> f64;
50
51 fn distance(&self, x: &V, y: &V) -> f64 {
53 self.norm(&self.sub(x, y))
54 }
55
56 fn normalize(&self, x: &V) -> Option<V>
60 where
61 S: From<f64>,
62 V: Clone;
63}
64
65pub trait BanachSpace<V, S = f64, C = Complete>: NormedSpace<V, S>
76where
77 C: CompletenessProperty,
78{
79 fn is_cauchy_sequence(&self, sequence: &[V], tolerance: f64) -> bool;
83
84 fn sequence_limit(&self, sequence: &[V], tolerance: f64) -> Result<V>;
86}
87
88pub trait InnerProductSpace<V, S = f64>: NormedSpace<V, S> {
102 fn inner_product(&self, x: &V, y: &V) -> S;
104
105 fn are_orthogonal(&self, x: &V, y: &V, tolerance: f64) -> bool
107 where
108 S: Into<f64>,
109 {
110 let ip: f64 = self.inner_product(x, y).into();
111 ip.abs() < tolerance
112 }
113
114 fn project(&self, x: &V, y: &V) -> V
118 where
119 S: Into<f64> + From<f64>,
120 V: Clone;
121
122 fn gram_schmidt(&self, vectors: &[V]) -> Vec<V>
124 where
125 S: Into<f64> + From<f64>,
126 V: Clone;
127}
128
129pub trait HilbertSpace<V, S = f64, C = Complete>:
140 InnerProductSpace<V, S> + BanachSpace<V, S, C>
141where
142 C: CompletenessProperty,
143{
144 fn riesz_representative<F>(&self, functional: F) -> Result<V>
149 where
150 F: Fn(&V) -> S;
151
152 fn orthogonal_complement_projection(&self, x: &V, subspace_basis: &[V]) -> V
157 where
158 S: Into<f64> + From<f64>,
159 V: Clone,
160 {
161 let mut result = x.clone();
162 for basis_vec in subspace_basis {
163 let proj = self.project(&result, basis_vec);
164 result = self.sub(&result, &proj);
165 }
166 result
167 }
168
169 fn best_approximation(&self, x: &V, subspace_basis: &[V]) -> V
173 where
174 S: Into<f64> + From<f64>,
175 V: Clone,
176 {
177 let mut result = self.zero();
178 for basis_vec in subspace_basis {
179 let proj = self.project(x, basis_vec);
180 result = self.add(&result, &proj);
181 }
182 result
183 }
184
185 fn is_orthonormal(&self, vectors: &[V], tolerance: f64) -> bool
187 where
188 S: Into<f64>,
189 {
190 for (i, vi) in vectors.iter().enumerate() {
191 let norm_i = self.norm(vi);
193 if (norm_i - 1.0).abs() > tolerance {
194 return false;
195 }
196
197 for vj in vectors.iter().skip(i + 1) {
199 if !self.are_orthogonal(vi, vj, tolerance) {
200 return false;
201 }
202 }
203 }
204 true
205 }
206}
207
208#[derive(Debug, Clone, Copy)]
210pub struct SpaceWithCompleteness<S, C: CompletenessProperty> {
211 space: S,
212 _completeness: PhantomData<C>,
213}
214
215impl<S, C: CompletenessProperty> SpaceWithCompleteness<S, C> {
216 pub fn new(space: S) -> Self {
218 Self {
219 space,
220 _completeness: PhantomData,
221 }
222 }
223
224 pub fn space(&self) -> &S {
226 &self.space
227 }
228
229 pub fn space_mut(&mut self) -> &mut S {
231 &mut self.space
232 }
233
234 pub fn into_inner(self) -> S {
236 self.space
237 }
238}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243
244 struct R3Space;
246
247 impl VectorSpace<[f64; 3], f64> for R3Space {
248 fn add(&self, x: &[f64; 3], y: &[f64; 3]) -> [f64; 3] {
249 [x[0] + y[0], x[1] + y[1], x[2] + y[2]]
250 }
251
252 fn sub(&self, x: &[f64; 3], y: &[f64; 3]) -> [f64; 3] {
253 [x[0] - y[0], x[1] - y[1], x[2] - y[2]]
254 }
255
256 fn scale(&self, scalar: f64, x: &[f64; 3]) -> [f64; 3] {
257 [scalar * x[0], scalar * x[1], scalar * x[2]]
258 }
259
260 fn zero(&self) -> [f64; 3] {
261 [0.0, 0.0, 0.0]
262 }
263
264 fn dimension(&self) -> Option<usize> {
265 Some(3)
266 }
267 }
268
269 impl NormedSpace<[f64; 3], f64> for R3Space {
270 fn norm(&self, x: &[f64; 3]) -> f64 {
271 (x[0] * x[0] + x[1] * x[1] + x[2] * x[2]).sqrt()
272 }
273
274 fn normalize(&self, x: &[f64; 3]) -> Option<[f64; 3]> {
275 let n = self.norm(x);
276 if n < 1e-15 {
277 None
278 } else {
279 Some(self.scale(1.0 / n, x))
280 }
281 }
282 }
283
284 impl InnerProductSpace<[f64; 3], f64> for R3Space {
285 fn inner_product(&self, x: &[f64; 3], y: &[f64; 3]) -> f64 {
286 x[0] * y[0] + x[1] * y[1] + x[2] * y[2]
287 }
288
289 fn project(&self, x: &[f64; 3], y: &[f64; 3]) -> [f64; 3] {
290 let ip_xy = self.inner_product(x, y);
291 let ip_yy = self.inner_product(y, y);
292 if ip_yy.abs() < 1e-15 {
293 self.zero()
294 } else {
295 self.scale(ip_xy / ip_yy, y)
296 }
297 }
298
299 fn gram_schmidt(&self, vectors: &[[f64; 3]]) -> Vec<[f64; 3]> {
300 let mut orthonormal = Vec::new();
301 for v in vectors {
302 let mut u = *v;
303 for q in &orthonormal {
304 let proj = self.project(&u, q);
305 u = self.sub(&u, &proj);
306 }
307 if let Some(normalized) = self.normalize(&u) {
308 orthonormal.push(normalized);
309 }
310 }
311 orthonormal
312 }
313 }
314
315 #[test]
316 fn test_vector_space_operations() {
317 let space = R3Space;
318
319 let x = [1.0, 2.0, 3.0];
320 let y = [4.0, 5.0, 6.0];
321
322 let sum = space.add(&x, &y);
323 assert_eq!(sum, [5.0, 7.0, 9.0]);
324
325 let diff = space.sub(&x, &y);
326 assert_eq!(diff, [-3.0, -3.0, -3.0]);
327
328 let scaled = space.scale(2.0, &x);
329 assert_eq!(scaled, [2.0, 4.0, 6.0]);
330
331 assert_eq!(space.dimension(), Some(3));
332 }
333
334 #[test]
335 fn test_normed_space_operations() {
336 let space = R3Space;
337
338 let x = [3.0, 4.0, 0.0];
339 assert!((space.norm(&x) - 5.0).abs() < 1e-10);
340
341 let normalized = space.normalize(&x).unwrap();
342 assert!((space.norm(&normalized) - 1.0).abs() < 1e-10);
343
344 let y = [1.0, 0.0, 0.0];
345 let dist = space.distance(&x, &y);
346 assert!((dist - (4.0_f64 + 16.0).sqrt()).abs() < 1e-10);
347 }
348
349 #[test]
350 fn test_inner_product_space_operations() {
351 let space = R3Space;
352
353 let x = [1.0, 0.0, 0.0];
354 let y = [0.0, 1.0, 0.0];
355 let z = [1.0, 1.0, 0.0];
356
357 assert!(space.are_orthogonal(&x, &y, 1e-10));
359 assert!(!space.are_orthogonal(&x, &z, 1e-10));
360
361 let proj = space.project(&z, &x);
363 assert!((proj[0] - 1.0).abs() < 1e-10);
364 assert!(proj[1].abs() < 1e-10);
365 assert!(proj[2].abs() < 1e-10);
366 }
367
368 #[test]
369 fn test_gram_schmidt() {
370 let space = R3Space;
371
372 let vectors = [[1.0, 1.0, 0.0], [1.0, 0.0, 1.0], [0.0, 1.0, 1.0]];
373 let orthonormal = space.gram_schmidt(&vectors);
374
375 assert_eq!(orthonormal.len(), 3);
376
377 for (i, vi) in orthonormal.iter().enumerate() {
379 assert!((space.norm(vi) - 1.0).abs() < 1e-10);
381
382 for (j, vj) in orthonormal.iter().enumerate() {
384 if i != j {
385 assert!(space.are_orthogonal(vi, vj, 1e-10));
386 }
387 }
388 }
389 }
390}