LUP分解法求解线性方程组

本节我们讨论如何用LUP分解法求解线性方程组,对于含有n个未知变量x1,x2,x3,…,xn的线性方程组:

image

同时满足方程组中所有方程的一个数值集:x1,x2,…,xn称为方程组的解。

将方程组改写成矩阵向量等式:

image

记为:

Ax=b

如果A为非奇异矩阵,那么A存在逆矩阵,亦即方程组有解。

LUP分解的思想是找出三个n*n的矩阵,L、U和P,满足

PA=LU

其中,L是一个单位下三角矩阵,U是一个上三角矩阵,P是一个置换矩阵。则称满足上述等式的L、U和P为矩阵A的LUP分解

等式Ax=b两边同乘以P,变形为PAx=Pb,亦即:

LUx=Pb

设y=Ux,其中x就是我们要求的向量解。我们首先通过正向替换求解下三角系统:

Ly=Pb

得到未知变量y。然后,通过正向替换求解上三角系统:

Ux=y

得到未知变量x。

由于置换矩阵P是可逆的,等式PA=LU两边同乘以P-1,得:

A=P-1LU

=P-1Ly

=P-1Pb

=b

于是x就是Ax=b的解。

调用方法:

    linear::CLinearEqualtion l(3);
    l.init_A("A.txt");
    l.init_b("b.txt");
    l.lu_decomposition();
    l.lup_solve();
    l.show_y();
    l.show_x();
    l.save_solution();

C++实现:

#include <iostream>
#include <vector>
#include <cassert>
#include <fstream>

using namespace std;

namespace linear
{
#define array_1(__type) std::vector<__type>
#define array_2(__type) std::vector<array_1(__type)>

    class CLinearEqualtion
    {
        /*
        使用方法:
        1. 定义计算方程组的类对象,并初始化其系数矩阵的大小
        linear::CLinearEqualtion l(3);

        2. 读取系数阵 A
        l.init_A("A.txt");

        3. 读取 b
        l.init_b("b.txt");

        4. 对系数矩阵进行lu分解
        l.lu_decomposition();

        5. 求解方程组
        l.lup_solve();

        6. 显示反向替换的解
        l.show_y();

        7. 显示正向替换的解
        l.show_x();

        8. 保存方程的解
        l.save_solution();

        A.txt
        1    5    4
        2    0    3
        5    8    2

        b.txt
        12
        9
        5

        x[0] = -0.157895
        x[1] = -0.0526316
        x[2] = 3.10526
        */
    private:
        array_2(double) A;
        array_2(double) L;
        array_2(double) U;

        array_1(double) b;
        array_1(int) p;

        array_1(double) x;
        array_1(double) y;

    public:
        CLinearEqualtion(int n)
        {
            assert(n>1);

            A = array_2(double)(n);
            L = array_2(double)(n);
            U = array_2(double)(n);
            for (int i= 0; i < n;i++)
            {
                A[i] = array_1(double)(n);
                L[i] = array_1(double)(n);
                U[i] = array_1(double)(n);
            }
            b = array_1(double)(n);
            x = array_1(double)(n);
            y = array_1(double)(n);
            p = array_1(int)(n);
        } // !CLinearEqualtion(int n)
        virtual ~CLinearEqualtion(){} // !virtual ~CLinearEqualtion()

    public:
        void init_A(array_2(double) _A)
        {
            for (int i = 0; i < _A.size(); i++)
                A[i].assign(_A[i].begin(), _A[i].end());
        } // !void init_A(array_2(double) _A)

        void init_A(std::string _fileName)
        {
            std::ifstream in(_fileName.c_str());
            int i = 0;
            int j = 0;
            while(!in.eof())
            {
                double e = 0;
                in>>e;
                std::cout<<e<<std::endl;
                A[i][j] = e;
                if (j==A.size() - 1)
                {
                    i++;
                    j = 0;
                }
                else
                {
                    j++;
                }
            }
        } // !void init_A(std::string _fileName)

        void init_b(std::string _fileName)
        {
            std::ifstream in(_fileName.c_str());
            int i = 0;
            while(!in.eof())
            {
                double e = 0;
                in>>e;
                std::cout<<e<<std::endl;
                b[i++] = e;
            }
        } // !void init_b(std::string _fileName)

        void lu_decomposition()
        {
            int n = A.size(); // get array size
            for (int i = 0; i < n; i++)
                p[i] = i;
            for (int k = 0; k < n; k++)
            {
                int max = 0;
                int k_ = k;
                // get max e in col k.
                for (int i = k; i < n; i++)
                {
                    if (fabs(A[i][k]) > max)
                    {
                        max = fabs(A[i][k]);
                        k_ = i;
                    }
                }
                // make sure not all is zero.
                if (max == 0)
                    assert("singular matrix");

                // swap cur row,max row.
                if (k != k_)
                {
                    swap(p[k], p[k_]);
                    for (int i = 0; i < n; i++)
                        swap(A[k][i], A[k_][i]);                    
                }
                
                for (int i = k + 1; i < n; i++)
                {
                    // gen v
                    A[i][k] /= A[k][k];
                    for (int j = k + 1; j < n; j++)
                    {
                        A[i][j] -= A[i][k] * A[k][j];
                    }
                }
            }

            init_LU();
        } // !void lu_decomposition()

        void init_LU()
        {
            int n = A.size(); // get array size

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    if (i > j)
                    {
                        L[i][j] = A[i][j];
                    } 
                    else
                    {
                        U[i][j] = A[i][j];
                        if (i == j)
                            L[i][i] = 1;
                    }
                }
            }

        } // !void init_LU()

        void lup_solve()
        {
            int n = A.size();
            int i = 0, j = 0;
            for (i = 0; i < n; i++)
            {
                x[i] = 0;
                y[i] = 0;
            }

            for (i = 0; i < n; i++)
            {
                y[i] = b[p[i]];
                for (j = 0; j < i; j++)
                    y[i] -= L[i][j] * y[j];
            }
            for (i = n - 1; i >= 0; i--)
            {
                double delt = y[i];
                for (j = n - 1; j > i; j--)
                    delt -= U[i][j] * x[j];
                x[i] = delt / U[i][j];
            }
        } // !void lup_solve()

        void show_y()
        {
            int n = A.size();
            std::cout << "###" << std::endl;
            for (int i = 0; i < n; i++)
            {
                std::cout << "y[" << i << "]=" << y[i] << std::endl;
            }
        } // !void show_y()

        void show_x()
        {
            int n = A.size();
            std::cout << "###" << std::endl;
            for (int i = 0; i < n; i++)
                std::cout << "x[" << i << "]=" << x[i] << std::endl;
        } // !void show_x()


        void save_solution()
        {
            int n = A.size();
            ofstream out("result.txt", ios::out);
            out << "-------------------------------------" << std::endl;
            std::cout << "-------------------------------------" << std::endl;
            for (int i = 0; i < n; i++)
            {                
                out << "x[" << i << "] = " << x[i]<< std::endl;
                std::cout << "x[" << i << "] = " << x[i]<< std::endl;
            }
            out << "-------------------------------------" << std::endl;
            std::cout << "-------------------------------------" << std::endl;
            out.close();
        }
    };
}

链接:http://pan.baidu.com/s/1hqJes4k 密码:elwz

posted @ 2015-11-13 16:42  leungcnblogs  阅读(4118)  评论(0编辑  收藏  举报