Wed, 07 Dec 2022 07:00:27 +0200
Added tag v0.1.0 for changeset 51bfde513cfa
| 0 | 1 | /*! |
| 2 | Norms, projections, etc. | |
| 3 | */ | |
| 4 | ||
| 5 | 5 | use serde::Serialize; |
| 0 | 6 | use crate::types::*; |
| 5 | 7 | use crate::euclidean::*; |
| 0 | 8 | |
| 9 | // | |
| 10 | // Abstract norms | |
| 11 | // | |
| 12 | ||
|
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
13 | /// An exponent for norms. |
|
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
14 | /// |
|
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
15 | // Just a collection of desirabl attributes for a marker type |
|
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
16 | pub trait NormExponent : Copy + Send + Sync + 'static {} |
|
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
17 | |
|
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
18 | |
| 5 | 19 | /// Exponent type for the 1-[`Norm`]. |
| 0 | 20 | #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] |
| 21 | pub struct L1; | |
|
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
22 | impl NormExponent for L1 {} |
| 0 | 23 | |
| 5 | 24 | /// Exponent type for the 2-[`Norm`]. |
| 0 | 25 | #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] |
| 26 | pub struct L2; | |
|
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
27 | impl NormExponent for L2 {} |
| 0 | 28 | |
| 5 | 29 | /// Exponent type for the ∞-[`Norm`]. |
| 0 | 30 | #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] |
| 31 | pub struct Linfinity; | |
|
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
32 | impl NormExponent for Linfinity {} |
| 0 | 33 | |
| 5 | 34 | /// Exponent type for 2,1-[`Norm`]. |
| 35 | /// (1-norm over a domain Ω, 2-norm of a vector at each point of the domain.) | |
| 0 | 36 | #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] |
| 37 | pub struct L21; | |
|
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
38 | impl NormExponent for L21 {} |
| 0 | 39 | |
| 5 | 40 | /// A Huber/Moreau–Yosida smoothed [`L1`] norm. (Not a norm itself.) |
| 41 | /// | |
| 42 | /// The parameter γ of this type is the smoothing factor. Zero means no smoothing, and higher | |
| 43 | /// values more smoothing. Behaviour with γ < 0 is undefined. | |
| 0 | 44 | #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] |
| 45 | pub struct HuberL1<F : Float>(pub F); | |
|
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
46 | impl<F : Float> NormExponent for HuberL1<F> {} |
| 0 | 47 | |
| 5 | 48 | /// A Huber/Moreau–Yosida smoothed [`L21`] norm. (Not a norm itself.) |
| 49 | /// | |
| 50 | /// The parameter γ of this type is the smoothing factor. Zero means no smoothing, and higher | |
| 51 | /// values more smoothing. Behaviour with γ < 0 is undefined. | |
| 0 | 52 | #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] |
| 53 | pub struct HuberL21<F : Float>(pub F); | |
|
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
54 | impl<F : Float> NormExponent for HuberL21<F> {} |
|
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
55 | |
| 0 | 56 | |
| 5 | 57 | /// A normed space (type) with exponent or other type `Exponent` for the norm. |
| 58 | /// | |
| 59 | /// Use as | |
| 60 | /// ``` | |
| 61 | /// # use alg_tools::norms::{Norm, L1, L2, Linfinity}; | |
| 62 | /// # use alg_tools::loc::Loc; | |
| 63 | /// let x = Loc([1.0, 2.0, 3.0]); | |
| 64 | /// | |
| 65 | /// println!("{}, {} {}", x.norm(L1), x.norm(L2), x.norm(Linfinity)) | |
| 66 | /// ``` | |
|
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
67 | pub trait Norm<F : Num, Exponent : NormExponent> { |
| 5 | 68 | /// Calculate the norm. |
| 0 | 69 | fn norm(&self, _p : Exponent) -> F; |
| 70 | } | |
| 71 | ||
| 5 | 72 | /// Indicates that the `Self`-[`Norm`] is dominated by the `Exponent`-`Norm` on the space |
| 73 | /// `Elem` with the corresponding field `F`. | |
|
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
74 | pub trait Dominated<F : Num, Exponent : NormExponent, Elem> { |
| 0 | 75 | /// Indicates the factor $c$ for the inequality $‖x‖ ≤ C ‖x‖_p$. |
| 76 | fn norm_factor(&self, p : Exponent) -> F; | |
| 77 | /// Given a norm-value $‖x‖_p$, calculates $C‖x‖_p$ such that $‖x‖ ≤ C‖x‖_p$ | |
| 78 | #[inline] | |
| 79 | fn from_norm(&self, p_norm : F, p : Exponent) -> F { | |
| 80 | p_norm * self.norm_factor(p) | |
| 81 | } | |
| 82 | } | |
| 83 | ||
| 5 | 84 | /// Trait for distances with respect to a norm. |
|
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
85 | pub trait Dist<F : Num, Exponent : NormExponent> : Norm<F, Exponent> { |
| 0 | 86 | /// Calculate the distance |
| 87 | fn dist(&self, other : &Self, _p : Exponent) -> F; | |
| 88 | } | |
| 89 | ||
| 5 | 90 | /// Trait for Euclidean projections to the `Exponent`-[`Norm`]-ball. |
| 91 | /// | |
| 92 | /// Use as | |
| 93 | /// ``` | |
| 94 | /// # use alg_tools::norms::{Projection, L2, Linfinity}; | |
| 95 | /// # use alg_tools::loc::Loc; | |
| 96 | /// let x = Loc([1.0, 2.0, 3.0]); | |
| 97 | /// | |
| 98 | /// println!("{:?}, {:?}", x.proj_ball(1.0, L2), x.proj_ball(0.5, Linfinity)); | |
| 99 | /// ``` | |
|
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
100 | pub trait Projection<F : Num, Exponent : NormExponent> : Norm<F, Exponent> + Euclidean<F> |
|
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
101 | where F : Float { |
| 5 | 102 | /// Projection of `self` to the `q`-norm-ball of radius ρ. |
| 0 | 103 | fn proj_ball(mut self, ρ : F, q : Exponent) -> Self { |
| 104 | self.proj_ball_mut(ρ, q); | |
| 105 | self | |
| 106 | } | |
| 107 | ||
| 5 | 108 | /// In-place projection of `self` to the `q`-norm-ball of radius ρ. |
| 0 | 109 | fn proj_ball_mut(&mut self, ρ : F, _q : Exponent); |
| 110 | } | |
| 111 | ||
| 112 | /*impl<F : Float, E : Euclidean<F>> Norm<F, L2> for E { | |
| 113 | #[inline] | |
| 114 | fn norm(&self, _p : L2) -> F { self.norm2() } | |
| 115 | ||
| 116 | fn dist(&self, other : &Self, _p : L2) -> F { self.dist2(other) } | |
| 117 | }*/ | |
| 118 | ||
| 119 | impl<F : Float, E : Euclidean<F> + Norm<F, L2>> Projection<F, L2> for E { | |
| 120 | #[inline] | |
| 121 | fn proj_ball(self, ρ : F, _p : L2) -> Self { self.proj_ball2(ρ) } | |
| 122 | ||
| 123 | #[inline] | |
| 124 | fn proj_ball_mut(&mut self, ρ : F, _p : L2) { self.proj_ball2_mut(ρ) } | |
| 125 | } | |
| 126 | ||
| 127 | impl<F : Float> HuberL1<F> { | |
| 128 | fn apply(self, xnsq : F) -> F { | |
| 129 | let HuberL1(γ) = self; | |
| 130 | let xn = xnsq.sqrt(); | |
| 131 | if γ == F::ZERO { | |
| 132 | xn | |
| 133 | } else { | |
| 134 | if xn > γ { | |
| 5 | 135 | xn-γ / F::TWO |
| 0 | 136 | } else if xn<(-γ) { |
| 5 | 137 | -xn-γ / F::TWO |
| 0 | 138 | } else { |
| 5 | 139 | xnsq / (F::TWO * γ) |
| 0 | 140 | } |
| 141 | } | |
| 142 | } | |
| 143 | } | |
| 144 | ||
| 145 | impl<F : Float, E : Euclidean<F>> Norm<F, HuberL1<F>> for E { | |
| 146 | fn norm(&self, huber : HuberL1<F>) -> F { | |
| 147 | huber.apply(self.norm2_squared()) | |
| 148 | } | |
| 149 | } | |
| 150 | ||
| 151 | impl<F : Float, E : Euclidean<F>> Dist<F, HuberL1<F>> for E { | |
| 152 | fn dist(&self, other : &Self, huber : HuberL1<F>) -> F { | |
| 153 | huber.apply(self.dist2_squared(other)) | |
| 154 | } | |
| 155 | } | |
| 156 |