def _get_start_not_allowed_per_task_and_agent(self, availability_agent, start_variable_task_agent, task_duration): job_space = (availability_agent["stop_available"] - availability_agent["start_available"]) job_fits = job_space >= task_duration possible_timeslots_df = availability_agent[job_fits] possible_timeslots_df["latest_start"] = ( possible_timeslots_df["stop_available"] - task_duration) if possible_timeslots_df.empty: return [start_variable_task_agent == -self.big_m] possible_timeslots_df = possible_timeslots_df.reset_index() auxiliary_variables = self._get_current_auxiliary_start_variables( possible_timeslots_df=possible_timeslots_df) left_bounds = [ start_variable_task_agent >= LpAffineExpression( slot["start_available"] * auxiliary_variables[i] - (1 - auxiliary_variables[i]) * self.big_m) for i, slot in possible_timeslots_df.iterrows() ] right_bounds = [ start_variable_task_agent <= LpAffineExpression(slot["latest_start"] * auxiliary_variables[i] + (1 - auxiliary_variables[i]) * self.big_m) for i, slot in possible_timeslots_df.iterrows() ] choose_one_interval = [lpSum(auxiliary_variables) == 1] constraints = left_bounds + right_bounds + choose_one_interval return constraints
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 add_dual_variables_and_constraints(self): # create dual variables associated with stoichiometric constraints self.var_lambda = dict([(m, LpVariable("lambda_%s" % m.id, lowBound=-M, upBound=M, cat=LpContinuous)) for m in self.model.metabolites]) # create dual variables associated with the constraints on the primal fluxes self.var_w_U = dict([(r, LpVariable("w_U_%s" % r.id, lowBound=0, upBound=M, cat=LpContinuous)) for r in self.model.reactions]) self.var_w_L = dict([(r, LpVariable("w_L_%s" % r.id, lowBound=0, upBound=M, cat=LpContinuous)) for r in self.model.reactions]) # add the dual constraints: # S'*lambda + w_U - w_L = c_biomass for r in self.model.reactions: S_times_lambda = LpAffineExpression([ (self.var_lambda[m], coeff) for m, coeff in r._metabolites.iteritems() if coeff != 0 ]) row_sum = S_times_lambda + self.var_w_U[r] - self.var_w_L[r] self.prob.addConstraint(row_sum == r.objective_coefficient, 'dual_%s' % r.id)
def binpacking(c, w): """ ビンパッキング問題 列生成法で解く(近似解法) 入力 c: ビンの大きさ w: 荷物の大きさのリスト 出力 ビンごとの荷物の大きさリスト """ from pulp import LpAffineExpression n = len(w) rn = range(n) mkp = LpProblem("knapsack", LpMaximize) # 子問題 mkpva = [addvar(cat=LpBinary) for _ in rn] mkp.addConstraint(lpDot(w, mkpva) <= c) mdl = LpProblem("dual", LpMaximize) # 双対問題 mdlva = [addvar() for _ in rn] for i, v in enumerate(mdlva): v.w = w[i] mdl.setObjective(lpSum(mdlva)) for i in rn: mdl.addConstraint(mdlva[i] <= 1) while True: mdl.solve() mkp.setObjective(lpDot([value(v) for v in mdlva], mkpva)) mkp.solve() if mkp.status != 1 or value(mkp.objective) < 1 + 1e-6: break mdl.addConstraint(lpDot([value(v) for v in mkpva], mdlva) <= 1) nwm = LpProblem("primal", LpMinimize) # 主問題 nm = len(mdl.constraints) rm = range(nm) nwmva = [addvar(cat=LpBinary) for _ in rm] nwm.setObjective(lpSum(nwmva)) dict = {} for v, q in mdl.objective.items(): dict[v] = LpAffineExpression() >= q const = list(mdl.constraints.values()) for i, q in enumerate(const): for v in q: dict[v].addterm(nwmva[i], 1) for q in dict.values(): nwm.addConstraint(q) nwm.solve() if nwm.status != 1: return None w0, result = list(w), [[] for _ in range(len(const))] for i, va in enumerate(nwmva): if value(va) < 0.5: continue for v in const[i]: if v.w in w0: w0.remove(v.w) result[i].append(v.w) return [r for r in result if r]
def _objective(xs, betas, route, msg_load, hosting_cost): # We want to minimize communication and hosting costs # Objective is the communication + hosting costs comm = LpAffineExpression() for c1, a1, c2, a2 in betas: comm += route(a1, a2) * msg_load(c1, c2) * betas[(c1, a1, c2, a2)] costs = lpSum([hosting_cost(a, c) * xs[(c, a)] for c, a in xs]) return lpSum([RATIO_HOST_COMM * comm, (1 - RATIO_HOST_COMM) * costs])
def test_teacher(self): self.teacher.addSection(self.testCoreSection) for res in self.teacher.getQualified(): self.assertTrue(res) right = [(LpVariable("test_t_1_0"), 1), (LpVariable("test_t_2_0"), 1), (LpVariable("test_t_3_0"), 1), (LpVariable("test_t_4_0"), 1), (LpVariable("test_t_5_0"), 1), (LpVariable("test_t_6_0"), 1), (LpVariable("test_t_7_0"), 1), (LpVariable("test_t_8_0"), 1)] for res in self.teacher.getConstraints(["test"]): self.assertEqual(res, LpAffineExpression(right) <= 1)
def getValidityConstr(self): """ Yields expressions of if periods have 0 or 1 class. """ for period in self._sections.keys(): section = self._sections[period] hasClass = 0 if section != None and section.courseType != CourseType.OFF: hasClass = 1 expr = [(var, 1) for var in self._lpVars[period]] yield (LpAffineExpression(expr) <= hasClass)
def sectSizeDev(self): """ Returns equation for measuring """ ret = [] avClass = len(self.students) / len(self.teachers) for sect in self.existing_sections: sectStudVariables = [] for stud in sect._students: sectStudVariables.append(stud._schedule._lpVars[sect._period][sect._courseCode]) ret.append(sectStudVariables) return LpAffineExpression(32*len(self.existing_sections) - summation(ret))
def prepare_FBA_dual(self, use_glpk=False): """ Run shadow FBA (dual) """ self.create_prob(sense=LpMinimize, use_glpk=use_glpk) self.add_dual_variables_and_constraints() w_sum = LpAffineExpression([(self.var_w_U[r], r.upper_bound) for r in self.model.reactions if r.upper_bound != 0] + [(self.var_w_L[r], -r.lower_bound) for r in self.model.reactions if r.lower_bound != 0]) self.prob.setObjective(w_sum)
def _get_single_assignment_constraints(self) -> Tuple[list, list]: # Left-hand side: rowsum <= 1 lhs_single_rowsum = [ LpAffineExpression( [(self.x_np[i, j], 1) for j in range(self.n)], name=f"lhs_single_rowsum_{i}", ) for i in range(self.n) ] # Left-hand side: colsum <= 1 lhs_single_colsum = [ LpAffineExpression( [(self.x_np[i, j], 1) for i in range(self.n)], name=f"lhs_single_colsum_{j}", ) for j in range(self.n) ] # Constraints constraints_single_rowsum = self._make_single_assignment_constraints( lhs_single=lhs_single_rowsum, kind="rowsum") constraints_single_colsum = self._make_single_assignment_constraints( lhs_single=lhs_single_colsum, kind="colsum") return constraints_single_rowsum, constraints_single_colsum
def solve_linear_problem(linear_problem): """ Solves linear problem and returns problem, objective and status. :param linear_problem: LpProblem object :return: (LpProblem, LpObjective, LpStatus) """ # Student implementation below. prob = LpProblem('linear_problem', LpMinimize) objective = LpAffineExpression(linear_problem) LpStatus = 1 if str(linear_problem) == str(LpProblem()): return prob, None, LpStatus else: return prob, objective, LpStatus raise NotImplementedError()
def add_optknock_variables_and_constraints(self): # create the binary variables indicating which reactions knocked out self.var_y = dict([(r, LpVariable("y_%s" % r.id, cat=LpBinary)) for r in self.model.reactions]) # create dual variables associated with the constraints on the primal fluxes self.var_mu = dict([(r, LpVariable("mu_%s" % r.id, cat=LpContinuous)) for r in self.model.reactions]) # equate the objectives of the primal and the dual of the inner problem # to force its optimization: # sum_j mu_j - v_biomass = 0 constr = (lpSum(self.var_mu.values()) - self.var_v[self.r_biomass] == 0) self.prob.addConstraint(constr, 'daul_equals_primal') # add the knockout constraints (when y_j = 0, v_j has to be 0) for r in self.model.reactions: # L_jj * y_j <= v_j self.prob.addConstraint( r.lower_bound * self.var_y[r] <= self.var_v[r], 'v_lower_%s' % r.id) # v_j <= U_jj * y_j self.prob.addConstraint( self.var_v[r] <= r.upper_bound * self.var_y[r], 'v_upper_%s' % r.id) # set the constraints on the auxiliary variables (mu): # mu_j == y_j * (U_jj * w_u_j - L_jj * w_l_j) for r in self.model.reactions: w_sum = LpAffineExpression([(self.var_w_U[r], r.upper_bound), (self.var_w_L[r], -r.lower_bound)]) # mu_j + M*y_j >= 0 self.prob.addConstraint(self.var_mu[r] + M * self.var_y[r] >= 0, 'aux_1_%s' % r.id) # -mu_j + M*y_j >= 0 self.prob.addConstraint(-self.var_mu[r] + M * self.var_y[r] >= 0, 'aux_2_%s' % r.id) # mu_j - (U_jj * w_u_j - L_jj * w_l_j) + M*(1-y_j) >= 0 self.prob.addConstraint( self.var_mu[r] - w_sum + M * (1 - self.var_y[r]) >= 0, 'aux_3_%s' % r.id) # -mu_j + (U_jj * w_u_j - L_jj * w_l_j) + M*(1-y_j) >= 0 self.prob.addConstraint( -self.var_mu[r] + w_sum + M * (1 - self.var_y[r]) >= 0, 'aux_4_%s' % r.id)
def generate_weight_cuts(prob, sol): # Define mu and T for each knapsack mu = {} S = {} for i in LOCATIONS: mu[i] = CAPACITY S[i] = [] # Use current assign_var values to assign items to locations assigning = True while assigning: bestValue = 0 bestAssign = None for i in LOCATIONS: for j in PRODUCTS: if j not in S[i]: # If this product is not in the subset if (sol[assign_vars[(i, j)]] > bestValue) \ and (REQUIREMENT[j] <= mu[i]): # The assignment variable for this product is closer # to 1 than any other product checked, and "fits" in # this location's remaining space bestValue = sol[assign_vars[(i, j)]] bestAssign = (i, j) # Make the best assignment found across all products and locactions if bestAssign: (i,j) = bestAssign mu[i] -= REQUIREMENT[j] # Decrease spare CAPACITY at this location S[i].append(j) # Assign this product to this location's set else: assigning = False # Didn't find anything to assign - stop # Generate the weight cuts from the sets found above new_cuts = [] for i in LOCATIONS: if len(S[i]) > 0: # If an item assigned to this location con = LpAffineExpression() # Start a new constraint con += sum(REQUIREMENT[j] * assign_vars[(i, j)] for j in S[i]) con += sum(max(0, REQUIREMENT[j] - mu[i]) * assign_vars[(i, j)] for j in PRODUCTS if j not in S[i]) new_cuts.append(con <= CAPACITY - mu[i]) # Return the set of cuts we created to DIP if len(new_cuts) > 0: return new_cuts
def testAll(self): self.assertEqual(self.schedule.getOpenPeriods(), [1, 2, 3, 4, 5, 6, 7, 8]) self.schedule.addSection(self.section) self.assertEqual(self.schedule.getOpenPeriods(), [2, 3, 4, 5, 6, 7, 8]) haveTeachers = [res for res in self.schedule.haveTeachers()] self.assertTrue(haveTeachers[0]) expr1 = [constr for constr in self.schedule.getValidityConstr()] expr2 = LpAffineExpression([(LpVariable("test_sched_1_0"), 1), (LpVariable("test_sched_1_1"), 1)]) <= 1 self.assertEqual(expr1[0], expr2) self.schedule.removeSection(self.section) self.assertEqual(self.schedule.getOpenPeriods(), [1, 2, 3, 4, 5, 6, 7, 8])
def add_primal_variables_and_constraints(self): # create the continuous flux variables (can be positive or negative) self.var_v = {} for r in self.model.reactions: self.var_v[r] = LpVariable("v_%s" % r.id, lowBound=r.lower_bound, upBound=r.upper_bound, cat=LpContinuous) # this flag will be used later to know if to expect the flux # variables to exist self.has_flux_as_variables = True # add the mass-balance constraints to each of the metabolites (S*v = 0) for m in self.model.metabolites: S_times_v = LpAffineExpression([(self.var_v[r], r.get_coefficient(m)) for r in m.reactions]) self.prob.addConstraint(S_times_v == 0, 'mass_balance_%s' % m.id)
def test_student(self): # remove, request vector, request checking, course checking testCore = Course("test_core", CourseType.CORE) testElective = Course("test_elective", CourseType.ELECTIVE) testOff = Course("test_off", CourseType.OFF) self.stud.addReqCore(testCore) self.assertEqual(self.stud.reqCores, [testCore]) self.assertEqual(self.stud.reqAll, [testCore]) self.stud.addReqElective(testElective) self.assertEqual(self.stud.reqElectives, [testElective]) self.assertEqual(self.stud.reqAll, [testCore, testElective]) self.stud.addReqOffPeriod(testOff) self.assertEqual(self.stud.reqOffPeriods, [testOff]) self.assertEqual(self.stud.reqAll, [testCore, testElective, testOff]) res1 = self.stud.getReqVector( ["test_core", "test_elective", "test_off"]) self.assertEqual(res1, [1, 1, 1]) res2 = self.stud.getReqVector( ["test_core", "test_elective", "test_offS"]) self.assertEqual(res2, [1, 1, 0]) right = [(LpVariable("test_s_1_0"), 1), (LpVariable("test_s_2_0"), 1), (LpVariable("test_s_3_0"), 1), (LpVariable("test_s_4_0"), 1), (LpVariable("test_s_5_0"), 1), (LpVariable("test_s_6_0"), 1), (LpVariable("test_s_7_0"), 1), (LpVariable("test_s_8_0"), 1)] for res in self.stud.getConstraints(["test"]): self.assertEqual(res, LpAffineExpression(right) == 1) self.stud.removeReqOff(testOff) self.assertEqual(self.stud.reqOffPeriods, []) self.assertEqual(self.stud.reqAll, [testCore, testElective]) self.stud.removeReqElective(testElective) self.assertEqual(self.stud.reqElectives, []) self.assertEqual(self.stud.reqAll, [testCore]) self.stud.removeReqCore(testCore) self.assertEqual(self.stud.reqCores, []) self.assertEqual(self.stud.reqAll, [])
def add_knockout_bounds(self, ko_candidates=None, num_deletions=5): """ construct the list of KO candidates and add a constraint that only K (num_deletians) of them can have a y_j = 0 """ ko_candidate_sum_y = [] if ko_candidates is None: ko_candidates = [r for r in self.model.reactions if r != self.r_biomass] for r in set(self.model.reactions).difference(ko_candidates): # if 'r' is not a candidate constrain it to be 'active' # i.e. y_j == 1 self.prob.addConstraint(self.var_y[r] == 1, 'active_%s' % r.id) # set the upper bound on the number of knockouts (K) # sum (1 - y_j) <= K ko_candidate_sum_y = [(self.var_y[r], 1) for r in ko_candidates] constr = (LpAffineExpression(ko_candidate_sum_y) >= len(ko_candidate_sum_y) - num_deletions) self.prob.addConstraint(constr, 'number_of_deletions')
def _get_feasibility_constraints(self) -> list: tups = [(i, j) for i in range(self.n) for j in range(self.n)] # Left-hand side lhs_like = [ LpAffineExpression([(self.x_np[tup[0], tup[1]], 1)], name=f"lhs_like_{tup[0]}_{tup[1]}") for tup in tups ] # Constraints constraints_like = [ LpConstraint( e=lhs_l, sense=-1, name=f"constraint_like_{tups[i][0]}_{tups[i][1]}", rhs=self.match_matrix[tups[i][0], tups[i][1]], ) for i, lhs_l in enumerate(lhs_like) ] return constraints_like
def _objective_function(cg: ComputationConstraintsHyperGraph, communication_load, alphas, agents_names): # The objective function is the negated sum of the communication cost on # the links in the constraint graph. objective = LpAffineExpression() for agt in agents_names: for link in cg.links: # logger.debug(f"link {link!r}") if len(link.nodes) == 1: # link representing a unary constraint: no com cost continue objective += lpSum([ -communication_load(cg.computation(end1), end2) * alphas[((end1, end2), agt)] for end1, end2 in combinations(link.nodes, 2) if ((end1, end2), agt) in alphas ]) logger.debug(f"Objective: {objective}") return objective
def _get_symmetry_constraints(self) -> list: tups = [(i, j) for i in range(self.n) for j in range(i + 1, self.n)] # Left-hand side lhs_symmetry = [ LpAffineExpression( [(self.x_np[tup[0], tup[1]], 1), (self.x_np[tup[1], tup[0]], -1)], name=f"lhs_sym_{tup[0]}_{tup[1]}", ) for tup in tups ] # Constraints constraints_symmetry = [ LpConstraint( e=lhs_s, sense=0, name=f"constraint_sym_{tups[i][0]}_{tups[i][1]}", rhs=0, ) for i, lhs_s in enumerate(lhs_symmetry) ] return constraints_symmetry
def solve_set_covering(num_terms, protein): """ Find minimum number of proteins needed to reconstruct annotation set for a given protein using integer programming - set covering problem :param num_terms: number of terms :type num_terms: int :param protein: protein annotations data :type protein: list :return: minimum number of proteins needed to reconstruct annotation set :rtype: np.float """ c = [1 for i in range(num_terms)] x_name = ['x_' + str(i + 1) for i in range(num_terms)] x = [ LpVariable(name=x_name[i], lowBound=0, upBound=1, cat='Binary') for i in range(num_terms) ] problem = LpProblem('set_covering', LpMinimize) z = LpAffineExpression([(x[i], c[i]) for i in range(num_terms)]) for i in protein: problem += sum([x[j] for j in i]) >= 1 problem += z problem.solve() return np.sum([value(i) for i in x])
def summation(terms): """ return a usable sum of `terms` where coefficients are 1 """ total = LpAffineExpression({t: 1 for t in terms}) return total
"slab": (2, 10), "plaque": (8, 150) } extraConstraint1 = False extraConstraint2 = False varTab = {} for obj in objects: varTab[obj] = LpVariable(obj, 0, 1, LpInteger) #the first line added to the problem is the objective objective = [] for obj, (wt, chs) in objects.items(): objective.append((varTab[obj], chs)) problem += LpAffineExpression(objective) constraint = [] for obj, (wt, chs) in objects.items(): constraint.append((varTab[obj], wt)) problem += (LpAffineExpression(constraint) <= 25) if extraConstraint1: problem += varTab["manuscript"] + varTab["codex"] <= 1 if extraConstraint2: problem += varTab["codex"] <= varTab["tablet"] #solve the problem... problem.solve()
def lin_expr(self, expr=None): return LpAffineExpression(expr)
def nzv2exp(nzv, lpvars): """ lpvars: all LpVariable used in the problem constraint: the target constraint """ return LpAffineExpression(map(lambda v: (lpvars[v], 1), nzv))
from pulp import LpProblem, LpVariable, LpMaximize, LpStatus, LpInteger,\ LpAffineExpression if __name__ == "__main__": #define an equation defined by c1x1 + c2x2 ... cnxn coefficients = [2, 4, -5, 1] #build an empty expression obj = LpAffineExpression() #add each var * coeff to the expression xis = [] for ind, coeff in enumerate(coefficients): xi = LpVariable("x%d" % ind, 0, 10, LpInteger) #store the variables for later use (usually in constraints) xis.append(xi) obj += coeff * xi print "Equation:" print obj print "Variables:" print xis