def subproblem(xhat): '''子问题求解 ''' # 初始化问题 r = xp.problem() # 定义变量 y = [xp.var() for i in range(n2)] z = [xp.var(lb=-xp.infinity) for i in range(n1)] epsilon = xp.var(lb=-xp.infinity) r.addVariable(y, z, epsilon) # 定义约束 dummy1 = [z[i] == xhat[i] for i in range(n1)] dummy2 = epsilon == 1 constr=[xp.Sum(A1[ii][jj]*z[jj] for jj in range(n1)) + \ xp.Sum(A2[ii][jj]*y[jj] for jj in range(n2)) \ - epsilon*b[ii]<=0 for ii in range(m)] r.addConstraint(constr, dummy1, dummy2) # 定义目标函数 r.setObjective(xp.Sum(c2[jj] * y[jj] for jj in range(n2)), sense=xp.minimize) r.setControl({"presolve": 0}) # 解该问题 r.setControl('outputlog', 0) r.solve() # 寻找切片 xind1 = [r.getIndex(dummy1[ii]) for ii in range(n1)] # 根据自问题的解的情况判断下一步 if r.getProbStatus() == xp.lp_optimal: # 获得了最优解 print("Optimal Subproblem") dualmult = r.getDual() lamb = [dualmult[ii] for ii in xind1] beta = r.getObjVal() return (lamb, beta, 'Optimal') elif r.getProbStatus() == xp.lp_infeas: # 子问题不可行 print("Infeasible Subproblem") if not r.hasdualray(): print("Could not retrieve a dual ray, return no good cut instead:") xhatones = set(ii for ii in range(n1) if xhat[ii] >= 0.5) lamb = [2 * xhat[ii] - 1 for ii in range(n1)] beta = -sum(xhat) + 1 else: # 求解对偶 dray = [] r.getdualray(dray) print("Dual Ray:", dray) lamb = [dray[ii] for ii in xind1] beta = dray[r.getIndex(dummy2)] return (lamb, beta, 'Infeasible') else: print("ERROR: Subproblem not optimal or infeasible. Terminating.") sys.exit()
def set_variables(self): self.x = np.array([[xp.var(vartype=xp.binary) for j in self.slots] for i in self.slots]) self.c = np.array([xp.var(vartype=xp.binary) for i in self.matches]) # print(self.x.shape) print(self.c.shape) self.m.addVariable(self.x, self.c)
def standard_linearization(quad, lhs_constraints=True, **kwargs): """ Apply the standard linearization to a QP and return resulting model param lhs_constraints: can choose to include optional lower bound constraints (or upper bound if mixed_sign) """ n = quad.n c = quad.c C = quad.C a = quad.a b = quad.b # create model and add variables m = xp.problem(name='standard_linearization') x = np.array([xp.var(vartype=xp.binary) for i in range(n)]) w = np.array([[xp.var(vartype=xp.continuous) for i in range(n)] for i in range(n)]) m.addVariable(x,w) if type(quad) is Knapsack: # HSP and UQP don't have cap constraint # add capacity constraint(s) for k in range(quad.m): m.addConstraint(xp.Sum(x[i]*a[k][i] for i in range(n)) <= b[k]) #k_item constraint if necessary (if KQKP or HSP) if quad.num_items > 0: m.addConstraint(xp.Sum(x[i] for i in range(n)) == quad.num_items) # add auxiliary constraints for i in range(n): for j in range(i+1, n): if lhs_constraints: if C[i,j]+C[j,i] > 0: m.addConstraint(w[i,j] <= x[i]) m.addConstraint(w[i,j] <= x[j]) else: m.addConstraint(x[i]+x[j]-1 <= w[i,j]) m.addConstraint(w[i,j] >= 0) else: m.addConstraint(w[i,j] <= x[i]) m.addConstraint(w[i,j] <= x[j]) m.addConstraint(x[i]+x[j]-1 <= w[i,j]) m.addConstraint(w[i,j] >= 0) #compute quadratic values contirbution to obj quadratic_values = 0 for i in range(n): for j in range(i+1, n): quadratic_values = quadratic_values + (w[i, j]*(C[i, j]+C[j, i])) # set objective function linear_values = sum(x[i]*c[i] for i in range(n)) m.setObjective(linear_values + quadratic_values, sense=xp.maximize) # return model + setup time return [m, 0]
def __init__(self, accs, intervals): self.accs = accs self.accsNum = len(accs) self.intervals = intervals self.intNum = len(intervals) self.matches = np.array(list(combinations(self.accs, 2))) self.p = xp.problem() self.x = np.array([[[xp.var(vartype=xp.binary) for _ in intervals] for _ in accs] for _ in self.accs]) self.m = np.array([xp.var(vartype=xp.binary) for _ in self.matches]) self.p.addVariable(self.x, self.m)
def qsap_ss(qsap, **kwargs): """ Sherali-Smith Linear Formulation for the quadratic semi-assignment problem """ n = qsap.n m = qsap.m e = qsap.e c = qsap.c #create model and add variables mdl = xp.problem(name='qsap_ss') x = np.array([[xp.var(vartype=xp.binary) for i in range(n)]for j in range(m)]) s = np.array([[xp.var(vartype=xp.continuous) for i in range(n)]for j in range(m)]) y = np.array([[xp.var(vartype=xp.continuous) for i in range(n)]for j in range(m)]) mdl.addVariable(x,s,y) mdl.addConstraint((sum(x[i,k] for k in range(n)) == 1) for i in range(m)) start = timer() U = np.zeros((m,n)) L = np.zeros((m,n)) bound_mdl = xp.problem(name='upper_bound_model') bound_mdl.setlogfile("xpress.log") bound_x = np.array([xp.var(vartype=xp.continuous, lb=0, ub=1) for i in range(m) for j in range(n)]).reshape(m,n) bound_mdl.addVariable(bound_x) bound_mdl.addConstraint((sum(bound_x[i,k] for k in range(n)) == 1) for i in range(m)) for i in range(m-1): for k in range(n): bound_mdl.setObjective(sum(sum(c[i,k,j,l]*bound_x[j,l] for l in range(n)) for j in range(i+1,m)), sense=xp.maximize) bound_mdl.solve() U[i,k] = bound_mdl.getObjVal() bound_mdl.setObjective(sum(sum(c[i,k,j,l]*bound_x[j,l] for l in range(n)) for j in range(i+1,m)), sense=xp.minimize) bound_mdl.solve() L[i,k] = bound_mdl.getObjVal() end = timer() setup_time = end-start #add auxiliary constraints for i in range(m-1): for k in range(n): mdl.addConstraint(sum(sum(c[i,k,j,l]*x[j,l] for j in range(i+1,m)) for l in range(n))-s[i,k]-L[i,k]==y[i,k]) mdl.addConstraint(y[i,k] <= (U[i,k]-L[i,k])*(1-x[i,k])) mdl.addConstraint(s[i,k] <= (U[i,k]-L[i,k])*x[i,k]) mdl.addConstraint(y[i,k] >= 0) mdl.addConstraint(s[i,k] >= 0) #set objective function linear_values = sum(sum(e[i,k]*x[i,k] for i in range(m)) for k in range(n)) mdl.setObjective(linear_values + sum(sum(s[i,k]+x[i,k]*(L[i,k]) for i in range(m-1)) for k in range(n)), sense=xp.maximize) #return model + setup time return [mdl, setup_time]
def extended_linear_formulation(quad, **kwargs): """ Apply the extended linear formulation to a QP and return resulting model """ start = timer() n = quad.n c = quad.c C = quad.C a = quad.a b = quad.b #create model and add variables m = xp.problem(name='extended_linear_formulation') x = np.array([xp.var(vartype=xp.binary) for i in range(n)]) z = np.array([[[xp.var(vartype=xp.continuous, lb=-xp.infinity) for i in range(n)] for j in range(n)] for k in range(n)]) m.addVariable(x,z) if type(quad) is Knapsack: #HSP and UQP don't have cap constraint #add capacity constraint(s) for k in range(quad.m): m.addConstraint(xp.Sum(x[i]*a[k][i] for i in range(n)) <= b[k]) #k_item constraint if necessary (if KQKP or HSP) if quad.num_items > 0: m.addConstraint(xp.Sum(x[i] for i in range(n)) == quad.num_items) #add auxiliary constraints for i in range(n): for j in range(i+1,n): m.addConstraint(z[i,i,j]+z[j,i,j] <= 1) if C[i,j] < 0: m.addConstraint(x[i] + z[i,i,j] <= 1) m.addConstraint(x[j] + z[j,i,j] <= 1) elif C[i,j] > 0: m.addConstraint(x[i] + z[i,i,j] + z[j,i,j] >= 1) m.addConstraint(x[j] + z[i,i,j] + z[j,i,j] >= 1) #compute quadratic values contirbution to obj constant = 0 quadratic_values = 0 for i in range(n): for j in range(i+1,n): constant = constant + C[i,j] quadratic_values = quadratic_values + (C[i,j]*(z[i,i,j]+z[j,i,j])) #set objective function linear_values = xp.Sum(x[i]*c[i] for i in range(n)) m.setObjective(linear_values + constant - quadratic_values, sense=xp.maximize) end = timer() setup_time = end-start #return model + setup time return [m, setup_time]
def qsap_standard(qsap, **kwargs): """ standard linearization for the quadratic semi-assignment problem """ n = qsap.n m = qsap.m e = qsap.e c = qsap.c #create model and add variables mdl = xp.problem(name='qsap_standard_linearization') x = np.array([[xp.var(vartype=xp.binary) for i in range(n)]for j in range(m)]) w = np.array([[[[xp.var(vartype=xp.continuous) for i in range(n)]for j in range(m)] for k in range(n)]for l in range(m)]) mdl.addVariable(x,w) mdl.addConstraint((sum(x[i,k] for k in range(n)) == 1) for i in range(m)) #add auxiliary constraints for i in range(m-1): for k in range(n): for j in range(i+1,m): for l in range(n): if lhs_constraints: if c[i,k,j,l]+c[j,l,i,k] > 0: mdl.add_constraint(w[i,k,j,l] <= x[i,k]) mdl.add_constraint(w[i,k,j,l] <= x[j,l]) else: mdl.add_constraint(x[i,k] + x[j,l] - 1 <= w[i,k,j,l]) mdl.add_constraint(w[i,k,j,l] >= 0) else: mdl.add_constraint(w[i,k,j,l] <= x[i,k]) mdl.add_constraint(w[i,k,j,l] <= x[j,l]) mdl.add_constraint(x[i,k] + x[j,l] - 1 <= w[i,k,j,l]) mdl.add_constraint(w[i,k,j,l] >= 0) #compute quadratic values contirbution to obj quadratic_values = 0 for i in range(m-1): for j in range(i+1,m): for k in range(n): for l in range(n): quadratic_values = quadratic_values + (c[i,k,j,l]*(w[i,k,j,l])) linear_values = sum(x[i,k]*e[i,k] for k in range(n) for i in range(m)) mdl.setObjective(linear_values + quadratic_values, sense=xp.maximize) #return model. no setup time for std return [mdl, 0]
def no_linearization(quad, **kwargs): """ Solve a problem using the solver's default approach to quadratics (for cplex, this is the std linearization) """ start = timer() n = quad.n c = quad.c m = xp.problem(name='no_linearization') x = np.array([xp.var(vartype=xp.binary) for i in range(n)]) m.addVariable(x) if type(quad) is Knapsack: #HSP and UQP don't have cap constraint #add capacity constraint(s) for k in range(quad.m): m.addConstraint(xp.Sum(x[i]*quad.a[k][i] for i in range(n)) <= quad.b[k]) #k_item constraint if necessary (if KQKP or HSP) if quad.num_items > 0: m.addConstraint(xp.Sum(x[i] for i in range(n)) == quad.num_items) #compute quadratic values contirbution to obj quadratic_values = 0 for i in range(n): for j in range(i+1,n): quadratic_values = quadratic_values + (x[i]*x[j]*quad.C[i,j]) #set objective function linear_values = xp.Sum(x[i]*c[i] for i in range(n)) m.setObjective(linear_values + quadratic_values, sense=xp.maximize) end = timer() setup_time = end-start return [m, setup_time]
def define_placement_variables(self, placements): self.x = { p: xp.var(vartype=xp.binary, name=f'x_{p.doctor.name}, {p.shift}, {p.hospital}') for p in placements } self.model.addVariable(self.x)
def define_auxiliary_variables_for_doctors(self, doctors): self.t = { d: xp.var(vartype=xp.continuous, lb=0, name=f'Auxiliary for doctor {d.name}') for d in doctors } self.model.addVariable(self.t)
def __init__(self, areas_list, periods): self._areasList = areas_list self._periods = periods self._matches = np.array(list(combinations(self._areasList, 2))) self.p = xp.problem() self.e = np.array([[xp.var(vartype=xp.integer) for _ in self._periods] for _ in areas_list]) self.y = np.array( [[[xp.var(vartype=xp.integer) for _ in self._periods] for _ in areas_list] for _ in areas_list]) self.m = np.array([xp.var(vartype=xp.binary) for _ in self._matches]) self.p.addVariable(self.e, self.y, self.m) self.flow = None self.solutionMatches = None
def define_nightshift_change(self, nightshifts): self.y = { n: xp.var(vartype=xp.integer, lb=-1, ub=1, name=f'y_{n.doctor.name},{n.day}') for n in nightshifts } self.model.addVariable(self.y)
def qsap_elf(qsap, **kwargs): """ extended linear formulation for the quadratic semi-assignment problem """ n = qsap.n m = qsap.m e = qsap.e c = qsap.c mdl = xp.problem(name='qsap_elf') x = np.array([[xp.var(vartype=xp.binary) for i in range(n)]for j in range(m)]) z = np.array([[[[[[xp.var(vartype=xp.continuous, lb=-xp.infinity) for i in range(n)] for j in range(m)] for k in range(n)] for l in range(m)] for r in range(n)] for s in range(m)]) mdl.addVariable(x, z) cons = [xp.constraint(sum(x[i,k] for k in range(n)) == 1) for i in range(m)] mdl.addConstraint(cons) #add auxiliary constraints for i in range(m-1): for j in range(i+1,m): for k in range(n): for l in range(n): mdl.addConstraint(z[i,k,i,k,j,l] + z[j,l,i,k,j,l] <= 1) mdl.addConstraint(x[i,k] + z[i,k,i,k,j,l] <= 1) mdl.addConstraint(x[j,l] + z[j,l,i,k,j,l] <= 1) mdl.addConstraint(x[i,k] + z[i,k,i,k,j,l] + z[j,l,i,k,j,l] >= 1) mdl.addConstraint(x[j,l] + z[i,k,i,k,j,l] + z[j,l,i,k,j,l] >= 1) #compute quadratic values contirbution to obj constant = 0 quadratic_values = 0 for i in range(m-1): for j in range(i+1,m): for k in range(n): for l in range(n): constant = constant + c[i,k,j,l] quadratic_values = quadratic_values + (c[i,k,j,l]*(z[i,k,i,k,j,l]+z[j,l,i,k,j,l])) linear_values = sum(x[i,k]*e[i,k] for k in range(n) for i in range(m)) mdl.setObjective(linear_values + constant - quadratic_values, sense=xp.maximize) #return model + setup time return [mdl, 0]
def add_var(self, lb=0, ub=float("inf"), type="continuous", name=""): """ Add a variable to the model. :param lb: The lower bound of the variable. :param ub: The upper bound of the variable. :param type: either 'binary' or 'continuous' :param name: The name of the variable. (Ignored if falsey). :return: The variable object associated with the model_type engine API """ verify(type in ["continuous", "binary"], "type needs to be 'continuous' or 'binary'") verify( utils.numericish(lb) and utils.numericish(ub), "lb, ub need to be numbers") verify(ub >= lb, "lb cannot be bigger than ub") verify(lb < float("inf"), "lb cannot be positive infinity") verify(ub > -float("inf"), "ub cannot be negative infinity") if type == "binary": ub = 1 if ub == float("inf") else ub verify(lb in [0, 1] and ub in [0, 1], "lb,ub need to be 0 or 1 when type = 'binary'") name_dict = {"name": name} if name else {} if self.model_type == "gurobi": vtype = { "continuous": gurobi.GRB.CONTINUOUS, "binary": gurobi.GRB.BINARY }[type] rtn = self.core_model.addVar(lb=lb, ub=ub, vtype=vtype, **name_dict) return rtn if self.model_type == "cplex": if type == "continuous": return self.core_model.continuous_var(lb=lb, ub=ub, **name_dict) rtn = self.core_model.binary_var(**name_dict) rhs = ub if ub == 0 else (lb if lb == 1 else None) if utils.numericish(rhs): self.core_model.add_constraint(rtn == rhs) return rtn if self.model_type == "xpress": vtype = { "continuous": xpress.continuous, "binary": xpress.binary }[type] rtn = xpress.var(lb=lb, ub=ub, vartype=vtype, **name_dict) self.core_model.addVariable(rtn) return rtn
def bb(A, b): pb = xp.problem() x_lp = np.array([xp.var(vartype=xp.continuous) for _ in range(A.shape[1])]) pb.addVariable(x_lp) pb.addConstraint(xp.Dot(A, x_lp) <= b) pb.setObjective(xp.Dot(c, x_lp), sense=xp.maximize) lb_node = Node(xp.problem(), -1) root_node = Node(pb) is_integer, is_infeasible = root_node.solve() show_tree(root_node) if is_integer: return root_node.pb.getObjVal(), root_node.pb.getSolution() elif is_infeasible: return False, False l_node, r_node = root_node.make_sub_problems() active_nodes = [l_node, r_node] while True: show_tree(root_node) not_pruned_nodes = [] for node in active_nodes: is_integer, is_infeasible = node.solve() if is_integer: if node.objVal > lb_node.objVal: lb_node = node elif not is_infeasible and node.objVal > lb_node.objVal: not_pruned_nodes.append(node) else: node.is_pruned = True # # inp = input() if is_optimal(lb_node, not_pruned_nodes): lb_node.is_optimal = True show_tree(root_node) return lb_node.pb.getObjVal(), lb_node.pb.getSolution() active_nodes = [] for node in not_pruned_nodes: l_node, r_node = node.make_sub_problems() active_nodes.append(l_node) active_nodes.append(r_node)
def _add_var(self, var): varname = self._symbol_map.getSymbol(var, self._labeler) vartype = self._xpress_vartype_from_var(var) lb, ub = self._xpress_lb_ub_from_var(var) xpress_var = xpress.var(name=varname, lb=lb, ub=ub, vartype=vartype) self._solver_model.addVariable(xpress_var) ## bounds on binary variables don't seem to be set correctly ## by the method above if vartype == xpress.binary: if lb == ub: self._solver_model.chgbounds([xpress_var], ['B'], [lb]) else: self._solver_model.chgbounds([xpress_var, xpress_var], ['L', 'U'], [lb,ub]) self._pyomo_var_to_solver_var_map[var] = xpress_var self._solver_var_to_pyomo_var_map[xpress_var] = var self._referenced_variables[var] = 0
def UDPPlocalOpt(airline: air.UDPPairline, slots: List[sl.Slot], xp_problem=None): if xp_problem is None: m = xp.problem() else: m = xp_problem x = np.array([[xp.var(vartype=xp.binary) for j in slots] for i in airline.flights]) m.addVariable(x) flight: fl.UDPPflight for k in range(airline.numFlights): #one x max for slot m.addConstraint( xp.Sum(x[flight.localNum, k] for flight in airline.flights) == 1) for flight in airline.flights: # flight assignment m.addConstraint( xp.Sum(x[flight.localNum, k] for k in range(eta_limit_slot(flight, airline.AUslots), airline.numFlights)) == 1) m.setObjective( xp.Sum( x[flight.localNum][k] * flight.costFun(flight, airline.AUslots[k]) for flight in airline.flights for k in range(airline.numFlights))) m.solve() # print("airline ",airline) for flight in airline.flights: for k in range(airline.numFlights): if m.getSolution(x[flight.localNum, k]) > 0.5: flight.newSlot = airline.flights[k].slot flight.priorityNumber = k flight.priorityValue = "N"
def solve(self, X): """ Implementation of the dual of SVDD problem Params: - X, the dataset without labels Returns: None """ m = X.shape[0] # Define Variables of the problem alphas = [xp.var(lb=0, ub=self.C) for i in range(m)] self.p.addVariable(alphas) # Define Constraints # constr1 = [alpha <= C for alpha in alphas] # p.addConstraint(constr1) # already defined in the definition of the variable as a upper bound # Define objective function obj1 = xp.Sum(alphas[i] * np.sum( self.kernel(X[i].reshape(1, -1), X[i].reshape(1, -1))[0][0]) for i in range(m)) obj2 = xp.Sum(alphas[i] * alphas[j] * np.sum( self.kernel(X[i].reshape(1, -1), X[j].reshape(1, -1))[0][0]) for i in range(m) for j in range(m)) obj = obj1 - obj2 self.p.setObjective(obj, sense=xp.maximize) #set maximization problem # solve the problem self.p.solve() self.opt = np.array( self.p.getSolution(alphas)) #save the values of alphas self.c0 = np.sum(self.opt.reshape(-1, 1) * X, axis=0) indices_support_vectors = self.select_support_vectors( ) #choose a point as support vector self.support_vectors = X[indices_support_vectors]
# Problem: given n, find the n-sided polygon of largest area inscribed # in the unit circle. # # While it is natural to prove that all vertices of a global optimum # reside on the unit circle, here we formulate the problem so that # every vertex i is at distance rho[i] from the center and at angle # theta[i]. We would certainly expect that the local optimum found has # all rho's are equal to 1. N = 9 Vertices = range(N) # Declare variables rho = [xp.var(name='rho_{}'.format(i), lb=1e-5, ub=1.0) for i in Vertices] theta = [ xp.var(name='theta_{}'.format(i), lb=-math.pi, ub=math.pi) for i in Vertices ] p = xp.problem() p.addVariable(rho, theta) # The objective function is the total area of the polygon. Considering # the segment S[i] joining the center to the i-th vertex and A(i,j) # the area of the triangle defined by the two segments S[i] and S[j], # the objective function is # # A[0,1] + A[1,2] + ... + A[N-1,0]
def solve(self): ### Params ### self.n_plyrs_per_game = [ self.game_list[i][1] for i in range(len(self.game_list)) ] req_plyrs_per_round = sum([ct * 2 for ct in self.n_plyrs_per_game]) if self.trim_gms & (req_plyrs_per_round > self.n_plyrs): if self.debug: st.text("Removing games to fit the number of passed players") while req_plyrs_per_round > self.n_plyrs: self.game_list = self.game_list[:-1] self.n_plyrs_per_game = [ self.game_list[i][1] for i in range(len(self.game_list)) ] req_plyrs_per_round = sum( [ct * 2 for ct in self.n_plyrs_per_game]) print(req_plyrs_per_round, self.n_plyrs) # max number of times a player can play a given game self.max_gm_plays = max( 2, math.ceil(req_plyrs_per_round * self.n_rounds / self.n_plyrs)) st.text(f'Final game list: {self.game_list}') if not self.max_gm_plays_soft: st.text( f'Max times a player is allowed to play same game: {self.max_gm_plays}' ) self.n_games = len(self.game_list) ## Instantiate problem ## self.model = xp.problem() ################# ### Variables ### ################# # Player-game-round-team plyrs = {} for p in range(self.n_plyrs): plyrs[p] = {} for g in range(self.n_games): plyrs[p][g] = {} for r in range(self.n_rounds): plyr_var_list = [ xp.var(name=f"p{p}_g{g}_r{r}_t{t}", vartype=xp.binary) for t in range(self.n_tms) ] plyrs[p][g][r] = plyr_var_list self.model.addVariable(plyr_var_list) # Team assignments tms = {} for t in range(self.n_tms): tm_var_list = [ xp.var(name=f"p{p}_tm{t}", vartype=xp.binary) for p in range(self.n_plyrs) ] tms[t] = tm_var_list self.model.addVariable(tm_var_list) # Variable set greater_than/equal_to game_played count for all players for all games - this quantity is minimized max_gm_plays_global = xp.var(name='max_gm_plays_global', lb=0) self.model.addVariable(max_gm_plays_global) ################### ### Constraints ### ################### # Correct number of plyrs per game per team ## Why need both less/greater than and not equal to? for g in range(self.n_games): for r in range(self.n_rounds): for t in range(self.n_tms): suff_plyrs_tm_1 = xp.Sum(plyrs[p][g][r][t] for p in range( self.n_plyrs)) >= self.n_plyrs_per_game[g] suff_plyrs_tm_2 = xp.Sum(plyrs[p][g][r][t] for p in range( self.n_plyrs)) <= self.n_plyrs_per_game[g] self.model.addConstraint( xp.constraint(suff_plyrs_tm_1, name=f'gteq_plyrs_tm{t}_rnd{r}_gm{g}')) self.model.addConstraint( xp.constraint(suff_plyrs_tm_2, name=f'lteq_plyrs_tm{t}_rnd{r}_gm{g}')) # One game per time per player for p in range(self.n_plyrs): for r in range(self.n_rounds): for t in range(self.n_tms): one_game_per_round_per_plyr = xp.Sum( plyrs[p][g][r][t] for g in range(self.n_games)) <= 1 self.model.addConstraint( xp.constraint( one_game_per_round_per_plyr, name=f"one_gm_in_rnd{r}_for_plyr{p}_tm{t}")) # Team assignment constraints for p in range(self.n_plyrs): # One team per player tm_lb = xp.Sum(tms[t][p] for t in range(self.n_tms)) <= 1 tm_ub = xp.Sum(tms[t][p] for t in range(self.n_tms)) >= 1 self.model.addConstraint( xp.constraint(tm_lb, name=f'plyr{p}_lteq_1_tm')) self.model.addConstraint( xp.constraint(tm_ub, name=f'plyr{p}_gteq_1_tm')) for t in range(self.n_tms): # Forcing tm variables to be flipped when player selected tm_enforce = xp.Sum( plyrs[p][g][r][t] for g in range(self.n_games) for r in range(self.n_rounds)) <= tms[t][p] * self.n_rounds self.model.addConstraint( xp.constraint(tm_enforce, name=f'plyr{p}_tm{t}_enforce')) # Teams evenly split tms_even_1 = xp.Sum(tms[0][p] for p in range(self.n_plyrs)) - xp.Sum( tms[1][p] for p in range(self.n_plyrs)) <= 1 tms_even_2 = xp.Sum(tms[1][p] for p in range(self.n_plyrs)) - xp.Sum( tms[0][p] for p in range(self.n_plyrs)) <= 1 self.model.addConstraint(tms_even_1) self.model.addConstraint(tms_even_2) # Each player plays each game at most 'self.max_gm_plays' for p in range(self.n_plyrs): for g in range(self.n_games): for t in range(self.n_tms): max_rds_per_game_per_plyr = xp.Sum( plyrs[p][g][r][t] for r in range(self.n_rounds)) if not self.max_gm_plays_soft: self.model.addConstraint( xp.constraint( max_rds_per_game_per_plyr <= self.max_gm_plays, name= f"plyr{p}_plays_gm{g}_max_{self.max_gm_plays}_times_tm{t}" )) self.model.addConstraint( xp.constraint( max_gm_plays_global >= max_rds_per_game_per_plyr, name=f'max_gm_plays_global_gteq_p{p}_g{g}_t{t}')) # Each player plays at most once more than every other player for p1 in range(self.n_plyrs): n_plays = xp.Sum(plyrs[p1][g][r][t] for g in range(self.n_games) for r in range(self.n_rounds) for t in range(self.n_tms)) for p2 in range(p1 + 1, self.n_plyrs): n_plays_ = xp.Sum(plyrs[p2][g][r][t] for g in range(self.n_games) for r in range(self.n_rounds) for t in range(self.n_tms)) self.model.addConstraint( (n_plays - n_plays_) <= self.max_gm_gap) self.model.addConstraint( (n_plays_ - n_plays) <= self.max_gm_gap) # Objective self.model.setObjective(max_gm_plays_global, sense=xp.minimize) self.model.solve() self.check_model_feasibility() return plyrs, tms
def create_variable(problem, edge, prefix="x", var_args=None): """ Create a single xpress variable and return it """ name = mip_utils.name_variable(edge, prefix=prefix) return xp.var(name=name, **var_args)
# # Example: changing an optimization problem # using the Xpress Python interface # import xpress as xp x = xp.var() y = xp.var() cons1 = x + y >= 2 upperlim = 2 * x + y <= 3 p = xp.problem() p.addVariable(x, y) p.setObjective((x - 4)**2 + (y - 1)**2) p.addConstraint(cons1, upperlim) p.write('original', 'lp') p.chgcoef(cons1, x, 3) # coefficient of x in cons1 becomes 3 p.chgcoef(1, 0, 4) # coefficient of y in upperlim becomes 4 p.write('changed', 'lp')
from __future__ import print_function import xpress as xp # # Construct a problem using addVariable and addConstraint, then use # the Xpress API routines to amend the problem with rows and quadratic # terms. # p = xp.problem () N = 5 S = range (N) x = [xp.var (vartype = xp.binary) for i in S] p.addVariable (x) # vectors can be used whole or addressed with their index c0 = xp.Sum (x) <= 10 cc = [x[i]/1.1 <= x[i+1]*2 for i in range (N-1)] p.addConstraint (c0, cc) p.setObjective (3 - x[0]) mysol = [0, 0, 1, 1, 1, 1.4] # add a variable with its coefficients
p = xp.problem () # fill in a problem with three variables and four constraints p.loadproblem ("", # probname ['G','G','E', 'L'], # qrtypes [-2.4, -3, 4, 5], # rhs None, # range [3,4,5], # obj [0,2,4,8], # mstart None, # mnel [0,1,2,3,0,1,2,3], # mrwind [1,1,1,1,1,1,1,1], # dmatval [-1,-1,-1], # lb [3,5,8], # ub colnames = ['x1','x2','x3'], # column names rownames = ['row1','row2','row3','constr_04']) # row names p.write ("loadlp", "lp") p.solve () # Create another variable and add it, then modify the objective # function. Note that the objective function is replaced by, not # amended with, the new objective x = xp.var() p.addVariable (x) p.setObjective (x**2 + 2*x + 444) p.solve() p.write ("updated", "lp")
def solve_via_data(self, data, warm_start, verbose, solver_opts, solver_cache=None): import xpress if 'no_qp_reduction' in solver_opts.keys( ) and solver_opts['no_qp_reduction'] is True: self.translate_back_QP_ = True c = data[s.C] # objective coefficients dims = dims_to_solver_dict( data[s.DIMS]) # contains number of columns, rows, etc. nrowsEQ = dims[s.EQ_DIM] nrowsLEQ = dims[s.LEQ_DIM] nrows = nrowsEQ + nrowsLEQ # linear constraints b = data[s.B][:nrows] # right-hand side A = data[s.A][:nrows] # coefficient matrix # Problem self.prob_ = xpress.problem() mstart = makeMstart(A, len(c), 1) varGroups = { } # If origprob is passed, used to tie IIS to original constraints transf2Orig = { } # Ties transformation constraints to originals via varGroups nOrigVar = len(c) # Uses flat naming. Warning: this mixes # original with auxiliary variables. varnames = ['x_{0:05d}'.format(i) for i in range(len(c))] linRownames = ['lc_{0:05d}'.format(i) for i in range(len(b))] self.prob_.loadproblem( "CVXproblem", ['E'] * nrowsEQ + ['L'] * nrowsLEQ, # qrtypes None, # range c, # obj coeff mstart, # mstart None, # mnel A.indices, # row indices A.data, # coefficients [-xpress.infinity] * len(c), # lower bound [xpress.infinity] * len(c), # upper bound colnames=varnames, # column names rownames=linRownames) # row names x = np.array(self.prob_.getVariable()) # get whole variable vector # Set variable types for discrete variables self.prob_.chgcoltype( data[s.BOOL_IDX] + data[s.INT_IDX], 'B' * len(data[s.BOOL_IDX]) + 'I' * len(data[s.INT_IDX])) currow = nrows iCone = 0 auxVars = set(range(nOrigVar, len(c))) # Conic constraints # # Quadratic objective and constraints fall in this category, # as all quadratic stuff is converted into a cone via a linear transformation for k in dims[s.SOC_DIM]: # k is the size of the i-th cone, where i is the index # within dims [s.SOC_DIM]. The cone variables in # CVXOPT, apparently, are separate variables that are # marked as conic but not shown in a cone explicitly. A = data[s.A][currow:currow + k].tocsr() b = data[s.B][currow:currow + k] currow += k if self.translate_back_QP_: # Conic problem passed by CVXPY is translated back # into a QP problem. The problem is passed to us # as follows: # # min c'x # s.t. Ax <>= b # y[i] = P[i]' * x + b[i] # ||y[i][1:]||_2 <= y[i][0] # # where P[i] is a matrix, b[i] is a vector. Get # rid of the y variables by explicitly rewriting # the conic constraint as quadratic: # # y[i][1:]' * y[i][1:] <= y[i][0]^2 # # and hence # # (P[i][1:]' * x + b[i][1:])^2 <= (P[i][0]' * x + b[i][0])^2 Plhs = A[1:] Prhs = A[0] indRowL, indColL = Plhs.nonzero() indRowR, indColR = Prhs.nonzero() coeL = Plhs.data coeR = Prhs.data lhs = list(b[1:]) rhs = b[0] for i in range(len(coeL)): lhs[indRowL[i]] -= coeL[i] * x[indColL[i]] for i in range(len(coeR)): rhs -= coeR[i] * x[indColR[i]] self.prob_.addConstraint( xpress.Sum([lhs[i]**2 for i in range(len(lhs))]) <= rhs**2) else: # Create new (cone) variables and add them to the problem conevar = np.array([ xpress.var(name='cX{0:d}_{1:d}'.format(iCone, i), lb=-xpress.infinity if i > 0 else 0) for i in range(k) ]) self.prob_.addVariable(conevar) initrow = self.prob_.attributes.rows mstart = makeMstart(A, k, 0) trNames = [ 'linT_qc{0:d}_{1:d}'.format(iCone, i) for i in range(k) ] # Linear transformation for cone variables <--> original variables self.prob_.addrows( ['E'] * k, # qrtypes b, # rhs mstart, # mstart A.indices, # ind A.data, # dmatval names=trNames) # row names self.prob_.chgmcoef([initrow + i for i in range(k)], conevar, [1] * k) conename = 'cone_qc{0:d}'.format(iCone) # Real cone on the cone variables (if k == 1 there's no # need for this constraint as y**2 >= 0 is redundant) if k > 1: self.prob_.addConstraint( xpress.constraint(constraint=xpress.Sum( conevar[i]**2 for i in range(1, k)) <= conevar[0]**2, name=conename)) auxInd = list(set(A.indices) & auxVars) if len(auxInd) > 0: group = varGroups[varnames[auxInd[0]]] for i in trNames: transf2Orig[i] = group transf2Orig[conename] = group iCone += 1 # Objective. Minimize is by default both here and in CVXOPT self.prob_.setObjective(xpress.Sum(c[i] * x[i] for i in range(len(c)))) # End of the conditional (warm-start vs. no warm-start) code, # set options, solve, and report. # Set options # # The parameter solver_opts is a dictionary that contains only # one key, 'solver_opt', and its value is a dictionary # {'control': value}, matching perfectly the format used by # the Xpress Python interface. if verbose: self.prob_.controls.miplog = 2 self.prob_.controls.lplog = 1 self.prob_.controls.outputlog = 1 else: self.prob_.controls.miplog = 0 self.prob_.controls.lplog = 0 self.prob_.controls.outputlog = 0 if 'solver_opts' in solver_opts.keys(): self.prob_.setControl(solver_opts['solver_opts']) self.prob_.setControl({ i: solver_opts[i] for i in solver_opts.keys() if i in xpress.controls.__dict__.keys() }) # Solve self.prob_.solve() results_dict = { 'problem': self.prob_, 'status': self.prob_.getProbStatus(), 'obj_value': self.prob_.getObjVal(), } status_map_lp, status_map_mip = self.get_status_maps() if self.is_mip(data): status = status_map_mip[results_dict['status']] else: status = status_map_lp[results_dict['status']] results_dict[s.XPRESS_TROW] = transf2Orig results_dict[ s.XPRESS_IIS] = None # Return no IIS if problem is feasible if status in s.SOLUTION_PRESENT: results_dict['x'] = self.prob_.getSolution() if not (data[s.BOOL_IDX] or data[s.INT_IDX]): results_dict['y'] = self.prob_.getDual() elif status == s.INFEASIBLE: # Retrieve all IIS. For LPs there can be more than one, # but for QCQPs there is only support for one IIS. iisIndex = 0 self.prob_.iisfirst(0) # compute all IIS row, col, rtype, btype, duals, rdcs, isrows, icols = [], [], [], [], [], [], [], [] self.prob_.getiisdata(0, row, col, rtype, btype, duals, rdcs, isrows, icols) origrow = [] for iRow in row: if iRow.name in transf2Orig.keys(): name = transf2Orig[iRow.name] else: name = iRow.name if name not in origrow: origrow.append(name) results_dict[s.XPRESS_IIS] = [{ 'orig_row': origrow, 'row': row, 'col': col, 'rtype': rtype, 'btype': btype, 'duals': duals, 'redcost': rdcs, 'isolrow': isrows, 'isolcol': icols }] while self.prob_.iisnext() == 0: iisIndex += 1 self.prob_.getiisdata(iisIndex, row, col, rtype, btype, duals, rdcs, isrows, icols) results_dict[s.XPRESS_IIS].append( (row, col, rtype, btype, duals, rdcs, isrows, icols)) # Generate solution. solution = {} if results_dict["status"] != s.SOLVER_ERROR: self.prob_ = results_dict['problem'] vartypes = [] self.prob_.getcoltype(vartypes, 0, len(data[s.C]) - 1) status_map_lp, status_map_mip = self.get_status_maps() if data[s.BOOL_IDX] or data[s.INT_IDX]: solution[s.STATUS] = status_map_mip[results_dict['status']] else: solution[s.STATUS] = status_map_lp[results_dict['status']] if solution[s.STATUS] in s.SOLUTION_PRESENT: solution[s.PRIMAL] = results_dict['x'] solution[s.VALUE] = results_dict['obj_value'] if not (data[s.BOOL_IDX] or data[s.INT_IDX]): solution[s.EQ_DUAL] = [-v for v in results_dict['y']] solution[s.XPRESS_IIS] = results_dict[s.XPRESS_IIS] solution[s.XPRESS_TROW] = results_dict[s.XPRESS_TROW] return solution
def max_flow(): global graph global vertices_no global vertices global weight thres = 0.4 # density of network thresdem = 0.8 # density of demand mesh dem = [] for i in range(vertices_no): for j in range(vertices_no): if i != j and np.random.random() < thresdem: dem.append((vertices[i], vertices[j], math.ceil(200 * np.random.random()))) print("This is a random demand for each node", dem) for i in range(vertices_no): for j in range(vertices_no): if graph[i][j] != 0: pair = vertices[i], vertices[j] print(pair) #*********************************************************************************************************************** #flow variables f = {(i, j, d): xp.var(name='f_{0}_{1}_{2}_{3}'.format(i, j, dem[d][0], dem[d][1])) for (i, j) in pair for d in range(len(dem))} # capacity variables x = {(i, j): xp.var(vartype=xp.integer, name='cap_{0}_{1}'.format(i, j)) for (i, j) in pair} print("this is x", x) p = xp.problem('network flow') p.addVariable(f, x) def demand(i, d): if dem[d][0] == i: # source return 1 elif dem[d][1] == i: # destination return -1 else: return 0 # Flow conservation constraints: total flow balance at node i for each demand d # must be 0 if i is an intermediate node, 1 if i is the source of demand d, and # -1 if i is the destination. flow = {(i, d): xp.constraint( constraint=xp.Sum(f[vertices[i], vertices[j], d] for j in range(vertices_no) if (vertices[i], vertices[j]) in weight) - xp.Sum(f[vertices[j], vertices[i], d] for j in range(vertices_no) if (vertices[j], vertices[i]) in weight) == demand( vertices[i], d), name='cons_{0}_{1}_{2}'.format(i, dem[d][0], dem[d][1])) for d in range(len(dem)) for i in range(vertices_no)} # Capacity constraints: weighted sum of flow variables must be contained in the # total capacity installed on the arc (i, j) capacity = { (i, j): xp.constraint(constraint=xp.Sum( dem[d][2] * f[vertices[i], vertices[j], d] for d in range(len(dem))) <= x[vertices[i], vertices[j]], name='capacity_{0}_{1}'.format(vertices[i], vertices[j])) for (i, j) in weight } p.addConstraint(flow, capacity) p.setObjective(xp.Sum(x[i, j] for (i, j) in weight)) p.solve() p.getSolution()
#!/bin/env python # Test problem on a dot product between matrices of scalars and/or of # variables. Note that the problem cannot be solved by the Optimizer # as it is nonconvex. from __future__ import print_function import xpress as xp import numpy as np a = 0.1 + np.arange(21).reshape(3, 7) y = np.array([xp.var() for i in range(21)]).reshape(3, 7) x = np.array([xp.var() for i in range(35)]).reshape(7, 5) p = xp.problem() p.addVariable(x, y) p.addConstraint(xp.Dot(y, x) <= 0) p.addConstraint(xp.Dot(a, x) == 1) p.setObjective(x[0][0]) p.write("test6-nonconv", "lp") p.solve()
# Q and a point x0, minimize the quadratic function # # x' (Q + alpha I) x # # subject to the linear system Q (x - x0) = 1 and nonnegativity on all # variables. Report solution if available from __future__ import print_function import xpress as xp import numpy as np N = 10 Q = np.arange(1, N**2 + 1).reshape(N, N) x = np.array([xp.var() for i in range(N)]) x0 = np.random.random(N) p = xp.problem() p.addVariable(x) # c1 and c2 are two systems of constraints of size N each written as # # (x-x0)' Q = 1 # # Qx >= 0 c1 = -xp.Dot((x - x0), Q) == 1 c2 = xp.Dot(Q, x) >= 0
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 Should the previous solver result be used to warm_start? 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 xpress verbose = True # Get problem data data = super(XPRESS, self).get_problem_data(objective, constraints, cached_data) origprob = None if 'original_problem' in solver_opts.keys(): origprob = solver_opts['original_problem'] if 'no_qp_reduction' in solver_opts.keys() and solver_opts['no_qp_reduction'] is True: self.translate_back_QP_ = True c = data[s.C] # objective coefficients dims = data[s.DIMS] # contains number of columns, rows, etc. nrowsEQ = dims[s.EQ_DIM] nrowsLEQ = dims[s.LEQ_DIM] nrows = nrowsEQ + nrowsLEQ # linear constraints b = data[s.B][:nrows] # right-hand side A = data[s.A][:nrows] # coefficient matrix n = c.shape[0] # number of variables solver_cache = cached_data[self.name()] ########################################################################################### # Allow warm start if all dimensions match, i.e., if the # modified problem has the same number of rows/column and the # same list of cone sizes. Failing that, we can just take the # standard route and build the problem from scratch. if warm_start and \ solver_cache.prev_result is not None and \ n == len(solver_cache.prev_result['obj']) and \ nrows == len(solver_cache.prev_result['rhs']) and \ data[s.DIMS][s.SOC_DIM] == solver_cache.prev_result['cone_ind']: # We are re-solving a problem that was previously solved # Initialize the problem as the same as the previous solve self.prob_ = solver_cache.prev_result['problem'] c0 = solver_cache.prev_result['obj'] A0 = solver_cache.prev_result['mat'] b0 = solver_cache.prev_result['rhs'] vartype0 = solver_cache.prev_result['vartype'] # If there is a parameter in the objective, it may have changed. if len(linutils.get_expr_params(objective)) > 0: dci = numpy.where(c != c0)[0] self.prob_.chgobj(dci, c[dci]) # Get equality and inequality constraints. sym_data = self.get_sym_data(objective, constraints, cached_data) all_constrs, _, _ = self.split_constr(sym_data.constr_map) # If there is a parameter in the constraints, # A or b may have changed. if any(len(linutils.get_expr_params(con.expr)) > 0 for con in constraints): dAi = (A != A0).tocoo() # retrieves row/col nonzeros as a tuple of two arrays dbi = numpy.where(b != b0)[0] if dAi.getnnz() > 0: self.prob_.chgmcoef(dAi.row, dAi.col, [A[i, j] for (i, j) in list(zip(dAi.row, dAi.col))]) if len(dbi) > 0: self.prob_.chgrhs(dbi, b[dbi]) vartype = [] self.prob_.getcoltype(vartype, 0, len(data[s.C]) - 1) vti = (numpy.array(vartype) != numpy.array(vartype0)) if any(vti): self.prob_.chgcoltype(numpy.arange(len(c))[vti], vartype[vti]) ############################################################################################ else: # No warm start, create problem from scratch # Problem self.prob_ = xpress.problem() mstart = makeMstart(A, len(c), 1) varGroups = {} # If origprob is passed, used to tie IIS to original constraints transf2Orig = {} # Ties transformation constraints to originals via varGroups nOrigVar = len(c) # From a summary knowledge of origprob.constraints() and # the constraints list, the following seems to hold: # # 1) origprob.constraints is the list as generated by the # user. origprob.constraints[i].size returns the number # of actual rows in each constraint, while .constr_id # returns its id (not necessarily numbered from 0). # # 2) constraints is also a list whose every element # contains fields size and constr_id. These correspond # to the items in origprob.constraints, though the list # is in not in order of constr_id. Also, given that it # refers to the transformed problem, it contains extra # constraints deriving from the cone transformations, # all with a constr_id and a size. # # Given this information, attempt to set names in varnames # and linRownames so that they can be easily identified # Load linear part of the problem. if origprob is not None: # The original problem was passed, we can take a # better guess at the constraints and variable names. nOrigVar = 0 orig_id = [i.id for i in origprob.constraints] varnames = [] for v in origprob.variables(): nOrigVar += v.size[0] if v.size[0] == 1: varnames.append('{0}'. format(v.var_id)) else: varnames.extend(['{0}_{1:d}'. format(v.var_id, j) for j in range(v.size[0])]) varnames.extend(['aux_{0:d}'.format(i) for i in range(len(varnames), len(c))]) # Construct constraint name list by checking constr_id for each linRownames = [] for con in constraints: if con.constr_id in orig_id: prefix = '' if type(con.constr_id) == int: prefix = 'row_' if con.size[0] == 1: name = '{0}{1}'.format(prefix, con.constr_id) linRownames.append(name) transf2Orig[name] = con.constr_id else: names = ['{0}{1}_{2:d}'.format(prefix, con.constr_id, j) for j in range(con.size[0])] linRownames.extend(names) for i in names: transf2Orig[i] = con.constr_id # Tie auxiliary variables to constraints. Scan all # auxiliary variables in the objective function and in # the corresponding columns of A.indices iObjQuad = 0 # keeps track of quadratic quantities in the objective for i in range(nOrigVar, len(c)): if c[i] != 0: varGroups[varnames[i]] = 'objF_{0}'.format(iObjQuad) iObjQuad += 1 if len(A.indices[mstart[i]:mstart[i+1]]) > 0: varGroups[varnames[i]] = linRownames[min(A.indices[mstart[i]:mstart[i+1]])] else: # fall back to flat naming. Warning: this mixes # original with auxiliary variables. varnames = ['x_{0:05d}'. format(i) for i in range(len(c))] linRownames = ['lc_{0:05d}'.format(i) for i in range(len(b))] self.prob_.loadproblem("CVXproblem", ['E'] * nrowsEQ + ['L'] * nrowsLEQ, # qrtypes b, # rhs None, # range c, # obj coeff mstart, # mstart None, # mnel A.indices, # row indices A.data, # coefficients [-xpress.infinity] * len(c), # lower bound [xpress.infinity] * len(c), # upper bound colnames=varnames, # column names rownames=linRownames) # row names x = numpy.array(self.prob_.getVariable()) # get whole variable vector # Set variable types for discrete variables self.prob_.chgcoltype(data[s.BOOL_IDX] + data[s.INT_IDX], 'B' * len(data[s.BOOL_IDX]) + 'I' * len(data[s.INT_IDX])) currow = nrows iCone = 0 auxVars = set(range(nOrigVar, len(c))) # Conic constraints # # Quadratic objective and constraints fall in this category, # as all quadratic stuff is converted into a cone via a linear transformation for k in dims[s.SOC_DIM]: # k is the size of the i-th cone, where i is the index # within dims [s.SOC_DIM]. The cone variables in # CVXOPT, apparently, are separate variables that are # marked as conic but not shown in a cone explicitly. A = data[s.A][currow: currow + k].tocsr() b = data[s.B][currow: currow + k] currow += k if self.translate_back_QP_: # Conic problem passed by CVXPY is translated back # into a QP problem. The problem is passed to us # as follows: # # min c'x # s.t. Ax <>= b # y[i] = P[i]' * x + b[i] # ||y[i][1:]||_2 <= y[i][0] # # where P[i] is a matrix, b[i] is a vector. Get # rid of the y variables by explicitly rewriting # the conic constraint as quadratic: # # y[i][1:]' * y[i][1:] <= y[i][0]^2 # # and hence # # (P[i][1:]' * x + b[i][1:])^2 <= (P[i][0]' * x + b[i][0])^2 Plhs = A[1:] Prhs = A[0] indRowL, indColL = Plhs.nonzero() indRowR, indColR = Prhs.nonzero() coeL = Plhs.data coeR = Prhs.data lhs = list(b[1:]) rhs = b[0] for i in range(len(coeL)): lhs[indRowL[i]] -= coeL[i] * x[indColL[i]] for i in range(len(coeR)): rhs -= coeR[i] * x[indColR[i]] self.prob_.addConstraint(xpress.Sum([lhs[i]**2 for i in range(len(lhs))]) <= rhs**2) else: # Create new (cone) variables and add them to the problem conevar = numpy.array([xpress.var(name='cX{0:d}_{1:d}'.format(iCone, i), lb=-xpress.infinity if i > 0 else 0) for i in range(k)]) self.prob_.addVariable(conevar) initrow = self.prob_.attributes.rows mstart = makeMstart(A, k, 0) trNames = ['linT_qc{0:d}_{1:d}'.format(iCone, i) for i in range(k)] # Linear transformation for cone variables <--> original variables self.prob_.addrows(['E'] * k, # qrtypes b, # rhs mstart, # mstart A.indices, # ind A.data, # dmatval names=trNames) # row names self.prob_.chgmcoef([initrow + i for i in range(k)], conevar, [1] * k) conename = 'cone_qc{0:d}'.format(iCone) # Real cone on the cone variables (if k == 1 there's no # need for this constraint as y**2 >= 0 is redundant) if k > 1: self.prob_.addConstraint( xpress.constraint(constraint=xpress.Sum (conevar[i]**2 for i in range(1, k)) <= conevar[0] ** 2, name=conename)) auxInd = list(set(A.indices) & auxVars) if len(auxInd) > 0: group = varGroups[varnames[auxInd[0]]] for i in trNames: transf2Orig[i] = group transf2Orig[conename] = group iCone += 1 # Objective. Minimize is by default both here and in CVXOPT self.prob_.setObjective(xpress.Sum(c[i] * x[i] for i in range(len(c)))) # End of the conditional (warm-start vs. no warm-start) code, # set options, solve, and report. # Set options # # The parameter solver_opts is a dictionary that contains only # one key, 'solver_opt', and its value is a dictionary # {'control': value}, matching perfectly the format used by # the Xpress Python interface. if verbose: self.prob_.controls.miplog = 2 self.prob_.controls.lplog = 1 self.prob_.controls.outputlog = 1 else: self.prob_.controls.miplog = 0 self.prob_.controls.lplog = 0 self.prob_.controls.outputlog = 0 if 'solver_opts' in solver_opts.keys(): self.prob_.setControl(solver_opts['solver_opts']) self.prob_.setControl({i: solver_opts[i] for i in solver_opts.keys() if i in xpress.controls.__dict__.keys()}) # Solve self.prob_.solve() results_dict = { 'problem': self.prob_, 'status': self.prob_.getProbStatus(), 'obj_value': self.prob_.getObjVal(), } status_map_lp, status_map_mip = self.get_status_maps() if self.is_mip(data): status = status_map_mip[results_dict['status']] else: status = status_map_lp[results_dict['status']] results_dict[s.XPRESS_TROW] = transf2Orig results_dict[s.XPRESS_IIS] = None # Return no IIS if problem is feasible if status in s.SOLUTION_PRESENT: results_dict['x'] = self.prob_.getSolution() if not self.is_mip(data): results_dict['y'] = self.prob_.getDual() elif status == s.INFEASIBLE: # Retrieve all IIS. For LPs there can be more than one, # but for QCQPs there is only support for one IIS. iisIndex = 0 self.prob_.iisfirst(0) # compute all IIS row, col, rtype, btype, duals, rdcs, isrows, icols = [], [], [], [], [], [], [], [] self.prob_.getiisdata(0, row, col, rtype, btype, duals, rdcs, isrows, icols) origrow = [] for iRow in row: if iRow.name in transf2Orig.keys(): name = transf2Orig[iRow.name] else: name = iRow.name if name not in origrow: origrow.append(name) results_dict[s.XPRESS_IIS] = [{'orig_row': origrow, 'row': row, 'col': col, 'rtype': rtype, 'btype': btype, 'duals': duals, 'redcost': rdcs, 'isolrow': isrows, 'isolcol': icols}] while self.prob_.iisnext() == 0: iisIndex += 1 self.prob_.getiisdata(iisIndex, row, col, rtype, btype, duals, rdcs, isrows, icols) results_dict[s.XPRESS_IIS].append(( row, col, rtype, btype, duals, rdcs, isrows, icols)) return self.format_results(results_dict, data, cached_data)
# # The n queens: place n queens on an nxn chessboard so that none of # them can be eaten in one move. # from __future__ import print_function import xpress as xp n = 8 # the size of the chessboard N = range(n) # Create a "dictionary" of variables, i.e. a mapping from all tuples # (i,j) to a variable. x = {(i, j): xp.var(vartype=xp.binary, name='q{0}_{1}'.format(i, j)) for i in N for j in N} vertical = [xp.Sum(x[i, j] for i in N) <= 1 for j in N] horizontal = [xp.Sum(x[i, j] for j in N) <= 1 for i in N] diagonal1 = [ xp.Sum(x[k - j, j] for j in range(max(0, k - n + 1), min(k + 1, n))) <= 1 for k in range(1, 2 * n - 2) ] diagonal2 = [ xp.Sum(x[k + j, j] for j in range(max(0, -k), min(n - k, n))) <= 1 for k in range(2 - n, n - 1) ] p = xp.problem()
#!/bin/env python # # Demonstrate how variables, or arrays thereof, and constraints, or # arrays of constraints, can be added into a problem. Prints the # solution and all attributes/controls of the problem. # from __future__ import print_function import xpress as xp N = 4 S = range(N) v = [xp.var(name="y{0}".format(i)) for i in S] # set name of a variable as m = xp.problem() v1 = xp.var(name="v1", lb=0, ub=10, threshold=5, vartype=xp.continuous) v2 = xp.var(name="v2", lb=1, ub=7, threshold=3, vartype=xp.continuous) vb = xp.var(name="vb", vartype=xp.binary) v = [xp.var(name="y{0}".format(i), lb=0, ub=2 * N) for i in S] # set name of a variable as m.addVariable( vb, v, v1, v2 ) # adds both v, a vector (list) of variables, and v1 and v2, two scalar variables. c1 = v1 + v2 >= 5