Skip to content

num: fix transcription error in eval_brent_safe_zero - #1089

Closed
pmocz wants to merge 3 commits into
mainfrom
fix-brent-transcription-1064
Closed

pmocz wants to merge 3 commits into
mainfrom
fix-brent-transcription-1064

Conversation

@pmocz

@pmocz pmocz commented Oct 21, 2026

Copy link
Copy Markdown
Member

Fixes #1064

The inverse quadratic interpolation branch of eval_brent_safe_zero (num/private/mod_brent.f90) used the left bracket end a, which the routine never updates, where Brent's algorithm has q = fa/fc:

-           p = s * ( 2.0D+00 * m * a * ( q - r ) - ( sb - sa ) * ( r - 1.0D+00 ) )
+           p = s * ( 2.0D+00 * m * q * ( q - r ) - ( sb - sa ) * ( r - 1.0D+00 ) )

This matches Burkardt's own 2013 fix to zero and FMM zeroin (2.0d0*xm*q*(q - r)).

The bad step was still screened by Brent's acceptance tests, so roots stayed bracketed and within the requested tolerance. Convergence was just slower, and how much slower depended on where the bracket sat on the x axis. This affects every safe_root* / brent_safe_zero caller, including EOS inversions, pre_ms_model, rsp_build and pgbinary_orbit.

Testing

I built the real routine standalone with gfortran, from main and from this branch, and counted function evaluations (bracket, t = 1e-12):

f(x) bracket evals before evals after |Δroot|
x³ − 2x − 5 [2, 3] 17 6 4e-13
sin x − x/2 [1.5708, 3.14159] 22 7 6e-15
eˣ − 2 [0, 1] 8 6 3e-16
e^(x−1000) − 2 [1000, 1001] 16 7 0
x¹⁰ − 1 [0, 1.3] 10 8 2e-13

The test_brent_zero cases in the num unit tests still converge to |f(z)| < 1e-14, so they stay silent in the output.

Expected follow-ups

  • num/test/test_output: the test_root / safe_root* lines print roots to 16 digits, and they change in the last digits. All results remain within the tests' epsx/epsy. The golden file was made with crmath, which I don't have locally. I'll update it from CI's make check output.
  • Test-suite checksums: EOS and other callers now converge along a different iteration path, so some results may differ at round-off level.

🤖 Generated with Claude Code

pmocz and others added 2 commits October 21, 2026 08:13
The inverse quadratic interpolation step used the left bracket end `a`
where Brent's algorithm has `q = fa/fc`. The bad step was still screened
by the acceptance tests, so roots stayed bracketed and within tolerance,
but convergence took up to ~3x more function evaluations and depended on
where the bracket sat on the x axis. Matches Burkardt's 2013 fix and
FMM zeroin.

Fixes #1064

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Values taken from CI make check output (identical on Linux and macOS,
with and without OpenMP). All three roots remain within the tests'
epsx tolerances; Brent now stops sooner instead of over-converging.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pmocz

pmocz commented Oct 21, 2026

Copy link
Copy Markdown
Member Author

Updated num/test/test_output from CI's make check diff. The diff was identical on all four build jobs (Linux and macOS, OpenMP on and off), and num was the only module that failed. Three test_root lines change:

test old new tolerance
root (expected 0.74800611) 7.4800610880593488D-01 7.4800609950637120D-01 epsx = 1e-6
safe_root (exact 0.5) 5.0000000000000011D-01 5.0000000000026457D-01 epsx = 1e-10
second safe_root_with_guess (exact 0.5) 5.0000000000000377D-01 5.0000000000003031D-01 epsx = 1e-10

The new roots are slightly less over-converged because Brent now reaches the tolerance in fewer steps. All of them are still well within each test's tolerance. first safe_root_with_guess is unchanged, since it converges in the Newton phase.

Values from CI make check (identical on Linux and macOS). The
eosDT_get_T logP inversion still meets its tol = 1d-5.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pmocz
pmocz requested a review from fxt44 as a code owner October 21, 2026 12:38
@pmocz

pmocz commented Oct 21, 2026

Copy link
Copy Markdown
Member Author

CI is now green on all four SDK builds. Besides num, the eos unit test also needed a test_output update. That test calls eosDT_get_T to invert logP, and its found logT and got logP lines shifted. Linux and macOS gave identical results, and the result still meets the test's tol = 1d-5. The logP error went from 4.7e-6 to 9.5e-6, both under 1e-5. No other module's make check changed.

I haven't run the star test suite: it's workflow_dispatch only. Since EOS inversions and other safe_root callers now converge along a different path, a TestHub run before merging would be worthwhile to check checksums.

@Debraheem

Copy link
Copy Markdown
Member

Closing as a duplicate of #1065, which contains the same solver correction. We can keep the remaining TestHub/EOS investigation there, however the testing/timing in this pr is still useful to that discussion.

@Debraheem Debraheem closed this Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Transcription error in eval_brent_safe_zero

2 participants