![](/img/trans.png)
[英]How to convert an Eigen sparse matrix into an array in C++ using the?
[英]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 求解器求解。 另请注意,需要定义x
和b
的大小: 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;
}
另请参阅SpMat 、 element 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.