% 优化版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');