--- a/src/linops.rs Wed Apr 30 01:06:25 2025 -0500 +++ b/src/linops.rs Wed Apr 30 16:39:01 2025 -0500 @@ -3,6 +3,7 @@ */ use crate::direct_product::Pair; +use crate::error::DynResult; use crate::instance::Instance; pub use crate::mapping::{Composition, DifferentiableImpl, Mapping, Space}; use crate::norms::{Linfinity, Norm, NormExponent, PairNorm, L1, L2}; @@ -84,7 +85,9 @@ /// This is not expected to be the norm, just any bound on it that can be /// reasonably implemented. The [`NormExponent`] `xexp` indicates the norm /// in `X`, and `codexp` in the codomain. - fn opnorm_bound(&self, xexp: XExp, codexp: CodExp) -> F; + /// + /// This may fail with an error if the bound is for some reason incalculable. + fn opnorm_bound(&self, xexp: XExp, codexp: CodExp) -> DynResult<F>; } // Linear operator application into mutable target. The [`AsRef`] bound @@ -183,8 +186,8 @@ F: Num, E: NormExponent, { - fn opnorm_bound(&self, _xexp: E, _codexp: E) -> F { - F::ONE + fn opnorm_bound(&self, _xexp: E, _codexp: E) -> DynResult<F> { + Ok(F::ONE) } } @@ -267,8 +270,8 @@ E1: NormExponent, E2: NormExponent, { - fn opnorm_bound(&self, _xexp: E1, _codexp: E2) -> F { - F::ZERO + fn opnorm_bound(&self, _xexp: E1, _codexp: E2) -> DynResult<F> { + Ok(F::ZERO) } } @@ -351,9 +354,9 @@ T: BoundedLinear<X, Xexp, Zexp, F, Codomain = Z>, S: BoundedLinear<Z, Zexp, Yexp, F>, { - fn opnorm_bound(&self, xexp: Xexp, yexp: Yexp) -> F { + fn opnorm_bound(&self, xexp: Xexp, yexp: Yexp) -> DynResult<F> { let zexp = self.intermediate_norm_exponent; - self.outer.opnorm_bound(zexp, yexp) * self.inner.opnorm_bound(xexp, zexp) + Ok(self.outer.opnorm_bound(zexp, yexp)? * self.inner.opnorm_bound(xexp, zexp)?) } } @@ -691,12 +694,12 @@ &self, PairNorm(expa, expb, _): PairNorm<ExpA, ExpB, $expj>, expr: ExpR, - ) -> F { + ) -> DynResult<F> { // An application of the triangle inequality bounds the norm by the maximum // of the individual norms. A simple observation shows this to be exact. - let na = self.0.opnorm_bound(expa, expr); - let nb = self.1.opnorm_bound(expb, expr); - na.max(nb) + let na = self.0.opnorm_bound(expa, expr)?; + let nb = self.1.opnorm_bound(expb, expr)?; + Ok(na.max(nb)) } } @@ -715,12 +718,12 @@ &self, expa: ExpA, PairNorm(exps, expt, _): PairNorm<ExpS, ExpT, $expj>, - ) -> F { + ) -> DynResult<F> { // This is based on the rule for RowOp and ‖A^*‖ = ‖A‖, hence, // for A=[S; T], ‖A‖=‖[S^*, T^*]‖ ≤ max{‖S^*‖, ‖T^*‖} = max{‖S‖, ‖T‖} - let ns = self.0.opnorm_bound(expa, exps); - let nt = self.1.opnorm_bound(expa, expt); - ns.max(nt) + let ns = self.0.opnorm_bound(expa, exps)?; + let nt = self.1.opnorm_bound(expa, expt)?; + Ok(ns.max(nt)) } } };