def _bcd(prob, fix_sets, max_iter, solver, mu, rho, mu_max, ep, lambd, linear, proximal): """ block coordinate descent :param prob: Problem :param max_iter: maximum number of iterations :param solver: solver used to solved each fixed problem :return: it: number of iterations; max_slack: maximum slack variable """ obj_pre = np.inf for it in range(max_iter): np.random.shuffle(fix_sets) #print "======= iteration", it, "=======" for subset in fix_sets: problem_variables = prob.variables() problem_variables.sort(key=lambda x: x.id) fix_var = [prob.variables()[idx] for idx in subset] # fix variables in fix_set fixed_p = fix(prob, fix_var) # linearize if linear: fixed_p_obj = cvx.linearize(fixed_p.objective.expr) fixed_p_constr = fixed_p.constraints if fixed_p.objective.NAME == 'minimize': fixed_p = cvx.Problem(cvx.Minimize(fixed_p_obj), fixed_p_constr) else: fixed_p = cvx.Problem(cvx.Maximize(fixed_p_obj), fixed_p_constr) # add slack variables fixed_p, var_slack = add_slack(fixed_p, mu) # proximal operator if proximal: fixed_p = proximal_op(fixed_p, var_slack, lambd) # solve fixed_p.solve(solver=solver) max_slack = 0 if not var_slack == []: max_slack = np.max( [np.max(np.abs(var.value)) for var in var_slack]) print("max abs slack =", max_slack, "mu =", mu, "original objective value =", prob.objective.args[0].value, "fixed objective value =", fixed_p.objective.args[0].value, "status=", fixed_p.status) else: print("original objective value =", prob.objective.args[0].value, "status=", fixed_p.status) mu = min(mu * rho, mu_max) # adaptive mu if np.linalg.norm(obj_pre - prob.objective.expr.value ) <= ep and max_slack <= ep: # quit return it, max_slack else: obj_pre = prob.objective.args[0].value return it, max_slack
def is_dmcp(obj): """ :param obj: an obj :return: a boolean indicating if the obj (Function, Expression, Variable) is DMCP """ for var in obj.variables(): fix_var = [avar for avar in obj.variables() if not avar.id == var.id] fix_var.sort(key=lambda x: x.id) if not fix(obj, fix_var).is_dcp(): return False return True
def test_fixExpr(self): ''' Tests whether or not the fix variable function works for expressions. ''' # Define expression expr = cvx.abs(self.x1 + self.x1 + self.x2 + self.x3 + self.x4) # Fix variables and get list of parameters new_expr = fix(expr, self.fix_vars) list_params = new_expr.parameters() # Assertion test # 2 variables since fix_vars has 2 elements self.assertEqual(len(list_params), 2)
def find_MIS(prob, is_all): """ find maximal independent sets of a graph until all vertices are included :param prob: a problem :param is_all: to find all minimal sets or not :return: a list of maximal independent sets """ if prob.is_dcp(): return [prob.variables()] # graph of conflict vars V = prob.variables() node_num = len(V) g = np.zeros((node_num, node_num)) # table of edges varid = [var.id for var in V] varid.sort() stack, g = search_conflict_l(prob.objective.expr, [], varid, g) for con in prob.constraints: stack, g = search_conflict_l(-con.expr, [], varid, g) # find all independent sets of the conflict graph i_subsets = find_all_iset(V, g) # sort all independent sets subsets_len = [len(subset) for subset in i_subsets] sort_idx = np.argsort(subsets_len) # sort the subsets by card # check all sorted sets result = [] U = [] # union of all collected vars # collecting from a subset with the largest cardinality for count in range(1, len(sort_idx) + 1): flag = 1 for subs in result: if is_subset( i_subsets[sort_idx[-count]], subs ): # the current one is a subset of a previously collected one flag = 0 break if flag: set_id = [var.id for var in i_subsets[sort_idx[-count]]] fix_set = [var for var in V if var.id not in set_id] if fix(prob, fix_set).is_dcp(): result.append(i_subsets[sort_idx[-count]]) U = union(U, i_subsets[sort_idx[-count]]) # break if the collected vars cover all vars if not is_all and is_subset(V, U): break return result
def test_fixProb(self): ''' Tests whether or not the fix variable function works for problems/ ''' # Define problem obj = cvx.Minimize(cvx.abs(self.x1*self.x2 + self.x3*self.x4)) constr = [self.x1 + self.x2 + self.x3 + self.x4 == 1] prob = cvx.Problem(obj, constr) # Fix variables and get list of parameters new_prob = fix(prob, self.fix_vars) list_params = new_prob.parameters() # Assertion test # 2 variables since x1 and x3 for both objective and constraints are fixed self.assertEqual(len(list_params), 2)
def test_fixPSD(self): ''' Tests whether or not the fix variable function works for problems/ ''' # Define problem x = cvx.Variable((4,4), PSD=True) obj = cvx.Minimize(cvx.norm(x)) constr = [x >> 0] prob = cvx.Problem(obj, constr) # Fix variables and get list of parameters new_prob = fix(prob, [x]) list_params = new_prob.parameters() # Assertion test # 1 variable since x is a single symmetric positive semi-definite matrix self.assertEqual(len(list_params), 1)
def find_dcp_maxset(expr, vars, current=[]): """ find maximal subsets of variables, so that expr is a dcp expression within each subset :param expr: an expression :param vars: variables that are not fixed :param current: current list of subsets :return: a list of subsets of variables and each subset is a list, or None """ if expr.is_dcp(): return [expr.variables()] result = [] next_level = [] for var in vars: vars_active = erase(vars, var) # active variables if vars_active == []: # an empty list indicates that the expression is not multi-dcp return None # if the set of active vars is not a subset of the current result if all([ not is_subset(vars_active, current_set) for current_set in current ]): vars_active_id = [var.id for var in vars_active] fix_vars_temp = [ var for var in expr.variables() if not var.id in vars_active_id ] if fix(expr, fix_vars_temp).is_dcp() == True: result.append(vars_active) # find a subset current.append(vars_active) else: next_level.append( vars_active) # to be decomposed in the next level for set in next_level: result_temp = find_dcp_maxset(expr, set, current) if result_temp is None: return None else: for set in result_temp: result.append(set) return result
def find_maxset_prob(prob, vars, current=[]): """ Analyze a problem to find maximal subsets of variables, so that the problem is dcp restricting on each subset :param prob: Problem :return: a list of subsets of Variables, or None """ if prob.is_dcp(): return [prob.variables()] result = [] next_level = [] for var in vars: vars_active = erase(vars, var) # active variables if vars_active == []: # an empty list indicates that the problem is not multi-convex return None # if the set of active vars is not a subset of the current result if all([ not is_subset(vars_active, current_set) for current_set in current ]): vars_active_id = [var.id for var in vars_active] fix_vars_temp = [ var for var in prob.variables() if not var.id in vars_active_id ] if fix(prob, fix_vars_temp).is_dcp() == True: result.append(vars_active) # find a subset current.append(vars_active) else: next_level.append( vars_active) # to be decomposed in the next level for set in next_level: result_temp = find_maxset_prob(prob, set, current) if result_temp is None: return None else: for set in result_temp: result.append(set) return result
def find_dcp_set(expr, vars): """ find subsets of variables, so that expr is a dcp expression within each subset :param expr: :param vars: variables that are not fixed :return: a list of lists of variables, or None """ if vars == []: # an empty list indicates that the expression is not multi-dcp return None vars_id = [var.id for var in vars] fix_vars = [var for var in expr.variables() if not var.id in vars_id] if fix(expr, fix_vars).is_dcp() == True: return [vars] else: result = [] for var in vars: # erase each variable from vars vars_temp = erase(vars, var) # active variables result_temp = find_dcp_set(expr, vars_temp) if result_temp is None: return None for var_set in result_temp: result.append(var_set) return result