Python 动态建模(1)

本文介绍了如何使用Python的sympy库进行方程求解,并详细讲解了方程转换的合法化过程,包括将方程式转换为符合sympy要求的格式,以及处理无法解析的方程时的错误提示。此外,还涉及到了tkinter库在显示错误信息中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#coding=utf-8

导入sympy;

import sympy

sympy是一个第三方库,请先打开你的cmd(命令行command)窗口运行:

pip install sympy

对这个库的具体介绍见:Python的解方程-SYMPY_Unconquerable&Llxy的博客-优快云博客_python sympy解方程1>第三方库,相信下面就不用我多说了8_8[没有接触过的人:打开电脑,在出现cmd.exe点击运行,输入以上代码]2>打开Python编辑器,开始解-方-程--------------------------这是几道例题(可以先手动解一解)1) 3x+6=24 解:x=62) 5y+3=-53解:y=-103) 3:x=9:6解:x=24) 3y+2x=100解:无实际解-----------------------......https://blog.youkuaiyun.com/html_finder/article/details/125114624

 再导入Python自带的库math

from math import *

具体的原因:

sympy是一个很“任性”的库,经常返回一个公式。比如:sqrt(5)*7

那么我们画图是需要一个数值的,所以我们用math库里的函数计算。


我们首先来明确一下实现的过程:

我们让电脑读懂方程似乎有一些困难,所以我们可以进行一个暴力模拟。把一个数丢进去不断推演,最后得知n个答案,把所有答案的坐标点连起来, 实现一个模型。

需要的变量:

x=[]
y=[]
z=[]
t=[]

这些列表用于储存坐标点。

x:横轴

y:纵轴

z:前后

t:模拟一个时间的变化。

比如:例式x=y=z=t得出的结果应该是一个移动向斜上的点。

原因:x轴、y轴、z轴都相等,随着时间(自增量t)的变大,xyz也会变大,坐标点会不断向斜上移动。


然后定义一个函数,用于计算具体值

def write(formula, min_=-10, max_=10, nums=100,printout=True):

formula是公式;

min_是模拟最小值;

max_是模拟最大值;

nums是模拟数量;

printout是是否打印进度条的布尔参数。


注:

有人问过我为什么不用numpy(numpy.linespace可以生成一个等差数列),原因其实也很简单:

因为有一些运算参数numpy的linespace无法进行运算,所以就没有使用。

(而且,numpy库太大了,打包成exe时不方便【手动狗头Doge】)


接下来,为了方便起见,函数不设置返回值,而是直接写入到前面定义的x,y,z,t四个列表里。

def write ...#省略参数部分
    global x,y,z,t

接下来定义一些变量:

    I=1j
    oo=inf
    step=(max_-min_)/nums
    a=min_-step

    solves=[]

解释:

1.

I=1j

sympy自带的虚数。对于方程x^2+1=0的解,sympy给出的是1*I;但是,如果对其进行运算的话,sympy在虚(复)数的运算上似乎有些确实。于是,Python的complex类型(复数类型)就起了作用。

sqrt(-1)=I=1j。所以,定义I=1j,在sympy返回的字符串表达式中使用eval函数进行再次计算取值。

2.

oo=inf

sympy里的无限就是oo。将math库里的inf(infinity,正无穷)赋给它。

3.

定义累加器a,每次加的值step。

step相当于每循环一次所加的值。

a是从min_开始的,但是因为第一次循环还会先加上一个step,所以定义a=min_-step。


def write(formula, min_=-10, max_=10, nums=100,printout=True):
    global x, y, z, t
    I=1j
    oo=inf
    step=(max_-min_)/nums
    a=min_-step

    r"""
    lf,un = legalSet(toLeg(formula))
    print(un)
    print(lf,toLeg(formula),sep="\n\n",end="\n\n")
    """
    solves=[]

(目前代码)

接下来需要新定义一个函数,叫做legalSet。

原因:

通过对t一次次的赋值得到的结果会形成一个新的方程。例,x=y=z=t就可以改为x=y=z=(具体数值),所以实际上formula就变成了一(N)个方程。所以,使用sympy的solve函数求解。

solve函数有它的特殊要求:

1)除号只有“/”,即Python法定除号。(比号“:”、除号“÷”都不行)

2)乘号只有“*”且不可省略。(其他的写法例如“x”、“×”不行,而且a乘b必须写成a*b,不能写成ab)

3)方程的结果必须等于0,省略等号。所以拖等式是无法计算的。

…………

但是,我们写的方程自然不会写成这样(麻烦死了)所以我们需要用程序进行修改。

第一个函数叫做Legalset,将以换行符分割的方程转换为一个符合要求的方程。

def legalSet(fx):
    ...

第一步,因为可能有许多方程,所以首先将它们以换行符("\n"是转义字符,就表示按一下<enter>后的换行符)分隔成列表。

def legalSet(fx):
    v=str(fx).split("\n")

定义一个临时变量nw对v进行初步处理再赋值给v。因为nw在赋值完之后已经没有用了,所以删掉。

    nw=[]
    for l in v:
        tmpstr=""
        if l=='':continue #滤除空行
        k=l.split("=")
        tmpstr+="(("+k[0]+")-("+k[1]+"))"#等号两边值相等,左边减右边就是结果为0的值。
        nw.append(tmpstr)
    v=nw
    del nw

然后转换字符:

    index=-1
    for i in v:
        index+=1
        if ":" in i: v[index] = i.replace(":", "/")
        if "^" in i: v[index] = i.replace("^", "**")
        if "÷" in i: v[index] = i.replace("÷", "/")
        if "×" in i: v[index] = i.replace("×", "*")
        if "[" in i: v[index] = i.replace("[", "(")
        if "]" in i: v[index] = i.replace("]", ")")
        if "【" in i: v[index] = i.replace("【", "(")
        if "】" in i: v[index] = i.replace("】", ")")
        if "{" in i: v[index] = i.replace("{", "(")
        if "}" in i: v[index] = i.replace("}", ")")
        if "(" in i: v[index] = i.replace("(", "(")
        if ")" in i: v[index] = i.replace(")", ")")

接下来的代码是添加省略的乘号并获取每一行方程的所有未知数。

    newlt=[]
    lt=[]
    for j in v:
        new=""
        pos=-1
        lt__=[]
        funcs=[]
        for i in j:
            pos+=1
            tmpos=pos+0
            string=""
            while (j[tmpos].isalpha()):
                string+=j[tmpos]
                tmpos=tmpos+1
            if string in sympy.__all__ :
                funcs+=[i for i in range(pos,tmpos+1)]


            if ((i.isalpha() or i == "(") and (j[pos-1].isnumeric() or j[pos-1].isalpha())
                    and pos!=0 and pos not in funcs):
                new+="*"+i

            else:
                new+=i
            if i.isalpha() and pos not in funcs:lt__.append(i)

        lt__=list(set(lt__))
        lt.append(lt__)
        newlt.append(str(new))
    return newlt,lt

返回值是一个tuple类型,包含:

(合法公式列表,每行公式对应的未知数)



(修改内容|此处是修改部分)

在试验方程时,发现部分方程可能在求解时遇到问题,legalSet函数的代码应当“全面”一点:

def legalSet(fx):


    v=str(fx).split("\n")
    nw=[]
    for l in v:

        tmpstr=""
        tmpstr2=""
        if l=='':continue
        k=l.split("=")
        tmpstr+="(("+k[0]+")-("+k[1]+"))"
        tmpstr2 += "((" + k[1] + ")-(" + k[0] + "))"
        tmpstrs=[tmpstr,tmpstr2]
        nw.append(tmpstrs)
    v=nw
    del nw

    index=-1
    for i in v:
        index+=1
        for j in range(2):
            if ":" in i: v[index][j] = i[j].replace(":", "/")
            if "^" in i: v[index][j] = i[j].replace("^", "**")
            if "÷" in i: v[index][j] = i[j].replace("÷", "/")
            if "×" in i: v[index][j] = i[j].replace("×", "*")
            if "[" in i: v[index][j] = i[j].replace("[", "(")
            if "]" in i: v[index][j] = i[j].replace("]", ")")
            if "【" in i: v[index][j] = i[j].replace("【", "(")
            if "】" in i: v[index][j] = i[j].replace("】", ")")
            if "{" in i: v[index][j] = i[j].replace("{", "(")
            if "}" in i: v[index][j] = i[j].replace("}", ")")
            if "(" in i: v[index][j] = i[j].replace("(", "(")
            if ")" in i: v[index][j] = i[j].replace(")", ")")
    newlt=[]
    lt=[]
    for j in v:


        lt__=[]
        funcs=[]
        news = []
        for i_ in j:
            new = ""
            pos = -1


            for i in i_:

                pos+=1
                tmpos=pos+0
                string=""
                while (i_[tmpos].isalpha()):
                    string+=i_[tmpos]
                    tmpos=tmpos+1
                if string in sympy.__all__ :
                    funcs+=[i for i in range(pos,tmpos+1)]


                if ((i.isalpha() or i == "(") and (i_[pos-1].isnumeric() or i_[pos-1].isalpha())
                        and pos!=0 and pos not in funcs):
                    new+="*"+i

                else:
                    new+=i
                if i.isalpha() and pos not in funcs:lt__.append(i)
            news.append(new)

        lt__=list(set(lt__))
        lt.append(lt__)
        newlt.append(news)
    return newlt,lt

主要改动:将单方程“a-b”改为列表性双方程“a-b”,“b-a”,思路大体一致,讲解略。



接下来是拖等式转多行单等式,上代码:

def toLeg(fx):
    v=str(fx).split("\n")
    val=[]
    for i in v:
        tv=i.split("=")
        length=len(tv)
        last=None
        while length!=0:
            if length==2:
                val.append('='.join(tv))
                break
            if length==1:
                val.append('='.join([tv[0],str(last)]))
                break
            val.append('='.join([tv[-2],tv[-1]]))
            length=length-1
            last=tv[-1]
            tv.pop()
    return '\n'.join(val)

这其实就是一个普通的Python代码。

通过计算等号的项数再两两搭配。



接下来,基本的转换函数就写好了。

关于它的调试部分在前面write函数的前部分有(用三引号标为注释了,运行时去掉就好)


今天再写上最后一个函数。

把最前面的import语句升级一下:

import sympy
from tkinter.messagebox import *
from tkinter import *
from math import *

接下来要编写的是当方程没有解析解的时候所显示的错误:

def no_ans():
    Tk().geometry("9x9+990000+999999")
    showerror("警告", "方程无解析解")

注:

1)showerror是tkinter.messagebox里面的函数,参见:

Python Tkinter:messagebox_Unconquerable&Llxy的博客-优快云博客tkinter messagebox,消息显示窗口,快捷方便https://blog.youkuaiyun.com/html_finder/article/details/1248294932)    Tk().geometry("9x9+990000+999999")是让附带的窗口消失。

下一篇参见:

Python动态建模(2)_Unconquerable&Llxy的博客-优快云博客bool布尔值(True、False)------------默认为True,真。tmin_,t值的最小取值点;tmax_,t值的最大取值点;https://blog.youkuaiyun.com/html_finder/article/details/126069751


-------------------------------------完------------------------------------------------------------------------------


这里是Unconquerable&Llxy,原名html_finder

Unconquerable&Llxy的博客_优快云博客-Python从负无穷到~,Vpython-3D,办公领域博主Unconquerable&Llxy擅长Python从负无穷到~,Vpython-3D,办公,等方面的知识,Unconquerable&Llxy关注算法,python,c++领域.https://blog.youkuaiyun.com/html_finder?type=blog

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Unconquerable p

给点吧~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值