C++ 向量*矩阵产品效率问题

C++ 向量*矩阵产品效率问题,c++,c,matrix,sse,simd,C++,C,Matrix,Sse,Simd,正如Z玻色子一样,我使用了列主矩阵格式,以避免使用点积。不过,当向量与矩阵相乘时,我看不到一种可行的方法来避免它。矩阵乘法技巧需要有效地提取行(或列,如果我们转置乘积的话)。因此,要将向量乘以矩阵,我们需要转置: (b * A)^T = A^T * b^T A是一个矩阵,b是一个行向量,经过转置后成为列向量。它的行只是单标量,向量*矩阵乘积实现成为(非转置)矩阵A与b列的点积的低效实现。有没有办法避免执行这些dot产品?我认为唯一可以做到这一点的方法是行提取,这对于列主矩阵格式来说效率很低。这

正如Z玻色子一样,我使用了列主矩阵格式,以避免使用点积。不过,当向量与矩阵相乘时,我看不到一种可行的方法来避免它。矩阵乘法技巧需要有效地提取行(或列,如果我们转置乘积的话)。因此,要将向量乘以矩阵,我们需要转置:

(b * A)^T = A^T * b^T

A
是一个矩阵,
b
是一个行向量,经过转置后成为列向量。它的行只是单标量,向量*矩阵乘积实现成为(非转置)矩阵
A
b
列的点积的低效实现。有没有办法避免执行这些dot产品?我认为唯一可以做到这一点的方法是行提取,这对于列主矩阵格式来说效率很低。

这可以从关于这一点的原始文章(我的第一篇文章)中理解 . 其余讨论适用于4x4矩阵

这里有两种做矩阵乘以向量的方法(v=Mu,其中v和u是列向量)

第一种方法在数学课上更为常见,而第二种方法在SIMD计算机上更为有效。第二种方法使用矢量化数学(如numpy)

现在让我们看看向量乘以矩阵(v=uM,其中v和u是行向量)

现在,列和行的角色已经交换,但方法2仍然是SIMD计算机上使用的有效方法

为了在SIMD计算机上有效地进行矩阵乘以向量运算,矩阵应按列主顺序存储。要在SIMD计算机上有效地执行向量乘以矩阵,矩阵应按行的主要顺序存储

据我所知,OpenGL使用列主排序和矩阵乘以向量,DirectX使用行主排序和向量乘以矩阵。 若你们有三个矩阵变换,你们先按M1的顺序,然后按M2的顺序,然后按M3的顺序,用矩阵乘以向量,把它写成

v = M3*M2*M1*u //u and v are column vectors - OpenGL form
用向量乘以你写的矩阵

v = u*M1*M2*M3 //u and v are row vectors - DirectX form
就效率而言,两种形式都不比另一种好。这只是一个表示法的问题(当你有竞争时会引起混乱)

需要注意的是,对于矩阵*矩阵,行主存储与列主存储是无关的


如果您想知道为什么垂直SIMD指令比水平SIMD指令快,这是一个单独的问题,应该提出,但简言之,水平SIMD指令实际上是串行而不是并行运行的,并且被分解为几个微操作(这就是为什么具有讽刺意味的是
dppd
dpps
快的原因)

这个问题更适合“哗众取宠”,为什么?我愿意改进/改变这个问题。@Claptrap:我不确定为什么程序员会更适合……你不能交换循环嵌套吗?(即保持N个部分和,而不是按顺序计算每个完整的输出值)。@OliCharlesworth只是不说数学家。他们可能只是翻白眼,说一些我们这些可怜的外行/熟练工听不懂的话。简言之,如果矩阵是按列大顺序排列的,那么如果不进行转置、提取行或做点积,就不能使用这个技巧?一次做1个点积以上(比如说,一次4个点积),也就是说,为了避免点积指令,你在矩阵乘法代码中做了什么。@user1095108,是的,这是正确的。如果你不能改变矩阵的顺序,那么你要么做转置,要么做点积。在这种情况下,方法1更快。你是说4x4矩阵吗?你的目标是什么?你写道“你几乎不想用SSE做两个向量的点积,而是一次做四个点积”,我认为这条规则每次都可以有效地应用(显然不行)。我尝试将您的规则应用于向量矩阵(b*A)与矩阵2x2到4x4的乘法(我确实注意到,它可以应用于colmatrix和matrixmatrix乘法的w/o问题),但无法。但是向量*矩阵积也需要在通用矩阵库中得到支持,即使它们很少被计算。@user1095108,您可以使用“我的规则”,只需先进行转置即可。但是,欢迎您尝试横向说明,看看它们是否对这种特殊情况产生影响。
method 1) v1 = dot(col1, u), v2 = dot(col2, u), v3 = dot(col3, u), v4 = dot(col4, u)
method 2) v = u1*row1 + u2*row2 + u3*row3 + u4*row4.
v = M3*M2*M1*u //u and v are column vectors - OpenGL form
v = u*M1*M2*M3 //u and v are row vectors - DirectX form