def var_cone_canon(expr, args): """Expand implicit constraints on variable. """ # Convert attributes into constraints. new_attr = expr.attributes.copy() for key in ['nonneg', 'nonpos', 'symmetric', 'PSD', 'NSD']: if new_attr[key]: new_attr[key] = False if expr.is_symmetric(): n = expr.shape[0] shape = (n * (n + 1) // 2, 1) upper_tri = Variable(shape, var_id=expr.id, **new_attr) fill_coeff = Constant(upper_tri_to_full(n)) full_mat = fill_coeff * upper_tri obj = reshape(full_mat, (n, n)) else: obj = Variable(expr.shape, var_id=expr.id, **new_attr) constr = [] if expr.is_nonneg(): constr.append(obj >= 0) elif expr.is_nonpos(): constr.append(obj <= 0) elif expr.attributes['PSD']: constr.append(obj >> 0) elif expr.attributes['NSD']: constr.append(obj << 0) return (obj, constr)
def apply(self, problem): if not attributes_present(problem.variables(), CONVEX_ATTRIBUTES): return problem, () # For each unique variable, add constraints. id2new_var = {} id2new_obj = {} id2old_var = {} constr = [] for var in problem.variables(): if var.id not in id2new_var: id2old_var[var.id] = var new_var = False new_attr = var.attributes.copy() for key in CONVEX_ATTRIBUTES: if new_attr[key]: new_var = True new_attr[key] = False if attributes_present([var], SYMMETRIC_ATTRIBUTES): n = var.shape[0] shape = (n*(n+1)//2, 1) upper_tri = Variable(shape, var_id=var.id, **new_attr) upper_tri.set_variable_of_provenance(var) id2new_var[var.id] = upper_tri fill_coeff = Constant(upper_tri_to_full(n)) full_mat = fill_coeff @ upper_tri obj = reshape(full_mat, (n, n)) elif var.attributes['diag']: diag_var = Variable(var.shape[0], var_id=var.id, **new_attr) diag_var.set_variable_of_provenance(var) id2new_var[var.id] = diag_var obj = diag(diag_var) elif new_var: obj = Variable(var.shape, var_id=var.id, **new_attr) obj.set_variable_of_provenance(var) id2new_var[var.id] = obj else: obj = var id2new_var[var.id] = obj id2new_obj[id(var)] = obj if var.is_pos() or var.is_nonneg(): constr.append(obj >= 0) elif var.is_neg() or var.is_nonpos(): constr.append(obj <= 0) elif var.is_psd(): constr.append(obj >> 0) elif var.attributes['NSD']: constr.append(obj << 0) # Create new problem. obj = problem.objective.tree_copy(id_objects=id2new_obj) cons_id_map = {} for cons in problem.constraints: constr.append(cons.tree_copy(id_objects=id2new_obj)) cons_id_map[cons.id] = constr[-1].id inverse_data = (id2new_var, id2old_var, cons_id_map) return cvxtypes.problem()(obj, constr), inverse_data