【问题标题】:Fast polynomial shift快速多项式移位
【发布时间】:2018-12-14 08:43:58
【问题描述】:

我正在尝试实现“F.卷积方法”(第 2.2 节):

来自Fast algorithms for Taylor shifts and certain difference equations(在底部,或here):

from math import factorial

def convolve(f, h):
    g = [0] * (len(f) + len(h) - 1)
    for hindex, hval in enumerate(h):
        for findex, fval in enumerate(f):
            g[hindex + findex] += fval * hval
    return g

def shift(f, a):
    n = len(f) - 1
    u = [factorial(i)*c for i, c in enumerate(f)]
    v = [factorial(n)*a**i//factorial(n-i) for i in range(n + 1)]
    g = convolve(u, v)
    g = [c//(factorial(n)*factorial(i)) for i, c in enumerate(g)]
    return g

f = [1, 2, 3, -4, 5, 6, -7, 8, 9]
print(shift(f, 1))

但我只得到零,而正确的结果应该是:

[1, 10, 45, 112, 170, 172, 116, 52, 23]

请问,有谁知道我在这里做错了什么?

【问题讨论】:

  • 在此处发布算法以便于帮助。就目前而言,您将小整数除以大整数(这就是 0 的原因),因此我们必须了解您期望 convolve(u,v) 返回的内容。
  • @kabanus 完成...
  • 你确定这是正确的输出吗,来自 isaac97 中的 (2)(以及我对 2.2(F) 的实现,我得到 {0: 23, 1: 132, 2: 396, 3: 720, 4: 840, 5: 636, 6: 301, 7: 80, 8: 9})
  • @jedwards 得到的也是我修复代码后得到的(见下文,颠倒过来)。仔细检查。
  • @EcirHana 我两个都加了,但是基本上是 kabanus'(并且使用了defaultdict,这样我就可以将所有的索引杂耍缠绕起来)。由于 kabanus 的回答很好地解释了您原始代码中的问题,我的基本上就是您要求的代码。

标签: python algorithm math polynomials taylor-series


【解决方案1】:

我还没有完全掌握算法,但是你犯了一些错误:

  1. u 的权力从 n 开始,到 0 结束。为了使卷积起作用,您需要反转它,因为您期望系数在卷积函数中是有序的。
  2. v 多项式中的系数仅取决于j,而不取决于n-j(您使用i
  3. 只需要卷积的第一个n+1 元素(您不需要n+1...2n 的幂。
  4. 产生的卷积(它不是真正的卷积是吗?)是“向后”的,因为最终结果将在i=0 开始计算,所以x**(n-i=n) 的力量。

将所有这些放在一起:

from math import factorial

def convolve(f, h):
    g = [0] * (len(f) + len(h) - 1)
    for hindex, hval in enumerate(h):
        for findex, fval in enumerate(f):
            g[hindex + findex] += fval * hval
    return g

def shift(f, a):
    n = len(f) - 1
    u = [factorial(i)*c for i, c in enumerate(f)][::-1]
    v = [factorial(n)*a**i//factorial(i) for i in range(n + 1)]
    g = convolve(u, v)
    g = [g[n-i]//(factorial(n)*factorial(i)) for i in range(n+1)][::-1]
    return g

f = [1, 2, 3, -4, 5, 6, -7, 8, 9]
print(shift(f, 1))

我明白了

[9, 80, 301, 636, 840, 720, 396, 132, 23]

我不知道为什么这与您的预期不同,但我希望这能让您走上正轨。

【讨论】:

  • 看起来 OP 的列表颠倒了(至少与我们的预期不同)。如果f = f[::-1] 你的代码应该得到他们想要的输出(我的)。
  • @jedwards 我同意,我认为这是正确的版本。 (注意我在 f 内故意反转)。
  • 愚蠢的我!确实,我的顺序颠倒了!谢谢。
【解决方案2】:

既然你问我的实现(这些有f“backwards”):

等式 2:

from math import factorial
from collections import defaultdict

def binomial(n, k):
    try:
        binom = factorial(n) // factorial(k) // factorial(n - k)
    except ValueError:
        binom = 0
    return binom

f = [1, 2, 3, -4, 5, 6, -7, 8, 9][::-1]
k=0
n = len(f) - 1

g = defaultdict(int)
for k in range(n+1):
    for i in range(k, n+1):
        g[i-k] += binomial(i,k) * f[i]

print(g)
# defaultdict(<class 'int'>, {0: 23, 1: 52, 2: 116, 3: 172, 4: 170, 5: 112, 6: 45, 7: 10, 8: 1})

2.2(F) 中的公式:

from math import factorial
from collections import defaultdict

def convolve(x, y):
    g = defaultdict(int)
    for (xi, xv) in x.items():
        for (yi, yv) in y.items():
            g[xi + yi] += xv * yv
    return g


def shift(f, a):
    n = len(f) - 1
    u = {n-i: factorial(i)*c for (i, c) in enumerate(f)}
    v = {j: factorial(n)*a**j//factorial(j) for j in range(n + 1)}
    uv = convolve(u, v)

    def g(k):
        ngk = uv[n-k]
        return ngk // factorial(n) // factorial(k)

    G = [g(k) for k in range(n+1)]
    return G

f = [1, 2, 3, -4, 5, 6, -7, 8, 9]

print(shift(f, 1))
# [23, 132, 396, 720, 840, 636, 301, 80, 9]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-29
    • 1970-01-01
    • 2021-10-02
    • 2015-12-10
    • 2011-12-04
    相关资源
    最近更新 更多