離散畳み込みまたは多項式乗算


19

整数の2つの空でないリストが与えられた場合、サブミットは2つの離散畳み込みを計算して返す必要があります。興味深いことに、リスト要素を多項式の係数と考えると、2つのリストの畳み込みは2つの多項式の積の係数を表します。

定義

リスト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)が与えられると、2つの畳み込みは次のよう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]*[] = []には当てはまらず、に対しても当てはまらない可能性があります[]*[] = ?。畳み込みは、空のリストでは明確に定義されていません。入力リストが空でないことを保証する必要があると思います。
アンデルスカセオルグ

1
@AndersKaseorgあなたは正しいです、私はそれを変えます。
flawr

回答:


14

J、10 8バイト

[:+//.*/

使用法:

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

説明:プログラムは2つのリストを取り、乗算表を作成し、正の対角線上に数値を追加します。


非常に賢いアプローチ!
ルイスメンドー

括弧を数える必要はありません。それらの中の式は、暗黙の動詞に評価され、変数に割り当てることができます。
デニス

副詞の素晴らしい例!
マイル

6

MATL、19バイト

PiYdt"TF2&YStpsw]xx

オンラインでお試しください!

説明

これにより、2つの入力を持つブロック対角行列が作成され、最初の入力が反転します。たとえば、inputsの[1 4 3 5]場合[1 3 2]、行列は

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

畳み込みの各エントリは、最初の行を1ポジション右にシフトし、各列の積を計算して、すべての結果を合計することによって取得されます。

原則として、シフトは左からゼロでパディングする必要があります。同様に、マトリックスの適切なエントリにゼロが含まれているため、循環シフトを使用できます。

たとえば、最初の結果はシフトされた行列から取得されます

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

したがって、1*1 == 1です。2番目はから取得されます

[ 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バイトを節約します。
アンデルスカセオルグ

あなたの答えをようやく理解したので、これは非常に賢いことだと言わざるを得ません!私が感銘を受けた!
-flawr

3

Matlab / Octave、41バイト

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

これは、匿名関数を定義します。呼び出すには、変数に割り当てるか、を使用しますans

ここで試してみてください

説明

これは、

  • (おそらく繰り返される)根は、多項式をその主要係数まで特徴付けます。
  • 2つの多項式の積には両方の根があります。

このコードは、2つの多項式の根(関数roots)を計算し、それらを列配列に連結します。それから、先頭1(関数poly)の積多項式の係数を取得します。最後に、結果に2つの多項式の主要係数が乗算されます。


3

オクターブ、48バイト

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

ここで試してみてください

説明

離散畳み込みは、(離散時間)フーリエ変換の乗算に対応します。したがって、多項式を乗算する1つの方法は、それらを変換し、変換されたシーケンスを乗算し、逆変換することです。

場合フーリエ変換、離散(DFT)は、フーリエ変換の代わりに使用され、結果は円形畳み込み多項式係数の元の配列。コードはこのルートに従います。循環たたみ込みを標準のたたみ込みと等しくするために、シーケンスにゼロが埋め込まれ、結果がトリミングされます。


ダムニット、私はまだFFTを禁止すべきだったが、良い仕事だ!
flawr

@flawrはい、私たちはそれについて話したと思います...?:-P
ルイスメンドー

2

05AB1E18 17バイト

コード

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

説明

背後にある理論:

畳み込みを見つけるには、の例を見てみましょう[1, 2, 3][3, 4, 5]。次のように、最初の配列の値を上下逆さまに配置します。

3
2
1

次に、2番目の配列を梯子のように配置し、それを乗算します。

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

したがって、各要素に対して、2番目の配列をプッシュし²、次に1番目の配列の長さを使用してプッシュし、¹gこれを1(with <)だけ減らします。これを(長さ1番目の配列-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長いことは定義上不可能です!
アダム

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エンド力には、入力ベクトルの一方は長さ1を有する場合、正しい方向に合計するには、MATLAB。

Octave spdiagsではベクトルに対して機能せず、入力の1つの長さが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て、値が正しい順序で返されることを保証します。さらにいくつかのテストケースがあればいいのにと思います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.