Matrizenmultiplikation nach Strassen Seminar Sommersemester 2015 Bearbeitet von: Tobias Menge Felix Mayer Dennis Schäfer Betreuer: Prof. Dr. habil. Thomas Thierauf Hochschule für Technik und Wirtschaft Aalen Fakultät Elektronik und Informatik Studiengang Informatik Inhaltsverzeichnis 1 Einleitung 2 2 Klassische Matrixmultiplikation 2.1 Iterative Methode . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Rekursive Methode . . . . . . . . . . . . . . . . . . . . . . . . 3 3 3 3 Matrixmultiplikation nach Strassen 3.1 Pseudocode . . . . . . . . . . . . . 3.2 Herleitung . . . . . . . . . . . . . . 3.3 Korrektheit . . . . . . . . . . . . . 3.4 Laufzeitverhalten . . . . . . . . . . 3.5 Einschränkungen . . . . . . . . . . 4 Weitere Algorithmen 5 Multiplikation nach Karatsuba 5.1 Allgemein . . . . . . . . . . . 5.2 Effizienzbetrachtung . . . . . 5.3 Beispielhafte Anwendung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 5 6 10 13 15 16 und . . . . . . . . . Ofman 19 . . . . . . . . . . . . . . . 19 . . . . . . . . . . . . . . . 20 . . . . . . . . . . . . . . . 21 Literaturverzeichnis 23 Abbildungsverzeichnis 25 1 Einleitung Als Matrixmultiplikation bezeichnet man die Multiplikation zweier Matrizen. Diese Problemstellung tritt in vielen Algorithmen als Teilproblem auf, sodass großes Interesse darin besteht die Laufzeitkomplexität möglichst stark zu reduzieren. Beispielsweise benötigt man die Matrixmultiplikation zum Lösen linearer Gleichungssysteme, zur Bestimmung von Determinanten und in der Graphentheorie. Es gibt aber auch Anwendungsgebiete außerhalb der klassischen Mathematik wie beispielsweise die Frage, ob ein Wort zur Sprache einer kontextfreien Grammatik gehört [Val75]. Oftmals ist die Matrixmultiplikation dabei sogar der entscheidende Faktor für den Aufwand bzw. die Schnelligkeit des Algorithmus [Wul08]. Die klassische Methode zur Matrixmultiplikation, bei der Zeilen und Spalten naiv multipliziert werden, hat eine Laufzeitkomplexität von Θ(n3 ) und galt lange Zeit als die einzige Methode [Bar13]. Im Jahre 1969 konnte Volker Strassen in seiner Arbeit mit dem Titel „Gaussian Elimination is not optimal“ zeigen, dass es möglich ist den Aufwand auf ca. O(n2,81 ) zu reduzieren [Str68]. Nach der Veröffentlichung dieser Arbeit wurden zahlreiche weitere Personen auf dieses Thema aufmerksam und es begann ein regelrechter Wettlauf nach dem theoretisch schnellsten Algorithmus [Bar13]. Auch Strassen selbst beteiligte sich an diesem Wettrennen und entdeckte 17 Jahre später einen komplett neuen Ansatz zur Lösung des Problems (→ Lasermethode) und konnte die Komplexität auf O(n2,48 ) reduzieren [Wil14]. Dieser Algorithmus soll jedoch in dieser Arbeit, wie andere noch schnellere Algorithmen, nur am Rande erwähnt werden. Stattdessen liegt der Fokus auf dem Originalalgorithmus von 1969, da dieser leicht zu verstehen ist und zeigt, wie das Programmierparadigma divide and conquer zur effizienteren Lösung eines Problems angewendet werden kann. Anschließend soll ein weiterer anschaulicher und schneller divide and conquer Algorithmus zur Multiplikation von langen Zahlen vorgestellt werden. 2 2 Klassische Matrixmultiplikation Definition 1. Allgemein ist eine Matrix ein rechteckiges Feld von Zahlen [CSRL10]. Im Folgenden werden nur quadratische n × n - Matrizen betrachtet: An,n a1,1 a2,1 = .. . a1,2 a2,2 .. . ··· ··· .. . an,1 an,2 · · · 2.1 a1,n a2,n .. . (1) an,n Iterative Methode Die Matrizenmultiplikation C = A · B ist für die Matrizen A, B, C wie folgt definiert: ci,j = n X ai,k · bk,j i, j ∈ N (2) k=1 [CSRL10] Diese Summe kann in einem äquivalenten Pseudocode formuliert werden. Algorithm 1 Quadratische Matrizenmultiplikation [CSRL10] 1: 2: 3: 4: 5: 6: 7: 8: 9: function Square-Matrix-Multiply(A,B) n ← A.zeilen sei C eine neue n × n - Matrix for i = 1 to n do for j = 1 to n do ci,j ← 0 for j = 1 to n do ci,j ← ci,j + ai,k · bk,j return C Im obigen Pseudocode werden drei geschachtelte For-Schleifen verwendet, die alle jeweils n Iterationen durchlaufen. Dies ergibt durch die O-Notation eine Laufzeit von Θ(n3 ). 2.2 Rekursive Methode Seien A, B und C n × n - Matrizen, wobei n eine Zweierpotenz ist. Dann können, alternativ zur ersten Methode, die Matrizen der Multiplikation C = 3 A · B rekursiv in n 2 × n 2 Matrizen zerlegt werden: C1,1 C1,2 C2,1 C2,2 ! ! = B1,1 B1,2 A1,1 A1,2 · B2,1 B2,2 A2,1 A2,2 ! (3) Die Teilmatrizen der Matrix C werden mit den nachfolgenden Formeln berechnet: C1,1 = A1,1 · B1,1 + A1,2 · B2,1 (4) C1,2 = A1,1 · B1,2 + A1,2 · B2,2 (5) C2,1 = A2,1 · B1,1 + A2,2 · B2,1 (6) C2,2 = A2,1 · B1,2 + A2,2 · B2,2 (7) Der dazugehörige Algorithmus lässt sich wie folgt formulieren: Algorithm 2 Quadratische Matrizenmultiplikation (Rekursiv) 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: function Square-Matrix-Multiply-Rekursiv(A,B) n ← A.zeilen sei C eine neue n × n - Matrix if n = 1 then c1,1 ← a1,1 · b1,1 else partitioniere A, B, C gemäß der Gleichung 3 C1,1 ← Square-Matrix-Multiply-Rekursiv(A1,1 , B1,1 ) + Square-Matrix-Multiply-Rekursiv(A1,2 , B2,1 ) C1,2 ← Square-Matrix-Multiply-Rekursiv(A1,1 , B1,2 ) + Square-Matrix-Multiply-Rekursiv(A1,2 , B2,2 ) C2,1 ← Square-Matrix-Multiply-Rekursiv(A2,1 , B1,1 ) + Square-Matrix-Multiply-Rekursiv(A2,2 , B2,1 ) C2,2 ← Square-Matrix-Multiply-Rekursiv(A2,1 , B1,2 ) + Square-Matrix-Multiply-Rekursiv(A2,2 , B2,2 ) return C Durch acht rekursive Aufrufe ergibt sich mit Hilfe des Master-Theorems (siehe Kap. 3.4) eine Laufzeit von Θ(n3 ). 4 3 3.1 Matrixmultiplikation nach Strassen Pseudocode Die Matrixmultiplikation nach Strassen basiert auf der rekursiven Methode (Kap. 2.2). Sie setzt n × n Matrizen ein (mit n = 2i i ∈ N) und teilt diese ebenso in vier n2 × n2 Matrizen auf (Zeile 7 des Pseudocode bzw. Gleichung (3)). Der Unterschied und letztendlich die Optimierung von Strassen basiert darauf, wie diese Teilmatrizen berechnet werden. Um die Optimierung zu veranschaulichen soll zunächst ein Pseudocode des Algorithmus vorgestellt werden. Algorithm 3 Matrixmultiplikation nach Strassen 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: function Strassen(A,B) n ← A.zeilen sei C eine neue n × n - Matrix if n = 1 then c1,1 ← a1,1 · b1,1 else partitioniere A, B, C gemäß der Gleichung 3 P 1 ← Strassen(A1,1 , (B1,2 − B2,2 )) P 2 ← Strassen((A1,1 + A1,2 ), B2,2 ) P 3 ← Strassen((A2,1 + A2,2 ), B1,1 ) P 4 ← Strassen(A2,2 , (B2,1 − B1,1 )) P 5 ← Strassen((A1,1 + A2,2 ), (B1,1 + B2,2 )) P 6 ← Strassen((A1,2 − A2,2 ), (B2,1 + B2,2 )) P 7 ← Strassen((A1,1 − A2,1 ), (B1,1 + B1,2 )) 15: ← P5 + P4 − P2 + P6 ← P1 + P2 ← P3 + P4 ← P5 + P1 − P3 − P7 19: C1,1 C1,2 C2,1 C2,2 20: return C 16: 17: 18: In Zeile 8-14 werden zunächst die 7 Zwischenergebnisse P 1 bis P 7 (Zeile 8-14) berechnet und diese wiederum in Kombination verwendet, um die Teilmatrizen Ci,j zu konstruieren (Zeile 16-19). Diese Kombinationen und die Berechnungen der Zwischenergebnisse stellen die Innovation von Strassen dar und sollen nun ausführlicher beleuchtet werden. 5 3.2 Herleitung Im Folgenden soll der eingangs vorgestellte Algorithmus von Strassen genauer erklärt und seine Vor- und Nachteile erläutert werden. Dazu wird zunächst ein möglicher Weg aufgezeigt, auf dem Volker Strassen seinen Algorithmus entwickelt haben könnte (nach [CSRL01]). Wie Strassen seinen Ansatz tatsächlich entdeckte und wie er sein Verfahren hergeleitet hat ist jedoch ungeklärt. Jedes Matrixprodukt Pi lässt sich in folgender Form schreiben: P i = Ai B i = (αi1 a + αi2 A1,2 + αi3 A2,1 + αi4 A2,2 ) · (βi1 B2,1 + βi2 B1,2 + βi3 B2,1 + βi4 B2,2 ) (8) Die Koeffizienten αi,j und βi,j sind ausschließlich Elemente aus der Menge {-1, 0, 1}. Wir nehmen an, dass jedes Produkt durch Addition oder Subtraktion einer der Teilmatrizen von A bzw. B und anschließender Multiplikation beider Teilergebnisse berechnet wird. Wenn wir alle Produkte auf diese Art formulieren, können wir diese Methode rekursiv, ohne die Voraussetzung der Kommutativität, bei der Multiplikation verwenden. Das wird dadurch ermöglicht, dass jedes Produkt Pi alle seine Teilmatrizen aus A links und seine Teilmatrizen aus B rechts hat. Diese Eigenschaft ist für die rekursive Anwendung notwendig, denn Matrizenmultiplikation ist nicht kommutativ. Um eine bessere Übersicht über die folgenden Gleichungen zu erhalten, werden diese in Form von 4 × 4 Matrizen dargestellt. Hierbei entspricht jedes Produkt der Multiplikation einer Teilmatrix aus A mit einer Teilmatrix aus B. C1,1 = A1,1 B1,1 + A1,2 B2,1 (9) B1,1 +1 0 0 0 0 +1 0 B1,2 · 0 0 0 B2,1 0 0 0 0 B2,2 0 = (A1,1 A1,2 A2,1 A2,2 ) · 0 B1,1 A1,1 + A1,2 · A2,1 · A2,2 · = B1,2 · · · · B2,1 · + · · B2,2 · · · · (10) (11) Der letzte Matrix stellt lediglich eine vereinfachte Notation dar, welche jede 1 durch "+", jede 0 durch "·" und jede -1 durch "−" ersetzt. 6 Die folgenden Matrizen stellen die verbleibenden drei Teilmatrizen der Matrix C dar: C1,2 = A1,1 B1,2 + A1,2 B2,2 · + · · · · · · = · · · + · · · · C2,1 = A2,1 B1,1 + A2,2 B2,1 · · · · · · + · · · · · C2,2 = A2,1 B1,2 + A2,2 B2,2 · · · · (14) (15) (16) · · · · · + · · · · + · = (13) · · + · = (12) (17) Im Folgenden werden die Matrizen P1 bis P7 betrachtet. Die Teilmatrix C1,2 kann als C1,2 = P1 +P2 berechnet werden. Dabei werden P1 und P2 jeweils mit einer eigenen Matrixmultiplikation berechnet: P1 = A1 B1 = A1,1 · (B1,2 − B2,2 ) = A1,1 B1,2 − A1,1 B2,2 · + · − · · · · = · · · · · · · · (18) P 2 = A2 B 2 = (A1,1 + A1,2 ) · B2,2 = A1,1 B1,2 + A1,1 B2,2 · · = · · · · · · · + · + · · · · 7 (19) Die Matrix C2,1 kann in gleicher Weise als C2,1 = P3 +P4 dargestellt werden: P 3 = A3 B 3 = (A2,1 + A2,2 ) · B2,2 = A1,1 B2,2 + A2,2 B2,2 · · = + + · · · · · · · · · · · · (20) P 4 = A4 B 4 = A2,2 · (B2,1 − B1,1 ) = A2,2 B2,1 − A2,2 B1,1 · · = · − · · · · · · · + · · · · (21) Bisher wurden vier Produkte benötigt, um zwei der vier Teilmatrizen von C zu berechnen. Dabei wurde der Term A1,1 B1,2 durch P1 , A1,2 B2,2 durch P2 , A2,1 B1,1 durch P3 und A2,2 B2,1 durch P4 ersetzt. Für die verbleibenden Teilmatrizen müssen noch die Terme A1,1 B1,1 , A1,2 B2,1 , A2,1 B1,2 und A2,2 B2,2 berechnet werden. Dabei ist es das Ziel, im Vergleich zu vorher eine Multiplikation einzusparen Dazu werden in einer Matrix zwei Terme auf einmal berechnet: P5 = A5 B5 = (A1,1 + A2,2 ) · (B1,1 + B2,2 ) = A1,1 B1,1 + A1,1 B2,2 + A2,2 B1,1 + A2,2 B2,2 + · = · + · · · · · + · · · · · + (22) Zusätzlich zu den Termen A1,1 B1,1 und A2,2 B2,2 müssen noch die beiden Produkte A1,1 B2,2 und A2,2 B1,1 berechnet werden, um störende Terme aus der Gleichung zu eliminieren. P5 + P4 − P2 = A1,1 B1,1 + A2,2 B2,2 + A2,2 B2,1 − A1,2 B2,2 8 · · · · · − · · · · + + + · = · · (23) (24) P 6 = A6 B 6 = (A1,2 − A2,2 ) · (B2,1 + B2,2 ) = A1,2 B2,1 + A1,2 B2, 2 − A2,2 B2,1 − A2,2 B2,2 · · = · · · · · · + + · · · · − − (25) (26) C1,1 = P5 + P4 − P2 + P6 = A1,1 B1,1 + A1,2 B2,1 + · = · · · · · · + · · · · · · · (27) (28) P5 + P1 − P3 = A1,1 B1,1 + A1,1 B1,2 − A2,1 B1,1 + A2,2 B2,2 + + · · · · · · = − · · · · · · + (29) (30) P 7 = A7 B 7 = (A1,1 − A2,1 ) · (B1,1 + B1,2 ) = A1,1 B1,1, + A1,1 B1,2 − A2,1 B1,1 − A2,1 B1,2 + + · · · · · · = − − · · · · · · (31) (32) C2,2 = P5 + P1 − P3 − P7 = A2,1 B1,2 + A2,2 B2,2 9 · · · · · · · · = · + · · · · · + 3.3 (33) Korrektheit Beweis. Die Korrektheit von Strassens Gleichungen lässt sich anschaulich im Vergleich zur rekursiven Methode aus 2.2 zeigen. Zunächst lassen sich die Gleichungen (4)-(7) anschaulicher darstellen: C1,1 + · · · · + · · = · · · · · · · · C1,2 · · · · = + · · + C2,1 · · = · · C2,2 · · = · · · · · · (34) · · · · (35) · + · · · + · · · · · · (36) · · · · · · · + · · · + (37) Dabei sei das Format nun abweichend von 3.2 wie folgt definiert: A1,1 B1,1 · B2,1 · B1,2 · B2,2 · A1,2 · · · · A2,1 · · · · A2,2 · · · · Es steht immer dann ein +, wenn das Produkt aus den Komponenten in die Summe Ci,j einfließt. Auch Strassens sieben Multiplikationsformeln P1 bis P7 lassen sich in der 10 gleichen Weise aufbereiten: P1 P2 · · = · · · · = + − P4 P5 P6 P7 · · = · · · + · · · · · + · + + · · · · · · · · · P3 · · · · + · = · + · · · · · · · · · · · · · · · · · − · + · · · · · · · · · + · · · · · + · · · · · · · · = · · + + − · = − · · · · · · · · · · + · − = · · · · · + · − Bei Strassen wird die Matrix C wie folgt berechnet: C1,1 = P5 + P4 − P2 + P6 (38) C1,2 = P1 + P2 (39) C2,1 = P3 + P4 (40) C1,1 = P5 + P1 − P3 − P7 (41) 11 Oder anschaulich: C1,1 = P1 + P4 − P5 − P7 = P1 + P4 + (−P5 ) + (−P7 ) · · · · · − + · · + · · · · · · · + · · = + + · · · · · · · · · · − − · · · · + · · + · · · · + · · · · + · · = · · · · · · · · C1,2 = P3 + P5 · · = + − · · · · · · · · = + · · + · · · · · · + · · · + + · · · · · · · · · · · · · · · · · · · · · C2,1 = P2 + P4 · + + · · · · · + · · · · · · · · · + · · · + · · · · · · · · = · · · · = · · 12 · · · · · · · · · · · + · − + · · · · · · + · − · · − · + · · · · C2,2 = P1 − P2 + P3 + P6 = P1 + (−P2 ) + P3 + P6 · · · − − + · · + · · · · · · · · · = + + · · · · · · · · + − · · · · + · · + · · = · · · · · · · · · · − · · · + · − · · · + · · · · · + · · · · · · · · · · · + · · · + Ein „−“ steht dabei für eine subtrahierte Teilmatrix, ein „+“ wiederum für eine addierte. Nun zeigt sich, dass die Formeln kombiniert wieder exakt die Zwischenergebnisse berechnen, die auch mit der rekursiven Methode entstehen (vgl. (34) - (37)). Diese Teile lassen sich anschließend wieder kombinieren und ergeben die selbe Ergebnismatrix C. 3.4 Laufzeitverhalten Sei TM (n) bzw. TA (n) die Anzahl der Multiplikationen bzw. Additionen in Algorithmus 3 (Kap. 3.1). Dabei gilt: ( TM (n) = ( TA (n) = 1, 7 · TM ( n2 ), n = 1, n>1 0, 18( n2 )( n2 ) + 7 · TA ( n2 ), n = 1, n>1 (42) (43) Die Multiplikationen aus (42) entstehen aus den 7 rekursiven Aufrufen der Methode mit Submatrizen der Größe n2 . Da die Dimension n der Matrix jeweils halbiert wird ruft man die Funktion rekursiv je log n-mal auf bis man bei der Dimension 1 (Rekursionasabbruch) angelangt. Insgesamt ergibt sich also: TM (n) = 7log n = nlog 7 ≤ n2.8074 (44) Die Additionen aus (43) resultieren aus den 18 Additionen/Subtraktionen pro rekursivem Aufruf (zur Berechnung von P 1-P 7 und der Matrix C). Zusätzlich werden 7 neue rekursive Berechnungen gestartet, die jeweils weitere Multiplikationen erfordern. Die Laufzeit dieser Komponente wird mit dem Master-Theorem bestimmt. 13 Einschub: Laufzeitbestimmung von TA (n) mit Hilfe des MasterTheorems Das Master-Theorem dient dazu, die Laufzeit rekursiver Algorithmen einzuschätzen [Mul]. Mit seiner Hilfe kann der Aufwand der Additionen aus dem Strassen-Algorithmus abgeschätzt werden (→ (43)). Um das Master-Theorem anwenden zu können muss eine rekursive Gleichung der folgenden Form vorliegen: n T (n) = a · T ( ) + f (n) (45) b Zusätzlich muss gelten: a≥1 (46) b>1 (47) + (48) f :N→R Diese Voraussetzungen sind in (43) erfüllt: n n a · T ( ) = 7 · TA ( ) b 2 n n f (n) = 18 · ( ) · ( ) = 4.5 · n2 > 0 n ∈ N 2 2 a = 7≥1 b = 2>1 (49) (50) (51) (52) Das Master-Theorem definiert drei Fälle für Gleichungen dieser Art. Für die Laufzeitbestimmung von (43) ist davon nur der Erste relevant: Fall 1 des Master-Theorems: f (n) = O(nlogb (a)−ε ) ε > 0 =⇒ T (n) = Θ(nlogb a ) (53) Werden die Werte (49) - (52) in (53) eingesetzt, ergibt sich: 4.5 · n2 = O(nlog2 (7)−ε ) = O(n 2.8074−ε ) (54) (55) Damit die Gleichung erfüllt ist, wähle ein geeignetes ε; z.B. ε = 0.5. Dann folgt nach (53) für die Laufzeit von TA (n): TA (n) = Θ(nlog2 7 ) (56) 2.8074 (57) = O(n 14 ) Insgesamt ergibt sich aus den Folgerungen (44) und (57) für den Algorithmus von Strassen (3) die Komplexität O(n2.8074 ). Das stellt entgegen dem ersten Eindruck eine deutliche Verbesserung im Vergleich zu den Verfahren aus Kapitel 2 dar. Zum Vergleich: Bei Matrizen der Größe 64 × 64 benötigt man mit der klassischen Methode 262.144 einzelne Schritte, mit Strassen hingegen nur 118.950. Bei noch größeren Matrizen (256 × 256) wird der Unterschied mit 16.777.216 Schritten der klassischen Methode gegenüber 5.849.979 Schritten mit Strassen noch größer [Bar13]. 3.5 Einschränkungen Für die praktische Verwendung des Algorithmus gibt es einige Problematiken, die beim Einsatz bedacht werden sollten [CSRL01]: 1. Der konstante Faktor, der in der O Notation versteckt wird, ist beim Algorithmus von Strassen größer als bei den Methoden aus Kap. 2, der Einsatz lohnt sich erst bei Größen ab n ≈ 100 [Ski08] 2. Für dünnbesetze Matrizen existieren schnellere Algorithmen 3. Strassens Algorithmus ist durch das Mehr an Berechnungen numerisch instabiler (Rundungsfehler) als die Methoden aus Kap. 2 4. Die Teilmatrizen, die auf jeder Rekusionsebene berechnet werden müssen, benötigen im Vergleich zur iterativen Schulmethode (Kap. 2.1) zusätzlichen Speicherplatz 15 4 Weitere Algorithmen Neben dem Algorithmus von Strassen gibt es noch weitere, sogar schnellere (vgl. Abb 1), Algorithmen um das Problem der Matrizenmultiplikation zu lösen. Jedoch war Strassen, wie in der Einleitung dargestellt, der Erste, der den klassischen Algorithmus verbessert hat und entwickelte einen der auch bis heute bekanntesten Algorithmen. In den 1970er und 1980er Jahren beschäftigten sich nach Strassens Entdeckung viele Mathematiker mit der Entwicklung eines noch besseren Algorithmus, weshalb in kurzer Folge immer schnellere und komplexere Verfahren vorgestellt wurden. Dargestellt sind diese kontinuierlichen Verbesserungen in Abbildung 1, wobei auf der y-Achse der Exponent von n aufgetragen ist. Abbildung 1: Entwicklung des Aufwands der Matrizenmultiplikation Entnommen aus: http://en.wikipedia.org/wiki/File:Bound_on_matrix_ multiplication_omega_over_time.svg aufgerufen am 16.5.15 16 Der vorläufige Höhepunkt dieses Wettrennens war ein Algorithmus von Coppersmith und Winograd aus dem Jahre 1987, der ebenfalls große Bekanntheit und Anerkennung erreicht hat. Er besitzt eine Komplexität von O(n2.376 ), was auf den ersten Blick wie eine dramatische Verbesserung gegenüber Strassen (O(n2.8074 )) aussieht [Bar13]. Allerdings wird hier in der O-Notation ein extrem großer konstanter Faktor versteckt, was den Algorithmus für die praktische Verwendung beinahe irrelevant macht. Die zu multiplizierenden Matrizen müssten eine enorme Dimension n besitzen um einen spürbaren Vorteil zu erzielen. Wie gering sich dieser zunächst groß erscheinende Unterschied der Komplexität in der Praxis auswirkt soll durch folgendes Laufzeitdiagramm demonstriert werden. Dazu wurden die beiden Algorithmen auf einer nVidia Tesla C1060 Grafikkarte ausgeführt und ihre Laufzeit vergleichen. Auf der y-Achse ist die Zeit aufgetragen, auf der x-Achse die Dimension der verwendeten Matrizen n. Abbildung 2: Laufzeiten einiger Algorithmen Entnommen aus: [LRS11] S.19 Dabei sieht man, dass es nur minimalste zeitliche Unterschiede zwischen den Methoden von Strassen und Winograd gibt, selbst bei großen Matrizen mit n = 16384 (≈ 0, 14 Sekunden bzw. 0, 82%). [LRS11] Die anderen Algorithmen wie tWinograd, tStrassen, sgemm oder GPU8 sollen in dieser Arbeit nicht weiter betrachtet werden, dabei handelt es sich um weitere Algorith17 men oder genauer auf die Gegebenheiten der Hardware angepasste Varianten der Vorgestellten. Es wird vermutet, dass sich die Matrizenmultiplikation in quadratischer Zeit lösen lässt, dies konnte jedoch bisher nicht bewiesen werden. Theorien haben sowohl Coppersmith und Winograd als auch Cohn et al. aufgestellt, teilweise würden diese jedoch anderen (ebenfalls unbestätigte) Theorien widersprechen. Aber auch wenn sich diese als falsch herausstellen würden verbleibt eine Theorie von Cohn et al., die zu einem Beweis führen könnte, dass Matrizenmulitplikation in O(n2 ) liegt. [Wil14] Genauer wird eine optimale Laufzeit von O(n2 log n) vermutet. [DA09] Bekannt ist, dass die Größenordnung O(n2 ) in jedem Fall eine untere Schranke sein wird, da schon das Einlesen der beiden beteiligten Matrizen mit n×n Elementen quadratische Zeit benötigt [DA09]. 18 5 Multiplikation nach Karatsuba und Ofman Einen zur Methode von Strassen ähnlichen Ansatz zur Verbesserung eines aus der Schule bekannten Verfahrens durch Rekursion und geschickte Kombination von vorberechneten Teilergebnissen gibt es auch für die Multiplikation von langen Zahlen. Die bekannte Methode zur schriftlichen Multiplikation von zwei n-stelligen Zahlen aus der Schule besitzt in diesem Fall die Komplexität O(n2 ) [EM08]. Der Mathematiker Anatolij Karazuba (engl.: Karatsuba) entdeckte 1962 ein Verfahren, das den Aufwand für sehr lange Zahlen reduzieren kann. 5.1 Allgemein Zunächst soll kurz vorgestellt werden, wie diese Optimierung erreicht wird. Im ersten Schritt teilt man zwei zu multiplizierende Zahlen x und y in je zwei Teile, sodass gilt [Sch11]: m x = x0 = x1 b 2 + x0 m y = y 0 = y1 b 2 + y0 Die Konstante m ist dabei frei wählbar, muss jedoch eine Zweiterpotenz sein. Wie später ersichtlich wird ist es geschickt, diese Potenz möglichst nahe der Länge der beiden Faktoren zu wählen, dies ist jedoch für die Korrektheit nicht erforderlich. b bezeichnet die Basis des verwendeten Zahlensystems. Durch die Multiplikation der zerlegten Zahlen x0 und y 0 erhält man: m x0 · y 0 = x1 y1 · bm + (x0 y1 + x1 y0 ) · b 2 + x0 y0 (58) Dann lässt sich die Multiplikation zweiter n-stelliger Zahlen mit diesem Trick durch die Multiplikation von vier Zahlen der Länge m 2 ausdrücken. Da aber gleichzeitig gilt m 4 2 = 2n bringt diese Umformung zunächst keinen Vorteil, der Aufwand bleibt in O(n2 ) [EM08]. Zu beachten ist, dass die Multiplikationen mit der Basis bi für die Effizienz keine entscheidende Rolle spielen, da sie im Zahlensystem einfach durch Shifts um i Abbildung 3: Shifts bei der Stellen effizient berechenbar sind (vgl. Abb. abschließenden Summe Entnommen aus [Sch11] S.268 3). Karazuba entdeckte folgende Umformung, die eine Verbesserung ermöglicht: x0 y1 + x1 y0 = x1 y1 + x0 y0 − (x0 − x1 )(y0 − y1 ) 19 Beweis. x1 y1 + x0 y0 − (x0 − x1 )(y0 − y1 ) = x1 y1 + x0 y0 − (x0 y0 − x0 y1 − x1 y0 + x1 y1 ) = x0 y1 + x1 y0 Auf den ersten Blick erhöht sich die Anzahl der Multiplikationen sogar von zwei auf drei, betrachtet man nun aber wieder den gesamten Term (58) wird klar, dass zwei dieser Multiplikationen (x1 y1 und x0 y0 ) auch in je einem anderen Summand vorkommen und ihre Ergebnisse somit bekannt sind. Tatsächlich wurde eine Multiplikation eingespart und es genügen drei Multiplikationen von Zahlen der Länge n2 . Durch die Modifikation sinkt der Aufwand zwar nicht ganz linear, verbessert sich aber deutlich auf O(nlog2 3 ) mit log2 3 ≈ 1.58. m x0 · y 0 = x1 y1 · bm + (x1 y1 + x0 y0 − (x0 − x1 )(y0 − y1 )) · b 2 + x0 y0 (59) Multiplikation nach Karatsuba und Ofman Die drei Multiplikationen, die für die Zwischenergebnisse nötig sind, lassen sich nun rekursiv nach dem gleichen Prinzip berechnen bis man beim Trivialfall, der Multiplikation von zwei einzelnen Ziffern, angelangt. Es handelt sich also um einen divide and conquer Ansatz. Nun ist auch klar, wieso m möglichst nahe der Länge der Zahlen gewählt werden sollte: So gewährleistet man eine möglichst effiziente Aufteilung der Zahlen in jeweils halb so lange Teile. Natürlich sollte m in jeder Rekusionsebene geeignet angepasst werden. Die Korrektheit dieses Verfahrens ergibt sich direkt aus den einzelnen Äquivalenzumformungen. 5.2 Effizienzbetrachtung Wie groß die Steigerung von Schulmethode zu Karatsuba ist, soll Abb. 4 verdeutlichen. Eingetragen ist dabei die Anzahl der nötigen Ziffernmultiplikationen bei der Multiplikation zweier Zahlen der Länge n. 20 Abbildung 4: Anzahl Ziffernmultiplikationen im Vergleich Entnommen aus: [EM08], S.116 Die Schulmethode benötigt bereits bei n = 16 über 3-Mal so viele Multiplikationen wie der Karatsuba/Ofman Algorithmus! Allerdings muss bedacht werden, dass Computer Multiplikationen zweier Zahlen ihrer Wortbreite effizient, d.h. in einer Instruktion, berechnen können [Kor15]. Daher spielt eine Methode zur Verbesserung in diesem Fall erst eine Rolle, wenn die Zahl länger als die Wortbreite der CPU (i.d.R. 32 oder 64 Bit) ist. Ein 32 Bit Integer kann beispielsweise 10 Stellen im Dezimalsystem darstellen, wovon 9 im Wertebereich uneingeschränkt sind. Die Rekursion wird abgebrochen (bzw. erst gar nicht begonnen), sobald diese Länge unterschritten wird und das Ergebnis effizient berechenbar ist. Interessant ist, dass Volker Strassen, der Entdecker des schnellen Algorithmus zur Matrixmultiplikation aus Kapitel 3, zusammen mit Arnold Schönhage später den lange Zeit (1971-2007) schnellsten Algorithmus zur Multiplikation entworfen hat, er besitzt die Komplexität O(n·log(n)·log(log(n)))[Kor15]. 5.3 Beispielhafte Anwendung Im folgenden soll das beschriebene Verfahren praktisch angewendet werden. Wähle m = 8 und sei b = 10. 123456 · 1234567 0 x = 12 · 104 + 3456 y 0 = 123 · 104 + 4567 21 Berechne die drei Multiplikationen: r = x1 y1 = 12 · 123 = 1476 t = x0 y0 = 3456 · 4567 = 15783552 s = r + t − (x0 − x1 )(y0 − y1 ) = 1476 + 15783552 − 15305136 = 479892 Berechne das Endergebnis: n x0 · y 0 = r · bn + s · b 2 + t = 1476 · 108 + 479892 · 104 + 15783552 x0 · y 0 = 152414703552 Alternative Lösung mit Shift: x0 · y 0 = 1476 + + = 479892 15783552 152414703552 Test: x · y = 152414703552 Aus Gründen der Übersichtlichkeit wurde hier nur auf die erste Rekursionsebene eingegangen; r, s und t lassen sich wie beschrieben rekursiv nach dem gleichen Verfahren berechnen. 22 Literatur [Bar13] Barth, Armin P.: Matrixmultiplikation: Jagd nach immer kleineren Exponenten. 2. Auflage. Springer-Verlag Berlin Heidelberg, 2013. – 107–108 S. – ISBN 978–3–658–02281–5 [CSRL01] Cormen, Thomas H. ; Stein, Clifford ; Rivest, Ronald L. ; Leiserson, Charles E.: Introduction to Algorithms. 2nd. McGrawHill Higher Education, 2001. – ISBN 0070131511 [CSRL10] Cormen, Thomas H. ; Stein, Clifford ; Rivest, Ronald L. ; Leiserson, Charles E.: Algorithmen - Eine Einführung. Oldenburg München, 2010. – ISBN 978–3–486–59002–9 [DA09] Dietzfelbinger, Martin ; Aumüller, Martin: Divideand-Conquer-Algorithmen. https://www.tu-ilmenau. de/fileadmin/public/ktea/Alte_Lehre/ea/SS09/ divide-and-conquer.pdf, 2009. – [Online; zugegriffen am 9.6.2015] [EM08] Eigenwillig, Arno ; Mehlhorn, Kurt: Multiplikation langer Zahlen (schneller als in der Schule). In: Taschenbuch der Algorithmen. Springer-Verlag Berlin Heidelberg, 2008. – ISBN 978– 3–540–76393–2, S. 109–118 [Kor15] Kortekaas, Theo: Multiplying large numbers and the Schönhage-Strassen Algorithm. http://tonjanee.home. xs4all.nl/SSAdescription.pdf, 2015. – [Online; zugegriffen am 17.5.2015] [LRS11] Li, Junjie ; Ranka, Sanjay ; Sahni, Sartaj: Strassen’s Matrix Multiplication on GPUs. (2011). https://www.cise.ufl. edu/~sahni/papers/strassen.pdf. – [Online; zugegriffen am 16.5.2015] [Mul] Mulzer, Wolfgang: Das Master Theorem. http://page.mi. fu-berlin.de/mulzer/notes/ha/master.pdf, . – [Online; zugegriffen am 23.6.2015] [Sch11] Schöning, Uwe: Algorithmik. Spektrum Akademischer Verlag, 2011. – ISBN 9783827427991 [Ski08] Skiena, Steven S.: The Algorithm Design Manual. 2nd. Springer Publishing Company, Incorporated, 2008. – ISBN 9781848000698 [Str68] Strassen, Volker: Gaussian Elimination is not optimal. http://scgroup.hpclab.ceid.upatras.gr/class/SC/ 23 Papers/Strassen.pdf, 1968. – 18.5.2015] [Online; zugegriffen am [Val75] Valiant, Leslie G.: General context-free recognition in less than cubic time. In: Journal of Computer and System Sciences 10 (1975), Nr. 2, 308–315. http://repository.cmu.edu/cgi/ viewcontent.cgi?article=2751&context=compsci. – [Online; zugegriffen am 20.5.2015] [Wil14] Williams, Virginia V.: Multiplying matrices in O(n2.373 ) time. (2014). http://theory.stanford.edu/~virgi/matrixmult-f. pdf. – [Online; zugegriffen am 20.5.2015] [Wul08] Wulfert, Daniel: Schnelle Matrixmultiplikation. Version: 2008. http://ls11-www.cs.uni-dortmund.de/people/rahmann/ teaching/ss2008/EleganteAlgorithmen/skript.pdf. In: Elegante Algorithmen. 2008, 107–116. – [Online; zugegriffen am 20.5.2015] 24 Abbildungsverzeichnis 1 Entwicklung des Aufwands der Matrizenmultiplikation Entnommen aus: http://en.wikipedia.org/wiki/File:Bound_ on_matrix_multiplication_omega_over_time.svg aufgerufen am 16.5.15 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 3 4 Laufzeiten einiger Algorithmen Entnommen aus: [LRS11] S.19 . . . . . . . . . . . . . . . . . . . Shifts bei der abschließenden Summe Entnommen aus [Sch11] S.268 . . . . . . . . . . . . . . . . . . . Anzahl Ziffernmultiplikationen im Vergleich Entnommen aus: [EM08], S.116 . . . . . . . . . . . . . . . . . . 25 16 17 19 21