Clear unavailable gravity measurements before each attempt
This commit is contained in:
@@ -33,9 +33,30 @@ Two separate requirements remain:
|
||||
|
||||
Diagnostics retain the raw affine discrepancy, raw target defect, arithmetic
|
||||
estimate, and resulting target threshold separately. Nonfinite or negative
|
||||
norm inputs fail the assessment. A failed preparation leaves these measurements
|
||||
unavailable rather than reusing the preceding trial's values. Diagnostics also
|
||||
report whether compact gravity operator and inverse applications were selected.
|
||||
norm inputs fail the assessment. Each gravity attempt clears its correction
|
||||
norm and prepared-assessment measurements before the raw candidate preparation.
|
||||
An early preparation or inner-solve failure therefore leaves unmeasured values
|
||||
as NaN, rather than reusing the preceding attempt's values. Initial gravity
|
||||
completion follows the same rule. A failure in the corrected preparation can
|
||||
still retain that attempt's measured correction norm.
|
||||
|
||||
The last completed inner solve's true defect and cumulative solve/iteration/
|
||||
failure/time counters have a different lifetime: a candidate that fails before
|
||||
calling the inner solver does not erase them. A line-search candidate rejected
|
||||
before invoking the gravity strategy does not begin an auxiliary attempt and
|
||||
leaves all last-attempt diagnostics intact. Diagnostic consumers must distinguish
|
||||
these meanings. Diagnostics also report whether compact gravity operator and
|
||||
inverse applications were selected.
|
||||
|
||||
`lastLinearReportSpace` labels the retained `lastLinearSolve` report from the
|
||||
outer strategy's `Solve`. A later positivity-direction relift can fail while
|
||||
that outer report remains converged in reduced coordinates. The evaluation then
|
||||
reports `linear_solve_failure`; the auxiliary failure is reflected by the gravity
|
||||
failure counter and last completed inner true defect. Changing only the report
|
||||
space would incorrectly relabel the retained reduced-system norms. The full
|
||||
lifted Newton gate precedes feasibility repair; a repaired direction must pass
|
||||
its relift, descent check, and nonlinear acceptance, but is not claimed to solve
|
||||
the original Newton equations.
|
||||
|
||||
Three focused tests, appended to `tests/solver/gravity_reduction.cpp`, cover
|
||||
large cancelling contributions, rejection of defects beyond either gate,
|
||||
@@ -43,3 +64,17 @@ nonfinite measurements, and scaling over twenty-four orders of magnitude.
|
||||
The real stellar rejection must still be reproduced and reassessed; passing a
|
||||
synthetic arithmetic test alone establishes neither the hypothesis nor stellar
|
||||
convergence.
|
||||
|
||||
|
||||
## Reporting regression
|
||||
|
||||
Branch `research/gravity-trial-diagnostics-20260917` moves this reset to a shared
|
||||
attempt-entry helper, used by both trial strategies and initial completion.
|
||||
Existing production rollback fixtures now assert finite measurements after a
|
||||
completed curvature assessment, and unavailable prepared/correction fields after
|
||||
a failed initial inner solve while retaining its finite true defect and counters.
|
||||
No new stellar fixture or numerical behavior is introduced. The source-level
|
||||
success-then-early-failure path is covered by the unconditional shared reset;
|
||||
a separate expensive campaign is not justified for this reporting change.
|
||||
Build/run of the added assertions is deferred until the running immutable
|
||||
production campaign completes.
|
||||
|
||||
@@ -81,9 +81,17 @@ export namespace mean_field::solver::nonlinear {
|
||||
std::uint64_t gravityPreparedFailures{0};
|
||||
bool compactGravityOperator{false};
|
||||
bool compactGravityInverse{false};
|
||||
// Coordinates of the evaluation's lastLinearSolve report. A later
|
||||
// feasibility relift or trial solve has its own auxiliary diagnostics
|
||||
// and does not replace that report or relabel its stored norms.
|
||||
LinearReportSpace lastLinearReportSpace{LinearReportSpace::full_system};
|
||||
double gravitySolveSeconds{0.0};
|
||||
// Last completed auxiliary solve; a later failure before Solve leaves
|
||||
// this value and the cumulative counters unchanged.
|
||||
double lastGravityTrueResidual{0.0};
|
||||
// Current gravity attempt: NaN until that attempt measures the value.
|
||||
// Candidates rejected before invoking gravity leave its prior attempt
|
||||
// untouched because no auxiliary work was attempted.
|
||||
double lastGravityCorrectionNorm{0.0};
|
||||
double lastGravityPreparedDefect{0.0};
|
||||
double lastGravityAffineDisagreement{0.0};
|
||||
|
||||
@@ -140,6 +140,17 @@ namespace mean_field::solver::detail {
|
||||
}
|
||||
|
||||
protected:
|
||||
void BeginGravityAttempt() noexcept {
|
||||
trialSolveSucceeded = true;
|
||||
// These measurements belong to this attempt. An early preparation
|
||||
// or inner-solve failure must not publish the preceding trial's
|
||||
// successful assessment. The last completed solve and cumulative
|
||||
// counters deliberately retain their separate lifetime.
|
||||
lastCorrectionNorm = lastPreparedDefect = lastAffineDisagreement =
|
||||
lastArithmeticAllowance = lastPreparedTargetThreshold =
|
||||
std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
|
||||
void Refresh(State &state) {
|
||||
// Preparing a trial invalidates both normalized and physical
|
||||
// inverses. Refreshing only the restricted wrapper would hide this.
|
||||
@@ -157,8 +168,6 @@ namespace mean_field::solver::detail {
|
||||
}
|
||||
|
||||
auto ApplyCorrection(State &state) {
|
||||
lastPreparedDefect = lastAffineDisagreement = lastArithmeticAllowance =
|
||||
lastPreparedTargetThreshold = std::numeric_limits<double>::quiet_NaN();
|
||||
const auto &partition = subsystem.GetPartition();
|
||||
partition.InjectGravityValues(gravityCorrection, fullCorrection);
|
||||
subsystem.GetOperator().Mult(gravityCorrection, gravityAction);
|
||||
@@ -249,7 +258,7 @@ namespace mean_field::solver::detail {
|
||||
return true;
|
||||
}
|
||||
auto PrepareTrial(State &state, const double alpha) {
|
||||
this->trialSolveSucceeded = true;
|
||||
this->BeginGravityAttempt();
|
||||
auto preparation = state.PrepareTrial();
|
||||
if (!preparation) { return preparation; }
|
||||
this->Refresh(state);
|
||||
@@ -281,6 +290,7 @@ namespace mean_field::solver::detail {
|
||||
m_rhs(m_operator.Height()), m_correction(m_operator.Width()) { }
|
||||
|
||||
bool Initialize(State &state, nonlinear::NumericalStrategyDiagnostics &diagnostics) {
|
||||
this->BeginGravityAttempt();
|
||||
const auto &partition = this->subsystem.GetPartition();
|
||||
partition.GatherGravityResiduals(state.acceptedNormalizedResidual, this->gravityResidual);
|
||||
diagnostics.initialGravityResidual = StrategyNorm(this->gravityResidual, this->subsystem.GetCommunicator());
|
||||
@@ -343,11 +353,14 @@ namespace mean_field::solver::detail {
|
||||
this->subsystem.GetPartition().GatherRetainedValues(state.normalizedCorrection, m_correction);
|
||||
this->lastSolve = m_operator.TryLiftCorrection(m_correction, state.linearRightHandSide,
|
||||
state.normalizedCorrection);
|
||||
// Keep the report space attached to the outer Solve result; this
|
||||
// later auxiliary failure is reported through DirectionSolveFailed
|
||||
// and the gravity counters/last completed inner defect.
|
||||
return this->lastSolve.Converged();
|
||||
}
|
||||
|
||||
auto PrepareTrial(State &state, double) {
|
||||
this->trialSolveSucceeded = true;
|
||||
this->BeginGravityAttempt();
|
||||
auto preparation = state.PrepareTrial();
|
||||
if (!preparation) { return preparation; }
|
||||
this->Refresh(state);
|
||||
|
||||
@@ -196,6 +196,11 @@ TEST_CASE("Production gravity strategies retain optional model borders and resto
|
||||
CHECK(report.diagnostics().lastLinearSolve->iterations == 0);
|
||||
CHECK(report.diagnostics().numericalStrategies.gravitySolves > 0);
|
||||
CHECK(report.diagnostics().numericalStrategies.gravityFailures == 0);
|
||||
CHECK(std::isfinite(report.diagnostics().numericalStrategies.lastGravityCorrectionNorm));
|
||||
CHECK(std::isfinite(report.diagnostics().numericalStrategies.lastGravityPreparedDefect));
|
||||
CHECK(std::isfinite(report.diagnostics().numericalStrategies.lastGravityAffineDisagreement));
|
||||
CHECK(std::isfinite(report.diagnostics().numericalStrategies.lastGravityArithmeticAllowance));
|
||||
CHECK(std::isfinite(report.diagnostics().numericalStrategies.lastGravityPreparedTargetThreshold));
|
||||
CHECK(report.lastAcceptedCheckpointView().valid());
|
||||
}
|
||||
REQUIRE(context.isReady());
|
||||
@@ -237,6 +242,15 @@ TEST_CASE("A failed initial gravity completion preserves the accepted stellar ch
|
||||
CHECK(report.diagnostics().numericalStrategies.initialGravityResidual > 0.0);
|
||||
CHECK(report.diagnostics().numericalStrategies.gravitySolves == 1);
|
||||
CHECK(report.diagnostics().numericalStrategies.gravityFailures == 1);
|
||||
const auto &auxiliary = report.diagnostics().numericalStrategies;
|
||||
// A completed but unsuccessful inner solve has a meaningful true
|
||||
// defect. No correction/prepared assessment occurred in this attempt.
|
||||
CHECK(std::isfinite(auxiliary.lastGravityTrueResidual));
|
||||
CHECK(std::isnan(auxiliary.lastGravityCorrectionNorm));
|
||||
CHECK(std::isnan(auxiliary.lastGravityPreparedDefect));
|
||||
CHECK(std::isnan(auxiliary.lastGravityAffineDisagreement));
|
||||
CHECK(std::isnan(auxiliary.lastGravityArithmeticAllowance));
|
||||
CHECK(std::isnan(auxiliary.lastGravityPreparedTargetThreshold));
|
||||
CHECK(report.diagnostics().acceptedNonlinearIterations == 0);
|
||||
CHECK(report.lastAcceptedCheckpointView().valid());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user