Minimizing Condition Number by Scaling¶
This notebook provides an example of how to minimize the condition number of a matrix by scaling, taken from https://web.stanford.edu/~boyd/lmibook/. The problem is formulated in CVXPY as a generalized eigenvalue problem (GEVP) and utilizes the DQCP capabilities in CVXPY. The problem for a matrix \(M \in \mathcal{R}^{m \times n}\), with \(m \ge n\) is
\[\begin{split}\begin{array}{llr}
\text{minimize} & \gamma^2 & \\
\text{subject to} & P \in \mathcal{R}^{m \times m} \text{ and diagonal}, & P > 0, \\
& Q \in \mathcal{R}^{n \times n} \text{ and diagonal}, & Q > 0, \\
& Q \le M^T P M \le \gamma^2 Q &
\end{array}\end{split}\]
Example¶
In the following code, we solve the above GEVP with CVXPY.
# import packages
import cvxpy as cp
import numpy as np
# create helper functions
def cond(A):
return np.linalg.cond(A)
def evalCond(M,Q,P):
L = np.diag(np.diag(P.value)**(1/2))
R = np.diag(np.diag(Q.value)**(-1/2))
Mnew = L @ M @ R
return np.linalg.cond(Mnew)
# create a random matrix
m = 3
n = 2
np.random.seed(2)
M = np.random.rand(m,n)
# specify the variables
p = cp.Variable(m,pos=True)
P = cp.diag(p)
q = cp.Variable(n,pos=True)
Q = cp.diag(q)
# define the variables for GEVP
A = M.T @ P @ M
B = Q
C = A - Q
# create the constraints and objective
ep = 1e-3
constr = [C >= ep*np.eye(C.shape[0]),
P >= ep*np.eye(P.shape[0]),
Q >= ep*np.eye(Q.shape[0])]
# note: the variable lambda = gamma^2 from the problem statement
objFun = cp.Minimize(cp.gen_lambda_max(A,B))
# create the problem
problem = cp.Problem(objFun,constr)
# check if DQCP
print("Is the problem DQCP? ",problem.is_dqcp())
# solve
problem.solve(qcp=True,solver="SCS")
# print results
if problem.status not in ["infeasible", "unbounded"]:
print("Initial Condition Number: ",cond(M))
print("Optimized Condition Number: ",evalCond(M,Q,P))
else:
print(problem.status)
Is the problem DQCP? True
Initial Condition Number: 4.1538811703979786
Optimized Condition Number: 1.7548711807791855