c++ 矩阵求逆

//矩阵乘法
void pbgMatricMul(zdouble_t C[DN * DN], double A[DN * DN],double B[DN * DN])
{
    for (int32_t i = 0; i < DN; i++)
    {
        for (int32_t j = 0; j < DN; j++)
        {
            for (int32_t k = 0; k < DN; k++)
            {
                C[i * DN + j] += A[ i * DN + k] * B[k * DN + j];
            }
        }
    }

    //若绝对值小于10^-5,则置为0
    for (int32_t i = 0; i < DN * DN ; i++)
    {
        if (abs(C[i]) < 1e-5)
        {
            C[i] = 0;
        }
    }
}

//LUP分解
void pbgLupDescomposition(zdouble_t A[DN * DN], zdouble_t L[DN * DN], zdouble_t U[DN * DN], int32_t P[DN])
{
    int32_t row = 0;
    for (int32_t i = 0;i < DN; i++)
    {
        P[i] = i;
    }
    for (int32_t i = 0; i < DN - 1;i++)
    {
        zdouble_t p = 0.0;
        for (int32_t j = i; j < DN; j++)
        {
            if (abs( A[j * DN + i]) > p)
            {
                p   = abs(A[j * DN + i]);
                row = j;
            }
        }
        if(0 == p)
        {
            //cout<< "矩阵奇异,无法计算逆" <<endl;
            return ;
        }

        //交换P[i]和P[row]
        int32_t tmp = P[i];
        P[i]        = P[row];
        P[row]      = tmp;

        zdouble_t tmp2 = 0.0;
        for (int32_t j = 0; j < DN; j++)
        {
            //交换A[i][j]和 A[row][j]
            tmp2 = A[i * DN + j];
            A[i * DN + j]   = A[row * DN + j];
            A[row * DN + j] = tmp2;
        }

        //以下同LU分解
        zdouble_t u = A[i * DN + i], l = 0.0;
        for (int32_t j = i + 1; j < DN; j++)
        {
            l = A[j * DN + i] / u;
            A[j * DN + i] = l;
            for (int32_t k = i + 1; k < DN; k ++)
            {
                A[j * DN + k] = A[j * DN + k] - A[i * DN + k] * l;
            }
        }
    }

    //构造L和U
    for (int32_t i = 0; i < DN; i++)
    {
        for (int32_t j = 0; j <= i; j++)
        {
            if (i != j)
            {
                L[i * DN + j] = A[i * DN + j];
            }
            else
            {
                L[i * DN + j] = 1;
            }
        }
        for (int32_t k = i; k < DN; k++)
        {
            U[i * DN + k] = A[i * DN + k];
        }
    }
}

//LUP求解方程
zdouble_t * pbgLupSolve(zdouble_t L[DN * DN], zdouble_t U[DN * DN], int P[DN], zdouble_t b[DN])
{
    zdouble_t *x=new double[DN]();
    zdouble_t *y=new double[DN]();

    //正向替换
    for (int32_t i = 0;i < DN;i++)
    {
        y[i] = b[P[i]];
        for (int32_t j = 0;j < i;j++)
        {
            y[i] = y[i] - L[i * DN + j] * y[j];
        }
    }
    //反向替换
    for (int32_t i = DN-1;i >= 0; i--)
    {
        x[i] = y[i];
        for (int32_t j = DN-1;j > i;j--)
        {
            x[i] = x[i] - U[i * DN + j] * x[j];
        }
        x[i] /= U[i * DN + i];
    }
    return x;
}

/*****************矩阵原地转置BEGIN********************/

/* 后继 */
int32_t pbgGetNext(int32_t i, int32_t m, int32_t n)
{
    return (i % n) * m + i / n;
}

/* 前驱 */
int32_t pbgGetPre(int32_t i, int32_t m, int32_t n)
{
    return (i % m) * n + i / m;
}

/* 处理以下标i为起点的环 */
void pbgMovedata(zdouble_t *mtx, int32_t i, int32_t m, int32_t n)
{
    zdouble_t temp = mtx[i]; // 暂存
    int32_t   cur = i;    // 当前下标
    int32_t   pre = pbgGetPre(cur, m, n);
    while(pre != i)
    {
        mtx[cur] = mtx[pre];
        cur = pre;
        pre = pbgGetPre(cur, m, n);
    }
    mtx[cur] = temp;
}

/* 转置,即循环处理所有环 */
void pbgTranspose(zdouble_t *mtx, int32_t m, int32_t n)
{
    for (int32_t i =0; i < m * n; ++i)
    {
        int32_t next = pbgGetNext(i, m, n);

        while(next > i) // 若存在后继小于i说明重复,就不进行下去了(只有不重复时进入while循环)
        {
            next = pbgGetNext(next, m, n);
        }
        if(next == i)  // 处理当前环
        {
            pbgMovedata(mtx, i, m, n);
        }
    }
}
/*****************矩阵原地转置END********************/

//LUP求逆(将每列b求出的各列x进行组装)
void pbgLupSolveInverse(zdouble_t inv_A[DN * DN], zdouble_t A[DN * DN])
{
    //创建矩阵A的副本,注意不能直接用A计算,因为LUP分解算法已将其改变
    zdouble_t *A_mirror   = new zdouble_t[DN * DN]();
    //zdouble_t *inv_A      = new zdouble_t[DN * DN]();//最终的逆矩阵(还需要转置)
    zdouble_t *inv_A_each = new zdouble_t[DN]();//矩阵逆的各列
    //double *B    =new double[DN*DN]();
    zdouble_t *b          =new zdouble_t[DN]();//b阵为B阵的列矩阵分量

    for(int32_t i = 0; i < DN; i++)
    {
        zdouble_t *L = new zdouble_t[DN * DN]();
        zdouble_t *U = new zdouble_t[DN * DN]();
        int32_t   *P = new int32_t[DN]();

        //构造单位阵的每一列
        for(int32_t j = 0; j < DN; j++)
        {
            b[j] = 0;
        }
        b[i] = 1;

        //每次都需要重新将A复制一份
        for(int32_t j = 0; j < DN * DN; j++)
        {
            A_mirror[j] = A[j];
        }

        pbgLupDescomposition(A_mirror, L, U, P);

        inv_A_each = pbgLupSolve (L, U, P, b);
        memcpy(inv_A + i * DN, inv_A_each, DN * sizeof(zdouble_t));//将各列拼接起来
    }
    pbgTranspose(inv_A, DN, DN);//由于现在根据每列b算出的x按行存储,因此需转置

   // return inv_A;
}

 

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
矩阵求逆LU分解是一种求解矩阵逆的算法,通过将矩阵分解为下三角矩阵L和上三角矩阵U的积,然后利用这两个矩阵求解矩阵的逆。 首先,我们需要将矩阵A进行LU分解,得到下三角矩阵L和上三角矩阵U。具体步骤如下: 1. 初始化L为单位下三角矩阵,即L的对角线元素全为1,U为矩阵A的副本。 2. 对于矩阵U的每一列,我们将其第一行元素记为U[1, j],然后计算L的第一列元素L[i, 1](i = 2, 3, ..., n)以及矩阵U的第i行元素U[i, j](i = 2, 3, ..., n): - L[i, 1] = U[i, 1] / U[1, 1] - U[i, j] = U[i, j] - L[i, 1] * U[1, j] 3. 对于矩阵U的第二列至第n列,我们依次计算L的第一行至第n-1行元素以及矩阵U的第i行元素(i = 2, 3, ..., n): - L[i, k] = (U[i, k] - sum(L[i, j] * U[j, k] for j in range(1, k))) / U[k, k] - U[i, j] = U[i, j] - sum(L[i, k] * U[k, j] for k in range(1, j)) 得到矩阵L和矩阵U后,我们可以按照以下步骤计算矩阵的逆: 1. 初始化矩阵I为单位矩阵。 2. 对于每一列的矩阵I的列向量b,利用L和U解出方程Ax = b,即x = U^(-1)L^(-1)b。 3. 将得到的每一列向量x按列组合起来得到矩阵的逆。 需要注意的是,在实际计算中,如果遇到U的对角线元素接近或者等于0的情况,则矩阵不存在逆,因此需要避免这种情况的发生。同时,如果矩阵A是一个稀疏矩阵,那么LU分解可能不是最优的求解方法,可以考虑使用其他方法求解矩阵逆。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值