src/linops.rs

branch
dev
changeset 129
d2994e34a5f5
parent 124
6aa955ad8122
child 130
0a689881b0f1
equal deleted inserted replaced
128:f75bf34adda0 129:d2994e34a5f5
4 4
5 use crate::direct_product::Pair; 5 use crate::direct_product::Pair;
6 use crate::error::DynResult; 6 use crate::error::DynResult;
7 use crate::instance::Instance; 7 use crate::instance::Instance;
8 pub use crate::mapping::{Composition, DifferentiableImpl, Mapping, Space}; 8 pub use crate::mapping::{Composition, DifferentiableImpl, Mapping, Space};
9 use crate::norms::{Linfinity, Norm, NormExponent, PairNorm, L1, L2}; 9 use crate::norms::{HasDual, Linfinity, Norm, NormExponent, PairNorm, L1, L2};
10 use crate::types::*; 10 use crate::types::*;
11 use numeric_literals::replace_float_literals; 11 use numeric_literals::replace_float_literals;
12 use serde::Serialize; 12 use serde::Serialize;
13 use std::marker::PhantomData; 13 use std::marker::PhantomData;
14 use std::ops::Mul; 14 use std::ops::Mul;
24 // self.apply(x) 24 // self.apply(x)
25 // } 25 // }
26 // } 26 // }
27 27
28 /// Efficient in-place summation. 28 /// Efficient in-place summation.
29 #[replace_float_literals(F::cast_from(literal))] 29 #[replace_float_literals(Self::Field::cast_from(literal))]
30 pub trait AXPY<F, X = Self>: Space + std::ops::MulAssign<F> 30 pub trait AXPY<X = Self>: Space + std::ops::MulAssign<Self::Field>
31 where 31 where
32 F: Num,
33 X: Space, 32 X: Space,
34 { 33 {
35 type Owned: AXPY<F, X>; 34 type Field: Num;
35 type Owned: AXPY<X, Field = Self::Field>;
36 // type OriginGen<'a>: OriginGenerator<Self::Owned, F>
37 // where
38 // Self: 'a;
36 39
37 /// Computes `y = βy + αx`, where `y` is `Self`. 40 /// Computes `y = βy + αx`, where `y` is `Self`.
38 fn axpy<I: Instance<X>>(&mut self, α: F, x: I, β: F); 41 fn axpy<I: Instance<X>>(&mut self, α: Self::Field, x: I, β: Self::Field);
39 42
40 /// Copies `x` to `self`. 43 /// Copies `x` to `self`.
41 fn copy_from<I: Instance<X>>(&mut self, x: I) { 44 fn copy_from<I: Instance<X>>(&mut self, x: I) {
42 self.axpy(1.0, x, 0.0) 45 self.axpy(1.0, x, 0.0)
43 } 46 }
44 47
45 /// Computes `y = αx`, where `y` is `Self`. 48 /// Computes `y = αx`, where `y` is `Self`.
46 fn scale_from<I: Instance<X>>(&mut self, α: F, x: I) { 49 fn scale_from<I: Instance<X>>(&mut self, α: Self::Field, x: I) {
47 self.axpy(α, x, 0.0) 50 self.axpy(α, x, 0.0)
48 } 51 }
49 52
50 /// Return a similar zero as `self`. 53 /// Return a similar zero as `self`.
51 fn similar_origin(&self) -> Self::Owned; 54 fn similar_origin(&self) -> Self::Owned;
55 // {
56 // self.make_origin_generator().make_origin()
57 // }
58
59 /// Return a similar zero as `x`.
60 fn similar_origin_inst<I: Instance<Self>>(x: I) -> Self::Owned {
61 x.eval(|xr| xr.similar_origin())
62 }
52 63
53 /// Set self to zero. 64 /// Set self to zero.
54 fn set_zero(&mut self); 65 fn set_zero(&mut self);
66
67 //fn make_origin_generator(&self) -> Self::OriginGen<'_>;
55 } 68 }
56 69
57 /// Efficient in-place application for [`Linear`] operators. 70 /// Efficient in-place application for [`Linear`] operators.
58 #[replace_float_literals(F::cast_from(literal))] 71 #[replace_float_literals(F::cast_from(literal))]
59 pub trait GEMV<F: Num, X: Space, Y = <Self as Mapping<X>>::Codomain>: Linear<X> { 72 pub trait GEMV<F: Num, X: Space, Y = <Self as Mapping<X>>::Codomain>: Linear<X> {
165 impl<X: Clone + Space> Linear<X> for IdOp<X> {} 178 impl<X: Clone + Space> Linear<X> for IdOp<X> {}
166 179
167 #[replace_float_literals(F::cast_from(literal))] 180 #[replace_float_literals(F::cast_from(literal))]
168 impl<F: Num, X, Y> GEMV<F, X, Y> for IdOp<X> 181 impl<F: Num, X, Y> GEMV<F, X, Y> for IdOp<X>
169 where 182 where
170 Y: AXPY<F, X>, 183 Y: AXPY<X, Field = F>,
171 X: Clone + Space, 184 X: Clone + Space,
172 { 185 {
173 // Computes `y = αAx + βy`, where `A` is `Self`. 186 // Computes `y = αAx + βy`, where `A` is `Self`.
174 fn gemv<I: Instance<X>>(&self, y: &mut Y, α: F, x: I, β: F) { 187 fn gemv<I: Instance<X>>(&self, y: &mut Y, α: F, x: I, β: F) {
175 y.axpy(α, x, β) 188 y.axpy(α, x, β)
213 fn preadjoint(&self) -> Self::Preadjoint<'_> { 226 fn preadjoint(&self) -> Self::Preadjoint<'_> {
214 IdOp::new() 227 IdOp::new()
215 } 228 }
216 } 229 }
217 230
218 /// The zero operator 231 /// The zero operator from a space to itself
219 #[derive(Clone, Copy, Debug, Serialize, Eq, PartialEq)] 232 #[derive(Clone, Copy, Debug, Serialize, Eq, PartialEq)]
220 pub struct ZeroOp<'a, X, XD, Y, F> { 233 pub struct SimpleZeroOp;
221 zero: &'a Y, // TODO: don't pass this in `new`; maybe not even store. 234
222 dual_or_predual_zero: XD, 235 impl<X> Mapping<X> for SimpleZeroOp
223 _phantoms: PhantomData<(X, Y, F)>, 236 where
224 } 237 X: AXPY + Instance<X>,
225 238 {
226 // TODO: Need to make Zero in Instance. 239 type Codomain = X::Owned;
227 240
228 impl<'a, F: Num, X: Space, XD, Y: Space + Clone> ZeroOp<'a, X, XD, Y, F> { 241 fn apply<I: Instance<X>>(&self, x: I) -> X::Owned {
229 pub fn new(zero: &'a Y, dual_or_predual_zero: XD) -> Self { 242 X::similar_origin_inst(x)
230 ZeroOp { 243 }
231 zero, 244 }
232 dual_or_predual_zero, 245
233 _phantoms: PhantomData, 246 impl<X> Linear<X> for SimpleZeroOp where X: AXPY + Instance<X> {}
234 }
235 }
236 }
237
238 impl<'a, F: Num, X: Space, XD, Y: AXPY<F> + Clone> Mapping<X> for ZeroOp<'a, X, XD, Y, F> {
239 type Codomain = Y;
240
241 fn apply<I: Instance<X>>(&self, _x: I) -> Y {
242 self.zero.clone()
243 }
244 }
245
246 impl<'a, F: Num, X: Space, XD, Y: AXPY<F> + Clone> Linear<X> for ZeroOp<'a, X, XD, Y, F> {}
247 247
248 #[replace_float_literals(F::cast_from(literal))] 248 #[replace_float_literals(F::cast_from(literal))]
249 impl<'a, F, X, XD, Y> GEMV<F, X, Y> for ZeroOp<'a, X, XD, Y, F> 249 impl<X, Y, F> GEMV<F, X, Y> for SimpleZeroOp
250 where 250 where
251 F: Num, 251 F: Num,
252 Y: AXPY<F, Y> + Clone, 252 Y: AXPY<Field = F>,
253 X: Space, 253 X: AXPY<Field = F> + Instance<X>,
254 { 254 {
255 // Computes `y = αAx + βy`, where `A` is `Self`. 255 // Computes `y = αAx + βy`, where `A` is `Self`.
256 fn gemv<I: Instance<X>>(&self, y: &mut Y, _α: F, _x: I, β: F) { 256 fn gemv<I: Instance<X>>(&self, y: &mut Y, _α: F, _x: I, β: F) {
257 *y *= β; 257 *y *= β;
258 } 258 }
260 fn apply_mut<I: Instance<X>>(&self, y: &mut Y, _x: I) { 260 fn apply_mut<I: Instance<X>>(&self, y: &mut Y, _x: I) {
261 y.set_zero(); 261 y.set_zero();
262 } 262 }
263 } 263 }
264 264
265 impl<'a, F, X, XD, Y, E1, E2> BoundedLinear<X, E1, E2, F> for ZeroOp<'a, X, XD, Y, F> 265 impl<X, F, E1, E2> BoundedLinear<X, E1, E2, F> for SimpleZeroOp
266 where 266 where
267 X: Space + Norm<E1, F>, 267 F: Num,
268 Y: AXPY<F> + Clone + Norm<E2, F>, 268 X: AXPY<Field = F> + Instance<X> + Norm<E1, F>,
269 F: Num,
270 E1: NormExponent, 269 E1: NormExponent,
271 E2: NormExponent, 270 E2: NormExponent,
272 { 271 {
273 fn opnorm_bound(&self, _xexp: E1, _codexp: E2) -> DynResult<F> { 272 fn opnorm_bound(&self, _xexp: E1, _codexp: E2) -> DynResult<F> {
274 Ok(F::ZERO) 273 Ok(F::ZERO)
275 } 274 }
276 } 275 }
277 276
278 impl<'a, F: Num, X, XD, Y, Yprime: Space> Adjointable<X, Yprime> for ZeroOp<'a, X, XD, Y, F> 277 impl<X, F> Adjointable<X, X::DualSpace> for SimpleZeroOp
279 where 278 where
280 X: Space, 279 F: Num,
281 Y: AXPY<F> + Clone + 'static, 280 X: AXPY<Field = F> + Instance<X> + HasDual<F>,
282 XD: AXPY<F> + Clone + 'static, 281 X::DualSpace: AXPY<Owned = X::DualSpace>,
283 { 282 {
284 type AdjointCodomain = XD; 283 type AdjointCodomain = X::DualSpace;
285 type Adjoint<'b> 284 type Adjoint<'b>
286 = ZeroOp<'b, Yprime, (), XD, F> 285 = SimpleZeroOp
287 where 286 where
288 Self: 'b; 287 Self: 'b;
289 // () means not (pre)adjointable. 288 // () means not (pre)adjointable.
290 289
291 fn adjoint(&self) -> Self::Adjoint<'_> { 290 fn adjoint(&self) -> Self::Adjoint<'_> {
292 ZeroOp::new(&self.dual_or_predual_zero, ()) 291 SimpleZeroOp
293 } 292 }
294 } 293 }
295 294
296 impl<'a, F, X, XD, Y, Ypre> Preadjointable<X, Ypre> for ZeroOp<'a, X, XD, Y, F> 295 /*
297 where 296 /// Trait for forming origins (zeroes) in vector spaces
298 F: Num, 297 pub trait OriginGenerator<X, F: Num = f64> {
299 X: Space, 298 fn make_origin(&self) -> X;
300 Y: AXPY<F> + Clone, 299 }
301 Ypre: Space, 300
302 XD: AXPY<F> + Clone + 'static, 301 /// Origin generator for statically sized Euclidean spaces.
303 { 302 pub struct StaticEuclideanOriginGenerator;
304 type PreadjointCodomain = XD; 303
305 type Preadjoint<'b> 304 impl<X, F: Float> OriginGenerator<X, F> for StaticEuclideanOriginGenerator
306 = ZeroOp<'b, Ypre, (), XD, F> 305 where
306 X: StaticEuclidean<F> + Euclidean<F, Output = X>,
307 {
308 #[inline]
309 fn make_origin(&self) -> X {
310 X::origin()
311 }
312 }
313
314 /// Origin generator arbitrary spaces that implement [`AXPY`], based on a sample vector.
315 pub struct SimilarOriginGenerator<'a, X>(&'a X);
316
317 impl<'a, X, F: Float> OriginGenerator<X, F> for SimilarOriginGenerator<'a, X>
318 where
319 X: AXPY<F, Owned = X>,
320 {
321 #[inline]
322 fn make_origin(&self) -> X {
323 self.0.similar_origin()
324 }
325 }
326
327 pub struct NotAnOriginGenerator;
328
329 /// The zero operator
330 #[derive(Clone, Copy, Debug, Serialize, Eq, PartialEq)]
331 pub struct ZeroOp<X, Y, YOrigin, XDOrigin = NotAnOriginGenerator, F: Num = f64> {
332 y_origin: YOrigin,
333 xd_origin: XDOrigin,
334 _phantoms: PhantomData<(X, Y, F)>,
335 }
336
337 // TODO: Need to make Zero in Instance.
338
339 impl<X, Y, F, YOrigin, XDOrigin> ZeroOp<X, Y, YOrigin, XDOrigin, F>
340 where
341 F: Num,
342 YOrigin: OriginGenerator<Y, F>,
343 {
344 pub fn new(y_origin: YOrigin, xd_origin: XDOrigin) -> Self {
345 ZeroOp {
346 y_origin,
347 xd_origin,
348 _phantoms: PhantomData,
349 }
350 }
351 }
352
353 impl<X, Y, F, YOrigin, XDOrigin> Mapping<X> for ZeroOp<X, Y, YOrigin, XDOrigin, F>
354 where
355 F: Num,
356 YOrigin: OriginGenerator<Y, F>,
357 Y: Space,
358 X: Space + Instance<X>,
359 {
360 type Codomain = Y;
361
362 fn apply<I: Instance<X>>(&self, _: I) -> Y {
363 self.y_origin.make_origin()
364 }
365 }
366
367 impl<X, Y, F, YOrigin, XDOrigin> Linear<X> for ZeroOp<X, Y, YOrigin, XDOrigin, F>
368 where
369 F: Num,
370 YOrigin: OriginGenerator<Y, F>,
371 Y: Space,
372 X: Space + Instance<X>,
373 {
374 }
375
376 #[replace_float_literals(F::cast_from(literal))]
377 impl<X, Y, F, YOrigin, XDOrigin> GEMV<F, X, Y> for ZeroOp<X, Y, YOrigin, XDOrigin, F>
378 where
379 F: Num,
380 YOrigin: OriginGenerator<Y, F>,
381 Y: Space + AXPY<F>,
382 X: Space + Instance<X>,
383 {
384 // Computes `y = αAx + βy`, where `A` is `Self`.
385 fn gemv<I: Instance<X>>(&self, y: &mut Y, _α: F, _x: I, β: F) {
386 *y *= β;
387 }
388
389 fn apply_mut<I: Instance<X>>(&self, y: &mut Y, _x: I) {
390 y.set_zero();
391 }
392 }
393
394 impl<X, Y, F, YOrigin, XDOrigin, E1, E2> BoundedLinear<X, E1, E2, F>
395 for ZeroOp<X, Y, YOrigin, XDOrigin, F>
396 where
397 F: Num,
398 YOrigin: OriginGenerator<Y, F>,
399 Y: Space + AXPY<F> + Norm<E2, F>,
400 X: Space + Instance<X> + Norm<E1, F>,
401 E1: NormExponent,
402 E2: NormExponent,
403 {
404 fn opnorm_bound(&self, _xexp: E1, _codexp: E2) -> DynResult<F> {
405 Ok(F::ZERO)
406 }
407 }
408
409 impl<X, Y, Yprime, F, YOrigin, XDOrigin> Adjointable<X, Yprime>
410 for ZeroOp<X, Y, YOrigin, XDOrigin, F>
411 where
412 F: Num,
413 YOrigin: OriginGenerator<Y, F>,
414 Y: Space + AXPY<F>,
415 X: Space + Instance<X> + HasDual<F>,
416 XDOrigin: OriginGenerator<X::DualSpace, F> + Clone,
417 Yprime: Space + Instance<Yprime>,
418 {
419 type AdjointCodomain = X::DualSpace;
420 type Adjoint<'b>
421 = ZeroOp<Yprime, X::DualSpace, XDOrigin, NotAnOriginGenerator, F>
307 where 422 where
308 Self: 'b; 423 Self: 'b;
309 // () means not (pre)adjointable. 424 // () means not (pre)adjointable.
310 425
311 fn preadjoint(&self) -> Self::Preadjoint<'_> { 426 fn adjoint(&self) -> Self::Adjoint<'_> {
312 ZeroOp::new(&self.dual_or_predual_zero, ()) 427 ZeroOp::new(self.xd_origin.clone(), NotAnOriginGenerator)
313 } 428 }
314 } 429 }
430 */
431
432 /*
433 impl<X, Y, Ypre, Xpre, F, YOrigin, XDOrigin> Preadjointable<X, Ypre>
434 for ZeroOp<X, Y, YOrigin, XDOrigin, F>
435 where
436 F: Num,
437 YOrigin: OriginGenerator<Y, F>,
438 Y: Space + AXPY<F>,
439 X: Space + Instance<X> + HasDual<F>,
440 XDOrigin: OriginGenerator<Xpre, F> + Clone,
441 Ypre: Space + Instance<Ypre> + HasDual<DualSpace = X>,
442 {
443 type PreadjointCodomain = Xpre;
444 type Preadjoint<'b>
445 = ZeroOp<Ypre, Xpre, XDOrigin, NotAnOriginGenerator, F>
446 where
447 Self: 'b;
448 // () means not (pre)adjointable.
449
450 fn adjoint(&self) -> Self::Adjoint<'_> {
451 ZeroOp::new(self.xpre_origin.clone(), NotAnOriginGenerator)
452 }
453 }
454 */
315 455
316 impl<S, T, E, X> Linear<X> for Composition<S, T, E> 456 impl<S, T, E, X> Linear<X> for Composition<S, T, E>
317 where 457 where
318 X: Space, 458 X: Space,
319 T: Linear<X>, 459 T: Linear<X>,

mercurial