将代码从 Eigen2 移植到 Eigen3 时的奇怪行为

Strange behaviours in porting code from Eigen2 to Eigen3

我正在考虑使用 this 库在我的研究项目中执行光谱聚类。

但是,为此,我需要将它从 Eigen2 移植到 Eigen3(这是我在代码中使用的)。

有一部分代码给我带来了一些麻烦。

这是针对 Eigen2 的:

double Evrot::evqual(Eigen::MatrixXd& X) {
    // take the square of all entries and find max of each row
    Eigen::MatrixXd X2 = X.cwise().pow(2);
    Eigen::VectorXd max_values = X2.rowwise().maxCoeff();

    // compute cost
    for (int i=0; i<mNumData; i++ ) {
        X2.row(i) = X2.row(i) / max_values[i];
    }
    double J = 1.0 - (X2.sum()/mNumData -1.0)/mNumDims;
    if( DEBUG )
        std::cout << "Computed quality = "<< J << std::endl;

    return J;
}

here 所述,Eigen3 用略有不同的 .array() 功能替换了 .cwise()。

所以,我写道:

double Evrot::evqual(Eigen::MatrixXd& X) {
    // take the square of all entries and find max of each row
    Eigen::MatrixXd X2 = X.array().pow(2);

    Eigen::VectorXd max_values = X2.rowwise().maxCoeff();

    // compute cost
    for (int i=0; i<mNumData; i++ ) {
        X2.row(i) = X2.row(i) / max_values[i];
    }
    double J = 1.0 - (X2.sum()/mNumData -1.0)/mNumDims;
    if( DEBUG )
        std::cout << "Computed quality = "<< J << std::endl;

    return J;
}

而且我没有遇到编译器错误。

但是,如果我给两个程序相同的输入(并检查它们实际上得到一致的输入),在第一种情况下我得到数字,在第二种情况下我只得到 NAN。

我的想法是,这是由于 max_values 计算错误,然后在除法中使用此向量导致所有 NAN。但是我不知道如何解决这个问题。

谁能告诉我如何解决这个问题?

谢谢!

您是否检查过值何时开始出现差异?您确定没有空行或 X^2 没有下溢吗?无论如何,在除以 max_values[i] 之前你应该有一个守卫。此外,为了避免平方中的下溢,您可以这样重写它:

VectorXd max_values = X.array().abs().rowwise().maxCoeff();
double sum = 0;
for (int i=0; i<mNumData; i++ ) {
  if(max_values[i]>0)
    sum += (X.row(i)/max_values[i]).squaredNorm();
}
double J = 1.0 - (sum/mNumData -1.0)/mNumDims;

即使 X.abs().maxCoeff()==1e-170 这也会起作用,而您的代码将下溢并产生 NaN。当然,如果您遇到这种情况,也许您应该先检查您的输入,因为您在数字问题上已经处于危险的一面。