示例#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'])
            }
            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)
示例#2
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)
示例#3
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)
示例#4
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)
示例#5
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)
示例#6
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)
示例#7
0
    def invert(self, solution, inverse_data):
        """Returns the solution to the original problem given the inverse_data.
        """
        status = solution['status']
        attr = {
            s.EXTRA_STATS: solution['model'],
            s.SOLVE_TIME: solution[s.SOLVE_TIME]
        }

        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, attr)
        else:
            return failure_solution(status, attr)
示例#8
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)
示例#9
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
示例#10
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)
示例#11
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)
示例#12
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
示例#13
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)
示例#14
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)
示例#15
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)
示例#16
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
示例#17
0
    def invert(self, solution, inverse_data):

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

        attr = {}
        if status in s.SOLUTION_PRESENT:
            opt_val = sln.rinfo[0] + inverse_data[s.OBJ_OFFSET]
            nr = inverse_data['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
            sol = Solution(status, opt_val, primal_vars, dual_vars, attr)
        else:
            sol = failure_solution(status)
        return sol
示例#18
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
示例#19
0
def bisect(problem,
           solver=None,
           low=None,
           high=None,
           eps=1e-6,
           verbose=False,
           max_iters=100,
           max_iters_interval_search=100):
    """Bisection on a one-parameter family of DCP problems.

    Bisects on a one-parameter family of DCP problems emitted by `Dqcp2Dcp`.

    Parameters
    ------
    problem : Problem
        problem emitted by Dqcp2Dcp
    solver : Solver
        solver to use for bisection
    low : float
        lower bound for bisection (optional)
    high : float
        upper bound for bisection (optional)
    eps : float
        terminate bisection when width of interval is < eps
    verbose : bool
        whether to print verbose output related to the bisection
    max_iters : int
        the maximum number of iterations to run bisection

    Returns
    -------
    A Solution object.
    """
    if not hasattr(problem, '_bisection_data'):
        raise ValueError("`bisect` only accepts problems emitted by Dqcp2Dcp.")

    feas_problem, t, tighten_lower, tighten_higher = problem._bisection_data
    if verbose:
        print("\n******************************************************"
              "**************************\n"
              "Preparing to bisect problem\n\n%s\n" % _lower_problem(problem))

    lowered_feas = _lower_problem(feas_problem)
    _solve(lowered_feas, solver)
    if _infeasible(lowered_feas):
        if verbose:
            print("Problem is infeasible.")
        return solution_module.failure_solution(s.INFEASIBLE)

    if low is None or high is None:
        if verbose:
            print("Finding interval for bisection ...")
        low, high = _find_bisection_interval(problem, t, solver, low, high,
                                             max_iters_interval_search)
    if verbose:
        print("initial lower bound: %0.6f" % low)
        print("initial upper bound: %0.6f\n" % high)

    soln, low, high = _bisect(problem, solver, t, low, high, tighten_lower,
                              tighten_higher, eps, verbose, max_iters)
    soln.opt_val = (low + high) / 2.0
    if verbose:
        print("Bisection completed, with lower bound %0.6f and upper bound "
              "%0.7f\n******************************************"
              "**************************************\n" % (low, high))
    return soln