From 6ede555d55d7310e74c9f8d0c927575f8244915d Mon Sep 17 00:00:00 2001 From: Rob Huisman Date: Tue, 2 Aug 2022 14:23:52 +0200 Subject: [PATCH 1/2] fix multidimensional quad form --- cvxpy/atoms/quad_form.py | 2 +- cvxpy/tests/test_grad.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/cvxpy/atoms/quad_form.py b/cvxpy/atoms/quad_form.py index b772bc310a..9f9d4abffb 100644 --- a/cvxpy/atoms/quad_form.py +++ b/cvxpy/atoms/quad_form.py @@ -113,8 +113,8 @@ def name(self) -> str: def _grad(self, values): x = np.array(values[0]) P = np.array(values[1]) - D = (P + np.conj(P.T)) @ x.T return [sp.csc_matrix(D.ravel(order='F')).T] + D = (P + np.conj(P.T)) @ x def shape_from_args(self) -> Tuple[int, ...]: return tuple() if self.args[0].ndim == 0 else (1, 1) diff --git a/cvxpy/tests/test_grad.py b/cvxpy/tests/test_grad.py index cef1595549..bcb689a369 100644 --- a/cvxpy/tests/test_grad.py +++ b/cvxpy/tests/test_grad.py @@ -267,6 +267,21 @@ def test_quad_form(self) -> None: # access quad_form.expr.grad without error prob.constraints[1].expr.grad + # define the optimization problem with a two-dimensional decision variable + x = cp.Variable((n, 1)) + prob = cp.Problem( + cp.Maximize(q.T @ x - (1 / 2) * cp.quad_form(x, P)), + [ + cp.norm(x, 1) <= 1.0, + cp.quad_form(x, P) <= 10, # quad form constraint + cp.abs(x) <= 0.01, + ], + ) + prob.solve(solver=cp.SCS) + + # access quad_form.expr.grad without error + prob.constraints[1].expr.grad + def test_max(self) -> None: """Test gradient for max """ From 12faa6d15cf30b8582072784abb8117e29197776 Mon Sep 17 00:00:00 2001 From: Rob Huisman Date: Tue, 2 Aug 2022 14:36:59 +0200 Subject: [PATCH 2/2] autoblack messed up line ordering --- cvxpy/atoms/quad_form.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvxpy/atoms/quad_form.py b/cvxpy/atoms/quad_form.py index 9f9d4abffb..115eafb23f 100644 --- a/cvxpy/atoms/quad_form.py +++ b/cvxpy/atoms/quad_form.py @@ -113,8 +113,8 @@ def name(self) -> str: def _grad(self, values): x = np.array(values[0]) P = np.array(values[1]) - return [sp.csc_matrix(D.ravel(order='F')).T] D = (P + np.conj(P.T)) @ x + return [sp.csc_matrix(D.ravel(order="F")).T] def shape_from_args(self) -> Tuple[int, ...]: return tuple() if self.args[0].ndim == 0 else (1, 1)