SymPy-1-13-中文文档-二十一-
SymPy 1.13 中文文档(二十一)
Codegen
此模块提供功能,可以从 SymPy 表达式直接生成可编译的代码。codegen
函数是 SymPy 中代码生成功能的用户界面。以下是实现的一些细节,供希望直接使用该框架的高级用户参考。
注意
codegen
可调用项不会自动位于 sympy 命名空间中,要使用它,您必须先执行
>>> from sympy.utilities.codegen import codegen
实现细节
在此,我们介绍了内部结构的最重要部分,因为高级用户可能希望直接使用它,例如通过为专业应用程序的代码生成器创建子类。很可能您更喜欢使用上面记录的 codegen()函数。
基本假设:
-
通用的 Routine 数据结构描述了必须转换为 C/Fortran/...代码的例程。此数据结构涵盖了一个或多个支持语言中存在的所有特性。
-
CodeGen 类的后代将多个 Routine 实例转换为可编译的代码。每个派生类将其转换为特定语言。
-
在许多情况下,人们希望有一个简单的工作流程。最后部分的友好功能是 Routine/CodeGen 的简单 API。它们使用起来更简单,但功能较弱。
Routine
Routine
类是 codegen 模块非常重要的一部分。将 codegen 实用程序视为将数学表达式转换为编程语言中的一组语句的翻译器,Routine
实例负责提取和存储关于如何将数学内容封装为函数调用的信息。因此,是Routine
构造函数决定例程将需要什么参数,以及是否应该有返回值。
API 参考
用于生成评估 SymPy 表达式的 C、C++、Fortran77、Fortran90、Julia、Rust 和 Octave/Matlab 例程的模块。该模块正在开发中。下面列表中带有‘+’字符的里程碑已经完成。
— sympy.utilities.codegen 与 sympy.printing.ccode 有何不同?—
我们考虑了扩展 SymPy 函数的打印例程的想法,使其打印完整的可编译代码,但这导致了一些无法克服的问题,只能用专用代码生成器来解决:
-
对于 C 语言,需要同时有代码文件和头文件,而打印例程只生成一个字符串。这个代码生成器可以扩展为支持.pyf 文件用于 f2py。
-
SymPy 函数不涉及编程技术问题,如输入、输出和输入-输出参数。其他示例是连续或非连续的数组,包括其他库的头文件,如 gsl 或其他库。
-
在一个 C 例程中评估多个 SymPy 函数非常有趣,最终可以借助 cse 例程共享共同的中间结果。这不仅仅是打印。
-
从编程角度来看,应尽可能在代码生成器中评估带有常量的表达式。这在打印时是不同的。
— 基本假设 —
-
通用的 Routine 数据结构描述了必须转换为 C/Fortran/… 代码的例程。此数据结构涵盖了所有支持语言中的一个或多个特性。
-
派生自 CodeGen 类的后代将多个 Routine 实例转换为可编译代码。每个派生类都会翻译成特定语言。
-
在许多情况下,人们希望有一个简单的工作流程。最后部分的友好函数是 Routine/CodeGen 系统之上的简单 API。它们更易于使用,但功能较弱。
— 里程碑 —
-
第一个工作版本使用标量输入参数,生成 C 代码和测试。
-
友好函数,比严格的 Routine/CodeGen 工作流程更易于使用。
-
整数和实数作为输入和输出
-
输出参数
-
输入输出参数
-
适当排序输入/输出参数
-
连续数组参数(numpy 矩阵)
-
同时生成 .pyf 代码以供 f2py 使用(在 autowrap 模块中)
-
孤立常量并在双精度中预先评估它们
-
Fortran 90
-
Octave/Matlab
-
公共子表达式消除
-
在生成的代码中用户定义的注释
-
可选的额外包含用于评估特殊函数的库/对象的行
-
测试其他 C 编译器和库:gcc、tcc、libtcc、gcc+gsl 等
-
连续数组参数(SymPy 矩阵)
-
非连续数组参数(SymPy 矩阵)
-
ccode 在遇到无法转换为 C 代码的情况时必须引发错误。
ccode(integrate(sin(x)/x, x))
没有意义。 -
复数作为输入和输出
-
默认的复杂数据类型
-
在头文件中包含额外信息:日期、用户、主机名、sha1 哈希等
-
Fortran 77
-
C++
-
Python
-
Julia
-
Rust
-
…
class sympy.utilities.codegen.Argument(name, datatype=None, dimensions=None, precision=None)
抽象的 Argument 数据结构:名称和数据类型。
此结构在下面的后代中得到细化。
class sympy.utilities.codegen.CCodeGen(project='project', printer=None, preprocessor_statements=None, cse=False)
C 代码生成器。
.write()
方法从 CodeGen 继承,将输出一个代码文件和一个接口文件,分别为 <prefix>.c
和 <prefix>.h
。
dump_c(routines, f, prefix, header=True, empty=True)
通过调用特定于语言的方法编写代码。
生成的文件包含低级代码中所有例程的定义,并在适当时引用头文件。
参数:
routines : 列表
一个 Routine 实例列表。
f : 类文件对象
文件写入位置。
prefix : 字符串
文件名前缀,用于引用正确的头文件。仅使用前缀的基本名称。
header : 布尔型,可选
当为 True 时,将在每个源文件顶部包含一个头注释。[默认值:True]
empty : 布尔型,可选
当为 True 时,包括空行以结构化源文件。[默认值:True]
dump_h(routines, f, prefix, header=True, empty=True)
写入 C 头文件。
此文件包含所有函数声明。
参数:
routines:列表
一组 Routine 实例。
f:类似文件的
写入文件的位置。
prefix:字符串
文件名前缀,用于构建包含保护。仅使用前缀的基本名称。
header:布尔值,可选
当为 True 时,在每个源文件顶部包括头部注释。[默认:True]
empty:布尔值,可选
当为 True 时,包括空行以结构化源文件。[默认:True]
get_prototype(routine)
返回例程的函数原型字符串。
如果例程具有多个结果对象,则引发 CodeGenError。
参见:zh.wikipedia.org/wiki/%E5%87%BD%E6%95%B0%E5%8E%9F%E5%9E%8B
class sympy.utilities.codegen.CodeGen(project='project', cse=False)
代码生成器的抽象类。
dump_code(routines, f, prefix, header=True, empty=True)
写入代码时,请调用特定语言的方法。
生成的文件包含低级代码中所有例程的定义,并在适当时引用头文件。
参数:
routines:列表
一组 Routine 实例。
f:类似文件的
写入文件的位置。
prefix:字符串
文件名前缀,用于引用正确的头文件。仅使用前缀的基本名称。
header:布尔值,可选
当为 True 时,在每个源文件顶部包括头部注释。[默认:True]
empty:布尔值,可选
当为 True 时,包括空行以结构化源文件。[默认:True]
routine(name, expr, argument_sequence=None, global_vars=None)
创建适合该语言的 Routine 对象。
至少对于 C/Fortran 适用的此实现。如有必要,子类可以覆盖这一点。
在这里,我们假设最多有一个返回值(左值),它必须是标量。额外的输出是 OutputArguments(例如右手边的指针或通过引用传递)。矩阵始终通过 OutputArguments 返回。如果argument_sequence
为 None,则参数将按字母顺序排序,但所有 InputArguments 首先,然后是 OutputArgument 和 InOutArguments。
write(routines, prefix, to_files=False, header=True, empty=True)
写入所有给定例程的源代码文件。
生成的源代码作为(文件名,内容)元组列表返回,或写入文件(见下文)。每个文件名由给定前缀加上适当的扩展名组成。
参数:
routines:列表
要写入的 Routine 实例列表
prefix:字符串
输出文件的前缀
to_files:布尔值,可选
当为 True 时,将输出写入文件。否则,将返回(文件名,内容)元组的列表。[默认:False]
header:布尔值,可选
当为 True 时,在每个源文件顶部包括头部注释。[默认:True]
empty:布尔值,可选
当为 True 时,包括空行以结构化源文件。[默认:True]
class sympy.utilities.codegen.DataType(cname, fname, pyname, jlname, octname, rsname)
在不同语言中为某种数据类型保存字符串。
class sympy.utilities.codegen.FCodeGen(project='project', printer=None)
生成 Fortran 95 代码的生成器
继承自 CodeGen 的.write()方法将输出一个代码文件和一个接口文件,分别为
dump_f95(routines, f, prefix, header=True, empty=True)
写入代码时,请调用特定语言的方法。
生成的文件包含低级代码中所有例程的定义,并在适当时引用头文件。
参数:
routines:列表
例程实例列表。
f:类似文件
写入文件的位置。
prefix:字符串
文件名前缀,用于引用适当的头文件。只使用前缀的基本名称。
header:布尔值,可选
当为 True 时,在每个源文件顶部包括一个头注释。[默认:True]
empty:布尔值,可选
当为 True 时,包括空行以结构化源文件。[默认:True]
dump_h(routines, f, prefix, header=True, empty=True)
写入接口到头文件。
此文件包含所有函数声明。
参数:
routines:列表
例程实例列表。
f:类似文件
写入文件的位置。
prefix:字符串
文件名前缀。
header:布尔值,可选
当为 True 时,在每个源文件顶部包括一个头注释。[默认:True]
empty:布尔值,可选
当为 True 时,包括空行以结构化源文件。[默认:True]
get_interface(routine)
返回函数接口的字符串。
例程应具有单个结果对象,可以为 None。如果例程具有多个结果对象,则会引发 CodeGenError。
class sympy.utilities.codegen.JuliaCodeGen(project='project', printer=None)
Julia 代码生成器。
从 CodeGen 继承的.write()方法将输出一个代码文件
dump_jl(routines, f, prefix, header=True, empty=True)
通过调用特定于语言的方法编写代码。
生成的文件包含低级代码中所有例程的定义,并在适当时引用头文件。
参数:
routines:列表
例程实例列表。
f:类似文件
写入文件的位置。
prefix:字符串
文件名前缀,用于引用适当的头文件。只使用前缀的基本名称。
header:布尔值,可选
当为 True 时,在每个源文件顶部包括一个头注释。[默认:True]
empty:布尔值,可选
当为 True 时,包括空行以结构化源文件。[默认:True]
routine(name, expr, argument_sequence, global_vars)
Julia 专用例程创建。
class sympy.utilities.codegen.OctaveCodeGen(project='project', printer=None)
Octave 代码生成器。
从 CodeGen 继承的.write()方法将输出一个代码文件
Octave .m 文件通常只包含一个函数。该函数名称应与文件名(prefix
)匹配。如果传递多个name_expr
对,则后面的被假定为由主函数访问的私有函数。
你应该只将输入传递给argument_sequence
:输出按照它们在name_expr
中的顺序排序。
dump_m(routines, f, prefix, header=True, empty=True, inline=True)
通过调用特定于语言的方法编写代码。
生成的文件包含低级代码中所有例程的定义,并在适当时引用头文件。
参数:
routines:列表
例程实例列表。
f:类似文件
写入文件的位置。
prefix:字符串
文件名前缀,用于引用适当的头文件。只使用前缀的基本名称。
header:布尔值,可选
当设置为 True 时,在每个源文件的顶部包含一个头部注释。[默认值:True]
empty:布尔值,可选
当设置为 True 时,包括空行以结构化源文件。[默认值:True]
routine(name, expr, argument_sequence, global_vars)
为 Octave 创建专用的例程。
class sympy.utilities.codegen.OutputArgument(name, result_var, expr, datatype=None, dimensions=None, precision=None)
OutputArgument 在例程中始终被初始化。
class sympy.utilities.codegen.Result(expr, name=None, result_var=None, datatype=None, dimensions=None, precision=None)
返回值的表达式。
在 Python 语言中,名称“result”用于避免与保留字“return”发生冲突。它也比“ReturnValue”更短。
在目标中可能需要这些名称(例如,“return(x*y)”可能会返回一个值,但从未命名它)。
class sympy.utilities.codegen.Routine(name, arguments, results, local_vars, global_vars)
对一组表达式进行评估例程的通用描述。
CodeGen 类可以将此类的实例转换为特定语言的代码。例程规范涵盖了这些语言中所有存在的特性。CodeGen 部分在目标语言中缺少某些特性时必须引发异常。例如,Python 中可能存在多个返回值,但 C 或 Fortran 中不存在。另一个例子是 Fortran 和 Python 支持复数,而 C 不支持。
property result_variables
返回 OutputArgument、InOutArgument 和 Result 的列表。
如果存在返回值,则它们位于列表的末尾。
property variables
返回可能在例程中使用的所有变量的集合。
对于具有无名称返回值的例程,可能或可能不会使用的虚拟变量将包含在集合中。
class sympy.utilities.codegen.RustCodeGen(project='project', printer=None)
Rust 代码生成器。
从 CodeGen 继承的.write()方法将输出一个名为
dump_rs(routines, f, prefix, header=True, empty=True)
通过调用特定于语言的方法编写代码。
生成的文件包含所有低级代码中的例程定义,并在适当时引用头文件。
参数:
例程:列表
一组例程实例的列表。
f:类似文件
写入文件的位置。
前缀:字符串
文件名前缀,用于引用适当的头文件。仅使用前缀的基本名称。
header:布尔值,可选
当设置为 True 时,在每个源文件的顶部包含一个头部注释。[默认值:True]
empty:布尔值,可选
当设置为 True 时,包括空行以结构化源文件。[默认值:True]
get_prototype(routine)
返回例程的函数原型字符串。
如果例程具有多个结果对象,则引发 CodeGenError。
routine(name, expr, argument_sequence, global_vars)
为 Rust 创建专用的例程。
sympy.utilities.codegen.codegen(name_expr, language=None, prefix=None, project='project', to_files=False, header=True, empty=True, argument_sequence=None, global_vars=None, standard=None, code_gen=None, printer=None)
为给定语言中的表达式生成源代码。
参数:
name_expr:元组或元组列表
单个(名称,表达式)元组或(名称,表达式)元组列表。每个元组对应一个例程。如果表达式是等式(Equality 类的实例),则左侧被视为输出参数。如果表达式是可迭代的,则例程将具有多个输出。
language:字符串,
表示源代码语言的字符串。不区分大小写。目前支持'C'、'F95'和'Octave'。'Octave'生成与 Octave 和 Matlab 兼容的代码。
prefix:字符串,可选
文件名称的前缀,用于包含源代码的文件。语言相关的后缀将被附加。如果省略,则使用第一个 name_expr 元组的名称。
project:字符串,可选
项目名称,用于生成唯一的预处理器指令。[默认值:“project”]
to_files:布尔值,可选
当设置为 True 时,代码将被写入一个或多个具有给定前缀的文件中,否则将返回包含这些文件名称和内容的字符串。[默认值:False]
header:布尔值,可选
当设置为 True 时,在每个源文件顶部写入头文件。[默认值:True]
empty:布尔值,可选
当设置为 True 时,空行用于代码的结构化。[默认值:True]
argument_sequence:可迭代对象,可选
按照首选顺序为例程的参数序列。如果缺少必需的参数,则引发 CodeGenError。冗余的参数将不会有警告。如果省略,则参数将按字母顺序排列,但所有输入参数先排列,然后是输出或输入输出参数。
global_vars:可迭代对象,可选
例程使用的全局变量序列。此处列出的变量不会显示为函数参数。
standard:字符串,可选
code_gen:CodeGen 实例,可选
一个 CodeGen 子类的实例。覆盖
language
。
printer:Printer 实例,可选
一个 Printer 子类的实例。
示例
>>> from sympy.utilities.codegen import codegen
>>> from sympy.abc import x, y, z
>>> [(c_name, c_code), (h_name, c_header)] = codegen(
... ("f", x+y*z), "C89", "test", header=False, empty=False)
>>> print(c_name)
test.c
>>> print(c_code)
#include "test.h"
#include <math.h>
double f(double x, double y, double z) {
double f_result;
f_result = x + y*z;
return f_result;
}
>>> print(h_name)
test.h
>>> print(c_header)
#ifndef PROJECT__TEST__H
#define PROJECT__TEST__H
double f(double x, double y, double z);
#endif
另一个使用 Equality 对象的示例,以给出具有命名输出的例程。这里的文件名(前缀)来自第一个(name,expr)对。
>>> from sympy.abc import f, g
>>> from sympy import Eq
>>> [(c_name, c_code), (h_name, c_header)] = codegen(
... [("myfcn", x + y), ("fcn2", [Eq(f, 2*x), Eq(g, y)])],
... "C99", header=False, empty=False)
>>> print(c_name)
myfcn.c
>>> print(c_code)
#include "myfcn.h"
#include <math.h>
double myfcn(double x, double y) {
double myfcn_result;
myfcn_result = x + y;
return myfcn_result;
}
void fcn2(double x, double y, double *f, double *g) {
(*f) = 2*x;
(*g) = y;
}
如果生成的函数将成为一个更大项目的一部分,其中定义了各种全局变量,则可以使用‘global_vars’选项从函数签名中移除指定的变量。
>>> from sympy.utilities.codegen import codegen
>>> from sympy.abc import x, y, z
>>> [(f_name, f_code), header] = codegen(
... ("f", x+y*z), "F95", header=False, empty=False,
... argument_sequence=(x, y), global_vars=(z,))
>>> print(f_code)
REAL*8 function f(x, y)
implicit none
REAL*8, intent(in) :: x
REAL*8, intent(in) :: y
f = x + y*z
end function
sympy.utilities.codegen.get_default_datatype(expr, complex_allowed=None)
基于表达式推导出适当的数据类型。
sympy.utilities.codegen.make_routine(name, expr, argument_sequence=None, global_vars=None, language='F95')
从表达式生成适当的 Routine 的工厂。
参数:
name:字符串
在生成的代码中此例程的名称。
expr:表达式或表达式列表/元组
Routine 实例将表示的 SymPy 表达式。如果给定一个表达式列表或元组,则认为该例程具有多个返回值和/或输出参数。
argument_sequence:列表或元组,可选
按首选顺序列出例程的列表参数。如果省略,则结果依赖于语言,例如按字母顺序或按给定表达式的相同顺序。
global_vars:可迭代对象,可选
例程使用的全局变量序列。此处列出的变量不会显示为函数参数。
language:字符串,可选
指定目标语言。例程本身应该是语言无关的,但是创建方式、错误检查等依赖于语言。[默认值:“F95”]。
注意
根据语言和具体的数学表达式,决定是使用输出参数还是返回值。对于类型为 Equality 的表达式,通常左侧会被转换为一个输出参数(或者在合适的情况下是一个 InOutArgument)。否则,通常计算后的表达式会成为例程的返回值。
示例
>>> from sympy.utilities.codegen import make_routine
>>> from sympy.abc import x, y, f, g
>>> from sympy import Eq
>>> r = make_routine('test', [Eq(f, 2*x), Eq(g, x + y)])
>>> [arg.result_var for arg in r.results]
[]
>>> [arg.name for arg in r.arguments]
[x, y, f, g]
>>> [arg.name for arg in r.result_variables]
[f, g]
>>> r.local_vars
set()
另一个更复杂的示例,混合了指定和自动分配的名称。还具有矩阵输出。
>>> from sympy import Matrix
>>> r = make_routine('fcn', [x*y, Eq(f, 1), Eq(g, x + g), Matrix([[x, 2]])])
>>> [arg.result_var for arg in r.results]
[result_5397460570204848505]
>>> [arg.expr for arg in r.results]
[x*y]
>>> [arg.name for arg in r.arguments]
[x, y, f, g, out_8598435338387848786]
我们可以更仔细地检查各种参数:
>>> from sympy.utilities.codegen import (InputArgument, OutputArgument,
... InOutArgument)
>>> [a.name for a in r.arguments if isinstance(a, InputArgument)]
[x, y]
>>> [a.name for a in r.arguments if isinstance(a, OutputArgument)]
[f, out_8598435338387848786]
>>> [a.expr for a in r.arguments if isinstance(a, OutputArgument)]
[1, Matrix([[x, 2]])]
>>> [a.name for a in r.arguments if isinstance(a, InOutArgument)]
[g]
>>> [a.expr for a in r.arguments if isinstance(a, InOutArgument)]
[g + x]
装饰器
有用的实用装饰器。
@sympy.utilities.decorator.deprecated(message, *, deprecated_since_version, active_deprecations_target, stacklevel=3)
将函数标记为已弃用。
如果整个函数或类已被弃用,应使用此装饰器。如果只弃用了某些功能,则应直接使用warns_deprecated_sympy()
。此装饰器只是一种便利。在使用此装饰器和在函数顶部调用warns_deprecated_sympy()
之间没有功能上的区别。
装饰器使用与warns_deprecated_sympy()
相同的参数。有关此装饰器关键字的详细信息,请参阅其文档。
有关何时以及如何在 SymPy 中弃用事物的详细信息,请参阅弃用政策文档。
示例
>>> from sympy.utilities.decorator import deprecated
>>> from sympy import simplify
>>> @deprecated(""" ... The simplify_this(expr) function is deprecated. Use simplify(expr)
... instead.""", deprecated_since_version="1.1",
... active_deprecations_target='simplify-this-deprecation')
... def simplify_this(expr):
... """
... Simplify ``expr``.
...
... .. deprecated:: 1.1
...
... The ``simplify_this`` function is deprecated. Use :func:`simplify`
... instead. See its documentation for more information. See
... :ref:`simplify-this-deprecation` for details.
...
... """
... return simplify(expr)
>>> from sympy.abc import x
>>> simplify_this(x*(x + 1) - x**2)
<stdin>:1: SymPyDeprecationWarning:
The simplify_this(expr) function is deprecated. Use simplify(expr)
instead.
See https://docs.sympy.org/latest/explanation/active-deprecations.html#simplify-this-deprecation
for details.
This has been deprecated since SymPy version 1.1\. It
will be removed in a future version of SymPy.
simplify_this(x)
x
另见
sympy.utilities.exceptions.SymPyDeprecationWarning
, sympy.utilities.exceptions.sympy_deprecation_warning
, sympy.utilities.exceptions.ignore_warnings
, sympy.testing.pytest.warns_deprecated_sympy
sympy.utilities.decorator.conserve_mpmath_dps(func)
在函数完成后,将mpmath.mp.dps
的值重置为函数运行之前的值。
sympy.utilities.decorator.doctest_depends_on(exe=None, modules=None, disable_viewers=None, python_version=None, ground_types=None)
添加关于必须满足的依赖项的元数据,以对装饰对象的文档字符串进行文档测试。
exe
应该是可执行文件的列表
modules
应该是模块的列表
disable_viewers
应该是禁用preview()
的查看器列表
python_version
应该是所需的最低 Python 版本,格式为元组(如(3, 0)
)
sympy.utilities.decorator.memoize_property(propfunc)
缓存可能昂贵的propfunc
的值的属性装饰器,在第一次评估之后。缓存的值存储在相应的属性名称上,附加了下划线。
class sympy.utilities.decorator.no_attrs_in_subclass(cls, f)
不要从基类‘继承’某些属性
>>> from sympy.utilities.decorator import no_attrs_in_subclass
>>> class A(object):
... x = 'test'
>>> A.x = no_attrs_in_subclass(A, A.x)
>>> class B(A):
... pass
>>> hasattr(A, 'x')
True
>>> hasattr(B, 'x')
False
sympy.utilities.decorator.public(obj)
将obj
的名称附加到全局__all__
变量(调用位置)。
通过在函数或类上使用此装饰器,您可以达到与手动填写__all__
变量相同的目的,只是无需重复自己(对象的名称)。您还可以在定义位置知道对象在公共还是随机位置(设置了__all__
的地方)。
请注意,在多个装饰器设置中(几乎所有情况下),必须在任何其他装饰器之前应用@public
装饰器,因为它依赖于指向对象全局命名空间的指针。如果您先应用其他装饰器,@public
可能会修改错误的命名空间。
示例
>>> from sympy.utilities.decorator import public
>>> __all__ # noqa: F821
Traceback (most recent call last):
...
NameError: name '__all__' is not defined
>>> @public
... def some_function():
... pass
>>> __all__ # noqa: F821
['some_function']
sympy.utilities.decorator.threaded(func)
对对象的子元素应用func
,包括Add
。
此装饰器旨在统一地使得能够将函数应用于复合对象的所有元素,例如矩阵、列表、元组和其他可迭代容器,或者只是表达式。
此版本的threaded()
装饰器允许对Add
类的元素进行线程处理。如果不希望此行为,请使用xthreaded()
装饰器。
函数使用此装饰器必须具有以下签名:
@threaded
def function(expr, *args, **kwargs):
sympy.utilities.decorator.threaded_factory(func, use_add)
一个用于threaded
装饰器的工厂。
sympy.utilities.decorator.xthreaded(func)
对对象的子元素应用func
,不包括Add
。
此装饰器旨在统一地使得能够将函数应用于复合对象的所有元素,例如矩阵、列表、元组和其他可迭代容器,或者只是表达式。
此版本的threaded()
装饰器禁止对Add
类的元素进行线程处理。如果不希望此行为,请使用threaded()
装饰器。
函数使用此装饰器必须具有以下签名:
@xthreaded
def function(expr, *args, **kwargs):
枚举
此模块包括用于枚举和计数多重集分区的函数和类。
sympy.utilities.enumerative.multiset_partitions_taocp(multiplicities)
枚举多重集的分区。
参数:
多重性
组件的整数多重性列表。
产生:
state
内部数据结构,用于编码特定的分区。然后,通常通过访问函数处理此输出数据结构,将其与组件本身结合起来生成实际的分区。
除非他们希望创建自己的访问函数,否则用户几乎没有必要查看此数据结构的内部。但是,供参考,它是一个具有三个元素的列表,其组件为:
f
是一个帧数组,用于将 pstack 分成部分。
lpart
指向最顶部部分的基础。
pstack
是一个 PartComponent 对象数组。
输出的
state
提供了对枚举函数内部数据结构的一瞥。客户端应将其视为只读;对数据结构的任何修改将导致不可预测(几乎肯定不正确)的结果。此外,state
的组件在每次迭代中都是就地修改的。因此,必须在每次循环迭代时调用访问者。累积state
实例并稍后处理它们将不起作用。
示例
>>> from sympy.utilities.enumerative import list_visitor
>>> from sympy.utilities.enumerative import multiset_partitions_taocp
>>> # variables components and multiplicities represent the multiset 'abb'
>>> components = 'ab'
>>> multiplicities = [1, 2]
>>> states = multiset_partitions_taocp(multiplicities)
>>> list(list_visitor(state, components) for state in states)
[[['a', 'b', 'b']],
[['a', 'b'], ['b']],
[['a'], ['b', 'b']],
[['a'], ['b'], ['b']]]
参见
sympy.utilities.iterables.multiset_partitions
接受多重集作为输入并直接生成多重集分区。它调度到许多函数,包括此函数,进行实现。大多数用户将发现它比multiset_partitions_taocp
更方便使用。
sympy.utilities.enumerative.factoring_visitor(state, primes)
与multiset_partitions_taocp
一起使用,以枚举将一个数表示为因子乘积的方式。对于此用法,一个数的质因数的指数是分区枚举器的参数,而相应的质因数是此处的输入。
示例
要枚举一个数的因子化,我们可以将分区的元素视为其质因数,而多重性视为其指数。
>>> from sympy.utilities.enumerative import factoring_visitor
>>> from sympy.utilities.enumerative import multiset_partitions_taocp
>>> from sympy import factorint
>>> primes, multiplicities = zip(*factorint(24).items())
>>> primes
(2, 3)
>>> multiplicities
(3, 1)
>>> states = multiset_partitions_taocp(multiplicities)
>>> list(factoring_visitor(state, primes) for state in states)
[[24], [8, 3], [12, 2], [4, 6], [4, 2, 3], [6, 2, 2], [2, 2, 2, 3]]
sympy.utilities.enumerative.list_visitor(state, components)
返回一个列表的列表来表示分区。
示例
>>> from sympy.utilities.enumerative import list_visitor
>>> from sympy.utilities.enumerative import multiset_partitions_taocp
>>> states = multiset_partitions_taocp([1, 2, 1])
>>> s = next(states)
>>> list_visitor(s, 'abc') # for multiset 'a b b c'
[['a', 'b', 'b', 'c']]
>>> s = next(states)
>>> list_visitor(s, [1, 2, 3]) # for multiset '1 2 2 3
[[1, 2, 2], [3]]
函数multiset_partitions_taocp
的方法被类MultisetPartitionTraverser
扩展和泛化的方法。
class sympy.utilities.enumerative.MultisetPartitionTraverser
具有枚举和计数多重集分区的方法。
这实现了 Knuth 算法 7.1.2.5M 的重构和扩展版本[AOCP]。
此类的枚举方法是生成器,并返回可以由用于multiset_partitions_taocp
输出的相同访问函数解释的数据结构。
示例
>>> from sympy.utilities.enumerative import MultisetPartitionTraverser
>>> m = MultisetPartitionTraverser()
>>> m.count_partitions([4,4,4,2])
127750
>>> m.count_partitions([3,3,3])
686
参见
multiset_partitions_taocp
,sympy.utilities.iterables.multiset_partitions
参考资料
[AOCP] (1,2,3,4)
第 4A 卷,组合算法的第一部分中的算法 7.1.2.5M,《计算机编程艺术》作者 Donald Knuth。
[Factorisatio]
关于 Oppenheim 问题的一个问题:“Factorisatio Numerorum”,E. R. Canfield,Paul Erdos,Carl Pomerance,NUMBER THEORY 杂志,第 17 卷,第 1 号。1983 年 8 月。请参见第七部分,了解与 Knuth 相似的算法的描述。
[Yorgey]
生成多重集合分区,Brent Yorgey,Monad.Reader,第 8 期,2007 年 9 月。
count_partitions(multiplicities)
返回具有给定multiplicities
中的组件的多重集合的分区数。
对于较大的计数,这种方法比调用一个枚举器并计数结果要快得多。使用动态规划来减少实际探索的节点数。用于加速计数过程的字典存储在MultisetPartitionTraverser
对象中,并且跨调用保持不变。如果用户不希望为任何额外的多重集调用count_partitions
,则应清除对象以节省内存。另一方面,从一个计数运行中建立起来的缓存可以显著加快后续调用count_partitions
的速度,因此不清除对象可能是有利的。
例子
>>> from sympy.utilities.enumerative import MultisetPartitionTraverser
>>> m = MultisetPartitionTraverser()
>>> m.count_partitions([9,8,2])
288716
>>> m.count_partitions([2,2])
9
>>> del m
注意
如果我们观察 Knuth 的算法 M [AOCP]的运行方式,可以将其视为部分二叉树的遍历。一个部分最多有两个子节点,左子节点是由扩展操作产生的,右子节点是由减少操作产生的。普通的多重集合分区枚举是这棵树的中序遍历,其中分区对应于从根到叶子的路径。从路径到分区的映射有些复杂,因为分区只包含那些是叶子或扩展链接的父节点,而不包含那些是减少链接的父节点。
对于计数目的,只需计算叶子即可,这可以通过递归的中序遍历来完成。在特定部分为根的子树的叶子数仅是该部分本身的函数,因此记忆化具有显著加速计数的潜力。
这种方法采用了类似于假设化的记忆递归函数的计算方法,但有两个不同之处:
-
该方法是迭代的,借鉴其他枚举的结构,并维护正在计数的部分的显式堆栈。(此实现可能会快速地计算一些多重集,但在使用递归实现时可能会超出默认的 Python 递归限制。)
-
而不是直接使用部件数据结构,会构造更紧凑的键。这样做可以节省空间,但更重要的是,可以将某些本来会保持分离的物理键合并在一起。
与枚举函数不同,目前没有 _range 版本的 count_partitions。如果有人想要挑战自己,可以通过使用计数直方图而不是单个计数进行记忆化,并结合这些直方图来构造一个。
enum_all(multiplicities)
枚举多重集的分区。
示例
>>> from sympy.utilities.enumerative import list_visitor
>>> from sympy.utilities.enumerative import MultisetPartitionTraverser
>>> m = MultisetPartitionTraverser()
>>> states = m.enum_all([2,2])
>>> list(list_visitor(state, 'ab') for state in states)
[[['a', 'a', 'b', 'b']],
[['a', 'a', 'b'], ['b']],
[['a', 'a'], ['b', 'b']],
[['a', 'a'], ['b'], ['b']],
[['a', 'b', 'b'], ['a']],
[['a', 'b'], ['a', 'b']],
[['a', 'b'], ['a'], ['b']],
[['a'], ['a'], ['b', 'b']],
[['a'], ['a'], ['b'], ['b']]]
另请参阅
multiset_partitions_taocp
提供了与此方法相同的结果,但大约快了一倍。因此,enum_all 主要用于测试。还请参见该函数有关状态和访问者的讨论。
enum_large(multiplicities, lb)
枚举多重集的分区,其中 lb < num(parts)
等同于 enum_range(multiplicities, lb, sum(multiplicities))
参数:
分量的重复次数
多重集分量的重复列表。
lb
分区中的部分数必须大于此下限。
示例
>>> from sympy.utilities.enumerative import list_visitor
>>> from sympy.utilities.enumerative import MultisetPartitionTraverser
>>> m = MultisetPartitionTraverser()
>>> states = m.enum_large([2,2], 2)
>>> list(list_visitor(state, 'ab') for state in states)
[[['a', 'a'], ['b'], ['b']],
[['a', 'b'], ['a'], ['b']],
[['a'], ['a'], ['b', 'b']],
[['a'], ['a'], ['b'], ['b']]]
另请参阅
enum_all
, enum_small
, enum_range
enum_range(multiplicities, lb, ub)
枚举多重集的分区,其中lb < num(parts) <= ub
。
特别是,如果要求确切有 k
个部分的分区,则调用 (multiplicities, k - 1, k)
。该方法泛化了 enum_all、enum_small 和 enum_large。
示例
>>> from sympy.utilities.enumerative import list_visitor
>>> from sympy.utilities.enumerative import MultisetPartitionTraverser
>>> m = MultisetPartitionTraverser()
>>> states = m.enum_range([2,2], 1, 2)
>>> list(list_visitor(state, 'ab') for state in states)
[[['a', 'a', 'b'], ['b']],
[['a', 'a'], ['b', 'b']],
[['a', 'b', 'b'], ['a']],
[['a', 'b'], ['a', 'b']]]
enum_small(multiplicities, ub)
枚举多重集分区,部件数不超过 ub
。
等同于 enum_range(multiplicities, 0, ub)
参数:
分量的重复次数
多重集分量的重复列表。
ub
最大部分数
示例
>>> from sympy.utilities.enumerative import list_visitor
>>> from sympy.utilities.enumerative import MultisetPartitionTraverser
>>> m = MultisetPartitionTraverser()
>>> states = m.enum_small([2,2], 2)
>>> list(list_visitor(state, 'ab') for state in states)
[[['a', 'a', 'b', 'b']],
[['a', 'a', 'b'], ['b']],
[['a', 'a'], ['b', 'b']],
[['a', 'b', 'b'], ['a']],
[['a', 'b'], ['a', 'b']]]
实现部分基于 Knuth 在《TAOCP》中练习 69 的答案。
另请参阅
enum_all
, enum_large
, enum_range
异常和警告
一般的 SymPy 异常和警告。
exception sympy.utilities.exceptions.SymPyDeprecationWarning(message, *, deprecated_since_version, active_deprecations_target)
关于 SymPy 弃用特性的警告。
有关在 SymPy 中何时以及如何弃用事物的详细信息,请参阅 Deprecation Policy 文档。
请注意,仅仅构造这个类不会引发警告。为此,必须调用 :funcsympy_deprecation_warning
函数。因此,不建议直接构造这个类。
解释
SymPyDeprecationWarning
类是 DeprecationWarning
的子类,用于 SymPy 中的所有弃用警告。使用特殊子类是为了能够自动增加警告消息,包括有关引入弃用的版本的附加元数据和指向文档的链接。这也允许用户使用 warnings
过滤器显式地过滤 SymPy 的弃用警告(参见 Silencing SymPy Deprecation Warnings)。
此外,默认情况下启用了 SymPyDeprecationWarning
的显示,不像普通的 DeprecationWarning
,只有在交互式会话中才默认显示。这确保了 SymPy 中的弃用警告实际上会被用户看到。
有关此函数参数的描述,请参见 sympy_deprecation_warning()
的文档。
要标记函数为弃用,可以使用 @deprecated
装饰器。
另请参见
sympy.utilities.exceptions.sympy_deprecation_warning
,sympy.utilities.exceptions.ignore_warnings
,sympy.utilities.decorator.deprecated
,sympy.testing.pytest.warns_deprecated_sympy
sympy.utilities.exceptions.ignore_warnings(warningcls)
在测试期间抑制警告的上下文管理器。
注意
在测试中不要与 SymPyDeprecationWarning 一起使用。应改用 warns_deprecated_sympy()。
此函数在测试期间抑制警告很有用。应该使用 warns
函数来断言是否会引发警告。ignore_warnings
函数在警告不一定会被引发时很有用(例如在导入模块时)或者警告来自第三方代码时。
由于递归调用而导致相同或类似警告被发出两次时,此函数也非常有用。
当警告(可靠地)来自 SymPy 时,应优先使用 warns 函数而不是 ignore_warnings。
>>> from sympy.utilities.exceptions import ignore_warnings
>>> import warnings
这里有一个警告:
>>> with warnings.catch_warnings(): # reset warnings in doctest
... warnings.simplefilter('error')
... warnings.warn('deprecated', UserWarning)
Traceback (most recent call last):
...
UserWarning: deprecated
让我们使用 ignore_warnings 来抑制它:
>>> with warnings.catch_warnings(): # reset warnings in doctest
... warnings.simplefilter('error')
... with ignore_warnings(UserWarning):
... warnings.warn('deprecated', UserWarning)
(未发出警告)
另见
sympy.utilities.exceptions.SymPyDeprecationWarning
, sympy.utilities.exceptions.sympy_deprecation_warning
, sympy.utilities.decorator.deprecated
, sympy.testing.pytest.warns_deprecated_sympy
sympy.utilities.exceptions.sympy_deprecation_warning(message, *, deprecated_since_version, active_deprecations_target, stacklevel=3)
在 SymPy 中警告某个特性已弃用。
请查看弃用策略文档,了解 SymPy 中事物何时以及如何进行弃用。
要标记整个函数或类作为弃用,可以使用 @deprecated
装饰器。
参数:
message : str
弃用消息。可能跨越多行且包含代码示例。消息应该被限制在 80 个字符内。消息会自动去除缩进和前后空白。消息可能包含基于用户输入的动态内容,但是如果表达式可以是任意的,请避免使用
str(expression)
,因为它可能会很大,使得警告消息难以阅读。
deprecated_since_version : str
特性自 SymPy 弃用的版本。对于新的弃用,应使用不带
.dev
的版本在 sympy/release.py 中。如果下一个 SymPy 版本与此不同,发布经理将需要更新任何使用不正确版本的SymPyDeprecationWarning
。
active_deprecations_target : str
对应于活跃弃用列表文档中弃用部分的 Sphinx 目标(参见
doc/src/explanation/active-deprecations.md
)。这用于自动生成警告消息中页面的 URL。此参数是必需的,并且必须作为关键字参数传递。(示例:active_deprecations_target="deprecated-feature-abc"
)
stacklevel : int, 默认值:3
warnings.warn
函数中传递的stacklevel
参数。如果您创建一个调用此函数的包装器,应增加此参数,以便警告消息显示出产生警告的代码行。请注意,在某些情况下,可能会有多个可能导致警告的用户代码路径。在这种情况下,只需选择最小的公共stacklevel
。
示例
>>> from sympy.utilities.exceptions import sympy_deprecation_warning
>>> def is_this_zero(x, y=0):
... """
... Determine if x = 0.
...
... Parameters
... ==========
...
... x : Expr
... The expression to check.
...
... y : Expr, optional
... If provided, check if x = y.
...
... .. deprecated:: 1.1
...
... The ``y`` argument to ``is_this_zero`` is deprecated. Use
... ``is_this_zero(x - y)`` instead.
...
... """
... from sympy import simplify
...
... if y != 0:
... sympy_deprecation_warning("""
... The y argument to is_zero() is deprecated. Use is_zero(x - y) instead.""",
... deprecated_since_version="1.1",
... active_deprecations_target='is-this-zero-y-deprecation')
... return simplify(x - y) == 0
>>> is_this_zero(0)
True
>>> is_this_zero(1, 1)
<stdin>:1: SymPyDeprecationWarning:
The y argument to is_zero() is deprecated. Use is_zero(x - y) instead.
See https://docs.sympy.org/latest/explanation/active-deprecations.html#is-this-zero-y-deprecation
for details.
This has been deprecated since SymPy version 1.1\. It
will be removed in a future version of SymPy.
is_this_zero(1, 1)
True
另请参见
sympy.utilities.exceptions.SymPyDeprecationWarning
, sympy.utilities.exceptions.ignore_warnings
, sympy.utilities.decorator.deprecated
, sympy.testing.pytest.warns_deprecated_sympy
可迭代对象
class sympy.utilities.iterables.NotIterable
在创建不应在其实例上调用 iterable()时返回 true 的类时使用此方法,例如,对实例调用 list()将导致无限循环。
sympy.utilities.iterables.binary_partitions(n)
生成n的二进制分区。
二进制分区仅由 2 的幂次数构成。每一步将(2{k+1})减少为(2k)和(2^k)。因此,16 转换为 8 和 8。
示例
>>> from sympy.utilities.iterables import binary_partitions
>>> for i in binary_partitions(5):
... print(i)
...
[4, 1]
[2, 2, 1]
[2, 1, 1, 1]
[1, 1, 1, 1, 1]
参考文献
[R1053]
TAOCP 4,第 7.2.1.5 节,问题 64
sympy.utilities.iterables.bracelets(n, k)
项链转换器以返回自由(无限制)项链。
sympy.utilities.iterables.capture(func)
返回 func()的打印输出。
func
应为不带参数的函数,其通过打印语句产生输出。
>>> from sympy.utilities.iterables import capture
>>> from sympy import pprint
>>> from sympy.abc import x
>>> def foo():
... print('hello world!')
...
>>> 'hello' in capture(foo) # foo, not foo()
True
>>> capture(lambda: pprint(2/x))
'2\n-\nx\n'
sympy.utilities.iterables.common_prefix(*seqs)
返回 seqs 中的公共起始子序列。
>>> from sympy.utilities.iterables import common_prefix
>>> common_prefix(list(range(3)))
[0, 1, 2]
>>> common_prefix(list(range(3)), list(range(4)))
[0, 1, 2]
>>> common_prefix([1, 2, 3], [1, 2, 5])
[1, 2]
>>> common_prefix([1, 2, 3], [1, 3, 5])
[1]
sympy.utilities.iterables.common_suffix(*seqs)
返回 seqs 中的公共结束子序列。
>>> from sympy.utilities.iterables import common_suffix
>>> common_suffix(list(range(3)))
[0, 1, 2]
>>> common_suffix(list(range(3)), list(range(4)))
[]
>>> common_suffix([1, 2, 3], [9, 2, 3])
[2, 3]
>>> common_suffix([1, 2, 3], [9, 7, 3])
[3]
sympy.utilities.iterables.connected_components(G)
无向图的连通分量或有向图的弱连通分量。
参数:
G:元组[列表,列表[元组[T,T]]]
由图的顶点列表和边列表组成的元组,其连接的组件将被找到。
示例
给定一个无向图:
graph {
A -- B
C -- D
}
图 { A -- B C -- D }
如果我们在两个方向上都包含每条边,则可以使用此函数找到连接的组件。
>>> from sympy.utilities.iterables import connected_components
>>> V = ['A', 'B', 'C', 'D']
>>> E = [('A', 'B'), ('B', 'A'), ('C', 'D'), ('D', 'C')]
>>> connected_components((V, E))
[['A', 'B'], ['C', 'D']]
可以通过相同的方式找到有向图的弱连通分量。
注意事项
用于数据结构中必须为哈希的图顶点。如果顶点是不可哈希的,请用整数索引替换。
此函数使用 Tarjan 算法在(O(|V|+|E|))(线性)时间内计算连接的组件。
另见
sympy.utilities.iterables.strongly_connected_components
参考文献
[R1054]
[R1055]
sympy.utilities.iterables.dict_merge(*dicts)
将字典合并为单个字典。
sympy.utilities.iterables.filter_symbols(iterator, exclude)
仅从(iterator)中生成不出现在(exclude)中的元素。
参数:
iterator:可迭代对象
从中取元素的迭代器
exclude:可迭代对象
要排除的元素
返回:
iterator:迭代器
过滤的迭代器
sympy.utilities.iterables.flatten(iterable, levels=None, cls=None)
递归地去嵌套可迭代容器。
>>> from sympy import flatten
>>> flatten([1, 2, 3])
[1, 2, 3]
>>> flatten([1, 2, [3]])
[1, 2, 3]
>>> flatten([1, [2, 3], [4, 5]])
[1, 2, 3, 4, 5]
>>> flatten([1.0, 2, (1, None)])
[1.0, 2, 1, None]
如果要仅取消嵌套的容器的指定层数,则将levels
标志设置为所需的层数:
>>> ls = [[(-2, -1), (1, 2)], [(0, 0)]]
>>> flatten(ls, levels=1)
[(-2, -1), (1, 2), (0, 0)]
如果指定了 cls 参数,则仅展开该类的实例,例如:
>>> from sympy import Basic, S
>>> class MyOp(Basic):
... pass
...
>>> flatten([MyOp(S(1), MyOp(S(2), S(3)))], cls=MyOp)
[1, 2, 3]
改编自Python 技巧
sympy.utilities.iterables.generate_bell(n)
返回[0, 1, …, n - 1]的排列,使得每个排列与上一个排列仅通过交换一对相邻元素不同。将返回n!
排列作为迭代器。为了从随机起始排列获取下一个排列,请使用 Permutation 类的next_trotterjohnson
方法(以不同的方式生成相同的序列)。
示例
>>> from itertools import permutations
>>> from sympy.utilities.iterables import generate_bell
>>> from sympy import zeros, Matrix
这是用于物理钟声的排列,不按字典顺序生成排列。相反,排列彼此之间仅有一个反转,并且交换发生的位置以简单的方式周期性地变化。考虑由permutations
和generate_bell
生成的前几个 4 个元素的排列:
>>> list(permutations(range(4)))[:5]
[(0, 1, 2, 3), (0, 1, 3, 2), (0, 2, 1, 3), (0, 2, 3, 1), (0, 3, 1, 2)]
>>> list(generate_bell(4))[:5]
[(0, 1, 2, 3), (0, 1, 3, 2), (0, 3, 1, 2), (3, 0, 1, 2), (3, 0, 2, 1)]
注意第二和第三字典序排列的元素位置不同,而每个“贝尔”排列始终与前一个排列相比只有两个元素位置不同(因此排列的符号(+/-1)与前一个排列的符号相反)。
可以通过跟踪最大数出现的排列来看反转的位置是如何变化的:
>>> m = zeros(4, 24)
>>> for i, p in enumerate(generate_bell(4)):
... m[:, i] = Matrix([j - 3 for j in list(p)]) # make largest zero
>>> m.print_nonzero('X')
[XXX XXXXXX XXXXXX XXX]
[XX XX XXXX XX XXXX XX XX]
[X XXXX XX XXXX XX XXXX X]
[ XXXXXX XXXXXX XXXXXX ]
参见
sympy.combinatorics.permutations.Permutation.next_trotterjohnson
参考文献
[R1056]
en.wikipedia.org/wiki/Method_ringing
[R1057]
stackoverflow.com/questions/4856615/recursive-permutation/4857018
[R1058]
web.archive.org/web/20160313023044/http://programminggeeks.com/bell-algorithm-for-permutation/
[R1059]
en.wikipedia.org/wiki/Steinhaus%E2%80%93Johnson%E2%80%93Trotter_algorithm
[R1060]
生成自反排列、错位排列和亲戚的方法由 ECO Vincent Vajnovszki, DMTCS vol 1 issue 12, 2010
sympy.utilities.iterables.generate_derangements(s)
返回可迭代对象s
的唯一错位排列。
示例
>>> from sympy.utilities.iterables import generate_derangements
>>> list(generate_derangements([0, 1, 2]))
[[1, 2, 0], [2, 0, 1]]
>>> list(generate_derangements([0, 1, 2, 2]))
[[2, 2, 0, 1], [2, 2, 1, 0]]
>>> list(generate_derangements([0, 1, 1]))
[]
参见
sympy.functions.combinatorial.factorials.subfactorial
sympy.utilities.iterables.generate_involutions(n)
生成自反排列。
一个自反排列是一个乘以自身得到单位排列的排列。在这个实现中,自反排列使用固定点生成。
或者,可以将自反排列视为不包含长度大于两个的循环的排列。
示例
>>> from sympy.utilities.iterables import generate_involutions
>>> list(generate_involutions(3))
[(0, 1, 2), (0, 2, 1), (1, 0, 2), (2, 1, 0)]
>>> len(list(generate_involutions(4)))
10
参考文献
[R1061]
mathworld.wolfram.com/PermutationInvolution.html
sympy.utilities.iterables.generate_oriented_forest(n)
此算法生成有向森林。
有向图是一种没有对称有向边的有向图。森林是无环图,即没有循环。森林也可以描述为树的不相交并集,其中任意两个顶点都恰好由一条简单路径连接。
示例
>>> from sympy.utilities.iterables import generate_oriented_forest
>>> list(generate_oriented_forest(4))
[[0, 1, 2, 3], [0, 1, 2, 2], [0, 1, 2, 1], [0, 1, 2, 0], [0, 1, 1, 1], [0, 1, 1, 0], [0, 1, 0, 1], [0, 1, 0, 0], [0, 0, 0, 0]]
参考
[R1062]
T. Beyer 和 S.M. Hedetniemi:常数时间生成根树,SIAM J.计算机 Vol. 9,No. 4,1980 年 11 月
[R1063]
stackoverflow.com/questions/1633833/oriented-forest-taocp-algorithm-in-python
sympy.utilities.iterables.group(seq, multiple=True)
将序列拆分为相等、相邻元素的列表。
示例
>>> from sympy import group
>>> group([1, 1, 1, 2, 2, 3])
[[1, 1, 1], [2, 2], [3]]
>>> group([1, 1, 1, 2, 2, 3], multiple=False)
[(1, 3), (2, 2), (3, 1)]
>>> group([1, 1, 3, 2, 2, 1], multiple=False)
[(1, 2), (3, 1), (2, 2), (1, 1)]
参见也
multiset
sympy.utilities.iterables.has_dups(seq)
如果seq
中有任何重复元素,则返回 True。
示例
>>> from sympy import has_dups, Dict, Set
>>> has_dups((1, 2, 1))
True
>>> has_dups(range(3))
False
>>> all(has_dups(c) is False for c in (set(), Set(), dict(), Dict()))
True
sympy.utilities.iterables.has_variety(seq)
如果seq
中有任何不同的元素,则返回 True。
示例
>>> from sympy import has_variety
>>> has_variety((1, 2, 1))
True
>>> has_variety((1, 1, 1))
False
sympy.utilities.iterables.ibin(n, bits=None, str=False)
返回一个长度为bits
的列表,表示n
的二进制值,小位于右侧(最后)。如果省略了bits
,则长度将是表示n
所需的位数。如果希望位的顺序是反向的,请使用返回列表的[::-1]
切片。
如果希望从[0, 0,..., 0]
到[1, 1, ..., 1]
开始的所有位长列表序列,则传递非整数以表示位,例如'all'
。
如果需要位串,请传递str=True
。
示例
>>> from sympy.utilities.iterables import ibin
>>> ibin(2)
[1, 0]
>>> ibin(2, 4)
[0, 0, 1, 0]
如果所有列表与 0 到 2 ** n - 1 对应,则传递非整数以表示位:
>>> bits = 2
>>> for i in ibin(2, 'all'):
... print(i)
(0, 0)
(0, 1)
(1, 0)
(1, 1)
如果需要指定特定长度的位串,请使用str=True
:
>>> n = 123
>>> bits = 10
>>> ibin(n, bits, str=True)
'0001111011'
>>> ibin(n, bits, str=True)[::-1] # small bits left
'1101111000'
>>> list(ibin(3, 'all', str=True))
['000', '001', '010', '011', '100', '101', '110', '111']
sympy.utilities.iterables.iproduct(*iterables)
可迭代集合的笛卡尔积。
生成可迭代集合的笛卡尔积。这类似于 itertools.product,但它可以处理无限可迭代对象,并且最终会产生来自无限积的任何项。
示例
>>> from sympy.utilities.iterables import iproduct
>>> sorted(iproduct([1,2], [3,4]))
[(1, 3), (1, 4), (2, 3), (2, 4)]
使用无限迭代器:
>>> from sympy import S
>>> (3,) in iproduct(S.Integers)
True
>>> (3, 4) in iproduct(S.Integers, S.Integers)
True
参见也
sympy.utilities.iterables.is_palindromic(s, i=0, j=None)
如果序列从左到右与整个序列中的右到左相同(默认),或在 Python 切片s[i: j]
中,则返回 True;否则返回 False。
示例
>>> from sympy.utilities.iterables import is_palindromic
>>> is_palindromic([1, 0, 1])
True
>>> is_palindromic('abcbb')
False
>>> is_palindromic('abcbb', 1)
False
在原地执行普通的 Python 切片,因此不需要为测试创建序列的切片:
>>> is_palindromic('abcbb', 1, -1)
True
>>> is_palindromic('abcbb', -4, -1)
True
参见也
sympy.ntheory.digits.is_palindromic
测试整数
sympy.utilities.iterables.is_sequence(i, include=None)
返回一个布尔值,指示i
是否在 SymPy 意义上是序列。如果你的应用程序需要包含任何不通过以下测试的对象作为序列,请将'include'设置为该对象的类型;多个类型应作为类型元组传递。
注意:虽然生成器可以生成一个序列,但通常需要特殊处理以确保其元素在生成器耗尽之前被捕获,因此默认情况下不包括这些在序列的定义中。
参见:可迭代对象
示例
>>> from sympy.utilities.iterables import is_sequence
>>> from types import GeneratorType
>>> is_sequence([])
True
>>> is_sequence(set())
False
>>> is_sequence('abc')
False
>>> is_sequence('abc', include=str)
True
>>> generator = (c for c in 'abc')
>>> is_sequence(generator)
False
>>> is_sequence(generator, include=(str, GeneratorType))
True
sympy.utilities.iterables.iterable(i, exclude=(<class 'str'>, <class 'dict'>, <class 'sympy.utilities.iterables.NotIterable'>))
返回一个布尔值,指示i
是否为 SymPy 可迭代对象。True 也表示迭代器是有限的,例如可以在实例上调用 list(…)。
当 SymPy 处理可迭代对象时,几乎总是假设可迭代对象不是字符串或映射,因此默认情况下排除它们。如果希望纯 Python 定义,请设置 exclude=None。要排除多个项,请作为元组传递它们。
您还可以在您的类上将 _iterable 属性设置为 True 或 False,这将覆盖这里的检查,包括排除测试。
一般来说,某些 SymPy 函数使用这个来检查它们是否应该递归地映射一个对象。如果一个对象在 Python 意义上是可迭代的,但不希望有此行为(例如因为其迭代不是有限的,或者因为迭代可能引起不想要的计算),它应该通过将 _iterable 属性设置为 False 来禁用它。
参见:is_sequence
示例
>>> from sympy.utilities.iterables import iterable
>>> from sympy import Tuple
>>> things = [[1], (1,), set([1]), Tuple(1), (j for j in [1, 2]), {1:2}, '1', 1]
>>> for i in things:
... print('%s %s' % (iterable(i), type(i)))
True <... 'list'>
True <... 'tuple'>
True <... 'set'>
True <class 'sympy.core.containers.Tuple'>
True <... 'generator'>
False <... 'dict'>
False <... 'str'>
False <... 'int'>
>>> iterable({}, exclude=None)
True
>>> iterable({}, exclude=str)
True
>>> iterable("no", exclude=str)
False
sympy.utilities.iterables.kbins(l, k, ordered=None)
返回序列l
分成k
个箱子。
示例
默认情况下,按相同顺序提供项目,但分成 k 个分区而无需重新排序:
>>> from sympy.utilities.iterables import kbins
>>> for p in kbins(list(range(5)), 2):
... print(p)
...
[[0], [1, 2, 3, 4]]
[[0, 1], [2, 3, 4]]
[[0, 1, 2], [3, 4]]
[[0, 1, 2, 3], [4]]
ordered
标志要么为 None(提供元素的简单分区),要么为一个两位数表示箱子的顺序和箱子中项目的顺序是否重要。给定:
A = [[0], [1, 2]]
B = [[1, 2], [0]]
C = [[2, 1], [0]]
D = [[0], [2, 1]]
ordered
的以下值具有所示的含义:
00 means A == B == C == D
01 means A == B
10 means A == D
11 means A == A
>>> for ordered_flag in [None, 0, 1, 10, 11]:
... print('ordered = %s' % ordered_flag)
... for p in kbins(list(range(3)), 2, ordered=ordered_flag):
... print(' %s' % p)
...
ordered = None
[[0], [1, 2]]
[[0, 1], [2]]
ordered = 0
[[0, 1], [2]]
[[0, 2], [1]]
[[0], [1, 2]]
ordered = 1
[[0], [1, 2]]
[[0], [2, 1]]
[[1], [0, 2]]
[[1], [2, 0]]
[[2], [0, 1]]
[[2], [1, 0]]
ordered = 10
[[0, 1], [2]]
[[2], [0, 1]]
[[0, 2], [1]]
[[1], [0, 2]]
[[0], [1, 2]]
[[1, 2], [0]]
ordered = 11
[[0], [1, 2]]
[[0, 1], [2]]
[[0], [2, 1]]
[[0, 2], [1]]
[[1], [0, 2]]
[[1, 0], [2]]
[[1], [2, 0]]
[[1, 2], [0]]
[[2], [0, 1]]
[[2, 0], [1]]
[[2], [1, 0]]
[[2, 1], [0]]
参见
partitions
, multiset_partitions
sympy.utilities.iterables.least_rotation(x, key=None)
返回获取词汇上最小的字符串/列表/元组等所需的左旋转步骤数。
示例
>>> from sympy.utilities.iterables import least_rotation, rotate_left
>>> a = [3, 1, 5, 1, 2]
>>> least_rotation(a)
3
>>> rotate_left(a, _)
[1, 2, 3, 1, 5]
参考文献
[R1064]
zh.wikipedia.org/wiki/词汇最小化字符串旋转
sympy.utilities.iterables.minlex(seq, directed=True, key=None)
返回序列的旋转,在其中词汇上最小的元素首先出现,例如 (cba \rightarrow acb)。
返回的序列是一个元组,除非输入序列是一个字符串,此时返回一个字符串。
如果directed
为 False,则返回序列和反向序列中较小的那个,例如 (cba \rightarrow abc)。
如果key
不为 None,则用于从可迭代对象的每个元素中提取比较键。
示例
>>> from sympy.combinatorics.polyhedron import minlex
>>> minlex((1, 2, 0))
(0, 1, 2)
>>> minlex((1, 0, 2))
(0, 2, 1)
>>> minlex((1, 0, 2), directed=False)
(0, 1, 2)
>>> minlex('11010011000', directed=True)
'00011010011'
>>> minlex('11010011000', directed=False)
'00011001011'
>>> minlex(('bb', 'aaa', 'c', 'a'))
('a', 'bb', 'aaa', 'c')
>>> minlex(('bb', 'aaa', 'c', 'a'), key=len)
('c', 'a', 'bb', 'aaa')
sympy.utilities.iterables.multiset(seq)
返回可散列序列的多重集形式,其中值是序列中项目的多重性。
示例
>>> from sympy.utilities.iterables import multiset
>>> multiset('mississippi')
{'i': 4, 'm': 1, 'p': 2, 's': 4}
参见
group
sympy.utilities.iterables.multiset_combinations(m, n, g=None)
返回从多重集m
中大小为n
的唯一组合。
示例
>>> from sympy.utilities.iterables import multiset_combinations
>>> from itertools import combinations
>>> [''.join(i) for i in multiset_combinations('baby', 3)]
['abb', 'aby', 'bby']
>>> def count(f, s): return len(list(f(s, 3)))
组合数取决于字母的数量;唯一组合的数量取决于字母的重复方式。
>>> s1 = 'abracadabra'
>>> s2 = 'banana tree'
>>> count(combinations, s1), count(multiset_combinations, s1)
(165, 23)
>>> count(combinations, s2), count(multiset_combinations, s2)
(165, 54)
sympy.utilities.iterables.multiset_derangements(s)
在原地生成集合s
的错排。
示例
>>> from sympy.utilities.iterables import multiset_derangements, uniq
因为多重集合(而不是集合)的错排是原地生成的,如果需要一组错排的副本,则必须进行复制,否则所有值将相同:
>>> list(uniq([i for i in multiset_derangements('1233')]))
[[None, None, None, None]]
>>> [i.copy() for i in multiset_derangements('1233')]
[['3', '3', '1', '2'], ['3', '3', '2', '1']]
>>> [''.join(i) for i in multiset_derangements('1233')]
['3312', '3321']
sympy.utilities.iterables.multiset_partitions(multiset, m=None)
返回给定多重集合的唯一分区(以列表形式)。如果m
为 None,则将返回所有多重集合,否则仅返回具有m
部分的分区。
如果multiset
是整数,则提供一个范围[0, 1, …, multiset - 1]。
示例
>>> from sympy.utilities.iterables import multiset_partitions
>>> list(multiset_partitions([1, 2, 3, 4], 2))
[[[1, 2, 3], [4]], [[1, 2, 4], [3]], [[1, 2], [3, 4]],
[[1, 3, 4], [2]], [[1, 3], [2, 4]], [[1, 4], [2, 3]],
[[1], [2, 3, 4]]]
>>> list(multiset_partitions([1, 2, 3, 4], 1))
[[[1, 2, 3, 4]]]
只返回唯一的分区,并且不管输入的顺序如何,它们将以规范顺序返回:
>>> a = [1, 2, 2, 1]
>>> ans = list(multiset_partitions(a, 2))
>>> a.sort()
>>> list(multiset_partitions(a, 2)) == ans
True
>>> a = range(3, 1, -1)
>>> (list(multiset_partitions(a)) ==
... list(multiset_partitions(sorted(a))))
True
如果省略m
,则将返回所有分区:
>>> list(multiset_partitions([1, 1, 2]))
[[[1, 1, 2]], [[1, 1], [2]], [[1, 2], [1]], [[1], [1], [2]]]
>>> list(multiset_partitions([1]*3))
[[[1, 1, 1]], [[1], [1, 1]], [[1], [1], [1]]]
计数
集合的分区数由贝尔数给出:
>>> from sympy import bell
>>> len(list(multiset_partitions(5))) == bell(5) == 52
True
从大小为 n 的集合中长度为 k 的分区数量由第二类斯特林数给出:
>>> from sympy.functions.combinatorial.numbers import stirling
>>> stirling(5, 2) == len(list(multiset_partitions(5, 2))) == 15
True
这些计数的注释适用于集合,而不是多重集。
注释
当多重集中的所有元素相同时,返回分区的顺序由partitions
例程决定。如果要计数分区,则最好使用nT
函数。
另请参阅
partitions
, sympy.combinatorics.partitions.Partition
, sympy.combinatorics.partitions.IntegerPartition
, sympy.functions.combinatorial.numbers.nT
sympy.utilities.iterables.multiset_permutations(m, size=None, g=None)
返回多重集合m
的唯一排列。
示例
>>> from sympy.utilities.iterables import multiset_permutations
>>> from sympy import factorial
>>> [''.join(i) for i in multiset_permutations('aab')]
['aab', 'aba', 'baa']
>>> factorial(len('banana'))
720
>>> len(list(multiset_permutations('banana')))
60
sympy.utilities.iterables.necklaces(n, k, free=False)
一个用于生成项链的例程,可能(free=True)或者不可以(free=False)被翻转查看。返回的“项链”由n
个整数(珠子)组成,有k
个不同的值(颜色)。只返回唯一的项链。
示例
>>> from sympy.utilities.iterables import necklaces, bracelets
>>> def show(s, i):
... return ''.join(s[j] for j in i)
“无限制项链”有时也被称为“手镯”(一个可以翻转的对象,一个可以反转的序列),术语“项链”用来暗示一个不能被反转的序列。因此,对于手镯(旋转和反转),ACB == ABC,而对于项链,这两个序列是不同的,因为仅仅旋转不能使两个序列相同。
(记忆法:手镯可以反向查看,但项链不行。)
>>> B = [show('ABC', i) for i in bracelets(3, 3)]
>>> N = [show('ABC', i) for i in necklaces(3, 3)]
>>> set(N) - set(B)
{'ACB'}
>>> list(necklaces(4, 2))
[(0, 0, 0, 0), (0, 0, 0, 1), (0, 0, 1, 1),
(0, 1, 0, 1), (0, 1, 1, 1), (1, 1, 1, 1)]
>>> [show('.o', i) for i in bracelets(4, 2)]
['....', '...o', '..oo', '.o.o', '.ooo', 'oooo']
参考
[R1065]
mathworld.wolfram.com/Necklace.html
[R1066]
Frank Ruskey, Carla Savage, and Terry Min Yih Wang, Generating necklaces, Journal of Algorithms 13 (1992), 414-430; doi.org/10.1016/0196-6774(92)90047-G
sympy.utilities.iterables.numbered_symbols(prefix='x', cls=None, start=0, exclude=(), *args, **assumptions)
生成由前缀和递增下标组成的符号的无限流,前提是它们不会出现在exclude
中。
参数:
prefix:str,可选
要使用的前缀。默认情况下,此函数将生成形式为“x0”、“x1”等的符号。
cls:class,可选
要使用的类。默认情况下,它使用
Symbol
,但您也可以使用Wild
或Dummy
。
start:int,可选
起始编号。默认情况下为 0。
exclude:list、tuple、cls 的集合,可选
要排除的符号。
***args, kwargs
传递给cls类的额外位置和关键字参数。
返回:
sym:符号
带下标的符号。
sympy.utilities.iterables.ordered_partitions(n, m=None, sort=True)
生成整数n的有序分区。
参数:
n:int
m:int,可选
默认值提供所有尺寸的分区,否则只提供尺寸为 m 的分区。此外,如果m不为 None,则会生成就地分区(请参见示例)。
sort:bool,默认为 True
控制在m不为 None 时是否返回排序的分区;当 False 时,分区尽快返回并排序元素,但当 m|n 时,分区将不按升序字典顺序返回。
示例
>>> from sympy.utilities.iterables import ordered_partitions
所有大小为 5 的分区按升序字典顺序排列:
>>> for p in ordered_partitions(5):
... print(p)
[1, 1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 3]
[1, 2, 2]
[1, 4]
[2, 3]
[5]
只有两个部分的大小为 5 的分区:
>>> for p in ordered_partitions(5, 2):
... print(p)
[1, 4]
[2, 3]
当给定m
时,由于速度原因,将多次使用给定列表对象,因此除非在生成时复制每个对象,否则将无法看到正确的分区:
>>> [p for p in ordered_partitions(7, 3)]
[[1, 1, 1], [1, 1, 1], [1, 1, 1], [2, 2, 2]]
>>> [list(p) for p in ordered_partitions(7, 3)]
[[1, 1, 5], [1, 2, 4], [1, 3, 3], [2, 2, 3]]
当n
是m
的倍数时,元素仍然被排序,但如果 sort 为 False,则分区本身将是无序的;默认是以升序字典顺序返回它们。
>>> for p in ordered_partitions(6, 2):
... print(p)
[1, 5]
[2, 4]
[3, 3]
但是,如果速度比顺序更重要,则可以将排序设置为 False:
>>> for p in ordered_partitions(6, 2, sort=False):
... print(p)
[1, 5]
[3, 3]
[2, 4]
参考文献
[R1067]
生成整数分区,[在线],可用:jeromekelleher.net/generating-integer-partitions.html
[R1068]
Jerome Kelleher 和 Barry O’Sullivan,“生成所有分区:两种编码的比较”,[在线],可用:arxiv.org/pdf/0909.2331v2.pdf
sympy.utilities.iterables.partitions(n, m=None, k=None, size=False)
生成正整数 n 的所有分区。
每个分区都表示为字典,将整数映射到分区中该整数的副本数。例如,返回的第一个大小为 4 的分区是{4: 1},“4:其中一个”。
参数:
n:int
m:int,可选
限制分区中部分的数量(助记符:m,最大部分)
k:int,可选
限制保留在分区中的数字(助记符:k,键)
size:bool,默认为 False
如果为
True
,则返回(M, P),其中 M 是多重度的总和,P 是生成的分区。如果为False
,则仅返回生成的分区。
示例
>>> from sympy.utilities.iterables import partitions
在分区中出现的数字(返回字典的键)限制为 k:
>>> for p in partitions(6, k=2):
... print(p)
{2: 3}
{1: 2, 2: 2}
{1: 4, 2: 1}
{1: 6}
分区中的部分数目最多为分区中的值之和(返回的字典中的值之和),受 m 限制(默认值为 None,给出从 1 到 n 的分区):
>>> for p in partitions(6, m=2):
... print(p)
...
{6: 1}
{1: 1, 5: 1}
{2: 1, 4: 1}
{3: 2}
另见
sympy.combinatorics.partitions.Partition
,sympy.combinatorics.partitions.IntegerPartition
参考文献
[R1069]
修改自 Tim Peter 的版本,以允许 k 和 m 值:code.activestate.com/recipes/218332-generator-for-integer-partitions/
sympy.utilities.iterables.permute_signs(t)
返回一个迭代器,其中 t 的非零元素的符号被排列。
示例
>>> from sympy.utilities.iterables import permute_signs
>>> list(permute_signs((0, 1, 2)))
[(0, 1, 2), (0, -1, 2), (0, 1, -2), (0, -1, -2)]
sympy.utilities.iterables.postfixes(seq)
生成序列的所有后缀。
示例
>>> from sympy.utilities.iterables import postfixes
>>> list(postfixes([1,2,3,4]))
[[4], [3, 4], [2, 3, 4], [1, 2, 3, 4]]
sympy.utilities.iterables.prefixes(seq)
生成序列的所有前缀。
示例
>>> from sympy.utilities.iterables import prefixes
>>> list(prefixes([1,2,3,4]))
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]
sympy.utilities.iterables.random_derangement(t, choice=None, strict=True)
返回一个元素列表,其中没有元素处于原始位置。如果一个元素填充了超过一半的位置,则会引发错误,因为不可能有一个置换。要获得尽可能多项目的置换 - 一些最多的保留在它们的原始位置 - 通过传递像 choice
这样的伪随机选择器来产生一个伪随机置换(见下文)。
示例
>>> from sympy.utilities.iterables import random_derangement
>>> t = 'SymPy: a CAS in pure Python'
>>> d = random_derangement(t)
>>> all(i != j for i, j in zip(d, t))
True
使用伪随机生成器选择可以得到可预测的结果:
>>> from sympy.core.random import seed, choice as c
>>> seed(1)
>>> d = [''.join(random_derangement(t, c)) for i in range(5)]
>>> assert len(set(d)) != 1 # we got different values
通过重新播种,可以获得相同的序列:
>>> seed(1)
>>> d2 = [''.join(random_derangement(t, c)) for i in range(5)]
>>> assert d == d2
sympy.utilities.iterables.reshape(seq, how)
根据 how
中的模板重新整形序列。
示例
>>> from sympy.utilities import reshape
>>> seq = list(range(1, 9))
>>> reshape(seq, [4]) # lists of 4
[[1, 2, 3, 4], [5, 6, 7, 8]]
>>> reshape(seq, (4,)) # tuples of 4
[(1, 2, 3, 4), (5, 6, 7, 8)]
>>> reshape(seq, (2, 2)) # tuples of 4
[(1, 2, 3, 4), (5, 6, 7, 8)]
>>> reshape(seq, (2, [2])) # (i, i, [i, i])
[(1, 2, [3, 4]), (5, 6, [7, 8])]
>>> reshape(seq, ((2,), [2])) # etc....
[((1, 2), [3, 4]), ((5, 6), [7, 8])]
>>> reshape(seq, (1, [2], 1))
[(1, [2, 3], 4), (5, [6, 7], 8)]
>>> reshape(tuple(seq), ([[1], 1, (2,)],))
(([[1], 2, (3, 4)],), ([[5], 6, (7, 8)],))
>>> reshape(tuple(seq), ([1], 1, (2,)))
(([1], 2, (3, 4)), ([5], 6, (7, 8)))
>>> reshape(list(range(12)), [2, [3], {2}, (1, (3,), 1)])
[[0, 1, [2, 3, 4], {5, 6}, (7, (8, 9, 10), 11)]]
sympy.utilities.iterables.rotate_left(x, y)
左旋转列表 x 按 y 中指定的步数。
示例
>>> from sympy.utilities.iterables import rotate_left
>>> a = [0, 1, 2]
>>> rotate_left(a, 1)
[1, 2, 0]
sympy.utilities.iterables.rotate_right(x, y)
右旋转列表 x 按 y 中指定的步数。
示例
>>> from sympy.utilities.iterables import rotate_right
>>> a = [0, 1, 2]
>>> rotate_right(a, 1)
[2, 0, 1]
sympy.utilities.iterables.rotations(s, dir=1)
返回一个生成器,将 s 中的项作为列表给出,其中每个后续列表相对于前一个列表向左(默认)或向右(dir=-1
)旋转。
示例
>>> from sympy import rotations
>>> list(rotations([1,2,3]))
[[1, 2, 3], [2, 3, 1], [3, 1, 2]]
>>> list(rotations([1,2,3], -1))
[[1, 2, 3], [3, 1, 2], [2, 3, 1]]
sympy.utilities.iterables.roundrobin(*iterables)
roundrobin 配方取自 itertools 文档:docs.python.org/3/library/itertools.html#itertools-recipes
roundrobin('ABC', 'D', 'EF') –> A D E B F C
由 George Sakkis 贡献的配方
sympy.utilities.iterables.runs(seq, op=<built-in function gt>)
将序列分组成列表,其中连续元素都使用比较运算符 op
相同:op(seq[i + 1], seq[i]) 从一个运行中的所有元素为 True。
示例
>>> from sympy.utilities.iterables import runs
>>> from operator import ge
>>> runs([0, 1, 2, 2, 1, 4, 3, 2, 2])
[[0, 1, 2], [2], [1, 4], [3], [2], [2]]
>>> runs([0, 1, 2, 2, 1, 4, 3, 2, 2], op=ge)
[[0, 1, 2, 2], [1, 4], [3], [2, 2]]
sympy.utilities.iterables.sequence_partitions(l, n, /)
返回序列 (l) 的分区为 (n) 个箱子
参数:
l : Sequence[T]
任意 Python 对象的非空序列
n : int
正整数
产生:
out : list[Sequence[T]]
一个序列列表,其连接等于 (l)。这应符合 (l) 的类型。
解释
给定序列 (l_1 \cdots l_m \in V^+),其中 (V^+) 是 (V) 的 Kleene 加号
(l) 的 (n) 个分区集合定义为:
[{(s_1, \cdots, s_n) | s_1 \in V^+, \cdots, s_n \in V^+, s_1 \cdots s_n = l_1 \cdots l_m}]
示例
>>> from sympy.utilities.iterables import sequence_partitions
>>> for out in sequence_partitions([1, 2, 3, 4], 2):
... print(out)
[[1], [2, 3, 4]]
[[1, 2], [3, 4]]
[[1, 2, 3], [4]]
笔记
这是对 EnricoGiampieri 的分区生成器的修改版本,来源于 stackoverflow.com/questions/13131491/partition-n-items-into-k-bins-in-python-lazily
参见
sequence_partitions_empty
sympy.utilities.iterables.sequence_partitions_empty(l, n, /)
返回序列 (l) 的分区,分为 (n) 个空序列
参数:
l : Sequence[T]
任意 Python 对象的序列(可能为空)
n : int
一个正整数
产生:
out : list[Sequence[T]]
一个序列的列表,其连接等于 (l)。这应符合 (l) 的类型。
解释
给定序列 (l_1 \cdots l_m \in V^),其中 (V^) 是 (V) 的 Kleene 星号
(l) 的 (n) 个分区集合被定义为:
[{(s_1, \cdots, s_n) | s_1 \in V^, \cdots, s_n \in V^, s_1 \cdots s_n = l_1 \cdots l_m}]
与 sequence_partitions()
相比,有更多的组合,因为空序列可以填充到任何地方,因此我们尝试为此提供不同的实用工具。
示例
>>> from sympy.utilities.iterables import sequence_partitions_empty
>>> for out in sequence_partitions_empty([1, 2, 3, 4], 2):
... print(out)
[[], [1, 2, 3, 4]]
[[1], [2, 3, 4]]
[[1, 2], [3, 4]]
[[1, 2, 3], [4]]
[[1, 2, 3, 4], []]
参见
sequence_partitions
sympy.utilities.iterables.sift(seq, keyfunc, binary=False)
根据 keyfunc
对序列 seq
进行筛选。
返回:
当 binary
为 False
(默认)时,输出是一个字典
其中 seq
的元素存储在一个列表中,以值为键
对于该元素的 keyfunc。如果 binary
为 True,则返回一个元组
返回 T
和 F
的列表,其中 T
是一个列表
包含了 seq 的元素,其中 keyfunc
为 True
,并且
包含那些 keyfunc
为 False
的元素的 F
;
如果 keyfunc
不是二进制的,则会引发 ValueError。
示例
>>> from sympy.utilities import sift
>>> from sympy.abc import x, y
>>> from sympy import sqrt, exp, pi, Tuple
>>> sift(range(5), lambda x: x % 2)
{0: [0, 2, 4], 1: [1, 3]}
sift() 返回一个 defaultdict() 对象,因此任何没有匹配的键都会返回 []。
>>> sift([x], lambda x: x.is_commutative)
{True: [x]}
>>> _[False]
[]
有 有时您不知道将获得多少个键:
>>> sift([sqrt(x), exp(x), (y**x)**2],
... lambda x: x.as_base_exp()[0])
{E: [exp(x)], x: [sqrt(x)], y: [y**(2*x)]}
有时您希望结果是二进制的;结果可以通过将 binary
设置为 True 来解包:
>>> sift(range(4), lambda x: x % 2, binary=True)
([1, 3], [0, 2])
>>> sift(Tuple(1, pi), lambda x: x.is_rational, binary=True)
([1], [pi])
如果谓词实际上不是二进制的(这是用于测试筛选逻辑并且期望二进制结果的好测试)则引发 ValueError:
>>> unknown = exp(1) - pi # the rationality of this is unknown
>>> args = Tuple(1, pi, unknown)
>>> sift(args, lambda x: x.is_rational, binary=True)
Traceback (most recent call last):
...
ValueError: keyfunc gave non-binary output
非二进制筛选显示产生了 3 个键:
>>> set(sift(args, lambda x: x.is_rational).keys())
{None, False, True}
如果需要对筛选后的项目进行排序,最好使用 ordered
,它可以在排序时将多个排序键经济地应用于序列。
参见
ordered
sympy.utilities.iterables.signed_permutations(t)
返回迭代器,其中 t 的非零元素的符号和元素的顺序被排列,并且所有返回的值都是唯一的。
示例
>>> from sympy.utilities.iterables import signed_permutations
>>> list(signed_permutations((0, 1, 2)))
[(0, 1, 2), (0, -1, 2), (0, 1, -2), (0, -1, -2), (0, 2, 1),
(0, -2, 1), (0, 2, -1), (0, -2, -1), (1, 0, 2), (-1, 0, 2),
(1, 0, -2), (-1, 0, -2), (1, 2, 0), (-1, 2, 0), (1, -2, 0),
(-1, -2, 0), (2, 0, 1), (-2, 0, 1), (2, 0, -1), (-2, 0, -1),
(2, 1, 0), (-2, 1, 0), (2, -1, 0), (-2, -1, 0)]
sympy.utilities.iterables.strongly_connected_components(G)
有向图的强连通分量按反向拓扑顺序排列。
参数:
G : tuple[list, list[tuple[T, T]]
由顶点列表和边列表组成的元组,其中强连通分量的图将被找到。
示例
考虑一个有向图(使用点表示法):
digraph {
A -> B
A -> C
B -> C
C -> B
B -> D
}
有向图 { A -> B A -> C B -> C C -> B B -> D }
其中顶点是字母 A、B、C 和 D。此图可以使用 Python 的基本数据结构编码,如下所示:
>>> V = ['A', 'B', 'C', 'D']
>>> E = [('A', 'B'), ('A', 'C'), ('B', 'C'), ('C', 'B'), ('B', 'D')]
此图的强连通分量可以计算为
>>> from sympy.utilities.iterables import strongly_connected_components
>>> strongly_connected_components((V, E))
[['D'], ['B', 'C'], ['A']]
这也按照反向拓扑顺序给出组件。
由于包含 B 和 C 的子图具有循环,它们必须作为一个强连通分量出现。A 和 D 与图的其余部分连接,但不是以循环方式连接,因此它们会作为它们自己的强连通分量出现。
注释
图的顶点必须可散列以供所使用的数据结构使用。如果顶点不可散列,请用整数索引替换它们。
此函数使用 Tarjan 算法以 (O(|V|+|E|))(线性)时间计算强连通分量。
另请参见
sympy.utilities.iterables.connected_components
参考文献
[R1070]
en.wikipedia.org/wiki/Strongly_connected_component
[R1071]
en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
sympy.utilities.iterables.subsets(seq, k=None, repetition=False)
从 (n)-元素集合 seq
生成所有 (k)-子集(组合)。
一个 (n)-元素集合的 (k)-子集是长度为 (k) 的任意子集。 (n)-元素集合的 (k)-子集数由 binomial(n, k)
给出,总共有 (2^n) 个子集。如果 (k) 是 None
,则将按从最短到最长的顺序返回所有 (2^n) 个子集。
示例
>>> from sympy import subsets
subsets(seq, k)
将返回不重复的 (\frac{n!}{k!(n - k)!}) 个 (k)-子集(组合):
>>> list(subsets([1, 2], 2))
[(1, 2)]
>>> list(subsets([1, 2]))
[(), (1,), (2,), (1, 2)]
>>> list(subsets([1, 2, 3], 2))
[(1, 2), (1, 3), (2, 3)]
subsets(seq, k, repetition=True)
将返回带有重复的 (\frac{(n - 1 + k)!}{k!(n - 1)!}) 组合:
>>> list(subsets([1, 2], 2, repetition=True))
[(1, 1), (1, 2), (2, 2)]
如果要求的项数超过集合中的项数,则会返回空集,除非允许重复:
>>> list(subsets([0, 1], 3, repetition=False))
[]
>>> list(subsets([0, 1], 3, repetition=True))
[(0, 0, 0), (0, 0, 1), (0, 1, 1), (1, 1, 1)]
sympy.utilities.iterables.take(iter, n)
从 iter
迭代器返回 n
个项。
sympy.utilities.iterables.topological_sort(graph, key=None)
图的顶点的拓扑排序。
参数:
graph:元组[list, list[tuple[T, T]]
由图的顶点列表和边列表组成的元组,用于对图进行拓扑排序。
key:callable[T](可选)
在同一级别上对顶点进行排序的键。默认情况下使用自然(如词典)排序(在这种情况下,基本类型必须实现排序关系)。
示例
考虑一个图:
+---+ +---+ +---+
| 7 |\ | 5 | | 3 |
+---+ \ +---+ +---+
| _\___/ ____ _/ |
| / \___/ \ / |
V V V V |
+----+ +---+ |
| 11 | | 8 | |
+----+ +---+ |
| | \____ ___/ _ |
| \ \ / / \ |
V \ V V / V V
+---+ \ +---+ | +----+
| 2 | | | 9 | | | 10 |
+---+ | +---+ | +----+
\________/
其中顶点是整数。此图可以使用 Python 的基本数据结构进行编码,如下所示:
>>> V = [2, 3, 5, 7, 8, 9, 10, 11]
>>> E = [(7, 11), (7, 8), (5, 11), (3, 8), (3, 10),
... (11, 2), (11, 9), (11, 10), (8, 9)]
要计算图 (V, E)
的拓扑排序,请执行:
>>> from sympy.utilities.iterables import topological_sort
>>> topological_sort((V, E))
[3, 5, 7, 8, 11, 2, 9, 10]
如果需要特定的破解方法,请使用 key
参数:
>>> topological_sort((V, E), key=lambda v: -v)
[7, 5, 11, 3, 10, 8, 9, 2]
只有非循环图可以进行排序。如果输入图有循环,则会引发 ValueError
:
>>> topological_sort((V, E + [(10, 7)]))
Traceback (most recent call last):
...
ValueError: cycle detected
参考文献
[R1072]
en.wikipedia.org/wiki/Topological_sorting
sympy.utilities.iterables.unflatten(iter, n=2)
将iter
中的项分组成长度为n
的元组。如果iter
的长度不是n
的倍数,则会引发错误。
sympy.utilities.iterables.uniq(seq, result=None)
将seq
中的唯一元素作为迭代器返回。第二个参数result
在内部使用;对于此参数,不需要传递任何内容。
注意:在迭代过程中更改序列将引发 RuntimeError(如果序列的大小已知);如果传递一个迭代器并推进迭代器,您将更改此例程的输出,但不会收到警告。
Examples
>>> from sympy.utilities.iterables import uniq
>>> dat = [1, 4, 1, 5, 4, 2, 1, 2]
>>> type(uniq(dat)) in (list, tuple)
False
>>> list(uniq(dat))
[1, 4, 5, 2]
>>> list(uniq(x for x in dat))
[1, 4, 5, 2]
>>> list(uniq([[1], [2, 1], [1]]))
[[1], [2, 1]]
sympy.utilities.iterables.variations(seq, n, repetition=False)
返回seq
的大小为 N 的 n 元变异的迭代器。repetition
控制seq
中的项是否可以多次出现;
Examples
variations(seq, n)
将返回seq
元素的无重复排列的(\frac{N!}{(N - n)!}):
>>> from sympy import variations
>>> list(variations([1, 2], 2))
[(1, 2), (2, 1)]
variations(seq, n, True)
将返回允许元素重复的(N^n)排列:
>>> list(variations([1, 2], 2, repetition=True))
[(1, 1), (1, 2), (2, 1), (2, 2)]
如果你请求的项数超过集合中的项数,则会得到空集,除非允许重复:
>>> list(variations([0, 1], 3, repetition=False))
[]
>>> list(variations([0, 1], 3, repetition=True))[:4]
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1)]
See also
itertools.permutations, itertools.product
variations
variations(seq, n) 返回大小为 n 的列表的所有变异。
有一个可选的第三个参数。必须是布尔值,如果设置为 True,则方法返回带重复项的变异,如果设置为 False,则返回不带重复项的变异。
Examples::
>>> from sympy.utilities.iterables import variations
>>> list(variations([1,2,3], 2))
[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
>>> list(variations([1,2,3], 2, True))
[(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)]
partitions
虽然组合模块包含用于研究和操作分区的 Partition 和 IntegerPartition 类,但有一些函数可生成分区,可用作低级工具进行例程:partitions
和multiset_partitions
。前者提供整数分区,后者提供元素的枚举分区。还有一个名为kbins
的例程,它将给出分区的各种排列。为了将分区作为列表而不是字典获取,有ordered_partition
函数,其速度相当快。最后,为了简单地获得分区数量的计数,有nT
函数。
See Also
sympy.utilities.iterables.ordered_partitions, sympy.functions.combinatorial.numbers.nT
partitions:
>>> from sympy.utilities.iterables import partitions
>>> [p.copy() for s, p in partitions(7, m=2, size=True) if s == 2]
[{1: 1, 6: 1}, {2: 1, 5: 1}, {3: 1, 4: 1}]
multiset_partitions:
>>> from sympy.utilities.iterables import multiset_partitions
>>> [p for p in multiset_partitions(3, 2)]
[[[0, 1], [2]], [[0, 2], [1]], [[0], [1, 2]]]
>>> [p for p in multiset_partitions([1, 1, 1, 2], 2)]
[[[1, 1, 1], [2]], [[1, 1, 2], [1]], [[1, 1], [1, 2]]]
kbins:
>>> from sympy.utilities.iterables import kbins
>>> def show(k):
... rv = []
... for p in k:
... rv.append(','.join([''.join(j) for j in p]))
... return sorted(rv)
...
>>> show(kbins("ABCD", 2))
['A,BCD', 'AB,CD', 'ABC,D']
>>> show(kbins("ABC", 2))
['A,BC', 'AB,C']
>>> show(kbins("ABC", 2, ordered=0)) # same as multiset_partitions
['A,BC', 'AB,C', 'AC,B']
>>> show(kbins("ABC", 2, ordered=1))
['A,BC', 'A,CB',
'B,AC', 'B,CA',
'C,AB', 'C,BA']
>>> show(kbins("ABC", 2, ordered=10))
['A,BC', 'AB,C', 'AC,B',
'B,AC', 'BC,A',
'C,AB']
>>> show(kbins("ABC", 2, ordered=11))
['A,BC', 'A,CB', 'AB,C', 'AC,B',
'B,AC', 'B,CA', 'BA,C', 'BC,A',
'C,AB', 'C,BA', 'CA,B', 'CB,A']
Lambdify
此模块提供便捷函数,将 SymPy 表达式转换为可以快速计算数值的 lambda 函数。
sympy.utilities.lambdify.implemented_function(symfunc, implementation)
将数值 implementation
添加到函数 symfunc
中。
symfunc
可以是一个 UndefinedFunction
实例,或者是一个名称字符串。在后一种情况下,我们将创建一个具有该名称的 UndefinedFunction
实例。
请注意,这是一个快速的解决方法,而不是创建特殊符号函数的通用方法。如果要创建一个可以由 SymPy 所有机制使用的符号函数,您应该子类化 Function
类。
参数:
symfunc:str
或 UndefinedFunction
实例
如果是
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 函数替换为
scipy
或numpy
函数(如果可用),或 Python 的标准库math
或mpmath
函数(否则)。模块可以是以下类型之一:
- 字符串
"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 函数 sin
和 cos
创建了 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
。但是,在第一个文件中,sin
和cos
被定义为 SymPy 的sin
和cos
。在第二个文件中,它们被定义为 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 的符号sin
和cos
函数。在第二种情况下,我们得到了一个数值结果,因为sin_cos
使用了 NumPy 的数值sin
和cos
函数。但请注意,使用的sin
和cos
的版本并不是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)
,其中sin
和cos
来自numpy
命名空间。这也是为什么lambdify
中符号参数在第一位,而不是大多数 SymPy 函数中表达式之后的原因:为了更好地模仿lambda
关键字。
lambdify
接受输入表达式(例如sin(x) + cos(x)
)并
-
将其转换为字符串
-
基于传入的模块创建一个模块全局字典(默认情况下使用 NumPy 模块)
-
创建字符串
"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
命名空间中的sin
和cos
将是numpy.sin
和numpy.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]
杂项
不属于其他地方的各种杂项。
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()
。
请参见
strlines
,rawlines
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'
' '
)
请参见
filldedent
,strlines
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
源代码检查
该模块为交互式源代码检查添加了几个函数。
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')
时间工具
当 IPython 不可用时,用于计时函数执行的简单工具。
sympy.utilities.timeutils.timed(func, setup='pass', limit=None)
自适应地测量函数的执行时间。
交互式
用于设置交互式 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_print
为True
时才相关。
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:
可以使用
latex
和pretty
命令的任何额外设置来微调输出。
示例
>>> 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.latex
,sympy.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
解析
解析函数参考
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()
的标准转换。插入对Symbol
、Integer
和其他 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 基础的解析器不支持的额外功能。它们包括:
-
检测模棱两可的表达式,以及
-
允许在运行时定制 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
可以是matrix
、bmatrix
、pmatrix
、smallmatrix
和array
之一。 -
矩阵操作,如矩阵加法、标量与矩阵乘法、矩阵与矩阵乘法。
-
高阶导数和偏导数。
-
双重和三重积分。
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