Skip to content

Include canon_backend in the compilation cache key#3400

Draft
PTNobel wants to merge 1 commit into
masterfrom
ptn/fix-cache-canon-backend
Draft

Include canon_backend in the compilation cache key#3400
PTNobel wants to merge 1 commit into
masterfrom
ptn/fix-cache-canon-backend

Conversation

@PTNobel

@PTNobel PTNobel commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Description

Re-solving a Problem with a different canon_backend silently reused the
previously compiled canonicalization: Cache.make_key only keyed on
(solver, gp, ignore_dpp, use_quad_obj), so get_problem_data treated the
second solve as a cache hit and never constructed a solving chain with
the requested backend.

Fix: add canon_backend to Cache.make_key and its single call site in
get_problem_data. The value is keyed as passed (None for the default),
so the common None -> None re-solve still hits the cache, while None and
an explicit backend are kept distinct (None enables auto-COO selection
for large DPP problems, so they are not equivalent).

Audited the other arguments construct_solving_chain consumes: solver,
gp, ignore_dpp, and solver_opts['use_quad_obj'] were already in the key;
verbose only affects logging; remaining solver_opts are forwarded to the
solver at solve time and do not change canonicalization. enforce_dpp
only gates raising DPPError versus warning for non-DPP problems and
never changes the compiled chain, so it is left out of the key.

Tests: TestCanonBackendCacheKey in test_backend_selection.py asserts a
backend switch re-canonicalizes (via the cached chain's
ConeMatrixStuffing.canon_backend) and that same-backend and default
re-solves still reuse the cached chain object.

Found by an automated bug-hunting audit of master; each finding was reproduced against an independent oracle before fixing.

Type of change

  • New feature (backwards compatible)
  • New feature (breaking API changes)
  • Bug fix
  • Other (Documentation, CI, ...)

Contribution checklist

  • Add our license to new files.
  • Check that your code adheres to our coding style.
  • Write unittests.
  • Run the unittests and check that they’re passing.
  • Run the benchmarks to make sure your change doesn’t introduce a regression.

Re-solving a Problem with a different canon_backend silently reused the
previously compiled canonicalization: Cache.make_key only keyed on
(solver, gp, ignore_dpp, use_quad_obj), so get_problem_data treated the
second solve as a cache hit and never constructed a solving chain with
the requested backend.

Fix: add canon_backend to Cache.make_key and its single call site in
get_problem_data. The value is keyed as passed (None for the default),
so the common None -> None re-solve still hits the cache, while None and
an explicit backend are kept distinct (None enables auto-COO selection
for large DPP problems, so they are not equivalent).

Audited the other arguments construct_solving_chain consumes: solver,
gp, ignore_dpp, and solver_opts['use_quad_obj'] were already in the key;
verbose only affects logging; remaining solver_opts are forwarded to the
solver at solve time and do not change canonicalization. enforce_dpp
only gates raising DPPError versus warning for non-DPP problems and
never changes the compiled chain, so it is left out of the key.

Tests: TestCanonBackendCacheKey in test_backend_selection.py asserts a
backend switch re-canonicalizes (via the cached chain's
ConeMatrixStuffing.canon_backend) and that same-backend and default
re-solves still reuse the cached chain object.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@github-actions

Copy link
Copy Markdown

Benchmarks that have stayed the same:

   before           after         ratio
 [1a5c7eb0]       [9002640b]
      6.63±0s          6.76±0s     1.02  gini_portfolio.Cajas.time_compile_problem
      1.22±0s          1.23±0s     1.01  gini_portfolio.Murray.time_compile_problem
      1.60±0s          1.60±0s     1.00  tv_inpainting.TvInpainting.time_compile_problem
      3.46±0s          3.46±0s     1.00  matrix_stuffing.ConeMatrixStuffingBench.time_compile_problem
      2.78±0s          2.78±0s     1.00  simple_QP_benchmarks.ParametrizedQPBenchmark.time_compile_problem
      2.02±0s          2.02±0s     1.00  simple_QP_benchmarks.LeastSquares.time_compile_problem
      3.94±0s          3.94±0s     1.00  huber_regression.HuberRegression.time_compile_problem
      4.49±0s          4.49±0s     1.00  svm_l1_regularization.SVMWithL1Regularization.time_compile_problem
      12.1±0s          12.1±0s     1.00  finance.CVaRBenchmark.time_compile_problem
      3.71±0s          3.69±0s     0.99  simple_QP_benchmarks.UnconstrainedQP.time_compile_problem
      5.27±0s          5.21±0s     0.99  optimal_advertising.OptimalAdvertising.time_compile_problem
      1.40±0s          1.38±0s     0.99  matrix_stuffing.ParamConeMatrixStuffing.time_compile_problem
      20.5±0s          20.2±0s     0.99  sdp_segfault_1132_benchmark.SDPSegfault1132Benchmark.time_compile_problem
      2.43±0s          2.40±0s     0.99  matrix_stuffing.SmallMatrixStuffing.time_compile_problem
      735±0ms          721±0ms     0.98  simple_LP_benchmarks.SimpleFullyParametrizedLPBenchmark.time_compile_problem
      10.2±0s          10.0±0s     0.98  simple_LP_benchmarks.SimpleLPBenchmark.time_compile_problem
      162±0ms          158±0ms     0.98  high_dim_convex_plasticity.ConvexPlasticity.time_compile_problem
      1.94±0s          1.89±0s     0.97  finance.FactorCovarianceModel.time_compile_problem
      2.84±0s          2.77±0s     0.97  quantum_hilbert_matrix.QuantumHilbertMatrix.time_compile_problem
      3.75±0s          3.65±0s     0.97  matrix_stuffing.ParamSmallMatrixStuffing.time_compile_problem
      2.00±0s          1.94±0s     0.97  semidefinite_programming.SemidefiniteProgramming.time_compile_problem
      2.51±0s          2.43±0s     0.97  slow_pruning_1668_benchmark.SlowPruningBenchmark.time_compile_problem
      4.21±0s          4.06±0s     0.96  simple_QP_benchmarks.SimpleQPBenchmark.time_compile_problem
      1.95±0s          1.86±0s     0.95  simple_LP_benchmarks.SimpleScalarParametrizedLPBenchmark.time_compile_problem
      1.44±0s          1.37±0s     0.95  gini_portfolio.Yitzhaki.time_compile_problem

@PTNobel PTNobel marked this pull request as draft June 10, 2026 06:26
@PTNobel

PTNobel commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator Author

canon_backend shouldn't change the compiled form right? I think this is a hallucination.

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