Ayrık Konvolüsyon veya Polinom Çarpımı


19

Boş olmayan iki tamsayı listesi verildiğinde , gönderiminiz bu ikisinin ayrık dönüşümü hesaplamalı ve döndürmelidir . İlginçtir ki, liste öğelerini polinom katsayıları olarak görürseniz, iki listenin katlanması iki polinomun çarpım katsayılarını temsil eder.

Tanım

Listeleri göz önüne alındığında A=[a(0),a(1),a(2),...,a(n)]ve B=[b(0),b(1),b(2),...,b(m)](ayar a(k)=0 for k<0 and k>nve b(k)=0 for k<0 and k>mdaha sonra iki kıvrım) gibi tanımlanmıştır; A*B=[c(0),c(1),...,c(m+n)]buradac(k) = sum [ a(x)*b(y) for all integers x y such that x+y=k]

kurallar

  • Diliniz için uygun giriş ve çıkış biçimlendirmelerine izin verilir.
  • Evrişim için yerleşikler, evrişim matrisleri oluşturma, korelasyon ve polinom çoğalmasına izin verilmez.

Örnekler

[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
Spesifikasyon, n, m uzunluk girişlerinin n + m - 1 uzunluk çıktısı üretmesi gerektiği anlamına gelir, ancak bu test durumunuz için geçerli değildir [1,1]*[] = []ve muhtemelen dayanamaz []*[] = ?. Konvolüsyon boş listelerde iyi tanımlanmamıştır. Giriş listelerinin boş olmadığını garanti etmelisiniz.
Anders Kaseorg

1
@AndersKaseorg Haklısın, bunu değiştireceğim.
Kusur

Yanıtlar:


14

J, 10 8 bayt

[:+//.*/

Kullanımı:

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

Açıklama: Program iki liste alır, çarpım tablosu yapar, sonra sayıları pozitif köşegenlere ekler.


Çok akıllı bir yaklaşım!
Luis Mendo

Parantez saymanıza gerek yoktur. İçlerindeki ifade, bir değişkene atanabilen zımni bir fiil olarak değerlendirilir.
Dennis

Zarflara harika bir örnek!
mil

6

MATL , 19 bayt

PiYdt"TF2&YStpsw]xx

Çevrimiçi deneyin!

açıklama

Bu, ilk girişi tersine çevirerek iki girişi olan bir blok diyagonal matris oluşturur. Örneğin, girdilerle [1 4 3 5], [1 3 2]matris

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

Evrişimin her girişi, ilk sırayı bir konum sağa kaydırarak, her bir sütunun ürününü hesaplayarak ve tüm sonuçları toplayarak elde edilir.

Prensip olarak, vites değiştirme soldan sıfırlarla doldurulmalıdır. Eşdeğer olarak, dairesel kaydırma kullanılabilir, çünkü matris uygun girişlerde sıfırlar içerir.

Örneğin, ilk sonuç kaydırılan matristen elde edilir

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

ve böylece 1*1 == 1. İkincisi,

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

ve dolayısıyla, 4*1+1*3 == 7bu yapılmalıdır, vb m+n-1kez, burada mve ngiriş uzunlukları vardır. Kod, m+nyinelemeleri olan bir döngü kullanır (bazı baytları kaydeder) ve son sonucu atar.

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 bayt

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

Bir işleci tanımlar #.


1
Dolgunun tam olarak gereken uzunluğu vermek ve boş taban kasasına izin vermek [0,0..]olabileceğini düşünüyorum . (0<$b)_#b=0<$b
xnor

@xnor Gerçekten, bu 6 bayt tasarruf sağlar.
Anders Kaseorg

Sonunda cevabınızı anladığım için, bunun çok zeki olduğunu söylemeliyim! Etkilendim!
Kusur

3

Matlab / Oktav, 41 bayt

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

Bu anonim bir işlevi tanımlar. Bunu çağırmak için bir değişkene atayın veya kullanın ans.

Burada deneyin .

açıklama

Bu,

  • (Muhtemelen tekrarlanan) kökler, önde gelen katsayılarına kadar bir polinomu karakterize eder.
  • İki polinomun ürünü her ikisinin de köklerine sahiptir.

Kod, iki polinomun (fonksiyonun roots) köklerini hesaplar ve bunları bir sütun dizisine birleştirir. Bundan önden 1(işlev poly) bir polinom ürünü katsayılarını elde eder . Son olarak sonuç, iki polinomun önde gelen katsayıları ile çarpılır.


3

Oktav , 48 bayt

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

Burada deneyin .

açıklama

Ayrık evrişim (ayrık zamanlı) Fourier dönüşümlerinin çoğalmasına karşılık gelir. Dolayısıyla, polinomları çoğaltmanın bir yolu onları dönüştürmek, dönüştürülmüş dizileri çoğaltmak ve geri dönüştürmek olacaktır.

Eğer Fourier dönüşümü ayrık (DFT) Fourier dönüşümü yerine kullanılan, sonuç dairesel kıvrım polinom katsayılarının orijinal dizilerin. Kod bu yolu takip eder. Dairesel konvolüsyonu standart konvolüsyona eşit yapmak için sekanslar sıfır dolguludur ve sonuç kesilir.


Damnit, hala fft yasaklıyordum, ama iyi iş çıkardın!
Kusur

@flawr Evet, sanırım bunun hakkında konuştuk ...? :-P
Luis Mendo

2

05AB1E , 18 17 bayt

kod

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

açıklama

Arkasındaki teori:

Konvolüsyonunu bulmak için, örneğini ele alalım [1, 2, 3], [3, 4, 5]. İlk dizinin değerlerini baş aşağı ve dikey olarak konumlandırıyoruz, şöyle:

3
2
1

Şimdi, ikinci diziyi bir merdiven gibi yerleştirip şu şekilde çarpıyoruz:

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

Sonuç olarak:

        9   12   15
    6   8   10
3   4   5

Sonra, onları toplayarak sonuçlanır:

        9   12   15
    6   8   10
3   4   5       

3   10  22  22   15

Yani, evrişim [3, 10, 22, 22, 15].

Kodun kendisi:

Biz kullanarak adım adım yapacağız [1, 2, 3], [3, 4, 5]test durumu olarak.

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

Önce itiyoruz, 0sonra Eilk girdi dizisine değer veriyoruz . Her öğeyi kullanarak haritalandırıyoruz v.

Bu nedenle, her öğe için ikinci diziyi ²ve ardından ilk dizinin uzunluğunu kullanarak iteriz ¹gve bunu 1 (ile <) azaltırız. Bunu kullanarak (uzunluk 1. dizi - 1) sıfırlarla sıfırlar listesine dönüştürüyoruz ve bunu listemize ekliyoruz. Yığımız artık giriş listesindeki ilk öğe için şu şekilde görünüyor:Å0

[3, 4, 5, 0, 0]

Bu diziyi, ile yapılan geçerli öğeyle çarpıyoruz y*. Bundan sonra N, geçerli öğenin dizinini (sıfır dizinli) gösteren iteriz ve diziyi birçok kez sağa kullanarak döndürürüz FÁ}. Son olarak, bunu başlangıç ​​değerimize ( 0) ekliyoruz . Yani, temel olarak aşağıdakiler yapılır:

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

[3, 10, 22, 22, 15]

Hangisi dolaylı olarak yazdırılır. CP-1252 kodlamasını kullanır . Çevrimiçi deneyin! .


2

Jöle , 9 bayt

0;+
×'Ṛç/

Çevrimiçi deneyin! veya tüm test senaryolarını doğrulayın .

Nasıl çalışır

×'Ṛç/  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.

Ne? J'den daha uzun jöle Bu tanımı ile imkansız!
53

2

Kabuk , 5 bayt

mΣ∂Ṫ*

Çevrimiçi deneyin!

Not: Sıfır polinom / boş liste verirken, türünü belirtmeniz gerekir (örn. []:LN)!

açıklama

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 bayt

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

Çevrimiçi deneyin!

Girdilerin tüm elemanlar arası ürünlerinin bir matrisini oluşturur, ardından köşegenler boyunca toplar. ,1Uç kuvvetlerinde giriş vektörü bir uzunluğa 1 olduğunda doğru bir yön boyunca toplamak için MATLAB.

Octave spdiagsgirişlerden biri, uzunluk 1. Matlab 2016b sahiptir ya da daha yeni öğeye ürünün açık genişlemesi için gerekli olan zaman bir hata ile sonuçlanır vektörler için çalışmaz.


Güzel yaklaşım !!
Luis Mendo


1

Python, 90 bayt

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 bayt

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

Girişlerden biri boşsa boş diziyi döndürür. Polinomiyaliteye cevabım temel alınarak .



1

Clojure, 104 bayt

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

sorted-mapDeğerlerin doğru sırada döndürülmesini garanti etmek için birleştirme . Keşke birkaç test vakası daha olsaydı.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.