Пример #1
0
def johnson(g: Graph):
    g.vertices["s"] = Vertex("s")
    g.neighbors["s"] = []
    for vertex in g.vertices:
        g.edges.append(Edge("s", vertex, 0))
        g.neighbors["s"] += [(vertex, 0)]
    bf = bellman_ford(g, "s")
    if not bf:
        print("Ujemny cykl")
        return
    distances_b_f, _ = bf
    for edge in g.edges:
        edge.weight = edge.weight + \
                      distances_b_f[edge.start] \
                      - distances_b_f[edge.end]
    s_edges = [edge for edge in g.edges
               if edge.start == "s"]
    for edge in s_edges:
        g.edges.remove(edge)
    g.vertices.pop("s")
    g.neighbors.pop("s")
    distances = {}
    path = {}
    for vertex in g.vertices:
        distances[vertex], path[vertex] = \
            dijkstra(g, vertex)
    for v_1 in g.vertices:
        for v_2 in g.vertices:
            distances[v_1][v_2] += \
                distances_b_f[v_2] - distances_b_f[v_1]
    for edge in g.edges:
        edge.weight = edge.weight + \
                      distances_b_f[edge.start] \
                      - distances_b_f[edge.end]
    return distances, path
Пример #2
0
def floyd_warshall(g: Graph):
    """
    Funkcja algorytmu Floyda-Warshalla

        :param g: Obiekt klasy Graph, badany graf
        :type g: Graph
        :return: Najkrótsze ścieżki między wszystkimi wierzchołkami oraz listę poprzedników

    Zwracana jest krotka:
        (distances, path)
    zawierająca macierz odległości między wszystkimi wierzchołkami oraz macierz poprzedników
    oprócz zwracania wyników, algorytm zapisuje wyniki do obiektów wierzchołków w grafie (klasa Vertex)
    """

    # sprawdzamy czy podany graf nie zawiera ujemnych cykli, przechodzimy przez wszystkie wierzchołki dlatego,
    # że dla wierzchołka izolowanego lub takiego, który nie ma krawędzi wychodzących algorytm bellmana_forda
    # nie zwróci False, tylko dla każdego wierzchołka odległość będzie inf
    for vertex in g.vertices:
        # code może być wartością kodu błędu (-1 lub -2) lub też poprawnym wynikiem algorytmu
        code = bellman_ford(g, vertex)
        # -1 oznacza ujemny cykl wtedy wychodzimy z funkcji
        if code == -1:
            print("Ujemny cykl")
            return False
        # -2 oznacza że wierzchołek nie zawiera krawędzi wychodzących więc nie można stwierdzić czy występuje
        # ujemny cykl, więc przechodzimy do następnego
        elif code == -2:
            continue
        # jeśli nie nastąpił żaden błąd to graf nie zawiera ujemnych cykli - można przejść do algorytmu
        else:
            break
    # wyznaczamy wielkość macierzy
    n = len(g.vertices)
    # główna pętla algorytmu
    for k in range(n):
        for i in range(n):
            for j in range(n):
                if g.distance_matrix[i][
                        j] > g.distance_matrix[i][k] + g.distance_matrix[k][j]:
                    g.distance_matrix[i][
                        j] = g.distance_matrix[i][k] + g.distance_matrix[k][j]
                    g.path_matrix[i][j] = g.path_matrix[i][k]

    # przypisujemy wyniki do grafu
    for vertex in g.vertices:
        g.vertices[vertex].distance = {
            v: g.distance_matrix[g.indexes[vertex]][g.indexes[v]]
            for v in g.vertices
        }
        g.vertices[vertex].path = {
            v: g.path_matrix[g.indexes[vertex]][g.indexes[v]]
            for v in g.vertices
        }

    # zwracamy krotkę zawierającą macierz z odległościami oraz macierz poprzedników
    return g.distance_matrix, g.path_matrix
Пример #3
0
def matrix_multiply(g: Graph):
    for vertex in g.vertices:
        code = bellman_ford(g, vertex)
        if code == -1:
            print("Ujemny cykl")
            return False
        elif code == -2:
            continue
        else:
            break

    n = len(g.vertices)
    distance = deepcopy(g.distance_matrix)

    for _ in range(n - 2):
        old_distance = deepcopy(distance)
        for i in range(n):
            for j in range(n):
                distance[i][j] = inf
                for k in range(n):
                    distance[i][j] = min(
                        distance[i][j],
                        old_distance[i][k] + g.distance_matrix[k][j])

    # wyniki przypisujemy do grafu
    g.distance_matrix = deepcopy(distance)

    return distance
Пример #4
0
def generate(vertices_number, edges_number):
    vertices = []
    for i in range(vertices_number):
        name = ""
        first_letter = int(i / 26)
        second_letter = i % 26
        if first_letter != 0:
            first_letter = chr(97 + first_letter - 1)
            name += first_letter
        second_letter = chr(97 + second_letter)
        name += second_letter
        vertices.append(Vertex(name))
    edges = []
    graph_edges = []
    available_edges = []
    for v_start in vertices:
        for v_end in vertices:
            if v_start == v_end:
                continue
            available_edges.append((v_start, v_end))
    for i in range(edges_number):
        random_edge = random.choice(available_edges)
        edges.append(random_edge)
        available_edges.remove(random_edge)
    for edge in edges:
        start_vertex, end_vertex = edge
        weight = random.randint(0, 10)
        graph_edges.append(Edge(start_vertex.name, end_vertex.name, weight))
    graph_edges.sort(key=operator.attrgetter('start', 'end'))
    graph = Graph(vertices={vertex.name: vertex
                            for vertex in vertices},
                  edges=graph_edges)
    return graph
Пример #5
0
def faster_matrix_multiply(g: Graph):
    """
    Funkcja algorytmu z iloczynem odległości - wersja ulepszona
        :param g: Obiekt klasy Graph, graf na którym wykonujemy algorytm
        :type g: Graph
        :return: Najkrótsze ścieżki między wszystkimi wierzchołkami w postaci macierzy

    Zwracana jest macierz z odległościami, macierz jest listą list
    oprócz zwracania wyników, algorytm przypisuje wyniki do obiektu macierzy w grafie (distance_matrix)
    """
    # dodatkowe sprawdzanie czy graf nie zawiera ujemnego cyklu
    for vertex in g.vertices:
        code = bellman_ford(g, vertex)
        if code == -1:
            print("Ujemny cykl")
            return False
        elif code == -2:
            continue
        else:
            break

    # wyznaczamy n - wielkość macierzy
    n = len(g.vertices)
    # wykonujemy tak zwaną głęboką kopię bazowego grafu
    distance = deepcopy(g.distance_matrix)

    # wykonujemy główne działanie algorytmu log(V) razy
    m = 1
    while n - 1 > m:
        # działamy na macierzy distance ale potrzebować będziemy starych wartości więc tworzymy kopię
        old_distance = deepcopy(distance)
        for i in range(n):
            for j in range(n):
                distance[i][j] = inf
                for k in range(n):
                    distance[i][j] = min(
                        distance[i][j],
                        old_distance[i][k] + old_distance[k][j])
        m = 2 * m

    # wyniki przypisujemy do grafu
    g.distance_matrix = deepcopy(distance)

    return distance
from described.bellman_ford import bellman_ford, \
    print_bellman_ford
from described.graph import Edge, Graph, Vertex

G = Graph(vertices={
    "a": Vertex("a"),
    "b": Vertex("b"),
    "c": Vertex("c"),
    "d": Vertex("d"),
    "e": Vertex("e")
},
          edges=[
              Edge("a", "b", 4),
              Edge("a", "c", 5),
              Edge("b", "a", -3),
              Edge("b", "c", -4),
              Edge("c", "d", 7),
              Edge("d", "b", 9),
              Edge("d", "e", 10),
              Edge("e", "b", 8)
          ])

print_bellman_ford(G, "e", bellman_ford(G, "e"))
Пример #7
0
from described.dijkstra import dijkstra, print_dijkstra
from described.graph import Edge, Graph, Vertex

G = Graph(vertices={
    "a": Vertex("a"),
    "b": Vertex("b"),
    "c": Vertex("c"),
    "d": Vertex("d"),
    "e": Vertex("e"),
    "f": Vertex("f")
},
          edges=[
              Edge("a", "b", 7),
              Edge("a", "c", 9),
              Edge("a", "f", 14),
              Edge("b", "c", 10),
              Edge("b", "d", 15),
              Edge("c", "d", 11),
              Edge("c", "f", 2),
              Edge("d", "e", 6),
              Edge("e", "f", 9)
          ])

dijkstra(G, "a")
print_dijkstra(G, "a")
from described.bellman_ford import bellman_ford, print_bellman_ford
from described.graph import Edge, Graph, Vertex

G = Graph(vertices={
    "a": Vertex("a"),
    "b": Vertex("b"),
    "c": Vertex("c"),
    "d": Vertex("d"),
    "e": Vertex("e")
},
          edges=[
              Edge("a", "c", 10),
              Edge("a", "b", 3),
              Edge("b", "a", 2),
              Edge("c", "d", -9),
              Edge("d", "e", 7),
              Edge("e", "a", 1),
              Edge("e", "c", -5)
          ])

print_bellman_ford(G, "a", bellman_ford(G, "a"))
def johnson(g: Graph):
    """
    Funkcja algorytmu Johnsona

        :param g: Obiekt klasy Graph, graf na którym wykonujemy algorytm
        :type g: Graph
        :return: Najkrótsze ścieżki między wszystkimi wierzchołkami oraz listę poprzedników

    Zwracana jest krotka:
        (distances, path)
    zawierająca odległości między wszystkimi wierzchołkami oraz macierz poprzedników
    oprócz zwracania wyników, algorytm przypisuje wyniki do obiektów wierzchołków grafu (klasa Vertex)
    """

    # sprawdzanie na wstępie czy graf zawiera ujemny cykl, nadmiarowe - usunięcie przyśpieszy w pewnym stopniu algorytm
    # przechodzimy przez wszystkie wierzchołki dlatego, że dla wierzchołka izolowanego lub takiego, który nie ma
    # krawędzi wychodzących algorytm bellmana_forda nie zwróci False, tylko dla każdego wierzchołka odległość będzie inf
    for vertex in g.vertices:
        # code może być wartością kodu błędu (-1 lub -2) lub też poprawnym wynikiem algorytmu
        code = bellman_ford(g, vertex)
        # -1 oznacza ujemny cykl wtedy wychodzimy z funkcji
        if code == -1:
            print("Ujemny cykl")
            return False
        # -2 oznacza że wierzchołek nie zawiera krawędzi wychodzących więc nie można stwierdzić czy występuje
        # ujemny cykl, więc przechodzimy do następnego
        elif code == -2:
            continue
        # jeśli nie nastąpił żaden błąd to graf nie zawiera ujemnych cykli - można przejść do algorytmu
        else:
            break

    # tworzymy pomocniczy wierzchołek "-s" oraz krawędzie z wierzchołka "-s" do każdego innego w grafie
    g.vertices["-s"] = Vertex("-s")
    g.neighbors["-s"] = []
    for vertex in g.vertices:
        g.edges.append(Edge("-s", vertex, 0))
        g.neighbors["-s"] += [(vertex, 0)]

    # po utworzeniu wierzchołka "-s" obliczamy odległości z wierzchołka "-s" do pozostałych wierzchołków
    # dodatkowo sprawdzamy czy graf nie zawiera ujemnych cykli, jeśli tak to wychodzimy z funkcji
    result = bellman_ford(g, "-s")
    # jeśli algorytm Bellmana-Forda zwróci False, również algorytm Johnsona zwraca False - ujemny cykl
    if not result:
        return False
    distances_b_f, _ = result
    # zmieniamy wagi dla każdej krawędzi uwzględniając odległości wyliczone przez algorytm Bellmana-Forda
    # przez co likwidujemy ujemne wagi i umożliwiamy użycie algorytmu Dijkstry
    for edge in g.edges:
        edge.weight = edge.weight + distances_b_f[edge.start] - distances_b_f[edge.end]
    # usuwamy wierzchołek "-s" oraz wszystkie krawędzie wyprowadzone z tego wierzchołka
    s_edges = [edge for edge in g.edges if edge.start == "-s"]
    for edge in s_edges:
        g.edges.remove(edge)
    g.vertices.pop("-s")
    g.neighbors.pop("-s")
    # wyliczamy algorytmem Dijkstry odległości i poprzedniki dla każdego wierzchołka
    distances = {}
    path = {}
    for vertex in g.vertices:
        distances[vertex], path[vertex] = dijkstra(g, vertex)
    # ponownie zmieniamy wagi dla każdej krawędzi oraz poprawiamy odległości uwzględniając poprzednio zmienione
    # ujemne wagi
    for v_1 in g.vertices:
        for v_2 in g.vertices:
            distances[v_1][v_2] += distances_b_f[v_2] - distances_b_f[v_1]
    for edge in g.edges:
        edge.weight = edge.weight + distances_b_f[edge.start] - distances_b_f[edge.end]

    # zwracamy krotkę zawierającą odległości oraz macierz poprzedników
    return distances, path
from described.graph import Edge, Graph, Vertex
from described.matrix_multiply\
    import faster_matrix_multiply

G = Graph(vertices=["a", "b", "c", "d", "e"],
          edges=[
              Edge("a", "c", -3),
              Edge("a", "d", 2),
              Edge("b", "a", -5),
              Edge("b", "c", 4),
              Edge("c", "d", 6),
              Edge("d", "e", 1),
              Edge("e", "b", 9),
              Edge("e", "c", -4)
          ])

for line in faster_matrix_multiply(G):
    print(line)