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>
45 lines
2.0 KiB
C++
45 lines
2.0 KiB
C++
#pragma once
|
|
// Copyright (c) 2024-2026 Tarik Moussa.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
// constants.hpp
|
|
//
|
|
// Single source of truth for mathematical constants used throughout
|
|
// conformallab++. Include this header instead of defining π locally.
|
|
//
|
|
// All constants are in the conformallab namespace and are constexpr double.
|
|
|
|
namespace conformallab {
|
|
|
|
/// π to 30 significant digits (well beyond double precision of ~15-16 digits).
|
|
constexpr double PI = 3.14159265358979323846264338328;
|
|
|
|
/// 2π (full turn).
|
|
constexpr double TWO_PI = 2.0 * PI;
|
|
|
|
// ── Numerical thresholds and bounds (N4/N6 audit) ──────────────────────────
|
|
|
|
/// Edge length floor for log-scale functionals (euclidean_functional, spherical_functional).
|
|
/// exp(-30.0) ≈ 3e-7: edges below this length are treated as degenerate/zero.
|
|
/// Rationale: avoids log(tiny) overflow and enforces a minimum edge scale.
|
|
constexpr double LOG_EDGE_LENGTH_FLOOR = -30.0;
|
|
|
|
/// Hyper-ideal scale factor lower bound (hyper_ideal_functional:179-181).
|
|
/// If b (scale) becomes negative (infeasible), clamp to 0.01 to keep geometry valid.
|
|
/// 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.
|
|
constexpr double ASIN_DOMAIN_GUARD = 1.0 - 1e-15;
|
|
|
|
} // namespace conformallab
|