| 1 /*! |
1 /*! |
| 2 Euclidean spaces. |
2 Euclidean spaces. |
| 3 */ |
3 */ |
| 4 |
4 |
| 5 use crate::instance::Instance; |
5 use crate::instance::Instance; |
| 6 use crate::linops::AXPY; |
6 use crate::linops::{VectorSpace, AXPY}; |
| 7 use crate::norms::{HasDual, Reflexive}; |
7 use crate::norms::{HasDual, Reflexive}; |
| 8 use crate::types::*; |
8 use crate::types::*; |
| 9 use std::ops::{Add, AddAssign, Sub, SubAssign}; |
9 use std::ops::{Add, AddAssign, Sub, SubAssign}; |
| 10 |
10 |
| 11 pub mod wrap; |
11 pub mod wrap; |
| 12 |
12 |
| |
13 // TODO: Euclidean & EuclideanMut |
| |
14 // |
| 13 /// Space (type) with Euclidean and vector space structure |
15 /// Space (type) with Euclidean and vector space structure |
| 14 /// |
16 /// |
| 15 /// The type should implement vector space operations (addition, subtraction, scalar |
17 /// The type should implement vector space operations (addition, subtraction, scalar |
| 16 /// multiplication and scalar division) along with their assignment versions, as well |
18 /// multiplication and scalar division) along with their assignment versions, as well |
| 17 /// as an inner product. |
19 /// as an inner product. |
| 18 // TODO: remove F parameter, use AXPY::Field |
20 // TODO: remove F parameter, use AXPY::Field |
| 19 pub trait Euclidean<F: Float = f64>: |
21 pub trait Euclidean<F: Float = f64>: |
| 20 HasDual<F, DualSpace = Self> |
22 HasDual<F, DualSpace = Self> |
| 21 + AXPY<Field = F> |
23 + VectorSpace<Field = F> |
| 22 + Reflexive<F> |
24 + Reflexive<F> |
| 23 // TODO: move the following to AXPY |
25 // TODO: move the following to AXPY |
| 24 + for<'b> Add<&'b Self, Output = <Self as AXPY>::Owned> |
26 + for<'b> Add<&'b Self, Output = <Self as VectorSpace>::Owned> |
| 25 + for<'b> Sub<&'b Self, Output = <Self as AXPY>::Owned> |
27 + for<'b> Sub<&'b Self, Output = <Self as VectorSpace>::Owned> |
| 26 + for<'b> AddAssign<&'b Self> |
28 + for<'b> AddAssign<&'b Self> |
| 27 + for<'b> SubAssign<&'b Self> |
29 + for<'b> SubAssign<&'b Self> |
| 28 { |
30 { |
| 29 // Inner product |
31 // Inner product |
| 30 fn dot<I: Instance<Self>>(&self, other: I) -> F; |
32 fn dot<I: Instance<Self>>(&self, other: I) -> F; |
| 57 self.dist2_squared(y).sqrt() |
59 self.dist2_squared(y).sqrt() |
| 58 } |
60 } |
| 59 |
61 |
| 60 /// Projection to the 2-ball. |
62 /// Projection to the 2-ball. |
| 61 #[inline] |
63 #[inline] |
| 62 fn proj_ball2(mut self, ρ: F) -> Self { |
64 fn proj_ball2(self, ρ: F) -> Self::Owned { |
| 63 self.proj_ball2_mut(ρ); |
65 let r = self.norm2(); |
| 64 self |
66 if r > ρ { |
| |
67 self * (ρ / r) |
| |
68 } else { |
| |
69 self.into_owned() |
| |
70 } |
| 65 } |
71 } |
| |
72 } |
| 66 |
73 |
| |
74 // TODO: remove F parameter, use AXPY::Field |
| |
75 pub trait EuclideanMut<F: Float = f64>: |
| |
76 Euclidean<F> + AXPY<Field = F> + for<'b> AddAssign<&'b Self> + for<'b> SubAssign<&'b Self> |
| |
77 { |
| 67 /// In-place projection to the 2-ball. |
78 /// In-place projection to the 2-ball. |
| 68 #[inline] |
79 #[inline] |
| 69 fn proj_ball2_mut(&mut self, ρ: F) { |
80 fn proj_ball2_mut(&mut self, ρ: F) { |
| 70 let r = self.norm2(); |
81 let r = self.norm2(); |
| 71 if r > ρ { |
82 if r > ρ { |
| 72 *self *= ρ / r |
83 *self *= ρ / r |
| 73 } |
84 } |
| 74 } |
85 } |
| 75 } |
86 } |
| 76 |
87 |
| |
88 impl<X, F: Float> EuclideanMut<F> for X where |
| |
89 X: Euclidean<F> + AXPY<Field = F> + for<'b> AddAssign<&'b Self> + for<'b> SubAssign<&'b Self> |
| |
90 { |
| |
91 } |
| |
92 |
| 77 /// Trait for [`Euclidean`] spaces with dimensions known at compile time. |
93 /// Trait for [`Euclidean`] spaces with dimensions known at compile time. |
| 78 pub trait StaticEuclidean<F: Float = f64>: Euclidean<F> { |
94 pub trait StaticEuclidean<F: Float = f64>: Euclidean<F> { |
| 79 /// Returns the origin |
95 /// Returns the origin |
| 80 fn origin() -> <Self as AXPY>::Owned; |
96 fn origin() -> <Self as VectorSpace>::Owned; |
| 81 } |
97 } |