I am attempting to optimize following problem, but cvxopt does not return a positive semi-definite matrix (although it returns a symmetric matrix) even when I set the constraints rightly (i think).
Please find below code. Kindly help me out.
# maximize Tr(MY)
# subject to
# ||Y|| - kz <= 0
# Tr(Y) - z = 0
# Tr(BY) = 1
# Y >= 0 - positive semidefinite
#
# where
# Y = X z = 1
# -------- ----------
# Tr(BX) Tr(BX)
#
# M = A'B A
# B = covariance matrix
# X = xx' - x are the weights
# k = max no. of stocks in mean reverting portfolio
#
# build model and compute matrices for CVXOPT
# CXOPT requires SDP in standard form as below:
#
# minimize c'Y
#
# subject to:
# G Y + s = h
# A Y = b
#
#
# note we use technique in solution by Fanfan to represent
# the L1 norm constraint ||Y|| in cvxopt by introducting
# new variables.
# Therefore number of variables of optimization are
# Y, z, new variables (lets call it W) for L1 norm
# total variables = 2 x n x n + 1
M = np.dot(Ahat.T, B)
M = np.dot(M, Ahat)
(n,n) = np.shape(M)
# constant in optimization objective requires n x n x 2 + 1
c = np.ravel(M.T).tolist() # constants for Y i.e. n x n
c = [x * -1.0 for x in c] # -1.0 because its minimization
c = c + ([0] * (n*n)) # constants for new variables W
c.append(0) # constant for z
c = np.asarray(c)
# now we construct matrix A. It has 3 parts
# a1 for Tr(Y) - z = 0
# a2 for Tr(BY) = 1
# a3 for sum(W) - kz = 0
a1 = np.ravel(np.eye(n)).tolist() # for Y
a1 = a1 + ([0] * (n*n)) # for W
a1.append(-1.0) # for z
a2 = np.ravel(B.T).tolist() # for Y
a2 = a2 + ([0] * (n*n+1)) # for W and z
a3 = [0] * (n*n) # for Y
a3 = a3 + ([1] * (n*n)) # for W
a3.append(-context.K) # for z
# now A = [a1, a2, a3, a4]'
Alist = [np.asarray(a1),np.asarray(a2),np.asarray(a3)]
A = np.matrix(Alist)
context.H = np.zeros((2*n*n+1,1))
context.G = getG(n,context.K)
context.Hs = getHs(n)
context.Gs = getGs(n)
#CVXOPT begins
cm = matrix(c)
hm = matrix(context.H)
Gm = matrix(context.G)
Am = matrix(A)
bm = matrix([0.0,1.0, 0.0])
sol = sdp(c=cm,Gl=Gm,hl=hm,Gs=context.Gs,hs=context.Hs,A=Am,b=bm)
if sol['status'] <> 'optimal':
return
Y = matrix(sol['x'][0:(n*n)],(n,n))
if (np.any(np.linalg.eigvals(Y) < 0)):
log.info('Y is not positive semidefinite')
def getHs(n):
return [matrix(np.eye(n) * -0.0)]
def getGs(n):
G = np.zeros((n**2,2*n**2+1))
row = 0
for i in range(0,n):
for j in range(0,n):
g = np.zeros((n,n))
if i == j:
g[i,j] = -2.0
else:
g[i,j] = -1.0
g[j,i] = -1.0
g = np.ravel(g).tolist()
g = g + ([0] *(n**2+1))
G[row,:] = g
row += 1
return [matrix(G)]
def getG(n, k):
# we have n x n variables in Y
# we introduct n x n new variables for L1 norm constraint
# we have one more variable for z >= 0
G = np.zeros((2*n*n+1, 2*n*n + 1))
# constraints for inequalities
for i in range(0,n*n):
G[i,i] = -1.0
G[i,n*n+i] = -1.0
# constraints for inequalities
for i in range(0, n*n):
G[n*n+i,i] = 1.0
G[n*n+i,n*n+i] = -1.0
# constraint for z
G[2*n*n,-1] = -1
return G