返回目录

Jacobi.m

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

文件预览

% 优化版Jacobi方法(解决卡住问题)
% 新增:最大迭代次数限制、非对称矩阵强制退出、索引有效性检查
clear; clc;

%% 1. 输入参数(可修改)
A = [4 1 1; 
     1 3 2; 
     1 2 3];  % 对称矩阵(示例)
% A = [1 2 3; 4 5 6; 7 8 9];  % 非对称矩阵(测试用,会快速退出)
X = 1;  % 1=上三角模式,2=下三角模式
max_iter = 10000;  % 最大迭代次数(防止无限循环)
tol = 1e-8;        % 收敛阈值


%% 2. 初始化与参数检查
[m,n] = size(A);
if m ~= n
    error('矩阵必须为方阵!');
end
% 检查对称性,非对称矩阵提示并限制迭代
is_symmetric = isequal(A, A');
if ~is_symmetric
    warning('输入矩阵非对称,Jacobi方法可能不收敛,将限制迭代次数!');
end

C2 = 1;          % 最大非对角元素绝对值
Rk = eye(n);     % 旋转矩阵累积器
k = 0;           % 迭代计数器

% 选择旋转模式(上三角/下三角)
switch X
    case 1
        fun = @(M) triu(M,1);  % 提取上三角非对角元素(不含对角线)
    case 2
        fun = @(M) tril(M,-1); % 提取下三角非对角元素(不含对角线)
    otherwise
        error('X必须为1或2!');
end


%% 3. 核心迭代(添加退出保护)
while abs(C2) > tol && k < max_iter
    % 提取非对角元素并找最大值位置
    A1 = fun(A);
    [C1, I1] = max(abs(A1));  % 每列最大绝对值及行索引
    [C2, j] = max(C1);        % 全局最大绝对值及列索引
    i = I1(j);                % 行索引
    
    % 保护:避免i=j(对角线元素)或索引越界
    if i == j || i < 1 || i > n || j < 1 || j > n
        warning('无效索引(i,j),提前退出迭代!');
        break;
    end
    
    % 计算Givens旋转参数(避免除以零)
    a_ij = A(i,j);
    if abs(a_ij) < 1e-15  % 防止分母为零
        C2 = 0;  % 视为已收敛
        continue;
    end
    dij = (A(i,i) - A(j,j)) / (2 * a_ij);
    t = sign(dij) / (abs(dij) + sqrt(1 + dij^2));
    c = 1 / sqrt(1 + t^2);
    s = t * c;
    
    % 构造旋转矩阵并更新A和Rk
    R = eye(n);
    R(i,i) = c;  R(i,j) = s;
    R(j,i) = -s; R(j,j) = c;
    A = R * A * R';  % 相似变换
    Rk = R * Rk;     % 累积旋转
    k = k + 1;       % 计数迭代次数
end


%% 4. 输出结果与状态判断
fprintf('迭代结束:\n');
if k >= max_iter && abs(C2) > tol
    fprintf('警告:达到最大迭代次数(%d次),未完全收敛!\n', max_iter);
else
    fprintf('成功收敛:迭代次数=%d次,最终非对角最大元素=%.2e\n', k, C2);
end

fprintf('\n对角化矩阵Ak:\n');
disp(A);
fprintf('\n正交矩阵Qk:\n');
disp(Rk');


%% 5. 结果验证
fprintf('\n验证:\n');
fprintf('Qk的正交性(Qk''*Qk):\n');
disp(Rk' * Rk);
fprintf('原始矩阵恢复(Qk*Ak*Qk''):\n');
disp(Rk * A * Rk');