返回目录

GivensQLR.m

text/plain
5.27 KB
2025-10-22 16:15:57

文件预览

% Givens旋转变换的QL/R分解脚本(直接运行版)
% 功能:无需函数调用,通过Givens旋转变换实现QL分解(X=1)或QR分解(X=2),输出变换矩阵Q、分解后矩阵A及迭代次数k
% 原理:根据X选择上三角(QL)或下三角(QR)分解,通过Givens旋转逐步消去非三角元素,直到收敛
% 运行方式:直接运行此m脚本,无需命令行操作,结果自动输出
clear; clc;  % 清空工作区变量与命令行窗口,避免历史数据干扰


%% 1. 输入计算所需参数(可根据需求替换)
% 待分解的方阵A(示例为3阶矩阵,可替换为任意方阵,确保迭代收敛)
A = [5 2 1; 
     2 6 3; 
     1 3 7];  

% 分解模式选择:X=1为QL分解(基于上三角);X=2为QR分解(基于下三角)
X = 1;  % 可修改为2切换至QR分解

% 输出输入信息,便于后续对比
fprintf('待分解的矩阵A:\n');
disp(A);
if X == 1
    fprintf('\n分解模式:QL分解(基于Givens旋转变换,目标化为下三角矩阵)\n');
elseif X == 2
    fprintf('\n分解模式:QR分解(基于Givens旋转变换,目标化为上三角矩阵)\n');
else
    error('分解模式X必须为1(QL)或2(QR)!');  % 检查输入合法性
end
[m,n] = size(A);
if m ~= n
    error('输入矩阵A必须为方阵!');  % QL/R分解仅适用于方阵
end


%% 2. Givens旋转变换QL/R分解核心逻辑(整合原R_QLR函数核心代码)
C2 = 1;          % 收敛判断指标(初始设为1,满足循环条件)
Q = eye(n);      % 初始化变换矩阵Q为n阶单位矩阵(累积Givens旋转)
k = 0;           % 迭代次数计数器

% 根据X选择分解模式(QL或QR),设置对应的矩阵提取函数和参数
switch X
    case 1  % QL分解:基于上三角部分,目标将A化为下三角矩阵
        fun = @triu;       % 提取上三角矩阵(含对角线)
        option = 1;        % triu的第二个参数,1表示提取主对角线及以上
        opbreak = 1;       % 停止条件的列索引(当最大元素在第1列时停止)
    case 2  % QR分解:基于下三角部分,目标将A化为上三角矩阵
        fun = @tril;       % 提取下三角矩阵(含对角线)
        option = -1;       % tril的第二个参数,-1表示提取主对角线及以下
        opbreak = n;       % 停止条件的列索引(当最大元素在第n列时停止)
end

% 迭代循环:当最大非三角元素的绝对值小于1e-10时收敛
while abs(C2) > 1e-10
    % 步骤1:提取当前模式下的三角部分(上三角或下三角)
    A1 = fun(A, option);
    % 步骤2:寻找三角部分中绝对值最大的元素位置(i,j)
    [C1, I1] = max(abs(A1));  % C1为每列最大绝对值,I1为对应行索引
    [C2, j] = max(C1);        % C2为全局最大绝对值,j为对应列索引
    i = I1(j);                % i为全局最大元素的行索引
    % 步骤3:判断是否达到停止条件(最大元素在目标列时停止)
    if j == opbreak
        break;
    end
    % 步骤4:构造Givens旋转矩阵R(用于消去A(i,j)元素)
    d = A(i,j) / A(j,j);               % 计算旋转参数d
    c = 1 / sqrt(1 + d^2);             % 旋转矩阵的余弦分量
    s = -d * c;                        % 旋转矩阵的正弦分量
    R = eye(n);                        % 初始化n阶单位矩阵
    R(i,i) = c; R(i,j) = s;            % 填充旋转矩阵的(i,i)和(i,j)位置
    R(j,i) = -s; R(j,j) = c;           % 填充旋转矩阵的(j,i)和(j,j)位置
    % 步骤5:更新变换矩阵Q和待分解矩阵A
    Q = Q * R';    % Q累积旋转(R'为R的转置,因Givens矩阵正交,R'=R逆)
    A = R * A;     % 左乘R,逐步将A化为目标三角矩阵
    k = k + 1;     % 迭代次数加1
end


%% 3. 输出计算结果
fprintf('\n==================== Givens旋转变换分解结果 ====================\n');
fprintf('1. 迭代次数 k = %d\n', k);  % 输出总迭代次数

fprintf('\n2. 正交变换矩阵 Q(满足Q''=Q逆):\n');
disp(Q);

if X == 1
    fprintf('\n3. QL分解后的下三角矩阵 A(满足A = QL,L为下三角):\n');
else
    fprintf('\n3. QR分解后的上三角矩阵 A(满足A = QR,R为上三角):\n');
end
disp(A);


%% 4. 结果验证(验证分解正确性)
fprintf('\n==================== 结果验证 ====================\n');
% 验证1:Q是否为正交矩阵(Q'*Q应接近单位矩阵)
ortho_check = Q' * Q;
fprintf('Q的正交性验证(Q''*Q 应接近单位矩阵):\n');
disp(ortho_check);

% 验证2:分解正确性(QL或QR应接近原始矩阵)
if X == 1  % QL分解:原始A ≈ Q * 分解后的A(因A=QL,L为分解后的下三角)
    recover_A = Q * A;
    fprintf('\nQL分解验证(原始A ≈ Q * 分解后A):\n');
else  % QR分解:原始A ≈ Q * 分解后的A(因A=QR,R为分解后的上三角)
    recover_A = Q * A;
    fprintf('\nQR分解验证(原始A ≈ Q * 分解后A):\n');
end
disp(recover_A);

% 量化误差(Frobenius范数)
error = norm(recover_A - A, 'fro');
fprintf('\n分解误差(||恢复矩阵 - 原始矩阵||_F):%.6e\n', error);
fprintf('说明:误差为浮点计算误差,数值≤1e-10时表明分解正确。\n');