生物医学网络科学Biomedical Network Science
Example07 / 13

单纯复形的贝蒂数——空心三角形与实心三角形

所属专题
结果呈现与研究前沿
下载
Notebook · .py

构造边界矩阵 B1(节点 × 边)与 B2(边 × 三角形),用秩计算贝蒂数: beta_0 = n0 - rank B1,beta_1 = (n1 - rank B1) - rank B2。 同时构造霍奇拉普拉斯 L1 = B1^T B1 + B2 B2^T,其零空间维数等于 beta_1。 解读:只有三条边时有一个一维“洞”(beta_1 = 1);把三角形 {0,1,2} 作为 2-单形填上后洞消失。 这正是“三人两两认识”与“三人同属一个群体”在拓扑上的区别。

Output输出图

单纯复形的贝蒂数——空心三角形与实心三角形:输出图 1

Output文字输出

空心三角形:beta_0, beta_1, dim ker L1 = (1, 1, 1)
实心三角形:beta_0, beta_1, dim ker L1 = (1, 0, 0)
四边形环 + 一条孤立边:beta_0, beta_1, dim ker L1 = (2, 1, 1)

Code代码

# 构造边界矩阵 B1(节点 × 边)与 B2(边 × 三角形),用秩计算贝蒂数:
# beta_0 = n0 - rank B1,beta_1 = (n1 - rank B1) - rank B2。
# 同时构造霍奇拉普拉斯 L1 = B1^T B1 + B2 B2^T,其零空间维数等于 beta_1。
# 解读:只有三条边时有一个一维“洞”(beta_1 = 1);把三角形 {0,1,2} 作为 2-单形填上后洞消失。
# 这正是“三人两两认识”与“三人同属一个群体”在拓扑上的区别。
import numpy as np
from itertools import combinations

def boundary_matrices(n_nodes, edges, triangles):
    edges = [tuple(sorted(e)) for e in edges]
    eidx = {e: i for i, e in enumerate(edges)}
    B1 = np.zeros((n_nodes, len(edges)))
    for j, (u, v) in enumerate(edges):
        B1[u, j], B1[v, j] = -1, 1
    B2 = np.zeros((len(edges), len(triangles)))
    for k, t in enumerate(triangles):
        a, b, c = sorted(t)
        # ∂[a,b,c] = [b,c] - [a,c] + [a,b]
        B2[eidx[(b, c)], k], B2[eidx[(a, c)], k], B2[eidx[(a, b)], k] = 1, -1, 1
    return B1, B2

def betti(n_nodes, edges, triangles):
    B1, B2 = boundary_matrices(n_nodes, edges, triangles)
    r1 = np.linalg.matrix_rank(B1) if B1.size else 0
    r2 = np.linalg.matrix_rank(B2) if B2.size else 0
    L1 = B1.T @ B1 + (B2 @ B2.T if B2.size else 0)
    null_L1 = int(np.sum(np.linalg.eigvalsh(L1) < 1e-9))
    assert np.allclose(B1 @ B2, 0) if B2.size else True  # 边界的边界为零
    return int(n_nodes - r1), int(len(edges) - r1 - r2), null_L1

edges = list(combinations(range(3), 2))
print("空心三角形:beta_0, beta_1, dim ker L1 =", betti(3, edges, []))
print("实心三角形:beta_0, beta_1, dim ker L1 =", betti(3, edges, [(0, 1, 2)]))
square = [(0, 1), (1, 2), (2, 3), (0, 3), (4, 5)]
print("四边形环 + 一条孤立边:beta_0, beta_1, dim ker L1 =", betti(6, square, []))

# 作图:三个单纯复形及其贝蒂数(填充 = 2-单形)
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 3, figsize=(10, 3.4))
tri = np.array([[0, 0], [1, 0], [0.5, 0.87]])
sq = np.array([[0, 0], [1, 0], [1, 1], [0, 1], [1.6, 0.2], [1.6, 0.8]])
cases = [(tri, edges, [], "hollow triangle"), (tri, edges, [(0, 1, 2)], "filled triangle"),
         (sq, square, [], "square loop + isolated edge")]
for a, (P, E, T, ttl) in zip(ax, cases):
    for t in T:
        a.fill(*P[list(t)].T, color="C0", alpha=0.3)
    for u, v in E:
        a.plot(*P[[u, v]].T, color="0.3", lw=2)
    a.plot(*P[:max(max(e) for e in E) + 1].T, "o", color="C3", ms=8)
    b0, b1, _ = betti(len(P), E, T)
    a.set_title(f"{ttl}\nbeta_0 = {b0}, beta_1 = {b1}", fontsize=10); a.set_aspect("equal"); a.axis("off")
plt.tight_layout(); plt.show()

Run在浏览器中运行

首次加载 Python 环境约需 20–40 秒;可以修改参数后重新运行。

单纯复形的贝蒂数——空心三角形与实心三角形