Exemplo n.º 1
0
def fl_mip_solver(input_data):
    # Modify this code to run your optimization algorithm

    # parse the input
    lines = input_data.split('\n')

    parts = lines[0].split()
    facility_count = int(parts[0])
    customer_count = int(parts[1])
    
    facilities = []
    for i in range(1, facility_count+1):
        parts = lines[i].split()
        facilities.append(Facility(i-1, float(parts[0]), int(parts[1]), Point(float(parts[2]), float(parts[3])) ))

    customers = []
    for i in range(facility_count+1, facility_count+1+customer_count):
        parts = lines[i].split()
        customers.append(Customer(i-1-facility_count, int(parts[0]), Point(float(parts[1]), float(parts[2]))))
    
    print('F count:',facility_count)
    print('C count:',customer_count)
    
    # instantiates setup cost vector
    set_cost = [f.setup_cost for f in facilities]
    
    # instantiates proportional capacity matrix such that Cap[i,j] represents the demand of 
    # customer 'j' as a fraction of the total capacity of facility 'i'
    Cap = [[c.demand/f.capacity  for c in customers] for f in facilities]
    
    # instantiates distance matrix in such a way that "sum_{j \in M} D[i,j]*at[i,j]" is the total
    # distance cost for facility 'i'
    D = [[length(c.location, f.location)  for c in customers] for f in facilities]
    
    # declares MIP model
    #m = Model(solver_name=CBC)
    m = Model(solver_name='GRB')
    print('-Model instatiated!',datetime.datetime.now())
    
    # states search emphasis
    #     - '0' (default) balanced approach
    #     - '1' (feasibility) aggressively searches for feasible solutions
    #     - '2' (optimality) explores search space to tighten dual gap
    m.emphasis = 2
    
    # whenever the distance of the lower and upper bounds is less or 
    # equal max_gap*100%, the search can be finished
    m.max_gap = 0.05
    
    # specifies number of used threads
    # 0 uses solver default configuration, 
    # -1 uses the number of available processing cores 
    # ≥1 uses the specified number of threads. 
    # An increased number of threads may improve the solution time but also increases 
    # the memory consumption. Each thread needs to store a different model instance!
    m.threads = -1
    
    
    # controls the generation of cutting planes
    # cutting planes usually improve the LP relaxation bound but also make the solution time of the LP relaxation larger
    # -1 means automatic
    #  0 disables completely
    #  1 (default) generates cutting planes in a moderate way
    #  2 generates cutting planes aggressively
    #  3 generates even more cutting planes
    m.cuts=-1

    m.preprocess=1
    m.pump_passes=10
    m.sol_pool_size=1

    # instantiates open facilities variables
    op = [m.add_var(name="op{}".format(i),var_type='B') for i in range(facility_count)]
    
    # instantiates matrix of atribution variables 
    # (line 'i' is an atribution vector for facility 'i')
    # e.g.: At[3][4] returns whether customer 4 is assigned to facility 3
    At = [[m.add_var(name="At{},{}".format(i,j) ,var_type='B') for j in range(customer_count)] 
          for i in range(facility_count)]
    
    print('-Variables declared!',datetime.datetime.now())
    
    # instantiates objective function
    # m.objective = minimize("setup costs" + "distance costs")
    # Form example:
    # m.objective = minimize(
    # xsum(dist[i, j] * x[i, j] for (i, j) in product(F, C)) + xsum(y[i] for i in F) )
    
    m.objective = minimize(
        xsum(set_cost[i]*op[i] for i in range(facility_count)) +
        xsum(sum(D[i][j]*At[i][j] for j in range(customer_count)) for i in range(facility_count)) 
            )
    
    print('-Objective declared!',datetime.datetime.now())
    
    # instatiates capacity constraints
    #     -can be expressed as "sum_{j \in M} Cap[i,j]*At[i,j] <= op[i]" for all facilities 'i'
    #     -if a facility is closed (op[i]=0), its effective capacity is 0
    for i in range(facility_count):
        m.add_lazy_constr( xsum(Cap[i][j]*At[i][j] for j in range(customer_count)) <= op[i] )
    
    # instantiates assignment constraints (maximum of 1 facility per customer)
    #     -can be expressed as: "sum of elements over of each column of 'At' == 1"     
    for i in range(customer_count):
        m += xsum(At[j][i] for j in range(facility_count)) == 1 
    
    print('-Contraints processed!',datetime.datetime.now())
    
    #Maximum time in seconds that the search can go on if a feasible solution 
    #is available and it is not being improved
    mssi = 1000 #default = inf
    # specifies maximum number of nodes to be explored in the search tree (default = inf)
    mn = 40000 #default = 1073741824
    # optimize model m within a processing time limit of 'ms' seconds
    ms = 3000 #default = inf
    
    print('-Optimizer start.',datetime.datetime.now())
    # executes the optimization
    #status = m.optimize(max_seconds = ms,max_seconds_same_incumbent = mssi,max_nodes = mn)
    status = m.optimize(max_seconds = ms , max_seconds_same_incumbent = mssi)
    final_obj = m.objective_value

    print('Opt. Status:',status)
    print('MIP Sol. Obj.:',final_obj)
    print('Dual Bound:',m.objective_bound)
    print('Dual gap:',m.gap)
    
    
    used=[i for i in range(facility_count) if m.vars[i].x==1]

    solution=[None] * customer_count
    for i in range(facility_count):
        for j in range(customer_count):
            if round(m.vars[i*customer_count + j + facility_count].x) == 1:
                solution[j]=i
    # parse output varibles and convert to conventional solution output format
    
    # calculate the cost of the solution
    obj = sum([facilities[f].setup_cost for f in used])
    
    for customer in customers:
        obj += length(customer.location, facilities[solution[customer.index]].location)

    if status == OptimizationStatus.OPTIMAL:
    	# prepare the solution in the specified output format
    	output_data = '%.2f' % obj + ' ' + str(1) + '\n'
    	output_data += ' '.join(map(str, solution))
    elif status == OptimizationStatus.FEASIBLE:
    	output_data = '%.2f' % obj + ' ' + str(0) + '\n'
    	output_data += ' '.join(map(str, solution))
    
    return output_data
def tsp_mip_solver(input_data):
    # parse the input
    lines = input_data.split('\n')

    nodeCount = int(lines[0])

    points = []
    for i in range(1, nodeCount + 1):
        line = lines[i]
        parts = line.split()
        points.append(Point(float(parts[0]), float(parts[1])))
    print('Points parsed!')

    # calculate distance matrix
    d_m = [[length(q, p) for q in points] for p in points]
    print('Distance matrix ready!')

    # declare MIP model
    m = Model(solver_name='GRB')
    print('-Model instatiated!', datetime.datetime.now())

    # states search emphasis
    #     - '0' (default) balanced approach
    #     - '1' (feasibility) aggressively searches for feasible solutions
    #     - '2' (optimality) explores search space to tighten dual gap
    m.emphasis = 0

    # whenever the distance of the lower and upper bounds is less or
    # equal max_gap*100%, the search can be finished
    m.max_gap = 0.05

    # specifies number of used threads
    # 0 uses solver default configuration,
    # -1 uses the number of available processing cores
    # ≥1 uses the specified number of threads.
    # An increased number of threads may improve the solution time but also increases
    # the memory consumption. Each thread needs to store a different model instance!
    m.threads = 0

    # controls the generation of cutting planes
    # cutting planes usually improve the LP relaxation bound but also make the solution time of the LP relaxation larger
    # -1 means automatic
    #  0 disables completely
    #  1 (default) generates cutting planes in a moderate way
    #  2 generates cutting planes aggressively
    #  3 generates even more cutting planes
    m.cuts = -1

    m.preprocess = 1
    m.pump_passes = 20
    m.sol_pool_size = 1

    nodes = set(range(nodeCount))

    # instantiate "entering and leaving" variables
    x = [[m.add_var(name="x{}_{}".format(p, q), var_type='B') for q in nodes]
         for p in nodes]
    # instantiate subtour elimination variables
    y = [m.add_var(name="y{}".format(i)) for i in nodes]
    print('-Variables instantiated', datetime.datetime.now())

    # declare objective function
    m.objective = minimize(
        xsum(d_m[i][j] * x[i][j] for i in nodes for j in nodes))

    print('-Objective declared!', datetime.datetime.now())

    # declare constraints
    # leave each city only once
    for i in tqdm(nodes):
        m.add_constr(xsum(x[i][j] for j in nodes - {i}) == 1)

    # enter each city only once
    for i in tqdm(nodes):
        m.add_constr(xsum(x[j][i] for j in nodes - {i}) == 1)

    # subtour elimination constraints
    for (i, j) in tqdm(product(nodes - {0}, nodes - {0})):
        if i != j:
            m.add_constr(y[i] - (nodeCount + 1) * x[i][j] >= y[j] - nodeCount)

    print('-Constraints declared!', datetime.datetime.now())

    #Maximum time in seconds that the search can go on if a feasible solution
    #is available and it is not being improved
    mssi = 1000  #default = inf
    # specifies maximum number of nodes to be explored in the search tree (default = inf)
    mn = 1000000  #default = 1073741824
    # optimize model m within a processing time limit of 'ms' seconds
    ms = 3000  #default = inf

    # executes the optimization
    print('-Optimizer start.', datetime.datetime.now())
    #status = m.optimize(max_seconds = ms,max_seconds_same_incumbent = mssi,max_nodes = mn)
    status = m.optimize(max_seconds=ms, max_seconds_same_incumbent=mssi)

    print('Opt. Status:', status)
    print('MIP Sol. Obj.:', m.objective_value)
    print('Dual Bound:', m.objective_bound)
    print('Dual gap:', m.gap)

    sol = [0]
    c_node = 0
    for j in range(nodeCount - 1):
        for i in range(nodeCount):
            if round(m.var_by_name("x{}_{}".format(c_node, i)).x) != 0:
                sol.append(i)
                c_node = i
                break

    obj = m.objective_value

    # prepare the solution in the specified output format
    if status == OptimizationStatus.OPTIMAL:
        output_data = '%.2f' % obj + ' ' + str(1) + '\n'
        output_data += ' '.join(map(str, sol))
    elif status == OptimizationStatus.FEASIBLE:
        output_data = '%.2f' % obj + ' ' + str(0) + '\n'
        output_data += ' '.join(map(str, sol))

    return output_data
Exemplo n.º 3
0
def mip_solver(input_data):
    # Modify this code to run your optimization algorithm

    # parse the input
    lines = input_data.split('\n')

    firstLine = lines[0].split()
    item_count = int(firstLine[0])
    capacity = int(firstLine[1])

    items = []

    for i in range(1, item_count+1):
        line = lines[i]
        parts = line.split()
        items.append(Item(i-1, int(parts[0]), int(parts[1])))

    # a trivial algorithm for filling the knapsack
    # it takes items in-order until the knapsack is full
    value = 0
    weight = 0
    taken = [0]*len(items)
    
    # declare value vector
    val_vec = [item.value for item in items]
    
    # declare weight vector scaled by capacity
    wgt_vec = [item.weight/capacity for item in items]
    
    # start MIP solver
    m = Model(solver_name='GRB')
    print('-Model instatiated!',datetime.datetime.now())
    
    # states search emphasis
    #     - '0' (default) balanced approach
    #     - '1' (feasibility) aggressively searches for feasible solutions
    #     - '2' (optimality) explores search space to tighten dual gap
    m.emphasis = 2
    
    # whenever the distance of the lower and upper bounds is less or 
    # equal max_gap*100%, the search can be finished
    m.max_gap = 0.05
    
    # specifies number of used threads
    # 0 uses solver default configuration, 
    # -1 uses the number of available processing cores 
    # ≥1 uses the specified number of threads. 
    # An increased number of threads may improve the solution time but also increases 
    # the memory consumption. Each thread needs to store a different model instance!
    m.threads = -1
    
    
    # controls the generation of cutting planes
    # cutting planes usually improve the LP relaxation bound but also make the solution time of the LP relaxation larger
    # -1 means automatic
    #  0 disables completely
    #  1 (default) generates cutting planes in a moderate way
    #  2 generates cutting planes aggressively
    #  3 generates even more cutting planes
    m.cuts=-1

    m.preprocess=1
    m.pump_passes=10
    m.sol_pool_size=1
    
    # instantiates taken items variable vector
    taken = [m.add_var(name="it{}".format(i),var_type='B') for i in range(item_count)]
    print('-Variables declared!',datetime.datetime.now())
    
    # instantiates objective function
    m.objective = maximize( xsum( val_vec[i]*taken[i] for i in range(item_count) ) )
    print('-Objective declared!',datetime.datetime.now())
    
    m.add_constr( xsum( wgt_vec[i]*taken[i] for i in range(item_count)) <=1 )
    print('-Contraints processed!',datetime.datetime.now())
    
    #Maximum time in seconds that the search can go on if a feasible solution 
    #is available and it is not being improved
    mssi = 1000 #default = inf
    # specifies maximum number of nodes to be explored in the search tree (default = inf)
    mn = 40000 #default = 1073741824
    # optimize model m within a processing time limit of 'ms' seconds
    ms = 3000 #default = inf
    
    print('-Optimizer start.',datetime.datetime.now())
    # executes the optimization
    #status = m.optimize(max_seconds = ms,max_seconds_same_incumbent = mssi,max_nodes = mn)
    status = m.optimize(max_seconds = ms , max_seconds_same_incumbent = mssi)
    final_obj = m.objective_value
    
    print('Opt. Status:',status)
    print('MIP Sol. Obj.:',final_obj)
    print('Dual Bound:',m.objective_bound)
    print('Dual gap:',m.gap)
    
    sol = [round(it.x) for it in taken]
    value = int(final_obj)
    
    taken = sol
    # prepare the solution in the specified output format
    if status == OptimizationStatus.OPTIMAL:
        output_data = str(value) + ' ' + str(1) + '\n'
        output_data += ' '.join(map(str, taken))
    elif status == OptimizationStatus.FEASIBLE:
        output_data = str(value) + ' ' + str(0) + '\n'
        output_data += ' '.join(map(str, taken))


    if item_count == 10000:
        output_data=greedy(input_data)

    return output_data