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

        primal_vars = None
        dual_vars = None
        if status in s.SOLUTION_PRESENT:
            opt_val = solution['value'] + inverse_data[s.OFFSET]
            primal_vars = {inverse_data[GUROBI.VAR_ID]: solution['primal']}
            if "eq_dual" in solution and not inverse_data['is_mip']:
                eq_dual = utilities.get_dual_values(
                    solution['eq_dual'],
                    utilities.extract_dual_value,
                    inverse_data[GUROBI.EQ_CONSTR])
                leq_dual = utilities.get_dual_values(
                    solution['ineq_dual'],
                    utilities.extract_dual_value,
                    inverse_data[GUROBI.NEQ_CONSTR])
                eq_dual.update(leq_dual)
                dual_vars = eq_dual
            return Solution(status, opt_val, primal_vars, dual_vars, {})
        else:
            return failure_solution(status)

        return Solution(status, opt_val, primal_vars, dual_vars, {})
Beispiel #2
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)
Beispiel #3
0
    def invert(self, solution: Dict[str, Any],
               inverse_data: Dict[str, Any]) -> Solution:
        """Returns the solution to the original problem given the inverse_data."""

        status = solution['status']
        dual_vars = None

        if status in s.SOLUTION_PRESENT:
            opt_val = solution['value'] + inverse_data[s.OFFSET]
            primal_vars = {inverse_data[SCIP.VAR_ID]: solution['primal']}

            if "eq_dual" in solution and not inverse_data['is_mip']:
                eq_dual = utilities.get_dual_values(
                    result_vec=solution['eq_dual'],
                    parse_func=utilities.extract_dual_value,
                    constraints=inverse_data[SCIP.EQ_CONSTR],
                )
                leq_dual = utilities.get_dual_values(
                    result_vec=solution['ineq_dual'],
                    parse_func=utilities.extract_dual_value,
                    constraints=inverse_data[SCIP.NEQ_CONSTR],
                )

                eq_dual.update(leq_dual)
                dual_vars = eq_dual

            return Solution(status, opt_val, primal_vars, dual_vars, {})
        else:
            return failure_solution(status)
Beispiel #4
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'])
            }
            eq_dual = utilities.get_dual_values(
                solution['y'],
                utilities.extract_dual_value,
                inverse_data[self.EQ_CONSTR])
            leq_dual = utilities.get_dual_values(
                solution['z'],
                utilities.extract_dual_value,
                inverse_data[self.NEQ_CONSTR])
            eq_dual.update(leq_dual)
            dual_vars = eq_dual
            return Solution(status, opt_val, primal_vars, dual_vars, attr)
        else:
            return failure_solution(status)
Beispiel #5
0
    def invert(self, solution, inverse_data):
        """Returns the solution to the original problem given the inverse_data.
        """
        status = self.STATUS_MAP[solution['status']]

        primal_vars = None
        dual_vars = None
        if status in s.SOLUTION_PRESENT:
            primal_val = solution['fun']
            opt_val = primal_val + inverse_data[s.OFFSET]
            primal_vars = {inverse_data[self.VAR_ID]: solution['x']}

            # SciPy linprog only returns duals for version >= 1.7.0
            # and method is one of 'highs', 'highs-ds' or 'highs-ipm'
            if ('ineqlin' in solution.keys()):
                eq_dual = utilities.get_dual_values(
                    -solution['eqlin']['marginals'],
                    utilities.extract_dual_value, inverse_data[self.EQ_CONSTR])
                leq_dual = utilities.get_dual_values(
                    -solution['ineqlin']['marginals'],
                    utilities.extract_dual_value,
                    inverse_data[self.NEQ_CONSTR])
                eq_dual.update(leq_dual)
                dual_vars = eq_dual

            return Solution(status, opt_val, primal_vars, dual_vars, {})
        else:
            return failure_solution(status)
Beispiel #6
0
    def invert(self, solution, inverse_data):
        """Returns the solution to the original problem given the inverse_data.
        """
        status = solution['status']

        if status in s.SOLUTION_PRESENT:
            opt_val = solution['value']
            primal_vars = {inverse_data[self.VAR_ID]: solution['primal']}
            eq_dual = utilities.get_dual_values(solution['eq_dual'],
                                                utilities.extract_dual_value,
                                                inverse_data[Solver.EQ_CONSTR])
            leq_dual = utilities.get_dual_values(
                solution['ineq_dual'], utilities.extract_dual_value,
                inverse_data[Solver.NEQ_CONSTR])
            eq_dual.update(leq_dual)
            dual_vars = eq_dual
        else:
            if status == s.INFEASIBLE:
                opt_val = np.inf
            elif status == s.UNBOUNDED:
                opt_val = -np.inf
            else:
                opt_val = None
            primal_vars = None
            dual_vars = None

        return Solution(status, opt_val, primal_vars, dual_vars, {})
Beispiel #7
0
    def invert(self, results, inverse_data):
        model = results["model"]
        attr = {}
        if "cputime" in results:
            attr[s.SOLVE_TIME] = results["cputime"]
        attr[s.NUM_ITERS] = \
            int(model.solution.progress.get_num_barrier_iterations()) \
            if not inverse_data[CPLEX.IS_MIP] \
            else 0

        status = get_status(model)

        if status in s.SOLUTION_PRESENT:
            # Get objective value
            opt_val = model.solution.get_objective_value() + \
                inverse_data[s.OFFSET]

            # Get solution
            x = np.array(model.solution.get_values())
            primal_vars = {
                CPLEX.VAR_ID: intf.DEFAULT_INTF.const_to_matrix(np.array(x))
            }

            # Only add duals if not a MIP.
            dual_vars = None
            if not inverse_data[CPLEX.IS_MIP]:
                y = -np.array(model.solution.get_dual_values())
                dual_vars = {CPLEX.DUAL_VAR_ID: y}

            sol = Solution(status, opt_val, primal_vars, dual_vars, attr)
        else:
            sol = failure_solution(status, attr)
        return sol
Beispiel #8
0
    def invert(self, solution, inverse_data):
        """Returns solution to original problem, given inverse_data.
        """
        status = self.STATUS_MAP[solution['info']['exitFlag']]

        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 = None
            if not inverse_data['is_mip']:
                eq_dual = utilities.get_dual_values(
                    solution['y'], utilities.extract_dual_value,
                    inverse_data[self.EQ_CONSTR])
                leq_dual = utilities.get_dual_values(
                    solution['z'], utilities.extract_dual_value,
                    inverse_data[self.NEQ_CONSTR])
                eq_dual.update(leq_dual)
                dual_vars = eq_dual
            return Solution(status, opt_val, primal_vars, dual_vars, {})
        else:
            return failure_solution(status)
Beispiel #9
0
    def invert(self, solution, inverse_data):
        """Returns the solution to the original problem given the inverse_data.
        """
        status = self.STATUS_MAP[solution["info"]["status"]]

        attr = {}
        attr[s.SOLVE_TIME] = solution["info"]["solveTime"]
        attr[s.SETUP_TIME] = solution["info"]["setupTime"]
        attr[s.NUM_ITERS] = solution["info"]["iter"]

        if status in s.SOLUTION_PRESENT:
            primal_val = solution["info"]["pobj"]
            opt_val = primal_val + inverse_data[s.OFFSET]
            # TODO expand primal and dual variables from lower triangular to full.
            # TODO but this makes map from solution to variables not a slice.
            primal_vars = {
                inverse_data[SCS.VAR_ID]: solution["x"]
            }
            eq_dual_vars = utilities.get_dual_values(
                solution["y"][:inverse_data[ConicSolver.DIMS].zero],
                self.extract_dual_value,
                inverse_data[SCS.EQ_CONSTR]
            )
            ineq_dual_vars = utilities.get_dual_values(
                solution["y"][inverse_data[ConicSolver.DIMS].zero:],
                self.extract_dual_value,
                inverse_data[SCS.NEQ_CONSTR]
            )
            dual_vars = {}
            dual_vars.update(eq_dual_vars)
            dual_vars.update(ineq_dual_vars)
            return Solution(status, opt_val, primal_vars, dual_vars, attr)
        else:
            return failure_solution(status)
Beispiel #10
0
    def invert(self, solution, inverse_data):
        """Returns the solution to the original problem given the inverse_data.
        """
        model = solution["model"]
        attr = {}
        if s.SOLVE_TIME in solution:
            attr[s.SOLVE_TIME] = solution[s.SOLVE_TIME]

        status = get_status(model)

        primal_vars = None
        dual_vars = None
        if status in s.SOLUTION_PRESENT:
            opt_val = (model.solution.get_objective_value() +
                       inverse_data[s.OFFSET])

            x = np.array(model.solution.get_values())
            primal_vars = {inverse_data[CPLEX.VAR_ID]: x}

            if not inverse_data['is_mip']:
                # The dual values are retrieved in the order that the
                # constraints were added in solve_via_data() below. We
                # must be careful to map them to inverse_data[EQ_CONSTR]
                # followed by inverse_data[NEQ_CONSTR] accordingly.
                y = -np.array(model.solution.get_dual_values())
                dual_vars = utilities.get_dual_values(
                    y,
                    utilities.extract_dual_value,
                    inverse_data[CPLEX.EQ_CONSTR] + inverse_data[CPLEX.NEQ_CONSTR])

            return Solution(status, opt_val, primal_vars, dual_vars, attr)
        else:
            return failure_solution(status)
Beispiel #11
0
    def invert(self, solution, inverse_data):
        """Returns the solution to the original problem given the inverse_data.
        """
        status = solution[s.STATUS]

        primal_vars = None
        dual_vars = None
        if status in s.SOLUTION_PRESENT:
            opt_val = solution[s.VALUE] + inverse_data[s.OFFSET]
            primal_vars = {inverse_data[XPRESS.VAR_ID]: solution['primal']}
            if not inverse_data['is_mip']:
                dual_vars = utilities.get_dual_values(
                    solution[s.EQ_DUAL], utilities.extract_dual_value,
                    inverse_data[s.EQ_CONSTR])
        else:
            if status == s.INFEASIBLE:
                opt_val = np.inf
            elif status == s.UNBOUNDED:
                opt_val = -np.inf
            else:
                opt_val = None

        other = {}
        other[s.XPRESS_IIS] = solution[s.XPRESS_IIS]
        other[s.XPRESS_TROW] = solution[s.XPRESS_TROW]
        return Solution(status, opt_val, primal_vars, dual_vars, other)
Beispiel #12
0
    def invert(self, solution, inverse_data):
        """Returns the solution to the original problem given the inverse_data.
        """
        status = solution[s.STATUS]

        if status in s.SOLUTION_PRESENT:
            opt_val = solution[s.VALUE]
            primal_vars = {inverse_data[self.VAR_ID]: solution[s.PRIMAL]}
            eq_dual = ConicSolver.get_dual_values(solution[s.EQ_DUAL],
                                                  inverse_data[self.EQ_CONSTR])
            leq_dual = ConicSolver.get_dual_values(
                solution[s.INEQ_DUAL], inverse_data[self.NEQ_CONSTR])
            eq_dual.update(leq_dual)
            dual_vars = eq_dual
        else:
            if status == s.INFEASIBLE:
                opt_val = np.inf
            elif status == s.UNBOUNDED:
                opt_val = -np.inf
            else:
                opt_val = None
            primal_vars = None
            dual_vars = None

        return Solution(status, opt_val, primal_vars, dual_vars, {})
Beispiel #13
0
    def invert(self, solution, inverse_data):
        """Returns the solution to the original problem given the inverse_data.
        """
        status = self.STATUS_MAP[solution["info"]["status"]]

        attr = {}
        attr[s.SOLVE_TIME] = solution["info"]["solveTime"]
        attr[s.SETUP_TIME] = solution["info"]["setupTime"]
        attr[s.NUM_ITERS] = solution["info"]["iter"]

        if status in s.SOLUTION_PRESENT:
            primal_val = solution["info"]["pobj"]
            opt_val = primal_val + inverse_data[s.OFFSET]
            primal_vars = {
                inverse_data[SCS.VAR_ID]:
                intf.DEFAULT_INTF.const_to_matrix(solution["x"])
            }
            eq_dual_vars = utilities.get_dual_values(
                intf.DEFAULT_INTF.const_to_matrix(
                    solution["y"][:inverse_data[ConicSolver.DIMS].zero]),
                self.extract_dual_value, inverse_data[SCS.EQ_CONSTR])
            ineq_dual_vars = utilities.get_dual_values(
                intf.DEFAULT_INTF.const_to_matrix(
                    solution["y"][inverse_data[ConicSolver.DIMS].zero:]),
                self.extract_dual_value, inverse_data[SCS.NEQ_CONSTR])
            dual_vars = {}
            dual_vars.update(eq_dual_vars)
            dual_vars.update(ineq_dual_vars)
            return Solution(status, opt_val, primal_vars, dual_vars, attr)
        else:
            return failure_solution(status)
Beispiel #14
0
    def invert(self, solution, inverse_data):
        """Returns the solution to the original problem given the inverse_data.
        """
        status = solution['status']

        if status in s.SOLUTION_PRESENT:
            opt_val = solution['value'] + inverse_data[s.OFFSET]
            primal_vars = {inverse_data[self.VAR_ID]: solution['primal']}
            return Solution(status, opt_val, primal_vars, None, {})
        else:
            return failure_solution(status)
Beispiel #15
0
 def invert(self, solution, inverse_data):
     pvars = {
         vid: solution.primal_vars[vid]
         for vid in inverse_data.id_map if vid in solution.primal_vars
     }
     for vid in inverse_data.id_map:
         if vid not in pvars:
             # Variable was optimized out because it was unconstrainted.
             pvars[vid] = 0.0
     return Solution(solution.status, solution.opt_val, pvars, {},
                     solution.attr)
Beispiel #16
0
 def invert(self, solution, inverse_data):
     pvars = {}
     dvars = {}
     if solution.status in s.SOLUTION_PRESENT:
         for vid, var in inverse_data.id2var.items():
             if var.is_real():
                 pvars[vid] = solution.primal_vars[vid]
             elif var.is_imag():
                 imag_id = inverse_data.real2imag[vid]
                 pvars[vid] = 1j * solution.primal_vars[imag_id]
             elif var.is_complex() and var.is_hermitian():
                 imag_id = inverse_data.real2imag[vid]
                 # Imaginary part may have been lost.
                 if imag_id in solution.primal_vars:
                     imag_val = solution.primal_vars[imag_id]
                     pvars[vid] = solution.primal_vars[vid] + \
                         1j*(imag_val - imag_val.T)/2
                 else:
                     pvars[vid] = solution.primal_vars[vid]
             elif var.is_complex():
                 imag_id = inverse_data.real2imag[vid]
                 # Imaginary part may have been lost.
                 if imag_id in solution.primal_vars:
                     pvars[vid] = solution.primal_vars[vid] + \
                         1j*solution.primal_vars[imag_id]
                 else:
                     pvars[vid] = solution.primal_vars[vid]
         for cid, cons in inverse_data.id2cons.items():
             if cons.is_real():
                 dvars[vid] = solution.dual_vars[cid]
             elif cons.is_imag():
                 imag_id = inverse_data.real2imag[cid]
                 dvars[cid] = 1j * solution.dual_vars[imag_id]
             # For equality and inequality constraints.
             elif isinstance(
                     cons, (Equality, Zero, NonPos)) and cons.is_complex():
                 imag_id = inverse_data.real2imag[cid]
                 if imag_id in solution.dual_vars:
                     dvars[cid] = solution.dual_vars[cid] + \
                         1j*solution.dual_vars[imag_id]
                 else:
                     dvars[cid] = solution.dual_vars[cid]
             elif isinstance(cons, SOC) and cons.is_complex():
                 # TODO add dual variables for complex SOC.
                 pass
             # For PSD constraints.
             elif isinstance(cons, PSD) and cons.is_complex():
                 n = cons.args[0].shape[0]
                 dual = solution.dual_vars[cid]
                 dvars[cid] = dual[:n, :n] + 1j * dual[n:, :n]
             else:
                 raise Exception("Unknown constraint type.")
     return Solution(solution.status, solution.opt_val, pvars, dvars,
                     solution.attr)
Beispiel #17
0
    def solve_via_data(self,
                       data,
                       warm_start,
                       verbose,
                       solver_opts,
                       solver_cache=None):
        import mosek

        if 'dualized' in data:
            if len(data[s.C]) == 0 and len(data['c_bar_data']) == 0:
                # primal problem was unconstrained minimization of a linear function.
                if np.linalg.norm(data[s.B]) > 0:
                    sol = Solution(s.INFEASIBLE, -np.inf, None, None, dict())
                    return {'sol': sol}
                else:
                    sol = Solution(s.OPTIMAL, 0.0, dict(),
                                   {s.EQ_DUAL: data[s.B]}, dict())
                    return {'sol': sol}
            else:
                env = mosek.Env()
                task = env.Task(0, 0)
                task = MOSEK._build_dualized_task(task, data)
        else:
            if len(data[s.C]) == 0:
                sol = Solution(s.OPTIMAL, 0.0, dict(), dict(), dict())
                return {'sol': sol}
            else:
                env = mosek.Env()
                task = env.Task(0, 0)
                task = MOSEK._build_slack_task(task, data)

        # Set parameters, optimize the Mosek Task, and return the result.
        save_file = MOSEK.handle_options(env, task, verbose, solver_opts)
        if save_file:
            task.writedata(save_file)
        task.optimize()

        if verbose:
            task.solutionsummary(mosek.streamtype.msg)

        return {'env': env, 'task': task, 'solver_options': solver_opts}
 def invert(self, solution, inverse_data):
     pvars = {
         vid: solution.primal_vars[vid]
         for vid in inverse_data.id_map if vid in solution.primal_vars
     }
     dvars = {
         orig_id: solution.dual_vars[vid]
         for orig_id, vid in inverse_data.cons_id_map.items()
         if vid in solution.dual_vars
     }
     return Solution(solution.status, solution.opt_val, pvars, dvars,
                     solution.attr)
Beispiel #19
0
    def invert(self, solution, inverse_data):

        status = self.STATUS_MAP[solution['status']]
        sln = solution['sln']

        opt_val = None
        primal_vars = None
        dual_vars = None
        attr = {}
        if status in s.SOLUTION_PRESENT:
            opt_val = sln.rinfo[0] + inverse_data[s.OBJ_OFFSET]
            nr = inverse_data['nr']
            x = [0.0] * nr
            x = sln.x[0:nr]
            primal_vars = {inverse_data[self.VAR_ID]: x}
            attr[s.SOLVE_TIME] = sln.stats[5]
            attr[s.NUM_ITERS] = sln.stats[0]
            # Recover dual variables
            dual_vars = dict()
            lin_dim = sum(ell for _, ell in inverse_data['lin_dim'])
            if lin_dim > 0:
                lin_dvars = np.zeros(lin_dim)
                idx = 0
                for i in range(lin_dim):
                    lin_dvars[i] = sln.u[idx+1] - sln.u[idx]
                    idx += 2
                idx = 0
                for id, dim in inverse_data['lin_dim']:
                    if dim == 1:
                        dual_vars[id] = lin_dvars[idx]
                    else:
                        dual_vars[id] = np.array(lin_dvars[idx:(idx + dim)])
                    idx += dim
            soc_dim = sum(ell for _, ell in inverse_data['soc_dim'])
            if soc_dim > 0:
                idx = 0
                for id, dim in inverse_data['soc_dim']:
                    if dim == 1:
                        dual_vars[id] = sln.uc[idx]
                    else:
                        dual_vars[id] = np.array(sln.uc[idx:(idx + dim)])
                    idx += dim
        else:
            if status == s.INFEASIBLE:
                opt_val = np.inf
            elif status == s.UNBOUNDED:
                opt_val = -np.inf
            else:
                opt_val = None
            primal_vars = None
            dual_vars = None
        return Solution(status, opt_val, primal_vars, dual_vars, attr)
Beispiel #20
0
    def invert(self, results, inverse_data):
        model = results["model"]
        x_grb = model.getVars()
        n = len(x_grb)
        constraints_grb = model.getConstrs()
        m = len(constraints_grb)

        # Note: Gurobi does not always fill BarIterCount
        # and IterCount so better using try/except
        try:
            bar_iter_count = model.BarIterCount
        except AttributeError:
            bar_iter_count = 0
        try:
            simplex_iter_count = model.IterCount
        except AttributeError:
            simplex_iter_count = 0
        # Take the sum in case they both appear. One of them
        # will be 0 anyway
        iter_count = bar_iter_count + simplex_iter_count

        # Start populating attribute dictionary
        attr = {
            s.SOLVE_TIME: model.Runtime,
            s.NUM_ITERS: iter_count,
            s.EXTRA_STATS: model
        }

        # Map GUROBI statuses back to CVXPY statuses
        status = self.STATUS_MAP.get(model.Status, s.SOLVER_ERROR)
        if status == s.USER_LIMIT and not model.SolCount:
            status = s.INFEASIBLE_INACCURATE

        if (status in s.SOLUTION_PRESENT) or (model.solCount > 0):
            opt_val = model.objVal + inverse_data[s.OFFSET]
            x = np.array([x_grb[i].X for i in range(n)])

            primal_vars = {
                GUROBI.VAR_ID: intf.DEFAULT_INTF.const_to_matrix(np.array(x))
            }

            # Only add duals if not a MIP.
            dual_vars = None
            if not inverse_data[GUROBI.IS_MIP]:
                y = -np.array([constraints_grb[i].Pi for i in range(m)])
                dual_vars = {GUROBI.DUAL_VAR_ID: y}

            sol = Solution(status, opt_val, primal_vars, dual_vars, attr)
        else:
            sol = failure_solution(status, attr)
        return sol
Beispiel #21
0
    def invert(self, solution: Dict[str, Any],
               inverse_data: Dict[str, Any]) -> Solution:
        """Returns the solution to the original problem."""
        status = solution["status"]

        if status in s.SOLUTION_PRESENT:
            primal_vars = {inverse_data[self.VAR_ID]: solution["primal"]}
            dual_vars = utilities.get_dual_values(
                result_vec=solution["dual"],
                parse_func=utilities.extract_dual_value,
                constraints=inverse_data["constraints"],
            )
            return Solution(status, solution["value"], primal_vars, dual_vars,
                            {})
        else:
            return failure_solution(status)
Beispiel #22
0
    def invert(self, solution, inverse_data):
        if not inverse_data:
            return solution

        id2new_var, id2old_var, cons_id_map = inverse_data
        pvars = {}
        for id, var in id2old_var.items():
            new_var = id2new_var[id]
            if new_var.id in solution.primal_vars:
                pvars[id] = recover_value_for_variable(
                    var, solution.primal_vars[new_var.id])

        dvars = {orig_id: solution.dual_vars[vid]
                 for orig_id, vid in cons_id_map.items()
                 if vid in solution.dual_vars}
        return Solution(solution.status, solution.opt_val, pvars, dvars,
                        solution.attr)
Beispiel #23
0
    def invert(self, solution, inverse_data):
        """Returns the solution to the original problem given the inverse_data.
        """
        attr = {}
        if solution["solve_method"] == s.SCS:
            import scs
            if Version(scs.__version__) < Version('3.0.0'):
                status = scs_conif.SCS.STATUS_MAP[solution["info"]["statusVal"]]
                attr[s.SOLVE_TIME] = solution["info"]["solveTime"]
                attr[s.SETUP_TIME] = solution["info"]["setupTime"]
            else:
                status = scs_conif.SCS.STATUS_MAP[solution["info"]["status_val"]]
                attr[s.SOLVE_TIME] = solution["info"]["solve_time"]
                attr[s.SETUP_TIME] = solution["info"]["setup_time"]
        elif solution["solve_method"] == s.ECOS:
            status = self.STATUS_MAP[solution["info"]["status"]]
            attr[s.SOLVE_TIME] = solution["info"]["solveTime"]
            attr[s.SETUP_TIME] = solution["info"]["setupTime"]

        attr[s.NUM_ITERS] = solution["info"]["iter"]
        attr[s.EXTRA_STATS] = solution

        if status in s.SOLUTION_PRESENT:
            primal_val = solution["info"]["pobj"]
            opt_val = primal_val + inverse_data[s.OFFSET]
            # TODO expand primal and dual variables from lower triangular to full.
            # TODO but this makes map from solution to variables not a slice.
            primal_vars = {
                inverse_data[DIFFCP.VAR_ID]: solution["x"]
            }
            eq_dual_vars = utilities.get_dual_values(
                solution["y"][:inverse_data[ConicSolver.DIMS].zero],
                self.extract_dual_value,
                inverse_data[DIFFCP.EQ_CONSTR]
            )
            ineq_dual_vars = utilities.get_dual_values(
                solution["y"][inverse_data[ConicSolver.DIMS].zero:],
                self.extract_dual_value,
                inverse_data[DIFFCP.NEQ_CONSTR]
            )
            dual_vars = {}
            dual_vars.update(eq_dual_vars)
            dual_vars.update(ineq_dual_vars)
            return Solution(status, opt_val, primal_vars, dual_vars, attr)
        else:
            return failure_solution(status, attr)
Beispiel #24
0
    def invert(self, solution, inverse_data):
        attr = {s.SOLVE_TIME: solution.info.run_time}
        attr[s.EXTRA_STATS] = solution

        # Map OSQP statuses back to CVXPY statuses
        status = self.STATUS_MAP.get(solution.info.status_val, s.SOLVER_ERROR)

        if status in s.SOLUTION_PRESENT:
            opt_val = solution.info.obj_val + inverse_data[s.OFFSET]
            primal_vars = {
                OSQP.VAR_ID:
                intf.DEFAULT_INTF.const_to_matrix(np.array(solution.x))
            }
            dual_vars = {OSQP.DUAL_VAR_ID: solution.y}
            attr[s.NUM_ITERS] = solution.info.iter
            sol = Solution(status, opt_val, primal_vars, dual_vars, attr)
        else:
            sol = failure_solution(status, attr)
        return sol
Beispiel #25
0
    def invert(self, solution, inverse_data):
        """Returns the solution to the original problem given the inverse_data.
        """
        status = solution['status']

        if status in s.SOLUTION_PRESENT:
            opt_val = solution['value'] + inverse_data[s.OFFSET]
            primal_vars = {inverse_data[self.VAR_ID]: solution['primal']}
            eq_dual = utilities.get_dual_values(solution[s.EQ_DUAL],
                                                utilities.extract_dual_value,
                                                inverse_data[self.EQ_CONSTR])
            leq_dual = utilities.get_dual_values(solution[s.INEQ_DUAL],
                                                 utilities.extract_dual_value,
                                                 inverse_data[self.NEQ_CONSTR])
            eq_dual.update(leq_dual)
            dual_vars = eq_dual
            return Solution(status, opt_val, primal_vars, dual_vars, {})
        else:
            return failure_solution(status)
Beispiel #26
0
    def invert(self, solution, inverse_data):
        """Returns the solution to the original problem given the inverse_data.
        """
        status = solution['status']

        if status in s.SOLUTION_PRESENT:
            opt_val = solution['value']
            primal_vars = {inverse_data[self.VAR_ID]: solution['primal']}
        else:
            if status == s.INFEASIBLE:
                opt_val = np.inf
            elif status == s.UNBOUNDED:
                opt_val = -np.inf
            else:
                opt_val = None
            primal_vars = None
        dual_vars = None

        return Solution(status, opt_val, primal_vars, dual_vars, {})
Beispiel #27
0
    def invert(self, results, inverse_data):
        # model = results["model"]
        attr = {}
        if s.SOLVE_TIME in results:
            attr[s.SOLVE_TIME] = results[s.SOLVE_TIME]
        attr[s.NUM_ITERS] = \
            int(results['bariter']) \
            if not inverse_data[XPRESS.IS_MIP] \
            else 0

        status_map_lp, status_map_mip = get_status_maps()

        if results['status'] == 'solver_error':
            status = 'solver_error'
        elif 'mip_' in results['getProbStatusString']:
            status = status_map_mip[results['status']]
        else:
            status = status_map_lp[results['status']]

        if status in s.SOLUTION_PRESENT:
            # Get objective value
            opt_val = results['getObjVal'] + inverse_data[s.OFFSET]

            # Get solution
            x = np.array(results['getSolution'])
            primal_vars = {
                XPRESS.VAR_ID: intf.DEFAULT_INTF.const_to_matrix(np.array(x))
            }

            # Only add duals if not a MIP.
            dual_vars = None
            if not inverse_data[XPRESS.IS_MIP]:
                y = -np.array(results['getDual'])
                dual_vars = {XPRESS.DUAL_VAR_ID: y}

            sol = Solution(status, opt_val, primal_vars, dual_vars, attr)
        else:
            sol = failure_solution(status, attr)
        return sol
Beispiel #28
0
    def invert(solution, inv_data):
        """
        ``solution`` is a CVXPY Solution object, formatted where

            (D-Opt) max{ -b @ y : c = A.T @ y, y in K^* } + d

        is the primal problem from the solver's perspective. The purpose of this function
        is to map such a solution back to the format

                (P-Opt) min{ c.T @ x : A @ x + b in K } + d.

        This function handles mapping of primal and dual variables, and solver status codes.
        The variable "x" in (P-Opt) is trivially populated from the dual variables to the
        constraint "c = A.T @ y" in (D-Opt). Status codes also map back in a simple way.

        Details on required formatting of solution.primal_vars
        ------------------------------------------------------

        We assume the dict solution.primal_vars is keyed by string-enums FREE ('fr'), NONNEG ('+'),
        SOC ('s'), PSD ('p'), and DUAL_EXP ('de'). The corresponding values are described below.

        solution.primal_vars[FREE] should be a single vector. It corresponds to the (possibly
        concatenated) components of "y" which are subject to no conic constraints. We map these
        variables back to dual variables for equality constraints in (P-Opt).

        solution.primal_vars[NONNEG] should also be a single vector, this time giving the
        possibly concatenated components of "y" which must be >= 0. We map these variables
        back to dual variables for inequality constraints in (P-Opt).

        solution.primal_vars[SOC] is a list of vectors specifying blocks of "y" which belong
        to the second-order-cone under the CVXPY standard ({ z : z[0] >= || z[1:] || }).
        We map these variables back to dual variables for SOC constraints in (P-Opt).

        solution.primal_vars[PSD] is a list of symmetric positive semidefinite matrices
        which result by lifting the vectorized PSD blocks of "y" back into matrix form.
        We assign these as dual variables to PSD constraints appearing in (P-Opt).

        solution.primal_vars[DUAL_EXP] is a vector of concatenated length-3 slices of y, where
        each constituent length-3 slice belongs to dual exponential cone as implied by the CVXPY
        standard of the primal exponential cone (see cvxpy/constraints/exponential.py:ExpCone).
        We map these back to dual variables for exponential cone constraints in (P-Opt).

        """
        status = solution.status
        prob_attr = solution.attr
        primal_vars, dual_vars = None, None
        if status in s.SOLUTION_PRESENT:
            opt_val = solution.opt_val + inv_data[s.OBJ_OFFSET]
            primal_vars = {inv_data['x_id']: solution.dual_vars[s.EQ_DUAL]}
            dual_vars = dict()
            direct_prims = solution.primal_vars
            constr_map = inv_data['constr_map']
            i = 0
            for con in constr_map[Zero_obj]:
                dv = direct_prims[FREE][i:i + con.size]
                dual_vars[con.id] = dv if dv.size > 1 else dv.item()
                i += con.size
            i = 0
            for con in constr_map[NonNeg_obj]:
                dv = direct_prims[NONNEG][i:i + con.size]
                dual_vars[con.id] = dv if dv.size > 1 else dv.item()
                i += con.size
            i = 0
            for con in constr_map[SOC_obj]:
                block_len = con.shape[0]
                dv = np.concatenate(direct_prims[SOC][i:i + block_len])
                dual_vars[con.id] = dv
                i += block_len
            for i, con in enumerate(constr_map[PSD_obj]):
                dv = direct_prims[PSD][i]
                dual_vars[con.id] = dv
            i = 0
            for con in constr_map[ExpCone_obj]:
                dv = direct_prims[DUAL_EXP][i:i + con.size]
                dual_vars[con.id] = dv
                i += con.size
            for con in constr_map[PowCone_obj]:
                dv = direct_prims[DUAL_POW3D][i:i + con.size]
                dual_vars[con.id] = dv
                i += con.size
        elif status == s.INFEASIBLE:
            status = s.UNBOUNDED
            opt_val = -np.inf
        elif status == s.INFEASIBLE_INACCURATE:
            status = s.UNBOUNDED_INACCURATE
            opt_val = -np.inf
        elif status == s.UNBOUNDED:
            status = s.INFEASIBLE
            opt_val = np.inf
        elif status == s.UNBOUNDED_INACCURATE:
            status = s.INFEASIBLE_INACCURATE
            opt_val = np.inf
        else:
            status = s.SOLVER_ERROR
            opt_val = np.NaN
        sol = Solution(status, opt_val, primal_vars, dual_vars, prob_attr)
        return sol
Beispiel #29
0
 def solve(self, problem, warm_start: bool, verbose: bool, solver_opts):
     if all(c.value() for c in problem.constraints):
         return Solution(s.OPTIMAL, problem.objective.value, {}, {}, {})
     else:
         return Solution(s.INFEASIBLE, None, {}, {}, {})
Beispiel #30
0
    def invert(self, results, inverse_data):
        """
        Use information contained within "results" and "inverse_data" to properly
        define a cvxpy Solution object.

        :param results: a dictionary with three key-value pairs:
            results['env'] == the mosek Environment object generated during solve_via_data,
            results['task'] == the mosek Task object generated during solve_via_data,
            results['solver_options'] == the dictionary of parameters passed to solve_via_data.
        :param inverse_data: data recorded during "apply".

        :return: a cvxpy Solution object, instantiated with the following fields:

            (1) status - the closest cvxpy analog of mosek's status code.
            (2) opt_val - the optimal objective function value
            (after translation by a possible constant).
            (3) primal_vars - a dictionary with a single element: "z", represented as a list.
            (4) dual_vars - a dictionary with as many elements as
            constraints in the cvxpy standard form problem.
                The elements of the dictionary are either scalars, or numpy arrays.
        """
        import mosek
        # Status map is taken from:
        # https://docs.mosek.com/8.1/pythonapi/constants.html?highlight=solsta#mosek.solsta
        STATUS_MAP = {
            mosek.solsta.optimal: s.OPTIMAL,
            mosek.solsta.integer_optimal: s.OPTIMAL,
            mosek.solsta.prim_feas:
            s.OPTIMAL_INACCURATE,  # for integer problems
            mosek.solsta.prim_infeas_cer: s.INFEASIBLE,
            mosek.solsta.dual_infeas_cer: s.UNBOUNDED
        }
        # "Near" statuses only up to Mosek 8.1
        if hasattr(mosek.solsta, 'near_optimal'):
            STATUS_MAP_INACCURATE = {
                mosek.solsta.near_optimal: s.OPTIMAL_INACCURATE,
                mosek.solsta.near_integer_optimal: s.OPTIMAL_INACCURATE,
                mosek.solsta.near_prim_infeas_cer: s.INFEASIBLE_INACCURATE,
                mosek.solsta.near_dual_infeas_cer: s.UNBOUNDED_INACCURATE
            }
            STATUS_MAP.update(STATUS_MAP_INACCURATE)
        STATUS_MAP = defaultdict(lambda: s.SOLVER_ERROR, STATUS_MAP)

        env = results['env']
        task = results['task']
        solver_opts = results['solver_options']

        if inverse_data['integer_variables']:
            sol = mosek.soltype.itg
        elif 'bfs' in solver_opts and solver_opts['bfs'] and inverse_data[
                'is_LP']:
            sol = mosek.soltype.bas  # the basic feasible solution
        else:
            sol = mosek.soltype.itr  # the solution found via interior point method

        problem_status = task.getprosta(sol)
        solution_status = task.getsolsta(sol)

        status = STATUS_MAP[solution_status]

        # For integer problems, problem status determines infeasibility (no solution)
        if sol == mosek.soltype.itg and problem_status == mosek.prosta.prim_infeas:
            status = s.INFEASIBLE

        if status in s.SOLUTION_PRESENT:
            # get objective value
            opt_val = task.getprimalobj(sol) + inverse_data[s.OBJ_OFFSET]
            # recover the cvxpy standard-form primal variable
            z = [0.] * inverse_data['n0']
            task.getxxslice(sol, 0, len(z), z)
            primal_vars = {inverse_data[self.VAR_ID]: z}
            # recover the cvxpy standard-form dual variables
            if sol == mosek.soltype.itg:
                dual_vars = None
            else:
                dual_vars = MOSEK.recover_dual_variables(
                    task, sol, inverse_data)
        else:
            if status == s.INFEASIBLE:
                opt_val = np.inf
            elif status == s.UNBOUNDED:
                opt_val = -np.inf
            else:
                opt_val = None
            primal_vars = None
            dual_vars = None

        # Store computation time
        attr = {}
        attr[s.SOLVE_TIME] = task.getdouinf(mosek.dinfitem.optimizer_time)

        # Delete the mosek Task and Environment
        task.__exit__(None, None, None)
        env.__exit__(None, None, None)

        return Solution(status, opt_val, primal_vars, dual_vars, attr)