pub enum CustomFamilyError {
InvalidInput {
context: &'static str,
reason: String,
},
Optimization {
context: &'static str,
reason: String,
},
DimensionMismatch {
reason: String,
},
NumericalFailure {
reason: String,
},
ConstraintViolation {
reason: String,
},
UnsupportedConfiguration {
reason: String,
},
InnerSolveNotConverged {
cycles: usize,
terminal: Option<InnerConvergenceTerminalState>,
kkt_residual: Option<f64>,
kkt_tol: Option<f64>,
theta_dim: usize,
rho_dim: usize,
psi_dim: usize,
},
BasisDecompositionFailed {
reason: String,
},
IdentifiabilityFailure {
audit: IdentifiabilityAudit,
},
MapUniquenessFailure {
error: MapUniquenessError,
},
TrialPointRefused {
reason: String,
},
}Variants§
InvalidInput
Optimization
DimensionMismatch
NumericalFailure
ConstraintViolation
UnsupportedConfiguration
InnerSolveNotConverged
The inner solve did not reach its KKT condition at THIS trial
point, so the analytic outer gradient/Hessian cannot be exposed
(they require F_beta(beta, theta) = 0).
This is a statement about one theta, not about the problem: the
outer search should treat the trial as infeasible, back off, and
continue. It previously travelled as
UnsupportedConfiguration — a
variant that means the configuration is structurally
unsupported, i.e. fatal — with the real distinction encoded only
in the message text. Downstream then had to recover it by
substring-matching that text, and two call sites reached opposite
verdicts on the same error (#2553). Choosing the variant that says
what happened removes the need to guess.
Fields
terminal: Option<InnerConvergenceTerminalState>The decision variables the inner loop’s verdict was taken on. See
InnerConvergenceTerminalState — a cycle count alone cannot say
which conjunct of the convergence test failed.
kkt_residual: Option<f64>Sup-norm of the projected KKT residual at the terminal inner iterate,
i.e. the quantity this refusal was decided against. A cycle count
alone cannot distinguish a solve that ran out of budget one order
from its tolerance — where the budget is the thing to look at — from
one sitting many orders away, which is a stalled or diverging solve
and a different defect entirely. None when the producing solver
path emits no typed KKT diagnostic (blockwise NR fallback,
eager-stop), which is itself worth seeing in the refusal.
BasisDecompositionFailed
IdentifiabilityFailure
Pre-fit cross-block identifiability audit refused the fit. The
joint design across ParameterBlockSpecs carries a rank
deficiency that the post-joint_null_rotation absorption did
not resolve: two or more blocks contribute the same direction,
or a structural >2-way alias was detected without per-pair
attribution. The full IdentifiabilityAudit is held so
consumers (logs, structured-error sinks, the seed driver’s
classifier) can extract the alias pairs and the summary string
without reparsing.
Fields
audit: IdentifiabilityAuditMapUniquenessFailure
MAP estimate uniqueness condition ker(J^T W J) ∩ ker(S) = {0} is
violated. A null direction of J^T W J carries zero penalty
curvature, so the posterior is flat along that direction and the
MAP is non-unique. The structured MapUniquenessError names the
dominant block so the caller can add the missing penalty or remove
the unpenalised direction.
Fields
error: MapUniquenessErrorTrialPointRefused
A numerical verdict the inner solve reached AT ONE TRIAL POINT: no Laplace mode here, this active face’s curvature refuses certification here, this quadratic subproblem is degenerate here.
Like Self::InnerSolveNotConverged this is a statement about one
theta, not about the problem — an indefinite coefficient point at one
rho is an ordinary Laplace mode at another — so the outer search should
reject the trial and step away, which is what the inner solver’s own
logs say should happen. It is a separate variant because
InnerSolveNotConverged carries a fixed cycles/theta_dim/rho_dim/psi_dim
shape and a message specifically about refusing to expose profile
derivatives; reusing it for a curvature refusal would state something
untrue.
Implementations§
Source§impl CustomFamilyError
impl CustomFamilyError
Sourcepub fn trial_point(reason: impl Into<String>) -> CustomFamilyError
pub fn trial_point(reason: impl Into<String>) -> CustomFamilyError
A numerical refusal raised while evaluating at one trial point.
The named constructor exists so a boundary that knows it is reporting
a rho-local failure can say so, rather than leaning on the blanket
From<String> below and hoping its default is right.
Sourcepub fn into_trial_point(self) -> CustomFamilyError
pub fn into_trial_point(self) -> CustomFamilyError
Grade an already-typed error rho-local WITHOUT re-wrapping one that already says so.
A boundary whose whole contract is “evaluate at this rho” answers the
trial-point question for everything that crosses it (see the
From<String> rationale below and gam#2590). Doing that with
Self::trial_point on a value that is already a
Self::TrialPointRefused renders the inner error to text and prefixes
it a second time, which is how
inner solve refused this trial point: inner solve refused this trial
point: synthetic outer objective failure: block[0] evaluate()reached a user (gam#2667). The doubled prefix was cosmetic; the loss it
made visible is not, because rendering to String discards the variant
and only From<String>’s default put a classification back.
So: keep the error untouched when it already answers the question
(is_trial_point_infeasible()), and only render one that does not –
which is the single case where the classification is genuinely being
changed rather than restated.
Source§impl CustomFamilyError
impl CustomFamilyError
Sourcepub fn is_trial_point_infeasible(&self) -> bool
pub fn is_trial_point_infeasible(&self) -> bool
Whether a failure of this kind invalidates the whole outer run or only the trial point it was produced at.
The producer’s judgement, made once against the variant. It replaces a downstream substring match on the rendered message that classified one variant two different ways depending on which call site it crossed (#2553).
The match is deliberately exhaustive with no wildcard arm: a new variant must be classified when it is added, rather than defaulting to whichever answer happens to be listed last.
Trait Implementations§
Source§impl Clone for CustomFamilyError
impl Clone for CustomFamilyError
Source§fn clone(&self) -> CustomFamilyError
fn clone(&self) -> CustomFamilyError
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for CustomFamilyError
impl Debug for CustomFamilyError
Source§impl Display for CustomFamilyError
impl Display for CustomFamilyError
Source§impl Error for CustomFamilyError
impl Error for CustomFamilyError
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()
Source§impl From<CustomFamilyError> for EstimationError
impl From<CustomFamilyError> for EstimationError
Source§fn from(source: CustomFamilyError) -> EstimationError
fn from(source: CustomFamilyError) -> EstimationError
Source§impl From<String> for CustomFamilyError
impl From<String> for CustomFamilyError
Source§fn from(value: String) -> CustomFamilyError
fn from(value: String) -> CustomFamilyError
§Why this lands on TrialPointRefused and not InvalidInput
A String cannot carry the one bit the outer smoothing search needs —
is this failure a property of the trial point, or of the problem? — so
any conversion from it must answer by default. This one used to answer
InvalidInput, the variant Self::is_trial_point_infeasible returns
false for, and gam-custom-family’s inner solver reports every
refusal as Err(String). So “there is no Laplace mode at this rho”, a
verdict about one rho, was graded fatal and killed the whole fit at the
first probe, at an optimizer whose seed loop has the correct branch one
line above the one it took (gam#2590).
The default is not a coin flip, because the two mistakes are not comparable:
- A structural failure graded rho-local recurs at every probed rho. The seed loop exhausts, the run still fails, and it fails quoting this same reason — after a bounded number of cheap, identical inner failures.
- A rho-local refusal graded structural aborts a fit that was perfectly fittable one rho away. Measured twice: #2553, #2590.
So where the type system forces a guess, the guess must be
“trial point”. Where a caller knows better in either direction, it
should construct the variant it means — Self::trial_point or the
structural variant — instead of routing through here.
Auto Trait Implementations§
impl Freeze for CustomFamilyError
impl RefUnwindSafe for CustomFamilyError
impl Send for CustomFamilyError
impl Sync for CustomFamilyError
impl Unpin for CustomFamilyError
impl UnsafeUnpin for CustomFamilyError
impl UnwindSafe for CustomFamilyError
Blanket Implementations§
impl<T> Allocation for T
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> DistributionExt for Twhere
T: ?Sized,
impl<T> DistributionExt for Twhere
T: ?Sized,
impl<T, U> Imply<T> for U
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pointable for T
impl<T> Pointable for T
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.