我从我在 Github 上公开的讨论中重新发布了这篇文章,以接触更多的人,因为我的问题取决于个人喜好。
我想我的问题是由于 sympy 在 python(一般编程语言)中使用,而不是在特殊的数学语言中使用。我还是想听听你的建议。
我已经使用 sympy 一段时间了。我的目标是仅通过输出创建尽可能可重复的计算。
我一直在努力解决的问题是如何构建我的代码/存储在变量中。
我在计算面积和体积的示例中提出的一些不同方法:
期望的输出是:
import sympy as sp
from sympy.abc import *
display(sp.Eq(A, a*b), sp.Eq(V, A*h), sp.Eq(V, a*b*h))
第一种方法是将它们存储在 sp.Eq 中:
import sympy as sp
from sympy.abc import *
eq_A = sp.Eq(A, a*b)
eq_V = sp.Eq(V, A*h)
display(eq_A, eq_V)
eq_V_subs = sp.Eq(V, A.subs(A, eq_A.rhs))
display(eq_V_subs)
这种方法似乎太乏味并且容易出错,因为我必须不断用其对应的方程重新替换符号。
我采取的下一个方法是覆盖符号:
A = a*b
V = A*h
display(sp.Eq(sp.Symbol('A'),A), sp.Eq(sp.Symbol('V'),V))
以这种方式进行计算感觉很自然。问题是,我覆盖了符号,这阻碍了我获得所需的
sp.Eq(V, A*h)
输出。特别是当变量中的计算量越来越大时,需要用简单的符号替换以保持概览:
我的最后一个方法是以某种方式为我的表情创建一个商店:
import sympy as sp
from sympy.abc import *
store={}
store[A] = a*b
store[V] = A*h
display(sp.Eq(A, A.subs(store)), sp.Eq(V, V.subs(store)), sp.Eq(V, V.subs(store).subs(store)))
效果还不错,但正如在显示功能中可以看到的那样:要获得最终显示的音量,需要 sub V 2 次。随着字典大小的增加以及彼此建立的方程,n-subs 增加,这不再是手工可行的(也许编写一个函数来 subs n 次,其中 n 是字典的长度)。
如果有一个类似于 sp.symbols() 的类,我可以在其中存储符号和相应的表达式,那不是很好吗?该类能够对符号和表达式执行 sympy 中的所有操作。通过一些定义的函数,我可以仅使用符号来显示,使用不同的函数,我可以使用表达式来呈现它。一些伪代码来说明我的意思:
import sympy as sp
from sympy.abc import *
A = mock_class(sp.Symbol('A'), a*b)
V = mock_class(sp.Symbol('V'), A*h)
mock_display_Symbol(V, V)
moch_display_expression(A, A)
所以我的问题是,你如何处理这个问题?你有什么建议我可以实现我的目标?
您可能想探索一个不错的软件包,Algebra with SymPy。
它实现了您在学校可能熟悉的“方程”概念,其中可以对方程两边应用相同的数学运算,或对两个或多个方程应用数学运算。
我认为这是一个强大的扩展,可以让 SymPy 计算感觉更自然。但有一个问题:它不会执行任何检查来验证您输入的内容是好还是坏。因此,你必须小心你想要实现的目标。
我会给你一个非常简短的介绍:
from sympy import *
from algebra_with_sympy import solve, Equation as Eqn, algwsym_config
init_printing()
Eqn
是实现魔法的类。 solve
是 SymPy 的 solve
函数的包装器,它能够处理 Equation
类型的对象。
# by default, when an equation is shown on the screen, it also shows
# a label with a unique number. Usually, I hide them:
algwsym_config.output.label = False
# by default, the algebra_with_sympy's solve returns objects of type
# FiniteSet. I don't like that behavior: I prefer lists of solutions.
algwsym_config.output.solve_to_list = True
现在举个例子:
var("a, b, h, V, A")
eq_V = Eqn(V, A*h)
eq_A = Eqn(A, a*b)
eq_V.subs(eq_A)
# out: V = a*b*h
上面的
subs
命令相当于eq_V.subs(eq_A.lhs, eq_A.rhs)
。从本质上讲,您大大减少了输入错误的机会。