Gate test: restore the affine gate's detail ball and add FogField.InsideFog to the field list [affine-gate-loses-fog-culls] [interval-gate-detail-unpinned]

Deleting the affine gate's detail ball (51a4034c) gave up 6 of 5933 provable culls inside the fog
(first: (b) inside the fog [affine]); the gate never gives up a provable cull, and a 1.4% probe
saving does not buy breaking that. The detail ball is back in the affine gate, and the gate test
now includes the fog interior, the only field where the interval gate's detail ball decides, so
saturating either gate's detail ball fails the test.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-04 12:12:36 +02:00
commit c01ff025bb

View file

@ -938,7 +938,7 @@ public sealed class NoiseBoundTests
/// empty (its upper density 0) must be proved empty gated too. A gate that errs toward giving up
/// (the reach inflated, a gradient or Hessian term overstated) loosens the bound exactly there and
/// costs only culling, which no enclosure test sees; a gate that errs the other way only costs probes,
/// which the cost contract (IntervalSkipHalvesEvaluations) sees. Over seeded slices of both wells at
/// which the cost contract (IntervalSkipHalvesEvaluations) sees. Over seeded slices of both wells and the fog interior at
/// warp 0 and the Aetheria warp, N = 8, in both modes, no slice the ungated bound proves empty is
/// left open by the gated one, and at least 200 are proved empty.
/// </summary>
@ -949,7 +949,7 @@ public sealed class NoiseBoundTests
var (proved, lost) = (0, new List<string>());
foreach (var mode in new[] { BoundMode.Interval, BoundMode.Affine })
foreach (var warp in new[] { 0.0f, FogField.AetheriaWarp })
foreach (var field in new[] { FogField.DeepWell(warp, mode), FogField.Wells(warp, mode) })
foreach (var field in new[] { FogField.DeepWell(warp, mode), FogField.Wells(warp, mode), FogField.InsideFog(warp, mode) })
for (var t = 0; t < 1500; t++)
{
var tile = field.DrawTile(random, 8);
@ -1796,11 +1796,6 @@ public sealed class NoiseBoundTests
return low ? new float2(-1.0f, min(-1.0f + e, 1.0f)) : new float2(max(1.0f - e, -1.0f), 1.0f);
}
// The affine gate takes the detail octave at its full range: its best-case ball never decided a probe
// on the gate test's slices or the deep wells, and a gate that skips it proves the same slices with
// fewer probes. (The interval gate keeps its detail ball: inside the fog, row (b), it decides.)
private static readonly float2 DetailRange = new(-0.5f, 0.5f);
private static float2 Clip(float2 range) => new(max(range.x, -1.0f), min(range.y, 1.0f));
/// <summary>
@ -1823,7 +1818,7 @@ public sealed class NoiseBoundTests
foreach (var low in new[] { true, false })
{
var coverage = Noise.CoverageBound(BestForm(slice.Coverage0.Reach, low), BestForm(slice.Coverage1.Reach, low), tile.Time);
provable |= Compose(s, fade, iv_add(coverage, DetailRange)).y <= 0.0f;
provable |= Compose(s, fade, iv_add(coverage, iv_scale(BestForm(slice.Detail.Reach, low), 0.5f))).y <= 0.0f;
}
if (!provable)