Avoid discarded objective evaluations in OptimizationOptimisers#1268
Conversation
|
Audit scratchpad for commit
No test was skipped, silenced, loosened, or changed to match buggy output. |
|
Scheduled CI checkpoint (2026-07-15 10:18 EDT):
No observed package-test failure is attributable to this PR. A separate NeuralLyapunov Benchmarking investigation should not be conflated with this result: its seeded stochastic policy tests remain context-sensitive, and a full run with this patch moves rather than robustly removes that package's accuracy failure. That will be tracked separately without changing assertions or tolerances. |
1e488d7 to
33d9282
Compare
|
Post-rebase verification (2026-07-16): rebased commit Downstream audit note: a repeated full NeuralLyapunov Benchmarking run against this source passed 25/25 in 89m16.3s, but the same source failed the isolated ODESystem benchmark at 0.825 and an earlier full context failed the first benchmark at 0.62. I am therefore retaining this PR's deterministic evaluation-count/NeuralPDE evidence without claiming it reliably repairs NeuralLyapunov's stochastic benchmark. |
|
One-hour CI checkpoint (2026-07-16 15:09 EDT): 46 checks have succeeded, 3 were skipped, 1 failed, and 3 downstream checks remain in progress. The changed package's complete matrix is green: OptimizationOptimisers Core passes on LTS, current, and prerelease Julia, and its QA lane passes on current Julia. Both root AD lanes are also green. NeuralPDE NNPDE2 has completed successfully. The only failure is the standalone Documentation link check. I inspected job 87703529098 directly: Documenter received HTTP 429 responses for Still running at this checkpoint: DiffEqFlux All, ModelingToolkit Optimization, and NeuralPDE NNPDE1 downstream tests. I am recording these as in progress, not as passed or failed. |
33d9282 to
329e950
Compare
|
Updated in 329e950 after the inference concern:
Final-source local checks:
|
Evaluate the objective through the optimizer loop without a discarded pre-loop call, so stochastic objectives keep the expected RNG sequence and reported evaluation counts match actual work. Preserve positive fractional maxiters values that round to zero by evaluating the initial objective only when the loop performs no iterations, and count that fallback evaluation. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Initialize the result with Inf so JET can prove the local is defined, while using the completed iteration count—not the objective value—to decide whether the zero-iteration fallback is needed. Add coverage showing a genuine infinite objective is evaluated only once. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Construct the Inf placeholder using the real scalar element type of the initial parameters. Exercise the infinite-objective regression with Float32 inputs and verify that the solution objective retains Float32. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
329e950 to
2d45824
Compare
|
Updated in 2d45824:
Exact local results on Julia 1.12.6:
|
|
The clean-master QA investigation is complete:
SciMLTesting #27 reduces OptimizationOptimisers' false positives from 300 names to 9 inherited constants/enum values, but does not yet pass. Both current OptimizationOptimisers and OptimizationPolyalgorithms QA CI failures resolve SciMLTesting 2.3.0 and are unrelated to this PR's product-code diff. No checks were disabled or silenced. |
Summary
OptimizationOptimisers.eltype(real(cache.u0)), avoiding an undefined/nullable placeholder and a hard-codedFloat64.Float32objective.OptimizationOptimisers 0.3.19 initialized the eventual objective result by evaluating
cache.fbefore the loop. Normal iterations overwrite that value, so the call was unreported work and advanced global RNG state for stochastic objectives before optimization began.The typed
Infis only an initialization value. The fallback is keyed toiszero(iterations), not to the value ofx; therefore an objective that genuinely returns infinity after an iteration is not evaluated a second time. Constructing it withconvert(eltype(real(cache.u0)), Inf)yieldsInf32forFloat32parameters and a realFloat32infinity forComplexF32parameters.Local verification
GROUP=OptimizationOptimisers: Core — 39 passed, 1 pre-existing broken; both OptimizationOptimisers and root Optimization test harnesses passed.GROUP=OptimizationOptimisers_QA: 18 passed, 1 failed, 1 pre-existing broken. The sole failure is the public-API rendered-docs check reporting approximately 300 re-exported names; the identical failure reproduces on detached cleanorigin/masterat34a8fd5c.044d89a. SciMLTesting #27 reduces the false positives from 300 to 9 inherited constants/enum values but does not yet fully fix the check.git diff --check: passed.Float32 → Float32 Inf,Float64 → Float64 Inf, andComplexF32 → Float32 Inf.The regression uses
OptimizationFunctionandOptimizationProblemfrom their declaring public module,SciMLBase, andsolvefromCommonSolve. No assertion, tolerance, or expected-broken marker was loosened or disabled.Please ignore this draft until it has been reviewed by @ChrisRackauckas.