维托里斯里普斯复形
维托里斯里普斯复形(Vietoris–Rips complex,常简称里普斯复形)由有限度量点集中的两两距离建立。给定距离阈值,先连接距离足够近的点,再把邻接图中的每个完全子图填成相应维数的单形。它只需要距离信息,因而适合点云、距离矩阵与持久同调计算。
三点两两相连便会填成三角面,四点两两相连便会填成一个三维单形。只画出满图的六条边,或只加入它的四个三角面,都还没有构造完整的四点里普斯复形。
距离阈值与旗复形
设 是有限度量空间,。本文使用边长阈值,并包括临界等号: 任意子集仍满足相同距离限制,因此这是单纯复形。邻接图中一个有 个顶点的团对应一个 维单形;由图的全部团构造的复形称为旗复形或团复形。单形的进入值为 单顶点的值约定为零。阈值增大时复形只会增加,形成嵌套过滤。GUDHI采用直径或最大边长作为过滤值,同时提醒有些文献将同一参数记为半个边长。比较结果前应先统一尺度。[1]
如果距离矩阵来自观测,应先检查对称性、零对角线与度量假设。任意对称的非负不相似度也能按相同团规则生成过滤,但涉及度量空间的稳定性或几何解释时,不能自动沿用尚未满足的假设。图构造本身与数据是否具有所声明的几何意义是两件事。
正方形点云的完整计算
取平面上四个点 相邻点距离为二,对角点距离为 。
当 时,没有边,故 。当 时只有四条周边边,没有三点完全子图,因此没有三角面。图连通,并有 个独立循环,所以 。
达到 时,全部六条边同时存在。四点成为一个团,必须加入四个三角面以及四面体本身。完整复形是一个实心三维单形,可缩,普通贝蒂数为 。
也可直接用边界秩公式核验。其各维单形数为 ,在 上, 第一式由图连通性得到。四个面的边界之和为零,其中任取三个独立:每个面有一条未出现在另外两个所选面中的边,逐列检查可得独立性。三维单形的边界是四个面之和,非零,故第三式成立。于是
这个点云的一维条形区间因此为 ,寿命为 。如果只截取到二维,四个三角面围成的二维循环没有三维边界可抵消,计算将得到 ;那是截断复形的结果,不是完整里普斯复形的结果。一般要正确计算 ,需保留至少到 维,因为 也参与同调定义。
两两接近与共同交点
切赫复形要求一组球有共同交点,而里普斯复形只检查球心之间的两两距离。取边长二的等边三角形,本文里普斯阈值 时三边齐全,三角面立即加入;半径为一的三个闭球却没有共同交点,相应切赫复形仍只是三边圈。
在欧氏空间中,两者满足 第一包含由共同点及三角不等式得到;第二包含可取单形中任一顶点作为半径 球族的共同点。因此两者能从不同尺度夹住彼此,但同一数值参数下不能混用球半径与最大边长。
可复算的小规模构造
下面的实现枚举所有非空顶点子集,用欧氏距离判定每对点是否通过阈值。输入为有限二维点列及非负有限阈值,输出各维单形的顶点编号元组,不改写输入。重复坐标按不同编号保留,距离为零;若研究对象要求去重后的点集,可先去重。它适合核对小例子,限制点数不超过十六;没有加入人为容差,临界等号应结合浮点误差解释。
from itertools import combinations
from math import hypot, isfinite
def rips_simplices(points, epsilon):
points = tuple(tuple(p) for p in points)
if len(points) > 16 or not isfinite(epsilon) or epsilon < 0:
raise ValueError("require at most 16 points and finite epsilon >= 0")
if any(len(p) != 2 or not all(isfinite(v) for v in p)
for p in points):
raise ValueError("require finite two-dimensional points")
edges = set()
for i, j in combinations(range(len(points)), 2):
dx = points[i][0] - points[j][0]
dy = points[i][1] - points[j][1]
if hypot(dx, dy) <= epsilon:
edges.add((i, j))
return [
s for size in range(1, len(points) + 1)
for s in combinations(range(len(points)), size)
if all(pair in edges for pair in combinations(s, 2))
]
square = [(-1, -1), (1, -1), (1, 1), (-1, 1)]
for eps in (1.5, 2.3, 2.9):
simplices = rips_simplices(square, eps)
counts = [sum(len(s) == k + 1 for s in simplices)
for k in range(4)]
print(eps, counts)
# 1.5 [4, 0, 0, 0]
# 2.3 [4, 4, 0, 0]
# 2.9 [4, 6, 4, 1]
assert rips_simplices([], 1) == []
正确性。 一个候选集合被保留,当且仅当它的每个二元子集都在邻接边集中,正好是定义中的两两距离条件。枚举覆盖每个非空顶点子集且没有重复,因此输出既不缺单形,也不多添单形。对子集的二元检查同样保证面包含在输出中。
预计算边需要 次距离计算;最坏情况下枚举检查耗时 ,全部输出需要 个顶点编号的存储。十六点上限只是这个教学实现的操作限制,不是理论边界。实际实现常按团扩张、限制所需维数或使用有理论保证的稀疏化;必须报告这些选择,不能仅凭软件输出较小就认为得到同一个完整复形。[2]
参考文献
- ↑ GUDHI,Rips complex user manual,“Definition”及关于参数二倍关系的说明。
- ↑ GUDHI,同上,“Definition”“Example step by step”,关于维数截断、团扩张及稀疏近似的说明。