【c++/c】反幂法求解绝对值最小的特征值

part 1:反幂法和LU分解

  【反幂法】

 

 

     难点:对A进行LU分解。特别是程序编写过程中的下标。

    【doolittle 分解】   

    

 

     

 

   【A->C】

    对于大型n元带状线性方程组Ax=b。当n>>r+s+1(A的总带宽)时,为了节省存储量,A的带外元素不给存储,仅存A的带内元素。

      

 

       

 

 point 2 程序的实现

#include <iostream>
#include <vector>
#include <math.h>
#include <cassert>
#include <iomanip>

using vec = std::vector<std::vector<double>>;
using vecRow = std::vector<double>;


/*
    定义一些全局变量
    g_r:矩阵A的下半带宽
    g_s:矩阵A的上半带宽
    g_time:迭代的最大次数,超出此数停止计算
    g_err:给定误差
*/
int g_r{ 2 };
int g_s{ 2 };
int g_time{ 5000 };
double g_err{ 10e-12 };
/*
    求a,b中的最小值
*/
int min(int a, int b) {
    return (a < b) ? a : b;
}


/*
    求最大值的函数重载
*/
int max(int a, int b, int c) {
    int max1{};
    (a > b) ? max1 = a : max1 = b;
    (max1 > c) ? max1 = max1 : max1 = c;
    return max1;
}

/*
    本题需要对int ,double两种类型的数进行处理
    因此使用了功能模板
*/
template <typename T>
T max(T a, T b) {
    return (a > b) ? a : b;
}

 

/*
    将矩阵A变为零矩阵
*/
vec changeZero(vec A) {
    int row{ static_cast<int> (A.size()) };
    int col{ static_cast<int>(A[0].size()) };
    for (int i = 0;i!=row;++i) {
        for (int j = 0;j != col;++j) {
            A[i][j] = 0.0;
        }
    }
    return A;
}

/*
    将向量A变为零向量
*/
vecRow changeZero(vecRow A) {
    int row{ static_cast<int> (A.size()) };
    for (int i = 0;i < row;++i) {
        A[i] = 0;
    }
    return A;
}

 

【将A矩阵变化为C矩阵】

vec createC(vec A) {
    int row{ static_cast<int> (A.size()) };
    int col{ static_cast<int>(A[0].size()) };
    int m{ g_r + g_s + 1 }; //5
    int n{ col }; //501
    vec C(m, vecRow(n));
    C = changeZero(C);
    int temp{};
    int start{};
    int end{};
    int mid{ g_s + 1  };//3
    int i{};// A矩阵的行
    int k{};// C矩阵的行
    for (int j = 0;j < n;j++) {  //j为A\C矩阵的列
        if (j < mid - 1) {
            start = mid - j - 1;//实际矩阵存放位置需要减去1
            end = m - start;
i = 0;
k = start;
while ((k < m) && (i < end)) {
    C[k][j] = A[i][j];
    ++i;
    ++k;
}
        }
       else if (j >= mid - 1 && j < n - g_r) {
       start = j - g_s;
       end = j + g_r + 1;
       i = start;
       k = 0;
       while ((i < end) && (k < m)) {
           C[k][j] = A[i][j];
           ++i;
           ++k;
       }

        }
       else if (j >= n - g_r) {
       start = j - g_r;
       end = n - start + 1;
       i = start;
       k = 0;
       while ((i < n) && (k < end)) {
           C[k][j] = A[i][j];
           ++i;
           ++k;
       }
        }
       else {
       continue;
        }
    }
    return C;
}

【将C矩阵进行LU分解】

//Doolittle 分解法 LU分解
vec dooLittleLU(vec C) {
    int row{ static_cast<int> (C.size()) };
    int col{ static_cast<int>(C[0].size()) };
    int m{ g_r + g_s + 1 };
    int n{ col };
    vecRow u(col);
    // LU分解,A->C
    //对于k=1,2,...,n计算
    int min1{};
    double sum{};
    int t0{};
    for (int k = 0;k < n;++k) {
        min1 = min((k + g_s), n - 1); //n需要-1,而k已经比原来小1了
        for (int j = k;j < min1 + 1;++j) {
            t0 = max(1 - 1, k - g_r, j - g_s);
            //t0 = (k > 2) * (k >= j) * (k - 2) + (j > 2) * (j > k) * (j - 2);
            for (int t = t0;t < k;++t) {
                //C[k - j + g_s + 1][j] = C[k - j + g_s + 1][j] - C[k - t + g_s + 1][t] * C[t - j + g_s + 1][j];
                //注意下标的转换,比公式上小1,因为从k=0开始计数
                C[k - j + g_s + 1 - 1][j] -= C[k - t + g_s + 1 - 1][t] * C[t - j + g_s + 1 - 1][j];
            }
        }
        if (k < n - 1) {
            min1 = min(k + g_r, n - 1);
            for (int i = k + 1;i < min1 + 1;++i) {
                //t0 = (k > 2) * (k >= i) * (k - 2) + (i > 2) * (i > k) * (i - 2);
                t0 = max(0, i - g_r, k - g_s);
                //sum = 0;
                for (int t = t0;t < k;++t) {
                    // std::cout << "mid: " << i - k + g_s + 1 - 1 << '\n';
                     // sum += C[i - t + g_s + 1][t] * C[t - k + g_s + 1][k];
                    C[i - k + g_s + 1 - 1][k] -= C[i - t + g_s + 1 - 1][t] * C[t - k + g_s + 1 - 1][k];
                }
                C[i - k + g_s + 1 - 1][k] = C[i - k + g_s + 1 - 1][k] / C[g_s + 1 - 1][k];
            }
        }

    }
    return C;
    //求解
}

【C矩阵回代,解方程】

vecRow dooLittleSolve(vec C, vecRow uk) {
    int row{ static_cast<int> (uk.size()) };
    int n{ row };
    int t0{};
    double min1{};
    for (int i = 2 - 1;i < row + 1 - 1;++i) {
        t0 = static_cast<int>(max(1 - 1, i - g_r));
        for (int t = t0;t < i - 1 + 1;++t) {
            uk[i] -= C[i - t + g_s + 1 - 1][t] * uk[t];
        }
    }
    uk[n - 1] = uk[n - 1] / C[g_s + 1 - 1][n - 1];
    for (int i = n - 1 - 1;i >= 0;--i) {
        min1 = min(i + g_s, n-1);
        for (int t = i + 1;t < min1 + 1;++t) {
            uk[i] -= C[i - t + g_s + 1 - 1][t] * uk[t];
        }
        uk[i] /= C[g_s + 1 - 1][i];
    }
    return uk;
}

【反幂法迭代求解】

double inverseMi(vec A, vecRow u0) {
    int row{ static_cast<int> (u0.size()) };
    vecRow y(row);
    vecRow uk(row);
    int m{ g_r + g_s + 1 };
    int n{ row };
    vec C(m, vecRow(n));
    double betak{};
    double beta0{};
    int t0{};
    double sum{};
    double min1{};
    C = createC(A);
    C = dooLittleLU(C); //LU分解
    //std::cout << "beta: " << betak << '\n';
    int k{ 1 };
    double distance{};
    while (k) {
        beta0 = betak;
        y = normalize(u0);
       // C = dooLittleLU(A); //LU分解
        uk = y;
        uk = dooLittleSolve(C, y);
        betak = 1 / multi(y, uk);
        distance = fabs((betak - beta0) / betak);
        if (distance <= g_err) {
            return betak;
        }
        if (k > g_time) {
            std::cout << "out of g_time" << '\n';
            return 0;
        }
        //std::cout << "step: " << k << '\n';
        u0 = uk;
        k++;
    }
    //return u;
    return betak;
 }

betak即为所求绝对值最小的特征值。

posted @ 2023-02-18 10:54  致命一姬  阅读(255)  评论(0编辑  收藏  举报