def test_basic(self): import kvxopt a = kvxopt.matrix([1.0, 2.0, 3.0]) assert list(a) == [1.0, 2.0, 3.0] b = kvxopt.matrix([3.0, -2.0, -1.0]) c = kvxopt.spmatrix([1.0, -2.0, 3.0], [0, 2, 4], [1, 2, 4], (6, 5)) d = kvxopt.spmatrix([1.0, 2.0, 5.0], [0, 1, 2], [0, 0, 0], (3, 1)) e = kvxopt.mul(a, b) self.assertEqualLists(e, [3.0, -4.0, -3.0]) self.assertAlmostEqualLists(list(kvxopt.div(a, b)), [1.0 / 3.0, -1.0, -3.0]) self.assertAlmostEqual(kvxopt.div([1.0, 2.0, 0.25]), 2.0) self.assertEqualLists(list(kvxopt.min(a, b)), [1.0, -2.0, -1.0]) self.assertEqualLists(list(kvxopt.max(a, b)), [3.0, 2.0, 3.0]) self.assertEqual(kvxopt.max([1.0, 2.0]), 2.0) self.assertEqual(kvxopt.max(a), 3.0) self.assertEqual(kvxopt.max(c), 3.0) self.assertEqual(kvxopt.max(d), 5.0) self.assertEqual(kvxopt.min([1.0, 2.0]), 1.0) self.assertEqual(kvxopt.min(a), 1.0) self.assertEqual(kvxopt.min(c), -2.0) self.assertEqual(kvxopt.min(d), 1.0) self.assertEqual(len(c.imag()), 0) with self.assertRaises(OverflowError): kvxopt.matrix(1.0, (32780 * 4, 32780)) with self.assertRaises(OverflowError): kvxopt.spmatrix(1.0, (0, 32780 * 4), (0, 32780)) + 1
def test_get_det(self): try: import numpy as np except ImportError: self.skipTest("Numpy not available for determinant testing") from kvxopt.klu import numeric, symbolic, get_det from kvxopt import matrix, spmatrix V = [2, 3, 3, -1, 4, 4, -3, 1, 2, 2, 6, 1] Vc = list(map(lambda x: x + x * 1j, V)) I = [0, 1, 0, 2, 4, 1, 2, 3, 4, 2, 1, 4] J = [0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 4, 4] B = matrix([1.0j] * 5) A = spmatrix(V, I, J) Ac = spmatrix(Vc, I, J) # Double matrix case Fs = symbolic(A) Fn = numeric(A, Fs) det1 = get_det(A, Fs, Fn) det2 = np.linalg.det(np.array(matrix(A))) self.assertAlmostEqual(det1, det2) # Complex matrix case Fs = symbolic(Ac) Fn = numeric(Ac, Fs) det1 = get_det(Ac, Fs, Fn) det2 = np.linalg.det(np.array(matrix(Ac))) self.assertAlmostEqual(det1, det2)
def test_basic_complex(self): import kvxopt a = kvxopt.matrix([1, -2, 3]) b = kvxopt.matrix([1.0, -2.0, 3.0]) c = kvxopt.matrix([1.0 + 2j, 1 - 2j, 0 + 1j]) d = kvxopt.spmatrix( [complex(1.0, 0.0), complex(0.0, 1.0), complex(2.0, -1.0)], [0, 1, 3], [0, 2, 3], (4, 4)) e = kvxopt.spmatrix( [complex(1.0, 0.0), complex(0.0, 1.0), complex(2.0, -1.0)], [2, 3, 3], [1, 2, 3], (4, 4)) self.assertAlmostEqualLists(list(kvxopt.div(b, c)), [0.2 - 0.4j, -0.4 - 0.8j, -3j]) self.assertAlmostEqualLists(list(kvxopt.div(b, 2.0j)), [-0.5j, 1j, -1.5j]) self.assertAlmostEqualLists(list(kvxopt.div(a, c)), [0.2 - 0.4j, -0.4 - 0.8j, -3j]) self.assertAlmostEqualLists(list(kvxopt.div(c, a)), [(1 + 2j), (-0.5 + 1j), 0.3333333333333333j]) self.assertAlmostEqualLists(list(kvxopt.div(c, c)), [1.0, 1.0, 1.0]) self.assertAlmostEqualLists(list(kvxopt.div(a, 2.0j)), [-0.5j, 1j, -1.5j]) self.assertAlmostEqualLists(list(kvxopt.div(c, 1.0j)), [2 - 1j, -2 - 1j, 1 + 0j]) self.assertAlmostEqualLists(list(kvxopt.div(1j, c)), [0.4 + 0.2j, -0.4 + 0.2j, 1 + 0j]) self.assertTrue(len(d) + len(e) == len(kvxopt.sparse([d, e]))) self.assertTrue(len(d) + len(e) == len(kvxopt.sparse([[d], [e]])))
def F(x=None, z=None): if x is None: return 0, matrix(1.0, (n, 1)) if min(x) <= 0.0: return None f = -sum(log(x)) Df = -(x**-1).T if z is None: return matrix(f), Df H = spdiag(z[0] * x**-2) return f, Df, H
def test_case2(self): x = variable(2) A = matrix([[2., 1., -1., 0.], [1., 2., 0., -1.]]) b = matrix([3., 3., 0., 0.]) c = matrix([-4., -5.]) ineq = (A * x <= b) lp2 = op(dot(c, x), ineq) lp2.solve() self.assertAlmostEqual(lp2.objective.value()[0], -9.0, places=4)
def F(x=None, z=None): if x is None: return 5, matrix(17 * [0.0] + 5 * [1.0]) if min(x[17:]) <= 0.0: return None f = -x[12:17] + div(Amin, x[17:]) Df = matrix(0.0, (5, 22)) Df[:, 12:17] = spmatrix(-1.0, range(5), range(5)) Df[:, 17:] = spmatrix(-div(Amin, x[17:]**2), range(5), range(5)) if z is None: return f, Df H = spmatrix(2.0 * mul(z, div(Amin, x[17::]**3)), range(17, 22), range(17, 22)) return f, Df, H
def setUp(self): try: from kvxopt import glpk, matrix c = matrix([-4., -5.]) G = matrix([[2., 1., -1., 0.], [1., 2., 0., -1.]]) h = matrix([3., 3., 0., 0.]) A = matrix([1.0,1.0],(1,2)) b = matrix(1.0) self._prob_data = (c,G,h,A,b) except: self.skipTest("GLPK not available")
def f(x, y, z): """ Solve -diag(z) = bx -diag(x) - inv(rti*rti') * z * inv(rti*rti') = bs On entry, x and z contain bx and bs. On exit, they contain the solution, with z scaled (inv(rti)'*z*inv(rti) is returned instead of z). We first solve ((rti*rti') .* (rti*rti')) * x = bx - diag(t*bs*t) and take z = -rti' * (diag(x) + bs) * rti. """ # tbst := t * zs * t = t * bs * t tbst = matrix(z, (n, n)) cngrnc(t, tbst) # x := x - diag(tbst) = bx - diag(rti*rti' * bs * rti*rti') x -= tbst[::n + 1] # x := (t.*t)^{-1} * x = (t.*t)^{-1} * (bx - diag(t*bs*t)) lapack.potrs(tsq, x) # z := z + diag(x) = bs + diag(x) z[::n + 1] += x # z := -rti' * z * rti = -rti' * (diag(x) + bs) * rti cngrnc(rti, z, alpha=-1.0)
def F(x=None, z=None): if x is None: return 0, matrix(0.0, (n, 1)) if max(abs(x)) >= 1.0: return None r = -b blas.gemv(A, x, r, beta=-1.0) w = x**2 f = 0.5 * blas.nrm2(r)**2 - sum(log(1 - w)) gradf = div(x, 1.0 - w) blas.gemv(A, r, gradf, trans='T', beta=2.0) if z is None: return f, gradf.T else: def Hf(u, v, alpha=1.0, beta=0.0): """ v := alpha * (A'*A*u + 2*((1+w)./(1-w)).*u + beta *v """ v *= beta v += 2.0 * alpha * mul(div(1.0 + w, (1.0 - w)**2), u) blas.gemv(A, u, r) blas.gemv(A, r, v, alpha=alpha, beta=1.0, trans='T') return f, gradf.T, Hf
def solve(self, A, b): """ Solve linear system ``Ax = b`` using numeric factorization ``N`` and symbolic factorization ``F``. Store the solution in ``b``. This function caches the symbolic factorization in ``self.F`` and is faster in general. Will attempt ``Solver.linsolve`` if the cached symbolic factorization is invalid. Parameters ---------- A Sparse matrix for the equation set coefficients. F The symbolic factorization of A or a matrix with the same non-zero shape as ``A``. N Numeric factorization of A. b RHS of the equation. Returns ------- numpy.ndarray The solution in a 1-D ndarray """ self.A = A self.b = b if self.factorize is True: self.F = self._symbolic(self.A) self.factorize = False try: self.N = self._numeric(self.A, self.F) self._solve(self.A, self.F, self.N, self.b) return np.ravel(self.b) except ValueError: logger.debug('Unexpected symbolic factorization.') self.F = self._symbolic(self.A) self.solve(self.A, self.b) return np.ravel(self.b) except ArithmeticError: logger.error('Jacobian matrix is singular.') # diag = self.A[0:self.A.size[0] ** 2:self.A.size[0]+1] # idx = (np.argwhere(np.array(matrix(diag)).ravel() == 0.0)).ravel() # logger.error('The xy indices of associated variables:') # logger.error(' '.join([str(item) for item in idx])) # works around a KVXOPT bug suspect_diag = [] for i in range(self.A.size[0]): if self.A[i, i] == 0.0: suspect_diag.append(i) logger.error('Suspect diagonal elements: {}'.format(suspect_diag)) return np.ravel(matrix(np.nan, self.b.size, 'd'))
def F(x=None, z=None): if x is None: return 0, matrix(0.0, (n, 1)) y = A * x - b w = sqrt(rho + y**2) f = sum(w) Df = div(y, w).T * A if z is None: return f, Df H = A.T * spdiag(z[0] * rho * (w**-3)) * A return f, Df, H
def F(x = None, z = None): if x is None: return 0, matrix(0.0, (3,1)) if max(abs(x)) >= 1.0: return None u = 1 - x**2 val = -sum(log(u)) Df = div(2*x, u).T if z is None: return val, Df H = spdiag(2 * z[0] * div(1 + u**2, u**2)) return val, Df, H
def setUp(self): try: from kvxopt import dsdp, matrix c = matrix([1., -1., 1.]) G = [ matrix([[-7., -11., -11., 3.], [7., -18., -18., 8.], [-2., -8., -8., 1.]]) ] G += [ matrix([[-21., -11., 0., -11., 10., 8., 0., 8., 5.], [0., 10., 16., 10., -10., -10., 16., -10., 3.], [-5., 2., -17., 2., -6., 8., -17., 8., 6.]]) ] h = [matrix([[33., -9.], [-9., 26.]])] h += [matrix([[14., 9., 40.], [9., 91., 10.], [40., 10., 15.]])] self._prob_data = (c, G, h) except: self.skipTest("DSDP not available")
def acent(A,b): """ Computes analytic center of A*x <= b with A m by n of rank n. We assume that b > 0 and the feasible set is bounded. """ MAXITERS = 100 ALPHA = 0.01 BETA = 0.5 TOL = 1e-8 ntdecrs = [] m, n = A.size x = matrix(0.0, (n,1)) H = matrix(0.0, (n,n)) for iter in range(MAXITERS): # Gradient is g = A^T * (1./(b-A*x)). d = (b-A*x)**-1 g = A.T * d # Hessian is H = A^T * diag(1./(b-A*x))^2 * A. Asc = mul( d[:,n*[0]], A) blas.syrk(Asc, H, trans='T') # Newton step is v = H^-1 * g. v = -g lapack.posv(H, v) # Directional derivative and Newton decrement. lam = blas.dot(g, v) ntdecrs += [ sqrt(-lam) ] print("%2d. Newton decr. = %3.3e" %(iter,ntdecrs[-1])) if ntdecrs[-1] < TOL: return x, ntdecrs # Backtracking line search. y = mul(A*v, d) step = 1.0 while 1-step*max(y) < 0: step *= BETA while True: if -sum(log(1-step*y)) < ALPHA*step*lam: break step *= BETA x += step*v
def test_print(self): from kvxopt import printing, matrix, spmatrix printing.options['height'] = 2 A = spmatrix(1.0, range(3), range(3), tc='d') print(printing.matrix_repr_default(matrix(A))) print(printing.matrix_str_default(matrix(A))) print(printing.spmatrix_repr_default(A)) print(printing.spmatrix_str_default(A)) print(printing.spmatrix_str_triplet(A)) A = spmatrix(1.0, range(3), range(3), tc='z') print(printing.matrix_repr_default(matrix(A))) print(printing.matrix_str_default(matrix(A))) print(printing.spmatrix_repr_default(A)) print(printing.spmatrix_str_default(A)) print(printing.spmatrix_str_triplet(A)) A = spmatrix([], [], [], (3, 3)) print(printing.spmatrix_repr_default(A)) print(printing.spmatrix_str_default(A)) print(printing.spmatrix_str_triplet(A))
def test_ilp(self): from kvxopt import glpk, matrix c,G,h,A,b = self._prob_data sol1 = glpk.ilp(c, G, h, A, b, set([0]), set()) self.assertTrue(sol1[0]=='optimal') sol2 = glpk.ilp(c, G, h, A, b, set([0]), set()) self.assertTrue(sol2[0]=='optimal') sol3 = glpk.ilp(c, G, h, None, None, set([0, 1]), set()) self.assertTrue(sol3[0]=='optimal') sol4 = glpk.ilp(c, G, h, None, None, set(), set([1])) self.assertTrue(sol4[0]=='optimal') sol5 = glpk.ilp(c, G, h, A, matrix(-1.0), set(), set([0,1])) self.assertTrue(sol5[0]=='LP relaxation is primal infeasible')
def Fkkt(W): rti = W['rti'][0] # t = rti*rti' as a nonsymmetric matrix. t = matrix(0.0, (n, n)) blas.gemm(rti, rti, t, transB='T') # Cholesky factorization of tsq = t.*t. tsq = t**2 lapack.potrf(tsq) def f(x, y, z): """ Solve -diag(z) = bx -diag(x) - inv(rti*rti') * z * inv(rti*rti') = bs On entry, x and z contain bx and bs. On exit, they contain the solution, with z scaled (inv(rti)'*z*inv(rti) is returned instead of z). We first solve ((rti*rti') .* (rti*rti')) * x = bx - diag(t*bs*t) and take z = -rti' * (diag(x) + bs) * rti. """ # tbst := t * zs * t = t * bs * t tbst = matrix(z, (n, n)) cngrnc(t, tbst) # x := x - diag(tbst) = bx - diag(rti*rti' * bs * rti*rti') x -= tbst[::n + 1] # x := (t.*t)^{-1} * x = (t.*t)^{-1} * (bx - diag(t*bs*t)) lapack.potrs(tsq, x) # z := z + diag(x) = bs + diag(x) z[::n + 1] += x # z := -rti' * z * rti = -rti' * (diag(x) + bs) * rti cngrnc(rti, z, alpha=-1.0) return f
def cngrnc(r, x, alpha=1.0): """ Congruence transformation x := alpha * r'*x*r. r and x are square matrices. """ # Scale diagonal of x by 1/2. x[::n + 1] *= 0.5 # a := tril(x)*r a = +r tx = matrix(x, (n, n)) blas.trmm(tx, a, side='L') # x := alpha*(a*r' + r*a') blas.syr2k(r, a, tx, trans='T', alpha=alpha) x[:] = tx[:]
G[25, [16, 21]] = 1.0, -gamma # solve and return W, H, x, y, w, h sol = solvers.cpl(c, F, G, h) return sol['x'][0], sol['x'][1], sol['x'][2:7], sol['x'][7:12], \ sol['x'][12:17], sol['x'][17:] try: import pylab except ImportError: pass else: pylab.figure(facecolor='w') pylab.subplot(221) Amin = matrix([100., 100., 100., 100., 100.]) W, H, x, y, w, h = floorplan(Amin) for k in range(5): pylab.fill([x[k], x[k], x[k] + w[k], x[k] + w[k]], [y[k], y[k] + h[k], y[k] + h[k], y[k]], facecolor='#D0D0D0', edgecolor='black') pylab.text(x[k] + .5 * w[k], y[k] + .5 * h[k], "%d" % (k + 1)) pylab.axis([-1.0, 26, -1.0, 26]) pylab.xticks([]) pylab.yticks([]) pylab.subplot(222) Amin = matrix([20., 50., 80., 150., 200.]) W, H, x, y, w, h = floorplan(Amin) for k in range(5):
# The risk-return trade-off of section 8.4 (Quadratic programming). from math import sqrt from kvxopt import matrix from kvxopt.blas import dot from kvxopt.solvers import qp, options n = 4 S = matrix([[4e-2, 6e-3, -4e-3, 0.0], [6e-3, 1e-2, 0.0, 0.0], [-4e-3, 0.0, 2.5e-3, 0.0], [0.0, 0.0, 0.0, 0.0]]) pbar = matrix([.12, .10, .07, .03]) G = matrix(0.0, (n, n)) G[::n + 1] = -1.0 h = matrix(0.0, (n, 1)) A = matrix(1.0, (1, n)) b = matrix(1.0) N = 100 mus = [10**(5.0 * t / N - 1.0) for t in range(N)] options['show_progress'] = False xs = [qp(mu * S, -pbar, G, h, A, b)['x'] for mu in mus] returns = [dot(pbar, x) for x in xs] risks = [sqrt(dot(x, S * x)) for x in xs] try: import pylab except ImportError: pass else: pylab.figure(1, facecolor='w')
def conelp(c, G, h, dims=None, taskfile=None, **kwargs): """ Solves a pair of primal and dual SOCPs minimize c'*x subject to G*x + s = h s >= 0 maximize -h'*z subject to G'*z + c = 0 z >= 0 using MOSEK 8. The inequalities are with respect to a cone C defined as the Cartesian product of N + M + 1 cones: C = C_0 x C_1 x .... x C_N x C_{N+1} x ... x C_{N+M}. The first cone C_0 is the nonnegative orthant of dimension ml. The next N cones are second order cones of dimension mq[0], ..., mq[N-1]. The second order cone of dimension m is defined as { (u0, u1) in R x R^{m-1} | u0 >= ||u1||_2 }. The next M cones are positive semidefinite cones of order ms[0], ..., ms[M-1] >= 0. The formats of G and h are identical to that used in solvers.conelp(). Input arguments. c is a dense 'd' matrix of size (n,1). dims is a dictionary with the dimensions of the components of C. It has three fields. - dims['l'] = ml, the dimension of the nonnegative orthant C_0. (ml >= 0.) - dims['q'] = mq = [ mq[0], mq[1], ..., mq[N-1] ], a list of N integers with the dimensions of the second order cones C_1, ..., C_N. (N >= 0 and mq[k] >= 1.) - dims['s'] = ms = [ ms[0], ms[1], ..., ms[M-1] ], a list of M integers with the orders of the semidefinite cones C_{N+1}, ..., C_{N+M}. (M >= 0 and ms[k] >= 0.) The default value of dims is {'l': G.size[0], 'q': [], 's': []}. G is a dense or sparse 'd' matrix of size (K,n), where K = ml + mq[0] + ... + mq[N-1] + ms[0]**2 + ... + ms[M-1]**2. Each column of G describes a vector v = ( v_0, v_1, ..., v_N, vec(v_{N+1}), ..., vec(v_{N+M}) ) in V = R^ml x R^mq[0] x ... x R^mq[N-1] x S^ms[0] x ... x S^ms[M-1] stored as a column vector [ v_0; v_1; ...; v_N; vec(v_{N+1}); ...; vec(v_{N+M}) ]. Here, if u is a symmetric matrix of order m, then vec(u) is the matrix u stored in column major order as a vector of length m**2. We use BLAS unpacked 'L' storage, i.e., the entries in vec(u) corresponding to the strictly upper triangular entries of u are not referenced. h is a dense 'd' matrix of size (K,1), representing a vector in V, in the same format as the columns of G. A is a dense or sparse 'd' matrix of size (p,n). The default value is a sparse 'd' matrix of size (0,n). b is a dense 'd' matrix of size (p,1). The default value is a dense 'd' matrix of size (0,1). Optionally, the interface can write a .task file, required for support questions on the MOSEK solver. Return values solsta is a MOSEK solution status key. If solsta is mosek.solsta.optimal, then (x, zl, zq, zs) contains the primal-dual solution. If solsta is moseksolsta.prim_infeas_cer, then (x, zl, zq, zs) is a certificate of dual infeasibility. If solsta is moseksolsta.dual_infeas_cer, then (x, zl, zq, zs) is a certificate of primal infeasibility. If solsta is mosek.solsta.unknown, then (x, zl, zq, zs) are all None Other return values for solsta include: mosek.solsta.dual_feas mosek.solsta.near_dual_feas mosek.solsta.near_optimal mosek.solsta.near_prim_and_dual_feas mosek.solsta.near_prim_feas mosek.solsta.prim_and_dual_feas mosek.solsta.prim_feas in which case the (x,y,z) value may not be well-defined. x, z the primal-dual solution. Options are passed to MOSEK solvers via the msk.options dictionary, e.g., the following turns off output from the MOSEK solvers >>> msk.options = {mosek.iparam.log:0} see the MOSEK Python API manual. """ with mosek.Env() as env: if dims is None: (solsta, x, y, z) = lp(c, G, h) return (solsta, x, z, None) N, n = G.size ml, mq, ms = dims['l'], dims['q'], [k * k for k in dims['s']] cdim = ml + sum(mq) + sum(ms) if cdim == 0: raise ValueError("ml+mq+ms cannot be 0") # Data for kth 'q' constraint are found in rows indq[k]:indq[k+1] of G. indq = [dims['l']] for k in dims['q']: indq = indq + [indq[-1] + k] # Data for the kth 's' constraint are found in rows indq[-1] + (inds[k]:inds[k+1]) of G. inds = [0] for k in dims['s']: inds = inds + [inds[-1] + k * k] if type(h) is not matrix or h.typecode != 'd' or h.size[1] != 1: raise TypeError("'h' must be a 'd' matrix with 1 column") if type(G) is matrix or type(G) is spmatrix: if G.typecode != 'd' or G.size[0] != cdim: raise TypeError("'G' must be a 'd' matrix with %d rows " % cdim) if h.size[0] != cdim: raise TypeError("'h' must have %d rows" % cdim) else: raise TypeError("'G' must be a matrix") if len(dims['q']) and min(dims['q']) < 1: raise TypeError("dimensions of quadratic cones must be positive") if len(dims['s']) and min(dims['s']) < 1: raise TypeError( "dimensions of semidefinite cones must be positive") bkc = n * [mosek.boundkey.fx] blc = list(-c) buc = list(-c) dimx = ml + sum(mq) bkx = ml * [mosek.boundkey.lo] + sum(mq) * [mosek.boundkey.fr] blx = ml * [0.0] + sum(mq) * [-inf] bux = dimx * [+inf] c = list(-h) cl, cs = c[:dimx], sparse(c[dimx:]) Gl, Gs = sparse(G[:dimx, :]), sparse(G[dimx:, :]) colptr, asub, acof = Gl.T.CCS aptrb, aptre = colptr[:-1], colptr[1:] with env.Task(0, 0) as task: task.set_Stream(mosek.streamtype.log, streamprinter) # set MOSEK options options = kwargs.get('options', globals()['options']) for (param, val) in options.items(): if str(param)[:6] == "iparam": task.putintparam(param, val) elif str(param)[:6] == "dparam": task.putdouparam(param, val) elif str(param)[:6] == "sparam": task.putstrparam(param, val) else: raise ValueError("invalid MOSEK parameter: " + str(param)) task.inputdata( n, # number of constraints dimx, # number of variables cl, # linear objective coefficients 0.0, # objective fixed value list(aptrb), list(aptre), list(asub), list(acof), bkc, blc, buc, bkx, blx, bux) task.putobjsense(mosek.objsense.maximize) numbarvar = len(dims['s']) task.appendbarvars(dims['s']) barcsubj, barcsubk, barcsubl = (inds[-1]) * [0], ( inds[-1]) * [0], (inds[-1]) * [0] barcval = [-h[indq[-1] + k] for k in range(inds[0], inds[-1])] for s in range(numbarvar): for (k, idx) in enumerate(range(inds[s], inds[s + 1])): barcsubk[idx] = k // dims['s'][s] barcsubl[idx] = k % dims['s'][s] barcsubj[idx] = s # filter out upper triangular part trilidx = [ idx for idx in range(len(barcsubk)) if barcsubk[idx] >= barcsubl[idx] ] barcsubj = [barcsubj[k] for k in trilidx] barcsubk = [barcsubk[k] for k in trilidx] barcsubl = [barcsubl[k] for k in trilidx] barcval = [barcval[k] for k in trilidx] task.putbarcblocktriplet(len(trilidx), barcsubj, barcsubk, barcsubl, barcval) Gst = Gs.T barasubi = len(Gst) * [0] barasubj = len(Gst) * [0] barasubk = len(Gst) * [0] barasubl = len(Gst) * [0] baraval = len(Gst) * [0.0] colptr, row, val = Gst.CCS for s in range(numbarvar): for j in range(ms[s]): for idx in range(colptr[inds[s] + j], colptr[inds[s] + j + 1]): barasubi[idx] = row[idx] barasubj[idx] = s barasubk[idx] = j // dims['s'][s] barasubl[idx] = j % dims['s'][s] baraval[idx] = val[idx] # filter out upper triangular part trilidx = [ idx for (idx, (k, l)) in enumerate(zip(barasubk, barasubl)) if k >= l ] barasubi = [barasubi[k] for k in trilidx] barasubj = [barasubj[k] for k in trilidx] barasubk = [barasubk[k] for k in trilidx] barasubl = [barasubl[k] for k in trilidx] baraval = [baraval[k] for k in trilidx] task.putbarablocktriplet(len(trilidx), barasubi, barasubj, barasubk, barasubl, baraval) for k in range(len(mq)): task.appendcone(mosek.conetype.quad, 0.0, range(ml + sum(mq[:k]), ml + sum(mq[:k + 1]))) if taskfile: task.writetask(taskfile) task.optimize() task.solutionsummary(mosek.streamtype.msg) solsta = task.getsolsta(mosek.soltype.itr) xu, xl, zq = n * [0.0], n * [0.0], sum(mq) * [0.0] task.getsolutionslice(mosek.soltype.itr, mosek.solitem.slc, 0, n, xl) task.getsolutionslice(mosek.soltype.itr, mosek.solitem.suc, 0, n, xu) task.getsolutionslice(mosek.soltype.itr, mosek.solitem.xx, ml, dimx, zq) x = matrix(xu) - matrix(xl) zq = matrix(zq) for s in range(numbarvar): xx = (dims['s'][s] * (dims['s'][s] + 1) >> 1) * [0.0] task.getbarxj(mosek.soltype.itr, s, xx) xs = matrix(0.0, (dims['s'][s], dims['s'][s])) idx = 0 for j in range(dims['s'][s]): for i in range(j, dims['s'][s]): xs[i, j] = xx[idx] if i != j: xs[j, i] = xx[idx] idx += 1 zq = matrix([zq, xs[:]]) if ml: zl = ml * [0.0] task.getsolutionslice(mosek.soltype.itr, mosek.solitem.xx, 0, ml, zl) zl = matrix(zl) else: zl = matrix(0.0, (0, 1)) if (solsta is mosek.solsta.unknown): return (solsta, None, None) else: return (solsta, x, matrix([zl, zq]))
def socp(c, Gl=None, hl=None, Gq=None, hq=None, taskfile=None, **kwargs): """ Solves a pair of primal and dual SOCPs minimize c'*x subject to Gl*x + sl = hl Gq[k]*x + sq[k] = hq[k], k = 0, ..., N-1 sl >= 0, sq[k] >= 0, k = 0, ..., N-1 maximize -hl'*zl - sum_k hq[k]'*zq[k] subject to Gl'*zl + sum_k Gq[k]'*zq[k] + c = 0 zl >= 0, zq[k] >= 0, k = 0, ..., N-1. using MOSEK 8. solsta, x, zl, zq = socp(c, Gl = None, hl = None, Gq = None, hq = None, taskfile=None) Return values solsta is a MOSEK solution status key. If solsta is mosek.solsta.optimal, then (x, zl, zq) contains the primal-dual solution. If solsta is mosek.solsta.prim_infeas_cer, then (x, zl, zq) is a certificate of dual infeasibility. If solsta is mosek.solsta.dual_infeas_cer, then (x, zl, zq) is a certificate of primal infeasibility. If solsta is mosek.solsta.unknown, then (x, zl, zq) are all None Other return values for solsta include: mosek.solsta.dual_feas mosek.solsta.near_dual_feas mosek.solsta.near_optimal mosek.solsta.near_prim_and_dual_feas mosek.solsta.near_prim_feas mosek.solsta.prim_and_dual_feas mosek.solsta.prim_feas in which case the (x,y,z) value may not be well-defined. x, zl, zq the primal-dual solution. Options are passed to MOSEK solvers via the msk.options dictionary, e.g., the following turns off output from the MOSEK solvers >>> msk.options = {mosek.iparam.log: 0} see the MOSEK Python API manual. Optionally, the interface can write a .task file, required for support questions on the MOSEK solver. """ with mosek.Env() as env: if type(c) is not matrix or c.typecode != 'd' or c.size[1] != 1: raise TypeError("'c' must be a dense column matrix") n = c.size[0] if n < 1: raise ValueError("number of variables must be at least 1") if Gl is None: Gl = spmatrix([], [], [], (0, n), tc='d') if (type(Gl) is not matrix and type(Gl) is not spmatrix) or \ Gl.typecode != 'd' or Gl.size[1] != n: raise TypeError("'Gl' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) ml = Gl.size[0] if hl is None: hl = matrix(0.0, (0, 1)) if type(hl) is not matrix or hl.typecode != 'd' or \ hl.size != (ml,1): raise TypeError("'hl' must be a dense 'd' matrix of " \ "size (%d,1)" %ml) if Gq is None: Gq = [] if type(Gq) is not list or [ G for G in Gq if (type(G) is not matrix and type(G) is not spmatrix) or G.typecode != 'd' or G.size[1] != n ]: raise TypeError("'Gq' must be a list of sparse or dense 'd' "\ "matrices with %d columns" %n) mq = [G.size[0] for G in Gq] a = [k for k in range(len(mq)) if mq[k] == 0] if a: raise TypeError("the number of rows of Gq[%d] is zero" % a[0]) if hq is None: hq = [] if type(hq) is not list or len(hq) != len(mq) or [ h for h in hq if (type(h) is not matrix and type(h) is not spmatrix) or h.typecode != 'd' ]: raise TypeError("'hq' must be a list of %d dense or sparse "\ "'d' matrices" %len(mq)) a = [k for k in range(len(mq)) if hq[k].size != (mq[k], 1)] if a: k = a[0] raise TypeError("'hq[%d]' has size (%d,%d). Expected size "\ "is (%d,1)." %(k, hq[k].size[0], hq[k].size[1], mq[k])) N = ml + sum(mq) h = matrix(0.0, (N, 1)) if type(Gl) is matrix or [Gk for Gk in Gq if type(Gk) is matrix]: G = matrix(0.0, (N, n)) else: G = spmatrix([], [], [], (N, n), 'd') h[:ml] = hl G[:ml, :] = Gl ind = ml for k in range(len(mq)): h[ind:ind + mq[k]] = hq[k] G[ind:ind + mq[k], :] = Gq[k] ind += mq[k] bkc = n * [mosek.boundkey.fx] blc = list(-c) buc = list(-c) bkx = ml * [mosek.boundkey.lo] + sum(mq) * [mosek.boundkey.fr] blx = ml * [0.0] + sum(mq) * [-inf] bux = N * [+inf] c = -h colptr, asub, acof = sparse([G.T]).CCS aptrb, aptre = colptr[:-1], colptr[1:] with env.Task(0, 0) as task: task.set_Stream(mosek.streamtype.log, streamprinter) # set MOSEK options options = kwargs.get('options', globals()['options']) for (param, val) in options.items(): if str(param)[:6] == "iparam": task.putintparam(param, val) elif str(param)[:6] == "dparam": task.putdouparam(param, val) elif str(param)[:6] == "sparam": task.putstrparam(param, val) else: raise ValueError("invalid MOSEK parameter: " + str(param)) task.inputdata( n, # number of constraints N, # number of variables list(c), # linear objective coefficients 0.0, # objective fixed value list(aptrb), list(aptre), list(asub), list(acof), bkc, blc, buc, bkx, blx, bux) task.putobjsense(mosek.objsense.maximize) for k in range(len(mq)): task.appendcone( mosek.conetype.quad, 0.0, list(range(ml + sum(mq[:k]), ml + sum(mq[:k + 1])))) if taskfile: task.writetask(taskfile) task.optimize() task.solutionsummary(mosek.streamtype.msg) solsta = task.getsolsta(mosek.soltype.itr) xu, xl, zq = n * [0.0], n * [0.0], sum(mq) * [0.0] task.getsolutionslice(mosek.soltype.itr, mosek.solitem.slc, 0, n, xl) task.getsolutionslice(mosek.soltype.itr, mosek.solitem.suc, 0, n, xu) task.getsolutionslice(mosek.soltype.itr, mosek.solitem.xx, ml, N, zq) x = matrix(xu) - matrix(xl) zq = [ matrix(zq[sum(mq[:k]):sum(mq[:k + 1])]) for k in range(len(mq)) ] if ml: zl = ml * [0.0] task.getsolutionslice(mosek.soltype.itr, mosek.solitem.xx, 0, ml, zl) zl = matrix(zl) else: zl = matrix(0.0, (0, 1)) if (solsta is mosek.solsta.unknown): return (solsta, None, None, None) else: return (solsta, x, zl, zq)
def lp(c, G, h, A=None, b=None, taskfile=None, **kwargs): """ Solves a pair of primal and dual LPs minimize c'*x maximize -h'*z - b'*y subject to G*x + s = h subject to G'*z + A'*y + c = 0 A*x = b z >= 0. s >= 0 using MOSEK 8. (solsta, x, z, y) = lp(c, G, h, A=None, b=None). Input arguments c is n x 1, G is m x n, h is m x 1, A is p x n, b is p x 1. G and A must be dense or sparse 'd' matrices. c, h and b are dense 'd' matrices with one column. The default values for A and b are empty matrices with zero rows. Optionally, the interface can write a .task file, required for support questions on the MOSEK solver. Return values solsta is a MOSEK solution status key. If solsta is mosek.solsta.optimal, then (x, y, z) contains the primal-dual solution. If solsta is mosek.solsta.prim_infeas_cer, then (x, y, z) is a certificate of primal infeasibility. If solsta is mosek.solsta.dual_infeas_cer, then (x, y, z) is a certificate of dual infeasibility. If solsta is mosek.solsta.unknown, then (x, y, z) are all None. Other return values for solsta include: mosek.solsta.dual_feas mosek.solsta.near_dual_feas mosek.solsta.near_optimal mosek.solsta.near_prim_and_dual_feas mosek.solsta.near_prim_feas mosek.solsta.prim_and_dual_feas mosek.solsta.prim_feas in which case the (x,y,z) value may not be well-defined. x, y, z the primal-dual solution. Options are passed to MOSEK solvers via the msk.options dictionary. For example, the following turns off output from the MOSEK solvers >>> msk.options = {mosek.iparam.log: 0} see the MOSEK Python API manual. """ with mosek.Env() as env: if type(c) is not matrix or c.typecode != 'd' or c.size[1] != 1: raise TypeError("'c' must be a dense column matrix") n = c.size[0] if n < 1: raise ValueError("number of variables must be at least 1") if (type(G) is not matrix and type(G) is not spmatrix) or \ G.typecode != 'd' or G.size[1] != n: raise TypeError("'G' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) m = G.size[0] if m == 0: raise ValueError("m cannot be 0") if type(h) is not matrix or h.typecode != 'd' or h.size != (m, 1): raise TypeError("'h' must be a 'd' matrix of size (%d,1)" % m) if A is None: A = spmatrix([], [], [], (0, n), 'd') if (type(A) is not matrix and type(A) is not spmatrix) or \ A.typecode != 'd' or A.size[1] != n: raise TypeError("'A' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) p = A.size[0] if b is None: b = matrix(0.0, (0, 1)) if type(b) is not matrix or b.typecode != 'd' or b.size != (p, 1): raise TypeError("'b' must be a dense matrix of size (%d,1)" % p) bkc = m * [mosek.boundkey.up] + p * [mosek.boundkey.fx] blc = m * [-inf] + [bi for bi in b] buc = list(h) + list(b) bkx = n * [mosek.boundkey.fr] blx = n * [-inf] bux = n * [+inf] colptr, asub, acof = sparse([G, A]).CCS aptrb, aptre = colptr[:-1], colptr[1:] with env.Task(0, 0) as task: task.set_Stream(mosek.streamtype.log, streamprinter) # set MOSEK options options = kwargs.get('options', globals()['options']) for (param, val) in options.items(): if str(param)[:6] == "iparam": task.putintparam(param, val) elif str(param)[:6] == "dparam": task.putdouparam(param, val) elif str(param)[:6] == "sparam": task.putstrparam(param, val) else: raise ValueError("invalid MOSEK parameter: " + str(param)) task.inputdata( m + p, # number of constraints n, # number of variables list(c), # linear objective coefficients 0.0, # objective fixed value list(aptrb), list(aptre), list(asub), list(acof), bkc, blc, buc, bkx, blx, bux) task.putobjsense(mosek.objsense.minimize) if taskfile: task.writetask(taskfile) task.optimize() task.solutionsummary(mosek.streamtype.msg) solsta = task.getsolsta(mosek.soltype.bas) x, z = n * [0.0], m * [0.0] task.getsolutionslice(mosek.soltype.bas, mosek.solitem.xx, 0, n, x) task.getsolutionslice(mosek.soltype.bas, mosek.solitem.suc, 0, m, z) x, z = matrix(x), matrix(z) if p != 0: yu, yl = p * [0.0], p * [0.0] task.getsolutionslice(mosek.soltype.bas, mosek.solitem.suc, m, m + p, yu) task.getsolutionslice(mosek.soltype.bas, mosek.solitem.slc, m, m + p, yl) y = matrix(yu) - matrix(yl) else: y = matrix(0.0, (0, 1)) if (solsta is mosek.solsta.unknown): return (solsta, None, None, None) else: return (solsta, x, z, y)
def ilp(c, G, h, A=None, b=None, I=None, taskfile=None, **kwargs): """ Solves the mixed integer LP minimize c'*x subject to G*x + s = h A*x = b s >= 0 xi integer, forall i in I using MOSEK 8. solsta, x = ilp(c, G, h, A=None, b=None, I=None, taskfile=None). Input arguments G is m x n, h is m x 1, A is p x n, b is p x 1. G and A must be dense or sparse 'd' matrices. h and b are dense 'd' matrices with one column. The default values for A and b are empty matrices with zero rows. I is a Python set with indices of integer elements of x. By default all elements in x are constrained to be integer, i.e., the default value of I is I = set(range(n)) Dual variables are not returned for MOSEK. Optionally, the interface can write a .task file, required for support questions on the MOSEK solver. Return values solsta is a MOSEK solution status key. If solsta is mosek.solsta.integer_optimal, then x contains the solution. If solsta is mosek.solsta.unknown, then x is None. Other return values for solsta include: mosek.solsta.near_integer_optimal in which case the x value may not be well-defined, c.f., section 17.48 of the MOSEK Python API manual. x is the solution Options are passed to MOSEK solvers via the msk.options dictionary, e.g., the following turns off output from the MOSEK solvers >>> msk.options = {mosek.iparam.log: 0} see the MOSEK Python API manual. """ with mosek.Env() as env: if type(c) is not matrix or c.typecode != 'd' or c.size[1] != 1: raise TypeError("'c' must be a dense column matrix") n = c.size[0] if n < 1: raise ValueError("number of variables must be at least 1") if (type(G) is not matrix and type(G) is not spmatrix) or \ G.typecode != 'd' or G.size[1] != n: raise TypeError("'G' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) m = G.size[0] if m == 0: raise ValueError("m cannot be 0") if type(h) is not matrix or h.typecode != 'd' or h.size != (m, 1): raise TypeError("'h' must be a 'd' matrix of size (%d,1)" % m) if A is None: A = spmatrix([], [], [], (0, n), 'd') if (type(A) is not matrix and type(A) is not spmatrix) or \ A.typecode != 'd' or A.size[1] != n: raise TypeError("'A' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) p = A.size[0] if b is None: b = matrix(0.0, (0, 1)) if type(b) is not matrix or b.typecode != 'd' or b.size != (p, 1): raise TypeError("'b' must be a dense matrix of size (%d,1)" % p) if I is None: I = set(range(n)) if type(I) is not set: raise TypeError("invalid argument for integer index set") for i in I: if type(i) is not int: raise TypeError("invalid integer index set I") if len(I) > 0 and min(I) < 0: raise IndexError("negative element in integer index set I") if len(I) > 0 and max(I) > n - 1: raise IndexError( "maximum element in in integer index set I is larger than n-1") bkc = m * [mosek.boundkey.up] + p * [mosek.boundkey.fx] blc = m * [-inf] + [bi for bi in b] buc = list(h) + list(b) bkx = n * [mosek.boundkey.fr] blx = n * [-inf] bux = n * [+inf] colptr, asub, acof = sparse([G, A]).CCS aptrb, aptre = colptr[:-1], colptr[1:] with env.Task(0, 0) as task: task.set_Stream(mosek.streamtype.log, streamprinter) # set MOSEK options options = kwargs.get('options', globals()['options']) for (param, val) in options.items(): if str(param)[:6] == "iparam": task.putintparam(param, val) elif str(param)[:6] == "dparam": task.putdouparam(param, val) elif str(param)[:6] == "sparam": task.putstrparam(param, val) else: raise ValueError("invalid MOSEK parameter: " + str(param)) task.inputdata( m + p, # number of constraints n, # number of variables list(c), # linear objective coefficients 0.0, # objective fixed value list(aptrb), list(aptre), list(asub), list(acof), bkc, blc, buc, bkx, blx, bux) task.putobjsense(mosek.objsense.minimize) # Define integer variables if len(I) > 0: task.putvartypelist(list(I), len(I) * [mosek.variabletype.type_int]) task.putintparam(mosek.iparam.mio_mode, mosek.miomode.satisfied) if taskfile: task.writetask(taskfile) task.optimize() task.solutionsummary(mosek.streamtype.msg) if len(I) > 0: solsta = task.getsolsta(mosek.soltype.itg) else: solsta = task.getsolsta(mosek.soltype.bas) x = n * [0.0] if len(I) > 0: task.getsolutionslice(mosek.soltype.itg, mosek.solitem.xx, 0, n, x) else: task.getsolutionslice(mosek.soltype.bas, mosek.solitem.xx, 0, n, x) x = matrix(x) if (solsta is mosek.solsta.unknown): return (solsta, None) else: return (solsta, x)
def qp(P, q, G=None, h=None, A=None, b=None, taskfile=None, **kwargs): """ Solves a quadratic program minimize (1/2)*x'*P*x + q'*x subject to G*x <= h A*x = b. using MOSEK 8. solsta, x, z, y = qp(P, q, G=None, h=None, A=None, b=None, taskfile=None) Return values solsta is a MOSEK solution status key. If solsta is mosek.solsta.optimal, then (x, y, z) contains the primal-dual solution. If solsta is mosek.solsta.prim_infeas_cer, then (x, y, z) is a certificate of primal infeasibility. If solsta is mosek.solsta.dual_infeas_cer, then (x, y, z) is a certificate of dual infeasibility. If solsta is mosek.solsta.unknown, then (x, y, z) are all None. Other return values for solsta include: mosek.solsta.dual_feas mosek.solsta.near_dual_feas mosek.solsta.near_optimal mosek.solsta.near_prim_and_dual_feas mosek.solsta.near_prim_feas mosek.solsta.prim_and_dual_feas mosek.solsta.prim_feas in which case the (x,y,z) value may not be well-defined. x, z, y the primal-dual solution. Options are passed to MOSEK solvers via the msk.options dictionary, e.g., the following turns off output from the MOSEK solvers >>> msk.options = {mosek.iparam.log: 0} see the MOSEK Python API manual. Optionally, the interface can write a .task file, required for support questions on the MOSEK solver. """ with mosek.Env() as env: if (type(P) is not matrix and type(P) is not spmatrix) or \ P.typecode != 'd' or P.size[0] != P.size[1]: raise TypeError("'P' must be a square dense or sparse 'd' matrix ") n = P.size[0] if n < 1: raise ValueError("number of variables must be at least 1") if type(q) is not matrix or q.typecode != 'd' or q.size != (n, 1): raise TypeError("'q' must be a 'd' matrix of size (%d,1)" % n) if G is None: G = spmatrix([], [], [], (0, n), 'd') if (type(G) is not matrix and type(G) is not spmatrix) or \ G.typecode != 'd' or G.size[1] != n: raise TypeError("'G' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) m = G.size[0] if h is None: h = matrix(0.0, (0, 1)) if type(h) is not matrix or h.typecode != 'd' or h.size != (m, 1): raise TypeError("'h' must be a 'd' matrix of size (%d,1)" % m) if A is None: A = spmatrix([], [], [], (0, n), 'd') if (type(A) is not matrix and type(A) is not spmatrix) or \ A.typecode != 'd' or A.size[1] != n: raise TypeError("'A' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) p = A.size[0] if b is None: b = matrix(0.0, (0, 1)) if type(b) is not matrix or b.typecode != 'd' or b.size != (p, 1): raise TypeError("'b' must be a dense matrix of size (%d,1)" % p) if m + p == 0: raise ValueError("m + p must be greater than 0") c = list(q) bkc = m * [mosek.boundkey.up] + p * [mosek.boundkey.fx] blc = m * [-inf] + [bi for bi in b] buc = list(h) + list(b) bkx = n * [mosek.boundkey.fr] blx = n * [-inf] bux = n * [+inf] colptr, asub, acof = sparse([G, A]).CCS aptrb, aptre = colptr[:-1], colptr[1:] with env.Task(0, 0) as task: task.set_Stream(mosek.streamtype.log, streamprinter) # set MOSEK options options = kwargs.get('options', globals()['options']) for (param, val) in options.items(): if str(param)[:6] == "iparam": task.putintparam(param, val) elif str(param)[:6] == "dparam": task.putdouparam(param, val) elif str(param)[:6] == "sparam": task.putstrparam(param, val) else: raise ValueError("invalid MOSEK parameter: " + str(param)) task.inputdata( m + p, # number of constraints n, # number of variables c, # linear objective coefficients 0.0, # objective fixed value list(aptrb), list(aptre), list(asub), list(acof), bkc, blc, buc, bkx, blx, bux) Ps = sparse(P) I, J = Ps.I, Ps.J tril = [k for k in range(len(I)) if I[k] >= J[k]] task.putqobj(list(I[tril]), list(J[tril]), list(Ps.V[tril])) task.putobjsense(mosek.objsense.minimize) if taskfile: task.writetask(taskfile) task.optimize() task.solutionsummary(mosek.streamtype.msg) solsta = task.getsolsta(mosek.soltype.itr) x = n * [0.0] task.getsolutionslice(mosek.soltype.itr, mosek.solitem.xx, 0, n, x) x = matrix(x) if m != 0: z = m * [0.0] task.getsolutionslice(mosek.soltype.itr, mosek.solitem.suc, 0, m, z) z = matrix(z) else: z = matrix(0.0, (0, 1)) if p != 0: yu, yl = p * [0.0], p * [0.0] task.getsolutionslice(mosek.soltype.itr, mosek.solitem.suc, m, m + p, yu) task.getsolutionslice(mosek.soltype.itr, mosek.solitem.slc, m, m + p, yl) y = matrix(yu) - matrix(yl) else: y = matrix(0.0, (0, 1)) if (solsta is mosek.solsta.unknown): return (solsta, None, None, None) else: return (solsta, x, z, y)
# The quadratic cone program of section 8.2 (Quadratic cone programs). # minimize (1/2)*x'*A'*A*x - b'*A*x # subject to x >= 0 # ||x||_2 <= 1 from kvxopt import matrix, solvers A = matrix([[.3, -.4, -.2, -.4, 1.3], [.6, 1.2, -1.7, .3, -.3], [-.3, .0, .6, -1.2, -2.0]]) b = matrix([1.5, .0, -1.2, -.7, .0]) m, n = A.size I = matrix(0.0, (n, n)) I[::n + 1] = 1.0 G = matrix([-I, matrix(0.0, (1, n)), I]) h = matrix(n * [0.0] + [1.0] + n * [0.0]) dims = {'l': n, 'q': [n + 1], 's': []} x = solvers.coneqp(A.T * A, -A.T * b, G, h, dims)['x'] print("\nx = \n") print(x)
def covsel(Y): """ Returns the solution of minimize -log det K + tr(KY) subject to K_ij = 0 if (i,j) not in zip(I, J). Y is a symmetric sparse matrix with nonzero diagonal elements. I = Y.I, J = Y.J. """ cholmod.options['supernodal'] = 2 I, J = Y.I, Y.J n, m = Y.size[0], len(I) # non-zero positions for one-argument indexing N = I + J*n # position of diagonal elements D = [ k for k in range(m) if I[k]==J[k] ] # starting point: symmetric identity with nonzero pattern I,J K = spmatrix(0.0, I, J) K[::n+1] = 1.0 # Kn is used in the line search Kn = spmatrix(0.0, I, J) # symbolic factorization of K F = cholmod.symbolic(K) # Kinv will be the inverse of K Kinv = matrix(0.0, (n,n)) for iters in range(100): # numeric factorization of K cholmod.numeric(K, F) d = cholmod.diag(F) # compute Kinv by solving K*X = I Kinv[:] = 0.0 Kinv[::n+1] = 1.0 cholmod.solve(F, Kinv) # solve Newton system grad = 2 * (Y.V - Kinv[N]) hess = 2 * ( mul(Kinv[I,J], Kinv[J,I]) + mul(Kinv[I,I], Kinv[J,J]) ) v = -grad lapack.posv(hess,v) # stopping criterion sqntdecr = -blas.dot(grad,v) print("Newton decrement squared:%- 7.5e" %sqntdecr) if (sqntdecr < 1e-12): print("number of iterations: %d" %(iters+1)) break # line search dx = +v dx[D] *= 2 f = -2.0*sum(log(d)) # f = -log det K s = 1 for lsiter in range(50): Kn.V = K.V + s*dx try: cholmod.numeric(Kn, F) except ArithmeticError: s *= 0.5 else: d = cholmod.diag(F) fn = -2.0 * sum(log(d)) + 2*s*blas.dot(v,Y.V) if (fn < f - 0.01*s*sqntdecr): break else: s *= 0.5 K.V = Kn.V return K
def l1regls(A, y): """ Returns the solution of l1-norm regularized least-squares problem minimize || A*x - y ||_2^2 + || x ||_1. """ m, n = A.size q = matrix(1.0, (2 * n, 1)) q[:n] = -2.0 * A.T * y def P(u, v, alpha=1.0, beta=0.0): """ v := alpha * 2.0 * [ A'*A, 0; 0, 0 ] * u + beta * v """ v *= beta v[:n] += alpha * 2.0 * A.T * (A * u[:n]) def G(u, v, alpha=1.0, beta=0.0, trans='N'): """ v := alpha*[I, -I; -I, -I] * u + beta * v (trans = 'N' or 'T') """ v *= beta v[:n] += alpha * (u[:n] - u[n:]) v[n:] += alpha * (-u[:n] - u[n:]) h = matrix(0.0, (2 * n, 1)) # Customized solver for the KKT system # # [ 2.0*A'*A 0 I -I ] [x[:n] ] [bx[:n] ] # [ 0 0 -I -I ] [x[n:] ] = [bx[n:] ]. # [ I -I -D1^-1 0 ] [zl[:n]] [bzl[:n]] # [ -I -I 0 -D2^-1 ] [zl[n:]] [bzl[n:]] # # where D1 = W['di'][:n]**2, D2 = W['di'][n:]**2. # # We first eliminate zl and x[n:]: # # ( 2*A'*A + 4*D1*D2*(D1+D2)^-1 ) * x[:n] = # bx[:n] - (D2-D1)*(D1+D2)^-1 * bx[n:] + # D1 * ( I + (D2-D1)*(D1+D2)^-1 ) * bzl[:n] - # D2 * ( I - (D2-D1)*(D1+D2)^-1 ) * bzl[n:] # # x[n:] = (D1+D2)^-1 * ( bx[n:] - D1*bzl[:n] - D2*bzl[n:] ) # - (D2-D1)*(D1+D2)^-1 * x[:n] # # zl[:n] = D1 * ( x[:n] - x[n:] - bzl[:n] ) # zl[n:] = D2 * (-x[:n] - x[n:] - bzl[n:] ). # # The first equation has the form # # (A'*A + D)*x[:n] = rhs # # and is equivalent to # # [ D A' ] [ x:n] ] = [ rhs ] # [ A -I ] [ v ] [ 0 ]. # # It can be solved as # # ( A*D^-1*A' + I ) * v = A * D^-1 * rhs # x[:n] = D^-1 * ( rhs - A'*v ). S = matrix(0.0, (m, m)) Asc = matrix(0.0, (m, n)) v = matrix(0.0, (m, 1)) def Fkkt(W): # Factor # # S = A*D^-1*A' + I # # where D = 2*D1*D2*(D1+D2)^-1, D1 = d[:n]**-2, D2 = d[n:]**-2. d1, d2 = W['di'][:n]**2, W['di'][n:]**2 # ds is square root of diagonal of D ds = math.sqrt(2.0) * div(mul(W['di'][:n], W['di'][n:]), sqrt(d1 + d2)) d3 = div(d2 - d1, d1 + d2) # Asc = A*diag(d)^-1/2 Asc = A * spdiag(ds**-1) # S = I + A * D^-1 * A' blas.syrk(Asc, S) S[::m + 1] += 1.0 lapack.potrf(S) def g(x, y, z): x[:n] = 0.5 * (x[:n] - mul(d3, x[n:]) + mul( d1, z[:n] + mul(d3, z[:n])) - mul(d2, z[n:] - mul(d3, z[n:]))) x[:n] = div(x[:n], ds) # Solve # # S * v = 0.5 * A * D^-1 * ( bx[:n] - # (D2-D1)*(D1+D2)^-1 * bx[n:] + # D1 * ( I + (D2-D1)*(D1+D2)^-1 ) * bzl[:n] - # D2 * ( I - (D2-D1)*(D1+D2)^-1 ) * bzl[n:] ) blas.gemv(Asc, x, v) lapack.potrs(S, v) # x[:n] = D^-1 * ( rhs - A'*v ). blas.gemv(Asc, v, x, alpha=-1.0, beta=1.0, trans='T') x[:n] = div(x[:n], ds) # x[n:] = (D1+D2)^-1 * ( bx[n:] - D1*bzl[:n] - D2*bzl[n:] ) # - (D2-D1)*(D1+D2)^-1 * x[:n] x[n:] = div( x[n:] - mul(d1, z[:n]) - mul(d2, z[n:]), d1+d2 )\ - mul( d3, x[:n] ) # zl[:n] = D1^1/2 * ( x[:n] - x[n:] - bzl[:n] ) # zl[n:] = D2^1/2 * ( -x[:n] - x[n:] - bzl[n:] ). z[:n] = mul(W['di'][:n], x[:n] - x[n:] - z[:n]) z[n:] = mul(W['di'][n:], -x[:n] - x[n:] - z[n:]) return g return solvers.coneqp(P, q, G, h, kktsolver=Fkkt)['x'][:n]
def floorplan(Amin): # minimize W+H # subject to Amink / hk <= wk, k = 1,..., 5 # x1 >= 0, x2 >= 0, x4 >= 0 # x1 + w1 + rho <= x3 # x2 + w2 + rho <= x3 # x3 + w3 + rho <= x5 # x4 + w4 + rho <= x5 # x5 + w5 <= W # y2 >= 0, y3 >= 0, y5 >= 0 # y2 + h2 + rho <= y1 # y1 + h1 + rho <= y4 # y3 + h3 + rho <= y4 # y4 + h4 <= H # y5 + h5 <= H # hk/gamma <= wk <= gamma*hk, k = 1, ..., 5 # # 22 Variables W, H, x (5), y (5), w (5), h (5). # # W, H: scalars; bounding box width and height # x, y: 5-vectors; coordinates of bottom left corners of blocks # w, h: 5-vectors; widths and heigths of the 5 blocks rho, gamma = 1.0, 5.0 # min spacing, min aspect ratio # The objective is to minimize W + H. There are five nonlinear # constraints # # -wk + Amink / hk <= 0, k = 1, ..., 5 c = matrix(2 * [1.0] + 20 * [0.0]) def F(x=None, z=None): if x is None: return 5, matrix(17 * [0.0] + 5 * [1.0]) if min(x[17:]) <= 0.0: return None f = -x[12:17] + div(Amin, x[17:]) Df = matrix(0.0, (5, 22)) Df[:, 12:17] = spmatrix(-1.0, range(5), range(5)) Df[:, 17:] = spmatrix(-div(Amin, x[17:]**2), range(5), range(5)) if z is None: return f, Df H = spmatrix(2.0 * mul(z, div(Amin, x[17::]**3)), range(17, 22), range(17, 22)) return f, Df, H G = matrix(0.0, (26, 22)) h = matrix(0.0, (26, 1)) # -x1 <= 0 G[0, 2] = -1.0 # -x2 <= 0 G[1, 3] = -1.0 # -x4 <= 0 G[2, 5] = -1.0 # x1 - x3 + w1 <= -rho G[3, [2, 4, 12]], h[3] = [1.0, -1.0, 1.0], -rho # x2 - x3 + w2 <= -rho G[4, [3, 4, 13]], h[4] = [1.0, -1.0, 1.0], -rho # x3 - x5 + w3 <= -rho G[5, [4, 6, 14]], h[5] = [1.0, -1.0, 1.0], -rho # x4 - x5 + w4 <= -rho G[6, [5, 6, 15]], h[6] = [1.0, -1.0, 1.0], -rho # -W + x5 + w5 <= 0 G[7, [0, 6, 16]] = -1.0, 1.0, 1.0 # -y2 <= 0 G[8, 8] = -1.0 # -y3 <= 0 G[9, 9] = -1.0 # -y5 <= 0 G[10, 11] = -1.0 # -y1 + y2 + h2 <= -rho G[11, [7, 8, 18]], h[11] = [-1.0, 1.0, 1.0], -rho # y1 - y4 + h1 <= -rho G[12, [7, 10, 17]], h[12] = [1.0, -1.0, 1.0], -rho # y3 - y4 + h3 <= -rho G[13, [9, 10, 19]], h[13] = [1.0, -1.0, 1.0], -rho # -H + y4 + h4 <= 0 G[14, [1, 10, 20]] = -1.0, 1.0, 1.0 # -H + y5 + h5 <= 0 G[15, [1, 11, 21]] = -1.0, 1.0, 1.0 # -w1 + h1/gamma <= 0 G[16, [12, 17]] = -1.0, 1.0 / gamma # w1 - gamma * h1 <= 0 G[17, [12, 17]] = 1.0, -gamma # -w2 + h2/gamma <= 0 G[18, [13, 18]] = -1.0, 1.0 / gamma # w2 - gamma * h2 <= 0 G[19, [13, 18]] = 1.0, -gamma # -w3 + h3/gamma <= 0 G[20, [14, 18]] = -1.0, 1.0 / gamma # w3 - gamma * h3 <= 0 G[21, [14, 19]] = 1.0, -gamma # -w4 + h4/gamma <= 0 G[22, [15, 19]] = -1.0, 1.0 / gamma # w4 - gamma * h4 <= 0 G[23, [15, 20]] = 1.0, -gamma # -w5 + h5/gamma <= 0 G[24, [16, 21]] = -1.0, 1.0 / gamma # w5 - gamma * h5 <= 0.0 G[25, [16, 21]] = 1.0, -gamma # solve and return W, H, x, y, w, h sol = solvers.cpl(c, F, G, h) return sol['x'][0], sol['x'][1], sol['x'][2:7], sol['x'][7:12], \ sol['x'][12:17], sol['x'][17:]
step = 1.0 while 1-step*max(y) < 0: step *= BETA while True: if -sum(log(1-step*y)) < ALPHA*step*lam: break step *= BETA x += step*v # Generate an analytic centering problem # # -b1 <= Ar*x <= b2 # # with random mxn Ar and random b1, b2. m, n = 500, 500 Ar = normal(m,n); A = matrix([Ar, -Ar]) b = uniform(2*m,1) x, ntdecrs = acent(A, b) try: import pylab except ImportError: pass else: pylab.semilogy(range(len(ntdecrs)), ntdecrs, 'o', range(len(ntdecrs)), ntdecrs, '-') pylab.xlabel('Iteration number') pylab.ylabel('Newton decrement') pylab.show()