简体   繁体   English

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

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

I am trying to build a spars Matrix using a Eigen or Armadillo library in C++ to solve a system of linear equations Ax=b.我正在尝试使用 C++ 中的 Eigen 或 Armadillo 库构建一个晶石矩阵来求解线性方程组 Ax=b。 A is the coefficient matrix with a dimension of n*n, and B is a vector of right hand side with a dimension of n the Spars Matrix A is like this, see the figure A为系数矩阵,维度为n*n,B为右手边向量,维度为n。Spars矩阵A是这样的,见图

I had a look though the Eigen document but I have a problem with defining and filling the Spars Matrix in C++.我查看了 Eigen 文档,但在用 C++ 定义和填充 Spars 矩阵时遇到了问题。

could you please give me an example code to define the spars matrix and how to fill the values into the matrix using Eigen library in c++?你能给我一个示例代码来定义spars矩阵以及如何使用C++中的Eigen库将值填充到矩阵中吗?

consider for example a simple spars matrix A:例如考虑一个简单的spars矩阵A:

1 2 0 0 1 2 0 0

0 3 0 0 0 3 0 0

0 0 4 5 0 0 4 5

0 0 6 7 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;
} 

The sparse matrix could be filled with the values mentioned in the post by using the .coeffRef() member function, as shown in this routine:稀疏矩阵可以使用.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;
}

However, the SparseCholesky module ( SimplicialCholesky<SparseMatrix<double> > ) won't work in this case because the matrix is not Hermitian.但是, SparseCholesky模块 ( SimplicialCholesky<SparseMatrix<double> > ) 在这种情况下不起作用,因为矩阵不是 Hermitian。 The system could be solved with a LU or BiCGStab solver.该系统可以用 LU 或 BiCGStab 求解器求解。 Also note that sizes of x and b need to be defined: VectorXd b(A.rows()), x(A.cols());另请注意,需要定义xb的大小: VectorXd b(A.rows()), x(A.cols());

In case of larger sparse matrices you may also want to look at the .reserve() function in order to allocate memory before filling the elements.对于较大的稀疏矩阵,您可能还需要查看.reserve()函数,以便在填充元素之前分配内存。 The .reserve() function can be used to provide an estimate of the number of non-zero entries per column (or row, depending on the storage order. The default is comumn-major). .reserve()函数可用于估计每列(或每行,取决于存储顺序。默认为 comumn-major)的非零条目数。 In the example above that estimate is 4, but it does not make sense in such a small matrix.在上面的示例中,估计值为 4,但在如此小的矩阵中没有意义。 The documentation states that it is preferable to overestimate the number of non-zeros per column .该文档指出,最好高估每列的非零数

Since this question also asks about Armadillo , here is the corresponding Armadillo-based code.由于这个问题还涉及Armadillo ,因此这里是相应的基于 Armadillo 的代码。 Best to use Armadillo version 9.100+ or later, and link with SuperLU.最好使用 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;
}

See also the documentation for SpMat , element access , .load() , spsolve() .另请参阅SpMatelement access 、 .load( )spsolve()的文档。

The coord file format is simple.坐标文件格式很简单。 It stores non-zeros values.它存储非零值。 Each line contains:每行包含:

row col value

The row and column counts start at zero.行数和列数从零开始。 Example:例子:

  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

Values not explicitly listed are assumed to be zero.未明确列出的值假定为零。

#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;

} }

Here is a full code of a numerical problem.这是一个数值问题的完整代码。 Look at the matrix v .查看矩阵v It has all the nonzero elements.它具有所有非零元素。 In the next loop I made a series of tripletlist.push_back(.....) with their indexes and values.在下一个循环中,我制作了一系列Tripletlist.push_back(.....)及其索引和值。 The values will hold the position of Sparse Matrix at their accompanied indexes.这些值将在其伴随的索引处保持稀疏矩阵的位置。 Now declare a Sparse Matrix with a size and use the function setFromTroplets(....) and you will have your Sparse Matrix.现在声明一个具有大小的稀疏矩阵并使用函数setFromTroplets(....) ,你将拥有你的稀疏矩阵。

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

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