1.1.7. 高级表达式操作¶
参考 Advanced Expression Manipulation
在本节中,我们将讨论一些可以对表达式执行高级操作的方法。
理解表达式树¶
在我们这样做之前,我们需要了解表达式在 SymPy 中是如何表示的。数学表达式表示为一棵树。让我们采用表达式 \(x^2+xy\),即 x**2 + x*y
。我们可以通过使用 srepr
在内部看到这个表达式的样子
import warnings
from sympy import *
import pydot
from IPython.display import SVG
warnings.filterwarnings('ignore')
def display_dot(expr):
g = pydot.graph_from_dot_data(dotprint(expr))[0]
g.set_bgcolor('lightyellow')
t = SVG(g.create_svg())
return t
x, y, z = symbols('x y z')
expr = x**2 + x*y
srepr(expr)
"Add(Pow(Symbol('x'), Integer(2)), Mul(Symbol('x'), Symbol('y')))"
拆解这个最简单的方法是查看表达式树的图表:
display_dot(expr)
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
~/.local/lib/python3.8/site-packages/pydot.py in create(self, prog, format, encoding)
1922 try:
-> 1923 stdout_data, stderr_data, process = call_graphviz(
1924 program=prog,
~/.local/lib/python3.8/site-packages/pydot.py in call_graphviz(program, arguments, working_dir, **kwargs)
131
--> 132 process = subprocess.Popen(
133 program_with_args,
/usr/lib/python3.8/subprocess.py in __init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, encoding, errors, text)
853
--> 854 self._execute_child(args, executable, preexec_fn, close_fds,
855 pass_fds, cwd, env,
/usr/lib/python3.8/subprocess.py in _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, start_new_session)
1701 err_msg = os.strerror(errno_num)
-> 1702 raise child_exception_type(errno_num, err_msg, err_filename)
1703 raise child_exception_type(err_msg)
FileNotFoundError: [Errno 2] No such file or directory: 'dot'
During handling of the above exception, another exception occurred:
FileNotFoundError Traceback (most recent call last)
<ipython-input-3-23e704996809> in <module>
----> 1 display_dot(expr)
<ipython-input-1-fa565b96c54e> in display_dot(expr)
9 g = pydot.graph_from_dot_data(dotprint(expr))[0]
10 g.set_bgcolor('lightyellow')
---> 11 t = SVG(g.create_svg())
12 return t
~/.local/lib/python3.8/site-packages/pydot.py in new_method(f, prog, encoding)
1731 encoding=None):
1732 """Refer to docstring of method `create`."""
-> 1733 return self.create(
1734 format=f, prog=prog, encoding=encoding)
1735 name = 'create_{fmt}'.format(fmt=frmt)
~/.local/lib/python3.8/site-packages/pydot.py in create(self, prog, format, encoding)
1931 args[1] = '"{prog}" not found in path.'.format(
1932 prog=prog)
-> 1933 raise OSError(*args)
1934 else:
1935 raise
FileNotFoundError: [Errno 2] "dot" not found in path.
首先,让我们看看这棵树的叶子。符号是类 Symbol
的实例。虽然我们一直在做
x = symbols('x')
我们也可以做到
x = Symbol('x')
无论哪种方式,我们都会得到一个名为“x”的 Symbol。对于表达式中的数字 2,我们得到了 Integer(2)
。Integer
是整数的 SymPy 类。它类似于 Python 的内置类型 int
,不同之处在于 Integer
可以很好地与其他 SymPy 类型一起使用。
当我们写 x**2
时,这会创建一个 Pow
对象。Pow
是“power”的缩写。
srepr(x**2)
"Pow(Symbol('x'), Integer(2))"
display_dot(x**2)
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
~/.local/lib/python3.8/site-packages/pydot.py in create(self, prog, format, encoding)
1922 try:
-> 1923 stdout_data, stderr_data, process = call_graphviz(
1924 program=prog,
~/.local/lib/python3.8/site-packages/pydot.py in call_graphviz(program, arguments, working_dir, **kwargs)
131
--> 132 process = subprocess.Popen(
133 program_with_args,
/usr/lib/python3.8/subprocess.py in __init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, encoding, errors, text)
853
--> 854 self._execute_child(args, executable, preexec_fn, close_fds,
855 pass_fds, cwd, env,
/usr/lib/python3.8/subprocess.py in _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, start_new_session)
1701 err_msg = os.strerror(errno_num)
-> 1702 raise child_exception_type(errno_num, err_msg, err_filename)
1703 raise child_exception_type(err_msg)
FileNotFoundError: [Errno 2] No such file or directory: 'dot'
During handling of the above exception, another exception occurred:
FileNotFoundError Traceback (most recent call last)
<ipython-input-7-d69e3d2afdc7> in <module>
----> 1 display_dot(x**2)
<ipython-input-1-fa565b96c54e> in display_dot(expr)
9 g = pydot.graph_from_dot_data(dotprint(expr))[0]
10 g.set_bgcolor('lightyellow')
---> 11 t = SVG(g.create_svg())
12 return t
~/.local/lib/python3.8/site-packages/pydot.py in new_method(f, prog, encoding)
1731 encoding=None):
1732 """Refer to docstring of method `create`."""
-> 1733 return self.create(
1734 format=f, prog=prog, encoding=encoding)
1735 name = 'create_{fmt}'.format(fmt=frmt)
~/.local/lib/python3.8/site-packages/pydot.py in create(self, prog, format, encoding)
1931 args[1] = '"{prog}" not found in path.'.format(
1932 prog=prog)
-> 1933 raise OSError(*args)
1934 else:
1935 raise
FileNotFoundError: [Errno 2] "dot" not found in path.
我们可以通过调用 Pow(x, 2)
创建相同的对象
Pow(x, 2)
\[\displaystyle x^{2}\]
其他的运算以此类推:
expr = sin(x*y)/2 - x**2 + 1/y
expr
\[\displaystyle - x^{2} + \frac{\sin{\left(x y \right)}}{2} + \frac{1}{y}\]
srepr(expr)
"Add(Mul(Integer(-1), Pow(Symbol('x'), Integer(2))), Mul(Rational(1, 2), sin(Mul(Symbol('x'), Symbol('y')))), Pow(Symbol('y'), Integer(-1)))"
display_dot(expr)
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
~/.local/lib/python3.8/site-packages/pydot.py in create(self, prog, format, encoding)
1922 try:
-> 1923 stdout_data, stderr_data, process = call_graphviz(
1924 program=prog,
~/.local/lib/python3.8/site-packages/pydot.py in call_graphviz(program, arguments, working_dir, **kwargs)
131
--> 132 process = subprocess.Popen(
133 program_with_args,
/usr/lib/python3.8/subprocess.py in __init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, encoding, errors, text)
853
--> 854 self._execute_child(args, executable, preexec_fn, close_fds,
855 pass_fds, cwd, env,
/usr/lib/python3.8/subprocess.py in _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, start_new_session)
1701 err_msg = os.strerror(errno_num)
-> 1702 raise child_exception_type(errno_num, err_msg, err_filename)
1703 raise child_exception_type(err_msg)
FileNotFoundError: [Errno 2] No such file or directory: 'dot'
During handling of the above exception, another exception occurred:
FileNotFoundError Traceback (most recent call last)
<ipython-input-11-23e704996809> in <module>
----> 1 display_dot(expr)
<ipython-input-1-fa565b96c54e> in display_dot(expr)
9 g = pydot.graph_from_dot_data(dotprint(expr))[0]
10 g.set_bgcolor('lightyellow')
---> 11 t = SVG(g.create_svg())
12 return t
~/.local/lib/python3.8/site-packages/pydot.py in new_method(f, prog, encoding)
1731 encoding=None):
1732 """Refer to docstring of method `create`."""
-> 1733 return self.create(
1734 format=f, prog=prog, encoding=encoding)
1735 name = 'create_{fmt}'.format(fmt=frmt)
~/.local/lib/python3.8/site-packages/pydot.py in create(self, prog, format, encoding)
1931 args[1] = '"{prog}" not found in path.'.format(
1932 prog=prog)
-> 1933 raise OSError(*args)
1934 else:
1935 raise
FileNotFoundError: [Errno 2] "dot" not found in path.