Convoluzione discreta o moltiplicazione polinomiale


19

Dati due elenchi di numeri interi non vuoti , l'invio deve calcolare e restituire la convoluzione discreta dei due. È interessante notare che se si considerano gli elementi della lista come coefficienti di polinomi, la convoluzione delle due liste rappresenta i coefficienti del prodotto dei due polinomi.

Definizione

Dati gli elenchi A=[a(0),a(1),a(2),...,a(n)]e B=[b(0),b(1),b(2),...,b(m)](impostazione a(k)=0 for k<0 and k>ne b(k)=0 for k<0 and k>m), la convoluzione dei due viene definita come A*B=[c(0),c(1),...,c(m+n)]dovec(k) = sum [ a(x)*b(y) for all integers x y such that x+y=k]

Regole

  • È consentita qualsiasi formattazione di input e output per la tua lingua.
  • Non sono consentiti incorporamenti per la convoluzione, la creazione di matrici di convoluzione, correlazione e moltiplicazione polinomiale.

Esempi

[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
La specifica implica che input di lunghezza n, m dovrebbero produrre un output di lunghezza n + m - 1, ma ciò non vale per il tuo caso di test [1,1]*[] = []e non può essere ritenuto valido per []*[] = ?. La convoluzione non è ben definita su elenchi vuoti. Penso che dovresti garantire che gli elenchi di input siano vuoti.
Anders Kaseorg,

1
@AndersKaseorg Hai ragione, lo cambierò.
flawr,

Risposte:


14

J, 10 8 byte

[:+//.*/

Uso:

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

Descrizione: il programma prende due elenchi, crea una tabella di moltiplicazione, quindi aggiunge i numeri sulle diagonali positive.


Approccio molto intelligente!
Luis Mendo,

Non è necessario contare le parentesi. L'espressione al loro interno restituisce un verbo tacito, che può essere assegnato a una variabile.
Dennis,

Ottimo esempio di avverbi!
miglia,

6

MATL , 19 byte

PiYdt"TF2&YStpsw]xx

Provalo online!

Spiegazione

Questo crea una matrice diagonale a blocchi con i due ingressi, invertendo il primo. Ad esempio, con gli input [1 4 3 5], [1 3 2]la matrice è

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

Ogni voce della convoluzione si ottiene spostando la prima riga di una posizione verso destra, calcolando il prodotto di ciascuna colonna e sommando tutti i risultati.

In linea di principio, lo spostamento dovrebbe essere fatto imbottitura con zeri da sinistra. Allo stesso modo, è possibile utilizzare lo spostamento circolare , poiché la matrice contiene zeri nelle voci appropriate.

Ad esempio, il primo risultato si ottiene dalla matrice spostata

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

ed è così 1*1 == 1. Il secondo è ottenuto da

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

ed è così 4*1+1*3 == 7, ecc. Questo deve essere fatto m+n-1volte, dove me nsono le lunghezze di input. Il codice utilizza un ciclo con m+niterazioni (che salva alcuni byte) e scarta l'ultimo risultato.

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 byte

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

Definisce un operatore #.


1
Penso che l'imbottitura [0,0..]possa essere quella (0<$b)di dare esattamente la lunghezza necessaria, consentendo la custodia vuota _#b=0<$b.
xnor

@xnor In effetti, ciò consente di risparmiare 6 byte.
Anders Kaseorg,

Ora che ho finalmente capito la tua risposta, devo dire che è così dannatamente intelligente! Sono impressionato!
flawr

3

Matlab / Octave, 41 byte

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

Questo definisce una funzione anonima. Per chiamarlo, assegnarlo a una variabile o utilizzare ans.

Provalo qui .

Spiegazione

Questo sfrutta i fatti che

  • Le radici (forse ripetute) caratterizzano un polinomio fino al suo coefficiente principale.
  • Il prodotto di due polinomi ha le radici di entrambi.

Il codice calcola le radici dei due polinomi (funzione roots) e li concatena in una matrice di colonne. Da ciò ottiene i coefficienti del polinomio del prodotto con un segno 1(funzione poly). Infine, il risultato viene moltiplicato per i coefficienti principali dei due polinomi.


3

Ottava , 48 byte

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

Provalo qui .

Spiegazione

La convoluzione discreta corrisponde alla moltiplicazione delle trasformazioni di Fourier (a tempo discreto). Quindi un modo per moltiplicare i polinomi sarebbe trasformarli, moltiplicare le sequenze trasformate e tornare indietro.

Se viene utilizzata la trasformata di Fourier discreta (DFT) al posto della trasformata di Fourier, il risultato è la convoluzione circolare delle sequenze originali di coefficienti polinomiali. Il codice segue questo percorso. Per rendere la convoluzione circolare uguale alla convoluzione standard, le sequenze sono a zero e il risultato viene ritagliato.


Dannazione, avrei comunque potuto vietare fft, ma buon lavoro!
Flawr,

@flawr Sì, penso che ne abbiamo parlato ...? :-P
Luis Mendo,

2

05AB1E , 18 17 byte

Codice

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

Spiegazione

La teoria dietro:

Per trovare la convoluzione, prendiamo l'esempio [1, 2, 3], [3, 4, 5]. Posizioniamo i valori del primo array sottosopra e verticalmente, in questo modo:

3
2
1

Ora posizioniamo il secondo array come una scala e lo moltiplichiamo per:

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

Risultato in:

        9   12   15
    6   8   10
3   4   5

Quindi, li sommiamo, risultando in:

        9   12   15
    6   8   10
3   4   5       

3   10  22  22   15

Quindi, la convoluzione è [3, 10, 22, 22, 15].

Il codice stesso:

Faremo questo passo per passo usando [1, 2, 3], [3, 4, 5]come caso di test.

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

Prima spingiamo 0e poi Evalutiamo il primo array di input. Mappiamo su ogni elemento usando v.

Quindi, per ogni elemento, spingiamo il secondo array con ²e poi la lunghezza del primo array usando ¹ge diminuiamo di 1 (con <). Lo convertiamo in un elenco di zeri con (length 1st array - 1) zeri, usando Å0e aggiungendo questo al nostro elenco. Il nostro stack ora assomiglia a questo per il primo elemento nell'elenco di input:

[3, 4, 5, 0, 0]

Moltiplichiamo questo array per l'elemento corrente, fatto con y*. Dopodiché, premiamo N, che indica l'indice dell'elemento corrente (indicizzato a zero) e ruotiamo l'array che molte volte verso destra usando FÁ}. Infine, lo aggiungiamo al nostro valore iniziale ( 0). Quindi, ciò che sostanzialmente viene fatto è il seguente:

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

[3, 10, 22, 22, 15]

Che viene quindi implicitamente stampato. Utilizza la codifica CP-1252 . Provalo online! .


2

Gelatina , 9 byte

0;+
×'Ṛç/

Provalo online! o verifica tutti i casi di test .

Come funziona

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

What‽ Jelly più a lungo di J‽ È impossibile per definizione!
Adám,

2

Buccia , 5 byte

mΣ∂Ṫ*

Provalo online!

Nota: quando si fornisce l'elenco a zero polinomi / vuoto, è necessario specificarne il tipo (ad es. []:LN)!

Spiegazione

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 byte

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

Provalo online!

Crea una matrice di tutti i prodotti per input degli elementi, quindi somma lungo le diagonali. Alla ,1fine forza il matlab a sommare lungo la direzione corretta quando uno dei vettori di input ha lunghezza 1.

In Octave spdiagsnon funziona per i vettori, causando un errore quando uno degli input ha lunghezza 1. Matlab 2016b o più recente è necessario per l'espansione esplicita del prodotto saggio elemento.


Bel approccio !!
Luis Mendo,


1

Python, 90 byte

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 byte

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

Restituisce l'array vuoto se uno degli input è vuoto. Sulla base della mia risposta a Polynomialception .



1

Clojure, 104 byte

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

Fusione per sorted-mapgarantire che i valori vengano restituiti nell'ordine corretto. Vorrei che ci fossero altri casi di test.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.