百万次重三角剖分后,他为何弃用 CGAL 自研 Delaunay 三角剖分?

原创
alex 2分钟前 阅读数 1 #头条

百万次重三角剖分后,他为何弃用 CGAL 自研 Delaunay 三角剖分?

CGAL 的“重”与“轻”:依赖管理的现实代价

有人劝我:CGAL 是几十年学术积累的结晶,你折腾它干嘛?我一开始也这么想。直到我为用上它,不得不引入超过 160 个 C++ 库,其中就包括 Boost 和 Eigen 这样的重量级依赖 来源:Adam Getchell。这些依赖不会自己装好,版本冲突、编译选项、链接顺序,每一个都是坑。我花在管理这些依赖上的时间,超过了我写有用代码的时间。这件事我到现在都觉得荒谬。

那段时间的挣扎,最后浓缩成一篇 951 词、5 分钟阅读的博客,发布于 2025 年 12 月 27 日 来源:Adam Getchell。从“用 battle-tested 库”到“自己实现”,这个转变不是突发奇想,而是被现实反复锤打出来的。160 多个库的负担,对比 951 词博客的反思,这个量级差距本身就说明问题:我们以为成熟库是垫脚石,结果它变成了必须扛着走的行李。

问题出在哪里?不是 CGAL 不好,而是它太“重”了。重到让人忘记为什么要用它。

Pachner moves 与 CDT:理论到工程的鸿沟

我做的项目涉及因果动力学三角剖分(CDT),核心操作之一是实现 Pachner moves。理论上的 Pachner moves 很优雅,但真正动手写代码时,我发现它比预期的困难得多 来源:Adam Getchell。我交替经历着“有进展”和“卡住”两种状态,卡住的原因五花八门:库自身的 bug、库与库之间的阻抗不匹配、甚至编译器层面的问题。

更麻烦的是我的特定用例。它涉及数百万次重复重三角剖分,结果出现了内存泄漏、段错误,以及我无法调试的问题 来源:Adam Getchell。为了保持项目更新,我提交了非常多的 bug 报告,这些 bug 在常规测试用例里根本不会暴露。讽刺的是,这些成熟库在常规使用中很稳,一旦放到大规模重复使用的场景,它们反而成了主要障碍。

我一度怀疑是自己的用法有问题,但反复检查后确认,问题出在库本身。理论上的简洁,落地到工程里就变成了另一回事。

多源交叉验证:从库到自研的决策依据

回头看,这个决策有迹可循。CGAL 确实有几十年的学术积累 来源:CGAL,但它的现实代价是 160+ 个库的依赖管理负担。理论算法再优美,如果工程实现中充斥着 bug、编译问题、内存问题,那它就是不可用的。Pachner moves 在数学上很简洁,但我在实现过程中遇到的问题,从库 bug 到编译器问题,每一步都消耗着时间 来源:Adam Getchell。

预期和现实之间的差距,在 MCMC 采样这个场景下被放大了。Metropolis 类算法进行 MCMC 采样时,需要数百万次重复重三角剖分 来源:Adam Getchell。常规测试用例跑个几千次就结束了,测试里不会出现内存泄漏,但当你把它乘上一百万倍,问题就全冒出来了。我原本以为用成熟库能省时间,结果管理依赖反而花了我更多时间。

这些对比放在一起,结论自然就出来了:自研实现是合理的。不是因为自研更好,而是因为依赖库的隐性成本已经超过了它带来的收益。

自研的技术选型:性能、函数式与工具链

决定自研之后,我对语言提了几个硬性要求:性能好、内存安全、线程安全,同时允许我做低层操作,还要能管理复杂性 来源:Adam Getchell。最好有函数式编程范式,让代码推理更简单。工具链也要省心,依赖管理、lint、测试、文档,最好都容易上手,而不是一场持久战。库生态也不能差,数值计算、线性代数这些总得有地方找。

我选了 Rust。我考虑过 Julia,但排除了垃圾回收的语言,这同样排除了 Python,尽管它在科学计算里很流行。我承认我在工具和数据分析上用 Python,但性能关键代码不会用它 来源:Adam Getchell。

这个项目已经经历过多次迭代和语言更替。最初用 Lisp 实现,然后试图移植到 Clojure,再试 F# 来源:Adam Getchell。走到 Rust 这一步,不是一开始就规划好的,而是试错试出来的。

在工程里,依赖管理成本可能超过算法实现的收益。这个道理,我花了几个月才真正明白。


原文:

Building Delaunay Triangulations · 来源:Hacker News

作者:itfan123 值班编辑 · 发布于 2026年10月28日

版权声明

所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除