def setUp(self): 'Test remove constraint' model = CyLPModel() x = model.addVariable('x', 3) y = model.addVariable('y', 2) A = csc_matrixPlus(([1, 2, 1, 1], ([0, 0, 1, 1], [0, 1, 0, 2])), shape=(2, 3)) B = csc_matrixPlus(([1, 1], ([0, 1], [0, 2])), shape=(2, 3)) D = np.matrix([[1., 2.],[0, 1]]) a = CyLPArray([3, 2.5]) b = CyLPArray([4.2, 3]) x_u= CyLPArray([2., 3.5]) model.addConstraint(A * x <= a, 'res1') model.addConstraint(2 <= B * x + D * y <= b, 'res2') model.addConstraint(y >= 0) model.addConstraint(1.1 <= x[1:3] <= x_u) model.addConstraint(x[0] >= 0.1) c = CyLPArray([1., -2., 3.]) model.objective = c * x + 2 * y[0] + 2 * y[1] s = CyClpSimplex(model) self.s = s self.x = x self.y = y
def test_Sparse(self): model = CyLPModel() x = model.addVariable('x', 3) y = model.addVariable('y', 2) A = csc_matrixPlus(([1, 2, 1, 1], ([0, 0, 1, 1], [0, 1, 0, 2])), shape=(2, 3)) B = csc_matrixPlus(([1, 1], ([0, 1], [0, 2])), shape=(2, 3)) D = np.matrix([[1., 2.], [0, 1]]) a = CyLPArray([5, 2.5]) b = CyLPArray([4.2, 3]) x_u = CyLPArray([2., 3.5]) model.addConstraint(A * x <= a) model.addConstraint(2 <= B * x + D * y <= b) model.addConstraint(y >= 0) model.addConstraint(1.1 <= x[1:3] <= x_u) c = CyLPArray([1., -2., 3.]) model.objective = c * x + 2 * y[0] + 2 * y[1] s = CyClpSimplex(model) s.primal() sol = np.concatenate( (s.primalVariableSolution['x'], s.primalVariableSolution['y'])) self.assertTrue( (abs(sol - np.array([0.2, 2, 1.1, 0, 0.9])) <= 10**-6).all())
def test_Sparse(self): model = CyLPModel() x = model.addVariable('x', 3) y = model.addVariable('y', 2) A = csc_matrixPlus(([1, 2, 1, 1], ([0, 0, 1, 1], [0, 1, 0, 2])), shape=(2, 3)) B = csc_matrixPlus(([1, 1], ([0, 1], [0, 2])), shape=(2, 3)) D = np.matrix([[1., 2.],[0, 1]]) a = CyLPArray([5, 2.5]) b = CyLPArray([4.2, 3]) x_u= CyLPArray([2., 3.5]) model.addConstraint(A*x <= a) model.addConstraint(2 <= B * x + D * y <= b) model.addConstraint(y >= 0) model.addConstraint(1.1 <= x[1:3] <= x_u) c = CyLPArray([1., -2., 3.]) model.objective = c * x + 2 * y[0] + 2 * y[1] s = CyClpSimplex(model) s.primal() sol = np.concatenate((s.primalVariableSolution['x'], s.primalVariableSolution['y'])) self.assertTrue((abs(sol - np.array([0.2, 2, 1.1, 0, 0.9]) ) <= 10**-6).all())
def setUp(self): 'Test remove constraint' model = CyLPModel() x = model.addVariable('x', 3) y = model.addVariable('y', 2) A = csc_matrixPlus(([1, 2, 1, 1], ([0, 0, 1, 1], [0, 1, 0, 2])), shape=(2, 3)) B = csc_matrixPlus(([1, 1], ([0, 1], [0, 2])), shape=(2, 3)) D = np.matrix([[1., 2.], [0, 1]]) a = CyLPArray([3, 2.5]) b = CyLPArray([4.2, 3]) x_u = CyLPArray([2., 3.5]) model.addConstraint(A * x <= a, 'res1') model.addConstraint(2 <= B * x + D * y <= b, 'res2') model.addConstraint(y >= 0) model.addConstraint(1.1 <= x[1:3] <= x_u) model.addConstraint(x[0] >= 0.1) c = CyLPArray([1., -2., 3.]) model.objective = c * x + 2 * y[0] + 2 * y[1] s = CyClpSimplex(model) self.s = s self.x = x self.y = y
def test_scale_scale(self): m = csc_matrixPlus(([1, 2, 6, 4, 5, 7, 3, 2], ([0, 0, 1, 1, 1, 2, 2, 2], [0, 1, 0, 2, 3, 0, 2, 3])), shape=(3, 4), dtype=np.float) unscaledM = m.copy() row_scale = m.row_scale() col_scale = m.col_scale() m.col_scale(1/col_scale) m.row_scale(1/row_scale) assert(((m - unscaledM).todense() < 1.0e-7).all())
def test_scale_scale(self): m = csc_matrixPlus( ([1, 2, 6, 4, 5, 7, 3, 2], ([0, 0, 1, 1, 1, 2, 2, 2], [0, 1, 0, 2, 3, 0, 2, 3])), shape=(3, 4), dtype=np.float, ) unscaledM = m.copy() row_scale = m.row_scale() col_scale = m.col_scale() m.col_scale(1 / col_scale) m.row_scale(1 / row_scale) assert ((m - unscaledM).todense() < 1.0e-7).all()
def makeMatrices(self): ''' Makes coef matrix and rhs vector from CyLPConstraints in self.constraints ''' #if len(self.constraints) == 0: # return self.makeIndexFactory() #self.getVarBounds() # Create the aggregated coef matrix masterCoefMat = None masterCoefMat = None if self.nCons > 0: for varName in self.varNames:# self.pvdims.keys():#self.allVarNames: vmat = self.generateVarMatrix(varName) if vmat is None: vmat = csc_matrixPlus((self.nCons, self.pvdims[varName])) masterCoefMat = sparseConcat(masterCoefMat, vmat, 'h') # Create bound vectors c_lower = np.array([]) c_upper = np.array([]) for c in self.constraints: if not c.isRange: c_lower = np.concatenate((c_lower, c.lower), axis=0) c_upper = np.concatenate((c_upper, c.upper), axis=0) # Create variables bound vectors v_lower = np.array([]) v_upper = np.array([]) if self.nVars: v_lower = -getCoinInfinity() * np.ones(self.nVars) v_upper = getCoinInfinity() * np.ones(self.nVars) for v in self.variables: varinds = self.inds.varIndex[v.name] v_lower[varinds] = v.lower v_upper[varinds] = v.upper #v_lower = np.concatenate((v_lower, v.lower), axis=0) #v_upper = np.concatenate((v_upper, v.upper), axis=0) #if masterCoefMat is not None: return masterCoefMat, c_lower, c_upper, v_lower, v_upper
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 []
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 []