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