昆仑山:眼中无形心中有穴之穴人合一

夫君子之行,静以修身,俭以养德;非澹泊无以明志,非宁静无以致远。夫学须静也,才须学也;非学无以广才,非志无以成学。怠慢则不能励精,险躁则不能冶性。年与时驰,意与岁去,遂成枯落,多不接世。悲守穷庐,将复何及!

 

超松弛迭代法求解线性方程组

import numpy as np
import matplotlib.pyplot as plt


def sor_solver(A, b, omega, x0, tol=1e-5, max_iterations=200):
    """
    使用SOR方法求解线性方程组 Ax = b.

    参数:
        A (np.array): 系数矩阵.
        b (np.array): 常数向量.
        omega (float): 松弛因子 (0 < omega < 2).
        x0 (np.array): 初始猜测向量.
        tol (float): 收敛容差.
        max_iterations (int): 最大迭代次数.

    返回:
        x (np.array): 方程组的解.
        iterations (int): 达到收敛所用的迭代次数.
        errors (list): 每次迭代的误差历史 (无穷范数).
    """
    n = len(b)
    x = x0.copy()
    # 文档中例子的精确解,用于计算真实误差
    x_exact = np.array([1.1, 1.2, 1.3])
    errors = []

    for k in range(max_iterations):
        x_old = x.copy()

        # 应用SOR迭代公式
        # x_i^(k+1) = (1-ω)x_i^(k) + (ω/a_ii)*(b_i - Σ(j<i) a_ij*x_j^(k+1) - Σ(j>i) a_ij*x_j^(k))
        for i in range(n):
            sigma1 = np.dot(A[i, :i], x[:i])
            sigma2 = np.dot(A[i, i + 1:], x_old[i + 1:])
            x[i] = (1 - omega) * x_old[i] + (omega / A[i, i]) * (b[i] - sigma1 - sigma2)

        # 记录与精确解的误差(使用无穷范数)
        error = np.linalg.norm(x - x_exact, np.inf)
        errors.append(error)

        # 检查迭代是否收敛(基于相邻两次迭代结果的差异)
        if np.linalg.norm(x - x_old, np.inf) < tol:
            return x, k + 1, errors

    return x, max_iterations, errors


# --- 主程序 ---
# 从文档【例6.8】中获取方程组信息
A = np.array([
    [10.0, -1.0, -2.0],
    [-1.0, 10.0, -2.0],
    [-1.0, -1.0, 5.0]
])

b = np.array([7.2, 8.3, 4.2])

# 初始猜测向量
x0 = np.zeros_like(b)

# 从文档表6.4中选择不同的松弛因子进行测试
omegas_to_test = [0.8, 1.0, 1.055, 1.2, 1.4, 1.8]

# --- 可视化 ---
# 设置matplotlib以支持中文显示
# 请确保你的环境中已安装支持中文的字体,如'SimHei', 'Microsoft YaHei'等
try:
    plt.rcParams['font.family'] = 'serif'
    plt.rcParams['font.serif'] = ['SimHei','DejaVu Serif', 'Times New Roman', 'Computer Modern Roman']
    plt.rcParams['mathtext.fontset'] = 'cm'
    plt.rcParams['axes.unicode_minus'] = False
except:
    print("未找到中文字体'SimHei', 图表标签可能无法正常显示。")

plt.figure(figsize=(12, 9))

# 对每个omega值运行SOR算法并绘图
for omega in omegas_to_test:
    solution, iterations, errors = sor_solver(A, b, omega, x0)
    label_text = f'ω = {omega} ({iterations} 次迭代)'
    if omega == 1.0:
        label_text = f'高斯-赛德尔 (ω = 1.0) ({iterations} 次迭代)'
    if omega == 1.055:
        label_text = f'最佳因子 ω = {omega} ({iterations} 次迭代)'

    plt.plot(range(1, len(errors) + 1), errors, marker='o', linestyle='-', markersize=4, label=label_text)

# --- 绘图设置 ---
plt.yscale('log')  # Y轴使用对数刻度以更好地观察误差下降
plt.xlabel('迭代次数 (k)', fontsize=14)
plt.ylabel('误差 (无穷范数 ||x^(k) - x*||∞)', fontsize=14)
plt.title('不同松弛因子(ω)对SOR算法收敛速度的影响', fontsize=16)
plt.legend(fontsize=12)
plt.grid(True, which="both", ls="--")
plt.show()


SOR-V2

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties, findfont
from scipy.sparse import diags


# ========== 自动检测中文字体 ==========
def setup_chinese_font():
    """自动检测并设置可用的中文字体"""
    chinese_fonts = ["Microsoft YaHei", "FangSong", "KaiTi", "SimHei", "SimSun"]

    found_font = None
    for font in chinese_fonts:
        try:
            if findfont(FontProperties(family=[font])) not in ['', None]:
                found_font = font
                break
        except:
            continue

    if found_font:
        plt.rcParams['font.sans-serif'] = [found_font]
        plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题
        print(f"✅ 使用中文字体: {found_font}")
    else:
        print("⚠️ 未找到可用中文字体,请手动安装 SimHei.ttf 或指定字体路径。")


# 初始化中文字体
setup_chinese_font()


# ========== SOR迭代求解器 ==========
def sor_solver(A, b, omega, x0, tol=1e-5, max_iterations=200):
    """
    使用SOR(逐次超松弛)方法求解线性方程组 Ax = b

    参数:
        A: 系数矩阵 (n x n)
        b: 右侧向量 (n x 1)
        omega: 松弛因子 (0 < omega < 2)
        x0: 初始猜测解 (n x 1)
        tol: 收敛容差
        max_iterations: 最大迭代次数

    返回:
        x: 解向量
        residuals: 残差历史记录
        iterations: 实际迭代次数
    """
    n = len(b)
    x = x0.copy()
    residuals = []

    for k in range(max_iterations):
        x_new = x.copy()
        for i in range(n):
            sigma = 0.0
            # 前向替换 (已经更新的分量)
            for j in range(i):
                sigma += A[i, j] * x_new[j]
            # 后向替换 (尚未更新的分量)
            for j in range(i + 1, n):
                sigma += A[i, j] * x[j]

            # SOR更新公式
            x_new[i] = (1 - omega) * x[i] + (omega / A[i, i]) * (b[i] - sigma)

        # 计算残差
        residual = np.linalg.norm(A @ x_new - b)
        residuals.append(residual)

        # 检查收敛
        if residual < tol:
            break

        x = x_new

    return x_new, np.array(residuals), k + 1


# ========== 测试案例生成 ==========
def generate_test_case(n=100, k=3):
    """
    生成对角占优的三对角矩阵测试案例

    参数:
        n: 矩阵维度
        k: 对角占优系数 (越大对角占优越强)

    返回:
        A: 系数矩阵
        b: 右侧向量
        x_true: 真实解 (随机生成)
    """
    # 主对角线元素
    main_diag = (2 * k + 1) * np.ones(n)
    # 上下对角线元素
    off_diag = -k * np.ones(n - 1)
    # 构造三对角矩阵
    A = diags([off_diag, main_diag, off_diag], [-1, 0, 1]).toarray()

    # 生成随机真实解
    x_true = np.random.rand(n)
    # 计算对应的右侧向量
    b = A @ x_true

    return A, b, x_true


# ========== 可视化分析 ==========
def plot_convergence(residuals, omega):
    """绘制单个松弛因子的收敛曲线"""
    plt.figure(figsize=(10, 6))
    plt.semilogy(residuals, 'o-', label=f'ω={omega:.2f}')
    plt.title('SOR方法收敛曲线', fontsize=14)
    plt.xlabel('迭代次数', fontsize=12)
    plt.ylabel('残差 (log scale)', fontsize=12)
    plt.legend()
    plt.grid(True, which="both", ls="--")
    plt.show()


def plot_omega_comparison(omega_list, all_residuals):
    """绘制不同松弛因子的收敛对比图"""
    plt.figure(figsize=(12, 6))
    for omega, residuals in zip(omega_list, all_residuals):
        plt.semilogy(residuals, 'o-', markersize=3, label=f'ω={omega:.2f}')

    plt.title('不同松弛因子下的SOR收敛对比', fontsize=14)
    plt.xlabel('迭代次数', fontsize=12)
    plt.ylabel('残差 (log scale)', fontsize=12)
    plt.legend()
    plt.grid(True, which="both", ls="--")
    plt.show()


def plot_omega_performance(omega_list, iterations_list):
    """绘制松弛因子与迭代次数的关系图"""
    plt.figure(figsize=(12, 6))
    plt.plot(omega_list, iterations_list, 'bo-')
    plt.title('松弛因子对收敛速度的影响', fontsize=14)
    plt.xlabel('松弛因子 ω', fontsize=12)
    plt.ylabel('达到收敛所需迭代次数', fontsize=12)
    plt.grid(True)
    plt.show()


# ========== 主程序 ==========
def main():
    # 生成测试案例
    n = 100
    A, b, x_true = generate_test_case(n)
    x0 = np.zeros(n)  # 初始猜测

    # 测试不同松弛因子
    omega_list = np.linspace(1.0, 1.9, 10)  # 测试1.0到1.9之间的5个ω值
    all_residuals = []
    iterations_list = []

    print("开始不同松弛因子的对比测试...")
    for omega in omega_list:
        # 使用SOR求解
        x_sor, residuals, iterations = sor_solver(A, b, omega, x0)
        all_residuals.append(residuals)
        iterations_list.append(iterations)

        # 计算误差
        error = np.linalg.norm(x_sor - x_true)
        print(f"ω={omega:.2f}: {iterations}次迭代, 最终误差={error:.2e}")

    # 绘制对比图
    plot_omega_comparison(omega_list, all_residuals)
    plot_omega_performance(omega_list, iterations_list)

    # 单独展示最优ω的结果
    best_idx = np.argmin(iterations_list)
    best_omega = omega_list[best_idx]
    print(f"\n最佳松弛因子: ω={best_omega:.2f}")
    plot_convergence(all_residuals[best_idx], best_omega)


if __name__ == "__main__":
    main()



SOR三图合一

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from matplotlib.font_manager import FontProperties, findfont
from scipy.sparse import diags


# ========== 自动检测中文字体 ==========
def setup_chinese_font():
    """自动检测并设置可用的中文字体"""
    chinese_fonts = ["Microsoft YaHei", "FangSong", "KaiTi", "SimHei", "SimSun"]

    found_font = None
    for font in chinese_fonts:
        try:
            if findfont(FontProperties(family=[font])) not in ['', None]:
                found_font = font
                break
        except:
            continue

    if found_font:
        plt.rcParams['font.sans-serif'] = [found_font]
        plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题
        print(f"✅ 使用中文字体: {found_font}")
    else:
        print("⚠️ 未找到可用中文字体,请手动安装 SimHei.ttf 或指定字体路径。")


# 初始化中文字体
setup_chinese_font()


# ========== SOR迭代求解器 ==========
def sor_solver(A, b, omega, x0, tol=1e-5, max_iterations=200):
    """
    使用SOR(逐次超松弛)方法求解线性方程组 Ax = b

    参数:
        A: 系数矩阵 (n x n)
        b: 右侧向量 (n x 1)
        omega: 松弛因子 (0 < omega < 2)
        x0: 初始猜测解 (n x 1)
        tol: 收敛容差
        max_iterations: 最大迭代次数

    返回:
        x: 解向量
        residuals: 残差历史记录
        iterations: 实际迭代次数
    """
    n = len(b)
    x = x0.copy()
    residuals = []

    for k in range(max_iterations):
        x_new = x.copy()
        for i in range(n):
            sigma = 0.0
            # 前向替换 (已经更新的分量)
            for j in range(i):
                sigma += A[i, j] * x_new[j]
            # 后向替换 (尚未更新的分量)
            for j in range(i + 1, n):
                sigma += A[i, j] * x[j]

            # SOR更新公式
            x_new[i] = (1 - omega) * x[i] + (omega / A[i, i]) * (b[i] - sigma)

        # 计算残差
        residual = np.linalg.norm(A @ x_new - b)
        residuals.append(residual)

        # 检查收敛
        if residual < tol:
            break

        x = x_new

    return x_new, np.array(residuals), k + 1


# ========== 测试案例生成 ==========
def generate_test_case(n=100, k=3):
    """
    生成对角占优的三对角矩阵测试案例

    参数:
        n: 矩阵维度
        k: 对角占优系数 (越大对角占优越强)

    返回:
        A: 系数矩阵
        b: 右侧向量
        x_true: 真实解 (随机生成)
    """
    # 主对角线元素
    main_diag = (2 * k + 1) * np.ones(n)
    # 上下对角线元素
    off_diag = -k * np.ones(n - 1)
    # 构造三对角矩阵
    A = diags([off_diag, main_diag, off_diag], [-1, 0, 1]).toarray()

    # 生成随机真实解
    x_true = np.random.rand(n)
    # 计算对应的右侧向量
    b = A @ x_true

    return A, b, x_true


# ========== 可视化分析 ==========
def plot_combined_analysis(omega_list, all_residuals, iterations_list):
    """
    将三种可视化结果整合到一张图中:
        1. 不同 ω 的收敛曲线
        2. 所有 ω 的残差对比
        3. 松弛因子与迭代次数关系图
    """
    # 准备数据:收敛曲线数据
    df_curve = pd.DataFrame()
    for residuals, omega in zip(all_residuals, omega_list):
        df_single = pd.DataFrame({
            'Iteration': range(1, len(residuals) + 1),
            'Residual': residuals,
            'Omega': f'ω={omega:.2f}'
        })
        df_curve = pd.concat([df_curve, df_single], ignore_index=True)

    # 创建画布:3个子图横向排列
    fig, axes = plt.subplots(1, 3, figsize=(20, 6))

    # 子图1: 多个 ω 的收敛曲线对比
    sns.lineplot(data=df_curve, x='Iteration', y='Residual', hue='Omega', style='Omega',
                 markers=True, dashes=False, ax=axes[0])
    axes[0].set_title('不同松弛因子下的收敛曲线')
    axes[0].set_yscale('log')
    axes[0].set_xlabel('迭代次数')
    axes[0].set_ylabel('残差 (log scale)')
    axes[0].grid(True, which="both", linestyle="--")
    axes[0].legend(title='松弛因子 ω')

    # 子图2: 松弛因子 vs 迭代次数关系图
    axes[1].plot(omega_list, iterations_list, 'bo-')
    axes[1].set_title('松弛因子对收敛速度的影响')
    axes[1].set_xlabel('松弛因子 ω')
    axes[1].set_ylabel('达到收敛所需迭代次数')
    axes[1].grid(True)
    axes[1].axvline(x=omega_list[np.argmin(iterations_list)], color='r', linestyle='--', linewidth=1.5)

    # 子图3: 最佳 ω 的收敛曲线放大展示
    best_idx = np.argmin(iterations_list)
    best_omega = omega_list[best_idx]
    best_residuals = all_residuals[best_idx]

    axes[2].semilogy(best_residuals, 'o-', label=f'ω={best_omega:.2f}')
    axes[2].set_title(f'最佳松弛因子收敛曲线 (ω={best_omega:.2f})')
    axes[2].set_xlabel('迭代次数')
    axes[2].set_ylabel('残差 (log scale)')
    axes[2].legend()
    axes[2].grid(True, which="both", ls="--")

    plt.tight_layout()
    plt.show()


# ========== 主程序 ==========
def main():
    # 生成测试案例
    n = 100
    A, b, x_true = generate_test_case(n)
    x0 = np.zeros(n)  # 初始猜测

    # 测试不同松弛因子
    omega_list = np.linspace(1.0, 1.9, 10)  # 测试1.0到1.9之间的5个ω值
    all_residuals = []
    iterations_list = []

    print("开始不同松弛因子的对比测试...")
    for omega in omega_list:
        x_sor, residuals, iterations = sor_solver(A, b, omega, x0)
        all_residuals.append(residuals)
        iterations_list.append(iterations)

        error = np.linalg.norm(x_sor - x_true)
        print(f"ω={omega:.2f}: {iterations}次迭代, 最终误差={error:.2e}")

    # 替换原有多个绘图函数,统一显示三合一图像
    plot_combined_analysis(omega_list, all_residuals, iterations_list)

    # 单独展示最优ω的结果
    best_idx = np.argmin(iterations_list)
    best_omega = omega_list[best_idx]
    print(f"\n最佳松弛因子: ω={best_omega:.2f}")


if __name__ == "__main__":
    main()



posted on 2025-06-27 09:53  Indian_Mysore  阅读(11)  评论(0)    收藏  举报

导航