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 |