Skip to content

Add Problem::is_step_acceptable and take steps with one rounding per coefficient - #121

Open
fsichetti wants to merge 3 commits into
mainfrom
static-check-hook
Open

fsichetti wants to merge 3 commits into
mainfrom
static-check-hook

Conversation

@fsichetti

Copy link
Copy Markdown
Contributor

Adds a hook for problems that certify steps after the line search accepts them, and makes the steps the solver takes exactly reproducible so a problem can certify them. Needed by polyfem/polyfem#549 (conservative Jacobian checks).

What changes

  • Problem::is_step_acceptable(x0, x1): new virtual, default true. The line search calls it on a step that already passed its descent criteria. A rejection ends the line search as failed, so the solver computes a new direction; the problem may change in between (polyfem refines its quadrature there), and each line search stays on one fixed problem.
  • step_along(x, s, dx) forms every trial and accepted step as fma(s, dx, x), one rounding per coefficient, in the line searches and in the solver's final update.
  • product_rounded_down(a, b) replaces the fesetround(FE_DOWNWARD) block that scaled the step by max_step_size. That block needed FENV_ACCESS or -frounding-math to be honored; the FMA version is correct in any rounding mode and at any optimization level.

Impact on existing users

  • is_step_acceptable defaults to true, so problems that don't override it see no change from the hook.
  • ⚠️ step_along changes every solve: x + s*dx was two roundings per coefficient, now one. Iterates differ from before in the last bit, so results that depend on bitwise reproducibility, or tests with very tight tolerances, can move. polyfem's full test suite passes with it (280/280).
  • std::fma is a hardware instruction on arm64 and on x86-64 with FMA; elsewhere it is a correctly rounded library call, which is slower than a separate multiply and add.

Tests

  • line-search-step-acceptable: the hook is called once per accepted step, a rejection ends the line search (NaN step), and the next line search sees the changed problem.
  • step_along matches a single rounding where a separate multiply and add differ; product_rounded_down never exceeds the exact product.
  • Full unit_tests on this branch: 27 test cases pass (macOS, Apple clang 17, Release).

fsichetti and others added 3 commits October 13, 2026 17:01
…epts

is_step_valid() runs on every trial point, which makes it the wrong place
for checks that are expensive, or that can only veto a step without the
energy reflecting why. Add is_step_acceptable(): it is called only once a
trial step has passed the descent criteria, and returning false makes the
line search keep backtracking.

A problem may change its own discretization before rejecting (e.g. refine
a quadrature where it found the step invalid, so the energy there is no
longer finite). The line search therefore re-evaluates the energy and
gradient at x0 after a rejection, so its criteria keep comparing like
with like. If the old direction no longer descends on the changed
problem, the line search fails through its usual path so the solver picks
a new direction; the "energy at x unchanged" assert in that path is
relaxed accordingly.

Only Backtracking implements the loop, so Armijo, RobustArmijo and
ResidualBacktracking inherit it. NoLineSearch never backtracks and does
not call the hook. The default returns true, so existing problems are
unaffected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A problem that certifies the whole segment x + t*dx (e.g. polyfem's
continuous inversion check) can only trust the configuration the solver
takes if that configuration is within a known distance of the segment.

- step_along(x, s, dx) forms x + s*dx with std::fma, so each coefficient is
  rounded once. Every trial and accepted step in the line searches and the
  final solver update goes through it.
- product_rounded_down(a, b) replaces the fesetround(FE_DOWNWARD) block that
  scaled the step by the max step size. That block needed FENV_ACCESS or
  -frounding-math to be honored; the FMA-based version is correct in any
  rounding mode and under any optimization.
- Tests: step_along matches a single rounding where a separate multiply and
  add differ; product_rounded_down never exceeds the exact product.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A rejection may change the problem's discretization (polyfem refines a
quadrature where the step was found invalid), and the search direction was
computed for the old one. Rather than re-evaluating the energy and gradient
at x and backtracking further along that direction, fail the line search
through the caller's usual path, so the solver computes a new direction on
the problem as it is now. Each line search thus works on a single, fixed
problem, and the re-evaluation and descent re-check go away.

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

codecov Bot commented Oct 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.53%. Comparing base (da4e7fe) to head (7ab0a75).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #121      +/-   ##
==========================================
+ Coverage   79.45%   79.53%   +0.07%     
==========================================
  Files          55       55              
  Lines        2940     2951      +11     
  Branches      377      378       +1     
==========================================
+ Hits         2336     2347      +11     
  Misses        604      604              
Flag Coverage Δ
polysolve 79.53% <100.00%> (+0.07%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

1 participant