def cap_mip_gr(customers,facilities,max_time = 60):
    n_cust = len(customers)
    n_fac = len(facilities)
    dist = distance_matrix(customers, facilities)
    cartesian_prod = list(product(range(n_cust), range(n_fac)))
    setup_cost = [f.setup_cost for f in facilities]
    shipping_cost = {(c,f):dist[f,c] for c,f in cartesian_prod}
    demands = np.array([c.demand for c in customers])
    caps = np.array([f.capacity for f in facilities])
    solver = gp.Model('facility_location')
    
    # Define Variables
    x = solver.addVars(n_fac,vtype=GRB.BINARY, name='Select')
    y = solver.addVars(cartesian_prod, ub=1, vtype=GRB.CONTINUOUS, name='Assign')
    
    # Define Constraints
    solver.addConstrs((y[(c,f)] <= x[f] for c,f in cartesian_prod), name='Setup2ship')
    solver.addConstrs((gp.quicksum(y[(c,f)] for f in range(n_fac)) == 1 for c in range(n_cust)), name='Demand')
    solver.addConstrs((gp.quicksum(y[(c,f)]*demands[c] for c in range(n_cust)) <= caps[f] for f in range(n_fac)),name = 'Capacity')
    # Set Objective
    solver.setObjective(x.prod(setup_cost)+y.prod(shipping_cost), GRB.MINIMIZE)
    solver.setParam("TimeLimit",max_time)
    
    # Solve
    solver.optimize()
    # Parse Outputs
    solution = np.zeros((n_fac,n_cust))
    for c in range(n_cust):
        for f in range(n_fac):
            solution[f,c] = y[(c,f)].x
            
    return solution.argmax(axis=0)
Exemple #2
0
def ant_colony(
    customers,
    facilities,
    q=1,
    offset=0,
    evaporation=0.1,
    ants=100,
    generations=100,
):
    n_cust = len(customers)
    n_fac = len(facilities)
    dist = distance_matrix(customers, facilities)
    weights = np.ones_like(dist)
    best_sol = None
    best_cost = np.inf
    metrics = defaultdict(list)
    for gen in trange(generations):
        probs = weights / dist
        updates = np.zeros_like(dist)
        costs = []
        for ant in range(ants):
            solution = ant_simulator(customers, facilities, dist, probs)
            cost = total_cost(solution, customers, facilities)
            edges = allocation2matrix(solution, n_fac)
            updates += edges * q / (cost - offset)
            costs.append(cost)
            if cost < best_cost:
                best_cost = cost
                best_sol = solution

        weights = weights * (1 - evaporation) + updates
        metrics["min_cost"].append(np.min(costs))
        metrics["max_cost"].append(np.max(costs))
        metrics["mean_cost"].append(np.mean(costs))
    return best_sol, metrics
Exemple #3
0
def cap_mip(customers, facilities, max_time=60):
    n_fac = len(facilities)
    n_cust = len(customers)
    solver = Solver.CreateSolver("FacilityLocation", "SCIP")

    x = []
    y = []
    for f in range(n_fac):
        y.append([solver.BoolVar(f"y_{f}_{c}") for c in range(n_cust)])
        x.append(solver.BoolVar(f"x_{f}"))

    caps = [f.capacity for f in facilities]
    setup = [f.setup_cost for f in facilities]
    dist = distance_matrix(customers, facilities).astype(int)
    demands = [c.demand for c in customers]

    for f in range(n_fac):
        for c in range(n_cust):
            solver.Add(y[f][c] <= x[f])
    for c in range(n_cust):
        solver.Add(sum([y[f][c] for f in range(n_fac)]) == 1)
    for f in range(n_fac):
        solver.Add(sum([y[f][c] * demands[c] for c in range(n_cust)]) <= caps[f])

    obj = 0
    for f in range(n_fac):
        obj += setup[f] * x[f]
        obj += sum([dist[f][c] * y[f][c] for c in range(n_cust)])

    solver.Minimize(obj)

    STATUS = {
        Solver.FEASIBLE: "FEASIBLE",
        Solver.UNBOUNDED: "UNBOUNDED",
        Solver.BASIC: "BASIC",
        Solver.INFEASIBLE: "INFEASIBLE",
        Solver.NOT_SOLVED: "NOT_SOLVED",
        Solver.OPTIMAL: "OPTIMAL",
    }
    solver.SetTimeLimit(max_time * 1000)

    status = solver.Solve()
    STATUS[status]
    a = []
    for f in range(n_fac):
        a.append([y[f][c].solution_value() for c in range(n_cust)])

    sol = np.array(a).argmax(axis=0)
    return sol, STATUS[status]
def ant_colony(
    customers,
    facilities,
    q=1,
    offset=0,
    evaporation=.1,
    ants=100,
    generations=100,
):
    n_cust = len(customers)
    n_fac = len(facilities)
    dist = distance_matrix(customers, facilities)
    weights = np.ones_like(dist)
    best_sol = None
    best_cost = np.inf
    metrics = defaultdict(list)
    greedy_solution = double_trial(
        customers,
        facilities,
        greedy_furthest,
        p_skip=0,
        pbar=False,
    )
    for gen in trange(generations):
        probs = weights/dist
        updates = np.zeros_like(dist)
        costs = []
        for ant in range(ants):
            if ant==0:
                solution = greedy_solution.copy()
            else:
                solution = ant_simulator(customers, facilities, dist, probs)
            cost = total_cost(solution,customers, facilities)
            edges = allocation2matrix(solution, n_fac)
            updates += edges*q/(cost-offset)
            costs.append(cost)
            if cost<best_cost:
                best_cost = cost
                best_sol = solution
                
        weights = weights*(1-evaporation) + updates
        metrics['min_cost'].append(np.min(costs))
        metrics['max_cost'].append(np.max(costs))
        metrics['mean_cost'].append(np.mean(costs))
    return best_sol, metrics
Exemple #5
0
def greedy_furthest(
    customers,
    facilities,
    ignore_setup=True,
    p_skip=0,
    pbar=True,
    order=None,
):
    dist = distance_matrix(customers, facilities)
    n_cust = len(customers)
    n_fac = len(facilities)
    solution = -np.ones(n_cust)
    opened_fac = np.zeros(n_fac)
    remaining_cap = np.array([f.capacity for f in facilities])
    caps = np.array([f.capacity for f in facilities])
    setup_cost = np.array([f.setup_cost for f in facilities])
    dist_ord = dist.mean(axis=0).argsort()
    if order is not None:
        dist_ord = np.array(order)
    if pbar:
        iterator = tqdm(reversed(dist_ord), total=n_cust)
    else:
        iterator = reversed(dist_ord)
    for c in iterator:
        customer = customers[c]
        choice_cost = dist[:, c]
        if not ignore_setup:
            # choice_cost += (1 - opened_fac) * setup_cost
            choice_cost += setup_cost * customer.demand / caps / 2
        for f in np.argsort(choice_cost):
            if remaining_cap[f] >= customer.demand:
                if np.random.rand() < p_skip:
                    continue
                opened_fac[f] = 1
                remaining_cap[f] -= customer.demand
                solution[c] = f
                break
    return solution.astype(int)
def cap_mip2(customers,
             facilities,
             max_time=60,
             min_fac=None,
             max_fac=None,
             k_neigh=None):
    n_fac = len(facilities)
    n_cust = len(customers)
    solver = Solver.CreateSolver("FacilityLocation", "SCIP")
    if min_fac is None:
        min_fac = min_facilities(customers, facilities)
    print(f'Minimum Facilities: {min_fac}')
    est_fac = est_facilities(customers, facilities)
    est_fac = max(5, min_fac)
    print('Estimated Facilities:', est_fac)
    if k_neigh is None:
        k_neigh = n_fac // est_fac * 2
        k_neigh = min(k_neigh, n_fac // 2)
    print(f'Only using {k_neigh} nearest facilities')

    # Estimate Customers per Facilitiy
    cpf = n_cust // min_fac
    cpf = np.clip(cpf, 2, n_cust // 2)

    # Define Variables
    x = []
    y = []
    for f in range(n_fac):
        y.append([solver.BoolVar(f"y_{f}_{c}") for c in range(n_cust)])
        x.append(solver.BoolVar(f"x_{f}"))

    caps = np.array([f.capacity for f in facilities])
    setup = np.array([f.setup_cost * 100 for f in facilities])
    dist = distance_matrix(customers, facilities) * 100
    dist = dist.astype(int)
    demands = np.array([c.demand for c in customers])

    # Problem Analysis
    free_setup = np.where(caps == 0)[0]
    is_fixed_setup = True if np.std(caps[caps > 0]) == 0 else False

    # Add Constraints
    print('\t Adding Constaints')
    # If facility is closed then it is not connected to any customer
    for f in range(n_fac):
        for c in range(n_cust):
            solver.Add(y[f][c] <= x[f])

    # Each customer is connected to only one facility
    for c in range(n_cust):
        solver.Add(sum([y[f][c] for f in range(n_fac)]) == 1)

    # The demand is not more than the capacity of the facility
    for f in range(n_fac):
        solver.Add(
            sum([y[f][c] * demands[c]
                 for c in range(n_cust)]) <= caps[f] * x[f])
        solver.Add(
            sum([y[f][c] * demands[c] for c in range(n_cust)]) <= caps[f])

    # Customers per facility
    for f in range(n_fac):
        solver.Add(sum([y[f][c] for c in range(n_cust)]) <= n_cust * x[f])

    # The free facilities must be open
    for f in free_setup:
        solver.Add(x[f] == 1)

    # Customer can ONLY connect to nearby facilities
    for c in range(n_cust):
        idx = np.argsort(dist[:, c])
        for f in idx[k_neigh:]:
            solver.Add(y[f][c] == 0)

    print('\t Adding Covercut Constaints')
    # Cover cut for customers which can be connected to a facility
    #     round1 = []
    #     round2 = []
    #     for f in range(n_fac):
    #         argsort = np.argsort(dist[f, :])
    #         idx = argsort[:cpf]
    #         if sum(demands[idx]) > caps[f]:
    #             round1.append(f)
    #             solver.Add(sum([y[f][c] for c in idx]) <= (cpf - 1))
    #         if cpf > 4:
    #             k = int(cpf * .9)
    #             idx = argsort[:k]
    #             if sum(demands[idx]) > caps[f]:
    #                 round2.append(f)
    #                 solver.Add(sum([y[f][c] for c in idx]) <= (k - 1))

    #     print(round1)
    #     print(round2, flush=True)

    # Maximum Facility open
    solver.Add(sum(x) >= min_fac)
    if max_fac is not None:
        solver.Add(sum(x) <= max_fac)
    #     solver.Add(sum(x)>=2)

    # Define objective
    obj = 0
    for f in range(n_fac):
        # Setup cost
        if not is_fixed_setup:
            obj += setup[f] * x[f]
        # Service cost
        obj += sum([dist[f][c] * y[f][c] for c in range(n_cust)])
    solver.Minimize(obj)

    STATUS = {
        Solver.FEASIBLE: "FEASIBLE",
        Solver.UNBOUNDED: "UNBOUNDED",
        Solver.BASIC: "BASIC",
        Solver.INFEASIBLE: "INFEASIBLE",
        Solver.NOT_SOLVED: "NOT_SOLVED",
        Solver.OPTIMAL: "OPTIMAL",
    }
    solver.SetTimeLimit(max_time * 1000)

    # Solve
    print('\t Starting the Solver')
    status = solver.Solve()
    STATUS[status]

    # Retreive values
    a = []
    for f in range(n_fac):
        a.append([y[f][c].solution_value() for c in range(n_cust)])

    # Convert solution matrix to facility index
    sol = np.array(a).argmax(axis=0)

    return sol, STATUS[status]
# ## Constraint Programming

# ### Uncapacitated Facilities

from ortools.sat.python import cp_model
from calc import distance_matrix


customers,facilities= load_data('fl_100_1')
n_cust = len(customers)
n_fac = len(facilities)


caps = [f.capacity for f in facilities]
setup = [f.setup_cost for f in facilities]
dist = distance_matrix(customers,facilities).astype(int)
demands = [c.demand for c in customers]

model = cp_model.CpModel()

a = [] # allocation matrix (facilities x customers)
for f in range(n_fac):
    a.append([model.NewBoolVar(f'a_{c}_{f}') for c in range(n_cust)])

# +
# Only one facility per customer
for c in range(n_cust):
    model.Add(sum([a[f][c] for f in range(n_fac)])==1)
    
# Capacity check
for f in range(n_fac):