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 } |