Beispiel #1
0
 def epigraph_conic_form(self):
     """
     Refer to coniclifts/standards/cone_standards.txt to see that
     "(x, y) : e^x <= y" is represented as "(x, y, 1) \in K_{exp}".
     :return:
     """
     b = np.zeros(3, )
     K = [Cone('e', 3)]
     A_rows, A_cols, A_vals = [], [], []
     x = self.args[0]
     # first coordinate
     num_nonconst = len(x) - 1
     if num_nonconst > 0:
         A_rows += num_nonconst * [0]
         A_cols = [var.id for var, co in x[:-1]]
         A_vals = [co for var, co in x[:-1]]
     else:
         # infer correct dimensions later on
         A_rows.append(0)
         A_cols.append(ScalarVariable.curr_variable_count() - 1)
         A_vals.append(0)
     b[0] = x[-1][1]
     # second coordinate
     A_rows.append(1),
     A_cols.append(self._epigraph_variable.id)
     A_vals.append(1)
     # third coordinate (zeros for A, but included to infer correct dims later on)
     A_rows.append(2)
     A_cols.append(ScalarVariable.curr_variable_count() - 1)
     A_vals.append(0)
     b[2] = 1
     return A_vals, np.array(A_rows), A_cols, b, K
Beispiel #2
0
    def conic_form(self):
        """
        Returns a sparse matrix representation of the Power
        cone object. It represents of the object as :math:'Ax+b \\in K'
        where K is a cone object

        Returns
        -------
        A_vals - list (of floats)
        A_rows - numpy 1darray (of integers)
        A_cols - list (of integers)
        b - numpy 1darray (of floats)
        K - list (of coniclifts Cone objects)
        """
        A_rows, A_cols, A_vals = [], [], []
        K = [
            Cone('pow',
                 self.w.size,
                 annotations={'weights': self.alpha.tolist()})
        ]
        b = np.zeros(shape=(self.w.size, ))

        # Loop through w and add every variable
        for i, se in enumerate(self.w_low.flat):
            if len(se.atoms_to_coeffs) == 0:
                b[i] = se.offset
                A_rows.append(i)
                A_cols.append(ScalarVariable.curr_variable_count() - 1)
                # make sure scipy infers correct dimensions later on.
                A_vals.append(0)
            else:
                b[i] = se.offset
                A_rows += [i] * len(se.atoms_to_coeffs)
                col_idx_to_coeff = [(a.id, c)
                                    for a, c in se.atoms_to_coeffs.items()]
                A_cols += [atom_id for (atom_id, _) in col_idx_to_coeff]
                A_vals += [c for (_, c) in col_idx_to_coeff]

        # Make final row of matrix the information about z
        i = self.w_low.size
        # Loop through w and add every variable
        for se in self.z_low.flat:
            if len(se.atoms_to_coeffs) == 0:
                b[i] = se.offset
                A_rows.append(i)
                A_cols.append(ScalarVariable.curr_variable_count() - 1)
                # make sure scipy infers correct dimensions later on.
                A_vals.append(0)
            else:
                b[i] = se.offset
                A_rows += [i] * len(se.atoms_to_coeffs)
                col_idx_to_coeff = [(a.id, c)
                                    for a, c in se.atoms_to_coeffs.items()]
                A_cols += [atom_id for (atom_id, _) in col_idx_to_coeff]
                A_vals += [c for (_, c) in col_idx_to_coeff]

        return [(A_vals, np.array(A_rows), A_cols, b, K)]
Beispiel #3
0
 def epigraph_conic_form(self):
     """
     Generate conic constraint for epigraph
         np.linalg.norm( np.array(self.args), ord=2) <= self._epigraph_variable
     The coniclifts standard for the second order cone (of length n) is
         { (t,x) : x \in R^{n-1}, t \in R, || x ||_2 <= t }.
     """
     m = len(self.args) + 1
     b = np.zeros(m, )
     A_rows, A_cols, A_vals = [0], [self._epigraph_variable.id
                                    ], [1]  # for first row
     for i, arg in enumerate(self.args):
         nonconst_terms = len(arg) - 1
         if nonconst_terms > 0:
             A_rows += nonconst_terms * [i + 1]
             for var, coeff in arg[:-1]:
                 A_cols.append(var.id)
                 A_vals.append(coeff)
         else:
             # make sure we infer correct dimensions later on
             A_rows.append(i + 1)
             A_cols.append(ScalarVariable.curr_variable_count() - 1)
             A_vals.append(0)
         b[i + 1] = arg[-1][1]
     K = [Cone('S', m)]
     A_rows = np.array(A_rows)
     return A_vals, A_rows, A_cols, b, K
Beispiel #4
0
def columns_sum_leq_vec(mat, vec, mat_offsets=False):
    # This function assumes that each ScalarExpression in mat
    # consists of a single ScalarVariable with coefficient one,
    # and has no offset term.
    A_rows, A_cols, A_vals = [], [], []
    m = mat.shape[0]
    if m != vec.size:
        raise RuntimeError('Incompatible dimensions.')
    b = np.zeros(m, )
    for i in range(m):
        # update cols and data to reflect addition of elements in ith row of mat
        svs = mat[i, :].scalar_variables()
        A_cols += [sv.id for sv in svs]
        A_vals += [-1] * len(svs)
        # update cols and data to reflect addition of elements from ith element of vec
        #   ith element of vec is a ScalarExpression!
        id2co = [(a.id, co) for a, co in vec[i].atoms_to_coeffs.items()]
        A_cols += [aid for aid, _ in id2co]
        A_vals += [co for _, co in id2co]
        # update rows with appropriate number of "i"s.
        total_len = len(svs) + len(id2co)
        if total_len > 0:
            A_rows += [i] * total_len
        else:
            A_rows.append(i)
            A_vals.append(0)
            A_cols.append(ScalarVariable.curr_variable_count() - 1)
        # update b
        b[i] = vec[i].offset
        if mat_offsets:
            b[i] -= sum([matij.offset for matij in mat[i, :]])
    A_rows = np.array(A_rows)
    return A_vals, A_rows, A_cols, b
Beispiel #5
0
    def epigraph_conic_form(self):
        """
        Generate conic constraint for epigraph
            self.args[0] * ln( self.args[0] / self.args[1] ) <= self._epigraph_variable.

        :return:
        """
        b = np.zeros(3,)
        K = [Cone('e', 3)]
        # ^ initializations
        A_rows, A_cols, A_vals = [0], [self._epigraph_variable.id], [-1]
        # ^ first row
        x = self.args[0]
        num_nonconst = len(x) - 1
        if num_nonconst > 0:
            A_rows += num_nonconst * [2]
            A_cols += [var.id for var, co in x[:-1]]
            A_vals += [co for var, co in x[:-1]]
        else:
            A_rows.append(2)
            A_cols.append(ScalarVariable.curr_variable_count() - 1)
            A_vals.append(0)
        b[2] = x[-1][1]
        # ^ third row
        y = self.args[1]
        num_nonconst = len(y) - 1
        if num_nonconst > 0:
            A_rows += num_nonconst * [1]
            A_cols += [var.id for var, co in y[:-1]]
            A_vals += [co for var, co in y[:-1]]
        else:
            A_rows.append(1)
            A_cols.append(ScalarVariable.curr_variable_count() - 1)
            A_vals.append(0)
        b[1] = y[-1][1]
        # ^ second row
        return A_vals, np.array(A_rows), A_cols, b, K
Beispiel #6
0
 def conic_form(self):
     A_rows, A_cols, A_vals = [], [], []
     b = np.zeros(shape=(self.K_size,))
     for i, se in enumerate(self.y.flat):
         if len(se.atoms_to_coeffs) == 0:
             b[i] = se.offset
             A_rows.append(i)
             A_cols.append(ScalarVariable.curr_variable_count() - 1)
             A_vals.append(0)  # make sure scipy infers correct dimensions later on.
         else:
             b[i] = se.offset
             A_rows += [i] * len(se.atoms_to_coeffs)
             col_idx_to_coeff = [(a.id, c) for a, c in se.atoms_to_coeffs.items()]
             A_cols += [atom_id for (atom_id, _) in col_idx_to_coeff]
             A_vals += [c for (_, c) in col_idx_to_coeff]
     return [(A_vals, np.array(A_rows), A_cols, b, self.K)]
Beispiel #7
0
 def conic_form(self):
     self_dual_cones = {'+', 'S', 'P'}
     start_row = 0
     y_mod = []
     for co in self.K:
         stop_row = start_row + co.len
         if co.type in self_dual_cones:
             y_mod.append(self.y[start_row:stop_row])
         elif co.type == 'e':
             temp_y = np.array([
                 -self.y[start_row + 2],
                 np.exp(1) * self.y[start_row + 1], -self.y[start_row]
             ])
             y_mod.append(temp_y)
         elif co.type != '0':
             raise RuntimeError('Unexpected cone type "%s".' % str(co.type))
         start_row = stop_row
     y_mod = np.hstack(y_mod)
     y_mod = Expression(y_mod)
     # Now we can pretend all nonzero cones are self-dual.
     A_vals, A_rows, A_cols = [], [], []
     cur_K = [Cone(co.type, co.len) for co in self.K if co.type != '0']
     cur_K_size = sum([co.len for co in cur_K])
     if cur_K_size > 0:
         b = np.zeros(shape=(cur_K_size, ))
         for i, se in enumerate(y_mod):
             if len(se.atoms_to_coeffs) == 0:
                 b[i] = se.offset
                 A_rows.append(i)
                 A_cols.append(
                     int(ScalarVariable.curr_variable_count()) - 1)
                 A_vals.append(
                     0
                 )  # make sure scipy infers correct dimensions later on.
             else:
                 b[i] = se.offset
                 A_rows += [i] * len(se.atoms_to_coeffs)
                 col_idx_to_coeff = [(a.id, c)
                                     for a, c in se.atoms_to_coeffs.items()]
                 A_cols += [atom_id for (atom_id, _) in col_idx_to_coeff]
                 A_vals += [c for (_, c) in col_idx_to_coeff]
         return [(A_vals, np.array(A_rows), A_cols, b, cur_K)]
     else:
         return [([], np.zeros(shape=(0, ),
                               dtype=int), [], np.zeros(shape=(0, )), [])]
Beispiel #8
0
 def conic_form(self):
     from sageopt.coniclifts.base import Expression, ScalarVariable
     expr = np.triu(self.arg).view(Expression)
     expr = expr[np.triu_indices(expr.shape[0])]
     K = [Cone('P', expr.size)]
     b = np.empty(shape=(expr.size, ))
     A_rows, A_cols, A_vals = [], [], []
     for i, se in enumerate(expr):
         b[i] = se.offset
         if len(se.atoms_to_coeffs) == 0:
             A_rows.append(i)
             A_cols.append(ScalarVariable.curr_variable_count())
             A_vals.append(
                 0)  # make sure scipy infers correct dimensions later on.
         else:
             A_rows += [i] * len(se.atoms_to_coeffs)
             cols_and_coeff = [(a.id, c)
                               for a, c in se.atoms_to_coeffs.items()]
             A_cols += [atom_id for (atom_id, _) in cols_and_coeff]
             A_vals += [c for (_, c) in cols_and_coeff]
     return [(A_vals, np.array(A_rows), A_cols, b, K)]
Beispiel #9
0
 def conic_form(self):
     from sageopt.coniclifts.base import ScalarVariable
     # This function assumes that self.expr is affine (i.e. that any necessary epigraph
     # variables have been substituted into the nonlinear expression).
     #
     # The vector "K" returned by this function may only include entries for
     # the zero cone and R_+.
     #
     # Note: signs on coefficients are inverted in this function. This happens
     # because flipping signs on A and b won't affect the zero cone, and
     # it correctly converts affine constraints of the form "expression <= 0"
     # to the form "-expression >= 0". We want this latter form because our
     # primitive cones are the zero cone and R_+.
     if not self.epigraph_checked:
         raise RuntimeError(
             'Cannot canonicalize without check for epigraph substitution.')
     m = self.expr.size
     b = np.empty(shape=(m, ))
     if self.operator == '==':
         K = [Cone('0', m)]
     elif self.operator == '<=':
         K = [Cone('+', m)]
     else:
         raise RuntimeError('Unknown operator.')
     A_rows, A_cols, A_vals = [], [], []
     for i, se in enumerate(self.expr.flat):
         if len(se.atoms_to_coeffs) == 0:
             b[i] = -se.offset
             A_rows.append(i)
             A_cols.append(int(ScalarVariable.curr_variable_count()) - 1)
             A_vals.append(
                 0)  # make sure scipy infers correct dimensions later on.
         else:
             b[i] = -se.offset
             A_rows += [i] * len(se.atoms_to_coeffs)
             col_idx_to_coeff = [(a.id, c)
                                 for a, c in se.atoms_to_coeffs.items()]
             A_cols += [atom_id for (atom_id, _) in col_idx_to_coeff]
             A_vals += [-c for (_, c) in col_idx_to_coeff]
     return A_vals, np.array(A_rows), A_cols, b, K