Exemple #1
0
def bidirectional_alt(graph, node_from, node_to):
    if not isinstance(graph, classes.Graph.Graph):
        raise IOError("Wrong graph type")
    if not isinstance(node_from, classes.Node.Node):
        raise IOError("Wrong node_from type")
    if not isinstance(node_to, classes.Node.Node):
        raise IOError("Wrong node_to type")

    # def heuristic(nf, t, s):
    #     result = math.sqrt(math.pow((nf.x - t.x), 2) + math.pow((nf.y - t.y), 2)) - \
    #              math.sqrt(math.pow((nf.x - s.x), 2) + math.pow((nf.y - s.y), 2))
    #     return result / 2

    def heuristic(nf, t, s):

        result1 = -1
        for i in range(16):
            temp1 = abs(nf.dist_to_mark[i] - t.dist_to_mark[i])
            # temp2 = abs(nf.dist_to_mark[i] - s.dist_to_mark[i])
            if temp1 > result1:
                result1 = temp1

        result2 = -1
        for i in range(16):
            temp2 = abs(nf.dist_to_mark[i] - s.dist_to_mark[i])
            # temp2 = abs(nf.dist_to_mark[i] - s.dist_to_mark[i])
            if temp2 > result2:
                result2 = temp2

        return (result1 - result2) / 2

    time_start = time.time()

    dists_fw = {a: -1 for a in graph.nodes}
    dists_fw[node_from.id] = 0

    dists_bw = {a: -1 for a in graph.nodes}
    dists_bw[node_to.id] = 0

    edge_to_fw = dict()
    edge_to_bw = dict()

    covering_fw = dict()
    covering_bw = dict()

    queue_fw = PQ.PriorityQueueByDict()
    queue_fw.update(node_from)
    queue_bw = PQ.PriorityQueueByDict()
    queue_bw.update(node_to)

    center = None
    centers_amount = 0

    while not queue_fw.empty() and not queue_bw.empty():

        # Forward step
        current_node = queue_fw.get()[0]
        covering_fw.update({current_node: True})

        if covering_bw.get(current_node, False):
            if center is None or dists_fw[current_node.id] + dists_bw[
                    current_node.id] < dists_fw[center.id] + dists_bw[
                        center.id]:
                center = current_node
            centers_amount += 1
            if centers_amount > 20:
                break

        # next_edges = [x for x in current_node.incidentEdges if x.n_from == current_node]
        for edge in current_node.incidentEdges:
            if current_node == edge.n_from:
                if not covering_fw.get(edge.n_to, False) and dists_fw[
                        edge.n_to.id] == -1 or dists_fw[
                            edge.n_to.id] > dists_fw[
                                current_node.id] + edge.get_weight():
                    dists_fw[edge.n_to.id] = dists_fw[
                        current_node.id] + edge.get_weight()
                    edge_to_fw.update({edge.n_to: edge})
                    queue_fw.update(
                        edge.n_to, dists_fw[edge.n_to.id] +
                        heuristic(edge.n_to, node_to, node_from))
            else:
                if not covering_fw.get(edge.n_from, False) and dists_fw[
                        edge.n_from.id] == -1 or dists_fw[
                            edge.n_from.id] > dists_fw[
                                current_node.id] + edge.get_weight():
                    dists_fw[edge.n_from.id] = dists_fw[
                        current_node.id] + edge.get_weight()
                    edge_to_fw.update({edge.n_from: edge})
                    queue_fw.update(
                        edge.n_from, dists_fw[edge.n_from.id] +
                        heuristic(edge.n_from, node_to, node_from))

        # Backward step
        current_node = queue_bw.get()[0]
        covering_bw.update({current_node: True})

        if covering_fw.get(current_node, False):
            if center is None or dists_fw[current_node.id] + dists_bw[
                    current_node.id] < dists_fw[center.id] + dists_bw[
                        center.id]:
                center = current_node
            centers_amount += 1
            if centers_amount > 20:
                break

        # next_edges = [x for x in current_node.incidentEdges if x.n_to == current_node]
        for edge in current_node.incidentEdges:
            if current_node == edge.n_to:
                if not covering_bw.get(edge.n_from, False) and dists_bw[
                        edge.n_from.id] == -1 or dists_bw[
                            edge.n_from.id] > dists_bw[
                                current_node.id] + edge.get_weight():
                    dists_bw[edge.n_from.id] = dists_bw[
                        current_node.id] + edge.get_weight()
                    edge_to_bw.update({edge.n_from: edge})
                    queue_bw.update(
                        edge.n_from, dists_bw[edge.n_from.id] +
                        heuristic(edge.n_from, node_from, node_to))
            else:
                if not covering_bw.get(edge.n_to, False) and dists_bw[
                        edge.n_to.id] == -1 or dists_bw[
                            edge.n_to.id] > dists_bw[
                                current_node.id] + edge.get_weight():
                    dists_bw[edge.n_to.id] = dists_bw[
                        current_node.id] + edge.get_weight()
                    edge_to_bw.update({edge.n_to: edge})
                    queue_bw.update(
                        edge.n_to, dists_bw[edge.n_to.id] +
                        heuristic(edge.n_to, node_from, node_to))

    if center is None:
        return -1, [], -1

    path_fw = list()
    current_node = center
    while current_node != node_from:
        if current_node == edge_to_fw[current_node].n_to:
            current_node = edge_to_fw[current_node].n_from
            path_fw.append(current_node)
        else:
            current_node = edge_to_fw[current_node].n_to
            path_fw.append(current_node)

    current_node = center
    path_bw = list()
    while current_node != node_to:
        if current_node == edge_to_bw[current_node].n_from:
            current_node = edge_to_bw[current_node].n_to
            path_bw.append(current_node)
        else:
            current_node = edge_to_bw[current_node].n_from
            path_bw.append(current_node)

    path = path_fw[::-1]
    path.append(center)
    path += path_bw

    time_end = time.time()

    return dists_fw[center.id] + dists_bw[center.id], [path
                                                       ], time_end - time_start
Exemple #2
0
def bidirectional_dijkstra_un_p(graph, node_from, node_to):
    if not isinstance(graph, classes.Graph.Graph):
        raise IOError("Wrong graph type")
    if not isinstance(node_from, classes.Node.Node):
        raise IOError("Wrong node_from type")
    if not isinstance(node_to, classes.Node.Node):
        raise IOError("Wrong node_to type")

    # time_start = time.time()

    dists_fw = {a: -1 for a in graph.nodes}
    dists_fw[node_from.id] = 0

    dists_bw = {a: -1 for a in graph.nodes}
    dists_bw[node_to.id] = 0

    edge_to_fw = dict()
    edge_to_bw = dict()

    covering_fw = dict()
    covering_bw = dict()

    queue_fw = PQ.PriorityQueueByDict()
    queue_fw.update(node_from)
    queue_bw = PQ.PriorityQueueByDict()
    queue_bw.update(node_to)

    center = None

    t_fw_done, t_bw_done = False, False
    # current_node_f, current_node_b = None, None
    iter_f, iter_b = 0, 0

    covering_fw_lock = thr.Lock()
    covering_bw_lock = thr.Lock()

    t_fw_done_lock = thr.Lock()
    t_bw_done_lock = thr.Lock()

    center_lock = thr.Lock()

    def search_f():
        nonlocal queue_fw, t_bw_done, center, dists_fw, edge_to_fw, covering_fw, t_fw_done, covering_bw, iter_f
        while not queue_fw.empty():

            t_bw_done_lock.acquire()
            if t_bw_done:
                t_bw_done_lock.release()
                break

            t_bw_done_lock.release()

            # print('iter f {}'.format(iter_f))
            # iter_f += 1
            # Forward step
            current_node_f = queue_fw.get()[0]

            covering_fw_lock.acquire()
            covering_fw[current_node_f] = True
            covering_fw_lock.release()

            covering_bw_lock.acquire()
            if covering_bw.get(current_node_f, False):
                covering_bw_lock.release()

                center_lock.acquire()
                center = current_node_f
                center_lock.release()
                t_fw_done = True
                break
            covering_bw_lock.release()

            # next_edges = [x for x in current_node.incidentEdges if x.n_from == current_node]
            for edge in current_node_f.incidentEdges:
                if current_node_f == edge.n_from:
                    if not covering_fw.get(edge.n_to.id, False) and dists_fw[edge.n_to.id] == -1 or \
                            dists_fw[edge.n_to.id] > dists_fw[current_node_f.id] + edge.get_weight():
                        dists_fw[edge.n_to.id] = dists_fw[
                            current_node_f.id] + edge.get_weight()
                        edge_to_fw.update({edge.n_to: edge})
                        queue_fw.update(edge.n_to, dists_fw[edge.n_to.id])
                else:
                    if not covering_fw.get(edge.n_from.id, False) and dists_fw[edge.n_from.id] == -1 or \
                            dists_fw[edge.n_from.id] > dists_fw[current_node_f.id] + edge.get_weight():
                        dists_fw[edge.n_from.id] = dists_fw[
                            current_node_f.id] + edge.get_weight()
                        edge_to_fw.update({edge.n_from: edge})
                        queue_fw.update(edge.n_from, dists_fw[edge.n_from.id])
        pass

    def search_b():
        nonlocal queue_bw, t_bw_done, center, dists_bw, edge_to_bw, covering_fw, t_fw_done, covering_bw, iter_b
        while not queue_bw.empty():

            t_fw_done_lock.acquire()
            if t_fw_done:
                t_fw_done_lock.release()
                break
            t_fw_done_lock.release()

            # print('iter b {}'.format(iter_b))
            # iter_b += 1
            # Backward step
            current_node_b = queue_bw.get()[0]

            covering_bw_lock.acquire()
            covering_bw[current_node_b] = True
            covering_bw_lock.release()

            covering_fw_lock.acquire()
            if covering_fw.get(current_node_b, False):
                covering_fw_lock.release()

                center_lock.acquire()
                center = current_node_b
                center_lock.release()
                t_bw_done = True
                break
            covering_fw_lock.release()

            # next_edges = [x for x in current_node.incidentEdges if x.n_to == current_node]
            for edge in current_node_b.incidentEdges:
                if current_node_b == edge.n_to:
                    if not covering_fw.get(edge.n_from.id, False) and dists_bw[edge.n_from.id] == -1 or \
                            dists_bw[edge.n_from.id] > dists_bw[current_node_b.id] + edge.get_weight():
                        dists_bw[edge.n_from.id] = dists_bw[
                            current_node_b.id] + edge.get_weight()
                        edge_to_bw.update({edge.n_from: edge})
                        queue_bw.update(edge.n_from, dists_bw[edge.n_from.id])
                else:
                    if not covering_fw.get(edge.n_to.id, False) and dists_bw[edge.n_to.id] == -1 or \
                            dists_bw[edge.n_to.id] > dists_bw[current_node_b.id] + edge.get_weight():
                        dists_bw[edge.n_to.id] = dists_bw[
                            current_node_b.id] + edge.get_weight()
                        edge_to_bw.update({edge.n_to: edge})
                        queue_bw.update(edge.n_to, dists_bw[edge.n_to.id])
        pass

    # def calculate_async():
    #     t_forward = thr.Thread(target=search_f)
    #     t_backward = thr.Thread(target=search_b)
    #
    #     t_forward.run()
    #     t_backward.run()
    #
    # calc_thread = thr.Thread(target=calculate_async)
    # calc_thread.join()

    t_forward = thr.Thread(target=search_f)
    t_backward = thr.Thread(target=search_b)

    t_forward.start()
    t_backward.start()

    time_start = time.time()

    t_forward.join(timeout=0)
    t_backward.join(timeout=0)

    while not t_fw_done and not t_bw_done:
        pass

    if center is None:
        return -1, [], -1

    path_fw = list()
    current_node = center
    while current_node != node_from:
        if current_node == edge_to_fw[current_node].n_to:
            current_node = edge_to_fw[current_node].n_from
            path_fw.append(current_node)
        else:
            current_node = edge_to_fw[current_node].n_to
            path_fw.append(current_node)

    current_node = center
    path_bw = list()
    while current_node != node_to:
        if current_node == edge_to_bw[current_node].n_from:
            current_node = edge_to_bw[current_node].n_to
            path_bw.append(current_node)
        else:
            current_node = edge_to_bw[current_node].n_from
            path_bw.append(current_node)

    path = path_fw[::-1]
    path.append(center)
    path += path_bw

    time_end = time.time()

    return dists_fw[center.id] + dists_bw[center.id], [path
                                                       ], time_end - time_start
Exemple #3
0
def alt(graph, node_from, node_to, k=16):
    if not isinstance(graph, classes.Graph.Graph):
        raise IOError("Wrong graph type")
    if not isinstance(node_from, classes.Node.Node):
        raise IOError("Wrong node_from type")
    if not isinstance(node_to, classes.Node.Node):
        raise IOError("Wrong node_to type")

    def heuristic(nf, nt):
        result = -1
        for i in range(16):
            temp = abs(nt.dist_to_mark[i] - nf.dist_to_mark[i])
            if temp > result:
                result = temp
        return result

    time_start = time.time()

    # Инициализируем расстояния
    dists = {a: -1 for a in graph.nodes}
    dists[node_from.id] = 0
    # Init edges that leads to a node
    edges_to = dict()
    edges_to.update({node_from.id: []})
    # Init queue for BFS
    queue = PQ.PriorityQueueByDict()
    queue.update(node_from)

    is_node_done = dict()

    # Ищем расстояния до точек
    while not queue.empty():

        # Поиск минимального (по расстоянию) элемента
        current_node = queue.get()[0]

        if current_node == node_to:
            break

        is_node_done[current_node] = True

        # Считаем пути до следующих вершин
        # next_edges = [x for x in current_node.incidentEdges if x.n_from == current_node]
        # next_edges = [x for x in current_node.incidentEdges]
        for x in current_node.incidentEdges:
            # Refresh distances
            # if we haven't been to node
            if current_node == x.n_from:
                if not is_node_done.get(x.n_to, False) and dists[
                        x.n_to.id] == -1 or dists[x.n_to.id] > dists[
                            current_node.id] + x.get_weight():
                    # queue.append(x.n_to)
                    dists[x.n_to.id] = dists[current_node.id] + x.get_weight()
                    edges_to.update({x.n_to.id: [x]})
                    queue.update(x.n_to,
                                 dists[x.n_to.id] + heuristic(x.n_to, node_to))
            else:
                if not is_node_done.get(x.n_from, False) and dists[
                        x.n_from.id] == -1 or dists[x.n_from.id] > dists[
                            current_node.id] + x.get_weight():
                    # queue.append(x.n_to)
                    dists[
                        x.n_from.id] = dists[current_node.id] + x.get_weight()
                    edges_to.update({x.n_from.id: [x]})
                    queue.update(
                        x.n_from,
                        dists[x.n_from.id] + heuristic(x.n_from, node_to))

    # Итоговое расстояние и переменная для путей (might be more than one)
    length = dists[node_to.id]

    print('Dijkstra\'s main done in {} sec'.format(time.time() - time_start))

    # Если добраться невозможно
    if length == -1:
        return -1, [], -1

    # Searching for all paths
    paths = list()
    paths.append([])
    path_n = 0
    stacks = list()
    stack = [node_to]
    stacks.append(stack)
    count = 0
    while stacks:
        current_node = stacks[0].pop()
        paths[path_n].append(current_node)
        amount_of_ways_from = len(edges_to[current_node.id])
        if amount_of_ways_from > 0:
            if current_node == edges_to[current_node.id][0].n_to:
                stacks[0].append(edges_to[current_node.id][0].n_from)
            else:
                stacks[0].append(edges_to[current_node.id][0].n_to)

        else:
            stacks.pop(0)
            path_n += 1
            count += 1

    time_end = time.time()

    final_time = time_end - time_start
    print('Full Dijkstra done in {} sec'.format(final_time))

    for i in range(count):
        paths[i] = paths[i][::-1]

    return dists[node_from.id], paths, final_time
Exemple #4
0
def bidirectional_dijkstra_un(graph, node_from, node_to):
    if not isinstance(graph, classes.Graph.Graph):
        raise IOError("Wrong graph type")
    if not isinstance(node_from, classes.Node.Node):
        raise IOError("Wrong node_from type")
    if not isinstance(node_to, classes.Node.Node):
        raise IOError("Wrong node_to type")

    time_start = time.time()

    dists_fw = {a: -1 for a in graph.nodes}
    dists_fw[node_from.id] = 0

    dists_bw = {a: -1 for a in graph.nodes}
    dists_bw[node_to.id] = 0

    edge_to_fw = dict()
    edge_to_bw = dict()

    covering_fw = dict()
    covering_bw = dict()

    queue_fw = PQ.PriorityQueueByDict()
    queue_fw.update(node_from)
    queue_bw = PQ.PriorityQueueByDict()
    queue_bw.update(node_to)

    center = None
    centers_amount = 0

    while not queue_fw.empty() and not queue_bw.empty():

        # Forward step
        current_node = queue_fw.get()[0]
        covering_fw[current_node] = True

        if covering_bw.get(current_node, False):
            if center is None or dists_fw[current_node.id] + dists_bw[
                    current_node.id] < dists_fw[center.id] + dists_bw[
                        center.id]:
                center = current_node
            centers_amount += 1
            if centers_amount > 20:
                break

        # next_edges = [x for x in current_node.incidentEdges if x.n_from == current_node]
        for edge in current_node.incidentEdges:
            if current_node == edge.n_from:
                if not covering_fw.get(edge.n_to.id, False) and dists_fw[
                        edge.n_to.id] == -1 or dists_fw[
                            edge.n_to.id] > dists_fw[
                                current_node.id] + edge.get_weight():
                    dists_fw[edge.n_to.id] = dists_fw[
                        current_node.id] + edge.get_weight()
                    edge_to_fw.update({edge.n_to: edge})
                    queue_fw.update(edge.n_to, dists_fw[edge.n_to.id])
            else:
                if not covering_fw.get(edge.n_from.id, False) and dists_fw[
                        edge.n_from.id] == -1 or dists_fw[
                            edge.n_from.id] > dists_fw[
                                current_node.id] + edge.get_weight():
                    dists_fw[edge.n_from.id] = dists_fw[
                        current_node.id] + edge.get_weight()
                    edge_to_fw.update({edge.n_from: edge})
                    queue_fw.update(edge.n_from, dists_fw[edge.n_from.id])

        # Backward step
        current_node = queue_bw.get()[0]
        covering_bw[current_node] = True

        if covering_fw.get(current_node, False):
            if center is None or dists_fw[current_node.id] + dists_bw[
                    current_node.id] < dists_fw[center.id] + dists_bw[
                        center.id]:
                center = current_node
            centers_amount += 1
            if centers_amount > 20:
                break

        # next_edges = [x for x in current_node.incidentEdges if x.n_to == current_node]
        for edge in current_node.incidentEdges:
            if current_node == edge.n_to:
                if not covering_fw.get(edge.n_from.id, False) and dists_bw[
                        edge.n_from.id] == -1 or dists_bw[
                            edge.n_from.id] > dists_bw[
                                current_node.id] + edge.get_weight():
                    dists_bw[edge.n_from.id] = dists_bw[
                        current_node.id] + edge.get_weight()
                    edge_to_bw.update({edge.n_from: edge})
                    queue_bw.update(edge.n_from, dists_bw[edge.n_from.id])
            else:
                if not covering_fw.get(edge.n_to.id, False) and dists_bw[
                        edge.n_to.id] == -1 or dists_bw[
                            edge.n_to.id] > dists_bw[
                                current_node.id] + edge.get_weight():
                    dists_bw[edge.n_to.id] = dists_bw[
                        current_node.id] + edge.get_weight()
                    edge_to_bw.update({edge.n_to: edge})
                    queue_bw.update(edge.n_to, dists_bw[edge.n_to.id])
        pass

    if center is None:
        return -1, [], -1

    path_fw = list()
    current_node = center
    while current_node != node_from:
        if current_node == edge_to_fw[current_node].n_to:
            current_node = edge_to_fw[current_node].n_from
            path_fw.append(current_node)
        else:
            current_node = edge_to_fw[current_node].n_to
            path_fw.append(current_node)

    current_node = center
    path_bw = list()
    while current_node != node_to:
        if current_node == edge_to_bw[current_node].n_from:
            current_node = edge_to_bw[current_node].n_to
            path_bw.append(current_node)
        else:
            current_node = edge_to_bw[current_node].n_from
            path_bw.append(current_node)

    path = path_fw[::-1]
    path.append(center)
    path += path_bw

    time_end = time.time()

    return dists_fw[center.id] + dists_bw[center.id], [path
                                                       ], time_end - time_start
Exemple #5
0
def dijkstra_early_stop_way_un(graph, node_from, node_to):
    if not isinstance(graph, classes.Graph.Graph):
        raise IOError("Wrong graph type")
    if not isinstance(node_from, classes.Node.Node):
        raise IOError("Wrong node_from type")
    if not isinstance(node_to, classes.Node.Node):
        raise IOError("Wrong node_to type")

    time_start = time.time()

    # Инициализируем расстояния
    dists = {a: -1 for a in graph.nodes}
    is_node_done = {a: False for a in graph.nodes}
    dists[node_from.id] = 0
    # Init edges that leads to a node
    edges_to = dict()
    edges_to.update({node_from.id: []})
    # Init queue for BFS
    queue = PQ.PriorityQueueByDict()
    queue.update(node_from)

    # Ищем расстояния до точек
    while not queue.empty():

        # Поиск минимального (по расстоянию) элемента
        # minimum = -1
        # current_node = None
        # for i in queue:
        #     if minimum == -1 or dists[i.id] <= minimum:
        #         current_node = i
        #         minimum = dists[i.id]

        current_node = queue.get()[0]

        if current_node == node_to:
            break

        is_node_done[current_node] = True

        # Считаем пути до следующих вершин
        # next_edges = [x for x in current_node.incidentEdges]
        # next_edges = [x for x in current_node.incidentEdges]
        # queue.remove(current_node)
        for x in current_node.incidentEdges:
            # Refresh distances
            # if we haven't been to node
            if x.n_from == current_node:
                if not is_node_done[x.n_to.id] and dists[
                        x.n_to.id] == -1 or dists[x.n_to.id] > dists[
                            current_node.id] + x.get_weight():
                    dists[x.n_to.id] = dists[current_node.id] + x.get_weight()
                    queue.update(x.n_to, dists[x.n_to.id])
                    edges_to.update({x.n_to.id: [x]})
            else:
                if not is_node_done[x.n_from.id] and dists[
                        x.n_from.id] == -1 or dists[x.n_from.id] > dists[
                            current_node.id] + x.get_weight():
                    dists[
                        x.n_from.id] = dists[current_node.id] + x.get_weight()
                    queue.update(x.n_from, dists[x.n_from.id])
                    edges_to.update({x.n_from.id: [x]})

    # Итоговое расстояние и переменная для путей (might be more than one)
    length = dists[node_to.id]

    print('Dijkstra\'s main done in {} sec'.format(time.time() - time_start))

    final_time = -1

    # Если добраться невозможно
    if length == -1:
        return -1, [], final_time

    # Searching for all paths
    paths = list()
    paths.append([])
    path_n = 0
    stacks = list()
    stack = [node_to]
    stacks.append(stack)
    count = 0
    while stacks:
        current_node = stacks[0].pop()
        paths[path_n].append(current_node)
        amount_of_ways_from = len(edges_to[current_node.id])
        if amount_of_ways_from > 0:
            # for i in range(amount_of_ways_from - 1):
            #     copy = stacks[0].copy()
            #     copy.append(edges_to[current_node.id][i + 1].n_from)
            #     stacks.append(copy)
            #     copy = paths[path_n].copy()
            #     # copy.append(edges_to[current_node][i + 1].n_from)
            #     paths.append(copy)
            if current_node == edges_to[current_node.id][0].n_to:
                stacks[0].append(edges_to[current_node.id][0].n_from)
            else:
                stacks[0].append(edges_to[current_node.id][0].n_to)

        else:
            stacks.pop(0)
            path_n += 1
            count += 1

    time_end = time.time()

    final_time = time_end - time_start

    print('Full Dijkstra done in {} sec'.format(final_time))

    for i in range(count):
        paths[i] = paths[i][::-1]

    return dists[node_from.id], paths, final_time
Exemple #6
0
def alt_un_sc(graph, node_from, node_to, k = 16):
    if not isinstance(graph, classes.Graph.Graph):
        raise IOError("Wrong graph type")
    if not isinstance(node_from, classes.Node.Node):
        raise IOError("Wrong node_from type")
    if not isinstance(node_to, classes.Node.Node):
        raise IOError("Wrong node_to type")

    def heuristic(nf, nt):
        result = -1
        for i in range(16):
            temp = abs(nt.dist_to_mark[i] - nf.dist_to_mark[i])
            if temp > result:
                result = temp
        return result

    time_start = time.time()

    # Инициализируем расстояния
    dists = {a: -1 for a in graph.nodes}
    is_node_done = {a: False for a in graph.nodes}
    dists[node_from.id] = 0
    # Init edges that leads to a node
    edges_to = dict()
    edges_to.update({node_from.id: []})

    node_from_s1 = node_from
    node_from_s2 = node_from
    # Init queue for BFS
    queue = PQ.PriorityQueueByDict()
    # Get out of a node_from shortcut if it needs
    if node_from.hidden_in:
        try:
            node_from_s1, weight_s1 = node_from.hidden_in.unpack_until(node_from, reverse=False)
            node_from_s1 = node_from_s1[0]
            node_from_s2, weight_s2 = node_from.hidden_in.unpack_until(node_from, reverse=True)
            node_from_s2 = node_from_s2[0]

            queue.update(node_from_s1, weight_s1)
            queue.update(node_from_s2, weight_s2)
        except IndexError:
            node_from_s1 = node_from.hidden_in.n_from
            node_from_s2 = node_from.hidden_in.n_to
            queue.update(node_from_s1)
            queue.update(node_from_s2)
            print('Warning! Not the whole path unpacked cause of Index Error')

    else:
        queue.update(node_from)

    last_sc_node = None

    # May be None
    last_sc = None

    # Ищем расстояния до точек
    while queue:

        # Поиск минимального (по расстоянию) элемента
        current_node = queue.get()[0]

        if current_node == node_to:
            last_sc_node = current_node
            break

        is_node_done[current_node] = True

        found = False

        for x in current_node.incidentShortcuts:

            # if x is a shortcut and it contains the node_to then search only by edges
            if isinstance(x, classes.Edge.Shortcut):
                if x.is_containing_node(node_to):
                    last_sc_node = current_node
                    last_sc = x
                    found = True
                    break

            # Refresh distances
            # if we haven't been to node
            if current_node == x.n_from:
                if not is_node_done.get(x.n_to, False) and dists[x.n_to.id] == -1 or dists[x.n_to.id] > dists[current_node.id] + x.get_weight():
                    # queue.append(x.n_to)
                    dists[x.n_to.id] = dists[current_node.id] + x.get_weight()
                    edges_to.update({x.n_to.id: [x]})
                    queue.update(x.n_to, dists[x.n_to.id] + heuristic(x.n_to, node_to))
            else:
                if not is_node_done.get(x.n_from, False) and dists[x.n_from.id] == -1 or dists[x.n_from.id] > dists[current_node.id] + x.get_weight():
                    # queue.append(x.n_to)
                    dists[x.n_from.id] = dists[current_node.id] + x.get_weight()
                    edges_to.update({x.n_from.id: [x]})
                    queue.update(x.n_from, dists[x.n_from.id] + heuristic(x.n_from, node_to))

        if found:
            break

    # Итоговое расстояние и переменная для путей (might be more than one)
    if last_sc_node is None:
        last_sc_node = node_to
    length = dists[last_sc_node.id]

    print('Dijkstra\'s main done in {} sec'.format(time.time() - time_start))

    # Если добраться невозможно
    if length == -1:
        return -1, [], -1

    path = list()
    path.append(last_sc_node)
    current_node = last_sc_node
    side_node = None
    while current_node != node_from and current_node != node_from_s1 and current_node != node_from_s2:
        sc = edges_to[current_node.id][0]

        # Set next 'current'
        if current_node == sc.n_from:
            current_node = sc.n_to
        else:
            current_node = sc.n_from

        # Build the path
        if isinstance(sc, classes.Edge.Shortcut):
            if current_node == sc.n_to:
                path += sc.unpack()[:-1:1]
            else:
                path += sc.unpack()[-1::-1]
        else:
            if current_node == sc.n_from:
                path.append(sc.n_from)
            else:
                path.append(sc.n_to)

        if current_node == node_from_s1:
            side_node = node_from_s1
        elif current_node == node_from_s2:
            side_node = node_from_s2

    # DONT FORGET TO UNPACK LAST
    if last_sc is not None:
        if last_sc_node == last_sc.n_from:
            try:
                path_l, weight_l = last_sc.unpack_until(node_to)
                path = path_l + path
                length += weight_l
            except IndexError:
                print('Warning! Not the whole path unpacked cause of Index Error')

        else:
            try:
                path_l, weight_l = last_sc.unpack_until(node_to, reverse=True)
                path = path_l[::-1] + path
                length += weight_l
            except IndexError:
                print('Warning! Not the whole path unpacked cause of Index Error')

    # DONT FORGET TO UNPACK FIRST
    if node_from != node_from_s1 and node_from != node_from_s2:
        nodes_s1, w1 = node_from.hidden_in.unpack_until(node_from)
        nodes_s2, w2 = node_from.hidden_in.unpack_until(node_from, reverse=True)

        if side_node == node_from_s1:
            length += w1
            path += nodes_s1[::-1]
        elif node_from == node_from_s2:
            path += nodes_s2[::-1]
            length += w2

    time_end = time.time()

    final_time = time_end - time_start
    print('Full Dijkstra done in {} sec'.format(final_time))

    path = path[::-1]

    return dists[node_from.id], [path], final_time
Exemple #7
0
def bidirectional_astar(graph, node_from, node_to):
    if not isinstance(graph, classes.Graph.Graph):
        raise IOError("Wrong graph type")
    if not isinstance(node_from, classes.Node.Node):
        raise IOError("Wrong node_from type")
    if not isinstance(node_to, classes.Node.Node):
        raise IOError("Wrong node_to type")

    def heuristic(nf, nt):
        result = math.sqrt(
            math.pow((nf.x - nt.x), 2) +
            math.pow((nf.y - nt.y), 2)
        )
        return result

    time_start = time.time()

    dists_fw = {a: -1 for a in graph.nodes}
    dists_fw[node_from.id] = 0

    dists_bw = {a: -1 for a in graph.nodes}
    dists_bw[node_to.id] = 0

    edge_to_fw = dict()
    edge_to_bw = dict()

    covering_fw = dict()
    covering_bw = dict()

    queue_fw = PQ.PriorityQueueByDict()
    queue_fw.update(node_from)
    queue_bw = PQ.PriorityQueueByDict()
    queue_bw.update(node_to)

    center = None

    while not queue_fw.empty() and not queue_bw.empty():

        # Forward step
        current_node = queue_fw.get()[0]
        covering_fw.update({current_node: True})

        if covering_bw.get(current_node, False):
            center = current_node
            break

        next_edges = [x for x in current_node.incidentEdges if x.n_from == current_node]
        for edge in next_edges:
            if dists_fw[edge.n_to.id] == -1 or dists_fw[edge.n_to.id] > dists_fw[current_node.id] + edge.get_weight():
                dists_fw[edge.n_to.id] = dists_fw[current_node.id] + edge.get_weight()
                edge_to_fw.update({edge.n_to: edge})
                queue_fw.update(edge.n_to, dists_fw[edge.n_to.id] + heuristic(edge.n_to, node_to))


        # Backward step
        current_node = queue_bw.get()[0]
        covering_bw.update({current_node: True})

        if covering_fw.get(current_node, False):
            center = current_node
            break

        next_edges = [x for x in current_node.incidentEdges if x.n_to == current_node]
        for edge in next_edges:
            if dists_bw[edge.n_from.id] == -1 or dists_bw[edge.n_from.id] > dists_bw[current_node.id] + edge.get_weight():
                dists_bw[edge.n_from.id] = dists_bw[current_node.id] + edge.get_weight()
                edge_to_bw.update({edge.n_from: edge})
                queue_bw.update(edge.n_from, dists_bw[edge.n_from.id] + heuristic(edge.n_from, node_from))
        pass

    if center is None:
        return -1, [], -1

    path_fw = list()
    current_node = center
    while current_node != node_from:
        current_node = edge_to_fw[current_node].n_from
        path_fw.append(current_node)

    current_node = center
    path_bw = list()
    while current_node != node_to:
        current_node = edge_to_bw[current_node].n_to
        path_bw.append(current_node)

    path = path_fw[::-1]
    path.append(center)
    path += path_bw

    time_end = time.time()

    return dists_fw[center.id] + dists_bw[center.id], [path], time_end - time_start