| 3 */ |
3 */ |
| 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::{ClosedSpace, Composition, DifferentiableImpl, Mapping, Space}; |
| 9 use crate::norms::{HasDual, 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; |
| 23 // fn differential_impl<I: Instance<X>>(&self, x: I) -> Self::Derivative { |
23 // fn differential_impl<I: Instance<X>>(&self, x: I) -> Self::Derivative { |
| 24 // self.apply(x) |
24 // self.apply(x) |
| 25 // } |
25 // } |
| 26 // } |
26 // } |
| 27 |
27 |
| 28 /// Efficient in-place summation. |
28 /// Vector spaces |
| 29 #[replace_float_literals(Self::Field::cast_from(literal))] |
29 #[replace_float_literals(Self::Field::cast_from(literal))] |
| 30 pub trait AXPY<X = Self>: |
30 pub trait VectorSpace: |
| 31 Space |
31 Space<OwnedSpace = Self::Owned> |
| 32 + MulAssign<Self::Field> |
|
| 33 + DivAssign<Self::Field> |
|
| 34 + AddAssign<Self> |
|
| 35 + AddAssign<Self::Owned> |
|
| 36 + SubAssign<Self> |
|
| 37 + SubAssign<Self::Owned> |
|
| 38 + Mul<Self::Field, Output = Self::Owned> |
32 + Mul<Self::Field, Output = Self::Owned> |
| 39 + Div<Self::Field, Output = Self::Owned> |
33 + Div<Self::Field, Output = Self::Owned> |
| 40 + Add<Self, Output = Self::Owned> |
34 + Add<Self, Output = Self::Owned> |
| 41 + Add<Self::Owned, Output = Self::Owned> |
35 + Add<Self::Owned, Output = Self::Owned> |
| 42 + Sub<Self, Output = Self::Owned> |
36 + Sub<Self, Output = Self::Owned> |
| 43 + Sub<Self::Owned, Output = Self::Owned> |
37 + Sub<Self::Owned, Output = Self::Owned> |
| 44 + Neg |
38 + Neg |
| 45 where |
|
| 46 X: Space, |
|
| 47 { |
39 { |
| 48 type Field: Num; |
40 type Field: Num; |
| 49 type Owned: AXPY<X, Field = Self::Field>; |
41 type Owned: ClosedSpace |
| 50 |
42 + AXPY< |
| 51 /// Computes `y = βy + αx`, where `y` is `Self`. |
43 Self, |
| 52 fn axpy<I: Instance<X>>(&mut self, α: Self::Field, x: I, β: Self::Field); |
44 Field = Self::Field, |
| 53 |
45 Owned = Self::Owned, |
| 54 /// Copies `x` to `self`. |
46 OwnedVariant = Self::Owned, |
| 55 fn copy_from<I: Instance<X>>(&mut self, x: I) { |
47 OwnedSpace = Self::Owned, |
| 56 self.axpy(1.0, x, 0.0) |
48 >; |
| 57 } |
|
| 58 |
|
| 59 /// Computes `y = αx`, where `y` is `Self`. |
|
| 60 fn scale_from<I: Instance<X>>(&mut self, α: Self::Field, x: I) { |
|
| 61 self.axpy(α, x, 0.0) |
|
| 62 } |
|
| 63 |
49 |
| 64 /// Return a similar zero as `self`. |
50 /// Return a similar zero as `self`. |
| 65 fn similar_origin(&self) -> Self::Owned; |
51 fn similar_origin(&self) -> Self::Owned; |
| 66 // { |
52 // { |
| 67 // self.make_origin_generator().make_origin() |
53 // self.make_origin_generator().make_origin() |
| 69 |
55 |
| 70 /// Return a similar zero as `x`. |
56 /// Return a similar zero as `x`. |
| 71 fn similar_origin_inst<I: Instance<Self>>(x: I) -> Self::Owned { |
57 fn similar_origin_inst<I: Instance<Self>>(x: I) -> Self::Owned { |
| 72 x.eval(|xr| xr.similar_origin()) |
58 x.eval(|xr| xr.similar_origin()) |
| 73 } |
59 } |
| |
60 } |
| |
61 |
| |
62 /// Efficient in-place summation. |
| |
63 #[replace_float_literals(Self::Field::cast_from(literal))] |
| |
64 pub trait AXPY<X = Self>: |
| |
65 VectorSpace |
| |
66 + MulAssign<Self::Field> |
| |
67 + DivAssign<Self::Field> |
| |
68 + AddAssign<Self> |
| |
69 + AddAssign<Self::Owned> |
| |
70 + SubAssign<Self> |
| |
71 + SubAssign<Self::Owned> |
| |
72 where |
| |
73 X: Space, |
| |
74 { |
| |
75 /// Computes `y = βy + αx`, where `y` is `Self`. |
| |
76 fn axpy<I: Instance<X>>(&mut self, α: Self::Field, x: I, β: Self::Field); |
| |
77 |
| |
78 /// Copies `x` to `self`. |
| |
79 fn copy_from<I: Instance<X>>(&mut self, x: I) { |
| |
80 self.axpy(1.0, x, 0.0) |
| |
81 } |
| |
82 |
| |
83 /// Computes `y = αx`, where `y` is `Self`. |
| |
84 fn scale_from<I: Instance<X>>(&mut self, α: Self::Field, x: I) { |
| |
85 self.axpy(α, x, 0.0) |
| |
86 } |
| 74 |
87 |
| 75 /// Set self to zero. |
88 /// Set self to zero. |
| 76 fn set_zero(&mut self); |
89 fn set_zero(&mut self); |
| 77 |
|
| 78 //fn make_origin_generator(&self) -> Self::OriginGen<'_>; |
|
| 79 } |
90 } |
| 80 |
91 |
| 81 /// Efficient in-place application for [`Linear`] operators. |
92 /// Efficient in-place application for [`Linear`] operators. |
| 82 #[replace_float_literals(F::cast_from(literal))] |
93 #[replace_float_literals(F::cast_from(literal))] |
| 83 pub trait GEMV<F: Num, X: Space, Y = <Self as Mapping<X>>::Codomain>: Linear<X> { |
94 pub trait GEMV<F: Num, X: Space, Y = <Self as Mapping<X>>::Codomain>: Linear<X> { |
| 176 pub fn new() -> IdOp<X> { |
187 pub fn new() -> IdOp<X> { |
| 177 IdOp(PhantomData) |
188 IdOp(PhantomData) |
| 178 } |
189 } |
| 179 } |
190 } |
| 180 |
191 |
| 181 impl<X: Clone + Space> Mapping<X> for IdOp<X> { |
192 impl<X: Space> Mapping<X> for IdOp<X> { |
| 182 type Codomain = X; |
193 type Codomain = X::OwnedVariant; |
| 183 |
194 |
| 184 fn apply<I: Instance<X>>(&self, x: I) -> X { |
195 fn apply<I: Instance<X>>(&self, x: I) -> X { |
| 185 x.own() |
196 x.own() |
| 186 } |
197 } |
| 187 } |
198 } |
| 188 |
199 |
| 189 impl<X: Clone + Space> Linear<X> for IdOp<X> {} |
200 impl<X: Space> Linear<X> for IdOp<X> {} |
| 190 |
201 |
| 191 #[replace_float_literals(F::cast_from(literal))] |
202 #[replace_float_literals(F::cast_from(literal))] |
| 192 impl<F: Num, X, Y> GEMV<F, X, Y> for IdOp<X> |
203 impl<F: Num, X, Y> GEMV<F, X, Y> for IdOp<X> |
| 193 where |
204 where |
| 194 Y: AXPY<X, Field = F>, |
205 Y: AXPY<X, Field = F>, |
| 195 X: Clone + Space, |
206 X: Space, |
| 196 { |
207 { |
| 197 // Computes `y = αAx + βy`, where `A` is `Self`. |
208 // Computes `y = αAx + βy`, where `A` is `Self`. |
| 198 fn gemv<I: Instance<X>>(&self, y: &mut Y, α: F, x: I, β: F) { |
209 fn gemv<I: Instance<X>>(&self, y: &mut Y, α: F, x: I, β: F) { |
| 199 y.axpy(α, x, β) |
210 y.axpy(α, x, β) |
| 200 } |
211 } |
| 241 |
252 |
| 242 /// The zero operator from a space to itself |
253 /// The zero operator from a space to itself |
| 243 #[derive(Clone, Copy, Debug, Serialize, Eq, PartialEq)] |
254 #[derive(Clone, Copy, Debug, Serialize, Eq, PartialEq)] |
| 244 pub struct SimpleZeroOp; |
255 pub struct SimpleZeroOp; |
| 245 |
256 |
| 246 impl<X> Mapping<X> for SimpleZeroOp |
257 impl<X: VectorSpace> Mapping<X> for SimpleZeroOp { |
| 247 where |
|
| 248 X: AXPY + Instance<X>, |
|
| 249 { |
|
| 250 type Codomain = X::Owned; |
258 type Codomain = X::Owned; |
| 251 |
259 |
| 252 fn apply<I: Instance<X>>(&self, x: I) -> X::Owned { |
260 fn apply<I: Instance<X>>(&self, x: I) -> X::Owned { |
| 253 X::similar_origin_inst(x) |
261 X::similar_origin_inst(x) |
| 254 } |
262 } |
| 255 } |
263 } |
| 256 |
264 |
| 257 impl<X> Linear<X> for SimpleZeroOp where X: AXPY + Instance<X> {} |
265 impl<X: VectorSpace> Linear<X> for SimpleZeroOp {} |
| 258 |
266 |
| 259 #[replace_float_literals(F::cast_from(literal))] |
267 #[replace_float_literals(F::cast_from(literal))] |
| 260 impl<X, Y, F> GEMV<F, X, Y> for SimpleZeroOp |
268 impl<X, Y, F> GEMV<F, X, Y> for SimpleZeroOp |
| 261 where |
269 where |
| 262 F: Num, |
270 F: Num, |
| 263 Y: AXPY<Field = F>, |
271 Y: AXPY<Field = F>, |
| 264 X: AXPY<Field = F> + Instance<X>, |
272 X: VectorSpace<Field = F> + Instance<X>, |
| 265 { |
273 { |
| 266 // Computes `y = αAx + βy`, where `A` is `Self`. |
274 // Computes `y = αAx + βy`, where `A` is `Self`. |
| 267 fn gemv<I: Instance<X>>(&self, y: &mut Y, _α: F, _x: I, β: F) { |
275 fn gemv<I: Instance<X>>(&self, y: &mut Y, _α: F, _x: I, β: F) { |
| 268 *y *= β; |
276 *y *= β; |
| 269 } |
277 } |
| 274 } |
282 } |
| 275 |
283 |
| 276 impl<X, F, E1, E2> BoundedLinear<X, E1, E2, F> for SimpleZeroOp |
284 impl<X, F, E1, E2> BoundedLinear<X, E1, E2, F> for SimpleZeroOp |
| 277 where |
285 where |
| 278 F: Num, |
286 F: Num, |
| 279 X: AXPY<Field = F> + Instance<X> + Norm<E1, F>, |
287 X: VectorSpace<Field = F> + Norm<E1, F>, |
| 280 E1: NormExponent, |
288 E1: NormExponent, |
| 281 E2: NormExponent, |
289 E2: NormExponent, |
| 282 { |
290 { |
| 283 fn opnorm_bound(&self, _xexp: E1, _codexp: E2) -> DynResult<F> { |
291 fn opnorm_bound(&self, _xexp: E1, _codexp: E2) -> DynResult<F> { |
| 284 Ok(F::ZERO) |
292 Ok(F::ZERO) |
| 286 } |
294 } |
| 287 |
295 |
| 288 impl<X, F> Adjointable<X, X::DualSpace> for SimpleZeroOp |
296 impl<X, F> Adjointable<X, X::DualSpace> for SimpleZeroOp |
| 289 where |
297 where |
| 290 F: Num, |
298 F: Num, |
| 291 X: AXPY<Field = F> + Instance<X> + HasDual<F>, |
299 X: VectorSpace<Field = F> + HasDual<F>, |
| 292 X::DualSpace: AXPY<Owned = X::DualSpace>, |
300 X::DualSpace: VectorSpace<Owned = X::DualSpace>, |
| 293 { |
301 { |
| 294 type AdjointCodomain = X::DualSpace; |
302 type AdjointCodomain = X::DualSpace; |
| 295 type Adjoint<'b> |
303 type Adjoint<'b> |
| 296 = SimpleZeroOp |
304 = SimpleZeroOp |
| 297 where |
305 where |
| 301 fn adjoint(&self) -> Self::Adjoint<'_> { |
309 fn adjoint(&self) -> Self::Adjoint<'_> { |
| 302 SimpleZeroOp |
310 SimpleZeroOp |
| 303 } |
311 } |
| 304 } |
312 } |
| 305 |
313 |
| 306 pub trait OriginGenerator<Y: AXPY> { |
314 pub trait OriginGenerator<Y: VectorSpace> { |
| 307 type Ref<'b>: OriginGenerator<Y> |
315 type Ref<'b>: OriginGenerator<Y> |
| 308 where |
316 where |
| 309 Self: 'b; |
317 Self: 'b; |
| 310 |
318 |
| 311 fn origin(&self) -> Y::Owned; |
319 fn origin(&self) -> Y::Owned; |
| 312 fn as_ref(&self) -> Self::Ref<'_>; |
320 fn as_ref(&self) -> Self::Ref<'_>; |
| 313 } |
321 } |
| 314 |
322 |
| 315 impl<Y: AXPY> OriginGenerator<Y> for Y { |
323 impl<Y: VectorSpace> OriginGenerator<Y> for Y { |
| 316 type Ref<'b> |
324 type Ref<'b> |
| 317 = &'b Y |
325 = &'b Y |
| 318 where |
326 where |
| 319 Self: 'b; |
327 Self: 'b; |
| 320 |
328 |
| 346 } |
354 } |
| 347 } |
355 } |
| 348 |
356 |
| 349 /// A zero operator that can be eitherh dualised or predualised (once). |
357 /// A zero operator that can be eitherh dualised or predualised (once). |
| 350 /// This is achieved by storing an oppropriate zero. |
358 /// This is achieved by storing an oppropriate zero. |
| 351 pub struct ZeroOp<X, Y: AXPY<Field = F>, OY: OriginGenerator<Y>, O, F: Float = f64> { |
359 pub struct ZeroOp<X, Y: VectorSpace<Field = F>, OY: OriginGenerator<Y>, O, F: Float = f64> { |
| 352 codomain_origin_generator: OY, |
360 codomain_origin_generator: OY, |
| 353 other_origin_generator: O, |
361 other_origin_generator: O, |
| 354 _phantoms: PhantomData<(X, Y, F)>, |
362 _phantoms: PhantomData<(X, Y, F)>, |
| 355 } |
363 } |
| 356 |
364 |
| 357 impl<X, Y, OY, F> ZeroOp<X, Y, OY, (), F> |
365 impl<X, Y, OY, F> ZeroOp<X, Y, OY, (), F> |
| 358 where |
366 where |
| 359 OY: OriginGenerator<Y>, |
367 OY: OriginGenerator<Y>, |
| 360 X: AXPY<Field = F>, |
368 X: VectorSpace<Field = F>, |
| 361 Y: AXPY<Field = F>, |
369 Y: VectorSpace<Field = F>, |
| 362 F: Float, |
370 F: Float, |
| 363 { |
371 { |
| 364 pub fn new(y_og: OY) -> Self { |
372 pub fn new(y_og: OY) -> Self { |
| 365 ZeroOp { |
373 ZeroOp { |
| 366 codomain_origin_generator: y_og, |
374 codomain_origin_generator: y_og, |
| 375 OY: OriginGenerator<Y>, |
383 OY: OriginGenerator<Y>, |
| 376 OXprime: OriginGenerator<Xprime>, |
384 OXprime: OriginGenerator<Xprime>, |
| 377 X: HasDual<F, DualSpace = Xprime>, |
385 X: HasDual<F, DualSpace = Xprime>, |
| 378 Y: HasDual<F, DualSpace = Yprime>, |
386 Y: HasDual<F, DualSpace = Yprime>, |
| 379 F: Float, |
387 F: Float, |
| 380 Xprime: AXPY<Field = F, Owned = Xprime>, |
388 Xprime: VectorSpace<Field = F, Owned = Xprime>, |
| 381 Xprime::Owned: AXPY<Field = F>, |
389 Xprime::Owned: AXPY<Field = F>, |
| 382 Yprime: Space + Instance<Yprime>, |
390 Yprime: Space + Instance<Yprime>, |
| 383 { |
391 { |
| 384 pub fn new_dualisable(y_og: OY, xprime_og: OXprime) -> Self { |
392 pub fn new_dualisable(y_og: OY, xprime_og: OXprime) -> Self { |
| 385 ZeroOp { |
393 ZeroOp { |
| 390 } |
398 } |
| 391 } |
399 } |
| 392 |
400 |
| 393 impl<X, Y, O, OY, F> Mapping<X> for ZeroOp<X, Y, OY, O, F> |
401 impl<X, Y, O, OY, F> Mapping<X> for ZeroOp<X, Y, OY, O, F> |
| 394 where |
402 where |
| 395 X: Space + Instance<X>, |
403 X: Space, |
| 396 Y: AXPY<Field = F>, |
404 Y: VectorSpace<Field = F>, |
| 397 F: Float, |
405 F: Float, |
| 398 OY: OriginGenerator<Y>, |
406 OY: OriginGenerator<Y>, |
| 399 { |
407 { |
| 400 type Codomain = Y::Owned; |
408 type Codomain = Y::Owned; |
| 401 |
409 |
| 404 } |
412 } |
| 405 } |
413 } |
| 406 |
414 |
| 407 impl<X, Y, OY, O, F> Linear<X> for ZeroOp<X, Y, OY, O, F> |
415 impl<X, Y, OY, O, F> Linear<X> for ZeroOp<X, Y, OY, O, F> |
| 408 where |
416 where |
| 409 X: Space + Instance<X>, |
417 X: Space, |
| 410 Y: AXPY<Field = F>, |
418 Y: VectorSpace<Field = F>, |
| 411 F: Float, |
419 F: Float, |
| 412 OY: OriginGenerator<Y>, |
420 OY: OriginGenerator<Y>, |
| 413 { |
421 { |
| 414 } |
422 } |
| 415 |
423 |
| 416 #[replace_float_literals(F::cast_from(literal))] |
424 #[replace_float_literals(F::cast_from(literal))] |
| 417 impl<X, Y, OY, O, F> GEMV<F, X, Y> for ZeroOp<X, Y, OY, O, F> |
425 impl<X, Y, OY, O, F> GEMV<F, X, Y> for ZeroOp<X, Y, OY, O, F> |
| 418 where |
426 where |
| 419 X: Space + Instance<X>, |
427 X: Space, |
| 420 Y: AXPY<Field = F, Owned = Y>, |
428 Y: AXPY<Field = F, Owned = Y>, |
| 421 F: Float, |
429 F: Float, |
| 422 OY: OriginGenerator<Y>, |
430 OY: OriginGenerator<Y>, |
| 423 { |
431 { |
| 424 // Computes `y = αAx + βy`, where `A` is `Self`. |
432 // Computes `y = αAx + βy`, where `A` is `Self`. |
| 432 } |
440 } |
| 433 |
441 |
| 434 impl<X, Y, OY, O, F, E1, E2> BoundedLinear<X, E1, E2, F> for ZeroOp<X, Y, OY, O, F> |
442 impl<X, Y, OY, O, F, E1, E2> BoundedLinear<X, E1, E2, F> for ZeroOp<X, Y, OY, O, F> |
| 435 where |
443 where |
| 436 X: Space + Instance<X> + Norm<E1, F>, |
444 X: Space + Instance<X> + Norm<E1, F>, |
| 437 Y: AXPY<Field = F>, |
445 Y: VectorSpace<Field = F>, |
| 438 Y::Owned: Clone, |
446 Y::Owned: Clone, |
| 439 F: Float, |
447 F: Float, |
| 440 E1: NormExponent, |
448 E1: NormExponent, |
| 441 E2: NormExponent, |
449 E2: NormExponent, |
| 442 OY: OriginGenerator<Y>, |
450 OY: OriginGenerator<Y>, |
| 450 for ZeroOp<X, Y, OY, OXprime, F> |
458 for ZeroOp<X, Y, OY, OXprime, F> |
| 451 where |
459 where |
| 452 X: HasDual<F, DualSpace = Xprime>, |
460 X: HasDual<F, DualSpace = Xprime>, |
| 453 Y: HasDual<F, DualSpace = Yprime>, |
461 Y: HasDual<F, DualSpace = Yprime>, |
| 454 F: Float, |
462 F: Float, |
| 455 Xprime: AXPY<Field = F, Owned = Xprime>, |
463 Xprime: VectorSpace<Field = F, Owned = Xprime>, |
| 456 Xprime::Owned: AXPY<Field = F>, |
464 Xprime::Owned: AXPY<Field = F>, |
| 457 Yprime: Space + Instance<Yprime>, |
465 Yprime: Space + Instance<Yprime>, |
| 458 OY: OriginGenerator<Y>, |
466 OY: OriginGenerator<Y>, |
| 459 OXprime: OriginGenerator<X::DualSpace>, |
467 OXprime: OriginGenerator<X::DualSpace>, |
| 460 { |
468 { |