fix: raise ValueError when cp.Parameter receives a sparse value (#2890)#3280
fix: raise ValueError when cp.Parameter receives a sparse value (#2890)#3280Vivaan-Atharva wants to merge 4 commits into
Conversation
|
Benchmarks that have improved:
Benchmarks that have stayed the same: |
| from __future__ import annotations | ||
|
|
||
| import cvxpy.lin_ops.lin_utils as lu | ||
| import scipy.sparse as sp |
There was a problem hiding this comment.
please install the pre-commit
There was a problem hiding this comment.
Donee, installed pre commit and ran it, ruff fixed the import ordering.
| def value(self, val) -> None: | ||
| if sp.issparse(val): | ||
| raise ValueError( | ||
| "Setting a cp.Parameter value to a sparse matrix or array " |
There was a problem hiding this comment.
This error message is not quite right. We have a distinction now between .value and .value_sparse. I think now that Scipy has ND sparse arrays we can pass in sparse inputs via .value.
There was a problem hiding this comment.
Updated the message, it no longer claims Parameters are dense only. It now points to the sparsity attribute + .value_sparse for sparse parameters, and cp.Constant() for the constant use case.
ec120d0 to
7644bb2
Compare
| "To use a sparse constant, use cp.Constant() instead." | ||
| ) | ||
| Leaf.value.fset(self, val) | ||
| Leaf.value.fset(self, val) # type: ignore[misc] |
There was a problem hiding this comment.
We generally avoid just masking pyright errors; can you explain why we can't fix the underlying issue? I think the problem is we don't have an annotation on val.
There was a problem hiding this comment.
ah got it, added an assert to narrow the type instead
There was a problem hiding this comment.
Why is this a new file? If we keep it as a new file it needs the copyright header etc.
There was a problem hiding this comment.
Overall I think this is way too many tests
There was a problem hiding this comment.
Why is this a new file? If we keep it as a new file it needs the copyright header etc.
moved everything into test_parameters_failures, deleted the new file
| p.value = None | ||
| assert p.value is None | ||
|
|
||
| def test_accepts_scalar(self): |
There was a problem hiding this comment.
Surely we already have this test somewhere?
There was a problem hiding this comment.
yeah removed those, they're already in test_parameters_successes
|
|
||
| @staticmethod | ||
| def _make_sparse_csc(n: int = 4) -> sp.csc_array: | ||
| return sp.eye(n, format="csc") |
There was a problem hiding this comment.
| return sp.eye(n, format="csc") | |
| return sp.eye_array(n, format="csc") |
|
|
||
| def test_rejects_sparse_csc_at_construction(self): | ||
| with pytest.raises(ValueError, match="sparse"): | ||
| cp.Parameter((4, 4), value=self._make_sparse_csc(4)) |
There was a problem hiding this comment.
Why are we using a helper method here but not elsewhere?
There was a problem hiding this comment.
removed the helper, just inlined sp.eye_array directly
Fixes #2890
Problem
cp.Parametersilently accepted a scipy sparse matrix as itsvalue,storing it without error. The failure only surfaced later during
canonicalization with a confusing traceback.
Reproduction
Fix
Override the
valuesetter inParameterto checkscipy.sparse.issparse()before delegating to
Leaf.value.fset. Catches the error at assignment timewith a clear message pointing to
cp.Constantas the alternative.Tests
.value =setter after construction