C++最常用的向量/矩阵数学/线性代数库是哪些,它们的成本和效益权衡如何?

285

看起来许多项目都需要进行矩阵数学计算,并陷入首先构建某些向量类的陷阱,然后逐步添加功能,直到他们被困在半吊子自定义线性代数库中并依赖它。

我想避免这种情况,同时又不会依赖于某些间接相关的库(例如OpenCV、OpenSceneGraph)。

有哪些常用的矩阵数学/线性代数库?为什么要选择其中一个而不是另一个?有没有建议不使用某些库的原因?我具体在几何/时间*(2,3,4维)*上使用,但将来可能会使用更高维的数据。

我正在寻找以下方面的差异:API、速度、内存使用、广度/完整性、狭窄/特定性、可扩展性和/或成熟度/稳定性。

更新

最终我使用了Eigen3,非常满意。


2
既然你提到了OSG和OpenCV,我猜想你只需要3D图形类型的向量/矩阵,即3x3和4x4矩阵。我根据这个回答了你的问题,但是你可能需要说明你具体是如何使用它的——你需要矩阵求解吗?高维矩阵数学等等。 - Reed Copsey
现在我只做基于2D几何的东西,但是假设有时候你需要对2D数据进行3x3操作,而且不清楚是否需要3D数据和因此4x4操作。我们希望在公司内使用一个通用库。我没有很好的感觉来权衡利弊。更通用的库会更好,但代价是什么呢? - Catskul
1
如果你只想进行几何变换,我强烈推荐看一下我在回答中提到的GGT。它对于这方面非常全面,但实际上除此之外什么也不干,因此是一个非常干净、简单的选择。BLAS和LAPACK更多用于科学和数学中进行复杂矩阵解决方案(例如:50x50矩阵、稀疏矩阵等),而不是用于几何变换。 - Reed Copsey
C++ Vector Class Library使用SIMD指令进行并行处理。 https://github.com/vectorclass/version2 - A Fog
11个回答

129
有很多项目已经选择通用图形工具包。其中的GMTL非常好用,它相当小巧、功能强大,并且被广泛使用,因此非常可靠。OpenSG、VRJuggler和其他项目都已经转而使用它,而不是他们自己手写的向量/矩阵运算。
我发现这非常好用——它通过模板实现所有功能,因此非常灵活和快速。

编辑:

在评论讨论和编辑后,我想提供一些关于特定实现的优缺点以及为什么在特定情况下你可能会选择其中之一的更多信息。

GMTL -

优点:简单的API,专门设计用于图形引擎。包括许多面向渲染的基本类型(如平面、AABB、带有多重插值的四元数等),这些类型在任何其他软件包中都没有。非常低的内存开销,速度相当快,易于使用。

缺点:API非常专注于渲染和图形,不包括通用的(NxM)矩阵、矩阵分解和求解等,因为这些超出了传统图形/几何应用的范畴。

Eigen -

优点:清晰的API,相当易于使用。包括一个几何模块,具有四元数和几何变换。内存开销较小。完整的,高性能的求解大型NxN矩阵和其他通用数学例程。

缺点:可能比你想要的范围更大(?)。与GMTL相比,几何/渲染特定例程较少(即:欧拉角定义等)。

IMSL -

优点:非常完整的数值库。速度非常快(据说是最快的求解器)。迄今为止最大、最完整的数学API。商业支持、成熟、稳定。

缺点:费用高,不便宜。几乎没有几何/渲染特定方法,因此您需要在其线性代数类之上自己编写。

NT2 -

优点:提供更熟悉的语法,如果您习惯MATLAB的话。提供了大型矩阵的完整分解和求解等功能。

缺点:数学方面,不注重渲染。可能不如Eigen性能好。

LAPACK -

优点:非常稳定,经过长时间证明的算法。存在已久。完整的矩阵求解等。许多晦涩的数学选项。

缺点:在某些情况下性能不如其他库。从Fortran移植而来,使用奇怪的API。

对我来说,问题归结为一个问题 - 你计划如何使用它。如果你只关注渲染和图形,我喜欢通用图形工具包,因为它表现良好,并支持许多有用的渲染操作,无需自己实现。如果你需要一般目的的矩阵求解(即:大矩阵的SVD或LU分解),我会选择Eigen,因为它处理这个问题,提供一些几何操作,并且在大矩阵解决方案方面非常高效。您可能需要编写更多自己的图形/几何操作(在它们的矩阵/向量之上),但那并不可怕。


在决定使用GMTL之前,您有评估其他库吗?表面上的比较让我相信Eigen得到了更好的支持,但这是基于审查各自的网站。您是否知道其中一个具有特定优势? - Catskul
Eigen 也很不错。在我进行调查时,它还没有那么成熟,但我相信现在它是一个很好的选择。GMTL 已经被广泛使用,并且在我决定使用它时非常成熟和稳定。 - Reed Copsey
这就是我喜欢GMTL并使用它的原因之一。它使用起来非常自然,而且非常容易操作。在这种情况下,它还支持我所需的所有功能,因为我只需要直接处理几何变换和四元数旋转。 - Reed Copsey
请参阅以下讨论:http://scicomp.stackexchange.com/questions/351/recommendations-for-a-usable-fast-c-matrix-library - Damien
GNU Scientific Library(用于C语言)也支持BLAS。https://www.gnu.org/software/gsl/ - Reza
显示剩余2条评论

43

我是一个很挑剔的人,认为如果我要投资于一个代码库中,最好知道自己到底在投资什么。当我在审查这个库时,我认为批判性思维比吹捧更加有利,因为它的问题对未来的影响比好处要多得多。所以我会稍微过度地描述一下,提供一种能够帮助我自己和其他人的回答。请注意,这是基于我进行的少量评论/测试而得出的结论。噢,我从Reed那里偷了一些正面的描述。

我首先要提到的是,尽管GMTL有其独特之处,但由于Eigen2存在不安全性问题,我还是选择了GMTL。但我最近了解到,Eigen2的下一个版本将包含定义文件,可以关闭对齐代码,使其变得安全。所以我可能会转向Eigen2。

更新:我已经转向使用Eigen3。尽管它有些独特之处,但其范围和优雅程度是难以忽视的,而且可以通过定义文件关闭使其不安全的优化。

Eigen2/Eigen3

优点:LGPL MPL2、干净、设计精良的API,相当易于使用。似乎得到了充满活力的社区的精心维护。内存占用低,性能高。是面向普通线性代数的,但也提供了很好的几何功能。全为头文件库,无需链接。

独特之处/缺点:(一些或全部可以通过当前发展分支 Eigen3中可用的定义文件避免)

  • 不安全的性能优化要求需要认真遵循规则,否则会导致崩溃。
    • 不能安全地按值传递
    • 使用Eigen类型作为成员需要特殊的分配器定制(否则会崩溃)
    • 与stl容器类型和可能其他模板一起使用需要特殊的分配定制(否则你将会崩溃)
    • 某些编译器需要特别小心以防止函数调用时的崩溃(GCC Windows)

GMTL

好处: LGPL协议,API简单易懂,专为图形引擎而设计。包含很多针对渲染优化的原始类型(如平面、AABB、具有多种插值的四元数等),其他软件包中没有这些类型。内存开销非常低,速度相当快,易于使用。全部基于头文件实现,不需要链接。

缺点:

  • API有些古怪
    • 在其他库中可能是myVec.x()的东西只能通过myVec[0]访问(可读性差)
      • 数组或stl::vector的点列表可能会导致你做类似pointsList[0][0]这样的操作来访问第一个点的x分量
    • 为了尝试优化而删除了交叉(vec,vec)并替换为makeCross(vec,vec,vec),因为编译器会消除不必要的临时变量
    • 普通数学运算不会返回普通类型,除非你关闭一些优化功能,例如:vec1-vec2不会返回一个普通向量,所以length(vecA-vecB)无法工作,即使vecC=vecA-vecB可以正常工作。你必须像这样包装:length( Vec( vecA - vecB ) )
    • 向量操作由外部函数提供而不是成员。这可能需要你在所有地方使用作用域解析符号,因为常见的符号名称可能会冲突
    • 你必须这样做:
        length( makeCross( vecA, vecB ) )
      或者
        gmtl::length( gmtl::makeCross( vecA, vecB ) )
      否则你可能会尝试这样做:
        vecA.cross( vecB ).length()
  • 维护得不好
    • 仍被称为“beta”版
    • 文档缺少基本信息,如需要使用正常功能的头文件
      • Vec.h没有向量的操作,VecOps.h中包含一些操作,其他操作在Generate.h中。例如,VecOps.h中的cross(vec&,vec&,vec&),[make]cross(vec&,vec&)在Generate.h中。
    • 不成熟/不稳定的API;仍在更改中。
      • 例如,“cross”从“VecOps.h”转移到“Generate.h”,然后更名为“makeCross”。文档示例失败,因为仍然引用不再存在的旧函数版本。

      NT2

      无法确定,因为他们似乎对网页的分形图像头部更感兴趣。看起来更像一个学术项目而不是一个严肃的软件项目。

      最新版发布已经超过两年了。

      显然没有英语文档,尽管据说有一些法语文档在某个地方。

      无法找到项目周围的社区痕迹。

      LAPACK&BLAS

      优点:老而成熟。

      缺点:

      • 与恐龙一样古老,具有非常糟糕的API。

1
关于Eigen对齐断言:为了从SSE(1,2,3或4)操作中获得高性能,对于小数据集,您绝对需要对齐的数据。未对齐的加载/存储操作要慢得多。选择对齐或未对齐的加载/存储也需要时间。 任何“通用”实现都会为每个人做正确的事情而感到非常困难,除非他们将接口分成“对齐”和“未对齐”的操作 - 然后它再次不是非常通用。 - Joris Timmermans
@Catskul 我想使用Eigen3。您能否详细说明一下“可以通过定义关闭使其不安全的优化”?您在Eigen2下列出的其他问题在文档中都有详细说明,与对齐问题相关的主题下有介绍。我可以接受这些问题。 - Ali
我所提到的安全问题都与对齐相关,并且与Eigen2相同。如果您对Eigen2感到满意,那么使用Eigen3也不会有问题。 - Catskul
2
BLAS和LAPACK实际上并不是库,而是规范/API。您可以提到它们最初由netlib或其他实现(如ATLAS和OpenBLAS)实现。 - Foad S. Farimani

13

就我所知,我尝试过Eigen和Armadillo,下面是简要评估:

Eigen的优点: 1. 完全自包含 - 不依赖于外部的BLAS或LAPACK。 2. 文档不错。 3. 据说很快,尽管我还没有测试过。

缺点: QR算法仅返回一个矩阵,其中R矩阵嵌入在上三角中。不知道其余矩阵来自何处,也无法访问Q矩阵。

Armadillo的优点: 1. 广泛的分解和其他函数(包括QR)。 2. 相当快(使用表达式模板),但我还没有真正将其推向高维度。

缺点: 1. 依赖于外部的BLAS和/或LAPACK进行矩阵分解。 2. 我认为文档不足(包括有关LAPACK的具体信息,除了更改#define语句)。

如果有一个自包含且易于使用的开源库可用,那将是很好的事情。我遇到了这个问题已经10年了,这让人沮丧。曾经,我使用GSL进行C编程,并编写了C++封装器,但使用现代C++ - 尤其是利用表达式模板的优点 - 我们不应该在21世纪还需要使用C。只是我的个人见解。


2
Armadillo 的语法类似于 Matlab,使用起来很容易。我不确定您所说的“文档缺乏...LAPACK 的具体细节”的意思。该文档清晰地记录了所有用户可用的函数,以及如何使用它们的示例。C++ 包装库的整个重点是抽象化 LAPACK 的复杂性和冗长性。如果您想查看 Armadillo 如何调用 LAPACK,则可以随时浏览源代码。 - mtall
关于Eigen中的QR分解,您是指Eigen2还是Eigen3? - qed

11
如果你正在寻找在英特尔处理器上进行高性能矩阵/线性代数/优化的工具,我会建议使用英特尔的MKL库。MKL经过仔细优化以获得快速的运行时性能 - 其中许多是基于非常成熟的BLAS / LAPACK Fortran标准的。它的性能随可用核心数量扩展。与可用核心的免提可扩展性是计算的未来,我不会使用任何不支持多核处理器的数学库进行新项目。
简单来说,它包括以下内容:
  1. 基本的向量-向量,向量-矩阵和矩阵-矩阵运算
  2. 矩阵因子分解(LU分解,Hermitian,稀疏)
  3. 最小二乘拟合和特征值问题
  4. 稀疏线性系统求解器
  5. 非线性最小二乘求解器(信任区域)
  6. 加上信号处理例程,如FFT和卷积
  7. 非常快速的随机数生成器(Mersenne Twist)
  8. 还有更多...请参见:链接文本
MKL的一个缺点是其API可能会相当复杂,具体取决于您需要的例程。您还可以查看他们的IPP(集成性能基元)库,该库针对高性能图像处理操作,但也相当广泛。
这段文字由Paul提供。 CenterSpace Software,.NET数学库,centerspace.net

9

关于GLM呢?

它基于OpenGL着色器语言(GLSL)规范,并在MIT许可下发布。显然是针对图形编程人员的。


2
它提供了图形编程向量和矩阵。为了保持GLSL的兼容性,引入了相当数量的开销(如果你可以在GLSL中完成它,大多数情况下在GLSL中完成会更好,特别是在GL 4.x中),并且错过了许多图形编程原语(截锥体、AABB、BB、椭球体)。它的swizzle接口太肥了。更好的选择是使用一些代码生成生成".xyzz()"函数。当您需要原型OpenGL应用程序并开始显示其负面影响时,它是完美的。永远不要编写数学库。 - CoffeDeveloper

8
我听说EigenNT2都不错,但我个人没有使用过。还有Boost.UBLAS,我认为它已经有点老了。NT2的开发人员正在构建下一个版本,并打算将其纳入Boost,因此可能会更好一些。
我的线性代数需求不超过4x4矩阵情况,因此我无法评论高级功能;我只是指出一些选择。

根据我的经验(更大的矩阵),Boost.UBLAS被更多地使用。然而,当我深入研究时,我并不喜欢它(主要是因为文档),所以我专注于Eigen。Eigen有一个几何模块,但我自己没有使用过。 - Jitse Niesen
Eigen 显然被 ROS(willow garage)、Celestia、Koffice 和 libmv 使用。我看到一些关于 UBLAS 的交流,但很难找到宣传使用它的项目。NT2 也是如此。你能详细说明一下你听到的好消息吗? - Catskul
在 Boost 邮件列表的讨论中,关于将现代 LinAlg 库添加到 Boost 中的问题被提出 - Eigen 和 NT2 都被提及为可能的候选库,但只有 NT2 的开发人员表达了追求的兴趣。两个库都似乎不错;正如你所说,Eigen 更受欢迎,也更符合 C++ 的风格;NT2 设计得尽可能模仿 MATLAB。 - Jeff Hardy

8
我对这个主题还不是很了解,但BLAS在科学计算中几乎是标准。BLAS实际上是一个API标准,有许多实现。我不确定哪些实现最受欢迎或为什么最受欢迎。
如果您想进行常见的线性代数操作(解决系统、最小二乘回归、分解等),请查看LAPACK

6
我会为Eigen投票:我将很多代码(3D几何,线性代数和微分方程)从不同的库移植到这个库中,并在几乎所有情况下提高了性能和代码可读性。
其中一个未被提及的优点是:使用SSE非常容易与Eigen一起使用,这显着提高了2D-3D操作的性能(其中所有内容都可以填充到128位)。

1
整个“如果你这样做,则确保...”的事情让我有点警惕。到目前为止,我已经两次遇到了这些问题,而我刚开始使用它。我真的希望不会因为知道每个包含库的各种特殊性而负担未来的开发人员,特别是对齐问题,如果您每次都有成员,则崩溃,以及它们将单个类的功能分散在多个头文件中的事实。虽然它本身可能无法阻止我选择它,但它已经引起了一些警惕。 - Catskul
1
对齐和宏仅在使用SSE时才有影响,这绝不是必需的。如果您确实使用SIMD,那么无论使用哪个库,这些问题都会出现。至少Eigen不会崩溃,而是提供有意义的错误消息,直接指向问题。 - ima
有一种简单的方法可以避免使用对齐宏 - 就是将指针或引用作为成员。 - ima
1
我不认为这是正确的。我没有使用任何特殊的SSE选项,在使用它与STL容器后遇到了几次崩溃。是的,我知道它会提供有用的信息,我也知道有特殊的指令,但那就是我的观点。我不想为每个包含的库都加上特殊的指令而给其他开发人员带来负担。例如,不按值传递的事情就太多了。 - Catskul
我刚刚发现最新的开发分支有一些定义可以用来关闭对齐并避免相关问题。 - Catskul

4

好的,我认为我知道你在寻找什么。从 Reed Copsey 的建议来看,GGT 是一个相当不错的解决方案。

个人而言,我们自己编写了一个小型库,因为我们经常处理有理点——大量有理 NURBS 和 Bezier 曲线。

事实证明,大多数 3D 图形库使用的是投影点进行计算,这些投影点在投影数学中没有任何基础,因为这样可以得到您想要的答案。我们最终使用了 Grassmann 点,它们具有坚实的理论基础并减少了点类型的数量。Grassmann 点基本上是现在人们正在使用的相同计算,具有健全的理论优势。最重要的是,它使我们的思维更加清晰,因此我们出现了更少的错误。Ron Goldman 在计算机图形学中写了一篇关于 Grassmann 点的论文,名为 "On the Algebraic and Geometric Foundations of Computer Graphics"

虽然这与你的问题没有直接关系,但是是一篇有趣的阅读材料。


这是故意开放的,因为我不知道权衡的是什么。可以说几何图形是我们关注的主要问题,几何图形的维数不清楚。目前它是 2/3(2 + 时间),理论上可能会很高(3 维度 + 时间 + 多维成本地图)。 - Catskul
我同意这个问题。例如,许多此类应用程序需要实时(一致的时间行为)性能,而其他许多应用程序则可以放弃一致性和/或速度以换取准确性。 - T.E.D.
那么你的意思是说,在你调查的库中,没有一个库处理NURBS和Beziers?不采用现有的库并在其旁边构建NURBS和Bezier支持的特定原因是什么? - Catskul
我想说的是,理性NURBS和Beziers比大多数3D应用程序更多地使用有理控制点,因此我们犯了更多错误。通常,大多数3D应用程序只有普通的3D点和向量,直到经过透视变换后才有。我们的许多算法必须能够正确处理加权/有理/投影和笛卡尔点,来回转换等。 - tfinniga

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接