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