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

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

 

可视化求解线性方程组

# -*- 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)    收藏  举报

导航