def factor(W, H = None, Df = None): blas.scal(0.0, K) if H is not None: K[:n, :n] = H K[n:n+p, :n] = A for k in range(n): if mnl: g[:mnl] = Df[:,k] g[mnl:] = G[:,k] scale(g, W, trans = 'T', inverse = 'I') pack(g, K, dims, mnl, offsety = k*ldK + n + p) K[(ldK+1)*(p+n) :: ldK+1] = -1.0 # Add positive regularization in 1x1 block and negative in 2x2 block. blas.copy(K, Ktilde) Ktilde[0 : (ldK+1)*n : ldK+1] += EPSILON Ktilde[(ldK+1)*n :: ldK+1] += -EPSILON lapack.sytrf(Ktilde, ipiv) def solve(x, y, z): # Solve # # [ H A' GG'*W^{-1} ] [ ux ] [ bx ] # [ A 0 0 ] * [ uy [ = [ by ] # [ W^{-T}*GG 0 -I ] [ W*uz ] [ W^{-T}*bz ] # # and return ux, uy, W*uz. # # On entry, x, y, z contain bx, by, bz. On exit, they contain # the solution ux, uy, W*uz. blas.scal(0.0, sltn) blas.copy(x, u) blas.copy(y, u, offsety = n) scale(z, W, trans = 'T', inverse = 'I') pack(z, u, dims, mnl, offsety = n + p) blas.copy(u, r) # Iterative refinement algorithm: # Init: sltn = 0, r_0 = [bx; by; W^{-T}*bz] # 1. u_k = Ktilde^-1 * r_k # 2. sltn += u_k # 3. r_k+1 = r - K*sltn # Repeat until exceed MAX_ITER iterations or ||r|| <= ERROR_BOUND iteration = 0 resid_norm = 1 while iteration <= MAX_ITER and resid_norm > ERROR_BOUND: lapack.sytrs(Ktilde, ipiv, u) blas.axpy(u, sltn, alpha = 1.0) blas.copy(r, u) blas.symv(K, sltn, u, alpha = -1.0, beta = 1.0) resid_norm = math.sqrt(blas.dot(u, u)) iteration += 1 blas.copy(sltn, x, n = n) blas.copy(sltn, y, offsetx = n, n = p) unpack(sltn, z, dims, mnl, offsetx = n + p) return solve
def __init__(self, prob=QP(), Free=[], **kwargs): 'Initialize the PDASc' # Initialize the superclass super(PDASc, self).__init__(prob, **kwargs) # Add additional data self.F = Free nf = len(self.F) m = self.QP.numeq Q1 = sparse([self.QP.H[self.F, self.F], self.QP.Aeq[:, self.F]]) Q2 = sparse([self.QP.Aeq[:, self.F].T, spmatrix([], [], [], (m, m))]) self.ipiv = matrix(1, (nf + m, 1)) self.Q = matrix([[Q1], [Q2]]) lapack.sytrf(self.Q, self.ipiv) # LDL factorization of Q, dense, option 1 # lapack.sytrf(self.Q,self.ipiv) # self.DiagQi = spdiag([self.Q[i,i] for i in range(nf+m)]) # self.LQ = copy(self.Q) # for i in range(nf+m): # self.LQ[i,i] = 1 # for j in range(i+1,nf+m): # self.LQ[i,j] = 0 # LDL factorization of Q, dense, option 2 by calling Matlab library # mlab = Matlab() # mlab.start() filename = 'temp/' + ''.join([ random.choice(string.ascii_letters + string.digits) for n in xrange(32) ]) s = dict() s['A'] = sparse([[Q1], [Q2]]) write(filename + '.mat', s) d = '/home/zhh210/workspace/pypdas/numeric/control/' # Memory failure when size is large # output = mlab.run_func('getldp.m',{'arg1':filename}) # self.LQ = matrix(output['result']['L']) # self.Dinv = matrix(output['result']['Dinv']) # self.P = matrix(output['result']['P']) # output = mlab.run_func('saveldp.m',{'arg1':filename}) # Execute shell command cmd = 'matlab -r ' + '"' + "saveldp('" + filename + "');quit" + '"' print cmd os.system(cmd) data = read(filename + '.mat') self.LQ = matrix(data['L']) self.Dinv = data['Dinv'] self.P = data['P']
def __init__(self,prob = QP(),Free=[],**kwargs): 'Initialize the PDASc' # Initialize the superclass super(PDASc,self).__init__(prob,**kwargs) # Add additional data self.F = Free nf = len(self.F) m = self.QP.numeq Q1 = sparse([self.QP.H[self.F,self.F], self.QP.Aeq[:,self.F] ]) Q2 = sparse([self.QP.Aeq[:,self.F].T, spmatrix([],[],[],(m,m)) ]) self.ipiv = matrix(1,(nf+m,1)) self.Q = matrix([[Q1],[Q2]]) lapack.sytrf(self.Q,self.ipiv) # LDL factorization of Q, dense, option 1 # lapack.sytrf(self.Q,self.ipiv) # self.DiagQi = spdiag([self.Q[i,i] for i in range(nf+m)]) # self.LQ = copy(self.Q) # for i in range(nf+m): # self.LQ[i,i] = 1 # for j in range(i+1,nf+m): # self.LQ[i,j] = 0 # LDL factorization of Q, dense, option 2 by calling Matlab library # mlab = Matlab() # mlab.start() filename = 'temp/'+''.join([random.choice(string.ascii_letters + string.digits) for n in xrange(32)]) s = dict() s['A'] = sparse([[Q1],[Q2]]) write(filename+'.mat',s) d = '/home/zhh210/workspace/pypdas/numeric/control/' # Memory failure when size is large # output = mlab.run_func('getldp.m',{'arg1':filename}) # self.LQ = matrix(output['result']['L']) # self.Dinv = matrix(output['result']['Dinv']) # self.P = matrix(output['result']['P']) # output = mlab.run_func('saveldp.m',{'arg1':filename}) # Execute shell command cmd = 'matlab -r '+'"'+ "saveldp('"+filename + "');quit" + '"' print cmd os.system(cmd) data = read(filename+'.mat') self.LQ = matrix(data['L']) self.Dinv = data['Dinv'] self.P = data['P']
def factor(W, H=None, Df=None): blas.scal(0.0, K) if H is not None: K[:n, :n] = H K[n:n+p, :n] = A for k in range(n): if mnl: g[:mnl] = Df[:, k] g[mnl:] = G[:, k] scale(g, W, trans='T', inverse='I') pack(g, K, dims, mnl, offsety=k*ldK + n + p) K[(ldK+1)*(p+n):: ldK+1] = -1.0 # Add positive regularization in 1x1 block and negative in 2x2 block. K[0: (ldK+1)*n: ldK+1] += REG_EPS K[(ldK+1)*n:: ldK+1] += -REG_EPS lapack.sytrf(K, ipiv) def solve(x, y, z): # Solve # # [ H A' GG'*W^{-1} ] [ ux ] [ bx ] # [ A 0 0 ] * [ uy [ = [ by ] # [ W^{-T}*GG 0 -I ] [ W*uz ] [ W^{-T}*bz ] # # and return ux, uy, W*uz. # # On entry, x, y, z contain bx, by, bz. On exit, they contain # the solution ux, uy, W*uz. blas.copy(x, u) blas.copy(y, u, offsety=n) scale(z, W, trans='T', inverse='I') pack(z, u, dims, mnl, offsety=n + p) lapack.sytrs(K, ipiv, u) blas.copy(u, x, n=n) blas.copy(u, y, offsetx=n, n=p) unpack(u, z, dims, mnl, offsetx=n + p) return solve
def Aopt_KKT_solver(si2, W): ''' Construct a solver that solves the KKT equations associated with the cone programming for A-optimal: / 0 At Gt \ / x \ / p \ | A 0 0 | | y | = | q | \ G 0 -Wt W / \ z / \ s / Args: si2: symmetric KxK matrix, si2[i,j] = 1/s_{ij}^2 ''' K = si2.size[0] ds = W['d'] dis = W['di'] # dis[i] := 1./ds[i] rtis = W['rti'] ris = W['r'] d2s = ds**2 di2s = dis**2 # R_i = r_i^{-t}r_i^{-1} Ris = [matrix(0.0, (K + 1, K + 1)) for i in xrange(K)] for i in xrange(K): blas.gemm(rtis[i], rtis[i], Ris[i], transB='T') ddR2 = matrix(0., (K * (K + 1) / 2, K * (K + 1) / 2)) sumdR2_C(Ris, ddR2, K) # upper triangular representation si2ab[(a,b)] := si2[a,b] si2ab = matrix(0., (K * (K + 1) / 2, 1)) p = 0 for i in xrange(K): si2ab[p:p + (K - i)] = si2[i:, i] p += (K - i) si2q = matrix(0., (K * (K + 1) / 2, K * (K + 1) / 2)) blas.syr(si2ab, si2q) sRVR = cvxopt.mul(si2q, ddR2) # We first solve for K(K+1)/2 n_{ab}, K u_i, 1 y nvars = K * (K + 1) / 2 + K # + 1 We solve y by elimination of n and u. Bm = matrix(0.0, (nvars, nvars)) # The LHS matrix of equations # # d_{ab}^{-2} n_{ab} + vec(V_{ab})^t . vec( \sum_i R_i* F R_i*) # + \sum_i vec(V_{ab})^t . vec( g_i g_i^t) u_i + y # = -d_{ab}^{-2}l_{ab} + ( p_{ab} - vec(V_{ab})^t . vec(\sum_i L_i*) # # Coefficients for n_{ab} Bm[:K * (K + 1) / 2, :K * (K + 1) / 2] = cvxopt.mul(si2q, ddR2) row = 0 for a in xrange(K): for b in xrange(a, K): Bm[row, row] += di2s[row] # d_{ab}^{-2} n_{ab} row += 1 assert (K * (K + 1) / 2 == row) # Coefficients for u_i # The LHS of equations # g_i^t F g_i + R_{i,K+1,K+1}^2 u_i = pi - L_{i,K+1,K+1} dg = matrix(0., (K, K * (K + 1) / 2)) g = matrix(0., (K, K)) for i in xrange(K): g[i, :] = Ris[i][K, :K] # dg[:,(a,b)] = g[a] - g[b] if a!=b else g[a] pairwise_diff(g, dg, K) dg2 = dg**2 # dg2 := s[(a,b)]^{-2} dg[(a,b)]^2 for i in xrange(K): dg2[i, :] = cvxopt.mul(si2ab.T, dg2[i, :]) Bm[K * (K + 1) / 2:K * (K + 1) / 2 + K, :-K] = dg2 # Diagonal coefficients for u_i. uoffset = K * (K + 1) / 2 for i in xrange(K): RiKK = Ris[i][K, K] Bm[uoffset + i, uoffset + i] = RiKK**2 # Compare with the default KKT solver. TEST_KKT = False if (TEST_KKT): Bm0 = matrix(0., Bm.size) blas.copy(Bm, Bm0) G, h, A = Aopt_GhA(si2) dims = dict(l=K * (K + 1) / 2, q=[], s=[K + 1] * K) default_solver = misc.kkt_ldl(G, dims, A)(W) ipiv = matrix(0, Bm.size) lapack.sytrf(Bm, ipiv) # TODO: IS THIS A POSITIVE DEFINITE MATRIX? # lapack.potrf( Bm) # oz := (1, ..., 1, 0, ..., 0)' with K*(K+1)/2 ones and K zeros oz = matrix(0., (Bm.size[0], 1)) oz[:K * (K + 1) / 2] = 1. # iB1 := B^{-1} oz iB1 = matrix(oz[:], oz.size) lapack.sytrs(Bm, ipiv, iB1) # lapack.potrs( Bm, iB1) ####### # # The solver # ####### def kkt_solver(x, y, z): if (TEST_KKT): x0 = matrix(0., x.size) y0 = matrix(0., y.size) z0 = matrix(0., z.size) x0[:] = x[:] y0[:] = y[:] z0[:] = z[:] # Get default solver solutions. xp = matrix(0., x.size) yp = matrix(0., y.size) zp = matrix(0., z.size) xp[:] = x[:] yp[:] = y[:] zp[:] = z[:] default_solver(xp, yp, zp) offset = K * (K + 1) / 2 for i in xrange(K): symmetrize_matrix(zp, K + 1, offset) offset += (K + 1) * (K + 1) # pab = x[:K*(K+1)/2] # p_{ab} 1<=a<=b<=K # pis = x[K*(K+1)/2:] # \pi_i 1<=i<=K # z_{ab} := d_{ab}^{-1} z_{ab} # \mat{z}_i = r_i^{-1} \mat{z}_i r_i^{-t} misc.scale(z, W, trans='T', inverse='I') l = z[:] # l_{ab} := d_{ab}^{-2} z_{ab} # \mat{z}_i := r_i^{-t}r_i^{-1} \mat{z}_i r_i^{-t} r_i^{-1} misc.scale(l, W, trans='N', inverse='I') # The RHS of equations # # d_{ab}^{-2}n_{ab} + vec(V_{ab})^t . vec( \sum_i R_i* F R_i*) # + \sum_i vec(V_{ab})^t . vec( g_i g_i^t) u_i + y # = -d_{ab}^{-2} l_{ab} + ( p_{ab} - vec(V_{ab})^t . vec(\sum_i L_i*) # ### # Lsum := \sum_i L_i moffset = K * (K + 1) / 2 Lsum = np.sum(np.array(l[moffset:]).reshape((K, (K + 1) * (K + 1))), axis=0) Lsum = matrix(Lsum, (K + 1, K + 1)) Ls = Lsum[:K, :K] x[:K * (K + 1) / 2] -= l[:K * (K + 1) / 2] dL = matrix(0., (K * (K + 1) / 2, 1)) ab = 0 for a in xrange(K): dL[ab] = Ls[a, a] ab += 1 for b in xrange(a + 1, K): dL[ab] = Ls[a, a] + Ls[b, b] - 2 * Ls[b, a] ab += 1 x[:K * (K + 1) / 2] -= cvxopt.mul(si2ab, dL) # The RHS of equations # g_i^t F g_i + R_{i,K+1,K+1}^2 u_i = pi - L_{i,K+1,K+1} x[K * (K + 1) / 2:] -= l[K * (K + 1) / 2 + (K + 1) * (K + 1) - 1::(K + 1) * (K + 1)] # x := B^{-1} Cv lapack.sytrs(Bm, ipiv, x) # lapack.potrs( Bm, x) # y := (oz'.B^{-1}.Cv[:-1] - y)/(oz'.B^{-1}.oz) y[0] = (blas.dotu(oz, x) - y[0]) / blas.dotu(oz, iB1) # x := B^{-1} Cv - B^{-1}.oz y blas.axpy(iB1, x, -y[0]) # Solve for -n_{ab} - d_{ab}^2 z_{ab} = l_{ab} # We need to return scaled d*z. # z := d_{ab} d_{ab}^{-2}(n_{ab} + l_{ab}) # = d_{ab}^{-1}n_{ab} + d_{ab}^{-1}l_{ab} z[:K * (K + 1) / 2] += cvxopt.mul(dis, x[:K * (K + 1) / 2]) z[:K * (K + 1) / 2] *= -1. # Solve for \mat{z}_i = -R_i (\mat{l}_i + diag(F, u_i)) R_i # = -L_i - R_i diag(F, u_i) R_i # We return # r_i^t \mat{z}_i r_i = -r_i^{-1} (\mat{l}_i + diag(F, u_i)) r_i^{-t} ui = x[-K:] nab = tri2symm(x, K) F = Fisher_matrix(si2, nab) offset = K * (K + 1) / 2 for i in xrange(K): start, end = i * (K + 1) * (K + 1), (i + 1) * (K + 1) * (K + 1) Fu = matrix(0.0, (K + 1, K + 1)) Fu[:K, :K] = F Fu[K, K] = ui[i] Fu = matrix(Fu, ((K + 1) * (K + 1), 1)) # Fu := -r_i^{-1} diag( F, u_i) r_i^{-t} cngrnc(rtis[i], Fu, K + 1, alpha=-1.) # Fu := -r_i^{-1} (\mat{l}_i + diag( F, u_i )) r_i^{-t} blas.axpy(z[offset + start:offset + end], Fu, alpha=-1.) z[offset + start:offset + end] = Fu if (TEST_KKT): offset = K * (K + 1) / 2 for i in xrange(K): symmetrize_matrix(z, K + 1, offset) offset += (K + 1) * (K + 1) dz = np.max(np.abs(z - zp)) dx = np.max(np.abs(x - xp)) dy = np.max(np.abs(y - yp)) tol = 1e-5 if dx > tol: print 'dx=' print dx print x print xp if dy > tol: print 'dy=' print dy print y print yp if dz > tol: print 'dz=' print dz print z print zp if dx > tol or dy > tol or dz > tol: for i, (r, rti) in enumerate(zip(ris, rtis)): print 'r[%d]=' % i print r print 'rti[%d]=' % i print rti print 'rti.T*r=' print rti.T * r for i, d in enumerate(ds): print 'd[%d]=%g' % (i, d) print 'x0, y0, z0=' print x0 print y0 print z0 print Bm0 ### # END of kkt_solver. ### return kkt_solver