Esempio n. 1
0
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
Esempio n. 2
0
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
Esempio n. 3
0
    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)
Esempio n. 4
0
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
Esempio n. 5
0
    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)
Esempio n. 6
0
    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)
Esempio n. 7
0
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
Esempio n. 8
0
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
Esempio n. 9
0
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