Fluent Bit 集成指南:Ripser 高效 Vietoris–Rips 持续同调条形码计算库
【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit
导读
Ripser 是一个精简的 C++ 实现,专门用于计算 Vietoris–Rips 持续同调条形码(persistence barcodes),以"只做一件事但做到极致"著称。本文以仓库内 lib/ripser-1.2.1/README.md 为主线,完整讲解它的输入格式、命令行选项、编译期宏与核心算法原理,并结合 Fluent Bit 仓库中的实际集成(src/ripser/flb_ripser_wrapper.cpp与plugins/processor_tda插件)展示它如何被用于拓扑数据分析(TDA)。读完本文,你将掌握 Ripser 的独立构建、运行与参数调优方法,并理解它在 Fluent Bit 中如何驱动 TDA 处理器输出 Betti 数指标。
Ripser 是什么:定位与设计哲学
Ripser 由 Ulrich Bauer 开发(© 2015–2021),核心代码位于 lib/ripser-1.2.1/ripser.cpp(连同内部头文件 lib/ripser-1.2.1/ripser_internal.hpp 构成完整实现)。它的定位非常纯粹:只计算 Vietoris–Rips 持续同调条形码,但在这件事上做得非常出色。
README 中列出的主要特性:
- 时间与内存双高效:通过持续上同调(persistent cohomology)等技巧大幅降低资源占用;
- 代码极简:整个核心实现仅约 1000 行代码,位于单个 C++ 文件中;
- 支持素数有限域系数(编译期启用);
- 无外部依赖(可选支持 Google sparsehash,或 Martin Ankerl 的 robin hood hashmap)。
说明:README 声称 Ripser 在计算时间上比其他实现(Dionysus、DIPHA、GUDHI、Perseus、PHAT)快一个数量级以上(>40 倍)、内存效率高 15 倍以上(针对 live.ripser.org 的示例),并特别注明 PHAT 本身不包含生成 Vietoris–Rips 过滤的代码。这是上游文档的陈述,具体到不同数据集上的表现仍需自行验证。
核心概念:Vietoris–Rips 复形与持续同调
要理解 Ripser 的输出,需要先厘清两个概念:
- Vietoris–Rips 复形:给定一组点及两两距离,固定一个直径阈值
t,当两个点距离 ≤t时连边,进而张成单纯复形。随着t从 0 增长到无穷,复形不断生长,形成一个过滤(filtration)。 - 持续同调(persistent homology):跟踪该过滤过程中各维度的拓扑特征(连通分量、环、空洞等)何时"出生"(birth)与"消亡"(death),从而得到一系列区间(interval),即条形码(barcode)或持续对(persistence pair)。
Ripser 的输出正是这些持续对——(birth, death)二元组。当某个特征在阈值达到无穷时仍未消亡(即"本质同调类",essential homology class),其 death 记为无穷。
支持的输入格式与示例数据
Ripser 支持 7 种输入格式,仓库 lib/ripser-1.2.1/examples/ 提供了多种格式的实测样例数据:
| 格式 | 说明 | 仓库内示例 |
|---|---|---|
lower-distance | 下三角距离矩阵,逗号(或空白/其他非数字字符)分隔对角线下方的条目,按行索引、再列索引的字典序排列 | sphere_3_192.lower_distance_matrix、projective_plane.lower_distance_matrix、random16.lower_distance_matrix、random20.lower_distance_matrix |
upper-distance | 上三角距离矩阵,适合 MATLABpdist/seqpdist导出到 CSV 的输出 | rp2_600.lower_distance_matrix.csv(CSV 类数据) |
distance(默认) | 完整距离矩阵,每行对应矩阵的一行;实际只读取对角线以下部分 | 可由 pointsCycloOctane.csv 等点云数据推算 |
dipha | DIPHA 距离矩阵数据格式 | projective_plane.dipha |
point-cloud | 点云,每行一个点,坐标为逗号(或空白等)分隔的欧氏空间坐标 | pointsCycloOctane.csv、projective_plane.csv、o3_1024.txt 等 |
binary | 二进制下三角距离矩阵,32 位浮点(IEEE 754 单精度、小端)序列 | — |
sparse | 稀疏三元组格式,每行一个条目i j d(i,j),表示点 i 与点 j 的距离;每对点至多出现一次 | — |
构建与运行
独立构建(Makefile)
Ripser 仅需支持 C++11 的编译器。仓库内 lib/ripser-1.2.1/Makefile 提供了三个构建目标:
make # 默认:带 -O3 -D NDEBUG 的 ripser make all # 依次构建 ripser、ripser-coeff(启用 USE_COEFFICIENTS)、ripser-debug(带 -g 调试符号) make clean # 清理三个产物各目标的实际编译命令(见 Makefile):
c++ -std=c++11 -Wall ripser.cpp -o ripser -O3 -D NDEBUG c++ -std=c++11 -Wall ripser.cpp -o ripser-coeff -O3 -D NDEBUG -D USE_COEFFICIENTS c++ -std=c++11 -Wall ripser.cpp -o ripser-debug -g构建后即可运行,输入既可以是命令行参数指定的文件,也可以通过 stdin 传入。README 中的标准示例(以球面点云距离矩阵为例):
./ripser examples/sphere_3_192.lower_distance_matrixCMake 静态库构建
仓库还提供了 lib/ripser-1.2.1/CMakeLists.txt,将ripser.cpp编译为静态库ripser-static(同时指定 C++11 标准,并把仓库目录加入公共 include 路径,使ripser_internal.hpp可被外部引用)。Fluent Bit 正是通过这条路径把 Ripser 集成进构建系统的。
命令行选项详解
Ripser 支持以下命令行参数:
--format <fmt>:指定输入格式,取值与上文输入格式表格一一对应:lower-distance:下三角距离矩阵;upper-distance:上三角距离矩阵(MATLABpdist/seqpdist导出的 CSV);distance(未指定格式时的默认值):完整距离矩阵,只读取对角线以下部分;dipha:DIPHA 距离矩阵;point-cloud:欧氏空间点云,每行一个点;binary:32 位浮点(IEEE 754 单精度、小端)下三角矩阵的二进制序列;sparse:稀疏三元组格式i j d(i,j),每对点至多出现一次。
--dim k:计算最高至维数k的持续同调。--threshold t:计算直径至t的 Rips 复形。若不指定阈值,Ripser 会选择外接半径(enclosing radius)作为阈值——在此阈值之后同调必然平凡(该思路由 Greg Henselman-Petrusek 提出,见其 Eirene.jl 项目)。--modulus p:在素数域 Z/pZ 上计算系数同调(仅在编译时启用USE_COEFFICIENTS后可用)。--ratio r:仅输出 death/birth 比值 >r的持续对。
编译期选项(预处理宏)
编译期宏在 lib/ripser-1.2.1/ripser.cpp 顶部以注释形式列出,通过#define或在编译命令行传入-D开关启用:
| 宏 | 作用 | 默认状态 |
|---|---|---|
USE_COEFFICIENTS | 启用素数有限域系数支持(配合--modulus) | 注释关闭 |
INDICATE_PROGRESS | 在控制台指示当前计算进度 | 注释关闭 |
PRINT_PERSISTENCE_PAIRS | 输出计算得到的持续对 | 默认开启(注释掉以禁用) |
USE_ROBINHOOD_HASHMAP | 启用 Martin Ankerl 的 robin hood hashmap,可进一步降低内存占用 | 注释关闭 |
README 给出的手动编译示例(启用 robin hood hashmap):
c++ -std=c++11 ripser.cpp -o ripser -O3 -D NDEBUG -D USE_ROBINHOOD_HASHMAP从源码看,哈希表的选择在 ripser.cpp 通过hash_map/hash模板别名统一抽象:启用USE_ROBINHOOD_HASHMAP时使用robin_hood::unordered_map,否则回退到std::unordered_map。此外,源码中还有num_coefficient_bits = 8与max_simplex_index的设计(ripser.cpp),用于在启用系数时对单纯形索引做溢出检查——这也是USE_COEFFICIENTS会占用部分索引位宽的原因。
效率背后的四个关键原理
Ripser 的高效并非偶然,README 明确指出它建立在四项核心原理之上(均引用自计算拓扑领域的前人工作):
- 计算持续上同调(persistent cohomology):由 Vin de Silva、Dmitriy Morozov 与 Mikael Vejdemo-Johansson 提出,相比同调计算通常更节省内存;
- 利用"边界是圈"的链复形性质:采用clearing优化(又称 "persistence with a twist",由 Chao Chen 与 Michael Kerber 提出),避免重复消元;
- 默认阈值取外接半径:未指定
--threshold时,选取保证同调平凡的外接半径作为阈值,避免无谓的过大过滤; - 不存储可随时重算的信息:特别是原始矩阵与约简后的边界矩阵都不保留;
- 利用计算捷径:apparent与emergent persistence pairs的快速判定。
这些原理共同保证了时间和内存的双重高效。从实现结构看,核心计算逻辑被抽取到 ripser_internal.hpp,其中定义了compressed_lower_distance_matrix/compressed_upper_distance_matrix两种压缩距离矩阵类型(ripser_internal.hpp)、供调用方注册的interval_recorder回调结构(ripser_internal.hpp),以及统一的入口函数ripser_run_from_compressed_lower(ripser_internal.hpp)。距离矩阵的存取抽象与回调式的区间输出设计,为上层集成(如 Fluent Bit)提供了干净的调用接口。
Fluent Bit 中的集成:从 CLI 工具到处理器插件
Ripser 在 Fluent Bit 中并非以独立 CLI 形式存在,而是被封装为静态库并服务于processor_tda拓扑数据分析插件。整条集成链路清晰可循:
- 上游核心库:lib/ripser-1.2.1/CMakeLists.txt 把
ripser.cpp编译为ripser-static; - C 桥接层:src/ripser/flb_ripser_wrapper.cpp 将 C++ 接口封装为 C ABI,src/ripser/CMakeLists.txt 将其编译为
flb-ripser-wrapper-static并链接ripser-static。桥接层暴露两个核心 API:flb_ripser_compute_betti_from_dense_distance(flb_ripser_wrapper.cpp):输入稠密距离矩阵,输出各维 Betti 数;flb_ripser_compute_intervals_from_dense_distance(flb_ripser_wrapper.cpp):输入稠密距离矩阵,通过回调逐条输出持续区间(dim, birth, death)。- 两者都把稠密矩阵转换为
compressed_lower_distance_matrix(make_compressed_from_dense,flb_ripser_wrapper.cpp),然后调用ripser_run_from_compressed_lower;threshold ≤ 0 时传入numeric_limits<value_t>::max(),等价于 README 所述的"外接半径自动模式"。
- TDA 处理器插件:plugins/processor_tda/tda.c 中的
tda_window_run_ripser(tda.c)把 cmetrics 指标快照做延迟嵌入(delay embedding)后构造成欧氏距离矩阵,再调用 wrapper 计算 Betti 数(betti0/betti1/betti2),并以 gauge 形式输出(ensure_betti_gauges,tda.c)。plugins/processor_tda/CMakeLists.txt 中可见target_link_libraries(flb-plugin-processor_tda ripser-static flb-ripser-wrapper-static),印证了这条依赖链。
从源码结构可以推断:Fluent Bit 复用了 Ripser 上游的ripser.cpp(含 2025 年 Fluent Bit Authors 的修改),将"计算持续同调"这一能力嵌入到指标处理器中,用于检测监控指标时间序列中的拓扑结构变化。
实验性特性(独立分支)
除主线功能外,README 还列出了三个实验性特性,它们以独立分支形式提供:
representative-cocycles:输出持续上同调的代表上闭链(representative cocycles);representative-cycles:计算并输出持续同调的代表圈(representative cycles)——注意标准版本只计算上圈(cocycles);simple:精简版 Ripser,不支持稀疏距离矩阵与系数,可作为阅读源码的入门起点。
引用与许可证
如果你在研究中使用了 Ripser,README 提供了如下 BibTeX 条目:
@misc{1908.02518, Author = {Ulrich Bauer}, Title = {Ripser: efficient computation of Vietoris-Rips persistence barcodes}, Month = Feb, Year = {2021}, Eprint = {1908.02518v2}, Note = {Preprint} }许可证方面,Ripser 采用 MIT 许可证(lib/ripser-1.2.1/COPYING.txt),并附加一条条款(lib/ripser-1.2.1/CONTRIBUTING.txt)说明:若无另行签署书面许可协议,对外发布的修改版本自动授予非独占、免版税、永久的安装、使用、修改、衍生、分发与再许可权利。Fluent Bit 集成的ripser.cpp头部同时保留了两者版权声明(Ulrich Bauer 2015–2021 与 The Fluent Bit Authors 2025)。如需在其他软件中以不同许可证使用 Ripser,请与作者联系。
小结
Ripser 以约千行代码实现了业界领先的 Vietoris–Rips 持续同调条形码计算:7 种输入格式、5 个命令行选项、4 个编译期宏,配合上同调、clearing、外接半径与 apparent/emergent pair 等算法原理,构成了一个"小而精"的计算几何利器。在 Fluent Bit 仓库中,它被桥接为 C API 并服务于 TDA 处理器插件,把持续同调能力从独立的 CLI 工具延伸到了实时的指标监控场景,这也是阅读 lib/ripser-1.2.1/README.md 之外、深入源码后最值得关注的集成路径。
【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考