使用犰狳进行基准测试时,SuperLu 和 LaPack 的比较失败
Comparison of SuperLu and LaPack fails when benchmarking with armadillo
我想比较 SuperLu 的稀疏求解器和在犰狳中使用 spsolve()
时使用 LaPack 的密集版本的速度。因此我写了这个程序:
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <armadillo\armadillo>
#define SIZE 2500
#define ROUNDS 2500
int main()
{
//Time measurement stuff
LARGE_INTEGER frequency;
LARGE_INTEGER t1, t2, t3, t4;
QueryPerformanceFrequency(&frequency);
//Other stuff
arma::cx_colvec b = arma::randu<arma::cx_colvec>(SIZE);
arma::cx_colvec b1 = b, b2 = b;
arma::sp_cx_mat A = arma::sp_cx_mat(SIZE, SIZE);
A.diag(-2).fill(-1);
A.diag(-1).fill(16);
A.diag(0).fill(-30);
A.diag(1).fill(16);
A.diag(2).fill(-1);
arma::cx_colvec c = arma::zeros<arma::cx_colvec>(SIZE), d = arma::zeros<arma::cx_colvec>(SIZE);
QueryPerformanceCounter(&t1);
for (size_t i = 0; i < ROUNDS; i++)
{
if(arma::spsolve(c, A, b1, "superlu") == false)
{
std::cout << "Error in round 1\n";
break;
}
b1 = c;
}
QueryPerformanceCounter(&t2);
QueryPerformanceCounter(&t3);
for (size_t i = 0; i < ROUNDS; i++)
{
if(arma::spsolve(d, A, b2, "lapack") == false)
{
std::cout << "Error in round 2\n";
break;
}
b2 = d;
}
QueryPerformanceCounter(&t4);
std::cout << "Superlu took " << (t2.QuadPart - t1.QuadPart)*1000.0 / frequency.QuadPart << '\n';
std::cout << "Lapack took " << (t4.QuadPart - t3.QuadPart)*1000.0 / frequency.QuadPart << '\n';
std::cout << "Both results are equal: " << arma::approx_equal(b1, b2, "abstol", 1e-5) << '\n';
return 0;
}
现在对于 SIZE
和 ROUND
的小值,函数 approx_equal
returns 为真,但对于较大的值,结果 b1
和 b2
根据 approx_equal
不再相等。为什么?会不会是我的superlu-library没有正常使用?
我不会责怪 SuperLU 库。这里的"issue"好像是矩阵A
的最小特征值随着SIZE
的值越来越大越来越小。现在,for
循环重复将 inv(A)
应用于给定向量。由于您开始的向量是随机的,因此 A
的特征向量的一些非零 "admixture" 对应于最小的特征值。如果反演重复多次,该分量会显着放大,因此矢量的各个分量 b1/b2
会变大。
例如,对于 SIZE=2000
和 ROUNDS=2
,我得到解的最大分量(绝对值)在 10^9
附近。然后,您的测试似乎规定了 10^-5
的 绝对公差 。然而,对于如此大的数字,这意味着 14 位有效数字必须完全匹配,这几乎是双精度的极限。
在我看来,鉴于这里比较的数字的性质,测试更有意义,例如 approx_equal(b1, b2, "reldiff", 1E-8)
.
的相对误差
此外,应该检查解决方案实际上是否有意义 - 对于大量 ROUNDS
,它迟早会溢出。例如,已经有了 SIZE=2000
和 ROUNDS=80
,我在 b1/b2
向量中得到无穷大...
我想比较 SuperLu 的稀疏求解器和在犰狳中使用 spsolve()
时使用 LaPack 的密集版本的速度。因此我写了这个程序:
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <armadillo\armadillo>
#define SIZE 2500
#define ROUNDS 2500
int main()
{
//Time measurement stuff
LARGE_INTEGER frequency;
LARGE_INTEGER t1, t2, t3, t4;
QueryPerformanceFrequency(&frequency);
//Other stuff
arma::cx_colvec b = arma::randu<arma::cx_colvec>(SIZE);
arma::cx_colvec b1 = b, b2 = b;
arma::sp_cx_mat A = arma::sp_cx_mat(SIZE, SIZE);
A.diag(-2).fill(-1);
A.diag(-1).fill(16);
A.diag(0).fill(-30);
A.diag(1).fill(16);
A.diag(2).fill(-1);
arma::cx_colvec c = arma::zeros<arma::cx_colvec>(SIZE), d = arma::zeros<arma::cx_colvec>(SIZE);
QueryPerformanceCounter(&t1);
for (size_t i = 0; i < ROUNDS; i++)
{
if(arma::spsolve(c, A, b1, "superlu") == false)
{
std::cout << "Error in round 1\n";
break;
}
b1 = c;
}
QueryPerformanceCounter(&t2);
QueryPerformanceCounter(&t3);
for (size_t i = 0; i < ROUNDS; i++)
{
if(arma::spsolve(d, A, b2, "lapack") == false)
{
std::cout << "Error in round 2\n";
break;
}
b2 = d;
}
QueryPerformanceCounter(&t4);
std::cout << "Superlu took " << (t2.QuadPart - t1.QuadPart)*1000.0 / frequency.QuadPart << '\n';
std::cout << "Lapack took " << (t4.QuadPart - t3.QuadPart)*1000.0 / frequency.QuadPart << '\n';
std::cout << "Both results are equal: " << arma::approx_equal(b1, b2, "abstol", 1e-5) << '\n';
return 0;
}
现在对于 SIZE
和 ROUND
的小值,函数 approx_equal
returns 为真,但对于较大的值,结果 b1
和 b2
根据 approx_equal
不再相等。为什么?会不会是我的superlu-library没有正常使用?
我不会责怪 SuperLU 库。这里的"issue"好像是矩阵A
的最小特征值随着SIZE
的值越来越大越来越小。现在,for
循环重复将 inv(A)
应用于给定向量。由于您开始的向量是随机的,因此 A
的特征向量的一些非零 "admixture" 对应于最小的特征值。如果反演重复多次,该分量会显着放大,因此矢量的各个分量 b1/b2
会变大。
例如,对于 SIZE=2000
和 ROUNDS=2
,我得到解的最大分量(绝对值)在 10^9
附近。然后,您的测试似乎规定了 10^-5
的 绝对公差 。然而,对于如此大的数字,这意味着 14 位有效数字必须完全匹配,这几乎是双精度的极限。
在我看来,鉴于这里比较的数字的性质,测试更有意义,例如 approx_equal(b1, b2, "reldiff", 1E-8)
.
此外,应该检查解决方案实际上是否有意义 - 对于大量 ROUNDS
,它迟早会溢出。例如,已经有了 SIZE=2000
和 ROUNDS=80
,我在 b1/b2
向量中得到无穷大...