Convolution discrète ou multiplication polynomiale


19

Étant donné deux listes d'entiers non vides , votre soumission doit calculer et renvoyer la convolution discrète des deux. Fait intéressant, si vous considérez les éléments de la liste comme des coefficients de polynômes, la convolution des deux listes représente les coefficients du produit des deux polynômes.

Définition

Étant donné les listes A=[a(0),a(1),a(2),...,a(n)]et B=[b(0),b(1),b(2),...,b(m)](réglage a(k)=0 for k<0 and k>net b(k)=0 for k<0 and k>m), la convolution des deux est définie comme 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]

Règles

  • Tout formatage d'entrée et de sortie pratique pour votre langue est autorisé.
  • Les fonctions intégrées pour la convolution, la création de matrices de convolution, la corrélation et la multiplication polynomiale ne sont pas autorisées.

Exemples

[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 spécification implique que les entrées de longueur n, m devraient produire une sortie de longueur n + m - 1, mais cela ne vaut pas pour votre cas de test [1,1]*[] = [], et ne peut pas tenir pour []*[] = ?. La convolution n'est pas bien définie sur les listes vides. Je pense que vous devez garantir que les listes d'entrée ne sont pas vides.
Anders Kaseorg

1
@AndersKaseorg Vous avez raison, je vais changer cela.
flawr

Réponses:


14

J, 10 8 octets

[:+//.*/

Usage:

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

Description: Le programme prend deux listes, crée une table de multiplication, puis ajoute les nombres sur les diagonales positives.


Approche très intelligente!
Luis Mendo

Vous n'avez pas besoin de compter les parenthèses. L'expression à l'intérieur d'eux est évaluée en un verbe tacite, qui peut être affecté à une variable.
Dennis

Excellent exemple d'adverbes!
miles

6

MATL , 19 octets

PiYdt"TF2&YStpsw]xx

Essayez-le en ligne!

Explication

Cela crée une matrice diagonale de bloc avec les deux entrées, inversant la première. Par exemple, avec des entrées [1 4 3 5], [1 3 2]la matrice est

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

Chaque entrée de la convolution est obtenue en décalant la première ligne d'une position vers la droite, en calculant le produit de chaque colonne et en additionnant tous les résultats.

En principe, le décalage doit être effectué avec un remplissage avec des zéros à partir de la gauche. De manière équivalente, un décalage circulaire peut être utilisé, car la matrice contient des zéros aux entrées appropriées.

Par exemple, le premier résultat est obtenu à partir de la matrice décalée

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

et est ainsi 1*1 == 1. Le second est obtenu à partir de

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

et est donc 4*1+1*3 == 7, etc. Cela doit être fait m+n-1fois, où met nsont les longueurs d'entrée. Le code utilise une boucle avec des m+nitérations (qui économise quelques octets) et ignore le dernier résultat.

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 octets

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

Définit un opérateur #.


1
Je pense que le rembourrage [0,0..]peut être (0<$b)de donner exactement la longueur nécessaire, permettant le cas de base vide _#b=0<$b.
xnor

@xnor En effet, cela économise 6 octets.
Anders Kaseorg

Maintenant que j'ai enfin compris votre réponse, je dois dire que c'est tellement sacrément intelligent! Je suis impressionné!
flawr

3

Matlab / Octave, 41 octets

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

Cela définit une fonction anonyme. Pour l'appeler, affectez-le à une variable ou utilisez ans.

Essayez-le ici .

Explication

Cela exploite les faits

  • Les racines (éventuellement répétées) caractérisent un polynôme jusqu'à son coefficient dominant.
  • Le produit de deux polynômes a les racines des deux.

Le code calcule les racines des deux polynômes (fonction roots) et les concatène dans un tableau de colonnes. De là, il obtient les coefficients du polynôme produit avec une 1fonction ( leader poly). Enfin, le résultat est multiplié par les coefficients de tête des deux polynômes.


3

Octave , 48 octets

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

Essayez-le ici .

Explication

La convolution discrète correspond à la multiplication des transformées de Fourier (en temps discret). Donc, une façon de multiplier les polynômes serait de les transformer, de multiplier les séquences transformées et de les retransformer.

Si la transformée de Fourier discrète (DFT) est utilisée à la place de la transformée de Fourier, le résultat est la convolution circulaire des séquences originales de coefficients polynomiaux. Le code suit cette route. Pour rendre la convolution circulaire égale à la convolution standard, les séquences sont complétées par un zéro et le résultat est tronqué.


Merde, j'aurais toujours dû interdire le fft, mais bon travail!
flawr

@flawr Oui, je pense que nous en avons parlé ...? :-P
Luis Mendo

2

05AB1E , 18 17 octets

Code

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

Explication

La théorie derrière:

Pour trouver la convolution, nous allons prendre l'exemple [1, 2, 3], [3, 4, 5]. Nous positionnons les valeurs du premier tableau à l'envers et verticalement, comme ceci:

3
2
1

Maintenant, nous plaçons le deuxième tableau comme une échelle et le multiplions par:

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

Résultat en:

        9   12   15
    6   8   10
3   4   5

Ensuite, nous les additionnons, ce qui donne:

        9   12   15
    6   8   10
3   4   5       

3   10  22  22   15

Ainsi, la convolution est [3, 10, 22, 22, 15].

Le code lui-même:

Nous allons le faire étape par étape en utilisant le [1, 2, 3], [3, 4, 5]comme cas de test.

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

Nous poussons d'abord 0et ensuite nous Eévaluons le premier tableau d'entrée. Nous cartographions chaque élément en utilisant v.

Donc, pour chaque élément, nous poussons le deuxième tableau avec ²puis la longueur du premier tableau en utilisant ¹get diminuons cela de 1 (avec <). Nous convertissons cela en une liste de zéros avec (longueur 1er tableau - 1) zéros, en l'utilisant Å0et en l'ajoutant à notre liste. Notre pile ressemble maintenant à ceci pour le premier élément de la liste d'entrée:

[3, 4, 5, 0, 0]

On multiplie ce tableau par l'élément courant, fini avec y*. Après cela, nous poussons N, ce qui indique l'index de l'élément actuel (indexé zéro) et tournons le tableau autant de fois vers la droite en utilisant FÁ}. Enfin, nous ajoutons cela à notre valeur initiale ( 0). Donc, ce qui est essentiellement fait est le suivant:

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

[3, 10, 22, 22, 15]

Qui est ensuite implicitement imprimé. Utilise l' encodage CP-1252 . Essayez-le en ligne! .


2

Gelée , 9 octets

0;+
×'Ṛç/

Essayez-le en ligne! ou vérifiez tous les cas de test .

Comment ça fonctionne

×'Ṛç/  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 plus longtemps que J‽ C'est impossible par définition!
Adám

2

Husk , 5 octets

mΣ∂Ṫ*

Essayez-le en ligne!

Remarque: Lorsque vous fournissez la liste zéro-polynôme / vide, vous devez spécifier son type (c'est-à-dire. []:LN)!

Explication

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 octets

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

Essayez-le en ligne!

Crée une matrice de tous les produits élément par élément des entrées, puis additionne le long des diagonales. L' ,1extrémité oblige matlab à additionner le long de la bonne direction lorsque l'un des vecteurs d'entrée a la longueur 1.

Dans Octave spdiagsne fonctionne pas pour les vecteurs, ce qui entraîne une erreur lorsqu'une des entrées a une longueur 1. Matlab 2016b ou plus récent est requis pour l'expansion explicite du produit par élément.


Belle approche !!
Luis Mendo


1

Python, 90 octets

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 octets

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

Renvoie le tableau vide si l'une des entrées est vide. Basé sur ma réponse à Polynomialception .



1

Clojure, 104 octets

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

La fusion sorted-mapgarantit que les valeurs sont retournées dans le bon ordre. Je souhaite qu'il y ait encore quelques cas de test.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.