def test_psd_constraints(self): """ Test positive semi-definite constraints """ C = Variable((3, 3)) obj = Maximize(C[0, 2]) constraints = [ diag(C) == 1, C[0, 1] == 0.6, C[1, 2] == -0.3, C == C.T, C >> 0 ] prob = Problem(obj, constraints) self.assertTrue(FlipObjective().accepts(prob)) p_min = FlipObjective().apply(prob) self.assertTrue(ConeMatrixStuffing().accepts(p_min[0])) C = Variable((2, 2)) obj = Maximize(C[0, 1]) constraints = [C == 1, C >> [[2, 0], [0, 2]]] prob = Problem(obj, constraints) self.assertTrue(FlipObjective().accepts(prob)) p_min = FlipObjective().apply(prob) self.assertTrue(ConeMatrixStuffing().accepts(p_min[0])) C = Variable((2, 2), symmetric=True) obj = Minimize(C[0, 0]) constraints = [C << [[2, 0], [0, 2]]] prob, _ = CvxAttr2Constr().apply(Problem(obj, constraints)) self.assertTrue(ConeMatrixStuffing().accepts(prob))
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