SymPy-1-13-中文文档-四十四-

155 阅读41分钟

SymPy 1.13 中文文档(四十四)

原文:docs.sympy.org/latest/index.html

Lambdify

原文:docs.sympy.org/latest/modules/utilities/lambdify.html

此模块提供便捷函数,将 SymPy 表达式转换为可以快速计算数值的 lambda 函数。

sympy.utilities.lambdify.implemented_function(symfunc, implementation)

将数值 implementation 添加到函数 symfunc 中。

symfunc 可以是一个 UndefinedFunction 实例,或者是一个名称字符串。在后一种情况下,我们将创建一个具有该名称的 UndefinedFunction 实例。

请注意,这是一个快速的解决方法,而不是创建特殊符号函数的通用方法。如果要创建一个可以由 SymPy 所有机制使用的符号函数,您应该子类化 Function 类。

参数:

symfuncstrUndefinedFunction 实例

如果是 str,则使用此名称创建新的 UndefinedFunction。如果 symfunc 是一个未定义的函数,则创建一个具有相同名称和附加的实现函数的新函数。

implementation:可调用对象

可通过 evalf()lambdify 调用数值实现。

返回:

afunc:sympy.FunctionClass 实例

带有附加实现的函数

示例

>>> from sympy.abc import x
>>> from sympy.utilities.lambdify import implemented_function
>>> from sympy import lambdify
>>> f = implemented_function('f', lambda x: x+1)
>>> lam_f = lambdify(x, f(x))
>>> lam_f(4)
5 
sympy.utilities.lambdify.lambdastr(args, expr, printer=None, dummify=None)

返回一个可以评估为 lambda 函数的字符串。

示例

>>> from sympy.abc import x, y, z
>>> from sympy.utilities.lambdify import lambdastr
>>> lambdastr(x, x**2)
'lambda x: (x**2)'
>>> lambdastr((x,y,z), [z,y,x])
'lambda x,y,z: ([z, y, x])' 

尽管元组在 Python 3 中可能不会作为 lambda 的参数出现,lambdastr 将创建一个 lambda 函数,以便展开原始参数,从而可以处理嵌套参数:

>>> lambdastr((x, (y, z)), x + y)
'lambda _0,_1: (lambda x,y,z: (x + y))(_0,_1[0],_1[1])' 
sympy.utilities.lambdify.lambdify(args, expr, modules=None, printer=None, use_imps=True, dummify=False, cse=False, docstring_limit=1000)

将 SymPy 表达式转换为允许快速数值评估的函数。

警告

此函数使用 exec,因此不应在未经过消毒的输入上使用。

自版本 1.7 起已弃用:将 args 参数传递给集合因为集合是无序的。请使用有序可迭代对象如列表或元组。

参数:

args:List[Symbol]

变量或其嵌套表示将传递给函数的参数的嵌套列表。

变量可以是符号、未定义函数或矩阵符号。

>>> from sympy import Eq

>>> from sympy.abc import x, y, z 

变量列表应与将传递给函数的参数结构相匹配。只需将参数如它们将在列表中传递一样包围起来。

要调用类似 f(x) 的函数,然后 [x] 应该是 lambdify 的第一个参数;对于这种情况,也可以使用单个 x

>>> f = lambdify(x, x + 1)

>>> f(1)

2

>>> f = lambdify([x], x + 1)

>>> f(1)

2 

要调用类似 f(x, y) 的函数,然后 [x, y] 将是 lambdify 的第一个参数:

>>> f = lambdify([x, y], x + y)

>>> f(1, 1)

2 

要使用单个 3 元组调用函数如 f((x, y, z)),则 [(x, y, z)] 将是 lambdify 的第一个参数:

>>> f = lambdify([(x, y, z)], Eq(z**2, x**2 + y**2))

>>> f((3, 4, 5))

True 

如果将传递两个参数,并且第一个是标量,但第二个是包含两个参数的元组,则列表中的项应与该结构匹配:

>>> f = lambdify([x, (y, z)], x + y + z)

>>> f(1, (2, 3))

6 

expr:Expr

要评估的表达式、表达式列表或矩阵。

列表可以是嵌套的。如果表达式是列表,则输出也将是列表。

>>> f = lambdify(x, [x, [x + 1, x + 2]])

>>> f(1)

[1, [2, 3]] 

如果是矩阵,则将返回一个数组(用于 NumPy 模块)。

>>> from sympy import Matrix

>>> f = lambdify(x, Matrix([x, x + 1]))

>>> f(1)

[[1]

[2]] 

请注意,此处的参数顺序(变量然后表达式)用于模仿 Python 的lambda关键字。lambdify(x, expr)的工作方式(大致)类似于lambda x: expr(见下文的 How It Works)。

modules : 字符串,可选

指定要使用的数值库。

如果未指定,默认情况下模块为:

  • 如果安装了 SciPy,则为["scipy", "numpy"]
  • 如果仅安装了 NumPy,则为["numpy"]
  • 如果未安装任何一个,则为["math", "mpmath", "sympy"]

换句话说,尽可能地将 SymPy 函数替换为scipynumpy函数(如果可用),或 Python 的标准库mathmpmath函数(否则)。

模块可以是以下类型之一:

  • 字符串"math""mpmath""numpy""numexpr""scipy""sympy""tensorflow""jax"。这使用该模块的相应打印机和命名空间映射。
  • 一个模块(例如,math)。这使用模块的全局命名空间。如果模块是上述已知模块之一,则还将使用相应的打印机和命名空间映射(即modules=numpy相当于modules="numpy")。
  • 一个字典,将 SymPy 函数的名称映射到任意函数(例如,{'sin': custom_sin})。
  • 包含上述参数混合的列表,优先考虑首次出现的条目(例如,要使用 NumPy 模块但使用自定义版本覆盖sin函数,可以使用[{'sin': custom_sin}, 'numpy'])。

dummify : 布尔值,可选

是否将提供的表达式中不是有效 Python 标识符的变量替换为虚拟符号。

这允许像Function('f')(t)这样的未定义函数作为参数提供。默认情况下,仅当它们不是有效的 Python 标识符时,变量才会被 dummy 化。

设置dummify=True以将所有参数替换为虚拟符号(如果args不是字符串),例如,确保参数不重新定义任何内置名称。

cse : 布尔值或可调用对象,可选

当识别和预先计算常见子表达式以便在多次使用之前时,可以更高效地计算大型表达式。然而,找到这些子表达式会使创建‘lambdify’函数变慢。

当设置为True时,使用sympy.simplify.cse,否则(默认情况下),用户可以传递与cse签名匹配的函数。

docstring_limit : 整数或 None

在 lambdify 大型表达式时,lambdify 内部花费的大部分时间都用于生成表达式的字符串表示,以用于返回函数的自动生成文档字符串。对于包含数百个或更多节点的表达式,生成的文档字符串通常变得如此之长和密集,以至于难以阅读。为了减少 lambdify 的运行时间,可以禁用文档字符串内部完整表达式的渲染。

当为 None 时,完整表达式将在文档字符串中呈现。当为 0 或负整数时,文档字符串中会呈现省略号而不是表达式。当为严格正整数时,如果表达式中的节点数超过 docstring_limit,则在文档字符串中呈现省略号,否则正常呈现表达式的字符串表示。默认为 1000

解释

例如,要将 SymPy 表达式 sin(x) + cos(x) 转换为一个等效的 NumPy 函数来进行数值评估:

>>> from sympy import sin, cos, symbols, lambdify
>>> import numpy as np
>>> x = symbols('x')
>>> expr = sin(x) + cos(x)
>>> expr
sin(x) + cos(x)
>>> f = lambdify(x, expr, 'numpy')
>>> a = np.array([1, 2])
>>> f(a)
[1.38177329 0.49315059] 

此函数的主要目的是提供从 SymPy 表达式到数值库(如 NumPy、SciPy、NumExpr、mpmath 和 tensorflow)的桥梁。一般来说,SymPy 函数不适用于来自其他库(如 NumPy 数组)的对象,而来自数值库(如 NumPy 或 mpmath)的函数不适用于 SymPy 表达式。lambdify 通过将 SymPy 表达式转换为等效的数值函数来连接这两者。

使用 lambdify 的基本工作流程是首先创建一个表示您希望评估的任何数学函数的 SymPy 表达式。这应该仅使用 SymPy 函数和表达式来完成。然后,使用 lambdify 将其转换为等效的用于数值评估的函数。例如,我们以上述方法使用 SymPy 符号 x 和 SymPy 函数 sincos 创建了 expr,然后将其转换为等效的 NumPy 函数 f,并在 NumPy 数组 a 上调用它。

示例

>>> from sympy.utilities.lambdify import implemented_function
>>> from sympy import sqrt, sin, Matrix
>>> from sympy import Function
>>> from sympy.abc import w, x, y, z 
>>> f = lambdify(x, x**2)
>>> f(2)
4
>>> f = lambdify((x, y, z), [z, y, x])
>>> f(1,2,3)
[3, 2, 1]
>>> f = lambdify(x, sqrt(x))
>>> f(4)
2.0
>>> f = lambdify((x, y), sin(x*y)**2)
>>> f(0, 5)
0.0
>>> row = lambdify((x, y), Matrix((x, x + y)).T, modules='sympy')
>>> row(1, 2)
Matrix([[1, 3]]) 

lambdify 可以用于将 SymPy 表达式转换为 mpmath 函数。在某些情况下,这可能比使用 evalf 更可取(它在后端使用 mpmath)。

>>> f = lambdify(x, sin(x), 'mpmath')
>>> f(1)
0.8414709848078965 

元组参数将被处理,lambdify 函数应该使用创建函数时使用的相同类型的参数进行调用:

>>> f = lambdify((x, (y, z)), x + y)
>>> f(1, (2, 4))
3 

flatten 函数可用于始终使用展平的参数进行操作:

>>> from sympy.utilities.iterables import flatten
>>> args = w, (x, (y, z))
>>> vals = 1, (2, (3, 4))
>>> f = lambdify(flatten(args), w + x + y + z)
>>> f(*flatten(vals))
10 

expr 中存在的函数也可以携带自己的数值实现,作为附加到 _imp_ 属性的可调用函数。这可以与使用 implemented_function 工厂函数的未定义函数一起使用:

>>> f = implemented_function(Function('f'), lambda x: x+1)
>>> func = lambdify(x, f(x))
>>> func(4)
5 

lambdify 总是优先 _imp_ 命名空间中的实现,而不是其他命名空间中的实现,除非 use_imps 输入参数为 False。

使用 Tensorflow:

>>> import tensorflow as tf
>>> from sympy import Max, sin, lambdify
>>> from sympy.abc import x 
>>> f = Max(x, sin(x))
>>> func = lambdify(x, f, 'tensorflow') 

在 tensorflow v2 之后,默认启用即时执行。如果您想要在 tensorflow v1 和 v2 中获取兼容的结果,就像本教程一样,请运行此行。

>>> tf.compat.v1.enable_eager_execution() 

如果启用了即时执行,您可以立即将结果输出,因为您可以使用 numpy。

如果传递 tensorflow 对象,则可能会得到一个 EagerTensor 对象而不是值。

>>> result = func(tf.constant(1.0))
>>> print(result)
tf.Tensor(1.0, shape=(), dtype=float32)
>>> print(result.__class__)
<class 'tensorflow.python.framework.ops.EagerTensor'> 

您可以使用 .numpy() 来获取张量的 numpy 值。

>>> result.numpy()
1.0 
>>> var = tf.Variable(2.0)
>>> result = func(var) # also works for tf.Variable and tf.Placeholder
>>> result.numpy()
2.0 

它适用于任何形状的数组。

>>> tensor = tf.constant([[1.0, 2.0], [3.0, 4.0]])
>>> result = func(tensor)
>>> result.numpy()
[[1\. 2.]
 [3\. 4.]] 

注意

  • 对于涉及大数组计算的函数,numexpr 可以比 numpy 提供显著的加速。请注意,numexpr 的可用函数比 numpy 有限,但可以通过implemented_function和用户定义的 Function 子类进行扩展。如果指定了,numexpr 可能是模块中唯一的选项。numexpr 的官方函数列表可以在这里找到:numexpr.readthedocs.io/en/latest/user_guide.html#supported-functions

  • 在上述示例中,生成的函数可以接受标量值或 numpy 数组作为参数。但是,在某些情况下,生成的函数依赖于输入是一个 numpy 数组:

    >>> import numpy
    >>> from sympy import Piecewise
    >>> from sympy.testing.pytest import ignore_warnings
    >>> f = lambdify(x, Piecewise((x, x <= 1), (1/x, x > 1)), "numpy") 
    
    >>> with ignore_warnings(RuntimeWarning):
    ...     f(numpy.array([-1, 0, 1, 2]))
    [-1\.   0\.   1\.   0.5] 
    
    >>> f(0)
    Traceback (most recent call last):
      ...
    ZeroDivisionError: division by zero 
    

    在这种情况下,输入应该包装在一个 numpy 数组中:

    >>> with ignore_warnings(RuntimeWarning):
    ...     float(f(numpy.array([0])))
    0.0 
    

    或者如果不需要 numpy 功能,则可以使用另一个模块:

    >>> f = lambdify(x, Piecewise((x, x <= 1), (1/x, x > 1)), "math")
    >>> f(0)
    0 
    

工作原理

当使用此函数时,理解它的工作原理非常有帮助。在核心上,lambdify 只是一个命名空间的转换,在一个特殊的打印机之上,使一些边缘情况正常工作。

要理解lambdify,首先我们必须正确理解 Python 命名空间的工作方式。假设我们有两个文件。一个名为sin_cos_sympy.py,其中包含

# sin_cos_sympy.py

from sympy.functions.elementary.trigonometric import (cos, sin)

def sin_cos(x):
    return sin(x) + cos(x) 

和一个称为sin_cos_numpy.py的文件与

# sin_cos_numpy.py

from numpy import sin, cos

def sin_cos(x):
    return sin(x) + cos(x) 

这两个文件定义了一个相同的函数sin_cos。但是,在第一个文件中,sincos被定义为 SymPy 的sincos。在第二个文件中,它们被定义为 NumPy 的版本。

如果我们导入第一个文件并使用sin_cos函数,我们将得到类似于

>>> from sin_cos_sympy import sin_cos 
>>> sin_cos(1) 
cos(1) + sin(1) 

另一方面,如果我们从第二个文件导入sin_cos,我们将得到

>>> from sin_cos_numpy import sin_cos 
>>> sin_cos(1) 
1.38177329068 

在第一种情况下,我们得到了一个符号输出,因为它使用了 SymPy 的符号sincos函数。在第二种情况下,我们得到了一个数值结果,因为sin_cos使用了 NumPy 的数值sincos函数。但请注意,使用的sincos的版本并不是sin_cos函数定义本身固有的。这两个sin_cos定义是完全相同的。相反,它基于定义sin_cos函数的模块中定义的名称。

这里的关键点是,在 Python 函数中引用一个未在函数中定义的名称时,该名称会在定义该函数的模块的“全局”命名空间中查找。

现在,在 Python 中,我们可以模拟这种行为,而无需实际将文件写入磁盘,使用exec函数。exec接受一个包含 Python 代码块的字符串,并且一个应该包含模块全局变量的字典。然后,它在该字典中“执行”代码,就像它是模块全局变量一样。以下与在sin_cos_sympy.py中定义的sin_cos相同:

>>> import sympy
>>> module_dictionary = {'sin': sympy.sin, 'cos': sympy.cos}
>>> exec('''
... def sin_cos(x):
...     return sin(x) + cos(x)
... ''', module_dictionary)
>>> sin_cos = module_dictionary['sin_cos']
>>> sin_cos(1)
cos(1) + sin(1) 

同样与sin_cos_numpy

>>> import numpy
>>> module_dictionary = {'sin': numpy.sin, 'cos': numpy.cos}
>>> exec('''
... def sin_cos(x):
...     return sin(x) + cos(x)
... ''', module_dictionary)
>>> sin_cos = module_dictionary['sin_cos']
>>> sin_cos(1)
1.38177329068 

现在我们可以了解lambdify的工作原理了。名称lambdify来源于我们可以将类似lambdify(x, sin(x) + cos(x), 'numpy')的东西视为lambda x: sin(x) + cos(x),其中sincos来自numpy命名空间。这也是为什么lambdify中符号参数在第一位,而不是大多数 SymPy 函数中表达式之后的原因:为了更好地模仿lambda关键字。

lambdify接受输入表达式(例如sin(x) + cos(x))并

  1. 将其转换为字符串

  2. 基于传入的模块创建一个模块全局字典(默认情况下使用 NumPy 模块)

  3. 创建字符串"def func({vars}): return {expr}",其中{vars}是以逗号分隔的变量列表,{expr}是步骤 1 中创建的字符串,然后pyexec``s that string with the module globals namespace and returns ``func

实际上,lambdify返回的函数支持检查。因此,您可以使用inspect.getsource或 IPython 或 Jupyter 笔记本中的??来准确查看它们是如何定义的。

>>> f = lambdify(x, sin(x) + cos(x))
>>> import inspect
>>> print(inspect.getsource(f))
def _lambdifygenerated(x):
 return sin(x) + cos(x) 

这向我们展示了函数的源代码,但没有显示它被定义在哪个命名空间。我们可以通过查看f__globals__属性来检查这一点:

>>> f.__globals__['sin']
<ufunc 'sin'>
>>> f.__globals__['cos']
<ufunc 'cos'>
>>> f.__globals__['sin'] is numpy.sin
True 

这向我们展示了f命名空间中的sincos将是numpy.sinnumpy.cos

请注意,每个步骤中都有一些便利层,但在核心部分,lambdify的工作方式就是如此。第 1 步是使用打印模块中定义的LambdaPrinter打印机(参见sympy.printing.lambdarepr)。这允许不同的 SymPy 表达式定义它们应该如何为不同模块转换为字符串。您可以通过向printer参数传递自定义打印机来更改lambdify使用的打印机。

第 2 步通过某些翻译来增强。每个模块都有默认的翻译,但您可以通过将列表传递给modules参数来提供自己的翻译。例如,

>>> def mysin(x):
...     print('taking the sin of', x)
...     return numpy.sin(x)
...
>>> f = lambdify(x, sin(x), [{'sin': mysin}, 'numpy'])
>>> f(1)
taking the sin of 1
0.8414709848078965 

全局字典是通过合并字典{'sin': mysin}和 NumPy 的模块字典生成的。合并是这样做的,早期的项目优先,这就是为什么上面使用mysin而不是numpy.sin的原因。

如果您想修改lambdify处理给定函数的方式,通常最容易的方法是通过修改全局字典来实现。在更复杂的情况下,可能需要创建并传递自定义的打印机。

最后,第 3 步通过某些便利操作进行增强,例如添加文档字符串。

理解lambdify的工作方式可以使在使用它时更容易避免某些陷阱。例如,常见的错误是为一个模块(比如 NumPy)创建一个 lambdified 函数,并将来自另一个模块(例如 SymPy 表达式)的对象传递给它。

例如,假设我们创建

>>> from sympy.abc import x
>>> f = lambdify(x, x + 1, 'numpy') 

现在,如果我们传递一个 NumPy 数组,我们将得到该数组加上 1

>>> import numpy
>>> a = numpy.array([1, 2])
>>> f(a)
[2 3] 

但是,如果您错误地传递 SymPy 表达式而不是 NumPy 数组会发生什么:

>>> f(x + 1)
x + 2 

这种方法确实有效,但只是偶然的。现在我们来看一个不同的 lambdify 函数:

>>> from sympy import sin
>>> g = lambdify(x, x + sin(x), 'numpy') 

在 NumPy 数组上运行如预期:

>>> g(a)
[1.84147098 2.90929743] 

但是如果我们尝试传入一个 SymPy 表达式,它会失败

>>> g(x + 1)
Traceback (most recent call last):
...
TypeError: loop of ufunc does not support argument 0 of type Add which has
 no callable sin method 

现在,让我们看看发生了什么。这种方法失败的原因是 g 在输入表达式上调用了 numpy.sin,而 numpy.sin 不知道如何处理 SymPy 对象。作为一个一般规则,NumPy 函数不知道如何操作 SymPy 表达式,而 SymPy 函数也不知道如何操作 NumPy 数组。这就是为什么 lambdify 存在的原因:它提供了 SymPy 和 NumPy 之间的桥梁。

然而,为什么 f 能够工作呢?那是因为 f 没有调用任何函数,它只是加了 1。因此,所创建的结果函数 def _lambdifygenerated(x): return x + 1 不依赖于它所定义的全局命名空间。因此它能工作,但只是偶然的。未来版本的 lambdify 可能会移除这种行为。

请注意,此处描述的某些实现细节可能会在 SymPy 的未来版本中发生变化。传入自定义模块和打印机的 API 将不会更改,但是创建 Lambda 函数的详细信息可能会发生变化。然而,基本理念将保持不变,并且理解它将有助于理解 lambdify 的行为。

一般而言:您应该为一个模块(比如 NumPy)创建 Lambda 函数,并且只传递与该模块兼容的输入类型(比如 NumPy 数组)。 请记住,默认情况下,如果未提供 module 参数,lambdify 将使用 NumPy 和 SciPy 命名空间创建函数。

Memoization

原文链接:docs.sympy.org/latest/modules/utilities/memoization.html

sympy.utilities.memoization.assoc_recurrence_memo(base_seq)

基于从基础开始的递归定义相关序列的备忘录装饰器

base_seq(n) – 用于获取基础序列元素的可调用函数

XXX 仅适用于 Pn0 = base_seq(0) 情况 XXX 仅适用于 m <= n 情况

sympy.utilities.memoization.recurrence_memo(initial)

基于递归定义的序列的备忘录装饰器

示例

>>> from sympy.utilities.memoization import recurrence_memo
>>> @recurrence_memo([1]) # 0! = 1
... def factorial(n, prev):
...     return n * prev[-1]
>>> factorial(4)
24
>>> factorial(3) # use cache values
6
>>> factorial.cache_length() # cache length can be obtained
5
>>> factorial.fetch_item(slice(2, 4))
[2, 6] 

杂项

原文:docs.sympy.org/latest/modules/utilities/misc.html

不属于其他地方的各种杂项。

sympy.utilities.misc.as_int(n, strict=True)

将参数转换为内置整数。

返回值保证等于输入。如果输入具有非整数值,则引发 ValueError。当strict为 True 时,使用index,当为 False 时使用int

示例

>>> from sympy.utilities.misc import as_int
>>> from sympy import sqrt, S 

该函数主要涉及对需要与内置整数一起工作的函数进行输入清理,因此任何明确为整数的内容应返回为 int:

>>> as_int(S(3))
3 

浮点数由于精度有限,不被假定为精确值,除非strict标志为 False,否则会引发错误。对于大的浮点数,这一精度问题显而易见:

>>> big = 1e23
>>> type(big) is float
True
>>> big == int(big)
True
>>> as_int(big)
Traceback (most recent call last):
...
ValueError: ... is not an integer
>>> as_int(big, strict=False)
99999999999999991611392 

默认情况下也会拒绝可能是整数值的复杂表示形式的输入:

>>> one = sqrt(3 + 2*sqrt(2)) - sqrt(2)
>>> int(one) == 1
True
>>> as_int(one)
Traceback (most recent call last):
...
ValueError: ... is not an integer 
sympy.utilities.misc.debug(*args)

如果 SYMPY_DEBUG 为 True,则打印*args,否则什么都不做。

sympy.utilities.misc.debug_decorator(func)

如果 SYMPY_DEBUG 为 True,则打印带有所有装饰函数的参数和结果的漂亮执行树,否则什么都不做。

sympy.utilities.misc.debugf(string, args)

如果 SYMPY_DEBUG 为 True,则打印string%args,否则什么都不做。这用于使用格式化字符串的调试消息。

sympy.utilities.misc.filldedent(s, w=70, **kwargs)

s的副本中去除前导和尾随空行,然后去除缩进、填充并返回它。

空行剥离用于处理像这样以初始三重引号后紧随换行符开头的文档字符串,将空行插入到字符串开头。

额外的关键字参数将传递给textwrap.fill()

请参见

strlinesrawlines

sympy.utilities.misc.find_executable(executable, path=None)

尝试在‘path’列出的目录中找到‘executable’(由‘os.pathsep’分隔的字符串列出目录;默认为 os.environ[‘PATH’])。返回完整的文件名或如果找不到则返回 None

sympy.utilities.misc.func_name(x, short=False)

返回(x)的函数名称(如果已定义),否则返回(type(x))。如果 short 为 True 且结果有较短的别名,则返回该别名。

示例

>>> from sympy.utilities.misc import func_name
>>> from sympy import Matrix
>>> from sympy.abc import x
>>> func_name(Matrix.eye(3))
'MutableDenseMatrix'
>>> func_name(x < 1)
'StrictLessThan'
>>> func_name(x < 1, short=True)
'Lt' 
sympy.utilities.misc.ordinal(num)

返回 num 的序数字符串,例如 1 变成 1st。

sympy.utilities.misc.rawlines(s)

返回一个可剪切和粘贴的字符串,打印时等同于输入。在字符串中有多行时使用此功能。返回的字符串格式化良好,可以很好地缩进测试中;在某些情况下,它包装在必须从 textwrap 导入的 dedent 函数中。

示例

注意:由于以下示例中的字符需要转义,因为它们本身位于三重引号文档字符串内,所以下面的表达式看起来比在解释器窗口中打印时更复杂。

>>> from sympy.utilities.misc import rawlines
>>> from sympy import TableForm
>>> s = str(TableForm([[1, 10]], headings=(None, ['a', 'bee'])))
>>> print(rawlines(s))
(
 'a bee\n'
 '-----\n'
 '1 10 '
)
>>> print(rawlines('''this
... that'''))
dedent('''\
 this
 that''') 
>>> print(rawlines('''this
... that
... '''))
dedent('''\
 this
 that
 ''') 
>>> s = """this
... is a triple '''
... """
>>> print(rawlines(s))
dedent("""\
 this
 is a triple '''
 """) 
>>> print(rawlines('''this
... that
...     '''))
(
 'this\n'
 'that\n'
 '    '
) 

请参见

filldedentstrlines

sympy.utilities.misc.replace(string, *reps)

返回string,其中所有reps中的键都替换为其对应的值,较长的字符串优先,不考虑它们给定的顺序。reps可以作为元组或单个映射传递。

示例

>>> from sympy.utilities.misc import replace
>>> replace('foo', {'oo': 'ar', 'f': 'b'})
'bar'
>>> replace("spamham sha", ("spam", "eggs"), ("sha","md5"))
'eggsham md5' 

如果映射中的键重叠(即长度相同且开头/结尾有相同序列),不能保证获得唯一答案:

>>> reps = [
...     ('ab', 'x'),
...     ('bc', 'y')]
>>> replace('abc', *reps) in ('xc', 'ay')
True 

参考

[R1073]

stackoverflow.com/questions/6116978/how-to-replace-multiple-substrings-of-a-string

sympy.utilities.misc.strlines(s, c=64, short=False)

返回一个可剪切粘贴的字符串,打印时等效于输入。行将被括在括号中,没有一行会超过 c(默认 64)个字符。如果行包含换行符,则将返回(rawlines)结果。如果short为 True(默认为 False),则如果只有一行,将返回不带边界括号的结果。

示例

>>> from sympy.utilities.misc import strlines
>>> q = 'this is a long string that should be broken into shorter lines'
>>> print(strlines(q, 40))
(
'this is a long string that should be b'
'roken into shorter lines'
)
>>> q == (
... 'this is a long string that should be b'
... 'roken into shorter lines'
... )
True 

另见

filldedent, rawlines

sympy.utilities.misc.translate(s, a, b=None, c=None)

返回s,其中的字符已被替换或删除。

语法

translate(s, None, deletechars):

删除deletechars中的所有字符

translate(s, map [,deletechars]):

如果提供了deletechars,则删除其中的所有字符,然后根据映射定义进行替换;如果映射的键是字符串,则较长的字符串优先处理。多字符删除应该是‘’。

translate(s, oldchars, newchars, deletechars)

删除deletechars中的所有字符,然后用oldchars中的每个字符替换newchars中对应的字符

示例

>>> from sympy.utilities.misc import translate
>>> abc = 'abc'
>>> translate(abc, None, 'a')
'bc'
>>> translate(abc, {'a': 'x'}, 'c')
'xb'
>>> translate(abc, {'abc': 'x', 'a': 'y'})
'x' 
>>> translate('abcd', 'ac', 'AC', 'd')
'AbC' 

如果映射中的键重叠(长度相同且开头/结尾有相同序列),不能保证获得唯一答案:

>>> translate(abc, {'ab': 'x', 'bc': 'y'}) in ('xc', 'ay')
True 

源代码检查

原文:docs.sympy.org/latest/modules/utilities/source.html

该模块为交互式源代码检查添加了几个函数。

sympy.utilities.source.get_class(lookup_view)

将类名的字符串版本转换为对象。

例如,get_class('sympy.core.Basic') 将返回位于 sympy.core 模块中的 Basic 类。

sympy.utilities.source.get_mod_func(callback)

将类的字符串路径分割为模块的字符串路径和类的名称。

示例

>>> from sympy.utilities.source import get_mod_func
>>> get_mod_func('sympy.core.basic.Basic')
('sympy.core.basic', 'Basic') 

时间工具

原文:docs.sympy.org/latest/modules/utilities/timeutils.html

当 IPython 不可用时,用于计时函数执行的简单工具。

sympy.utilities.timeutils.timed(func, setup='pass', limit=None)

自适应地测量函数的执行时间。

交互式

原文链接:docs.sympy.org/latest/modules/interactive.html

用于设置交互式 SymPy 会话的辅助模块。

Session

设置交互式会话的工具。

sympy.interactive.session.enable_automatic_int_sympification(shell)

允许 IPython 自动将整数字面量转换为 Integer。

sympy.interactive.session.enable_automatic_symbols(shell)

允许 IPython 自动创建符号 (isympy -a)。

sympy.interactive.session.init_ipython_session(shell=None, argv=[], auto_symbols=False, auto_int_to_Integer=False)

构建新的 IPython 会话。

sympy.interactive.session.init_python_session()

构建新的 Python 会话。

sympy.interactive.session.init_session(ipython=None, pretty_print=True, order=None, use_unicode=None, use_latex=None, quiet=False, auto_symbols=False, auto_int_to_Integer=False, str_printer=None, pretty_printer=None, latex_printer=None, argv=[])

初始化嵌入式 IPython 或 Python 会话。IPython 会话是通过 --pylab 选项启动的,没有 numpy 导入,以便 matplotlib 绘图可以是交互式的。

参数:

pretty_print: boolean

如果为 True,使用 pretty_print 来转换为字符串;如果为 False,则使用 sstrrepr 来转换为字符串。

order: string or None

对于此参数有几个不同的设置:lex(默认),即词法顺序;grlex,即分级词法顺序;grevlex,即反向分级词法顺序;old,由于兼容性和长表达式而使用;None,将其设置为 lex。

use_unicode: boolean or None

如果为 True,使用 Unicode 字符;如果为 False,则不使用 Unicode 字符。

use_latex: boolean or None

如果为 True,如果 IPython GUI,则使用 LaTeX 渲染;如果为 False,则不使用 LaTeX 渲染。

quiet: boolean

如果为 True,init_session 将不会打印关于其状态的消息;如果为 False,init_session 将打印关于其状态的消息。

auto_symbols: boolean

如果为 True,IPython 将为您自动创建符号。如果为 False,则不会。默认为 False。

auto_int_to_Integer: boolean

如果为 True,IPython 将自动用 Integer 包装 int 字面量,这样像 1/2 这样的内容将给出 Rational(1, 2)。如果为 False,则不会。默认为 False。

ipython: boolean or None

如果为 True,打印将为 IPython 控制台初始化;如果为 False,则打印将为普通控制台初始化;默认值为 None,自动确定是否在 IPython 实例中。

str_printer: function, optional, default=None

自定义字符串打印函数。这应该模仿 sympy.printing.sstrrepr()。

pretty_printer: function, optional, default=None

自定义漂亮打印机。这应该模仿 sympy.printing.pretty()。

latex_printer: function, optional, default=None

自定义的 LaTeX 打印机。这应该模仿 sympy.printing.latex() 这应该模仿 sympy.printing.latex()。

argv: list of arguments for IPython

参见 sympy.bin.isympy,以获取可以用于初始化 IPython 的选项。

举例

>>> from sympy import init_session, Symbol, sin, sqrt
>>> sin(x) 
NameError: name 'x' is not defined
>>> init_session() 
>>> sin(x) 
sin(x)
>>> sqrt(5) 
 ___
\/ 5
>>> init_session(pretty_print=False) 
>>> sqrt(5) 
sqrt(5)
>>> y + x + y**2 + x**2 
x**2 + x + y**2 + y
>>> init_session(order='grlex') 
>>> y + x + y**2 + x**2 
x**2 + y**2 + x + y
>>> init_session(order='grevlex') 
>>> y * x**2 + x * y**2 
x**2*y + x*y**2
>>> init_session(order='old') 
>>> x**2 + y**2 + x + y 
x + y + x**2 + y**2
>>> theta = Symbol('theta') 
>>> theta 
theta
>>> init_session(use_unicode=True) 
>>> theta 
θ 

另请参阅

sympy.interactive.printing.init_printing

举例和其余的参数。

sympy.interactive.session.int_to_Integer(s)

用 Integer 包装整数字面量。

这是基于来自 docs.python.org/3/library/tokenize.html 的 decistmt 示例。

仅转换整数字面量。浮点数字面量保持不变。

Examples

>>> from sympy import Integer # noqa: F401
>>> from sympy.interactive.session import int_to_Integer
>>> s = '1.2 + 1/2 - 0x12 + a1'
>>> int_to_Integer(s)
'1.2 +Integer (1 )/Integer (2 )-Integer (0x12 )+a1 '
>>> s = 'print (1/2)'
>>> int_to_Integer(s)
'print (Integer (1 )/Integer (2 ))'
>>> exec(s)
0.5
>>> exec(int_to_Integer(s))
1/2 
```  ## Printing

用于在交互式会话中设置打印的工具。

```py
sympy.interactive.printing.init_printing(pretty_print=True, order=None, use_unicode=None, use_latex=None, wrap_line=None, num_columns=None, no_global=False, ip=None, euler=False, forecolor=None, backcolor='Transparent', fontsize='10pt', latex_mode='plain', print_builtin=True, str_printer=None, pretty_printer=None, latex_printer=None, scale=1.0, **settings)

根据环境初始化漂亮打印机。

参数:

pretty_print:布尔值,默认为 True

如果为 True,则使用 pretty_print() 来字符串化或提供的漂亮打印机;如果为 False,则使用 sstrrepr() 来字符串化或提供的字符串打印机。

order:字符串或 None,默认为’lex’

有几种不同的参数设置:'lex'(默认),即词法顺序;'grlex',即分级词法顺序;'grevlex',即反向分级词法顺序;'old',用于兼容性和长表达式;None,将其设置为词法顺序。

use_unicode:布尔值或 None,默认为 None

如果为 True,则使用 Unicode 字符;如果为 False,则不使用 Unicode 字符;如果为 None,则根据环境猜测。

use_latex:字符串、布尔值或 None,默认为 None

如果为 True,则在 GUI 界面中使用默认的 LaTeX 渲染(png 和 mathjax);如果为 False,则不使用 LaTeX 渲染;如果为 None,则根据环境猜测;如果为 'png',则启用带有外部 LaTeX 编译器的 LaTeX 渲染,如果外部编译失败,则回退到 matplotlib;如果为 'matplotlib',则使用 matplotlib 启用 LaTeX 渲染;如果为 'mathjax',则启用 LaTeX 文本生成,例如 IPython 笔记本中的 MathJax 渲染或 LaTeX 文档中的文本渲染;如果为 'svg',则使用外部 LaTeX 编译器启用 LaTeX 渲染,无回退。

wrap_line:布尔值

如果为 True,则行末会换行;如果为 False,则不会换行,而是作为一行继续。只有在 pretty_print 为 True 时才相关。

num_columns:整数或 None,默认为 None

如果为 int,则在换行之前的列数设置为 num_columns;如果为 None,则在换行之前的列数设置为终端宽度。只有在 pretty_printTrue 时才相关。

no_global:布尔值,默认为 False

如果为 True,则设置变为系统范围;如果为 False,则仅用于此控制台/会话。

ip:交互式控制台

这可以是 IPython 的实例,也可以是从 code.InteractiveConsole 派生的类。

euler:布尔值,可选,默认为 False

在 LaTeX 前言中加载 euler 包,用于手写风格的字体(www.ctan.org/pkg/euler)。

forecolor:字符串或 None,可选,默认为 None

DVI 前景色设置。None 意味着根据 IPython 终端颜色设置的猜测,将选择 'Black''White''Gray' 中的一种。参见注释。

backcolor:字符串,可选,默认为’Transparent’

DVI 背景色设置。参见注释。

fontsize:字符串或整数,可选,默认为’10pt’

字体大小传递给 LaTeX 文档类函数的前文。请注意,选项受文档类的限制。考虑使用scale替代。

latex_mode:字符串,可选,默认为’plain’

LaTeX 打印机使用的模式。可以是{'inline'|'plain'|'equation'|'equation*'}之一。

print_builtin:布尔值,可选,默认为 True

如果为True,则将打印浮点数和整数。如果为False,则打印机仅打印 SymPy 类型。

str_printer:函数,可选,默认为 None

自定义字符串打印函数。这应该模仿sstrrepr()

pretty_printer:函数,可选,默认为 None

自定义的漂亮打印机。这应该模仿pretty()

latex_printer:函数,可选,默认为 None

自定义的 LaTeX 打印机。这应该模仿latex()

scale:浮点数,可选,默认为 1.0

缩放 LaTeX 输出时使用'png''svg'后端。适用于高分辨率屏幕。

settings:

可以使用latexpretty命令的任何额外设置来微调输出。

示例

>>> from sympy.interactive import init_printing
>>> from sympy import Symbol, sqrt
>>> from sympy.abc import x, y
>>> sqrt(5)
sqrt(5)
>>> init_printing(pretty_print=True) 
>>> sqrt(5) 
 ___
\/ 5
>>> theta = Symbol('theta') 
>>> init_printing(use_unicode=True) 
>>> theta 
\u03b8
>>> init_printing(use_unicode=False) 
>>> theta 
theta
>>> init_printing(order='lex') 
>>> str(y + x + y**2 + x**2) 
x**2 + x + y**2 + y
>>> init_printing(order='grlex') 
>>> str(y + x + y**2 + x**2) 
x**2 + x + y**2 + y
>>> init_printing(order='grevlex') 
>>> str(y * x**2 + x * y**2) 
x**2*y + x*y**2
>>> init_printing(order='old') 
>>> str(x**2 + y**2 + x + y) 
x**2 + x + y**2 + y
>>> init_printing(num_columns=10) 
>>> x**2 + x + y**2 + y 
x + y +
x**2 + y**2 

注释

在使用'png''svg' LaTeX 渲染时可以选择前景和背景颜色。请注意,在执行init_printing命令之前,LaTeX 渲染由 IPython 控制台处理而不是 SymPy。

颜色可以从dvips已知的 68 种标准颜色中选择,列表请参见[R596]。此外,背景颜色可以设置为'透明'(默认值)。

在使用'Auto'前景色时,猜测基于 IPython 控制台中的colors变量,请参见[R597]。因此,如果在您的 IPython 控制台中正确设置了该变量,则输出可读性较高,尽管可能需要手动设置。

另请参阅

sympy.printing.latexsympy.printing.pretty

参考文献

[R596] (1,2)

en.wikibooks.org/wiki/LaTeX/Colors#The_68_standard_colors_known_to_dvips

[R597] (1,2)

ipython.readthedocs.io/en/stable/config/details.html#terminal-colors

解析

原文:docs.sympy.org/latest/modules/parsing.html

解析函数参考

sympy.parsing.sympy_parser.parse_expr(s: str, local_dict: ~typing.Dict[str, ~typing.Any] | None = None, transformations: ~typing.Tuple[~typing.Callable[[~typing.List[~typing.Tuple[int, str]], ~typing.Dict[str, ~typing.Any], ~typing.Dict[str, ~typing.Any]], ~typing.List[~typing.Tuple[int, str]]], ...] | str = (<function lambda_notation>, <function auto_symbol>, <function repeated_decimals>, <function auto_number>, <function factorial_notation>), global_dict: ~typing.Dict[str, ~typing.Any] | None = None, evaluate=True)

将字符串s转换为 SymPy 表达式,在local_dict中。

参数:

s : str

要解析的字符串。

local_dict : dict, optional

用于解析时使用的局部变量字典。

global_dict : dict, optional

全局变量的字典。默认情况下,这是通过from sympy import *初始化的;提供此参数以覆盖此行为(例如,解析"Q & S")。

transformations : tuple or str

用于修改解析表达式中的令牌以进行评估之前的转换函数元组。默认转换将数值文字转换为它们的 SymPy 等效项,将未定义的变量转换为 SymPy 符号,并允许使用标准数学阶乘符号表示法(例如,x!)。可以通过字符串选择(请参见下文)。

evaluate : bool, optional

当设置为 False 时,参数的顺序将保持在字符串中的原样,并且将抑制通常会发生的自动简化。(参见示例)

示例

>>> from sympy.parsing.sympy_parser import parse_expr
>>> parse_expr("1/2")
1/2
>>> type(_)
<class 'sympy.core.numbers.Half'>
>>> from sympy.parsing.sympy_parser import standard_transformations,\
... implicit_multiplication_application
>>> transformations = (standard_transformations +
...     (implicit_multiplication_application,))
>>> parse_expr("2x", transformations=transformations)
2*x 

当 evaluate=False 时,某些自动简化将不会发生:

>>> parse_expr("2**3"), parse_expr("2**3", evaluate=False)
(8, 2**3) 

此外,参数的顺序不会变得规范化。此功能允许精确了解表达式的输入方式:

>>> a = parse_expr('1 + x', evaluate=False)
>>> b = parse_expr('x + 1', evaluate=0)
>>> a == b
False
>>> a.args
(1, x)
>>> b.args
(x, 1) 

注意,但是,当打印这些表达式时,它们看起来将是相同的:

>>> assert str(a) == str(b) 

作为便利,可以通过打印transformations查看转换:

>>> from sympy.parsing.sympy_parser import transformations 
>>> print(transformations)
0: lambda_notation
1: auto_symbol
2: repeated_decimals
3: auto_number
4: factorial_notation
5: implicit_multiplication_application
6: convert_xor
7: implicit_application
8: implicit_multiplication
9: convert_equals_signs
10: function_exponentiation
11: rationalize 

T对象提供了一种选择这些转换的方法:

>>> from sympy.parsing.sympy_parser import T 

如果打印它,您将看到与上面显示的相同列表。

>>> str(T) == str(transformations)
True 

标准切片将返回转换的元组:

>>> T[:5] == standard_transformations
True 

因此,T可用于指定解析转换:

>>> parse_expr("2x", transformations=T[:5])
Traceback (most recent call last):
...
SyntaxError: invalid syntax
>>> parse_expr("2x", transformations=T[:6])
2*x
>>> parse_expr('.3', transformations=T[3, 11])
3/10
>>> parse_expr('.3x', transformations=T[:])
3*x/10 

进一步方便起见,可以使用字符串'implicit'和'all'来选择 0-5 个和所有转换,分别。

>>> parse_expr('.3x', transformations='all')
3*x/10 

另请参阅

stringify_expr, eval_expr, standard_transformations, implicit_multiplication_application

sympy.parsing.sympy_parser.stringify_expr(s: str, local_dict: Dict[str, Any], global_dict: Dict[str, Any], transformations: Tuple[Callable[[List[Tuple[int, str]], Dict[str, Any], Dict[str, Any]], List[Tuple[int, str]]], ...]) → str

将字符串s转换为 Python 代码,在local_dict

通常应使用parse_expr

sympy.parsing.sympy_parser.eval_expr(code, local_dict: Dict[str, Any], global_dict: Dict[str, Any])

评估由stringify_expr生成的 Python 代码。

通常应使用parse_expr

sympy.parsing.maxima.parse_maxima(str, globals=None, name_dict={})
sympy.parsing.mathematica.parse_mathematica(s)

将包含 Wolfram Mathematica 表达式的字符串转换为 SymPy 表达式。

如果转换器无法找到合适的 SymPy 表达式,则将输出 Mathematica 表达式的FullForm,使用 SymPy Function 对象作为语法树的节点。

示例

>>> from sympy.parsing.mathematica import parse_mathematica
>>> parse_mathematica("Sin[x]² Tan[y]")
sin(x)**2*tan(y)
>>> e = parse_mathematica("F[7,5,3]")
>>> e
F(7, 5, 3)
>>> from sympy import Function, Max, Min
>>> e.replace(Function("F"), lambda *x: Max(*x)*Min(*x))
21 

支持标准输入形式和 Mathematica 完整形式:

>>> parse_mathematica("x*(a + b)")
x*(a + b)
>>> parse_mathematica("Times[x, Plus[a, b]]")
x*(a + b) 

从 Wolfram 的代码中获取矩阵:

>>> m = parse_mathematica("{{a, b}, {c, d}}")
>>> m
((a, b), (c, d))
>>> from sympy import Matrix
>>> Matrix(m)
Matrix([
[a, b],
[c, d]]) 

如果翻译成相应的 SymPy 表达式失败,则将创建一个类似于 Wolfram Mathematica 的“FullForm”的 SymPy 表达式:

>>> parse_mathematica("x_.")
Optional(Pattern(x, Blank()))
>>> parse_mathematica("Plus @@ {x, y, z}")
Apply(Plus, (x, y, z))
>>> parse_mathematica("f[x_, 3] := x³ /; x > 0")
SetDelayed(f(Pattern(x, Blank()), 3), Condition(x**3, x > 0)) 

解析转换参考

转换是一个接受参数tokens, local_dict, global_dict的函数,返回一个转换后的令牌列表。它们可以通过将函数列表传递给parse_expr()来使用,并按给定顺序应用。

sympy.parsing.sympy_parser.standard_transformations: Tuple[Callable[[List[Tuple[int, str]], Dict[str, Any], Dict[str, Any]], List[Tuple[int, str]]], ...] = (<function lambda_notation>, <function auto_symbol>, <function repeated_decimals>, <function auto_number>, <function factorial_notation>)

parse_expr()的标准转换。插入对SymbolInteger和其他 SymPy 数据类型的调用,并允许使用标准阶乘符号(例如x!)。

sympy.parsing.sympy_parser.split_symbols(tokens: List[Tuple[int, str]], local_dict: Dict[str, Any], global_dict: Dict[str, Any])

为隐式乘法分割符号名称。

旨在使表达式如xyz被解析为x*y*z。不会分割希腊字符名称,因此theta不会变成t*h*e*t*a。通常与implicit_multiplication一起使用。

sympy.parsing.sympy_parser.split_symbols_custom(predicate: Callable[[str], bool])

创建一个能分割符号名称的转换。

如果符号名称应分割,则predicate应返回 True。

例如,为保留默认行为但避免分割某些符号名称,可以使用类似这样的谓词:

>>> from sympy.parsing.sympy_parser import (parse_expr, _token_splittable,
... standard_transformations, implicit_multiplication,
... split_symbols_custom)
>>> def can_split(symbol):
...     if symbol not in ('list', 'of', 'unsplittable', 'names'):
...             return _token_splittable(symbol)
...     return False
...
>>> transformation = split_symbols_custom(can_split)
>>> parse_expr('unsplittable', transformations=standard_transformations +
... (transformation, implicit_multiplication))
unsplittable 
sympy.parsing.sympy_parser.implicit_multiplication(tokens: List[Tuple[int, str]], local_dict: Dict[str, Any], global_dict: Dict[str, Any]) → List[Tuple[int, str]]

在大多数情况下使乘法运算符可选。

implicit_application()之前使用此转换,否则类似sin 2x的表达式将被解析为x * sin(2)而不是sin(2*x)

示例

>>> from sympy.parsing.sympy_parser import (parse_expr,
... standard_transformations, implicit_multiplication)
>>> transformations = standard_transformations + (implicit_multiplication,)
>>> parse_expr('3 x y', transformations=transformations)
3*x*y 
sympy.parsing.sympy_parser.implicit_application(tokens: List[Tuple[int, str]], local_dict: Dict[str, Any], global_dict: Dict[str, Any]) → List[Tuple[int, str]]

在某些情况下使括号对函数调用可选。

implicit_multiplication()之后使用此转换,否则类似sin 2x的表达式将被解析为x * sin(2)而不是sin(2*x)

示例

>>> from sympy.parsing.sympy_parser import (parse_expr,
... standard_transformations, implicit_application)
>>> transformations = standard_transformations + (implicit_application,)
>>> parse_expr('cot z + csc z', transformations=transformations)
cot(z) + csc(z) 
sympy.parsing.sympy_parser.function_exponentiation(tokens: List[Tuple[int, str]], local_dict: Dict[str, Any], global_dict: Dict[str, Any])

允许对函数进行指数化,例如cos**2(x)

示例

>>> from sympy.parsing.sympy_parser import (parse_expr,
... standard_transformations, function_exponentiation)
>>> transformations = standard_transformations + (function_exponentiation,)
>>> parse_expr('sin**4(x)', transformations=transformations)
sin(x)**4 
sympy.parsing.sympy_parser.implicit_multiplication_application(result: List[Tuple[int, str]], local_dict: Dict[str, Any], global_dict: Dict[str, Any]) → List[Tuple[int, str]]

允许稍微宽松的语法。

  • 对单参数方法调用的括号是可选的。

  • 乘法是隐式的。

  • 符号名称可以被分割(即符号之间不需要空格)。

  • 函数可以被指数化。

示例

>>> from sympy.parsing.sympy_parser import (parse_expr,
... standard_transformations, implicit_multiplication_application)
>>> parse_expr("10sin**2 x**2 + 3xyz + tan theta",
... transformations=(standard_transformations +
... (implicit_multiplication_application,)))
3*x*y*z + 10*sin(x**2)**2 + tan(theta) 
sympy.parsing.sympy_parser.rationalize(tokens: List[Tuple[int, str]], local_dict: Dict[str, Any], global_dict: Dict[str, Any])

将浮点数转换为Rational。在auto_number之后运行。

sympy.parsing.sympy_parser.convert_xor(tokens: List[Tuple[int, str]], local_dict: Dict[str, Any], global_dict: Dict[str, Any])

将 XOR ^视为指数运算**

这些包含在sympy.parsing.sympy_parser.standard_transformations中,通常不需要用户手动添加。

sympy.parsing.sympy_parser.lambda_notation(tokens: List[Tuple[int, str]], local_dict: Dict[str, Any], global_dict: Dict[str, Any])

将“lambda”替换为其 SymPy 等效的 Lambda()。但是,如果仅传递“lambda”,则不会进行转换,因为那是语法错误。

sympy.parsing.sympy_parser.auto_symbol(tokens: List[Tuple[int, str]], local_dict: Dict[str, Any], global_dict: Dict[str, Any])

插入对未定义变量的Symbol/Function调用。

sympy.parsing.sympy_parser.repeated_decimals(tokens: List[Tuple[int, str]], local_dict: Dict[str, Any], global_dict: Dict[str, Any])

允许 0.2[1]表示重复的十进制数 0.2111...(19/90)。

auto_number之前运行。

sympy.parsing.sympy_parser.auto_number(tokens: List[Tuple[int, str]], local_dict: Dict[str, Any], global_dict: Dict[str, Any])

将数值文字转换为 SymPy 的等价物。

复数使用 I,整数文字使用 Integer,浮点文字使用 Float

sympy.parsing.sympy_parser.factorial_notation(tokens: List[Tuple[int, str]], local_dict: Dict[str, Any], global_dict: Dict[str, Any])

允许阶乘的标准表示法。

实验性的 (\mathrm{\LaTeX}) 解析

当前实现是实验性的。行为、解析器后端和 API 可能会在未来发生变化。与其他一些解析器不同,(\mathrm{\LaTeX}) 设计为排版语言,而不是计算代数系统,因此可能包含可被多种方式解释的排版约定。

(\mathrm{\LaTeX}) 解析函数参考

sympy.parsing.latex.parse_latex(s, strict=False, backend='antlr')

将输入的 LaTeX 字符串 s 转换为 SymPy 的 Expr

参数:

s:str

要解析的 LaTeX 字符串。在包含 LaTeX 的 Python 源代码中,推荐使用原始字符串(用r"表示,像这样),因为 LaTeX 大量使用\字符,这会触发正常 Python 字符串中的转义。

后端:str,可选

目前支持两种后端:ANTLR 和 Lark。默认设置为使用 ANTLR 后端,可以根据需要更改为 Lark。

使用 backend="antlr" 选择基于 ANTLR 的解析器,使用 backend="lark" 选择基于 Lark 的解析器。

backend 选项区分大小写,必须全部小写。

严格模式:bool,可选

此选项仅在 ANTLR 后端可用。

如果为 True,如果字符串无法解析为有效的 LaTeX,则引发异常。如果为 False,则尝试从常见错误中恢复。

示例

>>> from sympy.parsing.latex import parse_latex
>>> expr = parse_latex(r"\frac {1 + \sqrt {\a}} {\b}")
>>> expr
(sqrt(a) + 1)/b
>>> expr.evalf(4, subs=dict(a=5, b=2))
1.618
>>> func = parse_latex(r"\int_1^\alpha \dfrac{\mathrm{d}t}{t}", backend="lark")
>>> func.evalf(subs={"alpha": 2})
0.693147180559945 

ANTLR 后端

基于 ANTLR 的 (\mathrm{\LaTeX}) 解析器是从latex2sympy移植过来的。虽然功能齐备,其 API 应保持稳定,但解析行为或后端可能会在未来版本中更改。

ANTLR (\mathrm{\LaTeX}) 解析器注意事项

在当前定义中,解析器可能无法完全解析表达式,但不会发出警告:

parse_latex(r'x -') 

简单地找到 x。这种行为的覆盖范围几乎肯定会在版本之间发生变化,并变得更严格、更宽松或者两者兼而有之。

Lark 后端

基于 Lark 的 LaTeX 解析器是更新的,旨在最终完全取代基于 ANTLR 的解析器。它具有大多数基于 ANTLR 的解析器提供的功能,并添加了一些额外功能。

Lark (\mathrm{\LaTeX}) 解析器特性

值得注意的是,Lark 后端不支持格式不正确的表达式,并且不会尝试修复任何可能发生的常见错误。例如,如在前一节中提到的,ANTLR 基础的解析器将简单地找到 x 如果我们运行:

parse_latex(r'x -', backend='ANTLR') 

然而,运行:

parse_latex(r'x -', backend='Lark') 

将引发一个 lark.exceptions.UnexpectedEOF 异常。

除此之外,Lark 基础的解析器支持一些 ANTLR 基础的解析器不支持的额外功能。它们包括:

  1. 检测模棱两可的表达式,以及

  2. 允许在运行时定制 LaTeX 语法。

像 (f(x)) 这样的表达式在技术上是模棱两可的 (\mathrm{\LaTeX}) 表达式,因为 (f) 可能是一个函数或变量名。Lark 具有指出这些模棱两可性并通知用户的能力,甚至可以返回所有可能的解释。

基于 Lark 的解析器公开了多个内部功能,允许用户自定义解析器的行为。例如,用户可以在实例化解析器时通过传递语法文件的路径来指定自己的 (\mathrm{\LaTeX}) 语法。

用户还可以为 LarkLaTeXParser 类指定自定义的转换器类。

上述两个示例可以在 test_custom_latex.py 文件中找到。

Lark (\mathrm{\LaTeX}) 解析器的能力

为了使用基于 Lark 的 LaTeX 解析器,了解它能做什么和不能做什么是非常重要的。由于解析器仍处于实验阶段,它支持许多功能,但某些功能仍然只部分实现或者不可用。

因此,我们将列出它能解析的表达式类型,然后列出一些可能失败的表达式类型。

这里是支持的事物列表:

  • 单个字母符号,例如 a, b, x 等。希腊符号和带下标的符号也被支持。数字也被支持,以及 \infty

  • 支持多个字母符号,只要它们包含在 \mathit 中。

  • 包括 (+), (-), (*), (/) 和 \cdot, \times, \div 等替代运算符的表达式。如果两个表达式挨在一起,例如 (xy) 或者 ((\sin x)(\cos t)),则被视为隐式乘法。

  • 关系运算符 (<), (>), (\le), (\ge), (=), 和 (\ne).

  • 常用的函数如

    • 平方根,
    • 阶乘,
    • 复共轭(例如 (\overline{z}))
    • (\log),
    • (\ln),
    • (\exp),
    • 绝对值(例如 (|x|))。注意 (||x||) 被解析为 Abs(Abs(x))
    • floor(例如 (\lfloor x \rfloor))和 ceiling(例如 (\lceil x \rceil))函数,
    • (\min) 和 (\max) 函数。
  • 所有三角函数及其反三角函数。支持类似 \sin⁴ 的幂运算。幂 (-1) 被解释为反函数(例如 \sin^{-1} x 被解释为 \arcsin x)。

  • 双曲三角函数(目前仅有 (\sinh), (\cosh), 和 (\tanh))及其反函数。如前所述,支持类似 \tanh² 的幂运算,且 (-1) 被解释为反函数(例如 \tanh^{-1} x 被解释为 \arctanh x)。

  • AppliedFunctions,例如 (f(x, y, z)).

  • 所有类型的分数(\frac, \tfrac, \dfrac, \nicefrac)和二项式(\binom, \tbinom, \dbinom)都被支持。

  • 定积分和不定积分。当被积函数是分数时,允许分母中有微分项。微分符号可以是d\text{d}\mathrm{d}

  • 单变量的导数。例如,(\dfrac{d}{dx} (\sin x))。高阶导数和偏导数目前尚不支持。

  • 单变量的极限。例如,(\lim\limits_{t\to 3^{+}} \sin t)。

  • 简单条件下的求和与乘积。例如,允许(\sum\limits_{k=0}^n k²),因为(k)的条件简单。类似(\sum\limits_{d \mid n} d²)的表达式不允许,因为下标(d)的条件复杂。指数变量在上标中指定的表达式也是允许的。例如,(\prod\limits_{k=0}^{k=n} k²)可以被正确解析。

  • Bra(例如,(| x \rangle)),以及 Ket(例如,(\langle p |))符号。解析内积(例如,(\langle x | y \rangle))和外积(例如,( | y \rangle \langle x |))也受支持。

这是当前不支持但可能在未来添加的事物的(不完整)列表:

  • 矩阵。如\begin{env}...\end{env},其中env可以是matrixbmatrixpmatrixsmallmatrixarray之一。

  • 矩阵操作,如矩阵加法、标量与矩阵乘法、矩阵与矩阵乘法。

  • 高阶导数和偏导数。

  • 双重和三重积分。

Lark((\mathrm{\LaTeX})解析器函数)

sympy.parsing.latex.parse_latex_lark(s: str)

使用 Lark 的实验性(\mathrm{\LaTeX})解析器。

此函数仍在开发中,其 API 可能会在未来的 SymPy 版本中更改。

Lark (\mathrm{\LaTeX})解析器类

class sympy.parsing.latex.lark.LarkLaTeXParser(print_debug_output=False, transform=True, grammar_file=None, transformer=None)

用于将输入的(\mathrm{\LaTeX})字符串转换为 SymPy 表达式的类。它包含进行此操作所需的所有内部数据,并公开了用于自定义其行为的挂钩。

参数:

print_debug_output:布尔值,可选

如果设置为True,将调试输出打印到日志记录器。默认为False

transform:布尔值,可选

如果设置为True,该类将在输入字符串上运行Lark.parse生成的解析树上运行 Transformer 类。默认为True

将其设置为False可以帮助调试(\mathrm{\LaTeX})语法。

grammar_file:字符串,可选

解析器应使用的语法文件路径。如果设置为None,将使用默认语法,位于grammar/latex.lark,相对于sympy/parsing/latex/lark/目录。

transformer:字符串,可选

用于指定要使用的 Transformer 类的名称。如果设置为None,将使用默认的 Transformer 类,即TransformToSymPyExpr()

class sympy.parsing.latex.lark.TransformToSymPyExpr

返回通过遍历传递给.transform()函数的lark.Tree生成的 SymPy 表达式。

参数:

visit_tokens:布尔值,可选

有关此选项的详细信息,请参见这里

请注意,选项必须设置为True才能使默认解析器工作。

注意事项

这个类不应该直接使用。

为了调整此类的行为,必须对其进行子类化,然后在完成所需修改后,通过使用构造函数中的transformer参数将新类的名称传递给LarkLaTeXParser类。

(\mathrm{\LaTeX})解析异常参考

class sympy.parsing.latex.LaTeXParsingError

SymPy 表达式参考

class sympy.parsing.sym_expr.SymPyExpression(source_code=None, mode=None)

用于存储和处理 SymPy 表达式的类

此类将保存 SymPy 表达式并处理其 API,以便进行不同语言的转换。

它与 C 和 Fortran 解析器一起工作,生成存储在此处的 SymPy 表达式,并且可以转换为多种语言的源代码。

注意事项

此模块及其 API 目前正在开发和试验阶段,可能在开发过程中进行更改。

Fortran 解析器不支持数字赋值,因此所有变量都已初始化为零。

此模块还依赖于外部依赖项:

  • LFortran 是使用 Fortran 解析器所必需的

  • C 解析器所需的 Clang

示例

解析 C 代码示例:

>>> from sympy.parsing.sym_expr import SymPyExpression
>>> src = '''
... int a,b;
... float c = 2, d =4;
... '''
>>> a = SymPyExpression(src, 'c')
>>> a.return_expr()
[Declaration(Variable(a, type=intc)),
Declaration(Variable(b, type=intc)),
Declaration(Variable(c, type=float32, value=2.0)),
Declaration(Variable(d, type=float32, value=4.0))] 

变量定义示例:

>>> from sympy.parsing.sym_expr import SymPyExpression
>>> src2 = '''
... integer :: a, b, c, d
... real :: p, q, r, s
... '''
>>> p = SymPyExpression()
>>> p.convert_to_expr(src2, 'f')
>>> p.convert_to_c()
['int a = 0', 'int b = 0', 'int c = 0', 'int d = 0', 'double p = 0.0', 'double q = 0.0', 'double r = 0.0', 'double s = 0.0'] 

分配示例:

>>> from sympy.parsing.sym_expr import SymPyExpression
>>> src3 = '''
... integer :: a, b, c, d, e
... d = a + b - c
... e = b * d + c * e / a
... '''
>>> p = SymPyExpression(src3, 'f')
>>> p.convert_to_python()
['a = 0', 'b = 0', 'c = 0', 'd = 0', 'e = 0', 'd = a + b - c', 'e = b*d + c*e/a'] 

函数定义示例:

>>> from sympy.parsing.sym_expr import SymPyExpression
>>> src = '''
... integer function f(a,b)
... integer, intent(in) :: a, b
... integer :: r
... end function
... '''
>>> a = SymPyExpression(src, 'f')
>>> a.convert_to_python()
['def f(a, b):\n   f = 0\n    r = 0\n    return f'] 
convert_to_c()

返回包含 SymPy 表达式的 C 源代码列表

示例

>>> from sympy.parsing.sym_expr import SymPyExpression
>>> src2 = '''
... integer :: a, b, c, d
... real :: p, q, r, s
... c = a/b
... d = c/a
... s = p/q
... r = q/p
... '''
>>> p = SymPyExpression()
>>> p.convert_to_expr(src2, 'f')
>>> p.convert_to_c()
['int a = 0', 'int b = 0', 'int c = 0', 'int d = 0', 'double p = 0.0', 'double q = 0.0', 'double r = 0.0', 'double s = 0.0', 'c = a/b;', 'd = c/a;', 's = p/q;', 'r = q/p;'] 
convert_to_expr(src_code, mode)

将给定的源代码转换为 SymPy 表达式

示例

>>> from sympy.parsing.sym_expr import SymPyExpression
>>> src3 = '''
... integer function f(a,b) result(r)
... integer, intent(in) :: a, b
... integer :: x
... r = a + b -x
... end function
... '''
>>> p = SymPyExpression()
>>> p.convert_to_expr(src3, 'f')
>>> p.return_expr()
[FunctionDefinition(integer, name=f, parameters=(Variable(a), Variable(b)), body=CodeBlock(
Declaration(Variable(r, type=integer, value=0)),
Declaration(Variable(x, type=integer, value=0)),
Assignment(Variable(r), a + b - x),
Return(Variable(r))
))] 

属性

src_code(String) 要转换的源代码或源代码的文件名
mode: String用于根据源代码的语言确定要使用的解析器的模式,f 或 F 用于 Fortran,c 或 C 用于 C/C++
convert_to_fortran()

返回包含 SymPy 表达式的 Fortran 源代码列表

示例

>>> from sympy.parsing.sym_expr import SymPyExpression
>>> src2 = '''
... integer :: a, b, c, d
... real :: p, q, r, s
... c = a/b
... d = c/a
... s = p/q
... r = q/p
... '''
>>> p = SymPyExpression(src2, 'f')
>>> p.convert_to_fortran()
['      integer*4 a', '      integer*4 b', '      integer*4 c', '      integer*4 d', '      real*8 p', '      real*8 q', '      real*8 r', '      real*8 s', '      c = a/b', '      d = c/a', '      s = p/q', '      r = q/p'] 
convert_to_python()

返回包含 SymPy 表达式的 Python 代码列表

示例

>>> from sympy.parsing.sym_expr import SymPyExpression
>>> src2 = '''
... integer :: a, b, c, d
... real :: p, q, r, s
... c = a/b
... d = c/a
... s = p/q
... r = q/p
... '''
>>> p = SymPyExpression(src2, 'f')
>>> p.convert_to_python()
['a = 0', 'b = 0', 'c = 0', 'd = 0', 'p = 0.0', 'q = 0.0', 'r = 0.0', 's = 0.0', 'c = a/b', 'd = c/a', 's = p/q', 'r = q/p'] 
return_expr()

返回表达式列表

示例

>>> from sympy.parsing.sym_expr import SymPyExpression
>>> src3 = '''
... integer function f(a,b)
... integer, intent(in) :: a, b
... integer :: r
... r = a+b
... f = r
... end function
... '''
>>> p = SymPyExpression()
>>> p.convert_to_expr(src3, 'f')
>>> p.return_expr()
[FunctionDefinition(integer, name=f, parameters=(Variable(a), Variable(b)), body=CodeBlock(
Declaration(Variable(f, type=integer, value=0)),
Declaration(Variable(r, type=integer, value=0)),
Assignment(Variable(f), Variable(r)),
Return(Variable(f))
))] 

运行时安装

当前打包的 LaTeX 解析器后端部分由ANTLR4生成,但是为了使用解析器,您只需要安装antlr4 Python 软件包即可。

根据您的包管理器,例如pip,您可以安装正确的软件包:

$ pip install antlr4-python3-runtime==4.11 

或者conda

$ conda install -c conda-forge antlr-python-runtime==4.11 

C 解析器依赖于clang,Fortran 解析器依赖于LFortran。您可以使用以下命令安装这些软件包:

$ conda install -c conda-forge lfortran clang