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