Example #1
0
 def numeric(self, values):
     """Matrix multiplication.
     """
     if self.args[0].shape == () or self.args[1].shape == () or \
        intf.is_sparse(values[0]) or intf.is_sparse(values[1]):
         return values[0] * values[1]
     else:
         return np.matmul(values[0], values[1])
Example #2
0
 def test_cvxopt_sparse(self):
     interface = intf.get_matrix_interface(cvxopt.spmatrix)
     # const_to_matrix
     mat = interface.const_to_matrix([1, 2, 3])
     self.assertEquals(interface.size(mat), (3, 1))
     # identity
     mat = interface.identity(4)
     cmp_mat = interface.const_to_matrix(np.eye(4))
     self.assertEquals(interface.size(mat), interface.size(cmp_mat))
     assert not mat - cmp_mat
     assert intf.is_sparse(mat)
     # scalar_matrix
     mat = interface.scalar_matrix(2, 4, 3)
     self.assertEquals(interface.size(mat), (4, 3))
     self.assertEquals(interface.index(mat, (1, 2)), 2)
     # reshape
     mat = interface.const_to_matrix([[1, 2, 3], [3, 4, 5]])
     mat = interface.reshape(mat, (6, 1))
     self.assertEquals(interface.index(mat, (4, 0)), 4)
     # Test scalars.
     scalar = interface.scalar_matrix(1, 1, 1)
     self.assertEquals(type(scalar), cvxopt.spmatrix)
     scalar = interface.scalar_matrix(1, 1, 3)
     self.assertEquals(scalar.size, (1, 3))
     # index
     mat = interface.const_to_matrix([[1, 2, 3, 4], [3, 4, 5, 6]])
     self.assertEquals(interface.index(mat, (0, 1)), 3)
     mat = interface.index(mat, (slice(1, 4, 2), slice(0, 2, None)))
     self.assertEquals(list(mat), [2, 4, 4, 6])
     # Sign
     self.sign_for_intf(interface)
Example #3
0
 def test_cvxopt_sparse(self):
     interface = intf.get_matrix_interface(cvxopt.spmatrix)
     # const_to_matrix
     mat = interface.const_to_matrix([1, 2, 3])
     self.assertEquals(interface.size(mat), (3, 1))
     # identity
     mat = interface.identity(4)
     cmp_mat = interface.const_to_matrix(np.eye(4))
     self.assertEquals(interface.size(mat), interface.size(cmp_mat))
     assert not mat - cmp_mat
     assert intf.is_sparse(mat)
     # scalar_matrix
     mat = interface.scalar_matrix(2, 4, 3)
     self.assertEquals(interface.size(mat), (4, 3))
     self.assertEquals(interface.index(mat, (1, 2)), 2)
     # reshape
     mat = interface.const_to_matrix([[1, 2, 3], [3, 4, 5]])
     mat = interface.reshape(mat, (6, 1))
     self.assertEquals(interface.index(mat, (4, 0)), 4)
     mat = interface.const_to_matrix(1, convert_scalars=True)
     self.assertEquals(type(interface.reshape(mat, (1, 1))), type(mat))
     # Test scalars.
     scalar = interface.scalar_matrix(1, 1, 1)
     self.assertEquals(type(scalar), cvxopt.spmatrix)
     scalar = interface.scalar_matrix(1, 1, 3)
     self.assertEquals(scalar.size, (1, 3))
     # index
     mat = interface.const_to_matrix([[1, 2, 3, 4], [3, 4, 5, 6]])
     self.assertEquals(interface.index(mat, (0, 1)), 3)
     mat = interface.index(mat, (slice(1, 4, 2), slice(0, 2, None)))
     self.assertEquals(list(mat), [2, 4, 4, 6])
     # Sign
     self.sign_for_intf(interface)
Example #4
0
    def project(self, val):
        """Project value onto the attribute set of the leaf.

        A sensible idiom is ``leaf.value = leaf.project(val)``.

        Parameters
        ----------
        val : numeric type
            The value assigned.

        Returns
        -------
        numeric type
            The value rounded to the attribute type.
        """
        # Only one attribute can be active at once (besides real,
        # nonpos/nonneg, and bool/int).
        if not self.is_complex():
            val = np.real(val)

        if self.attributes['nonpos'] and self.attributes['nonneg']:
            return 0 * val
        elif self.attributes['nonpos']:
            return np.minimum(val, 0.)
        elif self.attributes['nonneg']:
            return np.maximum(val, 0.)
        elif self.attributes['imag']:
            return np.imag(val)
        elif self.attributes['complex']:
            return val.astype(np.complex)
        elif self.attributes['boolean']:
            # TODO(akshayka): respect the boolean indices.
            return np.round(np.clip(val, 0., 1.))
        elif self.attributes['integer']:
            # TODO(akshayka): respect the integer indices.
            # also, a variable may be integer in some indices and
            # boolean in others.
            return np.round(val)
        elif self.attributes['diag']:
            if intf.is_sparse(val):
                val = val.diagonal()
            else:
                val = np.diag(val)
            return sp.diags([val], [0])
        elif self.attributes['hermitian']:
            return (val + np.conj(val).T) / 2
        elif any([self.attributes[key]
                  for key in ['symmetric', 'PSD', 'NSD']]):
            val = (val + val.T) / 2
            if self.attributes['symmetric']:
                return val
            w, V = LA.eigh(val)
            if self.attributes['PSD']:
                w = np.maximum(w, 0)
            else:  # NSD
                w = np.minimum(w, 0)
            return V.dot(np.diag(w)).dot(V.T)
        else:
            return val
Example #5
0
 def numeric(self, values):
     """Sums the entries of value.
     """
     if intf.is_sparse(values[0]):
         result = np.sum(values[0], axis=self.axis)
         if not self.keepdims and self.axis is not None:
             result = result.A.flatten()
     else:
         result = np.sum(values[0], axis=self.axis, keepdims=self.keepdims)
     return result
Example #6
0
 def __init__(self, value):
     # Keep sparse matrices sparse.
     if intf.is_sparse(value):
         self._value = intf.DEFAULT_SPARSE_INTERFACE.const_to_matrix(value)
         self._sparse = True
     else:
         self._value = intf.DEFAULT_INTERFACE.const_to_matrix(value)
         self._sparse = False
     # Set DCP attributes.
     self.init_dcp_attr()
Example #7
0
 def __init__(self, value):
     # Keep sparse matrices sparse.
     if intf.is_sparse(value):
         self._value = intf.DEFAULT_SPARSE_INTERFACE.const_to_matrix(value)
         self._sparse = True
     else:
         self._value = intf.DEFAULT_INTERFACE.const_to_matrix(value)
         self._sparse = False
     # Set DCP attributes.
     self.init_dcp_attr()
Example #8
0
    def _validate_value(self, val):
        """Check that the value satisfies the leaf's symbolic attributes.

        Parameters
        ----------
        val : numeric type
            The value assigned.

        Returns
        -------
        numeric type
            The value converted to the proper matrix type.
        """
        if val is not None:
            # Convert val to ndarray or sparse matrix.
            val = intf.convert(val)
            if intf.shape(val) != self.shape:
                raise ValueError(
                    "Invalid dimensions %s for %s value." %
                    (intf.shape(val), self.__class__.__name__)
                )
            projection = self.project(val)
            # ^ might be a numpy array, or sparse scipy matrix.
            delta = np.abs(val - projection)
            # ^ might be a numpy array, scipy matrix, or sparse scipy matrix.
            if intf.is_sparse(delta):  # is a scipy sparse matrix
                is_close_enough = np.allclose(delta.data, 0)
                # ^ only check for near-equality on nonzero values.
            else:
                delta = np.array(delta)  # make sure we have a numpy array.
                is_close_enough = np.allclose(delta, 0, atol=1e-8)
            if not is_close_enough:
                if self.attributes['nonneg']:
                    attr_str = 'nonnegative'
                elif self.attributes['nonpos']:
                    attr_str = 'nonpositive'
                elif self.attributes['diag']:
                    attr_str = 'diagonal'
                elif self.attributes['PSD']:
                    attr_str = 'positive semidefinite'
                elif self.attributes['NSD']:
                    attr_str = 'negative semidefinite'
                elif self.attributes['imag']:
                    attr_str = 'imaginary'
                else:
                    attr_str = ([k for (k, v) in self.attributes.items() if v] + ['real'])[0]
                raise ValueError(
                    "%s value must be %s." % (self.__class__.__name__, attr_str)
                )
        return val
Example #9
0
 def __init__(self, value):
     # Keep sparse matrices sparse.
     if intf.is_sparse(value):
         self._value = intf.DEFAULT_SPARSE_INTF.const_to_matrix(
             value, convert_scalars=True)
         self._sparse = True
     else:
         self._value = intf.DEFAULT_INTF.const_to_matrix(value)
         self._sparse = False
     self._imag = None
     self._nonneg = self._nonpos = None
     self._symm = None
     self._herm = None
     self._eigvals = None
     super(Constant, self).__init__(intf.shape(self.value))
Example #10
0
 def __init__(self, value):
     # TODO HACK.
     # A fix for c.T*x where c is a 1D array.
     self.is_1D_array = False
     # Keep sparse matrices sparse.
     if intf.is_sparse(value):
         self._value = intf.DEFAULT_SPARSE_INTF.const_to_matrix(value)
         self._sparse = True
     else:
         if isinstance(value, np.ndarray) and len(value.shape) == 1:
             self.is_1D_array = True
         self._value = intf.DEFAULT_INTF.const_to_matrix(value)
         self._sparse = False
     # Set DCP attributes.
     self.init_dcp_attr()
     super(Constant, self).__init__()
Example #11
0
 def __init__(self, value):
     # TODO HACK.
     # A fix for c.T*x where c is a 1D array.
     self.is_1D_array = False
     # Keep sparse matrices sparse.
     if intf.is_sparse(value):
         self._value = intf.DEFAULT_SPARSE_INTF.const_to_matrix(value)
         self._sparse = True
     else:
         if isinstance(value, np.ndarray) and len(value.shape) == 1:
             self.is_1D_array = True
         self._value = intf.DEFAULT_INTF.const_to_matrix(value)
         self._sparse = False
     # Set DCP attributes.
     self.init_dcp_attr()
     super(Constant, self).__init__()
Example #12
0
 def __init__(self, value) -> None:
     # Keep sparse matrices sparse.
     if intf.is_sparse(value):
         self._value = intf.DEFAULT_SPARSE_INTF.const_to_matrix(
             value, convert_scalars=True)
         self._sparse = True
     else:
         self._value = intf.DEFAULT_INTF.const_to_matrix(value)
         self._sparse = False
     self._imag: Optional[bool] = None
     self._nonneg: Optional[bool] = None
     self._nonpos: Optional[bool] = None
     self._symm: Optional[bool] = None
     self._herm: Optional[bool] = None
     self._top_eig: Optional[float] = None
     self._bottom_eig: Optional[float] = None
     self._cached_is_pos = None
     super(Constant, self).__init__(intf.shape(self.value))
Example #13
0
    def _process_constr(self, constr, mat_cache, vert_offset):
        """Extract the coefficients from a constraint.

        Parameters
        ----------
        constr : LinConstr
            The linear constraint to process.
        mat_cache : MatrixCache
            The cached version of the matrix-vector pair.
        vert_offset : int
            The row offset of the constraint.
        """
        V, I, J = mat_cache.coo_tup
        coeffs = op2mat.get_coefficients(constr.expr)
        for id_, block in coeffs:
            vert_start = vert_offset
            vert_end = vert_start + constr.size[0]*constr.size[1]
            if id_ is lo.CONSTANT_ID:
                # Flatten the block.
                block = self.vec_intf.const_to_matrix(block)
                block_size = intf.size(block)
                block = self.vec_intf.reshape(
                    block,
                    (block_size[0]*block_size[1], 1)
                )
                mat_cache.const_vec[vert_start:vert_end, :] += block
            else:
                horiz_offset = self.sym_data.var_offsets[id_]
                if intf.is_scalar(block):
                    block = intf.scalar_value(block)
                    V.append(block)
                    I.append(vert_start)
                    J.append(horiz_offset)
                else:
                    # Block is a numpy matrix or
                    # scipy CSC sparse matrix.
                    if not intf.is_sparse(block):
                        block = intf.DEFAULT_SPARSE_INTF.const_to_matrix(
                            block
                        )
                    block = block.tocoo()
                    V.extend(block.data)
                    I.extend(block.row + vert_start)
                    J.extend(block.col + horiz_offset)
Example #14
0
    def _process_constr(self, constr, mat_cache, vert_offset):
        """Extract the coefficients from a constraint.

        Parameters
        ----------
        constr : LinConstr
            The linear constraint to process.
        mat_cache : MatrixCache
            The cached version of the matrix-vector pair.
        vert_offset : int
            The row offset of the constraint.
        """
        V, I, J = mat_cache.coo_tup
        coeffs = op2mat.get_coefficients(constr.expr)
        for id_, block in coeffs:
            vert_start = vert_offset
            vert_end = vert_start + constr.size[0] * constr.size[1]
            if id_ is lo.CONSTANT_ID:
                # Flatten the block.
                block = self.vec_intf.const_to_matrix(block)
                block_size = intf.size(block)
                block = self.vec_intf.reshape(
                    block, (block_size[0] * block_size[1], 1))
                mat_cache.const_vec[vert_start:vert_end, :] += block
            else:
                horiz_offset = self.sym_data.var_offsets[id_]
                if intf.is_scalar(block):
                    block = intf.scalar_value(block)
                    V.append(block)
                    I.append(vert_start)
                    J.append(horiz_offset)
                else:
                    # Block is a numpy matrix or
                    # scipy CSC sparse matrix.
                    if not intf.is_sparse(block):
                        block = intf.DEFAULT_SPARSE_INTERFACE.const_to_matrix(
                            block)
                    block = block.tocoo()
                    V.extend(block.data)
                    I.extend(block.row + vert_start)
                    J.extend(block.col + horiz_offset)
Example #15
0
    def _constr_matrix(self, constraints, var_offsets, x_length,
                       matrix_intf, vec_intf):
        """Returns a matrix and vector representing a list of constraints.

        In the matrix, each constraint is given a block of rows.
        Each variable coefficient is inserted as a block with upper
        left corner at matrix[variable offset, constraint offset].
        The constant term in the constraint is added to the vector.

        Parameters
        ----------
        constraints : list
            A list of constraints.
        var_offsets : dict
            A dict of variable id to horizontal offset.
        x_length : int
            The length of the x vector.
        matrix_intf : interface
            The matrix interface to use for creating the constraints matrix.
        vec_intf : interface
            The matrix interface to use for creating the constant vector.

        Returns
        -------
        tuple
            A (matrix, vector) tuple.
        """

        rows = sum([c.size[0] * c.size[1] for c in constraints])
        cols = x_length
        V, I, J = [], [], []
        const_vec = vec_intf.zeros(rows, 1)
        vert_offset = 0
        for constr in constraints:
            coeffs = op2mat.get_coefficients(constr.expr)
            for id_, block in coeffs:
                vert_start = vert_offset
                vert_end = vert_start + constr.size[0]*constr.size[1]
                if id_ is lo.CONSTANT_ID:
                    # Flatten the block.
                    block = self._DENSE_INTF.const_to_matrix(block)
                    block_size = intf.size(block)
                    block = self._DENSE_INTF.reshape(
                        block,
                        (block_size[0]*block_size[1], 1)
                    )
                    const_vec[vert_start:vert_end, :] += block
                else:
                    horiz_offset = var_offsets[id_]
                    if intf.is_scalar(block):
                        block = intf.scalar_value(block)
                        V.append(block)
                        I.append(vert_start)
                        J.append(horiz_offset)
                    else:
                        # Block is a numpy matrix or
                        # scipy CSC sparse matrix.
                        if not intf.is_sparse(block):
                            block = self._SPARSE_INTF.const_to_matrix(block)
                        block = block.tocoo()
                        V.extend(block.data)
                        I.extend(block.row + vert_start)
                        J.extend(block.col + horiz_offset)
            vert_offset += constr.size[0]*constr.size[1]

        # Create the constraints matrix.
        if len(V) > 0:
            matrix = sp.coo_matrix((V, (I, J)), (rows, cols))
            # Convert the constraints matrix to the correct type.
            matrix = matrix_intf.const_to_matrix(matrix, convert_scalars=True)
        else: # Empty matrix.
            matrix = matrix_intf.zeros(rows, cols)
        return (matrix, -const_vec)
Example #16
0
    def _validate_value(self, val):
        """Check that the value satisfies the leaf's symbolic attributes.

        Parameters
        ----------
        val : numeric type
            The value assigned.

        Returns
        -------
        numeric type
            The value converted to the proper matrix type.
        """
        if val is not None:
            # Convert val to ndarray or sparse matrix.
            val = intf.convert(val)
            if intf.shape(val) != self.shape:
                raise ValueError("Invalid dimensions %s for %s value." %
                                 (intf.shape(val), self.__class__.__name__))
            projection = self.project(val)
            # ^ might be a numpy array, or sparse scipy matrix.
            delta = np.abs(val - projection)
            # ^ might be a numpy array, scipy matrix, or sparse scipy matrix.
            if intf.is_sparse(delta):
                # ^ based on current implementation of project(...),
                #   is is not possible for this Leaf to be PSD/NSD *and*
                #   a sparse matrix.
                close_enough = np.allclose(delta.data,
                                           0,
                                           atol=SPARSE_PROJECTION_TOL)
                # ^ only check for near-equality on nonzero values.
            else:
                # the data could be a scipy matrix, or a numpy array.
                # First we convert to a numpy array.
                delta = np.array(delta)
                # Now that we have the residual, we need to measure it
                # in some canonical way.
                if self.attributes['PSD'] or self.attributes['NSD']:
                    # For PSD/NSD Leafs, we use the largest-singular-value norm.
                    close_enough = LA.norm(delta,
                                           ord=2) <= PSD_NSD_PROJECTION_TOL
                else:
                    # For all other Leafs we use the infinity norm on
                    # the vectorized Leaf.
                    close_enough = np.allclose(delta,
                                               0,
                                               atol=GENERAL_PROJECTION_TOL)
            if not close_enough:
                if self.attributes['nonneg']:
                    attr_str = 'nonnegative'
                elif self.attributes['pos']:
                    attr_str = 'positive'
                elif self.attributes['nonpos']:
                    attr_str = 'nonpositive'
                elif self.attributes['neg']:
                    attr_str = 'negative'
                elif self.attributes['diag']:
                    attr_str = 'diagonal'
                elif self.attributes['PSD']:
                    attr_str = 'positive semidefinite'
                elif self.attributes['NSD']:
                    attr_str = 'negative semidefinite'
                elif self.attributes['imag']:
                    attr_str = 'imaginary'
                else:
                    attr_str = ([k
                                 for (k, v) in self.attributes.items() if v] +
                                ['real'])[0]
                raise ValueError("%s value must be %s." %
                                 (self.__class__.__name__, attr_str))
        return val
Example #17
0
    def _constr_matrix(self, constraints, var_offsets, x_length, matrix_intf,
                       vec_intf):
        """Returns a matrix and vector representing a list of constraints.

        In the matrix, each constraint is given a block of rows.
        Each variable coefficient is inserted as a block with upper
        left corner at matrix[variable offset, constraint offset].
        The constant term in the constraint is added to the vector.

        Parameters
        ----------
        constraints : list
            A list of constraints.
        var_offsets : dict
            A dict of variable id to horizontal offset.
        x_length : int
            The length of the x vector.
        matrix_intf : interface
            The matrix interface to use for creating the constraints matrix.
        vec_intf : interface
            The matrix interface to use for creating the constant vector.

        Returns
        -------
        tuple
            A (matrix, vector) tuple.
        """

        rows = sum([c.size[0] * c.size[1] for c in constraints])
        cols = x_length
        V, I, J = [], [], []
        const_vec = vec_intf.zeros(rows, 1)
        vert_offset = 0
        for constr in constraints:
            coeffs = op2mat.get_coefficients(constr.expr)
            for id_, size, block in coeffs:
                vert_start = vert_offset
                vert_end = vert_start + constr.size[0] * constr.size[1]
                if id_ is lo.CONSTANT_ID:
                    # Flatten the block.
                    block = self._DENSE_INTF.const_to_matrix(block)
                    block_size = intf.size(block)
                    block = self._DENSE_INTF.reshape(
                        block, (block_size[0] * block_size[1], 1))
                    const_vec[vert_start:vert_end, :] += block
                else:
                    horiz_offset = var_offsets[id_]
                    if intf.is_scalar(block):
                        block = intf.scalar_value(block)
                        V.append(block)
                        I.append(vert_start)
                        J.append(horiz_offset)
                    else:
                        # Block is a numpy matrix or
                        # scipy CSC sparse matrix.
                        if not intf.is_sparse(block):
                            block = self._SPARSE_INTF.const_to_matrix(block)
                        block = block.tocoo()
                        V.extend(block.data)
                        I.extend(block.row + vert_start)
                        J.extend(block.col + horiz_offset)
            vert_offset += constr.size[0] * constr.size[1]

        # Create the constraints matrix.
        if len(V) > 0:
            matrix = sp.coo_matrix((V, (I, J)), (rows, cols))
            # Convert the constraints matrix to the correct type.
            matrix = matrix_intf.const_to_matrix(matrix, convert_scalars=True)
        else:  # Empty matrix.
            matrix = matrix_intf.zeros(rows, cols)
        return (matrix, -const_vec)