| 2 Euclidean spaces. |
2 Euclidean spaces. |
| 3 */ |
3 */ |
| 4 |
4 |
| 5 use crate::types::*; |
5 use crate::types::*; |
| 6 use std::ops::{Mul, MulAssign, Div, DivAssign, Add, Sub, AddAssign, SubAssign, Neg}; |
6 use std::ops::{Mul, MulAssign, Div, DivAssign, Add, Sub, AddAssign, SubAssign, Neg}; |
| |
7 pub use crate::types::{HasScalarField, HasRealField}; |
| 7 |
8 |
| 8 /// Space (type) with a defined dot product. |
9 /// Space (type) with a defined dot product. |
| 9 /// |
10 /// |
| 10 /// `U` is the space of the multiplier, and `F` the space of scalars. |
11 /// `U` is the space of the multiplier, and `F` the space of scalars. |
| 11 /// Since `U` ≠ `Self`, this trait can also implement dual products. |
12 /// Since `U` ≠ `Self`, this trait can also implement dual products. |
| 12 pub trait Dot<U, F> { |
13 pub trait Dot<U> : HasScalarField { |
| 13 fn dot(&self, other : &U) -> F; |
14 fn dot(&self, other : U) -> Self::Field; |
| 14 } |
15 } |
| 15 |
16 |
| 16 /// Space (type) with Euclidean and vector space structure |
17 /// Space (type) with Euclidean and vector space structure |
| 17 /// |
18 /// |
| 18 /// The type should implement vector space operations (addition, subtraction, scalar |
19 /// The type should implement vector space operations (addition, subtraction, scalar |
| 19 /// multiplication and scalar division) along with their assignment versions, as well |
20 /// multiplication and scalar division) along with their assignment versions, as well |
| 20 /// as the [`Dot`] product with respect to `Self`. |
21 /// as the [`Dot`] product with respect to `Self`. |
| 21 pub trait Euclidean<F : Float> : Sized + Dot<Self,F> |
22 pub trait Euclidean : Sized |
| 22 + Mul<F, Output=<Self as Euclidean<F>>::Output> + MulAssign<F> |
23 + HasRealField |
| 23 + Div<F, Output=<Self as Euclidean<F>>::Output> + DivAssign<F> |
24 + Dot<Self> + for<'a> Dot<&'a Self> |
| 24 + Add<Self, Output=<Self as Euclidean<F>>::Output> |
25 + Mul<Self::Field, Output=<Self as Euclidean>::Output> |
| 25 + Sub<Self, Output=<Self as Euclidean<F>>::Output> |
26 + MulAssign<Self::Field> |
| 26 + for<'b> Add<&'b Self, Output=<Self as Euclidean<F>>::Output> |
27 + Div<Self::Field, Output=<Self as Euclidean>::Output> |
| 27 + for<'b> Sub<&'b Self, Output=<Self as Euclidean<F>>::Output> |
28 + DivAssign<Self::Field> |
| |
29 + Add<Self, Output=<Self as Euclidean>::Output> |
| |
30 + Sub<Self, Output=<Self as Euclidean>::Output> |
| |
31 + for<'b> Add<&'b Self, Output=<Self as Euclidean>::Output> |
| |
32 + for<'b> Sub<&'b Self, Output=<Self as Euclidean>::Output> |
| 28 + AddAssign<Self> + for<'b> AddAssign<&'b Self> |
33 + AddAssign<Self> + for<'b> AddAssign<&'b Self> |
| 29 + SubAssign<Self> + for<'b> SubAssign<&'b Self> |
34 + SubAssign<Self> + for<'b> SubAssign<&'b Self> |
| 30 + Neg<Output=<Self as Euclidean<F>>::Output> { |
35 + Neg<Output=<Self as Euclidean>::Output> { |
| 31 type Output : Euclidean<F>; |
36 |
| |
37 type Output : Euclidean<Field = Self::Field>; |
| 32 |
38 |
| 33 /// Returns origin of same dimensions as `self`. |
39 /// Returns origin of same dimensions as `self`. |
| 34 fn similar_origin(&self) -> <Self as Euclidean<F>>::Output; |
40 fn similar_origin(&self) -> <Self as Euclidean>::Output; |
| 35 |
41 |
| 36 /// Calculate the square of the 2-norm, $\frac{1}{2}\\|x\\|_2^2$, where `self` is $x$. |
42 /// Calculate the square of the 2-norm, $\frac{1}{2}\\|x\\|_2^2$, where `self` is $x$. |
| 37 #[inline] |
43 #[inline] |
| 38 fn norm2_squared(&self) -> F { |
44 fn norm2_squared(&self) -> Self::Field { |
| 39 self.dot(self) |
45 self.dot(self) |
| 40 } |
46 } |
| 41 |
47 |
| 42 /// Calculate the square of the 2-norm divided by 2, $\frac{1}{2}\\|x\\|_2^2$, |
48 /// Calculate the square of the 2-norm divided by 2, $\frac{1}{2}\\|x\\|_2^2$, |
| 43 /// where `self` is $x$. |
49 /// where `self` is $x$. |
| 44 #[inline] |
50 #[inline] |
| 45 fn norm2_squared_div2(&self) -> F { |
51 fn norm2_squared_div2(&self) -> Self::Field { |
| 46 self.norm2_squared()/F::TWO |
52 self.norm2_squared()/Self::Field::TWO |
| 47 } |
53 } |
| 48 |
54 |
| 49 /// Calculate the 2-norm $‖x‖_2$, where `self` is $x$. |
55 /// Calculate the 2-norm $‖x‖_2$, where `self` is $x$. |
| 50 #[inline] |
56 #[inline] |
| 51 fn norm2(&self) -> F { |
57 fn norm2(&self) -> Self::Field { |
| 52 self.norm2_squared().sqrt() |
58 self.norm2_squared().sqrt() |
| 53 } |
59 } |
| 54 |
60 |
| 55 /// Calculate the 2-distance squared $\\|x-y\\|_2^2$, where `self` is $x$. |
61 /// Calculate the 2-distance squared $\\|x-y\\|_2^2$, where `self` is $x$. |
| 56 fn dist2_squared(&self, y : &Self) -> F; |
62 fn dist2_squared(&self, y : &Self) -> Self::Field; |
| 57 |
63 |
| 58 /// Calculate the 2-distance $\\|x-y\\|_2$, where `self` is $x$. |
64 /// Calculate the 2-distance $\\|x-y\\|_2$, where `self` is $x$. |
| 59 #[inline] |
65 #[inline] |
| 60 fn dist2(&self, y : &Self) -> F { |
66 fn dist2(&self, y : &Self) -> Self::Field { |
| 61 self.dist2_squared(y).sqrt() |
67 self.dist2_squared(y).sqrt() |
| 62 } |
68 } |
| 63 |
69 |
| 64 /// Projection to the 2-ball. |
70 /// Projection to the 2-ball. |
| 65 #[inline] |
71 #[inline] |
| 66 fn proj_ball2(mut self, ρ : F) -> Self { |
72 fn proj_ball2(mut self, ρ : Self::Field) -> Self { |
| 67 self.proj_ball2_mut(ρ); |
73 self.proj_ball2_mut(ρ); |
| 68 self |
74 self |
| 69 } |
75 } |
| 70 |
76 |
| 71 /// In-place projection to the 2-ball. |
77 /// In-place projection to the 2-ball. |
| 72 #[inline] |
78 #[inline] |
| 73 fn proj_ball2_mut(&mut self, ρ : F) { |
79 fn proj_ball2_mut(&mut self, ρ : Self::Field) { |
| 74 let r = self.norm2(); |
80 let r = self.norm2(); |
| 75 if r>ρ { |
81 if r>ρ { |
| 76 *self *= ρ/r |
82 *self *= ρ/r |
| 77 } |
83 } |
| 78 } |
84 } |
| 79 } |
85 } |
| 80 |
86 |
| 81 /// Trait for [`Euclidean`] spaces with dimensions known at compile time. |
87 /// Trait for [`Euclidean`] spaces with dimensions known at compile time. |
| 82 pub trait StaticEuclidean<F : Float> : Euclidean<F> { |
88 pub trait StaticEuclidean : Euclidean { |
| 83 /// Returns the origin |
89 /// Returns the origin |
| 84 fn origin() -> <Self as Euclidean<F>>::Output; |
90 fn origin() -> <Self as Euclidean>::Output; |
| 85 } |
91 } |