QCQP

QCQP is a package for modeling and nonconvex solving quadratically constrained quadratic programs (QCQPs) using relaxations and local search heuristics. Our heuristics are based on the Suggest-and-Improve framework:

The notion of better points is defined by the maximum violation of a point and the objective value. See our associated paper for more information on the Suggest-and-Improve framework.

QCQP is built on top of CVXPY, a domain-specific language for convex optimization embedded in Python.

Installation

NOTE: QCQP was developed before the release of CVXPY 1.0, which is not backward compatible with the previous version CVXPY 0.4. As of August 2018, QCQP is only compatible with CVXPY 0.4.

You should first install CVXPY 0.4, following the instructions here. If you already have CVXPY, make sure you have the version compatible with QCQP by running conda list cvxpy or pip show cvxpy. You can install the compatible version of CVXPY by running the following.

conda install -c cvxgrp cvxpy=0.4.9

The simplest and recommended way of installing QCQP is to run pip install qcqp. To install the package from source, run python setup.py install in the source directory. You may need to run the commands with the sudo privilege.

Example

The following code uses semidefinite relaxation (SDR) to get a lower bound on a random instance of the Boolean least squares problem. Then, using a candidate point generated from the SDR, it runs a coordinate descent method to attempt to find a feasible point with better objective value.

from numpy.random import randn
import cvxpy as cvx
from qcqp import *

n, m = 10, 15
A = randn(m, n)
b = randn(m, 1)

# Form a nonconvex problem.
x = cvx.Variable(n)
obj = cvx.sum_squares(A*x - b)
cons = [cvx.square(x) == 1]
prob = cvx.Problem(cvx.Minimize(obj), cons)

# Create a QCQP handler.
qcqp = QCQP(prob)

# Solve the SDP relaxation and get a starting point to a local method
qcqp.suggest(SDR)
print("SDR lower bound: %.3f" % qcqp.sdr_bound)

# Attempt to improve the starting point given by the suggest method
f_cd, v_cd = qcqp.improve(COORD_DESCENT)
print("Coordinate descent: objective %.3f, violation %.3f" % (f_cd, v_cd))
print(x.value)

Quadratic expressions

The quadraticity of an expression e can be tested using e.is_quadratic(). Below is a list of expressions that CVXPY recognizes as a quadratic expression. Refer to the CVXPY documentation for the specifications of the functions.

Constructing and solving problems

QCQPs must be represented using the standard CVXPY syntax. In order for the problem to be accepted by QCQP, the problem must have a quadratic objective function and quadratic constraints. To apply the Suggest and Improve methods on a QCQP, the corresponding CVXPY problem object must be passed to the QCQP constructor first. For example, if problem is a CVXPY problem object describing a QCQP, then the following code checks the validity and prepares the Suggest and Improve methods:

qcqp = QCQP(problem)

Currently two Suggest methods are available for QCQPs:

Below is a list of available solve methods for QCQPs:

Both improve() and suggest() methods return a pair (f, v), where f represents the current objective value, and v represents the maximum constraint violation of the current point.