【刘庆源码共享】稀疏线性系统求解算法MGMRES(m) 之 矩阵类定义二(C++)
来源:互联网 发布:电棍专卖网淘宝 编辑:程序博客网 时间:2024/05/16 13:41
/*
* Copyright (c) 2009 湖南师范大学数计院 一心飞翔项目组
* All Right Reserved
*
* 文件名:matrix.cpp 定义Point、Node、Matrix类的各个方法
* 摘 要:定义矩阵类,包括矩阵的相关信息和方法
*
* 作 者:刘 庆
* 修改日期:2009年7月19日21:15:12
*
*/
/* 该类方法均基于稀疏线性系统的MCRF存储结构,MCRF相关介绍参见:http://blog.csdn.net/lq_0402/archive/2010/11/11/6003822.aspx */
/* 行初等变换 第base行乘以gene, 没有过滤掉乘以gene之后小于门槛值的元素 */
void Matrix::LnTransformMultiply(const long base,const Double& gene)
{
long offset=data[base].index;
/* 该行的非零非对角元素乘以gene */
long i=0;
for(i=data[base].index; i<data[base+1].index; i++)
{
data[i].value *= gene;
data[offset].value = data[i].value;
data[offset].index = data[i].index;
offset++;
}
if(offset!=i)
{
for( ; i<total_elem+1; i++)
{
data[offset].value = data[i].value;
data[offset].index = data[i].index;
offset++;
}
total_elem = offset-1;
for(long j=base+1; j<total_ln+1; j++)
data[j].index -= i-offset;
}
/* 该行对角元素乘以gene */
data[base].value *= gene;
}
/* 行初等变换 第base行加上第ln行 */
/* 算法:
1、开辟一个辅助数组tempData存放一行的数据,其长度为total_col
2、将base行的数据根据下标放于tempData中。
3、将ln行的数据根据下标,加到tempData相应下标位置。
4、开辟一个辅助数组tempDataAll,存放base和ln相加之后的整个新data的值
5、将tempDataAll覆盖原有的data
*/
void Matrix::LnTransfromAdd(const long base,const long ln)
{
Double *tempData = new Double[(total_col>total_ln?total_col:total_ln)+10];
long nonZero = 0; // 非零非对角元素个素 */
long i=0;
for( i=0; i<total_col+1; i++)
tempData[i] = 0;
/* 将base行的元素置于tempData中 */
/* 处理非零非对角元素 */
for(i=data[base].index; i<data[base+1].index; i++ )
{
if(data[i].value!=0.0f)
{
tempData[data[i].index] = data[i].value;
nonZero++;
}
}
/* 处理对角元素 */
tempData[base] = data[base].value;
/* 将ln行的元素加到tempData相应位置 */
/* 处理非零非对角元素 */
for(i=data[ln].index; i<data[ln+1].index; i++)
{
// 先判断其值是否为0
if(tempData[data[i].index]==0&&data[i].index!=base)
nonZero++;
tempData[data[i].index] += data[i].value;
if(tempData[data[i].index]==0&&data[i].index!=base)
nonZero--;
}
/* 处理对角元素 */
if(tempData[ln]==0)
nonZero++;
tempData[ln] += data[ln].value;
if(tempData[ln]==0)
nonZero--;
/* 将数组tempData中的数复制到data中的相应位置,涉及到三个步骤:
1、新增一辅助data空间 tempDataAll
2、将data和tempData中的数据复制到tempDataAll中
3、用tempDataAll覆盖data
*/
long overNum = nonZero-(data[base+1].index-data[base].index);
total_elem = total_elem+overNum;
Node tempDataAll;
tempDataAll.GetSpace(total_elem+1);
/* 将辅助数组初始化 */
for(i=0; i<total_elem+1; i++)
{
tempDataAll[i].value = 0;
tempDataAll[i].index = -1;
}
/* 前total_ln+1个位置 */
for(i=0; i<total_ln+1; i++)
{
tempDataAll[i].value = data[i].value;
if(i<=base)
tempDataAll[i].index = data[i].index;
else
{
tempDataAll[i].index = data[i].index+overNum;
}
}
/* tota_ln+2 到 data[base].index-1 个位置 */
for( ; i<data[base].index; i++){
tempDataAll[i].value = data[i].value;
tempDataAll[i].index = data[i].index;
}
long j=0;
/* 新的 base 行的数据 */
for( ; j<total_col; j++)
{
if(j==base){
tempDataAll[base].value = tempData[j];
}
else if(tempData[j]!=0.0f)
{
tempDataAll[i].value = tempData[j];
tempDataAll[i].index = j;
i++;
}
}
/* data[base+1].index 到最后 */
j=data[base+1].index;
for( ; i<total_elem+1; )
{
tempDataAll[i].value = data[j].value;
tempDataAll[i].index = data[j].index;
i++;
j++;
}
data = tempDataAll;
delete[] tempData;
}
/* 矩阵转置 考虑nm矩阵,当n>m、n=m、n<m三种情况,不管哪种情况,对角元素个数为小的那个 */
Matrix& Matrix::Transpose()
{
if(this->data.point==0)
return *this;
long over = 0;
over = total_col - total_ln;
Node tempData;
tempData.GetSpace(total_elem+1+over); /* 缓存器 */
long *numCol = new long[total_col]; /* 记录每列非零非对角元素个数 */
long *countCol = new long[total_col];
long i=0;
for(i=0; i<total_col; i++)
{
numCol[i] = 0;
countCol[i] = 0;
}
/* 将辅助数组初始化 */
for(i=0; i<total_elem+1+over; i++)
{
tempData[i].value = 0;
tempData[i].index = -1;
}
long smallNum = total_ln<total_col?total_ln:total_col;
/* tempData前面的对角元素赋值,以及计算每列的非零元素个数 */
for(i=0; i<total_elem+1; i++)
{
if(i<smallNum&&i!=total_ln)
{
if(data[i].value!=0.0f)
tempData[i].value = data[i].value;
else
tempData[i].value = 0;
}
else if(i>=smallNum&&i!=total_ln)
{
if(i<total_ln)
{
if(data[i].value!=0.0f)
{
numCol[i]++;
}
}
else
{
numCol[data[i].index]++;
}
}
}
tempData[total_col].value = data[total_ln].value;
tempData[0].index = total_col+1;
/* 计算每行第一个非零非对角元素的位置 */
for(i=1; i<=total_col; i++)
tempData[i].index = tempData[i-1].index + numCol[i-1];
/* smallNum前的元素已经被赋值了。 */
/* 替smallNum及以后的元素赋值,index从total_col+1开始 */
long j = 1;
for(i=total_ln+1; i<=total_elem; i++)
{
/* 当前元素的列标 */
long tempCol = data[i].index;
/* 当前元素转置之后的这列第一个非零元素的位置 */
long temp = 0;
temp = tempData[tempCol].index; // tempCol行第一个非零非对角元素的position
tempData[temp+countCol[tempCol]].value = data[i].value;
/* 得到当前元素的行标 */
while(j<=total_ln)
{
/* 假如当前元素的位置小于第j行第一个非零非对角元素元素的序列号 */
/* 那么这一行必定在第j-1行 【第一次符合条件便退出循环】*/
/* data 中的下一元素的行标必定大于或等于当前元素的行标 */
if(i<data[j].index)
{
tempData[temp+countCol[tempCol]].index = j-1;
/* 这一列已添加一个元素,该列计数器自加1 */
countCol[tempCol]++;
break;
}
j++;
}
}
total_elem += over;
long temp = total_ln;
total_ln = total_col;
total_col = temp;
/* 用缓存器里的元素值覆盖data中的值,以实现转置 */
data = tempData;
delete[] numCol;
numCol = NULL;
delete[] countCol;
countCol = NULL;
return *this;
}
/* 单位化一个矩阵 */
void Matrix::ToBeIdentityMatrix()
{
total_elem = total_ln;
data.GetSpace(total_elem+1);
for(long i=0; i<=total_ln;i++)
{
if(i<total_ln)
{
data[i].value = 1;
data[i].index = total_ln+1;
}
else if(i==total_ln)
{
data[i].value = 0;
data[i].index = total_ln+1;
}
}
}
/* 将当前矩阵化为0矩阵 */
void Matrix::ToBeZeroMatrix()
{
total_elem = total_ln;
for(long i=0; i<total_elem+1; i++)
{
data[i].value = 0.0;
data[i].index = total_ln+1;
}
}
// 求逆矩阵 返回当前矩阵的逆矩阵
/* 思路:因为矩阵可逆,所以,任何一行或者任意列,都至少存在一个非零元素。
1、假若A00不为零(若为零,则查找第0列不为零的行m,将其加上第m行,使A00不为零),将第0行所元素都除以
A00,将A00化为1,然后针对任意第0列不为零的行m,将其加上-Am0*A0j(j=0,1,2,total_col-1),即将Am0
化为0。
2、假若A11不为零,....
*/
void Matrix::ContraryMatrix()
{
Matrix matrix = *this;
this->total_col = matrix.total_col;
this->total_ln = matrix.total_ln;
this->total_elem = this->total_ln+1;
this->ToBeIdentityMatrix();
for(long i=0; i<matrix.total_ln; i++)
{
/* 第i行元素都除以 Aii,将Aii 化为1 */
/* 假如Aii==0,那么,得找到一个元素Aji!=0的行j,将其元素加到第i行,使Aii!=0 */
/* Note: 假如找到的所有Aji!=0中的都有j<i,则说明此矩阵不满秩,因为对这些Aji,都可以通过
Ajj(第j列只有Ajj==1,其他已为0)将其转化为0,以导致i列全为0。
*/
if(matrix.data[i].value==0)
{
/* 在第i列找不为0的元素Aji,如果j<i,则继续查找。直到j>i,或者自动退出循环。*/
/* 此处代码有冗余 变量ok可以省掉 */
long ok=0, j = 0;
for( j=0; j<total_ln; j++)
{
long pos = -1;
if(j!=i)
pos = matrix.QuickLocate(j,i);
if(pos!=-1)
{
if(j<i)
ok = j;
else if(j>i)
break;
}
}
if(j==total_ln&&ok==0)
{
cout<<"此矩阵不满秩!"<<endl;
return;
}
else if(ok==0)
matrix.LnTransfromAdd(i, j);
else
{
cout<<"此矩阵不满秩!"<<endl;
return;
}
}
/* 将matrix和indentityMatrix的第i行所有元素除以Aii */
long j = 0;
for(j=matrix.data[i].index; j<matrix.data[i+1].index; j++)
matrix.data[j].value = matrix.data[j].value/matrix.data[i].value;
for(j = data[i].index; j<data[i+1].index; j++)
data[j].value = data[j].value/matrix.data[i].value;
data[i].value /= matrix.data[i].value;
matrix.data[i].value /= matrix.data[i].value;
/* 通过行初等变换,将第i列所有元素(除了Aii)都化为0
此时i是定值,将除了第i行以外的行都减去 Aji*Aii (j=1,2,3,..total_ln且j!=i) */
for(j=0; j<matrix.total_ln; j++)
{
/* 将第i行乘以Aji */
if(j!=i)
{
/* 查找Aji,如果为非零,则通过行变换Aji+(-1)*Aji*Aii变成0 */
long pos = matrix.QuickLocate(j,i);
/* pos == -1 说明此元素为0 */
if(pos!=-1)
{
/* 将第i行临时存储,包括右端向量 */
/* 对矩阵matrix进行操作 */
long k;
long temp = matrix.data[i+1].index-matrix.data[i].index;
Double *tempLn = new Double[temp+2];
tempLn[0] = matrix.data[i].value;
for( k=1; k<=temp; k++)
tempLn[k] = matrix.data[matrix.data[i].index+k-1].value;
/* 对 单位矩阵进行操作 */
long tempIden = data[i+1].index-data[i].index;
Double *tempLnIden = new Double[tempIden+2];
tempLnIden[0] = data[i].value;
for(k=1; k<tempIden+1; k++)
tempLnIden[k] = data[data[i].index+k-1].value;
matrix.LnTransformMultiply(i, matrix.data[pos].value*(-1));
LnTransformMultiply(i,matrix.data[pos].value*(-1));
/* 将第i行加到第j行 */
matrix.LnTransfromAdd(j, i);
LnTransfromAdd(j,i);
/* 将第i行复原 */
matrix.data[i].value = tempLn[0];
for(k=1; k<=temp; k++)
matrix.data[matrix.data[i].index+k-1].value = tempLn[k];
data[i].value = tempLnIden[0];
for(k=1; k<tempIden+1;k++)
data[data[i].index+k-1].value = tempLnIden[k];
delete[] tempLn;
tempLn = NULL;
delete[] tempLnIden;
tempLnIden = NULL;
}
}
}
// this->DisplayAsMatrix("E", 1);
matrix.DisplayAsMatrix("matrix", 1);
}
}
/* 求矩阵的秩 */
long Matrix::GetMatrixRank() const
{
long rank = 0;
Matrix AA = *this;
long i = 0, j=0;
for( i=0; i< AA.total_col; i++)
{
if( i>=(AA.total_col<AA.total_ln ? AA.total_col:AA.total_ln) )
{
return AA.total_col<AA.total_ln ? AA.total_col:AA.total_ln;
}
// 假如i行的对角元素为0,则需要通过行变换将其变为不等于0,方法如下:
// 在第i列(j,i)[j>i]中查找非零的元素,假若存在,则将j行的元素加到第i行,假若不存在,则说明第i列可用之前列线性表出
if(AA.data[i].value==0)
{
for(j=i+1; j<AA.total_ln; j++)
{
long pos = AA.QuickLocate(j, i);
if(pos!=-1)
{
AA.LnTransfromAdd(i, j);
break;
}
}
if(j==AA.total_ln)
{
i++;
break;
}
}
j = i+1;
for( ; j<AA.total_ln; j++)
{
long pos = AA.QuickLocate(j, i);
// 假如j,i位置的元素为0,则该行不需要变化
if(pos!=-1)
{
// 假如j,i位置的元素不为0,则第j行的元素都必须加上(j,i)/(i,i)*(i,k)[k>=i],将(j,i)化为0
// 完成上述步骤,分为两步:
// 1、首先将第i行的数据备份
// 2、将第i行乘以(j,i)/(i,i) 注意:在此程序中,某行乘以一个数,没有过滤掉小于门槛值的元素
// 3、将第j行加上第i行
// 4、将第i行复原
// 保存第i行的数据,以便后续步骤中恢复i-1行数据
long length = AA.data[i+1].index-AA.data[i].index+1;
Double *tempValue = new Double[length];
tempValue[0] = AA.data[i].value;
long kk = 0;
for(kk=AA.data[i].index; kk<AA.data[i+1].index; kk++)
{
tempValue[kk-AA.data[i].index+1] = AA.data[kk].value;
}
Double gene = AA.data[pos].value/AA.data[i].value*(-1);
AA.LnTransformMultiply(i,gene);
AA.LnTransfromAdd(j,i);
AA.data[i].value = tempValue[0];
for(kk=AA.data[i].index; kk<AA.data[i+1].index; kk++)
{
AA.data[kk].value = tempValue[kk-AA.data[i].index+1];
}
delete[] tempValue;
}
}
rank++;
}
return rank;
}
/* 求增广矩阵的秩 */
long Matrix::GetExtendMatrixRank(const Matrix& b) const
{
if(&b==0||&b.data==0||b.total_col!=1||b.total_ln!=this->total_ln)
{
cout<<"右端向量不合法"<<endl;
return 0;
}
long rank = 0;
Matrix AA = *this;
Matrix bb = b;
long i = 0, j=0;
for( i=0; i< AA.total_col; i++)
{
if( i>=(AA.total_col<AA.total_ln ? AA.total_col:AA.total_ln) )
{
return AA.total_col<AA.total_ln ? AA.total_col:AA.total_ln;
}
// 假如i行的对角元素为0,则需要通过行变换将其变为不等于0,方法如下:
// 在第i列(j,i)[j>i]中查找非零的元素,假若存在,则将j行的元素加到第i行,假若不存在,则说明第i列可用之前列线性表出
if(AA.data[i].value==0)
{
for(j=i+1; j<AA.total_ln; j++)
{
long pos = AA.QuickLocate(j, i);
if(pos!=-1)
{
AA.LnTransfromAdd(i, j);
bb.LnTransfromAdd(i, j);
break;
}
}
if(j==AA.total_ln)
{
i++;
break;
}
}
j = i+1;
for( ; j<AA.total_ln; j++)
{
long pos = AA.QuickLocate(j, i);
// 假如j,i位置的元素为0,则该行不需要变化
if(pos!=-1)
{
// 假如j,i位置的元素不为0,则第j行的元素都必须加上(j,i)/(i,i)*(i,k)[k>=i],将(j,i)化为0
// 完成上述步骤,分为两步:
// 1、首先将第i行的数据备份
// 2、将第i行乘以(j,i)/(i,i) 注意:在此程序中,某行乘以一个数,没有过滤掉小于门槛值的元素
// 3、将第j行加上第i行
// 4、将第i行复原
// 保存第i行的数据,以便后续步骤中恢复i-1行数据
long length = AA.data[i+1].index-AA.data[i].index+1;
Double *tempValue = new Double[length+1];
tempValue[0] = AA.data[i].value;
long kk = 0;
for(kk=AA.data[i].index; kk<AA.data[i+1].index; kk++)
{
tempValue[kk-AA.data[i].index+1] = AA.data[kk].value;
}
long bPos = bb.QuickLocate(i,0);
if(bPos!=-1)
{
tempValue[kk-AA.data[i].index+1] = bb.data[bPos].value;
}else
tempValue[kk-AA.data[i].index+1] = 0;
Double gene = AA.data[pos].value/AA.data[i].value*(-1);
AA.LnTransformMultiply(i,gene);
AA.LnTransfromAdd(j,i);
bb.LnTransformMultiply(i, gene);
bb.LnTransfromAdd(j,i);
AA.data[i].value = tempValue[0];
for(kk=AA.data[i].index; kk<AA.data[i+1].index; kk++)
{
AA.data[kk].value = tempValue[kk-AA.data[i].index+1];
}
if(bPos!=-1)
bb.data[bPos].value = tempValue[kk-AA.data[i].index+1];
delete[] tempValue;
}
}
rank++;
}
// 判断增广矩阵的秩 和 非增光矩阵的秩是否一致
for(i=rank; i<bb.total_ln; i++)
{
long pos = bb.QuickLocate(i,0);
if(pos!=-1)
rank++;
}
return rank;
}
/* 判断矩阵和其增广矩阵的秩是否一致,一致返回1,不一致返回0 */
int Matrix::IsEMRequalMR(const Matrix& b) const
{
if(&b==0||&b.data==0||b.total_col!=1||b.total_ln!=this->total_ln)
{
cout<<"右端向量不合法"<<endl;
return 0;
}
long rank = 0;
Matrix AA = *this;
Matrix bb = b;
long i = 0, j=0;
for( i=0; i< AA.total_col; i++)
{
if( i>=(AA.total_col<AA.total_ln ? AA.total_col:AA.total_ln) )
{
return AA.total_col<AA.total_ln ? AA.total_col:AA.total_ln;
}
// 假如i行的对角元素为0,则需要通过行变换将其变为不等于0,方法如下:
// 在第i列(j,i)[j>i]中查找非零的元素,假若存在,则将j行的元素加到第i行,假若不存在,则说明第i列可用之前列线性表出
if(AA.data[i].value==0)
{
for(j=i+1; j<AA.total_ln; j++)
{
long pos = AA.QuickLocate(j, i);
if(pos!=-1)
{
AA.LnTransfromAdd(i, j);
bb.LnTransfromAdd(i, j);
break;
}
}
if(j==AA.total_ln)
{
i++;
break;
}
}
j = i+1;
for( ; j<AA.total_ln; j++)
{
long pos = AA.QuickLocate(j, i);
// 假如j,i位置的元素为0,则该行不需要变化
if(pos!=-1)
{
// 假如j,i位置的元素不为0,则第j行的元素都必须加上(j,i)/(i,i)*(i,k)[k>=i],将(j,i)化为0
// 完成上述步骤,分为两步:
// 1、首先将第i行的数据备份
// 2、将第i行乘以(j,i)/(i,i) 注意:在此程序中,某行乘以一个数,没有过滤掉小于门槛值的元素
// 3、将第j行加上第i行
// 4、将第i行复原
// 保存第i行的数据,以便后续步骤中恢复i-1行数据
long length = AA.data[i+1].index-AA.data[i].index+1;
Double *tempValue = new Double[length+1];
tempValue[0] = AA.data[i].value;
long kk = 0;
for(kk=AA.data[i].index; kk<AA.data[i+1].index; kk++)
{
tempValue[kk-AA.data[i].index+1] = AA.data[kk].value;
}
long bPos = bb.QuickLocate(i,0);
if(bPos!=-1)
{
tempValue[kk-AA.data[i].index+1] = bb.data[bPos].value;
}
else
tempValue[kk-AA.data[i].index+1] = 0;
Double gene = AA.data[pos].value/AA.data[i].value*(-1);
AA.LnTransformMultiply(i,gene);
AA.LnTransfromAdd(j,i);
bb.LnTransformMultiply(i, gene);
bb.LnTransfromAdd(j,i);
AA.data[i].value = tempValue[0];
for(kk=AA.data[i].index; kk<AA.data[i+1].index; kk++)
{
AA.data[kk].value = tempValue[kk-AA.data[i].index+1];
}
if(bPos!=-1)
bb.data[bPos].value = tempValue[kk-AA.data[i].index+1];
delete[] tempValue;
}
}
rank++;
}
// 判断增广矩阵的秩 和 非增光矩阵的秩是否一致
for(i=rank; i<bb.total_ln; i++)
{
long pos = bb.QuickLocate(i,0);
if(pos!=-1)
return 0;
}
return 1;
}
- 【刘庆源码共享】稀疏线性系统求解算法MGMRES(m) 之 矩阵类定义二(C++)
- 【刘庆源码共享】稀疏线性系统求解算法MGMRES(m) 之 矩阵类(C++)
- 【刘庆源码共享】稀疏线性系统求解算法MGMRES(m) 之 矩阵类定义一(C++)
- 【刘庆源码共享】稀疏线性系统求解算法MGMRES(m) 之 矩阵类定义三(C++)
- 【刘庆源码共享】稀疏线性系统求解算法MGMRES(m) 之 矩阵类定义四(C++)
- 【刘庆源码共享】稀疏线性系统求解算法MGMRES(m) 之 MGMRES类定义(C++)
- 【刘庆源码共享】稀疏线性系统求解算法MGMRES(m) 之 赋值类定义(C++)
- 【刘庆源码共享】稀疏线性系统求解算法MGMRES(m) 之 MGMRES类申明(C++)
- 【刘庆源码共享】稀疏线性系统求解算法MGMRES(m) 之 赋值类申明(C++)
- 【刘庆源码共享】稀疏线性系统求解算法MGMRES(m) 之 基础类(Double类,封装double)
- 【刘庆源码共享】稀疏线性系统求解算法 之 高斯-塞德尔算法(Gauss_Seide)GS类定义(C++)
- 【刘庆源码共享】稀疏线性系统求解算法 之 高斯-塞德尔算法(Gauss_Seide)GS类声明(C++)
- 线性表再谈之稀疏矩阵+
- GPU上大规模稀疏矩阵特征值计算高效算法之二——稀疏矩阵
- 稀疏矩阵存储之二
- 稀疏线性系统求解算法 之 存储结构(MCRF) 强于二维数组、三元组、行压缩、修正行压缩等
- 稀疏矩阵线性表示
- 数据结构实验之数组二:稀疏矩阵
- 单源最短路径通用解法—BellmanFord
- redhat linux命令大全
- 编程之美笔记——金刚坐飞机
- NOIP2010前一周的总结
- 语法,学习资源
- 【刘庆源码共享】稀疏线性系统求解算法MGMRES(m) 之 矩阵类定义二(C++)
- 用租赁汽车作质押是否构成犯罪?
- 【刘庆源码共享】稀疏线性系统求解算法MGMRES(m) 之 矩阵类定义三(C++)
- java filter 应用介绍
- 窗体闪烁效果
- 【刘庆源码共享】稀疏线性系统求解算法MGMRES(m) 之 矩阵类定义四(C++)
- 新的开始
- 【刘庆源码共享】稀疏线性系统求解算法MGMRES(m) 之 赋值类申明(C++)
- Linux的使用