我怎样才能说服 Sympy 对 1961 年麻省理工学院本科生微积分问题进行相同的简化?

How can I convince Sympy to come to the same simplification SAINT does for the 1961 MIT undergrad calculus problem?

James R Slagle麻省理工学院论文A heuristic program that solves symbolic integration problems in freshman calculus, symbolic automatic integrator (SAINT) 因成为第一个实用的“专家系统”符号积分器而出名,并且能够解决麻省理工学院本科生微积分测试中的所有问题(迂腐地,有几个问题被遗漏了,但它本可以解决它们;详细信息在这里in this excellent YouTube video)

他的论文可在此处免费获得:https://dspace.mit.edu/handle/1721.1/11997

我很高兴尝试使用 Sympy,因为它看起来平易近人,而且是一个相当困难的简化我碰巧已经有了答案..然而,Sympy 并没有将积分简化到如此好的(主观?)简化为 1961 年计划(尽管它确实 return 等效结果!)


疑问与猜测

如何说服 Sympy 简化为相同的方程式?
为什么它没有得出相同的、看似更简单的结果?

也许它选择了第一个可能的结果,或者tan**3被确定为更糟?如果是这样,为什么它不简化 SAINT 的输出?)

也许当它找到一些匹配项时,它会沿着不同的分支出发 ?

试题3c

Sympy 简化

from sympy import *
x = symbols("x", real=True)  # should this be assumed?
expr_inner = (x**4) / ((1 - x**2)**Rational(5,2))
expr_integral = integrate((expr_inner), x)
print(simplify(expr_integral))

(x**4*asin(x) + 4*x**3*sqrt(1 - x**2)/3 - 2*x**2*asin(x) - x*sqrt(1 - x**2) + asin(x))/(x**4 - 2*x**2 + 1)

平等证明

from sympy import *
x = symbols("x", real=True)  # should this be assumed?
expr_saint = asin(x) + Rational(1,3)*tan(asin(x))**3 - tan(asin(x))
expr_sympy = (x**4*asin(x) + 4*x**3*sqrt(1 - x**2)/3 - 2*x**2*asin(x) - x*sqrt(1 - x**2) + asin(x))/(x**4 - 2*x**2 + 1)
expr_saint.equals(expr_sympy)  # alternatively simplify(expr_saint - expr_sympy) 

True

方程式显示

主要部分是分解 asin(x) 并将其从分数中分离出来。之后,sympy 可以证明两个表达式相等:

from sympy import *
from IPython.display import Math, display
x = symbols("x", real=True)  # should this be assumed?
expr_saint = asin(x) + Rational(1,3)*tan(asin(x))**3 - tan(asin(x))
expr_sympy = (x**4*asin(x) + 4*x**3*sqrt(1 - x**2)/3 - 2*x**2*asin(x) - x*sqrt(1 - x**2) + asin(x))/(x**4 - 2*x**2 + 1)

r=[]
r.append(latex(expr_sympy))
expr_sympy = expr_sympy.collect(asin(x))
r.append(latex(expr_sympy))
expr_sympy = apart(expr_sympy,asin(x))
r.append(latex(expr_sympy))

display(Math(" \Longrightarrow ".join(r)))

display(simplify(expr_saint - expr_sympy))

输出:

@wsdookadr 给了我缺少的简化步骤;显示 apart() 可以很容易地自己得到 asin(x)(这显然是一个公因数),因此创建一个非常相似但比 SAINT 输出更简化的形式。

沿着这些思路思考更多,SAINT 输出并没有尽可能地简化,因此在比较之前应该进一步简化(据我所知,SAINT 的设计并不是为了在集成后继续简化)

  • 首先使用 ratsimp() 将结果强制为单个分数,推动 Sympy 清理分母(这结合了分数)
  • 调用 apart() 将它们拆分回来,尽管它们仍然是简化的

这给出了更符合预期的匹配