src/linops.rs

branch
dev
changeset 81
d2acaaddd9af
parent 13
465fa2121ccb
equal deleted inserted replaced
49:edb95d2b83cc 81:d2acaaddd9af
8 use serde::Serialize; 8 use serde::Serialize;
9 pub use crate::mapping::Apply; 9 pub use crate::mapping::Apply;
10 10
11 /// Trait for linear operators on `X`. 11 /// Trait for linear operators on `X`.
12 pub trait Linear<X> : Apply<X, Output=Self::Codomain> 12 pub trait Linear<X> : Apply<X, Output=Self::Codomain>
13 + for<'a> Apply<&'a X, Output=Self::Codomain> { 13 + for<'a> Apply<&'a X, Output=Self::Codomain>
14 + HasScalarField {
14 type Codomain; 15 type Codomain;
15 } 16 }
16 17
17 /// Efficient in-place summation. 18 /// Efficient in-place summation.
18 #[replace_float_literals(F::cast_from(literal))] 19 #[replace_float_literals(F::cast_from(literal))]
19 pub trait AXPY<F : Num, X = Self> { 20 pub trait AXPY<F : Num, X = Self> {
20 /// Computes `y = βy + αx`, where `y` is `Self`. 21 /// Computes `y = βy + αx`, where `y` is `Self`.
21 fn axpy(&mut self, α : F, x : &X, β : F); 22 fn axpy(&mut self, α : F, x : X, β : F);
22 23
23 /// Copies `x` to `self`. 24 /// Copies `x` to `self`.
24 fn copy_from(&mut self, x : &X) { 25 fn copy_from(&mut self, x : X) {
25 self.axpy(1.0, x, 0.0) 26 self.axpy(1.0, x, 0.0)
26 } 27 }
27 28
28 /// Computes `y = αx`, where `y` is `Self`. 29 /// Computes `y = αx`, where `y` is `Self`.
29 fn scale_from(&mut self, α : F, x : &X) { 30 fn scale_from(&mut self, α : F, x : X) {
30 self.axpy(α, x, 0.0) 31 self.axpy(α, x, 0.0)
31 } 32 }
32 } 33 }
33 34
34 /// Efficient in-place application for [`Linear`] operators. 35 /// Efficient in-place application for [`Linear`] operators.
35 #[replace_float_literals(F::cast_from(literal))] 36 #[replace_float_literals(F::cast_from(literal))]
36 pub trait GEMV<F : Num, X, Y = <Self as Linear<X>>::Codomain> : Linear<X> { 37 pub trait GEMV<F : Num, X, Y = <Self as Apply<X>>::Output> : Apply<X> {
37 /// Computes `y = αAx + βy`, where `A` is `Self`. 38 /// Computes `y = αAx + βy`, where `A` is `Self`.
38 fn gemv(&self, y : &mut Y, α : F, x : &X, β : F); 39 fn gemv(&self, y : &mut Y, α : F, x : X, β : F);
39 40
40 /// Computes `y = Ax`, where `A` is `Self` 41 /// Computes `y = Ax`, where `A` is `Self`
41 fn apply_mut(&self, y : &mut Y, x : &X){ 42 fn apply_mut(&self, y : &mut Y, x : X){
42 self.gemv(y, 1.0, x, 0.0) 43 self.gemv(y, 1.0, x, 0.0)
43 } 44 }
44 45
45 /// Computes `y += Ax`, where `A` is `Self` 46 /// Computes `y += Ax`, where `A` is `Self`
46 fn apply_add(&self, y : &mut Y, x : &X){ 47 fn apply_add(&self, y : &mut Y, x : X){
47 self.gemv(y, 1.0, x, 1.0) 48 self.gemv(y, 1.0, x, 1.0)
48 } 49 }
49 } 50 }
50 51
51 52
52 /// Bounded linear operators 53 /// Bounded linear operators
53 pub trait BoundedLinear<X> : Linear<X> { 54 pub trait BoundedLinear<X> : Linear<X> {
54 type FloatType : Float;
55 /// A bound on the operator norm $\|A\|$ for the linear operator $A$=`self`. 55 /// A bound on the operator norm $\|A\|$ for the linear operator $A$=`self`.
56 /// This is not expected to be the norm, just any bound on it that can be 56 /// This is not expected to be the norm, just any bound on it that can be
57 /// reasonably implemented. 57 /// reasonably implemented.
58 fn opnorm_bound(&self) -> Self::FloatType; 58 fn opnorm_bound(&self) -> Self::Field;
59 } 59 }
60 60
61 // Linear operator application into mutable target. The [`AsRef`] bound 61 // Linear operator application into mutable target. The [`AsRef`] bound
62 // is used to guarantee compatibility with `Yʹ` and `Self::Codomain`; 62 // is used to guarantee compatibility with `Yʹ` and `Self::Codomain`;
63 // the former is assumed to be e.g. a view into the latter. 63 // the former is assumed to be e.g. a view into the latter.
68 } 68 }
69 }*/ 69 }*/
70 70
71 /// Trait for forming the adjoint operator of `Self`. 71 /// Trait for forming the adjoint operator of `Self`.
72 pub trait Adjointable<X,Yʹ> : Linear<X> { 72 pub trait Adjointable<X,Yʹ> : Linear<X> {
73 type AdjointCodomain; 73 type AdjointCodomain : HasScalarField<Field=Self::Field>;
74 type Adjoint<'a> : Linear<Yʹ, Codomain=Self::AdjointCodomain> where Self : 'a; 74 type Adjoint<'a> : Linear<Yʹ, Codomain=Self::AdjointCodomain> where Self : 'a;
75 75
76 /// Form the adjoint operator of `self`. 76 /// Form the adjoint operator of `self`.
77 fn adjoint(&self) -> Self::Adjoint<'_>; 77 fn adjoint(&self) -> Self::Adjoint<'_>;
78 78
87 /// such that its adjoint $(A\_\*)^\*=A$. The space `X` is the domain of the `Self` 87 /// such that its adjoint $(A\_\*)^\*=A$. The space `X` is the domain of the `Self`
88 /// operator. The space `Ypre` is the predual of its codomain, and should be the 88 /// operator. The space `Ypre` is the predual of its codomain, and should be the
89 /// domain of the adjointed operator. `Self::Preadjoint` should be 89 /// domain of the adjointed operator. `Self::Preadjoint` should be
90 /// [`Adjointable`]`<'a,Ypre,X>`. 90 /// [`Adjointable`]`<'a,Ypre,X>`.
91 pub trait Preadjointable<X,Ypre> : Linear<X> { 91 pub trait Preadjointable<X,Ypre> : Linear<X> {
92 type PreadjointCodomain; 92 type PreadjointCodomain : HasScalarField<Field=Self::Field>;
93 type Preadjoint<'a> : Adjointable<Ypre, X, Codomain=Self::PreadjointCodomain> where Self : 'a; 93 type Preadjoint<'a> : Adjointable<Ypre, X, Codomain=Self::PreadjointCodomain> where Self : 'a;
94 94
95 /// Form the preadjoint operator of `self`. 95 /// Form the preadjoint operator of `self`.
96 fn preadjoint(&self) -> Self::Preadjoint<'_>; 96 fn preadjoint(&self) -> Self::Preadjoint<'_>;
97 } 97 }
98 98
99 /// Adjointable operators $A: X → Y$ on between reflexive spaces $X$ and $Y$. 99 /// Adjointable operators $A: X → Y$ on between reflexive spaces $X$ and $Y$.
100 pub trait SimplyAdjointable<X> : Adjointable<X,<Self as Linear<X>>::Codomain> {} 100 pub trait SimplyAdjointable<X> : Adjointable<X,<Self as Linear<X>>::Codomain> {}
101 impl<'a,X,T> SimplyAdjointable<X> for T where T : Adjointable<X,<Self as Linear<X>>::Codomain> {} 101 impl<'a,X,T> SimplyAdjointable<X> for T where T : Adjointable<X,<Self as Linear<X>>::Codomain> {}
102 102
103 /// The identity operator 103 /// The identity operator on `X` with scalar field `F`.
104 #[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)] 104 #[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)]
105 pub struct IdOp<X> (PhantomData<X>); 105 pub struct IdOp<X, F : Num> (PhantomData<(X, F)>);
106 106
107 impl<X> IdOp<X> { 107 impl<X, F : Num> HasScalarField for IdOp<X, F> {
108 fn new() -> IdOp<X> { IdOp(PhantomData) } 108 type Field = F;
109 } 109 }
110 110
111 impl<X> Apply<X> for IdOp<X> { 111 impl<X, F : Num> IdOp<X, F> {
112 fn new() -> IdOp<X, F> { IdOp(PhantomData) }
113 }
114
115 impl<X, F : Num, T : CloneIfNeeded<X>> Apply<T> for IdOp<X, F> {
112 type Output = X; 116 type Output = X;
113 117
114 fn apply(&self, x : X) -> X { 118 fn apply(&self, x : T) -> X {
115 x 119 x.clone_if_needed()
116 } 120 }
117 } 121 }
118 122
119 impl<'a, X> Apply<&'a X> for IdOp<X> where X : Clone { 123 impl<X : Clone, F : Num> Linear<X> for IdOp<X, F> {
120 type Output = X;
121
122 fn apply(&self, x : &'a X) -> X {
123 x.clone()
124 }
125 }
126
127 impl<X> Linear<X> for IdOp<X> where X : Clone {
128 type Codomain = X; 124 type Codomain = X;
129 } 125 }
130 126
131
132 #[replace_float_literals(F::cast_from(literal))] 127 #[replace_float_literals(F::cast_from(literal))]
133 impl<F : Num, X, Y> GEMV<F, X, Y> for IdOp<X> where Y : AXPY<F, X>, X : Clone { 128 impl<F : Num, X : Clone, Y> GEMV<F, X, Y> for IdOp<X, F> where Y : AXPY<F, X> {
134 // Computes `y = αAx + βy`, where `A` is `Self`. 129 // Computes `y = αAx + βy`, where `A` is `Self`.
135 fn gemv(&self, y : &mut Y, α : F, x : &X, β : F) { 130 fn gemv(&self, y : &mut Y, α : F, x : X, β : F) {
136 y.axpy(α, x, β) 131 y.axpy(α, x, β)
137 } 132 }
138 133
139 fn apply_mut(&self, y : &mut Y, x : &X){ 134 fn apply_mut(&self, y : &mut Y, x : X){
140 y.copy_from(x); 135 y.copy_from(x);
141 } 136 }
142 } 137 }
143 138
144 impl<X> BoundedLinear<X> for IdOp<X> where X : Clone { 139 impl<X, F : Num> BoundedLinear<X> for IdOp<X, F> where X : Clone {
145 type FloatType = float; 140 fn opnorm_bound(&self) -> F { F::ONE }
146 fn opnorm_bound(&self) -> float { 1.0 }
147 } 141 }
148 142
149 impl<X> Adjointable<X,X> for IdOp<X> where X : Clone { 143 impl<X, F : Num> Adjointable<X,X> for IdOp<X, F> where X : Clone + HasScalarField<Field=F> {
150 type AdjointCodomain=X; 144 type AdjointCodomain=X;
151 type Adjoint<'a> = IdOp<X> where X : 'a; 145 type Adjoint<'a> = IdOp<X, F> where X : 'a;
152 fn adjoint(&self) -> Self::Adjoint<'_> { IdOp::new() } 146 fn adjoint(&self) -> Self::Adjoint<'_> { IdOp::new() }
153 } 147 }
154 148

mercurial