src/euclidean.rs

changeset 198
3868555d135c
parent 197
1f301affeae3
equal deleted inserted replaced
94:1f19c6bbf07b 198:3868555d135c
1 /*! 1 /*!
2 Euclidean spaces. 2 Euclidean spaces.
3 */ 3 */
4 4
5 use std::ops::{Mul, MulAssign, Div, DivAssign, Add, Sub, AddAssign, SubAssign, Neg}; 5 use crate::instance::Instance;
6 use crate::linops::{VectorSpace, AXPY};
7 use crate::norms::{HasDual, Norm, Normed, Reflexive, L2};
6 use crate::types::*; 8 use crate::types::*;
7 use crate::instance::Instance;
8 use crate::norms::{HasDual, Reflexive};
9 9
10 pub mod wrap;
11
12 // TODO: Euclidean & EuclideanMut
13 //
10 /// Space (type) with Euclidean and vector space structure 14 /// Space (type) with Euclidean and vector space structure
11 /// 15 ///
12 /// The type should implement vector space operations (addition, subtraction, scalar 16 /// The type should implement vector space operations (addition, subtraction, scalar
13 /// multiplication and scalar division) along with their assignment versions, as well 17 /// multiplication and scalar division) along with their assignment versions, as well
14 /// as an inner product. 18 /// as an inner product.
15 pub trait Euclidean<F : Float> : HasDual<F, DualSpace=Self> + Reflexive<F> 19 // TODO: remove F parameter, use VectorSpace::Field
16 + Mul<F, Output=<Self as Euclidean<F>>::Output> + MulAssign<F> 20 pub trait Euclidean<F: Float = f64>:
17 + Div<F, Output=<Self as Euclidean<F>>::Output> + DivAssign<F> 21 VectorSpace<Field = F, PrincipalV = Self::PrincipalE> + Reflexive<F, DualSpace = Self::PrincipalE>
18 + Add<Self, Output=<Self as Euclidean<F>>::Output>
19 + Sub<Self, Output=<Self as Euclidean<F>>::Output>
20 + for<'b> Add<&'b Self, Output=<Self as Euclidean<F>>::Output>
21 + for<'b> Sub<&'b Self, Output=<Self as Euclidean<F>>::Output>
22 + AddAssign<Self> + for<'b> AddAssign<&'b Self>
23 + SubAssign<Self> + for<'b> SubAssign<&'b Self>
24 + Neg<Output=<Self as Euclidean<F>>::Output>
25 { 22 {
26 type Output : Euclidean<F>; 23 /// Principal form of the space; always equal to [`crate::linops::Space::Principal`] and
24 /// [`VectorSpace::PrincipalV`], but with more traits guaranteed.
25 type PrincipalE: ClosedEuclidean<F>;
27 26
28 // Inner product 27 // Inner product
29 fn dot<I : Instance<Self>>(&self, other : I) -> F; 28 fn dot<I: Instance<Self>>(&self, other: I) -> F;
30 29
31 /// Calculate the square of the 2-norm, $\frac{1}{2}\\|x\\|_2^2$, where `self` is $x$. 30 /// Calculate the square of the 2-norm, $\frac{1}{2}\\|x\\|_2^2$, where `self` is $x$.
32 /// 31 ///
33 /// This is not automatically implemented to avoid imposing 32 /// This is not automatically implemented to avoid imposing
34 /// `for <'a> &'a Self : Instance<Self>` trait bound bloat. 33 /// `for <'a> &'a Self : Instance<Self>` trait bound bloat.
36 35
37 /// Calculate the square of the 2-norm divided by 2, $\frac{1}{2}\\|x\\|_2^2$, 36 /// Calculate the square of the 2-norm divided by 2, $\frac{1}{2}\\|x\\|_2^2$,
38 /// where `self` is $x$. 37 /// where `self` is $x$.
39 #[inline] 38 #[inline]
40 fn norm2_squared_div2(&self) -> F { 39 fn norm2_squared_div2(&self) -> F {
41 self.norm2_squared()/F::TWO 40 self.norm2_squared() / F::TWO
42 } 41 }
43 42
44 /// Calculate the 2-norm $‖x‖_2$, where `self` is $x$. 43 /// Calculate the 2-norm $‖x‖_2$, where `self` is $x$.
45 #[inline] 44 #[inline]
46 fn norm2(&self) -> F { 45 fn norm2(&self) -> F {
47 self.norm2_squared().sqrt() 46 self.norm2_squared().sqrt()
48 } 47 }
49 48
50 /// Calculate the 2-distance squared $\\|x-y\\|_2^2$, where `self` is $x$. 49 /// Calculate the 2-distance squared $\\|x-y\\|_2^2$, where `self` is $x$.
51 fn dist2_squared<I : Instance<Self>>(&self, y : I) -> F; 50 fn dist2_squared<I: Instance<Self>>(&self, y: I) -> F;
52 51
53 /// Calculate the 2-distance $\\|x-y\\|_2$, where `self` is $x$. 52 /// Calculate the 2-distance $\\|x-y\\|_2$, where `self` is $x$.
54 #[inline] 53 #[inline]
55 fn dist2<I : Instance<Self>>(&self, y : I) -> F { 54 fn dist2<I: Instance<Self>>(&self, y: I) -> F {
56 self.dist2_squared(y).sqrt() 55 self.dist2_squared(y).sqrt()
57 } 56 }
58 57
59 /// Projection to the 2-ball. 58 /// Projection to the 2-ball.
60 #[inline] 59 #[inline]
61 fn proj_ball2(mut self, ρ : F) -> Self { 60 fn proj_ball2(self, ρ: F) -> Self::PrincipalV {
62 self.proj_ball2_mut(ρ);
63 self
64 }
65
66 /// In-place projection to the 2-ball.
67 #[inline]
68 fn proj_ball2_mut(&mut self, ρ : F) {
69 let r = self.norm2(); 61 let r = self.norm2();
70 if r>ρ { 62 if r > ρ {
71 *self *= ρ/r 63 self * (ρ / r)
64 } else {
65 self.into_owned()
72 } 66 }
73 } 67 }
74 } 68 }
75 69
70 pub trait ClosedEuclidean<F: Float = f64>:
71 Instance<Self> + Euclidean<F, PrincipalE = Self>
72 {
73 }
74 impl<F: Float, X: Instance<X> + Euclidean<F, PrincipalE = Self>> ClosedEuclidean<F> for X {}
75
76 // TODO: remove F parameter, use AXPY::Field
77 pub trait EuclideanMut<F: Float = f64>: Euclidean<F> + AXPY<Field = F> {
78 /// In-place projection to the 2-ball.
79 #[inline]
80 fn proj_ball2_mut(&mut self, ρ: F) {
81 let r = self.norm2();
82 if r > ρ {
83 *self *= ρ / r
84 }
85 }
86 }
87
88 impl<X, F: Float> EuclideanMut<F> for X where X: Euclidean<F> + AXPY<Field = F> {}
89
76 /// Trait for [`Euclidean`] spaces with dimensions known at compile time. 90 /// Trait for [`Euclidean`] spaces with dimensions known at compile time.
77 pub trait StaticEuclidean<F : Float> : Euclidean<F> { 91 pub trait StaticEuclidean<F: Float = f64>: Euclidean<F> {
78 /// Returns the origin 92 /// Returns the origin
79 fn origin() -> <Self as Euclidean<F>>::Output; 93 fn origin() -> <Self as Euclidean<F>>::PrincipalE;
80 } 94 }
95
96 macro_rules! scalar_euclidean {
97 ($f:ident) => {
98 impl VectorSpace for $f {
99 type Field = $f;
100 type PrincipalV = $f;
101
102 #[inline]
103 fn similar_origin(&self) -> Self::PrincipalV {
104 0.0
105 }
106 }
107 impl AXPY for $f {
108 #[inline]
109 fn axpy<I: Instance<$f>>(&mut self, α: $f, x: I, β: $f) {
110 *self = β * *self + α * x.own()
111 }
112
113 #[inline]
114 fn set_zero(&mut self) {
115 *self = 0.0
116 }
117 }
118
119 impl Norm<L2, $f> for $f {
120 fn norm(&self, _p: L2) -> $f {
121 self.abs()
122 }
123 }
124
125 impl Normed<$f> for $f {
126 type NormExp = L2;
127
128 fn norm_exponent(&self) -> Self::NormExp {
129 L2
130 }
131 }
132
133 impl HasDual<$f> for $f {
134 type DualSpace = $f;
135
136 #[inline]
137 fn dual_origin(&self) -> $f {
138 0.0
139 }
140 }
141
142 impl Euclidean<$f> for $f {
143 type PrincipalE = $f;
144
145 #[inline]
146 fn dot<I: Instance<Self>>(&self, other: I) -> $f {
147 *self * other.own()
148 }
149
150 #[inline]
151 fn norm2_squared(&self) -> $f {
152 *self * *self
153 }
154
155 #[inline]
156 fn dist2_squared<I: Instance<Self>>(&self, y: I) -> $f {
157 let d = *self - y.own();
158 d * d
159 }
160 }
161 };
162 }
163
164 scalar_euclidean!(f64);
165 scalar_euclidean!(f32);

mercurial