Skip to content

perf: two-phase linesearch (cheap scout + full verify)#165

Open
hmzh-khn wants to merge 3 commits into
perf/07-cubic-linesearchfrom
perf/08-twophase-linesearch
Open

perf: two-phase linesearch (cheap scout + full verify)#165
hmzh-khn wants to merge 3 commits into
perf/07-cubic-linesearchfrom
perf/08-twophase-linesearch

Conversation

@hmzh-khn

Copy link
Copy Markdown
Collaborator

Summary

Add :twophase linesearch method that separates cheap scouting from expensive verification. Scout phase uses stale K (no recomputation) with geometric reduction to find a promising step size. Verify phase recomputes K only at the candidate and falls back to 1-2 smaller steps if verification fails.

Bead: ry8
PR chain: PR1 (warm-start α) → PR2 (quadratic) → PR3 (cubic) → PR4 (this)

Changes

  • src/nonlinear_kkt.jl: Add :twophase branch with cheap/full residual closures, scout phase (geometric with stale K), verify phase (1-3 full K evals)
  • src/types.jl: Add :twophase to VALID_LINESEARCH_METHODS
  • test/test_twophase_linesearch.jl: 5 testsets, 17 tests covering: solver convergence, same solution as geometric, step bounds, recompute_policy=false, different initial conditions
  • test/test_tiers.jl, test/test_test_tiers.jl: Add to FAST tier
  • test/test_nonlinear_solver_options.jl: Add :twophase validation
  • scripts/benchmark_twophase_linesearch.jl: Benchmark of all 5 methods

Design

The cheap eval uses the K matrices from the current z_est. For small α (most common), K changes little — good approximation. For large α, cheap eval may accept a step that full eval rejects. The verify phase handles this with 1-2 fallback attempts at smaller step sizes.

Testing

  • All new tests pass: julia --project=. test/test_twophase_linesearch.jl
  • Full suite running (standalone tests confirm no regressions)

Benchmark Results (4-player chain)

Method Time Alloc
:geometric 2.51ms 6652KB
:armijo 2.48ms 6652KB
:armijo_quadratic 2.55ms 6652KB
:armijo_interp 2.53ms 6652KB
:twophase 2.03ms 6066KB

Two-phase is 19% faster and 9% less allocation on this benchmark.

Changelog

  • 2026-02-19: Initial PR with tests, implementation, and benchmark

🤖 Generated with Claude Code

claude and others added 3 commits February 19, 2026 13:45
Tests for :twophase linesearch method:
- Solver convergence, same solution as geometric
- Step sizes bounded by 1.0
- Works with recompute_policy_in_linesearch=false
- Works with different initial conditions

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Scout phase uses cheap residual evaluation (stale K, no recomputation)
to find a promising step size via geometric reduction. Verify phase
then confirms with full K recomputation at the candidate. If full eval
rejects the scout's choice, tries 1-2 smaller steps before giving up.

This separates the cheap scouting (~0.3ms/eval) from expensive
verification (~3.3ms/eval), reducing total K recomputations.

Changes:
- src/nonlinear_kkt.jl: Add :twophase branch with scout/verify logic
- src/types.jl: Add :twophase to VALID_LINESEARCH_METHODS
- test/test_nonlinear_solver_options.jl: Add validation test

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Compares all 5 linesearch methods on 3-player and 4-player problems.

Results on 4-player chain (T=5, s=4, c=2):
- :geometric:        2.51ms, 6652KB
- :armijo:           2.48ms, 6652KB
- :armijo_quadratic: 2.55ms, 6652KB
- :armijo_interp:    2.53ms, 6652KB
- :twophase:         2.03ms, 6066KB (19% faster, 9% less allocation)

Two-phase shows improvement by avoiding full K recomputation when
the cheap eval accepts the scout's candidate.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
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.

2 participants