pub struct ShiftLadderProfile {
pub nodes: Vec<ShiftLadderNodeProfile>,
pub log_det: f64,
pub std_err: f64,
pub total_iterations: usize,
pub hardest_solve: ShiftedPcgTrace,
pub cold_seed_solve: ShiftedPcgTrace,
pub cold_seed_solve_undiagonalized: ShiftedPcgTrace,
pub symmetry_defect: f64,
pub bracket: (f64, f64),
}Expand description
The complete work profile of one rational log-determinant evaluation, node by node, plus the residual history of its single most expensive solve.
This is the #2576 discriminator. The issue’s headline evidence — “loosening the CG tolerance from 1e-8 to 1e-4 changes nothing” — is equally consistent with a solve stagnating at its iteration cap and a solve converging so fast that four decades of tolerance cost a handful of iterations, and those need opposite repairs. The two are told apart by the residual CURVE (geometric decay versus a flat line) and by the Ritz spectrum the same solve hands over for free. Neither existed before: the evaluation reported one summed iteration count and nothing else.
Fields§
§nodes: Vec<ShiftLadderNodeProfile>One row per quadrature node, in ladder (descending-shift) order.
log_det: f64The surrogate value this evaluation produced.
std_err: f64Its Hutchinson error bar.
total_iterations: usizeIterations over the whole ladder — the quantity the existing
reduced_schur_logdet_preconditioner_study reports as a single number.
hardest_solve: ShiftedPcgTraceFull residual and coefficient history of the ladder’s most expensive single solve. This one is WARM-STARTED from the node above it, so its curve begins wherever the previous shift’s solution left it.
cold_seed_solve: ShiftedPcgTraceOne COLD solve at the ladder’s smallest shift, from a zero start, on the first probe.
This is the honest price of the family: the smallest shift is the
worst-conditioned member, and a Krylov space built from the right-hand
side alone — no warm start — is what any evaluator that serves all shifts
from ONE space must pay. It is also the trace whose residual curve is
interpretable, since it starts at ‖r‖/‖b‖ = 1 rather than wherever the
previous node’s solution happened to land.
cold_seed_solve_undiagonalized: ShiftedPcgTraceThe same cold seed solve with NO diagonal, i.e. on the raw operator.
A shifted family shares its Krylov space only when nothing shift-dependent
is applied to it, and this module’s diagonal is 1/(d + t) — shift
dependent by construction. So the two cold traces price the two ways to
serve the family from one space: rescale the operator by its diagonal ONCE
(and carry Σ ln d_g in the value), or keep the operator and pay the raw
conditioning. Which is cheaper is a measurement, not an argument.
symmetry_defect: f64|vᵀSw − wᵀSv| / (‖Sv‖·‖w‖) on a deterministic probe pair. CG is only
valid on a symmetric operator, so a non-negligible value here means no
preconditioner can help and the algorithm itself is wrong for the problem.
bracket: (f64, f64)The [λ_min, λ_max] bracket the plan was sized from. λ_min is the
deflation-floor convention SPECTRAL_DEFLATION_REL_FLOOR·λ_max, i.e. an
ASSUMED lower bound, not a measurement — comparing it against
hardest_solve’s smallest Ritz value is how one sees whether the
quadrature window is sized for a spectrum the operator does not have.
Implementations§
Source§impl ShiftLadderProfile
impl ShiftLadderProfile
Sourcepub fn ladder_concentration(&self) -> f64
pub fn ladder_concentration(&self) -> f64
Iterations of the single hardest solve, against the whole ladder’s total.
A shifted family (S + t_ℓ I) spans ONE Krylov space for every t_ℓ, so
a multi-shift Krylov evaluator would pay the hardest solve and get the
rest as vector updates. This ratio is exactly what such a change could
win, and it is a measurement rather than an argument.
Sourcepub fn one_krylov_space_apply_budget(&self) -> Option<f64>
pub fn one_krylov_space_apply_budget(&self) -> Option<f64>
The applies ONE right-hand side may cost, given the operator’s own conditioning and the plan’s own node count:
½·√κ·ln(2/rel_tol) + node_count— the textbook CG bound for a single solve at the conditioning κ the
cold seed measured, plus one certification apply per node. Nothing here is
chosen: κ is read off the seed’s Ritz values and the node count is the
plan’s, so a better-conditioned operator or a coarser quadrature moves the
budget on its own.
κ is the UNDIAGONALIZED seed’s, because that is the space a family
evaluator can actually share: the diagonal here is 1/(diag(S) + t) and
anything shift-dependent destroys the shift invariance the one-space
argument rests on. The diagonal remains available to the single-shift
repair path, where one fixed t makes it a preconditioner again.
None when the cold seed resolved no spectrum.
Trait Implementations§
Source§impl Clone for ShiftLadderProfile
impl Clone for ShiftLadderProfile
Source§fn clone(&self) -> ShiftLadderProfile
fn clone(&self) -> ShiftLadderProfile
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl Freeze for ShiftLadderProfile
impl RefUnwindSafe for ShiftLadderProfile
impl Send for ShiftLadderProfile
impl Sync for ShiftLadderProfile
impl Unpin for ShiftLadderProfile
impl UnsafeUnpin for ShiftLadderProfile
impl UnwindSafe for ShiftLadderProfile
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.