图/超图拉普拉斯分解 Graph/Hypergraph Laplacian eigendecomposition

图/超图拉普拉斯分解 Graph/Hypergraph Laplacian eigendecomposition

大家好,还是之前的风格,简单粗暴,直接开干!

一、图拉普拉斯特征分解

1. 数学公式

直接上公式,下边公式是图的归一化 拉普拉斯特征分解公式:
Δ = I − D − 1 2 A D − 1 2 = U T Λ U \Delta = I-D^{-\frac{1}{2}}AD^{-\frac{1}{2}} = U^{T}\Lambda U Δ=I−D−21AD−21=UTΛU

各参数的含义是,给定一个图G,假如它有n个节点和m个边:

  • Δ \Delta Δ :拉普拉斯特征矩阵,我们要先计算出这个矩阵,才方便进行特征分解, 矩阵shape是 n × n n\times n n×n

  • I I I:单位矩阵, 矩阵shape是 n × n n\times n n×n

  • D D D:节点度矩阵,矩阵shape是 n × n n\times n n×n

  • A A A :邻接矩阵,矩阵shape是 n × n n\times n n×n

  • U U U:特征向量, 矩阵shape是 n × n n\times n n×n,用代码获取的一般是按照对应特征值从小到大的顺序排列的,每一行对应每个节点的特征值,每一列对应一个特征值。对应特征值小的特征向量包含了更多图整体的结构信息,对应特征值大的特征向量包含了更多这个节点附近的局部信息。

  • Λ \Lambda Λ:特征值, 矩阵shape是 1 × n 1\times n 1×n,一般从函数获得后都是自动排好序的,从小到大

2. 参考代码

参考代码 Github

下边的代码是我加了一些个人注释的,便于理解:

python 复制代码
import torch
import torch.utils.data
import numpy as np


def eig(sym_mat):
	# 特征分解函数
    # (sorted) eigenvectors with numpy
    EigVal, EigVec = np.linalg.eigh(sym_mat) # 特征分解函数,输入图邻接矩阵A,返回特征值和特征向量

    # for eigval, take abs because numpy sometimes computes the first eigenvalue approaching 0 from the negative
    eigvec = torch.from_numpy(EigVec).float()  # [N, N (channels)] # 转一下type,无伤大雅
    eigval = torch.from_numpy(np.sort(np.abs(np.real(EigVal)))).float()  # [N (channels),] #其实分解函数返回的时候就已经是排过序的了
    return eigvec, eigval  # [N, N (channels)]  [N (channels),]


def lap_eig(dense_adj, number_of_nodes, in_degree):
    """
    拉普拉斯特征矩阵函数
    Graph positional encoding v/ Laplacian eigenvectors
    https://github.com/DevinKreuzer/SAN/blob/main/data/molecules.py
    """
    dense_adj = dense_adj.detach().float().numpy() # 邻接矩阵
    
    # 节点入度,这里in_degree输入的是每个节点的入度,现在还是一个一维的向量
    # 大概长这样:[2, 1, 4, 2, ..., 3, 3],长度就是number_of_nodes,对于无向图来说也是出度矩阵
    in_degree = in_degree.detach().float().numpy() 

    # Laplacian
    A = dense_adj # 邻接矩阵
    N = np.diag(in_degree.clip(1) ** -0.5) # diag就是把 1xn 的向量转为 nxn 的矩阵
    L = np.eye(number_of_nodes) - N @ A @ N #这就是上文说的计算拉普拉斯特征矩阵的公式

    eigvec, eigval = eig(L) # 上边那个特征分解函数
    return eigvec, eigval  # [N, N (channels)]  [N (channels),]

二、超图拉普拉斯特征分解

1. 数学公式

下边公式是超图的归一化 拉普拉斯特征分解公式:

L = I − D v − 1 2 H W D e − 1 H T D v − 1 2 = U T Λ U L=I-D_{v}^{-\frac{1}{2}}HWD_{e}^{-1}H^{T}D_{v}^{-\frac{1}{2}}= U^{T}\Lambda U L=I−Dv−21HWDe−1HTDv−21=UTΛU

各参数的含义是,给定一个超图G,假如它有n个节点和m个边:

  • L L L :拉超图普拉斯特征矩阵,我们要先计算出这个矩阵,才方便进行特征分解,矩阵shape是 n × n n \times n n×n

  • I I I:单位矩阵, 矩阵shape是 n × n n \times n n×n

  • D v D_{v} Dv:节点度矩阵,矩阵shape是 n × n n \times n n×n

  • D e D_{e} De:超边度矩阵,矩阵shape是 m × m m \times m m×m

  • H H H :关联矩阵,矩阵shape是 n × m n \times m n×m

  • W W W:包含超边权重的对角矩阵,如果没有明确给出超边权重矩阵,一般超边的权重矩阵就按超边的度矩阵算,矩阵shape是 m × m m \times m m×m

  • U U U:特征向量, 矩阵shape是 n × n n \times n n×n

  • Λ \Lambda Λ:特征值, 矩阵shape是 1 × n 1\times n 1×n

2. 参考代码

参考代码 Github

这是我自己写的参考代码,由于接收的数据不太理想,所以代码中可能含有除公式外一些额外的东西:

python 复制代码
import numpy as np

def getEigvec(HT):
    H, Dv, De, W = getHypergraph(HT)
    eigval, eigvec = eig(H, Dv, De, W)

    return eigval, eigvec

def getHypergraph(HT):
    """
    This function aims to convert a graph to a hypergraph.
    
    graph: 
        HT: a hypergraph incidence matrix, shape is [num_hyperedges, num_hypernodes], contains 0 and 1.
    
    return Hypergraph:
        H: a hypergraph incidence matrix, shape is [num_hypernodes, num_hyperedges], contains 0 and 1.
        Dv: node degree matrix --> [num_nodes, num_nodes]
        De: hyperedge degree matrix --> [hyperedge_num, hyperedge_num]
        W: hyperedge weight matrix --> [hyperedge_num, hyperedge_num]
        
    """
    H = HT.T

    De = np.diag(np.sum(H, axis = 0)) # hyperedge degree matrix --> [num_hyperedges, num_hyperedge]
    Dv = np.diag(np.sum(H, axis = 1)) # nodes degree matrix  --> [num_nodes, num_nodes]
    W = De    # hyperedge weight matrix --> [hyperedge_num, hyperedge_num]
    
    return H, Dv, De, W

def eig(H, Dv, De, W):
    """
    This function aims to get hypergraph eigendecomposition.
    Reference: 
        https://github.com/DevinKreuzer/SAN/blob/main/data/molecules.py
        https://github.com/jw9730/tokengt/blob/main/large-scale-regression/tokengt/data/algos.py
    
    H: a hypergraph incidence matrix, shape is [num_hypernodes, num_hyperedges], contains 0 and 1.
    Dv: node degree matrix --> [num_nodes, num_nodes]
    De: hyperedge degree matrix --> [hyperedge_num, hyperedge_num]
    W: hyperedge weight matrix --> [hyperedge_num, hyperedge_num]
    
    return:
        EigVal: eigenvalue --> [num_nodes, 1]
        EigVec: eigenvector --> [num_nodes, num_nodes]
    """
    
    Dv_half = np.diag(Dv.sum(axis = 0).clip(1) ** -0.5)
    De_1 = np.diag(De.sum(axis = 1).clip(1) ** -1)
    num_nodes = len(Dv)
    
    delta = np.eye(num_nodes) - Dv_half @ H @  De_1 @ H.T @ Dv_half
    
    EigVal, EigVec = np.linalg.eigh(delta)
    # EigVal = np.sort(np.abs(np.real(EigVal)))
    idx = EigVal.argsort()
    EigVal, EigVec = EigVal[idx], np.real(EigVec[:, idx])


    return EigVal, EigVec
相关推荐
乌萨奇也要立志学C++1 分钟前
【洛谷】BFS 求解最短路:从马的遍历到迷宫问题的实战解析
算法·宽度优先
老鼠只爱大米10 分钟前
LeetCode经典算法面试题 #46:全排列(回溯、交换、剪枝等五种实现方案详细解析)
算法·leetcode·剪枝·回溯·全排列·stj算法
Dovis(誓平步青云)24 分钟前
《滑动窗口算法:从 “暴力遍历” 到 “线性高效” 的思维跃迁》
运维·服务器·数据库·算法
_OP_CHEN1 小时前
【算法基础篇】(五十七)线性代数之矩阵乘法从入门到实战:手撕模板 + 真题详解
线性代数·算法·矩阵·蓝桥杯·c/c++·矩阵乘法·acm/icpc
天天爱吃肉82181 小时前
【跨界封神|周杰伦×王传福(陶晶莹主持):音乐创作与新能源NVH测试,底层逻辑竟完全同源!(新人必看入行指南)】
python·嵌入式硬件·算法·汽车
im_AMBER1 小时前
Leetcode 114 链表中的下一个更大节点 | 删除排序链表中的重复元素 II
算法·leetcode
xhbaitxl1 小时前
算法学习day38-动态规划
学习·算法·动态规划
多恩Stone1 小时前
【3D AICG 系列-6】OmniPart 训练流程梳理
人工智能·pytorch·算法·3d·aigc
历程里程碑1 小时前
普通数组----轮转数组
java·数据结构·c++·算法·spring·leetcode·eclipse
pp起床1 小时前
贪心算法 | part02
算法·leetcode·贪心算法