Skip to content

Commit 7ed5a2c

Browse files
committed
refactor: Enhance Newton's method with early termination, improved line search, and refined candidate processing in extremum evaluations
1 parent 4fd84e6 commit 7ed5a2c

4 files changed

Lines changed: 273 additions & 74 deletions

File tree

src/FoundationClasses/TKMath/MathSys/MathSys_Newton2D.hxx

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -450,14 +450,38 @@ Newton2DResult Newton2DSymmetric(const Function& theFunc,
450450
aNewU = std::max(aExtUMin, std::min(aExtUMax, aNewU));
451451
aNewV = std::max(aExtVMin, std::min(aExtVMax, aNewV));
452452

453+
// Step size relative to domain - used for early termination and line search skip
454+
const double aStepNormSq = aDU * aDU + aDV * aDV;
455+
const double aDomainSizeSq = aDomainU * aDomainU + aDomainV * aDomainV;
456+
const double aRelStepSq = aStepNormSq / std::max(aDomainSizeSq, THE_HESSIAN_DEGENERACY_ABS);
457+
458+
// Early convergence: if step is very small relative to domain, we're converged
459+
if (aRelStepSq < THE_NEWTON_STEP_TOL_FACTOR * THE_NEWTON_STEP_TOL_FACTOR)
460+
{
461+
aRes.FNorm = std::sqrt(aFNormSq);
462+
aRes.Status = Status::OK;
463+
return aRes;
464+
}
465+
466+
// Skip line search for small steps - Newton is working well
467+
// This avoids expensive Value() calls when not needed
468+
const bool aSkipLineSearch = (aRelStepSq < THE_NEWTON2D_SKIP_LINESEARCH_SQ);
469+
453470
// Line search if step increases function value significantly
454471
double aNewF1, aNewF2;
455-
if (theFunc.Value(aNewU, aNewV, aNewF1, aNewF2))
472+
if (!aSkipLineSearch && theFunc.Value(aNewU, aNewV, aNewF1, aNewF2))
456473
{
457474
double aNewFNormSq = aNewF1 * aNewF1 + aNewF2 * aNewF2;
458475

459-
// Backtrack if function increased too much
460-
if (aNewFNormSq > aFNormSq * THE_NEWTON2D_BACKTRACK_TRIGGER)
476+
// Compute directional derivative for Armijo condition: grad_f . d
477+
// For f = 0.5*(F1^2 + F2^2), grad_f = [F1, F2] (simplified)
478+
// d = [dU, dV], so grad_f . d = F1*dU + F2*dV
479+
const double aDirectionalDeriv = aF1 * aDU + aF2 * aDV;
480+
481+
// Backtrack if function increased too much OR Armijo not satisfied
482+
// Armijo: f(x + d) <= f(x) + c1 * grad_f . d
483+
const bool aArmijoFailed = (aNewFNormSq > aFNormSq + THE_ARMIJO_C1 * aDirectionalDeriv);
484+
if (aNewFNormSq > aFNormSq * THE_NEWTON2D_BACKTRACK_TRIGGER || aArmijoFailed)
461485
{
462486
// Use quadratic interpolation for first estimate
463487
// Model: f(α) ≈ f(0) + f'(0)*α + c*α², where c = (f(1) - f(0) - f'(0))/1
@@ -492,7 +516,9 @@ Newton2DResult Newton2DSymmetric(const Function& theFunc,
492516
if (theFunc.Value(aTryU, aTryV, aTryF1, aTryF2))
493517
{
494518
double aTryFNormSq = aTryF1 * aTryF1 + aTryF2 * aTryF2;
495-
if (aTryFNormSq < aFNormSq * THE_NEWTON2D_BACKTRACK_ACCEPT)
519+
// Accept if Armijo condition satisfied: f(x + α*d) <= f(x) + c1*α*(grad·d)
520+
const double aArmijoThreshold = aFNormSq + THE_ARMIJO_C1 * aAlpha * aDirectionalDeriv;
521+
if (aTryFNormSq <= aArmijoThreshold || aTryFNormSq < aFNormSq * THE_NEWTON2D_BACKTRACK_ACCEPT)
496522
{
497523
aNewU = aTryU;
498524
aNewV = aTryV;

src/FoundationClasses/TKMath/MathUtils/MathUtils_Config.hxx

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ constexpr double THE_NEWTON2D_MAX_STEP_RATIO = 0.5;
4747

4848
//! Domain extension factor for soft boundary handling.
4949
//! Solutions slightly outside domain (by this fraction) are allowed if converged.
50-
constexpr double THE_NEWTON2D_DOMAIN_EXT = 0.01;
50+
//! Reduced to 1e-4 to closely match old algorithm behavior.
51+
constexpr double THE_NEWTON2D_DOMAIN_EXT = 1.0e-4;
5152

5253
//! Stagnation progress ratio - improvement required each iteration to avoid stagnation.
5354
//! Value of 0.999 means at least 0.1% improvement required.
@@ -57,7 +58,11 @@ constexpr double THE_NEWTON2D_STAGNATION_RATIO = 0.999;
5758
constexpr int THE_NEWTON2D_STAGNATION_COUNT = 3;
5859

5960
//! Maximum line search backtracking iterations.
60-
constexpr int THE_NEWTON2D_LINE_SEARCH_MAX = 12;
61+
constexpr int THE_NEWTON2D_LINE_SEARCH_MAX = 8;
62+
63+
//! Relative step threshold below which line search is skipped.
64+
//! If step^2 / domain^2 < threshold, Newton is converging well.
65+
constexpr double THE_NEWTON2D_SKIP_LINESEARCH_SQ = 0.01;
6166

6267
//! Tolerance relaxation factor for accepting stagnated solutions.
6368
//! Stagnated solution accepted if |F| < tolerance * factor.
@@ -74,8 +79,27 @@ constexpr double THE_NEWTON2D_BACKTRACK_ACCEPT = 1.2;
7479
//! Maximum relaxation factor for solutions at max iterations.
7580
constexpr double THE_NEWTON2D_MAXITER_RELAX = 10.0;
7681

77-
//! High precision tolerance target (5e-8, better than Precision::Confusion).
78-
constexpr double THE_HIGH_PRECISION_TOL = 5.0e-8;
82+
//==================================================================================================
83+
//! @name Hessian Classification Constants
84+
//! Constants for extremum classification using second derivatives.
85+
//==================================================================================================
86+
87+
//! Relative tolerance for Hessian degeneracy detection.
88+
//! If |det(H)| < threshold * |H_ii| * |H_jj|, Hessian is considered degenerate.
89+
constexpr double THE_HESSIAN_DEGENERACY_REL = 1.0e-8;
90+
91+
//! Absolute tolerance for Hessian degeneracy detection.
92+
//! Minimum threshold for determinant comparison.
93+
constexpr double THE_HESSIAN_DEGENERACY_ABS = 1.0e-20;
94+
95+
//==================================================================================================
96+
//! @name Line Search Constants
97+
//! Constants for line search acceptance conditions.
98+
//==================================================================================================
99+
100+
//! Armijo condition constant (sufficient decrease).
101+
//! Step accepted if: f(x + alpha*d) <= f(x) + c1 * alpha * grad_f . d
102+
constexpr double THE_ARMIJO_C1 = 1.0e-4;
79103

80104
//! Configuration for iterative solvers.
81105
//! Provides common settings for convergence criteria and iteration limits.

src/ModelingData/TKGeomBase/ExtremaPS/ExtremaPS.hxx

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,27 @@ constexpr double THE_CELL_EXPAND_RATIO = 0.1;
7575
//! Ratio of distance for scaling tolerance in cell search.
7676
constexpr double THE_DISTANCE_SCALE_RATIO = 0.1;
7777

78+
//==================================================================================================
79+
//! @name Early Termination and Candidate Processing Constants
80+
//! Constants controlling candidate filtering, early termination, and iteration limits.
81+
//==================================================================================================
82+
7883
//! Threshold for skipping max candidates that are clearly worse.
84+
//! For Max mode: skip if estDist < bestDist * threshold (i.e., 90% of best).
7985
constexpr double THE_MAX_SKIP_THRESHOLD = 0.9;
8086

81-
//! Threshold for refined distance comparison (slightly less than 1.0).
82-
constexpr double THE_REFINED_DIST_THRESHOLD = 0.99;
87+
//! Threshold margin for Min mode early termination.
88+
//! For Min mode: skip if estDist > bestDist * (1 + margin).
89+
//! Value of 0.2 means skip candidates 20% worse than current best.
90+
constexpr double THE_MIN_SKIP_MARGIN = 0.2;
91+
92+
//! Maximum number of candidates to process before stopping.
93+
//! Limits Newton iterations per grid scan for performance.
94+
constexpr int THE_MAX_CANDIDATES_TO_PROCESS = 50;
95+
96+
//! Threshold for refined distance comparison.
97+
//! Grid fallback accepted if refinedDist < currentMin * threshold.
98+
constexpr double THE_REFINED_DIST_THRESHOLD = 1.0;
8399

84100
//! Relaxation factor for gradient-based zero detection.
85101
//! Multiplied with tolerance for more robust extremum detection.
@@ -89,24 +105,46 @@ constexpr double THE_GRADIENT_TOL_FACTOR = 100.0;
89105
//! Multiplier for Newton retry tolerance when initial Newton fails.
90106
constexpr double THE_NEWTON_RETRY_TOL_FACTOR = 10.0;
91107

92-
//! High precision tolerance target (5e-8, better than Precision::Confusion ~1e-7).
93-
//! Used for multi-start Newton and two-phase refinement.
94-
constexpr double THE_HIGH_PRECISION_TOL = 5.0e-8;
108+
//==================================================================================================
109+
//! @name Cache and Coherent Scanning Constants
110+
//! Constants for spatial coherence optimization and trajectory prediction.
111+
//==================================================================================================
95112

96113
//! Squared threshold for spatial coherence optimization.
97114
//! Query points within this squared distance use cached solution.
115+
//! Value of 100.0 corresponds to distance of 10.0 units.
98116
constexpr double THE_COHERENCE_THRESHOLD_SQ = 100.0;
99117

100118
//! Minimum ratio for trajectory prediction (step magnitude ratio).
119+
//! Ratios below this indicate irregular step sizes.
101120
constexpr double THE_TRAJECTORY_MIN_RATIO = 0.5;
102121

103122
//! Maximum ratio for trajectory prediction (step magnitude ratio).
123+
//! Ratios above this indicate acceleration/deceleration too large.
104124
constexpr double THE_TRAJECTORY_MAX_RATIO = 2.0;
105125

106126
//! Minimum cosine for trajectory prediction (direction alignment).
107127
//! Values above this indicate roughly same direction (< ~45 degrees).
108128
constexpr double THE_TRAJECTORY_MIN_COS = 0.7;
109129

130+
//! Minimum cosine for quadratic extrapolation (high coherence).
131+
//! Values above this indicate very smooth trajectory (< ~25 degrees).
132+
constexpr double THE_TRAJECTORY_QUADRATIC_COS = 0.9;
133+
134+
//! Cache size for coherent scanning (number of solutions stored).
135+
//! Increased from 3 to 5 to enable quadratic extrapolation.
136+
constexpr int THE_CACHE_SIZE = 5;
137+
138+
//! Sanity factor for cache result validation.
139+
//! If cache-based Newton result has squared distance > (theTol^2 * factor),
140+
//! it's rejected as likely converging to wrong local minimum.
141+
//! Value of 1e6 allows reasonable tolerance range while catching gross errors.
142+
constexpr double THE_CACHE_SANITY_FACTOR = 1.0e6;
143+
144+
//! Velocity adjustment limit for trajectory prediction.
145+
//! Limits acceleration factor to prevent overshoot.
146+
constexpr double THE_VELOCITY_ADJUST_LIMIT = 1.5;
147+
110148
//! Maximum number of Newton iterations for grid optimization.
111149
constexpr int THE_MAX_GOLDEN_ITERATIONS = 50;
112150

0 commit comments

Comments
 (0)