优秀的编程知识分享平台

网站首页 > 技术文章 正文

GPT4o AI编程帮你写链路表转拓扑代码,检测环和重复链路,断环功能

nanyue 2024-08-05 20:11:59 技术文章 7 ℃

#头条创作挑战赛##python##AI编程助手##GPT4o到底可以干些啥#

更新:增加断环的节点优化建议。

本代码实现EXCEL XLSX格式的微波链路转换成拓扑图。并自动检测成环链路和重复链路,说明一下,程序完全是与GPT4o对话修改写成,这个AI写python代码相当强大,有点基础就可以实现相当复杂的功能,代码注释让AI可劲写,AI注释写的非常详细:

输入在E:\develop\save\links.xlsx文件,文件宏列标题只要含有SITE A和SITE B两列即可。

举例的数据输入格式如下:

LINK

SITE A

SITE B

BA

B

A

FC

F

C

EB

E

B

MD

M

D

HD

H

D

LA

L

A

GD

G

D

CA

C

A

IF

I

F

DA

D

A

KJ

K

J

JG

J

G

XY

X

Y

ffA

ff

A

hhC

hh

C

AK

A

K

DA

D

A

KD

K

D

EL

E

L

IA

I

A

结果输出output.txt的检测结果,

Duplicate Links Count: 1

Duplicate Links: [('D', 'A')]

Cycle Count: 3

Cycles: [['B', 'A', 'L', 'E', 'B'], ['A', 'C', 'F', 'I', 'A'], ['D', 'G', 'J', 'K', 'D']]

输出的拓扑图:graph_1和graph_2,输出特意,将孤立的子图分别保存到不同的文件中,一个图就是一个链路。具体如下,可以调整links.xlsx得到不同的拓扑图,甚至可以直接用实际的微波链路文件之间运行。

断开后得TOPO(程序每个断开都会输出)贴最后的断环图(考虑分支最多和深度最小的优化断开)

import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
from collections import defaultdict
import matplotlib

matplotlib.use('Agg')  # 使用Agg后端,不显示图像


def build_graph(links):
    """
    构建图并检测重复链路
    :param links: 链接列表,每个元素是一个包含两个节点的元组
    :return: 图的字典表示和重复链路列表
    """
    graph = defaultdict(list)
    edges = set()
    duplicate_links = []

    for link in links:
        site_a, site_b = link
        # 检查是否为重复链路
        if (site_a, site_b) in edges or (site_b, site_a) in edges:
            duplicate_links.append((site_a, site_b))
        else:
            # 添加链路到图中
            graph[site_a].append(site_b)
            graph[site_b].append(site_a)
            edges.add((site_a, site_b))

    return graph, duplicate_links


def detect_cycles(graph):
    """
    检测图中的成环链路
    :param graph: 图的字典表示
    :return: 成环链路列表
    """
    visited = set()
    parent = {}
    cycles = []

    def dfs(node, par, path):
        """
        深度优先搜索检测成环链路
        :param node: 当前节点
        :param par: 父节点
        :param path: 当前路径
        :return: 是否找到成环链路
        """
        visited.add(node)
        parent[node] = par
        path.append(node)

        for neighbor in graph[node]:
            if neighbor not in visited:
                if dfs(neighbor, node, path):
                    return True
            elif neighbor != par and neighbor in path:
                # 找到成环链路
                cycle = path[path.index(neighbor):] + [neighbor]
                if cycle not in cycles:  # 避免重复记录
                    cycles.append(cycle)

        path.pop()
        return False

    for node in graph:
        if node not in visited:
            dfs(node, None, [])

    return cycles


def draw_subgraph(subgraph, file_path):
    """
    绘制子图并保存到文件
    :param subgraph: 子图的字典表示
    :param file_path: 保存文件路径
    """
    G = nx.Graph()

    for node, neighbors in subgraph.items():
        for neighbor in neighbors:
            G.add_edge(node, neighbor)

    # 设置绘图布局和参数
    pos = nx.spring_layout(G, k=0.3, iterations=50)  # 调整k值和iterations参数
    plt.figure(figsize=(16, 12))  # 调整图形大小
    nx.draw(G, pos, with_labels=True, node_size=3000, node_color='skyblue', font_size=20, font_color='black',
            font_weight='bold', edge_color='gray')
    plt.title('Graph Visualization')
    plt.savefig(file_path)  # 保存图形到指定路径
    plt.close()  # 关闭图像,避免显示


def get_subgraphs(graph):
    """
    获取图的所有子图
    :param graph: 图的字典表示
    :return: 子图列表
    """
    G = nx.Graph(graph)
    subgraphs = [G.subgraph(c).copy() for c in nx.connected_components(G)]
    return subgraphs


def calculate_subtree_depth(graph, node, visited):
    """
    计算节点的子树深度,包括其下挂站点的深度
    :param graph: 图的字典表示
    :param node: 当前节点
    :param visited: 已访问节点集合
    :return: 节点的子树深度
    """
    visited.add(node)
    depths = [calculate_subtree_depth(graph, neighbor, visited) for neighbor in graph[node] if neighbor not in visited]
    visited.remove(node)
    return 1 + max(depths, default=0)


def break_cycle(graph, cycle):
    """
    在成环链路上分支最多且搜索深度最小的位置断开环
    :param graph: 图的字典表示
    :param cycle: 成环链路
    :return: 断开环后的图
    """
    min_combined_depth = float('inf')
    node_to_remove = None
    neighbor_to_remove = None

    for i, node in enumerate(cycle):
        for neighbor in graph[node]:
            if neighbor in cycle:
                # 计算断开(node, neighbor)后的综合深度
                graph[node].remove(neighbor)
                graph[neighbor].remove(node)

                subtree_depth_node = calculate_subtree_depth(graph, node, set())
                subtree_depth_neighbor = calculate_subtree_depth(graph, neighbor, set())
                combined_depth = max(subtree_depth_node, subtree_depth_neighbor)

                if combined_depth < min_combined_depth:
                    min_combined_depth = combined_depth
                    node_to_remove = node
                    neighbor_to_remove = neighbor

                # 恢复连接
                graph[node].append(neighbor)
                graph[neighbor].append(node)

    # 断开找到的最优连接
    if node_to_remove and neighbor_to_remove:
        graph[node_to_remove].remove(neighbor_to_remove)
        graph[neighbor_to_remove].remove(node_to_remove)

    return graph


# 从Excel文件读取数据,只读取"SITE A"和"SITE B"两列
file_path = "E:/develop/save/links.xlsx"
df = pd.read_excel(file_path, usecols=["SITE A", "SITE B"])
links = [tuple(x) for x in df.values]

# 构建图和检测重复链路
graph, duplicate_links = build_graph(links)

# 检测成环链路
cycles = detect_cycles(graph)

# 将结果输出到文本文件
output_file_path = "E:/develop/save/output.txt"
with open(output_file_path, "w") as f:
    f.write(f"Duplicate Links Count: {len(duplicate_links)}\n")
    f.write(f"Duplicate Links: {duplicate_links}\n")
    f.write(f"Cycle Count: {len(cycles)}\n")
    f.write(f"Cycles: {cycles}\n")

# 获取子图并分别保存
subgraphs = get_subgraphs(graph)
for i, subgraph in enumerate(subgraphs):
    subgraph_dict = {node: list(subgraph.neighbors(node)) for node in subgraph.nodes()}
    draw_subgraph(subgraph_dict, f"E:/develop/save/graph_{i + 1}.png")

# 断开成环链路并绘制图
for i, cycle in enumerate(cycles):
    graph_copy = graph.copy()
    graph_copy = break_cycle(graph_copy, cycle)
    subgraphs = get_subgraphs(graph_copy)
    for j, subgraph in enumerate(subgraphs):
        subgraph_dict = {node: list(subgraph.neighbors(node)) for node in subgraph.nodes()}
        draw_subgraph(subgraph_dict, f"E:/develop/save/graph_cycle_{i + 1}_subgraph_{j + 1}.png")

解释:

  1. 导入必要的库:pandas 用于读取 Excel 文件。networkx 用于图的操作和分析。matplotlib 用于绘制和保存图像。defaultdict 用于创建默认字典。
  2. build_graph 函数:构建图并检测重复链路。使用 defaultdict 创建图的字典表示。记录重复链路。
  3. detect_cycles 函数:使用深度优先搜索(DFS)检测图中的成环链路。避免重复记录成环链路。
  4. draw_subgraph 函数:绘制子图并保存到文件。使用 Agg 后端避免显示图像。
  5. get_subgraphs 函数:获取图的所有子图。
  6. 读取 Excel 文件:只读取 "SITE A" 和 "SITE B" 两列数据。
  7. 构建图和检测重复链路:使用 build_graph 函数构建图并检测重复链路。
  8. 检测成环链路:使用 detect_cycles 函数检测成环链路。
  9. 将结果输出到文本文件:将重复链路和成环链路的结果输出到指定的文本文件中。
  10. 获取子图并分别保存:使用 get_subgraphs 函数获取子图,并使用 draw_subgraph 函数绘制并保存每个子图。

Tags:

最近发表
标签列表