Add technical report + switch base IP solver to KLU - #56
Merged
Conversation
First draft: abstract, teaser figure placeholder, and full introduction for a short report advertising the batched interior-point solver against PATH, with a focus on trajectory-game benchmarks. Vendors IEEEtran.cls/.bst locally since neither is available via this machine's TeX Live install, and adds a Makefile wrapping the pdflatex/bibtex build sequence. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…etric view)
Adds Sec. II with four subsections: the general box-form MCP definition,
the KKT-to-primal-dual-MCP reduction that sets up notation for the solver
design section, the generalization to noncooperative games/GNEPs (with the
lane-change trajectory game introduced as the running example tied to the
teaser figure), and the parametric view motivating batching/differentiability.
Two \todo{add reference} placeholders remain for citations.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- New paragraph deriving the concatenated (G, H) for the N-agent game
case, spelling out how shared multipliers lambda_sh/mu_sh (single
vectors, not per-agent copies) couple every agent's stationarity
block -- cross-checked against src/game.jl's actual construction.
- New `runningexample` environment (bold title, light grey colorbox,
no extra package deps) wrapping the lane-change trajectory game
paragraph, for reuse in the batched-solving section.
- Consistency fixes: unify x_{-i}/x_{\neg i} notation, and align the
KKT subsection header (which had picked up "and noncooperative
games" without the matching content) with the games subsection that
follows it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Adds the primal-dual interior-point pseudocode as a proper algorithm2e float (alg:solver), with vertical scoping bars, line numbers, and a ruled caption box. - Fills in the two \todo line-reference pointers left in the prose: turns out cleveref's extended tracking is broken for algorithm2e's per-line counter (every \cref resolved to "Line 1" regardless of actual position, confirmed via the .aux file), so these use plain \ref instead, which is what the original placeholder text already assumed. - Gives explicit rho/epsilon tightening and loosening formulas and introduces the inner-loop iteration counter k, both lifted directly from src/solver.jl's actual update rule (tightening_rate/ loosening_rate, max_inner_iters) rather than invented generically. - Fixes a stray \lamdba typo that was breaking compilation. - Needed three more TeX packages not present in this machine's minimal TeX Live install (algorithm2e, ifoddpage, relsize); installed via `tlmgr --usermode`, which needs no sudo. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Covers the device/strategy-agnostic verb set (residual!/jacobian!/ factorize!/ldiv!) that lets Algorithm 1 run unchanged on CPU or GPU, the three changes needed to batch it (per-instance rho/epsilon, closed-form batched linesearch, stall-freezing), and the CPU (KLU) / GPU (cuDSS) backends, grounded in the actual BatchedInteriorPoint implementation and README. Extends the running-example contentbox to the batched setting and adds a Remark (new theorem environment) flagging BatchedDense/SparseSingle as not-yet-implemented future strategies.
Algorithm 2 makes per-instance stall detection explicit (status_b, stall_b), grounded in the actual BatchedInteriorPoint loop. Fills in the Backends subsection with why CPU and GPU treat frozen instances differently: CPU's independent per-instance KLU factorization lets it literally skip inactive instances (cost scales with active count), while cuDSS's batched GPU solver processes the whole batch every round regardless (confirmed via ext/MixedComplementarityProblemsCUDSSExt.jl, where `active` is accepted but ignored). Also fixes a stray math-mode \: used in text mode that broke compilation.
Player index vs. batch index share the same subscript convention, and batched iterates are capitalized while batched stepsizes aren't. Left as a \todo in the Batched section rather than fixing now.
Fill in the previously-stubbed Section VII with the full four-axis
structure agreed on: (i) single-instance reliability/speed vs PATH,
(ii) batched throughput vs PATH, (iii) CPU thread scaling, and (iv) the
regime-dependent GPU-vs-CPU crossover.
All numbers, tables, and figures are left as \todo placeholders to be
populated from a fresh benchmark run. Notable open items baked into the
TODOs:
- single-instance baseline includes an InteriorPoint (KLU) row, to test
whether swapping the unbatched solver's UMFPACK factorization for KLU
(as the batched CPU path uses) closes the gap to PATH.
- GPU crossover framed honestly (GPU wins only once per-instance size is
large enough to amortize cuDSS's batched-factorization overhead), with
the solved-fraction and QP-sweep confounds flagged as caveats.
Adds \usepackage{multirow} for the new tables.
Note for the benchmark step: this branch is behind origin/main by the
PR #55 fixes (trajectory-game solved-fraction fix, cuDSS algo1 tuning),
which must be merged before regenerating numbers.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The unbatched InteriorPoint solver factorized ∇F with UMFPACK. Switch the default to KLU (LinearSolve's KLUFactorization, whose default reuse_symbolic reuses the symbolic analysis and pivot ordering across Newton steps and refactorizes in place). ∇F is always sparse (SparseFunction) with a fixed pattern, so this is safe and makes each per-iteration solve ~4-6x faster at identical reliability -- the same reason the batched CPU path already uses KLU. Verified: full test suite passes (555/555); single-instance timing in benchmark/results/table1_summary.txt (per-solve median QP 0.58ms vs UMFPACK 2.49ms; game 0.75ms vs 4.43ms; same solved fractions). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a `use_initial_guess` kwarg to `benchmark_throughput` so the batched solve can be forced to cold-start (matching the always-cold PATH and unbatched-IP baselines) for apples-to-apples comparison, or warm-started (the game's zero-input rollout) for the realistic receding-horizon regime. Both are reported. Adds benchmark/results/ with the raw data behind the technical report's Experiments section: throughput vs PATH, GPU-vs-CPU scaling, per-instance distributions (bimodal from infeasible QP draws), the GPU/CPU per-call kernel crossover and active-set-skip mechanism, and the Table I KLU-vs-UMFPACK single-instance comparison. See benchmark/results/README.md for the data dictionary, findings (incl. the correction to PR #55's GPU-beats-CPU headline), and reproduction commands. Driver + analysis scripts in results/scripts/. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The previous "GPU beats 32 CPU threads 2.5-2.8x on the trajectory game" claim (from PRs #54/#55) was wrong for end-to-end throughput: that ratio had the GPU in the numerator, i.e. the GPU is ~2.5x slower, mislabeled as GPU-favorable. Re-measured (median-of-N, RTX 4090): the CPU is faster than the GPU end-to-end on the game at every tested horizon; the GPU wins end-to-end only on large dense per-instance systems (>=128-primal QPs, 2-3x) or large batches. Both backends still clear a batch far faster than sequential PATH. The GPU factorization kernel does cross over CPU at large d, but the CPU's active-set skip (it factorizes only the still-active instances each Newton step, while cuDSS always does the whole batch) keeps the CPU ahead end-to-end. Full data in benchmark/results/. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Populate Section VII (setup, single-instance, batched throughput, GPU-vs-CPU) with the fresh benchmark numbers, and correct the GPU-vs-CPU narrative: the CPU batched backend beats the GPU end-to-end on the trajectory game at every tested horizon; the GPU pulls ahead only on large, dense per-instance systems (large-n_x QPs). The per-call factorization kernel does cross over in the GPU's favor at large KKT dimension, but the active-set skip -- the CPU factorizes only still-active instances each step while cuDSS always does the whole batch -- keeps the CPU ahead end-to-end. Abstract and intro updated to match. The single-instance section reflects the new KLU default: with KLU the unbatched solver is per-solve competitive with, and often faster than, PATH. Remaining (left as TODOs): the thread-scaling subsection numbers, the three plots (teaser (b), thread scaling, GPU vs CPU), the teaser schematic, and the Discussion section. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
throughput_klu.csv: clean single-run throughput (PATH, sequential IP, batched CPU) with KLU as the default linear solver -- source for Table II. thread_scaling.csv: batched throughput vs CPU thread count (1-32) for QP and game. Plus the generating scripts and README data-dictionary entries. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Report batched throughput vs CPU thread count: sublinear scaling with diminishing returns; the trajectory game peaks at the 16 physical cores and regresses under simultaneous multithreading, while the larger QP batch gains marginally out to 32 threads. Figure TODO notes the game should be re-run at N=1024 for a cleaner curve (current N=256 run is noisy at low thread counts). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Both the QP and trajectory game now use a fixed batch of N=1024, removing the earlier N=256 game artifact (noisy super-linear low-thread points). Clean result: throughput gains concentrate in the first ~4 threads, then both curves plateau around physical-core saturation with no systematic SMT gain. Update the prose, figure caption, and drop the stale "re-run at N=1024" todo note. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the stub with three paragraphs grounded in the experiments: batching (not hardware) is the decisive speedup and the verb-set abstraction makes it portable; the CPU-vs-GPU choice is regime-dependent (active-set skip), with an active-set-aware cuDSS call as the natural GPU fix; limitations (narrow benchmark families, long-horizon solved-fraction decline) motivate a broader suite and stronger globalization, and differentiability via the implicit function theorem on the KKT conditions is flagged as the primary next step. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two related benchmark-fairness/consistency fixes: Problem-size study now median-of-5. Added a `problem_size_raw` stage to raw_data.jl that fills per_rep.csv with 5-rep batched CPU/GPU timings for the larger per-instance sizes (QP p64i32/p128i64; game T20/T30/T40/T50 at B=1024, cold+warm). The base configs p32i16/T10 already had >=30 reps, so both figure panels now draw median-of-N from one file. Updated the §VII-D game numbers to medians (T=30: GPU 8.0s vs CPU 4.1s, 1.9x; T=50: 16.3s vs 12.7s) and the benchmark README to match. PATH held to matched tolerance. PATH was running at its built-in default convergence_tolerance=1e-6 while our solver used tol=1e-4 -- a 100x tighter bar for PATH. Every PATH call now passes convergence_tolerance=tol (batched_benchmark.jl, path.jl, raw_data.jl, table1_klu.jl). rerun_path_tol.jl re-timed PATH at 1e-4 and patched only the PATH rows of every results CSV, leaving all batched/IP/GPU rows byte-identical. Effect is negligible (identical solved counts, times within run-to-run noise) since PATH's quadratic convergence drives the residual below both thresholds in the same iteration -- so the comparison is now provably fair with no material change. Updated Table II PATH numbers and added a fairness note to the setup section. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- docs/paper/figures/: scripts (+ output PDFs) that generate the four figures main.tex includes (teaser schematic/throughput, thread scaling, GPU-vs-CPU), plus the car-icon assets and prep script used by the schematic. - benchmark/results/scripts/verify_paper_numbers.jl: recomputes every cited number in the Experiments section from the raw benchmark data and diffs against the paper's claims. - benchmark/results/scripts/ad_gradient_check.jl: finite-difference correctness check for the AD sensitivities described in the new Differentiable Solving section.
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.
Summary
docs/paper/): a short IEEEtran two-column write-up of the package — MCP/KKT background, the interior-point algorithm, batched CPU/GPU solving, differentiable solving (implicit-function-theorem sensitivities), and an experiments section benchmarking against PATH across single-instance reliability, thread scaling, and GPU-vs-CPU batched throughput. Compiled PDF and all figure-generation scripts/data are included (benchmark/results/), along with averify_paper_numbers.jlscript that recomputes every cited number from raw data and checks it against the paper's claims.README.mdnow links the arXiv preprint and includes a citation entry.src/solver.jl): replacesUMFPACKFactorization()as the defaultlinear_solve_algorithm, giving ~4-6x faster per-iteration solves at identical reliability by reusing KLU's symbolic factorization/pivot ordering across Newton steps (matching what the batched CPU path already does).README.md's performance-status blurb is updated to reflect current, more nuanced GPU-vs-CPU numbers (GPU wins on large dense per-instance systems / large batches; CPU wins on the trajectory game at all tested horizons due to its active-set skip).Test plan
verify_paper_numbers.jlpasses (60/60 checks against raw benchmark data)docs/paper/main.pdffor the rendered report