src/mapping/quadratic.rs

branch
dev
changeset 99
9e5b9fc81c52
child 102
aead46a19767
equal deleted inserted replaced
98:2e4517b55442 99:9e5b9fc81c52
1 /*!
2 Quadratic functions of the form $\frac{1}{2}\|Ax-b\|_2^2$ for an operator $A$
3 to a [`Euclidean`] space.
4 */
5
6 #![allow(non_snake_case)]
7
8 use super::{DifferentiableImpl, Differential, Lipschitz, Mapping};
9 use crate::convex::ConvexMapping;
10 use crate::euclidean::Euclidean;
11 use crate::instance::{Instance, Space};
12 use crate::linops::{BoundedLinear, Linear, Preadjointable};
13 use crate::norms::{Norm, NormExponent, L2};
14 use crate::types::Float;
15 use std::marker::PhantomData;
16
17 /// Functions of the form $\frac{1}{2}\|Ax-b\|_2^2$ for an operator $A$
18 /// to a [`Euclidean`] space.
19 #[derive(Clone, Copy)]
20 pub struct Quadratic<'a, F: Float, Domain: Space, A: Mapping<Domain>> {
21 opA: &'a A,
22 b: &'a <A as Mapping<Domain>>::Codomain,
23 _phantoms: PhantomData<F>,
24 }
25
26 #[allow(non_snake_case)]
27 impl<'a, F: Float, Domain: Space, A: Mapping<Domain>> Quadratic<'a, F, Domain, A> {
28 pub fn new(opA: &'a A, b: &'a A::Codomain) -> Self {
29 Quadratic {
30 opA,
31 b,
32 _phantoms: PhantomData,
33 }
34 }
35
36 pub fn operator(&self) -> &'a A {
37 self.opA
38 }
39
40 pub fn data(&self) -> &'a <A as Mapping<Domain>>::Codomain {
41 self.b
42 }
43 }
44
45 //+ AdjointProductBoundedBy<RNDM<F, N>, P, FloatType = F>,
46
47 impl<'a, F: Float, X: Space, A: Mapping<X>> Mapping<X> for Quadratic<'a, F, X, A>
48 where
49 A::Codomain: Euclidean<F>,
50 {
51 type Codomain = F;
52
53 fn apply<I: Instance<X>>(&self, x: I) -> F {
54 // TODO: possibly (if at all more effcient) use GEMV once generalised
55 // to not require preallocation. However, Rust should be pretty efficient
56 // at not doing preallocations or anything here, as the result of self.opA.apply()
57 // can be consumed, so maybe GEMV is no use.
58 (self.opA.apply(x) - self.b).norm2_squared() / F::TWO
59 }
60 }
61
62 impl<'a, F: Float, X: Space, A: Linear<X>> ConvexMapping<X, F> for Quadratic<'a, F, X, A> where
63 A::Codomain: Euclidean<F>
64 {
65 }
66
67 impl<'a, F, X, A> DifferentiableImpl<X> for Quadratic<'a, F, X, A>
68 where
69 F: Float,
70 X: Space,
71 <A as Mapping<X>>::Codomain: Euclidean<F>,
72 A: Linear<X> + Preadjointable<X>,
73 <<A as Mapping<X>>::Codomain as Euclidean<F>>::Output: Instance<<A as Mapping<X>>::Codomain>,
74 {
75 type Derivative = A::PreadjointCodomain;
76
77 fn differential_impl<I: Instance<X>>(&self, x: I) -> Self::Derivative {
78 // TODO: possibly (if at all more effcient) use GEMV once generalised
79 // to not require preallocation. However, Rust should be pretty efficient
80 // at not doing preallocations or anything here, as the result of self.opA.apply()
81 // can be consumed, so maybe GEMV is no use.
82 self.opA.preadjoint().apply(self.opA.apply(x) - self.b)
83 }
84 }
85
86 impl<'a, 'b, F, X, ExpX, A> Lipschitz<ExpX> for Differential<'b, X, Quadratic<'a, F, X, A>>
87 where
88 F: Float,
89 X: Space + Clone + Norm<F, ExpX>,
90 ExpX: NormExponent,
91 A: Clone + BoundedLinear<X, ExpX, L2, F>,
92 {
93 type FloatType = F;
94
95 fn lipschitz_factor(&self, seminorm: ExpX) -> Option<F> {
96 Some((*self.g).opA.opnorm_bound(seminorm, L2).powi(2))
97 }
98 }

mercurial