| 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> { |
| 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>, |