Source
engines/design23_v1/notes/v_and_beta_gradients_are_untrustworthy.md · assembled 2026-09-05 15:14 UTC.
The V and beta gradients are secants, and they cannot be trusted¶
Opened 2026-08-08, after the composite Q/V/beta campaign stalled at accepted step 7 with six consecutive line-search failures and no accepted step in six hours of wall clock.
The headline is in the name of the thing. _objective_gradient
(campaigns/composite_qv_beta_40holes/run_pure_bfgs.py:174) assembles
gradient = -(cavity_weight * (dlogQ - dlogV) + dlogbeta)
where only dlogQ is a gradient. dlogV and dlogbeta come from
_minimum_norm_secant, which fits a linear response to the history of
accepted steps. The code says so plainly -- "V and beta derivatives become
data-informed secants after the first accepted direction, while dlogQ is exact
at every iterate" -- and the campaign ran for seven accepted steps before the
consequence surfaced.
What the stall measured¶
Iteration 15's line search halved its step ten times, from 0.078 nm down to
0.15 pm, and recorded Q, V and beta at every attempt. That is a ten-point
directional derivative measurement along the failing direction, and its
alpha -> 0 limits are flat to four digits across a 64x range of step size.
Against the three predicted terms:
| term | predicted | measured | ratio | source | share of predicted slope |
|---|---|---|---|---|---|
| dlogQ/dalpha | +8.555e-5 | -7.624e-4 | -0.11 | exact | 0.1% |
| dlogV/dalpha | -1.965e-2 | +3.216e-3 | -6.11 | secant | 16.2% |
| dlogbeta/dalpha | +4.880e-2 | +3.792e-4 | +128.7 | secant | 83.7% |
| dJ/dalpha | +5.831e-2 | -1.538e-3 | -37.9 |
The decomposition is exact rather than approximate: rebuilding the directional
derivative from the three terms returns -5.831261e-02 against the recorded
-5.831261e-02, digit for digit. So the search direction at step 7 was 83.7%
determined by a quantity that overestimates the true response by two orders of
magnitude, and the objective's one honest gradient contributed 0.1%.
Why the secant blows up¶
_minimum_norm_secant solves a least-norm problem over at most sixteen past
accepted steps, regularized by ridge = 1e-8 * mean(diag(gram)). At step 7 it
had seven steps in a 60-parameter space, and their singular values are
1.702, 0.727, 0.610, 0.599, 8.394e-6, 1.285e-9, 7.606e-13
so the numerical rank is four. The last three accepted steps were very nearly parallel to earlier ones, which is not a malfunction -- it is what a converging BFGS does. The shipped ridge of 1.0e-8 sits above the fifth mode's gram eigenvalue of 7.046e-11 but nowhere near far enough above it: that mode ends up weighted roughly 1400x more per unit response than the dominant one. A trace of noise along a nearly-degenerate step direction becomes the largest term in the gradient.
Re-solving with a truncated SVD instead, which needs no physics at all:
| relative cut | rank | beta ratio | V ratio | composite dJ/dalpha ratio |
|---|---|---|---|---|
| shipped (ridge) | 7 | 128.69 | -6.11 | -37.91 |
| 1e-6 | 5 | 18130.81 | -797.28 | -5273.54 |
| 1e-4 ... 1e-1 | 4 | 1.84 | -0.54 | -1.02 |
Admitting the fifth direction is catastrophic and truncating below it is stable at any threshold between 1e-4 and 1e-1. That is the mechanism confirmed from both sides.
The part a better ridge does not fix¶
At rank four the predicted composite slope is +1.570e-3 against a measured
-1.538e-3. Right magnitude, still the wrong sign. Repairing the
conditioning alone would have bought confidently sized steps in the wrong
direction rather than absurdly sized ones.
Only beta has the correct sign after truncation. V is -0.54 and Q is -0.11,
and the Q one is worth its own line: the exact analytical gradient says Q
rises along this direction while measurement says it falls, consistently at
every step size sampled. It contributed 0.1% of this direction so it did not
cause this stall, but "exact at every iterate" is carrying less weight than the
name implies, and it has not been checked against measurement anywhere else in
this campaign either.
What follows¶
V and beta must not steer an optimizer in this engine until they have real gradients. The secants are not a cheap approximation to a derivative; they are a fit whose conditioning degrades exactly as the optimizer converges, so the failure is structural rather than a tuning accident. Optimizing Q alone, with V and beta demoted to measured acceptance constraints, is the only configuration currently supported by evidence.
Three repairs, none of them yet done:
- Truncate the secant below its rank and add a gradient-versus-measurement gate to the line search. The gate would have caught this at iteration 10 rather than at iteration 15. It does not fix the sign.
- Give V and beta real gradients. The meep lab has a derived and partially
validated
dV/dhadjoint at ratio 0.72 with its discrepancy localized to the boundary kernel's cross term; see the mode-volume note. - Check
dlogQagainst measurement in its own right, at more than one iterate. Nothing in this campaign has ever done so.
One process defect worth fixing regardless: after iteration 10 reset the BFGS
memory, iterations 11-15 are bit-identical -- same direction, same directional
derivative -0.05831260757897166, same ten alphas, same ten failures --
because steepest descent from an unchanged incumbent is deterministic. Four of
the six hours produced no new information. The stall detector fires on six
consecutive failures; it should fire on the second identical direction.
Reproducing¶
All three stages read the stalled run's state.json and need no new physics
except the exact dlogQ, which costs one confirmation pole solve of about
350 s:
engines/design23_v1/runs/20260728T013605Z_design23_40hole_composite_bfgs/state.json
The measured slopes are in history[-1].line_search, the secants are a pure
function of history, and the incumbent reproduces on this host to 6.7e-10
after the /root to /home/qluster migration.