src/mapping/quadratic.rs

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

mercurial