Exemple #1
0
    def invert(self, solution, inverse_data):
        """Returns solution to original problem, given inverse_data.
        """
        status = self.STATUS_MAP[solution['info']['exitFlag']]

        # Timing data
        attr = {}
        attr[s.SOLVE_TIME] = solution["info"]["timing"]["tsolve"]
        attr[s.SETUP_TIME] = solution["info"]["timing"]["tsetup"]
        attr[s.NUM_ITERS] = solution["info"]["iter"]

        if status in s.SOLUTION_PRESENT:
            primal_val = solution['info']['pcost']
            opt_val = primal_val + inverse_data[s.OFFSET]
            primal_vars = {
                inverse_data[self.VAR_ID]:
                intf.DEFAULT_INTF.const_to_matrix(solution['x'])
            }
            dual_vars = utilities.get_dual_values(
                solution['z'], utilities.extract_dual_value,
                inverse_data[self.NEQ_CONSTR])
            for con in inverse_data[self.NEQ_CONSTR]:
                if isinstance(con, ExpCone):
                    cid = con.id
                    n_cones = con.num_cones()
                    perm = utilities.expcone_permutor(n_cones,
                                                      ECOS.EXP_CONE_ORDER)
                    dual_vars[cid] = dual_vars[cid][perm]
            eq_duals = utilities.get_dual_values(solution['y'],
                                                 utilities.extract_dual_value,
                                                 inverse_data[self.EQ_CONSTR])
            dual_vars.update(eq_duals)
            return Solution(status, opt_val, primal_vars, dual_vars, attr)
        else:
            return failure_solution(status)
Exemple #2
0
 def recover_primal_variables(task, sol, K_dir):
     # This function applies both when slacks are introduced, and
     # when the problem is dualized.
     prim_vars = dict()
     idx = 0
     m_free = K_dir[a2d.FREE]
     if m_free > 0:
         temp = [0.] * m_free
         task.getxxslice(sol, idx, len(temp), temp)
         prim_vars[a2d.FREE] = np.array(temp)
         idx += m_free
     if task.getnumintvar() > 0:
         return prim_vars  # Skip the slack variables.
     m_pos = K_dir[a2d.NONNEG]
     if m_pos > 0:
         temp = [0.] * m_pos
         task.getxxslice(sol, idx, idx + m_pos, temp)
         prim_vars[a2d.NONNEG] = np.array(temp)
         idx += m_pos
     num_soc = len(K_dir[a2d.SOC])
     if num_soc > 0:
         soc_vars = []
         for dim in K_dir[a2d.SOC]:
             temp = [0.] * dim
             task.getxxslice(sol, idx, idx + dim, temp)
             soc_vars.append(np.array(temp))
             idx += dim
         prim_vars[a2d.SOC] = soc_vars
     num_dexp = K_dir[a2d.DUAL_EXP]
     if num_dexp > 0:
         temp = [0.] * (3 * num_dexp)
         task.getxxslice(sol, idx, idx + len(temp), temp)
         temp = np.array(temp)
         perm = expcone_permutor(num_dexp, MOSEK.EXP_CONE_ORDER)
         prim_vars[a2d.DUAL_EXP] = temp[perm]
         idx += (3 * num_dexp)
     num_dpow = len(K_dir[a2d.DUAL_POW3D])
     if num_dpow > 0:
         temp = [0.] * (3 * num_dpow)
         task.getxxslice(sol, idx, idx + len(temp), temp)
         temp = np.array(temp)
         prim_vars[a2d.DUAL_POW3D] = temp
         idx += (3 * num_dpow)
     num_psd = len(K_dir[a2d.PSD])
     if num_psd > 0:
         psd_vars = []
         for j, dim in enumerate(K_dir[a2d.PSD]):
             xj = [0.] * (dim * (dim + 1) // 2)
             task.getbarxj(sol, j, xj)
             psd_vars.append(vectorized_lower_tri_to_mat(xj, dim))
         prim_vars[a2d.PSD] = psd_vars
     return prim_vars
Exemple #3
0
    def recover_dual_variables(task, sol, inverse_data):
        """
        A cvxpy Constraint "constr" views itself as
            affine_expression(z) in K.
        The "apply(...)" function represents constr as
            G * z <=_K h
        for appropriate arrays (G, h).
        After adding slack variables, constr becomes
            G * z + s == h, s in K.
        From "apply(...)" and "solve_via_data(...)", one will find
            affine_expression(z) == h - G * z == s.
        As a result, the dual variable suitable for "constr" is
        the conic dual variable to the constraint "s in K".

        Mosek documentation refers to conic dual variables as follows:
            zero cone: 'y'
            nonnegative orthant: 'suc'
            second order cone: 'snx'
            exponential cone: 'snx'
            PSD cone: 'barsj'.

        :param task: the mosek task object which was just optimized
        :param sol: the mosek solution type (usually mosek.soltype.itr,
        but possibly mosek.soltype.bas if the problem was a linear
        program and the user requested a basic feasible solution).
        :param inverse_data: data recorded during "apply(...)".

        :return: a dictionary mapping a cvxpy constraint object's id to its
        corresponding dual variables in the current solution.
        """
        dual_vars = dict()

        # Dual variables for the inequality constraints
        suc_len = sum(ell for _, ell in inverse_data['suc_slacks'])
        if suc_len > 0:
            suc = [0.] * suc_len
            task.getsucslice(sol, 0, suc_len, suc)
            dual_vars.update(MOSEK._parse_dual_var_block(suc, inverse_data['suc_slacks']))

        # Dual variables for the original equality constraints
        y_len = sum(ell for _, ell in inverse_data['y_slacks'])
        if y_len > 0:
            y = [0.] * y_len
            task.getyslice(sol, suc_len, suc_len + y_len, y)
            y = [-val for val in y]
            dual_vars.update(MOSEK._parse_dual_var_block(y, inverse_data['y_slacks']))

        # Dual variables for SOC and EXP constraints
        snx_len = sum(ell for _, ell in inverse_data['snx_slacks'])
        if snx_len > 0:
            snx = np.zeros(snx_len)
            task.getsnxslice(sol, inverse_data['n0'], inverse_data['n0'] + snx_len, snx)
            dual_vars.update(MOSEK._parse_dual_var_block(snx, inverse_data['snx_slacks']))

        # Dual variables for PSD constraints
        for j, (id, dim) in enumerate(inverse_data['psd_dims']):
            sj = [0.] * (dim * (dim + 1) // 2)
            task.getbarsj(sol, j, sj)
            dual_vars[id] = vectorized_lower_tri_to_mat(sj, dim)

        # Now that all dual variables have been recovered, find those corresponding
        # to the exponential cone, and permute the entries to reflect the CVXPY
        # standard for the exponential cone.
        for con in inverse_data['constraints']:
            if isinstance(con, ExpCone):
                cid = con.id
                perm = expcone_permutor(con.num_cones(), MOSEK.EXP_CONE_ORDER)
                dual_vars[cid] = dual_vars[cid][perm]
        return dual_vars