cvxgrp/cvxpylayers

ValueError: Can't apply Jacobian with a quadratic objective

mr-mikmik opened this issue · 2 comments

Hi all,
I am trying to get gradients on a QP solution, but I am having the following error: ValueError: Can't apply Jacobian with a quadratic objective.
This is the trace:

File python3.8/site-packages/cvxpylayers/torch/cvxpylayer.py:286, in _CvxpyLayerFn.<locals>._CvxpyLayerFnFn.backward(ctx, *dvars)
    284 grad = [[] for _ in range(len(param_order))]
    285 for i in range(ctx.batch_size):
--> 286     del_param_dict = compiler.apply_param_jac(
    287         dcs[i], -dAs[i], dbs[i])
    288     for j, p in enumerate(param_order):
    289         grad[j] += [to_torch(del_param_dict[p.id],
    290                              ctx.dtype, ctx.device).unsqueeze(0)]
File python3.8/site-packages/cvxpy/reductions/dcp2cone/cone_matrix_stuffing.py:222, in ParamConeProg.apply_param_jac(self, delc, delA, delb, active_params)
    214 """Multiplies by Jacobian of parameter mapping.
    215 
    216 Assumes delA is sparse.
   (...)
    219     A dictionary param.id -> dparam
    220 """
    221 if self.P is not None:
--> 222     raise ValueError("Can't apply Jacobian with a quadratic objective.")
    224 if active_params is None:
    225     active_params = {p.id for p in self.parameters}

using cvxpy 1.4.1 and cvxpylayers 0.0.1

I need help understanding why it does not work with quadratic objectives. Any insights will be much appreciated.
Thank you.

Just for reference, this is the form of my program:

$$\begin{array}{ccc} \underset{\mathbf x}{\min} & \frac{1}{2}\mathbf x^T\mathbf Q\mathbf x& \\ \text{s.t.} & \mathbf G \mathbf x \preceq \mathbf h & \\ & \mathbf A\mathbf x = \mathbf b, & \end{array}$$

where $\mathbf x$ is a cp.Variable, $\mathbf Q$ is a constant, and $\mathbf G$, $\mathbf h$, $\mathbf A$, and $\mathbf b$ are cp.Parameter.

For context, the goal is to optimize via the backpropagated gradients a set of parameters that produce $\mathbf G$, $\mathbf h$, $\mathbf A$, and $\mathbf b$.

x1o commented

Can confirm this issue persists with the latest stable of cvxpy & cvxpylayers. The relevant change commited by @SteveDiamond made it into v1.3.0 and above.

I tried 1.2.5 and it seemed to have worked in my case, namely

$$\min_{\mathbf{y}} \mathbf{y}^{\intercal}\boldsymbol{\Sigma}\mathbf{y}, \quad \text{s.t.}\ \mathbf{y} \geq \boldsymbol{0},\ \log(\mathbf{y})^{\intercal} \mathbf{b} \geq 1.$$

>>> import tensorflow as tf
>>> import cvxpy as cp
>>> from cvxpylayers.tensorflow import CvxpyLayer
>>> y = cp.Variable(2, pos=True)
>>> b = cp.Parameter(2, pos=True)
>>> S = cp.Parameter((2, 2), PSD=True)
>>> constraints = [y >= 0, cp.log(y) @ b >= 1]
>>> objective = cp.Minimize(cp.sum_squares(S @ y))
>>> problem = cp.Problem(objective, constraints)
>>> cvxpylayer = CvxpyLayer(problem, parameters=[S, b], variables=[y])
>>> problem.is_dpp()
True
>>> Sigma = tf.constant([[1, 0.5], [0.5, 1]])
>>> b_t = tf.Variable([0.4, 0.6])
>>>
>>> with tf.GradientTape() as tape:
...     y_s, = cvxpylayer(Sigma, b_t)
...     m = tf.reduce_sum(tf.square(y_s))
>>> tape.gradient(m, b_t)
<tf.Tensor: shape=(2,), dtype=float64, numpy=array([-27.85296513, -30.29720541])>
>>>

Probably @bamos or @akshayka have more to say 🙏🏻

x1o commented

Most likely relevant: #137