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 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(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 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 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 read_mtx(self): from kvxopt import spmatrix fn = path.join(path.dirname(path.realpath(__file__)), self._matx_fn) with open(fn, 'r') as fd: size = None for row in fd.readlines(): if row.startswith('%'): continue elif not size: size = list(map(int, row.split(' '))) I = [None] * size[2] J = [None] * size[2] V = [None] * size[2] i = 0 continue val = row.split(' ') I[i] = int(val[0]) - 1 J[i] = int(val[1]) - 1 V[i] = float(val[2]) i += 1 return spmatrix(V, I, J, (size[0], size[1]))
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 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)
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)