我最近从Eigen 3.2.0到3.3.4推出了使用一些基本向量数学和SelfAdjointEigenSolver
的代码。该代码是使用Matlab进行原型设计的,并同意3.2.0。滚动到3.3.4的动机是为了避免在C ++ 11(及更高版本)和3.2.0中发生一些警告和错误。
该代码通过将成千上万的点读入Eigen::Matrix<double, Eigen::Dynamic, 3>
来工作。当我使用gdb检查值时,输入值是相同的。下面显示了一段显示数值差异的代码。 pilType
被定义为double
。
// this is the point cloud, center it about the origin
Eigen::Matrix<pilType, 1, 3> center = gridPnts.colwise().mean();
gridPnts.rowwise() -= center;
// Get the transformation matrix to align the point cloud with it's normal
// Build the co variance matrix
Eigen::Matrix<double, 3, 3> S = gridPnts.transpose() * gridPnts;
S /= static_cast<pilType>(gridPnts.rows() - 1);
Eigen::SelfAdjointEigenSolver<pilMat3> es(S);
Eigen::Matrix<pilType, 3, 2> trans;
trans = es.eigenvectors().block<3, 2>(0, 1);
// convert the point cloud to 2D for Convex Hull calculation
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> output(gridPnts.rows(), 2);
output = gridPnts * trans;
我正在使用GCC 5.3.0编译新版本,标志-std = c ++ 11 -O3 -DEIGEN_NO_DEBUG -Wall -Wextra -Werror -march = native -mtune = native。我已经尝试过是否带有进行曲和调整选项。旧版本使用GCC 4.3.4和标志-O3 -DEIGEN_NO_DEBUG -Wall -Wextra -Werror编译。 CPU是运行SuSE Enterprise SLES 11的SandyBridge E5-2670。区别在于S
除以点数-1之后开始。它们很小,大约为1e-12,但是当它出现时对于本征解,非常接近0的值可能会导致本征向量的符号改变。这导致转换矩阵在一个轴上切换。结果输出沿该轴翻转。将生成的2D补丁发送到例程以查找凸包。返回相同的点,但由于轴翻转而以相反的顺序返回。这不是错误,但出乎意料。
实际上,在整个应用程序中,各种数字在1e-12至1e-15范围内显示出差异。
在使用GDB运行时,有一些值(最高值来自3.3.4版,最低值来自3.2.0版)
S
除法之前:
Eigen::Matrix<double,3,3,ColMajor> (data ptr: 0x7fffffffb0b0) = {[0,0] = 3532221.7020642869,
[1,0] = 1.0913936421275139e-11, [2,0] = 3332.4628071428679, [0,1] = 1.0913936421275139e-11,
[1,1] = 335265.83999999962, [2,1] = -1.3073986337985843e-12, [0,2] = 3332.4628071428679,
[1,2] = -1.3073986337985843e-12, [2,2] = 4697.4509785714226}
Eigen::Matrix<double,3,3,ColMajor> (data ptr: 0x7fffffffb8f0) = {[0,0] = 3532221.7020642869,
[1,0] = 1.0913936421275139e-11, [2,0] = 3332.4628071428679, [0,1] = 1.0913936421275139e-11,
[1,1] = 335265.83999999962, [2,1] = -1.3073986337985843e-12, [0,2] = 3332.4628071428679,
[1,2] = -1.3073986337985843e-12, [2,2] = 4697.4509785714226}
S
除后
Eigen::Matrix<double,3,3,ColMajor> (data ptr: 0x7fffffffb0b0) = {[0,0] = 21151.028156073575,
[1,0] = 6.5352912702246338e-14, [2,0] = 19.954867108639927, [0,1] = 6.5352912702246338e-14,
[1,1] = 2007.5798802395186, [2,1] = -7.8287343341232597e-15, [0,2] = 19.954867108639927,
[1,2] = -7.8287343341232597e-15, [2,2] = 28.128448973481571}
Eigen::Matrix<double,3,3,ColMajor> (data ptr: 0x7fffffffb8f0) = {[0,0] = 21151.028156073575,
[1,0] = 6.5352912702246351e-14, [2,0] = 19.954867108639927, [0,1] = 6.5352912702246351e-14,
[1,1] = 2007.5798802395188, [2,1] = -7.8287343341232597e-15, [0,2] = 19.954867108639927,
[1,2] = -7.8287343341232597e-15, [2,2] = 28.128448973481575}
在执行本征解之后,trans
的值是:
{[0,0] = 3.4096942364292876e-18, [1,0] = -1,
[2,0] = 3.9893751393767394e-18, [0,1] = 0.99999955376919869, [1,1] = 3.4134614846087836e-18,
[2,1] = 0.00094470175363752104}
{[0,0] = 0, [1,0] = 1,
[2,0] = -3.2750362278258563e-15, [0,1] = 0.9999995537691988, [1,1] = 3.093932467653499e-18,
[2,1] = 0.00094470175363752125}
公认的数值差异很小,并且在准确性的范围内。在所示的数字中,转换矩阵的符号翻转,从而导致2D云翻转。是否有办法清理所做的工作,以消除这些差异?我见过一些Eigen
函数,这些函数的阈值较小,但没有除法函数。
答案 0 :(得分:2)
您根本不应该依赖特征向量的符号(无论求解器和库如何),而应根据需要进行调整。例如,如果您想确保有一个惯用右手的基础,请从前两个叉号的叉积更新最后一个。
答案 1 :(得分:0)
Eigen用version 3.2.7计算标量除法的方式发生了变化。
operator / =(Scalar)现在执行真正的除法(而不是mat *(1 / s))
使用S *= 1.0 / (static_cast<pilType>(gridPnts.rows() - 1));
测试代码表明数字差异已解决。