我尝试使用稀疏QR和LU来解决我的FEA程序中的复杂情况,似乎QR和BiCGSTAB方法无法获得正确的结果。 同时BiCGSTAB与IncompleteLUT是可以的。 Eigen版本3.3.1,mingw-x86_64 gcc 6.2
最小代码
#include <vector>
#include <complex>
#include <iostream>
#include <Eigen/Eigen>
using namespace std::complex_literals;
struct mat_cell
{
int row;
int col;
double value;
};
// matrix data.
mat_cell mat01[]={
{ 0, 0, 40432.2974517006}, { 0, 6, -20216.1487258503}, { 0, 12, -20216.1487258503},
{ 1, 1, 180.518062136147}, { 1, 7, -90.2590310680736}, { 1, 11, -9025.90310680736},
{ 1, 13, -90.2590310680736}, { 1, 17, 9025.90310680736},
{ 2, 2, 180.518062136147}, { 2, 8, -90.2590310680736}, { 2, 10, 9025.90310680736},
{ 2, 14, -90.2590310680736}, { 2, 16, -9025.90310680736},
{ 3, 3, 456735.213970955}, { 3, 9, -228367.606985477}, { 3, 15, -228367.606985477},
{ 4, 4, 2421773.15749991}, { 4, 8, -9025.90310680736}, { 4, 10, 594294.042611519},
{ 4, 14, 9025.90310680736}, { 4, 16, 594294.042611519},
{ 5, 5, 2421773.15749991}, { 5, 7, 9025.90310680736}, { 5, 11, 594294.042611519},
{ 5, 13, -9025.90310680736}, { 5, 17, 594294.042611519},
{ 6, 0, -20216.1487258503}, { 6, 6, 40432.2974517006}, { 6, 24, -20216.1487258503},
{ 7, 1, -90.2590310680736}, { 7, 5, 9025.90310680736}, { 7, 7, 180.518062136147},
{ 7, 25, -90.2590310680736}, { 7, 29, -9025.90310680736},
{ 8, 2, -90.2590310680736}, { 8, 4, -9025.90310680736}, { 8, 8, 180.518062136147},
{ 8, 26, -90.2590310680736}, { 8, 28, 9025.90310680736},
{ 9, 3, -228367.606985477}, { 9, 9, 456735.213970955}, { 9, 27, -228367.606985477},
{10, 2, 9025.90310680736}, {10, 4, 594294.042611519}, {10, 10, 2421773.15749991},
{10, 26, -9025.90310680736}, {10, 28, 594294.042611519},
{11, 1, -9025.90310680736}, {11, 5, 594294.042611519}, {11, 11, 2421773.15749991},
{11, 25, 9025.90310680736}, {11, 29, 594294.042611519},
{12, 0, -20216.1487258503}, {12, 12, 20216.1487258503},
{13, 1, -90.2590310680736}, {13, 5, -9025.90310680736}, {13, 13, 90.2590310680736},
{13, 17, -9025.90310680736},
{14, 2, -90.2590310680736}, {14, 4, 9025.90310680736}, {14, 14, 90.2590310680736},
{14, 16, 9025.90310680736},
{15, 3, -228367.606985477}, {15, 15, 228367.606985477},
{16, 2, -9025.90310680736}, {16, 4, 594294.042611519}, {16, 14, 9025.90310680736},
{16, 16, 1210886.57874995},
{17, 1, 9025.90310680736}, {17, 5, 594294.042611519}, {17, 13, -9025.90310680736},
{17, 17, 1210886.57874995},
{18, 18, 40432.2974517006}, {18, 24, -20216.1487258503},
{19, 19, 180.518062136147}, {19, 25, -90.2590310680736}, {19, 29, 9025.90310680736},
{20, 20, 180.518062136147}, {20, 26, -90.2590310680736}, {20, 28, -9025.90310680736},
{21, 21, 456735.213970955}, {21, 27, -228367.606985477},
{22, 22, 2421773.15749991}, {22, 26, 9025.90310680736}, {22, 28, 594294.042611519},
{23, 23, 2421773.15749991}, {23, 25, -9025.90310680736}, {23, 29, 594294.042611519},
{24, 6, -20216.1487258503}, {24, 18, -20216.1487258503}, {24, 24, 40432.2974517006},
{25, 7, -90.2590310680736}, {25, 11, 9025.90310680736}, {25, 19, -90.2590310680736},
{25, 23, -9025.90310680736}, {25, 25, 180.518062136147},
{26, 8, -90.2590310680736}, {26, 10, -9025.90310680736}, {26, 20, -90.2590310680736},
{26, 22, 9025.90310680736}, {26, 26, 180.518062136147},
{27, 9, -228367.606985477}, {27, 21, -228367.606985477}, {27, 27, 456735.213970955},
{28, 8, 9025.90310680736}, {28, 10, 594294.042611519}, {28, 20, -9025.90310680736},
{28, 22, 594294.042611519}, {28, 28, 2421773.15749991},
{29, 7, -9025.90310680736}, {29, 11, 594294.042611519}, {29, 19, 9025.90310680736},
{29, 23, 594294.042611519}, {29, 29, 2421773.15749991}};
int main(int argc, char *argv[])
{
int nn{30};
Eigen::MatrixXcd A_dens = Eigen::MatrixXcd::Zero(nn, nn);
Eigen::VectorXcd rhs = Eigen::VectorXcd::Zero(nn);
Eigen::SparseMatrix<std::complex<double>> A_sp(nn, nn);
std::vector<Eigen::Triplet<std::complex<double>>> triList;
double yita{0.02};// small imag.
for(auto const cell: mat01){
A_dens(cell.row, cell.col) = cell.value*(1.+yita*1.0i);
triList.push_back({cell.row, cell.col, cell.value*(1.+yita*1.0i)});
}
A_sp.setFromTriplets(triList.begin(), triList.end());
triList.clear();
A_sp.makeCompressed();
int ix[]={12, 13, 14};
double scale{1.e60};// Large than 1e38.
for(auto const j: ix){
A_dens(j, j) *= scale;
A_sp.coeffRef(j, j) *= scale;
}
rhs(ix[1]) = 0.618*A_sp.coeff(ix[1], ix[1]);
// solve by dense LU method.
Eigen::VectorXcd x_lu = A_dens.lu().solve(rhs);
// define sparse solver.
Eigen::SparseLU<Eigen::SparseMatrix<std::complex<double>>, Eigen::COLAMDOrdering<int>> solver_lu;
Eigen::SparseQR<Eigen::SparseMatrix<std::complex<double>>, Eigen::COLAMDOrdering<int>> solver_qr;
Eigen::BiCGSTAB<Eigen::SparseMatrix<std::complex<double>>> solver_bi;
Eigen::BiCGSTAB<Eigen::SparseMatrix<std::complex<double>>, Eigen::IncompleteLUT<std::complex<double>, int>> solver_bi_2;
solver_lu.compute(A_sp);
if(solver_lu.info()!=Eigen::ComputationInfo::Success)std::cout << "SparseLU decomposition failed!\n";
Eigen::VectorXcd x_sp_lu = solver_lu.solve(rhs);
if(solver_lu.info()!=Eigen::ComputationInfo::Success)std::cout << "SparseLU solve failed!\n";
solver_qr.compute(A_sp);
if(solver_qr.info()!=Eigen::ComputationInfo::Success)std::cout << "SparseQR decomposition failed!\n";
Eigen::VectorXcd x_sp_qr = solver_qr.solve(rhs);
if(solver_qr.info()!=Eigen::ComputationInfo::Success)std::cout << "SparseQR solve failed!\n";
solver_bi.compute(A_sp);
if(solver_bi.info()!=Eigen::ComputationInfo::Success)std::cout << "SparseBi decomposition failed!\n";
Eigen::VectorXcd x_sp_bi = solver_bi.solve(rhs);
if(solver_bi.info()!=Eigen::ComputationInfo::Success)std::cout << "SparseBi solve failed!\n";
solver_bi_2.compute(A_sp);
if(solver_bi_2.info()!=Eigen::ComputationInfo::Success)std::cout << "SparseBi2 decomposition failed!\n";
Eigen::VectorXcd x_sp_bi_2 = solver_bi_2.solve(rhs);
if(solver_bi_2.info()!=Eigen::ComputationInfo::Success)std::cout << "SparseBi2 solve failed!\n";
std::cout << "No | Dense LU | SparseLU | SparseQR | BiCGSTAB |BiCGSTAB+ILUT|\n";
std::cout << "---|---|---|---|---|---|\n";
for(int i=0; i<nn; i++){
std::cout << i << "|";
std::cout << x_lu(i) << "|";
std::cout << x_sp_lu(i) << "|";
std::cout << x_sp_qr(i) << "|";
std::cout << x_sp_bi(i) << "|";
std::cout << x_sp_bi_2(i) << "|\n";
}
}
方法 X(1)X(5)
DenseLU (0.435087,-1.73121e-017)(0.0008897,7.91857e-020)
SparseLU (0.435087,3.61979e-017)(0.0008897,-1.2936e-019)
SparseQR (0,0)(0,0)
BiCGSTAB (0.187474,-8.66607e-019)(0.00139743,-2.34841e-021)
BiCGSTAB + ILUT (0.435068,1.58791e-017)(0.000889823,-1.00545e-019)
答案 0 :(得分:0)
你的矩阵非常奇异。对于双精度数字,矩阵的等级仅为3,因为您对3列进行了奇怪的缩放。因此,您的问题有一个无限的解决方案空间。如果您查看相对错误:(A*x-b).norm()/b.norm()
,则会得到:
No | Dense LU | SparseLU | SparseQR | BiCGSTAB |BiCGSTAB+ILUT
--- | ---------- | ---------- | ---------- | ---------- |-------------
res | 3.6633e-74 | 1.4915e-74 | 3.1977e-18 | 1.9095e-59 | 2.67692e-63
意味着关于双精度浮点数的精度,所有结果都是“正确的”。