| 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) |