在 C++ 中创建带状矩阵
Creating a Banded Matrix in C++
我正在尝试转换创建带状对角矩阵的 Matlab 代码。我要转换的 Matlab 代码是:
N = 5;
e = ones(N-1, 1);
D = spdiags([-e 2*e -e], [-1 0 1], N-1, N-1);
D = full(D);
以上Matlab代码的输出,D=
2 -1 0 0
-1 2 -1 0
0 -1 2 -1
0 0 -1 2
我最接近的 C++ 转换尝试如下:
#include<iostream>
#include<vector>
using namespace std;
vector< vector<double> > bandedMat(vector<double> &e,int N);
int main()
{
int N = 5 ;
vector<double> e = {-1,2,-1};
vector< vector<double> > B = bandedMat(e,N);
return 0;
}
vector< vector<double> > bandedMat(vector<double> &e,int N)
{
vector< vector<double> > D(N-2, vector<double>(N,0.0));
double val = 0.0;
for(int i = 0; i < D.size(); i++)
{
for(int j = 0; j < e.size(); j++)
{
val = e[j];
D[i][i+j] = val; // Put along the diagonal of matrix D. Note the index.
}
}
return D;
}
我的以下 C++ 代码的输出是 D=
-1 2 -1 0 0
0 -1 2 -1 0
0 0 -1 2 -1
如您所见,我的 C++ 版本非常不同,它生成的 D 为 3x5,而 Matlab 版本生成的 D 为 4 x 4。另外,我的 C++ 版本的对角线有点小不同的。有人能指出我怎样才能像 Matlab 版本那样获得准确的 D 吗?
虽然我觉得不够优雅,但至少暂时解决了我的问题。这是:
vector< vector<double> > bandedMat(vector<double> &e,int N)
{
// Do some checking, Only tridiagonals are allowed.
if(e.size()>3)
{
cout << "Only tridiagonals are allowed. Input vector to function must be only 3 elements." << endl;
exit(EXIT_FAILURE);
}
vector< vector<double> > D(N-1, vector<double>(N-1,0.0));
for(size_t i = 0; i < D.size(); i++)
{
for(size_t j = 0; j < D.size(); j++)
{
if(i == j)
{
D[i][j] = e[1]; // put value of e[1] as the main diagonal of D
}
}
}
int j =0; // index
int k =0; // index
for(size_t i =0; i < D.size()-1;i++)
{
D[i][j+1] = e[0]; // put value e[0] as the upper diagonal
j = j+1;
}
for(size_t i =0; i < D.size()-1;i++)
{
D[i+1][k] = e[2]; // put value of e[2] as the lower diagonal
k = k+1;
}
return D;
}
将生成类似于 Matlab 版本的精确矩阵。如果有人有更好的主意或更优雅的方法,请分享。谢谢
稍微优雅一些...您可以将所有三个放在一个循环中
for(size_t i = 0; i < D.size(); i++)
{
if (i<D.size()) {
D[i][i+1] = e[0];
}
D[i][i] = e[1]; // put value of e[1] as the main diagonal of D
if (i>0) {
D[i][i-1] = e[2];
}
}
我正在尝试转换创建带状对角矩阵的 Matlab 代码。我要转换的 Matlab 代码是:
N = 5;
e = ones(N-1, 1);
D = spdiags([-e 2*e -e], [-1 0 1], N-1, N-1);
D = full(D);
以上Matlab代码的输出,D=
2 -1 0 0
-1 2 -1 0
0 -1 2 -1
0 0 -1 2
我最接近的 C++ 转换尝试如下:
#include<iostream>
#include<vector>
using namespace std;
vector< vector<double> > bandedMat(vector<double> &e,int N);
int main()
{
int N = 5 ;
vector<double> e = {-1,2,-1};
vector< vector<double> > B = bandedMat(e,N);
return 0;
}
vector< vector<double> > bandedMat(vector<double> &e,int N)
{
vector< vector<double> > D(N-2, vector<double>(N,0.0));
double val = 0.0;
for(int i = 0; i < D.size(); i++)
{
for(int j = 0; j < e.size(); j++)
{
val = e[j];
D[i][i+j] = val; // Put along the diagonal of matrix D. Note the index.
}
}
return D;
}
我的以下 C++ 代码的输出是 D=
-1 2 -1 0 0
0 -1 2 -1 0
0 0 -1 2 -1
如您所见,我的 C++ 版本非常不同,它生成的 D 为 3x5,而 Matlab 版本生成的 D 为 4 x 4。另外,我的 C++ 版本的对角线有点小不同的。有人能指出我怎样才能像 Matlab 版本那样获得准确的 D 吗?
虽然我觉得不够优雅,但至少暂时解决了我的问题。这是:
vector< vector<double> > bandedMat(vector<double> &e,int N)
{
// Do some checking, Only tridiagonals are allowed.
if(e.size()>3)
{
cout << "Only tridiagonals are allowed. Input vector to function must be only 3 elements." << endl;
exit(EXIT_FAILURE);
}
vector< vector<double> > D(N-1, vector<double>(N-1,0.0));
for(size_t i = 0; i < D.size(); i++)
{
for(size_t j = 0; j < D.size(); j++)
{
if(i == j)
{
D[i][j] = e[1]; // put value of e[1] as the main diagonal of D
}
}
}
int j =0; // index
int k =0; // index
for(size_t i =0; i < D.size()-1;i++)
{
D[i][j+1] = e[0]; // put value e[0] as the upper diagonal
j = j+1;
}
for(size_t i =0; i < D.size()-1;i++)
{
D[i+1][k] = e[2]; // put value of e[2] as the lower diagonal
k = k+1;
}
return D;
}
将生成类似于 Matlab 版本的精确矩阵。如果有人有更好的主意或更优雅的方法,请分享。谢谢
稍微优雅一些...您可以将所有三个放在一个循环中
for(size_t i = 0; i < D.size(); i++)
{
if (i<D.size()) {
D[i][i+1] = e[0];
}
D[i][i] = e[1]; // put value of e[1] as the main diagonal of D
if (i>0) {
D[i][i-1] = e[2];
}
}