| 2 Abstract linear operators. |
2 Abstract linear operators. |
| 3 */ |
3 */ |
| 4 |
4 |
| 5 use numeric_literals::replace_float_literals; |
5 use numeric_literals::replace_float_literals; |
| 6 use std::marker::PhantomData; |
6 use std::marker::PhantomData; |
| |
7 use serde::Serialize; |
| 7 use crate::types::*; |
8 use crate::types::*; |
| 8 use serde::Serialize; |
9 pub use crate::mapping::{Mapping, Space, Composition}; |
| 9 pub use crate::mapping::Apply; |
10 use crate::direct_product::Pair; |
| |
11 use crate::instance::Instance; |
| |
12 use crate::norms::{NormExponent, PairNorm, L1, L2, Linfinity, Norm}; |
| 10 |
13 |
| 11 /// Trait for linear operators on `X`. |
14 /// Trait for linear operators on `X`. |
| 12 pub trait Linear<X> : Apply<X, Output=Self::Codomain> |
15 pub trait Linear<X : Space> : Mapping<X> |
| 13 + for<'a> Apply<&'a X, Output=Self::Codomain> { |
16 { } |
| 14 type Codomain; |
|
| 15 } |
|
| 16 |
17 |
| 17 /// Efficient in-place summation. |
18 /// Efficient in-place summation. |
| 18 #[replace_float_literals(F::cast_from(literal))] |
19 #[replace_float_literals(F::cast_from(literal))] |
| 19 pub trait AXPY<F : Num, X = Self> { |
20 pub trait AXPY<F, X = Self> : Space + std::ops::MulAssign<F> |
| |
21 where |
| |
22 F : Num, |
| |
23 X : Space, |
| |
24 { |
| |
25 type Owned : AXPY<F, X>; |
| |
26 |
| 20 /// Computes `y = βy + αx`, where `y` is `Self`. |
27 /// Computes `y = βy + αx`, where `y` is `Self`. |
| 21 fn axpy(&mut self, α : F, x : &X, β : F); |
28 fn axpy<I : Instance<X>>(&mut self, α : F, x : I, β : F); |
| 22 |
29 |
| 23 /// Copies `x` to `self`. |
30 /// Copies `x` to `self`. |
| 24 fn copy_from(&mut self, x : &X) { |
31 fn copy_from<I : Instance<X>>(&mut self, x : I) { |
| 25 self.axpy(1.0, x, 0.0) |
32 self.axpy(1.0, x, 0.0) |
| 26 } |
33 } |
| 27 |
34 |
| 28 /// Computes `y = αx`, where `y` is `Self`. |
35 /// Computes `y = αx`, where `y` is `Self`. |
| 29 fn scale_from(&mut self, α : F, x : &X) { |
36 fn scale_from<I : Instance<X>>(&mut self, α : F, x : I) { |
| 30 self.axpy(α, x, 0.0) |
37 self.axpy(α, x, 0.0) |
| 31 } |
38 } |
| |
39 |
| |
40 /// Return a similar zero as `self`. |
| |
41 fn similar_origin(&self) -> Self::Owned; |
| |
42 |
| |
43 /// Set self to zero. |
| |
44 fn set_zero(&mut self); |
| 32 } |
45 } |
| 33 |
46 |
| 34 /// Efficient in-place application for [`Linear`] operators. |
47 /// Efficient in-place application for [`Linear`] operators. |
| 35 #[replace_float_literals(F::cast_from(literal))] |
48 #[replace_float_literals(F::cast_from(literal))] |
| 36 pub trait GEMV<F : Num, X, Y = <Self as Linear<X>>::Codomain> : Linear<X> { |
49 pub trait GEMV<F : Num, X : Space, Y = <Self as Mapping<X>>::Codomain> : Linear<X> { |
| 37 /// Computes `y = αAx + βy`, where `A` is `Self`. |
50 /// Computes `y = αAx + βy`, where `A` is `Self`. |
| 38 fn gemv(&self, y : &mut Y, α : F, x : &X, β : F); |
51 fn gemv<I : Instance<X>>(&self, y : &mut Y, α : F, x : I, β : F); |
| 39 |
52 |
| |
53 #[inline] |
| 40 /// Computes `y = Ax`, where `A` is `Self` |
54 /// Computes `y = Ax`, where `A` is `Self` |
| 41 fn apply_mut(&self, y : &mut Y, x : &X){ |
55 fn apply_mut<I : Instance<X>>(&self, y : &mut Y, x : I){ |
| 42 self.gemv(y, 1.0, x, 0.0) |
56 self.gemv(y, 1.0, x, 0.0) |
| 43 } |
57 } |
| 44 |
58 |
| |
59 #[inline] |
| 45 /// Computes `y += Ax`, where `A` is `Self` |
60 /// Computes `y += Ax`, where `A` is `Self` |
| 46 fn apply_add(&self, y : &mut Y, x : &X){ |
61 fn apply_add<I : Instance<X>>(&self, y : &mut Y, x : I){ |
| 47 self.gemv(y, 1.0, x, 1.0) |
62 self.gemv(y, 1.0, x, 1.0) |
| 48 } |
63 } |
| 49 } |
64 } |
| 50 |
65 |
| 51 |
66 |
| 52 /// Bounded linear operators |
67 /// Bounded linear operators |
| 53 pub trait BoundedLinear<X> : Linear<X> { |
68 pub trait BoundedLinear<X, XExp, CodExp, F = f64> : Linear<X> |
| 54 type FloatType : Float; |
69 where |
| |
70 F : Num, |
| |
71 X : Space + Norm<F, XExp>, |
| |
72 XExp : NormExponent, |
| |
73 CodExp : NormExponent |
| |
74 { |
| 55 /// A bound on the operator norm $\|A\|$ for the linear operator $A$=`self`. |
75 /// A bound on the operator norm $\|A\|$ for the linear operator $A$=`self`. |
| 56 /// This is not expected to be the norm, just any bound on it that can be |
76 /// This is not expected to be the norm, just any bound on it that can be |
| 57 /// reasonably implemented. |
77 /// reasonably implemented. The [`NormExponent`] `xexp` indicates the norm |
| 58 fn opnorm_bound(&self) -> Self::FloatType; |
78 /// in `X`, and `codexp` in the codomain. |
| |
79 fn opnorm_bound(&self, xexp : XExp, codexp : CodExp) -> F; |
| 59 } |
80 } |
| 60 |
81 |
| 61 // Linear operator application into mutable target. The [`AsRef`] bound |
82 // Linear operator application into mutable target. The [`AsRef`] bound |
| 62 // is used to guarantee compatibility with `Yʹ` and `Self::Codomain`; |
83 // is used to guarantee compatibility with `Yʹ` and `Self::Codomain`; |
| 63 // the former is assumed to be e.g. a view into the latter. |
84 // the former is assumed to be e.g. a view into the latter. |
| 67 self.apply(x) |
88 self.apply(x) |
| 68 } |
89 } |
| 69 }*/ |
90 }*/ |
| 70 |
91 |
| 71 /// Trait for forming the adjoint operator of `Self`. |
92 /// Trait for forming the adjoint operator of `Self`. |
| 72 pub trait Adjointable<X,Yʹ> : Linear<X> { |
93 pub trait Adjointable<X, Yʹ> : Linear<X> |
| 73 type AdjointCodomain; |
94 where |
| |
95 X : Space, |
| |
96 Yʹ : Space, |
| |
97 { |
| |
98 type AdjointCodomain : Space; |
| 74 type Adjoint<'a> : Linear<Yʹ, Codomain=Self::AdjointCodomain> where Self : 'a; |
99 type Adjoint<'a> : Linear<Yʹ, Codomain=Self::AdjointCodomain> where Self : 'a; |
| 75 |
100 |
| 76 /// Form the adjoint operator of `self`. |
101 /// Form the adjoint operator of `self`. |
| 77 fn adjoint(&self) -> Self::Adjoint<'_>; |
102 fn adjoint(&self) -> Self::Adjoint<'_>; |
| 78 |
|
| 79 /*fn adjoint_apply(&self, y : &Yʹ) -> Self::AdjointCodomain { |
|
| 80 self.adjoint().apply(y) |
|
| 81 }*/ |
|
| 82 } |
103 } |
| 83 |
104 |
| 84 /// Trait for forming a preadjoint of an operator. |
105 /// Trait for forming a preadjoint of an operator. |
| 85 /// |
106 /// |
| 86 /// For an operator $A$ this is an operator $A\_\*$ |
107 /// For an operator $A$ this is an operator $A\_\*$ |
| 87 /// such that its adjoint $(A\_\*)^\*=A$. The space `X` is the domain of the `Self` |
108 /// such that its adjoint $(A\_\*)^\*=A$. The space `X` is the domain of the `Self` |
| 88 /// operator. The space `Ypre` is the predual of its codomain, and should be the |
109 /// operator. The space `Ypre` is the predual of its codomain, and should be the |
| 89 /// domain of the adjointed operator. `Self::Preadjoint` should be |
110 /// domain of the adjointed operator. `Self::Preadjoint` should be |
| 90 /// [`Adjointable`]`<'a,Ypre,X>`. |
111 /// [`Adjointable`]`<'a,Ypre,X>`. |
| 91 pub trait Preadjointable<X,Ypre> : Linear<X> { |
112 /// We do not make additional restrictions on `Self::Preadjoint` (in particular, it |
| 92 type PreadjointCodomain; |
113 /// does not have to be adjointable) to allow `X` to be a subspace yet the preadjoint |
| 93 type Preadjoint<'a> : Adjointable<Ypre, X, Codomain=Self::PreadjointCodomain> where Self : 'a; |
114 /// have the full space as the codomain, etc. |
| 94 |
115 pub trait Preadjointable<X : Space, Ypre : Space> : Linear<X> { |
| 95 /// Form the preadjoint operator of `self`. |
116 type PreadjointCodomain : Space; |
| |
117 type Preadjoint<'a> : Linear< |
| |
118 Ypre, Codomain=Self::PreadjointCodomain |
| |
119 > where Self : 'a; |
| |
120 |
| |
121 /// Form the adjoint operator of `self`. |
| 96 fn preadjoint(&self) -> Self::Preadjoint<'_>; |
122 fn preadjoint(&self) -> Self::Preadjoint<'_>; |
| 97 } |
123 } |
| 98 |
124 |
| 99 /// Adjointable operators $A: X → Y$ on between reflexive spaces $X$ and $Y$. |
125 /// Adjointable operators $A: X → Y$ between reflexive spaces $X$ and $Y$. |
| 100 pub trait SimplyAdjointable<X> : Adjointable<X,<Self as Linear<X>>::Codomain> {} |
126 pub trait SimplyAdjointable<X : Space> : Adjointable<X,<Self as Mapping<X>>::Codomain> {} |
| 101 impl<'a,X,T> SimplyAdjointable<X> for T where T : Adjointable<X,<Self as Linear<X>>::Codomain> {} |
127 impl<'a,X : Space, T> SimplyAdjointable<X> for T |
| |
128 where T : Adjointable<X,<Self as Mapping<X>>::Codomain> {} |
| 102 |
129 |
| 103 /// The identity operator |
130 /// The identity operator |
| 104 #[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)] |
131 #[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)] |
| 105 pub struct IdOp<X> (PhantomData<X>); |
132 pub struct IdOp<X> (PhantomData<X>); |
| 106 |
133 |
| 107 impl<X> IdOp<X> { |
134 impl<X> IdOp<X> { |
| 108 fn new() -> IdOp<X> { IdOp(PhantomData) } |
135 pub fn new() -> IdOp<X> { IdOp(PhantomData) } |
| 109 } |
136 } |
| 110 |
137 |
| 111 impl<X> Apply<X> for IdOp<X> { |
138 impl<X : Clone + Space> Mapping<X> for IdOp<X> { |
| 112 type Output = X; |
|
| 113 |
|
| 114 fn apply(&self, x : X) -> X { |
|
| 115 x |
|
| 116 } |
|
| 117 } |
|
| 118 |
|
| 119 impl<'a, X> Apply<&'a X> for IdOp<X> where X : Clone { |
|
| 120 type Output = X; |
|
| 121 |
|
| 122 fn apply(&self, x : &'a X) -> X { |
|
| 123 x.clone() |
|
| 124 } |
|
| 125 } |
|
| 126 |
|
| 127 impl<X> Linear<X> for IdOp<X> where X : Clone { |
|
| 128 type Codomain = X; |
139 type Codomain = X; |
| 129 } |
140 |
| 130 |
141 fn apply<I : Instance<X>>(&self, x : I) -> X { |
| |
142 x.own() |
| |
143 } |
| |
144 } |
| |
145 |
| |
146 impl<X : Clone + Space> Linear<X> for IdOp<X> |
| |
147 { } |
| 131 |
148 |
| 132 #[replace_float_literals(F::cast_from(literal))] |
149 #[replace_float_literals(F::cast_from(literal))] |
| 133 impl<F : Num, X, Y> GEMV<F, X, Y> for IdOp<X> where Y : AXPY<F, X>, X : Clone { |
150 impl<F : Num, X, Y> GEMV<F, X, Y> for IdOp<X> |
| |
151 where |
| |
152 Y : AXPY<F, X>, |
| |
153 X : Clone + Space |
| |
154 { |
| 134 // Computes `y = αAx + βy`, where `A` is `Self`. |
155 // Computes `y = αAx + βy`, where `A` is `Self`. |
| 135 fn gemv(&self, y : &mut Y, α : F, x : &X, β : F) { |
156 fn gemv<I : Instance<X>>(&self, y : &mut Y, α : F, x : I, β : F) { |
| 136 y.axpy(α, x, β) |
157 y.axpy(α, x, β) |
| 137 } |
158 } |
| 138 |
159 |
| 139 fn apply_mut(&self, y : &mut Y, x : &X){ |
160 fn apply_mut<I : Instance<X>>(&self, y : &mut Y, x : I){ |
| 140 y.copy_from(x); |
161 y.copy_from(x); |
| 141 } |
162 } |
| 142 } |
163 } |
| 143 |
164 |
| 144 impl<X> BoundedLinear<X> for IdOp<X> where X : Clone { |
165 impl<F, X, E> BoundedLinear<X, E, E, F> for IdOp<X> |
| 145 type FloatType = float; |
166 where |
| 146 fn opnorm_bound(&self) -> float { 1.0 } |
167 X : Space + Clone + Norm<F, E>, |
| 147 } |
168 F : Num, |
| 148 |
169 E : NormExponent |
| 149 impl<X> Adjointable<X,X> for IdOp<X> where X : Clone { |
170 { |
| |
171 fn opnorm_bound(&self, _xexp : E, _codexp : E) -> F { F::ONE } |
| |
172 } |
| |
173 |
| |
174 impl<X : Clone + Space> Adjointable<X,X> for IdOp<X> { |
| 150 type AdjointCodomain=X; |
175 type AdjointCodomain=X; |
| 151 type Adjoint<'a> = IdOp<X> where X : 'a; |
176 type Adjoint<'a> = IdOp<X> where X : 'a; |
| |
177 |
| 152 fn adjoint(&self) -> Self::Adjoint<'_> { IdOp::new() } |
178 fn adjoint(&self) -> Self::Adjoint<'_> { IdOp::new() } |
| 153 } |
179 } |
| 154 |
180 |
| |
181 impl<X : Clone + Space> Preadjointable<X,X> for IdOp<X> { |
| |
182 type PreadjointCodomain=X; |
| |
183 type Preadjoint<'a> = IdOp<X> where X : 'a; |
| |
184 |
| |
185 fn preadjoint(&self) -> Self::Preadjoint<'_> { IdOp::new() } |
| |
186 } |
| |
187 |
| |
188 |
| |
189 /// The zero operator |
| |
190 #[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)] |
| |
191 pub struct ZeroOp<'a, X, XD, Y, F> { |
| |
192 zero : &'a Y, // TODO: don't pass this in `new`; maybe not even store. |
| |
193 dual_or_predual_zero : XD, |
| |
194 _phantoms : PhantomData<(X, Y, F)>, |
| |
195 } |
| |
196 |
| |
197 // TODO: Need to make Zero in Instance. |
| |
198 |
| |
199 impl<'a, F : Num, X : Space, XD, Y : Space + Clone> ZeroOp<'a, X, XD, Y, F> { |
| |
200 pub fn new(zero : &'a Y, dual_or_predual_zero : XD) -> Self { |
| |
201 ZeroOp{ zero, dual_or_predual_zero, _phantoms : PhantomData } |
| |
202 } |
| |
203 } |
| |
204 |
| |
205 impl<'a, F : Num, X : Space, XD, Y : AXPY<F> + Clone> Mapping<X> for ZeroOp<'a, X, XD, Y, F> { |
| |
206 type Codomain = Y; |
| |
207 |
| |
208 fn apply<I : Instance<X>>(&self, _x : I) -> Y { |
| |
209 self.zero.clone() |
| |
210 } |
| |
211 } |
| |
212 |
| |
213 impl<'a, F : Num, X : Space, XD, Y : AXPY<F> + Clone> Linear<X> for ZeroOp<'a, X, XD, Y, F> |
| |
214 { } |
| |
215 |
| |
216 #[replace_float_literals(F::cast_from(literal))] |
| |
217 impl<'a, F, X, XD, Y> GEMV<F, X, Y> for ZeroOp<'a, X, XD, Y, F> |
| |
218 where |
| |
219 F : Num, |
| |
220 Y : AXPY<F, Y> + Clone, |
| |
221 X : Space |
| |
222 { |
| |
223 // Computes `y = αAx + βy`, where `A` is `Self`. |
| |
224 fn gemv<I : Instance<X>>(&self, y : &mut Y, _α : F, _x : I, β : F) { |
| |
225 *y *= β; |
| |
226 } |
| |
227 |
| |
228 fn apply_mut<I : Instance<X>>(&self, y : &mut Y, _x : I){ |
| |
229 y.set_zero(); |
| |
230 } |
| |
231 } |
| |
232 |
| |
233 impl<'a, F, X, XD, Y, E1, E2> BoundedLinear<X, E1, E2, F> for ZeroOp<'a, X, XD, Y, F> |
| |
234 where |
| |
235 X : Space + Norm<F, E1>, |
| |
236 Y : AXPY<F> + Clone + Norm<F, E2>, |
| |
237 F : Num, |
| |
238 E1 : NormExponent, |
| |
239 E2 : NormExponent, |
| |
240 { |
| |
241 fn opnorm_bound(&self, _xexp : E1, _codexp : E2) -> F { F::ZERO } |
| |
242 } |
| |
243 |
| |
244 impl<'a, F : Num, X, XD, Y, Yprime : Space> Adjointable<X, Yprime> for ZeroOp<'a, X, XD, Y, F> |
| |
245 where |
| |
246 X : Space, |
| |
247 Y : AXPY<F> + Clone + 'static, |
| |
248 XD : AXPY<F> + Clone + 'static, |
| |
249 { |
| |
250 type AdjointCodomain = XD; |
| |
251 type Adjoint<'b> = ZeroOp<'b, Yprime, (), XD, F> where Self : 'b; |
| |
252 // () means not (pre)adjointable. |
| |
253 |
| |
254 fn adjoint(&self) -> Self::Adjoint<'_> { |
| |
255 ZeroOp::new(&self.dual_or_predual_zero, ()) |
| |
256 } |
| |
257 } |
| |
258 |
| |
259 impl<'a, F, X, XD, Y, Ypre> Preadjointable<X, Ypre> for ZeroOp<'a, X, XD, Y, F> |
| |
260 where |
| |
261 F : Num, |
| |
262 X : Space, |
| |
263 Y : AXPY<F> + Clone, |
| |
264 Ypre : Space, |
| |
265 XD : AXPY<F> + Clone + 'static, |
| |
266 { |
| |
267 type PreadjointCodomain = XD; |
| |
268 type Preadjoint<'b> = ZeroOp<'b, Ypre, (), XD, F> where Self : 'b; |
| |
269 // () means not (pre)adjointable. |
| |
270 |
| |
271 fn preadjoint(&self) -> Self::Preadjoint<'_> { |
| |
272 ZeroOp::new(&self.dual_or_predual_zero, ()) |
| |
273 } |
| |
274 } |
| |
275 |
| |
276 impl<S, T, E, X> Linear<X> for Composition<S, T, E> |
| |
277 where |
| |
278 X : Space, |
| |
279 T : Linear<X>, |
| |
280 S : Linear<T::Codomain> |
| |
281 { } |
| |
282 |
| |
283 impl<F, S, T, E, X, Y> GEMV<F, X, Y> for Composition<S, T, E> |
| |
284 where |
| |
285 F : Num, |
| |
286 X : Space, |
| |
287 T : Linear<X>, |
| |
288 S : GEMV<F, T::Codomain, Y>, |
| |
289 { |
| |
290 fn gemv<I : Instance<X>>(&self, y : &mut Y, α : F, x : I, β : F) { |
| |
291 self.outer.gemv(y, α, self.inner.apply(x), β) |
| |
292 } |
| |
293 |
| |
294 /// Computes `y = Ax`, where `A` is `Self` |
| |
295 fn apply_mut<I : Instance<X>>(&self, y : &mut Y, x : I){ |
| |
296 self.outer.apply_mut(y, self.inner.apply(x)) |
| |
297 } |
| |
298 |
| |
299 /// Computes `y += Ax`, where `A` is `Self` |
| |
300 fn apply_add<I : Instance<X>>(&self, y : &mut Y, x : I){ |
| |
301 self.outer.apply_add(y, self.inner.apply(x)) |
| |
302 } |
| |
303 } |
| |
304 |
| |
305 impl<F, S, T, X, Z, Xexp, Yexp, Zexp> BoundedLinear<X, Xexp, Yexp, F> for Composition<S, T, Zexp> |
| |
306 where |
| |
307 F : Num, |
| |
308 X : Space + Norm<F, Xexp>, |
| |
309 Z : Space + Norm<F, Zexp>, |
| |
310 Xexp : NormExponent, |
| |
311 Yexp : NormExponent, |
| |
312 Zexp : NormExponent, |
| |
313 T : BoundedLinear<X, Xexp, Zexp, F, Codomain=Z>, |
| |
314 S : BoundedLinear<Z, Zexp, Yexp, F>, |
| |
315 { |
| |
316 fn opnorm_bound(&self, xexp : Xexp, yexp : Yexp) -> F { |
| |
317 let zexp = self.intermediate_norm_exponent; |
| |
318 self.outer.opnorm_bound(zexp, yexp) * self.inner.opnorm_bound(xexp, zexp) |
| |
319 } |
| |
320 } |
| |
321 |
| |
322 /// “Row operator” $(S, T)$; $(S, T)(x, y)=Sx + Ty$. |
| |
323 pub struct RowOp<S, T>(pub S, pub T); |
| |
324 |
| |
325 use std::ops::Add; |
| |
326 |
| |
327 impl<A, B, S, T> Mapping<Pair<A, B>> for RowOp<S, T> |
| |
328 where |
| |
329 A : Space, |
| |
330 B : Space, |
| |
331 S : Mapping<A>, |
| |
332 T : Mapping<B>, |
| |
333 S::Codomain : Add<T::Codomain>, |
| |
334 <S::Codomain as Add<T::Codomain>>::Output : Space, |
| |
335 |
| |
336 { |
| |
337 type Codomain = <S::Codomain as Add<T::Codomain>>::Output; |
| |
338 |
| |
339 fn apply<I : Instance<Pair<A, B>>>(&self, x : I) -> Self::Codomain { |
| |
340 let Pair(a, b) = x.decompose(); |
| |
341 self.0.apply(a) + self.1.apply(b) |
| |
342 } |
| |
343 } |
| |
344 |
| |
345 impl<A, B, S, T> Linear<Pair<A, B>> for RowOp<S, T> |
| |
346 where |
| |
347 A : Space, |
| |
348 B : Space, |
| |
349 S : Linear<A>, |
| |
350 T : Linear<B>, |
| |
351 S::Codomain : Add<T::Codomain>, |
| |
352 <S::Codomain as Add<T::Codomain>>::Output : Space, |
| |
353 { } |
| |
354 |
| |
355 |
| |
356 impl<'b, F, S, T, Y, U, V> GEMV<F, Pair<U, V>, Y> for RowOp<S, T> |
| |
357 where |
| |
358 U : Space, |
| |
359 V : Space, |
| |
360 S : GEMV<F, U, Y>, |
| |
361 T : GEMV<F, V, Y>, |
| |
362 F : Num, |
| |
363 Self : Linear<Pair<U, V>, Codomain=Y> |
| |
364 { |
| |
365 fn gemv<I : Instance<Pair<U, V>>>(&self, y : &mut Y, α : F, x : I, β : F) { |
| |
366 let Pair(u, v) = x.decompose(); |
| |
367 self.0.gemv(y, α, u, β); |
| |
368 self.1.gemv(y, α, v, F::ONE); |
| |
369 } |
| |
370 |
| |
371 fn apply_mut<I : Instance<Pair<U, V>>>(&self, y : &mut Y, x : I) { |
| |
372 let Pair(u, v) = x.decompose(); |
| |
373 self.0.apply_mut(y, u); |
| |
374 self.1.apply_add(y, v); |
| |
375 } |
| |
376 |
| |
377 /// Computes `y += Ax`, where `A` is `Self` |
| |
378 fn apply_add<I : Instance<Pair<U, V>>>(&self, y : &mut Y, x : I) { |
| |
379 let Pair(u, v) = x.decompose(); |
| |
380 self.0.apply_add(y, u); |
| |
381 self.1.apply_add(y, v); |
| |
382 } |
| |
383 } |
| |
384 |
| |
385 /// “Column operator” $(S; T)$; $(S; T)x=(Sx, Tx)$. |
| |
386 pub struct ColOp<S, T>(pub S, pub T); |
| |
387 |
| |
388 impl<A, S, T> Mapping<A> for ColOp<S, T> |
| |
389 where |
| |
390 A : Space, |
| |
391 S : Mapping<A>, |
| |
392 T : Mapping<A>, |
| |
393 { |
| |
394 type Codomain = Pair<S::Codomain, T::Codomain>; |
| |
395 |
| |
396 fn apply<I : Instance<A>>(&self, a : I) -> Self::Codomain { |
| |
397 Pair(self.0.apply(a.ref_instance()), self.1.apply(a)) |
| |
398 } |
| |
399 } |
| |
400 |
| |
401 impl<A, S, T> Linear<A> for ColOp<S, T> |
| |
402 where |
| |
403 A : Space, |
| |
404 S : Mapping<A>, |
| |
405 T : Mapping<A>, |
| |
406 { } |
| |
407 |
| |
408 impl<F, S, T, A, B, X> GEMV<F, X, Pair<A, B>> for ColOp<S, T> |
| |
409 where |
| |
410 X : Space, |
| |
411 S : GEMV<F, X, A>, |
| |
412 T : GEMV<F, X, B>, |
| |
413 F : Num, |
| |
414 Self : Linear<X, Codomain=Pair<A, B>> |
| |
415 { |
| |
416 fn gemv<I : Instance<X>>(&self, y : &mut Pair<A, B>, α : F, x : I, β : F) { |
| |
417 self.0.gemv(&mut y.0, α, x.ref_instance(), β); |
| |
418 self.1.gemv(&mut y.1, α, x, β); |
| |
419 } |
| |
420 |
| |
421 fn apply_mut<I : Instance<X>>(&self, y : &mut Pair<A, B>, x : I){ |
| |
422 self.0.apply_mut(&mut y.0, x.ref_instance()); |
| |
423 self.1.apply_mut(&mut y.1, x); |
| |
424 } |
| |
425 |
| |
426 /// Computes `y += Ax`, where `A` is `Self` |
| |
427 fn apply_add<I : Instance<X>>(&self, y : &mut Pair<A, B>, x : I){ |
| |
428 self.0.apply_add(&mut y.0, x.ref_instance()); |
| |
429 self.1.apply_add(&mut y.1, x); |
| |
430 } |
| |
431 } |
| |
432 |
| |
433 |
| |
434 impl<A, B, Yʹ, S, T> Adjointable<Pair<A,B>, Yʹ> for RowOp<S, T> |
| |
435 where |
| |
436 A : Space, |
| |
437 B : Space, |
| |
438 Yʹ : Space, |
| |
439 S : Adjointable<A, Yʹ>, |
| |
440 T : Adjointable<B, Yʹ>, |
| |
441 Self : Linear<Pair<A, B>>, |
| |
442 // for<'a> ColOp<S::Adjoint<'a>, T::Adjoint<'a>> : Linear< |
| |
443 // Yʹ, |
| |
444 // Codomain=Pair<S::AdjointCodomain, T::AdjointCodomain> |
| |
445 // >, |
| |
446 { |
| |
447 type AdjointCodomain = Pair<S::AdjointCodomain, T::AdjointCodomain>; |
| |
448 type Adjoint<'a> = ColOp<S::Adjoint<'a>, T::Adjoint<'a>> where Self : 'a; |
| |
449 |
| |
450 fn adjoint(&self) -> Self::Adjoint<'_> { |
| |
451 ColOp(self.0.adjoint(), self.1.adjoint()) |
| |
452 } |
| |
453 } |
| |
454 |
| |
455 impl<A, B, Yʹ, S, T> Preadjointable<Pair<A,B>, Yʹ> for RowOp<S, T> |
| |
456 where |
| |
457 A : Space, |
| |
458 B : Space, |
| |
459 Yʹ : Space, |
| |
460 S : Preadjointable<A, Yʹ>, |
| |
461 T : Preadjointable<B, Yʹ>, |
| |
462 Self : Linear<Pair<A, B>>, |
| |
463 for<'a> ColOp<S::Preadjoint<'a>, T::Preadjoint<'a>> : Linear< |
| |
464 Yʹ, Codomain=Pair<S::PreadjointCodomain, T::PreadjointCodomain>, |
| |
465 >, |
| |
466 { |
| |
467 type PreadjointCodomain = Pair<S::PreadjointCodomain, T::PreadjointCodomain>; |
| |
468 type Preadjoint<'a> = ColOp<S::Preadjoint<'a>, T::Preadjoint<'a>> where Self : 'a; |
| |
469 |
| |
470 fn preadjoint(&self) -> Self::Preadjoint<'_> { |
| |
471 ColOp(self.0.preadjoint(), self.1.preadjoint()) |
| |
472 } |
| |
473 } |
| |
474 |
| |
475 |
| |
476 impl<A, Xʹ, Yʹ, R, S, T> Adjointable<A,Pair<Xʹ,Yʹ>> for ColOp<S, T> |
| |
477 where |
| |
478 A : Space, |
| |
479 Xʹ : Space, |
| |
480 Yʹ : Space, |
| |
481 R : Space + ClosedAdd, |
| |
482 S : Adjointable<A, Xʹ, AdjointCodomain = R>, |
| |
483 T : Adjointable<A, Yʹ, AdjointCodomain = R>, |
| |
484 Self : Linear<A>, |
| |
485 // for<'a> RowOp<S::Adjoint<'a>, T::Adjoint<'a>> : Linear< |
| |
486 // Pair<Xʹ,Yʹ>, |
| |
487 // Codomain=R, |
| |
488 // >, |
| |
489 { |
| |
490 type AdjointCodomain = R; |
| |
491 type Adjoint<'a> = RowOp<S::Adjoint<'a>, T::Adjoint<'a>> where Self : 'a; |
| |
492 |
| |
493 fn adjoint(&self) -> Self::Adjoint<'_> { |
| |
494 RowOp(self.0.adjoint(), self.1.adjoint()) |
| |
495 } |
| |
496 } |
| |
497 |
| |
498 impl<A, Xʹ, Yʹ, R, S, T> Preadjointable<A,Pair<Xʹ,Yʹ>> for ColOp<S, T> |
| |
499 where |
| |
500 A : Space, |
| |
501 Xʹ : Space, |
| |
502 Yʹ : Space, |
| |
503 R : Space + ClosedAdd, |
| |
504 S : Preadjointable<A, Xʹ, PreadjointCodomain = R>, |
| |
505 T : Preadjointable<A, Yʹ, PreadjointCodomain = R>, |
| |
506 Self : Linear<A>, |
| |
507 for<'a> RowOp<S::Preadjoint<'a>, T::Preadjoint<'a>> : Linear< |
| |
508 Pair<Xʹ,Yʹ>, Codomain = R, |
| |
509 >, |
| |
510 { |
| |
511 type PreadjointCodomain = R; |
| |
512 type Preadjoint<'a> = RowOp<S::Preadjoint<'a>, T::Preadjoint<'a>> where Self : 'a; |
| |
513 |
| |
514 fn preadjoint(&self) -> Self::Preadjoint<'_> { |
| |
515 RowOp(self.0.preadjoint(), self.1.preadjoint()) |
| |
516 } |
| |
517 } |
| |
518 |
| |
519 /// Diagonal operator |
| |
520 pub struct DiagOp<S, T>(pub S, pub T); |
| |
521 |
| |
522 impl<A, B, S, T> Mapping<Pair<A, B>> for DiagOp<S, T> |
| |
523 where |
| |
524 A : Space, |
| |
525 B : Space, |
| |
526 S : Mapping<A>, |
| |
527 T : Mapping<B>, |
| |
528 { |
| |
529 type Codomain = Pair<S::Codomain, T::Codomain>; |
| |
530 |
| |
531 fn apply<I : Instance<Pair<A, B>>>(&self, x : I) -> Self::Codomain { |
| |
532 let Pair(a, b) = x.decompose(); |
| |
533 Pair(self.0.apply(a), self.1.apply(b)) |
| |
534 } |
| |
535 } |
| |
536 |
| |
537 impl<A, B, S, T> Linear<Pair<A, B>> for DiagOp<S, T> |
| |
538 where |
| |
539 A : Space, |
| |
540 B : Space, |
| |
541 S : Linear<A>, |
| |
542 T : Linear<B>, |
| |
543 { } |
| |
544 |
| |
545 impl<F, S, T, A, B, U, V> GEMV<F, Pair<U, V>, Pair<A, B>> for DiagOp<S, T> |
| |
546 where |
| |
547 A : Space, |
| |
548 B : Space, |
| |
549 U : Space, |
| |
550 V : Space, |
| |
551 S : GEMV<F, U, A>, |
| |
552 T : GEMV<F, V, B>, |
| |
553 F : Num, |
| |
554 Self : Linear<Pair<U, V>, Codomain=Pair<A, B>>, |
| |
555 { |
| |
556 fn gemv<I : Instance<Pair<U, V>>>(&self, y : &mut Pair<A, B>, α : F, x : I, β : F) { |
| |
557 let Pair(u, v) = x.decompose(); |
| |
558 self.0.gemv(&mut y.0, α, u, β); |
| |
559 self.1.gemv(&mut y.1, α, v, β); |
| |
560 } |
| |
561 |
| |
562 fn apply_mut<I : Instance<Pair<U, V>>>(&self, y : &mut Pair<A, B>, x : I){ |
| |
563 let Pair(u, v) = x.decompose(); |
| |
564 self.0.apply_mut(&mut y.0, u); |
| |
565 self.1.apply_mut(&mut y.1, v); |
| |
566 } |
| |
567 |
| |
568 /// Computes `y += Ax`, where `A` is `Self` |
| |
569 fn apply_add<I : Instance<Pair<U, V>>>(&self, y : &mut Pair<A, B>, x : I){ |
| |
570 let Pair(u, v) = x.decompose(); |
| |
571 self.0.apply_add(&mut y.0, u); |
| |
572 self.1.apply_add(&mut y.1, v); |
| |
573 } |
| |
574 } |
| |
575 |
| |
576 impl<A, B, Xʹ, Yʹ, R, S, T> Adjointable<Pair<A,B>, Pair<Xʹ,Yʹ>> for DiagOp<S, T> |
| |
577 where |
| |
578 A : Space, |
| |
579 B : Space, |
| |
580 Xʹ: Space, |
| |
581 Yʹ : Space, |
| |
582 R : Space, |
| |
583 S : Adjointable<A, Xʹ>, |
| |
584 T : Adjointable<B, Yʹ>, |
| |
585 Self : Linear<Pair<A, B>>, |
| |
586 for<'a> DiagOp<S::Adjoint<'a>, T::Adjoint<'a>> : Linear< |
| |
587 Pair<Xʹ,Yʹ>, Codomain=R, |
| |
588 >, |
| |
589 { |
| |
590 type AdjointCodomain = R; |
| |
591 type Adjoint<'a> = DiagOp<S::Adjoint<'a>, T::Adjoint<'a>> where Self : 'a; |
| |
592 |
| |
593 fn adjoint(&self) -> Self::Adjoint<'_> { |
| |
594 DiagOp(self.0.adjoint(), self.1.adjoint()) |
| |
595 } |
| |
596 } |
| |
597 |
| |
598 impl<A, B, Xʹ, Yʹ, R, S, T> Preadjointable<Pair<A,B>, Pair<Xʹ,Yʹ>> for DiagOp<S, T> |
| |
599 where |
| |
600 A : Space, |
| |
601 B : Space, |
| |
602 Xʹ: Space, |
| |
603 Yʹ : Space, |
| |
604 R : Space, |
| |
605 S : Preadjointable<A, Xʹ>, |
| |
606 T : Preadjointable<B, Yʹ>, |
| |
607 Self : Linear<Pair<A, B>>, |
| |
608 for<'a> DiagOp<S::Preadjoint<'a>, T::Preadjoint<'a>> : Linear< |
| |
609 Pair<Xʹ,Yʹ>, Codomain=R, |
| |
610 >, |
| |
611 { |
| |
612 type PreadjointCodomain = R; |
| |
613 type Preadjoint<'a> = DiagOp<S::Preadjoint<'a>, T::Preadjoint<'a>> where Self : 'a; |
| |
614 |
| |
615 fn preadjoint(&self) -> Self::Preadjoint<'_> { |
| |
616 DiagOp(self.0.preadjoint(), self.1.preadjoint()) |
| |
617 } |
| |
618 } |
| |
619 |
| |
620 /// Block operator |
| |
621 pub type BlockOp<S11, S12, S21, S22> = ColOp<RowOp<S11, S12>, RowOp<S21, S22>>; |
| |
622 |
| |
623 |
| |
624 macro_rules! pairnorm { |
| |
625 ($expj:ty) => { |
| |
626 impl<F, A, B, S, T, ExpA, ExpB, ExpR> |
| |
627 BoundedLinear<Pair<A, B>, PairNorm<ExpA, ExpB, $expj>, ExpR, F> |
| |
628 for RowOp<S, T> |
| |
629 where |
| |
630 F : Float, |
| |
631 A : Space + Norm<F, ExpA>, |
| |
632 B : Space + Norm<F, ExpB>, |
| |
633 S : BoundedLinear<A, ExpA, ExpR, F>, |
| |
634 T : BoundedLinear<B, ExpB, ExpR, F>, |
| |
635 S::Codomain : Add<T::Codomain>, |
| |
636 <S::Codomain as Add<T::Codomain>>::Output : Space, |
| |
637 ExpA : NormExponent, |
| |
638 ExpB : NormExponent, |
| |
639 ExpR : NormExponent, |
| |
640 { |
| |
641 fn opnorm_bound( |
| |
642 &self, |
| |
643 PairNorm(expa, expb, _) : PairNorm<ExpA, ExpB, $expj>, |
| |
644 expr : ExpR |
| |
645 ) -> F { |
| |
646 // An application of the triangle inequality bounds the norm by the maximum |
| |
647 // of the individual norms. A simple observation shows this to be exact. |
| |
648 let na = self.0.opnorm_bound(expa, expr); |
| |
649 let nb = self.1.opnorm_bound(expb, expr); |
| |
650 na.max(nb) |
| |
651 } |
| |
652 } |
| |
653 |
| |
654 impl<F, A, S, T, ExpA, ExpS, ExpT> |
| |
655 BoundedLinear<A, ExpA, PairNorm<ExpS, ExpT, $expj>, F> |
| |
656 for ColOp<S, T> |
| |
657 where |
| |
658 F : Float, |
| |
659 A : Space + Norm<F, ExpA>, |
| |
660 S : BoundedLinear<A, ExpA, ExpS, F>, |
| |
661 T : BoundedLinear<A, ExpA, ExpT, F>, |
| |
662 ExpA : NormExponent, |
| |
663 ExpS : NormExponent, |
| |
664 ExpT : NormExponent, |
| |
665 { |
| |
666 fn opnorm_bound( |
| |
667 &self, |
| |
668 expa : ExpA, |
| |
669 PairNorm(exps, expt, _) : PairNorm<ExpS, ExpT, $expj> |
| |
670 ) -> F { |
| |
671 // This is based on the rule for RowOp and ‖A^*‖ = ‖A‖, hence, |
| |
672 // for A=[S; T], ‖A‖=‖[S^*, T^*]‖ ≤ max{‖S^*‖, ‖T^*‖} = max{‖S‖, ‖T‖} |
| |
673 let ns = self.0.opnorm_bound(expa, exps); |
| |
674 let nt = self.1.opnorm_bound(expa, expt); |
| |
675 ns.max(nt) |
| |
676 } |
| |
677 } |
| |
678 } |
| |
679 } |
| |
680 |
| |
681 pairnorm!(L1); |
| |
682 pairnorm!(L2); |
| |
683 pairnorm!(Linfinity); |
| |
684 |