def K_dominance_check(self, _V_best_d, Q_d): """ :param _V_best_d: a list of d-dimension :param Q_d: a list of d-dimension :return: True if _V_best_d is prefered to Q_d regarding self.Lambda_inequalities and using Kdominance other wise it returns False """ _d = len(_V_best_d) prob = LpProblem("Ldominance", LpMinimize) lambda_variables = LpVariable.dicts("l", range(_d), 0) for inequ in self.Lambda_ineqalities: prob += lpSum([inequ[j + 1] * lambda_variables[j] for j in range(0, _d)]) + inequ[0] >= 0 prob += lpSum([lambda_variables[i] * (_V_best_d[i]-Q_d[i]) for i in range(_d)]) #prob.writeLP("show-Ldominance.lp") status = prob.solve() LpStatus[status] result = value(prob.objective) if result < 0: return False return True
def __init__(self): self._choices = LpVariable.dicts( "Choice", (self.VALUES, self.ROWS, self.COLUMNS), cat='Binary') self._values = LpVariable.dicts("Values", (self.ROWS, self.COLUMNS), min(self.ALL), max(self.ALL), cat='Integer')
def __load_data_simple(self): # There must be at least 9 teams to perform the assigment if len(self.teams) < 9: raise Exception(ERROR_MIN_TEAM_NOT_FULLFILLED) # The number of teams must be dividable by 3 if len(self.teams) % 3: raise Exception(ERROR_NOT_DIVIDABLE_BY_THREE) self.groups = [g for g in range(len(self.teams) // 3)] self.happiness = {} self.distance = {} for t in self.teams: self.happiness[t] = [0, 0, 0] self.happiness[t][t.preferred_course] = 1 self.happiness[t][t.disliked_course] = -1 # binary Decision Variables self.assign = LpVariable.dicts("Assign team t to group g for course ", (COURSES, self.teams, self.groups), 0, 1, LpBinary) self.chef = LpVariable.dicts("Make team t chef of group g for course ", (COURSES, self.teams, self.groups), 0, 1, LpBinary) # add equations to model self._objective_simple() self._team_to_group_per_course() self._teams_in_group_per_course() self._teams_only_once_in_same_group() self._team_as_chef_per_course() self._teams_as_chef_in_group() self._teams_as_chef_once() self._teams_as_chef_only_in_group()
def formulate(cp): prob = dippy.DipProblem("Coke", display_mode = 'xdot', # layout = 'bak', display_interval = None, ) # create variables LOC_SIZES = [(l, s) for l in cp.LOCATIONS for s in cp.SIZES] buildVars = LpVariable.dicts("Build", LOC_SIZES, cat=LpBinary) # create arcs flowVars = LpVariable.dicts("Arcs", cp.ARCS) BIG_M = max(sum(cp.supply.values()), sum(cp.demand.values())) for a in cp.ARCS: flowVars[a].bounds(0, BIG_M) # objective prob += 1e6 * lpSum(buildVars[(l, s)] * cp.build_costs[s] \ for (l, s) in LOC_SIZES) + \ lpSum(flowVars[(s, d)] * cp.transport_costs[(s, d)] \ for (s, d) in cp.ARCS), "min" # plant availability - assumes that SIZES are numeric, # which they should be for loc in cp.LOCATIONS: prob += lpSum(flowVars[(loc, i)] for i in cp.CUSTOMERS) \ <= lpSum(buildVars[(loc, s)] * s for s in cp.SIZES) # one size for loc in cp.LOCATIONS: prob += lpSum(buildVars[(loc, s)] for s in cp.SIZES) == 1 # conserve flow (mines) # flows are in terms of tonnes of coke for m in cp.MINES: prob += lpSum(flowVars[(m, j)] for j in cp.LOCATIONS) \ <= cp.supply[m] # conserve flow (locations) # convert from coal to coke for loc in cp.LOCATIONS: prob += lpSum(flowVars[(m, loc)] for m in cp.MINES) - \ cp.conversion_factor * \ lpSum(flowVars[(loc, c)] for c in cp.CUSTOMERS) \ >= 0 for c in cp.CUSTOMERS: prob += lpSum(flowVars[(loc, c)] for loc in cp.LOCATIONS) \ >= cp.demand[c] prob.cp = cp prob.buildVars = buildVars prob.flowVars = flowVars return prob
def formulate(cp): prob = dippy.DipProblem( "Coke", display_mode='xdot', # layout = 'bak', display_interval=None, ) # create variables LOC_SIZES = [(l, s) for l in cp.LOCATIONS for s in cp.SIZES] buildVars = LpVariable.dicts("Build", LOC_SIZES, cat=LpBinary) # create arcs flowVars = LpVariable.dicts("Arcs", cp.ARCS) BIG_M = max(sum(cp.supply.values()), sum(cp.demand.values())) for a in cp.ARCS: flowVars[a].bounds(0, BIG_M) # objective prob += 1e6 * lpSum(buildVars[(l, s)] * cp.build_costs[s] \ for (l, s) in LOC_SIZES) + \ lpSum(flowVars[(s, d)] * cp.transport_costs[(s, d)] \ for (s, d) in cp.ARCS), "min" # plant availability - assumes that SIZES are numeric, # which they should be for loc in cp.LOCATIONS: prob += lpSum(flowVars[(loc, i)] for i in cp.CUSTOMERS) \ <= lpSum(buildVars[(loc, s)] * s for s in cp.SIZES) # one size for loc in cp.LOCATIONS: prob += lpSum(buildVars[(loc, s)] for s in cp.SIZES) == 1 # conserve flow (mines) # flows are in terms of tonnes of coke for m in cp.MINES: prob += lpSum(flowVars[(m, j)] for j in cp.LOCATIONS) \ <= cp.supply[m] # conserve flow (locations) # convert from coal to coke for loc in cp.LOCATIONS: prob += lpSum(flowVars[(m, loc)] for m in cp.MINES) - \ cp.conversion_factor * \ lpSum(flowVars[(loc, c)] for c in cp.CUSTOMERS) \ >= 0 for c in cp.CUSTOMERS: prob += lpSum(flowVars[(loc, c)] for loc in cp.LOCATIONS) \ >= cp.demand[c] prob.cp = cp prob.buildVars = buildVars prob.flowVars = flowVars return prob
def load(self, df): self.df = df self.players = LpVariable.dicts("p", (player for player in df.index), cat="Binary") teams = df.team.unique() self.stack = LpVariable.dicts("v", (team for team in teams), cat="Binary") self.teams = LpVariable.dicts("t", (team for team in teams), cat="Binary")
def optimize_set_coverage(OD, existing_facilities=None): ### Function for identifying spatially optimal locations of facilities ### # REQUIRED: OD - an Origin:Destination matrix, origins as rows, destinations # as columns, in pandas DataFrame format. # facilities - the 'destinations' of the OD-Matrix. # MUST be a list of objects included in OD.columns (or subset) # if certain nodes are unsuitable for facility locations # OPTIONAL: existing_facilities - facilities to always include in the # solution. MUST be in 'facilities' list # -------------------------------------------------------------------------# from pulp import LpInteger, LpVariable, LpProblem, lpSum, LpMinimize import pandas origins = OD.index origins = list(map(int, origins)) facilities = OD.keys() facilities = list(map(int, facilities)) X = LpVariable.dicts('X', (facilities), 0, 1, LpInteger) Y = LpVariable.dicts('Y', (origins, facilities), 0, 1, LpInteger) #create a binary variable to state that a facility is placed #s = LpVariable.dicts('facility', facilities, lowBound=0,upBound=1,cat=LpInteger) prob = LpProblem('Set Cover', LpMinimize) #prob += sum(sum(OD.loc[i,j] * Y[i][j] for j in facilities) for i in origins) prob += sum(X[j] for j in facilities) #for i in origins: prob += sum(Y[i][j] for j in facilities) >= 1 #find a way to calculate percent coverage for i in origins: #set of facilities that are eligible to provide coverage to point i eligibleFacilities = [] for j in facilities: if OD.loc[i, j] <= 240: eligibleFacilities.append(j) prob += sum(X[j] for j in eligibleFacilities) >= 1 prob.solve() ans = [] for v in prob.variables(): subV = v.name.split('_') if subV[0] == "X" and v.varValue == 1: ans.append(int(str(v).split('_')[1])) return ans
def get_optimal(X, y): K, d = X.shape names = [str(i) for i in range(K)] prob = LpProblem("The Whiskas Problem", LpMinimize) w = LpVariable.dicts("w", names) abs_w = LpVariable.dicts("abs_w", names, lowBound=0) prob += lpSum([abs_w[i] for i in names]) for j in range(d): prob += (lpSum([X[int(i), j] * w[i] for i in names]) == y[j]) for i in names: prob += (abs_w[i] >= w[i]) prob += (abs_w[i] >= -w[i]) prob.solve() ratio = np.array([abs_w[i].value() for i in names]) return ratio
def __init__(self, costs, sigmas, thetas, alphas, bethas): self.prob = LpProblem("AsignacionPacientes", LpMinimize) self.A = LpVariable.dicts( "A", (ct.citiesIndex, ct.citiesIndex, ct.daysIndex), 0, None, LpInteger) self.D = LpVariable.dicts("D", (ct.citiesIndex, ct.daysIndex), 0, None, LpInteger) self.H = LpVariable.dicts("H", (ct.citiesIndex, ct.daysIndex), 0, None, LpInteger) self.costs = costs self.sigmas = sigmas self.thetas = thetas self.alphas = alphas self.bethas = bethas self.outMatrix = np.zeros((ct.citiesLength, ct.citiesLength))
def formulate(bpp): prob = dippy.DipProblem( "Bin Packing", display_mode='off', # layout = 'bak', display_interval=None, ) assign_vars = LpVariable.dicts("x", [(i, j) for i in bpp.BINS for j in bpp.ITEMS], cat=LpBinary) use_vars = LpVariable.dicts("y", bpp.BINS, cat=LpBinary) waste_vars = LpVariable.dicts("w", bpp.BINS, 0, None) prob += lpSum(waste_vars[i] for i in bpp.BINS), "min_waste" for j in bpp.ITEMS: prob += lpSum(assign_vars[i, j] for i in bpp.BINS) == 1 for i in bpp.BINS: prob.relaxation[i] += (lpSum(bpp.volume[j] * assign_vars[i, j] for j in bpp.ITEMS) + waste_vars[i] == bpp.capacity * use_vars[i]) for i in bpp.BINS: for j in bpp.ITEMS: prob.relaxation[i] += assign_vars[i, j] <= use_vars[i] if Bin_antisymmetry: for m in range(0, len(bpp.BINS) - 1): prob += use_vars[bpp.BINS[m]] >= use_vars[bpp.BINS[m + 1]] if Item_antisymmetry: for m in range(0, len(bpp.BINS)): for n in range(0, len(bpp.ITEMS)): if m > n: i = bpp.BINS[m] j = bpp.ITEMS[n] prob += assign_vars[i, j] == 0 # Attach the problem data and variable dictionaries # to the DipProblem prob.bpp = bpp prob.assign_vars = assign_vars prob.use_vars = use_vars prob.waste_vars = waste_vars return prob
def formulate(bpp): prob = dippy.DipProblem("Bin Packing", display_mode = 'xdot', # layout = 'bak', display_interval = None, ) assign_vars = LpVariable.dicts("x", [(i, j) for i in bpp.BINS for j in bpp.ITEMS], cat=LpBinary) use_vars = LpVariable.dicts("y", bpp.BINS, cat=LpBinary) waste_vars = LpVariable.dicts("w", bpp.BINS, 0, None) prob += lpSum(waste_vars[i] for i in bpp.BINS), "min_waste" for j in bpp.ITEMS: prob += lpSum(assign_vars[i, j] for i in bpp.BINS) == 1 for i in bpp.BINS: prob.relaxation[i] += (lpSum(bpp.volume[j] * assign_vars[i, j] for j in bpp.ITEMS) + waste_vars[i] == bpp.capacity * use_vars[i]) for i in bpp.BINS: for j in bpp.ITEMS: prob.relaxation[i] += assign_vars[i, j] <= use_vars[i] if Bin_antisymmetry: for m in range(0, len(bpp.BINS) - 1): prob += use_vars[bpp.BINS[m]] >= use_vars[bpp.BINS[m + 1]] if Item_antisymmetry: for m in range(0, len(bpp.BINS)): for n in range(0, len(bpp.ITEMS)): if m > n: i = bpp.BINS[m] j = bpp.ITEMS[n] prob += assign_vars[i, j] == 0 # Attach the problem data and variable dictionaries # to the DipProblem prob.bpp = bpp prob.assign_vars = assign_vars prob.use_vars = use_vars prob.waste_vars = waste_vars return prob
def K_dominnace_check_2(self, u_d, v_d, _inequalities): """ :param u_d: a d-dimensional vector(list) like [ 8.53149891 3.36436796] :param v_d: tha same list like u_d :param _inequalities: list of constraints on d-dimensional Lambda Polytope like [[0, 1, 0], [1, -1, 0], [0, 0, 1], [1, 0, -1], [0.0, 1.4770889, -3.1250839]] :return: True if u is Kdominance to v regarding given _inequalities otherwise False """ _d = len(u_d) prob = LpProblem("Kdominance", LpMinimize) lambda_variables = LpVariable.dicts("l", range(_d), 0) for inequ in _inequalities: prob += lpSum([inequ[j + 1] * lambda_variables[j] for j in range(0, _d)]) + inequ[0] >= 0 prob += lpSum([lambda_variables[i] * (u_d[i]-v_d[i]) for i in range(_d)]) #prob.writeLP("show-Ldominance.lp") status = prob.solve() LpStatus[status] result = value(prob.objective) if result < 0: return False return True
def knapsack(w, wi, vi): itens = list(sorted(vi.keys())) # modelo modelo = LpProblem("Knapsack", LpMaximize) # variaveis x = LpVariable.dicts('x', itens, lowBound=0, upBound=1, cat=LpInteger) # objetivo modelo += sum(vi[i] * x[i] for i in itens) # constantes modelo += sum(wi[i] * x[i] for i in itens) <= w # otimizacao modelo.solve() # status status = LpStatus[modelo.status] respostas = [] for i in itens: respostas.append("{0} = {1}".format(x[i].name.split('_')[1], int(x[i].varValue))) return status, respostas
def solve_starting_11_problem(selected_team_df): """ Use PuLP to select the starting 11 which maximises next fixture points subject to constraints. :param selected_team_df: DataFrame of players in selected team :return: List of starting 11 players """ selected_team = selected_team_df.copy() players = list(selected_team['name']) # CREATE NAME-VALUE DICTIONARIES FOR USE IN CONSTRAINTS predictions = dict(zip(selected_team['name'], selected_team['GW_plus_1'])) DEF_flag = dict(zip(selected_team['name'], selected_team['position_DEF'])) FWD_flag = dict(zip(selected_team['name'], selected_team['position_FWD'])) GK_flag = dict(zip(selected_team['name'], selected_team['position_GK'])) MID_flag = dict(zip(selected_team['name'], selected_team['position_MID'])) # SET OBJECTIVE FUNCTION prob = LpProblem('FPL team selection', LpMaximize) player_vars = LpVariable.dicts('player', players, 0, 1, LpInteger) prob += lpSum([predictions[p] * player_vars[p] for p in players]), "Total predicted points" # DEFINE CONSTRAINTS # Rules of the game constraints: prob += lpSum(player_vars[p] for p in players) == 11, "Select 11 players" prob += lpSum(DEF_flag[p] * player_vars[p] for p in players) >= 3, "At least 3 defenders" prob += lpSum(GK_flag[p] * player_vars[p] for p in players) == 1, "1 goalkeeper" prob += lpSum(FWD_flag[p] * player_vars[p] for p in players) >= 1, "At least 1 forward" # SOLVE OBJECTIVE FUNCTION SUBJECT TO CONSTRAINTS prob.solve() assert prob.status == 1, 'FPL team selection problem not solved!' # Return list of chosen player names: chosen_players = [] for v in prob.variables(): if v.varValue == 0: continue else: chosen_players.append(v.name.replace('player_', '')) return chosen_players
def _CreateLinearProblem(self): """ Generates a linear problem object (using PuLP) with all the mass balance constraints (Sv = 0), and with individual upper and lower bounds on reactions (as given by the model) """ lp = LpProblem("FBA", LpMaximize) # create the flux variables fluxes = LpVariable.dicts("v", self.reactions, lowBound=-1000, upBound=1000) for d in self.model['reactions']: if d['id'] not in self.reactions: print d['id'], "is not found in the list of reactions" fluxes[d['id']].lowBound = d['lower_bound'] fluxes[d['id']].upBound = d['upper_bound'] # add the mass balance constraints for all metabolites mass_balance_constraints = {} for met in self.metabolites: row = self.S.loc[met, :] mul = [row[i] * fluxes[self.reactions[i]] for i in row.nonzero()[0]] mass_balance_constraints[met] = (lpSum(mul) == 0) lp += mass_balance_constraints[met], "mass_balance_%s" % met return lp, fluxes, mass_balance_constraints
def getTechnicalEfficiency(r): # Model Building model = LpProblem('VRS_model', LpMinimize) # 建立一個新的model,命名為model # Decision variables Building theta_r = LpVariable(f'theta_r') lambda_k = LpVariable.dicts(f'lambda_k', lowBound=0, indexs=K) # Objective Function setting model += theta_r # Constraints setting for i in I: model += lpSum([lambda_k[k] * X[i][k] for k in K]) <= theta_r * float(X[i][K[r]]) for j in J: model += lpSum([lambda_k[k] * Y[j][k] for k in K]) >= float(Y[j][K[r]]) model += lpSum([lambda_k[k] for k in K]) == 1 # model solving model.solve() return f'{K[r]}:{round(value(model.objective), 3)}\n', value( model.objective)
def create_linear_objective_min_calorie(variables, prod_values): #testobjective """ Function returns linear objective to be minimized. :param variables: dictionary containing names and LpVariables :param prod_values: dictionary of dictionaries containing name and nutrients values :return: linear objective to be minimized """ # Student implementation below. products_names = list(prod_values.keys()) nutrients = ['calorie', 'proteins', 'carbs', 'sugar', 'fat'] prob = LpProblem('Diet problem', LpMinimize) calories = [] proteins = [] carbs = [] sugar = [] fat = [] for i in range(10): tmp = prod_values[products_names[i]] calories.append(tmp['calorie']) proteins.append(tmp['proteins']) carbs.append(tmp['carbs']) sugar.append(tmp['sugar']) fat.append(tmp['fat']) calories = list_to_dict(products_names, calories) proteins = list_to_dict(products_names, proteins) carbs = list_to_dict(products_names, carbs) sugar = list_to_dict(products_names, sugar) fat = list_to_dict(products_names, fat) food_vars = LpVariable.dicts("Food", products_names, lowBound=0) prob += lpSum([calories[i] * variables[i] for i in products_names]) return LpAffineExpression(prob) raise NotImplementedError()
def solve(n, p): prob = LpProblem("routage", LpMaximize) matrix = LpVariable.dicts("Matrix", (range(n), range(p)), 0, 1, LpInteger) for i in range(n - 1): prob += lpSum(matrix[i][j] for j in range(p)) == lpSum(matrix[i + 1][j] for j in range(p)) for j in range(p - 1): prob += lpSum(matrix[i][j] for i in range(n)) == lpSum(matrix[i][j + 1] for i in range(n)) res = zeros((n + 1, p + 1), dtype=int) while True: prob.solve() if prob.status == 1: nl = int(sum([value(matrix[0][j]) for j in range(p)])) nc = int(sum([value(matrix[i][0]) for i in range(n)])) res[nc, nl] += 1 prob += lpSum( matrix[i][j] for i in range(n) for j in range(p) if value(matrix[i][j]) == 1) + lpSum( 1 - matrix[i][j] for i in range(n) for j in range(p) if value(matrix[i][j]) == 0) <= n * p - 1 else: break return res
def _load_data_simple(self): # There must be at least 9 teams to perform the assigment if len(self.teams) < 9: raise ValidationError(ERROR_MIN_TEAM_NOT_FULLFILLED) # The number of teams must be dividable by 3 if len(self.teams) % 3: raise ValidationError(ERROR_NOT_DIVIDABLE_BY_THREE) self.COURSES = [ Course.objects.get(name="a"), Course.objects.get(name="m"), Course.objects.get(name="d"), ] self.event = None self.groups = [g for g in range(len(self.teams) / 3)] self.happiness = {} self.distance = {} # Sets for t in self.teams: # check if all teams are from the same event if self.event: if self.event != t.event: raise ValidationError(ERROR_MULTIPLE_EVENTS) else: self.event = t.event self.happiness[t] = {} for c in self.COURSES: self.happiness[t][c] = 0 for l in t.like.all(): self.happiness[t][l] = 1 for d in t.dislike.all(): self.happiness[t][d] = -1 # binary Decision Variables self.assign = LpVariable.dicts("Assign team t to group g for course ", (self.COURSES, self.teams, self.groups), 0, 1, LpBinary) self.chef = LpVariable.dicts("Make team t chef of group g for course ", (self.COURSES, self.teams, self.groups), 0, 1, LpBinary) # add equations to model self._objective_simple() self._team_to_group_per_course() self._teams_in_group_per_course() self._teams_only_once_in_same_group() self._team_as_chef_per_course() self._teams_as_chef_in_group() self._teams_as_chef_once() self._teams_as_chef_only_in_group()
def Solver(): global x,y prob = dippy.DipProblem("CVPMP", display_mode = display_mode, layout = 'dot', display_interval = 0) X = [(i, j) for i in V for j in V] x = LpVariable.dicts("x", X, 0, 1, LpBinary) y = LpVariable.dicts("y", V, 0, 1, LpBinary) prob += (lpSum(d[i, j] * x[(i, j)] for i in V for j in V), "min") #linking constraints for j in V: prob += lpSum(x[(i,j)] for i in V) == 1 #non-relaxing for i in V: prob.relaxation[i] += lpSum(w[j] * x[(i, j)] for j in V) <= s[i]*y[i] prob += lpSum(y[i] for i in V) == p prob.relaxed_solver = solve_subproblem dippy.Solve(prob, { 'TolZero' : '%s' % tol, 'doCut' : '1', 'generateInitVars' : '1', 'CutCGL' : '1', }) #Make solution solution = [] for i in V: if y[i].varValue: cluster = [] for j in V: if x[(i, j)].varValue: cluster.append(j) solution.append((i,cluster)) return round(prob.objective.value()), solution
def solve(self, max_menu_item=None, max_food_item=3, nutrition=DEFAULT_NUTR_REQS, exclude=None, include=None): """Create, formulate and solve the diet problem for given constraints """ self.prob = prob = LpProblem(__class__, LpMinimize) # Variables self.xm = xm = LpVariable.dicts('meals', self.meals, 0, max_menu_item, cat='Integer') self.xf = xf = LpVariable.dicts('foods', self.foods, 0, max_food_item, cat='Integer') # Objective prob += lpSum(self.menu[i]['price']*xm[i] for i in self.meals) # Ensure that foods eaten are available under meals bought for j in self.foods: prob += lpSum([self.menu[i]['foods'].get(j, 0)*xm[i] for i in self.meals]) >= xf[j] # Must meet nutrition for r, (lower, upper) in nutrition.items(): if lower: prob += lpSum([xf[i]*self.nutr[i][r] for i in self.foods]) >= lower if upper: prob += lpSum([xf[i]*self.nutr[i][r] for i in self.foods]) <= upper if include: for food in include: prob += xf[food] >= 1 if exclude: for food in exclude: prob += xf[food] == 0 # Solve and save status = LpStatus[prob.solve()] if status == 'Optimal': pass elif status == 'Infeasible': raise InfeasibleError() elif status == 'Unbounded': raise UnboundedError else: raise ValueError(status) solution = self.parse_solution() self.history.append(solution) return solution
def formulate(bpp, args): prob = DipProblem("Bin Packing") assign_vars = LpVariable.dicts("x", [(i, j) for i in bpp.BINS for j in bpp.ITEMS], cat=LpBinary) use_vars = LpVariable.dicts("y", bpp.BINS, cat=LpBinary) waste_vars = LpVariable.dicts("w", bpp.BINS, 0, None) prob += lpSum(waste_vars[i] for i in bpp.BINS), "min_waste" for j in bpp.ITEMS: prob += lpSum(assign_vars[i, j] for i in bpp.BINS) == 1 for i in bpp.BINS: prob.relaxation[i] += (lpSum(bpp.volume[j] * assign_vars[i, j] for j in bpp.ITEMS) + waste_vars[i] == bpp.capacity * use_vars[i]) for i in bpp.BINS: for j in bpp.ITEMS: prob.relaxation[i] += assign_vars[i, j] <= use_vars[i] if args.antisymmetryCutsBins: for m in range(0, len(bpp.BINS) - 1): prob += use_vars[bpp.BINS[m]] >= use_vars[bpp.BINS[m + 1]] if args.antisymmetryCutsItems: for m in range(0, len(bpp.BINS)): for n in range(0, len(bpp.ITEMS)): if m > n: i = bpp.BINS[m] j = bpp.ITEMS[n] prob += assign_vars[i, j] == 0 # Attach the problem data and variable dictionaries # to the DipProblem prob.bpp = bpp prob.assign_vars = assign_vars prob.use_vars = use_vars prob.waste_vars = waste_vars prob.tol = pow(pow(2, -24), old_div(2.0, 3.0)) return prob
def Solver(args): global x, y prob = DipProblem("CVPMP", display_mode=display_mode, layout='dot', display_interval=0) X = [(i, j) for i in V for j in V] x = LpVariable.dicts("x", X, 0, 1, LpBinary) y = LpVariable.dicts("y", V, 0, 1, LpBinary) prob += (lpSum(d[i, j] * x[(i, j)] for i in V for j in V), "min") #linking constraints for j in V: prob += lpSum(x[(i, j)] for i in V) == 1 #non-relaxing for i in V: prob.relaxation[i] += lpSum(w[j] * x[(i, j)] for j in V) <= s[i] * y[i] prob += lpSum(y[i] for i in V) == p if args.useCustomSolver: prob.relaxed_solver = solve_subproblem dippyOpts = addDippyOpts(args) Solve(prob, dippyOpts) #Make solution solution = [] for i in V: if y[i].varValue: cluster = [] for j in V: if x[(i, j)].varValue: cluster.append(j) solution.append((i, cluster)) return round(prob.objective.value()), solution
def _create_variables(self) -> None: """Creates the set of variables Y* and X* of the PuLP problem. Override it if you need to create extra variables (first use ``super().create_variables()`` to call the base class method).""" if self.relaxed: kind = LpContinuous else: kind = LpInteger # List all combinations of apps and instances and workloads comb_res = cartesian_product(self.system.apps, self.cooked.instances_res) comb_dem = cartesian_product(self.system.apps, self.cooked.instances_dem, self.load_hist.keys()) map_res = LpVariable.dicts("Y", comb_res, 0, None, kind) map_dem = LpVariable.dicts("X", comb_dem, 0, None, kind) self.cooked = self.cooked._replace(map_res=map_res, map_dem=map_dem)
def setup_vars(self, idx): """Create a dictionary with the pulp variables.""" return { 'imports': LpVariable.dicts('import', idx[:-1], lowBound=0, upBound=self.power, cat='Continuous'), 'exports': LpVariable.dicts('export', idx[:-1], lowBound=0, upBound=self.power, cat='Continuous'), 'charges': LpVariable.dicts('charge', idx, lowBound=0, cat='Continuous'), 'losses': LpVariable.dicts('loss', idx[:-1], lowBound=0, cat='Continuous') }
def solve_under_coverage(graph, min_coverage=80): prob = LpProblem("granularity selection", LpMinimize) codelet_vars = LpVariable.dicts("codelet", graph, lowBound=0, upBound=1, cat=LpInteger) # Objective function: minimize the total replay cost of selected codelets # Compute replay time for n, d in graph.nodes(data=True): d['_total_replay_cycles'] = 0 for inv in d['_invocations']: d['_total_replay_cycles'] = d['_total_replay_cycles'] + float( inv["Invivo (cycles)"]) prob += lpSum([ codelet_vars[n] * d['_total_replay_cycles'] for n, d in graph.nodes(data=True) ]) # and with good coverage prob += (lpSum( [codelet_vars[n] * d['_coverage'] for n, d in graph.nodes(data=True)]) >= min_coverage) # selected codelets should match for n, d in graph.nodes(data=True): if not d['_matching']: prob += codelet_vars[n] == 0 # Finally we should never include both the children and the parents for dad in graph.nodes(): for son in graph.nodes(): if not dad in nx.ancestors(graph, son): continue # We cannot select dad and son at the same time prob += codelet_vars[dad] + codelet_vars[son] <= 1 #prob.solve(GLPK()) prob.solve() if (LpStatus[prob.status] != 'Optimal'): raise Unsolvable() for v in prob.variables(): assert v.varValue == 1.0 or v.varValue == 0.0 if v.varValue == 1.0: for n, d in graph.nodes(data=True): if ("codelet_" + str(n)) == v.name: d["_selected"] = True yield n
def setup_vars(self, idx): """Create a dictionary with the pulp variables.""" return { "imports": LpVariable.dicts("import", idx[:-1], lowBound=0, upBound=self.power, cat="Continuous"), "exports": LpVariable.dicts("export", idx[:-1], lowBound=0, upBound=self.power, cat="Continuous"), "charges": LpVariable.dicts("charge", idx, lowBound=0, cat="Continuous"), "losses": LpVariable.dicts("loss", idx[:-1], lowBound=0, cat="Continuous"), }
def knapsack01(obj, weights, capacity): """ 0/1 knapsack solver, maximizes profit. weights and capacity integer """ debug_subproblem = False assert len(obj) == len(weights) n = len(obj) if n == 0: return 0, [] if debug_subproblem: relaxation = LpProblem('relaxation', LpMaximize) relax_vars = [str(i) for i in range(n)] var_dict = LpVariable.dicts("", relax_vars, 0, 1, LpBinary) relaxation += (lpSum(var_dict[str(i)] * weights[i] for i in range(n)) <= capacity) relaxation += lpSum(var_dict[str(i)] * obj[i] for i in range(n)) relaxation.solve() relax_obj = value(relaxation.objective) solution = [i for i in range(n) if var_dict[str(i)].varValue > tol ] print relax_obj, solution c = [[0]*(capacity+1) for i in range(n)] added = [[False]*(capacity+1) for i in range(n)] # c [items, remaining capacity] # important: this code assumes strictly positive objective values for i in range(n): for j in range(capacity+1): if (weights[i] > j): c[i][j] = c[i-1][j] else: c_add = obj[i] + c[i-1][j-weights[i]] if c_add > c[i-1][j]: c[i][j] = c_add added[i][j] = True else: c[i][j] = c[i-1][j] # backtrack to find solution i = n-1 j = capacity solution = [] while i >= 0 and j >= 0: if added[i][j]: solution.append(i) j -= weights[i] i -= 1 return c[n-1][capacity], solution
def VAR_matrix(self, rows=10, columns=10, prefix='x', type=LpBinary, to_print=False): m = LpVariable.dicts(prefix, (range(rows), range(columns)), cat=type, lowBound=0) if to_print: print(f"VAR_matrix : \n{m} - ({type.lower()})") return m
def pe185(): """ Modelling as an integer programming problem. Then using PuLP to solve it. It's really fast, just 0.24 seconds. For details, see https://pythonhosted.org/PuLP/index.html """ from pulp import LpProblem, LpVariable, LpMinimize, LpInteger, lpSum, value constraints = [ ('2321386104303845', 0), ('3847439647293047', 1), ('3174248439465858', 1), ('8157356344118483', 1), ('6375711915077050', 1), ('6913859173121360', 1), ('4895722652190306', 1), ('5616185650518293', 2), ('4513559094146117', 2), ('2615250744386899', 2), ('6442889055042768', 2), ('2326509471271448', 2), ('5251583379644322', 2), ('2659862637316867', 2), ('5855462940810587', 3), ('9742855507068353', 3), ('4296849643607543', 3), ('7890971548908067', 3), ('8690095851526254', 3), ('1748270476758276', 3), ('3041631117224635', 3), ('1841236454324589', 3) ] VALs = map(str, range(10)) LOCs = map(str, range(16)) choices = LpVariable.dicts("Choice", (LOCs, VALs), 0, 1, LpInteger) prob = LpProblem("pe185", LpMinimize) prob += 0, "Arbitrary Objective Function" for s in LOCs: prob += lpSum([choices[s][v] for v in VALs]) == 1, "" for c, n in constraints: prob += lpSum([choices[str(i)][v] for i,v in enumerate(c)]) == n, "" prob.writeLP("pe185.lp") prob.solve() res = int(''.join(v for s in LOCs for v in VALs if value(choices[s][v]))) # answer: 4640261571849533 return res
def solve_exact(self): ''' 整数計画法を用いて厳密解を得る parameters ----- なし returns ----- なし ''' from pulp import LpProblem, LpVariable, lpSum, LpStatus, PULP_CBC_CMD n_city = self.size #Pulpで解く p = LpProblem("TSP") x = LpVariable.dicts(name="x", indexs=(range(n_city), range(n_city)), cat='Binary') p += lpSum( self.dist(i, j) * x[i][j] for i, j in product(range(n_city), range(n_city))) for i in range(n_city): p += lpSum(x[i][j] for j in range(n_city)) == 1 for i in range(n_city): p += lpSum(x[j][i] for j in range(n_city)) == 1 V = set(range(n_city)) for s_len in range(1, n_city - 1): for S_list in combinations(range(n_city), s_len): S = set(S_list) _V = V - S tmp = 0 for i, j in product(S, _V): tmp += x[i][j] p += tmp >= 1 solver = PULP_CBC_CMD(threads=15) status = p.solve(solver) print(LpStatus[status]) self.exact_route = [0] for i in range(n_city - 1): for j in range(n_city): if x[self.exact_route[i]][j].value() == 1.0: self.exact_route.append(j) break self.exact_dist = self.route_len(self.exact_route)
def localPL(self, timeStamp): prob = LpProblem("Maximize monads", LpMaximize) vars_ = [ "X" + str(c) for c in range(len(self.monads.getMonadsByYear(timeStamp))) ] vars = LpVariable.dicts("Number of monads", vars_, lowBound=0) [ "X" + str(c) for c in range(len(self.monads.getMonadsByYear(timeStamp))) ] prob += lpSum([rois[c] * vars[c] for c in Chairs])
def formulate(bpp): prob = dippy.DipProblem("Bin Packing", display_mode = 'xdot', # layout = 'bak', display_interval = None, ) assign_vars = LpVariable.dicts("x", [(i, j) for i in bpp.ITEMS for j in bpp.BINS], cat=LpBinary) use_vars = LpVariable.dicts("y", bpp.BINS, cat=LpBinary) waste_vars = LpVariable.dicts("w", [(j, k) for j in bpp.BINS for k in bpp.LIMITS], 0, None) prob += lpSum(use_vars[j] for j in bpp.BINS), "min_bins" for j in bpp.BINS: for k in bpp.LIMITS: prob += lpSum(bpp.volume[i, k] * assign_vars[i, j] for i in bpp.ITEMS) \ + waste_vars[j, k] == bpp.capacity[k] * use_vars[j] for i in bpp.ITEMS: prob += lpSum(assign_vars[i, j] for j in bpp.BINS) == 1 for i in bpp.ITEMS: for j in bpp.BINS: prob += assign_vars[i, j] <= use_vars[j] for n in range(0, len(bpp.BINS) - 1): prob += use_vars[bpp.BINS[n]] >= use_vars[bpp.BINS[n + 1]] # Attach the problem data and variable dictionaries to the DipProblem prob.bpp = bpp prob.assign_vars = assign_vars prob.use_vars = use_vars prob.waste_vars = waste_vars return prob
def formulate(bpp): prob = dippy.DipProblem( "Bin Packing", display_mode='xdot', # layout = 'bak', display_interval=None, ) assign_vars = LpVariable.dicts("x", [(i, j) for i in bpp.ITEMS for j in bpp.BINS], cat=LpBinary) use_vars = LpVariable.dicts("y", bpp.BINS, cat=LpBinary) waste_vars = LpVariable.dicts("w", [(j, k) for j in bpp.BINS for k in bpp.LIMITS], 0, None) prob += lpSum(use_vars[j] for j in bpp.BINS), "min_bins" for j in bpp.BINS: for k in bpp.LIMITS: prob += lpSum(bpp.volume[i, k] * assign_vars[i, j] for i in bpp.ITEMS) \ + waste_vars[j, k] == bpp.capacity[k] * use_vars[j] for i in bpp.ITEMS: prob += lpSum(assign_vars[i, j] for j in bpp.BINS) == 1 for i in bpp.ITEMS: for j in bpp.BINS: prob += assign_vars[i, j] <= use_vars[j] for n in range(0, len(bpp.BINS) - 1): prob += use_vars[bpp.BINS[n]] >= use_vars[bpp.BINS[n + 1]] # Attach the problem data and variable dictionaries to the DipProblem prob.bpp = bpp prob.assign_vars = assign_vars prob.use_vars = use_vars prob.waste_vars = waste_vars return prob
def solve_pulp(self, start=0, end=4): #最小化問題 p = LpProblem("ShortestPath", sense=LpMinimize) #変数 x = LpVariable.dicts('x', range(len(self.edges)), 0, 1, cat=LpBinary) #目的関数 p += sum([x[i] * self.get_weight(i) for i in range(self.edges_num)]) #p += sum([ x[i] for i in range(self.edges_num)]) #制約式 for i in self.nodes: const_out = 0 tmp_edges = [] for e in self.G.edges(i): j = e[1] const_out += x[self.get_node_index((i, j))] tmp_edges.append(self.get_node_index((i, j))) logging.debug(tmp_edges) const_in = 0 tmp_edges = [] for e in self.G.in_edges(i): k = e[0] const_in += x[self.get_node_index((k, i))] tmp_edges.append(self.get_node_index((k, i))) logging.debug(tmp_edges) print(i, self.G.edges(i), self.G.in_edges(i)) #self.G.edges() if i == self.start: const_val = 1 elif i == self.goal: const_val = -1 else: const_val = 0 p += const_out - const_in == const_val self.status = p.solve() if self.status == 1: self.answer = [ self.edges[i] for i in range(self.edges_num) if x[i].value() == 1 ] logging.debug(f"ans {self.answer}") else: logging.error("Solve Failed") print(self.answer)
def create_problem(self, filename=None, use_no_fit=False): if self.polygons is None: raise ValueError('You must create the data before the model!') self.use_no_fit = use_no_fit self.problem = LpProblem('polygons_packing', LpMinimize) self.w = LpVariable('w', 0) self.tx = LpVariable.dicts('tx', range(self.N), 0) self.ty = LpVariable.dicts('ty', range(self.N), 0) # objective self.problem.setObjective(self.w) # w constraints widths = [ np.max(pol[:, 0]) - np.min(pol[:, 0]) for pol in self.polygons ] for i in range(self.N): self.problem += self.w - self.tx[i] >= widths[ i], f"w_constraint_{i}" # height constraints heights = [ np.max(pol[:, 1]) - np.min(pol[:, 1]) for pol in self.polygons ] for i in range(self.N): self.problem += self.ty[ i] <= self.H - heights[i], f"height_constraint_{i}" self._add_non_overl_constr() if filename is not None: self.problem.writeLP(filename)
def solve_under_coverage(graph, min_coverage=80): prob = LpProblem("granularity selection", LpMinimize) codelet_vars = LpVariable.dicts("codelet", graph, lowBound=0, upBound=1, cat=LpInteger) # Objective function: minimize the total replay cost of selected codelets # Compute replay time for n,d in graph.nodes(data=True): d['_total_replay_cycles'] = 0 for inv in d['_invocations']: d['_total_replay_cycles'] = d['_total_replay_cycles'] + float(inv["Invivo (cycles)"]) prob += lpSum([codelet_vars[n]*d['_total_replay_cycles'] for n,d in graph.nodes(data=True)]) # and with good coverage prob += (lpSum([codelet_vars[n]*d['_coverage'] for n,d in graph.nodes(data=True)]) >= min_coverage) # selected codelets should match for n,d in graph.nodes(data=True): if not d['_matching']: prob += codelet_vars[n] == 0 # Finally we should never include both the children and the parents for dad in graph.nodes(): for son in graph.nodes(): if not dad in nx.ancestors(graph, son): continue # We cannot select dad and son at the same time prob += codelet_vars[dad] + codelet_vars[son] <= 1 #prob.solve(GLPK()) prob.solve() if (LpStatus[prob.status] != 'Optimal'): raise Unsolvable() for v in prob.variables(): assert v.varValue == 1.0 or v.varValue == 0.0 if v.varValue == 1.0: for n,d in graph.nodes(data=True): if ("codelet_"+str(n)) == v.name: d["_selected"] = True yield n
def _recurse(work_pairs, mae, grace=None): req = grace or 1.0 demands = { 'morning': mae[0], 'afternoon': mae[1], 'exam': mae[2], } total_avg = float(sum([demands[i] for i in SHIFTS])) / work_pairs total_low, total_high = floor(total_avg), ceil(total_avg) work_pair_count = work_pairs avgs = [float(demands[i]) / work_pair_count for i in SHIFTS] lows = [floor(a) for a in avgs] highs = [ceil(a) for a in avgs] target = req * total_avg * float(sum([COSTS[i] for i in SHIFTS])) / len(SHIFTS) prob = LpProblem("Work Distribution", LpMinimize) var_prefix = "shift" shift_vars = LpVariable.dicts(var_prefix, SHIFTS, 0, cat=LpInteger) prob += lpSum([COSTS[i] * shift_vars[i] for i in SHIFTS]), "cost of combination" prob += lpSum([COSTS[i] * shift_vars[i] for i in SHIFTS]) >= target, "not too good" prob += lpSum([shift_vars[i] for i in SHIFTS]) >= total_low, "low TOTAL" prob += lpSum([shift_vars[i] for i in SHIFTS]) <= total_high, "high TOTAL" for shift, low, high in zip(SHIFTS, lows, highs): prob += lpSum([shift_vars[shift]]) >= low, "low %s" % shift prob += lpSum([shift_vars[shift]]) <= high, "high %s" % shift prob.solve(GLPK_CMD(msg=0)) if not LpStatus[prob.status] == 'Optimal': next_grace = req - 0.1 assert 0.0 < next_grace return _recurse(work_pairs, mae, next_grace) new_mae = [0, 0, 0] solution = [0, 0, 0] for v in prob.variables(): for pos, name in enumerate(SHIFTS): if v.name == "%s_%s" % (var_prefix, name): solution[pos] = v.varValue new_mae[pos] = mae[pos] - solution[pos] return (PairAlloc(solution), work_pairs - 1) + tuple(new_mae)
def get_optimal_routes(sources, destinations): sources = collections.OrderedDict([(x['id'], x) for x in sources]) destinations = collections.OrderedDict([(x['id'], x) for x in destinations]) sources_points = [{'lat': x['lat'], 'lng': x['lng']} for x in sources.values()] destinations_points = [{'lat': x['lat'], 'lng': x['lng']} for x in destinations.values()] source_ids = [str(x['id']) for x in sources.values()] dest_ids = [str(x['id']) for x in destinations.values()] demand = {str(x['id']): convert_int(x['num_students']) for x in sources.values()} supply = {str(x['id']): convert_int(x['num_students']) for x in destinations.values()} log.info("Calling gmaps api...") distances = gmaps.distance_matrix(origins=sources_points, destinations=destinations_points, mode='walking') costs = {} for i, origin in enumerate(distances['rows']): origin_costs = {} for j, entry in enumerate(origin['elements']): origin_costs[dest_ids[j]] = entry['duration']['value'] costs[source_ids[i]] = origin_costs prob = LpProblem("Evaucation Routing for Schools",LpMinimize) routes = [(s,d) for s in source_ids for d in dest_ids] route_lookup = {'Route_{}_{}'.format(x.replace(' ','_'),y.replace(' ','_')):(x,y) for (x,y) in routes} route_vars = LpVariable.dicts("Route",(source_ids,dest_ids),0,None,LpInteger) prob += lpSum([route_vars[w][b]*(costs[w][b]**2) for (w,b) in routes]) for dest in dest_ids: prob += lpSum([route_vars[source][dest] for source in source_ids]) <= supply[dest], "Students going to {} is <= {}".format(dest, supply[dest]) for source in source_ids: prob += lpSum([route_vars[source][dest] for dest in dest_ids]) == demand[source], "Students leaving {} is {}".format(source, demand[source]) log.info("Optimizing routes...") prob.solve() if prob.status != 1: raise Exception("Algorithm could not converge to a solution") result = [] for v in prob.variables(): src, dst = route_lookup[v.name] value = v.value() result.append({'src': sources[src], 'dst': destinations[dst], 'value': int(value)}) return result
def __init__(self, home_list, work_list, util_matrix): """ Input a list of utils utils = [ #Works #1 2 3 4 5 [2,4,5,2,1],#A Homes [3,1,3,2,3] #B ] """ self.util_matrix = util_matrix self.homes = dict((home, home.houses) for home in home_list) self.works = dict((work, work.jobs) for work in work_list) self.utils = makeDict([home_list, work_list], util_matrix, 0) # Creates the 'prob' variable to contain the problem data self.prob = LpProblem("Residential Location Choice Problem", LpMinimize) # Creates a list of tuples containing all the possible location choices self.choices = [(h, w) for h in self.homes for w in self.works.keys()] # A dictionary called 'volumes' is created to contain the referenced variables(the choices) self.volumes = LpVariable.dicts("choice", (self.homes, self.works), 0, None, LpContinuous) # The objective function is added to 'prob' first self.prob += ( lpSum([self.volumes[h][w] * self.utils[h][w] for (h, w) in self.choices]), "Sum_of_Transporting_Costs", ) # The supply maximum constraints are added to prob for each supply node (home) for h in self.homes: self.prob += ( lpSum([self.volumes[h][w] for w in self.works]) <= self.homes[h], "Sum_of_Products_out_of_Home_%s" % h, ) # The demand minimum constraints are added to prob for each demand node (work) for w in self.works: self.prob += ( lpSum([self.volumes[h][w] for h in self.homes]) >= self.works[w], "Sum_of_Products_into_Work%s" % w, )
def __generar_restricciones(self): X = LpVariable.dicts('X', self.variables, cat = LpBinary) self.cursado = LpProblem("Cursado",LpMaximize) # "\n\n Restricciones de dia-modulo\n\n" i = 1 for r in self.r1.values(): self.cursado += lpSum([X["".join(x)] for x in r]) <= 1, \ "_1C" + str(i).zfill(3) i += 1 #"\n\n Restricciones de cursado completo\n\n" for r in self.r2.values(): self.cursado += int(r[0][0]) *X[r[0][1]+r[0][2]] == lpSum([X["".join(x[1:])] for x in r]), \ "_2C" + str(i).zfill(3) i += 1 #""" #"\n\n Restricciones 1 sola comision\n\n" for r in self.r3.values(): self.cursado += int(r[0][0]) *X[r[0][1]] == lpSum([X["".join(x[1:])] for x in r]), \ "_3C" + str(i).zfill(3) i += 1 #"\n\n Restricciones de Colision\n\n" for r in self.r4.values(): self.cursado += lpSum([X["".join(x)] for x in r]) <= 1, \ "_4C" + str(i).zfill(3) i += 1 #"\n\n Restricciones de franja horaria\n\n" for r in [x + "" for x in ["".join(x) for x in self.r5]]: self.cursado += X[r] == 0, \ "_5C" + str(i).zfill(3) i += 1 self.X = X
def build_sudoku_problem(): # The values, rows and cols sequences all follow this form values = range(9) rows = range(9) columns = range(9) # The boxes list is created, with the row and column index of each square in each box boxes = [] for i in range(3): for j in range(3): box = [(rows[3 * i + k], columns[3 * j + l]) for k in range(3) for l in range(3)] boxes.append(box) # The problem variable is created to contain the problem data problem = LpProblem("Sudoku Problem", LpMinimize) # The problem variables are created choices = LpVariable.dicts("Choice", (rows, columns, values), 0, 1, LpBinary) # The arbitrary objective function is added problem += 0, "Arbitrary Objective Function" # A constraint ensuring that only one value can be in each square is created for r in rows: for c in columns: problem += lpSum(choices[r][c][v] for v in values) == 1, "unique_val_" + str(r) + '_' + str(c) # The row, column and box constraints are added for each value for v in values: for r in rows: problem += lpSum(choices[r][c][v] for c in columns) == 1, "row_" + str(v) + '_' + str(r) for c in columns: problem += lpSum(choices[r][c][v] for r in rows) == 1, "col_" + str(v) + '_' + str(c) for box_index, b in enumerate(boxes): problem += lpSum(choices[r][c][v] for (r, c) in b) == 1, "box_" + str(v) + '_' + str(box_index) return problem, choices, values, rows, columns
def learn_two_cat(self, performance_table): """Learn parameters for two categories and two training sets of alternatives.""" if len(self.categories) != 2: raise SemanticError, "The learnTwoCat() method requires exactly two categories." prob = LpProblem("twoCat", LpMaximize) alts = filter(lambda a: a.__class__.__name__ != "LimitProfile", performance_table.alts) crits = self.crits alts_name = [alt.name for alt in alts if alt.__class__.__name__ != "LimitProfile"] crits_name = [crit.name for crit in crits] self.categories.sort(key=lambda c: c.rank) alts1 = [alt for alt in alts if alt.category == self.categories[0]] alts2 = [alt for alt in alts if alt.category == self.categories[1]] #small float number epsilon = 0.00001 #variables (v: variable, d: dict of variables) v_lambda = LpVariable("lambda", lowBound=0.5, upBound=1) v_alpha = LpVariable("alpha", lowBound=0) d_x = LpVariable.dicts("x", alts_name, lowBound=0) d_y = LpVariable.dicts("y", alts_name, lowBound=0) d_p = LpVariable.dicts("p", crits_name, lowBound=0, upBound=1) d_gb = LpVariable.dicts("gb", crits_name, lowBound=0, upBound=1) d_delta = LpVariable.dicts("delta", \ [alt.name + crit.name for alt in alts for crit in crits]\ , cat=LpBinary) d_c = LpVariable.dicts("c", \ [alt.name + crit.name for alt in alts for crit in crits]\ , lowBound=0, upBound=1) #maximize prob += v_alpha #constraints for alt in alts2: prob += sum(d_c[alt.name + crit.name] for crit in crits) + d_x[alt.name] == v_lambda for alt in alts1: prob += sum(d_c[alt.name + crit.name] for crit in crits) == v_lambda + d_y[alt.name] for alt in alts: prob += v_alpha <= d_x[alt.name] prob += v_alpha <= d_y[alt.name] prob += d_x[alt.name] >= epsilon for crit in crits: prob += d_c[alt.name + crit.name] <= d_p[crit.name] prob += d_c[alt.name + crit.name] >= d_delta[alt.name + crit.name] + d_p[crit.name] - 1 prob += d_c[alt.name + crit.name] <= d_delta[alt.name + crit.name] prob += d_delta[alt.name + crit.name] >= performance_table[alt][crit] - d_gb[crit.name] + epsilon prob += d_delta[alt.name + crit.name] <= performance_table[alt][crit] - d_gb[crit.name] + 1 prob += sum(d_p[crit.name] for crit in crits) == 1 #solver GLPK().solve(prob) #prob.writeLP("SpamClassification.lp") #status = prob.solve() #update parameters self.cutting_threshold = v_lambda.value() for crit in crits: crit.weight = d_p[crit.name].value() for crit in crits: performance_table[self.limit_profiles[0]][crit] = d_gb[crit.name].value()
def BranchAndBound(T, CONSTRAINTS, VARIABLES, OBJ, MAT, RHS, branch_strategy = MOST_FRACTIONAL, search_strategy = DEPTH_FIRST, complete_enumeration = False, display_interval = None, binary_vars = True): if T.get_layout() == 'dot2tex': cluster_attrs = {'name':'Key', 'label':r'\text{Key}', 'fontsize':'12'} T.add_node('C', label = r'\text{Candidate}', style = 'filled', color = 'yellow', fillcolor = 'yellow') T.add_node('I', label = r'\text{Infeasible}', style = 'filled', color = 'orange', fillcolor = 'orange') T.add_node('S', label = r'\text{Solution}', style = 'filled', color = 'lightblue', fillcolor = 'lightblue') T.add_node('P', label = r'\text{Pruned}', style = 'filled', color = 'red', fillcolor = 'red') T.add_node('PC', label = r'\text{Pruned}$\\ $\text{Candidate}', style = 'filled', color = 'red', fillcolor = 'yellow') else: cluster_attrs = {'name':'Key', 'label':'Key', 'fontsize':'12'} T.add_node('C', label = 'Candidate', style = 'filled', color = 'yellow', fillcolor = 'yellow') T.add_node('I', label = 'Infeasible', style = 'filled', color = 'orange', fillcolor = 'orange') T.add_node('S', label = 'Solution', style = 'filled', color = 'lightblue', fillcolor = 'lightblue') T.add_node('P', label = 'Pruned', style = 'filled', color = 'red', fillcolor = 'red') T.add_node('PC', label = 'Pruned \n Candidate', style = 'filled', color = 'red', fillcolor = 'yellow') T.add_edge('C', 'I', style = 'invisible', arrowhead = 'none') T.add_edge('I', 'S', style = 'invisible', arrowhead = 'none') T.add_edge('S', 'P', style = 'invisible', arrowhead = 'none') T.add_edge('P', 'PC', style = 'invisible', arrowhead = 'none') T.create_cluster(['C', 'I', 'S', 'P', 'PC'], cluster_attrs) # The initial lower bound LB = -INFINITY # The number of LP's solved, and the number of nodes solved node_count = 1 iter_count = 0 lp_count = 0 if binary_vars: var = LpVariable.dicts("", VARIABLES, 0, 1) else: var = LpVariable.dicts("", VARIABLES) numCons = len(CONSTRAINTS) numVars = len(VARIABLES) # List of incumbent solution variable values opt = dict([(i, 0) for i in VARIABLES]) pseudo_u = dict((i, (OBJ[i], 0)) for i in VARIABLES) pseudo_d = dict((i, (OBJ[i], 0)) for i in VARIABLES) print("===========================================") print("Starting Branch and Bound") if branch_strategy == MOST_FRACTIONAL: print("Most fractional variable") elif branch_strategy == FIXED_BRANCHING: print("Fixed order") elif branch_strategy == PSEUDOCOST_BRANCHING: print("Pseudocost brancing") else: print("Unknown branching strategy %s" %branch_strategy) if search_strategy == DEPTH_FIRST: print("Depth first search strategy") elif search_strategy == BEST_FIRST: print("Best first search strategy") else: print("Unknown search strategy %s" %search_strategy) print("===========================================") # List of candidate nodes Q = PriorityQueue() # The current tree depth cur_depth = 0 cur_index = 0 # Timer timer = time.time() Q.push(0, -INFINITY, (0, None, None, None, None, None, None)) # Branch and Bound Loop while not Q.isEmpty(): infeasible = False integer_solution = False (cur_index, parent, relax, branch_var, branch_var_value, sense, rhs) = Q.pop() if cur_index is not 0: cur_depth = T.get_node_attr(parent, 'level') + 1 else: cur_depth = 0 print("") print("----------------------------------------------------") print("") if LB > -INFINITY: print("Node: %s, Depth: %s, LB: %s" %(cur_index,cur_depth,LB)) else: print("Node: %s, Depth: %s, LB: %s" %(cur_index,cur_depth,"None")) if relax is not None and relax <= LB: print("Node pruned immediately by bound") T.set_node_attr(parent, 'color', 'red') continue #==================================== # LP Relaxation #==================================== # Compute lower bound by LP relaxation prob = LpProblem("relax", LpMaximize) prob += lpSum([OBJ[i]*var[i] for i in VARIABLES]), "Objective" for j in range(numCons): prob += (lpSum([MAT[i][j]*var[i] for i in VARIABLES])<=RHS[j],\ CONSTRAINTS[j]) # Fix all prescribed variables branch_vars = [] if cur_index is not 0: sys.stdout.write("Branching variables: ") branch_vars.append(branch_var) if sense == '>=': prob += LpConstraint(lpSum(var[branch_var]) >= rhs) else: prob += LpConstraint(lpSum(var[branch_var]) <= rhs) print(branch_var, end=' ') pred = parent while not str(pred) == '0': pred_branch_var = T.get_node_attr(pred, 'branch_var') pred_rhs = T.get_node_attr(pred, 'rhs') pred_sense = T.get_node_attr(pred, 'sense') if pred_sense == '<=': prob += LpConstraint(lpSum(var[pred_branch_var]) <= pred_rhs) else: prob += LpConstraint(lpSum(var[pred_branch_var]) >= pred_rhs) print(pred_branch_var, end=' ') branch_vars.append(pred_branch_var) pred = T.get_node_attr(pred, 'parent') print() # Solve the LP relaxation prob.solve() lp_count = lp_count +1 # Check infeasibility infeasible = LpStatus[prob.status] == "Infeasible" or \ LpStatus[prob.status] == "Undefined" # Print status if infeasible: print("LP Solved, status: Infeasible") else: print("LP Solved, status: %s, obj: %s" %(LpStatus[prob.status], value(prob.objective))) if(LpStatus[prob.status] == "Optimal"): relax = value(prob.objective) # Update pseudocost if branch_var != None: if sense == '<=': pseudo_d[branch_var] = ( old_div((pseudo_d[branch_var][0]*pseudo_d[branch_var][1] + old_div((T.get_node_attr(parent, 'obj') - relax), (branch_var_value - rhs))),(pseudo_d[branch_var][1]+1)), pseudo_d[branch_var][1]+1) else: pseudo_u[branch_var] = ( old_div((pseudo_u[branch_var][0]*pseudo_d[branch_var][1] + old_div((T.get_node_attr(parent, 'obj') - relax), (rhs - branch_var_value))),(pseudo_u[branch_var][1]+1)), pseudo_u[branch_var][1]+1) var_values = dict([(i, var[i].varValue) for i in VARIABLES]) integer_solution = 1 for i in VARIABLES: if (abs(round(var_values[i]) - var_values[i]) > .001): integer_solution = 0 break # Determine integer_infeasibility_count and # Integer_infeasibility_sum for scatterplot and such integer_infeasibility_count = 0 integer_infeasibility_sum = 0.0 for i in VARIABLES: if (var_values[i] not in set([0,1])): integer_infeasibility_count += 1 integer_infeasibility_sum += min([var_values[i], 1.0-var_values[i]]) if (integer_solution and relax>LB): LB = relax for i in VARIABLES: # These two have different data structures first one #list, second one dictionary opt[i] = var_values[i] print("New best solution found, objective: %s" %relax) for i in VARIABLES: if var_values[i] > 0: print("%s = %s" %(i, var_values[i])) elif (integer_solution and relax<=LB): print("New integer solution found, objective: %s" %relax) for i in VARIABLES: if var_values[i] > 0: print("%s = %s" %(i, var_values[i])) else: print("Fractional solution:") for i in VARIABLES: if var_values[i] > 0: print("%s = %s" %(i, var_values[i])) #For complete enumeration if complete_enumeration: relax = LB - 1 else: relax = INFINITY if integer_solution: print("Integer solution") BBstatus = 'S' status = 'integer' color = 'lightblue' elif infeasible: print("Infeasible node") BBstatus = 'I' status = 'infeasible' color = 'orange' elif not complete_enumeration and relax <= LB: print("Node pruned by bound (obj: %s, UB: %s)" %(relax,LB)) BBstatus = 'P' status = 'fathomed' color = 'red' elif cur_depth >= numVars : print("Reached a leaf") BBstatus = 'fathomed' status = 'L' else: BBstatus = 'C' status = 'candidate' color = 'yellow' if BBstatus is 'I': if T.get_layout() == 'dot2tex': label = '\text{I}' else: label = 'I' else: label = "%.1f"%relax if iter_count == 0: if status is not 'candidate': integer_infeasibility_count = None integer_infeasibility_sum = None if status is 'fathomed': if T._incumbent_value is None: print('WARNING: Encountered "fathom" line before '+\ 'first incumbent.') T.AddOrUpdateNode(0, None, None, 'candidate', relax, integer_infeasibility_count, integer_infeasibility_sum, label = label, obj = relax, color = color, style = 'filled', fillcolor = color) if status is 'integer': T._previous_incumbent_value = T._incumbent_value T._incumbent_value = relax T._incumbent_parent = -1 T._new_integer_solution = True # #Currently broken # if ETREE_INSTALLED and T.attr['display'] == 'svg': # T.write_as_svg(filename = "node%d" % iter_count, # nextfile = "node%d" % (iter_count + 1), # highlight = cur_index) else: _direction = {'<=':'L', '>=':'R'} if status is 'infeasible': integer_infeasibility_count = T.get_node_attr(parent, 'integer_infeasibility_count') integer_infeasibility_sum = T.get_node_attr(parent, 'integer_infeasibility_sum') relax = T.get_node_attr(parent, 'lp_bound') elif status is 'fathomed': if T._incumbent_value is None: print('WARNING: Encountered "fathom" line before'+\ ' first incumbent.') print(' This may indicate an error in the input file.') elif status is 'integer': integer_infeasibility_count = None integer_infeasibility_sum = None T.AddOrUpdateNode(cur_index, parent, _direction[sense], status, relax, integer_infeasibility_count, integer_infeasibility_sum, branch_var = branch_var, branch_var_value = var_values[branch_var], sense = sense, rhs = rhs, obj = relax, color = color, style = 'filled', label = label, fillcolor = color) if status is 'integer': T._previous_incumbent_value = T._incumbent_value T._incumbent_value = relax T._incumbent_parent = parent T._new_integer_solution = True # Currently Broken # if ETREE_INSTALLED and T.attr['display'] == 'svg': # T.write_as_svg(filename = "node%d" % iter_count, # prevfile = "node%d" % (iter_count - 1), # nextfile = "node%d" % (iter_count + 1), # highlight = cur_index) if T.get_layout() == 'dot2tex': _dot2tex_label = {'>=':' \geq ', '<=':' \leq '} T.set_edge_attr(parent, cur_index, 'label', str(branch_var) + _dot2tex_label[sense] + str(rhs)) else: T.set_edge_attr(parent, cur_index, 'label', str(branch_var) + sense + str(rhs)) iter_count += 1 if BBstatus == 'C': # Branching: # Choose a variable for branching branching_var = None if branch_strategy == FIXED_BRANCHING: #fixed order for i in VARIABLES: frac = min(var[i].varValue-math.floor(var[i].varValue), math.ceil(var[i].varValue) - var[i].varValue) if (frac > 0): min_frac = frac branching_var = i # TODO(aykut): understand this break break elif branch_strategy == MOST_FRACTIONAL: #most fractional variable min_frac = -1 for i in VARIABLES: frac = min(var[i].varValue-math.floor(var[i].varValue), math.ceil(var[i].varValue)- var[i].varValue) if (frac> min_frac): min_frac = frac branching_var = i elif branch_strategy == PSEUDOCOST_BRANCHING: scores = {} for i in VARIABLES: # find the fractional solutions if (var[i].varValue - math.floor(var[i].varValue)) != 0: scores[i] = min(pseudo_u[i][0]*(1-var[i].varValue), pseudo_d[i][0]*var[i].varValue) # sort the dictionary by value branching_var = sorted(list(scores.items()), key=lambda x : x[1])[-1][0] else: print("Unknown branching strategy %s" %branch_strategy) exit() if branching_var is not None: print("Branching on variable %s" %branching_var) #Create new nodes if search_strategy == DEPTH_FIRST: priority = (-cur_depth - 1, -cur_depth - 1) elif search_strategy == BEST_FIRST: priority = (-relax, -relax) elif search_strategy == BEST_ESTIMATE: priority = (-relax - pseudo_d[branching_var][0]*\ (math.floor(var[branching_var].varValue) -\ var[branching_var].varValue), -relax + pseudo_u[branching_var][0]*\ (math.ceil(var[branching_var].varValue) -\ var[branching_var].varValue)) node_count += 1 Q.push(node_count, priority[0], (node_count, cur_index, relax, branching_var, var_values[branching_var], '<=', math.floor(var[branching_var].varValue))) node_count += 1 Q.push(node_count, priority[1], (node_count, cur_index, relax, branching_var, var_values[branching_var], '>=', math.ceil(var[branching_var].varValue))) T.set_node_attr(cur_index, color, 'green') if T.root is not None and display_interval is not None and\ iter_count%display_interval == 0: T.display(count=iter_count) timer = int(math.ceil((time.time()-timer)*1000)) print("") print("===========================================") print("Branch and bound completed in %sms" %timer) print("Strategy: %s" %branch_strategy) if complete_enumeration: print("Complete enumeration") print("%s nodes visited " %node_count) print("%s LP's solved" %lp_count) print("===========================================") print("Optimal solution") #print optimal solution for i in sorted(VARIABLES): if opt[i] > 0: print("%s = %s" %(i, opt[i])) print("Objective function value") print(LB) print("===========================================") if T.attr['display'] is not 'off': T.display(count=iter_count) T._lp_count = lp_count return opt, LB
numVars = 40 numCons = 20 density = 0.2 maxObjCoeff = 10 maxConsCoeff = 10 CONSTRAINTS = ["C"+str(i) for i in range(numCons)] if layout == 'ladot': VARIABLES = ["x_{"+str(i)+"}" for i in range(numVars)] else: VARIABLES = ["x"+str(i) for i in range(numVars)] OBJ = {i : randint(1, maxObjCoeff) for i in VARIABLES} MAT = {i : [randint(1, maxConsCoeff) if random() <= density else 0 for j in CONSTRAINTS] for i in VARIABLES} RHS = [randint(int(numVars*density*maxConsCoeff/2), int(numVars*density*maxConsCoeff/1.5)) for i in CONSTRAINTS] var = LpVariable.dicts("", VARIABLES, 0, 1) ################################################################ #Branching strategies MOST_FRAC = "MOST FRACTIONAL" FIXED = "FIXED" #search strategies DEPTH_FIRST = "Depth First" BEST_FIRST = "Best First" #Selected branching strategy branch_strategy = FIXED search_strategy = BEST_FIRST
def schedule(Jobs, Agents, D, C, R, B, P, M): """ Finds the optimal scheduling of Jobs to Agents (workers) given Jobs - a set of Jobs (an iterable of hashable objects) Agents - a set of Agents/workers (an iterable of hashable objects) D - Dictionary detailing execution cost of running jobs on agents : D[job, agent] = time to run job on agent C - Dictionary detailing Communication cost sending results of jobs between agents : C[job, a1, a2] = time to comm results of job on from a1 to a2 R - Additional constraint on start time of jobs, usually defaultdict(0) B - Dict saying which jobs can run on which agents: B[job, agent] == 1 if job can run on agent P - Dictionary containing precedence constraints - specifies DAG: P[job1, job2] == 1 if job1 immediately precedes job2 M - Upper bound on makespan Returns prob - the pulp problem instance X - Dictionary detailing which jobs were run on which agents: X[job][agent] == 1 iff job was run on agent S - Starting time of each job Cmax - Optimal makespan """ # Set up global precedence matrix Q = PtoQ(P) # PULP SETUP # The prob variable is created to contain the problem data prob = LpProblem("Scheduling Problem - Tompkins Formulation", LpMinimize) # The problem variables are created # X - 1 if job is scheduled to be completed by agent X = LpVariable.dicts("X", (Jobs, Agents), 0, 1, LpInteger) # S - Scheduled start time of job S = LpVariable.dicts("S", Jobs, 0, M, LpContinuous) # Theta - Whether two jobs overlap Theta = LpVariable.dicts("Theta", (Jobs, Jobs), 0, 1, LpInteger) # Makespan Cmax = LpVariable("C_max", 0, M, LpContinuous) ##################### # 4.2.2 CONSTRAINTS # ##################### # Objective function prob += Cmax # Subject to: # 4-1 Cmax is greater than the ending schedule time of all jobs for job in Jobs: prob += Cmax >= S[job] + lpSum([D[job, agent] * X[job][agent] for agent in Agents if B[job, agent]>0]) # 4-2 an agent cannot be assigned a job unless it provides the services # necessary to complete that job for job in Jobs: for agent in Agents: if B[job, agent] == 0: prob += X[job][agent] == 0 # 4-3 specifies that each job must be assigned once to exactly one agent for job in Jobs: prob += lpSum([X[job][agent] for agent in Agents]) == 1 # 4-4 a job cannot start until its predecessors are completed and data has # been communicated to it if the preceding jobs were executed on a # different agent for (j,k), prec in P.items(): if prec>0: # if j precedes k in the DAG prob += S[k]>=S[j] for a in Agents: for b in Agents: if B[j,a] and B[k,b]: # a is capable of j and b capable of k prob += S[k] >= (S[j] + (D[j,a] + C[j,a,b]) * (X[j][a] + X[k][b] -1)) # 4-5 a job cannot start until after its release time for job in Jobs: if R[job]>0: prob += S[job] >= R[job] # Collectively, (4-6) and (4-7) specify that an agent may process at most # one job at a time # 4-6 for j in Jobs: for k in Jobs: if j==k or Q[j,k]!=0: continue prob += S[k] - lpSum([D[j,a]*X[j][a] for a in Agents]) - S[j] >= ( -M*Theta[j][k]) # The following line had a < in the paper. We've switched to <= # Uncertain if this is a good idea prob += S[k] - lpSum([D[j,a]*X[j][a] for a in Agents]) - S[j] <= ( M*(1-Theta[j][k])) # 4-7 if two jobs j and k are assigned to the same agent, their execution # times may not overlap for j in Jobs: for k in Jobs: for a in Agents: prob += X[j][a] + X[k][a] + Theta[j][k] + Theta[k][j] <= 3 return prob, X, S, Cmax
numBlockVars = [10] numBlockCons = [5] numLinkingCons = 10 numVars = sum(numBlockVars) numCons = sum(numBlockCons) + numLinkingCons VARIABLES = dict(((i, j), 0) for i in range(numBlocks) for j in range(numBlockVars[i])) CONSTRAINTS = [] for k in range(numBlocks): CONSTRAINTS.append(["C"+str(k)+"_"+str(j) for j in range(numCons)]) CONSTRAINTS.append(["C"+str(numBlocks)+"_"+str(j) for j in range(numCons)]) #Generate random MILP var = LpVariable.dicts("x", VARIABLES, 0, 1, LpBinary) numCons = len(CONSTRAINTS) numVars = len(VARIABLES) OBJ, MAT, RHS = GenerateRandomBlock(VARIABLES, CONSTRAINTS[numBlocks]) prob += -lpSum([OBJ[i]*var[i] for i in var]), "Objective" #Linking constraints for j in CONSTRAINTS[numBlocks]: prob += lpSum([MAT[i, j]*var[i] for i in var]) <= RHS[j], j #Blocks for k in range(numBlocks): OBJ, MAT, RHS = GenerateRandomBlock([(k, i) for i in range(numBlockVars[k])], CONSTRAINTS[k])
ARC_COSTS.update(CUST_TRANS) ARCS = ARC_COSTS.keys() def cross(i1, i2): r = [] for a in i1: for b in i2: r.append((a, b)) return r LOC_SIZES = cross(LOCATIONS, SIZES) prob = dippy.DipProblem("Coke", LpMinimize) # create variables buildVars = LpVariable.dicts("Build", LOC_SIZES, None, \ None, LpBinary) prob.buildVars = buildVars # create arcs flowVars = LpVariable.dicts("Arcs", ARCS) for a in ARCS: flowVars[a].bounds(0, BIG_M) prob.SIZES = SIZES # objective prob += 1e6 * lpSum(buildVars[(l, s)] * SIZE_COSTS[s] \ for (l, s) in LOC_SIZES) + \ lpSum(flowVars[(s, d)] * ARC_COSTS[(s, d)] \ for (s, d) in ARCS), "min"
x -= (x >> 1) & 0x5555555555555555 x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333) x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f return ((x * 0x0101010101010101) & 0xffffffffffffffff ) >> 56 labels = range(2**nmice) # Only use labels with a Hamming weight <= 3 nonzeros = [i for i in labels if popcount(i) in [0,1,2,3]] # Initialize problem prob = LpProblem("drunk_mice", LpMinimize) # This is the answer, the allocation of bottles to each label: allocs = LpVariable.dicts( "alloc", nonzeros, 0, nbottles, LpInteger, ) # They must sum to nbottles: prob += lpSum(allocs) == nbottles # This is the number we are minimizing worst_loss = LpVariable( "worst_loss", npoisoned, nbottles, ) prob += worst_loss, "obj"
from math import floor, ceil tol = pow(pow(2, -24), 2.0 / 3.0) debug_print = False REQUIREMENT = data.REQUIREMENT PRODUCTS = data.PRODUCTS LOCATIONS = data.LOCATIONS CAPACITY = data.CAPACITY print REQUIREMENT prob = dippy.DipProblem("Bin Packing") assign_vars = LpVariable.dicts("AtLocation", [(i, j) for i in data.LOCATIONS for j in data.PRODUCTS], 0, 1, LpBinary) use_vars = LpVariable.dicts("UseLocation", data.LOCATIONS, 0, 1, LpBinary) waste_vars = LpVariable.dicts("Waste", data.LOCATIONS, 0, data.CAPACITY) # objective: minimise waste prob += lpSum(waste_vars[i] for i in LOCATIONS), "min" # assignment constraints for j in PRODUCTS: prob += lpSum(assign_vars[(i, j)] for i in LOCATIONS) == 1 # Aggregate capacity constraints for i in LOCATIONS:
try: from facility_ex2 import ASSIGNMENTS except ImportError: ASSIGNMENTS = [(i, j) for i in LOCATIONS for j in PRODUCTS] try: from facility_ex2 import ASSIGNMENT_COSTS except ImportError: ASSIGNMENT_COSTS = dict((i, 0) for i in ASSIGNMENTS) display_mode = 'xdot' prob = dippy.DipProblem("Facility Location", display_mode = display_mode, layout = 'dot', display_interval = 0) assign_vars = LpVariable.dicts("x", ASSIGNMENTS, 0, 1, LpBinary) use_vars = LpVariable.dicts("y", LOCATIONS, 0, 1, LpBinary) debug_print = False debug_print_lp = False prob += (lpSum(use_vars[i] * FIXED_COST[i] for i in LOCATIONS) + lpSum(assign_vars[j] * ASSIGNMENT_COSTS[j] for j in ASSIGNMENTS), "min") # assignment constraints for j in PRODUCTS: prob += lpSum(assign_vars[(i, j)] for i in LOCATIONS) == 1 # Aggregate capacity constraints
def learn_two_cat2(self, performance_table): """This version of learnTwoCat checks whether or not an alternative is to be kept in the learning process. This method is also faster than the previous version """ if len(self.categories) != 2: raise SemanticError, "The learnTwoCat() method requires exactly two categories." prob = LpProblem("twoCat2", LpMaximize) alts = filter(lambda a: a.__class__.__name__ != "LimitProfile", performance_table.alts) crits = self.crits alts_name = [alt.name for alt in alts] crits_name = [crit.name for crit in crits] self.categories.sort(key=lambda c: c.rank) alts1 = [alt for alt in alts if alt.category == self.categories[0]] alts2 = [alt for alt in alts if alt.category == self.categories[1]] #small float number epsilon = 0.0001 #variables (v: variable, d: dict of variables) v_lambda = LpVariable("lambda", lowBound=0.5, upBound=1) d_gamma = LpVariable.dicts("gamma", alts_name, cat=LpBinary) d_p = LpVariable.dicts("p", crits_name, lowBound=0, upBound=1) d_gb = LpVariable.dicts("gb", crits_name, lowBound=0, upBound=1) d_delta = LpVariable.dicts("delta", \ [alt.name + crit.name for alt in alts for crit in crits]\ , cat=LpBinary) d_c = LpVariable.dicts("c", \ [alt.name + crit.name for alt in alts for crit in crits]\ , lowBound=0, upBound=1) #maximize prob += sum(d_gamma[alt.name] for alt in alts) #constraints for alt in alts2: prob += sum(d_c[alt.name + crit.name] for crit in crits) + epsilon <= v_lambda + 2 * (1 - d_gamma[alt.name]) for alt in alts1: prob += sum(d_c[alt.name + crit.name] for crit in crits) >= v_lambda - 2 * (1 - d_gamma[alt.name]) for alt in alts: for crit in crits: prob += d_c[alt.name + crit.name] <= d_p[crit.name] prob += d_c[alt.name + crit.name] <= d_delta[alt.name + crit.name] prob += d_c[alt.name + crit.name] >= d_delta[alt.name + crit.name] + d_p[crit.name] - 1 prob += d_delta[alt.name + crit.name] >= performance_table[alt][crit] - d_gb[crit.name] + epsilon prob += d_delta[alt.name + crit.name] <= performance_table[alt][crit] - d_gb[crit.name] + 1 prob += sum(d_p[crit.name] for crit in crits) == 1 #solver GLPK().solve(prob) #update parameters self.cutting_threshold = v_lambda.value() for crit in crits: crit.weight = d_p[crit.name].value() for crit in crits: self.lp_performance_table[self.limit_profiles[0]][crit] = d_gb[crit.name].value() self.ignoredAlternatives = [] for alt in alts: if d_gamma[alt.name].value() == 0: self.ignoredAlternatives.append(alt)
def learn(self, performance_table): """Learn parameters""" prob = LpProblem("Learn", LpMaximize) alts = filter(lambda a: a.__class__.__name__ != "LimitProfile", performance_table.alts) crits = self.crits alts_name = [alt.name for alt in alts] crits_name = [crit.name for crit in crits] categories = self.categories categories.sort(key=lambda c: c.rank, reverse=True) categoriesUp = list(categories) firstCat = categoriesUp.pop(0) categoriesDown = list(categories) lastCat = categoriesDown.pop() categories0 = list(categories) categories0.insert(0, Category(rank = (categories[0].rank + 1), name = "fake")) #add a fake category on the first position alternativesByCat = {} for cat in categories: alternativesByCat[cat] = [alt for alt in alts if alt.category == cat] #small float number epsilon = 0.000001 #variables (v: variable, d: dict of variables) v_lambda = LpVariable("lambda", lowBound=0.5, upBound=1) v_alpha = LpVariable("alpha", lowBound=0) d_x = LpVariable.dicts("x", alts_name, lowBound=0) d_y = LpVariable.dicts("y", alts_name, lowBound=0) d_p = LpVariable.dicts("p", crits_name, lowBound=0, upBound=1) d_gb = LpVariable.dicts("gb", \ [crit.name + cat.name for crit in crits for cat in categories0], \ lowBound=0, \ upBound=1) d_deltaInf = LpVariable.dicts("deltaInf", \ [alt.name + crit.name for alt in alts for crit in crits], \ cat=LpBinary) d_deltaSup = LpVariable.dicts("deltaSup", \ [alt.name + crit.name for alt in alts for crit in crits], \ cat=LpBinary) d_cInf = LpVariable.dicts("cInf", \ [alt.name + crit.name for alt in alts for crit in crits], \ lowBound=0, upBound=1) d_cSup = LpVariable.dicts("cSup", \ [alt.name + crit.name for alt in alts for crit in crits], \ lowBound=0, upBound=1) #maximize prob += v_alpha #constraints for crit in crits: prob += d_gb[crit.name + "fake"] == 0 prob += d_gb[crit.name + lastCat.name] == 1 for cat in categoriesDown: for alt in alternativesByCat[cat]: prob += sum(d_cSup[alt.name + crit.name] for crit in crits) + d_x[alt.name] == v_lambda for cat in categoriesUp: for alt in alternativesByCat[cat]: prob += sum(d_cInf[alt.name + crit.name] for crit in crits) == v_lambda + d_y[alt.name] for alt in alts: prob += v_alpha <= d_x[alt.name] prob += v_alpha <= d_y[alt.name] prob += d_x[alt.name] >= epsilon for crit in crits: prob += d_cInf[alt.name + crit.name] <= d_p[crit.name] prob += d_cSup[alt.name + crit.name] <= d_p[crit.name] prob += d_cInf[alt.name + crit.name] <= d_deltaInf[alt.name + crit.name] prob += d_cSup[alt.name + crit.name] <= d_deltaSup[alt.name + crit.name] prob += d_cInf[alt.name + crit.name] >= d_deltaInf[alt.name + crit.name] + d_p[crit.name] - 1 prob += d_cSup[alt.name + crit.name] >= d_deltaSup[alt.name + crit.name] + d_p[crit.name] - 1 prev_cat_name = "fake" for cat in categories: for alt in alternativesByCat[cat]: for crit in crits: prob += d_deltaInf[alt.name + crit.name] >= performance_table[alt][crit] - d_gb[crit.name + prev_cat_name] + epsilon prob += d_deltaSup[alt.name + crit.name] >= performance_table[alt][crit] - d_gb[crit.name + cat.name] + epsilon prob += d_deltaInf[alt.name + crit.name] <= performance_table[alt][crit] - d_gb[crit.name + prev_cat_name] + 1 prob += d_deltaSup[alt.name + crit.name] <= performance_table[alt][crit] - d_gb[crit.name + cat.name] + 1 prev_cat_name = cat.name prev_cat_name = firstCat.name for cat in categoriesUp: for crit in crits: prob += d_gb[crit.name + cat.name] >= d_gb[crit.name + prev_cat_name] prev_cat_name = cat.name prob += sum(d_p[crit.name] for crit in crits) == 1 print prob #solver GLPK().solve(prob) #prob.writeLP("SpamClassification.lp") #status = prob.solve() #update parameters self.cutting_threshold = v_lambda.value() for crit in crits: crit.weight = d_p[crit.name].value() for cat in categoriesDown: for crit in crits: performance_table[cat.lp_sup][crit] = d_gb[crit.name + cat.name].value()
def learn2(self, performance_table): """This version of learn checks whether or not an alternative is to be kept in the learning process. This method is also faster than the previous version """ prob = LpProblem("Learn", LpMaximize) alts = filter(lambda a: a.__class__.__name__ != "LimitProfile", performance_table.alts) crits = self.crits alts_name = [alt.name for alt in alts] crits_name = [crit.name for crit in crits] categories = self.categories categories.sort(key=lambda c: c.rank, reverse=True) categoriesUp = list(categories) firstCat = categoriesUp.pop(0) categoriesDown = list(categories) lastCat = categoriesDown.pop() categories0 = list(categories) categories0.insert(0, Category(rank = (categories[0].rank + 1), name = "fake")) #add a fake category on the first position alternativesByCat = {} for cat in categories: alternativesByCat[cat] = [alt for alt in alts if alt.category == cat] #small float number epsilon = 0.001 #variables (v: variable, d: dict of variables) v_lambda = LpVariable("lambda", lowBound=0.5, upBound=1) d_gamma = LpVariable.dicts("gamma", alts_name, cat=LpBinary) d_p = LpVariable.dicts("p", crits_name, lowBound=0, upBound=1) d_gb = LpVariable.dicts("gb", \ [crit.name + cat.name for crit in crits for cat in categories0], \ lowBound=0, \ upBound=1) d_deltaInf = LpVariable.dicts("deltaInf", \ [alt.name + crit.name for alt in alts for crit in crits], \ cat=LpBinary) d_deltaSup = LpVariable.dicts("deltaSup", \ [alt.name + crit.name for alt in alts for crit in crits], \ cat=LpBinary) d_cInf = LpVariable.dicts("cInf", \ [alt.name + crit.name for alt in alts for crit in crits], \ lowBound=0, upBound=1) d_cSup = LpVariable.dicts("cSup", \ [alt.name + crit.name for alt in alts for crit in crits], \ lowBound=0, upBound=1) #maximize prob += sum(d_gamma[alt.name] for alt in alts) #constraints for crit in crits: prob += d_gb[crit.name + "fake"] == 0 prob += d_gb[crit.name + lastCat.name] == 1 for cat in categoriesDown: for alt in alternativesByCat[cat]: tmp = alt.name + crit.name #fixed a weird bug with pulp prob += sum(d_cSup[tmp] for crit in crits) + epsilon <= v_lambda + 2 * (1 - d_gamma[alt.name]) for cat in categoriesUp: for alt in alternativesByCat[cat]: tmp = alt.name + crit.name #fixed a weird bug with pulp prob += sum(d_cInf[tmp] for crit in crits) >= v_lambda - 2 * (1 - d_gamma[alt.name]) for alt in alts: for crit in crits: prob += d_cInf[alt.name + crit.name] <= d_p[crit.name] prob += d_cSup[alt.name + crit.name] <= d_p[crit.name] prob += d_cInf[alt.name + crit.name] <= d_deltaInf[alt.name + crit.name] prob += d_cSup[alt.name + crit.name] <= d_deltaSup[alt.name + crit.name] prob += d_cInf[alt.name + crit.name] >= d_deltaInf[alt.name + crit.name] + d_p[crit.name] - 1 prob += d_cSup[alt.name + crit.name] >= d_deltaSup[alt.name + crit.name] + d_p[crit.name] - 1 prev_cat_name = "fake" for cat in categories: for alt in alternativesByCat[cat]: for crit in crits: prob += d_deltaInf[alt.name + crit.name] >= performance_table[alt][crit] - d_gb[crit.name + prev_cat_name] + epsilon prob += d_deltaSup[alt.name + crit.name] >= performance_table[alt][crit] - d_gb[crit.name + cat.name] + epsilon prob += d_deltaInf[alt.name + crit.name] <= performance_table[alt][crit] - d_gb[crit.name + prev_cat_name] + 1 prob += d_deltaSup[alt.name + crit.name] <= performance_table[alt][crit] - d_gb[crit.name + cat.name] + 1 prev_cat_name = cat.name prev_cat_name = firstCat.name for cat in categoriesUp: for crit in crits: prob += d_gb[crit.name + cat.name] >= d_gb[crit.name + prev_cat_name] prev_cat_name = cat.name prob += sum(d_p[crit.name] for crit in crits) == 1 print prob #solver GLPK().solve(prob) #update parameters self.cutting_threshold = v_lambda.value() for crit in crits: crit.weight = d_p[crit.name].value() for cat in categoriesDown: for crit in crits: performance_table[cat.lp_sup][crit] = d_gb[crit.name + cat.name].value() self.ignoredAlternatives = [] for alt in alts: if d_gamma[alt.name].value() == 0: self.ignoredAlternatives.append(alt)
def weak_rev_lin_con(crn, eps, ubound): m = crn.n_complexes n = crn.n_species # Y is n by m Y = np.array(crn.complex_matrix).astype(np.float64) # Ak is m by m Ak = np.array(crn.kinetic_matrix).astype(np.float64) # M is n by m M = Y.dot(Ak) print("Input CRN defined by\nY =\n", Y) print("\nM =\n", M) print("\nAk =\n", Ak) print("\nComputing linearly conjugate network with min deficiency ... START\n") # Ranges for iteration col_range = range(1, m+1) row_range = range(1, n+1) # Set up problem model object prob = LpProblem("Weakly Reversible Linearly Conjugate Network", LpMaximize) # Get a list of all off-diagonal entries to use later to greatly # simplify loops off_diag = [(i, j) for i,j in product(col_range, repeat=2) if i != j] # Decision variables for matrix A, only need off-diagonal since A # has zero-sum columns A = LpVariable.dicts("A", [(i, j) for i in col_range for j in col_range]) Ah = LpVariable.dicts("Ah", [(i, j) for i in col_range for j in col_range]) # Decision variables for the diagonal of T T = LpVariable.dicts("T", row_range, eps, ubound) # Binary variables for counting partitions used and assigning complexes to linkage classes delta = LpVariable.dicts("delta", off_diag, 0, 1, "Integer") # Objective prob += -lpSum(delta[i, j] for (i,j) in off_diag) # Y*A = T*M for i in row_range: for j in col_range: prob += lpSum( Y[i-1, k-1]*A[k, j] for k in col_range ) == M[i-1, j-1]*T[i] # A and Ah have zero-sum columns for j in col_range: prob += lpSum( A[i,j] for i in col_range ) == 0 prob += lpSum( Ah[i,j] for i in col_range ) == 0 prob += lpSum( Ah[j,i] for i in col_range ) == 0 # Off-diagonal entries are nonnegative and are switch on/off by delta[i,j] for (i,j) in off_diag: # A constraints prob += A[i, j] >= 0 prob += A[i, j] - eps*delta[i, j] >= 0 prob += A[i, j] - ubound*delta[i, j] <= 0 # Ah constraints prob += Ah[i, j] >= 0 prob += Ah[i, j] - eps*delta[i, j] >= 0 prob += Ah[i, j] - ubound*delta[i, j] <= 0 # Diagonal entries of A, Ah are non-positive for j in col_range: prob += A[j, j] <= 0 prob += Ah[j, j] <= 0 status = prob.solve(solver=CPLEX()) #print(prob) # Problem successfully solved, report results if status == 1: # Get solutions to problem Tsol = np.zeros((n, n)) Asol = np.zeros((m,m)) for i in col_range: for j in col_range: Asol[i-1, j-1] = value(A[i, j]) for i in row_range: Tsol[i-1, i-1] = value(T[i]) print("\nA =\n", Asol) print("\nT =\n", Tsol) else: print("No solution found")
def opAss_LP(machineList, PBlist, PBskills, previousAssignment={}, weightFactors = [2, 1, 0, 2, 1, 1], Tool={}): from pulp import LpProblem, LpMaximize, LpVariable, LpBinary, lpSum, LpStatus import pulp import copy import glob import os import time from Globals import G startPulp=time.time() machines = machineList.keys() sumWIP = float(sum([machineList[mach]['WIP'] for mach in machines ])) # define LP problem prob = LpProblem("PBassignment", LpMaximize) obj = [] # declare variables...binary assignment variables (operator i to machine j) PB_ass = LpVariable.dicts('PB', [(oper,mach) for oper in PBlist for mach in machines if machineList[mach]['stationID'] in PBskills[oper]] , 0, 1, cat=pulp.LpBinary) # objective...assignment of PBs to stations with higher WIP...sum of WIP associated with stations where PB is assigned if weightFactors[0]>0 and sumWIP>0: obj.append([machineList[mach]['WIP']*PB_ass[(oper,mach)]*weightFactors[0]/float(sumWIP) for oper in PBlist for mach in machines if machineList[mach]['stationID'] in PBskills[oper]]) # second set of variables (delta assignment between stations) to facilitate the distribution of PBs across different stations if weightFactors[1]>0: stationGroup = {} for mach in machines: if machineList[mach]['stationID'] not in stationGroup: stationGroup[machineList[mach]['stationID']] = [] stationGroup[machineList[mach]['stationID']].append(mach) Delta_Station = LpVariable.dicts("D_station", [(st1, st2) for i1, st1 in enumerate(stationGroup.keys()) for st2 in stationGroup.keys()[i1 + 1:]]) # calculate global max number of machines within a station that will be used as dividers for Delta_Station maxNoMachines = 0 for st in stationGroup: if len(stationGroup[st]) > maxNoMachines: maxNoMachines = len(stationGroup[st]) # calculation of DeltaStation values for i, st1 in enumerate(stationGroup.keys()): tempList = [] for mach1 in stationGroup[st1]: for oper1 in PBlist: if st1 in PBskills[oper1]: tempList.append(PB_ass[(oper1,mach1)]/float(maxNoMachines)) for st2 in stationGroup.keys()[i+1:]: finalList = copy.copy(tempList) for mach2 in stationGroup[st2]: for oper2 in PBlist: if st2 in PBskills[oper2]: finalList.append(PB_ass[(oper2,mach2)]*-1/float(maxNoMachines)) prob += lpSum(finalList)>= Delta_Station[(st1,st2)] prob += lpSum([i*-1 for i in finalList])>= Delta_Station[(st1,st2)] # integration of second obj normalisingFactorDeltaStation = 0 for i in range(len(stationGroup)): normalisingFactorDeltaStation += i for i1, st1 in enumerate(stationGroup.keys()): for st2 in stationGroup.keys()[i1+1:]: obj.append(Delta_Station[(st1,st2)]*weightFactors[1]/float(normalisingFactorDeltaStation) ) # min variation in PB assignment if weightFactors[2]>0: Delta_Assignment = [] OldAss = {} for pb in previousAssignment: if pb in PBlist: for station in PBskills[pb]: for mach in machineList: if machineList[mach]['stationID'] == station: Delta_Assignment.append([pb, mach]) if previousAssignment[pb] == mach: OldAss[(pb,mach)] = 1 else: OldAss[(pb,mach)] = 0 # create delta assignment variables Delta_Ass = LpVariable.dicts("D_Ass",[(d[0],d[1]) for d in Delta_Assignment]) # integration of third objective for d in Delta_Assignment: obj.append(Delta_Ass[(d[0], d[1])]*(-1.0*weightFactors[2]/(2*len(previousAssignment))) ) # calculation of Delta_Ass for d in Delta_Assignment: if OldAss[(d[0],d[1])] == 1: prob += lpSum(OldAss[(d[0],d[1])] - PB_ass[(d[0],d[1])]) <= Delta_Ass[(d[0],d[1])] else: prob += lpSum(PB_ass[(d[0],d[1])] - OldAss[(d[0],d[1])]) <= Delta_Ass[(d[0],d[1])] # 4th obj = fill a subline if weightFactors[3]>0: # verify whether there are machines active in the sublines subline={0:{'noMach':0, 'WIP':0}, 1:{'noMach':0, 'WIP':0}} for mach in machineList: if machineList[mach]['stationID'] in [0,1,2]: subline[machineList[mach]['machineID']]['noMach'] += 1 subline[machineList[mach]['machineID']]['WIP'] += machineList[mach]['WIP'] chosenSubLine = False # choose subline to be filled first if subline[0]['noMach'] == 3: # case when both sublines are fully active if subline[1]['noMach'] == 3: if subline[0]['WIP'] >= subline [1]['WIP']: chosenSubLine = 1 else: chosenSubLine = 2 else: chosenSubLine = 1 elif subline[1]['noMach'] == 3: chosenSubLine = 2 #create variable for the chosen subline if chosenSubLine: chosenSubLine -= 1 subLine = LpVariable('SubL', lowBound=0) sub = [] for station in range(3): mach = Tool[station][chosenSubLine].name #'St'+str(station)+'_M'+str(chosenSubLine) for oper in PBlist: if station in PBskills[oper]: sub.append(PB_ass[(oper,mach)]) prob += lpSum(sub) >= subLine chosenSubLine+=1 obj.append(subLine*weightFactors[3]/3.0) # 5th objective: prioritise machines with furthest in time last assignment LastAssignmentSum = float(sum([machineList[mach]['lastAssignment'] for mach in machines ])) if LastAssignmentSum > 0 and weightFactors[4]>0: obj += [machineList[mach]['lastAssignment']*PB_ass[(oper,mach)]*weightFactors[4]/float(LastAssignmentSum) for oper in PBlist for mach in machines if machineList[mach]['stationID'] in PBskills[oper]] # 6th objective: max the number of pb assigned if weightFactors[5]>0: obj += [PB_ass[(oper,mach)]*weightFactors[5]/float(len(PBlist)) for oper in PBlist for mach in machines if machineList[mach]['stationID'] in PBskills[oper]] prob += lpSum(obj) # constraint 1: # operators assigned to a station <= 1 for machine in machines: prob += lpSum([PB_ass[(oper,machine)] for oper in PBlist if machineList[machine]['stationID'] in PBskills[oper]]) <= 1 # constraint 2: # machines assigned to an operator <= 1 for operator in PBlist: prob += lpSum([PB_ass[(operator,machine)] for machine in machines if machineList[machine]['stationID'] in PBskills[operator]]) <= 1 # write the problem data to an .lp file. prob.writeLP("PBassignment.lp") prob.solve() if LpStatus[prob.status] != 'Optimal': print 'WARNING: LP solution ', LpStatus[prob.status] PBallocation = {} for mach in machines: for oper in PBlist: if machineList[mach]['stationID'] in PBskills[oper]: if PB_ass[(oper,mach)].varValue > 0.00001: PBallocation[oper]=mach files = glob.glob('*.mps') for f in files: os.remove(f) files = glob.glob('*.lp') for f in files: os.remove(f) G.totalPulpTime+=time.time()-startPulp return PBallocation