Ejemplo n.º 1
0
 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]])))
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
 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
Ejemplo n.º 4
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
Ejemplo n.º 5
0
    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))
Ejemplo n.º 6
0
    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]))
Ejemplo n.º 7
0
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
Ejemplo n.º 8
0
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)
Ejemplo n.º 9
0
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)
Ejemplo n.º 10
0
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)
Ejemplo n.º 11
0
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)