Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Шелест ЛР / ПиАГМ2ДопЗадание

.docx
Скачиваний:
0
Добавлен:
03.06.2024
Размер:
292.02 Кб
Скачать

Дополнительное задание: доработать алгоритм с учетом взвешенности графа. При сжатии вершины, новое соединение имеет вес равный сумме смежных ребер для удаляемой вершины, если данной связи не существовало ранее. Иначе выбирается минимум из существующей связи и суммы смежных ребер для удаляемой вершины. Построить график зависимости отношения полученного в результате сжатия количества вершин к исходному количеству вершин от размера решетки. В результате должен быть код с комментариями, скриншот исходного графа и результата сжатия. График по отношению количества вершин.

Функция гомеоморфного сжатия графа дополнена для работы с весами ребер.

Листинг 1 – Функция гомеоморфного сжатия

def homeomorphic_compression(G):

# Создание копии графа, чтобы не изменять исходный граф

compressed = G.copy()

# Флаг изменений в графе

changed = True

while changed:

changed = False

# Перебор всех вершин в графе

for node in list(compressed.nodes):

# Проверка, является ли степень вершины равна 2

if compressed.degree(node) == 2:

# Получение соседей вершины

neighbors = list(compressed.neighbors(node))

neighbor1, neighbor2 = neighbors[0], neighbors[1]

# Получение весов смежных ребер

edge_weight_node_to_neighbor1 = compressed[node][neighbor1]['weight']

edge_weight_node_to_neighbor2 = compressed[node][neighbor2]['weight']

# Проверка, есть ли ребро между соседями

if compressed.has_edge(neighbor1, neighbor2):

# Если ребро есть, то его вес равен минимуму из суммы весов смежных ребер и веса существующего ребра

edge_weight = min((edge_weight_node_to_neighbor1 + edge_weight_node_to_neighbor2), compressed[neighbor1][neighbor2]['weight'])

compressed[neighbor1][neighbor2]['weight'] = edge_weight

else:

# Если ребра между соседями нет, оно добавляется, вес равен сумме смежных ребер

edge_weight = edge_weight_node_to_neighbor1 + edge_weight_node_to_neighbor2

compressed.add_edge(neighbor1, neighbor2, weight = edge_weight)

# Удаление вершины из графа

compressed.remove_node(node)

# Фиксация изменения в графе

changed = True

break # Начало цикла заново, так как граф был изменен во время итерации

# Возврат сжатого графа

return compressed

Написана функция для добавления случайных весов ребрам.

Листинг 2 – Функция для добавления случайных весов ребрам

def add_random_weights(G):

# Цикл по всем ребрам

for edge in G.edges():

# Генерация веса между 1 и 10

weight = np.random.randint(low=1, high=10)

# Добавление веса ребру

G.edges[edge]['weight'] = weight

# Возврат взвешенного графа

return G

Построен график зависимости отношения количества ребер графа после сжатия к исходному от размера решетки (Рисунок 1).

Рисунок 1 – График зависимости

Листинг 3 – Построение графика

# Диапазон значений M для построения решетки M^2 на M^2

M_values = np.arange(4, 13, 1)

# Пустые массивы для размера решетки и отношения

x = []

y = []

# Цикл для измерения среднего времени выполнения сжатия для каждого значения M

for M in M_values:

# Получение матрицы смежности

matrix = create_adjacency_matrix(M)

# Создание графа

G = nx.Graph(matrix)

# Выполнение гомеоморфного сжатия

compressed_G = homeomorphic_compression(G)

# Получение количества вершин в сжатом и исходном графах

n_nodes_compressed = compressed_G.number_of_nodes()

n_nodes = G.number_of_nodes()

# Занесение размера решетки и отношения в массивы x и y соответственно

x.append(M**2)

y.append(n_nodes_compressed/n_nodes)

# Построение графика

plt.figure(figsize=(10, 6))

plt.plot(x, y, marker='o')

plt.xticks(x)

plt.yticks(y)

plt.title('Зависимость отношения количества вершин к размеру решетки')

plt.xlabel('Размер решетки (M**2)')

plt.ylabel('Отношение количества вершин после сжатия к исходному')

plt.grid(True)

plt.show()

Провал на графике при размере решетки 25 связан с тем, что при размере решетки 16 и 25 в исходном графе количество вершин 6 и 10 соответственно, а в сжатых 2 вершины (Рисунок 2 – 4).

Рисунок 2 – Размер решетки 16

Рисунок 3 – Размер решетки 25

Рисунок 4 – Размер решетки 36

Листинг 4 – Визуализация графов

# Задание значения M

M = 6

# Получение матрицы смежности

matrix = create_adjacency_matrix(M)

# Создание графа

G = nx.Graph(matrix)

# Получение позиций вершин для визуализации

positions = get_nodes_postitions(G)

# Визуализация исходного графа

draw_graph(G, positions, 'Исходный граф')

# Добавление случайных весов ребрам

G = add_random_weights(G)

# Визуализация взвешенного графа

draw_weighted_graph(G, positions, "Граф со случайными весами")

# Выполнение гомеоморфного сжатия

compressed_G = homeomorphic_compression(G)

# Визуализация сжатого графа

draw_weighted_graph(compressed_G, nx.spectral_layout(G), "Сжатый граф")

Листинг 5 – Полный код программы

import networkx as nx

import matplotlib.pyplot as plt

import numpy as np

# Фиксация рандома для воспроизводимости результатов

np.random.seed(2)

# Функция для создания матрицы смежности графа правильной шестиугольной решетки

def create_adjacency_matrix(M):

# Создание нулевой квадратной матрицы Matrix размера M^2 на M^2

Matrix = np.zeros((M**2, M**2))

# Создание ребер между вершинами

for V in range(M**2):

R = V // M # Вычисление номера строки

C = V % M # Вычисление номера столбца

# Если вершина удовлетворяет условиям для создания ребер

if (R % 4 == 0 and C % 2 == 1) or (R % 4 == 2 and C % 2 == 0):

# Добавление ребер с верхними и нижними вершинами

if R > 0:

Matrix[V][V - M] = Matrix[V - M][V] = 1 # Ребро с верхней вершиной

if R < (M - 1) and C < (M - 1):

Matrix[V][V + M + 1] = Matrix[V + M + 1][V] = 1 # Ребро с нижней правой вершиной

if R < (M - 1) and C > 0:

Matrix[V][V + M - 1] = Matrix[V + M - 1][V] = 1 # Ребро с нижней левой вершиной

# Удаление лишних вершин

row_sums = np.sum(Matrix, axis=1) # Вычисление суммы по строкам

while np.any(row_sums < 2):

index = np.argmin(row_sums) # Индекс строки с минимальной суммой

Matrix = np.delete(Matrix, index, axis=0) # Удаление строки

Matrix = np.delete(Matrix, index, axis=1) # Удаление столбца

row_sums = np.sum(Matrix, axis=1) # Обновление суммы по строкам

return Matrix

def homeomorphic_compression(G):

# Создание копии графа, чтобы не изменять исходный граф

compressed = G.copy()

# Флаг изменений в графе

changed = True

while changed:

changed = False

# Перебор всех вершин в графе

for node in list(compressed.nodes):

# Проверка, является ли степень вершины равна 2

if compressed.degree(node) == 2:

# Получение соседей вершины

neighbors = list(compressed.neighbors(node))

neighbor1, neighbor2 = neighbors[0], neighbors[1]

# Получение весов смежных ребер

edge_weight_node_to_neighbor1 = compressed[node][neighbor1]['weight']

edge_weight_node_to_neighbor2 = compressed[node][neighbor2]['weight']

# Проверка, есть ли ребро между соседями

if compressed.has_edge(neighbor1, neighbor2):

# Если ребро есть, то его вес равен минимуму из суммы весов смежных ребер и веса существующего ребра

edge_weight = min((edge_weight_node_to_neighbor1 + edge_weight_node_to_neighbor2), compressed[neighbor1][neighbor2]['weight'])

compressed[neighbor1][neighbor2]['weight'] = edge_weight

else:

# Если ребра между соседями нет, оно добавляется, вес равен сумме смежных ребер

edge_weight = edge_weight_node_to_neighbor1 + edge_weight_node_to_neighbor2

compressed.add_edge(neighbor1, neighbor2, weight = edge_weight)

# Удаление вершины из графа

compressed.remove_node(node)

# Фиксация изменения в графе

changed = True

break # Начало цикла заново, так как граф был изменен во время итерации

# Возврат сжатого графа

return compressed

# Функция для генерации расположения вершин

def get_nodes_postitions(G):

pos = nx.kamada_kawai_layout(G)

return pos

# Функция для визуализации графа

def draw_graph(G, positions, title):

nx.draw(G, pos = positions, with_labels=True, node_color='lightblue', edge_color='gray', node_size=500)

plt.title(title)

plt.show()

# Функция для добавления случайных весов

def add_random_weights(G):

# Цикл по всем ребрам

for edge in G.edges():

# Генерация веса между 1 и 10

weight = np.random.randint(low=1, high=10)

# Добавление веса ребру

G.edges[edge]['weight'] = weight

# Возврат взвешенного графа

return G

# Функция для визуализации взвешенного графа

def draw_weighted_graph(G, positions, title):

edge_labels = nx.get_edge_attributes(G, 'weight')

nx.draw(G, pos=positions, with_labels=True, node_color='lightblue', edge_color='gray', node_size=500)

nx.draw_networkx_edge_labels(G, positions, edge_labels=edge_labels)

plt.title(title)

plt.show()

# Задание значения M

M = 6

# Получение матрицы смежности

matrix = create_adjacency_matrix(M)

# Создание графа

G = nx.Graph(matrix)

# Получение позиций вершин для визуализации

positions = get_nodes_postitions(G)

# Визуализация исходного графа

draw_graph(G, positions, 'Исходный граф')

# Добавление случайных весов ребрам

G = add_random_weights(G)

# Визуализация взвешенного графа

draw_weighted_graph(G, positions, "Граф со случайными весами")

# Выполнение гомеоморфного сжатия

compressed_G = homeomorphic_compression(G)

# Визуализация сжатого графа

draw_weighted_graph(compressed_G, nx.spectral_layout(G), "Сжатый граф")

# Диапазон значений M для построения решетки M^2 на M^2

M_values = np.arange(4, 13, 1)

# Пустые массивы для размера решетки и отношения

x = []

y = []

# Цикл для измерения среднего времени выполнения сжатия для каждого значения M

for M in M_values:

# Получение матрицы смежности

matrix = create_adjacency_matrix(M)

# Создание графа

G = nx.Graph(matrix)

# Выполнение гомеоморфного сжатия

compressed_G = homeomorphic_compression(G)

# Получение количества вершин в сжатом и исходном графах

n_nodes_compressed = compressed_G.number_of_nodes()

n_nodes = G.number_of_nodes()

# Занесение размера решетки и отношения в массивы x и y соответственно

x.append(M**2)

y.append(n_nodes_compressed/n_nodes)

# Построение графика

plt.figure(figsize=(10, 6))

plt.plot(x, y, marker='o')

plt.xticks(x)

plt.yticks(y)

plt.title('Зависимость отношения количества вершин к размеру решетки')

plt.xlabel('Размер решетки (M**2)')

plt.ylabel('Отношение количества вершин после сжатия к исходному')

plt.grid(True)

plt.show()

Соседние файлы в папке Шелест ЛР