src/mapping/dataterm.rs

changeset 198
3868555d135c
parent 194
a5ee4bfb0b87
equal deleted inserted replaced
94:1f19c6bbf07b 198:3868555d135c
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::error::DynResult;
11 use crate::instance::{ClosedSpace, Instance, Space};
12 use crate::linops::{BoundedLinear, Linear, Preadjointable};
13 use crate::norms::{Normed, L2};
14 use crate::types::Float;
15 use std::ops::Sub;
16
17 //use serde::{Deserialize, Serialize};
18
19 /// Functions of the form $g(Ax-b)$ for an operator $A$, data $b$, and fidelity $g$.
20 pub struct DataTerm<
21 F: Float,
22 Domain: Space,
23 A: Mapping<Domain>,
24 G: Mapping<A::Codomain, Codomain = F>,
25 > {
26 // The operator A
27 opA: A,
28 // The data b
29 b: <A as Mapping<Domain>>::Codomain,
30 // The outer fidelity
31 g: G,
32 }
33
34 // Derive has troubles with `b`.
35 impl<F, Domain, A, G> Clone for DataTerm<F, Domain, A, G>
36 where
37 F: Float,
38 Domain: Space,
39 A: Mapping<Domain> + Clone,
40 <A as Mapping<Domain>>::Codomain: Clone,
41 G: Mapping<A::Codomain, Codomain = F> + Clone,
42 {
43 fn clone(&self) -> Self {
44 DataTerm { opA: self.opA.clone(), b: self.b.clone(), g: self.g.clone() }
45 }
46 }
47
48 #[allow(non_snake_case)]
49 impl<F: Float, Domain: Space, A: Mapping<Domain>, G: Mapping<A::Codomain, Codomain = F>>
50 DataTerm<F, Domain, A, G>
51 {
52 pub fn new(opA: A, b: A::Codomain, g: G) -> Self {
53 DataTerm { opA, b, g }
54 }
55
56 pub fn operator(&self) -> &'_ A {
57 &self.opA
58 }
59
60 pub fn data(&self) -> &'_ <A as Mapping<Domain>>::Codomain {
61 &self.b
62 }
63
64 pub fn fidelity(&self) -> &'_ G {
65 &self.g
66 }
67
68 /// Returns the residual $Ax-b$.
69 pub fn residual<'a, 'b>(&'b self, x: &'a Domain) -> <A as Mapping<Domain>>::Codomain
70 where
71 &'a Domain: Instance<Domain>,
72 <A as Mapping<Domain>>::Codomain:
73 Sub<&'b <A as Mapping<Domain>>::Codomain, Output = <A as Mapping<Domain>>::Codomain>,
74 {
75 self.opA.apply(x) - &self.b
76 }
77 }
78
79 //+ AdjointProductBoundedBy<RNDM<N, F>, P, FloatType = F>,
80
81 impl<F, X, A, G> Mapping<X> for DataTerm<F, X, A, G>
82 where
83 F: Float,
84 X: Space,
85 A: Mapping<X>,
86 G: Mapping<A::Codomain, Codomain = F>,
87 A::Codomain: ClosedSpace + for<'a> Sub<&'a A::Codomain, Output = A::Codomain>,
88 {
89 type Codomain = F;
90
91 fn apply<I: Instance<X>>(&self, x: I) -> F {
92 // TODO: possibly (if at all more effcient) use GEMV once generalised
93 // to not require preallocation. However, Rust should be pretty efficient
94 // at not doing preallocations or anything here, as the result of self.opA.apply()
95 // can be consumed, so maybe GEMV is no use.
96 self.g.apply(self.opA.apply(x) - &self.b)
97 }
98 }
99
100 impl<F, X, A, G> ConvexMapping<X, F> for DataTerm<F, X, A, G>
101 where
102 F: Float,
103 X: Normed<F>,
104 A: Linear<X>,
105 G: ConvexMapping<A::Codomain, F>,
106 A::Codomain: ClosedSpace + Normed<F> + for<'a> Sub<&'a A::Codomain, Output = A::Codomain>,
107 {
108 }
109
110 impl<F, X, Y, A, G> DifferentiableImpl<X> for DataTerm<F, X, A, G>
111 where
112 F: Float,
113 X: Space,
114 Y: Space + Instance<Y> + for<'a> Sub<&'a Y, Output = Y>,
115 A: Linear<X, Codomain = Y> + Preadjointable<X, G::DerivativeDomain>,
116 G::DerivativeDomain: Instance<G::DerivativeDomain>,
117 A::PreadjointCodomain: ClosedSpace,
118 G: DifferentiableMapping<Y, Codomain = F>,
119 Self: Mapping<X, Codomain = F>,
120 {
121 type Derivative = A::PreadjointCodomain;
122
123 fn differential_impl<I: Instance<X>>(&self, x: I) -> Self::Derivative {
124 // TODO: possibly (if at all more effcient) use GEMV once generalised
125 // to not require preallocation. However, Rust should be pretty efficient
126 // at not doing preallocations or anything here, as the result of self.opA.apply()
127 // can be consumed, so maybe GEMV is no use.
128 //self.opA.preadjoint().apply(self.opA.apply(x) - self.b)
129 self.opA
130 .preadjoint()
131 .apply(self.g.differential(self.opA.apply(x) - &self.b))
132 }
133
134 fn apply_and_differential_impl<I: Instance<X>>(&self, x: I) -> (F, Self::Derivative) {
135 let j = self.opA.apply(x) - &self.b;
136 let (v, d) = self.g.apply_and_differential(j);
137 (v, self.opA.preadjoint().apply(d))
138 }
139 }
140
141 impl<'a, F, X, Y, A, G> LipschitzDifferentiableImpl<X, X::NormExp> for DataTerm<F, X, A, G>
142 where
143 F: Float,
144 X: Normed<F>,
145 Y: Normed<F>,
146 A: BoundedLinear<X, X::NormExp, L2, F, Codomain = Y>,
147 G: Mapping<Y, Codomain = F> + LipschitzDifferentiableImpl<Y, Y::NormExp>,
148 Self: DifferentiableImpl<X>,
149 {
150 type FloatType = F;
151
152 fn diff_lipschitz_factor(&self, seminorm: X::NormExp) -> DynResult<F> {
153 Ok(self.opA.opnorm_bound(seminorm, L2)?.powi(2))
154 }
155 }

mercurial