Exemplo n.º 1
0
def initialize_columns(instance):
    """ Se inicializan las columnas: cada cliente es atendido exclusivamente por un vehículo con la capacidad mínima
    entre todos los vehículos que pueden satisfacerlo. """
    routes = []

    clients = set(instance.demand)
    clients.remove(0)

    for i in clients:
        # Entre los vehículos que pueden satisface la demanda de i, elegimos al de menor capacidad
        k = min((v for v, c in instance.cap.items() if c >= instance.demand[i]), key=lambda v: instance.cap[v])
        path = Path(k)
        path.add_node(i, instance)
        routes.append(Route.from_path(path, instance))

    return routes
Exemplo n.º 2
0
def solve_SPk(pi, lamb, k, instance):
    """
    Se resulve el problema \bar{SP} restringido al tipo de vehículo k. Se utiliza el procedimiento de etiquetas
    detallada en la tercera sección del informe.
    :param pi: diccionario con los valores óptimos de las variables del dual correspondiente al primer conjunto de
    restricciones de CLP
    :type pi: dict
    :param lamb: diccionario con los valores óptimos de las variables del dual correspondiente al primer conjunto de
    restricciones de CLP
    :type lamb: dict
    :param k: tipo de vehículo
    :type k: int
    :param instance: datos del problema
    :type instance: Instance
    :return: ruta con menor costo reducido para el tipo de vehículo k y su costo reducido
    :rtype: Route, float
    """
    pi[0] = lamb[k]

    bk = instance.cap[k]

    # Removemos a los clientes cuya demanda supera a bk
    nodes = set(filter(lambda c: instance.demand[c] <= bk, instance.demand))
    clients = nodes.difference({0})

    # Se define la matriz de costos del subgrafo \bar{G}_k
    cost_matrix = make_cost_matrix(pi, k, instance)

    # Se inicializa el estado del depósito
    warehouse_label = Label.warehouse_label()

    # Se crean los conjuntos de estados cuya cota superior coincide con su cota inferior
    P = {j: [] for j in clients}
    P[0] = [warehouse_label]

    L = deque([warehouse_label])
    while L:
        label = L.popleft()

        for j in filter(lambda c: label.q + instance.demand[c] <= bk and c != label.pred and c != label.node, clients):
            new_label = Label(label.q + instance.demand[j], j)
            new_label.path = label.path + [j]
            new_label.pred = label.node
            new_label.reduced_cost = get_reduced_cost(new_label, cost_matrix, instance, k)

            dominates = []
            dominated = False

            # Se chequea si la nueva etiqueta no está dominada
            for s in P[j]:
                if s.reduced_cost > new_label.reduced_cost:
                    dominates.append(s)
                elif s.reduced_cost < new_label.reduced_cost:
                    dominated = True
                    break
            if not dominated:
                # Se encola la nueva etiqueta
                L.append(new_label)
                P[j].append(new_label)

                # Se eliminan todas las etiquetas dominadas por la nueva
                for s in dominates:
                    P[j].remove(s)
                    try:
                        L.remove(s)
                    except ValueError:
                        pass

    best_state = min((s for s in chain.from_iterable(P.values())), key=lambda s: getattr(s, 'reduced_cost'))
    best_path = Path.from_sequence(best_state.path, instance, k)
    return Route.from_path(best_path, instance), get_reduced_cost(best_state, cost_matrix, instance, k)
Exemplo n.º 3
0
def pulling_algorithm(pi, lamb, k, instance):
    """
    Método para resolver \bar{SP} restringido al tipo de vehículo k desarrollado por Desrochers. No utilizado para
    resolver las instancias.
    :param pi: diccionario con los valores óptimos de las variables del dual correspondiente al primer conjunto de
    restricciones de CLP
    :type pi: dict
    :param lamb: diccionario con los valores óptimos de las variables del dual correspondiente al primer conjunto de
    restricciones de CLP
    :type lamb: dict
    :param k: tipo de vehículo
    :type k: int
    :param instance: datos del problema
    :type instance: Instance
    :return: ruta con menor costo reducido para el tipo de vehículo k y su costo reducido
    :rtype: Route, float
    """
    pi[0] = lamb[k]

    bk = instance.cap[k]

    # Removemos a los clientes cuya demanda supera a bk
    nodes = set(filter(lambda c: instance.demand[c] <= bk, instance.demand))
    clients = nodes.difference({0})

    # Se define la matriz de costos del subgrafo \bar{G}_k
    cost_matrix = make_cost_matrix(pi, k, instance)

    # Se inicilizan los estados de los nodos correspondientes a los clientes
    states = [State(q, j) for j in clients for q in range(instance.demand[j], bk + 1)]

    # Se inicializa el estado del depósito
    depo_state = State.warehouse_state()
    states.append(depo_state)

    # Se crean los conjuntos de estados cuya cota superior coincide con su cota inferior
    P = {j: [] for j in clients}
    P[0] = [depo_state]

    # Consideramos el conjunto W de estados cuyas cotas no coinciden
    W = deque(sorted([s for s in states if s.ub != s.lb], key=lambda s: (s.q, s.node)))

    best_state = None
    best_rc = 1e6

    while W:
        # Entre los estados de cada j cuya cotas no coinciden, elegimos el que tiene menor q. Ante empates, elegimos el
        # que tiene menor j
        state = W.popleft()

        # Actualizamos la cota superior del estado. Primero calculamos el estado previo a (q,j) para el cual se realiza
        # el mínimo
        demand_bound = state.q - instance.demand[state.node]
        candidate_states = [s for s in states if s.node != state.node and s.q <= demand_bound]
        candidate_phis = [phi(s, state.node, cost_matrix) for s in candidate_states]
        prev_state, prev_phi = get_prev_state(candidate_states, candidate_phis)
        state.pred = prev_state.node
        state.ub = prev_phi
        state.path = prev_state.path + [state.node]

        # Se actualiza la cota superior del segundo mejor camino. Si el conjunto sobre el que se toma el mínimo es
        # vacío, la cota no se altera
        state.sub = get_secondary_ub(candidate_states, candidate_phis, state.pred)

        # Se actualiza la cota inferior del estado
        state.lb = min(map(lambda s: s.lb + cost_matrix[s.node][state.node], candidate_states))

        # Actualizamos Pj de ser necesario:
        if isclose(state.lb, state.ub):
            P[state.node].append(state)
            state_rc = get_reduced_cost(state, cost_matrix, instance, k)
            if state_rc < best_rc:
                best_rc = state_rc
                best_state = state

    best_path = Path.from_sequence(best_state.path, instance, k)
    return Route.from_path(best_path, instance), get_reduced_cost(best_state, cost_matrix, instance, k)