离散卷积或多项式乘法


19

给定两个非空的整数列表,您的提交应计算并返回二者的离散卷积。有趣的是,如果您将列表元素视为多项式的系数,则两个列表的卷积代表两个多项式的乘积的系数。

定义

给定列表A=[a(0),a(1),a(2),...,a(n)]B=[b(0),b(1),b(2),...,b(m)](设置a(k)=0 for k<0 and k>nb(k)=0 for k<0 and k>m),则两者的卷积被定义为A*B=[c(0),c(1),...,c(m+n)]其中c(k) = sum [ a(x)*b(y) for all integers x y such that x+y=k]

规则

  • 允许使用适用于您的语言的任何方便的输入和输出格式。
  • 不允许使用内置的卷积,创建卷积矩阵,相关性和多项式乘法。

例子

[1,1]*[1] = [1,1]
[1,1]*[1,1] = [1,2,1]
[1,1]*[1,2,1] = [1,3,3,1]
[1,1]*[1,3,3,1] = [1,4,6,4,1]
[1,1]*[1,4,6,4,1] = [1,5,10,10,5,1]

[1,-1]*[1,1,1,1,1] = [1,0,0,0,0,-1]
[80085,1337]*[-24319,406] = [-1947587115,7,542822]

3
该规范意味着长度为n,m的输入应产生长度为n + m − 1的输出,但这不适用于您的测试用例[1,1]*[] = [],也不能满足于[]*[] = ?。卷积在空列表中定义不明确。我认为您应该保证输入列表是非空的。
Anders Kaseorg '16

1
@AndersKaseorg你是对的,我会改变它。
瑕疵的

Answers:


14

J,10 8字节

[:+//.*/

用法:

ppc =: [:+//.*/    NB. polynomial product coefficients 
80085 1337 ppc _24319 406
_1947587115 7 542822

说明:该程序接受两个列表,制作一个乘法表,然后在正对角线上加上数字。


很聪明的办法!
路易斯·门多

您无需计算括号。它们内部的表达式计算为默认动词,可以将其分配给变量。
丹尼斯

副词的好例子!
英里

6

MATL,19字节

PiYdt"TF2&YStpsw]xx

在线尝试!

说明

这将使用两个输入构建一个块对角矩阵,将第一个输入反转。例如,对于input [1 4 3 5][1 3 2]矩阵为

[ 5 3 4 1 0 0 0
  0 0 0 0 1 3 2 ]

卷积的每个条目都是通过将第一行向右移动一个位置,计算每一列的乘积,并对所有结果求和而获得的。

原则上,移位应从左侧填充零。等效地,可以使用循环移位,因为矩阵在适当的条目处包含零。

例如,从移位矩阵获得第一个结果

[ 0 5 3 4 1 0 0
  0 0 0 0 1 3 2 ]

因此1*1 == 1。第二个是从

[ 0 0 5 3 4 1 0
  0 0 0 0 1 3 2 ]

,因此是4*1+1*3 == 7,等等。这必须完成一些m+n-1时间,其中mn是输入长度。该代码使用带有m+n迭代的循环(节省了一些字节),并丢弃了最后的结果。

P          % Take first input (numeric vactor) implicitly and reverse it
i          % Take second input (numeric vactor) 
Yd         % Build diagonal matrix with the two vectors
t          % Duplicate
"          % For each column of the matrix
  TF2&YS   %   Circularly shift first row 1 step to the right
  t        %   Duplicate
  p        %   Product of each column
  s        %   Sum all those products
  w        %   Swap top two elements in stack. The shifted matrix is left on top
]          % End for
xx         % Delete matrix and last result. Implicitly display

4

Haskell,55 49字节

(a:b)#c=zipWith(+)(0:b#c)$map(a*)c++[]#b
_#c=0<$c

定义一个运算符#


1
我认为填充[0,0..]可以(0<$b)恰好给出所需的长度,允许空的基本情况_#b=0<$b
xnor

@xnor的确,这节省了6个字节。
安德斯·卡塞格

现在,我终于明白了您的答案,我不得不说,这真是太聪明了!给我留下深刻的印象!
瑕疵的

3

Matlab /八度,41字节

@(p,q)poly([roots(p);roots(q)])*p(1)*q(1)

这定义了一个匿名函数。要调用它,请将其分配给变量或使用ans

在这里尝试

说明

这利用了以下事实:

  • (可能重复)根表示一个多项式,直至其前导系数。
  • 两个多项式的乘积都有两者的根。

该代码计算两个多项式(函数roots)的根并将它们连接到一个列数组中。由此得出具有前导1(函数poly)的乘积多项式系数。最后,将结果乘以两个多项式的前导系数。


3

八度,48字节

@(p,q)ifft(fft([p q*0]).*fft([q p*0]))(1:end-1)

在这里尝试

说明

离散卷积对应于(离散时间)傅立叶变换的乘法。因此,乘以多项式的一种方法是对它们进行变换,对变换后的序列进行乘后变换。

如果使用离散傅立叶变换(DFT)代替傅立叶变换,则结果将是多项式系数原始序列的圆形卷积。代码遵循此路线。为了使圆形卷积等于标准​​卷积,对序列进行零填充并修剪结果。


该死的,我还是很乐意禁止fft,但是干得好!
瑕疵的

@flawr是的,我想我们谈论过……?:-P
路易斯·门多

2

05AB1E18 17字节

0Ev²¹g<Å0«y*NFÁ}+

说明

背后的理论:

为了找到卷积,让我们的例子中[1, 2, 3][3, 4, 5]。我们将第一个数组的值上下颠倒并垂直放置,如下所示:

3
2
1

现在,我们将第二个数组像梯子一样放置并乘以:

3 ×       [3  4  5]
2 ×    [3  4  5]
1 × [3  4  5]

结果是:

        9   12   15
    6   8   10
3   4   5

然后,我们将它们加起来,得到:

        9   12   15
    6   8   10
3   4   5       

3   10  22  22   15

因此,卷积为[3, 10, 22, 22, 15]

代码本身:

我们要做采用一步一步来[1, 2, 3][3, 4, 5]作为测试用例。

0Ev²¹g<Å0«y*NFÁ}+

我们首先推送0,然后E评估第一个输入数组。我们使用映射每个元素v

因此,对于每个元素,我们先使用推第二个数组,²然后使用推第一个数组的长度,然后将其¹g减1(使用<)。我们使用并将其附加到列表中,将其转换为具有(长度1st数组-1)个零的零Å0列表。现在,对于输入列表中的第一项,我们的堆栈如下所示:

[3, 4, 5, 0, 0]

我们将此数组乘以当前项,并用完成y*。之后,我们按下N,指示当前项的索引(零索引),然后使用将数组向右旋转多次FÁ}。最后,将其添加到初始值(0)。因此,基本上完成了以下操作:

[0, 0, 9, 12, 15] +
[0, 6, 8, 10, 0] +
[3, 4, 5, 0, 0] =

[3, 10, 22, 22, 15]

然后隐式打印。使用CP-1252编码。在线尝试!


2

果冻,9 个字节

0;+
×'Ṛç/

在线尝试!验证所有测试用例

怎么运行的

×'Ṛç/  Main link. Arguments: p, q (lists)

×'     Spawned multiplication; multiply each item of p with each item of q.
  Ṛ    Reverse the rows of the result.
   ç/  Reduce the rows by the helper link.


0;+    Helper link. Arguments: p, q (lists)

0;     Prepend a 0 to p.
  +    Perform vectorized addition of the result and q.

‽果冻比J longer长,按照定义,这是不可能的!
阿达姆,2013年

2

外壳,5个字节

mΣ∂Ṫ*

在线尝试!

注意:提供零多项式/空列表时,您需要指定其类型(即[]:LN)!

说明

mΣ∂Ṫ*  -- implicit inputs xs ys, for example: [1,-1] [1,1]
   Ṫ*  -- compute the outer product xsᵀ·ys: [[1,1],[-1,-1]]
  ∂    -- diagonals: [[1],[1,-1],[-1]]
mΣ     -- map sum: [1,0,1]

2

Matlab,33个字节

@(x,y)sum(spdiags(flip(x').*y),1)

在线尝试!

创建输入的所有按元素乘积的矩阵,然后沿对角线求和。所述,1在端部的力MATLAB来总结沿着正确的方向时,所述输入矢量中的一个具有长度为1。

在Octave spdiags中,不适用于向量,当其中一个输入的长度为1时,会导致错误。显式扩展按元素乘积需要Matlab 2016b或更高版本。


不错的方法!
路易斯·门多


1

Python,90个字节

lambda p,q:[sum((p+k*[0])[i]*(q+k*[0])[k-i]for i in range(k+1))for k in range(len(p+q)-1)]

1

JavaScript(ES6),64字节

(a,b)=>a.map((n,i)=>b.map((m,j)=>r[j+=i]=m*n+(r[j]||0)),r=[])&&r

如果任一输入为空,则返回空数组。根据我对多项式的回答。



1

Clojure,104个字节

#(vals(apply merge-with +(sorted-map)(for[i(range(count %))j(range(count %2))]{(+ i j)(*(% i)(%2 j))})))

合并可sorted-map确保以正确的顺序返回值。我希望还有更多的测试用例。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.