| 1 /*! |
1 /*! |
| 2 Sensor grid forward model |
2 Sensor grid forward model |
| 3 */ |
3 */ |
| 4 |
4 |
| 5 use nalgebra::base::{DMatrix, DVector}; |
5 use super::{BasicCurvatureBoundEstimates, ForwardModel}; |
| 6 use numeric_literals::replace_float_literals; |
6 use crate::frank_wolfe::FindimQuadraticModel; |
| 7 use std::iter::Zip; |
7 use crate::kernels::{AutoConvolution, BoundedBy, Convolution}; |
| 8 use std::ops::RangeFrom; |
8 use crate::measures::{DiscreteMeasure, Radon, RNDM}; |
| 9 |
9 use crate::preadjoint_helper::PreadjointHelper; |
| |
10 use crate::seminorms::{ConvolutionOp, SimpleConvolutionKernel}; |
| |
11 use crate::types::*; |
| 10 use alg_tools::bisection_tree::*; |
12 use alg_tools::bisection_tree::*; |
| 11 use alg_tools::error::DynError; |
13 use alg_tools::bounds::Bounded; |
| |
14 use alg_tools::error::{DynError, DynResult}; |
| |
15 use alg_tools::euclidean::Euclidean; |
| 12 use alg_tools::instance::Instance; |
16 use alg_tools::instance::Instance; |
| 13 use alg_tools::iter::{MapX, Mappable}; |
17 use alg_tools::iter::{MapX, Mappable}; |
| 14 use alg_tools::lingrid::*; |
18 use alg_tools::lingrid::*; |
| 15 pub use alg_tools::linops::*; |
19 pub use alg_tools::linops::*; |
| 16 use alg_tools::mapping::{DifferentiableMapping, RealMapping}; |
20 use alg_tools::mapping::{DifferentiableMapping, RealMapping}; |
| 17 use alg_tools::maputil::map2; |
21 use alg_tools::maputil::map2; |
| 18 use alg_tools::nalgebra_support::ToNalgebraRealField; |
22 use alg_tools::nalgebra_support::ToNalgebraRealField; |
| 19 use alg_tools::norms::{Linfinity, Norm, L1, L2}; |
23 use alg_tools::norms::{Linfinity, Norm, L1, L2}; |
| 20 use alg_tools::tabledump::write_csv; |
24 use alg_tools::tabledump::write_csv; |
| 21 |
25 use anyhow::anyhow; |
| 22 use super::{AdjointProductBoundedBy, BoundedCurvature, ForwardModel}; |
26 use nalgebra::base::{DMatrix, DVector}; |
| 23 use crate::frank_wolfe::FindimQuadraticModel; |
27 use numeric_literals::replace_float_literals; |
| 24 use crate::kernels::{AutoConvolution, BoundedBy, Convolution}; |
28 use std::iter::Zip; |
| 25 use crate::measures::{DiscreteMeasure, Radon}; |
29 use std::ops::RangeFrom; |
| 26 use crate::preadjoint_helper::PreadjointHelper; |
30 |
| 27 use crate::seminorms::{ConvolutionOp, SimpleConvolutionKernel}; |
31 pub type ShiftedSensor<F, S, P, const N: usize> = Shift<Convolution<S, P>, N, F>; |
| 28 use crate::types::*; |
|
| 29 |
|
| 30 type RNDM<F, const N: usize> = DiscreteMeasure<Loc<F, N>, F>; |
|
| 31 |
|
| 32 pub type ShiftedSensor<F, S, P, const N: usize> = Shift<Convolution<S, P>, F, N>; |
|
| 33 |
32 |
| 34 /// Trait for physical convolution models. Has blanket implementation for all cases. |
33 /// Trait for physical convolution models. Has blanket implementation for all cases. |
| 35 pub trait Spread<F: Float, const N: usize>: |
34 pub trait Spread<const N: usize, F: Float = f64>: |
| 36 'static + Clone + Support<F, N> + RealMapping<F, N> + Bounded<F> |
35 'static + Clone + Support<N, F> + RealMapping<N, F> + Bounded<F> |
| 37 { |
36 { |
| 38 } |
37 } |
| 39 |
38 |
| 40 impl<F, T, const N: usize> Spread<F, N> for T |
39 impl<F, T, const N: usize> Spread<N, F> for T |
| 41 where |
40 where |
| 42 F: Float, |
41 F: Float, |
| 43 T: 'static + Clone + Support<F, N> + Bounded<F> + RealMapping<F, N>, |
42 T: 'static + Clone + Support<N, F> + Bounded<F> + RealMapping<N, F>, |
| 44 { |
43 { |
| 45 } |
44 } |
| 46 |
45 |
| 47 /// Trait for compactly supported sensors. Has blanket implementation for all cases. |
46 /// Trait for compactly supported sensors. Has blanket implementation for all cases. |
| 48 pub trait Sensor<F: Float, const N: usize>: |
47 pub trait Sensor<const N: usize, F: Float = f64>: |
| 49 Spread<F, N> + Norm<F, L1> + Norm<F, Linfinity> |
48 Spread<N, F> + Norm<L1, F> + Norm<Linfinity, F> |
| 50 { |
49 { |
| 51 } |
50 } |
| 52 |
51 |
| 53 impl<F, T, const N: usize> Sensor<F, N> for T |
52 impl<F, T, const N: usize> Sensor<N, F> for T |
| 54 where |
53 where |
| 55 F: Float, |
54 F: Float, |
| 56 T: Spread<F, N> + Norm<F, L1> + Norm<F, Linfinity>, |
55 T: Spread<N, F> + Norm<L1, F> + Norm<Linfinity, F>, |
| 57 { |
56 { |
| 58 } |
57 } |
| 59 |
58 |
| 60 pub trait SensorGridBT<F, S, P, const N: usize>: |
59 pub trait SensorGridBT<F, S, P, const N: usize>: |
| 61 Clone + BTImpl<F, N, Data = usize, Agg = Bounds<F>> |
60 Clone + BTImpl<N, F, Data = usize, Agg = Bounds<F>> |
| 62 where |
61 where |
| 63 F: Float, |
62 F: Float, |
| 64 S: Sensor<F, N>, |
63 S: Sensor<N, F>, |
| 65 P: Spread<F, N>, |
64 P: Spread<N, F>, |
| 66 { |
65 { |
| 67 } |
66 } |
| 68 |
67 |
| 69 impl<F, S, P, T, const N: usize> SensorGridBT<F, S, P, N> for T |
68 impl<F, S, P, T, const N: usize> SensorGridBT<F, S, P, N> for T |
| 70 where |
69 where |
| 71 T: Clone + BTImpl<F, N, Data = usize, Agg = Bounds<F>>, |
70 T: Clone + BTImpl<N, F, Data = usize, Agg = Bounds<F>>, |
| 72 F: Float, |
71 F: Float, |
| 73 S: Sensor<F, N>, |
72 S: Sensor<N, F>, |
| 74 P: Spread<F, N>, |
73 P: Spread<N, F>, |
| 75 { |
74 { |
| 76 } |
75 } |
| 77 |
76 |
| 78 // We need type alias bounds to access associated types |
77 // We need type alias bounds to access associated types |
| 79 #[allow(type_alias_bounds)] |
78 #[allow(type_alias_bounds)] |
| 80 pub type SensorGridBTFN<F, S, P, BT: SensorGridBT<F, S, P, N>, const N: usize> = |
79 pub type SensorGridBTFN<F, S, P, BT: SensorGridBT<F, S, P, N>, const N: usize> = |
| 81 BTFN<F, SensorGridSupportGenerator<F, S, P, N>, BT, N>; |
80 BTFN<F, SensorGridSupportGenerator<S, F, P, N>, BT, N>; |
| 82 |
81 |
| 83 /// Sensor grid forward model |
82 /// Sensor grid forward model |
| 84 #[derive(Clone)] |
83 #[derive(Clone)] |
| 85 pub struct SensorGrid<F, S, P, BT, const N: usize> |
84 pub struct SensorGrid<F, S, P, BT, const N: usize> |
| 86 where |
85 where |
| 87 F: Float, |
86 F: Float, |
| 88 S: Sensor<F, N>, |
87 S: Sensor<N, F>, |
| 89 P: Spread<F, N>, |
88 P: Spread<N, F>, |
| 90 Convolution<S, P>: Spread<F, N>, |
89 Convolution<S, P>: Spread<N, F>, |
| 91 BT: SensorGridBT<F, S, P, N>, |
90 BT: SensorGridBT<F, S, P, N>, |
| 92 { |
91 { |
| 93 domain: Cube<F, N>, |
92 domain: Cube<N, F>, |
| 94 sensor_count: [usize; N], |
93 sensor_count: [usize; N], |
| 95 sensor: S, |
94 sensor: S, |
| 96 spread: P, |
95 spread: P, |
| 97 base_sensor: Convolution<S, P>, |
96 base_sensor: Convolution<S, P>, |
| 98 bt: BT, |
97 bt: BT, |
| 139 |
138 |
| 140 impl<F, S, P, BT, const N: usize> SensorGrid<F, S, P, BT, N> |
139 impl<F, S, P, BT, const N: usize> SensorGrid<F, S, P, BT, N> |
| 141 where |
140 where |
| 142 F: Float, |
141 F: Float, |
| 143 BT: SensorGridBT<F, S, P, N>, |
142 BT: SensorGridBT<F, S, P, N>, |
| 144 S: Sensor<F, N>, |
143 S: Sensor<N, F>, |
| 145 P: Spread<F, N>, |
144 P: Spread<N, F>, |
| 146 Convolution<S, P>: Spread<F, N>, |
145 Convolution<S, P>: Spread<N, F>, |
| 147 { |
146 { |
| 148 /// Return the grid of sensor locations. |
147 /// Return the grid of sensor locations. |
| 149 pub fn grid(&self) -> LinGrid<F, N> { |
148 pub fn grid(&self) -> LinGrid<N, F> { |
| 150 lingrid_centered(&self.domain, &self.sensor_count) |
149 lingrid_centered(&self.domain, &self.sensor_count) |
| 151 } |
150 } |
| 152 |
151 |
| 153 /// Returns the number of sensors (number of grid points) |
152 /// Returns the number of sensors (number of grid points) |
| 154 pub fn n_sensors(&self) -> usize { |
153 pub fn n_sensors(&self) -> usize { |
| 155 self.sensor_count.iter().product() |
154 self.sensor_count.iter().product() |
| 156 } |
155 } |
| 157 |
156 |
| 158 /// Constructs a sensor shifted by `x`. |
157 /// Constructs a sensor shifted by `x`. |
| 159 #[inline] |
158 #[inline] |
| 160 fn shifted_sensor(&self, x: Loc<F, N>) -> ShiftedSensor<F, S, P, N> { |
159 fn shifted_sensor(&self, x: Loc<N, F>) -> ShiftedSensor<F, S, P, N> { |
| 161 self.base_sensor.clone().shift(x) |
160 self.base_sensor.clone().shift(x) |
| 162 } |
161 } |
| 163 |
162 |
| 164 #[inline] |
163 #[inline] |
| 165 fn _zero_observable(&self) -> DVector<F> { |
164 fn _zero_observable(&self) -> DVector<F> { |
| 178 .reduce(F::mul) |
177 .reduce(F::mul) |
| 179 .unwrap() |
178 .unwrap() |
| 180 } |
179 } |
| 181 } |
180 } |
| 182 |
181 |
| 183 impl<F, S, P, BT, const N: usize> Mapping<RNDM<F, N>> for SensorGrid<F, S, P, BT, N> |
182 impl<F, S, P, BT, const N: usize> Mapping<RNDM<N, F>> for SensorGrid<F, S, P, BT, N> |
| 184 where |
183 where |
| 185 F: Float, |
184 F: Float, |
| 186 BT: SensorGridBT<F, S, P, N>, |
185 BT: SensorGridBT<F, S, P, N>, |
| 187 S: Sensor<F, N>, |
186 S: Sensor<N, F>, |
| 188 P: Spread<F, N>, |
187 P: Spread<N, F>, |
| 189 Convolution<S, P>: Spread<F, N>, |
188 Convolution<S, P>: Spread<N, F>, |
| 190 { |
189 { |
| 191 type Codomain = DVector<F>; |
190 type Codomain = DVector<F>; |
| 192 |
191 |
| 193 #[inline] |
192 #[inline] |
| 194 fn apply<I: Instance<RNDM<F, N>>>(&self, μ: I) -> DVector<F> { |
193 fn apply<I: Instance<RNDM<N, F>>>(&self, μ: I) -> DVector<F> { |
| 195 let mut y = self._zero_observable(); |
194 let mut y = self._zero_observable(); |
| 196 self.apply_add(&mut y, μ); |
195 self.apply_add(&mut y, μ); |
| 197 y |
196 y |
| 198 } |
197 } |
| 199 } |
198 } |
| 200 |
199 |
| 201 impl<F, S, P, BT, const N: usize> Linear<RNDM<F, N>> for SensorGrid<F, S, P, BT, N> |
200 impl<F, S, P, BT, const N: usize> Linear<RNDM<N, F>> for SensorGrid<F, S, P, BT, N> |
| 202 where |
201 where |
| 203 F: Float, |
202 F: Float, |
| 204 BT: SensorGridBT<F, S, P, N>, |
203 BT: SensorGridBT<F, S, P, N>, |
| 205 S: Sensor<F, N>, |
204 S: Sensor<N, F>, |
| 206 P: Spread<F, N>, |
205 P: Spread<N, F>, |
| 207 Convolution<S, P>: Spread<F, N>, |
206 Convolution<S, P>: Spread<N, F>, |
| 208 { |
207 { |
| 209 } |
208 } |
| 210 |
209 |
| 211 #[replace_float_literals(F::cast_from(literal))] |
210 #[replace_float_literals(F::cast_from(literal))] |
| 212 impl<F, S, P, BT, const N: usize> GEMV<F, RNDM<F, N>, DVector<F>> for SensorGrid<F, S, P, BT, N> |
211 impl<F, S, P, BT, const N: usize> GEMV<F, RNDM<N, F>, DVector<F>> for SensorGrid<F, S, P, BT, N> |
| 213 where |
212 where |
| 214 F: Float, |
213 F: Float, |
| 215 BT: SensorGridBT<F, S, P, N>, |
214 BT: SensorGridBT<F, S, P, N>, |
| 216 S: Sensor<F, N>, |
215 S: Sensor<N, F>, |
| 217 P: Spread<F, N>, |
216 P: Spread<N, F>, |
| 218 Convolution<S, P>: Spread<F, N>, |
217 Convolution<S, P>: Spread<N, F>, |
| 219 { |
218 { |
| 220 fn gemv<I: Instance<RNDM<F, N>>>(&self, y: &mut DVector<F>, α: F, μ: I, β: F) { |
219 fn gemv<I: Instance<RNDM<N, F>>>(&self, y: &mut DVector<F>, α: F, μ: I, β: F) { |
| 221 let grid = self.grid(); |
220 let grid = self.grid(); |
| 222 if β == 0.0 { |
221 if β == 0.0 { |
| 223 y.fill(0.0) |
222 y.fill(0.0) |
| 224 } else if β != 1.0 { |
223 } else if β != 1.0 { |
| 225 *y *= β; // Need to multiply first, as we have to be able to add to y. |
224 *y *= β; // Need to multiply first, as we have to be able to add to y. |
| 226 } |
225 } |
| 227 if α == 1.0 { |
226 if α == 1.0 { |
| 228 self.apply_add(y, μ) |
227 self.apply_add(y, μ) |
| 229 } else { |
228 } else { |
| 230 for δ in μ.ref_instance() { |
229 μ.eval_ref(|μr| { |
| |
230 for δ in μr { |
| |
231 for &d in self.bt.iter_at(&δ.x) { |
| |
232 let sensor = self.shifted_sensor(grid.entry_linear_unchecked(d)); |
| |
233 y[d] += sensor.apply(&δ.x) * (α * δ.α); |
| |
234 } |
| |
235 } |
| |
236 }) |
| |
237 } |
| |
238 } |
| |
239 |
| |
240 fn apply_add<I: Instance<RNDM<N, F>>>(&self, y: &mut DVector<F>, μ: I) { |
| |
241 let grid = self.grid(); |
| |
242 μ.eval_ref(|μr| { |
| |
243 for δ in μr { |
| 231 for &d in self.bt.iter_at(&δ.x) { |
244 for &d in self.bt.iter_at(&δ.x) { |
| 232 let sensor = self.shifted_sensor(grid.entry_linear_unchecked(d)); |
245 let sensor = self.shifted_sensor(grid.entry_linear_unchecked(d)); |
| 233 y[d] += sensor.apply(&δ.x) * (α * δ.α); |
246 y[d] += sensor.apply(&δ.x) * δ.α; |
| 234 } |
247 } |
| 235 } |
248 } |
| 236 } |
249 }) |
| 237 } |
250 } |
| 238 |
251 } |
| 239 fn apply_add<I: Instance<RNDM<F, N>>>(&self, y: &mut DVector<F>, μ: I) { |
252 |
| 240 let grid = self.grid(); |
253 impl<F, S, P, BT, const N: usize> BoundedLinear<RNDM<N, F>, Radon, L2, F> |
| 241 for δ in μ.ref_instance() { |
|
| 242 for &d in self.bt.iter_at(&δ.x) { |
|
| 243 let sensor = self.shifted_sensor(grid.entry_linear_unchecked(d)); |
|
| 244 y[d] += sensor.apply(&δ.x) * δ.α; |
|
| 245 } |
|
| 246 } |
|
| 247 } |
|
| 248 } |
|
| 249 |
|
| 250 impl<F, S, P, BT, const N: usize> BoundedLinear<RNDM<F, N>, Radon, L2, F> |
|
| 251 for SensorGrid<F, S, P, BT, N> |
254 for SensorGrid<F, S, P, BT, N> |
| 252 where |
255 where |
| 253 F: Float, |
256 F: Float, |
| 254 BT: SensorGridBT<F, S, P, N, Agg = Bounds<F>>, |
257 BT: SensorGridBT<F, S, P, N>, |
| 255 S: Sensor<F, N>, |
258 S: Sensor<N, F>, |
| 256 P: Spread<F, N>, |
259 P: Spread<N, F>, |
| 257 Convolution<S, P>: Spread<F, N> + LocalAnalysis<F, BT::Agg, N>, |
260 Convolution<S, P>: Spread<N, F>, |
| 258 { |
261 { |
| 259 /// An estimate on the operator norm in $𝕃(ℳ(Ω); ℝ^n)$ with $ℳ(Ω)$ equipped |
262 /// An estimate on the operator norm in $𝕃(ℳ(Ω); ℝ^n)$ with $ℳ(Ω)$ equipped |
| 260 /// with the Radon norm, and $ℝ^n$ with the Euclidean norm. |
263 /// with the Radon norm, and $ℝ^n$ with the Euclidean norm. |
| 261 fn opnorm_bound(&self, _: Radon, _: L2) -> F { |
264 fn opnorm_bound(&self, _: Radon, _: L2) -> DynResult<F> { |
| 262 // With {x_i}_{i=1}^n the grid centres and φ the kernel, we have |
265 // With {x_i}_{i=1}^n the grid centres and φ the kernel, we have |
| 263 // |Aμ|_2 = sup_{|z|_2 ≤ 1} ⟨z,Αμ⟩ = sup_{|z|_2 ≤ 1} ⟨A^*z|μ⟩ |
266 // |Aμ|_2 = sup_{|z|_2 ≤ 1} ⟨z,Αμ⟩ = sup_{|z|_2 ≤ 1} ⟨A^*z|μ⟩ |
| 264 // ≤ sup_{|z|_2 ≤ 1} |A^*z|_∞ |μ|_ℳ |
267 // ≤ sup_{|z|_2 ≤ 1} |A^*z|_∞ |μ|_ℳ |
| 265 // = sup_{|z|_2 ≤ 1} |∑ φ(· - x_i)z_i|_∞ |μ|_ℳ |
268 // = sup_{|z|_2 ≤ 1} |∑ φ(· - x_i)z_i|_∞ |μ|_ℳ |
| 266 // ≤ sup_{|z|_2 ≤ 1} |φ(y)| ∑_{i:th sensor active at y}|z_i| |μ|_ℳ |
269 // ≤ sup_{|z|_2 ≤ 1} |φ(y)| ∑_{i:th sensor active at y}|z_i| |μ|_ℳ |
| 269 // where N_ψ is the maximum number of sensors that overlap, and |
272 // where N_ψ is the maximum number of sensors that overlap, and |
| 270 // |z|_2 is restricted to the active sensors. |
273 // |z|_2 is restricted to the active sensors. |
| 271 // = |φ|_∞ √N_ψ |μ|_ℳ. |
274 // = |φ|_∞ √N_ψ |μ|_ℳ. |
| 272 // Hence |
275 // Hence |
| 273 let n = self.max_overlapping(); |
276 let n = self.max_overlapping(); |
| 274 self.base_sensor.bounds().uniform() * n.sqrt() |
277 Ok(self.base_sensor.bounds().uniform() * n.sqrt()) |
| 275 } |
278 } |
| 276 } |
279 } |
| 277 |
280 |
| 278 type SensorGridPreadjoint<'a, A, F, const N: usize> = PreadjointHelper<'a, A, RNDM<F, N>>; |
281 type SensorGridPreadjoint<'a, A, F, const N: usize> = PreadjointHelper<'a, A, RNDM<N, F>>; |
| 279 |
282 |
| 280 impl<F, S, P, BT, const N: usize> Preadjointable<RNDM<F, N>, DVector<F>> |
283 impl<F, S, P, BT, const N: usize> Preadjointable<RNDM<N, F>, DVector<F>> |
| 281 for SensorGrid<F, S, P, BT, N> |
284 for SensorGrid<F, S, P, BT, N> |
| 282 where |
285 where |
| 283 F: Float, |
286 F: Float, |
| 284 BT: SensorGridBT<F, S, P, N>, |
287 BT: SensorGridBT<F, S, P, N>, |
| 285 S: Sensor<F, N>, |
288 S: Sensor<N, F>, |
| 286 P: Spread<F, N>, |
289 P: Spread<N, F>, |
| 287 Convolution<S, P>: Spread<F, N> + LocalAnalysis<F, BT::Agg, N>, |
290 Convolution<S, P>: Spread<N, F> + LocalAnalysis<F, BT::Agg, N>, |
| 288 { |
291 { |
| 289 type PreadjointCodomain = BTFN<F, SensorGridSupportGenerator<F, S, P, N>, BT, N>; |
292 type PreadjointCodomain = BTFN<F, SensorGridSupportGenerator<S, F, P, N>, BT, N>; |
| 290 type Preadjoint<'a> |
293 type Preadjoint<'a> |
| 291 = SensorGridPreadjoint<'a, Self, F, N> |
294 = SensorGridPreadjoint<'a, Self, F, N> |
| 292 where |
295 where |
| 293 Self: 'a; |
296 Self: 'a; |
| 294 |
297 |
| 301 #[replace_float_literals(F::cast_from(literal))] |
304 #[replace_float_literals(F::cast_from(literal))] |
| 302 impl<'a, F, S, P, BT, const N : usize> LipschitzValues |
305 impl<'a, F, S, P, BT, const N : usize> LipschitzValues |
| 303 for SensorGridPreadjoint<'a, SensorGrid<F, S, P, BT, N>, F, N> |
306 for SensorGridPreadjoint<'a, SensorGrid<F, S, P, BT, N>, F, N> |
| 304 where F : Float, |
307 where F : Float, |
| 305 BT : SensorGridBT<F, S, P, N>, |
308 BT : SensorGridBT<F, S, P, N>, |
| 306 S : Sensor<F, N>, |
309 S : Sensor<N, F>, |
| 307 P : Spread<F, N>, |
310 P : Spread<N, F>, |
| 308 Convolution<S, P> : Spread<F, N> + Lipschitz<L2, FloatType=F> + DifferentiableMapping<Loc<F,N>> + LocalAnalysis<F, BT::Agg, N>, |
311 Convolution<S, P> : Spread<N, F> + Lipschitz<L2, FloatType=F> + DifferentiableMapping<Loc<N, F>> + LocalAnalysis<F, BT::Agg, N>, |
| 309 for<'b> <Convolution<S, P> as DifferentiableMapping<Loc<F,N>>>::Differential<'b> : Lipschitz<L2, FloatType=F>, |
312 for<'b> <Convolution<S, P> as DifferentiableMapping<Loc<N, F>>>::Differential<'b> : Lipschitz<L2, FloatType=F>, |
| 310 { |
313 { |
| 311 |
314 |
| 312 type FloatType = F; |
315 type FloatType = F; |
| 313 |
316 |
| 314 fn value_unit_lipschitz_factor(&self) -> Option<F> { |
317 fn value_unit_lipschitz_factor(&self) -> Option<F> { |
| 330 } |
333 } |
| 331 } |
334 } |
| 332 */ |
335 */ |
| 333 |
336 |
| 334 #[replace_float_literals(F::cast_from(literal))] |
337 #[replace_float_literals(F::cast_from(literal))] |
| 335 impl<'a, F, S, P, BT, const N: usize> BoundedCurvature for SensorGrid<F, S, P, BT, N> |
338 impl<'a, F, S, P, BT, const N: usize> BasicCurvatureBoundEstimates<F> for SensorGrid<F, S, P, BT, N> |
| 336 where |
339 where |
| 337 F: Float, |
340 F: Float + ToNalgebraRealField, |
| 338 BT: SensorGridBT<F, S, P, N>, |
341 BT: SensorGridBT<F, S, P, N>, |
| 339 S: Sensor<F, N>, |
342 S: Sensor<N, F>, |
| 340 P: Spread<F, N>, |
343 P: Spread<N, F>, |
| 341 Convolution<S, P>: Spread<F, N> |
344 DVector<F>: Euclidean<F>, |
| |
345 Convolution<S, P>: Spread<N, F> |
| 342 + Lipschitz<L2, FloatType = F> |
346 + Lipschitz<L2, FloatType = F> |
| 343 + DifferentiableMapping<Loc<F, N>> |
347 + DifferentiableMapping<Loc<N, F>> |
| 344 + LocalAnalysis<F, BT::Agg, N>, |
348 + LocalAnalysis<F, BT::Agg, N>, |
| 345 for<'b> <Convolution<S, P> as DifferentiableMapping<Loc<F, N>>>::Differential<'b>: |
349 for<'b> <Convolution<S, P> as DifferentiableMapping<Loc<N, F>>>::Differential<'b>: |
| 346 Lipschitz<L2, FloatType = F>, |
350 Lipschitz<L2, FloatType = F>, |
| 347 { |
351 { |
| 348 type FloatType = F; |
352 fn basic_curvature_bound_components(&self) -> (DynResult<F>, DynResult<F>) { |
| 349 |
|
| 350 /// Returns factors $ℓ_F$ and $Θ²$ such that |
|
| 351 /// $B_{F'(μ)} dγ ≤ ℓ_F c_2$ and $⟨F'(μ)+F'(μ+Δ)|Δ⟩ ≤ Θ²|γ|(c_2)‖γ‖$, |
|
| 352 /// where $Δ=(π_♯^1-π_♯^0)γ$. |
|
| 353 /// |
|
| 354 /// See Lemma 3.8, Lemma 5.10, Remark 5.14, and Example 5.15. |
|
| 355 fn curvature_bound_components(&self) -> (Option<Self::FloatType>, Option<Self::FloatType>) { |
|
| 356 let n_ψ = self.max_overlapping(); |
353 let n_ψ = self.max_overlapping(); |
| 357 let ψ_diff_lip = self.base_sensor.diff_ref().lipschitz_factor(L2); |
354 let ψ_diff_lip = self.base_sensor.diff_ref().lipschitz_factor(L2); |
| 358 let ψ_lip = self.base_sensor.lipschitz_factor(L2); |
355 let ψ_lip = self.base_sensor.lipschitz_factor(L2); |
| 359 let ℓ_F = ψ_diff_lip.map(|l| (2.0 * n_ψ).sqrt() * l); |
356 let ℓ_F0 = ψ_diff_lip.map(|l| (2.0 * n_ψ).sqrt() * l); |
| 360 let θ2 = ψ_lip.map(|l| 4.0 * n_ψ * l.powi(2)); |
357 let Θ2 = ψ_lip.map(|l| 4.0 * n_ψ * l.powi(2)); |
| 361 |
358 |
| 362 (ℓ_F, θ2) |
359 (ℓ_F0, Θ2) |
| 363 } |
360 } |
| 364 } |
361 } |
| 365 |
362 |
| 366 #[derive(Clone, Debug)] |
363 #[derive(Clone, Debug)] |
| 367 pub struct SensorGridSupportGenerator<F, S, P, const N: usize> |
364 pub struct SensorGridSupportGenerator<S, F, P, const N: usize> |
| 368 where |
365 where |
| 369 F: Float, |
366 F: Float, |
| 370 S: Sensor<F, N>, |
367 S: Sensor<N, F>, |
| 371 P: Spread<F, N>, |
368 P: Spread<N, F>, |
| 372 { |
369 { |
| 373 base_sensor: Convolution<S, P>, |
370 base_sensor: Convolution<S, P>, |
| 374 grid: LinGrid<F, N>, |
371 grid: LinGrid<N, F>, |
| 375 weights: DVector<F>, |
372 weights: DVector<F>, |
| 376 } |
373 } |
| 377 |
374 |
| 378 impl<F, S, P, const N: usize> SensorGridSupportGenerator<F, S, P, N> |
375 impl<F, S, P, const N: usize> SensorGridSupportGenerator<S, F, P, N> |
| 379 where |
376 where |
| 380 F: Float, |
377 F: Float, |
| 381 S: Sensor<F, N>, |
378 S: Sensor<N, F>, |
| 382 P: Spread<F, N>, |
379 P: Spread<N, F>, |
| 383 Convolution<S, P>: Spread<F, N>, |
380 Convolution<S, P>: Spread<N, F>, |
| 384 { |
381 { |
| 385 #[inline] |
382 #[inline] |
| 386 fn construct_sensor(&self, id: usize, w: F) -> Weighted<ShiftedSensor<F, S, P, N>, F> { |
383 fn construct_sensor(&self, id: usize, w: F) -> Weighted<ShiftedSensor<F, S, P, N>, F> { |
| 387 let x = self.grid.entry_linear_unchecked(id); |
384 let x = self.grid.entry_linear_unchecked(id); |
| 388 self.base_sensor.clone().shift(x).weigh(w) |
385 self.base_sensor.clone().shift(x).weigh(w) |
| 432 .zip(self.weights.as_slice().iter()) |
429 .zip(self.weights.as_slice().iter()) |
| 433 .mapX(self, Self::construct_sensor_and_id) |
430 .mapX(self, Self::construct_sensor_and_id) |
| 434 } |
431 } |
| 435 } |
432 } |
| 436 |
433 |
| 437 impl<F, S, P, BT, const N: usize> ForwardModel<DiscreteMeasure<Loc<F, N>, F>, F> |
434 impl<F, S, P, BT, const N: usize> ForwardModel<DiscreteMeasure<Loc<N, F>, F>, F> |
| 438 for SensorGrid<F, S, P, BT, N> |
435 for SensorGrid<F, S, P, BT, N> |
| 439 where |
436 where |
| 440 F: Float + ToNalgebraRealField<MixedType = F> + nalgebra::RealField, |
437 F: Float + ToNalgebraRealField<MixedType = F> + nalgebra::RealField, |
| 441 BT: SensorGridBT<F, S, P, N>, |
438 BT: SensorGridBT<F, S, P, N>, |
| 442 S: Sensor<F, N>, |
439 S: Sensor<N, F>, |
| 443 P: Spread<F, N>, |
440 P: Spread<N, F>, |
| 444 Convolution<S, P>: Spread<F, N> + LocalAnalysis<F, BT::Agg, N>, |
441 Convolution<S, P>: Spread<N, F> + LocalAnalysis<F, BT::Agg, N>, |
| 445 { |
442 { |
| 446 type Observable = DVector<F>; |
443 type Observable = DVector<F>; |
| 447 |
444 |
| 448 fn write_observable(&self, b: &Self::Observable, prefix: String) -> DynError { |
445 fn write_observable(&self, b: &Self::Observable, prefix: String) -> DynError { |
| 449 let it = self.grid().into_iter().zip(b.iter()).map(|(x, &v)| (x, v)); |
446 let it = self.grid().into_iter().zip(b.iter()).map(|(x, &v)| (x, v)); |
| 454 fn zero_observable(&self) -> Self::Observable { |
451 fn zero_observable(&self) -> Self::Observable { |
| 455 self._zero_observable() |
452 self._zero_observable() |
| 456 } |
453 } |
| 457 } |
454 } |
| 458 |
455 |
| 459 impl<F, S, P, BT, const N: usize> FindimQuadraticModel<Loc<F, N>, F> for SensorGrid<F, S, P, BT, N> |
456 impl<F, S, P, BT, const N: usize> FindimQuadraticModel<Loc<N, F>, F> for SensorGrid<F, S, P, BT, N> |
| 460 where |
457 where |
| 461 F: Float + ToNalgebraRealField<MixedType = F> + nalgebra::RealField, |
458 F: Float + ToNalgebraRealField<MixedType = F> + nalgebra::RealField, |
| 462 BT: SensorGridBT<F, S, P, N>, |
459 BT: SensorGridBT<F, S, P, N>, |
| 463 S: Sensor<F, N>, |
460 S: Sensor<N, F>, |
| 464 P: Spread<F, N>, |
461 P: Spread<N, F>, |
| 465 Convolution<S, P>: Spread<F, N> + LocalAnalysis<F, BT::Agg, N>, |
462 Convolution<S, P>: Spread<N, F> + LocalAnalysis<F, BT::Agg, N>, |
| 466 { |
463 { |
| 467 fn findim_quadratic_model( |
464 fn findim_quadratic_model( |
| 468 &self, |
465 &self, |
| 469 μ: &DiscreteMeasure<Loc<F, N>, F>, |
466 μ: &DiscreteMeasure<Loc<N, F>, F>, |
| 470 b: &Self::Observable, |
467 b: &Self::Observable, |
| 471 ) -> (DMatrix<F::MixedType>, DVector<F::MixedType>) { |
468 ) -> (DMatrix<F::MixedType>, DVector<F::MixedType>) { |
| 472 assert_eq!(b.len(), self.n_sensors()); |
469 assert_eq!(b.len(), self.n_sensors()); |
| 473 let mut mA = DMatrix::zeros(self.n_sensors(), μ.len()); |
470 let mut mA = DMatrix::zeros(self.n_sensors(), μ.len()); |
| 474 let grid = self.grid(); |
471 let grid = self.grid(); |
| 481 let mAt = mA.transpose(); |
478 let mAt = mA.transpose(); |
| 482 (&mAt * mA, &mAt * b) |
479 (&mAt * mA, &mAt * b) |
| 483 } |
480 } |
| 484 } |
481 } |
| 485 |
482 |
| 486 /// Implements the calculation a factor $L$ such that $A_*A ≤ L 𝒟$ for $A$ the forward model |
483 /// Implements the calculation a factor $√L$ such that $A_*A ≤ L 𝒟$ for $A$ the forward model |
| 487 /// and $𝒟$ a seminorm of suitable form. |
484 /// and $𝒟$ a seminorm of suitable form. |
| 488 /// |
485 /// |
| 489 /// **This assumes (but does not check) that the sensors are not overlapping.** |
486 /// **This assumes (but does not check) that the sensors are not overlapping.** |
| 490 #[replace_float_literals(F::cast_from(literal))] |
487 #[replace_float_literals(F::cast_from(literal))] |
| 491 impl<F, BT, S, P, K, const N: usize> AdjointProductBoundedBy<RNDM<F, N>, ConvolutionOp<F, K, BT, N>> |
488 impl<'a, F, BT, S, P, K, const N: usize> |
| 492 for SensorGrid<F, S, P, BT, N> |
489 BoundedLinear<RNDM<N, F>, &'a ConvolutionOp<F, K, BT, N>, L2, F> for SensorGrid<F, S, P, BT, N> |
| 493 where |
490 where |
| 494 F: Float + nalgebra::RealField + ToNalgebraRealField, |
491 F: Float + ToNalgebraRealField, |
| 495 BT: SensorGridBT<F, S, P, N>, |
492 BT: SensorGridBT<F, S, P, N>, |
| 496 S: Sensor<F, N>, |
493 S: Sensor<N, F>, |
| 497 P: Spread<F, N>, |
494 P: Spread<N, F>, |
| 498 Convolution<S, P>: Spread<F, N>, |
495 Convolution<S, P>: Spread<N, F>, |
| 499 K: SimpleConvolutionKernel<F, N>, |
496 K: SimpleConvolutionKernel<N, F>, |
| 500 AutoConvolution<P>: BoundedBy<F, K>, |
497 AutoConvolution<P>: BoundedBy<F, K>, |
| 501 { |
498 Weighted<Shift<K, N, F>, F>: LocalAnalysis<F, BT::Agg, N>, |
| 502 type FloatType = F; |
499 { |
| 503 |
500 fn opnorm_bound(&self, seminorm: &'a ConvolutionOp<F, K, BT, N>, _: L2) -> DynResult<F> { |
| 504 fn adjoint_product_bound(&self, seminorm: &ConvolutionOp<F, K, BT, N>) -> Option<F> { |
|
| 505 // Sensors should not take on negative values to allow |
501 // Sensors should not take on negative values to allow |
| 506 // A_*A to be upper bounded by a simple convolution of `spread`. |
502 // A_*A to be upper bounded by a simple convolution of `spread`. |
| |
503 // TODO: Do we really need this restriction? |
| 507 if self.sensor.bounds().lower() < 0.0 { |
504 if self.sensor.bounds().lower() < 0.0 { |
| 508 return None; |
505 return Err(anyhow!("Sensor not bounded from below by zero")); |
| 509 } |
506 } |
| 510 |
507 |
| 511 // Calculate the factor $L_1$ for betwee $ℱ[ψ * ψ] ≤ L_1 ℱ[ρ]$ for $ψ$ the base spread |
508 // Calculate the factor $L_1$ for betwee $ℱ[ψ * ψ] ≤ L_1 ℱ[ρ]$ for $ψ$ the base spread |
| 512 // and $ρ$ the kernel of the seminorm. |
509 // and $ρ$ the kernel of the seminorm. |
| 513 let l1 = AutoConvolution(self.spread.clone()).bounding_factor(seminorm.kernel())?; |
510 let l1 = AutoConvolution(self.spread.clone()).bounding_factor(seminorm.kernel())?; |
| 515 // Calculate the factor for transitioning from $A_*A$ to `AutoConvolution<P>`, where A |
512 // Calculate the factor for transitioning from $A_*A$ to `AutoConvolution<P>`, where A |
| 516 // consists of several `Convolution<S, P>` for the physical model `P` and the sensor `S`. |
513 // consists of several `Convolution<S, P>` for the physical model `P` and the sensor `S`. |
| 517 let l0 = self.sensor.norm(Linfinity) * self.sensor.norm(L1); |
514 let l0 = self.sensor.norm(Linfinity) * self.sensor.norm(L1); |
| 518 |
515 |
| 519 // The final transition factor is: |
516 // The final transition factor is: |
| 520 Some(l0 * l1) |
517 Ok((l0 * l1).sqrt()) |
| 521 } |
518 } |
| 522 } |
519 } |
| 523 |
520 |
| 524 macro_rules! make_sensorgridsupportgenerator_scalarop_rhs { |
521 macro_rules! make_sensorgridsupportgenerator_scalarop_rhs { |
| 525 ($trait:ident, $fn:ident, $trait_assign:ident, $fn_assign:ident) => { |
522 ($trait:ident, $fn:ident, $trait_assign:ident, $fn_assign:ident) => { |
| 526 impl<F, S, P, const N: usize> std::ops::$trait_assign<F> |
523 impl<F, S, P, const N: usize> std::ops::$trait_assign<F> |
| 527 for SensorGridSupportGenerator<F, S, P, N> |
524 for SensorGridSupportGenerator<S, F, P, N> |
| 528 where |
525 where |
| 529 F: Float, |
526 F: Float, |
| 530 S: Sensor<F, N>, |
527 S: Sensor<N, F>, |
| 531 P: Spread<F, N>, |
528 P: Spread<N, F>, |
| 532 Convolution<S, P>: Spread<F, N>, |
529 Convolution<S, P>: Spread<N, F>, |
| 533 { |
530 { |
| 534 fn $fn_assign(&mut self, t: F) { |
531 fn $fn_assign(&mut self, t: F) { |
| 535 self.weights.$fn_assign(t); |
532 self.weights.$fn_assign(t); |
| 536 } |
533 } |
| 537 } |
534 } |
| 538 |
535 |
| 539 impl<F, S, P, const N: usize> std::ops::$trait<F> for SensorGridSupportGenerator<F, S, P, N> |
536 impl<F, S, P, const N: usize> std::ops::$trait<F> for SensorGridSupportGenerator<S, F, P, N> |
| 540 where |
537 where |
| 541 F: Float, |
538 F: Float, |
| 542 S: Sensor<F, N>, |
539 S: Sensor<N, F>, |
| 543 P: Spread<F, N>, |
540 P: Spread<N, F>, |
| 544 Convolution<S, P>: Spread<F, N>, |
541 Convolution<S, P>: Spread<N, F>, |
| 545 { |
542 { |
| 546 type Output = SensorGridSupportGenerator<F, S, P, N>; |
543 type Output = SensorGridSupportGenerator<S, F, P, N>; |
| 547 fn $fn(mut self, t: F) -> Self::Output { |
544 fn $fn(mut self, t: F) -> Self::Output { |
| 548 std::ops::$trait_assign::$fn_assign(&mut self.weights, t); |
545 std::ops::$trait_assign::$fn_assign(&mut self.weights, t); |
| 549 self |
546 self |
| 550 } |
547 } |
| 551 } |
548 } |
| 552 |
549 |
| 553 impl<'a, F, S, P, const N: usize> std::ops::$trait<F> |
550 impl<'a, F, S, P, const N: usize> std::ops::$trait<F> |
| 554 for &'a SensorGridSupportGenerator<F, S, P, N> |
551 for &'a SensorGridSupportGenerator<S, F, P, N> |
| 555 where |
552 where |
| 556 F: Float, |
553 F: Float, |
| 557 S: Sensor<F, N>, |
554 S: Sensor<N, F>, |
| 558 P: Spread<F, N>, |
555 P: Spread<N, F>, |
| 559 Convolution<S, P>: Spread<F, N>, |
556 Convolution<S, P>: Spread<N, F>, |
| 560 { |
557 { |
| 561 type Output = SensorGridSupportGenerator<F, S, P, N>; |
558 type Output = SensorGridSupportGenerator<S, F, P, N>; |
| 562 fn $fn(self, t: F) -> Self::Output { |
559 fn $fn(self, t: F) -> Self::Output { |
| 563 SensorGridSupportGenerator { |
560 SensorGridSupportGenerator { |
| 564 base_sensor: self.base_sensor.clone(), |
561 base_sensor: self.base_sensor.clone(), |
| 565 grid: self.grid, |
562 grid: self.grid, |
| 566 weights: (&self.weights).$fn(t), |
563 weights: (&self.weights).$fn(t), |
| 573 make_sensorgridsupportgenerator_scalarop_rhs!(Mul, mul, MulAssign, mul_assign); |
570 make_sensorgridsupportgenerator_scalarop_rhs!(Mul, mul, MulAssign, mul_assign); |
| 574 make_sensorgridsupportgenerator_scalarop_rhs!(Div, div, DivAssign, div_assign); |
571 make_sensorgridsupportgenerator_scalarop_rhs!(Div, div, DivAssign, div_assign); |
| 575 |
572 |
| 576 macro_rules! make_sensorgridsupportgenerator_unaryop { |
573 macro_rules! make_sensorgridsupportgenerator_unaryop { |
| 577 ($trait:ident, $fn:ident) => { |
574 ($trait:ident, $fn:ident) => { |
| 578 impl<F, S, P, const N: usize> std::ops::$trait for SensorGridSupportGenerator<F, S, P, N> |
575 impl<F, S, P, const N: usize> std::ops::$trait for SensorGridSupportGenerator<S, F, P, N> |
| 579 where |
576 where |
| 580 F: Float, |
577 F: Float, |
| 581 S: Sensor<F, N>, |
578 S: Sensor<N, F>, |
| 582 P: Spread<F, N>, |
579 P: Spread<N, F>, |
| 583 Convolution<S, P>: Spread<F, N>, |
580 Convolution<S, P>: Spread<N, F>, |
| 584 { |
581 { |
| 585 type Output = SensorGridSupportGenerator<F, S, P, N>; |
582 type Output = SensorGridSupportGenerator<S, F, P, N>; |
| 586 fn $fn(mut self) -> Self::Output { |
583 fn $fn(mut self) -> Self::Output { |
| 587 self.weights = self.weights.$fn(); |
584 self.weights = self.weights.$fn(); |
| 588 self |
585 self |
| 589 } |
586 } |
| 590 } |
587 } |
| 591 |
588 |
| 592 impl<'a, F, S, P, const N: usize> std::ops::$trait |
589 impl<'a, F, S, P, const N: usize> std::ops::$trait |
| 593 for &'a SensorGridSupportGenerator<F, S, P, N> |
590 for &'a SensorGridSupportGenerator<S, F, P, N> |
| 594 where |
591 where |
| 595 F: Float, |
592 F: Float, |
| 596 S: Sensor<F, N>, |
593 S: Sensor<N, F>, |
| 597 P: Spread<F, N>, |
594 P: Spread<N, F>, |
| 598 Convolution<S, P>: Spread<F, N>, |
595 Convolution<S, P>: Spread<N, F>, |
| 599 { |
596 { |
| 600 type Output = SensorGridSupportGenerator<F, S, P, N>; |
597 type Output = SensorGridSupportGenerator<S, F, P, N>; |
| 601 fn $fn(self) -> Self::Output { |
598 fn $fn(self) -> Self::Output { |
| 602 SensorGridSupportGenerator { |
599 SensorGridSupportGenerator { |
| 603 base_sensor: self.base_sensor.clone(), |
600 base_sensor: self.base_sensor.clone(), |
| 604 grid: self.grid, |
601 grid: self.grid, |
| 605 weights: (&self.weights).$fn(), |
602 weights: (&self.weights).$fn(), |
| 610 } |
607 } |
| 611 |
608 |
| 612 make_sensorgridsupportgenerator_unaryop!(Neg, neg); |
609 make_sensorgridsupportgenerator_unaryop!(Neg, neg); |
| 613 |
610 |
| 614 impl<'a, F, S, P, BT, const N: usize> Mapping<DVector<F>> |
611 impl<'a, F, S, P, BT, const N: usize> Mapping<DVector<F>> |
| 615 for PreadjointHelper<'a, SensorGrid<F, S, P, BT, N>, RNDM<F, N>> |
612 for PreadjointHelper<'a, SensorGrid<F, S, P, BT, N>, RNDM<N, F>> |
| 616 where |
613 where |
| 617 F: Float, |
614 F: Float, |
| 618 BT: SensorGridBT<F, S, P, N>, |
615 BT: SensorGridBT<F, S, P, N>, |
| 619 S: Sensor<F, N>, |
616 S: Sensor<N, F>, |
| 620 P: Spread<F, N>, |
617 P: Spread<N, F>, |
| 621 Convolution<S, P>: Spread<F, N> + LocalAnalysis<F, Bounds<F>, N>, |
618 Convolution<S, P>: Spread<N, F> + LocalAnalysis<F, Bounds<F>, N>, |
| 622 { |
619 { |
| 623 type Codomain = SensorGridBTFN<F, S, P, BT, N>; |
620 type Codomain = SensorGridBTFN<F, S, P, BT, N>; |
| 624 |
621 |
| 625 fn apply<I: Instance<DVector<F>>>(&self, x: I) -> Self::Codomain { |
622 fn apply<I: Instance<DVector<F>>>(&self, x: I) -> Self::Codomain { |
| 626 let fwd = &self.forward_op; |
623 let fwd = &self.forward_op; |