10 use crate::direct_product::Pair; |
10 use crate::direct_product::Pair; |
11 use crate::instance::Instance; |
11 use crate::instance::Instance; |
12 use crate::norms::{NormExponent, PairNorm, L1, L2, Linfinity, Norm, HasDual}; |
12 use crate::norms::{NormExponent, PairNorm, L1, L2, Linfinity, Norm, HasDual}; |
13 |
13 |
14 /// Trait for linear operators on `X`. |
14 /// Trait for linear operators on `X`. |
15 pub trait Linear<X : Space> : Mapping<X> |
15 pub trait Linear<X : AXPY> : Mapping<X, Codomain = Self::LinCodomain> { |
16 { } |
16 type LinCodomain : AXPY; // = Self::Codomain, but with AXPY enforced without trait bound bloat. |
|
17 } |
17 |
18 |
18 /// Efficient in-place summation. |
19 /// Efficient in-place summation. |
19 #[replace_float_literals(F::cast_from(literal))] |
20 #[replace_float_literals(Self::Field::cast_from(literal))] |
20 pub trait AXPY<F, X = Self> : Space |
21 pub trait AXPY : Space { |
|
22 type Field : Num; |
|
23 |
|
24 /// Computes `y = βy + αx`, where `y` is `Self`. |
|
25 fn axpy<I : Instance<Self>>(&mut self, α : Self::Field, x : I, β : Self::Field); |
|
26 |
|
27 /// Copies `x` to `self`. |
|
28 fn copy_from<I : Instance<Self>>(&mut self, x : I) { |
|
29 self.axpy(1.0, x, 0.0) |
|
30 } |
|
31 |
|
32 /// Computes `y = αx`, where `y` is `Self`. |
|
33 fn scale_from<I : Instance<Self>>(&mut self, α : Self::Field, x : I) { |
|
34 self.axpy(α, x, 0.0) |
|
35 } |
|
36 } |
|
37 |
|
38 macro_rules! impl_axpy { |
|
39 ($($type:ty)*) => { $( |
|
40 impl AXPY for $type { |
|
41 type Field = $type; |
|
42 fn axpy<I : Instance<Self>>(&mut self, α : $type, x : I, β : $type) { |
|
43 *self = *self * α + x.own() * β; |
|
44 } |
|
45 } |
|
46 )* }; |
|
47 } |
|
48 |
|
49 impl_axpy!(i8 i16 i32 i64 i128 isize f32 f64); |
|
50 |
|
51 |
|
52 /// Efficient in-place application for [`Linear`] operators. |
|
53 #[replace_float_literals(X::Field::cast_from(literal))] |
|
54 pub trait GEMV<X : AXPY> : Linear<X> { |
|
55 /// Computes `y = αAx + βy`, where `A` is `Self`. |
|
56 fn gemv<I : Instance<X>>(&self, y : &mut Self::LinCodomain, α : <Self::LinCodomain as AXPY>::Field, x : I, β : <Self::LinCodomain as AXPY>::Field); |
|
57 |
|
58 /// Computes `y = Ax`, where `A` is `Self` |
|
59 fn apply_mut<I : Instance<X>>(&self, y : &mut Self::LinCodomain, x : I){ |
|
60 self.gemv(y, 1.0, x, 0.0) |
|
61 } |
|
62 |
|
63 /// Computes `y += Ax`, where `A` is `Self` |
|
64 fn apply_add<I : Instance<X>>(&self, y : &mut Self::LinCodomain, x : I){ |
|
65 self.gemv(y, 1.0, x, 1.0) |
|
66 } |
|
67 } |
|
68 |
|
69 |
|
70 /// Bounded linear operators |
|
71 pub trait BoundedLinear<X, XExp, CodExp> : Linear<X> |
21 where |
72 where |
22 F : Num, |
73 F : Num, |
23 X : Space, |
74 X : AXP + Norm<F, XExp>, |
24 { |
|
25 /// Computes `y = βy + αx`, where `y` is `Self`. |
|
26 fn axpy<I : Instance<X>>(&mut self, α : F, x : I, β : F); |
|
27 |
|
28 /// Copies `x` to `self`. |
|
29 fn copy_from<I : Instance<X>>(&mut self, x : I) { |
|
30 self.axpy(1.0, x, 0.0) |
|
31 } |
|
32 |
|
33 /// Computes `y = αx`, where `y` is `Self`. |
|
34 fn scale_from<I : Instance<X>>(&mut self, α : F, x : I) { |
|
35 self.axpy(α, x, 0.0) |
|
36 } |
|
37 } |
|
38 |
|
39 /// Efficient in-place application for [`Linear`] operators. |
|
40 #[replace_float_literals(F::cast_from(literal))] |
|
41 pub trait GEMV<F : Num, X : Space, Y = <Self as Mapping<X>>::Codomain> : Linear<X> { |
|
42 /// Computes `y = αAx + βy`, where `A` is `Self`. |
|
43 fn gemv<I : Instance<X>>(&self, y : &mut Y, α : F, x : I, β : F); |
|
44 |
|
45 /// Computes `y = Ax`, where `A` is `Self` |
|
46 fn apply_mut<I : Instance<X>>(&self, y : &mut Y, x : I){ |
|
47 self.gemv(y, 1.0, x, 0.0) |
|
48 } |
|
49 |
|
50 /// Computes `y += Ax`, where `A` is `Self` |
|
51 fn apply_add<I : Instance<X>>(&self, y : &mut Y, x : I){ |
|
52 self.gemv(y, 1.0, x, 1.0) |
|
53 } |
|
54 } |
|
55 |
|
56 |
|
57 /// Bounded linear operators |
|
58 pub trait BoundedLinear<X, XExp, CodExp, F = f64> : Linear<X> |
|
59 where |
|
60 F : Num, |
|
61 X : Space + Norm<F, XExp>, |
|
62 XExp : NormExponent, |
75 XExp : NormExponent, |
63 CodExp : NormExponent |
76 CodExp : NormExponent |
64 { |
77 { |
65 /// A bound on the operator norm $\|A\|$ for the linear operator $A$=`self`. |
78 /// A bound on the operator norm $\|A\|$ for the linear operator $A$=`self`. |
66 /// This is not expected to be the norm, just any bound on it that can be |
79 /// This is not expected to be the norm, just any bound on it that can be |
67 /// reasonably implemented. The [`NormExponent`] `xexp` indicates the norm |
80 /// reasonably implemented. The [`NormExponent`] `xexp` indicates the norm |
68 /// in `X`, and `codexp` in the codomain. |
81 /// in `X`, and `codexp` in the codomain. |
69 fn opnorm_bound(&self, xexp : XExp, codexp : CodExp) -> F; |
82 fn opnorm_bound(&self, xexp : XExp, codexp : CodExp) -> X::Field; // TODO: Should pick real subfield |
70 } |
83 } |
71 |
84 |
72 // Linear operator application into mutable target. The [`AsRef`] bound |
85 // Linear operator application into mutable target. The [`AsRef`] bound |
73 // is used to guarantee compatibility with `Yʹ` and `Self::Codomain`; |
86 // is used to guarantee compatibility with `Yʹ` and `Self::Codomain`; |
74 // the former is assumed to be e.g. a view into the latter. |
87 // the former is assumed to be e.g. a view into the latter. |
103 /// domain of the adjointed operator. `Self::Preadjoint` should be |
116 /// domain of the adjointed operator. `Self::Preadjoint` should be |
104 /// [`Adjointable`]`<'a,Ypre,X>`. |
117 /// [`Adjointable`]`<'a,Ypre,X>`. |
105 /// |
118 /// |
106 /// We do not set further restrictions on the spacds, to allow preadjointing when `X` |
119 /// We do not set further restrictions on the spacds, to allow preadjointing when `X` |
107 /// is on the dual space of `Ypre`, but a subset of it. |
120 /// is on the dual space of `Ypre`, but a subset of it. |
108 pub trait Preadjointable<X : Space, Ypre : Space> : Linear<X> |
121 pub trait Preadjointable<X : AXPY, Ypre : AXPY> : Linear<X> |
109 //where |
122 //where |
110 // Ypre : HasDual<F, DualSpace=Self::Codomain>, |
123 // Ypre : HasDual<F, DualSpace=Self::Codomain>, |
111 { |
124 { |
112 type PreadjointCodomain : Space; |
125 type PreadjointCodomain : AXPY; |
113 type Preadjoint<'a> : Linear<Ypre, Codomain=Self::PreadjointCodomain> where Self : 'a; |
126 type Preadjoint<'a> : Linear<Ypre, Codomain=Self::PreadjointCodomain> where Self : 'a; |
114 |
127 |
115 /// Form the adjoint operator of `self`. |
128 /// Form the adjoint operator of `self`. |
116 fn preadjoint(&self) -> Self::Preadjoint<'_>; |
129 fn preadjoint(&self) -> Self::Preadjoint<'_>; |
117 } |
130 } |
118 |
131 |
119 |
|
120 /// The identity operator |
132 /// The identity operator |
121 #[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)] |
133 #[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)] |
122 pub struct IdOp<X> (PhantomData<X>); |
134 pub struct IdOp<X : AXPY> (PhantomData<X>); |
123 |
135 |
124 impl<X> IdOp<X> { |
136 impl<X : AXPY> IdOp<X> { |
125 pub fn new() -> IdOp<X> { IdOp(PhantomData) } |
137 pub fn new() -> IdOp<X> { IdOp(PhantomData) } |
126 } |
138 } |
127 |
139 |
128 impl<X : Clone + Space> Mapping<X> for IdOp<X> { |
140 impl<X : Clone + AXPY> Mapping<X> for IdOp<X> { |
129 type Codomain = X; |
141 type Codomain = X; |
130 |
142 |
131 fn apply<I : Instance<X>>(&self, x : I) -> X { |
143 fn apply<I : Instance<X>>(&self, x : I) -> X { |
132 x.own() |
144 x.own() |
133 } |
145 } |
134 } |
146 } |
135 |
147 |
136 impl<X : Clone + Space> Linear<X> for IdOp<X> |
148 impl<X : Clone + AXPY> Linear<X> for IdOp<X> { |
137 { } |
149 type LinCodomain = X; |
|
150 } |
138 |
151 |
139 #[replace_float_literals(F::cast_from(literal))] |
152 #[replace_float_literals(F::cast_from(literal))] |
140 impl<F : Num, X, Y> GEMV<F, X, Y> for IdOp<X> |
153 impl<X : Clone + AXPY> GEMV<X> for IdOp<X> { |
141 where |
|
142 Y : AXPY<F, X>, |
|
143 X : Clone + Space |
|
144 { |
|
145 // Computes `y = αAx + βy`, where `A` is `Self`. |
154 // Computes `y = αAx + βy`, where `A` is `Self`. |
146 fn gemv<I : Instance<X>>(&self, y : &mut Y, α : F, x : I, β : F) { |
155 fn gemv<I : Instance<X>>(&self, y : &mut Self::LinCodomain, α : X::Field, x : I, β : X::Field) { |
147 y.axpy(α, x, β) |
156 y.axpy(α, x, β) |
148 } |
157 } |
149 |
158 |
150 fn apply_mut<I : Instance<X>>(&self, y : &mut Y, x : I){ |
159 fn apply_mut<I : Instance<X>>(&self, y : &mut X, x : I){ |
151 y.copy_from(x); |
160 y.copy_from(x); |
152 } |
161 } |
153 } |
162 } |
154 |
163 |
155 impl<F, X, E> BoundedLinear<X, E, E, F> for IdOp<X> |
164 impl<X, E> BoundedLinear<X, E, E> for IdOp<X> |
156 where |
165 where |
157 X : Space + Clone + Norm<F, E>, |
166 X : AXPY + Clone + Norm<F, E>, |
158 F : Num, |
167 F : Num + AXPY, |
159 E : NormExponent |
168 E : NormExponent |
160 { |
169 { |
161 fn opnorm_bound(&self, _xexp : E, _codexp : E) -> F { F::ONE } |
170 fn opnorm_bound(&self, _xexp : E, _codexp : E) -> X::Field { F::ONE } |
162 } |
171 } |
163 |
172 |
164 impl<X : Clone + HasDual<F, DualSpace=X>, F : Float> Adjointable<X, F> for IdOp<X> { |
173 impl<X : Clone + HasDual<F, DualSpace=X>, F : Float> Adjointable<X, F> for IdOp<X> { |
165 type AdjointCodomain = X; |
174 type AdjointCodomain = X; |
166 type Adjoint<'a> = IdOp<X::DualSpace> where X : 'a; |
175 type Adjoint<'a> = IdOp<X::DualSpace> where X : 'a; |
167 |
176 |
168 fn adjoint(&self) -> Self::Adjoint<'_> { IdOp::new() } |
177 fn adjoint(&self) -> Self::Adjoint<'_> { IdOp::new() } |
169 } |
178 } |
170 |
179 |
171 impl<X : Clone + Space> Preadjointable<X, X> for IdOp<X> { |
180 impl<X : Clone + AXPY> Preadjointable<X, X> for IdOp<X> { |
172 type PreadjointCodomain = X; |
181 type PreadjointCodomain = X; |
173 type Preadjoint<'a> = IdOp<X> where X : 'a; |
182 type Preadjoint<'a> = IdOp<X> where X : 'a; |
174 |
183 |
175 fn preadjoint(&self) -> Self::Preadjoint<'_> { IdOp::new() } |
184 fn preadjoint(&self) -> Self::Preadjoint<'_> { IdOp::new() } |
176 } |
185 } |
177 |
186 |
178 |
187 |
179 impl<S, T, E, X> Linear<X> for Composition<S, T, E> |
188 impl<S, T, E, X> Linear<X> for Composition<S, T, E> |
180 where |
189 where |
181 X : Space, |
190 X : AXPY, |
182 T : Linear<X>, |
191 T : Linear<X>, |
183 S : Linear<T::Codomain> |
192 S : Linear<T::LinCodomain> |
184 { } |
193 { |
|
194 type LinCodomain = S::LinCodomain; |
|
195 } |
185 |
196 |
186 impl<F, S, T, E, X, Y> GEMV<F, X, Y> for Composition<S, T, E> |
197 impl<F, S, T, E, X, Y> GEMV<F, X, Y> for Composition<S, T, E> |
187 where |
198 where |
188 F : Num, |
199 F : Num, |
189 X : Space, |
200 X : Space, |
225 /// “Row operator” $(S, T)$; $(S, T)(x, y)=Sx + Ty$. |
236 /// “Row operator” $(S, T)$; $(S, T)(x, y)=Sx + Ty$. |
226 pub struct RowOp<S, T>(pub S, pub T); |
237 pub struct RowOp<S, T>(pub S, pub T); |
227 |
238 |
228 use std::ops::Add; |
239 use std::ops::Add; |
229 |
240 |
230 impl<A, B, S, T> Mapping<Pair<A, B>> for RowOp<S, T> |
241 impl<A, B, S, T, Y> Mapping<Pair<A, B>> for RowOp<S, T> |
231 where |
242 where |
232 A : Space, |
243 A : Space, |
233 B : Space, |
244 B : Space, |
|
245 Y : Space, |
234 S : Mapping<A>, |
246 S : Mapping<A>, |
235 T : Mapping<B>, |
247 T : Mapping<B>, |
236 S::Codomain : Add<T::Codomain>, |
248 S::Codomain : Add<T::Codomain, Output = Y>, |
237 <S::Codomain as Add<T::Codomain>>::Output : Space, |
249 { |
238 |
250 type Codomain = Y; |
239 { |
|
240 type Codomain = <S::Codomain as Add<T::Codomain>>::Output; |
|
241 |
251 |
242 fn apply<I : Instance<Pair<A, B>>>(&self, x : I) -> Self::Codomain { |
252 fn apply<I : Instance<Pair<A, B>>>(&self, x : I) -> Self::Codomain { |
243 let Pair(a, b) = x.decompose(); |
253 let Pair(a, b) = x.decompose(); |
244 self.0.apply(a) + self.1.apply(b) |
254 self.0.apply(a) + self.1.apply(b) |
245 } |
255 } |
246 } |
256 } |
247 |
257 |
248 impl<A, B, S, T> Linear<Pair<A, B>> for RowOp<S, T> |
258 impl<F, A, B, S, T, Y> Linear<Pair<A, B>> for RowOp<S, T> |
249 where |
259 where |
250 A : Space, |
260 F : Num + AXPY, |
251 B : Space, |
261 A : AXPY<Field=F>, |
|
262 B : AXPY<Field=F>, |
|
263 Y : AXPY, |
252 S : Linear<A>, |
264 S : Linear<A>, |
253 T : Linear<B>, |
265 T : Linear<B>, |
254 S::Codomain : Add<T::Codomain>, |
266 S::LinCodomain : Add<T::LinCodomain, Output=Y>, |
255 <S::Codomain as Add<T::Codomain>>::Output : Space, |
267 { |
256 { } |
268 type LinCodomain = Y; |
257 |
269 } |
258 |
270 |
259 impl<'b, F, S, T, Y, U, V> GEMV<F, Pair<U, V>, Y> for RowOp<S, T> |
271 |
260 where |
272 impl<'b, F, S, T, Y, G, U, V> GEMV<Pair<U, V>> for RowOp<S, T> |
261 U : Space, |
273 where |
262 V : Space, |
274 U : AXPY<Field=G>, |
263 S : GEMV<F, U, Y>, |
275 V : AXPY<Field=G>, |
264 T : GEMV<F, V, Y>, |
276 Y : AXPY<Field=F>, |
265 F : Num, |
277 S : GEMV<U>, |
266 Self : Linear<Pair<U, V>, Codomain=Y> |
278 T : GEMV<V>, |
|
279 F : Num + AXPY, |
|
280 G : Num + AXPY, |
|
281 S::LinCodomain : Add<T::LinCodomain, Output=Y>, |
267 { |
282 { |
268 fn gemv<I : Instance<Pair<U, V>>>(&self, y : &mut Y, α : F, x : I, β : F) { |
283 fn gemv<I : Instance<Pair<U, V>>>(&self, y : &mut Y, α : F, x : I, β : F) { |
269 let Pair(u, v) = x.decompose(); |
284 let Pair(u, v) = x.decompose(); |
270 self.0.gemv(y, α, u, β); |
285 self.0.gemv(y, α, u, β); |
271 self.1.gemv(y, α, v, F::ONE); |
286 self.1.gemv(y, α, v, F::ONE); |
286 } |
301 } |
287 |
302 |
288 /// “Column operator” $(S; T)$; $(S; T)x=(Sx, Tx)$. |
303 /// “Column operator” $(S; T)$; $(S; T)x=(Sx, Tx)$. |
289 pub struct ColOp<S, T>(pub S, pub T); |
304 pub struct ColOp<S, T>(pub S, pub T); |
290 |
305 |
291 impl<A, S, T> Mapping<A> for ColOp<S, T> |
306 impl<X, S, T> Mapping<X> for ColOp<S, T> |
292 where |
307 where |
293 A : Space, |
308 X : AXPY, |
294 S : Mapping<A>, |
309 S : Mapping<X>, |
295 T : Mapping<A>, |
310 T : Mapping<X>, |
296 { |
311 { |
297 type Codomain = Pair<S::Codomain, T::Codomain>; |
312 type Codomain = Pair<S::Codomain, T::Codomain>; |
298 |
313 |
299 fn apply<I : Instance<A>>(&self, a : I) -> Self::Codomain { |
314 fn apply<I : Instance<X>>(&self, a : I) -> Self::Codomain { |
300 Pair(self.0.apply(a.ref_instance()), self.1.apply(a)) |
315 Pair(self.0.apply(a.ref_instance()), self.1.apply(a)) |
301 } |
316 } |
302 } |
317 } |
303 |
318 |
304 impl<A, S, T> Linear<A> for ColOp<S, T> |
319 impl<X, S, T, A, B, F> Linear<X> for ColOp<S, T> |
305 where |
320 where |
306 A : Space, |
321 F : Num + AXPY, |
307 S : Mapping<A>, |
322 X : AXPY, |
308 T : Mapping<A>, |
323 S : Linear<X, LinCodomain=A>, |
309 { } |
324 T : Linear<X, LinCodomain=B>, |
310 |
325 A : AXPY<Field=F>, |
311 impl<F, S, T, A, B, X> GEMV<F, X, Pair<A, B>> for ColOp<S, T> |
326 B : AXPY<Field=F>, |
312 where |
327 { |
313 X : Space, |
328 type LinCodomain = Pair<S::LinCodomain, T::LinCodomain>; |
314 S : GEMV<F, X, A>, |
329 } |
315 T : GEMV<F, X, B>, |
330 |
316 F : Num, |
331 impl<F, S, T, A, B, X> GEMV<X> for ColOp<S, T> |
317 Self : Linear<X, Codomain=Pair<A, B>> |
332 where |
|
333 F : Num + AXPY, |
|
334 X : AXPY, |
|
335 S : GEMV<X, LinCodomain=A>, |
|
336 T : GEMV<X, LinCodomain=B>, |
|
337 A : AXPY<Field=F>, |
|
338 B : AXPY<Field=F>, |
318 { |
339 { |
319 fn gemv<I : Instance<X>>(&self, y : &mut Pair<A, B>, α : F, x : I, β : F) { |
340 fn gemv<I : Instance<X>>(&self, y : &mut Pair<A, B>, α : F, x : I, β : F) { |
320 self.0.gemv(&mut y.0, α, x.ref_instance(), β); |
341 self.0.gemv(&mut y.0, α, x.ref_instance(), β); |
321 self.1.gemv(&mut y.1, α, x, β); |
342 self.1.gemv(&mut y.1, α, x, β); |
322 } |
343 } |
359 fn adjoint(&self) -> Self::Adjoint<'_> { |
380 fn adjoint(&self) -> Self::Adjoint<'_> { |
360 ColOp(self.0.adjoint(), self.1.adjoint()) |
381 ColOp(self.0.adjoint(), self.1.adjoint()) |
361 } |
382 } |
362 } |
383 } |
363 |
384 |
364 impl<A, B, Yʹ, S, T> Preadjointable<Pair<A,B>, Yʹ> for RowOp<S, T> |
385 impl<F, A, B, Y, Yʹ, S, T> Preadjointable<Pair<A,B>, Yʹ> for RowOp<S, T> |
365 where |
386 wherea |
366 A : Space, |
387 A : AXPY, |
367 B : Space, |
388 B : AXPY, |
368 Yʹ : Space, |
389 Yʹ : AXPY, |
369 S : Preadjointable<A, Yʹ>, |
390 S : Preadjointable<A, Yʹ>, |
370 T : Preadjointable<B, Yʹ>, |
391 T : Preadjointable<B, Yʹ>, |
371 S::Codomain : Add<T::Codomain>, |
392 S::Codomain : Add<T::Codomain>, |
372 <S::Codomain as Add<T::Codomain>>::Output : Space, |
393 <S::Codomain as Add<T::Codomain>>::Output : AXPY, |
373 //Self : Linear<Pair<A, B>, Codomain=Y>, |
394 //Self : Linear<Pair<A, B>, Codomain=Y>, |
374 //for<'a> ColOp<S::Preadjoint<'a>, T::Preadjoint<'a>> : Adjointable<Yʹ, F>, |
395 //for<'a> ColOp<S::Preadjoint<'a>, T::Preadjoint<'a>> : Adjointable<Yʹ, F>, |
375 { |
396 { |
376 type PreadjointCodomain = Pair<S::PreadjointCodomain, T::PreadjointCodomain>; |
397 type PreadjointCodomain = Pair<S::PreadjointCodomain, T::PreadjointCodomain>; |
377 type Preadjoint<'a> = ColOp<S::Preadjoint<'a>, T::Preadjoint<'a>> where Self : 'a; |
398 type Preadjoint<'a> = ColOp<S::Preadjoint<'a>, T::Preadjoint<'a>> where Self : 'a; |
440 let Pair(a, b) = x.decompose(); |
461 let Pair(a, b) = x.decompose(); |
441 Pair(self.0.apply(a), self.1.apply(b)) |
462 Pair(self.0.apply(a), self.1.apply(b)) |
442 } |
463 } |
443 } |
464 } |
444 |
465 |
445 impl<A, B, S, T> Linear<Pair<A, B>> for DiagOp<S, T> |
466 impl<F, A, B, S, T, G, U, V> Linear<Pair<A, B>> for DiagOp<S, T> |
446 where |
467 where |
447 A : Space, |
468 F : Num + AXPY, |
448 B : Space, |
469 G : Num + AXPY, |
449 S : Linear<A>, |
470 A : AXPY<Field=F>, |
450 T : Linear<B>, |
471 B : AXPY<Field=F>, |
451 { } |
472 U : AXPY<Field=G>, |
452 |
473 V : AXPY<Field=G>, |
453 impl<F, S, T, A, B, U, V> GEMV<F, Pair<U, V>, Pair<A, B>> for DiagOp<S, T> |
474 S : Linear<A, LinCodomain=U>, |
454 where |
475 T : Linear<B, LinCodomain=V>, |
455 A : Space, |
476 { |
456 B : Space, |
477 type LinCodomain = Pair<U, V>; |
457 U : Space, |
478 } |
458 V : Space, |
479 |
459 S : GEMV<F, U, A>, |
480 impl<F, A, B, S, T, G, U, V> GEMV<Pair<U, V>> for DiagOp<S, T> |
460 T : GEMV<F, V, B>, |
481 where |
461 F : Num, |
482 F : Num + AXPY, |
462 Self : Linear<Pair<U, V>, Codomain=Pair<A, B>>, |
483 G : Num + AXPY, |
463 { |
484 A : AXPY<Field=F>, |
464 fn gemv<I : Instance<Pair<U, V>>>(&self, y : &mut Pair<A, B>, α : F, x : I, β : F) { |
485 B : AXPY<Field=F>, |
|
486 U : AXPY<Field=G>, |
|
487 V : AXPY<Field=G>, |
|
488 S : GEMV<A, LinCodomain=U>, |
|
489 T : GEMV<B, LinCodomain=V>, |
|
490 { |
|
491 fn gemv<I : Instance<Pair<U, V>>>(&self, y : &mut Pair<A, B>, α : G, x : I, β : G) { |
465 let Pair(u, v) = x.decompose(); |
492 let Pair(u, v) = x.decompose(); |
466 self.0.gemv(&mut y.0, α, u, β); |
493 self.0.gemv(&mut y.0, α, u, β); |
467 self.1.gemv(&mut y.1, α, v, β); |
494 self.1.gemv(&mut y.1, α, v, β); |
468 } |
495 } |
469 |
496 |
521 |
548 |
522 |
549 |
523 macro_rules! pairnorm { |
550 macro_rules! pairnorm { |
524 ($expj:ty) => { |
551 ($expj:ty) => { |
525 impl<F, A, B, S, T, ExpA, ExpB, ExpR> |
552 impl<F, A, B, S, T, ExpA, ExpB, ExpR> |
526 BoundedLinear<Pair<A, B>, PairNorm<ExpA, ExpB, $expj>, ExpR, F> |
553 BoundedLinear<Pair<A, B>, PairNorm<ExpA, ExpB, $expj>, ExpR> |
527 for RowOp<S, T> |
554 for RowOp<S, T> |
528 where |
555 where |
529 F : Float, |
556 F : Float, |
530 A : Space + Norm<F, ExpA>, |
557 A : AXPY + Norm<F, ExpA>, |
531 B : Space + Norm<F, ExpB>, |
558 B : AXPY + Norm<F, ExpB>, |
532 S : BoundedLinear<A, ExpA, ExpR, F>, |
559 S : BoundedLinear<A, ExpA, ExpR, F>, |
533 T : BoundedLinear<B, ExpB, ExpR, F>, |
560 T : BoundedLinear<B, ExpB, ExpR, F>, |
534 S::Codomain : Add<T::Codomain>, |
561 S::Codomain : Add<T::Codomain>, |
535 <S::Codomain as Add<T::Codomain>>::Output : Space, |
562 <S::Codomain as Add<T::Codomain>>::Output : AXPY, |
536 ExpA : NormExponent, |
563 ExpA : NormExponent, |
537 ExpB : NormExponent, |
564 ExpB : NormExponent, |
538 ExpR : NormExponent, |
565 ExpR : NormExponent, |
539 { |
566 { |
540 fn opnorm_bound( |
567 fn opnorm_bound( |
541 &self, |
568 &self, |
542 PairNorm(expa, expb, _) : PairNorm<ExpA, ExpB, $expj>, |
569 PairNorm(expa, expb, _) : PairNorm<ExpA, ExpB, $expj>, |
543 expr : ExpR |
570 expr : ExpR |
544 ) -> F { |
571 ) -> <Pair<A, B> as AXPY>::Field { |
545 // An application of the triangle inequality bounds the norm by the maximum |
572 // An application of the triangle inequality bounds the norm by the maximum |
546 // of the individual norms. A simple observation shows this to be exact. |
573 // of the individual norms. A simple observation shows this to be exact. |
547 let na = self.0.opnorm_bound(expa, expr); |
574 let na = self.0.opnorm_bound(expa, expr); |
548 let nb = self.1.opnorm_bound(expb, expr); |
575 let nb = self.1.opnorm_bound(expb, expr); |
549 na.max(nb) |
576 na.max(nb) |
550 } |
577 } |
551 } |
578 } |
552 |
579 |
553 impl<F, A, S, T, ExpA, ExpS, ExpT> |
580 impl<A, S, T, ExpA, ExpS, ExpT> |
554 BoundedLinear<A, ExpA, PairNorm<ExpS, ExpT, $expj>, F> |
581 BoundedLinear<A, ExpA, PairNorm<ExpS, ExpT, $expj>> |
555 for ColOp<S, T> |
582 for ColOp<S, T> |
556 where |
583 where |
557 F : Float, |
584 F : Float, |
558 A : Space + Norm<F, ExpA>, |
585 A : AXPY + Norm<F, ExpA>, |
559 S : BoundedLinear<A, ExpA, ExpS, F>, |
586 S : BoundedLinear<A, ExpA, ExpS, F>, |
560 T : BoundedLinear<A, ExpA, ExpT, F>, |
587 T : BoundedLinear<A, ExpA, ExpT, F>, |
561 ExpA : NormExponent, |
588 ExpA : NormExponent, |
562 ExpS : NormExponent, |
589 ExpS : NormExponent, |
563 ExpT : NormExponent, |
590 ExpT : NormExponent, |
564 { |
591 { |
565 fn opnorm_bound( |
592 fn opnorm_bound( |
566 &self, |
593 &self, |
567 expa : ExpA, |
594 expa : ExpA, |
568 PairNorm(exps, expt, _) : PairNorm<ExpS, ExpT, $expj> |
595 PairNorm(exps, expt, _) : PairNorm<ExpS, ExpT, $expj> |
569 ) -> F { |
596 ) -> A::Field { |
570 // This is based on the rule for RowOp and ‖A^*‖ = ‖A‖, hence, |
597 // This is based on the rule for RowOp and ‖A^*‖ = ‖A‖, hence, |
571 // for A=[S; T], ‖A‖=‖[S^*, T^*]‖ ≤ max{‖S^*‖, ‖T^*‖} = max{‖S‖, ‖T‖} |
598 // for A=[S; T], ‖A‖=‖[S^*, T^*]‖ ≤ max{‖S^*‖, ‖T^*‖} = max{‖S‖, ‖T‖} |
572 let ns = self.0.opnorm_bound(expa, exps); |
599 let ns = self.0.opnorm_bound(expa, exps); |
573 let nt = self.1.opnorm_bound(expa, expt); |
600 let nt = self.1.opnorm_bound(expa, expt); |
574 ns.max(nt) |
601 ns.max(nt) |