def QPModel(self, addW=False): A = self.A c = self.c s = CyClpSimplex() x = s.addVariable('x', self.nCols) if addW: w = s.addVariable('w', self.nCols) s += A * x >= 1 n = self.nCols if not addW: s += 0 <= x <= 1 else: s += x + w == 1 s += 0 <= w <= 1 ## s += -1 <= x <= 1 s.objective = c * x if addW: G = sparse.lil_matrix((2*n, 2*n)) for i in xrange(n/2, n): #xrange(n-1): G[i, i] = 1 G[2*n-1, 2*n-1] = 10**-10 else: G = sparse.lil_matrix((n, n)) for i in xrange(n/2, n): #xrange(n-1): G[i, i] = 1 s.Hessian = G return s
def test2(self): 'Same as test1, but use cylp indirectly.' s = CyClpSimplex() x = s.addVariable('x', 3) A = np.matrix([[1,2,3], [1,1,1]]) b = CyLPArray([5, 3]) s += A * x == b s += x >= 0 s.objective = 1 * x[0] + 1 * x[1] + 1.1 * x[2] # Solve it a first time s.primal() sol = s.primalVariableSolution['x'] self.assertTrue((abs(sol - np.array([1,2,0]) ) <= 10**-6).all()) # Add a cut s.addConstraint(x[0] >= 1.1) s.primal() sol = s.primalVariableSolution['x'] self.assertTrue((abs(sol - np.array([1.1, 1.8, 0.1]) ) <= 10**-6).all()) # Change the objective function c = csr_matrixPlus([[1, 10, 1.1]]).T s.objective = c.T * x s.primal() sol = s.primalVariableSolution['x'] self.assertTrue((abs(sol - np.array([2, 0, 1]) ) <= 10**-6).all())
def read_instance(module_name = None, file_name = None): if module_name is not None: lp = CyClpSimplex() mip = ilib.import_module(module_name) A = np.matrix(mip.A) #print np.linalg.cond(A) b = CyLPArray(mip.b) #Warning: At the moment, you must put bound constraints in explicitly for split cuts x_l = CyLPArray([0 for _ in range(mip.numVars)]) x = lp.addVariable('x', mip.numVars) lp += x >= x_l try: x_u = CyLPArray(getattr(mip, 'x_u')) lp += x <= x_u except: pass lp += (A * x <= b if mip.sense[1] == '<=' else A * x >= b) c = CyLPArray(mip.c) lp.objective = -c * x if mip.sense[0] == 'Max' else c * x return lp, x, mip.A, mip.b, mip.sense[1], mip.integerIndices elif file_name is not None: lp = CyClpSimplex() m = lp.extractCyLPModel(file_name) x = m.getVarByName('x') integerIndices = [i for (i, j) in enumerate(lp.integerInformation) if j == True] infinity = lp.getCoinInfinity() sense = None for i in range(lp.nRows): if lp.constraintsLower[i] > -infinity: if sense == '<=': print "Function does not support mixed constraint..." break else: sense = '>=' b = lp.constraintsLower if lp.constraintsUpper[i] < infinity: if sense == '>=': print "Function does not support mixed constraint..." break else: sense = '<=' b = lp.constraintsUpper return lp, x, lp.coefMatrix, b, sense, integerIndices else: print "No file or module name specified..." return None, None, None, None, None, None
def model(self): A = self.A c = self.c s = CyClpSimplex() x = s.addVariable('x', self.nCols) s += A * x >= 1 s += 0 <= x <= 1 s.objective = c * x return s
def test_removeVar2(self): s = CyClpSimplex() fp = os.path.join(currentFilePath, '../../input/p0033.mps') s.extractCyLPModel(fp) y = s.addVariable('y', 3) s.primal() x = s.getVarByName('x') s.addConstraint(x[1] + y[1] >= 1.2) #s.primal() s.removeVariable('x') s.primal() s = s.primalVariableSolution self.assertTrue((s['y'] - np.array([0, 1.2, 0]) <= 10**-6).all())
def test_multiDim(self): from cylp.cy import CyClpSimplex from cylp.py.modeling.CyLPModel import CyLPArray s = CyClpSimplex() x = s.addVariable('x', (5, 3, 6)) s += 2 * x[2, :, 3].sum() + 3 * x[0, 1, :].sum() >= 5 s += 0 <= x <= 1 c = CyLPArray(range(18)) s.objective = c * x[2, :, :] + c * x[0, :, :] s.primal() sol = s.primalVariableSolution['x'] self.assertTrue(abs(sol[0, 1, 0] - 1) <= 10**-6) self.assertTrue(abs(sol[2, 0, 3] - 1) <= 10**-6)
def test_ArrayIndexing(self): from cylp.cy import CyClpSimplex from cylp.py.modeling.CyLPModel import CyLPArray s = CyClpSimplex() x = s.addVariable('x', (5, 3, 6)) s += 2 * x[2, :, 3].sum() + 3 * x[0, 1, :].sum() >= 5 s += x[1, 2, [0, 3, 5]] - x[2, 1, np.array([1, 2, 4])] == 1 s += 0 <= x <= 1 c = CyLPArray(range(18)) s.objective = c * x[2, :, :] + c * x[0, :, :] s.primal() sol = s.primalVariableSolution['x'] self.assertTrue(abs(sol[1, 2, 0] - 1) <= 10**-6) self.assertTrue(abs(sol[1, 2, 3] - 1) <= 10**-6) self.assertTrue(abs(sol[1, 2, 5] - 1) <= 10**-6)
def test_onlyBounds2(self): s = CyClpSimplex() x = s.addVariable('x', 3) y = s.addVariable('y', 2) s += y >= 1 s += 2 <= x <= 4 c = CyLPArray([1., -2., 3.]) s.objective = c * x + 2 * y[0] + 2 * y[1] s.primal() sol = np.concatenate((s.primalVariableSolution['x'], s.primalVariableSolution['y'])) self.assertTrue((abs(sol - np.array([2, 4, 2, 1, 1]) ) <= 10**-6).all())
def test_multiDim_Cbc_solve(self): from cylp.cy import CyClpSimplex from cylp.py.modeling.CyLPModel import CyLPArray s = CyClpSimplex() x = s.addVariable('x', (5, 3, 6)) s += 2 * x[2, :, 3].sum() + 3 * x[0, 1, :].sum() >= 5.5 s += 0 <= x <= 2.2 c = CyLPArray(range(18)) s.objective = c * x[2, :, :] + c * x[0, :, :] s.setInteger(x) cbcModel = s.getCbcModel() cbcModel.solve() sol_x = cbcModel.primalVariableSolution['x'] self.assertTrue(abs(sol_x[0, 1, 0] - 1) <= 10**-6) self.assertTrue(abs(sol_x[2, 0, 3] - 2) <= 10**-6)
def read_instance(module_name = True, file_name = None): if module_name: lp = CyClpSimplex() mip = ilib.import_module(module_name) A = np.matrix(mip.A) #print np.linalg.cond(A) b = CyLPArray(mip.b) #We assume variables have zero lower bounds x_l = CyLPArray([0 for _ in range(mip.numVars)]) x = lp.addVariable('x', mip.numVars) lp += x >= x_l try: x_u = CyLPArray(getattr(mip, 'x_u')) lp += x <= x_u except: pass lp += (A * x <= b if mip.sense[1] == '<=' else A * x >= b) c = CyLPArray(mip.c) lp.objective = -c * x if mip.sense[0] == 'Max' else c * x return lp, x, mip.A, mip.b, mip.sense, mip.integerIndices else: #TODO Change sense of inequalities so they are all the same # by explicitly checking lp.constraintsUpper and lp.constraintsLower #Warning: Reading MP not well tested lp.extractCyLPModel(file_name) x = lp.cyLPModel.getVarByName('x') sense = ('Min', '>=') return lp, x, None, None, sense, integerIndices
#if isinstance(key, tuple): if val == 0: # See if necessary to use a tolerance return self.sol[key] = val def __repr__(self): return repr(self.sol) def getCoinInfinity(): return 1.79769313486e+308 if __name__ == '__main__': from cylp.cy import CyClpSimplex from cylp.py.modeling.CyLPModel import CyLPArray s = CyClpSimplex() x = s.addVariable('x', (5, 3, 6)) s += 2 * x[2, :, 3].sum() + 3 * x[0, 1, :].sum() >= 5 s += 0 <= x <= 1 c = CyLPArray(range(18)) s.objective = c * x[2, :, :] + c * x[0, :, :] s.writeMps('/Users/mehdi/Desktop/test.mps') s.primal() sol = s.primalVariableSolution print sol #model = CyLPModel() # #x = model.addVariable('x', 5) #y = model.addVariable('y', 4)
def solve(self, objective, constraints, cached_data, warm_start, verbose, solver_opts): """Returns the result of the call to the solver. Parameters ---------- objective : LinOp The canonicalized objective. constraints : list The list of canonicalized cosntraints. cached_data : dict A map of solver name to cached problem data. warm_start : bool Not used. verbose : bool Should the solver print output? solver_opts : dict Additional arguments for the solver. Returns ------- tuple (status, optimal value, primal, equality dual, inequality dual) """ # Import basic modelling tools of cylp from cylp.cy import CyClpSimplex from cylp.py.modeling.CyLPModel import CyLPArray # Get problem data data = self.get_problem_data(objective, constraints, cached_data) c = data[s.C] b = data[s.B] A = data[s.A] dims = data[s.DIMS] n = c.shape[0] solver_cache = cached_data[self.name()] # Problem model = CyClpSimplex() # Variables x = model.addVariable('x', n) if self.is_mip(data): for i in data[s.BOOL_IDX]: model.setInteger(x[i]) for i in data[s.INT_IDX]: model.setInteger(x[i]) # Constraints # eq model += A[0:dims[s.EQ_DIM], :] * x == b[0:dims[s.EQ_DIM]] # leq leq_start = dims[s.EQ_DIM] leq_end = dims[s.EQ_DIM] + dims[s.LEQ_DIM] model += A[leq_start:leq_end, :] * x <= b[leq_start:leq_end] # no boolean vars available in cbc -> model as int + restrict to [0,1] if self.is_mip(data): for i in data[s.BOOL_IDX]: model += 0 <= x[i] <= 1 # Objective model.objective = c # Build model & solve status = None if self.is_mip(data): cbcModel = model.getCbcModel() # need to convert model if not verbose: cbcModel.logLevel = 0 # Add cut-generators (optional) for cut_name, cut_func in six.iteritems(self.SUPPORTED_CUT_GENERATORS): if cut_name in solver_opts and solver_opts[cut_name]: module = importlib.import_module("cylp.cy.CyCgl") funcToCall = getattr(module, cut_func) cut_gen = funcToCall() cbcModel.addCutGenerator(cut_gen, name=cut_name) # solve status = cbcModel.branchAndBound() else: if not verbose: model.logLevel = 0 status = model.primal() # solve results_dict = {} results_dict["status"] = status if self.is_mip(data): results_dict["x"] = cbcModel.primalVariableSolution['x'] results_dict["obj_value"] = cbcModel.objectiveValue else: results_dict["x"] = model.primalVariableSolution['x'] results_dict["obj_value"] = model.objectiveValue return self.format_results(results_dict, data, cached_data)
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 c = CyLPArray(LP.c) # We are maximizing, so negate objective if LP.sense[1] == 'Min': lp.objective = c * x else: lp.objective = -c * x lp.logLevel = 0 lp.primal(startFinishOptions = 'x')
def tournament(args): # Configuration engine = create_engine('sqlite:///' + args.bdd, echo=False) DBSession.configure(bind=engine) # On récupere les donnes de la BDD students = DBSession.query(Etudiant).filter(Etudiant.enseignant.is_(None)) nb_students = DBSession.query(Etudiant).filter( Etudiant.enseignant.is_(None)).count() nb_parcours = DBSession.query(Parcours).count() # Capacité des groupes capa_min_pec = 14 capa_max_pec = 16 capa_min_pel = 14 capa_max_pel = 16 # On construit le modèle barre_min = args.b model = CyClpSimplex() x = [] s_list = {} for s in students.all(): v = model.addVariable('etu' + str(s.id), nb_parcours, isInt=True) x.append(v) z = 0.0 i = 0 for s in students.all(): reorder = False s_list[str(i)] = s.id voeux = DBSession.query(Voeu).filter(Voeu.idEtudiant == s.id).order_by( Voeu.idParcours).all() s_voeux = [] rang_q = voeux[nb_parcours - 1].rang if rang_q != nb_parcours and rang_q != -1: if s.nom not in special or 'quebec' not in special[s.nom]: reorder = True else: reorder = not special[s.nom]['quebec'] for v in voeux: if v.rang == -1: score = 0 else: if reorder and v.rang > rang_q: rang = v.rang - 1 elif reorder and v.rang == rang_q: rang = 9 else: rang = v.rang malus = 0.0 if s.malus > 0: malus += s.malus if s.absences is not None: malus += float(s.absences) / 15 score = 2.0**(rang - malus) s_voeux.append(score) a = CyLPArray(s_voeux) b = CyLPArray([1.0 for j in range(nb_parcours)]) z += a * x[i] model += b * x[i] >= 1 model += b * x[i] <= 1 model += x[i] >= 0 model += x[i] <= 1 i += 1 model.objective = z # Taille des groupes MpInge (PEL) for j in [ 0, 3, 6 ]: # Attention, dans la BDD, le parcours vont de 1 à 8 -> décalage de 1 c = 0 for i in range(nb_students): c += x[i][j] model += c <= capa_max_pel model += c >= capa_min_pel # Taille des groupes PEC for j in [1, 2, 4, 5, 7]: c = 0 for i in range(nb_students): c += x[i][j] model += c <= capa_max_pec model += c >= capa_min_pec # Etudiants trop bas en maths i = 0 for s in students.all(): if s.moyenneMaths is not None and s.moyenneMaths < barre_min: model += x[i][0] + x[i][3] + x[i][6] == 0 i += 1 # Québec i = 0 for s in students.all(): if s.nom not in special or 'quebec' not in special[s.nom]: model += x[i][nb_parcours - 1] == 0 i += 1 # Cas particuliers (cf special.py) i = 0 for s in students.all(): if s.nom in special and 'force' in special[s.nom]: for cas in special[s.nom]['force']: if not special[s.nom]['force'][cas]: model += x[i][int(cas) - 1] == 0 i += 1 cbc_model = model.getCbcModel() cbc_model.logLevel = 0 cbc_model.branchAndBound() if cbc_model.isRelaxationOptimal() and args.v: for s in students.all(): r = cbc_model.primalVariableSolution['etu' + str(s.id)] print s.nom + '|', j = 1 reorder = False for res in r: if res == 1: if j == 1 or j == 4 or j == 7: print "!", par = DBSession.query(Parcours).filter( Parcours.id == j).one() print par.nom, voeux = DBSession.query(Voeu).filter( Voeu.idEtudiant == s.id).order_by( Voeu.idParcours).all() rang_q = voeux[nb_parcours - 1].rang if rang_q != nb_parcours and rang_q != -1: if s.nom not in special or 'quebec' not in special[ s.nom]: reorder = True else: reorder = not special[s.nom]['quebec'] son_voeu = DBSession.query(Voeu).filter( Voeu.idEtudiant == s.id).filter( Voeu.idParcours == j).one() if reorder and son_voeu.rang == rang_q: rang = 9 elif reorder and son_voeu.rang > rang_q: rang = son_voeu.rang - 1 else: rang = son_voeu.rang print '|' + str(rang) + '', print '|' + str(s.moyenneMaths), print '|' + str(s.absences), if reorder: print '|*' else: print '|' j += 1 nb_stu_grp = [0 for n in range(nb_parcours)] rangs_stu = [0 for n in range(nb_parcours)] indecis = 0 pec2pel = 0 pel2pec = 0 if cbc_model.isRelaxationOptimal() and (args.s or args.csv): for s in students.all(): r = cbc_model.primalVariableSolution['etu' + str(s.id)] j = 1 reorder = False for res in r: if res == 1: nb_stu_grp[j - 1] += 1 voeux = DBSession.query(Voeu).filter( Voeu.idEtudiant == s.id).order_by( Voeu.idParcours).all() rang_q = voeux[nb_parcours - 1].rang if rang_q != nb_parcours and rang_q != -1: if s.nom not in special or 'quebec' not in special[ s.nom]: reorder = True else: reorder = not special[s.nom]['quebec'] son_voeu = DBSession.query(Voeu).filter( Voeu.idEtudiant == s.id).filter( Voeu.idParcours == j).one() if reorder and son_voeu.rang == rang_q: rang = 9 elif reorder and son_voeu.rang > rang_q: rang = son_voeu.rang - 1 else: rang = son_voeu.rang if rang != -1: rangs_stu[rang - 1] += 1 son_voeu_un = DBSession.query(Voeu).filter( Voeu.idEtudiant == s.id).filter( Voeu.rang == 1).one() if son_voeu_un.idParcours in [ 1, 4, 7 ] and son_voeu.idParcours not in [1, 4, 7]: pel2pec += 1 elif son_voeu_un.idParcours not in [ 1, 4, 7 ] and son_voeu.idParcours in [1, 4, 7]: pec2pel += 1 else: indecis += 1 j += 1 if args.s: print "Etudiants par groupe : ", nb_stu_grp print "Etudiants par rang de voeu : ", rangs_stu print "Passages PEC->PEL", pec2pel print "Passage PEL->PEC", pel2pec print "Indécis : ", indecis if args.csv: print barre_min, ",", for item in nb_stu_grp: print item, ",", for item in rangs_stu: print item, ",", print pec2pel, ",", pel2pec if cbc_model.isRelaxationInfeasible(): print "Pas de solution possible"
def solve_ilp(self): """ Solves problem exactly using MIP/ILP approach Used solver: CoinOR CBC Incidence-matrix Q holds complete information needed for opt-process """ if self.verbose: print('Solve: build model') if self.condorcet_red: condorcet_red_mat = extended_condorcet_simple(self.votes_arr) n = self.Q.shape[0] x_n = n * n model = CyClpSimplex() # MODEL x = model.addVariable('x', x_n, isInt=True) # VARS model.objective = self.Q.ravel() # OBJ # x_ab = boolean (already int; need to constrain to [0,1]) model += sp.eye(x_n) * x >= np.zeros(x_n) model += sp.eye(x_n) * x <= np.ones(x_n) idx = lambda i, j: np.ravel_multi_index((i, j), (n, n)) # constraints for every pair start_time = time() n_pairwise_constr = n * (n - 1) // 2 if self.verbose: print(' # pairwise constr: ', n_pairwise_constr) # Somewhat bloated just to get some vectorization / speed ! combs_ = combs(range(n), 2) inds_a = np.ravel_multi_index(combs_.T, (n, n)) inds_b = np.ravel_multi_index(combs_.T[::-1], (n, n)) row_inds = np.tile(np.arange(n_pairwise_constr), 2) col_inds = np.hstack((inds_a, inds_b)) pairwise_constraints = sp.coo_matrix( (np.ones(n_pairwise_constr * 2), (row_inds, col_inds)), shape=(n_pairwise_constr, n * n)) end_time = time() if self.verbose: print(" Took {:.{prec}f} secs".format(end_time - start_time, prec=3)) # and for every cycle of length 3 start_time = time() n_triangle_constrs = n * (n - 1) * (n - 2) if self.verbose: print(' # triangle constr: ', n_triangle_constrs) # Somewhat bloated just to get some vectorization / speed ! perms_ = perms(range(n), 3) inds_a = np.ravel_multi_index(perms_.T[(0, 1), :], (n, n)) inds_b = np.ravel_multi_index(perms_.T[(1, 2), :], (n, n)) inds_c = np.ravel_multi_index(perms_.T[(2, 0), :], (n, n)) row_inds = np.tile(np.arange(n_triangle_constrs), 3) col_inds = np.hstack((inds_a, inds_b, inds_c)) triangle_constraints = sp.coo_matrix( (np.ones(n_triangle_constrs * 3), (row_inds, col_inds)), shape=(n_triangle_constrs, n * n)) end_time = time() if self.verbose: print(" Took {:.{prec}f} secs".format(end_time - start_time, prec=3)) model += pairwise_constraints * x == np.ones(n_pairwise_constr) model += triangle_constraints * x >= np.ones(n_triangle_constrs) if self.condorcet_red: I, J, V = sp.find(condorcet_red_mat) indices_pos = np.ravel_multi_index([J, I], (n, n)) indices_neg = np.ravel_multi_index([I, J], (n, n)) nnz = len(indices_pos) if self.verbose: print( ' Extended Condorcet reductions: {} * 2 relations fixed'. format(nnz)) lhs = sp.coo_matrix( (np.ones(nnz * 2), (np.arange(nnz * 2), np.hstack((indices_pos, indices_neg)))), shape=(nnz * 2, n * n)) rhs = np.hstack( (np.ones(len(indices_pos)), np.zeros(len(indices_neg)))) model += lhs * x == rhs cbcModel = model.getCbcModel() # Clp -> Cbc model / LP -> MIP cbcModel.logLevel = self.verbose if self.verbose: print('Solve: run MIP\n') start_time = time() status = cbcModel.solve() #-> "Call CbcMain. Solve the problem # "using the same parameters used # "by CbcSolver." # This deviates from cylp's docs which are sparse! # -> preprocessing will be used and is very important! end_time = time() if self.verbose: print(" CoinOR CBC used {:.{prec}f} secs".format(end_time - start_time, prec=3)) x_sol = cbcModel.primalVariableSolution['x'] self.obj_sol = cbcModel.objectiveValue x = np.array(x_sol).reshape((n, n)).round().astype(int) self.aggr_rank = np.argsort(x.sum(axis=0))[::-1]
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