Diskrete Faltung oder polynomielle Multiplikation


19

Bei zwei nicht leeren Listen mit ganzen Zahlen sollte Ihre Übermittlung die diskrete Faltung der beiden berechnen und zurückgeben . Wenn Sie Listenelemente als Koeffizienten von Polynomen betrachten, repräsentiert die Faltung der beiden Listen interessanterweise die Koeffizienten des Produkts der beiden Polynome.

Definition

In Anbetracht der Listen A=[a(0),a(1),a(2),...,a(n)]und B=[b(0),b(1),b(2),...,b(m)](Setzen a(k)=0 for k<0 and k>nund b(k)=0 for k<0 and k>m) ist die Faltung der beiden als A*B=[c(0),c(1),...,c(m+n)]wo definiertc(k) = sum [ a(x)*b(y) for all integers x y such that x+y=k]

Regeln

  • Beliebige bequeme Eingabe- und Ausgabeformate für Ihre Sprache sind zulässig.
  • Integrierte Funktionen für Faltung, Erstellung von Faltungsmatrizen, Korrelation und Polynommultiplikation sind nicht zulässig.

Beispiele

[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
Die Spezifikation impliziert, dass Eingaben mit der Länge n, m eine Ausgabe mit der Länge n + m - 1 erzeugen sollten, aber dies gilt nicht für Ihren Testfall [1,1]*[] = []und kann möglicherweise nicht für gelten []*[] = ?. Faltung ist in leeren Listen nicht genau definiert. Ich denke, Sie sollten garantieren, dass die Eingabelisten nicht leer sind.
Anders Kaseorg

1
@AndersKaseorg Du hast recht, das werde ich ändern.
Fehler

Antworten:


14

J 10 8 Bytes

[:+//.*/

Verwendung:

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

Beschreibung: Das Programm nimmt zwei Listen auf, erstellt eine Multiplikationstabelle und addiert die Zahlen zu den positiven Diagonalen.


Sehr kluger Ansatz!
Luis Mendo

Sie müssen die Klammern nicht zählen. Der Ausdruck in ihnen ergibt ein implizites Verb, das einer Variablen zugewiesen werden kann.
Dennis

Tolles Beispiel für Adverbien!
Meilen

6

MATL , 19 Bytes

PiYdt"TF2&YStpsw]xx

Probieren Sie es online!

Erläuterung

Dadurch wird eine Blockdiagonalmatrix mit den beiden Eingängen erstellt, wobei der erste umgekehrt wird. Bei Eingaben [1 4 3 5]ist [1 3 2]die Matrix beispielsweise

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

Jeder Eintrag der Faltung wird erhalten, indem die erste Reihe um eine Position nach rechts verschoben, das Produkt jeder Spalte berechnet und alle Ergebnisse summiert werden.

Grundsätzlich sollte die Verschiebung mit Nullen von links aufgefüllt werden. Entsprechend kann die Umlaufverschiebung verwendet werden, da die Matrix an den entsprechenden Einträgen Nullen enthält.

Zum Beispiel wird das erste Ergebnis aus der verschobenen Matrix erhalten

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

und ist so 1*1 == 1. Die Sekunde wird von erhalten

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

und ist damit 4*1+1*3 == 7usw. Dies muss m+n-1mal gemacht werden, wo mund nsind die Eingangslängen. Der Code verwendet eine Schleife mit m+nIterationen (die einige Bytes einsparen) und verwirft das letzte Ergebnis.

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 Bytes

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

Definiert einen Operator #.


1
Ich denke, die Polsterung [0,0..]kann sein (0<$b), um genau die benötigte Länge zu geben, die das leere Basisgehäuse zulässt _#b=0<$b.
xnor

@xnor Das spart in der Tat 6 Bytes.
Anders Kaseorg

Jetzt, wo ich endlich deine Antwort verstehe, muss ich sagen, dass das nur so verdammt schlau ist! Ich bin beeindruckt!
1.

3

Matlab / Octave, 41 Bytes

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

Dies definiert eine anonyme Funktion. Um es aufzurufen, weisen Sie es einer Variablen zu oder verwenden Sie ans.

Probieren Sie es hier aus .

Erläuterung

Dies nutzt die Fakten, die

  • Die (möglicherweise wiederholten) Wurzeln charakterisieren ein Polynom bis zu seinem führenden Koeffizienten.
  • Das Produkt zweier Polynome hat die Wurzeln beider.

Der Code berechnet die Wurzeln der beiden Polynome (Funktion roots) und verknüpft sie zu einem Spaltenarray. Daraus erhält er die Koeffizienten des Produktpolynoms mit einer führenden 1(Funktion poly). Schließlich wird das Ergebnis mit den führenden Koeffizienten der beiden Polynome multipliziert.


3

Oktave , 48 Bytes

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

Probieren Sie es hier aus .

Erläuterung

Die diskrete Faltung entspricht der Multiplikation der (zeitdiskreten) Fouriertransformationen. Eine Möglichkeit, die Polynome zu multiplizieren, besteht darin, sie zu transformieren, die transformierten Sequenzen zu multiplizieren und zurück zu transformieren.

Wenn die diskrete Fouriertransformation (DFT) anstelle der Fouriertransformation verwendet wird, ist das Ergebnis die zirkuläre Faltung der ursprünglichen Folgen von Polynomkoeffizienten. Der Code folgt dieser Route. Damit die Kreisfaltung der Standardfaltung entspricht, werden die Sequenzen mit Nullen aufgefüllt und das Ergebnis wird getrimmt.


Verdammt, ich hätte noch fft verboten, aber gute Arbeit!
Fehler

@flawr Ja, ich denke wir haben darüber gesprochen ...? :-P
Luis Mendo

2

05AB1E , 18 17 Bytes

Code

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

Erläuterung

Die Theorie dahinter:

Um die Faltung zu finden, lassen Sie uns das Beispiel nehmen [1, 2, 3], [3, 4, 5]. Wir positionieren die Werte des ersten Arrays verkehrt herum und vertikal wie folgt:

3
2
1

Jetzt platzieren wir das zweite Array wie eine Leiter und multiplizieren es mit:

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

Resultierend in:

        9   12   15
    6   8   10
3   4   5

Dann addieren wir sie zu:

        9   12   15
    6   8   10
3   4   5       

3   10  22  22   15

Die Faltung ist also [3, 10, 22, 22, 15].

Der Code selbst:

Wir werden dies Schritt für Schritt mit dem [1, 2, 3], [3, 4, 5]als Testfall durchführen.

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

Wir drücken zuerst 0und Ebewerten dann das erste Eingabearray. Wir bilden jedes Element mit ab v.

Also drücken wir für jedes Element das zweite Array mit ²und dann die Länge des ersten Arrays mit ¹gund verringern diese um 1 (mit <). Wir wandeln dies in eine Liste von Nullen mit (Länge 1. Array - 1) Nullen um Å0und fügen dies unserer Liste hinzu. Unser Stack sieht jetzt für das erste Element in der Eingabeliste so aus:

[3, 4, 5, 0, 0]

Wir multiplizieren dieses Array mit dem aktuellen Element y*. Danach drücken wir N, was den Index des aktuellen Elements angibt (null-indiziert) und drehen das Array mit um ein Vielfaches nach rechts FÁ}. Schließlich addieren wir dies zu unserem Anfangswert ( 0). Im Grunde wird also Folgendes getan:

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

[3, 10, 22, 22, 15]

Welches wird dann implizit gedruckt. Verwendet die CP-1252- Codierung. Probieren Sie es online! .


2

Gelee , 9 Bytes

0;+
×'Ṛç/

Probieren Sie es online! oder überprüfen Sie alle Testfälle .

Wie es funktioniert

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

Was? Gelee länger als? Das ist per Definition unmöglich!
Adám

2

Schale , 5 Bytes

mΣ∂Ṫ*

Probieren Sie es online!

Hinweis: Wenn Sie die Nullpolynom- / Leerliste bereitstellen, müssen Sie deren Typ angeben (z. B. []:LN)!

Erläuterung

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 Bytes

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

Probieren Sie es online!

Erstellt eine Matrix aller elementweisen Produkte der Eingaben und summiert dann entlang der Diagonalen. Am ,1Ende wird matlab gezwungen, in der richtigen Richtung zu summieren, wenn einer der Eingabevektoren die Länge 1 hat.

In Octave spdiagsfunktioniert dies nicht für Vektoren, was zu einem Fehler führt, wenn einer der Eingänge die Länge 1 hat. Matlab 2016b oder neuer wird für die explizite Erweiterung des elementweisen Produkts benötigt.


Netter Ansatz !!
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)]

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

Gibt das leere Array zurück, wenn eine der Eingaben leer ist. Basierend auf meiner Antwort auf Polynomialception .



1

Clojure, 104 Bytes

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

Das Zusammenführen zu sorted-mapgarantiert, dass die Werte in der richtigen Reihenfolge zurückgegeben werden. Ich wünschte, es gäbe noch ein paar Testfälle.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.