什么是使用最广泛的C ++向量/矩阵数学/线性代数库,以及它们的成本和收益之间的取舍?[关闭]


242

似乎许多项目慢慢地需要进行矩阵数学运算,并陷入了以下陷阱:首先构建一些矢量类,然后缓慢地添加功能,直到被发现构建一个半确定的自定义线性代数库并依赖它。

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

那里最常用的矩阵数学/线性代数库是什么,为什么会决定使用另一个?是否出于某些原因建议不要使用?我专门在几何/时间上下文*(2,3,4 Dim)*中使用它,但将来可能会使用更高维度的数据。

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

更新资料

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


2
由于您提到了OSG和OpenCV,所以我猜您只需要3D图形类型的矢量/矩阵,即:3x3和4x4矩阵。我以此为依据,但是您可能需要指定使用的精确度-是否需要矩阵求解?高维矩阵数学?等等
Reed Copsey

现在,我只做基于2D几何的工作,但是假设您有时需要对2D数据进行3x3运算,并且不清楚3D数据是否需要4x4运算。我们想在公司范围内使用一个公共库。我对权衡会不太了解。更笼统的会更好,但是问题是什么呢?
Catskul

1
如果您只是在进行几何变换,那么我真的建议您看一下我在回答中提到的GGT。这是非常完整的,但实际上并没有执行任何操作,因此这是一个非常干净,简单的选择。BLAS和LAPACK更适合用于科学和数学的主导复杂矩阵解决方案(即:50x50矩阵,稀疏矩阵等),而不是几何变换。
Reed Copsey

Answers:


114

为此,有很多项目已经选择了通用图形工具包。那里的GMTL很不错-它非常小,非常实用,并且被广泛使用以使其非常可靠。OpenSG,VRJuggler和其他项目都已转而使用此方法,而不是使用自己的手动Vertor /矩阵数学方法。

我发现它非常不错-它通过模板完成所有操作,因此非常灵活且非常快。


编辑:

在讨论讨论和进行编辑之后,我想我会抛出更多有关特定实现的优点和缺点的信息,以及在给定情况的情况下为什么会选择其中一个的更多信息。

GMTL -

好处:简单的API,专门为图形引擎设计。包括许多其他渲染所没有的面向渲染的原始类型(例如,平面,AABB,具有多个插值的四边形等)。非常低的内存开销,相当快,易于使用。

缺点:API非常专注于渲染和图形。不包括通用(NxM)矩阵,矩阵分解和求解等,因为它们不在传统图形/几何应用程序的范围内。

本征 -

好处:干净的API,相当容易使用。包括带有四元数和几何变换的几何模块。低内存开销。大型NxN矩阵和其他通用数学例程的完整,高性能求解。

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

IMSL -

好处:非常完整的数字库。非常非常快(据说是最快的求解器)。迄今为止最大,最完整的数学API。商业支持,成熟且稳定。

缺点:成本-不便宜。很少有几何/渲染特定的方法,因此您需要在线性代数类的顶部滚动自己的方法。

NT2 -

好处:如果您习惯使用MATLAB,则可以提供更熟悉的语法。提供对大型矩阵等的完全分解和求解。

缺点:数学,而不是专注于渲染。可能不像本征那样出色。

手提包 -

好处:非常稳定,经过验证的算法。住了很久了。完整的矩阵求解等。模糊数学的许多选择。

缺点:在某些情况下,性能不那么出色。从Fortran移植,使用奇数API。

就我个人而言,这归结为一个问题-您打算如何使用它。如果您只专注于渲染和图形,那么我喜欢Generic Graphics Toolkit,因为它性能良好,并支持许多有用的开箱即用的渲染操作,而无需自己实现。如果您需要通用矩阵求解(即:大矩阵的SVD或LU分解),我将选择Eigen,因为它可以处理该问题,提供一些几何运算,并且对于大矩阵解决方案非常有效。您可能需要编写更多自己的图形/几何运算(在它们的矩阵/矢量之上),但这并不可怕。


在决定使用GMTL之前,您是否评估过其他库?表面的比较使我相信Eigen得到了更好的支持,但是那是基于对相应网站的审查。您是否知道一个相对于另一个的任何特定优势?
Catskul

本征也运作良好。在我进行调查时,它还不那么成熟,但是我认为这是一个不错的选择。GMTL已被广泛使用,当我决定使用它时,它已经非常成熟和牢固。
里德·科普西2009年

我想将我的问题简化为一个症结所在:您是否在主观上做出了“看起来更好”这样的选择,或者在哪些特定功能(api,速度,内存使用,广度,狭窄度,可扩展性)方面有所作为?我认为成熟度属于此条件,但是如果成熟度是唯一度量标准,我想您会选择基于BLAS或LAPACK的选项。
Catskul

我在尝试了多个选项之后选择了它,并基于它:性能,可用性和低运行时/编译时间开销。现在,Eigen看上去要比那时好得多,所以我无法在两者之间做出判断。但是,我对GMTL的使用感到非常满意。
Reed Copsey

这就是为什么我喜欢GMTL并使用它的部分原因。使用起来感觉很自然,并且非常非常容易使用。在这种情况下,它也支持我所需的一切,因为我只是担心直接处理几何变换和四元数旋转。
Reed Copsey

38

因此,我是一个非常重要的人,如果我打算投资图书馆,我最好知道自己要投入什么。我认为最好是在审查时多加批评和轻描淡写。它的问题对未来的影响远大于对的意义。因此,我将在这里进行一些讨论,以提供对我有帮助的答案,希望能帮助其他可能走这条路的人。请记住,这是基于我对这些库所做的很少的审查/测试。哦,我从里德那里偷了一些正面的描述。

我要特别提到的是,尽管GMTL具有特殊性,但我还是选择了GMTL,因为Eigen2的不安全性太大了。但是我最近了解到,Eigen2的下一版本将包含将关闭对齐代码并使其安全的定义。所以我可以切换。

更新:我已经切换到Eigen3。尽管有其特质,但它的范围和优雅度却很难忽略,可以使用定义关闭使其不安全的优化。

本征2 /本征3

好处:LGPL MPL2,干净,设计良好的API,相当易于使用。似乎可以通过一个充满活力的社区得到很好的维护。低内存开销。高性能。适用于一般线性代数,但也具有良好的几何功能。所有头文件库,无需链接。

惯用语/缺点:(某些/所有这些都可以通过一些当前开发分支 Eigen3 中可用的定义来避免)

  • 不安全的性能优化导致需要认真遵守规则。不遵守规则会导致崩溃。
    • 您根本无法安全地传递值
    • 使用Eigen类型作为成员需要特殊的分配器自定义(否则会崩溃)
    • 与stl容器类型以及可能的其他模板一起使用时,需要进行特殊的分配自定义(否则您将崩溃)
    • 某些编译器需要特别小心,以防止函数调用(GCC窗口)崩溃

通用标签

好处:LGPL,非常简单的API,专门为图形引擎设计。包括许多其他渲染所没有的面向渲染的原始类型(例如,平面,AABB,具有多个插值的四边形等)。非常低的内存开销,相当快,易于使用。基于所有标头,无需链接。

惯用语/缺点:

  • API是古怪的
    • 另一个库中的myVec.x()可能仅通过myVec [0]提供(可读性问题)
      • 点的数组或stl :: vector可能会导致您执行pointsList [0] [0]之类的操作来访问第一个点的x分量
    • 在天真的优化尝试中,当编译器消除了不必要的临时操作时,删除了cross(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()
  • 维护不好
    • 仍然声称是“测试版”
    • 文档缺少基本信息,例如使用正常功能需要哪些标题
      • Vec.h不包含Vector的操作,VecOps.h包含一些操作,例如,其他在Generate.h中。VecOps.h中的cross(vec&,vec&,vec&),Generate.h中的[make] cross(vec&,vec&)
  • API不成熟/不稳定;还在改变。
    • 例如,“ cross”已从“ VecOps.h”移至“ Generate.h”,然后将名称更改为“ makeCross”。文档示例失败,因为仍然引用了不再存在的旧功能。

NT2

无法判断,因为他们似乎对网页的分形图像标题比对内容更感兴趣。看起来更像是一个学术项目,而不是一个认真的软件项目。

2年前的最新版本。

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

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

拉帕克和布拉斯

好处:老而成熟。

缺点:

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

1
关于Eigen对齐的断言:要从小型数据集的SSE(1,2,3或4)操作中获得高性能,您绝对需要对齐的数据。未对齐的加载/存储操作要慢得多。对齐或不对齐的加载/存储之间的决定也需要时间。任何“通用”实现都很难为每个人做正确的事,除非他们也将接口分为“对齐”和“未对齐”操作-然后这又不是很通用。
Joris Timmermans

@Catskul我想使用Eigen3。您能否扩展“可以通过定义关闭不安全的优化”?你EIGEN2在列表中的其他问题进行认真详细的文档有关对齐问题的主题。我可以忍受这些问题。
阿里

关于安全性的问题,我指的是所有与对齐有关的问题,并且与Eigen2相同。如果您对Eigen2满意,那么对Eigen3会没事的。
Catskul 2012年

2
BLAS和LAPACK实际上不是库,而是规范/ API。您可能已经提到了netlib的最初实现或其他实现,例如ATLAS和OpenBLAS。
Foad

12

对于它的价值,我已经尝试了Eigen和Armadillo。下面是一个简短的评估。

本征的优势:1.完全独立-无需依赖外部BLAS或LAPACK。2.文件体面。3.据称速度很快,尽管我尚未对其进行测试。

缺点:QR算法仅返回单个矩阵,而R矩阵嵌入在上部三角形中。不知道矩阵的其余部分来自哪里,也无法访问Q矩阵。

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

缺点:1.依赖于外部BLAS和/或LAPACK进行矩阵分解。2.文档缺少恕我直言(除了更改#define语句外,还包括LAPACK的详细信息)。

如果有一个自包含且易于使用的开源库,那就太好了。我遇到这个问题已有十年了,这让我感到沮丧。有一次,我使用GSL编写C语言,并围绕它编写了C ++包装器,但是对于现代C ++-尤其是利用表达式模板的优势-我们在21世纪不必与C混淆。只是我的学生。


2
Armadillo具有类似于Matlab的故意语法,因此易于使用。我不确定您对“缺少文档...详细说明WAT LAPACK”的意思。该文档清楚地记录了所有用户可用的功能以及如何使用它们的示例。关于C ++包装器库的全部要点是抽象出LAPACK的复杂性和冗长性。如果要查看Armadillo如何调用LAPACK,可以始终浏览源代码。
mtall

关于Eigen中的QR分解,您是指Eigen2还是Eigen3?
2013年

11

如果您正在寻找Intel处理器上的高性能矩阵/线性代数/优化,我会看一下Intel的MKL库。

MKL经过精心优化,以实现快速的运行时性能-其中大部分基于非常成熟的BLAS / LAPACK fortran标准。而且其性能随可用内核数而定。具有可用内核的免提可扩展性是计算的未来,对于不支持多核处理器的新项目,我不会使用任何数学库。

非常简短,它包括:

  1. 基本向量-向量,向量-矩阵和矩阵-矩阵运算
  2. 矩阵分解(LU decomp,hermitian,sparse)
  3. 最小二乘拟合和特征值问题
  4. 稀疏线性系统求解器
  5. 非线性最小二乘法求解器(信任区域)
  6. 加上信号处理例程,例如FFT和卷积
  7. 非常快的随机数生成器(梅森捻)
  8. 更多...。请参阅:链接文本

缺点是MKL API可能非常复杂,具体取决于所需的例程。您也可以看看他们的IPP(集成性能基元)库,该库适用于高性能图像处理操作,但是功能库相当广泛。

保罗

CenterSpace软件,.NET数学库,centerspace.net


8

我听说过有关EigenNT2的好消息,但也没有个人使用。还有Boost.UBLAS,我相信它会长一些。NT2的开发人员正在构建下一个版本,目的是将其引入Boost,因此可能会有所作为。

我的林 阿尔格 需求不会超出4x4矩阵情况,因此我无法评论高级功能;我只是指出一些选择。


以我的经验(较大的矩阵),使用Boost.UBLAS的次数更多。但是,当我研究它时,我不喜欢它(主要是由于文档的原因),所以我专注于Eigen。Eigen有一个geometry模块,但是我自己没有使用过。
吉特·尼森

Eigen显然被ROS(柳树车库),Celestia,Koffice和libmv使用。我看到一些有关UBLAS的闲话,但是遇到一个很难做广告的项目。同上NT2。您能详细说明您听到的哪些好东西吗?
Catskul

在Boost邮件列表的讨论中,关于向Boost添加现代LinAlg库-提到Eigen和NT2都是可能的候选者,但是只有NT2开发人员表示有兴趣追求它。这两个图书馆看起来都不错。如您所说,Eigen更加流行,并且也具有C ++风格。NT2旨在尽可能地模仿MATLAB。
杰夫·哈迪

8

我是这个主题的新手,所以我不能说很多,但是BLAS几乎是科学计算的标准。BLAS实际上是一个API标准,具有许多实现。老实说,我不确定哪个实现最受欢迎或为什么流行。

如果您还希望能够进行常见的线性代数运算(求解系统,最小二乘回归,分解等),请查看LAPACK


7

那么GLM呢?

它基于OpenGL阴影语言(GLSL)规范,并在MIT许可下发布。明确针对图形程序员


好吧,它提供了图形编程向量和矩阵。它引入了大量开销以保持与GLSL的兼容性(如果您可以在GLSL中做到这一点,通常在GLSL中这样做尤其好,尤其是在GL 4.x中),并且错过了许多图形编程原语(平截头体,AABB,BB,椭圆体) )。它的肥胖界面非常肥胖。如果它具有通过某些代码生成生成的“ .xyzz()”函数,则更好的选择是。当您必须对opengl应用程序进行原型设计并开始在较大的项目中显示其负面影响时,它是完美的选择。永远不要编写数学库。
CoffeDeveloper 2015年

5

我将为Eigen投票:我将来自不同库的许多代码(3D几何,线性代数和微分方程)移植到了该库中-几乎在所有情况下都提高了性能和代码可读性。

没有提到的一个优点:与Eigen一起使用SSE非常容易,这可以显着提高2D-3D操作的性能(可以将所有内容填充为128位)。


1
整个“如果您这样做,那么请确保...”这件事使我感到有些震惊。到目前为止,我已经两次遇到这些问题,并且我才刚刚开始使用它。我确实希望不要让未来的开发人员负担每个包含的每个库的各种特性:特别是如果每​​次有成员时都没有使用某些宏,对齐问题就会崩溃,并且它们已经为各个函数散布了功能跨多个标头的类。单独使用它可能不会阻止我选择它,但是它发出了一些危险信号。
Catskul

1
对齐和该宏仅在您使用SSE时才重要,而这绝不是必需的。而且,如果您确实使用SIMD,则无论使用哪种库,这些问题都会引起。至少Eigen不仅会崩溃,而且还会提供有意义的错误消息,直接指出问题所在。
ima

还有一种避免对齐宏的简单方法-使用指针或引用作为成员。
ima

1
我不认为那是真的。我没有使用特殊的SSE选项,并将其与stl容器一起使用后发生了几次崩溃。是的,我知道它会为您提供有用的信息,是的,我知道有特殊说明,但这是我的意思。我不想为其他开发人员的每个包含的库提供特殊的说明。例如,“不按价值传递”的东西太多了。
Catskul

我刚刚发现,最新的开发分支具有一些定义,您可以用来关闭对齐并避免相关的问题。
Catskul

4

好吧,我想我知道您在寻找什么。正如Reed Copsey所建议的那样,GGT似乎是一个很好的解决方案。

就个人而言,我们推出了自己的小图书馆,因为我们处理了很多有理问题-很多有理NURBS和Beziers。

事实证明,大多数3D图形库都使用投影点进行计算,而投影点在投影数学中没有基础,因为这正是您想要的答案。我们最终使用了Grassmann点,这些点具有扎实的理论基础并减少了点类型的数量。得益于强大的理论,Grassmann点基本上与人们现在使用的计算相同。最重要的是,它使事情更加清晰明了,因此我们的bug更少了。罗恩·戈德曼(Ron Goldman)写了一篇关于格拉斯曼计算机图形学的论文,名为计算机图形学的代数和几何基础》

与您的问题没有直接关系,但很有趣。


这是故意开放的,因为我不知道要进行哪些折衷。可以公平地说,几何是我们的主要关注点,几何的尺寸尚不清楚。目前,它是2/3(2 +时间),并且可能会很高(3dims +时间+多点成本图)。
Catskul

我同意这个问题。例如,许多这类应用程序需要实时(一致的时间行为)性能,而其他许多应用程序则可以很好地放弃一致性和/或速度以提高准确性。
TED

那么,您是说在您调查的图书馆中,没有一个图书馆负责NURBS和Beziers吗?是否有某些特殊原因不采用现有的任何一个库并在其旁边建立NURBS和Bezier支持?
Catskul

我要说的是,有理数NURBS和贝塞尔曲线比大多数3d应用程序更多地使用有理数控制点,因此我们犯了更多的错误。通常,大多数3d应用程序只有经过透视变换后才具有原始3d点和矢量。我们的许多算法必须能够正确处理加权/有理/投影和笛卡尔点,以及来回移动等
。– tfinniga


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.