是否有一种非黑客方法可以在不评估的情况下使用整数在 SymPy 中打印连分数?
Is there a non-hack way to print continued fractions in SymPy with integers without evaluation?
我希望看到以 SymPy
形式显示的带整数的连续分数,但我似乎无法使 SymPy
符合要求。我发现 Stack Overflow 问答非常有用(见下文),但无法达到我的目标:
这是 $\frac{13}{5}$ 的连分式展开。此扩展的常用符号是仅给出方框内的术语,如下面的 SymPy
所示,即来自 SymPy
continued_fraction_iterator
的 $[2,1,1,2]$:
Rat_13_5 = list(continued_fraction_iterator(Rational(13, 5)))
print( Rat_13_5 )
Rat_13_5 = list(continued_fraction_iterator(Rational(13, 5)))
( Rat_13_5 )
print( Rat_13_5 )
输出[2, 1, 1, 2]
.
2019 年 12 月 9 日 Sympy 手册版本 1.5 的第 37 页给出了一个代码片段来打印这样一个扩展的分数列表:
def list_to_frac(l):
expr = Integer(0)
for i in reversed(l[1:]):
expr += i
expr = 1/expr
return l[0] + expr
如果您使用 Rat_13_5
连分数扩展列表调用 list_to_frac
,SymPy
会起飞并计算它:
print( list_to_frac( Rat_13_5 ) )
输出13/5
如果您改用符号列表,则 list_to_frac
会打印所需的连分数,例如,
n1, n2, n3, n4, n5, n6, n7, n8, n9 = symbols('n1:10')
cont_frac_list = [n2, n1, n1, n2]
contfrac12201015 = list_to_frac( [n2,n1,n1,n2] )
contfrac122010154
这会产生所需的(我在 JupyterLab 环境中工作,所以我实际上在整个过程中都获得了 typset LaTeX 输出):
n2 + 1/(n1 + 1/(n1 + 1/n2))
我重写了 list_to_frac
以使用 Francesco 在我之前引用的 Whosebug 问题中提供的 UnevaluatedExpr
工具:
def list_to_frac_noEval(l):
expr = Integer(0)
for i in reversed(l[1:]):
expr = UnevaluatedExpr(expr + i)
expr = UnevaluatedExpr( 1/expr )
return l[0] + expr
在 $\frac{13}{5}$ 扩展列表上调用 list_to_frac_noEval
:
list_to_frac_noEval( [2,1,1,2] )
我获得输出
2 + (1 + (1 + 2**(-1))**(-1))**(-1)
有些人使用这种表示法(所以我想在任何情况下分享 list_to_frac_noEval
,如果你想看到连分数,那比最终得到一个评估的单一有理数要好),例如 Roger Penrose在 The Road to Reality (2004) 的 $\unicode{x00A7}3.2$ 部分,但我仍然觉得很烦人,因为在使用整数而不是符号时我无法获得显式连分数格式.
我尝试使用 subs
方法和 Subs
函数用 evaluate=False
替换符号的整数,查看 sympify
和 srepr
和 parse_expr
与 evaluate=False
, ,但不能说服 SymPy 1.4
打印我用 list_to_frac
对符号参数进行操作获得的显式分数形式。有没有办法在不修改 SymPy
代码或对一组特定数字进行特殊封装的情况下完成此操作?
您可以构造表达式,将 evaluate=False
显式传递给表达式树的每个部分:
def list_to_frac(l):
expr = Integer(0)
for i in reversed(l[1:]):
expr = Add(i, expr, evaluate=False)
expr = Pow(expr, -1, evaluate=False)
return Add(l[0], expr, evaluate=False)
这给出:
In [2]: nums = list(continued_fraction_iterator(Rational(13, 5)))
In [3]: nums
Out[3]: [2, 1, 1, 2]
In [4]: list_to_frac(nums)
Out[4]:
1
───────────── + 2
1
───────── + 1
1
───── + 1
0 + 2
看起来这是错误的方式,但这正是使用默认设置打印的方式:
In [5]: init_printing(order='old')
In [6]: list_to_frac(nums)
Out[6]:
1
2 + ─────────────
1
1 + ─────────
1
1 + ─────
0 + 2
您可以使用 doit
触发评估:
In [7]: _.doit()
Out[7]: 13/5
我希望看到以 SymPy
形式显示的带整数的连续分数,但我似乎无法使 SymPy
符合要求。我发现
这是 $\frac{13}{5}$ 的连分式展开。此扩展的常用符号是仅给出方框内的术语,如下面的 SymPy
所示,即来自 SymPy
continued_fraction_iterator
的 $[2,1,1,2]$:
Rat_13_5 = list(continued_fraction_iterator(Rational(13, 5)))
print( Rat_13_5 )
Rat_13_5 = list(continued_fraction_iterator(Rational(13, 5)))
( Rat_13_5 )
print( Rat_13_5 )
输出[2, 1, 1, 2]
.
2019 年 12 月 9 日 Sympy 手册版本 1.5 的第 37 页给出了一个代码片段来打印这样一个扩展的分数列表:
def list_to_frac(l):
expr = Integer(0)
for i in reversed(l[1:]):
expr += i
expr = 1/expr
return l[0] + expr
如果您使用 Rat_13_5
连分数扩展列表调用 list_to_frac
,SymPy
会起飞并计算它:
print( list_to_frac( Rat_13_5 ) )
输出13/5
如果您改用符号列表,则 list_to_frac
会打印所需的连分数,例如,
n1, n2, n3, n4, n5, n6, n7, n8, n9 = symbols('n1:10')
cont_frac_list = [n2, n1, n1, n2]
contfrac12201015 = list_to_frac( [n2,n1,n1,n2] )
contfrac122010154
这会产生所需的(我在 JupyterLab 环境中工作,所以我实际上在整个过程中都获得了 typset LaTeX 输出):
n2 + 1/(n1 + 1/(n1 + 1/n2))
我重写了 list_to_frac
以使用 Francesco 在我之前引用的 Whosebug 问题中提供的 UnevaluatedExpr
工具:
def list_to_frac_noEval(l):
expr = Integer(0)
for i in reversed(l[1:]):
expr = UnevaluatedExpr(expr + i)
expr = UnevaluatedExpr( 1/expr )
return l[0] + expr
在 $\frac{13}{5}$ 扩展列表上调用 list_to_frac_noEval
:
list_to_frac_noEval( [2,1,1,2] )
我获得输出
2 + (1 + (1 + 2**(-1))**(-1))**(-1)
有些人使用这种表示法(所以我想在任何情况下分享 list_to_frac_noEval
,如果你想看到连分数,那比最终得到一个评估的单一有理数要好),例如 Roger Penrose在 The Road to Reality (2004) 的 $\unicode{x00A7}3.2$ 部分,但我仍然觉得很烦人,因为在使用整数而不是符号时我无法获得显式连分数格式.
我尝试使用 subs
方法和 Subs
函数用 evaluate=False
替换符号的整数,查看 sympify
和 srepr
和 parse_expr
与 evaluate=False
, ,但不能说服 SymPy 1.4
打印我用 list_to_frac
对符号参数进行操作获得的显式分数形式。有没有办法在不修改 SymPy
代码或对一组特定数字进行特殊封装的情况下完成此操作?
您可以构造表达式,将 evaluate=False
显式传递给表达式树的每个部分:
def list_to_frac(l):
expr = Integer(0)
for i in reversed(l[1:]):
expr = Add(i, expr, evaluate=False)
expr = Pow(expr, -1, evaluate=False)
return Add(l[0], expr, evaluate=False)
这给出:
In [2]: nums = list(continued_fraction_iterator(Rational(13, 5)))
In [3]: nums
Out[3]: [2, 1, 1, 2]
In [4]: list_to_frac(nums)
Out[4]:
1
───────────── + 2
1
───────── + 1
1
───── + 1
0 + 2
看起来这是错误的方式,但这正是使用默认设置打印的方式:
In [5]: init_printing(order='old')
In [6]: list_to_frac(nums)
Out[6]:
1
2 + ─────────────
1
1 + ─────────
1
1 + ─────
0 + 2
您可以使用 doit
触发评估:
In [7]: _.doit()
Out[7]: 13/5