LAPACKE_dgesvd的Intel MKL不匹配结果

问题描述 投票:0回答:1

我在我的代码中有一个对LAPACKE_dgesvd函数的调用。该代码由自动测试覆盖。在编译器迁移后,我们决定将MKL也从11.3.4升级到2019.0.5。

测试变成红色。经过深入研究,我发现此函数不再返回相同的U&V矩阵。

我提取了代码,并使其在单独的环境/项目中运行并具有相同的观察结果。观察结果是U的第一列和V的第一行具有相反的符号

您能告诉我我在做什么错吗?还是应该使用新版本来获得旧结果?

我做了一个简单的项目,可以轻松地重现该问题。这是代码:

// MKL.cpp : This file contains the 'main' function. Program execution begins and ends there
#include <iostream>
#include <algorithm>
#include <mkl.h>

int main()
{
    const int rows(3), cols(3);
    double covarMatrix[rows*cols] = { 0.9992441421012894, -0.6088405718211041, -0.4935146797825398,
                            -0.6088405718211041, 0.9992441421012869, -0.3357678733652218, 
                            -0.4935146797825398, -0.3357678733652218, 0.9992441421012761};
    double U[rows*rows] = { -1,-1,-1,
                    -1,-1,-1,
                    -1,-1,-1 };
    double V[cols*cols] = { -1,-1,-1,
                    -1,-1,-1,
                    -1,-1,-1 };
    double superb[std::min(rows, cols) - 1];
    double eigenValues[std::max(rows, cols)];

    MKL_INT info = LAPACKE_dgesvd(LAPACK_ROW_MAJOR, 'A', 'A',
        rows, cols, covarMatrix, cols, eigenValues, U, rows, V, cols, superb);

    if (info > 0)
        std::cout << "not converged!\n";

    std::cout << "U\n";
    for (int row(0); row < rows; ++row)
    {
        for (int col(0); col < rows; ++col)
            std::cout << U[row * rows + col] << " ";
        std::cout << std::endl;
    }

    std::cout << "V\n";
    for (int row(0); row < cols; ++row)
    {
        for (int col(0); col < cols; ++col)
            std::cout << V[row * rows + col] << " ";
        std::cout << std::endl;
    }

    std::cout << "Converged!\n";
}

这里有更多的数字解释:

A = 0.9992441421012894,-0.6088405718211041,-0.4935146797825398,-0.6088405718211041、0.9992441421012869,-0.3357678733652218,-0.4935146797825398,-0.3357678733652218,0.9992441421012761

结果:

11.3.4 2019.0.5&2020.1.216

U

-0.765774 -0.13397 0.629 0.765774 -0.13397 0.6290.575268 -0.579935 0.576838 -0.575268 -0.579935 0.5768380.2875 0.803572 0.521168 -0.2875 0.803572 0.521168

V

-0.765774 0.575268 0.2875 0.765774 -0.575268 -0.2875-0.13397 -0.579935 0.803572 -0.13397 -0.579935 0.8035720.629 0.576838 0.521168 0.629 0.576838 0.521168

我使用scipy测试,结果与11.3.4版本相同。

from scipy import linalg
from numpy import array

A = array([[0.9992441421012894, -0.6088405718211041, -0.4935146797825398], [-0.6088405718211041, 0.9992441421012869, -0.3357678733652218], [-0.4935146797825398, -0.3357678733652218, 0.9992441421012761]])
print(A)
u,s,vt,info = linalg.lapack.dgesvd(A)
print(u)
print(s)
print(vt)
print(info)

感谢您的帮助和最诚挚的问候

Mokhtar

c++ windows intel-mkl
1个回答
0
投票

奇异值分解不是唯一的。例如,如果我们进行了SVD分解(例如,一组矩阵U,S,V),从而A = U * S * V ^ T,则该组矩阵(-U,S,-V)也是SVD因为(-U)S (-V ^ T)= U S V ^ T =A。 U D,S,V D也是SVD分解,因为(U D)S D V ^ T = U S * V ^ T = A。

因为通过比较两组矩阵来验证SVD分解不是一个好主意。与许多其他出版物一样,《 LAPACK用户指南》建议检查计算的SVD分解的以下条件:1. || A V – U S || / || A ||应该足够小2. || U ^ T * U –我||接近零3. || V ^ T * V – I ||接近零4.对角线S的所有对角线项必须为正,并以降序排列。上面给出的所有表达式的错误范围可以在https://www.netlib.org/lapack/lug/node97.html

中找到

因此,后文中提到的两个MKL版本都返回满足所有4个误差范围的奇异值和奇异矢量。既然如此,并且由于SVD不是唯一的,因此两种结果都是正确的。第一个奇异矢量的符号发生变化是因为对于非常小的矩阵,开始使用另一种更快的方法来简化为对角线形式。

© www.soinside.com 2019 - 2024. All rights reserved.