Пример #1
0
    def graph_implementation(self, arg_objs, shape: Tuple[int, ...], data=None):
        """Reshape

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        shape : tuple
            The shape of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        arg = arg_objs[0]
        if data[1] == 'F':
            return (lu.reshape(arg, shape), [])
        else:  # 'C':
            arg = lu.transpose(arg)
            if len(shape) <= 1:
                return (lu.reshape(arg, shape), [])
            else:
                result = lu.reshape(arg, (shape[1], shape[0]))
                return (lu.transpose(result), [])
Пример #2
0
 def canonicalize(self):
     obj, constraints = super(Assign, self).canonicalize()
     shape = (self.size[1], 1)
     one_row_vec = lu.create_const(np.ones(shape), shape)
     shape = (1, self.size[0])
     one_col_vec = lu.create_const(np.ones(shape), shape)
     # Row sum <= 1
     row_sum = lu.rmul_expr(obj, one_row_vec, (self.size[0], 1))
     constraints += [lu.create_leq(row_sum, lu.transpose(one_col_vec))]
     # Col sum == 1.
     col_sum = lu.mul_expr(one_col_vec, obj, (1, self.size[1]))
     constraints += [lu.create_eq(col_sum, lu.transpose(one_row_vec))]
     return (obj, constraints)
Пример #3
0
 def canonicalize(self):
     obj, constraints = super(Assign, self).canonicalize()
     shape = (self.size[1], 1)
     one_row_vec = lu.create_const(np.ones(shape), shape)
     shape = (1, self.size[0])
     one_col_vec = lu.create_const(np.ones(shape), shape)
     # Row sum <= 1
     row_sum = lu.rmul_expr(obj, one_row_vec, (self.size[0], 1))
     constraints += [lu.create_leq(row_sum, lu.transpose(one_col_vec))]
     # Col sum == 1.
     col_sum = lu.mul_expr(one_col_vec, obj, (1, self.size[1]))
     constraints += [lu.create_eq(col_sum, lu.transpose(one_row_vec))]
     return (obj, constraints)
Пример #4
0
    def __format(self):
        """Internal version of format with cached results.

        Returns
        -------
        tuple
            (equality constraints, inequality constraints)
        """
        eq_constr = lu.create_eq(self.A, lu.transpose(self.A))
        leq_constr = lu.create_geq(self.A)
        return ([eq_constr], [leq_constr])
Пример #5
0
    def __format(self):
        """Internal version of format with cached results.

        Returns
        -------
        tuple
            (equality constraints, inequality constraints)
        """
        eq_constr = lu.create_eq(self.A, lu.transpose(self.A))
        leq_constr = lu.create_geq(self.A)
        return ([eq_constr], [leq_constr])
Пример #6
0
def format_axis(t, X, axis):
    """Formats all the row/column cones for the solver.

    Parameters
    ----------
        t: The scalar part of the second-order constraint.
        X: A matrix whose rows/columns are each a cone.
        axis: Slice by column 0 or row 1.

    Returns
    -------
    list
        A list of LinLeqConstr that represent all the elementwise cones.
    """
    # Reduce to norms of columns.
    if axis == 1:
        X = lu.transpose(X)
    # Create matrices Tmat, Xmat such that Tmat*t + Xmat*X
    # gives the format for the elementwise cone constraints.
    num_cones = t.size[0]
    cone_size = 1 + X.size[0]
    terms = []
    # Make t_mat
    mat_size = (cone_size, 1)
    prod_size = (cone_size, t.size[0])
    t_mat = sp.coo_matrix(([1.0], ([0], [0])), mat_size).tocsc()
    t_mat = lu.create_const(t_mat, mat_size, sparse=True)
    terms += [lu.mul_expr(t_mat, lu.transpose(t), prod_size)]
    # Make X_mat
    mat_size = (cone_size, X.size[0])
    prod_size = (cone_size, X.size[1])
    val_arr = (cone_size - 1)*[1.0]
    row_arr = range(1, cone_size)
    col_arr = range(cone_size-1)
    X_mat = sp.coo_matrix((val_arr, (row_arr, col_arr)), mat_size).tocsc()
    X_mat = lu.create_const(X_mat, mat_size, sparse=True)
    terms += [lu.mul_expr(X_mat, X, prod_size)]
    return [lu.create_geq(lu.sum_expr(terms))]
Пример #7
0
def format_axis(t, X, axis):
    """Formats all the row/column cones for the solver.

    Parameters
    ----------
        t: The scalar part of the second-order constraint.
        X: A matrix whose rows/columns are each a cone.
        axis: Slice by column 0 or row 1.

    Returns
    -------
    list
        A list of LinLeqConstr that represent all the elementwise cones.
    """
    # Reduce to norms of columns.
    if axis == 1:
        X = lu.transpose(X)
    # Create matrices Tmat, Xmat such that Tmat*t + Xmat*X
    # gives the format for the elementwise cone constraints.
    num_cones = t.size[0]
    cone_size = 1 + X.size[0]
    terms = []
    # Make t_mat
    mat_size = (cone_size, 1)
    prod_size = (cone_size, t.size[0])
    t_mat = sp.coo_matrix(([1.0], ([0], [0])), mat_size).tocsc()
    t_mat = lu.create_const(t_mat, mat_size, sparse=True)
    terms += [lu.mul_expr(t_mat, lu.transpose(t), prod_size)]
    # Make X_mat
    mat_size = (cone_size, X.size[0])
    prod_size = (cone_size, X.size[1])
    val_arr = (cone_size - 1) * [1.0]
    row_arr = range(1, cone_size)
    col_arr = range(cone_size - 1)
    X_mat = sp.coo_matrix((val_arr, (row_arr, col_arr)), mat_size).tocsc()
    X_mat = lu.create_const(X_mat, mat_size, sparse=True)
    terms += [lu.mul_expr(X_mat, X, prod_size)]
    return [lu.create_geq(lu.sum_expr(terms))]
Пример #8
0
    def canonicalize(self):
        """Returns the graph implementation of the object.

        Marks the top level constraint as the dual_holder,
        so the dual value will be saved to the EqConstraint.

        Returns:
            A tuple of (affine expression, [constraints]).
        """
        obj, constraints = self._expr.canonical_form
        half = lu.create_const(0.5, (1, 1))
        symm = lu.mul_expr(half, lu.sum_expr([obj, lu.transpose(obj)]),
                           obj.size)
        dual_holder = SDP(symm, enforce_sym=False, constr_id=self.id)
        return (None, constraints + [dual_holder])
Пример #9
0
    def canonicalize(self):
        """Returns the graph implementation of the object.

        Marks the top level constraint as the dual_holder,
        so the dual value will be saved to the EqConstraint.

        Returns:
            A tuple of (affine expression, [constraints]).
        """
        obj, constraints = self._expr.canonical_form
        half = lu.create_const(0.5, (1,1))
        symm = lu.mul_expr(half, lu.sum_expr([obj, lu.transpose(obj)]),
                           obj.size)
        dual_holder = SDP(symm, enforce_sym=False, constr_id=self.id)
        return (None, constraints + [dual_holder])
Пример #10
0
def format_axis(t, X, axis):
    """Formats all the row/column cones for the solver.

    Parameters
    ----------
        t: The scalar part of the second-order constraint.
        X: A matrix whose rows/columns are each a cone.
        axis: Slice by column 0 or row 1.

    Returns
    -------
    list
        A list of LinLeqConstr that represent all the elementwise cones.
    """
    # Reduce to norms of columns.
    if axis == 1:
        X = lu.transpose(X)
    # Create matrices Tmat, Xmat such that Tmat*t + Xmat*X
    # gives the format for the elementwise cone constraints.
    cone_size = 1 + X.shape[0]
    terms = []
    # Make t_mat
    mat_shape = (cone_size, 1)
    t_mat = sp.csc_matrix(([1.0], ([0], [0])), mat_shape)
    t_mat = lu.create_const(t_mat, mat_shape, sparse=True)
    t_vec = t
    if not t.shape:
        # t is scalar
        t_vec = lu.reshape(t, (1, 1))
    else:
        # t is 1D
        t_vec = lu.reshape(t, (1, t.shape[0]))
    mul_shape = (cone_size, t_vec.shape[1])
    terms += [lu.mul_expr(t_mat, t_vec, mul_shape)]
    # Make X_mat
    if len(X.shape) == 1:
        X = lu.reshape(X, (X.shape[0], 1))
    mat_shape = (cone_size, X.shape[0])
    val_arr = (cone_size - 1) * [1.0]
    row_arr = list(range(1, cone_size))
    col_arr = list(range(cone_size - 1))
    X_mat = sp.csc_matrix((val_arr, (row_arr, col_arr)), mat_shape)
    X_mat = lu.create_const(X_mat, mat_shape, sparse=True)
    mul_shape = (cone_size, X.shape[1])
    terms += [lu.mul_expr(X_mat, X, mul_shape)]
    return [lu.create_geq(lu.sum_expr(terms))]
Пример #11
0
    def graph_implementation(arg_objs, size, data=None):
        """Create a new variable equal to the argument transposed.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        return (lu.transpose(arg_objs[0]), [])
Пример #12
0
    def graph_implementation(arg_objs, size, data=None):
        """Create a new variable equal to the argument transposed.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        return lu.transpose(arg_objs[0])
Пример #13
0
    def graph_implementation(self, arg_objs, shape, data=None):
        """Create a new variable equal to the argument transposed.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        shape : tuple
            The shape of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        # TODO(akshakya): This will need to be updated when we add support
        # for >2D ararys.
        return (lu.transpose(arg_objs[0]), [])
Пример #14
0
    def format(self, eq_constr, leq_constr, dims, solver):
        """Formats SDP constraints as inequalities for the solver.

        Parameters
        ----------
        eq_constr : list
            A list of the equality constraints in the canonical problem.
        leq_constr : list
            A list of the inequality constraints in the canonical problem.
        dims : dict
            A dict with the dimensions of the conic constraints.
        solver : str
            The solver being called.
        """
        # A == A.T
        eq_constr.append(lu.create_eq(self.A, lu.transpose(self.A)))
        # 0 <= A
        leq_constr.append(lu.create_geq(self.A))
        # Update dims.
        dims[s.EQ_DIM] += self.size[0]*self.size[1]
        dims[s.SDP_DIM].append(self.size[0])
Пример #15
0
 def _get_eq_constr(self):
     """Returns the equality constraints for the SDP constraint.
     """
     upper_tri = lu.upper_tri(self.A)
     lower_tri = lu.upper_tri(lu.transpose(self.A))
     return lu.create_eq(upper_tri, lower_tri)
Пример #16
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Creates the equivalent problem::

           maximize    sum(log(D[i, i]))
           subject to: D diagonal
                       diag(D) = diag(Z)
                       Z is upper triangular.
                       [D Z; Z.T A] is positive semidefinite

        The problem computes the LDL factorization:

        .. math::

           A = (Z^TD^{-1})D(D^{-1}Z)

        This follows from the inequality:

        .. math::

           \det(A) >= \det(D) + \det([D, Z; Z^T, A])/\det(D)
                   >= \det(D)

        because (Z^TD^{-1})D(D^{-1}Z) is a feasible D, Z that achieves
        det(A) = det(D) and the objective maximizes det(D).

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        A = arg_objs[0] # n by n matrix.
        n, _ = A.size
        X = lu.create_var((2*n, 2*n))
        Z = lu.create_var((n, n))
        D = lu.create_var((n, 1))
        # Require that X and A are PSD.
        constraints = [SDP(X), SDP(A)]
        # Fix Z as upper triangular, D as diagonal,
        # and diag(D) as diag(Z).
        Z_lower_tri = lu.upper_tri(lu.transpose(Z))
        constraints.append(lu.create_eq(Z_lower_tri))
        # D[i, i] = Z[i, i]
        constraints.append(lu.create_eq(D, lu.diag_mat(Z)))
        # Fix X using the fact that A must be affine by the DCP rules.
        # X[0:n, 0:n] == D
        index.block_eq(X, lu.diag_vec(D), constraints, 0, n, 0, n)
        # X[0:n, n:2*n] == Z,
        index.block_eq(X, Z, constraints, 0, n, n, 2*n)
        # X[n:2*n, n:2*n] == A
        index.block_eq(X, A, constraints, n, 2*n, n, 2*n)
        # Add the objective sum(log(D[i, i])
        obj, constr = log.graph_implementation([D], (n, 1))
        return (lu.sum_entries(obj), constraints + constr)
Пример #17
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Creates the equivalent problem::

           maximize    sum(log(D[i, i]))
           subject to: D diagonal
                       diag(D) = diag(Z)
                       Z is upper triangular.
                       [D Z; Z.T A] is positive semidefinite

        The problem computes the LDL factorization:

        .. math::

           A = (Z^TD^{-1})D(D^{-1}Z)

        This follows from the inequality:

        .. math::

           \det(A) >= \det(D) + \det([D, Z; Z^T, A])/\det(D)
                   >= \det(D)

        because (Z^TD^{-1})D(D^{-1}Z) is a feasible D, Z that achieves
        det(A) = det(D) and the objective maximizes det(D).

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        A = arg_objs[0]  # n by n matrix.
        n, _ = A.size
        X = lu.create_var((2 * n, 2 * n))
        X, constraints = Semidef(2 * n).canonical_form
        Z = lu.create_var((n, n))
        D = lu.create_var((n, 1))
        # Require that X and A are PSD.
        constraints += [SDP(A)]
        # Fix Z as upper triangular, D as diagonal,
        # and diag(D) as diag(Z).
        Z_lower_tri = lu.upper_tri(lu.transpose(Z))
        constraints.append(lu.create_eq(Z_lower_tri))
        # D[i, i] = Z[i, i]
        constraints.append(lu.create_eq(D, lu.diag_mat(Z)))
        # Fix X using the fact that A must be affine by the DCP rules.
        # X[0:n, 0:n] == D
        index.block_eq(X, lu.diag_vec(D), constraints, 0, n, 0, n)
        # X[0:n, n:2*n] == Z,
        index.block_eq(X, Z, constraints, 0, n, n, 2 * n)
        # X[n:2*n, n:2*n] == A
        index.block_eq(X, A, constraints, n, 2 * n, n, 2 * n)
        # Add the objective sum(log(D[i, i])
        obj, constr = log.graph_implementation([D], (n, 1))
        return (lu.sum_entries(obj), constraints + constr)