Exemple #1
0
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
Exemple #3
0
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
Exemple #6
0
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
Exemple #7
0
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