def create_linear_constraints_min_calorie(variables, prod_values, req_values): """ Function returns list of linear constraints needed to satisfy requirements. Every constraint should include min and max for nutrient and all variables multiplied by amount of nutrient in given product. :param variables: dictionary containing names and LpVariables :param prod_values: dictionary of dictionaries containing name and nutrients values :param req_values: dictionary of pairs containing requirements for nutrients :return: list of linear constraints """ constraints = list() # Student implementation below. constr = 0 for j in req_values.keys(): constr = LpConstraint(e=None, sense=1, name=constr, rhs=req_values[j][0]) for i in variables: constr += variables[i] * prod_values[i][j] constraints.append(constr) constr = LpConstraint(e=None, sense=-1, name=constr, rhs=req_values[j][1]) for i in variables: constr += variables[i] * prod_values[i][j] constraints.append(constr) return constraints[2:] raise NotImplementedError()
def _make_single_assignment_constraints(lhs_single: list, kind: str) -> list: constraints_single = [ LpConstraint(e=lhs_s, sense=-1, name=f"constraint_single_{kind}_{i}", rhs=1) for i, lhs_s in enumerate(lhs_single) ] return constraints_single
def addline(m, p1, p2, x, y, upper=True): """2点直線制約""" from pulp import LpConstraint, LpConstraintGE, LpConstraintLE dx = p2[0] - p1[0] if dx != 0: m += LpConstraint( y - (p2[1] - p1[1]) / dx * x - (p2[0] * p1[1] - p1[0] * p2[1]) / dx, LpConstraintGE if upper else LpConstraintLE)
def add_constraint(self, expr, relation, value, name=None): """ Add a constraint to the model """ if relation == '==': pulp_relation = LpConstraintEQ elif relation == '<=': pulp_relation = LpConstraintLE elif relation == '>=': pulp_relation = LpConstraintGE else: raise Exception("relation must be either '==' or '>=' or '<='") self.model += LpConstraint(e=expr, sense=pulp_relation, rhs=value, name=name)
def random_model(nv, nc, sense=1, seed=1, rtfr=0, rtco=0.1, rteq=0, feasible=False): """ ランダムなLP作成 nv,nc:変数数、制約条件数 sense:種類(LpMinimize=1) seed:乱数シード rtfr:自由変数割合 rtco:係数行列非零割合 rteq:制約条件等号割合 feasible:実行可能かどうか """ from pulp import LpConstraint, LpStatusOptimal rtco = max(1e-3, rtco) if seed: np.random.seed(seed) var_count = [0] x = np.array(addvars(nv, var_count=var_count)) while True: m = LpProblem(sense=sense) m += lpDot(np.random.rand(nv) * 2 - 1, x) for v in x[np.random.rand(nv) < rtfr]: v.lowBound = None rem = nc while rem > 0: a = np.random.rand(nv) * 2 - 1 a[np.random.rand(nv) >= rtco] = 0 if (a == 0).all(): continue if (a <= 0).all(): a = -a se = int(np.random.rand() >= rteq) * np.random.choice([-1, 1]) m += LpConstraint(lpDot(a, x), se, rhs=np.random.rand()) rem -= 1 if not feasible or m.solve() == LpStatusOptimal: return m
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 _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 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 != 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 != 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 == 'I': if T.get_layout() == 'dot2tex': label = r'\text{I}' else: label = 'I' else: label = "%.1f"%relax if iter_count == 0: if status != 'candidate': integer_infeasibility_count = None integer_infeasibility_sum = None if status == '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 == '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 == '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 == '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 == '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 == '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'] != 'off': T.display(count=iter_count) T._lp_count = lp_count return opt, LB
# 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: print("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 str(pred) is not '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')
def solve_diet_min_calorie(prod_values, req_values): """ Function creates and sets up linear programming problem for calorie minimization. Returns problem, objective value and solver status. :param prod_values: dictionary of dictionaries containing name and nutrients values :param req_values: dictionary of pairs containing requirements for nutrients :return: (LpProblem, LpObjective, LpStatus) """ # 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 = [] constraints = [] 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) problem = LpProblem('Diet problem', LpMinimize) prob = LpProblem('Diet problem', LpMinimize) prob += lpSum([calories[i] * food_vars[i] for i in products_names]) objective = lpSum([calories[i] * food_vars[i] for i in products_names]) prob += LpConstraint(lpSum([food_vars[f] for f in products_names]) >= 0) prob += LpConstraint( lpSum([calories[f] * food_vars[f] for f in products_names]) >= req_values['calorie'][0]) prob += LpConstraint( lpSum([calories[f] * food_vars[f] for f in products_names]) <= req_values['calorie'][1]) prob += LpConstraint( lpSum([proteins[f] * food_vars[f] for f in products_names]) >= req_values['proteins'][0]) prob += LpConstraint( lpSum([proteins[f] * food_vars[f] for f in products_names]) <= req_values['proteins'][1]) prob += LpConstraint( lpSum([carbs[f] * food_vars[f] for f in products_names]) >= req_values['carbs'][0]) prob += LpConstraint( lpSum([carbs[f] * food_vars[f] for f in products_names]) <= req_values['carbs'][1]) prob += LpConstraint( lpSum([sugar[f] * food_vars[f] for f in products_names]) >= req_values['sugar'][0]) prob += LpConstraint( lpSum([sugar[f] * food_vars[f] for f in products_names]) <= req_values['sugar'][1]) prob += LpConstraint( lpSum([fat[f] * food_vars[f] for f in products_names]) >= req_values['fat'][0]) prob += LpConstraint( lpSum([fat[f] * food_vars[f] for f in products_names]) <= req_values['fat'][1]) prob.solve() return prob, food_vars, 1
def create_linear_constraints_min_calorie( variables, prod_values, req_values): #TestConstraintsMinCalorie """ Function returns list of linear constraints needed to satisfy requirements. Every constraint should include min and max for nutrient and all variables multiplied by amount of nutrient in given product. :param variables: dictionary containing names and LpVariables :param prod_values: dictionary of dictionaries containing name and nutrients values :param req_values: dictionary of pairs containing requirements for nutrients :return: list of linear constraints """ constraints = [] # 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) constraints.append( LpConstraint( lpSum([calories[f] * food_vars[f] for f in products_names]) >= req_values['calorie'][0])) constraints.append( LpConstraint( lpSum([calories[f] * food_vars[f] for f in products_names]) <= req_values['calorie'][1])) constraints.append( LpConstraint( lpSum([proteins[f] * food_vars[f] for f in products_names]) >= req_values['proteins'][0])) constraints.append( LpConstraint( lpSum([proteins[f] * food_vars[f] for f in products_names]) <= req_values['proteins'][1])) constraints.append( LpConstraint( lpSum([carbs[f] * food_vars[f] for f in products_names]) >= req_values['carbs'][0])) constraints.append( LpConstraint( lpSum([carbs[f] * food_vars[f] for f in products_names]) <= req_values['carbs'][1])) constraints.append( LpConstraint( lpSum([sugar[f] * food_vars[f] for f in products_names]) >= req_values['sugar'][0])) constraints.append( LpConstraint( lpSum([sugar[f] * food_vars[f] for f in products_names]) <= req_values['sugar'][1])) constraints.append( LpConstraint( lpSum([fat[f] * food_vars[f] for f in products_names]) >= req_values['fat'][0])) constraints.append( LpConstraint( lpSum([fat[f] * food_vars[f] for f in products_names]) <= req_values['fat'][1])) return constraints
from pulp import LpProblem, LpVariable, LpConstraint, LpConstraintLE, LpConstraintGE, LpMaximize, LpBinary, LpStatus # Create a new model m = LpProblem(name="MIP Model", sense=LpMaximize) # Create variables x = LpVariable(cat=LpBinary, name="x") y = LpVariable(cat=LpBinary, name="y") z = LpVariable(cat=LpBinary, name="z") # Add constraint: x + 2 y + 3 z <= 4 m += LpConstraint(e=(x + 2 * y + 3 * z), sense=LpConstraintLE, rhs=4, name='c0') # Add constraint: x + y >= 1 m += LpConstraint(e=(x + y), sense=LpConstraintGE, rhs=1, name='c1') # Set objective m.setObjective(x + y + 2 * z) # Calculate with the default CBC optimizer status = m.solve() if LpStatus[status] == 'Optimal': for v in m.variables(): print('%s %g' % (v.name, v.varValue)) print('Obj: %g' % m.objective.value())
def ilp_solve(co_occur_matrix, weights, lengths, max_length=None, concepts_discrete=True): """ co_occur_matrix : A, Co-occurence matrix of dimensions NxM weights : w, List of length N of Weight values (float) lengths : l, List of length M of sentence lengths (int) max_length : L, If set to some number, max. length cannot be greater than L concepts_discrete: Set to True if z should be discrete in [0,1] and False if z should be continuous # Change this to return only 'y' later Returns a dict with 'y' and 'z' as keys. 'y' contains a list (size M) of 0s and 1s to say if a sentence should be included or not. 'z' the same but for concepts from 1 to N. """ # Smaller variable names A = co_occur_matrix w = weights l = lengths # N represents concepts, M represents sentences N = len(A) M = len(A[0]) L = max_length if len(w) != N: raise ValueError("weights not the same dimension as A[rows]") if L and len(l) != M: raise ValueError("lengths not the same dimension as A[cols]") # Target variables # y[i] decides if sentence[i] is included or not. Only Binary values allowed y = [LpVariable("y%s" % i, 0, 1, LpInteger) for i in range(M)] # z[i] decides if concept[j] is included or not. args = [LpInteger] if concepts_discrete else [] z = [LpVariable("z%s" % i, 0, 1, *args) for i in range(N)] # Objective function problem = LpProblem("Class Evaluation Summary", LpMaximize) problem += lpSum([w[i] * z[i] for i in range(N)]), "Obj. function" # Constraints for i in range(N): problem += lpSum([A[i][j] * y[j] for j in range(M)]) >= z[ i], "z cond 1 (i) -> sum_{j=0_to_M-1}(A[%s][j]y[j] >= z[%s]" % (i, i) for j in range(M): problem += LpConstraint( A[i][j] <= z[i]) #, "z cond 2 (i,j) -> A[%s][%s] <= z[%s]" % (i,j,i) if L: problem += lpSum([l[j] * y[j] for j in range(M)]) <= L, "length constraint" # Solve problem.solve() # Assign and return res_y = [0 for i in range(M)] res_z = [0 for i in range(N)] for var in problem.variables(): char, index = var.name[0], int(var.name[1:]) if char == 'y': res_y[index] = var.varValue elif char == 'z': res_z[index] = var.varValue return {'y': res_y, 'z': res_z}