feat(num): N3 selectable scale-floor clamp mode (HardJava | SmoothBarrier)

The hyper-ideal vertex scale b is floored to keep the geometry valid.  The
original clamp `b<0 → 0.01` mirrors the Java oracle but is only C⁰ (in fact
value-discontinuous at b=0): a Newton step crossing the feasibility boundary
hits a kink that can stall convergence (numerical-stability audit N3).

Rather than replace the Java-faithful behaviour (which would break the golden
parity tests), make the floor a selectable mode so BOTH the Java standpoint
and the clean mathematics are available:

- HyperIdealScaleClamp::HardJava (DEFAULT) — the original snap, bit-for-bit
  faithful to HyperIdealFunctional.java → all parity tests unchanged.
- HyperIdealScaleClamp::SmoothBarrier — C¹ softplus floor
  b ↦ floor + softplus_β(b−floor), β = HYPER_IDEAL_SCALE_SHARPNESS (=100);
  ≈ identity away from the floor, smooth across b=0.  Opt-in.

clamp_hyper_ideal_scale centralises the logic (also folds in the N4 nachzügler:
compute_face_angles used a bare 0.01).  The mode threads with a defaulted
trailing parameter through compute_face_angles, face_angles_from_local_dofs,
evaluate_hyper_ideal, the four hyper_ideal_hessian* variants and
newton_hyper_ideal — so every existing call site keeps HardJava behaviour.

Tests (+4): clamp-function C¹/floor/identity contract, mode-equivalence away
from the boundary, and end-to-end SmoothBarrier convergence to the same Java
golden vector (LawsonHyperIdeal).  296/296 CGAL tests pass.
Documented in doc/math/geometry-modes.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tarik Moussa
2026-05-31 16:27:48 +02:00
parent b7c7d108b5
commit 186f11b11a
7 changed files with 242 additions and 27 deletions

View File

@@ -29,6 +29,13 @@ constexpr double LOG_EDGE_LENGTH_FLOOR = -30.0;
/// Rationale: ensures b > 0 maintains the Lorentzian model's causal structure.
constexpr double HYPER_IDEAL_SCALE_FLOOR = 0.01;
/// Sharpness β of the optional C¹ smooth-barrier scale floor (N3 audit).
/// Only used when the hyper-ideal clamp mode is `SmoothBarrier`; larger β
/// makes the softplus transition tighter around `HYPER_IDEAL_SCALE_FLOOR`
/// (β·floor ≈ 1, so β ≈ 100 keeps the barrier ≈ identity for b ≳ 0.05 while
/// staying C¹ across b = 0). See `clamp_hyper_ideal_scale`.
constexpr double HYPER_IDEAL_SCALE_SHARPNESS = 100.0;
/// Domain guard for asin in spherical_l (spherical_geometry:34).
/// Clamps exp(λ/2) to slightly below 1.0 so asin stays in [−π/2, π/2].
/// Rationale: asin(x) is undefined for |x| > 1; this prevents IEEE Inf/NaN.