def formulate_tsp(tsp, options={}): prob = dippy.DipProblem( "TSP", # display_mode='matplotlib', display_mode='None', display_interval=10) assign_vars = LpVariable.dicts("y", [(i, j) for i in tsp.EXTLOCS for j in tsp.EXTLOCS if i != j], cat=LpBinary) prob += lpSum(tsp.dist[i, j] * assign_vars[i, j] for i in tsp.EXTLOCS for j in tsp.EXTLOCS if i != j), "min_dist" for j in tsp.EXTLOCS: # One arc in prob += lpSum(assign_vars[i, j] for i in tsp.EXTLOCS if i != j) == 1 for i in tsp.EXTLOCS: # One arc out prob += lpSum(assign_vars[i, j] for j in tsp.EXTLOCS if j != i) == 1 # Attach the problem data and variable dictionaries to the DipProblem prob.tsp = tsp prob.assign_vars = assign_vars if "Tol" in options: prob.tol = options["Tol"] else: prob.tol = pow(pow(2, -24), 2.0 / 3.0) return prob
def formulate(vrp, options={}): prob = dippy.DipProblem( "VRP", # display_mode='matplotlib', display_mode='none', display_interval=1000) assign_vars = LpVariable.dicts("y", [(i, j, k) for i in vrp.EXTLOCS for j in vrp.EXTLOCS for k in vrp.VEHS if i != j], cat=LpBinary) use_vars = LpVariable.dicts("x", vrp.VEHS, cat=LpBinary) # Objective function: minimise the distance between nodes * whether that arc is used by any vehicle. prob += lpSum(vrp.dist[i, j] * assign_vars[i, j, k] for i in vrp.EXTLOCS for j in vrp.EXTLOCS for k in vrp.VEHS if i != j), "min_dist" # Each node (excluding 'O') must have one arc entering from any other node (including 'O') for j in vrp.LOCS: prob += lpSum(assign_vars[i, j, k] for i in vrp.EXTLOCS for k in vrp.VEHS if i != j) == 1 # Each node (excluding 'O') must have one arc leaving to any other node (including 'O') for i in vrp.LOCS: prob += lpSum(assign_vars[i, j, k] for j in vrp.EXTLOCS for k in vrp.VEHS if j != i) == 1 for k in vrp.VEHS: # Conservation of flows # If an arc enters a certain node j from any other node, then there must be # an arc leaving j to any other node. for j in vrp.LOCS: prob += lpSum(assign_vars[i_1, j, k] for i_1 in vrp.EXTLOCS if i_1 != j) == lpSum(assign_vars[j, i_2, k] for i_2 in vrp.EXTLOCS if i_2 != j) # If all ncurr vehicles specified in the veh_rout_cart[i].py are to be used if vrp.allused: # Specify that all vehicles must enter the depot prob += lpSum(assign_vars[i, 'O', k] for i in vrp.LOCS) == 1 # Specify all vehicles must leave the depot prob += lpSum(assign_vars['O', j, k] for j in vrp.LOCS) == 1 else: # # Moved this into the vrp.distcap set of constraints # # Specify that if a vehicle is used it must enter the depot # prob += lpSum(assign_vars[i, 'O', k] # for i in vrp.LOCS) == use_vars[k] # Specify that if a vehicle is used it must leave the depot prob += lpSum(assign_vars['O', j, k] for j in vrp.LOCS) == use_vars[k] # Condition for checking if the route taken by each vehicle does not exceed the allowed maximum # journey distance if vrp.distcap is not None: # For each vehicle k, ensure that the maximum distance travelled is less than the distance # capacity and 0 if that vehicle is not used. prob += lpSum(vrp.dist[i, j] * assign_vars[i, j, k] for i in vrp.EXTLOCS for j in vrp.EXTLOCS if i != j) <= vrp.distcap * use_vars[k] else: # Strangely returns better solutions with this isolated here. # Specify that if a vehicle is used it must enter the depot if not vrp.allused: prob += lpSum(assign_vars[i, 'O', k] for i in vrp.LOCS) == use_vars[k] # Cardinality of arcs for vehicles in use prob += lpSum(assign_vars[i, j, k] for i in vrp.EXTLOCS for j in vrp.EXTLOCS if i != j) <= len(vrp.EXTLOCS) * use_vars[k] if ('Antisymmetry' in options) and (options['Antisymmetry'] == 'on'): # Order the use of the vehicles for k in vrp.VEHS: if k != vrp.VEHS[-1]: prob += use_vars[k] >= use_vars[k + 1] if ('Tight' in options) and (options['Tight'] == 'on'): for k in vrp.VEHS: for i in vrp.EXTLOCS: for j in vrp.EXTLOCS: if i != j: prob += assign_vars[i, j, k] <= use_vars[k] # Attach the problem data and variable dictionaries to the DipProblem prob.vrp = vrp prob.assign_vars = assign_vars prob.use_vars = use_vars if "Tol" in options: prob.tol = options["Tol"] else: prob.tol = pow(pow(2, -24), 2.0 / 3.0) return prob
def create_tsp_problem(doRelaxed=False): """ creates and returns the tsp problem """ from math import sqrt # 2d Euclidean TSP with extremely simple cut generation # x,y coords of cities CITY_LOCS = [(0, 2), (0, 4), (1, 2), (1, 4), \ (4, 1), (4, 4), (4, 5), (5, 0), \ (5, 2), (5, 5)] CITIES = range(len(CITY_LOCS)) ARCS = [] # list of arcs (no duplicates) ARC_COSTS = {} # distance # for each city, list of arcs into/out of CITY_ARCS = [[] for i in CITIES] # use 2d euclidean distance def dist(x1, y1, x2, y2): return sqrt((x1 - x2)**2 + (y1 - y2)**2) # construct list of arcs for i in CITIES: i_x, i_y = CITY_LOCS[i] for j in CITIES[i + 1:]: j_x, j_y = CITY_LOCS[j] ARC_COSTS[(i, j)] = dist(i_x, i_y, j_x, j_y) ARCS.append((i, j)) CITY_ARCS[i].append((i, j)) CITY_ARCS[j].append((i, j)) prob = dippy.DipProblem() arc_vars = LpVariable.dicts("UseArc", ARCS, 0, 1, LpBinary) # objective prob += sum(ARC_COSTS[x] * arc_vars[x] for x in ARCS) # degree constraints for city in CITIES: prob += sum(arc_vars[x] for x in CITY_ARCS[city]) == 2 # generate subtour elimination constraints # dictionary for symmetric arcs, can be # accessed using (i, j) and (j, i) symmetric = {} for i in CITIES: for j in CITIES: if i < j: symmetric[(i, j)] = (i, j) symmetric[(j, i)] = (i, j) def generate_cuts(prob, sol): cons = [] not_connected = set(CITIES) while not_connected: # print "not_connected", [n for n in not_connected] start = not_connected.pop() nodes, arcs = get_subtour(sol, start) if len(nodes) == len(arcs) and \ len(nodes) < len(CITIES): cons.append( sum(arc_vars[a] for a in arcs) \ <= len(arcs) - 1 ) # print "nodes", [n for n in nodes] # print "arcs", [a for a in arcs] nodes.remove(start) not_connected -= nodes ## print "# cons = ", len(cons) ## print "cons = ", [ con for con in cons ] return cons def is_solution_feasible(prob, sol, tol): nodes, arcs = get_subtour(sol, 0) # print "Checking: # nodes = ", len(nodes), \ # ", # cities = ", len(CITIES) # print "nodes", [n for n in nodes] return len(nodes) == len(arcs) and \ len(nodes) == len(CITIES) def get_subtour(sol, node): # returns: list of nodes and arcs # in subtour containing node nodes = set([node]) arcs = set([]) not_processed = set(CITIES) to_process = set([node]) tol = 1e-6 one = 1 - tol while to_process: c = to_process.pop() not_processed.remove(c) new_arcs = [ symmetric[(c, i)] \ for i in not_processed \ if sol[ \ arc_vars[symmetric[(c, i)]]] > one] new_nodes = [ i for i in not_processed \ if symmetric[(i, c)] in new_arcs ] # print "new_nodes", [n for n in new_nodes] # print "new_arcs", [a for a in new_arcs] arcs |= set(new_arcs) nodes |= set(new_nodes) to_process |= set(new_nodes) # print "not_processed", [n for n in not_processed] # print "nodes", [n for n in nodes] # print "arcs", [a for a in arcs] return nodes, arcs return prob, generate_cuts, is_solution_feasible
def formulate(vrp, options={}): prob = dippy.DipProblem( "VRP", # display_mode='matplotlib', display_mode='None', display_interval=10) assign_vars = LpVariable.dicts("y", [(i, j, k) for i in vrp.EXTLOCS for j in vrp.EXTLOCS for k in vrp.VEHS if i != j], cat=LpBinary) use_vars = LpVariable.dicts("x", vrp.VEHS, cat=LpBinary) # Objective function prob += lpSum(vrp.dist[i, j] * assign_vars[i, j, k] for i in vrp.EXTLOCS for j in vrp.EXTLOCS for k in vrp.VEHS if i != j), "min_dist" # Each node (excluding 'O') must have one arc entering from any other node (including 'O') for j in vrp.LOCS: prob += lpSum(assign_vars[i, j, k] for i in vrp.EXTLOCS for k in vrp.VEHS if i != j) == 1 # Each node (excluding 'O') must have one arc leaving to any other node (including 'O') for i in vrp.LOCS: prob += lpSum(assign_vars[i, j, k] for j in vrp.EXTLOCS for k in vrp.VEHS if j != i) == 1 for k in vrp.VEHS: # Specify all vehicles must leave the depot if vrp.allused: prob += lpSum(assign_vars['O', j, k] for j in vrp.LOCS) >= 1 # Conservation of flows for j in vrp.LOCS: prob += lpSum(assign_vars[i_1, j, k] for i_1 in vrp.EXTLOCS if i_1 != j) == lpSum(assign_vars[j, i_2, k] for i_2 in vrp.EXTLOCS if i_2 != j) for k in vrp.VEHS: prob += lpSum(assign_vars[i, 'O', k] for i in vrp.LOCS) == use_vars[k] prob += lpSum(assign_vars['O', j, k] for j in vrp.LOCS) == use_vars[k] # For each vehicle k, ensure that the maximum distance travelled is less than the distance # capacity and 0 if that vehicle is not used. if vrp.distcap is not None: prob += lpSum(vrp.dist[i, j] * assign_vars[i, j, k] for i in vrp.EXTLOCS for j in vrp.EXTLOCS if i != j) <= vrp.distcap * use_vars[k] # Cardinality of arcs for vehicles in use else: prob += lpSum(assign_vars[i, j, k] for i in vrp.EXTLOCS for j in vrp.EXTLOCS if i != j) <= len(vrp.EXTLOCS) * use_vars[k] if ('Antisymmetry' in options) and (options['Antisymmetry'] == 'on'): # Order the use of the vehicles for k in vrp.VEHS: if k != vrp.VEHS[-1]: prob += use_vars[k] >= use_vars[k + 1] if ('Tight' in options) and (options['Tight'] == 'on'): for k in vrp.VEHS: for i in vrp.EXTLOCS: for j in vrp.EXTLOCS: if i != j: prob += assign_vars[i, j, k] <= use_vars[k] # Attach the problem data and variable dictionaries to the DipProblem prob.vrp = vrp prob.assign_vars = assign_vars prob.use_vars = use_vars if "Tol" in options: prob.tol = options["Tol"] else: prob.tol = pow(pow(2, -24), 2.0 / 3.0) return prob
def formulate(vrp, options={}): prob = dippy.DipProblem("VRP", # display_mode='matplotlib', display_mode='None', display_interval=10) assign_vars = LpVariable.dicts("y", [(i, j, k) for i in vrp.EXTLOCS for j in vrp.EXTLOCS for k in vrp.VEHS if i != j], cat=LpBinary) use_vars = LpVariable.dicts("x", vrp.VEHS, cat=LpBinary) prob += lpSum(vrp.dist[i, j] * assign_vars[i, j, k] for i in vrp.EXTLOCS for j in vrp.EXTLOCS for k in vrp.VEHS if i != j), "min_dist" for j in vrp.LOCS: # One arc in prob += lpSum(assign_vars[i, j, k] for i in vrp.EXTLOCS for k in vrp.VEHS if i != j) == 1 for i in vrp.LOCS: # One arc out prob += lpSum(assign_vars[i, j, k] for j in vrp.EXTLOCS for k in vrp.VEHS if j != i) == 1 for k in vrp.VEHS: if vrp.allused: # If all vehicles must be used prob += lpSum(assign_vars['O', j, k] for j in vrp.LOCS) >= 1 for j in vrp.LOCS: # Conserve vehicle flow prob += lpSum(assign_vars[ifrom, j, k] for ifrom in vrp.EXTLOCS if ifrom != j) == \ lpSum(assign_vars[j, ito, k] for ito in vrp.EXTLOCS if ito != j) # # Number of arcs into the origin = number of vehicles being used # prob += lpSum(assign_vars[i, 'O', k] for i in vrp.LOCS # for k in vrp.VEHS) \ # == lpSum(use_vars[k] for k in vrp.VEHS) # for k in vrp.VEHS: # prob += lpSum(assign_vars[i, 'O', k] for i in vrp.LOCS) \ # == use_vars[k] # # # Number of arcs out of the origin = number of vehicles being used # prob += lpSum(assign_vars['O', j, k] for j in vrp.LOCS # for k in vrp.VEHS) \ # == lpSum(use_vars[k] for k in vrp.VEHS) for k in vrp.VEHS: prob += lpSum(assign_vars[i, 'O', k] for i in vrp.LOCS) \ == use_vars[k] prob += lpSum(assign_vars['O', j, k] for j in vrp.LOCS) \ == use_vars[k] if ('Antisymmetry' in options) and (options['Antisymmetry'] == 'on'): # Order the use of the vehicles for k in vrp.VEHS: if k != vrp.VEHS[-1]: prob += use_vars[k] >= use_vars[k + 1] if vrp.distcap is not None: for k in vrp.VEHS: prob += lpSum(vrp.dist[i, j] * assign_vars[i, j, k] for i in vrp.EXTLOCS for j in vrp.EXTLOCS if i != j) <= vrp.distcap * use_vars[k] else: for k in vrp.VEHS: prob += lpSum(assign_vars[i, j, k] for i in vrp.EXTLOCS for j in vrp.EXTLOCS if i != j) <= len(vrp.EXTLOCS) * use_vars[k] if ('Tight' in options) and (options['Tight'] == 'on'): for k in vrp.VEHS: for i in vrp.EXTLOCS: for j in vrp.EXTLOCS: if i != j: prob += assign_vars[i, j, k] <= use_vars[k] # Attach the problem data and variable dictionaries to the DipProblem prob.vrp = vrp prob.assign_vars = assign_vars prob.use_vars = use_vars if "Tol" in options: prob.tol = options["Tol"] else: prob.tol = pow(pow(2, -24), 2.0 / 3.0) return prob
def create_coke_problem(): """ creates and returns the coke problem """ CC = 1.3 BIG_M = 1e10 MINE_SUPPLY = { "M1": 25.8, "M2": 728, "M3": 1456, "M4": 49, "M5": 36.9, "M6": 1100, } MINES = list(MINE_SUPPLY.keys()) MINES.sort() LOCATIONS = ["L1", "L2", "L3", "L4", "L5", "L6"] SIZE_COSTS = { 0: 0, 75: 4.4, 150: 7.4, 225: 10.5, 300: 13.5, 375: 16.5, 450: 19.6, } SIZES = list(SIZE_COSTS.keys()) SIZES.sort() CUSTOMER_DEMAND = { "C1": 83, "C2": 5.5, "C3": 6.975, "C4": 5.5, "C5": 720.75, "C6": 5.5, } CUSTOMERS = list(CUSTOMER_DEMAND.keys()) CUSTOMERS.sort() MINE_TRANSPORT_DATA = """ L1 L2 L3 L4 L5 L6 M1 231737 46813 79337 195845 103445 45186 M2 179622 267996 117602 200298 128184 49046 M3 45170 93159 156241 218655 103802 119616 M4 149925 254305 76423 123534 151784 104081 M5 152301 205126 24321 66187 195559 88979 M6 223934 132391 51004 122329 222927 54357 """ CUST_TRANSPORT_DATA = """ L1 L2 L3 L4 L5 L6 C1 6736 42658 70414 45170 184679 111569 C2 217266 227190 249640 203029 153531 117487 C3 35936 28768 126316 2498 130317 74034 C4 73446 52077 108368 75011 49827 62850 C5 174664 177461 151589 153300 59916 135162 C6 186302 189099 147026 164938 149836 286307 """ def read_table(data, coerce, transpose=False): lines = data.splitlines() headings = lines[1].split() result = {} for row in lines[2:]: items = row.split() for i, item in enumerate(items[1:]): if transpose: key = (headings[i], items[0]) else: key = (items[0], headings[i]) result[key] = coerce(item) return result MINE_TRANSPORT = read_table(MINE_TRANSPORT_DATA, int) CUST_TRANSPORT = read_table(CUST_TRANSPORT_DATA, int, \ transpose=True) #add both parts of the network together ARC_COSTS = MINE_TRANSPORT.copy() ARC_COSTS.update(CUST_TRANSPORT) ARCS = list(ARC_COSTS.keys()) LOCATIONS_SIZES = [(l, s) for l in LOCATIONS for s in SIZES] prob = dippy.DipProblem("Coke", LpMinimize) # create variables buildVars = LpVariable.dicts("Build", LOCATIONS_SIZES, cat=LpBinary) # create arcs flowVars = LpVariable.dicts("Arcs", ARCS, lowBound=0, upBound=BIG_M) # objective prob += 1e6 * sum(buildVars[(l, s)] * SIZE_COSTS[s] for (l, s) in LOCATIONS_SIZES) + \ sum(flowVars[(s, d)] * ARC_COSTS[(s, d)] for (s, d) in ARCS), \ "cost_of_building_and_transport" # plant availability for loc in LOCATIONS: prob += sum(flowVars[(loc, c)] for c in CUSTOMERS) \ <= sum(buildVars[(loc, s)] * s for s in SIZES), \ "Plant_%s_availability"%loc # one size for loc in LOCATIONS: prob += sum(buildVars[(loc, s)] for s in SIZES) == 1, \ "Plant_%s_size"%loc # conserve flow (mines) # flows are in terms of tonnes of coke for m in MINES: prob += sum(flowVars[(m, j)] for j in LOCATIONS) \ <= MINE_SUPPLY[m], "Supply_mine_%s"%m for loc in LOCATIONS: prob += sum(flowVars[(m, loc)] for m in MINES) - \ CC * sum(flowVars[(loc, c)] for c in CUSTOMERS) \ == 0, "Conserve_flow_location_%s"%loc for c in CUSTOMERS: prob += sum(flowVars[(loc, c)] for loc in LOCATIONS) \ >= CUSTOMER_DEMAND[c], "Demand_cust_%s"%c def do_branch(prob, sol): tol = 1e-10 for loc in LOCATIONS: sol_size = sum(sol[buildVars[loc, size]] * \ size for size in SIZES) # determine if solsize is bigger than the largest # or smaller tham the smallest if (abs(sol_size - max(SIZES)) < tol or abs(sol_size - min(SIZES))) < tol: continue #find the first one bigger or equal to sol_size bigger = min([s for s in SIZES if s >= sol_size - tol]) if bigger - sol_size > tol: down_branch_ub = dict([(buildVars[loc, s], 0) for s in SIZES if s <= sol_size]) up_branch_ub = dict([(buildVars[loc, s], 0) for s in SIZES if s > sol_size]) return {}, down_branch_ub, {}, up_branch_ub return prob, do_branch
def create_facility_problem(): """ creates and returns the facility problem """ from math import floor, ceil tol = pow(pow(2, -24), old_div(2.0, 3.0)) # The requirements for the products REQUIREMENT = { 1: 66, 2: 4, 3: 85, 4: 93, 5: 68, 6: 76, 7: 74, 8: 39, 9: 66, 10: 17, } # Set of all products PRODUCTS = list(REQUIREMENT.keys()) PRODUCTS.sort() # Set of all locations LOCATIONS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] LOCATIONS.sort() # The capacity of the facilities CAPACITY = 100 prob = dippy.DipProblem("Facility_Location") assign_vars = LpVariable.dicts("AtLocation", [(i, j) for i in LOCATIONS for j in PRODUCTS], 0, 1, LpBinary) use_vars = LpVariable.dicts("UseLocation", LOCATIONS, 0, 1, LpBinary) waste_vars = LpVariable.dicts("Waste", LOCATIONS, 0, 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: prob += lpSum(assign_vars[(i, j)] * REQUIREMENT[j] for j in PRODUCTS) + waste_vars[i] == \ CAPACITY * use_vars[i] # disaggregate CAPACITY constraints for i in LOCATIONS: for j in PRODUCTS: prob += assign_vars[(i, j)] <= use_vars[i] # Ordering constraints for index, location in enumerate(LOCATIONS): if index > 0: prob += use_vars[LOCATIONS[index - 1]] >= use_vars[location] # Anti-symmetry branches def choose_antisymmetry_branch(prob, sol): num_locations = sum(sol[use_vars[i]] for i in LOCATIONS) up = ceil(num_locations) # Round up to next nearest integer down = floor(num_locations) # Round down if (up - num_locations > tol) \ and (num_locations - down > tol): # Is fractional? # Down branch: provide upper bounds, lower bounds are default down_branch_ub = dict([(use_vars[LOCATIONS[n]], 0) for n in range(int(down), len(LOCATIONS))]) # Up branch: provide lower bounds, upper bounds are default up_branch_lb = dict([(use_vars[LOCATIONS[n]], 1) for n in range(0, int(up))]) # Return the advanced branch to DIP return {}, down_branch_ub, up_branch_lb, {} def generate_weight_cuts(prob, sol): ## print "In generate_weight_cuts, sol = ", 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]) ## print new_cuts # Return the set of cuts we created to DIP return new_cuts return sols return prob, choose_antisymmetry_branch, generate_weight_cuts
def create_cutting_stock_problem(doRelaxed=False): """ creates and returns the cutting_stock problem """ length = { "9cm": 9, "7cm": 7, "5cm": 5 } ITEMS = list(length.keys()) demand = { "9cm": 1, "7cm": 1, "5cm": 4 } total_patterns = sum(demand[i] for i in ITEMS) total_length = {} for p in range(total_patterns): total_length[p] = 20 PATTERNS = list(total_length.keys()) CUTS = [(p, i) for p in PATTERNS for i in ITEMS] prob = dippy.DipProblem("Sponge_Rolls", LpMinimize) # create variables useVars = LpVariable.dicts("Use", PATTERNS, 0, 1, LpBinary) cutVars = LpVariable.dicts("Cut", CUTS, 0, 10, LpInteger) # objective prob += sum(useVars[p] for p in PATTERNS), "min" # Meet demand for i in ITEMS: prob += sum(cutVars[(p, i)] for p in PATTERNS) \ >= demand[i] # Ordering patterns for i, p in enumerate(PATTERNS): if p != PATTERNS[-1]: prob += useVars[p] >= useVars[PATTERNS[i+1]] # Cut patterns for p in PATTERNS: if doRelaxed: prob.relaxation[p] += sum(length[i] * cutVars[(p, i)] for i in ITEMS) \ <= total_length[p] * useVars[p] else: prob += sum(length[i] * cutVars[(p, i)] for i in ITEMS) \ <= total_length[p] * useVars[p] def relaxed_solver(prob, patt, redCosts, convexDual): ## print patt, "in", PATTERNS ## print "redCosts =", redCosts ## print "convexDual =", convexDual # get items with negative reduced cost item_idx = [i for i in ITEMS \ if redCosts[cutVars[(patt, i)]] < 0] vars = [cutVars[(patt, i)] for i in item_idx] obj = [-redCosts[cutVars[(patt, i)]] for i in item_idx] weights = [length[i] for i in item_idx] ## print "Using knapsack heuristic" ## print "item_idx =", item_idx ## print "obj =", obj ## print "weights =", weights ## print "capacity =", total_length[patt] z, solution = kp(obj, weights, total_length[patt]) ## print "Number of items = ", len(item_idx) ## for i in range(len(item_idx)): ## print "Item ", item_idx[i], " has profit ", obj[i], " and weight ", weights[i] ## print "Knapsack has capacity ", total_length[patt] ## print "Value = ", z ## for i in range(len(item_idx)): ## print "Included[", item_idx[i], "] = ", solution[i] total_weight = sum(w * solution[i] \ for i, w in enumerate(weights)) assert total_weight <= total_length[patt] # add in reduced cost of useVars totalCut = sum(solution) ## print "z, redCosts[useVars[", patt, "]], convexDual", z, redCosts[useVars[patt]], convexDual if totalCut > 0: rc = -z + redCosts[useVars[patt]] - convexDual else: rc = -convexDual ## print "rc =", rc ## sys.stdout.flush() if rc < 0: # Using this pattern var_values = dict([(v, solution[i]) \ for i, v in enumerate(vars) \ if solution[i] > 0]) if totalCut > 0: var_values[useVars[patt]] = 1 cost = 1 else: cost = 0 var_tuple = (cost, rc, var_values) return [var_tuple] return [] def kp(obj, weights, capacity): assert len(obj) == len(weights) n = len(obj) if n == 0: return 0, [] if capacity == 0: return 0, [0 for i in range(n)] n = len(obj) # Don't include item zbest, solbest = kp(obj, weights, capacity - 1) # Check all items for inclusion for i in range(n): if weights[i] <= capacity: zyes, solyes = kp(obj, weights, \ capacity - weights[i]) zyes += obj[i] solyes[i] += 1 if zyes > zbest: zbest = zyes solbest = solyes return zbest, solbest return prob, relaxed_solver