cultmath: BoundedLeastSquares tests observe the warm-start clamp and the workspace
The full-step clamp repairs an out-of-box start on a free column, so the warm-start clamp was invisible to the old test (Stryker: five survivors). The new table runs one column with b beyond the box and a cap of 0, where the solver returns the clamped start untouched, across finite, infinite and NaN starts and finite and infinite bounds. Workspace junk (including NaN doubles) is now checked on random boxed problems that release bounds and use the tolerance, with bit-identical x and equal iteration counts. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
d808941b87
commit
0a80624930
1 changed files with 39 additions and 7 deletions
|
|
@ -412,6 +412,29 @@ public sealed class BoundedLeastSquaresTests
|
|||
}
|
||||
}
|
||||
|
||||
// Junk in the workspace, including NaN doubles, must not reach any decision: random boxed problems (which release
|
||||
// bounds and use the tolerance) give bit-identical x and the same iteration count.
|
||||
[Fact]
|
||||
public void WorkspaceJunkNeverReachesTheSolveOnRandomProblems()
|
||||
{
|
||||
for (uint seed = 1; seed <= 25; seed++)
|
||||
{
|
||||
var (m, n, a, b, lo, hi) = RandomProblem(seed);
|
||||
var clean = new float[n];
|
||||
Solve(m, n, a, b, lo, hi, clean, out var cleanIterations);
|
||||
foreach (var junk in new[] { float.NaN, 7f, -1e30f })
|
||||
{
|
||||
var workspace = new float[BoundedLeastSquares.WorkspaceLength(n)];
|
||||
Array.Fill(workspace, junk);
|
||||
var x = new float[n];
|
||||
BoundedLeastSquares.Solve(m, n, a, b, lo, hi, x, workspace, out var iterations);
|
||||
Assert.Equal(cleanIterations, iterations);
|
||||
for (var j = 0; j < n; j++)
|
||||
Assert.Equal(BitConverter.SingleToInt32Bits(clean[j]), BitConverter.SingleToInt32Bits(x[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WarmStartAtAVertexTakesNoIterations()
|
||||
{
|
||||
|
|
@ -826,6 +849,9 @@ public sealed class BoundedLeastSquaresTests
|
|||
Assert.True(Cost(2, 2, a, b, y) < 1e-9, $"cost {Cost(2, 2, a, b, y)}");
|
||||
}
|
||||
|
||||
// One column, A = [1], with b beyond the box: the first Newton step would cross a bound, so with a cap of 0 the
|
||||
// solver returns the clamped start untouched. That makes the clamp itself the thing under test, for every
|
||||
// combination of a finite, infinite or NaN start with finite and infinite bounds.
|
||||
[Fact]
|
||||
public void WarmStartClampIsExact()
|
||||
{
|
||||
|
|
@ -836,23 +862,29 @@ public sealed class BoundedLeastSquaresTests
|
|||
(-1f, 1f, 5f, 1f),
|
||||
(-1f, 1f, -5f, -1f),
|
||||
(-1f, 1f, float.NaN, -1f),
|
||||
(-inf, inf, float.NaN, 0f),
|
||||
(-inf, inf, inf, 0f),
|
||||
(-inf, inf, -inf, 0f),
|
||||
(0.5f, 2f, inf, 2f),
|
||||
(0.5f, 2f, -inf, 0.5f),
|
||||
(0.2f, inf, inf, 0.2f),
|
||||
(0.2f, inf, -inf, 0.2f),
|
||||
(0.2f, inf, float.NaN, 0.2f),
|
||||
(-inf, -2f, -inf, -2f),
|
||||
(-inf, -2f, 3f, -2f),
|
||||
(-inf, 3f, float.NaN, 0f),
|
||||
(-inf, 3f, -inf, 0f),
|
||||
(-2f, inf, float.NaN, -2f),
|
||||
(-inf, -2f, float.NaN, -2f),
|
||||
(-inf, 3f, 1f, 1f),
|
||||
};
|
||||
foreach (var (l, h, start, expected) in cases)
|
||||
{
|
||||
var x = new[] { start, start, start };
|
||||
// No rows: every column is dependent and takes a zero step, so x is exactly the clamped start.
|
||||
Solve(0, 3, default, default, Fill(l, 3), Fill(h, 3), x, out var iterations);
|
||||
// b beyond the box on the side the start is not on the bound of, so the step crosses a bound (or the
|
||||
// start already sits on one).
|
||||
var b = new[] { float.IsInfinity(h) ? l - 10f : h + 10f };
|
||||
if (float.IsInfinity(l) && float.IsInfinity(h)) b[0] = 0f;
|
||||
var x = new[] { start };
|
||||
Solve(1, 1, new[] { 1f }, b, new[] { l }, new[] { h }, x, out var iterations, maxIterations: 0);
|
||||
Assert.Equal(0, iterations);
|
||||
Assert.Equal(new[] { expected, expected, expected }, x);
|
||||
Assert.True(x[0] == expected, $"box [{l}, {h}] start {start}: {x[0]}, expected {expected}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue