欢迎来阅!这里是一名Python小白,在Python的自学之旅中,他在畅游畅游~ 突然,好友发来消息(无中生友)问他一版线性代数的题目,他抚须长久,翻出尘封已久的《线性代数》一书…
众所周知(自以为),在Python的numpy扩展包中有许多进行线性代数运算的函数
再用上python内置的tkinter库进行GUI设计,我选取了Numpy中四个常用线性代数计算函数(inv、det、dot、solve),做了个线性代数计算小工具。
界面如下:
(1) 首先,导入tkinter库,利用其相关函数搭好整个窗体界面,从上到下分为三部分,最上面的Frame框架用于放置功能按钮组件;中间的文本框用于用户按特定形式输出要计算的行列式或矩阵;最下面的标签用于展示计算结果。
import tkinter as tk
# 窗体
win = tk.Tk()
win.title("线性代数计算小工具1.0")
win.geometry('600x500')
# 按钮组件的框架
win_frame = tk.Frame(win, width=550, height=120, bg='#7cacae')
win_frame.pack()
# 文本输入框
win_Text1 = tk.Text(win, height=9, width=55, font=3)
win_Text1.pack()
# 标签(用于展示计算结果)
var = tk.StringVar() # 文字变量储存器
win_label = tk.Label(win,
textvariable=var, # 使用textvariable替换text使标签内容可变
bg="#e2e2e2",
font=('Arial', 15),
width=50, height=12)
win_label.pack()
(2)添加按钮,将按钮添加到Frame框架中签到指定位置上去,并且设置按大小、按钮上的标签内容、指定点击时的触发功能命令。
tk.Button(win_frame, # 要添加到的框架
text='读入', #按钮上的文本信息
width=10, height=1, # 按钮的宽高
command=read).place(x=20, y=20) # place设置按钮的放置位置
#command为按钮的触发命令,需另外编写功能方法
tk.Button(win_frame,
text='清空',
width=10, height=1,
command=clear).place(x=20, y=60)
tk.Button(win_frame,
text='算逆矩阵',
width=10, height=1,
command=matrix_inv).place(x=130, y=20)
tk.Button(win_frame,
text='算行列式',
width=10, height=1,
command=Determinant_det).place(x=130, y=60)
tk.Button(win_frame,
text='矩阵相乘',
width=10, height=1,
command=matrix_dot).place(x=220, y=20)
tk.Button(win_frame,
text='解线性方程',
width=10, height=1,
command=linear_solve).place(x=220, y=60)
(3)运行与展示,一定要在最后加上下面这行代码,才能将窗体程序运行出来得以展现。
win.mainloop()
(1)【读入】按钮,该按钮的功能主要是获取输入到文本框中的内容,然后进行判断(判断要进行的运算),运用相关函数进行分割、替换等操作将文本框中的内容转换为特定格式的列表,并追加到指定的列表对象中用于后续运算。https://blog.csdn.net/m0_53156691/article/details/123549204
def read(): # 【读入】按钮功能
text = win_Text1.get('0.0', 'end') # 获取文本框所有内容
try:
if 'x' in text:
a, b = text.split('x') # 按'x'(小写X)进行分割成两个字符串对象
a = a.strip() # 去除字符串前后的空格内容
b = b.strip()
a1.append(a.replace('\n', ';')) # 将字符中的换行符用";"替换并追加到列表中
b1.append(b.replace('\n', ';'))
tk.messagebox.showinfo(title='提示', message='读入成功!') # 弹出框提示
elif '=' in text:
a, b = text.split('=')
a = a.strip()
b = b.strip()
a1.append(a.replace('\n', ';'))
b1.append(b.replace('\n', ';'))
tk.messagebox.showinfo(title='提示', message='读入成功!')
else:
p = text.split('\n') # 按换行符进行切分成一个列表
p.pop() # 将最后一个元素弹出(获取的文本内容最后是个空内容)
for i in range(len(p)):
p1 = p[i].split(' ') # 将列表中每一块的的数字按空格进一步切分成列表
intp1 = [int(x) for x in p1] # 使用列表推导试将字符串转换为数字
# intp1 = list(map(int, p1)) # 方法2 使用map做映射转换为数字
matrix.append(intp1) # 将转换后的数字列表追加存入列表
tk.messagebox.showinfo(title='提示', message='读入成功!')
except (Exception,) as e:
print(e)
tk.messagebox.showwarning(title='异常', message='输出数据或格式错误!') # 异常的弹窗
(2)【清空】按钮,该按钮主要用于将三个列表对象清空,将文本框中的内容清空和标签上的输出结果清空。
def clear(): # 【清空】按钮功能
matrix.clear()
a1.clear()
b1.clear()
win_Text1.delete('1.0', 'end')
var.set('')
(3)【算逆矩阵】按钮,先利用numpy中的array()函数将列表转换成数组,再利用numpy的子包linalg中的inv()函数进行逆矩阵的计算。
def matrix_inv(): # 【算逆矩阵】按钮功能
try:
n = np.array(matrix)
var.set(np.linalg.inv(n)) # 计算逆矩阵函数,并将结果显示在标签上
except (Exception,) as e:
print(e)
if len(matrix) == 0:
tk.messagebox.showwarning(title='异常', message='未读入数据(矩阵为空)')
else:
tk.messagebox.showwarning(title='异常', message='该矩阵不为方阵,无法求逆矩阵')
(4)【算行列式】按钮,同样也是先利用numpy中的array()函数将列表转换成数组,然后再利用numpy的子包linalg中的det()函数进行行列式的计算,但行列式计算的结果为浮点数,长度过大会导致精度失真,这里又用round()方法将其保留小数点后三位有效数字输出。
def Determinant_det(): # 【算行列式】按钮功能
try:
n = np.array(matrix)
print(n)
var.set(round(np.linalg.det(n), 3)) # 计算行列式函数,并保留小数点后三位有效数字
except (Exception,) as e:
print(e)
if len(matrix) == 0:
tk.messagebox.showwarning(title='异常', message='未读入数据(矩阵为空)')
else:
tk.messagebox.showwarning(title='异常', message='该矩阵不为方阵,无法计算出其行列式的值')
(5)【矩阵相乘】按钮,矩阵相乘是两个矩阵间进行的运算,所以需要用两个对象链接数组对象,然后再利用numpy中的dot()函数进行运算得出结果。
def matrix_dot(): # 【矩阵相乘】按钮功能
try:
a2 = np.mat(a1[0])
b2 = np.mat(b1[0])
c = np.dot(a2, b2) # 两个矩阵相乘函数
var.set(c)
except (Exception, TypeError) as e:
print(e)
if len(a1) == 0 or len(b1) == 0:
tk.messagebox.showwarning(title='异常', message='未读入数据(矩阵为空)')
else:
tk.messagebox.showwarning(title='异常', message='此两个矩阵无法相乘')
a1.clear() # 这里清空列表是为了可以直接在文本进行修改后重新读入
b1.clear()
(6)【解线性方程】按钮,在求解线性方程组的过程中往往是先写出其对应的增广矩阵,这里由于numpy的子包linalg中的solve()函数参数要求,需要分成系数矩阵和常数矩阵进行运算。(此外,有个小缺憾就是,当方程有无数解则无法给出运算结果)
def linear_solve(): # 【解线性方程】按钮功能
try:
a2 = np.mat(a1[0])
b2 = np.mat(b1[0])
c = np.linalg.solve(a2, b2) # 计算线性方程函数
var.set(c) # 若是奇异矩阵则有无数解会报错
except (Exception, ) as e:
print(e)
if len(a1) == 0 or len(b1) == 0:
tk.messagebox.showwarning(title='异常', message='未读入数据(矩阵为空)')
else:
tk.messagebox.showwarning(title='异常', message='此两个矩阵不为非奇异矩阵,无唯一解')
a1.clear() # 这里清空列表是为了可以直接在文本进行修改后重新读入
b1.clear()
(供参考)
import tkinter as tk
from tkinter import messagebox
import numpy as np
# 窗体
win = tk.Tk()
win.title("线性代数计算小工具1.0")
win.geometry('600x500')
# 按钮组件的框架
win_frame = tk.Frame(win, width=550, height=120, bg='#7cacae')
win_frame.pack()
# 文本输入框
win_Text1 = tk.Text(win, height=9, width=55, font=3)
win_Text1.pack()
# 定义三个列表对象,用于后面存储读入的数据
matrix = []
a1 = []
b1 = []
def read(): # 【读入】按钮功能
text = win_Text1.get('0.0', 'end') # 获取文本框所有内容
try:
if 'x' in text:
a, b = text.split('x')
a = a.strip()
b = b.strip()
a1.append(a.replace('\n', ';'))
b1.append(b.replace('\n', ';'))
tk.messagebox.showinfo(title='提示', message='读入成功!')
elif '=' in text:
a, b = text.split('=')
a = a.strip()
b = b.strip()
a1.append(a.replace('\n', ';'))
b1.append(b.replace('\n', ';'))
tk.messagebox.showinfo(title='提示', message='读入成功!')
else:
p = text.split('\n') # 按换行符进行切分成一个列表
p.pop() # 将最后一个元素弹出(获取的文本内容最后是个空内容)
for i in range(len(p)):
p1 = p[i].split(' ') # 将列表中每一块的的数字按空格进一步切分成列表
intp1 = [int(x) for x in p1] # 使用列表推导试将字符串转换为数字
# intp1 = list(map(int, p1)) # 方法2 使用map做映射转换为数字
matrix.append(intp1) # 将转换后的数字列表追加存入列表
tk.messagebox.showinfo(title='提示', message='读入成功!')
except (Exception,) as e:
print(e)
tk.messagebox.showwarning(title='异常', message='输出数据或格式错误!') # 异常的弹窗
def clear(): # 【清空】按钮功能
matrix.clear()
a1.clear()
b1.clear()
win_Text1.delete('1.0', 'end')
var.set('')
def matrix_inv(): # 【算逆矩阵】按钮功能
try:
n = np.array(matrix)
var.set(np.linalg.inv(n)) # 计算逆矩阵函数,并将结果显示在标签上
except (Exception,) as e:
print(e)
if len(matrix) == 0:
tk.messagebox.showwarning(title='异常', message='未读入数据(矩阵为空)')
else:
tk.messagebox.showwarning(title='异常', message='该矩阵不为方阵,无法求逆矩阵')
def Determinant_det(): # 【算行列式】按钮功能
try:
n = np.array(matrix)
print(n)
var.set(round(np.linalg.det(n), 3)) # 计算行列式函数,并保留小数点后三位有效数字
except (Exception,) as e:
print(e)
if len(matrix) == 0:
tk.messagebox.showwarning(title='异常', message='未读入数据(矩阵为空)')
else:
tk.messagebox.showwarning(title='异常', message='该矩阵不为方阵,无法计算出其行列式的值')
def matrix_dot(): # 【矩阵相乘】按钮功能
try:
a2 = np.mat(a1[0])
b2 = np.mat(b1[0])
c = np.dot(a2, b2) # 两个矩阵相乘函数
var.set(c)
except (Exception, TypeError) as e:
print(e)
if len(a1) == 0 or len(b1) == 0:
tk.messagebox.showwarning(title='异常', message='未读入数据(矩阵为空)')
else:
tk.messagebox.showwarning(title='异常', message='此两个矩阵无法相乘')
a1.clear() # 这里清空列表是为了可以直接在文本进行修改后重新读入
b1.clear()
def linear_solve(): # 【解线性方程】按钮功能
try:
a2 = np.mat(a1[0])
b2 = np.mat(b1[0])
c = np.linalg.solve(a2, b2) # 计算线性方程函数
var.set(c) # 若是奇异矩阵则有无数解会报错
except (Exception, ) as e:
print(e)
if len(a1) == 0 or len(b1) == 0:
tk.messagebox.showwarning(title='异常', message='未读入数据(矩阵为空)')
else:
tk.messagebox.showwarning(title='异常', message='此两个矩阵不为非奇异矩阵,无唯一解')
a1.clear() # 这里清空列表是为了可以直接在文本进行修改后重新读入
b1.clear()
tk.Button(win_frame,
text='读入',
width=10, height=1,
command=read).place(x=20, y=20)
tk.Button(win_frame,
text='清空',
width=10, height=1,
command=clear).place(x=20, y=60)
tk.Button(win_frame,
text='算逆矩阵',
width=10, height=1,
command=matrix_inv).place(x=130, y=20)
tk.Button(win_frame,
text='算行列式',
width=10, height=1,
command=Determinant_det).place(x=130, y=60)
tk.Button(win_frame,
text='矩阵相乘',
width=10, height=1,
command=matrix_dot).place(x=220, y=20)
tk.Button(win_frame,
text='解线性方程',
width=10, height=1,
command=linear_solve).place(x=220, y=60)
tk.Label(win_frame,
text='更多功能按钮ing!',
bg='#99e2e2',
font=(18,),
width=18, height=3).place(x=350, y=20)
var = tk.StringVar() # 文字变量储存器
win_label = tk.Label(win,
textvariable=var, # 使用textvariable替换text使标签内容可变
bg="#e2e2e2",
font=('Arial', 15),
width=50, height=12)
win_label.pack()
win.mainloop()