def main():
    x = Variable(1)
    y = Variable(1)
    constraints = [x >= 0, y >= 0, x+y == 1]
    objective = Maximize(square(x) + square(y))
    problem = Problem(objective, constraints)

    print("problem is DCP:", problem.is_dcp())
    print("problem is DCCP:", is_dccp(problem))

    problem.solve(method='dccp')

    print('solution (x,y): ', x.value, y.value)
Example #2
0
    def fit(self, X, y, x_sensitive, **cons_params):
        """
            X: n x d array
            y: n length vector
            x_sensitive: n length vector
            cons_params will be a dictionary
            cons_params["tau"], cons_params["mu"] and cons_params["EPS"] are the solver related parameters. Check DCCP documentation for details
            cons_params["cons_type"] specified which type of constraint to apply
                - cons_type = -1: No constraint
                - cons_type = 0: Parity
                - cons_type = 1: Preferred impact
                - cons_type = 2: Preferred treatment
                - cons_type = 3: Preferred both

            cons_params["s_val_to_cons_sum"]: The ramp approximation -- only needed for cons_type 1 and 3
        """

        n, d = X.shape
        group_labels = set(x_sensitive)

        intercept_idx = INTERCEPT_IDX
        coefficient_idx = np.arange(d)
        coefficient_idx = coefficient_idx[coefficient_idx != intercept_idx]

        self._group_labels = group_labels
        self._intercept_idx = intercept_idx
        self._coefficient_idx = coefficient_idx
        self._n = n
        self._d = d

        if self.train_multiple:
            if isinstance(self.lam, float):
                self.lam = {z: float(self.lam) for z in group_labels}

            assert isinstance(self.lam, dict)
            assert group_labels == self.lam.keys()

        assert isinstance(cons_params, dict)
        cons_type = cons_params.get('cons_type', self.CONSTRAINT_NONE)
        assert cons_type in CoupledRiskMinimizer.VALID_CONSTRAINTS

        if self.loss_function == CoupledRiskMinimizer.LOSS_LOGISTIC:
            solver_settings = {
                'method': 'dccp',
                'verbose': cons_params.get('print_flag', False),
                'max_iters': cons_params.get('max_iters',
                                             100),  # for CVXPY convex solver
                'max_iter': cons_params.get(
                    'max_iter', 50
                ),  # for the dccp. notice that DCCP hauristic runs the convex program iteratively until arriving at the solution
                'mu': cons_params.get('MU', self.MU),
                'tau': cons_params.get('TAU', self.TAU),
                'tau_max': 1e10,
                'feastol': cons_params.get('EPS', self.EPS),
                'abstol': cons_params.get('EPS', self.EPS),
                'reltol': cons_params.get('EPS', self.EPS),
                'feastol_inacc': cons_params.get('EPS', self.EPS),
                'abstol_inacc': cons_params.get('EPS', self.EPS),
                'reltol_inacc': cons_params.get('EPS', self.EPS),
            }
        else:
            solver_settings = {}

        ### setup optimization problem
        obj = 0
        np.random.seed(self.random_state
                       )  # set the seed before initializing the values of w

        if self.train_multiple:
            w = {}
            for k in group_labels:
                idx = x_sensitive == k

                # setup coefficients and initialize as uniform distribution over [0,1]
                w[k] = cp.Variable(d)
                w[k].value = np.random.rand(d)

                # first term in w is the intercept, so no need to regularize that
                obj += cp.sum_squares(w[k][coefficient_idx]) * self.lam[k]

                # setup
                X_k, y_k = X[idx], y[idx]

                if self.sparse_formulation:
                    XY = np.concatenate((X_k, y_k[:, np.newaxis]), axis=1)
                    UY, counts = np.unique(XY, return_counts=True, axis=0)
                    pos_idx = np.greater(UY[:, -1], 0)
                    neg_idx = np.logical_not(pos_idx)
                    U = UY[:, 0:d]
                    obj_weights_pos = counts[pos_idx] / float(n)
                    Z_pos = -U[pos_idx, :]

                    obj_weights_neg = counts[neg_idx] / float(n)
                    Z_neg = U[neg_idx, :]

                    if self.loss_function == CoupledRiskMinimizer.LOSS_LOGISTIC:
                        obj += cp.sum(
                            cp.multiply(obj_weights_pos,
                                        cp.logistic(Z_pos * w[k])))
                        obj += cp.sum(
                            cp.multiply(obj_weights_neg,
                                        cp.logistic(Z_neg * w[k])))

                    elif self.loss_function == CoupledRiskMinimizer.LOSS_SVM:
                        obj += cp.sum(
                            cp.multiply(obj_weights_pos,
                                        cp.pos(1.0 - Z_pos * w[k])))
                        obj += cp.sum(
                            cp.multiply(obj_weights_neg,
                                        cp.pos(1.0 + Z_neg * w[k])))

                else:

                    if self.loss_function == CoupledRiskMinimizer.LOSS_LOGISTIC:
                        obj += cp.sum(
                            cp.logistic(cp.multiply(-y_k,
                                                    X_k * w[k]))) / float(n)

                    elif self.loss_function == CoupledRiskMinimizer.LOSS_SVM:
                        obj += cp.sum(
                            cp.pos(1.0 -
                                   cp.multiply(y_k, X_k * w[k]))) / float(n)

                # notice that we are dividing by the length of the whole dataset, and not just of this sensitive group.
                # this way, the group that has more people contributes more to the loss

        else:
            w = cp.Variable(d)  # this is the weight vector
            w.value = np.random.rand(d)

            # regularizer -- first term in w is the intercept, so no need to regularize that
            obj += cp.sum_squares(w[1:]) * self.lam

            if self.loss_function == self.LOSS_LOGISTIC:
                obj += cp.sum(cp.logistic(cp.multiply(-y, X * w))) / float(n)

            elif self.loss_function == self.LOSS_SVM:
                obj += cp.sum(cp.maximum(
                    0.0, 1.0 - cp.multiply(y, X * w))) / float(n)

        constraints = []
        if cons_type in self.VALID_PREFERED_CONSTRAINTS:
            constraints = self._stamp_preference_constraints(
                X, x_sensitive, w, cons_type,
                cons_params.get('s_val_to_cons_sum'))

        elif cons_type == self.CONSTRAINT_PARITY:
            constraints = self._stamp_disparate_impact_constraint(
                X, y, x_sensitive, w, cov_thresh=np.abs(0.0))

        prob = cp.Problem(cp.Minimize(obj), constraints)

        ### solve optimization problem
        if is_dccp(prob):
            print("solving disciplined convex-concave program (DCCP)")
        else:
            assert prob.is_dcp()
            print("solving disciplined convex program (DCP)")

        prob.solve(**solver_settings)

        print("solver stopped (status: %r)" % prob.status)
        if prob.status != cp.OPTIMAL:
            warnings.warn('solver did not recover optimal solution')

        # check that the fairness constraint is satisfied
        for f_c in constraints:
            if not f_c.value:
                warnings.warn("fairness constraint %r not satisfied!" % f_c)

        self._prob = prob

        # store results
        if self.train_multiple:
            coefs = {k: np.array(w[k].value).flatten() for k in group_labels}
            self.w = {k: np.array(v) for k, v in coefs.items()}
        else:
            coefs = np.array(w.value).flatten()
            self.w = np.array(coefs)

        return coefs
Example #3
0
__author__ = 'Xinyue'
from cvxpy import *
import dccp
from dccp.problem import is_dccp

x = Variable(2)
y = Variable(2)
myprob = Problem(Maximize(norm(x-y,2)), [0<=x, x<=1, 0<=y, y<=1])
#myprob = Problem(Minimize(log(x)), [x**2 >= 5])
print "problem is DCP:", myprob.is_dcp()   # false
print "problem is DCCP:", is_dccp(myprob)  # true
result = myprob.solve(method = 'dccp', solver = 'SCS', use_indirect = False, warm_start = True)
print "========================"
print "x =", x.value
print "y =", y.value
print "cost value =", result[0]
print myprob.status
Example #4
0
File: test.py Project: cvxgrp/dccp
__author__ = 'Xinyue'
from cvxpy import *
import dccp
from dccp.problem import is_dccp
import matplotlib.pyplot as plt

x = Variable(2)
y = Variable(2)
myprob = Problem(Maximize(norm(x-y,2)), [0<=x, x<=1, 0<=y, y<=1])
#myprob = Problem(Minimize(log(x)), [x**2 >= 5])
print "problem is DCP:", myprob.is_dcp()   # false
print "problem is DCCP:", is_dccp(myprob)  # true
result = myprob.solve(method = 'dccp')
print "========================"
print "x =", x.value
print "y =", y.value
print "cost value =", result[0]