From 00a477e38732519ee5164560ce07ffbe2d5e7f93 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 14 Oct 2026 06:51:42 +0200 Subject: [PATCH] cultmath tests: snoise second-difference check tolerates kernel-edge points by a stated fraction Co-Authored-By: Claude Opus 5.5 --- .../tests/CultMath.Tests/SpanPrimitiveTests.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/cultmath/tests/CultMath.Tests/SpanPrimitiveTests.cs b/packages/cultmath/tests/CultMath.Tests/SpanPrimitiveTests.cs index 20d87e93..44814195 100644 --- a/packages/cultmath/tests/CultMath.Tests/SpanPrimitiveTests.cs +++ b/packages/cultmath/tests/CultMath.Tests/SpanPrimitiveTests.cs @@ -144,6 +144,7 @@ public sealed class SpanPrimitiveTests var random = new System.Random(0x5A12); double worst = 0.0, largest = 0.0; var compared = 0; + var outside = 0; for (var k = 0; k < 4000; k++) { var p = LatticePoint(random); @@ -154,7 +155,11 @@ public sealed class SpanPrimitiveTests // Richardson on the O(h^2) second difference: (4 S(h/2) - S(h)) / 3 is O(h^4). Two such // extrapolations, from (h, h/2) and from (h/2, h/4), differ by about fifteen times the // error of the finer one, so the comparison is against the finer and its tolerance is - // four times that gap, plus the roundoff of snoise (a few ulp) over (h/4)^2. + // four times that gap, plus the roundoff of snoise (a few ulp) over (h/4)^2. Near a + // kernel's edge (m = 0) snoise's fourth derivative jumps and the extrapolation loses its + // order: such an entry may exceed the tight tolerance, but never by more than the gap + // between the last two second differences (an error that shrinks at least linearly in h + // is at most that gap), and the tight tolerance must hold for all but a fraction. const float h = 1.0f / 16.0f; var s0 = SecondDifference(p, i, j, h); var s1 = SecondDifference(p, i, j, h / 2.0f); @@ -162,16 +167,20 @@ public sealed class SpanPrimitiveTests var coarseExtrapolation = (4.0 * s1 - s0) / 3.0; var extrapolated = (4.0 * s2 - s1) / 3.0; var tolerance = 4.0 * Math.Abs(extrapolated - coarseExtrapolation) + 64.0 * Unit / ((h / 4.0) * (h / 4.0)); + var loose = tolerance + 2.0 * Math.Abs(s1 - s2); var error = Math.Abs(hessian[i][j] - extrapolated); worst = Math.Max(worst, error / tolerance); largest = Math.Max(largest, Math.Abs(hessian[i][j])); compared++; - Assert.True(error <= tolerance, $"snoise_hessian({p})[{i}][{j}] = {hessian[i][j]:R} differs from the extrapolated second difference of snoise {extrapolated:R} by {error:R}, over the measured tolerance {tolerance:R}"); + if (error > tolerance) + outside++; + Assert.True(error <= loose, $"snoise_hessian({p})[{i}][{j}] = {hessian[i][j]:R} differs from the extrapolated second difference of snoise {extrapolated:R} by {error:R}, over the measured tolerance {loose:R}"); } } - output.WriteLine($"snoise_hessian vs Richardson second differences of snoise over 4000 seeded points: {compared} entries, worst error {worst:F3} of its tolerance, largest |H| {largest:R}"); + output.WriteLine($"snoise_hessian vs Richardson second differences of snoise over 4000 seeded points: {compared} entries, {outside} over the tight tolerance, worst error {worst:F3} of it, largest |H| {largest:R}"); Assert.True(largest > 10.0, $"the sample never meets curvature above 10 (largest {largest:R})"); + Assert.True(outside <= compared / 200, $"{outside} of {compared} entries are over the tight Richardson tolerance, more than 0.5%"); } [Fact]