可视化求解线性方程组
# -*- coding: utf-8 -*-
import tkinter as tk
from tkinter import ttk
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
# 设置中文字体和负号显示
matplotlib.rcParams['font.family'] = 'Microsoft YaHei'
matplotlib.rcParams['axes.unicode_minus'] = False
class MatrixDecompositionApp:
"""
矩阵分解应用类,用于演示高斯消元法和LU分解求解线性方程组
Attributes:
root: Tkinter根窗口对象
fig: Matplotlib图形对象
ax: Matplotlib坐标轴对象
canvas: 嵌入Tkinter的Matplotlib画布
n_var: 方程组阶数变量
range_var: 系数范围变量
method_var: 算法选择变量(高斯消元/LU分解)
steps: 存储分解过程的步骤数据
ops: 存储每个步骤的操作描述
pivots: 存储每个步骤的主元位置
current_frame: 当前显示的步骤索引
A: 随机生成的系数矩阵
b: 随机生成的常数向量
"""
def __init__(self, root):
"""
初始化应用界面和变量
Args:
root: Tkinter根窗口对象
"""
self.root = root
self.root.title("线性方程组求解演示(高斯消元 & LU分解)")
# 创建Matplotlib图形并嵌入到Tkinter
self.fig, self.ax = plt.subplots(figsize=(6, 6))
self.canvas = FigureCanvasTkAgg(self.fig, master=root)
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True)
# 初始化控制变量
self.n_var = tk.IntVar(value=3)
self.range_var = tk.DoubleVar(value=10.0)
self.method_var = tk.StringVar(value="Gaussian") # 默认高斯消元
# 创建控制面板
self.create_controls()
# 初始化存储分解过程的数据结构
self.steps = []
self.ops = []
self.pivots = []
self.current_frame = 0
# 保存随机生成矩阵和向量,用于求解
self.A = None
self.b = None
def create_controls(self):
"""
创建界面控制元素,包括算法选择、参数滑块和操作按钮
"""
controls = tk.Frame(self.root)
controls.pack(side=tk.BOTTOM, fill=tk.X)
# 算法选择区域
method_frame = tk.Frame(controls)
method_frame.pack(fill=tk.X, padx=10, pady=2)
tk.Label(method_frame, text="算法选择:", width=10).pack(side=tk.LEFT)
ttk.Radiobutton(method_frame, text="高斯消元", variable=self.method_var, value="Gaussian").pack(side=tk.LEFT, padx=5)
ttk.Radiobutton(method_frame, text="LU分解", variable=self.method_var, value="LU").pack(side=tk.LEFT, padx=5)
# 创建参数滑块
self.create_slider(controls, "方程组阶数 n", self.n_var, 2, 6, 1)
self.create_slider(controls, "系数范围 ±", self.range_var, 1.0, 20.0, 1.0)
# 按钮区域
btn_frame = tk.Frame(controls)
btn_frame.pack(pady=5)
gen_btn = ttk.Button(btn_frame, text="生成矩阵", command=self.generate_and_run)
gen_btn.pack(side=tk.LEFT, padx=5)
self.prev_btn = ttk.Button(btn_frame, text="上一步", command=self.prev_step, state=tk.DISABLED)
self.prev_btn.pack(side=tk.LEFT, padx=5)
self.next_btn = ttk.Button(btn_frame, text="下一步", command=self.next_step, state=tk.DISABLED)
self.next_btn.pack(side=tk.LEFT, padx=5)
def create_slider(self, parent, label, var, minval, maxval, step):
"""
创建带标签的滑块控件
Args:
parent: 父容器
label: 滑块标签文本
var: 关联的变量对象
minval: 滑块最小值
maxval: 滑块最大值
step: 滑块步长
"""
frame = tk.Frame(parent)
frame.pack(fill=tk.X, padx=10)
lbl = tk.Label(frame, text=label, width=15)
lbl.pack(side=tk.LEFT)
slider = ttk.Scale(frame, from_=minval, to=maxval, variable=var,
orient=tk.HORIZONTAL)
slider.pack(side=tk.LEFT, fill=tk.X, expand=True)
val_label = tk.Label(frame, textvariable=var, width=8)
val_label.pack(side=tk.RIGHT)
def generate_and_run(self):
"""
根据选择的算法生成随机矩阵并执行分解过程
"""
if self.method_var.get() == "Gaussian":
self.run_gaussian_elimination()
else:
self.run_lu_decomposition()
self.current_frame = 0
self.update_buttons()
def run_gaussian_elimination(self):
"""
执行高斯消元法并记录分解过程步骤
"""
# 初始化图形和数据结构
self.ax.clear()
self.steps.clear()
self.ops.clear()
self.pivots.clear()
# 获取参数并生成随机矩阵
n = self.n_var.get()
r = self.range_var.get()
self.A = np.random.uniform(-r, r, (n, n))
self.b = np.random.uniform(-r, r, n)
Ab = np.hstack((self.A.copy(), self.b.reshape(-1, 1)))
# 记录初始状态
self.steps.append(Ab.copy())
self.ops.append("初始增广矩阵")
self.pivots.append(None)
# 前向消元过程
for i in range(n):
# 部分主元选择
max_row = i + np.argmax(np.abs(Ab[i:, i]))
if max_row != i:
Ab[[i, max_row]] = Ab[[max_row, i]]
self.steps.append(Ab.copy())
self.ops.append(f"交换 R{i+1} <-> R{max_row+1}")
self.pivots.append(None)
# 归一化主元行
pivot = Ab[i, i]
Ab[i] = Ab[i] / pivot
self.steps.append(Ab.copy())
self.ops.append(f"R{i+1} ← R{i+1} ÷ 主元 {pivot:.3f}")
self.pivots.append((i, i))
# 消去下方元素
for j in range(i + 1, n):
factor = Ab[j, i]
Ab[j] = Ab[j] - factor * Ab[i]
self.steps.append(Ab.copy())
self.ops.append(f"R{j+1} ← R{j+1} – {factor:.3f} × R{i+1}")
self.pivots.append((i, i))
# 回代过程
for i in range(n - 1, -1, -1):
for j in range(i - 1, -1, -1):
factor = Ab[j, i]
Ab[j] = Ab[j] - factor * Ab[i]
self.steps.append(Ab.copy())
self.ops.append(f"R{j+1} ← R{j+1} – {factor:.3f} × R{i+1}")
self.pivots.append(None)
# 更新界面状态
self.current_frame = 0
self.update_buttons()
self.update_plot()
def run_lu_decomposition(self):
"""
执行LU分解并记录分解过程步骤
"""
# 初始化图形和数据结构
self.ax.clear()
self.steps.clear()
self.ops.clear()
self.pivots.clear()
# 获取参数并生成随机矩阵
n = self.n_var.get()
r = self.range_var.get()
self.A = np.random.uniform(-r, r, (n, n))
self.b = np.random.uniform(-r, r, n)
# 初始化L和U矩阵
L = np.eye(n)
U = self.A.copy()
# 记录初始状态
self.steps.append((L.copy(), U.copy()))
self.ops.append("初始矩阵")
self.pivots.append(None)
# LU分解主循环
for k in range(n - 1):
# 部分主元选择
max_row = k + np.argmax(np.abs(U[k:, k]))
if max_row != k:
U[[k, max_row]] = U[[max_row, k]]
L[[k, max_row], :k] = L[[max_row, k], :k]
self.steps.append((L.copy(), U.copy()))
self.ops.append(f"交换 U 行 {k+1} <-> {max_row+1}")
self.pivots.append(None)
# 计算乘数并更新U矩阵
for i in range(k + 1, n):
factor = 0 if U[k, k] == 0 else U[i, k] / U[k, k]
L[i, k] = factor
U[i, k:] = U[i, k:] - factor * U[k, k:]
self.steps.append((L.copy(), U.copy()))
self.ops.append(f"L[{i+1},{k+1}] = {factor:.3f}, U 行{i+1} ← U 行{i+1} – {factor:.3f} × U 行{k+1}")
self.pivots.append((k, k))
# 更新界面状态
self.current_frame = 0
self.update_buttons()
self.update_plot(lu_mode=True)
def solve_gaussian(self):
"""
使用高斯消元后的结果进行回代求解
Returns:
numpy.ndarray: 解向量x
"""
n = self.n_var.get()
Ab = self.steps[-1]
x = np.zeros(n)
# 回代求解
for i in reversed(range(n)):
x[i] = Ab[i, -1] - np.sum(Ab[i, i+1:n]*x[i+1:n])
return x
def solve_lu(self):
"""
使用LU分解结果求解方程组
Returns:
numpy.ndarray: 解向量x
"""
n = self.n_var.get()
L, U = self.steps[-1]
b = self.b
y = np.zeros(n)
x = np.zeros(n)
# 前向代入求解Ly=b
for i in range(n):
y[i] = b[i] - np.sum(L[i, :i] * y[:i])
# 回代求解Ux=y
for i in reversed(range(n)):
x[i] = (y[i] - np.sum(U[i, i+1:] * x[i+1:])) / U[i, i]
return x
def next_step(self):
"""显示下一步分解过程"""
if self.current_frame < len(self.steps) - 1:
self.current_frame += 1
self.update_buttons()
if self.method_var.get() == "Gaussian":
self.update_plot()
else:
self.update_plot(lu_mode=True)
def prev_step(self):
"""显示上一步分解过程"""
if self.current_frame > 0:
self.current_frame -= 1
self.update_buttons()
if self.method_var.get() == "Gaussian":
self.update_plot()
else:
self.update_plot(lu_mode=True)
def update_buttons(self):
"""更新按钮状态(启用/禁用)"""
if self.current_frame <= 0:
self.prev_btn.config(state=tk.DISABLED)
else:
self.prev_btn.config(state=tk.NORMAL)
if self.current_frame >= len(self.steps) - 1:
self.next_btn.config(state=tk.DISABLED)
else:
self.next_btn.config(state=tk.NORMAL)
def update_plot(self, lu_mode=False):
"""
更新图形显示当前分解步骤
Args:
lu_mode: 是否为LU分解模式(默认False)
"""
self.ax.clear()
if lu_mode:
# LU分解模式的表格显示
L, U = self.steps[self.current_frame]
n = L.shape[0]
m = n + 1 # L和U并排显示,列数多1作为分隔符
# 创建表格数据
table_data = []
for i in range(n):
row = [f"{L[i,j]:.2f}" for j in range(n)] + ['|'] + [f"{U[i,j]:.2f}" for j in range(n)]
table_data.append(row)
# 绘制表格
self.ax.axis('off')
table = self.ax.table(cellText=table_data, loc='center', cellLoc='center')
table.scale(1, 2)
table.auto_set_font_size(False)
table.set_fontsize(12)
# 高亮变化的单元格
if self.current_frame > 0:
prev_L, prev_U = self.steps[self.current_frame - 1]
for i in range(n):
for j in range(n):
if not np.isclose(L[i,j], prev_L[i,j]):
cell = table[(i, j)]
cell.get_text().set_color('red')
if not np.isclose(U[i,j], prev_U[i,j]):
cell = table[(i, j + n + 1)]
cell.get_text().set_color('red')
# 高亮主元行列
pivot = self.pivots[self.current_frame]
if pivot is not None:
pr, pc = pivot
for c in range(n):
table[(pr, c)].set_facecolor('#fff2cc')
for r in range(n):
table[(r, pc)].set_facecolor('#fff2cc')
for c in range(n):
table[(pr, c + n + 1)].set_facecolor('#fff2cc')
for r in range(n):
table[(r, pc + n + 1)].set_facecolor('#fff2cc')
# 添加标题和操作描述
op_text = self.ops[self.current_frame] if self.current_frame < len(self.ops) else ""
title = f"步骤 {self.current_frame + 1}/{len(self.steps)}\n{op_text}"
# 在最后一步显示解向量
if self.current_frame == len(self.steps) - 1:
x = self.solve_lu()
sol_str = "解向量 x = [" + ", ".join(f"{xi:.3f}" for xi in x) + "]"
title += "\n" + sol_str
self.ax.set_title(title)
else:
# 高斯消元模式的表格显示
matrix = self.steps[self.current_frame]
n, m = matrix.shape
self.ax.axis('off')
table_data = [[f"{matrix[i, j]:.2f}" for j in range(m)] for i in range(n)]
table = self.ax.table(cellText=table_data, loc='center', cellLoc='center')
table.scale(1, 2)
table.auto_set_font_size(False)
table.set_fontsize(12)
# 高亮变化的单元格
if self.current_frame > 0:
prev = self.steps[self.current_frame - 1]
for i in range(n):
for j in range(m):
if not np.isclose(matrix[i, j], prev[i, j]):
cell = table[(i, j)]
cell.get_text().set_color('red')
# 高亮主元行列
pivot = self.pivots[self.current_frame]
if pivot is not None:
pr, pc = pivot
for c in range(m):
table[(pr, c)].set_facecolor('#fff2cc')
for r in range(n):
table[(r, pc)].set_facecolor('#fff2cc')
# 添加标题和操作描述
op_text = self.ops[self.current_frame] if self.current_frame < len(self.ops) else ""
title = f"步骤 {self.current_frame + 1}/{len(self.steps)}\n{op_text}"
# 在最后一步显示解向量
if self.current_frame == len(self.steps) - 1:
x = self.solve_gaussian()
sol_str = "解向量 x = [" + ", ".join(f"{xi:.3f}" for xi in x) + "]"
title += "\n" + sol_str
self.ax.set_title(title)
# 重绘画布
self.canvas.draw()
if __name__ == "__main__":
# 创建主窗口并启动应用
root = tk.Tk()
app = MatrixDecompositionApp(root)
root.mainloop()
提示词
用 高斯消元法 求解决 线性方程组 的 Python 动画演示程序,使用 matplotlib 实现动画,并配有可调节参数的 GUI(通过tkinter 实现)要求 上面是演示界面,下面是可调节参数
posted on 2025-07-09 22:20 Indian_Mysore 阅读(9) 评论(0) 收藏 举报
浙公网安备 33010602011771号