Mon, 06 Jan 2025 11:32:57 -0500
Factor fix
35 | 1 | /*! |
2 | Simple parametric forward model. | |
3 | */ | |
4 | ||
5 | use numeric_literals::replace_float_literals; | |
6 | use alg_tools::types::{Float, ClosedAdd}; | |
7 | use alg_tools::mapping::Space; | |
8 | use alg_tools::direct_product::Pair; | |
9 | use alg_tools::linops::{Linear, RowOp, ColOp, IdOp, ZeroOp, AXPY}; | |
10 | use alg_tools::error::DynError; | |
11 | use alg_tools::norms::{L2, Norm, PairNorm, NormExponent}; | |
12 | use crate::types::L2Squared; | |
13 | use crate::measures::RNDM; | |
14 | use super::{ForwardModel, AdjointProductBoundedBy, AdjointProductPairBoundedBy, LipschitzValues}; | |
15 | use crate::transport::TransportLipschitz; | |
16 | ||
17 | impl<Domain, F, A, E> ForwardModel<Pair<Domain, A::Observable>, F, PairNorm<E, L2, L2>> | |
18 | for RowOp<A, IdOp<A::Observable>> | |
19 | where | |
20 | E : NormExponent, | |
21 | Domain : Space + Norm<F, E>, | |
22 | F : Float, | |
23 | A::Observable : ClosedAdd + Norm<F, L2> + 'static, | |
24 | A : ForwardModel<Domain, F, E> + 'static | |
25 | { | |
26 | type Observable = A::Observable; | |
27 | ||
28 | fn write_observable(&self, b : &Self::Observable, prefix : String) -> DynError { | |
29 | self.0.write_observable(b, prefix) | |
30 | } | |
31 | ||
32 | /// Returns a zero observable | |
33 | fn zero_observable(&self) -> Self::Observable { | |
34 | self.0.zero_observable() | |
35 | } | |
36 | } | |
37 | ||
38 | #[replace_float_literals(F::cast_from(literal))] | |
39 | impl<Domain, F, A, D, Z> AdjointProductPairBoundedBy<Pair<Domain, Z>, D, IdOp<Z>> | |
40 | for RowOp<A, IdOp<Z>> | |
41 | where | |
42 | Domain : Space, | |
43 | F : Float, | |
44 | Z : Clone + Space + ClosedAdd, | |
45 | A : AdjointProductBoundedBy<Domain, D, FloatType=F, Codomain = Z>, | |
46 | D : Linear<Domain>, | |
47 | A::Codomain : ClosedAdd, | |
48 | { | |
49 | type FloatType = F; | |
50 | ||
51 | fn adjoint_product_pair_bound(&self, d : &D, _ : &IdOp<Z>) -> Option<(F, F)> { | |
52 | self.0.adjoint_product_bound(d).map(|l_0| { | |
53 | // [A_*; B_*][A, B] = [A_*A, A_* B; B_* A, B_* B] ≤ diag(2A_*A, 2B_*B) | |
54 | // ≤ diag(2l_A𝒟_A, 2l_B𝒟_B), where now 𝒟_B=Id and l_B=1. | |
55 | (2.0 * l_0, 2.0) | |
56 | }) | |
57 | } | |
58 | } | |
59 | ||
60 | /// This `impl` is bit of an abuse as the codomain of `Apre` is a [`Pair`] of a measure predual, | |
61 | /// to which this `impl` applies, and another space. | |
62 | impl<F, Apre, Z> LipschitzValues | |
63 | for ColOp<Apre, IdOp<Z>> | |
64 | where | |
65 | F : Float, | |
66 | Z : Clone + Space + ClosedAdd, | |
67 | Apre : LipschitzValues<FloatType = F>, | |
68 | { | |
69 | type FloatType = F; | |
70 | /// Return (if one exists) a factor $L$ such that $A_*z$ is $L$-Lipschitz for all | |
71 | /// $z$ in the unit ball. | |
72 | fn value_unit_lipschitz_factor(&self) -> Option<Self::FloatType> { | |
73 | self.0.value_unit_lipschitz_factor() | |
74 | } | |
75 | ||
76 | /// Return (if one exists) a factor $L$ such that $∇A_*z$ is $L$-Lipschitz for all | |
77 | /// $z$ in the unit ball. | |
78 | fn value_diff_unit_lipschitz_factor(&self) -> Option<Self::FloatType> { | |
79 | self.0.value_diff_unit_lipschitz_factor() | |
80 | } | |
81 | } | |
82 | ||
83 | ||
84 | ||
85 | impl<'a, F : Float, Y : Space, XD, const N : usize> TransportLipschitz<L2Squared> for | |
86 | ZeroOp<'a, RNDM<F, N>, XD, Y, F> { | |
87 | type FloatType = F; | |
88 | ||
89 | fn transport_lipschitz_factor(&self, _ : L2Squared) -> Self::FloatType { | |
90 | F::ZERO | |
91 | } | |
92 | } | |
93 | ||
94 | ||
95 | /// TODO: should assume `D` to be positive semi-definite and self-adjoint. | |
96 | #[replace_float_literals(F::cast_from(literal))] | |
97 | impl<'a, F, D, XD, Y, const N : usize> AdjointProductBoundedBy<RNDM<F, N>, D> | |
98 | for ZeroOp<'a, RNDM<F, N>, XD, Y, F> | |
99 | where | |
100 | F : Float, | |
101 | Y : AXPY<F> + Clone, | |
102 | D : Linear<RNDM<F, N>>, | |
103 | { | |
104 | type FloatType = F; | |
105 | /// Return $L$ such that $A_*A ≤ L𝒟$ is bounded by some `other` operator $𝒟$. | |
106 | fn adjoint_product_bound(&self, _ : &D) -> Option<F> { | |
107 | Some(0.0) | |
108 | } | |
109 | } | |
110 |