def invert(self, solution, inverse_data): """Returns the solution to the original problem given the inverse_data.""" var_map = inverse_data.var_offsets con_map = inverse_data.cons_id_map # Flip sign of opt val if maximize. opt_val = solution.opt_val if solution.status not in s.ERROR and not inverse_data.minimize: opt_val = -solution.opt_val primal_vars, dual_vars = {}, {} if solution.status not in s.SOLUTION_PRESENT: return Solution(solution.status, opt_val, primal_vars, dual_vars, solution.attr) # Split vectorized variable into components. x_opt = solution.primal_vars.values()[0] for var_id, offset in var_map.items(): shape = inverse_data.var_shapes[var_id] size = np.prod(shape, dtype=int) primal_vars[var_id] = np.reshape(x_opt[offset:offset + size], shape, order='F') # Remap dual variables. for old_con, new_con in con_map.items(): dual_vars[old_con] = solution.dual_vars[new_con] # Add constant part if inverse_data.minimize: opt_val += inverse_data.r else: opt_val -= inverse_data.r return Solution(solution.status, opt_val, primal_vars, dual_vars, solution.attr)
def invert(self, solution, inverse_data): attr = {s.SOLVE_TIME: solution['time']} status = solution['status'] if status in s.SOLUTION_PRESENT: opt_val = solution['cost'] primal_vars = { KKTSolver.VAR_ID: intf.DEFAULT_INTF.const_to_matrix(np.array(solution['x'])) } # Build dual variables n_eq, n_ineq = inverse_data['n_eq'], inverse_data['n_ineq'] # equalities y_eq = solution['y'][:n_eq] # only dual variables for inequalities (not integer variables) y_ineq = np.zeros(n_ineq) n_tight = np.sum(inverse_data['tight_constraints']) y_ineq[inverse_data['tight_constraints']] = \ solution['y'][n_eq:n_eq + n_tight] y = np.concatenate([y_eq, y_ineq]) dual_vars = {KKTSolver.DUAL_VAR_ID: y} else: primal_vars = None dual_vars = None opt_val = np.inf if status == s.UNBOUNDED: opt_val = -np.inf return Solution(status, opt_val, primal_vars, dual_vars, attr)
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) # Start populating attribute dictionary attr = {s.SOLVE_TIME: model.Runtime, s.NUM_ITERS: model.BarIterCount} # Map GUROBI statuses back to CVXPY statuses status = self.STATUS_MAP.get(model.Status, s.SOLVER_ERROR) 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} else: primal_vars = None dual_vars = None opt_val = np.inf if status == s.UNBOUNDED: opt_val = -np.inf return Solution(status, opt_val, primal_vars, dual_vars, attr)
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] imag_val = solution.primal_vars[imag_id] pvars[vid] = solution.primal_vars[vid] + \ 1j*(imag_val - imag_val.T)/2 elif var.is_complex(): imag_id = inverse_data.real2imag[vid] pvars[vid] = solution.primal_vars[vid] + \ 1j*solution.primal_vars[imag_id] 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] elif cons.is_complex(): imag_id = inverse_data.real2imag[cid] dvars[cid] = solution.dual_vars[cid] + \ 1j*solution.dual_vars[imag_id] return Solution(solution.status, solution.opt_val, pvars, dvars, solution.attr)
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] # Need to map from constrained to symmetric variable. if new_var.id in solution.primal_vars: if var.attributes['diag']: pvars[id] = sp.diags( solution.primal_vars[new_var.id].flatten()) elif attributes_present([var], SYMMETRIC_ATTRIBUTES): n = var.shape[0] value = np.zeros(var.shape) idxs = np.triu_indices(n) value[idxs] = solution.primal_vars[new_var.id].flatten() value += value.T - np.diag(value.diagonal()) pvars[id] = value else: pvars[id] = var.project(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)
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)
def invert(self, solution, inverse_data): """Returns the solution to the original problem given the inverse_data.""" var_map = inverse_data.var_offsets con_map = inverse_data.cons_id_map # Flip sign of opt val if maximize. opt_val = solution.opt_val if solution.status not in s.ERROR and not inverse_data.minimize: opt_val = -solution.opt_val primal_vars, dual_vars = {}, {} if solution.status not in s.SOLUTION_PRESENT: return Solution(solution.status, opt_val, primal_vars, dual_vars, solution.attr) # Split vectorized variable into components. x_opt = list(solution.primal_vars.values())[0] for var_id, offset in list(var_map.items()): shape = inverse_data.var_shapes[var_id] size = np.prod(shape, dtype=int) primal_vars[var_id] = np.reshape(x_opt[offset:offset+size], shape, order='F') # Remap dual variables if dual exists (problem is convex). if solution.dual_vars is not None: for old_con, new_con in list(con_map.items()): con_obj = inverse_data.id2cons[old_con] shape = con_obj.shape # TODO rationalize Exponential. if shape == () or isinstance(con_obj, (ExpCone, SOC)): dual_vars[old_con] = solution.dual_vars[new_con] else: dual_vars[old_con] = np.reshape( solution.dual_vars[new_con], shape, order='F' ) # Add constant part if inverse_data.minimize: opt_val += inverse_data.r else: opt_val -= inverse_data.r return Solution(solution.status, opt_val, primal_vars, dual_vars, solution.attr)
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] if solution.dual_vars: for cid, cons in inverse_data.id2cons.items(): if cons.is_real(): dvars[cid] = 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, Inequality, NonNeg, 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)
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} else: primal_vars = None dual_vars = None opt_val = np.inf if status == s.UNBOUNDED: opt_val = -np.inf return Solution(status, opt_val, primal_vars, dual_vars, attr)
def invert(self, solution, inverse_data): """Retrieves the solution to the original problem.""" var_map = inverse_data.var_offsets # Flip sign of opt val if maximize. opt_val = solution.opt_val if solution.status not in s.ERROR and not inverse_data.minimize: opt_val = -solution.opt_val primal_vars, dual_vars = {}, {} if solution.status not in s.SOLUTION_PRESENT: return Solution(solution.status, opt_val, primal_vars, dual_vars, solution.attr) # Split vectorized variable into components. x_opt = list(solution.primal_vars.values())[0] for var_id, offset in var_map.items(): shape = inverse_data.var_shapes[var_id] size = np.prod(shape, dtype=int) primal_vars[var_id] = np.reshape(x_opt[offset:offset + size], shape, order='F') # Remap dual variables if dual exists (problem is convex). if solution.dual_vars is not None: # Giant dual variable. dual_var = list(solution.dual_vars.values())[0] offset = 0 for constr in inverse_data.constraints: # QP constraints can only have one argument. dual_vars[constr.id] = np.reshape( dual_var[offset:offset + constr.args[0].size], constr.args[0].shape, order='F') offset += constr.size # Add constant part if inverse_data.minimize: opt_val += inverse_data.r else: opt_val -= inverse_data.r return Solution(solution.status, opt_val, primal_vars, dual_vars, solution.attr)
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} else: primal_vars = None dual_vars = None opt_val = np.inf if status == s.UNBOUNDED: opt_val = -np.inf return Solution(status, opt_val, primal_vars, dual_vars, attr)
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)
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.is_mip \ else 0 status = self.STATUS_MAP.get(model.solution.get_status(), s.SOLVER_ERROR) if status in s.SOLUTION_PRESENT: # Get objective value opt_val = model.solution.get_objective_value() # Get solution x = np.array(model.solution.get_values()) primal_vars = { list(inverse_data.id_map.keys())[0]: intf.DEFAULT_INTF.const_to_matrix(np.array(x)) } # Only add duals if not a MIP. dual_vars = None if not inverse_data.is_mip: y = -np.array(model.solution.get_dual_values()) dual_vars = utilities.get_dual_values( intf.DEFAULT_INTF.const_to_matrix(y), utilities.extract_dual_value, inverse_data.sorted_constraints) else: primal_vars = None dual_vars = None opt_val = np.inf if status == s.UNBOUNDED: opt_val = -np.inf return Solution(status, opt_val, primal_vars, dual_vars, attr)
def invert(self, solution, inverse_data): attr = {s.SOLVE_TIME: solution.info.run_time} # 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 else: primal_vars = None dual_vars = None opt_val = np.inf if status == s.UNBOUNDED: opt_val = -np.inf return Solution(status, opt_val, primal_vars, dual_vars, attr)
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) # Start populating attribute dictionary attr = {s.SOLVE_TIME: model.Runtime, s.NUM_ITERS: model.BarIterCount} # Map GUROBI statuses back to CVXPY statuses status = self.STATUS_MAP.get(model.Status, s.SOLVER_ERROR) if status in s.SOLUTION_PRESENT: opt_val = model.objVal x = np.array([x_grb[i].X for i in range(n)]) primal_vars = { list(inverse_data.id_map.keys())[0]: intf.DEFAULT_INTF.const_to_matrix(np.array(x)) } # Only add duals if not a MIP. dual_vars = None if not inverse_data.is_mip: y = -np.array([constraints_grb[i].Pi for i in range(m)]) dual_vars = utilities.get_dual_values( intf.DEFAULT_INTF.const_to_matrix(y), utilities.extract_dual_value, inverse_data.sorted_constraints) else: primal_vars = None dual_vars = None opt_val = np.inf if status == s.UNBOUNDED: opt_val = -np.inf return Solution(status, opt_val, primal_vars, dual_vars, attr)
def invert(self, solution, inverse_data): pvars = {} dvars = {} if solution.status in s.SOLUTION_PRESENT: for vid, var in list(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] imag_val = solution.primal_vars[imag_id] pvars[vid] = solution.primal_vars[vid] + \ 1j*(imag_val - imag_val.T)/2 elif var.is_complex(): imag_id = inverse_data.real2imag[vid] pvars[vid] = solution.primal_vars[vid] + \ 1j*solution.primal_vars[imag_id] for cid, cons in list(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, (Zero, NonPos)) and cons.is_complex(): imag_id = inverse_data.real2imag[cid] dvars[cid] = solution.dual_vars[cid] + \ 1j*solution.dual_vars[imag_id] # 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)
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} else: primal_vars = None dual_vars = None opt_val = np.inf if status == s.UNBOUNDED: opt_val = -np.inf return Solution(status, opt_val, primal_vars, dual_vars, attr)
def invert(self, solution, inverse_data): attr = {s.SOLVE_TIME: solution.info.run_time} # 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 primal_vars = { list(inverse_data.id_map.keys())[0]: intf.DEFAULT_INTF.const_to_matrix(np.array(solution.x)) } dual_vars = utilities.get_dual_values( intf.DEFAULT_INTF.const_to_matrix(solution.y), utilities.extract_dual_value, inverse_data.sorted_constraints) attr[s.NUM_ITERS] = solution.info.iter else: primal_vars = None dual_vars = None opt_val = np.inf if status == s.UNBOUNDED: opt_val = -np.inf return Solution(status, opt_val, primal_vars, dual_vars, attr)