'Gives the (sub/super)gradient of the atom w.r.t. each argument.
Matrix expressions are vectorized, so the gradient is a matrix.
Args:
values: A list of numeric values for the arguments.
Returns:
A list of SciPy CSC sparse matrices or None.'

def _grad(self, values):

    fake_args = []
    var_offsets = {}
    offset = 0
    for (idx, arg) in enumerate(self.args):
        if arg.is_constant():
            fake_args += [Constant(arg.value).canonical_form[0]]
        else:
            fake_args += [lu.create_var(arg.size, idx)]
            var_offsets[idx] = offset
            offset += (arg.size[0] * arg.size[1])
    (fake_expr, _) = self.graph_implementation(fake_args, self.size, self.get_data())
    (V, I, J, _) = canonInterface.get_problem_matrix([lu.create_eq(fake_expr)], var_offsets, None)
    shape = (offset, (self.size[0] * self.size[1]))
    stacked_grad = sp.coo_matrix((V, (J, I)), shape=shape).tocsc()
    grad_list = []
    start = 0
    for arg in self.args:
        if arg.is_constant():
            grad_shape = ((arg.size[0] * arg.size[1]), shape[1])
            if (grad_shape == (1, 1)):
                grad_list += [0]
            else:
                grad_list += [sp.coo_matrix(grad_shape, dtype='float64')]
        else:
            stop = (start + (arg.size[0] * arg.size[1]))
            grad_list += [stacked_grad[start:stop, :]]
            start = stop
    return grad_list
