Exemple #1
0
def getqconstrmultipliers(cplex, tol):
    qpi = dict()

    x = dict(zip(cplex.variables.get_names(),
                 cplex.solution.get_values()))

    # Helper function to map a variable index to a variable name
    v2name = lambda x: cplex.variables.get_names(x)

    for q in cplex.quadratic_constraints.get_names():
        # 'dense' is the dense slack vector
        dense = dict(zip(cplex.variables.get_names(),
                         [0] * cplex.variables.get_num()))
        grad = dict(zip(cplex.variables.get_names(),
                        [0] * cplex.variables.get_num()))
        qdslack = cplex.solution.get_quadratic_dualslack(q)
        for (var, val) in zip(map(v2name, qdslack.ind), qdslack.val):
            dense[var] = val

        # Compute value of derivative at optimal solution.
        # The derivative of a quadratic constraint x^TQx + a^Tx + b <= 0
        # is Q^Tx + Qx + a.
        conetop = True
        quad = cplex.quadratic_constraints.get_quadratic_components(q)
        for (row, col, val) in zip(map(v2name, quad.ind1),
                                   map(v2name, quad.ind2),
                                   quad.val):
            if fabs(x[row]) > tol or fabs(x[col]) > tol:
                conetop = False
            grad[row] += val * x[col]
            grad[col] += val * x[row]
        l = cplex.quadratic_constraints.get_linear_components(q)
        for (var, val) in zip(map(v2name, l.ind), l.val):
            grad[var] += val
            if fabs(x[var]) > tol:
                conetop = False

        if conetop:
            raise Exception("Cannot compute dual multiplier at cone top!")

        # Compute qpi[q] as slack/gradient.
        # We may have several indices to choose from and use the one
        # with largest absolute value in the denominator.
        ok = False
        maxabs = -1.0
        for v in cplex.variables.get_names():
            if fabs(grad[v]) > tol:
                if fabs(grad[v]) > maxabs:
                    qpi[q] = dense[v] / grad[v]
                    maxabs = fabs(grad[v])
                ok = True

        if not ok:
            qpi[q] = 0

    return qpi
Exemple #2
0
def getqconstrmultipliers(cplex, tol):
    qpi = dict()

    x = dict(zip(cplex.variables.get_names(), cplex.solution.get_values()))

    # Helper function to map a variable index to a variable name
    def v2name(x):
        return cplex.variables.get_names(x)

    for q in cplex.quadratic_constraints.get_names():
        # 'dense' is the dense slack vector
        dense = dict(
            zip(cplex.variables.get_names(), [0] * cplex.variables.get_num()))
        grad = dict(
            zip(cplex.variables.get_names(), [0] * cplex.variables.get_num()))
        qdslack = cplex.solution.get_quadratic_dualslack(q)
        for (var, val) in zip(map(v2name, qdslack.ind), qdslack.val):
            dense[var] = val

        # Compute value of derivative at optimal solution.
        # The derivative of a quadratic constraint x^TQx + a^Tx + b <= 0
        # is Q^Tx + Qx + a.
        conetop = True
        quad = cplex.quadratic_constraints.get_quadratic_components(q)
        for (row, col, val) in zip(map(v2name, quad.ind1),
                                   map(v2name, quad.ind2), quad.val):
            if fabs(x[row]) > tol or fabs(x[col]) > tol:
                conetop = False
            grad[row] += val * x[col]
            grad[col] += val * x[row]
        l = cplex.quadratic_constraints.get_linear_components(q)
        for (var, val) in zip(map(v2name, l.ind), l.val):
            grad[var] += val
            if fabs(x[var]) > tol:
                conetop = False

        if conetop:
            raise Exception("Cannot compute dual multiplier at cone top!")

        # Compute qpi[q] as slack/gradient.
        # We may have several indices to choose from and use the one
        # with largest absolute value in the denominator.
        ok = False
        maxabs = -1.0
        for v in cplex.variables.get_names():
            if fabs(grad[v]) > tol:
                if fabs(grad[v]) > maxabs:
                    qpi[q] = dense[v] / grad[v]
                    maxabs = fabs(grad[v])
                ok = True

        if not ok:
            qpi[q] = 0

    return qpi
Exemple #3
0
def qcpdual():
    # ###################################################################### #
    #                                                                        #
    #    S E T U P   P R O B L E M                                           #
    #                                                                        #
    # ###################################################################### #
    c = cplex.Cplex()
    c.variables.add(obj=Data.obj, lb=Data.lb, ub=Data.ub, names=Data.cname)
    c.linear_constraints.add(lin_expr=Data.rows,
                             senses=Data.sense,
                             rhs=Data.rhs,
                             names=Data.rname)
    for q in range(0, len(Data.qname)):
        c.quadratic_constraints.add(lin_expr=Data.qlin[q],
                                    quad_expr=Data.quad[q],
                                    sense=Data.qsense[q],
                                    rhs=Data.qrhs[q],
                                    name=Data.qname[q])

    # ###################################################################### #
    #                                                                        #
    #    O P T I M I Z E   P R O B L E M                                     #
    #                                                                        #
    # ###################################################################### #
    c.parameters.barrier.qcpconvergetol.set(1e-10)
    c.solve()
    if not c.solution.get_status() == c.solution.status.optimal:
        raise Exception("No optimal solution found")

    # ###################################################################### #
    #                                                                        #
    #    Q U E R Y   S O L U T I O N                                         #
    #                                                                        #
    # ###################################################################### #
    # We store all results in a dictionary so that we can easily access
    # them by name.
    # Optimal solution and slacks for linear and quadratic constraints.
    x = dict(zip(c.variables.get_names(), c.solution.get_values()))
    slack = dict(
        zip(c.linear_constraints.get_names(), c.solution.get_linear_slacks()))
    qslack = dict(
        zip(c.quadratic_constraints.get_names(),
            c.solution.get_quadratic_slacks()))
    # Dual multipliers for constraints.
    cpi = dict(zip(c.variables.get_names(), c.solution.get_reduced_costs()))
    rpi = dict(
        zip(c.linear_constraints.get_names(), c.solution.get_dual_values()))
    qpi = getqconstrmultipliers(c, ZEROTOL)

    # Some CPLEX functions return results by index instead of by name.
    # Define a function that translates from index to name.
    v2name = lambda x: c.variables.get_names(x)

    # ###################################################################### #
    #                                                                        #
    #    C H E C K   K K T   C O N D I T I O N S                             #
    #                                                                        #
    #    Here we verify that the optimal solution computed by CPLEX (and     #
    #    the qpi[] values computed above) satisfy the KKT conditions.        #
    #                                                                        #
    # ###################################################################### #

    # Primal feasibility: This example is about duals so we skip this test. #

    # Dual feasibility: We must verify
    # - for <= constraints (linear or quadratic) the dual
    #   multiplier is non-positive.
    # - for >= constraints (linear or quadratic) the dual
    #   multiplier is non-negative.
    for r in c.linear_constraints.get_names():
        if c.linear_constraints.get_senses(r) == 'E':
            pass
        elif c.linear_constraints.get_senses(r) == 'R':
            pass
        elif c.linear_constraints.get_senses(r) == 'L':
            if rpi[r] > ZEROTOL:
                raise Exception("Dual feasibility test failed")
        elif c.linear_constraints.get_senses(r) == 'G':
            if rpi[r] < -ZEROTOL:
                raise Exception("Dual feasibility test failed")
    for q in c.quadratic_constraints.get_names():
        if c.quadratic_constraints.get_senses(q) == 'E':
            pass
        elif c.quadratic_constraints.get_senses(q) == 'L':
            if qpi[q] > ZEROTOL:
                raise Exception("Dual feasibility test failed")
        elif c.quadratic_constraints.get_senses(q) == 'G':
            if qpi[q] < -ZEROTOL:
                raise Exception("Dual feasibility test failed")

    # Complementary slackness.
    # For any constraint the product of primal slack and dual multiplier
    # must be 0.
    for r in c.linear_constraints.get_names():
        if ((not c.linear_constraints.get_senses(r) == 'E')
                and fabs(slack[r] * rpi[r]) > ZEROTOL):
            raise Exception("Complementary slackness test failed")
    for q in c.quadratic_constraints.get_names():
        if ((not c.quadratic_constraints.get_senses(q) == 'E')
                and fabs(qslack[q] * qpi[q]) > ZEROTOL):
            raise Exception("Complementary slackness test failed")
    for j in c.variables.get_names():
        if c.variables.get_upper_bounds(j) < cplex.infinity:
            slk = c.variables.get_upper_bounds(j) - x[j]
            if cpi[j] < -ZEROTOL:
                dual = cpi[j]
            else:
                dual = 0.0
            if fabs(slk * dual) > ZEROTOL:
                raise Exception("Complementary slackness test failed")
        if c.variables.get_lower_bounds(j) > -cplex.infinity:
            slk = x[j] - c.variables.get_lower_bounds(j)
            if cpi[j] > ZEROTOL:
                dual = cpi[j]
            else:
                dual = 0.0
            if fabs(slk * dual) > ZEROTOL:
                raise Exception("Complementary slackness test failed")

    # Stationarity.
    # The difference between objective function and gradient at optimal
    # solution multiplied by dual multipliers must be 0, i.e., for the
    # optimal solution x
    # 0 == c
    #      - sum(r in rows)  r'(x)*rpi[r]
    #      - sum(q in quads) q'(x)*qpi[q]
    #      - sum(c in cols)  b'(x)*cpi[c]
    # where r' and q' are the derivatives of a row or quadratic constraint,
    # x is the optimal solution and rpi[r] and qpi[q] are the dual
    # multipliers for row r and quadratic constraint q.
    # b' is the derivative of a bound constraint and cpi[c] the dual bound
    # multiplier for column c.

    # Objective function
    kktsum = dict(zip(c.variables.get_names(), c.objective.get_linear()))

    # Linear constraints.
    # The derivative of a linear constraint ax - b (<)= 0 is just a.
    for r in c.linear_constraints.get_names():
        row = c.linear_constraints.get_rows(r)
        for (var, val) in zip(map(v2name, row.ind), row.val):
            kktsum[var] -= rpi[r] * val
    # Quadratic constraints.
    # The derivative of a constraint xQx + ax - b <= 0 is
    # Qx + Q'x + a.
    for q in c.quadratic_constraints.get_names():
        lin = c.quadratic_constraints.get_linear_components(q)
        for (var, val) in zip(map(v2name, lin.ind), lin.val):
            kktsum[var] -= qpi[q] * val
        quad = c.quadratic_constraints.get_quadratic_components(q)
        for (row, col, val) in zip(map(v2name, quad.ind1),
                                   map(v2name, quad.ind2), quad.val):
            kktsum[row] -= qpi[q] * x[col] * val
            kktsum[col] -= qpi[q] * x[row] * val

    # Bounds.
    # The derivative for lower bounds is -1 and that for upper bounds
    # is 1.
    # CPLEX already returns dj with the appropriate sign so there is
    # no need to distinguish between different bound types here.
    for v in c.variables.get_names():
        kktsum[v] -= cpi[v]

    for v in c.variables.get_names():
        if fabs(kktsum[v]) > ZEROTOL:
            raise Exception("Stationarity test failed")

    # KKT conditions satisfied. Dump out solution and dual values.
    print("Optimal solution satisfies KKT conditions.")
    print("  x[] = [", end=' ')
    for n in c.variables.get_names():
        print(" %7.3f" % x[n], end=' ')
    print(" ]")
    print("cpi[] = [", end=' ')
    for n in c.variables.get_names():
        print(" %7.3f" % cpi[n], end=' ')
    print(" ]")
    print("rpi[] = [", end=' ')
    for n in c.linear_constraints.get_names():
        print(" %7.3f" % rpi[n], end=' ')
    print(" ]")
    print("qpi[] = [", end=' ')
    for n in c.quadratic_constraints.get_names():
        print(" %7.3f" % qpi[n], end=' ')
    print(" ]")
Exemple #4
0
def Chebyshev_CG(w):

    ######### Master Problem ###########

    M = cplex.Cplex()

    # Parameters
    var = list(range(len(w)))
    alpha = 1.0
    init_pi = sum(w) / 150
    epsilon = 0.1

    # decision varialbes types=["C"]*len(var)
    M.variables.add(obj=[1] * len(var), names=['x_' + str(i) for i in var])
    M.variables.add(obj=[-init_pi], names='z')
    M.variables.add(names=['y_' + str(i) for i in list(range(len(w)))])

    # pattern constraints
    vals = np.zeros((len(w), len(var)))

    np.fill_diagonal(vals, 1)

    M.linear_constraints.add(lin_expr=[
        cplex.SparsePair(ind=['x_' + str(j)
                              for j in var] + ['y_' + str(i)] + ['z'],
                         val=list(vals[i]) + [-1.0] + [-1.0])
        for i in range(len(w))
    ],
                             senses=["G" for i in w],
                             rhs=[0 for i in w])

    # chebyshev constraint
    M.linear_constraints.add(lin_expr=[
        cplex.SparsePair(
            ind=['x_' + str(j)
                 for j in var] + ['y_' + str(i)
                                  for i in range(len(w))] + ['z'],
            val=[1.0 for k in var] + [1.0 for l in w] + [alpha * 120**(1 / 2)])
    ],
                             senses=["G"],
                             rhs=[1.0])

    #list(np.linalg.norm(vals,1))

    # set objective
    M.objective.set_sense(M.objective.sense.minimize)

    ######### Separation Problem ###########
    S = cplex.Cplex()

    S.variables.add(types=[S.variables.type.integer] * len(w),
                    obj=[1] * len(w))

    totalsize = SparsePair(ind=list(range(len(w))), val=w)
    S.linear_constraints.add(lin_expr=[totalsize], senses=["L"], rhs=[150])

    S.objective.set_sense(S.objective.sense.maximize)

    ite = 0
    while True:
        ite += 1
        M.write('cheby_m.lp')

        M.set_log_stream(None)
        M.set_error_stream(None)
        M.set_warning_stream(None)
        M.set_results_stream(None)
        M.solve()

        price = [
            pie for pie in M.solution.get_dual_values(list(range(len(w))))
        ]
        S.objective.set_linear(list(zip(list(range(len(w))), price)))
        S.write('cheby_s.lp')
        S.set_log_stream(None)
        S.set_error_stream(None)
        S.set_warning_stream(None)
        S.set_results_stream(None)
        S.solve()

        if M.solution.get_objective_value(
        ) < epsilon * M.solution.get_values('z'):
            break

        if S.solution.get_objective_value() < 1 + 1.0e-6:
            newsub = S.solution.get_values()
            idx = M.variables.get_num()
            M.variables.add(obj=[1.0])
            M.linear_constraints.set_coefficients(
                list(zip(list(range(len(w))), [idx] * len(var), newsub)))
            var.append(idx)

        else:
            new_pi = M.solution.get_dual_values()
            M.objective.set_linear('z', -sum(new_pi))

    M.variables.set_types(
        list(zip(var, [M.variables.type.continuous] * len(var))))
    M.solve()

    return ite, M, S
Exemple #5
0
def General_CG(w):

    M = cplex.Cplex()

    var = list(range(len(w)))

    M.variables.add(obj=[1] * len(var))

    M.linear_constraints.add(lin_expr=[SparsePair()] * len(w),
                             senses=["G"] * len(w),
                             rhs=[1] * len(w))
    for i in range(len(w)):
        M.linear_constraints.set_coefficients(i, i, 1)

    M.objective.set_sense(M.objective.sense.minimize)

    S = cplex.Cplex()

    S.variables.add(types=[S.variables.type.integer] * len(w),
                    obj=[1] * len(w))

    totalsize = SparsePair(ind=list(range(len(w))), val=w)
    S.linear_constraints.add(lin_expr=[totalsize], senses=["L"], rhs=[150])

    S.objective.set_sense(S.objective.sense.maximize)

    ite = 0

    while True:
        ite += 1
        M.write('m.lp')

        M.set_log_stream(None)
        M.set_error_stream(None)
        M.set_warning_stream(None)
        M.set_results_stream(None)
        M.solve()

        price = [
            pie for pie in M.solution.get_dual_values(list(range(len(w))))
        ]
        S.objective.set_linear(list(zip(list(range(len(w))), price)))
        #     S.write('s.lp')
        S.set_log_stream(None)
        S.set_error_stream(None)
        S.set_warning_stream(None)
        S.set_results_stream(None)
        S.solve()

        if S.solution.get_objective_value() < 1 + 1.0e-6:
            break

        newsub = S.solution.get_values()

        idx = M.variables.get_num()
        M.variables.add(obj=[1.0])
        M.linear_constraints.set_coefficients(
            list(zip(list(range(len(w))), [idx] * len(var), newsub)))
        var.append(idx)

    M.variables.set_types(list(zip(var,
                                   [M.variables.type.integer] * len(var))))
    M.solve()

    return ite, M, S
Exemple #6
0
def cutstock(datafile):
    # Input data. If no file is given on the command line then use a
    # default file name. The data read is
    # width  - the width of the the roll,
    # size   - the sie of each strip,
    # amount - the demand for each strip.
    width, size, amount = read_dat_file(datafile)

    # Setup cutting optimization (master) problem.
    # This is the problem to which columns will be added in the loop
    # below.
    cut = cplex.Cplex()
    cutcons = list(range(len(amount)))  # constraint indices
    cutvars = list(range(len(size)))  # variable indices
    cut.variables.add(obj=[1] * len(cutvars))
    # Add constraints. They have empty left-hand side initially. The
    # left-hand side is filled in the next loop.
    cut.linear_constraints.add(lin_expr=[SparsePair()] * len(cutcons),
                               senses=["G"] * len(cutcons),
                               rhs=amount)
    for v in cutvars:
        cut.linear_constraints.set_coefficients(v, v, int(width / size[v]))

    # Setup pattern generation (worker) problem.
    # The constraints and variables in this problem always stay the same
    # but the objective function will change during the column generation
    # loop.
    pat = cplex.Cplex()
    use = list(range(len(size)))  # variable indices
    pat.variables.add(types=[pat.variables.type.integer] * len(use))
    # Add a constant 1 to the objective.
    pat.variables.add(obj=[1], lb=[1], ub=[1])
    # Single constraint: total size must not exceed the width.
    totalsize = SparsePair(ind=use, val=size)
    pat.linear_constraints.add(lin_expr=[totalsize], senses=["L"], rhs=[width])
    pat.objective.set_sense(pat.objective.sense.minimize)

    # Column generation procedure
    while True:

        # Optimize over current patterns
        cut.solve()
        report1(cut)

        # Find and add new pattern. The objective function of the
        # worker problem is constructed from the dual values of the
        # constraints of the master problem.
        price = [-d for d in cut.solution.get_dual_values(cutcons)]
        pat.objective.set_linear(list(zip(use, price)))
        pat.solve()
        report2(pat, use)

        # If reduced cost (worker problem objective function value) is
        # non-negative we are optimal. Otherwise we found a new column
        # to be added. Coefficients of the new column are given by the
        # optimal solution vector to the worker problem.
        if pat.solution.get_objective_value() > -RC_EPS:
            break
        newpat = pat.solution.get_values(use)

        # The new pattern constitutes a new variable in the cutting
        # optimization problem. Create that variable and add it to all
        # constraints with the coefficients read from the optimal solution
        # of the pattern generation problem.
        idx = cut.variables.get_num()
        cut.variables.add(obj=[1.0])
        cut.linear_constraints.set_coefficients(
            list(zip(cutcons, [idx] * len(use), newpat)))
        cutvars.append(idx)

    # Perform a final solve on the cutting optimization problem.
    # Turn all variables into integers before doing that.
    cut.variables.set_types(
        list(zip(cutvars, [cut.variables.type.integer] * len(cutvars))))
    cut.solve()
    report3(cut)
    print("Solution status = ", cut.solution.get_status())
Exemple #7
0
                               rhs = [width])
    pat.objective.set_sense(pat.objective.sense.minimize)

    
    # Column generation procedure
    while True:
        
        # Optimize over current patterns
        cut.solve()
        report1(cut)

        # Find and add new pattern. The objective function of the
        # worker problem is constructed from the dual values of the
        # constraints of the master problem.
        price = [-d for d in cut.solution.get_dual_values(cutcons)]
        pat.objective.set_linear(list(zip(use, price)))
        pat.solve()
        report2(pat, use)

        # If reduced cost (worker problem objective function value) is
        # non-negative we are optimal. Otherwise we found a new column
        # to be added. Coefficients of the new column are given by the
        # optimal solution vector to the worker problem.
        if pat.solution.get_objective_value() > -RC_EPS:
            break
        newpat = pat.solution.get_values(use)

        # The new pattern constitutes a new variable in the cutting
        # optimization problem. Create that variable and add it to all
        # constraints with the coefficients read from the optimal solution
        # of the pattern generation problem.
Exemple #8
0
    def Kelly(self):

        w = self.w
        I = range(len(w))

        M = cplex.Cplex()

        var = list(range(len(w)))

        M.variables.add(obj=[1] * len(var), lb=[0] * len(var))

        M.linear_constraints.add(lin_expr=[SparsePair()] * len(w),
                                 senses=["G"] * len(w),
                                 rhs=[1] * len(w))
        for i in range(len(w)):
            M.linear_constraints.set_coefficients(i, i, 1)

        M.objective.set_sense(M.objective.sense.minimize)
        M.set_log_stream(None)
        M.set_error_stream(None)
        M.set_warning_stream(None)
        M.set_results_stream(None)

        start = time.time()
        mt = 0
        st = 0
        ite = 0
        solutions = []
        iterations = []
        criteria = True

        while criteria:

            ite += 1

            M.set_problem_type(M.problem_type.LP)
            ct = time.time()

            M.solve()
            solutions.append(float(M.solution.get_objective_value()))
            iterations.append(
                float(cplex._internal._procedural.getitcnt(M._env._e, M._lp)))
            mt += time.time() - ct

            pi = list(M.solution.get_dual_values())[:len(w)]
            dual = list(M.solution.get_dual_values())

            v = pi
            W = self.W

            pt = time.time()
            # print(w)

            S_obj, sol = binpacking.KnapsackBnB(v, w, W)

            # print(S_obj, sol)

            st += time.time() - pt

            if S_obj - 0.000001 > 1.:

                criteria = True
                newsub = sol
                idx = M.variables.get_num()
                M.variables.add(obj=[1.0])
                M.linear_constraints.set_coefficients(
                    list(zip(list(range(len(w))), [idx] * len(var), newsub)))

                var.append(idx)
            else:
                criteria = False

        M.set_problem_type(M.problem_type.LP)
        ct = time.time()
        M.solve()
        # M.write('kelly.lp')
        solutions.append(float(M.solution.get_objective_value()))
        iterations.append(
            float(cplex._internal._procedural.getitcnt(M._env._e, M._lp)))
        mt += time.time() - ct
        tt = time.time() - start

        self.Kelly_M = M

        self.Kelly_result = [
            'Kelly', ite, mt, st, tt, mt / (st + mt), solutions,
            np.average(np.array(iterations))
        ]
Exemple #9
0
    def Kelly_CG(self, M, tolerence, var):

        w = self.w

        mt = 0
        st = 0
        ite = 0
        solutions = []
        iterations = []
        criteria = True

        while criteria:

            ite += 1

            M.set_problem_type(M.problem_type.LP)
            ct = time.time()

            M.solve()
            solutions.append(float(M.solution.get_objective_value()))
            iterations.append(
                float(cplex._internal._procedural.getitcnt(M._env._e, M._lp)))
            mt += time.time() - ct

            pi = list(M.solution.get_dual_values())[:len(w)]
            dual = list(M.solution.get_dual_values())

            v = pi
            W = self.W

            pt = time.time()
            # print(w)

            S_obj, sol = binpacking.KnapsackBnB(v, w, W)

            # print(S_obj, sol)

            st += time.time() - pt

            if S_obj - tolerence > 1.:

                criteria = True
                newsub = sol
                idx = M.variables.get_num()
                M.variables.add(obj=[1.0])
                M.linear_constraints.set_coefficients(
                    list(zip(list(range(len(w))), [idx] * len(var), newsub)))

                var.append(idx)
            else:
                criteria = False

        M.set_problem_type(M.problem_type.LP)
        ct = time.time()
        M.solve()
        # M.write('kelly.lp')
        solutions.append(float(M.solution.get_objective_value()))
        iterations.append(
            float(cplex._internal._procedural.getitcnt(M._env._e, M._lp)))
        mt += time.time() - ct
        # tt = time.time() - start

        self.Kelly_M = M

        Kelly_result = [ite, mt, st, solutions, iterations]

        return Kelly_result
Exemple #10
0
    def chevy(self):

        w = self.w

        ######### Master Problem ###########

        M = cplex.Cplex()

        # Parameters
        var = list(range(len(w)))
        alpha = 1.0
        init_pi = sum(w) / 150
        epsilon = 0.1

        # decision varialbes types=["C"]*len(var)
        M.variables.add(obj=[1] * len(var),
                        names=['x_' + str(i) for i in var],
                        lb=[0] * len(var))
        M.variables.add(obj=[-init_pi], names='z', lb=[0])
        M.variables.add(names=['y_' + str(i) for i in list(range(len(w)))],
                        lb=[0] * len(w))

        # pattern constraints
        vals = np.zeros((len(w), len(var)))

        np.fill_diagonal(vals, 1)

        M.linear_constraints.add(lin_expr=[
            cplex.SparsePair(ind=['x_' + str(j)
                                  for j in var] + ['y_' + str(i)] + ['z'],
                             val=list(vals[i]) + [-1.0] + [-1.0])
            for i in range(len(w))
        ],
                                 senses=["G" for i in w],
                                 rhs=[0 for i in w])

        # chebyshev constraint
        M.linear_constraints.add(lin_expr=[
            cplex.SparsePair(
                ind=['x_' + str(j)
                     for j in var] + ['y_' + str(i)
                                      for i in range(len(w))] + ['z'],
                val=[1.0
                     for k in var] + [1.0
                                      for l in w] + [alpha * len(w)**(1 / 2)])
        ],
                                 senses=["G"],
                                 rhs=[1.0])

        M.objective.set_sense(M.objective.sense.minimize)

        M.write('cheby.lp')

        ite = 0
        while True:
            ite += 1
            #         M.write('cheby_m.lp')

            M.set_log_stream(None)
            M.set_error_stream(None)
            M.set_warning_stream(None)
            M.set_results_stream(None)

            # M.write('cheby.lp')

            self.chevy_M = M
            M.solve()

            v = [
                pie for pie in M.solution.get_dual_values(list(range(len(w))))
            ]
            # S.objective.set_linear(list(zip(list(range(len(w))), price)))
            # #         S.write('cheby_s.lp')
            # S.set_log_stream(None)
            # S.set_error_stream(None)
            # S.set_warning_stream(None)
            # S.set_results_stream(None)
            # S.solve()

            S_obj, sol = binpacking.KnapsackBnB(v, w, W)
            print(sol)

            if M.solution.get_objective_value(
            ) < epsilon * M.solution.get_values('z'):
                break

            if S_obj < 1 + 1.0e-6:
                newsub = sol
                idx = M.variables.get_num()
                M.variables.add(obj=[1.0])
                M.linear_constraints.set_coefficients(
                    list(zip(list(range(len(w))), [idx] * len(var), newsub)))
                var.append(idx)

            else:
                new_pi = M.solution.get_dual_values()
                M.objective.set_linear('z', -sum(new_pi))

        M.variables.set_types(
            list(zip(var, [M.variables.type.continuous] * len(var))))
        M.solve()

        self.chevy_M = M

        self.chevy_result = [
            'Separation %s' % (self.sep), ite, mt, st, tt, mt / (st + mt),
            solutions,
            np.average(np.array(iterations))
        ]
Exemple #11
0
    def Separation(self):
        # sep = 2

        w = self.w

        I = range(len(w))
        Is = list(np.array_split(I, self.sep))
        BigM = 100000

        M = cplex.Cplex()

        var = list(range(len(w)))

        vals = np.zeros((len(w), len(var)))

        np.fill_diagonal(vals, 1)

        x_p = lambda p: 'x_%d' % (p)

        x = [x_p(p) for p in range(len(var))]

        M.variables.add(lb=[0] * len(x),
                        ub=[cplex.infinity] * len(x),
                        names=x,
                        obj=[1.] * len(x),
                        types=['C'] * len(x))

        y_i = lambda i: 'y_%d' % (i)

        y = [y_i(i) for i in I]

        ys = [[y[i] for i in Is[j]] for j in range(self.sep)]

        M.variables.add(
            # lb=[0] * len(y),
            # ub=[cplex.infinity] * len(y),
            names=y,
            obj=[BigM] * len(y),
            types=['C'] * len(y))

        M.linear_constraints.add(lin_expr=[
            cplex.SparsePair(ind=x + [y[i]], val=list(vals[i]) + [1.0])
            for i in I
        ],
                                 senses=["G" for i in w],
                                 rhs=[1. for i in w])

        M.objective.set_sense(M.objective.sense.minimize)
        M.set_log_stream(None)
        M.set_error_stream(None)
        M.set_warning_stream(None)
        M.set_results_stream(None)

        start = time.time()
        mt = 0
        st = 0
        ite = 0
        s2 = 0
        solutions = []
        iterations = []
        penalty = 0.6

        for twice in range(2):

            for sec in range(self.sep):

                print(ite)

                criteria = True
                y_fix = list(set(y) - set(list(ys[sec])))
                I_fix = list(set(I) - set(list(Is[sec])))
                # M.objective.set_linear(zip(y_fix, [BigM] * len(y_fix)))
                M.variables.set_upper_bounds(zip(y_fix, np.zeros(len(y_fix))))
                M.variables.set_lower_bounds(zip(y_fix, [0] * len(y_fix)))

                while criteria:
                    ite += 1

                    if ite % 500 == 0:
                        penalty = penalty * 0.6
                    if penalty < 0.1:
                        penalty = 100
                        # print(penalty)

                    M.set_problem_type(M.problem_type.LP)

                    ct = time.time()
                    M.solve()

                    solutions.append(float(M.solution.get_objective_value()))
                    iterations.append(
                        float(
                            cplex._internal._procedural.getitcnt(
                                M._env._e, M._lp)))

                    mt += time.time() - ct
                    dual = list(M.solution.get_dual_values())

                    pi = dual

                    pi_ = [dual[i] * penalty for i in I_fix]

                    v = pi
                    W = self.W

                    pt = time.time()
                    #####################################################
                    # if ite >= 51 and ite<=162:
                    #     S_obj, sol =binpacking.Knapsack2(v,w,W)
                    #     s2 += time.time() - pt

                    # # else:
                    #     aa = time.time()
                    #     S_obj, sol = binpacking.KnapsackBnB(v, w, W)
                    #     st += time.time() - pt
                    #####################################################

                    S_obj, sol = binpacking.KnapsackBnB(v, w, W)
                    if ite == 1000:
                        print(v, w, W)
                        print(time.time() - pt)
                    st += time.time() - pt

                    if S_obj - 0.00001 > 1.:

                        criteria = True
                        M.objective.set_linear(
                            list(
                                zip(
                                    list(
                                        map(lambda x: int(x + len(w)),
                                            Is[sec])), pi_)))

                        # M.objective.set_linear(zip(y_fix, [BigM] * len(y_fix)))
                        newsub = sol
                        idx = M.variables.get_num()
                        M.variables.add(obj=[1.0])
                        M.linear_constraints.set_coefficients(
                            list(
                                zip(list(range(len(w))), [idx] * len(var),
                                    newsub)))

                        var.append(idx)
                        # if ite >= 50:
                        #     print('2')

                    else:
                        criteria = False
                        # M.write('1.lp')

                if M.solution.get_values(ys[sec]) == [0] * len(ys[sec]):
                    print('dddd')
                    break
            else:
                continue
            break

        M.set_problem_type(M.problem_type.LP)

        ct = time.time()
        M.solve()
        # M.write('sep.lp')
        solutions.append(float(M.solution.get_objective_value()))
        iterations.append(
            float(cplex._internal._procedural.getitcnt(M._env._e, M._lp)))
        print(s2)
        mt += time.time() - ct
        tt = time.time() - start
        self.Separation_M = M

        self.Separation_result = [
            'Separation %s' % (self.sep), ite, mt, st, tt, mt / (st + mt),
            solutions,
            np.average(np.array(iterations))
        ]
Exemple #12
0
    def Stabilization(self):

        eps = 0.1

        w = self.w
        I = range(len(w))

        M = cplex.Cplex()

        var = list(range(len(w)))
        vals = np.zeros((len(w), len(var)))

        np.fill_diagonal(vals, 1)

        x_p = lambda p: 'x_%d' % (p)

        x = [x_p(p) for p in range(len(var))]

        M.variables.add(lb=[0] * len(x),
                        ub=[cplex.infinity] * len(x),
                        names=x,
                        obj=[1.] * len(x),
                        types=['C'] * len(x))

        dp_i = lambda i: 'dp_%d' % (i)

        dp = [dp_i(i) for i in I]

        M.variables.add(lb=[0] * len(dp),
                        ub=[eps] * len(dp),
                        names=dp,
                        obj=[0] * len(dp),
                        types=['C'] * len(dp))

        dm_i = lambda i: 'dm_%d' % (i)

        dm = [dm_i(i) for i in I]

        M.variables.add(lb=[0] * len(dm),
                        ub=[eps] * len(dm),
                        names=dm,
                        obj=[0] * len(dm),
                        types=['C'] * len(dm))

        M.linear_constraints.add(lin_expr=[
            cplex.SparsePair(ind=x + [dm[i]] + [dp[i]],
                             val=list(vals[i]) + [-1.0] + [1.0]) for i in I
        ],
                                 senses=["G" for i in w],
                                 rhs=[1. for i in w])

        # M.linear_constraints.add(lin_expr=[SparsePair()] * len(w),
        #                          senses=["G"] * len(w),
        #                          rhs=[1] * len(w))
        # for i in range(len(w)):
        #     M.linear_constraints.set_coefficients(i, i, 1)

        M.objective.set_sense(M.objective.sense.minimize)
        M.set_log_stream(None)
        M.set_error_stream(None)
        M.set_warning_stream(None)
        M.set_results_stream(None)

        start = time.time()
        mt = 0
        st = 0
        ite = 0
        solutions = []
        iterations = []
        criteria = True

        while criteria:

            ite += 1

            M.set_problem_type(M.problem_type.LP)
            ct = time.time()

            M.solve()
            solutions.append(float(M.solution.get_objective_value()))
            iterations.append(
                float(cplex._internal._procedural.getitcnt(M._env._e, M._lp)))
            mt += time.time() - ct

            pi = list(M.solution.get_dual_values())[:len(w)]
            dual = list(M.solution.get_dual_values())

            v = pi
            W = self.W

            pt = time.time()
            # print(w)

            S_obj, sol = binpacking.KnapsackBnB(v, w, W)

            # print(S_obj, sol)

            st += time.time() - pt

            if S_obj - 0.000001 > 1. or eps != 0:

                criteria = True
                newsub = sol
                idx = M.variables.get_num()
                M.variables.add(obj=[1.0])
                M.linear_constraints.set_coefficients(
                    list(zip(list(range(len(w))), [idx] * len(var), newsub)))

                var.append(idx)

                if ite % 100 == 0:
                    eps *= 0.1
                    if ite == 600:
                        eps = 0

                    for dv in dm + dp:
                        M.variables.set_upper_bounds(dv, eps)

            else:
                criteria = False

        M.set_problem_type(M.problem_type.LP)
        ct = time.time()
        M.solve()
        # M.write('kelly.lp')
        solutions.append(float(M.solution.get_objective_value()))
        iterations.append(
            float(cplex._internal._procedural.getitcnt(M._env._e, M._lp)))
        mt += time.time() - ct
        tt = time.time() - start

        self.Stab_M = M

        self.Stab_Result = [
            'Stabilization', ite, mt, st, tt, mt / (st + mt), solutions,
            np.average(np.array(iterations))
        ]
Exemple #13
0
def qcpdual():
    # ###################################################################### #
    #                                                                        #
    #    S E T U P   P R O B L E M                                           #
    #                                                                        #
    # ###################################################################### #
    c = cplex.Cplex()
    c.variables.add(obj=Data.obj,
                    lb=Data.lb, ub=Data.ub, names=Data.cname)
    c.linear_constraints.add(lin_expr=Data.rows, senses=Data.sense,
                             rhs=Data.rhs, names=Data.rname)
    for q in range(0, len(Data.qname)):
        c.quadratic_constraints.add(lin_expr=Data.qlin[q],
                                    quad_expr=Data.quad[q],
                                    sense=Data.qsense[q],
                                    rhs=Data.qrhs[q],
                                    name=Data.qname[q])

    # ###################################################################### #
    #                                                                        #
    #    O P T I M I Z E   P R O B L E M                                     #
    #                                                                        #
    # ###################################################################### #
    c.parameters.barrier.qcpconvergetol.set(1e-10)
    c.solve()
    if not c.solution.get_status() == c.solution.status.optimal:
        raise Exception("No optimal solution found")

    # ###################################################################### #
    #                                                                        #
    #    Q U E R Y   S O L U T I O N                                         #
    #                                                                        #
    # ###################################################################### #
    # We store all results in a dictionary so that we can easily access
    # them by name.
    # Optimal solution and slacks for linear and quadratic constraints.
    x = dict(zip(c.variables.get_names(),
                 c.solution.get_values()))
    slack = dict(zip(c.linear_constraints.get_names(),
                     c.solution.get_linear_slacks()))
    qslack = dict(zip(c.quadratic_constraints.get_names(),
                      c.solution.get_quadratic_slacks()))
    # Dual multipliers for constraints.
    cpi = dict(zip(c.variables.get_names(),
                   c.solution.get_reduced_costs()))
    rpi = dict(zip(c.linear_constraints.get_names(),
                   c.solution.get_dual_values()))
    qpi = getqconstrmultipliers(c, ZEROTOL)

    # Some CPLEX functions return results by index instead of by name.
    # Define a function that translates from index to name.
    v2name = lambda x: c.variables.get_names(x)

    # ###################################################################### #
    #                                                                        #
    #    C H E C K   K K T   C O N D I T I O N S                             #
    #                                                                        #
    #    Here we verify that the optimal solution computed by CPLEX (and     #
    #    the qpi[] values computed above) satisfy the KKT conditions.        #
    #                                                                        #
    # ###################################################################### #

    # Primal feasibility: This example is about duals so we skip this test. #

    # Dual feasibility: We must verify
    # - for <= constraints (linear or quadratic) the dual
    #   multiplier is non-positive.
    # - for >= constraints (linear or quadratic) the dual
    #   multiplier is non-negative.
    for r in c.linear_constraints.get_names():
        if c.linear_constraints.get_senses(r) == 'E':
            pass
        elif c.linear_constraints.get_senses(r) == 'R':
            pass
        elif c.linear_constraints.get_senses(r) == 'L':
            if rpi[r] > ZEROTOL:
                raise Exception("Dual feasibility test failed")
        elif c.linear_constraints.get_senses(r) == 'G':
            if rpi[r] < -ZEROTOL:
                raise Exception("Dual feasibility test failed")
    for q in c.quadratic_constraints.get_names():
        if c.quadratic_constraints.get_senses(q) == 'E':
            pass
        elif c.quadratic_constraints.get_senses(q) == 'L':
            if qpi[q] > ZEROTOL:
                raise Exception("Dual feasibility test failed")
        elif c.quadratic_constraints.get_senses(q) == 'G':
            if qpi[q] < -ZEROTOL:
                raise Exception("Dual feasibility test failed")

    # Complementary slackness.
    # For any constraint the product of primal slack and dual multiplier
    # must be 0.
    for r in c.linear_constraints.get_names():
        if ((not c.linear_constraints.get_senses(r) == 'E') and
                fabs(slack[r] * rpi[r]) > ZEROTOL):
            raise Exception("Complementary slackness test failed")
    for q in c.quadratic_constraints.get_names():
        if ((not c.quadratic_constraints.get_senses(q) == 'E') and
                fabs(qslack[q] * qpi[q]) > ZEROTOL):
            raise Exception("Complementary slackness test failed")
    for j in c.variables.get_names():
        if c.variables.get_upper_bounds(j) < cplex.infinity:
            slk = c.variables.get_upper_bounds(j) - x[j]
            if cpi[j] < -ZEROTOL:
                dual = cpi[j]
            else:
                dual = 0.0
            if fabs(slk * dual) > ZEROTOL:
                raise Exception("Complementary slackness test failed")
        if c.variables.get_lower_bounds(j) > -cplex.infinity:
            slk = x[j] - c.variables.get_lower_bounds(j)
            if cpi[j] > ZEROTOL:
                dual = cpi[j]
            else:
                dual = 0.0
            if fabs(slk * dual) > ZEROTOL:
                raise Exception("Complementary slackness test failed")

    # Stationarity.
    # The difference between objective function and gradient at optimal
    # solution multiplied by dual multipliers must be 0, i.e., for the
    # optimal solution x
    # 0 == c
    #      - sum(r in rows)  r'(x)*rpi[r]
    #      - sum(q in quads) q'(x)*qpi[q]
    #      - sum(c in cols)  b'(x)*cpi[c]
    # where r' and q' are the derivatives of a row or quadratic constraint,
    # x is the optimal solution and rpi[r] and qpi[q] are the dual
    # multipliers for row r and quadratic constraint q.
    # b' is the derivative of a bound constraint and cpi[c] the dual bound
    # multiplier for column c.

    # Objective function
    kktsum = dict(zip(c.variables.get_names(), c.objective.get_linear()))

    # Linear constraints.
    # The derivative of a linear constraint ax - b (<)= 0 is just a.
    for r in c.linear_constraints.get_names():
        row = c.linear_constraints.get_rows(r)
        for (var, val) in zip(map(v2name, row.ind), row.val):
            kktsum[var] -= rpi[r] * val
    # Quadratic constraints.
    # The derivative of a constraint xQx + ax - b <= 0 is
    # Qx + Q'x + a.
    for q in c.quadratic_constraints.get_names():
        lin = c.quadratic_constraints.get_linear_components(q)
        for (var, val) in zip(map(v2name, lin.ind), lin.val):
            kktsum[var] -= qpi[q] * val
        quad = c.quadratic_constraints.get_quadratic_components(q)
        for (row, col, val) in zip(map(v2name, quad.ind1),
                                   map(v2name, quad.ind2), quad.val):
            kktsum[row] -= qpi[q] * x[col] * val
            kktsum[col] -= qpi[q] * x[row] * val

    # Bounds.
    # The derivative for lower bounds is -1 and that for upper bounds
    # is 1.
    # CPLEX already returns dj with the appropriate sign so there is
    # no need to distinguish between different bound types here.
    for v in c.variables.get_names():
        kktsum[v] -= cpi[v]

    for v in c.variables.get_names():
        if fabs(kktsum[v]) > ZEROTOL:
            raise Exception("Stationarity test failed")

    # KKT conditions satisfied. Dump out solution and dual values.
    print("Optimal solution satisfies KKT conditions.")
    print("  x[] = [", end=' ')
    for n in c.variables.get_names():
        print(" %7.3f" % x[n], end=' ')
    print(" ]")
    print("cpi[] = [", end=' ')
    for n in c.variables.get_names():
        print(" %7.3f" % cpi[n], end=' ')
    print(" ]")
    print("rpi[] = [", end=' ')
    for n in c.linear_constraints.get_names():
        print(" %7.3f" % rpi[n], end=' ')
    print(" ]")
    print("qpi[] = [", end=' ')
    for n in c.quadratic_constraints.get_names():
        print(" %7.3f" % qpi[n], end=' ')
    print(" ]")
Exemple #14
0
def cutstock(datafile):
    # Input data. If no file is given on the command line then use a
    # default file name. The data read is
    # width  - the width of the the roll,
    # size   - the sie of each strip,
    # amount - the demand for each strip.
    width, size, amount = read_dat_file(datafile)

    # Setup cutting optimization (master) problem.
    # This is the problem to which columns will be added in the loop
    # below.
    cut = cplex.Cplex()
    cutcons = list(range(len(amount)))   # constraint indices
    cutvars = list(range(len(size)))     # variable indices
    cut.variables.add(obj=[1] * len(cutvars))
    # Add constraints. They have empty left-hand side initially. The
    # left-hand side is filled in the next loop.
    cut.linear_constraints.add(lin_expr=[SparsePair()] * len(cutcons),
                               senses=["G"] * len(cutcons),
                               rhs=amount)
    for v in cutvars:
        cut.linear_constraints.set_coefficients(v, v, int(width / size[v]))

    # Setup pattern generation (worker) problem.
    # The constraints and variables in this problem always stay the same
    # but the objective function will change during the column generation
    # loop.
    pat = cplex.Cplex()
    use = list(range(len(size)))         # variable indices
    pat.variables.add(types=[pat.variables.type.integer] * len(use))
    # Add a constant 1 to the objective.
    pat.variables.add(obj=[1], lb=[1], ub=[1])
    # Single constraint: total size must not exceed the width.
    totalsize = SparsePair(ind=use, val=size)
    pat.linear_constraints.add(lin_expr=[totalsize],
                               senses=["L"],
                               rhs=[width])
    pat.objective.set_sense(pat.objective.sense.minimize)

    # Column generation procedure
    while True:

        # Optimize over current patterns
        cut.solve()
        report1(cut)

        # Find and add new pattern. The objective function of the
        # worker problem is constructed from the dual values of the
        # constraints of the master problem.
        price = [-d for d in cut.solution.get_dual_values(cutcons)]
        pat.objective.set_linear(list(zip(use, price)))
        pat.solve()
        report2(pat, use)

        # If reduced cost (worker problem objective function value) is
        # non-negative we are optimal. Otherwise we found a new column
        # to be added. Coefficients of the new column are given by the
        # optimal solution vector to the worker problem.
        if pat.solution.get_objective_value() > -RC_EPS:
            break
        newpat = pat.solution.get_values(use)

        # The new pattern constitutes a new variable in the cutting
        # optimization problem. Create that variable and add it to all
        # constraints with the coefficients read from the optimal solution
        # of the pattern generation problem.
        idx = cut.variables.get_num()
        cut.variables.add(obj=[1.0])
        cut.linear_constraints.set_coefficients(list(zip(cutcons,
                                                         [idx] * len(use),
                                                         newpat)))
        cutvars.append(idx)

    # Perform a final solve on the cutting optimization problem.
    # Turn all variables into integers before doing that.
    cut.variables.set_types(
        list(zip(cutvars, [cut.variables.type.integer] * len(cutvars))))
    cut.solve()
    report3(cut)
    print("Solution status = ", cut.solution.get_status())