| 1 /*! |
1 /*! |
| 2 Simple parametric forward model. |
2 Simple parametric forward model. |
| 3 */ |
3 */ |
| 4 |
4 |
| 5 use super::{AdjointProductBoundedBy, AdjointProductPairBoundedBy, BoundedCurvature, ForwardModel}; |
5 use super::{BasicCurvatureBoundEstimates, BoundedCurvature, BoundedCurvatureGuess, ForwardModel}; |
| 6 use crate::measures::RNDM; |
6 use crate::dataterm::QuadraticDataTerm; |
| |
7 use crate::measures::{Radon, RNDM}; |
| |
8 use crate::prox_penalty::{RadonSquared, StepLengthBoundPair}; |
| |
9 use crate::seminorms::DiscreteMeasureOp; |
| 7 use alg_tools::direct_product::Pair; |
10 use alg_tools::direct_product::Pair; |
| 8 use alg_tools::error::DynError; |
11 use alg_tools::error::{DynError, DynResult}; |
| 9 use alg_tools::linops::{IdOp, Linear, RowOp, ZeroOp, AXPY}; |
12 use alg_tools::euclidean::ClosedEuclidean; |
| 10 use alg_tools::mapping::Space; |
13 use alg_tools::linops::{BoundedLinear, IdOp, RowOp, AXPY}; |
| |
14 use alg_tools::loc::Loc; |
| |
15 use alg_tools::mapping::{Mapping, Space}; |
| |
16 use alg_tools::nalgebra_support::ToNalgebraRealField; |
| 11 use alg_tools::norms::{Norm, NormExponent, PairNorm, L2}; |
17 use alg_tools::norms::{Norm, NormExponent, PairNorm, L2}; |
| 12 use alg_tools::types::{ClosedAdd, Float}; |
18 use alg_tools::types::{ClosedAdd, Float}; |
| 13 use numeric_literals::replace_float_literals; |
19 use numeric_literals::replace_float_literals; |
| 14 |
20 |
| 15 impl<Domain, F, A, E> ForwardModel<Pair<Domain, A::Observable>, F, PairNorm<E, L2, L2>> |
21 impl<Domain, F, A, E> ForwardModel<Pair<Domain, A::Observable>, F, PairNorm<E, L2, L2>> |
| 16 for RowOp<A, IdOp<A::Observable>> |
22 for RowOp<A, IdOp<A::Observable>> |
| 17 where |
23 where |
| 18 E: NormExponent, |
24 E: NormExponent, |
| 19 Domain: Space + Norm<F, E>, |
25 Domain: Space + Norm<E, F>, |
| 20 F: Float, |
26 F: Float, |
| 21 A::Observable: ClosedAdd + Norm<F, L2> + 'static, |
27 A::Observable: ClosedAdd + Norm<L2, F> + AXPY<Field = F> + 'static, |
| 22 A: ForwardModel<Domain, F, E> + 'static, |
28 A: ForwardModel<Domain, F, E> + 'static, |
| 23 { |
29 { |
| 24 type Observable = A::Observable; |
30 type Observable = A::Observable; |
| 25 |
31 |
| 26 fn write_observable(&self, b: &Self::Observable, prefix: String) -> DynError { |
32 fn write_observable(&self, b: &Self::Observable, prefix: String) -> DynError { |
| 32 self.0.zero_observable() |
38 self.0.zero_observable() |
| 33 } |
39 } |
| 34 } |
40 } |
| 35 |
41 |
| 36 #[replace_float_literals(F::cast_from(literal))] |
42 #[replace_float_literals(F::cast_from(literal))] |
| 37 impl<Domain, F, A, D, Z> AdjointProductPairBoundedBy<Pair<Domain, Z>, D, IdOp<Z>> |
43 impl<'a, F, A, 𝒟, Z, const N: usize> |
| 38 for RowOp<A, IdOp<Z>> |
44 StepLengthBoundPair<F, QuadraticDataTerm<F, Pair<RNDM<N, F>, Z>, RowOp<A, IdOp<Z>>>> |
| |
45 for Pair<&'a 𝒟, &'a IdOp<Z>> |
| 39 where |
46 where |
| 40 Domain: Space, |
47 RNDM<N, F>: Space + for<'b> Norm<&'b 𝒟, F>, |
| 41 F: Float, |
48 F: Float + ToNalgebraRealField, |
| 42 Z: Clone + Space + ClosedAdd, |
49 𝒟: DiscreteMeasureOp<Loc<N, F>, F>, |
| 43 A: AdjointProductBoundedBy<Domain, D, FloatType = F, Codomain = Z>, |
50 Z: Clone + ClosedEuclidean<F>, |
| 44 A::Codomain: ClosedAdd, |
51 A: for<'b> BoundedLinear<RNDM<N, F>, &'b 𝒟, L2, F, Codomain = Z>, |
| |
52 for<'b> &'b 𝒟: NormExponent, |
| 45 { |
53 { |
| 46 type FloatType = F; |
54 fn step_length_bound_pair( |
| |
55 &self, |
| |
56 f: &QuadraticDataTerm<F, Pair<RNDM<N, F>, Z>, RowOp<A, IdOp<Z>>>, |
| |
57 ) -> DynResult<(F, F)> { |
| |
58 let l_0 = f.operator().0.opnorm_bound(self.0, L2)?.powi(2); |
| |
59 // [A_*; B_*][A, B] = [A_*A, A_* B; B_* A, B_* B] ≤ diag(2A_*A, 2B_*B) |
| |
60 // ≤ diag(2l_A𝒟_A, 2l_B𝒟_B), where now 𝒟_B=Id and l_B=1. |
| |
61 Ok((2.0 * l_0, 2.0)) |
| |
62 } |
| |
63 } |
| 47 |
64 |
| 48 fn adjoint_product_pair_bound(&self, d: &D, _: &IdOp<Z>) -> Option<(F, F)> { |
65 #[replace_float_literals(F::cast_from(literal))] |
| 49 self.0.adjoint_product_bound(d).map(|l_0| { |
66 impl<'a, F, A, Z, const N: usize> |
| 50 // [A_*; B_*][A, B] = [A_*A, A_* B; B_* A, B_* B] ≤ diag(2A_*A, 2B_*B) |
67 StepLengthBoundPair<F, QuadraticDataTerm<F, Pair<RNDM<N, F>, Z>, RowOp<A, IdOp<Z>>>> |
| 51 // ≤ diag(2l_A𝒟_A, 2l_B𝒟_B), where now 𝒟_B=Id and l_B=1. |
68 for Pair<&'a RadonSquared, &'a IdOp<Z>> |
| 52 (2.0 * l_0, 2.0) |
69 where |
| 53 }) |
70 RNDM<N, F>: Space + Norm<Radon, F>, |
| |
71 F: Float + ToNalgebraRealField, |
| |
72 Z: Clone + ClosedEuclidean<F>, |
| |
73 A: BoundedLinear<RNDM<N, F>, Radon, L2, F, Codomain = Z>, |
| |
74 { |
| |
75 fn step_length_bound_pair( |
| |
76 &self, |
| |
77 f: &QuadraticDataTerm<F, Pair<RNDM<N, F>, Z>, RowOp<A, IdOp<Z>>>, |
| |
78 ) -> DynResult<(F, F)> { |
| |
79 let l_0 = f.operator().0.opnorm_bound(Radon, L2)?.powi(2); |
| |
80 // [A_*; B_*][A, B] = [A_*A, A_* B; B_* A, B_* B] ≤ diag(2A_*A, 2B_*B) |
| |
81 // ≤ diag(2l_A𝒟_A, 2l_B𝒟_B), where now 𝒟_B=Id and l_B=1. |
| |
82 Ok((2.0 * l_0, 2.0)) |
| 54 } |
83 } |
| 55 } |
84 } |
| 56 |
85 |
| 57 /* |
86 /* |
| 58 /// This `impl` is bit of an abuse as the codomain of `Apre` is a [`Pair`] of a measure predual, |
87 /// This `impl` is bit of an abuse as the codomain of `Apre` is a [`Pair`] of a measure predual, |
| 77 self.0.value_diff_unit_lipschitz_factor() |
106 self.0.value_diff_unit_lipschitz_factor() |
| 78 } |
107 } |
| 79 } |
108 } |
| 80 */ |
109 */ |
| 81 |
110 |
| 82 impl<F, A, Z> BoundedCurvature for RowOp<A, IdOp<Z>> |
111 use BoundedCurvatureGuess::*; |
| |
112 |
| |
113 /// Curvature error control: helper bounds for (4.2d), (5.2a), (5.2b), (5.15a), and (5.16a). |
| |
114 /// |
| |
115 /// Based on Lemma 5.11 and Example 5.12, the helper bound for (5.15a) and (5.16a) is (3.8). |
| |
116 /// Due to Example 6.1, defining $v^k$ as the projection $F'$ to the predual space of the |
| |
117 /// measures, returns, if possible, and subject to the guess being correct, factors $ℓ_F$ and |
| |
118 /// $Θ²$ such that $B_{P_ℳ^* F'(μ, z)} dγ ≤ ℓ_F c_2$ and |
| |
119 /// $⟨P_ℳ^*[F'(μ+Δ, z)-F'(μ, z)]|Δ⟩ ≤ Θ²|γ|(c_2)‖γ‖$, where $Δ=(π_♯^1-π_♯^0)γ$. |
| |
120 /// For our $F(μ, z)=\frac{1}{2}\|Aμ+z-b\|^2$, we have $F'(μ, z)=A\_*(Aμ+z-b)$, so |
| |
121 /// $F'(μ+Δ, z)-F'(μ, z)=A\_*AΔ$ is independent of $z$, and the bounding can be calculated |
| |
122 /// as in the case without $z$, based on Lemma 3.8. |
| |
123 /// |
| |
124 /// We use Remark 5.15 and Example 5.16 for (4.2d) and (5.2a) with the additional effect of $z$. |
| |
125 /// This is based on a Lipschitz estimate for $∇v^k$, where we still, similarly to the Example, |
| |
126 /// have $∇v^k(x)=∇A\_*(x)[Aμ^k+z^k-b]$. We estimate the final term similarly to the example, |
| |
127 /// assuming for the guess [`BetterThanZero`] that every iterate is better than $(μ, z)=0$. |
| |
128 /// This the final estimate is exactly as in the example, without $z$. |
| |
129 /// Thus we can directly use [`BasicCurvatureBoundEstimates`] on the operator $A$. |
| |
130 impl<F, A, Z, const N: usize> BoundedCurvature<F> |
| |
131 for QuadraticDataTerm<F, Pair<RNDM<N, F>, Z>, RowOp<A, IdOp<Z>>> |
| 83 where |
132 where |
| 84 F: Float, |
133 F: Float, |
| 85 Z: Clone + Space + ClosedAdd, |
134 Z: Clone + ClosedEuclidean<F>, |
| 86 A: BoundedCurvature<FloatType = F>, |
135 A: Mapping<RNDM<N, F>, Codomain = Z>, |
| |
136 A: BasicCurvatureBoundEstimates<F>, |
| 87 { |
137 { |
| 88 type FloatType = F; |
138 fn curvature_bound_components( |
| 89 |
139 &self, |
| 90 fn curvature_bound_components(&self) -> (Option<Self::FloatType>, Option<Self::FloatType>) { |
140 guess: BoundedCurvatureGuess, |
| 91 self.0.curvature_bound_components() |
141 ) -> (DynResult<F>, DynResult<F>) { |
| |
142 match guess { |
| |
143 BetterThanZero => { |
| |
144 let opA = &self.operator().0; |
| |
145 let b = self.data(); |
| |
146 let (ℓ_F0, θ2) = opA.basic_curvature_bound_components(); |
| |
147 (ℓ_F0.map(|l| l * b.norm2()), θ2) |
| |
148 } |
| |
149 } |
| 92 } |
150 } |
| 93 } |
151 } |
| 94 |
|
| 95 #[replace_float_literals(F::cast_from(literal))] |
|
| 96 impl<'a, F, D, XD, Y, const N: usize> AdjointProductBoundedBy<RNDM<F, N>, D> |
|
| 97 for ZeroOp<'a, RNDM<F, N>, XD, Y, F> |
|
| 98 where |
|
| 99 F: Float, |
|
| 100 Y: AXPY<F> + Clone, |
|
| 101 D: Linear<RNDM<F, N>>, |
|
| 102 { |
|
| 103 type FloatType = F; |
|
| 104 /// Return $L$ such that $A_*A ≤ L𝒟$ is bounded by some `other` operator $𝒟$. |
|
| 105 fn adjoint_product_bound(&self, _: &D) -> Option<F> { |
|
| 106 Some(0.0) |
|
| 107 } |
|
| 108 } |
|