| |
1 /*! |
| |
2 General deata terms of the form $g(Ax-b)$ for an operator $A$ |
| |
3 to a [`Euclidean`] space, and a function g on that space. |
| |
4 */ |
| |
5 |
| |
6 #![allow(non_snake_case)] |
| |
7 |
| |
8 use super::{DifferentiableImpl, DifferentiableMapping, /*LipschitzDifferentiableImpl,*/ Mapping,}; |
| |
9 use crate::convex::ConvexMapping; |
| |
10 use crate::instance::{Instance, Space}; |
| |
11 use crate::linops::{/*BoundedLinear,*/ Linear, Preadjointable}; |
| |
12 //use crate::norms::{Norm, NormExponent, L2}; |
| |
13 use crate::types::Float; |
| |
14 use std::ops::Sub; |
| |
15 //use serde::{Deserialize, Serialize}; |
| |
16 |
| |
17 /// Functions of the form $\frac{1}{2}\|Ax-b\|_2^2$ for an operator $A$ |
| |
18 /// to a [`Euclidean`] space. |
| |
19 pub struct DataTerm< |
| |
20 F: Float, |
| |
21 Domain: Space, |
| |
22 A: Mapping<Domain>, |
| |
23 G: Mapping<A::Codomain, Codomain = F>, |
| |
24 > { |
| |
25 opA: A, |
| |
26 b: <A as Mapping<Domain>>::Codomain, |
| |
27 g: G, |
| |
28 } |
| |
29 |
| |
30 #[allow(non_snake_case)] |
| |
31 impl<F: Float, Domain: Space, A: Mapping<Domain>, G: Mapping<A::Codomain, Codomain = F>> |
| |
32 DataTerm<F, Domain, A, G> |
| |
33 { |
| |
34 pub fn new(opA: A, b: A::Codomain, g: G) -> Self { |
| |
35 DataTerm { opA, b, g } |
| |
36 } |
| |
37 |
| |
38 pub fn operator(&self) -> &'_ A { |
| |
39 &self.opA |
| |
40 } |
| |
41 |
| |
42 pub fn data(&self) -> &'_ <A as Mapping<Domain>>::Codomain { |
| |
43 &self.b |
| |
44 } |
| |
45 |
| |
46 pub fn fidelity(&self) -> &'_ G { |
| |
47 &self.g |
| |
48 } |
| |
49 } |
| |
50 |
| |
51 //+ AdjointProductBoundedBy<RNDM<F, N>, P, FloatType = F>, |
| |
52 |
| |
53 impl<F, X, A, G> Mapping<X> for DataTerm<F, X, A, G> |
| |
54 where |
| |
55 F: Float, |
| |
56 X: Space, |
| |
57 A: Mapping<X>, |
| |
58 G: Mapping<A::Codomain, Codomain = F>, |
| |
59 A::Codomain: for<'a> Sub<&'a A::Codomain, Output = A::Codomain>, |
| |
60 { |
| |
61 type Codomain = F; |
| |
62 |
| |
63 fn apply<I: Instance<X>>(&self, x: I) -> F { |
| |
64 // TODO: possibly (if at all more effcient) use GEMV once generalised |
| |
65 // to not require preallocation. However, Rust should be pretty efficient |
| |
66 // at not doing preallocations or anything here, as the result of self.opA.apply() |
| |
67 // can be consumed, so maybe GEMV is no use. |
| |
68 self.g.apply(self.opA.apply(x) - &self.b) |
| |
69 } |
| |
70 } |
| |
71 |
| |
72 impl<F, X, A, G> ConvexMapping<X, F> for DataTerm<F, X, A, G> |
| |
73 where |
| |
74 F: Float, |
| |
75 X: Space, |
| |
76 A: Linear<X>, |
| |
77 G: ConvexMapping<A::Codomain, F>, |
| |
78 A::Codomain: for<'a> Sub<&'a A::Codomain, Output = A::Codomain>, |
| |
79 { |
| |
80 } |
| |
81 |
| |
82 impl<F, X, Y, A, G> DifferentiableImpl<X> for DataTerm<F, X, A, G> |
| |
83 where |
| |
84 F: Float, |
| |
85 X: Space, |
| |
86 Y: Space + for<'a> Sub<&'a Y, Output = Y>, |
| |
87 //<A as Mapping<X>>::Codomain: Euclidean<F>, |
| |
88 A: Linear<X, Codomain = Y> + Preadjointable<X, G::DerivativeDomain>, |
| |
89 //<<A as Mapping<X>>::Codomain as Euclidean<F>>::Output: Instance<<A as Mapping<X>>::Codomain>, |
| |
90 G: DifferentiableMapping<Y, Codomain = F>, |
| |
91 { |
| |
92 type Derivative = A::PreadjointCodomain; |
| |
93 |
| |
94 fn differential_impl<I: Instance<X>>(&self, x: I) -> Self::Derivative { |
| |
95 // TODO: possibly (if at all more effcient) use GEMV once generalised |
| |
96 // to not require preallocation. However, Rust should be pretty efficient |
| |
97 // at not doing preallocations or anything here, as the result of self.opA.apply() |
| |
98 // can be consumed, so maybe GEMV is no use. |
| |
99 //self.opA.preadjoint().apply(self.opA.apply(x) - self.b) |
| |
100 self.opA |
| |
101 .preadjoint() |
| |
102 .apply(self.g.diff_ref().apply(self.opA.apply(x) - &self.b)) |
| |
103 } |
| |
104 } |
| |
105 |
| |
106 /* |
| |
107 impl<'a, F, X, ExpX, Y, ExpY, A, G> LipschitzDifferentiableImpl<X, ExpX> for DataTerm<F, X, A, G> |
| |
108 where |
| |
109 F: Float, |
| |
110 X: Space + Clone + Norm<F, ExpX>, |
| |
111 Y: Space + Norm<F, ExpY>, |
| |
112 ExpX: NormExponent, |
| |
113 ExpY: NormExponent, |
| |
114 A: Clone + BoundedLinear<X, ExpX, L2, F, Codomain = Y>, |
| |
115 G: Mapping<Y, Codomain = F> + LipschitzDifferentiableImpl<Y, ExpY>, |
| |
116 Self: DifferentiableImpl<X>, |
| |
117 { |
| |
118 type FloatType = F; |
| |
119 |
| |
120 fn diff_lipschitz_factor(&self, seminorm: ExpX) -> Option<F> { |
| |
121 Some(self.opA.opnorm_bound(seminorm, L2).powi(2)) |
| |
122 } |
| |
123 } |
| |
124 */ |