Skip to content

Forward CVXPY direct cones to Moreau (fixes #252) - #253

Closed
sbarratt wants to merge 1 commit into
masterfrom
fix-moreau-dir-cones
Closed

sbarratt wants to merge 1 commit into
masterfrom
fix-moreau-dir-cones

Conversation

@sbarratt

@sbarratt sbarratt commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

Claude-generated PR.

Fixes #252.

Problem

With solver="MOREAU", CVXPY moves constraints on variables (x >= 0, nonneg=True, PSD=True, and SOC/exp/power cones on variables) out of the rows of A into data["dir_cones"]. cvxpylayers built Moreau's Cones from the cone dimensions alone, so the layer silently ignored these constraints. On cvxpy 1.9.3 this also caused 26 failures in the existing test_moreau.py / test_moreau_dual_variables.py.

Changes

  • Pass direct cones to Moreau. get_solver_ctx passes dir_cones to MOREAU_ctx, which sets them on moreau.Cones (as CVXPY's own interface does).
  • Scale PSD direct cones. Moreau expects sqrt(2)-scaled off-diagonals and CVXPY stores them unscaled, so the solver works in x_solver = scale * x. MOREAU_ctx precomputes a scale for each CSR nonzero. The Torch and JAX paths scale P, A and q and unscale the primal, and so does the constant-P/A setup() path. The JAX warm-start cache stores the scaled primal, since that is Moreau's coordinate system.
    • This runs in the solver context, not by rescaling the parametrization matrices at build time. param_prob is cached by CVXPY and shared between layers built from the same problem, so rescaling it in place would compound.
  • Direct-cone duals. Moreau returns them separately as z_x. Both backends now append z_x to the dual vector, and _build_constr_id_to_slice maps those constraints after the conic rows. So constraint.dual_variables[0] for e.g. x >= 0 still works, including gradients.

Only MOREAU produces dir_cones, so other solvers are unaffected.

Tests

New tests/test_moreau_direct_cones.py covers each direct-cone kind: nonneg constraint, nonneg attribute, SOC, exp, power, PSD (quadratic) and PSD with a parameter in A. It checks:

  • Values against CLARABEL, for Torch and JAX, unbatched and batched, plus JAX warm start
  • Gradients against finite differences (CLARABEL at tight tolerances), for Torch and JAX. Exp/power gradients match to ~3e-3, so the gradient tolerance is 5e-3. Moreau gives the same gradients whether the cone is direct or in the rows of A.
  • Duals of nonneg and PSD constraints that became direct cones

Locally (cvxpy 1.9.3, moreau 0.4.1, CPU): pytest tests/ gives 288 passed and 3 failed. The 3 failures (test_torch.py::test_sdp and 2 DIFFCP dual gradchecks in test_dual_variables.py) also fail on master. CUDA paths were not tested.

Found while working on this (not fixed here)

Building a second MOREAU layer from the same cp.Problem gives wrong results, even on master and without direct cones (reproduced with MOREAU only; CUCLARABEL/MPAX share the code path but were not tested). get_solver_ctx re-permutes CVXPY's cached param_prob.reduced_{P,A}.reduced_mat in place on every build. I'll leave that for a separate issue/PR.

🤖 Generated with Claude Code

CVXPY's MOREAU interface moves constraints on variables (x >= 0,
nonneg=True, PSD=True, SOC/exp/power cones on variables) out of the rows
of A into `dir_cones`. cvxpylayers built Moreau's cones from the cone
dimensions alone, so these constraints were silently dropped.

- Pass `dir_cones` to MOREAU_ctx and set them on moreau.Cones.
- For psd_triangle direct cones, apply CVXPY's sqrt(2) off-diagonal
  scaling (solve in x_solver = scale * x) in the Torch and JAX paths,
  including constant P/A setup and the JAX warm-start cache.
- Append Moreau's direct-cone duals (z_x) to the dual vector and map
  those constraints' duals in parse_args, so their dual variables can
  still be requested.

Fixes #252

Claude-generated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@PTNobel

PTNobel commented Sep 24, 2026

Copy link
Copy Markdown
Collaborator

I think #248 is the better approach here

@sbarratt

Copy link
Copy Markdown
Collaborator Author

Closing in favor of #248, which also forwards CVXPY's direct cones to Moreau (and fixes the shared-problem parametrization bug noted above). The direct-cone tests from this PR pass on #248's branch.

@sbarratt sbarratt closed this Sep 24, 2026
@sbarratt
sbarratt deleted the fix-moreau-dir-cones branch September 24, 2026 18:28
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.

Moreau backend silently drops constraints that CVXPY turns into direct cones

2 participants