Example06 / 13
超图与它的两两投影——投影会丢失信息
用关联矩阵 H(节点 × 超边)表示超图。超图 H1 含一个三元超边 {a,b,c}(如三个亚基组成的复合物); 超图 H2 含三条二元边 {a,b}、{b,c}、{a,c}(三对两两相互作用)。两者的两两投影 W = H H^T - D_v 完全相同,但超度(节点所在的超边数)与超边大小分布不同。 解读:投影图上无法区分“一个三元复合物”和“三个两两结合”,这正是需要高阶表示的原因。
Output输出图

Output文字输出
H1: 超边大小 = [3, 2],超度 = {'a': 1, 'b': 1, 'c': 2, 'd': 1}
[[0 1 1 0]
[1 0 1 0]
[1 1 0 1]
[0 0 1 0]]
H2: 超边大小 = [2, 2, 2, 2],超度 = {'a': 2, 'b': 2, 'c': 3, 'd': 1}
[[0 1 1 0]
[1 0 1 0]
[1 1 0 1]
[0 0 1 0]]
两个超图的两两投影是否相同: TrueCode代码
# 用关联矩阵 H(节点 × 超边)表示超图。超图 H1 含一个三元超边 {a,b,c}(如三个亚基组成的复合物);
# 超图 H2 含三条二元边 {a,b}、{b,c}、{a,c}(三对两两相互作用)。两者的两两投影 W = H H^T - D_v
# 完全相同,但超度(节点所在的超边数)与超边大小分布不同。
# 解读:投影图上无法区分“一个三元复合物”和“三个两两结合”,这正是需要高阶表示的原因。
import numpy as np
nodes = ["a", "b", "c", "d"]
H1 = np.array([[1, 0], # 超边 e1={a,b,c},e2={c,d}
[1, 0],
[1, 1],
[0, 1]])
H2 = np.array([[1, 0, 1, 0], # 超边 {a,b}、{b,c}、{a,c}、{c,d}
[1, 1, 0, 0],
[0, 1, 1, 1],
[0, 0, 0, 1]])
def projection(H):
W = H @ H.T
np.fill_diagonal(W, 0)
return (W > 0).astype(int)
for name, H in [("H1", H1), ("H2", H2)]:
print(f"{name}: 超边大小 = {H.sum(0).tolist()},超度 = {dict(zip(nodes, H.sum(1).tolist()))}")
print(projection(H))
print("两个超图的两两投影是否相同:", np.array_equal(projection(H1), projection(H2)))
# 作图:两个超图的关联矩阵不同,两两投影却完全相同
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 3, figsize=(10, 3.6), gridspec_kw={"width_ratios": [2, 4, 4]})
for a, M, ttl, xl in [(ax[0], H1, "H1: one triple {a,b,c}", ["{a,b,c}", "{c,d}"]),
(ax[1], H2, "H2: three pairs", ["{a,b}", "{b,c}", "{a,c}", "{c,d}"]),
(ax[2], projection(H1), "pairwise projection (H1 = H2)", nodes)]:
a.imshow(M, cmap="Greys", vmin=0, vmax=1.5)
a.set_xticks(range(M.shape[1])); a.set_xticklabels(xl, fontsize=8)
a.set_yticks(range(4)); a.set_yticklabels(nodes); a.set_title(ttl, fontsize=10)
ax[0].set_xlabel("hyperedge"); ax[1].set_xlabel("hyperedge"); ax[2].set_xlabel("node")
plt.tight_layout(); plt.show()Run在浏览器中运行
首次加载 Python 环境约需 20–40 秒;可以修改参数后重新运行。