| 60 } |
50 } |
| 61 |
51 |
| 62 use DiscretisationOrInterior::*; |
52 use DiscretisationOrInterior::*; |
| 63 |
53 |
| 64 /// Trait for different discretisations |
54 /// Trait for different discretisations |
| 65 pub trait Discretisation<F : Float + nalgebra::RealField> : Copy { |
55 pub trait Discretisation<F: Float + nalgebra::RealField>: Copy { |
| 66 /// Opposite discretisation, appropriate for adjoints with negated cell width. |
56 /// Opposite discretisation, appropriate for adjoints with negated cell width. |
| 67 type Opposite : Discretisation<F>; |
57 type Opposite: Discretisation<F>; |
| 68 |
58 |
| 69 /// Add to appropiate index of `v` (as determined by `b`) the appropriate difference |
59 /// Add to appropiate index of `v` (as determined by `b`) the appropriate difference |
| 70 /// of `x` with cell width `h`. |
60 /// of `x` with cell width `h`. |
| 71 fn add_diff_mut<SMut, S>( |
61 fn add_diff_mut<SMut, S>( |
| 72 &self, |
62 &self, |
| 73 v : &mut Matrix<F, Dyn, U1, SMut>, |
63 v: &mut Matrix<F, Dyn, U1, SMut>, |
| 74 x : &Matrix<F, Dyn, U1, S>, |
64 x: &Matrix<F, Dyn, U1, S>, |
| 75 α : F, |
65 α: F, |
| 76 b : DiscretisationOrInterior, |
66 b: DiscretisationOrInterior, |
| 77 ) where |
67 ) where |
| 78 SMut : StorageMut<F, Dyn, U1>, |
68 SMut: StorageMut<F, Dyn, U1>, |
| 79 S : Storage<F, Dyn, U1>; |
69 S: Storage<F, Dyn, U1>; |
| 80 |
70 |
| 81 /// Give the opposite discretisation, appropriate for adjoints with negated `h`. |
71 /// Give the opposite discretisation, appropriate for adjoints with negated `h`. |
| 82 fn opposite(&self) -> Self::Opposite; |
72 fn opposite(&self) -> Self::Opposite; |
| 83 |
73 |
| 84 /// Bound for the corresponding operator norm. |
74 /// Bound for the corresponding operator norm. |
| 85 #[replace_float_literals(F::cast_from(literal))] |
75 #[replace_float_literals(F::cast_from(literal))] |
| 86 fn opnorm_bound(&self, h : F) -> F { |
76 fn opnorm_bound(&self, h: F) -> DynResult<F> { |
| 87 // See: Chambolle, “An Algorithm for Total Variation Minimization and Applications”. |
77 // See: Chambolle, “An Algorithm for Total Variation Minimization and Applications”. |
| 88 // Ok for forward and backward differences. |
78 // Ok for forward and backward differences. |
| 89 // |
79 // |
| 90 // Fuck nalgebra for polluting everything with its own shit. |
80 // Fuck nalgebra for polluting everything with its own shit. |
| 91 num_traits::Float::sqrt(8.0) / h |
81 Ok(num_traits::Float::sqrt(8.0) / h) |
| 92 } |
82 } |
| 93 } |
83 } |
| 94 |
84 |
| 95 impl<F : Float + nalgebra::RealField> Discretisation<F> for ForwardNeumann { |
85 impl<F: Float + nalgebra::RealField> Discretisation<F> for ForwardNeumann { |
| 96 type Opposite = BackwardDirichlet; |
86 type Opposite = BackwardDirichlet; |
| 97 |
87 |
| 98 #[inline] |
88 #[inline] |
| 99 fn add_diff_mut<SMut, S>( |
89 fn add_diff_mut<SMut, S>( |
| 100 &self, |
90 &self, |
| 101 v : &mut Matrix<F, Dyn, U1, SMut>, |
91 v: &mut Matrix<F, Dyn, U1, SMut>, |
| 102 x : &Matrix<F, Dyn, U1, S>, |
92 x: &Matrix<F, Dyn, U1, S>, |
| 103 α : F, |
93 α: F, |
| 104 b : DiscretisationOrInterior, |
94 b: DiscretisationOrInterior, |
| 105 ) where |
95 ) where |
| 106 SMut : StorageMut<F, Dyn, U1>, |
96 SMut: StorageMut<F, Dyn, U1>, |
| 107 S : Storage<F, Dyn, U1> |
97 S: Storage<F, Dyn, U1>, |
| 108 { |
98 { |
| 109 match b { |
99 match b { |
| 110 Interior(c, (_, f)) | LeftBoundary(c, f) => { v[c] += (x[f] - x[c]) * α }, |
100 Interior(c, (_, f)) | LeftBoundary(c, f) => v[c] += (x[f] - x[c]) * α, |
| 111 RightBoundary(_c, _b) => { }, |
101 RightBoundary(_c, _b) => {} |
| 112 } |
102 } |
| 113 } |
103 } |
| 114 |
104 |
| 115 #[inline] |
105 #[inline] |
| 116 fn opposite(&self) -> Self::Opposite { |
106 fn opposite(&self) -> Self::Opposite { |
| 117 BackwardDirichlet |
107 BackwardDirichlet |
| 118 } |
108 } |
| 119 } |
109 } |
| 120 |
110 |
| 121 impl<F : Float + nalgebra::RealField> Discretisation<F> for BackwardNeumann { |
111 impl<F: Float + nalgebra::RealField> Discretisation<F> for BackwardNeumann { |
| 122 type Opposite = ForwardDirichlet; |
112 type Opposite = ForwardDirichlet; |
| 123 |
113 |
| 124 #[inline] |
114 #[inline] |
| 125 fn add_diff_mut<SMut, S>( |
115 fn add_diff_mut<SMut, S>( |
| 126 &self, |
116 &self, |
| 127 v : &mut Matrix<F, Dyn, U1, SMut>, |
117 v: &mut Matrix<F, Dyn, U1, SMut>, |
| 128 x : &Matrix<F, Dyn, U1, S>, |
118 x: &Matrix<F, Dyn, U1, S>, |
| 129 α : F, |
119 α: F, |
| 130 b : DiscretisationOrInterior, |
120 b: DiscretisationOrInterior, |
| 131 ) where |
121 ) where |
| 132 SMut : StorageMut<F, Dyn, U1>, |
122 SMut: StorageMut<F, Dyn, U1>, |
| 133 S : Storage<F, Dyn, U1> |
123 S: Storage<F, Dyn, U1>, |
| 134 { |
124 { |
| 135 match b { |
125 match b { |
| 136 Interior(c, (b, _)) | RightBoundary(c, b) => { v[c] += (x[c] - x[b]) * α }, |
126 Interior(c, (b, _)) | RightBoundary(c, b) => v[c] += (x[c] - x[b]) * α, |
| 137 LeftBoundary(_c, _f) => { }, |
127 LeftBoundary(_c, _f) => {} |
| 138 } |
128 } |
| 139 } |
129 } |
| 140 |
130 |
| 141 #[inline] |
131 #[inline] |
| 142 fn opposite(&self) -> Self::Opposite { |
132 fn opposite(&self) -> Self::Opposite { |
| 143 ForwardDirichlet |
133 ForwardDirichlet |
| 144 } |
134 } |
| 145 } |
135 } |
| 146 |
136 |
| 147 impl<F : Float + nalgebra::RealField> Discretisation<F> for BackwardDirichlet { |
137 impl<F: Float + nalgebra::RealField> Discretisation<F> for BackwardDirichlet { |
| 148 type Opposite = ForwardNeumann; |
138 type Opposite = ForwardNeumann; |
| 149 |
139 |
| 150 #[inline] |
140 #[inline] |
| 151 fn add_diff_mut<SMut, S>( |
141 fn add_diff_mut<SMut, S>( |
| 152 &self, |
142 &self, |
| 153 v : &mut Matrix<F, Dyn, U1, SMut>, |
143 v: &mut Matrix<F, Dyn, U1, SMut>, |
| 154 x : &Matrix<F, Dyn, U1, S>, |
144 x: &Matrix<F, Dyn, U1, S>, |
| 155 α : F, |
145 α: F, |
| 156 b : DiscretisationOrInterior, |
146 b: DiscretisationOrInterior, |
| 157 ) where |
147 ) where |
| 158 SMut : StorageMut<F, Dyn, U1>, |
148 SMut: StorageMut<F, Dyn, U1>, |
| 159 S : Storage<F, Dyn, U1> |
149 S: Storage<F, Dyn, U1>, |
| 160 { |
150 { |
| 161 match b { |
151 match b { |
| 162 Interior(c, (b, _f)) => { v[c] += (x[c] - x[b]) * α }, |
152 Interior(c, (b, _f)) => v[c] += (x[c] - x[b]) * α, |
| 163 LeftBoundary(c, _f) => { v[c] += x[c] * α }, |
153 LeftBoundary(c, _f) => v[c] += x[c] * α, |
| 164 RightBoundary(c, b) => { v[c] -= x[b] * α }, |
154 RightBoundary(c, b) => v[c] -= x[b] * α, |
| 165 } |
155 } |
| 166 } |
156 } |
| 167 |
157 |
| 168 #[inline] |
158 #[inline] |
| 169 fn opposite(&self) -> Self::Opposite { |
159 fn opposite(&self) -> Self::Opposite { |
| 170 ForwardNeumann |
160 ForwardNeumann |
| 171 } |
161 } |
| 172 } |
162 } |
| 173 |
163 |
| 174 impl<F : Float + nalgebra::RealField> Discretisation<F> for ForwardDirichlet { |
164 impl<F: Float + nalgebra::RealField> Discretisation<F> for ForwardDirichlet { |
| 175 type Opposite = BackwardNeumann; |
165 type Opposite = BackwardNeumann; |
| 176 |
166 |
| 177 #[inline] |
167 #[inline] |
| 178 fn add_diff_mut<SMut, S>( |
168 fn add_diff_mut<SMut, S>( |
| 179 &self, |
169 &self, |
| 180 v : &mut Matrix<F, Dyn, U1, SMut>, |
170 v: &mut Matrix<F, Dyn, U1, SMut>, |
| 181 x : &Matrix<F, Dyn, U1, S>, |
171 x: &Matrix<F, Dyn, U1, S>, |
| 182 α : F, |
172 α: F, |
| 183 b : DiscretisationOrInterior, |
173 b: DiscretisationOrInterior, |
| 184 ) where |
174 ) where |
| 185 SMut : StorageMut<F, Dyn, U1>, |
175 SMut: StorageMut<F, Dyn, U1>, |
| 186 S : Storage<F, Dyn, U1> |
176 S: Storage<F, Dyn, U1>, |
| 187 { |
177 { |
| 188 match b { |
178 match b { |
| 189 Interior(c, (_b, f)) => { v[c] += (x[f] - x[c]) * α }, |
179 Interior(c, (_b, f)) => v[c] += (x[f] - x[c]) * α, |
| 190 LeftBoundary(c, f) => { v[c] += x[f] * α }, |
180 LeftBoundary(c, f) => v[c] += x[f] * α, |
| 191 RightBoundary(c, _b) => { v[c] -= x[c] * α }, |
181 RightBoundary(c, _b) => v[c] -= x[c] * α, |
| 192 } |
182 } |
| 193 } |
183 } |
| 194 |
184 |
| 195 #[inline] |
185 #[inline] |
| 196 fn opposite(&self) -> Self::Opposite { |
186 fn opposite(&self) -> Self::Opposite { |
| 197 BackwardNeumann |
187 BackwardNeumann |
| 198 } |
188 } |
| 199 } |
189 } |
| 200 |
190 |
| 201 struct Iter<'a, const N : usize> { |
191 struct Iter<'a, const N: usize> { |
| 202 /// Dimensions |
192 /// Dimensions |
| 203 dims : &'a [usize; N], |
193 dims: &'a [usize; N], |
| 204 /// Dimension along which to calculate differences |
194 /// Dimension along which to calculate differences |
| 205 d : usize, |
195 d: usize, |
| 206 /// Stride along coordinate d |
196 /// Stride along coordinate d |
| 207 d_stride : usize, |
197 d_stride: usize, |
| 208 /// Cartesian indices |
198 /// Cartesian indices |
| 209 i : [usize; N], |
199 i: [usize; N], |
| 210 /// Linear index |
200 /// Linear index |
| 211 k : usize, |
201 k: usize, |
| 212 /// Maximal linear index |
202 /// Maximal linear index |
| 213 len : usize |
203 len: usize, |
| 214 } |
204 } |
| 215 |
205 |
| 216 impl<'a, const N : usize> Iter<'a, N> { |
206 impl<'a, const N: usize> Iter<'a, N> { |
| 217 fn new(dims : &'a [usize; N], d : usize) -> Self { |
207 fn new(dims: &'a [usize; N], d: usize) -> Self { |
| 218 let d_stride = dims[0..d].iter().product::<usize>(); |
208 let d_stride = dims[0..d].iter().product::<usize>(); |
| 219 let len = dims.iter().product::<usize>(); |
209 let len = dims.iter().product::<usize>(); |
| 220 Iter{ dims, d, d_stride, i : [0; N], k : 0, len } |
210 Iter { |
| 221 } |
211 dims, |
| 222 } |
212 d, |
| 223 |
213 d_stride, |
| 224 impl<'a, const N : usize> Iterator for Iter<'a, N> { |
214 i: [0; N], |
| |
215 k: 0, |
| |
216 len, |
| |
217 } |
| |
218 } |
| |
219 } |
| |
220 |
| |
221 impl<'a, const N: usize> Iterator for Iter<'a, N> { |
| 225 type Item = DiscretisationOrInterior; |
222 type Item = DiscretisationOrInterior; |
| 226 fn next(&mut self) -> Option<Self::Item> { |
223 fn next(&mut self) -> Option<Self::Item> { |
| 227 let res = if self.k >= self.len { |
224 let res = if self.k >= self.len { |
| 228 None |
225 None |
| 229 } else { |
226 } else { |
| 284 let h = self.h; |
277 let h = self.h; |
| 285 let m = self.len(); |
278 let m = self.len(); |
| 286 i.eval(|x| { |
279 i.eval(|x| { |
| 287 assert_eq!(x.len(), m); |
280 assert_eq!(x.len(), m); |
| 288 for d in 0..N { |
281 for d in 0..N { |
| 289 let mut v = y.generic_view_mut((d*m, 0), (Dyn(m), U1)); |
282 let mut v = y.generic_view_mut((d * m, 0), (Dyn(m), U1)); |
| 290 for b in Iter::new(&self.dims, d) { |
283 for b in Iter::new(&self.dims, d) { |
| 291 self.discretisation.add_diff_mut(&mut v, x, α/h, b) |
284 self.discretisation.add_diff_mut(&mut v, x, α / h, b) |
| 292 } |
285 } |
| 293 } |
286 } |
| 294 }) |
287 }) |
| 295 } |
288 } |
| 296 } |
289 } |
| 297 |
290 |
| 298 impl<F, B, const N : usize> Mapping<DVector<F>> |
291 impl<F, B, const N: usize> Mapping<DVector<F>> for Div<F, B, N> |
| 299 for Div<F, B, N> |
292 where |
| 300 where |
293 B: Discretisation<F>, |
| 301 B : Discretisation<F>, |
294 F: Float + nalgebra::RealField, |
| 302 F : Float + nalgebra::RealField, |
|
| 303 { |
295 { |
| 304 type Codomain = DVector<F>; |
296 type Codomain = DVector<F>; |
| 305 fn apply<I : Instance<DVector<F>>>(&self, i : I) -> DVector<F> { |
297 fn apply<I: Instance<DVector<F>>>(&self, i: I) -> DVector<F> { |
| 306 let mut y = DVector::zeros(self.len()); |
298 let mut y = DVector::zeros(self.len()); |
| 307 self.apply_add(&mut y, i); |
299 self.apply_add(&mut y, i); |
| 308 y |
300 y |
| 309 } |
301 } |
| 310 } |
302 } |
| 311 |
303 |
| 312 #[replace_float_literals(F::cast_from(literal))] |
304 #[replace_float_literals(F::cast_from(literal))] |
| 313 impl<F, B, const N : usize> GEMV<F, DVector<F>> |
305 impl<F, B, const N: usize> GEMV<F, DVector<F>> for Div<F, B, N> |
| 314 for Div<F, B, N> |
306 where |
| 315 where |
307 B: Discretisation<F>, |
| 316 B : Discretisation<F>, |
308 F: Float + nalgebra::RealField, |
| 317 F : Float + nalgebra::RealField, |
309 { |
| 318 { |
310 fn gemv<I: Instance<DVector<F>>>(&self, y: &mut DVector<F>, α: F, i: I, β: F) { |
| 319 fn gemv<I : Instance<DVector<F>>>( |
|
| 320 &self, y : &mut DVector<F>, α : F, i : I, β : F |
|
| 321 ) { |
|
| 322 if β == 0.0 { |
311 if β == 0.0 { |
| 323 y.as_mut_slice().iter_mut().for_each(|x| *x = 0.0); |
312 y.as_mut_slice().iter_mut().for_each(|x| *x = 0.0); |
| 324 } else if β != 1.0 { |
313 } else if β != 1.0 { |
| 325 //*y *= β; |
314 //*y *= β; |
| 326 y.as_mut_slice().iter_mut().for_each(|x| *x *= β); |
315 y.as_mut_slice().iter_mut().for_each(|x| *x *= β); |
| 328 let h = self.h; |
317 let h = self.h; |
| 329 let m = self.len(); |
318 let m = self.len(); |
| 330 i.eval(|x| { |
319 i.eval(|x| { |
| 331 assert_eq!(x.len(), N * m); |
320 assert_eq!(x.len(), N * m); |
| 332 for d in 0..N { |
321 for d in 0..N { |
| 333 let v = x.generic_view((d*m, 0), (Dyn(m), U1)); |
322 let v = x.generic_view((d * m, 0), (Dyn(m), U1)); |
| 334 for b in Iter::new(&self.dims, d) { |
323 for b in Iter::new(&self.dims, d) { |
| 335 self.discretisation.add_diff_mut(y, &v, α/h, b) |
324 self.discretisation.add_diff_mut(y, &v, α / h, b) |
| 336 } |
325 } |
| 337 } |
326 } |
| 338 }) |
327 }) |
| 339 } |
328 } |
| 340 } |
329 } |
| 341 |
330 |
| 342 impl<F, B, const N : usize> Grad<F, B, N> |
331 impl<F, B, const N: usize> Grad<F, B, N> |
| 343 where |
332 where |
| 344 B : Discretisation<F>, |
333 B: Discretisation<F>, |
| 345 F : Float + nalgebra::RealField |
334 F: Float + nalgebra::RealField, |
| 346 { |
335 { |
| 347 /// Creates a new discrete gradient operator for the vector `u`, verifying dimensions. |
336 /// Creates a new discrete gradient operator for the vector `u`, verifying dimensions. |
| 348 pub fn new_for(u : &DVector<F>, h : F, dims : [usize; N], discretisation : B) |
337 pub fn new_for(u: &DVector<F>, h: F, dims: [usize; N], discretisation: B) -> Option<Self> { |
| 349 -> Option<Self> |
|
| 350 { |
|
| 351 if u.len() == dims.iter().product::<usize>() { |
338 if u.len() == dims.iter().product::<usize>() { |
| 352 Some(Grad { dims, h, discretisation } ) |
339 Some(Grad { |
| |
340 dims, |
| |
341 h, |
| |
342 discretisation, |
| |
343 }) |
| 353 } else { |
344 } else { |
| 354 None |
345 None |
| 355 } |
346 } |
| 356 } |
347 } |
| 357 |
348 |
| 358 fn len(&self) -> usize { |
349 fn len(&self) -> usize { |
| 359 self.dims.iter().product::<usize>() |
350 self.dims.iter().product::<usize>() |
| 360 } |
351 } |
| 361 } |
352 } |
| 362 |
353 |
| 363 |
354 impl<F, B, const N: usize> Div<F, B, N> |
| 364 impl<F, B, const N : usize> Div<F, B, N> |
355 where |
| 365 where |
356 B: Discretisation<F>, |
| 366 B : Discretisation<F>, |
357 F: Float + nalgebra::RealField, |
| 367 F : Float + nalgebra::RealField |
|
| 368 { |
358 { |
| 369 /// Creates a new discrete gradient operator for the vector `u`, verifying dimensions. |
359 /// Creates a new discrete gradient operator for the vector `u`, verifying dimensions. |
| 370 pub fn new_for(u : &DVector<F>, h : F, dims : [usize; N], discretisation : B) |
360 pub fn new_for(u: &DVector<F>, h: F, dims: [usize; N], discretisation: B) -> Option<Self> { |
| 371 -> Option<Self> |
|
| 372 { |
|
| 373 if u.len() == dims.iter().product::<usize>() * N { |
361 if u.len() == dims.iter().product::<usize>() * N { |
| 374 Some(Div { dims, h, discretisation } ) |
362 Some(Div { |
| |
363 dims, |
| |
364 h, |
| |
365 discretisation, |
| |
366 }) |
| 375 } else { |
367 } else { |
| 376 None |
368 None |
| 377 } |
369 } |
| 378 } |
370 } |
| 379 |
371 |
| 380 fn len(&self) -> usize { |
372 fn len(&self) -> usize { |
| 381 self.dims.iter().product::<usize>() |
373 self.dims.iter().product::<usize>() |
| 382 } |
374 } |
| 383 } |
375 } |
| 384 |
376 |
| 385 impl<F, B, const N : usize> Linear<DVector<F>> |
377 impl<F, B, const N: usize> Linear<DVector<F>> for Grad<F, B, N> |
| 386 for Grad<F, B, N> |
378 where |
| 387 where |
379 B: Discretisation<F>, |
| 388 B : Discretisation<F>, |
380 F: Float + nalgebra::RealField, |
| 389 F : Float + nalgebra::RealField, |
381 { |
| 390 { |
382 } |
| 391 } |
383 |
| 392 |
384 impl<F, B, const N: usize> Linear<DVector<F>> for Div<F, B, N> |
| 393 impl<F, B, const N : usize> Linear<DVector<F>> |
385 where |
| 394 for Div<F, B, N> |
386 B: Discretisation<F>, |
| 395 where |
387 F: Float + nalgebra::RealField, |
| 396 B : Discretisation<F>, |
388 { |
| 397 F : Float + nalgebra::RealField, |
389 } |
| 398 { |
390 |
| 399 } |
391 impl<F, B, const N: usize> BoundedLinear<DVector<F>, L2, L2, F> for Grad<F, B, N> |
| 400 |
392 where |
| 401 impl<F, B, const N : usize> BoundedLinear<DVector<F>, L2, L2, F> |
393 B: Discretisation<F>, |
| 402 for Grad<F, B, N> |
394 F: Float + nalgebra::RealField, |
| 403 where |
395 DVector<F>: Norm<F, L2>, |
| 404 B : Discretisation<F>, |
396 { |
| 405 F : Float + nalgebra::RealField, |
397 fn opnorm_bound(&self, _: L2, _: L2) -> DynResult<F> { |
| 406 DVector<F> : Norm<F, L2>, |
|
| 407 { |
|
| 408 fn opnorm_bound(&self, _ : L2, _ : L2) -> F { |
|
| 409 // Fuck nalgebra. |
398 // Fuck nalgebra. |
| 410 self.discretisation.opnorm_bound(num_traits::Float::abs(self.h)) |
399 self.discretisation |
| 411 } |
400 .opnorm_bound(num_traits::Float::abs(self.h)) |
| 412 } |
401 } |
| 413 |
402 } |
| 414 |
403 |
| 415 impl<F, B, const N : usize> BoundedLinear<DVector<F>, L2, L2, F> |
404 impl<F, B, const N: usize> BoundedLinear<DVector<F>, L2, L2, F> for Div<F, B, N> |
| 416 for Div<F, B, N> |
405 where |
| 417 where |
406 B: Discretisation<F>, |
| 418 B : Discretisation<F>, |
407 F: Float + nalgebra::RealField, |
| 419 F : Float + nalgebra::RealField, |
408 DVector<F>: Norm<F, L2>, |
| 420 DVector<F> : Norm<F, L2>, |
409 { |
| 421 { |
410 fn opnorm_bound(&self, _: L2, _: L2) -> DynResult<F> { |
| 422 fn opnorm_bound(&self, _ : L2, _ : L2) -> F { |
|
| 423 // Fuck nalgebra. |
411 // Fuck nalgebra. |
| 424 self.discretisation.opnorm_bound(num_traits::Float::abs(self.h)) |
412 self.discretisation |
| 425 } |
413 .opnorm_bound(num_traits::Float::abs(self.h)) |
| 426 } |
414 } |
| 427 |
415 } |
| 428 impl<F, B, const N : usize> |
416 |
| 429 Adjointable<DVector<F>, DVector<F>> |
417 impl<F, B, const N: usize> Adjointable<DVector<F>, DVector<F>> for Grad<F, B, N> |
| 430 for Grad<F, B, N> |
418 where |
| 431 where |
419 B: Discretisation<F>, |
| 432 B : Discretisation<F>, |
420 F: Float + nalgebra::RealField, |
| 433 F : Float + nalgebra::RealField, |
|
| 434 { |
421 { |
| 435 type AdjointCodomain = DVector<F>; |
422 type AdjointCodomain = DVector<F>; |
| 436 type Adjoint<'a> = Div<F, B::Opposite, N> where Self : 'a; |
423 type Adjoint<'a> |
| |
424 = Div<F, B::Opposite, N> |
| |
425 where |
| |
426 Self: 'a; |
| 437 |
427 |
| 438 /// Form the adjoint operator of `self`. |
428 /// Form the adjoint operator of `self`. |
| 439 fn adjoint(&self) -> Self::Adjoint<'_> { |
429 fn adjoint(&self) -> Self::Adjoint<'_> { |
| 440 Div { |
430 Div { |
| 441 dims : self.dims, |
431 dims: self.dims, |
| 442 h : -self.h, |
432 h: -self.h, |
| 443 discretisation : self.discretisation.opposite(), |
433 discretisation: self.discretisation.opposite(), |
| 444 } |
434 } |
| 445 } |
435 } |
| 446 } |
436 } |
| 447 |
437 |
| 448 |
438 impl<F, B, const N: usize> Adjointable<DVector<F>, DVector<F>> for Div<F, B, N> |
| 449 impl<F, B, const N : usize> |
439 where |
| 450 Adjointable<DVector<F>, DVector<F>> |
440 B: Discretisation<F>, |
| 451 for Div<F, B, N> |
441 F: Float + nalgebra::RealField, |
| 452 where |
|
| 453 B : Discretisation<F>, |
|
| 454 F : Float + nalgebra::RealField, |
|
| 455 { |
442 { |
| 456 type AdjointCodomain = DVector<F>; |
443 type AdjointCodomain = DVector<F>; |
| 457 type Adjoint<'a> = Grad<F, B::Opposite, N> where Self : 'a; |
444 type Adjoint<'a> |
| |
445 = Grad<F, B::Opposite, N> |
| |
446 where |
| |
447 Self: 'a; |
| 458 |
448 |
| 459 /// Form the adjoint operator of `self`. |
449 /// Form the adjoint operator of `self`. |
| 460 fn adjoint(&self) -> Self::Adjoint<'_> { |
450 fn adjoint(&self) -> Self::Adjoint<'_> { |
| 461 Grad { |
451 Grad { |
| 462 dims : self.dims, |
452 dims: self.dims, |
| 463 h : -self.h, |
453 h: -self.h, |
| 464 discretisation : self.discretisation.opposite(), |
454 discretisation: self.discretisation.opposite(), |
| 465 } |
455 } |
| 466 } |
456 } |
| 467 } |
457 } |
| 468 |
458 |
| 469 #[cfg(test)] |
459 #[cfg(test)] |
| 470 mod tests { |
460 mod tests { |
| 471 use super::*; |
461 use super::*; |
| 472 |
462 |
| 473 #[test] |
463 #[test] |
| 474 fn grad_adjoint() { |
464 fn grad_adjoint() { |
| 475 let im = DVector::from( (0..9).map(|t| t as f64).collect::<Vec<_>>()); |
465 let im = DVector::from((0..9).map(|t| t as f64).collect::<Vec<_>>()); |
| 476 let v = DVector::from( (0..18).map(|t| t as f64).collect::<Vec<_>>()); |
466 let v = DVector::from((0..18).map(|t| t as f64).collect::<Vec<_>>()); |
| 477 |
467 |
| 478 let grad = Grad::new_for(&im, 1.0, [3, 3], ForwardNeumann).unwrap(); |
468 let grad = Grad::new_for(&im, 1.0, [3, 3], ForwardNeumann).unwrap(); |
| 479 let a = grad.apply(&im).dot(&v); |
469 let a = grad.apply(&im).dot(&v); |
| 480 let b = grad.adjoint().apply(&v).dot(&im); |
470 let b = grad.adjoint().apply(&v).dot(&im); |
| 481 assert_eq!(a, b); |
471 assert_eq!(a, b); |
| 482 |
472 |
| 483 let grad = Grad::new_for(&im, 1.0, [3, 3], ForwardDirichlet).unwrap(); |
473 let grad = Grad::new_for(&im, 1.0, [3, 3], ForwardDirichlet).unwrap(); |
| 484 let a = grad.apply(&im).dot(&v); |
474 let a = grad.apply(&im).dot(&v); |
| 485 let b = grad.adjoint().apply(&v).dot(&im); |
475 let b = grad.adjoint().apply(&v).dot(&im); |
| 486 assert_eq!(a, b); |
476 assert_eq!(a, b); |
| 487 |
477 } |
| 488 } |
478 } |
| 489 } |
|