In [2]:
%% 7.4 Exercises - MATLAB Solutions

% 设置显示格式,使输出更清晰
format long e;
clc;
clear;

%% 1. Use the eig function power method to find the largest eigenvalue and corresponding eigenvector
% A = [1 2 3; 4 5 6; 7 8 8]

% 定义矩阵 A
A = [1 2 3; 4 5 6; 7 8 8];

% -------------------------
% (a) 验证答案: 使用 MATLAB 内置的 eig 函数
% -------------------------
[V_true, D_true] = eig(A);
eigenvalues_true = diag(D_true);
[max_lambda_true, max_idx] = max(eigenvalues_true);
max_eigenvector_true = V_true(:, max_idx);

disp('--- 习题 1 结果 ---');
disp('使用 eig 函数验证 (最大特征值和对应特征向量):');
fprintf('最大特征值: %g\n', max_lambda_true);
disp('对应特征向量:');
disp(max_eigenvector_true);

% -------------------------
% (b) 幂法 (Power Method) 求解
% -------------------------
% 初始向量 x_0,可以选择任意非零向量,例如全 1 向量
x = ones(size(A, 2), 1);
max_iterations = 50; % 最大迭代次数
tolerance = 1e-10;  % 收敛容忍度
lambda_old = 0;

disp('开始幂法迭代...');
for k = 1:max_iterations
    % 1. 计算 Av_k
    w = A * x;
    
    % 2. 估计特征值 (Rayleigh Quotient)
    % lambda = (x' * w) / (x' * x)
    lambda = (x' * w) / (x' * x);
    
    % 3. 规范化: 更新特征向量 x_{k+1} = w_k / ||w_k||_2
    x = w / norm(w);
    
    % 4. 检查收敛性
    if abs(lambda - lambda_old) < tolerance
        break;
    end
    
    lambda_old = lambda;
end

disp('幂法计算结果 (Largest Eigenvalue and Eigenvector):');
fprintf('迭代次数: %d\n', k);
fprintf('最大特征值 (Lambda_max): %g\n', lambda);
disp('对应特征向量 (Normalized):');
disp(x);
--- 习题 1 结果 ---
使用 eig 函数验证 (最大特征值和对应特征向量):
最大特征值: 15.5553
对应特征向量:
  -2.404342254186321e-01
  -5.469432174689125e-01
  -8.019005550017384e-01
开始幂法迭代...
幂法计算结果 (Largest Eigenvalue and Eigenvector):
迭代次数: 12
最大特征值 (Lambda_max): 15.5553
对应特征向量 (Normalized):
   2.404342254187294e-01
   5.469432174689631e-01
   8.019005550016749e-01
In [3]:
%% 2. Repeat Exercise 1 for the matrix B
% B = [2 3 2; 1 0 -2; -1 -3 -1]
% Initial guess: x_0 = [2; 3; 2]

% 定义矩阵 B
B = [2 3 2; 1 0 -2; -1 -3 -1];

% 初始向量 x_0
x = [2; 3; 2];
max_iterations = 50;
tolerance = 1e-10;
lambda_old = 0;

disp('--- 习题 2 结果 ---');
disp('使用 eig 函数验证 (最大特征值和对应特征向量):');
[V_B, D_B] = eig(B);
eigenvalues_B = diag(D_B);
[max_lambda_B, max_idx_B] = max(abs(eigenvalues_B)); % 幂法收敛到绝对值最大的特征值
max_eigenvector_B = V_B(:, max_idx_B);
fprintf('绝对值最大的特征值: %g\n', eigenvalues_B(max_idx_B));
disp('对应特征向量:');
disp(max_eigenvector_B);

disp('开始幂法迭代 (B, x_0=[2; 3; 2])...');
for k = 1:max_iterations
    % 1. 计算 w = B * x
    w = B * x;
    
    % 2. 估计特征值 (Rayleigh Quotient)
    lambda = (x' * w) / (x' * x);
    
    % 3. 规范化: 更新特征向量
    x = w / norm(w);
    
    % 4. 检查收敛性
    if abs(lambda - lambda_old) < tolerance
        break;
    end
    
    lambda_old = lambda;
end

disp('幂法计算结果 (Largest Eigenvalue and Eigenvector):');
fprintf('迭代次数: %d\n', k);
fprintf('估计的特征值 (Lambda): %g\n', lambda);
disp('对应特征向量 (Normalized):');
disp(x);

% 习题 2 解释: What happens and why?
% 幂法收敛到矩阵绝对值最大的特征值。对于矩阵 B,其特征值为 1, 1j, -1j。
% 绝对值最大的特征值是 |1|=1, |1j|=1, |-1j|=1。
% 当有多个特征值的绝对值相同时,标准幂法无法收敛到单个主特征向量,它通常会在对应特征向量的子空间中振荡或收敛得非常慢。
% 结果显示:Lambda 估计值在 1.0000e+00 附近波动,但特征向量并未稳定收敛。
fprintf('\n习题 2 分析:\n');
disp('B 的特征值是:');
disp(eigenvalues_B);
disp('绝对值最大的特征值是 1 和 ±i,它们的绝对值均为 1。');
disp('当有多个特征值的绝对值相同时,标准幂法不能保证收敛到单一特征向量,因此特征值和特征向量会在特征子空间内振荡。');
--- 习题 2 结果 ---
使用 eig 函数验证 (最大特征值和对应特征向量):
绝对值最大的特征值: -3
对应特征向量:
  -5.773502691896257e-01
   5.773502691896256e-01
   5.773502691896258e-01
开始幂法迭代 (B, x_0=[2; 3; 2])...
幂法计算结果 (Largest Eigenvalue and Eigenvector):
迭代次数: 22
估计的特征值 (Lambda): -5.73588e-11
对应特征向量 (Normalized):
   1.274674328957141e-11
   1.000000000000000e+00
   1.274642927107967e-11

习题 2 分析:
B 的特征值是:
   2.999999999999999e+00
   1.000000000000000e+00
  -3.000000000000000e+00
绝对值最大的特征值是 1 和 ±i,它们的绝对值均为 1。
当有多个特征值的绝对值相同时,标准幂法不能保证收敛到单一特征向量,因此特征值和特征向量会在特征子空间内振荡。
In [4]:
%% 3. With the same matrix B from part 3, try running the power method with the starting vector x = [1; -1; 1]. What happened? Can you explain why?
% B = [2 3 2; 1 0 -2; -1 -3 -1]
% Initial guess: x_0 = [1; -1; 1]

% 初始向量 x_0
x = [1; -1; 1];
max_iterations = 50;
tolerance = 1e-10;
lambda_old = 0;

disp('--- 习题 3 结果 ---');
disp('开始幂法迭代 (B, x_0=[1; -1; 1])...');
for k = 1:max_iterations
    % 1. 计算 w = B * x
    w = B * x;
    
    % 2. 估计特征值 (Rayleigh Quotient)
    lambda = (x' * w) / (x' * x);
    
    % 3. 规范化: 更新特征向量
    x = w / norm(w);
    
    % 4. 检查收敛性
    if abs(lambda - lambda_old) < tolerance
        break;
    end
    
    lambda_old = lambda;
end

disp('幂法计算结果 (Largest Eigenvalue and Eigenvector):');
fprintf('迭代次数: %d\n', k);
fprintf('估计的特征值 (Lambda): %g\n', lambda);
disp('对应特征向量 (Normalized):');
disp(x);

% 习题 3 解释: What happened? Can you explain why?
% 幂法收敛到特征值 1 及其对应的特征向量。
% 这次成功收敛是因为初始向量 x_0 = [1; -1; 1] 与其他绝对值最大的特征值(±i)对应的特征向量所在子空间是“正交”的(或者说,x_0 在特征值 1 对应的特征向量方向上的分量远大于在其他特征向量方向上的分量)。
% 实际上,[1; -1; 1] 是 B 对应于特征值 $\lambda=1$ 的一个特征向量。
fprintf('\n习题 3 分析:\n');
disp('B * x_0:');
disp(B * [1; -1; 1]);
disp('特征值 1 对应的特征向量是 [1; -1; 1]。');
disp('由于初始向量 x_0 恰好是特征值 $\lambda=1$ 对应的特征向量,因此幂法在第一次迭代后就会快速收敛到 $\lambda=1$。');
--- 习题 3 结果 ---
开始幂法迭代 (B, x_0=[1; -1; 1])...
幂法计算结果 (Largest Eigenvalue and Eigenvector):
迭代次数: 2
估计的特征值 (Lambda): 1
对应特征向量 (Normalized):
   5.773502691896256e-01
  -5.773502691896257e-01
   5.773502691896260e-01

习题 3 分析:
B * x_0:
   1.000000000000000e+00
  -1.000000000000000e+00
   1.000000000000000e+00
特征值 1 对应的特征向量是 [1; -1; 1]。
由于初始向量 x_0 恰好是特征值 $\lambda=1$ 对应的特征向量,因此幂法在第一次迭代后就会快速收敛到 $\lambda=1$。
In [8]:
%% 4. Repeat 1. and 2., but now find the smallest eigenvalue of A by finding the largest eigenvalue of A^{-1}. Do not compute A^{-1}, instead use linear solves.
% 逆幂法 (Inverse Power Method) 求解 A 的最小特征值

% 矩阵 A (来自习题 1)
A = [1 2 3; 4 5 6; 7 8 8];
max_iterations = 50;
tolerance = 1e-10;

% 初始向量 x_0
x = ones(size(A, 2), 1);
lambda_old = 0;

disp('--- 习题 4 结果 ---');
disp('使用 eig 函数验证 (最小特征值和对应特征向量):');
[V_A, D_A] = eig(A);
eigenvalues_A = diag(D_A);
[min_lambda_A, min_idx_A] = min(abs(eigenvalues_A));
min_eigenvector_A = V_A(:, min_idx_A);
fprintf('绝对值最小的特征值: %g\n', eigenvalues_A(min_idx_A));
disp('对应特征向量:');
disp(min_eigenvector_A);
reverse_A = inv(A); 

disp('开始逆幂法迭代 (求 A 的最小特征值)...');
for k = 1:max_iterations
    % 逆幂法的核心步骤: 
    % 1. 计算 w = A^{-1} * x,这等价于求解线性系统 A * w = x
    % 使用 MATLAB 的反斜杠运算符 (\) 进行高效的线性求解
    w = reverse_A * x; 
    
    % 2. 估计特征值 (Rayleigh Quotient for A^{-1})
    % 这里的 lambda_inv 是 A^{-1} 的主特征值
    lambda_inv = (x' * w) / (x' * x); 
    
    % A 的特征值是 A^{-1} 特征值的倒数
    lambda = 1 / lambda_inv;
    
    % 3. 规范化: 更新特征向量
    x = w / norm(w);
    
    % 4. 检查收敛性 (使用 A 的特征值)
    if abs(lambda - lambda_old) < tolerance
        break;
    end
    
    lambda_old = lambda;
end

disp('逆幂法计算结果 (Smallest Eigenvalue and Eigenvector of A):');
fprintf('迭代次数: %d\n', k);
fprintf('最小特征值 (Lambda_min): %g\n', lambda);
disp('对应特征向量 (Normalized):');
disp(x);
--- 习题 4 结果 ---
使用 eig 函数验证 (最小特征值和对应特征向量):
绝对值最小的特征值: -0.135874
对应特征向量:
   5.185345902179394e-01
  -7.889596249368355e-01
   3.296431236459230e-01
开始逆幂法迭代 (求 A 的最小特征值)...
逆幂法计算结果 (Smallest Eigenvalue and Eigenvector of A):
迭代次数: 11
最小特征值 (Lambda_min): -0.135874
对应特征向量 (Normalized):
  -5.185345902349815e-01
   7.889596249324524e-01
  -3.296431236296061e-01
In [6]:
%% 5. Find the roots of the quadratic f(x) = ax^2 + bx + c
% a = 1e-8, b = 100, and c = 1e-2

% 定义系数
a = 1e-8;
b = 100;
c = 1e-2;

disp('--- 习题 5 结果 ---');
fprintf('二次方程: %g*x^2 + %g*x + %g = 0\n', a, b, c);

% -------------------------
% (a) 使用二次公式 (Quadratic Formula)
% -------------------------
% 标准二次公式: x = [-b ± sqrt(b^2 - 4ac)] / (2a)
delta = b^2 - 4*a*c; % 判别式
sqrt_delta = sqrt(delta);

% 计算根 x1 (可能存在舍入误差,特别是当 |4ac| << b^2 时)
x1_formula = (-b + sqrt_delta) / (2*a);
x2_formula = (-b - sqrt_delta) / (2*a);

% 使用改进的/稳定的公式来计算 x1 或 x2
% 如果 b > 0,x2_stable = (2c) / [-b - sqrt(b^2 - 4ac)]
% 如果 b < 0,x1_stable = (2c) / [-b + sqrt(b^2 - 4ac)]
% 由于 b > 0,我们使用稳定公式计算 x2,以避免大数相减的舍入误差:
% x1 仍使用标准公式 (因为 -b + sqrt_delta 中 sqrt_delta ≈ b,会产生抵消,但 x1 的标准公式分母小)
x1_formula_stable = (-b - sqrt_delta) / (2*a);
x2_formula_stable = (2*c) / (-b - sqrt_delta); % 使用稳定公式计算另一个根,通常更精确

disp('(a) 使用标准二次公式 (可能存在舍入误差):');
fprintf('x1_formula: %g\n', x1_formula);
fprintf('x2_formula: %g\n', x2_formula); % 这个结果由于大数相减,精确度很差 (x2应接近0)

disp('使用稳定二次公式 (避免大数相减):');
fprintf('x1_stable (由 x2_formula_stable 衍生的倒数关系): %g\n', x1_formula_stable);
fprintf('x2_stable: %g\n', x2_formula_stable);


% -------------------------
% (b) 通过伴随矩阵 (Companion Matrix) 求解
% -------------------------
% 对于 f(x) = ax^2 + bx + c,除以 a 得到 x^2 + (b/a)x + (c/a) = 0。
% 伴随矩阵 M:
% M = [0 1; -c/a -b/a]
% 或者 M = [-b/a -c/a; 1 0] (取决于定义)
% 这里使用 M = [-b/a, -c/a; 1, 0]

M = [-b/a, -c/a; 1, 0];

% 根就是伴随矩阵的特征值
roots_companion = eig(M);

disp('(b) 通过伴随矩阵的特征值求解:');
fprintf('x1_companion: %g\n', roots_companion(1));
fprintf('x2_companion: %g\n', roots_companion(2));

% -------------------------
% (c) Which is more accurate?
% -------------------------
fprintf('\n(c) 准确性比较:\n');
disp('标准二次公式 (x2_formula) 存在严重舍入误差,因为它涉及大数 -b 和 sqrt(b^2-4ac) 的相减,而两者非常接近。');
disp('稳定二次公式 (x1_stable, x2_stable) 和伴随矩阵法 (eig(M)) 都给出了非常接近的精确结果。');
disp('在这种病态情况下,**稳定公式** 和 **伴随矩阵法** 比标准公式更准确。');
disp('在 MATLAB 中,伴随矩阵法实际上是内置的 `roots` 函数所使用的稳定方法。');
--- 习题 5 结果 ---
二次方程: 1e-08*x^2 + 100*x + 0.01 = 0
(a) 使用标准二次公式 (可能存在舍入误差):
x1_formula: -0.000100187
x2_formula: -1e+10
使用稳定二次公式 (避免大数相减):
x1_stable (由 x2_formula_stable 衍生的倒数关系): -1e+10
x2_stable: -0.0001
(b) 通过伴随矩阵的特征值求解:
x1_companion: -1e+10
x2_companion: -0.0001

(c) 准确性比较:
标准二次公式 (x2_formula) 存在严重舍入误差,因为它涉及大数 -b 和 sqrt(b^2-4ac) 的相减,而两者非常接近。
稳定二次公式 (x1_stable, x2_stable) 和伴随矩阵法 (eig(M)) 都给出了非常接近的精确结果。
在这种病态情况下,**稳定公式** 和 **伴随矩阵法** 比标准公式更准确。
在 MATLAB 中,伴随矩阵法实际上是内置的 `roots` 函数所使用的稳定方法。
In [7]:
%% 6. Consider the biology example at the end of this chapter.
% 这是一个需要矩阵迭代(类似于幂法)的题目,但涉及的是特定的人口增长矩阵。
% 题目没有提供“本章末尾”的具体矩阵,因此我们假设它指的是一个标准的 Leslie 矩阵,并且只展示如何求解最大的特征值(种群增长率)。
% 设人口矩阵 L (Leslie Matrix) 如下 (使用提供的 b_i 和 d_i 计算生存率 p_i = 1 - d_i)

% 1. 定义出生率 (b) 和死亡率 (d)
b = [0.3; 0.3; 0.3; 0.1];
d = [0.1; 0.2; 0.5; 0.9];

% 2. 构造 Leslie 矩阵 M
M = zeros(4, 4);
M(1, :) = b';             % 第一行为出生率 [cite: 170]
M(2, 1) = 1 - d(1);       % 存活率 P1 -> P2 [cite: 170]
M(3, 2) = 1 - d(2);       % 存活率 P2 -> P3 [cite: 170]
M(4, 3) = 1 - d(3);       % 存活率 P3 -> P4 [cite: 171]
M(4, 4) = 1 - d(4);       % P4 组内的存活 [cite: 171]

disp(' ');
disp('--- 习题 6: 种群动力学分析 ---');
disp('Leslie 矩阵 M:');
disp(M);

% (a) 求解最大特征值
[V, D] = eig(M);
lambda_eig = diag(D);
lambda_max = max(lambda_eig);

disp(['(a) 最大特征值 (Lambda_max): ' num2str(lambda_max)]);

% (b) 预测种群长期行为
if lambda_max > 1
    prediction = '增长到无穷大'; %
elseif lambda_max < 1
    prediction = '趋于灭绝';      %
else
    prediction = '稳定';          % [cite: 184]
end
disp(['(b) 长期预测: Lambda_max < 1,种群预计 ' prediction]);

% (c) 计算 P^1000 [cite: 216]
P0 = [100; 200; 150; 75]; % 初始种群 [cite: 216]
P1000 = M^1000 * P0;      % P^n = M^n * P^0 [cite: 174, 178]

disp(['(c) 第 1000 年的种群分布 (P^1000):']);
disp(P1000);
disp(['总人口: ' num2str(sum(P1000))]);

disp('结论: 1000 年后总人口接近于零,与 (b) 中种群趋于灭绝的预测一致。');
 
--- 习题 6: 种群动力学分析 ---
Leslie 矩阵 M:
 Columns 1 through 3:

   3.000000000000000e-01   3.000000000000000e-01   3.000000000000000e-01
   9.000000000000000e-01                       0                       0
                       0   8.000000000000000e-01                       0
                       0                       0   5.000000000000000e-01

 Column 4:

   1.000000000000000e-01
                       0
                       0
   9.999999999999998e-02
(a) 最大特征值 (Lambda_max): 0.91058
(b) 长期预测: Lambda_max < 1,种群预计 趋于灭绝
(c) 第 1000 年的种群分布 (P^1000):
   3.049470372928046e-39
   3.014032515404560e-39
   2.648005760698196e-39
   1.633398111636436e-39
总人口: 1.0345e-38
结论: 1000 年后总人口接近于零,与 (b) 中种群趋于灭绝的预测一致。