gpt4 book ai didi

python - 与sympy逐步分化

转载 作者:行者123 更新时间:2023-12-02 16:23:53 28 4
gpt4 key购买 nike

我正在尝试制作一个 python proram 来查找导数和积分以及展示如何。到目前为止,我发现有一个 integral_steps 函数可以返回使用的步数,但我还没有找到一个等价的微分函数。

有谁知道是否有等价物?

如果没有,您对如何找到求导数所需的步骤有什么想法吗?

最佳答案

方法一(手动)

查看代码,the Derivative class是顶级逻辑所在的地方。这只是顶级部分。从那里开始,计算需要计算 expression tree 内不同节点的导数。 .

表达式树的每个特定节点的逻辑位于 _eval_derivative method 中对应于每个特定的节点类型。

这将允许您向那些 _eval_derivative 方法添加代码,以便跟踪整个过程并找到所有步骤。

方法二(使用示踪剂)

Python 有多个 tracing包。 python-hunter@ionelmc 撰写实际上非常好,非常适合这个用例。

在许多其他功能中,它允许在函数开始执行时安装某些回调,并在函数返回其值时安装另一个回调。事实上,这正是我们所需要的。

这是一个展示如何使用它的示例(我在 Python 3.7.3、SymPy 1.7 和 hunter 3.3.1 上运行并测试了它):

import hunter
import sys
from hunter import Q, When, Stop
hunter.trace(
Q(module_contains="sympy",function='_eval_derivative',kind_in=["call","return"],action=hunter.CallPrinter(repr_func=str))
)


from sympy import *
x = symbols('x')
f = 1/(x * sin(x)**2)
f.diff(x)

所以这允许我们选择我们想要检查的数据结构,我们想要如何打印它们,并且它允许我们看到微分过程的中间步骤:

[...]7/site-packages/sympy/core/power.py:1267  call      => _eval_derivative(self=sin(x)**(-2), s=x)
[...]7/site-packages/sympy/core/power.py:1267 call => _eval_derivative(self=<sympy.core.power.Pow object at 0x7f5925337150>, s=<sympy.core.symbol.Symbol object at 0x7f5925b6a2b0>)
[...]ite-packages/sympy/core/function.py:598 call => _eval_derivative(self=sin(x), s=x)
[...]ite-packages/sympy/core/function.py:598 call => _eval_derivative(self=<sympy.functions.elementary.trigonometric.sin object at 0x7f592589ee08>, s=<sympy.core.symbol.Symbol object at 0x7f5925b6a2b0>)
[...]ite-packages/sympy/core/function.py:612 return <= _eval_derivative: cos(x)
[...]ite-packages/sympy/core/function.py:612 return <= _eval_derivative: <sympy.functions.elementary.trigonometric.cos object at 0x7f592525fef8>
[...]7/site-packages/sympy/core/power.py:1271 return <= _eval_derivative: -2*cos(x)/sin(x)**3
[...]7/site-packages/sympy/core/power.py:1271 return <= _eval_derivative: <sympy.core.mul.Mul object at 0x7f5925259b48>
[...]7/site-packages/sympy/core/power.py:1267 call => _eval_derivative(self=1/x, s=x)
[...]7/site-packages/sympy/core/power.py:1267 call => _eval_derivative(self=<sympy.core.power.Pow object at 0x7f5925337200>, s=<sympy.core.symbol.Symbol object at 0x7f5925b6a2b0>)
[...]7/site-packages/sympy/core/power.py:1271 return <= _eval_derivative: -1/x**2
[...]7/site-packages/sympy/core/power.py:1271 return <= _eval_derivative: <sympy.core.mul.Mul object at 0x7f5925259f10>

如果您还想涵盖 diff 函数,您可以更改上面的代码并使用 function_in=['_eval_derivative','diff'] 。这样,不仅可以查看部分结果,还可以查看diff函数的调用及其返回值。

方法三(使用tracer,构建调用图并可视化)

使用 graphviz、latex 和示踪剂(同样是 python-hunter),您实际上可以看到 call graph更清楚。渲染每个中间步骤的所有公式确实需要一些时间,因为正在使用 pdflatex(不过我确信有更快的 latex 渲染器)。

enter image description here

每个节点的值采用以下格式:

function_name
argument => return_value

似乎有一些 diff 节点的参数等于返回值,我现在不确定如何解释。

如果该图以某种方式提到每条规则的应用位置,它可能会更有用(我想不出一种简单的方法来做到这一点)。

这也是代码:

import hunter
import sys
from hunter import Q, When, Stop, Action
from hunter.actions import ColorStreamAction

formula_ltx = r'''
\documentclass[border=2pt,varwidth]{letter}
\usepackage{amsmath}
\pagenumbering{gobble}
\begin{document}
\[ \texttt{TITLE} \]
\[ FORMULA \]
\end{document}
'''

# ==============
# == Tracing ===
# ==============

from sympy.printing.latex import LatexPrinter, print_latex, latex

global call_tree_root

# a node object to hold an observed function call
# with its argument, its return value and its function name
class Node(object):
def __init__(self, arg=None, retval=None, func_name=None):
self.arg = arg
self.retval = retval
self.arg_ascii = ""
self.retval_ascii = ""
self.func_name = func_name
self.uid = 0
self.children = []

# this is a hunter action where we build a call graph and populate it
# so we can later render it
#
# CGBAction (Call Graph Builder Action)
class CGBAction(ColorStreamAction):
def __init__(self, *args, **kwargs):
super(ColorStreamAction, self).__init__(*args, **kwargs)
# a custom call stack
self.tstack = []
global call_tree_root
call_tree_root = Node(arg="",func_name="root")
self.node_idx = 1
self.tstack.append(call_tree_root)

def __call__(self, event):
if event.kind in ['return','call']:
if event.kind == 'return':
print(str(event.arg))
if len(self.tstack) > 0:
top = self.tstack.pop()
top.retval = latex(event.arg)
top.retval_ascii = str(event.arg)

elif event.kind == 'call':
print(str(event.locals.get('self')))
new = Node()
new.uid = self.node_idx
new.arg = latex(event.locals.get('self'))
new.arg_ascii = str(event.locals.get('self'))
top = self.tstack[-1]
self.tstack.append(new)
top.children.append(new)
new.func_name = event.module + ":" + event.function
self.node_idx += 1

hunter.trace(
Q(module_contains="sympy",function_in=['_eval_derivative','diff'],kind_in=["call","return"],action=CGBAction)
)

from sympy import *
x = symbols('x')
f = 1 / (x * sin(x)**2)
#f = 1 / (x * 3)
#f = sin(exp(cos(x)*asin(x)))
f.diff(x)

# ============================
# == Call graph rendering ====
# ============================

import os
import re
OUT_DIR="formulas"

if not os.path.exists(OUT_DIR):
os.mkdir(OUT_DIR)

def write_formula(prefix,uid,formula,title):
TEX = uid + prefix + ".tex"
PDF = uid + prefix + ".pdf"
PNG = uid + prefix + ".png"

TEX_PATH = OUT_DIR + "/" + TEX
with open(TEX_PATH,"w") as f:
ll = formula_ltx
ll = ll.replace("FORMULA",formula)
ll = ll.replace("TITLE",title)
f.write(ll)

# compile formula
CMD = """
cd formulas ;
pdflatex {TEX} ;
convert -trim -density 300 {PDF} -quality 90 -colorspace RGB {PNG} ;
""".format(TEX=TEX,PDF=PDF,PNG=PNG)

os.system(CMD)

buf_nodes = ""
buf_edges = ""
def dfs_tree(x):
global buf_nodes, buf_edges

arg = ("" if x.arg is None else x.arg)
rv = ("" if x.retval is None else x.retval)
arg = arg.replace("\r","")
rv = rv.replace("\r","")

formula = arg + "\\Rightarrow " + rv
print(x.func_name + " -> " + x.arg_ascii + " -> " + x.retval_ascii)

x.func_name = x.func_name.replace("_","\\_")
write_formula("",str(x.uid),formula,x.func_name)

buf_nodes += """
{0} [image="{0}.png" label=""];
""".format(x.uid);

for y in x.children:
buf_edges += "{0} -> {1};\n".format(x.uid,y.uid);
dfs_tree(y)

dfs_tree(call_tree_root)

g = open(OUT_DIR + "/graph.dot", "w")
g.write("digraph g{")
g.write(buf_nodes)
g.write(buf_edges)
g.write("}\n")
g.close()
os.system("""cd formulas ; dot -Tpng graph.dot > graph.png ;""")

将 SymPy 逻辑映射到微分规则​​

我认为剩下的一步是将中间节点从 SymPy 映射到 differentiation rules .这是我能够映射的一些:

我还没有在 sympy.core 中看到 Fraction 类,所以可能是 quotient rule通过 product rule 间接处理, 和一个 generalized power rule指数为 -1。

运行

为了让它运行你需要:

sudo apt-get install graphviz imagemagick texlive texlive-latex-base

并且文件 /etc/ImageMagick-6/policy.xml 必须使用以下行更新以允许从 PDF->PNG 转换:

<policy domain="coder" rights="read|write" pattern="PDF" />

还有另一个调用图库叫做jonga但它有点通用,无法完全过滤掉不需要的电话。

关于python - 与sympy逐步分化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64943719/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com