Skip to content

积分和微分方程

SciPy 提供了强大的数值积分和微分方程求解功能,主要通过 scipy.integrate 模块实现。该模块包含了各种数值积分方法、常微分方程(ODE)求解器、偏微分方程(PDE)求解工具等。这些功能在科学计算、工程分析、物理建模等领域有着广泛的应用。本章将详细介绍如何使用 SciPy 进行数值积分和微分方程求解。

scipy.integrate 模块概述

scipy.integrate 模块包含以下主要功能:

  • 数值积分(定积分和不定积分)
  • 常微分方程求解
  • 边值问题求解
  • 积分方程求解
  • 多重积分计算
python
import numpy as np
from scipy import integrate
import matplotlib.pyplot as plt
from scipy.integrate import (
    quad, dblquad, tplquad, nquad,
    odeint, solve_ivp, solve_bvp,
    simpson, trapz, cumtrapz,
    fixed_quad, quadrature
)
import warnings
warnings.filterwarnings('ignore')

# 设置绘图样式
plt.style.use('seaborn-v0_8')
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 查看 integrate 模块的主要功能
print("scipy.integrate 主要功能:")
functions = [attr for attr in dir(integrate) if not attr.startswith('_')]
print(f"总共 {len(functions)} 个函数和类")
print("积分函数:", [f for f in functions if 'quad' in f or 'int' in f][:10])
print("ODE求解器:", [f for f in functions if 'ode' in f or 'solve' in f][:10])

数值积分

1. 一维积分

python
# 定义测试函数
def test_functions():
    """定义各种测试函数"""
    functions = {
        '多项式': lambda x: x**3 - 2*x**2 + x - 1,
        '三角函数': lambda x: np.sin(x) * np.cos(x),
        '指数函数': lambda x: np.exp(-x**2),
        '有理函数': lambda x: 1 / (1 + x**2),
        '振荡函数': lambda x: np.sin(10*x) / x if x != 0 else 10,
        '不连续函数': lambda x: np.where(x < 0.5, x**2, 2*x - 1)
    }
    
    # 解析解(用于验证)
    analytical_solutions = {
        '多项式': lambda a, b: (b**4/4 - 2*b**3/3 + b**2/2 - b) - (a**4/4 - 2*a**3/3 + a**2/2 - a),
        '三角函数': lambda a, b: (np.sin(b)**2 - np.sin(a)**2) / 2,
        '有理函数': lambda a, b: np.arctan(b) - np.arctan(a)
    }
    
    return functions, analytical_solutions

# 获取测试函数
test_funcs, analytical_sols = test_functions()

# 使用不同的积分方法
integration_methods = {
    'quad (自适应)': lambda f, a, b: quad(f, a, b),
    'fixed_quad (高斯)': lambda f, a, b: fixed_quad(f, a, b, n=5),
    'quadrature (自适应高斯)': lambda f, a, b: quadrature(f, a, b)
}

# 积分区间
a, b = 0, 1

print(f"数值积分比较 (区间 [{a}, {b}]):")
print(f"{'函数':>15} {'方法':>15} {'数值结果':>12} {'误差估计':>12} {'解析解':>12} {'绝对误差':>12}")
print("-" * 90)

for func_name, func in test_funcs.items():
    # 计算解析解(如果有)
    analytical_result = None
    if func_name in analytical_sols:
        try:
            analytical_result = analytical_sols[func_name](a, b)
        except:
            pass
    
    for method_name, method in integration_methods.items():
        try:
            result, error = method(func, a, b)
            
            # 计算与解析解的误差
            abs_error = ""
            if analytical_result is not None:
                abs_error = f"{abs(result - analytical_result):.2e}"
            
            analytical_str = f"{analytical_result:.6f}" if analytical_result is not None else "N/A"
            
            print(f"{func_name:>15} {method_name:>15} {result:>12.6f} {error:>12.2e} {analytical_str:>12} {abs_error:>12}")
        except Exception as e:
            print(f"{func_name:>15} {method_name:>15} {'失败':>12} {'N/A':>12} {'N/A':>12} {'N/A':>12}")
    print()

# 可视化积分过程
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
axes = axes.flatten()

x = np.linspace(0, 1, 1000)
for i, (name, func) in enumerate(test_funcs.items()):
    if i >= 6:
        break
    
    # 计算函数值
    try:
        y = [func(xi) for xi in x]
        
        axes[i].plot(x, y, 'b-', linewidth=2, label=f'{name}')
        axes[i].fill_between(x, 0, y, alpha=0.3, color='lightblue')
        axes[i].set_title(f'{name}')
        axes[i].set_xlabel('x')
        axes[i].set_ylabel('f(x)')
        axes[i].grid(True, alpha=0.3)
        axes[i].legend()
        
        # 添加积分值标注
        integral_value, _ = quad(func, a, b)
        axes[i].text(0.5, max(y)*0.8, f'∫f(x)dx = {integral_value:.4f}', 
                    ha='center', va='center', 
                    bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
    except Exception as e:
        axes[i].text(0.5, 0.5, f'绘图失败\n{str(e)}', ha='center', va='center')
        axes[i].set_title(f'{name} (绘图失败)')

plt.tight_layout()
plt.show()

2. 多重积分

python
# 二重积分示例
def double_integration_examples():
    """二重积分示例"""
    
    # 定义二元函数
    functions_2d = {
        '简单多项式': lambda y, x: x*y,
        '高斯函数': lambda y, x: np.exp(-(x**2 + y**2)),
        '三角函数': lambda y, x: np.sin(x) * np.cos(y),
        '有理函数': lambda y, x: 1 / (1 + x**2 + y**2)
    }
    
    # 积分区域
    regions = {
        '矩形区域': {'x_bounds': [0, 1], 'y_bounds': [0, 1]},
        '三角形区域': {'x_bounds': [0, 1], 'y_bounds': lambda x: [0, x]},
        '圆形区域': {'x_bounds': [-1, 1], 'y_bounds': lambda x: [-np.sqrt(1-x**2), np.sqrt(1-x**2)]}
    }
    
    print("二重积分计算:")
    print(f"{'函数':>15} {'区域':>15} {'积分值':>12} {'误差估计':>12}")
    print("-" * 60)
    
    results = {}
    
    for func_name, func in functions_2d.items():
        results[func_name] = {}
        
        for region_name, region in regions.items():
            try:
                if callable(region['y_bounds']):
                    # 变限积分
                    result, error = dblquad(func, 
                                          region['x_bounds'][0], region['x_bounds'][1],
                                          lambda x: region['y_bounds'](x)[0],
                                          lambda x: region['y_bounds'](x)[1])
                else:
                    # 常限积分
                    result, error = dblquad(func,
                                          region['x_bounds'][0], region['x_bounds'][1],
                                          region['y_bounds'][0], region['y_bounds'][1])
                
                results[func_name][region_name] = (result, error)
                print(f"{func_name:>15} {region_name:>15} {result:>12.6f} {error:>12.2e}")
                
            except Exception as e:
                print(f"{func_name:>15} {region_name:>15} {'失败':>12} {'N/A':>12}")
                results[func_name][region_name] = (None, None)
    
    return results

# 执行二重积分计算
double_integral_results = double_integration_examples()

# 三重积分示例
print("\n三重积分计算:")

# 定义三元函数
def triple_function(z, y, x):
    return x*y*z

# 计算三重积分
try:
    # 在单位立方体上积分
    result_3d, error_3d = tplquad(triple_function, 0, 1, 0, 1, 0, 1)
    print(f"∭xyz dxdydz (单位立方体) = {result_3d:.6f} ± {error_3d:.2e}")
    
    # 解析解: 1/8
    analytical_3d = 1/8
    print(f"解析解 = {analytical_3d:.6f}")
    print(f"绝对误差 = {abs(result_3d - analytical_3d):.2e}")
except Exception as e:
    print(f"三重积分计算失败: {e}")

# 可视化二重积分
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
axes = axes.flatten()

# 创建网格
x = np.linspace(-1, 1, 50)
y = np.linspace(-1, 1, 50)
X, Y = np.meshgrid(x, y)

# 可视化不同的二元函数
functions_for_plot = {
    '高斯函数': lambda x, y: np.exp(-(x**2 + y**2)),
    '三角函数': lambda x, y: np.sin(x) * np.cos(y),
    '有理函数': lambda x, y: 1 / (1 + x**2 + y**2),
    '波函数': lambda x, y: np.sin(np.sqrt(x**2 + y**2))
}

for i, (name, func) in enumerate(functions_for_plot.items()):
    Z = func(X, Y)
    
    contour = axes[i].contourf(X, Y, Z, levels=20, cmap='viridis')
    axes[i].set_title(f'{name}')
    axes[i].set_xlabel('x')
    axes[i].set_ylabel('y')
    plt.colorbar(contour, ax=axes[i])
    
    # 添加积分区域标记
    circle = plt.Circle((0, 0), 1, fill=False, color='red', linewidth=2, linestyle='--')
    axes[i].add_patch(circle)
    axes[i].text(0, -1.3, '红色虚线: 圆形积分区域', ha='center', color='red')

plt.tight_layout()
plt.show()

3. 数值积分方法比较

python
# 比较不同数值积分方法的精度和效率
import time

def compare_integration_methods():
    """比较不同积分方法"""
    
    # 测试函数
    def smooth_function(x):
        return np.exp(-x**2) * np.cos(x)
    
    def oscillatory_function(x):
        return np.sin(20*x) / (1 + x**2)
    
    def singular_function(x):
        return 1 / np.sqrt(x) if x > 0 else 0
    
    test_functions = {
        '光滑函数': smooth_function,
        '振荡函数': oscillatory_function,
        '奇异函数': singular_function
    }
    
    # 积分方法
    methods = {
        'quad': lambda f, a, b: quad(f, a, b),
        'simpson': lambda f, a, b: (simpson([f(x) for x in np.linspace(a, b, 1001)], dx=(b-a)/1000), 0),
        'trapz': lambda f, a, b: (trapz([f(x) for x in np.linspace(a, b, 1001)], dx=(b-a)/1000), 0),
        'fixed_quad': lambda f, a, b: fixed_quad(f, a, b, n=10)
    }
    
    # 积分区间
    intervals = {
        '光滑函数': (0, 2),
        '振荡函数': (0, 1),
        '奇异函数': (0.001, 1)  # 避免奇点
    }
    
    print("积分方法比较:")
    print(f"{'函数':>12} {'方法':>12} {'结果':>12} {'时间(ms)':>10} {'相对误差':>12}")
    print("-" * 70)
    
    for func_name, func in test_functions.items():
        a, b = intervals[func_name]
        
        # 使用quad作为参考
        reference_result, _ = quad(func, a, b)
        
        for method_name, method in methods.items():
            try:
                start_time = time.time()
                result, _ = method(func, a, b)
                exec_time = (time.time() - start_time) * 1000
                
                relative_error = abs(result - reference_result) / abs(reference_result) if reference_result != 0 else 0
                
                print(f"{func_name:>12} {method_name:>12} {result:>12.6f} {exec_time:>10.2f} {relative_error:>12.2e}")
                
            except Exception as e:
                print(f"{func_name:>12} {method_name:>12} {'失败':>12} {'N/A':>10} {'N/A':>12}")
        print()

# 执行方法比较
compare_integration_methods()

# 可视化积分精度
def visualize_integration_accuracy():
    """可视化积分精度"""
    
    def test_func(x):
        return np.sin(x) * np.exp(-x/2)
    
    # 解析解
    def analytical_integral(a, b):
        def F(x):
            return -2/5 * np.exp(-x/2) * (np.sin(x) + 2*np.cos(x))
        return F(b) - F(a)
    
    a, b = 0, 2*np.pi
    true_value = analytical_integral(a, b)
    
    # 不同的网格密度
    n_points = [5, 10, 20, 50, 100, 200, 500, 1000]
    
    methods_accuracy = {
        'Simpson': [],
        'Trapezoid': [],
        'Quad': []
    }
    
    for n in n_points:
        x = np.linspace(a, b, n)
        y = test_func(x)
        dx = (b - a) / (n - 1)
        
        # Simpson法
        if n >= 3:
            simpson_result = simpson(y, dx=dx)
            methods_accuracy['Simpson'].append(abs(simpson_result - true_value))
        else:
            methods_accuracy['Simpson'].append(np.nan)
        
        # 梯形法
        trapz_result = trapz(y, dx=dx)
        methods_accuracy['Trapezoid'].append(abs(trapz_result - true_value))
        
        # Quad法(参考)
        quad_result, _ = quad(test_func, a, b)
        methods_accuracy['Quad'].append(abs(quad_result - true_value))
    
    # 绘制精度比较
    plt.figure(figsize=(12, 8))
    
    plt.subplot(2, 2, 1)
    x_plot = np.linspace(a, b, 1000)
    y_plot = test_func(x_plot)
    plt.plot(x_plot, y_plot, 'b-', linewidth=2, label='f(x) = sin(x)exp(-x/2)')
    plt.fill_between(x_plot, 0, y_plot, alpha=0.3)
    plt.title('被积函数')
    plt.xlabel('x')
    plt.ylabel('f(x)')
    plt.legend()
    plt.grid(True, alpha=0.3)
    
    plt.subplot(2, 2, 2)
    for method, errors in methods_accuracy.items():
        if method != 'Quad':  # Quad误差太小,单独显示
            plt.loglog(n_points, errors, 'o-', label=method, linewidth=2, markersize=6)
    plt.xlabel('网格点数')
    plt.ylabel('绝对误差')
    plt.title('积分精度比较')
    plt.legend()
    plt.grid(True, alpha=0.3)
    
    plt.subplot(2, 2, 3)
    # 显示收敛阶
    simpson_errors = [e for e in methods_accuracy['Simpson'] if not np.isnan(e)]
    trapz_errors = methods_accuracy['Trapezoid']
    
    if len(simpson_errors) > 1:
        simpson_order = np.polyfit(np.log(n_points[-len(simpson_errors):]), 
                                 np.log(simpson_errors), 1)[0]
        plt.text(0.1, 0.8, f'Simpson收敛阶: {-simpson_order:.2f}', transform=plt.gca().transAxes)
    
    trapz_order = np.polyfit(np.log(n_points), np.log(trapz_errors), 1)[0]
    plt.text(0.1, 0.7, f'Trapezoid收敛阶: {-trapz_order:.2f}', transform=plt.gca().transAxes)
    
    plt.text(0.1, 0.6, f'真实积分值: {true_value:.6f}', transform=plt.gca().transAxes)
    plt.text(0.1, 0.5, f'Quad结果: {quad_result:.6f}', transform=plt.gca().transAxes)
    plt.text(0.1, 0.4, f'Quad误差: {abs(quad_result - true_value):.2e}', transform=plt.gca().transAxes)
    
    plt.title('收敛性分析')
    plt.axis('off')
    
    plt.subplot(2, 2, 4)
    # 显示不同方法的最终精度
    final_errors = {method: errors[-1] for method, errors in methods_accuracy.items()}
    methods_list = list(final_errors.keys())
    errors_list = list(final_errors.values())
    
    bars = plt.bar(methods_list, errors_list, color=['red', 'green', 'blue'], alpha=0.7)
    plt.yscale('log')
    plt.ylabel('绝对误差')
    plt.title('最终精度比较')
    plt.grid(True, alpha=0.3)
    
    # 添加数值标签
    for bar, error in zip(bars, errors_list):
        plt.text(bar.get_x() + bar.get_width()/2, error, f'{error:.2e}', 
                ha='center', va='bottom')
    
    plt.tight_layout()
    plt.show()

# 执行精度可视化
visualize_integration_accuracy()

常微分方程求解

1. 初值问题

python
# 常微分方程初值问题求解
def ode_examples():
    """常微分方程示例"""
    
    # 示例1: 一阶线性ODE
    # dy/dt = -2y + 1, y(0) = 0
    # 解析解: y(t) = 0.5(1 - exp(-2t))
    def linear_ode(t, y):
        return -2*y + 1
    
    def linear_analytical(t):
        return 0.5 * (1 - np.exp(-2*t))
    
    # 示例2: 非线性ODE (Logistic方程)
    # dy/dt = ry(1 - y/K), y(0) = y0
    def logistic_ode(t, y, r=1, K=10):
        return r * y * (1 - y/K)
    
    def logistic_analytical(t, y0=1, r=1, K=10):
        return K / (1 + (K/y0 - 1) * np.exp(-r*t))
    
    # 示例3: 振荡器 (简谐振动)
    # d²y/dt² + ω²y = 0 => dy/dt = v, dv/dt = -ω²y
    def harmonic_oscillator(t, y, omega=2):
        y_pos, y_vel = y
        return [y_vel, -omega**2 * y_pos]
    
    def harmonic_analytical(t, y0=1, v0=0, omega=2):
        A = np.sqrt(y0**2 + (v0/omega)**2)
        phi = np.arctan2(-v0/omega, y0)
        return A * np.cos(omega*t + phi)
    
    return {
        'linear': (linear_ode, linear_analytical, [0], 'dy/dt = -2y + 1'),
        'logistic': (logistic_ode, lambda t: logistic_analytical(t), [1], 'dy/dt = ry(1-y/K)'),
        'harmonic': (harmonic_oscillator, lambda t: harmonic_analytical(t), [1, 0], 'd²y/dt² + ω²y = 0')
    }

# 获取ODE示例
ode_examples = ode_examples()

# 求解ODE并比较方法
t_span = (0, 5)
t_eval = np.linspace(0, 5, 100)

print("常微分方程求解比较:")
print(f"{'方程':>15} {'方法':>15} {'最终值':>12} {'解析解':>12} {'绝对误差':>12} {'时间(ms)':>10}")
print("-" * 85)

# 不同的求解方法
methods = {
    'RK45': 'RK45',
    'RK23': 'RK23', 
    'DOP853': 'DOP853',
    'Radau': 'Radau',
    'BDF': 'BDF'
}

results = {}

for ode_name, (ode_func, analytical_func, y0, description) in ode_examples.items():
    results[ode_name] = {}
    
    # 计算解析解
    if ode_name == 'harmonic':
        analytical_values = [harmonic_analytical(t) for t in t_eval]
        final_analytical = analytical_values[-1]
    else:
        analytical_values = [analytical_func(t) for t in t_eval]
        final_analytical = analytical_values[-1]
    
    for method_name, method in methods.items():
        try:
            start_time = time.time()
            
            if ode_name == 'logistic':
                # 带参数的ODE
                sol = solve_ivp(lambda t, y: logistic_ode(t, y, r=1, K=10), 
                              t_span, y0, t_eval=t_eval, method=method)
            else:
                sol = solve_ivp(ode_func, t_span, y0, t_eval=t_eval, method=method)
            
            exec_time = (time.time() - start_time) * 1000
            
            if sol.success:
                if ode_name == 'harmonic':
                    final_numerical = sol.y[0, -1]  # 位置分量
                else:
                    final_numerical = sol.y[0, -1]
                
                abs_error = abs(final_numerical - final_analytical)
                
                results[ode_name][method_name] = {
                    'solution': sol,
                    'final_value': final_numerical,
                    'error': abs_error,
                    'time': exec_time
                }
                
                print(f"{ode_name:>15} {method_name:>15} {final_numerical:>12.6f} {final_analytical:>12.6f} {abs_error:>12.2e} {exec_time:>10.2f}")
            else:
                print(f"{ode_name:>15} {method_name:>15} {'失败':>12} {'N/A':>12} {'N/A':>12} {'N/A':>10}")
                
        except Exception as e:
            print(f"{ode_name:>15} {method_name:>15} {'错误':>12} {'N/A':>12} {'N/A':>12} {'N/A':>10}")
    print()

# 可视化ODE求解结果
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
axes = axes.flatten()

plot_idx = 0
for ode_name, (ode_func, analytical_func, y0, description) in ode_examples.items():
    if plot_idx >= 3:
        break
        
    ax = axes[plot_idx]
    
    # 绘制解析解
    if ode_name == 'harmonic':
        analytical_values = [harmonic_analytical(t) for t in t_eval]
        ax.plot(t_eval, analytical_values, 'k--', linewidth=3, label='解析解', alpha=0.8)
    else:
        analytical_values = [analytical_func(t) for t in t_eval]
        ax.plot(t_eval, analytical_values, 'k--', linewidth=3, label='解析解', alpha=0.8)
    
    # 绘制数值解
    colors = ['red', 'blue', 'green', 'orange', 'purple']
    for i, (method_name, method_data) in enumerate(results[ode_name].items()):
        if i >= len(colors):
            break
        
        sol = method_data['solution']
        if ode_name == 'harmonic':
            y_values = sol.y[0, :]  # 位置分量
        else:
            y_values = sol.y[0, :]
        
        ax.plot(sol.t, y_values, color=colors[i], linewidth=2, 
               label=f'{method_name} (误差: {method_data["error"]:.2e})', alpha=0.7)
    
    ax.set_title(f'{description}')
    ax.set_xlabel('时间 t')
    ax.set_ylabel('y(t)')
    ax.legend()
    ax.grid(True, alpha=0.3)
    
    plot_idx += 1

# 相空间图(仅对谐振子)
if 'harmonic' in results:
    ax = axes[3]
    
    for method_name, method_data in list(results['harmonic'].items())[:3]:  # 只显示前3个方法
        sol = method_data['solution']
        y_pos = sol.y[0, :]
        y_vel = sol.y[1, :]
        
        ax.plot(y_pos, y_vel, linewidth=2, label=f'{method_name}', alpha=0.7)
    
    # 解析解的相空间轨迹
    y_pos_analytical = [harmonic_analytical(t) for t in t_eval]
    y_vel_analytical = [-2 * harmonic_analytical(t, y0=1, v0=0, omega=2) * 
                       np.sin(2*t) for t in t_eval]  # 简化的速度
    
    ax.plot(y_pos_analytical, y_vel_analytical, 'k--', linewidth=3, 
           label='解析解', alpha=0.8)
    
    ax.set_title('谐振子相空间轨迹')
    ax.set_xlabel('位置 y')
    ax.set_ylabel('速度 dy/dt')
    ax.legend()
    ax.grid(True, alpha=0.3)
    ax.axis('equal')

plt.tight_layout()
plt.show()

2. 刚性方程和高阶方程

python
# 刚性方程示例
def stiff_ode_example():
    """刚性方程示例"""
    
    # Van der Pol振荡器 (刚性参数μ)
    def van_der_pol(t, y, mu=10):
        y1, y2 = y
        return [y2, mu * (1 - y1**2) * y2 - y1]
    
    # 化学反应动力学 (Robertson问题)
    def robertson(t, y):
        y1, y2, y3 = y
        return [-0.04*y1 + 1e4*y2*y3,
                0.04*y1 - 1e4*y2*y3 - 3e7*y2**2,
                3e7*y2**2]
    
    return {
        'van_der_pol': (van_der_pol, [2, 0], 'Van der Pol振荡器'),
        'robertson': (robertson, [1, 0, 0], 'Robertson化学反应')
    }

# 获取刚性方程示例
stiff_examples = stiff_ode_example()

# 比较适合刚性方程的方法
stiff_methods = {
    'Radau': 'Radau',  # 隐式方法,适合刚性方程
    'BDF': 'BDF',      # 后向差分,适合刚性方程
    'RK45': 'RK45'     # 显式方法,对比用
}

print("刚性方程求解比较:")
print(f"{'方程':>15} {'方法':>10} {'成功':>8} {'步数':>8} {'时间(ms)':>10} {'最终时间':>10}")
print("-" * 70)

t_span_stiff = (0, 20)
t_eval_stiff = np.linspace(0, 20, 200)

stiff_results = {}

for eq_name, (eq_func, y0, description) in stiff_examples.items():
    stiff_results[eq_name] = {}
    
    for method_name, method in stiff_methods.items():
        try:
            start_time = time.time()
            
            if eq_name == 'van_der_pol':
                sol = solve_ivp(lambda t, y: van_der_pol(t, y, mu=10), 
                              t_span_stiff, y0, method=method, 
                              dense_output=True, rtol=1e-6)
            else:
                sol = solve_ivp(eq_func, t_span_stiff, y0, method=method, 
                              dense_output=True, rtol=1e-6)
            
            exec_time = (time.time() - start_time) * 1000
            
            success = "是" if sol.success else "否"
            n_steps = len(sol.t)
            final_time = sol.t[-1] if len(sol.t) > 0 else 0
            
            stiff_results[eq_name][method_name] = {
                'solution': sol,
                'success': sol.success,
                'n_steps': n_steps,
                'time': exec_time
            }
            
            print(f"{eq_name:>15} {method_name:>10} {success:>8} {n_steps:>8} {exec_time:>10.2f} {final_time:>10.2f}")
            
        except Exception as e:
            print(f"{eq_name:>15} {method_name:>10} {'否':>8} {'N/A':>8} {'N/A':>10} {'N/A':>10}")
            stiff_results[eq_name][method_name] = {'success': False}
    print()

# 可视化刚性方程解
fig, axes = plt.subplots(2, 2, figsize=(15, 12))

# Van der Pol振荡器
if 'van_der_pol' in stiff_results:
    # 时间序列
    ax1 = axes[0, 0]
    ax2 = axes[0, 1]
    
    for method_name, result in stiff_results['van_der_pol'].items():
        if result['success']:
            sol = result['solution']
            t_dense = np.linspace(0, 20, 1000)
            y_dense = sol.sol(t_dense)
            
            ax1.plot(t_dense, y_dense[0], label=f'{method_name}', linewidth=2)
    
    ax1.set_title('Van der Pol振荡器 - 时间序列')
    ax1.set_xlabel('时间 t')
    ax1.set_ylabel('y1(t)')
    ax1.legend()
    ax1.grid(True, alpha=0.3)
    
    # 相空间
    for method_name, result in stiff_results['van_der_pol'].items():
        if result['success']:
            sol = result['solution']
            t_dense = np.linspace(0, 20, 1000)
            y_dense = sol.sol(t_dense)
            
            ax2.plot(y_dense[0], y_dense[1], label=f'{method_name}', linewidth=2)
    
    ax2.set_title('Van der Pol振荡器 - 相空间')
    ax2.set_xlabel('y1')
    ax2.set_ylabel('y2')
    ax2.legend()
    ax2.grid(True, alpha=0.3)

# Robertson反应
if 'robertson' in stiff_results:
    ax3 = axes[1, 0]
    ax4 = axes[1, 1]
    
    # 浓度随时间变化
    for method_name, result in stiff_results['robertson'].items():
        if result['success']:
            sol = result['solution']
            t_dense = np.linspace(0, 20, 1000)
            y_dense = sol.sol(t_dense)
            
            ax3.semilogy(t_dense, y_dense[0], label=f'{method_name} - A', linewidth=2)
            ax3.semilogy(t_dense, y_dense[1], '--', label=f'{method_name} - B', linewidth=2)
            ax3.semilogy(t_dense, y_dense[2], ':', label=f'{method_name} - C', linewidth=2)
    
    ax3.set_title('Robertson反应 - 浓度变化')
    ax3.set_xlabel('时间 t')
    ax3.set_ylabel('浓度 (对数尺度)')
    ax3.legend()
    ax3.grid(True, alpha=0.3)
    
    # 守恒量检查
    for method_name, result in stiff_results['robertson'].items():
        if result['success']:
            sol = result['solution']
            t_dense = np.linspace(0, 20, 1000)
            y_dense = sol.sol(t_dense)
            
            conservation = y_dense[0] + y_dense[1] + y_dense[2]
            ax4.plot(t_dense, conservation - 1, label=f'{method_name}', linewidth=2)
    
    ax4.set_title('Robertson反应 - 守恒量偏差')
    ax4.set_xlabel('时间 t')
    ax4.set_ylabel('总浓度 - 1')
    ax4.legend()
    ax4.grid(True, alpha=0.3)
    ax4.ticklabel_format(style='scientific', axis='y', scilimits=(0,0))

plt.tight_layout()
plt.show()

3. 边值问题

python
# 边值问题求解
def boundary_value_problems():
    """边值问题示例"""
    
    # 示例1: 二阶线性BVP
    # y'' + y = 0, y(0) = 0, y(π) = 0
    # 解析解: y(x) = A*sin(x), 由边界条件得 A = 0 或 sin(π) = 0
    
    def linear_bvp(x, y):
        return np.vstack((y[1], -y[0]))
    
    def linear_bc(ya, yb):
        return np.array([ya[0], yb[0]])  # y(0) = 0, y(π) = 0
    
    # 示例2: 非线性BVP (Bratu问题)
    # y'' + λ*exp(y) = 0, y(0) = y(1) = 0
    
    def bratu_bvp(x, y, lam=1):
        return np.vstack((y[1], -lam * np.exp(y[0])))
    
    def bratu_bc(ya, yb):
        return np.array([ya[0], yb[0]])  # y(0) = y(1) = 0
    
    return {
        'linear': (linear_bvp, linear_bc, [0, np.pi], '线性BVP: y\'\' + y = 0'),
        'bratu': (bratu_bvp, bratu_bc, [0, 1], 'Bratu问题: y\'\' + λe^y = 0')
    }

# 获取BVP示例
bvp_examples = boundary_value_problems()

print("边值问题求解:")
print(f"{'问题':>15} {'收敛':>8} {'残差':>12} {'迭代次数':>10}")
print("-" * 50)

bvp_results = {}

for bvp_name, (bvp_func, bc_func, domain, description) in bvp_examples.items():
    try:
        # 初始网格
        x = np.linspace(domain[0], domain[1], 11)
        
        # 初始猜测
        if bvp_name == 'linear':
            y_guess = np.zeros((2, x.size))
            y_guess[0] = np.sin(x)  # 猜测解的形状
        else:  # bratu
            y_guess = np.zeros((2, x.size))
            y_guess[0] = x * (1 - x)  # 满足边界条件的初始猜测
        
        # 求解BVP
        if bvp_name == 'bratu':
            sol = solve_bvp(lambda x, y: bratu_bvp(x, y, lam=1), bc_func, x, y_guess)
        else:
            sol = solve_bvp(bvp_func, bc_func, x, y_guess)
        
        converged = "是" if sol.success else "否"
        residual = np.max(np.abs(sol.rms_residuals)) if sol.success else float('inf')
        n_iter = sol.niter if hasattr(sol, 'niter') else 'N/A'
        
        bvp_results[bvp_name] = {
            'solution': sol,
            'success': sol.success,
            'residual': residual
        }
        
        print(f"{bvp_name:>15} {converged:>8} {residual:>12.2e} {n_iter:>10}")
        
    except Exception as e:
        print(f"{bvp_name:>15} {'否':>8} {'N/A':>12} {'N/A':>10}")
        bvp_results[bvp_name] = {'success': False}

# 可视化BVP解
fig, axes = plt.subplots(1, 2, figsize=(15, 6))

for i, (bvp_name, result) in enumerate(bvp_results.items()):
    if i >= 2 or not result['success']:
        continue
        
    ax = axes[i]
    sol = result['solution']
    
    # 绘制解
    x_plot = np.linspace(sol.x[0], sol.x[-1], 200)
    y_plot = sol.sol(x_plot)
    
    ax.plot(x_plot, y_plot[0], 'b-', linewidth=3, label='数值解')
    ax.plot(sol.x, sol.y[0], 'ro', markersize=6, label='网格点')
    
    # 添加边界条件标记
    ax.axhline(y=0, color='gray', linestyle='--', alpha=0.5)
    ax.plot([sol.x[0], sol.x[-1]], [0, 0], 'go', markersize=8, label='边界条件')
    
    ax.set_title(f'{bvp_examples[bvp_name][3]}')
    ax.set_xlabel('x')
    ax.set_ylabel('y(x)')
    ax.legend()
    ax.grid(True, alpha=0.3)
    
    # 添加残差信息
    ax.text(0.05, 0.95, f'最大残差: {result["residual"]:.2e}', 
           transform=ax.transAxes, verticalalignment='top',
           bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))

plt.tight_layout()
plt.show()

实际应用案例

1. 人口动力学模型

python
# 人口动力学建模
def population_dynamics():
    """人口动力学模型"""
    
    # Lotka-Volterra捕食者-猎物模型
    def lotka_volterra(t, y, a=1, b=0.1, c=1.5, d=0.075):
        """Lotka-Volterra方程
        y[0]: 猎物数量
        y[1]: 捕食者数量
        """
        prey, predator = y
        dprey_dt = a * prey - b * prey * predator
        dpredator_dt = -c * predator + d * prey * predator
        return [dprey_dt, dpredator_dt]
    
    # 竞争模型
    def competition_model(t, y, r1=1, r2=0.8, K1=100, K2=80, a12=0.5, a21=0.7):
        """种间竞争模型"""
        N1, N2 = y
        dN1_dt = r1 * N1 * (1 - (N1 + a12 * N2) / K1)
        dN2_dt = r2 * N2 * (1 - (N2 + a21 * N1) / K2)
        return [dN1_dt, dN2_dt]
    
    # SIR传染病模型
    def sir_model(t, y, beta=0.3, gamma=0.1):
        """SIR传染病模型"""
        S, I, R = y
        N = S + I + R
        dS_dt = -beta * S * I / N
        dI_dt = beta * S * I / N - gamma * I
        dR_dt = gamma * I
        return [dS_dt, dI_dt, dR_dt]
    
    return {
        'lotka_volterra': (lotka_volterra, [10, 5], 'Lotka-Volterra捕食模型'),
        'competition': (competition_model, [50, 40], '种间竞争模型'),
        'sir': (sir_model, [990, 10, 0], 'SIR传染病模型')
    }

# 获取人口动力学模型
population_models = population_dynamics()

# 求解人口动力学方程
t_span = (0, 20)
t_eval = np.linspace(0, 20, 1000)

print("人口动力学模型求解:")
population_results = {}

for model_name, (model_func, y0, description) in population_models.items():
    try:
        sol = solve_ivp(model_func, t_span, y0, t_eval=t_eval, method='RK45')
        population_results[model_name] = {
            'solution': sol,
            'success': sol.success,
            'description': description
        }
        print(f"{model_name:>15}: {'成功' if sol.success else '失败'}")
    except Exception as e:
        print(f"{model_name:>15}: 错误 - {e}")
        population_results[model_name] = {'success': False}

# 可视化人口动力学结果
fig, axes = plt.subplots(2, 3, figsize=(18, 12))
axes = axes.flatten()

plot_idx = 0
for model_name, result in population_results.items():
    if not result['success'] or plot_idx >= 6:
        continue
        
    sol = result['solution']
    description = result['description']
    
    # 时间序列图
    ax1 = axes[plot_idx]
    plot_idx += 1
    
    if model_name == 'lotka_volterra':
        ax1.plot(sol.t, sol.y[0], 'b-', linewidth=2, label='猎物')
        ax1.plot(sol.t, sol.y[1], 'r-', linewidth=2, label='捕食者')
        ax1.set_ylabel('数量')
    elif model_name == 'competition':
        ax1.plot(sol.t, sol.y[0], 'g-', linewidth=2, label='物种1')
        ax1.plot(sol.t, sol.y[1], 'm-', linewidth=2, label='物种2')
        ax1.set_ylabel('数量')
    elif model_name == 'sir':
        ax1.plot(sol.t, sol.y[0], 'b-', linewidth=2, label='易感者(S)')
        ax1.plot(sol.t, sol.y[1], 'r-', linewidth=2, label='感染者(I)')
        ax1.plot(sol.t, sol.y[2], 'g-', linewidth=2, label='康复者(R)')
        ax1.set_ylabel('人数')
    
    ax1.set_title(f'{description} - 时间序列')
    ax1.set_xlabel('时间')
    ax1.legend()
    ax1.grid(True, alpha=0.3)
    
    # 相空间图(除了SIR模型)
    if model_name != 'sir' and plot_idx < 6:
        ax2 = axes[plot_idx]
        plot_idx += 1
        
        ax2.plot(sol.y[0], sol.y[1], 'purple', linewidth=2)
        ax2.plot(sol.y[0, 0], sol.y[1, 0], 'go', markersize=8, label='起点')
        ax2.plot(sol.y[0, -1], sol.y[1, -1], 'ro', markersize=8, label='终点')
        
        if model_name == 'lotka_volterra':
            ax2.set_xlabel('猎物数量')
            ax2.set_ylabel('捕食者数量')
            ax2.set_title('Lotka-Volterra相空间轨迹')
        elif model_name == 'competition':
            ax2.set_xlabel('物种1数量')
            ax2.set_ylabel('物种2数量')
            ax2.set_title('竞争模型相空间轨迹')
        
        ax2.legend()
        ax2.grid(True, alpha=0.3)

# SIR模型的特殊分析
if 'sir' in population_results and population_results['sir']['success']:
    if plot_idx < 6:
        ax_sir = axes[plot_idx]
        sol_sir = population_results['sir']['solution']
        
        # 计算基本再生数R0和峰值时间
        I_max_idx = np.argmax(sol_sir.y[1])
        t_peak = sol_sir.t[I_max_idx]
        I_peak = sol_sir.y[1, I_max_idx]
        
        # 绘制感染者曲线和峰值
        ax_sir.plot(sol_sir.t, sol_sir.y[1], 'r-', linewidth=3, label='感染者')
        ax_sir.axvline(x=t_peak, color='orange', linestyle='--', 
                      label=f'峰值时间: {t_peak:.1f}')
        ax_sir.axhline(y=I_peak, color='orange', linestyle='--', 
                      label=f'峰值人数: {I_peak:.0f}')
        
        ax_sir.set_title('SIR模型 - 感染者峰值分析')
        ax_sir.set_xlabel('时间')
        ax_sir.set_ylabel('感染者人数')
        ax_sir.legend()
        ax_sir.grid(True, alpha=0.3)
        
        # 添加统计信息
        total_infected = 1000 - sol_sir.y[0, -1]  # 最终易感者减少量
        ax_sir.text(0.05, 0.95, f'总感染人数: {total_infected:.0f}\n感染率: {total_infected/1000*100:.1f}%', 
                   transform=ax_sir.transAxes, verticalalignment='top',
                   bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))

plt.tight_layout()
plt.show()

# 参数敏感性分析
print("\n参数敏感性分析 (SIR模型):")
if 'sir' in population_results and population_results['sir']['success']:
    beta_values = [0.1, 0.2, 0.3, 0.4, 0.5]
    gamma_values = [0.05, 0.1, 0.15, 0.2]
    
    fig, axes = plt.subplots(1, 2, figsize=(15, 6))
    
    # β参数影响
    for beta in beta_values:
        sol = solve_ivp(lambda t, y: sir_model(t, y, beta=beta, gamma=0.1), 
                       t_span, [990, 10, 0], t_eval=t_eval)
        if sol.success:
            axes[0].plot(sol.t, sol.y[1], linewidth=2, label=f'β={beta}')
    
    axes[0].set_title('传染率β对感染者峰值的影响')
    axes[0].set_xlabel('时间')
    axes[0].set_ylabel('感染者人数')
    axes[0].legend()
    axes[0].grid(True, alpha=0.3)
    
    # γ参数影响
    for gamma in gamma_values:
        sol = solve_ivp(lambda t, y: sir_model(t, y, beta=0.3, gamma=gamma), 
                       t_span, [990, 10, 0], t_eval=t_eval)
        if sol.success:
            axes[1].plot(sol.t, sol.y[1], linewidth=2, label=f'γ={gamma}')
    
    axes[1].set_title('康复率γ对感染者峰值的影响')
    axes[1].set_xlabel('时间')
    axes[1].set_ylabel('感染者人数')
    axes[1].legend()
    axes[1].grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()

2. 物理系统建模

python
# 物理系统建模
def physics_systems():
    """物理系统微分方程"""
    
    # 单摆方程
    def pendulum(t, y, g=9.81, L=1.0, damping=0.1):
        """阻尼单摆方程
        θ'' + (damping/m)θ' + (g/L)sin(θ) = 0
        """
        theta, omega = y
        return [omega, -damping * omega - (g/L) * np.sin(theta)]
    
    # 弹簧-质量-阻尼系统
    def spring_mass_damper(t, y, m=1.0, k=4.0, c=0.5):
        """弹簧-质量-阻尼系统
        mx'' + cx' + kx = 0
        """
        x, v = y
        return [v, -(c/m) * v - (k/m) * x]
    
    # RLC电路
    def rlc_circuit(t, y, R=1.0, L=1.0, C=1.0, V0=0):
        """RLC电路方程
        L(dI/dt) + R*I + Q/C = V0
        dQ/dt = I
        """
        Q, I = y  # 电荷和电流
        return [I, (V0 - R*I - Q/C) / L]
    
    # 洛伦兹方程(混沌系统)
    def lorenz(t, y, sigma=10, rho=28, beta=8/3):
        """洛伦兹方程"""
        x, y_coord, z = y
        return [sigma * (y_coord - x),
                x * (rho - z) - y_coord,
                x * y_coord - beta * z]
    
    return {
        'pendulum': (pendulum, [np.pi/4, 0], '阻尼单摆'),
        'spring_mass': (spring_mass_damper, [1, 0], '弹簧-质量-阻尼系统'),
        'rlc_circuit': (rlc_circuit, [0, 0], 'RLC电路'),
        'lorenz': (lorenz, [1, 1, 1], '洛伦兹混沌系统')
    }

# 获取物理系统模型
physics_models = physics_systems()

# 求解物理系统方程
t_span_physics = (0, 10)
t_eval_physics = np.linspace(0, 10, 2000)

print("物理系统建模:")
physics_results = {}

for model_name, (model_func, y0, description) in physics_models.items():
    try:
        if model_name == 'lorenz':
            # 洛伦兹系统需要更长的时间
            t_span_lorenz = (0, 30)
            t_eval_lorenz = np.linspace(0, 30, 5000)
            sol = solve_ivp(model_func, t_span_lorenz, y0, t_eval=t_eval_lorenz, method='RK45')
        else:
            sol = solve_ivp(model_func, t_span_physics, y0, t_eval=t_eval_physics, method='RK45')
        
        physics_results[model_name] = {
            'solution': sol,
            'success': sol.success,
            'description': description
        }
        print(f"{model_name:>15}: {'成功' if sol.success else '失败'}")
    except Exception as e:
        print(f"{model_name:>15}: 错误 - {e}")
        physics_results[model_name] = {'success': False}

# 可视化物理系统结果
fig, axes = plt.subplots(2, 4, figsize=(20, 10))
axes = axes.flatten()

plot_idx = 0
for model_name, result in physics_results.items():
    if not result['success']:
        continue
        
    sol = result['solution']
    description = result['description']
    
    # 时间序列图
    ax1 = axes[plot_idx]
    plot_idx += 1
    
    if model_name == 'pendulum':
        ax1.plot(sol.t, sol.y[0], 'b-', linewidth=2, label='角度θ')
        ax1.plot(sol.t, sol.y[1], 'r-', linewidth=2, label='角速度ω')
        ax1.set_ylabel('角度/角速度')
    elif model_name == 'spring_mass':
        ax1.plot(sol.t, sol.y[0], 'g-', linewidth=2, label='位移x')
        ax1.plot(sol.t, sol.y[1], 'm-', linewidth=2, label='速度v')
        ax1.set_ylabel('位移/速度')
    elif model_name == 'rlc_circuit':
        ax1.plot(sol.t, sol.y[0], 'c-', linewidth=2, label='电荷Q')
        ax1.plot(sol.t, sol.y[1], 'orange', linewidth=2, label='电流I')
        ax1.set_ylabel('电荷/电流')
    elif model_name == 'lorenz':
        ax1.plot(sol.t, sol.y[0], 'b-', linewidth=1, label='x', alpha=0.8)
        ax1.plot(sol.t, sol.y[1], 'r-', linewidth=1, label='y', alpha=0.8)
        ax1.plot(sol.t, sol.y[2], 'g-', linewidth=1, label='z', alpha=0.8)
        ax1.set_ylabel('坐标值')
    
    ax1.set_title(f'{description} - 时间序列')
    ax1.set_xlabel('时间')
    ax1.legend()
    ax1.grid(True, alpha=0.3)
    
    # 相空间图
    if plot_idx < 8:
        ax2 = axes[plot_idx]
        plot_idx += 1
        
        if model_name == 'lorenz':
            # 3D轨迹投影到2D
            ax2.plot(sol.y[0], sol.y[1], 'purple', linewidth=0.5, alpha=0.7)
            ax2.set_xlabel('x')
            ax2.set_ylabel('y')
            ax2.set_title('洛伦兹吸引子 (x-y投影)')
        else:
            ax2.plot(sol.y[0], sol.y[1], 'purple', linewidth=2)
            ax2.plot(sol.y[0, 0], sol.y[1, 0], 'go', markersize=8, label='起点')
            
            if model_name == 'pendulum':
                ax2.set_xlabel('角度θ')
                ax2.set_ylabel('角速度ω')
                ax2.set_title('单摆相空间轨迹')
            elif model_name == 'spring_mass':
                ax2.set_xlabel('位移x')
                ax2.set_ylabel('速度v')
                ax2.set_title('弹簧系统相空间轨迹')
            elif model_name == 'rlc_circuit':
                ax2.set_xlabel('电荷Q')
                ax2.set_ylabel('电流I')
                ax2.set_title('RLC电路相空间轨迹')
            
            ax2.legend()
        
        ax2.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

# 洛伦兹系统的3D可视化
if 'lorenz' in physics_results and physics_results['lorenz']['success']:
    from mpl_toolkits.mplot3d import Axes3D
    
    fig = plt.figure(figsize=(15, 5))
    
    sol_lorenz = physics_results['lorenz']['solution']
    
    # 3D轨迹
    ax1 = fig.add_subplot(131, projection='3d')
    ax1.plot(sol_lorenz.y[0], sol_lorenz.y[1], sol_lorenz.y[2], 
             'b-', linewidth=0.5, alpha=0.8)
    ax1.set_xlabel('X')
    ax1.set_ylabel('Y')
    ax1.set_zlabel('Z')
    ax1.set_title('洛伦兹吸引子 3D轨迹')
    
    # x-z投影
    ax2 = fig.add_subplot(132)
    ax2.plot(sol_lorenz.y[0], sol_lorenz.y[2], 'r-', linewidth=0.5, alpha=0.8)
    ax2.set_xlabel('X')
    ax2.set_ylabel('Z')
    ax2.set_title('洛伦兹吸引子 (x-z投影)')
    ax2.grid(True, alpha=0.3)
    
    # y-z投影
    ax3 = fig.add_subplot(133)
    ax3.plot(sol_lorenz.y[1], sol_lorenz.y[2], 'g-', linewidth=0.5, alpha=0.8)
    ax3.set_xlabel('Y')
    ax3.set_ylabel('Z')
    ax3.set_title('洛伦兹吸引子 (y-z投影)')
    ax3.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()

## 性能优化技巧

### 1. 算法选择和参数调优

```python
# 性能优化示例
def performance_optimization():
    """积分和ODE求解的性能优化"""
    
    # 测试函数
    def test_integration_performance():
        """积分性能测试"""
        
        def smooth_func(x):
            return np.exp(-x**2) * np.sin(x)
        
        def oscillatory_func(x):
            return np.sin(100*x) / (1 + x**2)
        
        methods = {
            'quad': lambda f, a, b: quad(f, a, b),
            'fixed_quad_5': lambda f, a, b: fixed_quad(f, a, b, n=5),
            'fixed_quad_10': lambda f, a, b: fixed_quad(f, a, b, n=10),
            'simpson_1000': lambda f, a, b: (simpson([f(x) for x in np.linspace(a, b, 1001)], dx=(b-a)/1000), 0)
        }
        
        functions = {'smooth': smooth_func, 'oscillatory': oscillatory_func}
        
        print("积分方法性能比较:")
        print(f"{'函数':>12} {'方法':>15} {'结果':>12} {'时间(ms)':>10} {'精度':>12}")
        print("-" * 70)
        
        for func_name, func in functions.items():
            # 参考结果
            ref_result, _ = quad(func, 0, 1)
            
            for method_name, method in methods.items():
                times = []
                for _ in range(10):  # 多次测试取平均
                    start = time.time()
                    result, _ = method(func, 0, 1)
                    times.append((time.time() - start) * 1000)
                
                avg_time = np.mean(times)
                accuracy = abs(result - ref_result)
                
                print(f"{func_name:>12} {method_name:>15} {result:>12.6f} {avg_time:>10.2f} {accuracy:>12.2e}")
        print()
    
    def test_ode_performance():
        """ODE求解性能测试"""
        
        def stiff_ode(t, y):
            return [-1000*y[0] + y[1], y[0] - y[1]]
        
        def nonstiff_ode(t, y):
            return [-y[0] + y[1], y[0] - y[1]]
        
        methods = ['RK45', 'RK23', 'Radau', 'BDF']
        odes = {
            'non_stiff': (nonstiff_ode, [1, 0]),
            'stiff': (stiff_ode, [1, 0])
        }
        
        print("ODE求解方法性能比较:")
        print(f"{'方程类型':>12} {'方法':>10} {'成功':>6} {'步数':>8} {'时间(ms)':>10} {'精度':>12}")
        print("-" * 70)
        
        for ode_name, (ode_func, y0) in odes.items():
            for method in methods:
                try:
                    start = time.time()
                    sol = solve_ivp(ode_func, (0, 1), y0, method=method, rtol=1e-6)
                    exec_time = (time.time() - start) * 1000
                    
                    success = "是" if sol.success else "否"
                    n_steps = len(sol.t)
                    
                    # 简单的精度估计(与最精确方法比较)
                    if method == 'Radau':
                        reference_sol = sol
                        accuracy = 0
                    else:
                        try:
                            ref_sol = solve_ivp(ode_func, (0, 1), y0, method='Radau', rtol=1e-8)
                            if ref_sol.success:
                                accuracy = np.max(np.abs(sol.y[:, -1] - ref_sol.y[:, -1]))
                            else:
                                accuracy = float('inf')
                        except:
                            accuracy = float('inf')
                    
                    print(f"{ode_name:>12} {method:>10} {success:>6} {n_steps:>8} {exec_time:>10.2f} {accuracy:>12.2e}")
                    
                except Exception as e:
                    print(f"{ode_name:>12} {method:>10} {'否':>6} {'N/A':>8} {'N/A':>10} {'N/A':>12}")
        print()
    
    # 执行性能测试
    test_integration_performance()
    test_ode_performance()

# 执行性能优化测试
performance_optimization()

2. 内存优化和并行计算

python
# 内存优化和并行计算
def memory_and_parallel_optimization():
    """内存优化和并行计算示例"""
    
    # 大规模积分的内存优化
    def memory_efficient_integration():
        """内存高效的积分计算"""
        
        def large_array_function(x):
            # 模拟需要大量内存的函数
            return np.sum(np.sin(np.arange(1000) * x))
        
        # 分块积分
        def chunked_integration(func, a, b, n_chunks=10):
            """分块积分以节省内存"""
            chunk_size = (b - a) / n_chunks
            total_integral = 0
            
            for i in range(n_chunks):
                chunk_a = a + i * chunk_size
                chunk_b = a + (i + 1) * chunk_size
                
                chunk_integral, _ = quad(func, chunk_a, chunk_b)
                total_integral += chunk_integral
            
            return total_integral
        
        # 比较内存使用
        print("内存优化积分比较:")
        
        # 直接积分
        start_time = time.time()
        direct_result, _ = quad(large_array_function, 0, 1)
        direct_time = time.time() - start_time
        
        # 分块积分
        start_time = time.time()
        chunked_result = chunked_integration(large_array_function, 0, 1, n_chunks=5)
        chunked_time = time.time() - start_time
        
        print(f"直接积分: {direct_result:.6f}, 时间: {direct_time*1000:.2f}ms")
        print(f"分块积分: {chunked_result:.6f}, 时间: {chunked_time*1000:.2f}ms")
        print(f"相对误差: {abs(direct_result - chunked_result)/abs(direct_result):.2e}")
        print()
    
    # 并行ODE求解
    def parallel_ode_solving():
        """并行ODE求解示例"""
        
        def parameter_study_ode(t, y, param):
            """参数化的ODE"""
            return [-param * y[0], y[0] - y[1]]
        
        # 参数范围
        parameters = np.linspace(0.1, 10, 20)
        
        # 串行求解
        start_time = time.time()
        serial_results = []
        for param in parameters:
            sol = solve_ivp(lambda t, y: parameter_study_ode(t, y, param), 
                          (0, 5), [1, 0], method='RK45')
            if sol.success:
                serial_results.append(sol.y[0, -1])
            else:
                serial_results.append(np.nan)
        serial_time = time.time() - start_time
        
        print(f"串行求解时间: {serial_time*1000:.2f}ms")
        print(f"成功求解: {np.sum(~np.isnan(serial_results))}/{len(parameters)}")
        
        return serial_results, parameters
    
    # 执行优化测试
    memory_efficient_integration()
    results, params = parallel_ode_solving()
    
    # 可视化参数研究结果
    plt.figure(figsize=(12, 5))
    
    plt.subplot(1, 2, 1)
    plt.plot(params, results, 'bo-', linewidth=2, markersize=6)
    plt.xlabel('参数值')
    plt.ylabel('最终状态 y[0](T)')
    plt.title('参数敏感性分析')
    plt.grid(True, alpha=0.3)
    
    plt.subplot(1, 2, 2)
    # 显示收敛性
    valid_results = np.array(results)[~np.isnan(results)]
    valid_params = params[~np.isnan(results)]
    
    if len(valid_results) > 1:
        # 计算梯度
        gradient = np.gradient(valid_results, valid_params)
        plt.plot(valid_params, gradient, 'ro-', linewidth=2, markersize=6)
        plt.xlabel('参数值')
        plt.ylabel('敏感性 dy/dp')
        plt.title('参数敏感性梯度')
        plt.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()

# 执行内存和并行优化
memory_and_parallel_optimization()

## 小结

SciPy的积分和微分方程模块提供了强大而灵活的数值计算工具:

### 积分功能
- **一维积分**: `quad``simpson``trapz`等方法适用于不同精度需求
- **多重积分**: `dblquad``tplquad``nquad`支持复杂区域积分
- **特殊积分**: 处理奇异点、无穷区间、振荡函数等特殊情况

### 微分方程求解
- **初值问题**: `solve_ivp`提供多种高精度求解器
- **边值问题**: `solve_bvp`处理复杂边界条件
- **刚性方程**: `Radau``BDF`等隐式方法处理刚性系统

### 应用领域
- **科学计算**: 物理建模、工程分析、数值仿真
- **生物数学**: 人口动力学、传染病模型、生态系统
- **工程应用**: 控制系统、信号处理、电路分析

### 性能优化
- **算法选择**: 根据问题特性选择合适的求解器
- **参数调优**: 合理设置容差、步长等参数
- **内存管理**: 分块处理大规模问题
- **并行计算**: 参数研究和蒙特卡罗模拟

掌握这些工具和技巧,可以高效解决各种数值积分和微分方程问题,为科学研究和工程应用提供强有力的计算支持。

## 练习题

1. **积分计算**: 计算 ∫₀^π sin(x)cos(x)dx,比较解析解和数值解的精度

2. **二重积分**: 计算圆形区域 x²+y²≤1 上函数 f(x,y)=e^(-(x²+y²)) 的积分

3. **ODE求解**: 求解 Lotka-Volterra 方程,分析不同初值对解的影响

4. **刚性方程**: 求解 Robertson 化学反应方程,比较不同求解器的性能

5. **边值问题**: 求解二阶边值问题 y''+λy=0, y(0)=y(π)=0,找出特征值λ

6. **参数研究**: 对 SIR 模型进行参数敏感性分析,研究 β 和 γ 对疫情峰值的影响

7. **混沌系统**: 分析洛伦兹方程的混沌行为,绘制不同参数下的吸引子

8. **性能优化**: 实现一个自适应积分算法,并与 scipy.integrate.quad 比较性能

本站内容仅供学习和研究使用。