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_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') f.add_line(coeff, r + 1, p.xlim, p.ylim, color='red', linestyle='dashed') if sol is not None: f.add_point(sol, radius=.05) f.show()
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()
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])
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)