Use Anderson acceleration for the TPI outer loop: 2x faster transition paths - #78
Open
vahid-ahmadi wants to merge 1 commit into
Open
Use Anderson acceleration for the TPI outer loop: 2x faster transition paths#78vahid-ahmadi wants to merge 1 commit into
vahid-ahmadi wants to merge 1 commit into
Conversation
OG-Core ships an Anderson accelerator for the TPI outer loop, but TPI_outer_method defaults to "picard", so OG-UK has never used it. Benchmarked at OG-UK's production shape (S=80, J=7, T=60, M=1, GS tax functions, ogcore 0.17.0), via _build_specs with live calibration. SS solved once per scenario and the pickle reused by both arms; arms run sequentially with an identical single-worker client. arm method iters TPIdist wall clock baseline picard 16 7.29e-05 94.9s baseline anderson 8 3.98e-05 47.7s reform (CIT 27%->32%) picard 16 7.46e-05 95.3s reform anderson 8 4.71e-05 46.9s Same equilibrium: max relative difference between the picard and anderson paths is 7.7e-6 (Y), 3.9e-6 (K), 7.2e-6 (L), 3.7e-5 (r), 1.0e-5 (w), 1.5e-5 (C) -- all inside mindist_TPI. No stalls, no divergence, nothing non-finite. Each anderson run logged one "accel step worsened; trust radius -> 0.5", the trust-region guard firing and recovering, after which the residual falls monotonically. The guard is left at its default; the unguarded variant is not used. Multi-sector keeps the default damped Picard: M=8 uses hybr with relaxed tolerances and has no evidence either way. The choice is extracted into tpi_outer_method() so it can be tested without a live calibration. Refs PSLmodels#76 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XCKMb1aicxYaeUC1us2nvF
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
OG-Core ships an Anderson accelerator for the TPI outer loop, but
TPI_outer_methoddefaults to"picard"— damped functional iteration atnu=0.4. OG-UK has never used it. It is available under the currentogcore<0.18pin (shipped in 0.17.0), so this needs no version change and no migration.What changes after merging
Single-sector transition paths take half as long: 16 outer iterations → 8, ~95s → ~47s at production shape. Same equilibrium. Multi-sector runs are unchanged.
This is the only PR in this set that changes numerical behaviour, so the evidence is below in full.
Benchmark
Run through
_build_specswith live calibration at OG-UK's own defaults — S=80, J=7, T=60, M=1, pooled GS, ogcore 0.17.0. SS solved once per scenario and reused by both arms; sequential runs, identical single-worker client; onlyTPI_outer_methoddiffers.Same equilibrium — max relative difference between the two paths, all inside
mindist_TPI = 1e-4:Diagnostics — no stall, no divergence, nothing non-finite. Each anderson run logged exactly one
accel step worsened; trust radius -> 0.5: the trust-region guard firing and recovering, after which the residual falls monotonically (0.106, 0.188, 0.082, 0.031, 9.5e-3, 1.5e-3, 3.7e-4, 4.0e-5). Picard is monotone but slow after iteration 4.A smaller run (S=40, J=2, T=120, OG-Core test params) gave the same 1.9x and was insensitive to
TPI_anderson_m∈ {2,5,10} andTPI_trust_radius∈ {0,1,2}, defaults best of the set.Change
tpi_outer_method(multi_sector)returns"anderson"for single-sector and"picard"otherwise;_build_specsuses it. The trust-region guard is left at its default — it demonstrably does work here, so the unguarded variant is not used.Multi-sector deliberately keeps Picard: M=8 uses
hybrwith relaxed SS tolerances and has no evidence either way. Obvious follow-up if someone wants to benchmark it.Extracted as a standalone function so it can be tested without a live calibration —
_build_specsitself calibrates, which makes it unusable in a fast test.Evidence
4 tests, 1.25s: single-sector selects anderson, multi-sector stays on picard, both values still accepted by OG-Core's
update_specifications(guards against an upstream rename), trust radius positive by default.Full suite 13 passed, 3 skipped.
ruffclean.Incidental
Every arm reported
max_RC_error≈ 0.158 (baseline) / 0.160 (reform), method-independent to six significant figures. That is theRC_TPI = 0.2waiver discussed in #72 and fixed by #75 — independent confirmation at production shape, unrelated to this change.Addresses the performance half of #76.