|
1 /*! |
|
2 Forward models from discrete measures to observations. |
|
3 */ |
|
4 |
|
5 use numeric_literals::replace_float_literals; |
|
6 use nalgebra::base::{ |
|
7 DMatrix, |
|
8 DVector |
|
9 }; |
|
10 use std::iter::Zip; |
|
11 use std::ops::RangeFrom; |
|
12 use std::marker::PhantomData; |
|
13 |
|
14 pub use alg_tools::linops::*; |
|
15 use alg_tools::euclidean::Euclidean; |
|
16 use alg_tools::norms::{ |
|
17 L1, Linfinity, Norm |
|
18 }; |
|
19 use alg_tools::bisection_tree::*; |
|
20 use alg_tools::mapping::RealMapping; |
|
21 use alg_tools::lingrid::*; |
|
22 use alg_tools::iter::{MapX, Mappable}; |
|
23 use alg_tools::nalgebra_support::ToNalgebraRealField; |
|
24 use alg_tools::tabledump::write_csv; |
|
25 use alg_tools::error::DynError; |
|
26 |
|
27 use crate::types::*; |
|
28 use crate::measures::*; |
|
29 use crate::seminorms::{ |
|
30 Lipschitz, |
|
31 ConvolutionOp, |
|
32 SimpleConvolutionKernel, |
|
33 }; |
|
34 use crate::kernels::{ |
|
35 Convolution, |
|
36 AutoConvolution, |
|
37 BoundedBy, |
|
38 }; |
|
39 |
|
40 pub type RNDM<F, const N : usize> = DiscreteMeasure<Loc<F,N>, F>; |
|
41 |
|
42 /// `ForwardeModel`s are bounded preadjointable linear operators $A ∈ 𝕃(𝒵(Ω); E)$ |
|
43 /// where $𝒵(Ω) ⊂ ℳ(Ω)$ is the space of sums of delta measures, presented by |
|
44 /// [`DiscreteMeasure`], and $E$ is a [`Euclidean`] space. |
|
45 pub trait ForwardModel<Domain, F : Float + ToNalgebraRealField> |
|
46 : BoundedLinear<DiscreteMeasure<Domain, F>, Codomain=Self::Observable, FloatType=F> |
|
47 + GEMV<F, DiscreteMeasure<Domain, F>, Self::Observable> |
|
48 + Linear<DeltaMeasure<Domain, F>, Codomain=Self::Observable> |
|
49 + Preadjointable<DiscreteMeasure<Domain, F>, Self::Observable> { |
|
50 /// The codomain or value space (of “observables”) for this operator. |
|
51 /// It is assumed to be a [`Euclidean`] space, and therefore also (identified with) |
|
52 /// the domain of the preadjoint. |
|
53 type Observable : Euclidean<F, Output=Self::Observable> |
|
54 + AXPY<F> |
|
55 + Clone; |
|
56 |
|
57 /// Return A_*A and A_* b |
|
58 fn findim_quadratic_model( |
|
59 &self, |
|
60 μ : &DiscreteMeasure<Domain, F>, |
|
61 b : &Self::Observable |
|
62 ) -> (DMatrix<F::MixedType>, DVector<F::MixedType>); |
|
63 |
|
64 /// Write an observable into a file. |
|
65 fn write_observable(&self, b : &Self::Observable, prefix : String) -> DynError; |
|
66 |
|
67 /// Returns a zero observable |
|
68 fn zero_observable(&self) -> Self::Observable; |
|
69 |
|
70 /// Returns an empty (uninitialised) observable. |
|
71 /// |
|
72 /// This is used as a placeholder for temporary [`std::mem::replace`] move operations. |
|
73 fn empty_observable(&self) -> Self::Observable; |
|
74 } |
|
75 |
|
76 pub type ShiftedSensor<F, S, P, const N : usize> = Shift<Convolution<S, P>, F, N>; |
|
77 |
|
78 /// Trait for physical convolution models. Has blanket implementation for all cases. |
|
79 pub trait Spread<F : Float, const N : usize> |
|
80 : 'static + Clone + Support<F, N> + RealMapping<F, N> + Bounded<F> {} |
|
81 |
|
82 impl<F, T, const N : usize> Spread<F, N> for T |
|
83 where F : Float, |
|
84 T : 'static + Clone + Support<F, N> + Bounded<F> + RealMapping<F, N> {} |
|
85 |
|
86 /// Trait for compactly supported sensors. Has blanket implementation for all cases. |
|
87 pub trait Sensor<F : Float, const N : usize> : Spread<F, N> + Norm<F, L1> + Norm<F, Linfinity> {} |
|
88 |
|
89 impl<F, T, const N : usize> Sensor<F, N> for T |
|
90 where F : Float, |
|
91 T : Spread<F, N> + Norm<F, L1> + Norm<F, Linfinity> {} |
|
92 |
|
93 |
|
94 pub trait SensorGridBT<F, S, P, const N : usize> : |
|
95 Clone + BTImpl<F, N, Data=usize, Agg=Bounds<F>> |
|
96 where F : Float, |
|
97 S : Sensor<F, N>, |
|
98 P : Spread<F, N> {} |
|
99 |
|
100 impl<F, S, P, T, const N : usize> |
|
101 SensorGridBT<F, S, P, N> |
|
102 for T |
|
103 where T : Clone + BTImpl<F, N, Data=usize, Agg=Bounds<F>>, |
|
104 F : Float, |
|
105 S : Sensor<F, N>, |
|
106 P : Spread<F, N> {} |
|
107 |
|
108 // We need type alias bounds to access associated types |
|
109 #[allow(type_alias_bounds)] |
|
110 type SensorGridBTFN<F, S, P, BT : SensorGridBT<F, S, P, N>, const N : usize> |
|
111 = BTFN<F, SensorGridSupportGenerator<F, S, P, N>, BT, N>; |
|
112 |
|
113 /// Sensor grid forward model |
|
114 #[derive(Clone)] |
|
115 pub struct SensorGrid<F, S, P, BT, const N : usize> |
|
116 where F : Float, |
|
117 S : Sensor<F, N>, |
|
118 P : Spread<F, N>, |
|
119 Convolution<S, P> : Spread<F, N>, |
|
120 BT : SensorGridBT<F, S, P, N>, { |
|
121 domain : Cube<F, N>, |
|
122 sensor_count : [usize; N], |
|
123 sensor : S, |
|
124 spread : P, |
|
125 base_sensor : Convolution<S, P>, |
|
126 bt : BT, |
|
127 } |
|
128 |
|
129 impl<F, S, P, BT, const N : usize> SensorGrid<F, S, P, BT, N> |
|
130 where F : Float, |
|
131 BT : SensorGridBT<F, S, P, N>, |
|
132 S : Sensor<F, N>, |
|
133 P : Spread<F, N>, |
|
134 Convolution<S, P> : Spread<F, N>, |
|
135 ShiftedSensor<F, S, P, N> : LocalAnalysis<F, BT::Agg, N> { |
|
136 |
|
137 pub fn new( |
|
138 domain : Cube<F, N>, |
|
139 sensor_count : [usize; N], |
|
140 sensor : S, |
|
141 spread : P, |
|
142 depth : BT::Depth |
|
143 ) -> Self { |
|
144 let base_sensor = Convolution(sensor.clone(), spread.clone()); |
|
145 let bt = BT::new(domain, depth); |
|
146 let mut sensorgrid = SensorGrid { |
|
147 domain, |
|
148 sensor_count, |
|
149 sensor, |
|
150 spread, |
|
151 base_sensor, |
|
152 bt, |
|
153 }; |
|
154 |
|
155 for (x, id) in sensorgrid.grid().into_iter().zip(0usize..) { |
|
156 let s = sensorgrid.shifted_sensor(x); |
|
157 sensorgrid.bt.insert(id, &s); |
|
158 } |
|
159 |
|
160 sensorgrid |
|
161 } |
|
162 |
|
163 pub fn grid(&self) -> LinGrid<F, N> { |
|
164 lingrid_centered(&self.domain, &self.sensor_count) |
|
165 } |
|
166 |
|
167 pub fn n_sensors(&self) -> usize { |
|
168 self.sensor_count.iter().product() |
|
169 } |
|
170 |
|
171 #[inline] |
|
172 fn shifted_sensor(&self, x : Loc<F, N>) -> ShiftedSensor<F, S, P, N> { |
|
173 self.base_sensor.clone().shift(x) |
|
174 } |
|
175 |
|
176 #[inline] |
|
177 fn _zero_observable(&self) -> DVector<F> { |
|
178 DVector::zeros(self.n_sensors()) |
|
179 } |
|
180 } |
|
181 |
|
182 impl<F, S, P, BT, const N : usize> Apply<RNDM<F, N>> for SensorGrid<F, S, P, BT, N> |
|
183 where F : Float, |
|
184 BT : SensorGridBT<F, S, P, N>, |
|
185 S : Sensor<F, N>, |
|
186 P : Spread<F, N>, |
|
187 Convolution<S, P> : Spread<F, N>, |
|
188 ShiftedSensor<F, S, P, N> : LocalAnalysis<F, BT::Agg, N> { |
|
189 |
|
190 type Output = DVector<F>; |
|
191 |
|
192 #[inline] |
|
193 fn apply(&self, μ : RNDM<F, N>) -> DVector<F> { |
|
194 self.apply(&μ) |
|
195 } |
|
196 } |
|
197 |
|
198 impl<'a, F, S, P, BT, const N : usize> Apply<&'a RNDM<F, N>> for SensorGrid<F, S, P, BT, N> |
|
199 where F : Float, |
|
200 BT : SensorGridBT<F, S, P, N>, |
|
201 S : Sensor<F, N>, |
|
202 P : Spread<F, N>, |
|
203 Convolution<S, P> : Spread<F, N>, |
|
204 ShiftedSensor<F, S, P, N> : LocalAnalysis<F, BT::Agg, N> { |
|
205 |
|
206 type Output = DVector<F>; |
|
207 |
|
208 fn apply(&self, μ : &'a RNDM<F, N>) -> DVector<F> { |
|
209 let mut res = self._zero_observable(); |
|
210 self.apply_add(&mut res, μ); |
|
211 res |
|
212 } |
|
213 } |
|
214 |
|
215 impl<F, S, P, BT, const N : usize> Linear<RNDM<F, N>> for SensorGrid<F, S, P, BT, N> |
|
216 where F : Float, |
|
217 BT : SensorGridBT<F, S, P, N>, |
|
218 S : Sensor<F, N>, |
|
219 P : Spread<F, N>, |
|
220 Convolution<S, P> : Spread<F, N>, |
|
221 ShiftedSensor<F, S, P, N> : LocalAnalysis<F, BT::Agg, N> { |
|
222 type Codomain = DVector<F>; |
|
223 } |
|
224 |
|
225 |
|
226 #[replace_float_literals(F::cast_from(literal))] |
|
227 impl<F, S, P, BT, const N : usize> GEMV<F, RNDM<F, N>, DVector<F>> for SensorGrid<F, S, P, BT, N> |
|
228 where F : Float, |
|
229 BT : SensorGridBT<F, S, P, N>, |
|
230 S : Sensor<F, N>, |
|
231 P : Spread<F, N>, |
|
232 Convolution<S, P> : Spread<F, N>, |
|
233 ShiftedSensor<F, S, P, N> : LocalAnalysis<F, BT::Agg, N> { |
|
234 |
|
235 fn gemv(&self, y : &mut DVector<F>, α : F, μ : &RNDM<F, N>, β : F) { |
|
236 let grid = self.grid(); |
|
237 if β == 0.0 { |
|
238 y.fill(0.0) |
|
239 } else if β != 1.0 { |
|
240 *y *= β; // Need to multiply first, as we have to be able to add to y. |
|
241 } |
|
242 if α == 1.0 { |
|
243 self.apply_add(y, μ) |
|
244 } else { |
|
245 for δ in μ.iter_spikes() { |
|
246 for &d in self.bt.iter_at(&δ.x) { |
|
247 let sensor = self.shifted_sensor(grid.entry_linear_unchecked(d)); |
|
248 y[d] += sensor.apply(&δ.x) * (α * δ.α); |
|
249 } |
|
250 } |
|
251 } |
|
252 } |
|
253 |
|
254 fn apply_add(&self, y : &mut DVector<F>, μ : &RNDM<F, N>) { |
|
255 let grid = self.grid(); |
|
256 for δ in μ.iter_spikes() { |
|
257 for &d in self.bt.iter_at(&δ.x) { |
|
258 let sensor = self.shifted_sensor(grid.entry_linear_unchecked(d)); |
|
259 y[d] += sensor.apply(&δ.x) * δ.α; |
|
260 } |
|
261 } |
|
262 } |
|
263 |
|
264 } |
|
265 |
|
266 impl<F, S, P, BT, const N : usize> Apply<DeltaMeasure<Loc<F, N>, F>> |
|
267 for SensorGrid<F, S, P, BT, N> |
|
268 where F : Float, |
|
269 BT : SensorGridBT<F, S, P, N>, |
|
270 S : Sensor<F, N>, |
|
271 P : Spread<F, N>, |
|
272 Convolution<S, P> : Spread<F, N>, |
|
273 ShiftedSensor<F, S, P, N> : LocalAnalysis<F, BT::Agg, N> { |
|
274 |
|
275 type Output = DVector<F>; |
|
276 |
|
277 #[inline] |
|
278 fn apply(&self, δ : DeltaMeasure<Loc<F, N>, F>) -> DVector<F> { |
|
279 self.apply(&δ) |
|
280 } |
|
281 } |
|
282 |
|
283 impl<'a, F, S, P, BT, const N : usize> Apply<&'a DeltaMeasure<Loc<F, N>, F>> |
|
284 for SensorGrid<F, S, P, BT, N> |
|
285 where F : Float, |
|
286 BT : SensorGridBT<F, S, P, N>, |
|
287 S : Sensor<F, N>, |
|
288 P : Spread<F, N>, |
|
289 Convolution<S, P> : Spread<F, N>, |
|
290 ShiftedSensor<F, S, P, N> : LocalAnalysis<F, BT::Agg, N> { |
|
291 |
|
292 type Output = DVector<F>; |
|
293 |
|
294 fn apply(&self, δ : &DeltaMeasure<Loc<F, N>, F>) -> DVector<F> { |
|
295 let mut res = DVector::zeros(self.n_sensors()); |
|
296 let grid = self.grid(); |
|
297 for &d in self.bt.iter_at(&δ.x) { |
|
298 let sensor = self.shifted_sensor(grid.entry_linear_unchecked(d)); |
|
299 res[d] += sensor.apply(&δ.x) * δ.α; |
|
300 } |
|
301 res |
|
302 } |
|
303 } |
|
304 |
|
305 impl<F, S, P, BT, const N : usize> Linear<DeltaMeasure<Loc<F, N>, F>> for SensorGrid<F, S, P, BT, N> |
|
306 where F : Float, |
|
307 BT : SensorGridBT<F, S, P, N>, |
|
308 S : Sensor<F, N>, |
|
309 P : Spread<F, N>, |
|
310 Convolution<S, P> : Spread<F, N>, |
|
311 ShiftedSensor<F, S, P, N> : LocalAnalysis<F, BT::Agg, N> { |
|
312 type Codomain = DVector<F>; |
|
313 } |
|
314 |
|
315 impl<F, S, P, BT, const N : usize> BoundedLinear<RNDM<F, N>> for SensorGrid<F, S, P, BT, N> |
|
316 where F : Float, |
|
317 BT : SensorGridBT<F, S, P, N, Agg=Bounds<F>>, |
|
318 S : Sensor<F, N>, |
|
319 P : Spread<F, N>, |
|
320 Convolution<S, P> : Spread<F, N>, |
|
321 ShiftedSensor<F, S, P, N> : LocalAnalysis<F, BT::Agg, N> { |
|
322 type FloatType = F; |
|
323 |
|
324 /// An estimate on the operator norm in $𝕃(ℳ(Ω); ℝ^n)$ with $ℳ(Ω)$ equipped |
|
325 /// with the Radon norm, and $ℝ^n$ with the Euclidean norm. |
|
326 fn opnorm_bound(&self) -> F { |
|
327 // With {x_i}_{i=1}^n the grid centres and φ the kernel, we have |
|
328 // |Aμ|_2 = sup_{|z|_2 ≤ 1} ⟨z,Αμ⟩ = sup_{|z|_2 ≤ 1} ⟨A^*z|μ⟩ |
|
329 // ≤ sup_{|z|_2 ≤ 1} |A^*z|_∞ |μ|_ℳ |
|
330 // = sup_{|z|_2 ≤ 1} |∑ φ(· - x_i)z_i|_∞ |μ|_ℳ |
|
331 // ≤ sup_{|z|_2 ≤ 1} |φ|_∞ ∑ |z_i| |μ|_ℳ |
|
332 // ≤ sup_{|z|_2 ≤ 1} |φ|_∞ √n |z|_2 |μ|_ℳ |
|
333 // = |φ|_∞ √n |μ|_ℳ. |
|
334 // Hence |
|
335 let n = F::cast_from(self.n_sensors()); |
|
336 self.base_sensor.bounds().uniform() * n.sqrt() |
|
337 } |
|
338 } |
|
339 |
|
340 type SensorGridPreadjoint<'a, A, F, const N : usize> = PreadjointHelper<'a, A, RNDM<F,N>>; |
|
341 |
|
342 |
|
343 impl<F, S, P, BT, const N : usize> |
|
344 Preadjointable<RNDM<F, N>, DVector<F>> |
|
345 for SensorGrid<F, S, P, BT, N> |
|
346 where F : Float, |
|
347 BT : SensorGridBT<F, S, P, N>, |
|
348 S : Sensor<F, N>, |
|
349 P : Spread<F, N>, |
|
350 Convolution<S, P> : Spread<F, N>, |
|
351 ShiftedSensor<F, S, P, N> : LocalAnalysis<F, BT::Agg, N>, |
|
352 Weighted<ShiftedSensor<F, S, P, N>, F> : LocalAnalysis<F, BT::Agg, N> { |
|
353 type PreadjointCodomain = BTFN<F, SensorGridSupportGenerator<F, S, P, N>, BT, N>; |
|
354 type Preadjoint<'a> = SensorGridPreadjoint<'a, Self, F, N> where Self : 'a; |
|
355 |
|
356 fn preadjoint(&self) -> Self::Preadjoint<'_> { |
|
357 PreadjointHelper::new(self) |
|
358 } |
|
359 } |
|
360 |
|
361 #[derive(Clone,Debug)] |
|
362 pub struct SensorGridSupportGenerator<F, S, P, const N : usize> |
|
363 where F : Float, |
|
364 S : Sensor<F, N>, |
|
365 P : Spread<F, N> { |
|
366 base_sensor : Convolution<S, P>, |
|
367 grid : LinGrid<F, N>, |
|
368 weights : DVector<F> |
|
369 } |
|
370 |
|
371 impl<F, S, P, const N : usize> SensorGridSupportGenerator<F, S, P, N> |
|
372 where F : Float, |
|
373 S : Sensor<F, N>, |
|
374 P : Spread<F, N>, |
|
375 Convolution<S, P> : Spread<F, N> { |
|
376 |
|
377 #[inline] |
|
378 fn construct_sensor(&self, id : usize, w : F) -> Weighted<ShiftedSensor<F, S, P, N>, F> { |
|
379 let x = self.grid.entry_linear_unchecked(id); |
|
380 self.base_sensor.clone().shift(x).weigh(w) |
|
381 } |
|
382 |
|
383 #[inline] |
|
384 fn construct_sensor_and_id<'a>(&'a self, (id, w) : (usize, &'a F)) |
|
385 -> (usize, Weighted<ShiftedSensor<F, S, P, N>, F>) { |
|
386 (id.into(), self.construct_sensor(id, *w)) |
|
387 } |
|
388 } |
|
389 |
|
390 impl<F, S, P, const N : usize> SupportGenerator<F, N> |
|
391 for SensorGridSupportGenerator<F, S, P, N> |
|
392 where F : Float, |
|
393 S : Sensor<F, N>, |
|
394 P : Spread<F, N>, |
|
395 Convolution<S, P> : Spread<F, N> { |
|
396 type Id = usize; |
|
397 type SupportType = Weighted<ShiftedSensor<F, S, P, N>, F>; |
|
398 type AllDataIter<'a> = MapX<'a, Zip<RangeFrom<usize>, |
|
399 std::slice::Iter<'a, F>>, |
|
400 Self, |
|
401 (Self::Id, Self::SupportType)> |
|
402 where Self : 'a; |
|
403 |
|
404 #[inline] |
|
405 fn support_for(&self, d : Self::Id) -> Self::SupportType { |
|
406 self.construct_sensor(d, self.weights[d]) |
|
407 } |
|
408 |
|
409 #[inline] |
|
410 fn support_count(&self) -> usize { |
|
411 self.weights.len() |
|
412 } |
|
413 |
|
414 #[inline] |
|
415 fn all_data(&self) -> Self::AllDataIter<'_> { |
|
416 (0..).zip(self.weights.as_slice().iter()).mapX(self, Self::construct_sensor_and_id) |
|
417 } |
|
418 } |
|
419 |
|
420 /// Helper structure for constructing preadjoints of `S` where `S : Linear<X>`. |
|
421 /// [`Linear`] needs to be implemented for each instance, but [`Adjointable`] |
|
422 /// and [`BoundedLinear`] have blanket implementations. |
|
423 #[derive(Clone,Debug)] |
|
424 pub struct PreadjointHelper<'a, S : 'a, X> { |
|
425 forward_op : &'a S, |
|
426 _domain : PhantomData<X> |
|
427 } |
|
428 |
|
429 impl<'a, S : 'a, X> PreadjointHelper<'a, S, X> { |
|
430 pub fn new(forward_op : &'a S) -> Self { |
|
431 PreadjointHelper { forward_op, _domain: PhantomData } |
|
432 } |
|
433 } |
|
434 |
|
435 impl<'a, X, Ypre, S> Adjointable<Ypre, X> |
|
436 for PreadjointHelper<'a, S, X> |
|
437 where Self : Linear<Ypre>, |
|
438 S : Clone + Linear<X> { |
|
439 type AdjointCodomain = S::Codomain; |
|
440 type Adjoint<'b> = S where Self : 'b; |
|
441 fn adjoint(&self) -> Self::Adjoint<'_> { |
|
442 self.forward_op.clone() |
|
443 } |
|
444 } |
|
445 |
|
446 impl<'a, X, Ypre, S> BoundedLinear<Ypre> |
|
447 for PreadjointHelper<'a, S, X> |
|
448 where Self : Linear<Ypre>, |
|
449 S : 'a + Clone + BoundedLinear<X> { |
|
450 type FloatType = S::FloatType; |
|
451 fn opnorm_bound(&self) -> Self::FloatType { |
|
452 self.forward_op.opnorm_bound() |
|
453 } |
|
454 } |
|
455 |
|
456 |
|
457 impl<'a, 'b, F, S, P, BT, const N : usize> Apply<&'b DVector<F>> |
|
458 for PreadjointHelper<'a, SensorGrid<F, S, P, BT, N>, RNDM<F,N>> |
|
459 where F : Float, |
|
460 BT : SensorGridBT<F, S, P, N>, |
|
461 S : Sensor<F, N>, |
|
462 P : Spread<F, N>, |
|
463 Convolution<S, P> : Spread<F, N>, |
|
464 ShiftedSensor<F, S, P, N> : LocalAnalysis<F, BT::Agg, N>, |
|
465 Weighted<ShiftedSensor<F, S, P, N>, F> : LocalAnalysis<F, BT::Agg, N> { |
|
466 |
|
467 type Output = SensorGridBTFN<F, S, P, BT, N>; |
|
468 |
|
469 fn apply(&self, x : &'b DVector<F>) -> Self::Output { |
|
470 self.apply(x.clone()) |
|
471 } |
|
472 } |
|
473 |
|
474 impl<'a, F, S, P, BT, const N : usize> Apply<DVector<F>> |
|
475 for PreadjointHelper<'a, SensorGrid<F, S, P, BT, N>, RNDM<F,N>> |
|
476 where F : Float, |
|
477 BT : SensorGridBT<F, S, P, N>, |
|
478 S : Sensor<F, N>, |
|
479 P : Spread<F, N>, |
|
480 Convolution<S, P> : Spread<F, N>, |
|
481 ShiftedSensor<F, S, P, N> : LocalAnalysis<F, BT::Agg, N>, |
|
482 Weighted<ShiftedSensor<F, S, P, N>, F> : LocalAnalysis<F, BT::Agg, N> { |
|
483 |
|
484 type Output = SensorGridBTFN<F, S, P, BT, N>; |
|
485 |
|
486 fn apply(&self, x : DVector<F>) -> Self::Output { |
|
487 let fwd = &self.forward_op; |
|
488 let generator = SensorGridSupportGenerator{ |
|
489 base_sensor : fwd.base_sensor.clone(), |
|
490 grid : fwd.grid(), |
|
491 weights : x |
|
492 }; |
|
493 BTFN::new_refresh(&fwd.bt, generator) |
|
494 } |
|
495 } |
|
496 |
|
497 impl<'a, F, S, P, BT, const N : usize> Linear<DVector<F>> |
|
498 for PreadjointHelper<'a, SensorGrid<F, S, P, BT, N>, RNDM<F,N>> |
|
499 where F : Float, |
|
500 BT : SensorGridBT<F, S, P, N>, |
|
501 S : Sensor<F, N>, |
|
502 P : Spread<F, N>, |
|
503 Convolution<S, P> : Spread<F, N>, |
|
504 ShiftedSensor<F, S, P, N> : LocalAnalysis<F, BT::Agg, N>, |
|
505 Weighted<ShiftedSensor<F, S, P, N>, F> : LocalAnalysis<F, BT::Agg, N> { |
|
506 |
|
507 type Codomain = SensorGridBTFN<F, S, P, BT, N>; |
|
508 } |
|
509 |
|
510 impl<F, S, P, BT, const N : usize> ForwardModel<Loc<F, N>, F> |
|
511 for SensorGrid<F, S, P, BT, N> |
|
512 where F : Float + ToNalgebraRealField<MixedType=F> + nalgebra::RealField, |
|
513 BT : SensorGridBT<F, S, P, N>, |
|
514 S : Sensor<F, N>, |
|
515 P : Spread<F, N>, |
|
516 Convolution<S, P> : Spread<F, N>, |
|
517 ShiftedSensor<F, S, P, N> : LocalAnalysis<F, BT::Agg, N>, |
|
518 Weighted<ShiftedSensor<F, S, P, N>, F> : LocalAnalysis<F, BT::Agg, N> { |
|
519 type Observable = DVector<F>; |
|
520 |
|
521 fn findim_quadratic_model( |
|
522 &self, |
|
523 μ : &DiscreteMeasure<Loc<F, N>, F>, |
|
524 b : &Self::Observable |
|
525 ) -> (DMatrix<F::MixedType>, DVector<F::MixedType>) { |
|
526 assert_eq!(b.len(), self.n_sensors()); |
|
527 let mut mA = DMatrix::zeros(self.n_sensors(), μ.len()); |
|
528 let grid = self.grid(); |
|
529 for (mut mAcol, δ) in mA.column_iter_mut().zip(μ.iter_spikes()) { |
|
530 for &d in self.bt.iter_at(&δ.x) { |
|
531 let sensor = self.shifted_sensor(grid.entry_linear_unchecked(d)); |
|
532 mAcol[d] += sensor.apply(&δ.x); |
|
533 } |
|
534 } |
|
535 let mAt = mA.transpose(); |
|
536 (&mAt * mA, &mAt * b) |
|
537 } |
|
538 |
|
539 fn write_observable(&self, b : &Self::Observable, prefix : String) -> DynError { |
|
540 let it = self.grid().into_iter().zip(b.iter()).map(|(x, &v)| (x, v)); |
|
541 write_csv(it, prefix + ".txt") |
|
542 } |
|
543 |
|
544 #[inline] |
|
545 fn zero_observable(&self) -> Self::Observable { |
|
546 self._zero_observable() |
|
547 } |
|
548 |
|
549 #[inline] |
|
550 fn empty_observable(&self) -> Self::Observable { |
|
551 DVector::zeros(0) |
|
552 } |
|
553 |
|
554 } |
|
555 |
|
556 /// Implements the calculation a factor $L$ such that $A_*A ≤ L 𝒟$ for $A$ the forward model |
|
557 /// and $𝒟$ a seminorm of suitable form. |
|
558 /// |
|
559 /// **This assumes (but does not check) that the sensors are not overlapping.** |
|
560 #[replace_float_literals(F::cast_from(literal))] |
|
561 impl<F, BT, S, P, K, const N : usize> Lipschitz<ConvolutionOp<F, K, BT, N>> |
|
562 for SensorGrid<F, S, P, BT, N> |
|
563 where F : Float + nalgebra::RealField + ToNalgebraRealField, |
|
564 BT : SensorGridBT<F, S, P, N>, |
|
565 S : Sensor<F, N>, |
|
566 P : Spread<F, N>, |
|
567 Convolution<S, P> : Spread<F, N>, |
|
568 K : SimpleConvolutionKernel<F, N>, |
|
569 AutoConvolution<P> : BoundedBy<F, K> { |
|
570 |
|
571 type FloatType = F; |
|
572 |
|
573 fn lipschitz_factor(&self, seminorm : &ConvolutionOp<F, K, BT, N>) -> Option<F> { |
|
574 // Sensors should not take on negative values to allow |
|
575 // A_*A to be upper bounded by a simple convolution of `spread`. |
|
576 if self.sensor.bounds().lower() < 0.0 { |
|
577 return None |
|
578 } |
|
579 |
|
580 // Calculate the factor $L_1$ for betwee $ℱ[ψ * ψ] ≤ L_1 ℱ[ρ]$ for $ψ$ the base spread |
|
581 // and $ρ$ the kernel of the seminorm. |
|
582 let l1 = AutoConvolution(self.spread.clone()).bounding_factor(seminorm.kernel())?; |
|
583 |
|
584 // Calculate the factor for transitioning from $A_*A$ to `AutoConvolution<P>`, where A |
|
585 // consists of several `Convolution<S, P>` for the physical model `P` and the sensor `S`. |
|
586 let l0 = self.sensor.norm(Linfinity) * self.sensor.norm(L1); |
|
587 |
|
588 // The final transition factor is: |
|
589 Some(l0 * l1) |
|
590 } |
|
591 } |
|
592 |
|
593 macro_rules! make_sensorgridsupportgenerator_scalarop_rhs { |
|
594 ($trait:ident, $fn:ident, $trait_assign:ident, $fn_assign:ident) => { |
|
595 impl<F, S, P, const N : usize> |
|
596 std::ops::$trait_assign<F> |
|
597 for SensorGridSupportGenerator<F, S, P, N> |
|
598 where F : Float, |
|
599 S : Sensor<F, N>, |
|
600 P : Spread<F, N>, |
|
601 Convolution<S, P> : Spread<F, N> { |
|
602 fn $fn_assign(&mut self, t : F) { |
|
603 self.weights.$fn_assign(t); |
|
604 } |
|
605 } |
|
606 |
|
607 impl<F, S, P, const N : usize> |
|
608 std::ops::$trait<F> |
|
609 for SensorGridSupportGenerator<F, S, P, N> |
|
610 where F : Float, |
|
611 S : Sensor<F, N>, |
|
612 P : Spread<F, N>, |
|
613 Convolution<S, P> : Spread<F, N> { |
|
614 type Output = SensorGridSupportGenerator<F, S, P, N>; |
|
615 fn $fn(mut self, t : F) -> Self::Output { |
|
616 std::ops::$trait_assign::$fn_assign(&mut self.weights, t); |
|
617 self |
|
618 } |
|
619 } |
|
620 |
|
621 impl<'a, F, S, P, const N : usize> |
|
622 std::ops::$trait<F> |
|
623 for &'a SensorGridSupportGenerator<F, S, P, N> |
|
624 where F : Float, |
|
625 S : Sensor<F, N>, |
|
626 P : Spread<F, N>, |
|
627 Convolution<S, P> : Spread<F, N> { |
|
628 type Output = SensorGridSupportGenerator<F, S, P, N>; |
|
629 fn $fn(self, t : F) -> Self::Output { |
|
630 SensorGridSupportGenerator{ |
|
631 base_sensor : self.base_sensor.clone(), |
|
632 grid : self.grid, |
|
633 weights : (&self.weights).$fn(t) |
|
634 } |
|
635 } |
|
636 } |
|
637 } |
|
638 } |
|
639 |
|
640 make_sensorgridsupportgenerator_scalarop_rhs!(Mul, mul, MulAssign, mul_assign); |
|
641 make_sensorgridsupportgenerator_scalarop_rhs!(Div, div, DivAssign, div_assign); |
|
642 |
|
643 macro_rules! make_sensorgridsupportgenerator_unaryop { |
|
644 ($trait:ident, $fn:ident) => { |
|
645 impl<F, S, P, const N : usize> |
|
646 std::ops::$trait |
|
647 for SensorGridSupportGenerator<F, S, P, N> |
|
648 where F : Float, |
|
649 S : Sensor<F, N>, |
|
650 P : Spread<F, N>, |
|
651 Convolution<S, P> : Spread<F, N> { |
|
652 type Output = SensorGridSupportGenerator<F, S, P, N>; |
|
653 fn $fn(mut self) -> Self::Output { |
|
654 self.weights = self.weights.$fn(); |
|
655 self |
|
656 } |
|
657 } |
|
658 |
|
659 impl<'a, F, S, P, const N : usize> |
|
660 std::ops::$trait |
|
661 for &'a SensorGridSupportGenerator<F, S, P, N> |
|
662 where F : Float, |
|
663 S : Sensor<F, N>, |
|
664 P : Spread<F, N>, |
|
665 Convolution<S, P> : Spread<F, N> { |
|
666 type Output = SensorGridSupportGenerator<F, S, P, N>; |
|
667 fn $fn(self) -> Self::Output { |
|
668 SensorGridSupportGenerator{ |
|
669 base_sensor : self.base_sensor.clone(), |
|
670 grid : self.grid, |
|
671 weights : (&self.weights).$fn() |
|
672 } |
|
673 } |
|
674 } |
|
675 } |
|
676 } |
|
677 |
|
678 make_sensorgridsupportgenerator_unaryop!(Neg, neg); |