简体   繁体   English

将多项式与numpy.convolve相乘会返回错误的结果

[英]Multiplying polynomials with numpy.convolve return wrong result

I'm trying to multiply two polynomials using the numpy.convolve function. 我正在尝试使用numpy.convolve函数将两个多项式相乘。 I thought that this would be really easy, but I found out that it does not always return the correct product. 我以为这真的很容易,但是我发现它并不总是返回正确的产品。

The implementation of multiplication is quite simple: 乘法的实现非常简单:

def __mul__(self, other):
    new = ModPolynomial(self._mod_r, self._mod_n)
    try:
         new_coefs = np.convolve(self._coefs, other._coefs)
         new_coefs %= self._mod_n                # coefficients in Z/nZ
         new._coefs = new_coefs.tolist()
         new._degree = self._finddegree(new._coefs)
    except AttributeError:
         new._coefs = [(c * other) % self._mod_n for c in self._coefs]
         new._degree = self._finddegree(new._coefs)
    new._mod()       #the polynomial mod x^r-1
    return new

An example that gives a wrong result: 一个给出错误结果的示例:

>>> N = 5915587277
>>> r = 1091
>>> pol = polynomials.ModPolynomial(r,N)
>>> pol += 1
>>> r_minus_1 = (pol**(r-1)).coefficients
>>> # (x+1)^r = (x+1)^(r-1) * (x+1) = (x+1)^(r-1) * x + (x+1)^(r-1) * 1
... shifted = [r_minus_1[-1]] + list(r_minus_1[:-1])   #(x+1)^(r-1) * x mod x^r-1
>>> res = [(a+b)%N for a,b in zip(shifted, r_minus_1)]
>>> tuple(res) == tuple((pol**r).coefficients)
False

The exponentiation is probably not a problem, since I use exactly the same algorithm with an other polynomial implementation that gives the correct result. 求幂可能不是问题,因为我将完全相同的算法与其他提供正确结果的多项式实现一起使用。 And by "exactly the same algorithm" I mean that the polynomial class that uses numpy.convolve is a subclass of the other class, reimplementing only __mul__ , and _mod() [in _mod() I simply call the other _mod() method and then delete the 0 coefficients for the terms greater than the polynomial degree]. “完全相同的算法”是指使用numpy.convolve的多项式类是另一个类的子类,仅重新实现__mul___mod() [在_mod()我只是简单地调用了另一个_mod()方法,然后删除大于多项式的项的0个系数]。

An other example in which this fail: 另一个失败的示例:

>>> pol = polynomials.ModPolynomial(r, N)   #r,N same as before
>>> pol += 1
>>> (pol**96).coefficients
(1, 96, 4560, 142880, 3321960, 61124064, 927048304, 88017926, 2458096246, 1029657217, 4817106694, 4856395617, 384842111, 2941717277, 5186464497, 5873440931, 526082533, 39852453, 1160839201, 1963430115, 3122515485, 3694777161, 1571327669, 5827174319, 2249616721, 501768628, 5713942687, 1107927924, 3954439741, 1346794697, 4091850467, 2576431255, 94278252, 5838836826, 3146740571, 1898930862, 4578131646, 1668290724, 2073150016, 2424971880, 1386950302, 1658296694, 5652662386, 1467437114, 2496056685, 1276577534, 4774523858, 5138784090, 4607975862, 5138784090, 4774523858, 1276577534, 2496056685, 1467437114, 5652662386, 1658296694, 1386950302, 2424971880, 2073150016, 1668290724, 4578131646, 1898930862, 3146740571, 5838836826, 94278252, 2576431255, 4091850467, 1346794697, 3954439741, 1107927924, 5713942687, 501768628, 2249616721, 5827174319, 1571327669, 3694777161, 3122515485, 1963430115, 1160839201, 39852453, 526082533, 5873440931, 5186464497, 2941717277, 384842111, 4856395617, 4817106694, 1029657217, 2458096246, 88017926, 927048304, 61124064, 3321960, 142880, 4560, 96, 1)
#the correct result[taken from wolframalpha]:
(1, 96, 4560, 142880, 3321960, 61124064, 927048304, 88017926, 2458096246, 1029657217, 4817106694, 4856395617, 384842111, 2941717277, 5186464497, 5873440931, 526082533, 39852453, 1160839201L, 1963430115L, 3122515485L, 3694777161L, 1571327669L, 5827174319L, 1209974072L, 5377713256L, 4674300038L, 68285275L, 2914797092L, 307152048L, 3052207818L, 1536788606L, 4970222880L, 4799194177L, 2107097922L, 859288213L, 4578131646L, 1668290724L, 1033507367L, 1385329231L, 347307653L, 618654045L, 4613019737L, 427794465L, 1456414036L, 236934885L, 3734881209L, 4099141441L, 3568333213L, 4099141441L, 3734881209L, 236934885L, 1456414036L, 427794465L, 4613019737L, 618654045L, 347307653L, 1385329231L, 1033507367L, 1668290724L, 4578131646L, 859288213L, 2107097922L, 4799194177L, 4970222880L, 1536788606L, 3052207818L, 307152048L, 2914797092L, 68285275L, 4674300038L, 5377713256L, 1209974072L, 5827174319L, 1571327669L, 3694777161L, 3122515485L, 1963430115L, 1160839201L, 39852453, 526082533, 5873440931, 5186464497, 2941717277, 384842111, 4856395617, 4817106694, 1029657217, 2458096246, 88017926, 927048304, 61124064, 3321960, 142880, 4560, 96, 1)

The wrong results only appeard with "big numbers", and also the exponent should be "big"[I couldn't find an example with exponent < 96]. 错误的结果只会出现在“大数字”上,并且指数也应该是“大” [我找不到指数<96]的示例。

I have no clue of why this is happening. 我不知道为什么会这样。 I'm using numpy.convolve because it was suggested in another my question, and I'm just trying to compare the speed of my approach to the numpy approach. 我使用numpy.convolve是因为在另一个问题中提出了建议,而我只是想将自己的方法与numpy方法的速度进行比较。 Maybe I'm using numpy.convolve in the wrong way? 也许我以错误的方式使用numpy.convolve

Later I'll try to do some more debugging, trying to understand where and when exactly things get wrong. 稍后,我将尝试进行更多调试,以尝试弄清楚哪里和何时出现问题。

NumPy is a library that implements fast operation on arrays of fixed-size numeric data types . NumPy是一个库,可对固定大小的数字数据类型的数组执行快速操作。 It does not implement arbitrary precision arithmetic. 它不执行任意精度算法。 So what you are seeing here is integer overflow: NumPy is representing your coefficients as 64-bit integers and when these are large enough, they overflow in numpy.convolve . 因此,您在这里看到的是整数溢出:NumPy将您的系数表示为64位整数,当它们足够大时,它们会在numpy.convolve溢出。

>>> import numpy
>>> a = numpy.convolve([1,1], [1,1])
>>> type(a[0])
<type 'numpy.int64'>

If you need arithmetic on arbitrary-precision integers, you need to implement your own convolution so that it can use Python's arbitrary-precision integers. 如果需要对任意精度整数进行算术运算,则需要实现自己的卷积,以便可以使用Python的任意精度整数。 For example, 例如,

def convolve(a, b):
    """
    Generate the discrete, linear convolution of two one-dimensional sequences.
    """
    return [sum(a[j] * b[i - j] for j in range(i + 1)
                if j < len(a) and i - j < len(b))
            for i in range(len(a) + len(b) - 1)]

>>> a = [1,1]
>>> for i in range(95): a = convolve(a, [1,1])
... 
>>> from math import factorial as f
>>> all(a[i] == f(96) / f(i) / f(96 - i) for i in range(97))
True

If speed is an issue when performing repeated convolutions with dtype=object (as in your case), you should consider using the karatsuba module rather than numpy.convolve . 如果使用dtype=object执行重复卷积时速度是一个问题(如您的情况),则应考虑使用karatsuba模块,而不是numpy.convolve It is intended to use high-level objects (like with dtype=object ) but relies on plans in order to pre-compute the convolution. 它打算使用高级对象(例如dtype=object ),但要依靠计划才能预先计算卷积。 It is useless for a single convolution but very efficient if many similar ones are wanted. 对于单个卷积它是没有用的,但是如果需要许多相似的卷积,则非常有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM