clear; clc; 


%% 1. 输入计算所需参数（可根据需求替换）
% 待求特征值的方阵A（示例为3阶对称矩阵，确保B=A-pI可逆，可替换为任意方阵）
A = [6 2 1; 
     2 5 3; 
     1 3 7];  

% 原点平移参数p（目标：求解A在p附近的特征值，若求最小特征值，可设p接近0或根据特征值估计值设置）
% 示例：假设A的特征值在1~10之间，取p=2（靠近较小特征值，加速收敛到最小特征值）
p = 2;  

% 初始特征向量u（需为非零列向量，维度与A匹配，通常设为全1列向量）
u = [1; 1; 1];  

% 输出输入信息，便于后续对比
fprintf('待计算特征值的矩阵A：\n');
disp(A);
fprintf('\n原点平移参数 p = %.2f（求解A在p附近的特征值）\n', p);
fprintf('\n初始特征向量u：\n');
disp(u);
[m,n] = size(A);  % 获取矩阵A维度（需满足m=n，即方阵）
if m ~= n
    error('输入矩阵A必须为方阵！');  % 反幂法仅适用于方阵
end


%% 2. 反幂法（带原点平移）核心计算逻辑（整合原Matrix_invpow2函数核心代码）
I = eye(n);               % 构造n阶单位矩阵
B = A - p * I;            % 原点平移后的矩阵：B = A - pI（核心：通过B⁻¹的特征值反推A的特征值）

i = 1;                    % 迭代次数计数器（初始为1）
dellab = 1;               % 相邻特征值差值（初始设为1，满足循环条件）
miu(1) = max(u);          % B⁻¹的特征值迭代序列（初始值设为u的最大元素）
u_normal = [];            % 存储迭代过程：[迭代次数, 特征向量元素]

% 迭代循环：当特征值差值小于1e-6时收敛
while abs(dellab) > 1e-6
    % 记录当前迭代次数与特征向量（第1列=迭代次数，后续列=特征向量元素，迭代次数从0开始）
    u_normal = [u_normal; i-1, u'];  % u'将列向量转为行向量，便于拼接
    % 步骤1：反幂法核心（解线性方程组Bv=u，等价于v = B⁻¹u，避免直接求逆矩阵）
    v = B \ u;  % 利用MATLAB的线性方程组求解器，比直接求逆更稳定
    i = i + 1;  % 迭代次数加1（因v是下一步结果，此处先更新i）
    % 步骤2：确定B⁻¹当前迭代的特征值miu(i)（取v中绝对值最大元素，保留符号）
    [vmax, j] = max(abs(v));        % vmax=v的最大绝对值，j=对应索引
    miu(i) = vmax * sign(v(j));     % B⁻¹的特征值（符号由v(j)决定）
    % 步骤3：归一化特征向量u（避免数值溢出，确保迭代稳定）
    u = v / miu(i);
    % 步骤4：计算相邻特征值差值（从第2次迭代开始判断收敛）
    if i >= 3  % 因i已在v计算后加1，此处i=3对应第2次迭代的差值
        dellab = miu(i) - miu(i-1);
    end
end

% 最终结果计算（与原函数输出对应）
lambta = 1 ./ miu + p;             % A的特征值序列（λ = 1/μ + p，μ为B⁻¹的特征值）
final_miu = miu(end);              % B⁻¹收敛后的特征值
final_lambta = lambta(end);        % A收敛后的目标特征值（最终结果）
final_u = u;                       % 收敛后的对应特征向量（A和B⁻¹的特征向量相同）


%% 3. 输出计算结果
fprintf('\n==================== 反幂法（带原点平移）计算结果 ====================\n');
% 1. 迭代过程记录
fprintf('1. 迭代过程（第1列：迭代次数，后续列：特征向量）：\n');
disp(u_normal);

% 2. 特征值迭代序列关系（B⁻¹的特征值μ vs A的特征值λ=1/μ+p）
fprintf('\n2. 特征值迭代序列关系：\n');
fprintf('   B⁻¹ = (A - pI)⁻¹ 的特征值序列μ：\n');
disp(miu);
fprintf('   A 的特征值序列λ = 1/μ + p：\n');
disp(lambta);

% 3. 最终核心结果
fprintf('\n3. 收敛后的核心结果：\n');
fprintf('   - B⁻¹ 的特征值μ：%.8f\n', final_miu);
fprintf('   - A 在p附近的特征值λ：%.8f\n', final_lambta);
fprintf('   - 对应特征值的特征向量u（归一化后）：\n');
disp(final_u);

% 4. 迭代收敛信息
fprintf('\n4. 迭代收敛信息：\n');
fprintf('   - 收敛条件：相邻特征值差值 |dellab| ≤ 1e-6\n');
fprintf('   - 总迭代次数：%d 次\n', length(miu)-1);  % 迭代次数=特征值序列长度-1
fprintf('   - 反幂法优势：比普通幂法更快收敛到指定p附近的特征值（尤其适合求最小特征值）\n');


%% 5. 结果验证（验证 A*u ≈ λu，确认特征值/向量正确性）
fprintf('\n==================== 结果验证 ====================\n');
left = A * final_u;              % 计算 A*u（特征方程左侧）
right = final_lambta * final_u;  % 计算 λ*u（特征方程右侧）
diff = left - right;             % 两者差值（理论应为0向量，误差源于浮点计算）
error = norm(diff, 'fro');       % 用Frobenius范数量化误差（越小越准确）

fprintf('A*u 的计算结果：\n');
disp(left);
fprintf('λ*u 的计算结果：\n');
disp(right);
fprintf('\n验证误差（||A*u - λ*u||_F）：%.6e\n', error);
fprintf('说明：误差为浮点计算误差，数值≤1e-6时表明特征值/向量正确。\n');