繁体   English   中英

使用 C++ 中的特征库定义和填充稀疏矩阵

[英]define and filling a sparse matrix using Eigen Library in C++

我正在尝试使用 C++ 中的 Eigen 或 Armadillo 库构建一个晶石矩阵来求解线性方程组 Ax=b。 A为系数矩阵,维度为n*n,B为右手边向量,维度为n。Spars矩阵A是这样的,见图

我查看了 Eigen 文档,但在用 C++ 定义和填充 Spars 矩阵时遇到了问题。

你能给我一个示例代码来定义spars矩阵以及如何使用C++中的Eigen库将值填充到矩阵中吗?

例如考虑一个简单的spars矩阵A:

1 2 0 0

0 3 0 0

0 0 4 5

0 0 6 7

int main()
{
     SparseMatrix<double> A;

     // fill the A matrix ????

     VectorXd b, x;
     SparseCholesky<SparseMatrix<double> > solver;
     solver.compute(A);

     x = solver.solve(b);
     return 0;
} 

稀疏矩阵可以使用.coeffRef()成员函数填充帖子中提到的值,如下例所示:

SparseMatrix<double> fillMatrix() {
  int N = 4;
  int M = 4;
  SparseMatrix<double> m1(N,M);
  m1.reserve(VectorXi::Constant(M, 4)); // 4: estimated number of non-zero enties per column
  m1.coeffRef(0,0) = 1;
  m1.coeffRef(0,1) = 2.;
  m1.coeffRef(1,1) = 3.;
  m1.coeffRef(2,2) = 4.;
  m1.coeffRef(2,3) = 5.;
  m1.coeffRef(3,2) = 6.;
  m1.coeffRef(3,3) = 7.;
  m1.makeCompressed();
  return m1;
}

但是, SparseCholesky模块 ( SimplicialCholesky<SparseMatrix<double> > ) 在这种情况下不起作用,因为矩阵不是 Hermitian。 该系统可以用 LU 或 BiCGStab 求解器求解。 另请注意,需要定义xb的大小: VectorXd b(A.rows()), x(A.cols());

对于较大的稀疏矩阵,您可能还需要查看.reserve()函数,以便在填充元素之前分配内存。 .reserve()函数可用于估计每列(或每行,取决于存储顺序。默认为 comumn-major)的非零条目数。 在上面的示例中,估计值为 4,但在如此小的矩阵中没有意义。 该文档指出,最好高估每列的非零数

由于这个问题还涉及Armadillo ,因此这里是相应的基于 Armadillo 的代码。 最好使用 Armadillo 9.100+ 或更高版本,并与 SuperLU 链接。

#include <armadillo>

using namespace arma; 

int main()
{
  sp_mat A(4,4);   // don't need to explicitly reserve the number of non-zeros

  // fill with direct element access
  A(0,0) = 1.0;
  A(0,1) = 2.0;
  A(1,1) = 3.0;
  A(2,2) = 4.0;
  A(2,3) = 5.0;
  A(3,2) = 6.0;
  A(3,3) = 7.0;  // etc

  // or load the sparse matrix from a text file with the data stored in coord format
  sp_mat AA;
  AA.load("my_sparse_matrix.txt", coord_ascii)

  vec b; // ... fill b here ...

  vec x = spsolve(A,b);  // solve sparse system

  return 0;
}

另请参阅SpMatelement access 、 .load( )spsolve()的文档。

坐标文件格式很简单。 它存储非零值。 每行包含:

row col value

行数和列数从零开始。 例子:

  0 0 1.0
  0 1 2.0
  1 1 3.0
  2 2 4.0
  2 3 5.0
  3 2 6.0
  3 3 7.0
  1000 2000 9.0

未明确列出的值假定为零。

#include <vector>
#include <iostream>                                  
#include <Eigen/Dense>                               
#include <Eigen/Sparse>                              
#include <Eigen/Core>
#include <cstdlib>

using namespace Eigen;
using namespace std;

int main()
{
//one_d_diffusion();

double L = 5; // Length
const int N = 120; // No of cells
double L_cell = L / N;
double k = 100; // Thermal Conductivity
double T_A = 100.;
double T_B = 200.;
double S = 1000.;

Vector<double, N> d, D, A, aL, aR, aP, S_u, S_p;
vector<double> xp;


xp.push_back((0 + L_cell) / 2.0);
double xm = xp[0];

for (int i = 0; i < N - 1; i++)
{
    xm = xm + L_cell;
    xp.push_back(xm);
}

for (int i = 0; i < N; i++)
{

    A(i) = .1;
    d(i) = L_cell;
    D(i) = k / d(i);
}

aL(0) = 0;
aR(0) = D(0) * A(0);
S_p(0) = -2 * D(0) * A(0);
aP(0) = aL(0) + aR(0) - S_p(0);
S_u(0) = 2 * D(0) * A(0) * T_A + S * L_cell * A(0);

for (int i = 1; i < N - 1; i++)
{
    aL(i) = D(i) * A(i);
    aR(i) = D(i) * A(i);
    S_p(i) = 0;
    aP(i) = aL(i) + aR(i) - S_p(i);
    S_u(i) = S * A(i) * L_cell;
}

aL(N - 1) = D(N - 1) * A(N - 1);
aR(N - 1) = 0;
S_p(N - 1) = -2 * D(N - 1) * A(N - 1);
aP(N - 1) = aL(N - 1) + aR(N - 1) - S_p(N - 1);
S_u(N - 1) = 2 * D(N - 1) * A(N - 1) * T_B + S * L_cell * A(N - 1);

typedef Eigen::Triplet<double> T;
std::vector<T> tripletList;
tripletList.reserve(N * 3);

Matrix<double, N, 3> v; ///   v is declared here

v << (-1) * aL, aP, (-1)* aR;

for (int i = 0, j = 0; i < N && j < N; i++, j++)
{
    tripletList.push_back(T(i, j, v(i, 1)));

    if (i + 1 < N && j + 1 < N)
    {
        tripletList.push_back(T(i + 1, j, v(i + 1, 0)));
        tripletList.push_back(T(i, j + 1, v(i, 2)));
    }
}
SparseMatrix<double> coeff(N, N);
coeff.setFromTriplets(tripletList.begin(), tripletList.end());

SimplicialLDLT<SparseMatrix<double> > solver;
solver.compute(coeff);

if (solver.info() != Success) {
    cout << "decomposition failed" << endl;
    return;
}

Vector<double, N> temparature;

temparature = solver.solve(S_u);

if (solver.info() != Success)
{
    cout << "Solving failed" << endl;
    return;
}

vector<double> Te = {}, x = {};

Te.push_back(T_A);
x.push_back(0);

for (int i = 0; i < N; i++)
{
    Te.push_back(temparature(i));
    x.push_back(xp[i]);
}

Te.push_back(T_B);
x.push_back(L);
for (int i = 0; i < N + 2; i++)
{
    cout << x[i] << " " << Te[i] << endl;
}

return 0;

}

这是一个数值问题的完整代码。 查看矩阵v 它具有所有非零元素。 在下一个循环中,我制作了一系列Tripletlist.push_back(.....)及其索引和值。 这些值将在其伴随的索引处保持稀疏矩阵的位置。 现在声明一个具有大小的稀疏矩阵并使用函数setFromTroplets(....) ,你将拥有你的稀疏矩阵。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM