Example #1
0
 def __init__(self, origProb, x0, pi_init=None):
     if pi_init == None:
         pi_init = [(v.name, 0) for v in list(self.var.values())]
     self.prob = origProb
     self.iter = 1
     self.x0 = x0
     self.var = origProb.variablesDict()
     self.dim = len(self.var)
     self.currentXtremePoint = {}
     self.solver = None
     self.c = dict(list((v.name, c) for v, c in origProb.objective.items()))
     for v in self.var:
         if v in self.c:
             continue
         else:
             self.c[v] = 0.0
     self.generate_separation_problem()
     self.piCurrent = dict([(v.name, pi_init[v.name])
                            for v in list(self.var.values())])
     self.piPrevious = dict([(v.name, 0) for v in list(self.var.values())])
     self.extremePoints = []
     self.f = Figure()
 def __init__(self, origProb, x0):
     self.prob = origProb
     self.iter = 1
     self.x0 = x0
     self.var = origProb.variablesDict()
     self.dim = len(self.var)
     self.currentXtremePoint = {}
     self.solver = None
     self.c = dict(list((v.name,c) for v,c in origProb.objective.iteritems()))
     for v in self.var:
         if v in self.c:
             continue
         else:
             self.c[v] = 0.0
     self.generate_separation_problem()
     self.piCurrent = dict([(v.name, 0) for v in self.var.values()]) 
     self.piPrevious = dict([(v.name, 0) for v in self.var.values()]) 
     self.extremePoints = []
     self.f = Figure()
Example #3
0
A1 = [[1, 1], [4, -10], [-2, -2], [-6, -2], [-1, 4]]
A2 = [[-7, 1], [0, -1], [1, -1], [4, 1], [0, 1], [-1, 5]]
b1 = [8, -3, -9, -19, 12]
b2 = [-13, -1, 3, 27, 5, 20]
sense = ('Min', '<=')
integerIndices = [0, 1]
c = [1, 0]
cuts = None
rhs = None
obj_val = 2

p1 = Polyhedron2D(A=A1, b=b1)
p2 = Polyhedron2D(A=A2, b=b2)
sR = p2.make_integer_hull()

f = Figure()
f.add_polyhedron(p1,
                 label='$\mathcal{P}^{\,\prime}$',
                 color='blue',
                 show_int_points=True)
f.add_polyhedron(p2,
                 label='$\mathcal{P}^{\,\prime\prime}$',
                 color='black',
                 show_int_points=True)
f.add_polyhedron(
    sR,
    label=
    '$\operatorname{conv}(\mathcal{P}^{\,\prime\prime} \cap \mathbb{Z}^{\,2})$',
    color='red',
    linestyle='dashed')
f.set_xlim(p2.xlim + [0, 1])
Example #4
0
     27,
     5,
     20
     ]
sense = ('Min', '<=')
integerIndices = [0, 1]
c = [1, 0]
cuts = None
rhs = None
obj_val = 2

p1 = Polyhedron2D(A = A1, b = b1)
p2 = Polyhedron2D(A = A2, b = b2)
sR = p2.make_integer_hull()

f = Figure()
f.add_polyhedron(p1, label = '$\mathcal{P}^{\,\prime}$', color = 'blue', show_int_points = True)
f.add_polyhedron(p2, label = '$\mathcal{P}^{\,\prime\prime}$', color = 'black', show_int_points = True)
f.add_polyhedron(sR, label = '$\operatorname{conv}(\mathcal{P}^{\,\prime\prime} \cap \mathbb{Z}^{\,2})$', color = 'red', linestyle = 'dashed')
f.set_xlim(p2.xlim + [0, 1])
f.set_ylim(p2.ylim + [0, 1])
opt = [2, 3.5]
f.add_point(opt, .05, 'red')
f.add_text([opt[0]-0.25, opt[1]], r'$x^*$')
if c is not None and obj_val is not None:
    f.add_line(c, obj_val, p2.xlim, p2.ylim + [0.5, - 1.5], 
               linestyle = 'dashed', color = 'green', label = "Objective Function")
f.show()
cuts = [[-3, 1]]
rhs = [-5]
opt = [[2.42, 2.25]]
class GenericSeparation(object):

    def __init__(self, origProb, x0):
        self.prob = origProb
        self.iter = 1
        self.x0 = x0
        self.var = origProb.variablesDict()
        self.dim = len(self.var)
        self.currentXtremePoint = {}
        self.solver = None
        self.c = dict(list((v.name,c) for v,c in origProb.objective.iteritems()))
        for v in self.var:
            if v in self.c:
                continue
            else:
                self.c[v] = 0.0
        self.generate_separation_problem()
        self.piCurrent = dict([(v.name, 0) for v in self.var.values()]) 
        self.piPrevious = dict([(v.name, 0) for v in self.var.values()]) 
        self.extremePoints = []
        self.f = Figure()
        
    def generate_separation_problem(self):
        self.sepProb = LpProblem (name='separation '+self.prob.name, sense=LpMinimize)
        self.pi = dict(list((v,LpVariable('pi'+v, None, None, LpContinuous,
                                         None))
                                         for v in self.var)) 
        self.sepProb += lpSum(self.pi[v]*self.x0[v] for v in self.var)

    def generate_xtreme_point(self):
        obj = LpConstraintVar()
        for v in self.prob.variables():
            obj.addVariable(v, self.piCurrent[v.name])
        self.prob.setObjective(obj)
        self.prob.solve()
        #solvers.COIN_CMD.solve(self.prob)
        for v in self.var:
            self.currentXtremePoint[v] = self.var[v].value()
        if self.output == 1:
            currentXtremePointList = self.currentXtremePoint.items()
            currentXtremePointList.sort()
            for v in currentXtremePointList:
                print v[0]+'\t', v[1]
        self.extremePoints.append(self.currentXtremePoint.values())
        return self.prob.objective.value()

    def add_inequality(self):
        # change this, you should not access sense directly call a method
        self.sepProb += lpSum (self.currentXtremePoint[v]*self.pi[v] for v in self.var) >= 1

    def separate(self, output = False, p = None):
        self.output = output
        while True:
            print 'Iteration ', self.iter
            if self.generate_xtreme_point() >= 1-EPS:
                break
            self.add_inequality()
            if self.output:
                print "Separation problem solution status:", LpStatus[self.sepProb.solve()]
                for v in self.var:
                    if self.pi[v].value() is not None:
                        print self.pi[v].name+'\t\t', self.pi[v].value()
                    else:
                        print self.pi[v].name+'\t\t', 0
            self.piPrevious = deepcopy(self.piCurrent)
            for v in self.var:
                if self.pi[v].value() is not None:
                    self.piCurrent[v] = self.pi[v].value()
                else:
                    self.piCurrent[v] = 0
            self.iter += 1
            if p is not None:
                self.f.initialize()
                self.f.add_polyhedron(p, label = 'Polyhedron P')
                xList = (self.x0.values()[0], self.x0.values()[1])
                if len(self.extremePoints) > 2:
                    pp = Polyhedron2D(points = self.extremePoints)
                    self.f.add_polyhedron(pp, color = 'red', linestyle = 'dashed',
                                          label = 'Convex Hull of Generated Points')
                elif len(self.extremePoints) == 1:
                    self.f.add_point(self.extremePoints[0], radius = 0.05, 
                                     color = 'green')
                    self.f.add_text(self.extremePoints[0][0]-0.5, 
                                    self.extremePoints[0][1]-0.08, '$x^0$')
                else:
                    self.f.add_line_segment(self.extremePoints[0], 
                                            self.extremePoints[1], 
                                            color = 'red',
                                            linestyle = 'dashed',
                                            label = 'Convex Hull of Generated Points')
                self.f.set_xlim(p.plot_min[0], p.plot_max[0])
                self.f.set_ylim(p.plot_min[1], p.plot_max[1])
                self.f.add_point(xList, radius = 0.05, color = 'red')
                self.f.add_text(xList[0]-0.5, xList[1]-0.08, '$x^*$')
                dList = (self.piCurrent.values()[0], self.piCurrent.values()[1])
                self.f.add_line(dList, 1, 
                                p.plot_max, p.plot_min, color = 'green', 
                                linestyle = 'dashed', label = 'Separating Hyperplane')
                self.f.show()
            if self.output:
                print self.sepProb.objective.value()            
        x.append(LpVariable('x_'+str(i), 0, None, LpInteger))
    # add obj function
    prob +=  lpSum(mip.c[i]*x[i] for i in range(len(mip.A[0])))
    # add constraints to the prob
    for i in range(len(mip.A)):
        prob +=  mip.A[i][0]*x[0] + mip.A[i][1]*x[1] <= mip.b[i]
    return prob, x, mip

if __name__ == '__main__':
    
    display = True
    prob, vars, mip = read_instance('MIP8')

    if display:
        p = Polyhedron2D(A = mip.A, b = mip.b)
        f = Figure()
        f.add_polyhedron(p, show_int_points = True, label = 'Polyhedron P')
        f.set_xlim(p.plot_min[0], p.plot_max[0])
        f.set_ylim(p.plot_min[1], p.plot_max[1])
        f.add_point(mip.x_sep, radius = 0.05, color = 'red')
        f.add_text(mip.x_sep[0]-0.5, mip.x_sep[1]-0.08, '$x^*$')
        f.show()
    # This is the point to be separated 
    x0 = {}
    for index, value in enumerate(mip.x_sep):
        x0[vars[index].name] = value
    i = 0
    ic = GenericSeparation(prob, x0)
    ic.separate(output = True, p = p)
    print 'separation problem objective value', ic.sepProb.objective.value()
Example #7
0
def disp_relaxation(A, b, cuts = [], sol = None):
    #TODO: Check sense of inequalities by looking explicitly at
    #      lp.constraintsUpper and lp.constraintsLower
    p = Polyhedron2D(A = A, b = b)
    f = Figure()
    f.add_polyhedron(p, label = 'Polyhedron $P$')
    f.set_xlim(p.plot_min[0], p.plot_max[0])
    f.set_ylim(p.plot_min[1], p.plot_max[1])
    pI = p.make_integer_hull()
    f.add_polyhedron(pI, show_int_points = True, color = 'red',
                     linestyle = 'dashed',
                     label = 'Convex hull of integer points')
    for (coeff, r) in cuts:
        f.add_line(coeff, r, plot_max = p.plot_max, plot_min = p.plot_min,
                   color = 'green', linestyle = 'dashed')
    if sol is not None:
        f.add_point(sol, radius = .05)
    f.show()
Example #8
0
def disp_relaxation(A, b, cuts = [], sol = None, disj = []):
    #TODO: Check sense of inequalities by looking explicitly at
    #      lp.constraintsUpper and lp.constraintsLower
    p = Polyhedron2D(A = A, b = b)
    f = Figure()
    f.add_polyhedron(p, label = 'Polyhedron $P$')
    f.set_xlim(p.xlim)
    f.set_ylim(p.ylim)
    pI = p.make_integer_hull()
    f.add_polyhedron(pI, show_int_points = True, color = 'red',
                     linestyle = 'dashed',
                     label = 'Convex hull of integer points')
    for (coeff, r) in cuts:
        f.add_line(coeff, r, p.xlim, p.ylim, color = 'green', linestyle = 'dashed')
    for (coeff, r) in disj:
        f.add_line(coeff, r, p.xlim, p.ylim, color = 'red', linestyle = 'dashed')
    if sol is not None:
        f.add_point(sol, radius = .05)
    f.show()
Example #9
0
class GenericSeparation(object):
    def __init__(self, origProb, x0, pi_init=None):
        if pi_init == None:
            pi_init = [(v.name, 0) for v in self.var.values()]
        self.prob = origProb
        self.iter = 1
        self.x0 = x0
        self.var = origProb.variablesDict()
        self.dim = len(self.var)
        self.currentXtremePoint = {}
        self.solver = None
        self.c = dict(
            list((v.name, c) for v, c in origProb.objective.iteritems()))
        for v in self.var:
            if v in self.c:
                continue
            else:
                self.c[v] = 0.0
        self.generate_separation_problem()
        self.piCurrent = dict([(v.name, pi_init[v.name])
                               for v in self.var.values()])
        self.piPrevious = dict([(v.name, 0) for v in self.var.values()])
        self.extremePoints = []
        self.f = Figure()

    def generate_separation_problem(self):
        self.sepProb = LpProblem(name='separation ' + self.prob.name,
                                 sense=LpMinimize)
        self.pi = dict(
            list((v, LpVariable('pi' + v, None, None, LpContinuous, None))
                 for v in self.var))
        self.sepProb += lpSum(self.pi[v] * self.x0[v] for v in self.var)

    def generate_xtreme_point(self):
        obj = LpConstraintVar()
        for v in self.prob.variables():
            obj.addVariable(v, self.piCurrent[v.name])
        self.prob.setObjective(obj)
        self.prob.solve()
        #solvers.COIN_CMD.solve(self.prob)
        for v in self.var:
            self.currentXtremePoint[v] = self.var[v].value()
        if self.output == 1:
            currentXtremePointList = self.currentXtremePoint.items()
            currentXtremePointList.sort()
            for v in currentXtremePointList:
                print v[0] + '\t', v[1]
        self.extremePoints.append(self.currentXtremePoint.values())
        return self.prob.objective.value()

    def add_inequality(self):
        # change this, you should not access sense directly call a method
        self.sepProb += lpSum(self.currentXtremePoint[v] * self.pi[v]
                              for v in self.var) >= 1

    def separate(self, output=False, p=None):
        self.output = output
        while True:
            print 'Iteration ', self.iter
            if self.generate_xtreme_point() >= 1 - EPS:
                break
            self.add_inequality()
            if self.output:
                print "Separation problem solution status:", LpStatus[
                    self.sepProb.solve()]
                for v in self.var:
                    if self.pi[v].value() is not None:
                        print self.pi[v].name + '\t\t', self.pi[v].value()
                    else:
                        print self.pi[v].name + '\t\t', 0
            self.piPrevious = deepcopy(self.piCurrent)
            for v in self.var:
                if self.pi[v].value() is not None:
                    self.piCurrent[v] = self.pi[v].value()
                else:
                    self.piCurrent[v] = 0
            self.iter += 1
            if p is not None:
                self.f.initialize()
                self.f.add_polyhedron(p, label='Polyhedron P')
                xList = (self.x0.values()[0], self.x0.values()[1])
                if len(self.extremePoints) > 2:
                    pp = Polyhedron2D(points=self.extremePoints)
                    self.f.add_polyhedron(
                        pp,
                        color='red',
                        linestyle='dashed',
                        label='Convex Hull of Generated Points')
                elif len(self.extremePoints) == 1:
                    self.f.add_point(self.extremePoints[0],
                                     radius=0.05,
                                     color='green')
                    self.f.add_text([
                        self.extremePoints[0][0] - 0.5,
                        self.extremePoints[0][1] - 0.08
                    ], '$x^0$')
                else:
                    self.f.add_line_segment(
                        self.extremePoints[0],
                        self.extremePoints[1],
                        color='red',
                        linestyle='dashed',
                        label='Convex Hull of Generated Points')
                self.f.set_xlim(p.xlim)
                self.f.set_ylim(p.ylim)
                self.f.add_point(xList, radius=0.05, color='red')
                self.f.add_text([xList[0] - 0.5, xList[1] - 0.08], '$x^*$')
                dList = (self.piCurrent.values()[0],
                         self.piCurrent.values()[1])
                self.f.add_line(dList,
                                1,
                                p.xlim,
                                p.ylim,
                                color='green',
                                linestyle='dashed',
                                label='Separating Hyperplane')
                self.f.show()
            if self.output:
                print self.sepProb.objective.value()
Example #10
0
    # add obj function
    prob += lpSum(mip.c[i] * x[i] for i in range(len(mip.A[0])))
    # add constraints to the prob
    for i in range(len(mip.A)):
        prob += mip.A[i][0] * x[0] + mip.A[i][1] * x[1] <= mip.b[i]
    return prob, x, mip


if __name__ == '__main__':

    display = True
    prob, vars, mip = read_instance(module_name='MIP8')

    if display:
        p = Polyhedron2D(A=mip.A, b=mip.b)
        f = Figure()
        f.add_polyhedron(p, show_int_points=True, label='Polyhedron P')
        f.set_xlim(p.xlim)
        f.set_ylim(p.ylim)
        f.add_point(mip.x_sep, radius=0.05, color='red')
        f.add_text([mip.x_sep[0] - 0.5, mip.x_sep[1] - 0.08], '$x^*$')
        f.show()

    # This is the point to be separated
    x0 = {}
    for index, value in enumerate(mip.x_sep):
        x0[vars[index].name] = value
    i = 0
    ic = GenericSeparation(prob, x0, {'x_0': -1, 'x_1': 0})
    ic.separate(output=True, p=p)
    print 'separation problem objective value', ic.sepProb.objective.value()
def disp_polyhedron(A = None, b = None, points = None, rays = None, c = None, obj_val = None,
                    opt = None, loc = None):
    if loc is None and opt is not None:
        loc = opt
    f = Figure()
    f.add_polyhedron(p, label = 'Polyhedron $P$', color = 'red')
    f.set_xlim([p.xlim[0], p.xlim[1]+1])
    f.set_ylim([p.ylim[0], p.ylim[1]+2])
    if c is not None and obj_val is not None:
        f.add_line(c, obj_val, p.xlim + [0.2, 0.8], p.ylim + [0.2, 1.8], 
                   linestyle = 'dashed', color = 'black', label = "Objective Function")
    if opt is not None:
        f.add_point(opt, 0.04, 'red')
        f.add_text(loc, r'$x^* = %s$' % str(opt))
    f.show()
def disp_polyhedron(A=None,
                    b=None,
                    points=None,
                    rays=None,
                    c=None,
                    obj_val=None,
                    opt=None,
                    loc=None):
    if loc is None and opt is not None:
        loc = opt
    f = Figure()
    f.add_polyhedron(p, label='Polyhedron $P$', color='red')
    f.set_xlim([p.xlim[0], p.xlim[1] + 1])
    f.set_ylim([p.ylim[0], p.ylim[1] + 2])
    if c is not None and obj_val is not None:
        f.add_line(c,
                   obj_val,
                   p.xlim + [0.2, 0.8],
                   p.ylim + [0.2, 1.8],
                   linestyle='dashed',
                   color='black',
                   label="Objective Function")
    if opt is not None:
        f.add_point(opt, 0.04, 'red')
        f.add_text(loc, r'$x^* = %s$' % str(opt))
    f.show()
Example #13
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)