src/mapping/dataterm.rs

branch
dev
changeset 105
103aa137fcb2
child 109
943c6b3b9414
equal deleted inserted replaced
104:e7f1cb4bec78 105:103aa137fcb2
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 */

mercurial