当前位置: 首页 > news >正文

图匹配(分解)相关代码学习

根据论文Factorized Graph Matching学习图分解和图匹配的相关代码,并进行逐行解读

版本1:

优:特征分解、按特征值降序排列特征向量、计算相似度矩阵、匈牙利算法寻找最优匹配

劣:缺少论文中提到的因式分解部分

import numpy as np
from scipy.optimize import linear_sum_assignment


# 用于接收两个邻接矩阵,A/B表示待匹配的图
def factorized_graph_matching(A, B):
    # 对邻接矩阵进行特征分解 np.linalg.eigh()函数专门用于对称矩阵
    # 结果是得到矩阵的特征值eigvals和对应的特征向量eigvecs
    eigvals_A, eigvecs_A = np.linalg.eigh(A)
    eigvals_B, eigvecs_B = np.linalg.eigh(B)

    # 按特征值降序排列特征向量(处理符号问题)
    # 特征值降序排列返回索引
    idx_A = np.argsort(eigvals_A)[::-1]
    # 通过索引对特征向量重排
    eigvecs_A = eigvecs_A[:, idx_A]
    # 图解过程 标准化特征向量符号
    eigvecs_A = np.sign(eigvecs_A[np.argmax(np.abs(eigvecs_A), axis=0), range(eigvecs_A.shape[1])]) * eigvecs_A

    idx_B = np.argsort(eigvals_B)[::-1]
    eigvecs_B = eigvecs_B[:, idx_B]
    eigvecs_B = np.sign(eigvecs_B[np.argmax(np.abs(eigvecs_B), axis=0), range(eigvecs_B.shape[1])]) * eigvecs_B

    # 计算特征向量间的相似度矩阵(余弦相似度)
    similarity = np.abs(eigvecs_A.T @ eigvecs_B)

    # 使用匈牙利算法寻找最优匹配(负号,默认最小代价但希望最大相似度)
    row_ind, col_ind = linear_sum_assignment(-similarity)

    # 构建匹配结果
    matching = np.zeros(A.shape[0], dtype=int)
    matching[row_ind] = col_ind
    return matching


# 示例用法
if __name__ == "__main__":
    np.random.seed(0)
    n = 5  # 节点数量

    # 生成原始图A和其排列版本B(添加噪声)
    A = np.random.rand(n, n)
    A = (A + A.T) / 2  # 对称化
    true_perm = np.random.permutation(n)
    B = A[true_perm][:, true_perm]
    B += np.random.normal(scale=0.05, size=(n, n))  # 添加噪声

    # 进行图匹配
    predicted_perm = factorized_graph_matching(A, B)

    # 显示结果
    print("真实排列:", true_perm)
    print("预测排列:", predicted_perm)
    accuracy = np.mean(predicted_perm == true_perm)
    print(f"匹配准确率: {accuracy * 100:.1f}%")

 ①随机生成矩阵A

②对称化,便于使用np.linalg.eigh()函数,专门用于对称矩阵

③生成一个随机重排列,用于生成B,并添加扰动噪声

 ④跳入函数进行匹配

输入:

 提取AB的特征值和特征向量:

特征值降序返回索引:

通过索引对特征值和特征向量重排:

 计算特征向量之间的相似度:

 匈牙利算法寻找最优匹配:

 构建0矩阵,填入匹配结果

版本2:

优:适用于小规模图的匹配任务,手动分块

劣:通过Euclidean距离来计算每个节点之间的相似度,使用了节点的属性值进行匹配

import numpy as np
import networkx as nx
from scipy.optimize import linear_sum_assignment


def compute_cost_matrix(graph1, graph2):
    # 获取节点数量
    num_nodes1 = len(graph1.nodes)
    num_nodes2 = len(graph2.nodes)

    # 初始化全为0的代价矩阵
    cost_matrix = np.zeros((num_nodes1, num_nodes2))

    # 遍历两个图的每个节点
    for i, node1 in enumerate(graph1.nodes):
        for j, node2 in enumerate(graph2.nodes):
            # 从图中获取节点特征值,若没有特征值设为0
            value1 = graph1.nodes[node1].get('value', np.array([0]))
            value2 = graph2.nodes[node2].get('value', np.array([0]))

            # 计算两个节点特征值之间的欧几里得距离,并将其作为匹配代价存入代价矩阵
            cost_matrix[i, j] = np.linalg.norm(value1 - value2)

    return cost_matrix


def factorized_graph_matching(graph1, graph2):
    # Step 1: 计算两个图之间的代价矩阵
    cost_matrix = compute_cost_matrix(graph1, graph2)

    # Step 2: 使用匈牙利算法求解代价矩阵的最优匹配
    row_ind, col_ind = linear_sum_assignment(cost_matrix)

    # Step 3: 将匹配结果组合成一个列表
    matching = list(zip(row_ind, col_ind))
    return matching


def create_sample_graph():
    graph1 = nx.Graph()
    # 创建一个包含三个节点(编号为0,1,2)的图1
    graph1.add_nodes_from([0, 1, 2])
    # 为每个节点添加一个名为value的属性
    graph1.nodes[0]['value'] = np.array([1, 2])
    graph1.nodes[1]['value'] = np.array([2, 3])
    graph1.nodes[2]['value'] = np.array([3, 4])

    graph2 = nx.Graph()
    graph2.add_nodes_from([0, 1, 2])
    graph2.nodes[0]['value'] = np.array([1, 1])
    graph2.nodes[1]['value'] = np.array([2, 2])
    graph2.nodes[2]['value'] = np.array([3, 3])

    return graph1, graph2


if __name__ == "__main__":
    graph1, graph2 = create_sample_graph()
    matching = factorized_graph_matching(graph1, graph2)
    print("Optimal Node Matching:")
    for node1, node2 in matching:
        print(f"Graph1 Node {node1} is matched with Graph2 Node {node2}")

①创建两张图,并为节点赋予属性值

graph1:

graph2: 

②调用图匹配函数,匹配graph1和graph2

step1:计算两个图之间的代价矩阵

1.获取节点数量并初始化代价矩阵

2. 遍历两个图的每个节点并获取节点特征值,若没有特征值则设为0;计算代价矩阵

代价越小,对应的匹配越优 

 step2:使用匈牙利算法求解代价矩阵的最优匹配

step3: 将匹配结果组合成一个列表

得到匹配结果

版本3:

结合上述两种

import numpy as np
import networkx as nx
from scipy.optimize import linear_sum_assignment


# 将输入图转换为邻接矩阵
def compute_adjacency_matrix(graph):

    return nx.to_numpy_array(graph)


def factorized_graph_matching(graph1, graph2, k=5):

    # Step 1: 计算邻接矩阵
    A1 = compute_adjacency_matrix(graph1)
    A2 = compute_adjacency_matrix(graph2)

    # Step 2: 计算特征值和特征向量
    eigvals_A1, eigvecs_A1 = np.linalg.eigh(A1)
    eigvals_A2, eigvecs_A2 = np.linalg.eigh(A2)

    # Step 3: 按特征值降序排列特征向量
    idx_A1 = np.argsort(eigvals_A1)[::-1]
    eigvecs_A1 = eigvecs_A1[:, idx_A1]

    idx_A2 = np.argsort(eigvals_A2)[::-1]
    eigvecs_A2 = eigvecs_A2[:, idx_A2]

    # Step 4: 选择前k个特征向量(更具有代表性)
    eigvecs_A1 = eigvecs_A1[:, :k]
    eigvecs_A2 = eigvecs_A2[:, :k]

    # Step 5: 计算特征向量之间的相似度矩阵
    similarity_matrix = np.abs(np.dot(eigvecs_A1.T, eigvecs_A2))

    # Step 6: 使用匈牙利算法找到最优匹配
    row_ind, col_ind = linear_sum_assignment(-similarity_matrix)

    # Step 7: 返回匹配结果
    matching = list(zip(row_ind, col_ind))
    return matching


def create_sample_graph():

    graph1 = nx.Graph()
    graph1.add_nodes_from([0, 1, 2, 3])
    graph1.add_edges_from([(0, 1), (1, 2), (2, 3)])

    graph2 = nx.Graph()
    graph2.add_nodes_from([0, 1, 2, 3])
    graph2.add_edges_from([(0, 2), (1, 3), (2, 3)])

    return graph1, graph2


# Test the factorized graph matching
if __name__ == "__main__":
    graph1, graph2 = create_sample_graph()
    matching = factorized_graph_matching(graph1, graph2, k=2)

    print("Optimal Node Matching:")
    for node1, node2 in matching:
        print(f"Graph1 Node {node1} is matched with Graph2 Node {node2}")

版本4:

使用SVD,和论文基本一致的因式分解

SVD分解函数:

import numpy as np


def factorize_cost_matrix(K, rank=2):

    # K:需要分解的矩阵 U:左因子矩阵 sigma:奇异值矩阵(对角矩阵) V:右因子矩阵

    # Step 1:对矩阵K进行奇异值分解
    U, sigma, Vt = np.linalg.svd(K, full_matrices=False)

    # Step 2:保留前rank个奇异值和对应的奇异向量

    # 从U中提取前rank列,表示保留的左奇异向量。
    U = U[:, :rank]  
    
    # 从奇异值数组中提取前rank个奇异值,并将它们转换为对角矩阵Σ。
    sigma = np.diag(sigma[:rank])  
    
    # 从VT的转置中提取前 rank 列,表示保留的右奇异向量
    V = Vt.T[:, :rank]  

    return U, sigma, V


# Example usage:
if __name__ == "__main__":
    # Example cost matrix K (could be a similarity or distance matrix)
    K = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

    # Factorize the cost matrix into U and V
    U, sigma, V = factorize_cost_matrix(K, rank=2)

    # Reconstruct the matrix K from U, sigma, and V
    K_reconstructed = U @ sigma @ V.T

    print("Original Matrix K:")
    print(K)
    print("\nReconstructed Matrix K:")
    print(K_reconstructed)

①传入分解的矩阵K

 ②对矩阵K进行奇异值分解

 ③保留前rank个奇异值和对应的奇异向量

低秩近似:通过保留矩阵的主要成分来近似原始矩阵,同时减少计算复杂度和数据维度

SVD分解可以表示为:K=U\sum V^{T}

UV:正交矩阵

\sum:对角矩阵,对角线上的元素是奇异值,按从大到小的顺序排列

奇异值的大小反映了矩阵中每个成分的重要性。较大的奇异值对应于矩阵的主要结构信息,而较小的奇异值通常可以被视为噪声或次要信息

左奇异向量:

 对角矩阵Σ:

 右奇异向量:

 ④重塑K

结合SVD后的图匹配:

import numpy as np
import networkx as nx
from scipy.optimize import linear_sum_assignment


# 计算节点间的相似度矩阵
def compute_similarity_matrix(graph1, graph2):
    """
    计算两个图之间的节点相似度矩阵。
    这里使用欧几里得距离来计算节点之间的相似度。
    """
    num_nodes1 = len(graph1.nodes)
    num_nodes2 = len(graph2.nodes)

    # 初始化相似度矩阵
    similarity_matrix = np.zeros((num_nodes1, num_nodes2))

    # 计算节点间的相似度(以欧几里得距离为例)
    for i, node1 in enumerate(graph1.nodes):
        for j, node2 in enumerate(graph2.nodes):
            # 假设每个节点有一个'value'属性,我们用该属性进行相似度计算
            value1 = graph1.nodes[node1].get('value', np.array([0]))
            value2 = graph2.nodes[node2].get('value', np.array([0]))

            # 使用欧几里得距离作为相似度(可以替换为其他相似度度量方法)
            similarity_matrix[i, j] = np.linalg.norm(value1 - value2)

    return similarity_matrix


# 使用SVD进行因式分解
def factorize_cost_matrix(K, rank=2):
    """
    使用SVD对代价矩阵K进行因式分解。
    """
    # 对K矩阵进行SVD分解
    U, sigma, Vt = np.linalg.svd(K, full_matrices=False)

    # 保留前rank个奇异值
    U = U[:, :rank]
    sigma = np.diag(sigma[:rank])
    V = Vt.T[:, :rank]

    return U, sigma, V


# 图匹配函数
def factorized_graph_matching(graph1, graph2, rank=2):
    """
    使用因式分解方法进行图匹配。
    """
    # 计算节点相似度矩阵(代价矩阵)
    similarity_matrix = compute_similarity_matrix(graph1, graph2)

    # 使用SVD进行因式分解
    U, sigma, V = factorize_cost_matrix(similarity_matrix, rank)

    # 重构代价矩阵
    reconstructed_matrix = U @ sigma @ V.T

    # 使用匈牙利算法进行最优匹配
    row_ind, col_ind = linear_sum_assignment(reconstructed_matrix)

    # 输出匹配结果
    matching = list(zip(row_ind, col_ind))
    return matching


# 创建样本图
def create_sample_graph():
    """
    创建测试用的样本图。
    图中每个节点都有一个'value'属性,用于计算相似度。
    """
    graph1 = nx.Graph()
    graph1.add_nodes_from([0, 1, 2])
    graph1.nodes[0]['value'] = np.array([1, 2])
    graph1.nodes[1]['value'] = np.array([2, 3])
    graph1.nodes[2]['value'] = np.array([3, 4])

    graph2 = nx.Graph()
    graph2.add_nodes_from([0, 1, 2])
    graph2.nodes[0]['value'] = np.array([1, 1])
    graph2.nodes[1]['value'] = np.array([2, 2])
    graph2.nodes[2]['value'] = np.array([3, 3])

    return graph1, graph2


# 测试图匹配
if __name__ == "__main__":
    # 创建样本图
    graph1, graph2 = create_sample_graph()

    # 进行图匹配
    matching = factorized_graph_matching(graph1, graph2)

    # 输出匹配结果
    print("Optimal Node Matching:")
    for node1, node2 in matching:
        print(f"Graph1 Node {node1} is matched with Graph2 Node {node2}")

相关文章:

  • 【Java 面试 八股文】并发编程篇
  • DeepSeek vs. ChatGPT:不同的诞生时间,对人工智能发展的不同影响
  • 基于 JavaWeb 的 Spring Boot 调查问卷管理系统设计和实现(源码+文档+部署讲解)
  • Java 内存区域详解
  • 测试data_management函数
  • python爬虫——爬取全年天气数据并做可视化分析
  • JAVA最新版本详细安装教程(附安装包)
  • 解决pyenv versions没有列出系统的python版本
  • ue5.2.1 quixel brideg显示asset not available in uAsset format
  • 2025年-G10-Lc84-235.二叉搜索树的最低公共祖先-java版
  • HarmonyOS NEXT 创新应用开发白皮书(api12+)
  • QML Image 圆角设置
  • SpringBoot核心框架之AOP详解
  • Linux 内核自旋锁spinlock(三)--- MCS locks
  • 区块链中的递归长度前缀(RLP)序列化详解
  • JCRQ1河马算法+消融实验!HO-CNN-LSTM-Attention系列四模型多变量时序预测
  • Redis中集合(Set)常见命令详解
  • nginx配置ssl
  • Spring Boot拦截器(Interceptor)详解
  • P1034 [NOIP 2002 提高组] 矩形覆盖
  • 交通运输局男子与两名女子办婚礼?官方通报:未登记结婚,开除该男子
  • 申伟强任上海申通地铁集团有限公司副总裁
  • 上海蝉联全国中小企业发展环境评估综合排名第一
  • 新华社千笔楼:地方文旅宣传应走出“魔性尬舞”的流量焦虑
  • 南京艺术学院博导、雕塑家尹悟铭病逝,年仅45岁
  • 光速晋级!2025年多哈世乒赛孙颖莎4比0战胜对手