Skip to content

Commit 007904b

Browse files
authored
Merge pull request #438 from PyAutoLabs/claude/fnnls-degenerate-sanity-assertion
fix(test): degenerate-band sanity check asserts on BLAS rounding, not the library
2 parents efaf304 + b0d3f41 commit 007904b

1 file changed

Lines changed: 20 additions & 5 deletions

File tree

test_autoarray/util/test_cholesky_degenerate.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,16 @@ def test__fnnls_cholesky__never_returns_a_non_finite_solution(jitter):
107107
# The producer regression: across the whole near-degenerate band, the
108108
# solver must either return a finite solution or raise -- never hand back
109109
# NaN as though it were a valid reconstruction.
110-
raised = 0
110+
solved = 0
111111

112112
for seed in range(40):
113113
ZTZ, ZTx = _normal_equations(n=12, n_data=40, jitter=jitter, seed=seed)
114114

115+
# The band really is degenerate. This is a property of the fixture, so it
116+
# holds on every machine -- unlike *how the solver responds* to it, which
117+
# is decided by floating-point summation order (see the module comment).
118+
assert np.linalg.cond(ZTZ) > 1.0e12
119+
115120
try:
116121
P_initial = np.linalg.solve(ZTZ, ZTx) > 0
117122
except np.linalg.LinAlgError:
@@ -120,14 +125,24 @@ def test__fnnls_cholesky__never_returns_a_non_finite_solution(jitter):
120125
try:
121126
reconstruction = fnnls_cholesky(ZTZ, ZTx.T, P_initial=P_initial)
122127
except np.linalg.LinAlgError:
123-
raised += 1
124128
continue
125129

130+
solved += 1
131+
126132
assert np.all(np.isfinite(reconstruction))
127133

128-
# Sanity: the degenerate band must actually be exercising the guard,
129-
# otherwise the assertion above is passing vacuously.
130-
assert raised > 0
134+
# Sanity: at least one seed must have reached the finiteness assertion above,
135+
# otherwise this test passes vacuously.
136+
#
137+
# NOT `raised > 0`. The invariant here is the same one
138+
# `test__cholinsertlast__singular_insertion_never_yields_an_unusable_pivot`
139+
# states: either raise, or return something finite. Raising is one *allowed*
140+
# outcome, not a required one, so requiring it of some seed asserts on which
141+
# side of zero the runner's BLAS happens to round the Schur complement. At
142+
# `jitter=0.0` exactly one of these 40 seeds raises on a single-threaded local
143+
# BLAS and none do on the CI runners, so `raised > 0` was a coin flip that
144+
# failed CI on a green library.
145+
assert solved > 0
131146

132147

133148
def test__fnnls_cholesky__well_conditioned_problem_is_unaffected():

0 commit comments

Comments
 (0)