SymPy 1.13 中文文档(四十三)
工具
该模块包含一些跨 SymPy 使用的通用工具。
内容:
-
自动包装模块
-
代码生成
-
装饰器
-
枚举
-
异常和警告
-
可迭代对象
-
Lambda 化
-
记忆化
-
杂项
-
源代码检查
-
时间工具
Autowrap 模块
autowrap 模块与 Tensor 的 Indexed 类协同工作非常出色。以下是一个简单的示例,展示如何设置计算矩阵-向量乘积的二进制例程。
>>> from sympy.utilities.autowrap import autowrap
>>> from sympy import symbols, IndexedBase, Idx, Eq
>>> A, x, y = map(IndexedBase, ['A', 'x', 'y'])
>>> m, n = symbols('m n', integer=True)
>>> i = Idx('i', m)
>>> j = Idx('j', n)
>>> instruction = Eq(y[i], A[i, j]*x[j]); instruction
Eq(y[i], A[i, j]*x[j])
因为代码打印程序将具有重复索引的 Indexed 对象视为求和,上述相等实例将转换为矩阵向量乘积的低级代码。这是告诉 SymPy 生成代码、编译它并将其封装为 Python 函数的方法:
>>> matvec = autowrap(instruction)
就这样。现在让我们用一些 numpy 数组来测试它。默认的封装器后端是 f2py。它提供的封装函数设置为接受 Python 列表,它会悄悄地将其转换为 numpy 数组。所以我们可以像这样测试矩阵向量乘积:
>>> M = [[0, 1],
... [1, 0]]
>>> matvec(M, [2, 3])
[ 3\. 2.]
实现细节
autowrap 模块是由 CodeWrapper 对象组成的后端实现。基类 CodeWrapper 处理模块名称、文件名和选项的详细信息。它还包含驱动程序例程,按正确顺序执行所有步骤,并负责设置和移除临时工作目录。
实际的编译和封装由外部资源完成,例如系统安装的 f2py 命令。Cython 后端在子进程中运行 distutils 设置脚本。CodeWrapper 的子类负责这些依赖于后端的细节。
API 参考
用于编译 codegen 输出并封装二进制以供 Python 使用的模块。
注意
要使用 autowrap 模块,必须先导入它。
>>> from sympy.utilities.autowrap import autowrap
该模块为不同的外部后端(如 f2py、fwrap、Cython、SWIG(?) 等)提供了一个通用接口。(目前仅实现了 f2py 和 Cython)目标是通过单按钮用户界面提供性能可接受的编译二进制访问。
>>> from sympy.abc import x,y
>>> expr = (x - y)**25
>>> flat = expr.expand()
>>> binary_callable = autowrap(flat)
>>> binary_callable(2, 3)
-1.0
尽管 SymPy 用户主要关注与数学表达式的工作,而不是在数值形式下有效评估这些表达式所需的封装工具的细节,但用户在没有对目标语言的限制有一定理解的情况下无法实现。例如,扩展表达式包含大系数,计算该表达式时会导致精度损失:
>>> binary_callable(3, 2)
0.0
>>> binary_callable(4, 5), binary_callable(5, 4)
(-22925376.0, 25165824.0)
封装未扩展的表达式会产生预期的行为:
>>> e = autowrap(expr)
>>> e(4, 5), e(5, 4)
(-1.0, 1.0)
autowrap() 返回的可调用对象是一个二进制的 Python 函数,而不是 SymPy 对象。如果希望在符号表达式中使用编译后的函数,最好使用 binary_function(),它返回一个 SymPy 函数对象。二进制可调用对象附加在 _imp_ 属性上,当使用 evalf() 或 lambdify() 请求数值评估时被调用。
>>> from sympy.utilities.autowrap import binary_function
>>> f = binary_function('f', expr)
>>> 2*f(x, y) + y
y + 2*f(x, y)
>>> (2*f(x, y) + y).evalf(2, subs={x: 1, y:2})
0.e-110
这在什么情况下有用?
- 对于大型数组的计算,Python 迭代可能太慢,根据数学表达式,可能难以利用 NumPy 提供的高级索引操作。
- 对于真正长的将被重复调用的表达式,编译后的二进制文件应比 SymPy 的.evalf()显著更快。
- 如果您正在使用 codegen 实用程序生成代码以在另一个项目中使用它,则自动的 Python 包装器可以让您立即从 SymPy 内部测试二进制文件。
- 为了创建用于 numpy 数组的定制 ufuncs。参见ufuncify。
何时此模块不是最佳方法?
- 如果您真的关心速度或内存优化,可能直接使用包装工具和低级代码会有更好的效果。但是,此实用程序生成的文件可能提供一个有用的起点和参考代码。如果提供了关键字 tempdir="path/to/files/",则临时文件将保持不变。
- 如果数组计算可以很容易地由 numpy 处理,并且您不需要为另一个项目的二进制文件。
class sympy.utilities.autowrap.CodeWrapper(generator, filepath=None, flags=[], verbose=False)
用于代码包装器的基类
class sympy.utilities.autowrap.CythonCodeWrapper(*args, **kwargs)
使用 Cython 的包装器
dump_pyx(routines, f, prefix)
编写一个带有 Python 包装的 Cython 文件
此文件包含 c 代码中所有例程的定义,并引用头文件。
参数
routines
例程列表
f
要写入文件的类文件对象
前缀
用于引用适当头文件的文件名前缀。仅使用前缀的基本名称。
class sympy.utilities.autowrap.DummyWrapper(generator, filepath=None, flags=[], verbose=False)
用于独立于后端测试的类
class sympy.utilities.autowrap.F2PyCodeWrapper(*args, **kwargs)
使用 f2py 的包装器
class sympy.utilities.autowrap.UfuncifyCodeWrapper(*args, **kwargs)
Ufuncify 的包装器
dump_c(routines, f, prefix, funcname=None)
编写一个带有 Python 包装的 C 文件
此文件包含 c 代码中所有例程的定义。
参数
routines
例程列表
f
要写入文件的类文件对象
前缀
用于命名导入模块的文件名前缀。
funcname
要返回的主函数的名称。
sympy.utilities.autowrap.autowrap(expr, language=None, backend='f2py', tempdir=None, args=None, flags=None, verbose=False, helpers=None, code_gen=None, **kwargs)
基于数学表达式生成 Python 可调用二进制文件。
参数:
expr
应包装为二进制例程的 SymPy 表达式。
language:字符串,可选的
如果提供(选项:'C'或'F95'),则指定生成代码的语言。如果
None(默认),则根据指定的后端推断语言。
backend:字符串,可选的
用于包装生成代码的后端。可以是'f2py' [默认]或'cython'。
tempdir:字符串,可选的
用于临时文件的目录路径。如果提供了此参数,则在指定路径中保留生成的代码和包装器输入文件。
args:可迭代的,可选的
有序的符号可迭代对象。指定函数的参数序列。
flags:可迭代的,可选的
附加选项标志,将传递给后端。
verbose:布尔值,可选的
如果为 True,则 autowrap 将不会静音命令行后端。这对于调试可能很有帮助。
helpers:3 元组或 3 元组的可迭代对象,可选的
用于定义主表达式所需的辅助表达式。如果主表达式需要调用特殊函数,则应通过
helpers传递。Autowrap 然后确保编译的主表达式可以链接到辅助例程。项目应该是 3 元组(<function_name>,<sympy_expression>,<argument_tuple>)。必须向辅助例程提供参数序列。
code_gen:CodeGen 实例
CodeGen 子类的实例。覆盖
language。
include_dirs:[字符串]
用于搜索 C/C++头文件的目录列表(以 Unix 格式以保证可移植性)。
library_dirs:[字符串]
用于在链接时搜索 C/C++库的目录列表。
libraries:[字符串]
一个库名称列表(不是文件名或路径),用于链接。
extra_compile_args:[字符串]
编译源文件时使用的任何额外的平台和编译器特定信息在‘sources’中。对于“命令行”有意义的平台和编译器,这通常是一系列命令行参数,但对于其他平台,它可能是任何内容。
extra_link_args:[字符串]
用于将对象文件链接在一起创建扩展(或创建新的静态 Python 解释器)时使用的任何额外的平台和编译器特定信息。与'extra_compile_args'的类似解释。
示例
>>> from sympy.abc import x, y, z
>>> from sympy.utilities.autowrap import autowrap
>>> expr = ((x - y + z)**(13)).expand()
>>> binary_func = autowrap(expr)
>>> binary_func(1, 4, 2)
-1.0
sympy.utilities.autowrap.binary_function(symfunc, expr, **kwargs)
返回具有 expr 作为二进制实现的 SymPy 函数。
这是一个便利函数,自动完成将 SymPy 表达式包装到 Function 对象中并用 implemented_function()实现的步骤。
参数:
symfunc:SymPy 函数
绑定可调用对象的函数。
expr:SymPy 表达式
用于生成函数的表达式。
kwargs:字典
autowrap 接受的任何 kwargs。
示例
>>> from sympy.abc import x, y
>>> from sympy.utilities.autowrap import binary_function
>>> expr = ((x - y)**(25)).expand()
>>> f = binary_function('f', expr)
>>> type(f)
<class 'sympy.core.function.UndefinedFunction'>
>>> 2*f(x, y)
2*f(x, y)
>>> f(x, y).evalf(2, subs={x: 1, y: 2})
-1.0
sympy.utilities.autowrap.ufuncify(args, expr, language=None, backend='numpy', tempdir=None, flags=None, verbose=False, helpers=None, **kwargs)
生成一个在 numpy 数组上支持广播的二进制函数。
参数:
args:可迭代
符号或符号的可迭代。指定函数的参数序列。
expr
定义逐元素操作的 SymPy 表达式。
language:字符串,可选的
如果提供(选项:'C'或'F95'),则指定生成代码的语言。如果为
None[默认],则根据指定的后端推断语言。
backend:字符串,可选的
用于包装生成的代码的后端。要么是'numpy' [默认],'cython'或'f2py'。
tempdir:字符串,可选的
临时文件目录的路径。如果提供了此参数,则生成的代码和包装器输入文件将保留在指定的路径中。
flags:可迭代的,可选的
将传递给后端的额外选项标志。
verbose:布尔值,可选的
如果为 True,autowrap 将不会将命令行后端静音。这对于调试很有帮助。
helpers:可迭代的,可选的
用于定义主表达式所需的辅助表达式。如果主表达式需要调用特定函数,则应将其放入
helpers可迭代对象中。Autowrap 将确保编译的主表达式可以链接到辅助例程。项目应为元组(<函数名>,<sympy 表达式>,<参数>)。向辅助例程提供参数序列是强制性的。
kwargs:dict
如果使用‘f2py’或‘cython’后端,这些 kwargs 将传递给 autowrap,并且如果使用‘numpy’后端,则会被忽略。
注意
默认后端(‘numpy’)将创建实际的numpy.ufunc实例。这些支持 n 维广播和隐式类型转换。使用其他后端将导致“ufunc-like”函数,它要求所有参数都是相等长度的一维数组,并且不会执行任何类型转换。
示例
>>> from sympy.utilities.autowrap import ufuncify
>>> from sympy.abc import x, y
>>> import numpy as np
>>> f = ufuncify((x, y), y + x**2)
>>> type(f)
<class 'numpy.ufunc'>
>>> f([1, 2, 3], 2)
array([ 3., 6., 11.])
>>> f(np.arange(5), 3)
array([ 3., 4., 7., 12., 19.])
对于‘f2py’和‘cython’后端,输入必须是相等长度的一维数组。‘f2py’后端将执行类型转换,但如果输入类型不符合预期,Cython 后端将报错。
>>> f_fortran = ufuncify((x, y), y + x**2, backend='f2py')
>>> f_fortran(1, 2)
array([ 3.])
>>> f_fortran(np.array([1, 2, 3]), np.array([1.0, 2.0, 3.0]))
array([ 2., 6., 12.])
>>> f_cython = ufuncify((x, y), y + x**2, backend='Cython')
>>> f_cython(1, 2)
Traceback (most recent call last):
...
TypeError: Argument '_x' has incorrect type (expected numpy.ndarray, got int)
>>> f_cython(np.array([1.0]), np.array([2.0]))
array([ 3.])
参考
[R1052]
numpy.org/doc/stable/reference/ufuncs.html
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()方法将输出一个代码文件和一个接口文件,分别为.f90 和.h。
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()方法将输出一个代码文件 .jl。
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()方法将输出一个代码文件 .m。
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()方法将输出一个名为.rs 的代码文件。
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})减少为(2^k)和(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']