Beispiel #1
0
    def generateCuts(self, si, cglTreeInfo):
        m = self.cyLPModel
        x = m.getVarByName('x')

        clpModel = si.clpModel
        clpModel.dual(startFinishOptions='x')
        solution = clpModel.primalVariableSolution
        bv = clpModel.basicVariables
        rhs = clpModel.rhs

        intInds = clpModel.integerInformation

        rhsIsInt = list(map(isInt, rhs))

        cuts = []
        for rowInd in range(s.nConstraints):
            basicVarInd = bv[rowInd]
            if basicVarInd < clpModel.nVariables and intInds[
                    basicVarInd] and not rhsIsInt[rowInd]:
                coef, b = gomoryCut(clpModel, rowInd)
                if b is not None:
                    #print 'Adding cut: ', coef, '>=', b
                    expr = CyLPArray(coef) * x >= b
                    cuts.append(expr)
        return cuts
Beispiel #2
0
    def generateQP(self):
        m = self.m
        n = self.n
        s = CyClpSimplex()

        iNonZero = set(random.randint(n, size=self.nnzPerCol))
        iZero = [i for i in range(n) if i not in iNonZero]
        x_star = np.matrix(np.zeros((n, 1)))
        z_star = np.matrix(np.zeros((n, 1)))

        for i in iNonZero:
            x_star[i, 0] = 1

        for i in iZero:
            z_star[i, 0] = 0 if random.randint(2) else random.random()

        G = getG(n)

        A = getA(m, n, self.nnzPerCol)
        y_star = np.matrix(random.random((m, 1)))

        c = -(G * x_star - A.T * y_star - z_star)

        obj = 0.5 * ((x_star.T * G) * x_star) + c.T * x_star
        print(obj)

        c = CyLPArray((c.T)[0])

        b = CyLPArray(((A * x_star).T)[0])
        b = np.squeeze(np.asarray(b))

        x = s.addVariable('x', n)

        s += A * x == b
        s += x >= 0

        c = CyLPArray(c)
        s.objective = c * x

        s.Hessian = G

        self.model = s
        return s
Beispiel #3
0
                    #print 'Adding cut: ', coef, '>=', b
                    expr = CyLPArray(coef) * x >= b
                    cuts.append(expr)
        return cuts


if __name__ == '__main__':
    m = CyLPModel()

    firstExample = False

    if (firstExample):
        x = m.addVariable('x', 2, isInt=True)

        A = np.matrix([[7., -2.], [0., 1], [2., -2]])
        b = CyLPArray([14, 3, 3])

        m += A * x <= b
        m += x >= 0

        c = CyLPArray([-4, 1])
        m.objective = c * x
        s = CyClpSimplex(m)
    else:
        s = CyClpSimplex()
        #cylpDir = os.environ['CYLP_SOURCE_DIR']
        inputFile = os.path.join('..', '..', 'input', 'p0033.mps')
        m = s.extractCyLPModel(inputFile)
        x = m.getVarByName('x')
        s.setInteger(x)
Beispiel #4
0
def solve(m, whichCuts = [], 
          debug_print = False, epsilon = .01, 
          max_iter = 100, max_cuts = 10, display = False):    

    if not isinstance(m, MILPInstance):
        raise "Invalid first parameter: Must be of type MILPInstance"

    if not DISPLAY_ENABLED:
        display = False
        
    if m.lp.nCols > 2 or m.A is None:
        display = False
    m.lp.logLevel = 0
    
    if display:
        disp_relaxation(m.A, m.b)
    
    for i in xrange(max_iter):
        print 'Iteration ', i
        m.lp.primal(startFinishOptions = 'x')
        print 'Current bound:', m.lp.objectiveValue
        #Binv = np.zeros(shape = (lp.nConstraints, lp.nConstraints))
        #for i in range(lp.nVariables, lp.nVariables+lp.nConstraints):
        #    lp.getBInvACol(i, Binv[i-lp.nVariables,:])
        #rhs = lp.rhs
        if m.sense == '<=':
            rhs = np.dot(m.lp.basisInverse, m.lp.constraintsUpper)
        else:
            rhs = np.dot(m.lp.basisInverse, m.lp.constraintsLower)
        sol = m.lp.primalVariableSolution['x']
        if debug_print:
            print 'Current basis inverse:'
            print m.lp.basisInverse
            print 'Condition number of basis inverse'
            print np.linalg.cond(m.lp.basisInverse)
            print "Current tableaux:"
            print m.lp.tableau
            print "Current right hand side:\n", rhs
            #print lp.rhs
        print 'Current solution: ', sol
        if isInt(sol[m.integerIndices], epsilon):
            print 'Integer solution found!'
            break
        cuts = []
        disj = []
        for (cg, args) in whichCuts:
            tmp_cuts, tmp_disj = cg(m.lp, m.integerIndices, m.sense, sol, **args)
            cuts += tmp_cuts
            disj += tmp_disj
        if cuts == []:
            print 'No cuts found!'
            break
        if display:
            disp_relaxation(m.A, m.b, cuts, sol, disj)
        for (coeff, r) in cuts[:max_cuts]:
            #TODO sort cuts by degree of violation
            if m.sense == '<=':
                print 'Adding cut: ', coeff, '<=', r
                m.lp += CyLPArray(coeff) * m.x <= r
            else:
                print 'Adding cut: ', coeff, '>=', r
                m.lp += CyLPArray(coeff) * m.x >= r
            if display:
                m.A.append(coeff.tolist())
                m.b.append(r)
    
    if display:
        disp_relaxation(m.A, m.b)
Beispiel #5
0
    def __init__(self,
                 module_name=None,
                 file_name=None,
                 A=None,
                 b=None,
                 c=None,
                 points=None,
                 rays=None,
                 sense=None,
                 integerIndices=None,
                 numVars=None):

        if file_name is not None:
            # We got a file name, so ignore everything else and read in the instance
            lp = CyClpSimplex()
            lp.extractCyLPModel(file_name)
            self.integerIndices = [
                i for (i, j) in enumerate(lp.integerInformation) if j == True
            ]
            infinity = lp.getCoinInfinity()
            A = lp.coefMatrix
            b = CyLPArray([0 for _ in range(lp.nRows)])
            for i in range(lp.nRows):
                if lp.constraintsLower[i] > -infinity:
                    if lp.constraintsUpper[i] < infinity:
                        raise Exception('Cannot handle ranged constraints')
                    b[i] = -lp.constraintsLower[i]
                    for j in range(lp.nCols):
                        A[i, j] = -A[i, j]
                elif lp.constraintsUpper[i] < infinity:
                    b[i] = lp.constraintsUpper[i]
                else:
                    raise Exception('Constraint with no bounds detected')
            x = lp.addVariable('x', lp.nCols)
            lp += A * x <= b
            lp += x <= lp.variablesUpper
            lp += x >= lp.variablesLower
            lp.objective = lp.objective
            self.sense = '<='
            numVars = lp.nCols
        else:
            min_or_max = None
            if module_name is not None:
                # We got a module name, read the data from there
                mip = ilib.import_module(module_name)
                self.A = mip.A if hasattr(mip, 'A') else None
                self.b = mip.b if hasattr(mip, 'b') else None
                points = mip.points if hasattr(mip, 'points') else None
                rays = mip.rays if hasattr(mip, 'rays') else None
                self.c = mip.c if hasattr(mip, 'c') else None
                self.sense = mip.sense[1] if hasattr(mip, 'sense') else None
                min_or_max = mip.sense[0] if hasattr(mip, 'sense') else None
                self.integerIndices = mip.integerIndices if hasattr(
                    mip, 'integerIndices') else None
                x_u = CyLPArray(mip.x_u) if hasattr(mip, 'x_u') else None
                numVars = mip.numVars if hasattr(mip, 'numVars') else None
                self.x_sep = mip.x_sep if hasattr(mip, 'x_sep') else None
                if numVars is None and mip.A is not None:
                    numVars = len(mip.A)

                if numVars is None:
                    raise "Must specify number of variables when problem is not"
            else:
                self.A = A
                self.b = b
                self.c = c
                self.points = points
                self.rays = rays
                if sense is not None:
                    self.sense = sense[1]
                    min_or_max = sense[0]
                self.integerIndices = integerIndices
                x_u = None

            lp = CyClpSimplex()
            if self.A is not None:
                A = np.matrix(self.A)
                b = CyLPArray(self.b)
            elif numVars <= 2 and GRUMPY_INSTALLED:
                p = Polyhedron2D(points=points, rays=rays)
                A = np.matrix(p.hrep.A)
                b = np.matrix(p.hrep.b)
            else:
                raise "Must specify problem in inequality form with more than two variables\n"

            #Warning: At the moment, you must put bound constraints in explicitly for split cuts
            x_l = CyLPArray([0 for _ in range(numVars)])

            x = lp.addVariable('x', numVars)

            lp += x >= x_l
            if x_u is not None:
                lp += x <= x_u
            lp += (A * x <= b if self.sense == '<=' else A * x >= b)
            c = CyLPArray(self.c)
            if min_or_max == 'Max':
                lp.objective = -c * x
            else:
                lp.objective = c * x
            self.lp = lp
            self.x = x
try:
    p = Polyhedron2D(A=LP.A, b=LP.b)
except AttributeError:
    try:
        p = Polyhedron2D(points=LP.points, rays=LP.rays)
    except AttributeError:
        print 'Error: Must specify either A and b or points and rays'
        p = None

if p is not None:

    if CYLP_INSTALLED:
        lp = CyClpSimplex()

        A = np.matrix(p.hrep.A)
        b = CyLPArray(p.hrep.b)

        print A
        print b

        if LP.numVars == 2:
            disp_polyhedron(A=A, b=b)

        x = lp.addVariable('x', LP.numVars)

        if LP.sense[0] == '>=':
            lp += A * x >= b
        else:
            lp += A * x <= b
        #lp += x >= 0
Beispiel #7
0
def solve(m,
          whichCuts=[],
          use_cglp=False,
          debug_print=False,
          eps=EPS,
          max_iter=100,
          max_cuts=10,
          display=False,
          filename=None):

    if not isinstance(m, MILPInstance):
        print("Invalid first parameter: Must be of type MILPInstance")
        exit

    if not DISPLAY_ENABLED:
        display = False
    else:
        f = Figure()

    if m.lp.nCols > 2 or m.A is None:
        display = False
    m.lp.logLevel = 0

    #Include bounds explicitly in the constraint matrix for display and for
    #use in cut generators.
    infinity = m.lp.getCoinInfinity()
    if m.sense == '<=':
        b = m.lp.constraintsUpper.copy()
        mult = -1.0
    else:
        b = m.lp.constraintsLower.copy()
        mult = 1.0
    if type(m.A) == csc_matrixPlus:
        A = m.A.toarray()
    else:
        A = m.A.copy()
    for i in range(m.lp.nCols):
        e = np.zeros((1, m.lp.nCols))
        if m.lp.variablesUpper[i] < infinity:
            b.resize(b.size + 1, refcheck=False)
            e[0, i] = -mult
            b[-1] = -mult * m.lp.variablesUpper[i]
            A = np.vstack((A, e))
        if m.lp.variablesLower[i] > -infinity:
            b.resize(b.size + 1, refcheck=False)
            e[0, i] = mult
            b[-1] = mult * m.lp.variablesLower[i]
            A = np.vstack((A, e))
    m.A = A
    m.b = b

    if display and filename is not None:
        disp_relaxation(f, m.A, m.b, filename=filename + '.png')
    elif display:
        disp_relaxation(f, m.A, m.b)

    disj = []
    prev_sol = np.zeros((1, m.lp.nCols))
    for i in range(max_iter):
        print('Iteration ', i)
        m.lp.primal(startFinishOptions='x')
        print('Current bound:', m.lp.objectiveValue)
        #Binv = np.zeros(shape = (lp.nConstraints, lp.nConstraints))
        #for i in range(lp.nVariables, lp.nVariables+lp.nConstraints):
        #    lp.getBInvACol(i, Binv[i-lp.nVariables,:])
        #rhs = lp.rhs
        if m.sense == '<=':
            rhs = np.dot(m.lp.basisInverse, m.lp.constraintsUpper)
        else:
            rhs = np.dot(m.lp.basisInverse, m.lp.constraintsLower)
        sol = m.lp.primalVariableSolution['x']
        if debug_print:
            print('Current basis inverse:')
            print(m.lp.basisInverse)
            print('Condition number of basis inverse',
                  np.around(np.linalg.cond(m.lp.basisInverse)))
            print('Current tableaux:')
            print(m.lp.tableau)
            print('Current right hand side:\n', rhs)
            #print('Dual solution:', m.lp.dualConstraintSolution)
            #print lp.rhs
        print('Current solution: ', sol)

        if (sol - prev_sol).any():
            prev_sol = sol
        else:
            print("Solution repeated, stalling detected")
            print("Exiting")
            break

        if isInt(sol[m.integerIndices], eps):
            print('Integer solution found!')
            break

        if np.around(np.linalg.cond(m.lp.basisInverse)) >= 10**32:
            print("Condition number of the basis matrix exceeds 10^32")
            print("Exiting")
            break

        cuts = []
        if disj == []:
            for (cg, args) in whichCuts:
                tmp_cuts, tmp_disj = cg(m, **args, eps=eps)
                cuts += tmp_cuts
                disj += tmp_disj
        cur_num_cuts = len(cuts)
        if use_cglp:
            if len(disj) > 0:
                for d in disj:
                    cuts += disjunctionToCut(m, d[0], d[1], eps=eps)
        if cuts == []:
            if disj == []:
                print('No cuts found and terminating!')
                break
            else:
                print('No cuts found but continuing!')
        if display and filename is not None:
            disp_relaxation(f,
                            m.A,
                            m.b,
                            cuts,
                            sol,
                            disj,
                            filename=filename + str(i) + '.png')
        elif display:
            disp_relaxation(f, m.A, m.b, cuts, sol, disj)
        if len(cuts) == cur_num_cuts:
            disj = []
        for (coeff, r) in cuts[:max_cuts]:
            #TODO sort cuts by degree of violation
            if m.sense == '<=':
                coeff = np.floor(coeff * (10**eps)) / (10**eps)
                r = np.ceil(r * (10**eps)) / (10**eps)
                print('Adding cut: ', coeff, '<=', r)
                m.lp += CyLPArray(coeff) * m.x <= r
            else:
                coeff = np.ceil(coeff * (10**eps)) / (10**eps)
                r = np.floor(r * (10**eps)) / (10**eps)
                print('Adding cut: ', coeff, '>=', r)
                m.lp += CyLPArray(coeff) * m.x >= r
            m.A = np.vstack((m.A, np.array(coeff)))
            m.b.resize(m.b.size + 1, refcheck=False)
            m.b[-1] = r

    if display:
        disp_relaxation(f, m.A, m.b)
Beispiel #8
0
def disjunctionToCut(m, pi, pi0, debug_print=False, use_cylp=True, eps=EPS):
    '''Generate the most violated valid inequality from a given disjunction'''
    me = "cglp_cuts: "
    lp = m.lp
    sol = lp.primalVariableSolution['x']

    if debug_print:
        print(me, "constraints sense = ", m.sense)
        print(me, "matrix = ")
        print(m.A)
        print(me, "rhs = ", m.b)
        print(me, "vars lower bounds = ", lp.variablesLower)
        print(me, "vars upper bounds = ", lp.variablesUpper)
        print(me, "objective = ", lp.objective)
        print(me, "current solution = ", sol)
        print(me, "pi = ", pi)
        print(me, "pi0 = ", pi0)

    ############################################################################
    ## There are two given LPs:
    ## s.t. Ax >= b           s.t. Ax >= b
    ##   -pi.x >= -pi_0          pi.x >= pi_0+1
    ## A, b, c, pi, pi_0 are given
    ##
    ## CGLP: alpha.x >= beta should be valid for both LPs above
    ##
    ## min alpha.x* - beta
    ## uA - u0.pi = alpha
    ## vA + v0.pi = alpha
    ## ub - u0.pi_0 >= beta
    ## vb + v0.(pi_0 + 1) >= beta
    ## u0 + v0 = 1
    ## u, v, u0, v0 >= 0
    ## if min value comes out < 0, then (alpha.x >= beta) is a cut.
    ############################################################################

    pi = CyLPArray(pi)

    Atran = m.A.transpose()
    b = CyLPArray(m.b)
    numRows, numCols = m.A.shape

    if use_cylp:
        sp = CyLPModel()
        u = sp.addVariable('u', numRows, isInt=False)
        v = sp.addVariable('v', numRows, isInt=False)
        u0 = sp.addVariable('u0', 1, isInt=False)
        v0 = sp.addVariable('v0', 1, isInt=False)
        alpha = sp.addVariable('alpha', lp.nVariables, isInt=False)
        beta = sp.addVariable('beta', 1, isInt=False)

        #This should be as simple as this, but it doesn't work.
        #Maybe a bug in CyLP?
        #sp += alpha - Atran*u - pi*u0 == 0
        #sp += alpha - Atran*v + pi*v0 == 0
        for i in range(numCols):
            sp += alpha[i] - sum(Atran[i, j] * u[j]
                                 for j in range(numRows)) - pi[i] * u0 == 0
        for i in range(numCols):
            sp += alpha[i] - sum(Atran[i, j] * v[j]
                                 for j in range(numRows)) + pi[i] * v0 == 0
        if m.sense == '<=':
            sp += beta - b * u - pi0 * u0 >= 0
            sp += beta - b * v + (pi0 + 1) * v0 >= 0
        else:
            sp += beta - b * u - pi0 * u0 <= 0
            sp += beta - b * v + (pi0 + 1) * v0 <= 0
        sp += u0 + v0 == 1
        sp += u >= 0
        sp += v >= 0
        sp += u0 >= 0
        sp += v0 >= 0
        if m.sense == '<=':
            sp.objective = sum(-sol[i] * alpha[i]
                               for i in range(numCols)) + beta
        else:
            #This direction is not debugged
            sp.objective = sum(sol[i] * alpha[i]
                               for i in range(numCols)) - beta

        cglp = CyClpSimplex(sp)
        # If we want to solve it as an MILP
        # cglp = CyClpSimplex(sp).getCbcModel()
        #cglp.writeLp('lp.lp')
        cglp.logLevel = 0
        cglp.primal(startFinishOptions='x')
        # Solve as MILP
        # cglp.solve()
        beta = cglp.primalVariableSolution['beta'][0]
        alpha = cglp.primalVariableSolution['alpha']
        u = cglp.primalVariableSolution['u']
        v = cglp.primalVariableSolution['v']
        u0 = cglp.primalVariableSolution['u0'][0]
        v0 = cglp.primalVariableSolution['v0'][0]
        if debug_print:
            print(me, 'Objective Value: ', cglp.objectiveValue)

        if debug_print:
            print(me, 'u: ', u)
            print(me, 'v: ', v)
            print(me, 'u0: ', u0)
            print(me, 'v0: ', v0)
    else:
        CG = AbstractModel()
        CG.u = Var(list(range(numRows)),
                   domain=NonNegativeReals,
                   bounds=(0.0, None))
        CG.v = Var(list(range(numRows)),
                   domain=NonNegativeReals,
                   bounds=(0.0, None))
        CG.u0 = Var(domain=NonNegativeReals, bounds=(0.0, None))
        CG.v0 = Var(domain=NonNegativeReals, bounds=(0.0, None))
        CG.alpha = Var(list(range(numRows)), domain=Reals, bounds=(None, None))
        CG.beta = Var(domain=Reals, bounds=(None, None))

        ## Constraints
        def pi_rule_left(CG, i):
            x = float(pi[i])
            return (sum(Atran[i, j] * CG.u[j] for j in range(numRows)) -
                    x * CG.u0 - CG.alpha[i] == 0.0)

        CG.pi_rule_left = Constraint(list(range(numCols)), rule=pi_rule_left)

        def pi_rule_right(CG, i):
            x = float(pi[i])
            return (sum(Atran[i, j] * CG.v[j] for j in range(numRows)) +
                    x * CG.v0 - CG.alpha[i] == 0.0)

        CG.pi_rule_right = Constraint(list(range(numCols)), rule=pi_rule_right)

        if m.sense == '<=':

            def pi0_rule_left(CG):
                return (sum(b[j] * CG.u[j]
                            for j in range(numRows)) - pi0 * CG.u0 - CG.beta <=
                        0.0)

            CG.pi0_rule_left = Constraint(rule=pi0_rule_left)

            def pi0_rule_right(CG):
                return (sum(b[j] * CG.v[j] for j in range(numRows)) +
                        (pi0 + 1) * CG.v0 - CG.beta <= 0.0)

            CG.pi0_rule_right = Constraint(rule=pi0_rule_right)
        else:

            def pi0_rule_left(CG):
                return (sum(b[j] * CG.u[j]
                            for j in range(numRows)) - pi0 * CG.u0 - CG.beta >=
                        0.0)

            CG.pi0_rule_left = Constraint(rule=pi0_rule_left)

            def pi0_rule_right(CG):
                return (sum(b[j] * CG.v[j] for j in range(numRows)) +
                        (pi0 + 1) * CG.v0 - CG.beta >= 0.0)

            CG.pi0_rule_right = Constraint(rule=pi0_rule_right)

        def normalization_rule(CG):
            return (CG.u0 + CG.v0 == 1.0)

        CG.normalization_rule = Constraint(rule=normalization_rule)

        def objective_rule(CG):
            return (sum(sol[i] * CG.alpha[i]
                        for i in range(numCols)) - CG.beta)

        if m.sense == '<=':
            CG.objective = Objective(sense=maximize, rule=objective_rule)
        else:
            CG.objective = Objective(sense=minimize, rule=objective_rule)

        opt = SolverFactory("cbc")
        instance = CG.create_instance()
        #instance.pprint()
        #instance.write("foo.nl", format = "nl")
        #opt.options['bonmin.bb_log_level'] = 5
        #opt.options['bonmin.bb_log_interval'] = 1
        results = opt.solve(instance, tee=False)
        #results = opt.solve(instance)
        instance.solutions.load_from(results)

        beta = instance.beta.value
        alpha = np.array(
            [instance.alpha[i].value for i in range(lp.nVariables)])

    violation = beta - np.dot(alpha, sol)
    if debug_print:
        print(me, 'Beta: ', beta)
        print(me, 'alpha: ', alpha)
        print(me, 'Violation of cut: ', violation)

    if np.abs(violation) > 10**(-eps):
        return [(alpha, beta)]

    print('No violated cuts found solving CGLP', violation)
    return []
Beispiel #9
0
def solve(m,
          whichCuts=[],
          use_cglp=False,
          debug_print=False,
          epsilon=.01,
          max_iter=100,
          max_cuts=10,
          display=False):

    if not isinstance(m, MILPInstance):
        print("Invalid first parameter: Must be of type MILPInstance")
        exit

    if not DISPLAY_ENABLED:
        display = False

    if m.lp.nCols > 2 or m.A is None:
        display = False
    m.lp.logLevel = 0

    if display:
        disp_relaxation(m.A, m.b)

    disj = []
    for i in range(max_iter):
        print('Iteration ', i)
        m.lp.primal(startFinishOptions='x')
        print('Current bound:', m.lp.objectiveValue)
        #Binv = np.zeros(shape = (lp.nConstraints, lp.nConstraints))
        #for i in range(lp.nVariables, lp.nVariables+lp.nConstraints):
        #    lp.getBInvACol(i, Binv[i-lp.nVariables,:])
        #rhs = lp.rhs
        if m.sense == '<=':
            rhs = np.dot(m.lp.basisInverse, m.lp.constraintsUpper)
        else:
            rhs = np.dot(m.lp.basisInverse, m.lp.constraintsLower)
        sol = m.lp.primalVariableSolution['x']
        if debug_print:
            print('Current basis inverse:')
            print(m.lp.basisInverse)
            print('Condition number of basis inverse')
            print(np.linalg.cond(m.lp.basisInverse))
            print("Current tableaux:")
            print(m.lp.tableau)
            print("Current right hand side:\n", rhs)
            #print lp.rhs
        print('Current solution: ', sol)
        if isInt(sol[m.integerIndices], epsilon):
            print('Integer solution found!')
            break
        cuts = []
        if disj == []:
            for (cg, args) in whichCuts:
                tmp_cuts, tmp_disj = cg(m.lp, m.integerIndices, m.sense, sol,
                                        **args)
                cuts += tmp_cuts
                disj += tmp_disj
        cur_num_cuts = len(cuts)
        if use_cglp and len(disj) > 0:
            for d in disj:
                cuts += disjunctionToCut(m.lp, d[0], d[1], sense=m.sense)
        if cuts == []:
            if disj == []:
                print('No cuts found and terminating!')
                break
            else:
                print('No cuts found but continuing!')
        if display:
            disp_relaxation(m.A, m.b, cuts, sol, disj)
        if len(cuts) == cur_num_cuts:
            disj = []
        for (coeff, r) in cuts[:max_cuts]:
            #TODO sort cuts by degree of violation
            if m.sense == '<=':
                print('Adding cut: ', coeff, '<=', r)
                m.lp += CyLPArray(coeff) * m.x <= r
            else:
                print('Adding cut: ', coeff, '>=', r)
                m.lp += CyLPArray(coeff) * m.x >= r
            if display:
                m.A.append(coeff.tolist())
                m.b.append(r)

    if display:
        disp_relaxation(m.A, m.b)
Beispiel #10
0
def disjunctionToCut(lp,
                     pi,
                     pi0,
                     integerIndices=None,
                     sense='>=',
                     sol=None,
                     debug_print=False,
                     use_cylp=True):

    me = "cglp_cuts: "

    if sol is None:
        sol = lp.primalVariableSolution['x']
    infinity = lp.getCoinInfinity()

    if debug_print:
        print(me, "constraints sense = ", sense)
        print(me, "con lower bounds = ", lp.constraintsLower)
        print(me, "con upper bounds = ", lp.constraintsUpper)
        print(me, "con matrix = ", lp.coefMatrix.toarray())
        print(me, "vars lower bounds = ", lp.variablesLower)
        print(me, "vars upper bounds = ", lp.variablesUpper)
        print(me, "Assuming objective is to minimize")
        print(me, "objective = ", lp.objective)
        print(me, "infinity = ", infinity)
        print(me, "current point = ", sol)
        print(me, "pi = ", pi)
        print(me, "pi0 = ", pi0)

    A = lp.coefMatrix.toarray()
    #c = lp.objective
    ## Convert to >= if the problem is in <= form.
    if sense == '<=':
        b = deepcopy(lp.constraintsUpper)
        b = -1.0 * b
        A = -1.0 * A
    else:
        b = deepcopy(lp.constraintsLower)

    #Add bounds on variables as explicit constraints
    for i in range(lp.nCols):
        e = np.zeros((1, lp.nCols))
        if lp.variablesUpper[i] < infinity:
            b.resize(b.size + 1, refcheck=False)
            e[0, i] = -1.0
            b[-1] = -1.0 * lp.variablesUpper[i]
            A = np.vstack((A, e))
        if lp.variablesLower[i] > -infinity:
            b.resize(b.size + 1, refcheck=False)
            e[0, i] = 1.0
            b[-1] = lp.variablesLower[i]
            A = np.vstack((A, e))
    A = csc_matrixPlus(A)

    ############################################################################
    ## There are two given LPs:
    ## s.t. Ax >= b           s.t. Ax >= b
    ##   -pi.x >= -pi_0          pi.x >= pi_0+1
    ## A, b, c, pi, pi_0 are given
    ##
    ## CGLP: alpha.x >= beta should be valid for both LPs above
    ##
    ## min alpha.x* - beta
    ## uA - u0.pi = alpha
    ## vA + v0.pi = alpha
    ## ub - u0.pi_0 >= beta
    ## vb + v0.(pi_0 + 1) >= beta
    ## u0 + v0 = 1
    ## u, v, u0, v0 >= 0
    ## if min value comes out < 0, then (alpha.x >= beta) is a cut.
    ############################################################################

    b = CyLPArray(b)
    pi = CyLPArray(pi)

    Atran = A.transpose()

    if use_cylp:
        sp = CyLPModel()
        u = sp.addVariable('u', A.shape[0], isInt=False)
        v = sp.addVariable('v', A.shape[0], isInt=False)
        u0 = sp.addVariable('u0', 1, isInt=False)
        v0 = sp.addVariable('v0', 1, isInt=False)
        alpha = sp.addVariable('alpha', lp.nVariables, isInt=False)
        beta = sp.addVariable('beta', 1, isInt=False)

        for i in range(A.shape[1]):
            sp += alpha[i] - sum(Atran[i, j] * u[j]
                                 for j in range(A.shape[0])) + pi[i] * u0 == 0
        for i in range(A.shape[1]):
            sp += alpha[i] - sum(Atran[i, j] * v[j]
                                 for j in range(A.shape[0])) - pi[i] * v0 == 0
        sp += beta - b * u + pi0 * u0 <= 0
        sp += beta - b * v - (pi0 + 1) * v0 <= 0
        sp += u0 + v0 == 1
        if sense == '<=':
            sp += u >= 0
            sp += v >= 0
            sp += u0 >= 0
            sp += v0 >= 0
        else:
            #TODO this direction is not debugged
            # Is this all we need?
            sp += u <= 0
            sp += v <= 0
            sp += u0 <= 0
            sp += v0 <= 0
        sp.objective = sum(sol[i] * alpha[i] for i in range(A.shape[1])) - beta
        cbcModel = CyClpSimplex(sp).getCbcModel()
        cbcModel.logLevel = 0
        #cbcModel.maximumSeconds = 5
        cbcModel.solve()
        beta = cbcModel.primalVariableSolution['beta'][0]
        alpha = cbcModel.primalVariableSolution['alpha']
        u = cbcModel.primalVariableSolution['u']
        v = cbcModel.primalVariableSolution['v']
        u0 = cbcModel.primalVariableSolution['u0'][0]
        v0 = cbcModel.primalVariableSolution['v0'][0]
        if debug_print:
            print('Objective Value: ', cbcModel.objectiveValue)
            print('alpha: ', alpha, 'alpha*sol: ', np.dot(alpha, sol))
            print('beta: ', beta)
            print('Violation of cut: ', np.dot(alpha, sol) - beta)
    else:
        CG = AbstractModel()
        CG.u = Var(list(range(A.shape[0])),
                   domain=NonNegativeReals,
                   bounds=(0.0, None))
        CG.v = Var(list(range(A.shape[0])),
                   domain=NonNegativeReals,
                   bounds=(0.0, None))
        CG.u0 = Var(domain=NonNegativeReals, bounds=(0.0, None))
        CG.v0 = Var(domain=NonNegativeReals, bounds=(0.0, None))
        CG.alpha = Var(list(range(A.shape[0])),
                       domain=Reals,
                       bounds=(None, None))
        CG.beta = Var(domain=Reals, bounds=(None, None))

        ## Constraints
        def pi_rule_left(CG, i):
            x = float(pi[i])
            return (sum(Atran[i, j] * CG.u[j] for j in range(A.shape[0])) -
                    x * CG.u0 - CG.alpha[i] == 0.0)

        CG.pi_rule_left = Constraint(list(range(A.shape[1])),
                                     rule=pi_rule_left)

        def pi_rule_right(CG, i):
            x = float(pi[i])
            return (sum(Atran[i, j] * CG.v[j] for j in range(A.shape[0])) +
                    x * CG.v0 - CG.alpha[i] == 0.0)

        CG.pi_rule_right = Constraint(list(range(A.shape[1])),
                                      rule=pi_rule_right)

        def pi0_rule_left(CG):
            return (sum(b[j] * CG.u[j]
                        for j in range(A.shape[0])) - pi0 * CG.u0 - CG.beta >=
                    0.0)

        CG.pi0_rule_left = Constraint(rule=pi0_rule_left)

        def pi0_rule_right(CG):
            return (sum(b[j] * CG.v[j] for j in range(A.shape[0])) +
                    (pi0 + 1) * CG.v0 - CG.beta >= 0.0)

        CG.pi0_rule_right = Constraint(rule=pi0_rule_right)

        def normalization_rule(CG):
            return (CG.u0 + CG.v0 == 1.0)

        CG.normalization_rule = Constraint(rule=normalization_rule)

        def objective_rule(CG):
            return (sum(sol[i] * CG.alpha[i]
                        for i in range(A.shape[1])) - CG.beta)

        CG.objective = Objective(sense=minimize, rule=objective_rule)

        opt = SolverFactory("cbc")
        instance = CG.create_instance()
        #instance.pprint()
        #instance.write("foo.nl", format = "nl")
        #opt.options['bonmin.bb_log_level'] = 5
        #opt.options['bonmin.bb_log_interval'] = 1
        results = opt.solve(instance, tee=False)
        #results = opt.solve(instance)
        instance.solutions.load_from(results)

        beta = instance.beta.value
        alpha = np.array(
            [instance.alpha[i].value for i in range(lp.nVariables)])
    violation = beta - np.dot(alpha, sol)
    if debug_print:
        print(me, 'Beta: ', beta)
        print(me, 'alpha: ', alpha)
        print(me, 'Violation of cut: ', violation)

    if violation > 0.001:
        if (sense == ">="):
            return [(alpha, beta)]
        else:
            return [(-alpha, -beta)]
    return []