Add diffengine as DCP canonicalization backend with parameter support#185
Draft
Transurgeon wants to merge 46 commits intomasterfrom
Draft
Add diffengine as DCP canonicalization backend with parameter support#185Transurgeon wants to merge 46 commits intomasterfrom
Transurgeon wants to merge 46 commits intomasterfrom
Conversation
Enable cp.Parameter objects to be treated as updatable nodes in the C expression DAG instead of being baked in as constants. On re-solve with new parameter values, the cached DAG and sparsity structures are reused via problem._nlp_cache, analogous to DPP for conic programs. Requires SparseDiffPy PR #10 for make_parameter, problem_register_params, and problem_update_params bindings. Tests skip gracefully until installed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove diag_mat, upper_tri, vstack, and kron converters and their tests. Simplify solve_nlp parameter caching to mirror the best_of pattern: always re-run the full reduction chain, cache only the solver_cache (Oracles) on problem._nlp_cache between solve() calls. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace build_theta(params, inverse_data) with simple concatenation. Add build_param_id_map() helper. Replace inverse_data parameter with param_id_map dict throughout converters, C_problem, and Oracles. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Will revisit testing after SparseDiffPy parameter bindings are available. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace scattered var_dict/n_vars/param_id_map threading with a single ConvertContext class built from InverseData. All atom converters now have uniform (expr, children, ctx) signature. Remove _is_parametric, _PARAMETRIC_CONVERTERS, build_param_id_map, build_variable_dict, convert_expressions. C_problem creates its own InverseData internally. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move matmul/multiply parameter handling to ConvertContext methods. All other converters keep their original (expr, children) signature untouched. convert_expr dispatches matmul/multiply specially via ctx. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Keep all atom converters with their original (expr, children) signatures. Only matmul and multiply are handled via ConvertContext methods. ATOM_CONVERTERS dict entries preserved exactly as original. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move update_params call into ipopt solve_via_data (where oracles are reused). Remove _get_solver_cache helper and _nlp_cache dict. Store solver_cache in the existing problem._solver_cache['NLP'] — zero changes to problem.py. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move theta construction into Oracles.update_params(problem). Remove build_theta from converters. Add update_params call to all four NLP solvers (IPOPT, Knitro, Uno, COPT) on oracle reuse path. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add test_nlp_parameters.py with 3 tests (scalar, vector, matrix) - Initialize parameter values after registration in C_problem - Add oracles.update_params() call to all NLP solvers on cache reuse - Use problem._solver_cache['NLP'] for oracle caching - Restore original docstrings in c_problem.py Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The parameter-bindings branch of SparseDiffPy always requires param_or_none as the first arg to matmul functions. Pass it unconditionally (None for non-parametric). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ab79296 to
000315b
Compare
|
Benchmarks that have stayed the same: |
Introduces the diffengine (sparsediffpy) as an alternative canonicalization backend for the DCP→Cone path, selected via canon_backend='DIFFENGINE'. Unlike the standard tensor pipeline, this backend evaluates the C expression DAG directly at x=0 to extract A, b, q, d, P matrices. Parameters are supported via update_params + re-evaluation on subsequent solves, enabling efficient DPP re-solving. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
000315b to
22851ec
Compare
Keep master's convert_expr(expr, var_dict, n_vars) pattern, adding param_dict as an optional arg. Matmul/multiply stay as standalone functions rather than class methods. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- helpers.py: shared utilities, matmul helpers, var/param dict builders - registry.py: atom converter functions and ATOM_CONVERTERS dict - converters.py: convert_expr entry point and param-aware matmul/multiply Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Syncs the diffengine DCP backend with the parameter-support branch's refactored converter architecture (ConvertContext -> flat functions, converters.py split into helpers.py + registry.py + converters.py). Updates diffengine_cone_program.py to use build_var_dict/build_param_dict. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move DIFFENGINE_CANON_BACKEND to settings.py with other backend constants - Extract build_capsule() in converters.py to deduplicate capsule-building logic between C_problem (NLP path) and DiffengineConeProgram (DCP path) - Use inverse_data.param_id_map instead of manually rebuilding param_id_to_col - Fix flatten order='C' -> 'F' in apply_parameters for consistency - Replace complex _symmetrize_hessian caching with simple P + P.T - diag() Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…import - Remove unnecessary NonPos import and branch from lower_and_order_constraints (added by a previous session, not in master, deprecated constraint type) - Rename DIFFENGINE_CANON_BACKEND -> DIFFENGINE_BACKEND - Replace lazy _get_diffengine() with direct import in diffengine_cone_program Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace separate variables, var_id_to_col, param_id_to_col, and n_vars constructor params with a single inverse_data object. Parameter metadata (param_id_to_col, param_id_to_size) and variable mappings now read directly from inverse_data instead of being rebuilt. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move build_capsule and extract_lower/upper_bounds imports to top of file - Remove de = _diffengine aliases, use _diffengine directly - Remove double np.asarray(np.array(...)) wrapping - Remove unused self._n_vars, read from inverse_data.x_length - Replace unused param_dict with _ Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove self._x0 caching, create zeros inline each call - Move Hessian computation into quad_obj return branch - Remove intermediate P = None / if P is not None pattern Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Keep only externally-accessed properties (variables, var_id_to_col, id_to_var, param_id_to_col). Inline constr_size and total_param_size checks directly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rename _A, _b, _q, _d, _inverse_data to A, b, q, d, inverse_data for consistency with x and P which were already public. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
# Conflicts: # cvxpy/reductions/dcp2cone/cone_matrix_stuffing.py # cvxpy/reductions/solvers/nlp_solvers/diff_engine/__init__.py # cvxpy/reductions/solvers/nlp_solvers/diff_engine/c_problem.py # cvxpy/reductions/solvers/nlp_solvers/diff_engine/converters.py # cvxpy/reductions/solvers/nlp_solvers/diff_engine/helpers.py # cvxpy/reductions/solvers/nlp_solvers/diff_engine/registry.py # cvxpy/reductions/solvers/nlp_solvers/nlp_solver.py # cvxpy/tests/nlp_tests/test_nlp_parameters.py
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
9 tasks
#190) * fix diff engine converter bugs: 1D matmul dims, reshape, transpose, quad form - helpers.py: fix 1D dimension normalization in dense matmul helpers. Right-matmul treated 1D A as (1,n) instead of (n,1), causing segfaults. - converters.py: reshape 1D child to column vector in left-matmul for dot products; add constant-atom fallback for unfolded expressions; move QuadForm/SymbolicQuadForm dispatch out of ATOM_CONVERTERS (needs n_vars); tolerate 1D dimension mismatches via reshape instead of error. - registry.py: support C-order reshape via transpose decomposition; fix 1D transpose to be a no-op; improve scalar quad form P handling; raise NotImplementedError for vector SymbolicQuadForm (TODO: native block quadform in SparseDiffPy). - perspective_canon.py: handle DiffengineConeProgram which stores q, d, A, b as separate arrays (vs ParamConeProg sparse tensors). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * adds converters changes for right matmul support * fixes crashes for left matmul * add changes to registry * run linter --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
# Conflicts: # cvxpy/reductions/solvers/nlp_solvers/diff_engine/converters.py # cvxpy/reductions/solvers/nlp_solvers/diff_engine/registry.py
The [tool.uv.sources] block pinned sparsediffpy to ../SparseDiffPy for local dev, but it also applied in CI where that path doesn't exist, causing `uv pip install -e .` to fail with "Distribution not found". The required bindings have shipped to PyPI under the existing >= 0.2.2, < 0.3.0 range, so the override is no longer needed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Introduces the diffengine (sparsediffpy) as an alternative canonicalization backend for the DCP→Cone path, selected via canon_backend='DIFFENGINE'. Unlike the standard tensor pipeline, this backend evaluates the C expression DAG directly at x=0 to extract A, b, q, d, P matrices. Parameters are supported via update_params + re-evaluation on subsequent solves, enabling efficient DPP re-solving.
Description
Please include a short summary of the change.
Issue link (if applicable):
Type of change
Contribution checklist