Convolución discreta o multiplicación polinómica

19

Dadas dos listas no enteras de enteros, su envío debe calcular y devolver la convolución discreta de los dos. Curiosamente, si considera los elementos de la lista como coeficientes de polinomios, la convolución de las dos listas representa los coeficientes del producto de los dos polinomios.

Definición

Dadas las listas A=[a(0),a(1),a(2),...,a(n)]y B=[b(0),b(1),b(2),...,b(m)](configuración a(k)=0 for k<0 and k>ny b(k)=0 for k<0 and k>m), entonces la convolución de los dos se define como A*B=[c(0),c(1),...,c(m+n)]dondec(k) = sum [ a(x)*b(y) for all integers x y such that x+y=k]

Reglas

  • Se permite cualquier formato de entrada y salida conveniente para su idioma.
  • Las incorporaciones para convolución, creación de matrices de convolución, correlación y multiplicación polinómica no están permitidas.

Ejemplos

[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]
falla
fuente
3
La especificación implica que las entradas de longitud n, m deberían producir una salida de longitud n + m - 1, pero esto no es válido para su caso de prueba [1,1]*[] = [], y no es posible que lo sea []*[] = ?. La convolución no está bien definida en las listas vacías. Creo que debe garantizar que las listas de entrada no estén vacías.
Anders Kaseorg
1
@ AndersKaseorg Tienes razón, cambiaré eso.
falla

Respuestas:

14

J, 10 8 bytes

[:+//.*/

Uso:

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

Descripción: El programa toma dos listas, hace una tabla de multiplicar, luego agrega los números en las diagonales positivas.

ljeabmreosn
fuente
Enfoque muy inteligente!
Luis Mendo
No necesitas contar los paréntesis. La expresión dentro de ellos se evalúa como un verbo tácito, que puede asignarse a una variable.
Dennis
Gran ejemplo de adverbios!
millas
6

MATL , 19 bytes

PiYdt"TF2&YStpsw]xx

Pruébalo en línea!

Explicación

Esto construye una matriz de bloques en diagonal con las dos entradas, invirtiendo la primera. Por ejemplo, con entradas [1 4 3 5], [1 3 2]la matriz es

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

Cada entrada de la convolución se obtiene desplazando la primera fila una posición hacia la derecha, calculando el producto de cada columna y sumando todos los resultados.

En principio, el desplazamiento debe hacerse rellenando con ceros desde la izquierda. De manera equivalente, se puede usar desplazamiento circular , porque la matriz contiene ceros en las entradas apropiadas.

Por ejemplo, el primer resultado se obtiene de la matriz desplazada

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

y es asi 1*1 == 1. El segundo se obtiene de

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

y es así 4*1+1*3 == 7, etc. Esto debe hacerse m+n-1veces, donde my nson las longitudes de entrada. El código usa un bucle con m+niteraciones (que ahorra algunos bytes) y descarta el último resultado.

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
Luis Mendo
fuente
4

Haskell, 55 49 bytes

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

Define un operador #.

Anders Kaseorg
fuente
1
Creo que el relleno [0,0..]puede ser (0<$b)para dar exactamente la longitud necesaria, permitiendo el caso base vacío _#b=0<$b.
xnor
@xnor De hecho, eso ahorra 6 bytes.
Anders Kaseorg
Ahora que finalmente entiendo tu respuesta, ¡tengo que decir que esto es muy inteligente! ¡Estoy impresionado!
error
3

Matlab / Octave, 41 bytes

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

Esto define una función anónima. Para llamarlo, asígnelo a una variable o use ans.

Probar aquí .

Explicación

Esto explota los hechos que

  • Las raíces (posiblemente repetidas) caracterizan un polinomio hasta su coeficiente principal.
  • El producto de dos polinomios tiene las raíces de ambos.

El código calcula las raíces de los dos polinomios (función roots) y los concatena en una matriz de columnas. De ahí obtiene los coeficientes del polinomio del producto con una 1función ( principal poly). Finalmente, el resultado se multiplica por los coeficientes principales de los dos polinomios.

Luis Mendo
fuente
3

Octava , 48 bytes

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

Probar aquí .

Explicación

La convolución discreta corresponde a la multiplicación de las transformadas de Fourier (tiempo discreto). Entonces, una forma de multiplicar los polinomios sería transformarlos, multiplicar las secuencias transformadas y transformar de nuevo.

Si se usa la transformada discreta de Fourier (DFT) en lugar de la transformada de Fourier, el resultado es la convolución circular de las secuencias originales de coeficientes polinomiales. El código sigue esta ruta. Para hacer que la convolución circular sea igual a la convolución estándar, las secuencias se rellenan con ceros y el resultado se recorta.

Luis Mendo
fuente
Maldición, todavía debería haber prohibido fft, ¡pero buen trabajo!
flawr
@flawr Sí, creo que hablamos de eso ...? :-P
Luis Mendo
2

05AB1E , 18 17 bytes

Código

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

Explicación

La teoría detrás de:

Para encontrar la convolución, tomemos el ejemplo [1, 2, 3], [3, 4, 5]. Colocamos los valores de la primera matriz boca abajo y verticalmente, así:

3
2
1

Ahora, colocamos la segunda matriz como una escalera y la multiplicamos por:

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

Resultando en:

        9   12   15
    6   8   10
3   4   5

Luego, los sumamos, resultando en:

        9   12   15
    6   8   10
3   4   5       

3   10  22  22   15

Entonces, la convolución es [3, 10, 22, 22, 15].

El código en sí:

Vamos a hacer esto paso a paso usando [1, 2, 3], [3, 4, 5]como el caso de prueba.

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

Primero presionamos 0y luego valoramos Ela primera matriz de entrada. Mapeamos cada elemento usando v.

Entonces, para cada elemento, empujamos la segunda matriz con ²y luego la longitud de la primera matriz usando ¹gy disminuimos esto en 1 (con <). Convertimos esto en una lista de ceros con (longitud 1ª matriz - 1) ceros, usando Å0y agregamos esto a nuestra lista. Nuestra pila ahora se ve así para el primer elemento en la lista de entrada:

[3, 4, 5, 0, 0]

Multiplicamos esta matriz con el elemento actual, hecho con y*. Después de eso, presionamos N, lo que indica el índice del elemento actual (indexado a cero) y rotamos la matriz que muchas veces hacia la derecha usando FÁ}. Finalmente, agregamos esto a nuestro valor inicial ( 0). Entonces, lo que básicamente se hace es lo siguiente:

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

[3, 10, 22, 22, 15]

Que luego se imprime implícitamente. Utiliza la codificación CP-1252 . Pruébalo en línea! .

Adnan
fuente
2

Jalea , 9 bytes

0;+
×'Ṛç/

Pruébalo en línea! o verificar todos los casos de prueba .

Cómo funciona

×'Ṛç/  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.
Dennis
fuente
¿Qué? Jalea más que J. ¡Eso es imposible por definición!
Adám
2

Casco , 5 bytes

mΣ∂Ṫ*

Pruébalo en línea!

Nota: ¡ Al suministrar la lista de polinomio cero / vacío, debe especificar su tipo (es decir []:LN)!

Explicación

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]
ბიმო
fuente
2

Matlab, 33 bytes

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

Pruébalo en línea!

Crea una matriz de todos los productos basados ​​en elementos de las entradas, luego suma a lo largo de las diagonales. Al ,1final, obliga a matlab a sumar a lo largo de la dirección correcta cuando uno de los vectores de entrada tiene longitud 1.

En Octave spdiagsno funciona para vectores, lo que genera un error cuando una de las entradas tiene una longitud 1. Se requiere Matlab 2016b o posterior para la expansión explícita del producto basado en elementos.

Lucas
fuente
Buen enfoque !!
Luis Mendo
1

Python, 90 bytes

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)]
orlp
fuente
1

JavaScript (ES6), 64 bytes

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

Devuelve la matriz vacía si alguna de las entradas está vacía. Basado en mi respuesta a Polynomialception .

Neil
fuente
1

Clojure, 104 bytes

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

La fusión con sorted-mapgarantías de que los valores se devuelven en el orden correcto. Desearía que hubiera más casos de prueba.

NikoNyrh
fuente