• 【Python Sympy】将表达式化为关于x的多项式,求出多项式系数


    今天遇到一个问题。老师让用C++实现三次样条插值函数,输出多项式系数,其中有一个公式长这样 S ( x ) = m i ( x − x i ) ( x − x i + 1 ) 2 h i 2 + m i + 1 ( x − x i ) 2 ( x − x i + 1 ) h i 2 + y i ( x − x i + 1 ) 2 ( h i + 2 x − 2 x i ) h i 3 + y i + 1 ( x − x i ) 2 ( h i − 2 x + 2 x i + 1 ) h i 3 S(x)=\frac{m_{i} \left(x - x_{i}\right) \left(x - x_{i+1}\right)^{2}}{h_{i}^{2}} + \frac{m_{i+1} \left(x - x_{i}\right)^{2} \left(x - x_{i+1}\right)}{h_{i}^{2}} + \frac{y_{i} \left(x - x_{i+1}\right)^{2} \left(h_{i} + 2 x - 2 x_{i}\right)}{h_{i}^{3}} + \frac{y_{i+1} \left(x - x_{i}\right)^{2} \left(h_{i} - 2 x + 2 x_{i+1}\right)}{h_{i}^{3}} S(x)=hi2mi(xxi)(xxi+1)2+hi2mi+1(xxi)2(xxi+1)+hi3yi(xxi+1)2(hi+2x2xi)+hi3yi+1(xxi)2(hi2x+2xi+1)对应的 LaTeX \LaTeX LATEX代码为

    S(x)=\frac{m_{i} \left(x - x_{i}\right) \left(x - x_{i+1}\right)^{2}}{h_{i}^{2}} + \frac{m_{i+1} \left(x - x_{i}\right)^{2} \left(x - x_{i+1}\right)}{h_{i}^{2}} + \frac{y_{i} \left(x - x_{i+1}\right)^{2} \left(h_{i} + 2 x - 2 x_{i}\right)}{h_{i}^{3}} + \frac{y_{i+1} \left(x - x_{i}\right)^{2} \left(h_{i} - 2 x + 2 x_{i+1}\right)}{h_{i}^{3}}
    
    • 1

    要求出各项系数,就必须把上面这个贼长的式子化成关于x多项式。……那得累死。怎么办呢?

    Python里有一个模块叫sympy,是做符号计算的。安装方法为:

    pip install -i https://pypi.tuna.tsinghua.edu.cn/simple sympy
    
    • 1

    sympy里面有一个函数collect,作用是将关于一个/几个变量的同次项合并在一起。函数定义为:

    sympy.simplify.radsimp.collect(expr, syms, func=None, evaluate=None, exact=False, distribute_order_term=True)
    
    • 1

    其中,expr是要化简的表达式,syms指定化简成关于谁的多项式(可以是一个变量或是变量的列表),evaluate表示是否对结果赋值。若evaluate = True,则直接返回化简后的多项式;若evaluate = False,则返回一个字典,存储每一项的系数。

    例如,要把 a x 2 + 3 x + c + 1 b x 2 + 9 + d 3 x ax^2+3x+c+\frac1b x^2+9+\frac d3x ax2+3x+c+b1x2+9+3dx化为关于 x x x的多项式,可以这么写(下面的结果是在IPython中运行得到的):

    In [4]: from sympy import *
    
    In [5]: a, b, c, d, x = symbols('a, b, c, d, x')
    
    In [6]: collect(a * x ** 2 + 3 * x + c + 1 / b * x ** 2 + 9 + d / 3 * x, x)
    Out[6]: c + x**2*(a + 1/b) + x*(d/3 + 3) + 9
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    结果是 ( a + 1 b ) x 2 + ( d 3 + 3 ) x + c + 9 \left(a+\frac1b\right)x^2+\left(\frac d3+3\right)x+c+9 (a+b1)x2+(3d+3)x+c+9

    若设evaluate = False

    In [8]: p = collect(a * x ** 2 + 3 * x + c + 1 / b * x ** 2 + 9 + d / 3 * x, x, evaluate = False)
    
    In [9]: p
    Out[9]: {x: d/3 + 3, x**2: a + 1/b, 1: c + 9}
    
    In [10]: p[x ** 2] # x平方项的系数
    Out[10]: a + 1/b
    
    In [11]: p[1] # 常数项
    Out[11]: c + 9
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    也可以用它来化简多变量的表达式。

    In [12]: y = Symbol('y')
    
    In [13]: collect(x ** 2 + y * x ** 2 + x * y + y + a * y, [x, y])
    Out[13]: x**2*(y + 1) + x*y + y*(a + 1)
    
    In [14]: collect(x ** 2 + y * x ** 2 + x * y + y + a * y, [x, y], evaluate = False)
    Out[14]: {y: a + 1, x**2: y + 1, x: y}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    注意这个算法是贪心的,它同一时刻只处理一个变量。

    还有更高级的用法:

    In [15]: collect(a * sin(2 * x) + b * sin(2 * x), sin(2 * x))
    Out[15]: (a + b)*sin(2*x)
    
    In [16]: collect(a * x * log(x) + b * (x * log(x)) + x, x * log(x))
    Out[16]: x*(a + b)*log(x) + x
    
    • 1
    • 2
    • 3
    • 4
    • 5

    现在解决我们一开始提出的问题。注意,要先调用expand展开括号中的东西才能继续化简。

    In [18]: S, h_i, x_i, x_j, y_i, y_j, m_i, m_j = symbols('S, h_i, x_i, x_j, y_i, y_j, m_i, m_j')
    
    In [19]: S = (h_i + 2 * (x - x_i)) * (x - x_j) ** 2 * y_i / h_i ** 3 + \
        ...: (h_i - 2 * (x - x_j)) * (x - x_i) ** 2 * y_j / h_i ** 3 + \
        ...: (x - x_i) * (x - x_j) ** 2 * m_i / h_i ** 2 + \
        ...: (x - x_j) * (x - x_i) ** 2 * m_j / h_i ** 2
    
    In [20]: collect(expand(S), x)
    Out[20]: x**3*(m_i/h_i**2 + m_j/h_i**2 + 2*y_i/h_i**3 - 2*y_j/h_i**3) + x**2*(-m_i*x_i/h_i**2 - 2*m_i*x_j/h_i**2 - 2*m_j*x_i/h_i**2 - m_j*x_j/h_i**2 + y_i/h_i**2 + y_j/h_i**2 - 2*x_i*y_i/h_i**3 + 4*x_i*y_j/h_i**3 - 4*x_j*y_i/h_i**3 + 2*x_j*y_j/h_i**3) + x*(2*m_i*x_i*x_j/h_i**2 + m_i*x_j**2/h_i**2 + m_j*x_i**2/h_i**2 + 2*m_j*x_i*x_j/h_i**2 - 2*x_i*y_j/h_i**2 - 2*x_j*y_i/h_i**2 - 2*x_i**2*y_j/h_i**3 + 4*x_i*x_j*y_i/h_i**3 - 4*x_i*x_j*y_j/h_i**3 + 2*x_j**2*y_i/h_i**3) - m_i*x_i*x_j**2/h_i**2 - m_j*x_i**2*x_j/h_i**2 + x_i**2*y_j/h_i**2 + x_j**2*y_i/h_i**2 + 2*x_i**2*x_j*y_j/h_i**3 - 2*x_i*x_j**2*y_i/h_i**3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    稍稍化简之后得 S ( x ) = h i ( m i + m i + 1 ) + 2 y i − 2 y i + 1 h i 3 x 3 + h i ( − m i x i − 2 m i x i + 1 − 2 m i + 1 x i − m i + 1 x i + 1 + y i + y i + 1 ) − 2 x i y i + 4 x i y i + 1 − 4 x i + 1 y i + 2 x i + 1 y i + 1 h i 3 x 2 + h i ( 2 m i x i x i + 1 + m i x i + 1 2 + m i + 1 x i 2 + 2 m i + 1 x i x i + 1 − 2 x i y i + 1 − 2 x i + 1 y i ) − 2 x i 2 y i + 1 + 4 x i x i + 1 y i − 4 x i x i + 1 y i + 1 + 2 x i + 1 2 y i h i 3 x + h i ( − m i x i x i + 1 2 − m i + 1 x i 2 x i + 1 + x i 2 y i + 1 + x i + 1 2 y i ) + 2 x i x i + 1 ( x i y i + 1 − x i + 1 y i ) h i 3 S\left(x\right)=\frac{h_i\left(m_i+m_{i+1}\right)+2y_i-2y_{i+1}}{h_i^3}x^3+\frac{h_i\left(-m_ix_i-2m_ix_{i+1}-2m_{i+1}x_i-m_{i+1}x_{i+1}+y_i+y_{i+1}\right)-2x_iy_i+4x_iy_{i+1}-4x_{i+1}y_i+2x_{i+1}y_{i+1}}{h_i^3}x^2+\frac{h_i\left(2m_ix_ix_{i+1}+m_ix_{i+1}^2+m_{i+1}x_i^2+2m_{i+1}x_ix_{i+1}-2x_iy_{i+1}-2x_{i+1}y_i\right)-2x_i^2y_{i+1}+4x_ix_{i+1}y_i-4x_ix_{i+1}y_{i+1}+2x_{i+1}^2y_i}{h_i^3}x+\frac{h_i\left(-m_ix_ix_{i+1}^2-m_{i+1}x_i^2x_{i+1}+x_i^2y_{i+1}+x_{i+1}^2y_i\right)+2x_ix_{i+1}\left(x_iy_{i+1}-x_{i+1}y_i\right)}{h_i^3} S(x)=hi3hi(mi+mi+1)+2yi2yi+1x3+hi3hi(mixi2mixi+12mi+1ximi+1xi+1+yi+yi+1)2xiyi+4xiyi+14xi+1yi+2xi+1yi+1x2+hi3hi(2mixixi+1+mixi+12+mi+1xi2+2mi+1xixi+12xiyi+12xi+1yi)2xi2yi+1+4xixi+1yi4xixi+1yi+1+2xi+12yix+hi3hi(mixixi+12mi+1xi2xi+1+xi2yi+1+xi+12yi)+2xixi+1(xiyi+1xi+1yi)

    对应的 LaTeX \LaTeX LATEX代码为

    S\left(x\right)=\frac{h_i\left(m_i+m_{i+1}\right)+2y_i-2y_{i+1}}{h_i^3}x^3+\frac{h_i\left(-m_ix_i-2m_ix_{i+1}-2m_{i+1}x_i-m_{i+1}x_{i+1}+y_i+y_{i+1}\right)-2x_iy_i+4x_iy_{i+1}-4x_{i+1}y_i+2x_{i+1}y_{i+1}}{h_i^3}x^2+\frac{h_i\left(2m_ix_ix_{i+1}+m_ix_{i+1}^2+m_{i+1}x_i^2+2m_{i+1}x_ix_{i+1}-2x_iy_{i+1}-2x_{i+1}y_i\right)-2x_i^2y_{i+1}+4x_ix_{i+1}y_i-4x_ix_{i+1}y_{i+1}+2x_{i+1}^2y_i}{h_i^3}x+\frac{h_i\left(-m_ix_ix_{i+1}^2-m_{i+1}x_i^2x_{i+1}+x_i^2y_{i+1}+x_{i+1}^2y_i\right)+2x_ix_{i+1}\left(x_iy_{i+1}-x_{i+1}y_i\right)}{h_i^3}
    
    • 1

    至此,问题圆满解决。


    参考资料
    1. https://docs.sympy.org/latest/modules/simplify/simplify.html
    2. https://www.geeksforgeeks.org/python-sympy-collect-method/
  • 相关阅读:
    基于 .net core 8.0 的 swagger 文档优化分享-根据命名空间分组显示
    uniapp 使用了uview 的dropdown下拉菜单后出现页面无法滚动
    使用Go的encoding/asn1库处理复杂数据:技巧与最佳实践
    [原创]基于Comsol的方形、三角形、椭圆形克拉尼板仿真研究
    美国、欧洲、中国关于工业互联网的比较分析
    java实现状态模式
    计算机网络——如何构造HTTP请求
    Android音频子系统(十一)------耳机返听(耳返)原理实现
    【kubernetes】kubernetes二次开发
    LeetCode654. Maximum Binary Tree
  • 原文地址:https://blog.csdn.net/qaqwqaqwq/article/details/127416493