Algoritmul Strassen

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită pe 22 noiembrie 2021; verificările necesită 20 de modificări .

Algoritmul lui Strassen este conceput pentru multiplicarea rapidă a matricei . A fost dezvoltat de Volker Strassen în 1969 și este o generalizare a metodei Karatsuba de înmulțire a matricei.

Spre deosebire de algoritmul tradițional de înmulțire a matricei (conform formulei ) care rulează în timp , algoritmul Strassen înmulțește matricele în timp , ceea ce oferă un câștig pe matrici mari dense.

În ciuda faptului că algoritmul lui Strassen nu este asimptotic cel mai rapid dintre algoritmii de multiplicare rapidă a matricei existenți, este mai ușor de programat și mai eficient atunci când se înmulțesc matrici relativ mici, deci este cel mai des folosit în practică.

Descrierea algoritmului

Dacă adăugăm aceleași rânduri și coloane zero la matrice , produsul lor devine egal cu matricea cu aceleași rânduri și coloane adăugate. Prin urmare, numai matricele de dimensiune pot fi luate în considerare , iar alte cazuri pot fi reduse la aceasta prin adăugarea de zerouri, care se pot dubla doar.

Fie matrice de dimensiune . Ele pot fi reprezentate ca matrici bloc de dimensiune din -matrice:

Prin principiul înmulțirii blocurilor , o matrice este exprimată în funcție de produsul lor

unde în partea dreaptă sunt opt ​​înmulțiri de matrici de mărime . Deoarece matricele formează un inel , atunci orice algoritm de înmulțire a matricelor care utilizează numai adunări, scăderi și înmulțiri este potrivit pentru calcularea părții drepte. Strassen a propus următorul algoritm cu șapte înmulțiri:

Fiecare înmulțire se poate face recursiv folosind aceeași procedură, iar adunarea se poate face trivial prin adăugarea de elemente. Apoi timpul de rulare al algoritmului este estimat prin relația recursivă :

Exemplu de implementare

Mai jos este un exemplu de implementare a algoritmului în Python folosind biblioteca NumPy pentru a prelua rapid submatrice. Funcția principală este strassen_mul. Se presupune că toate matricele sunt pătrate, reprezentate prin tip numpy.array, iar dimensiunea lor este o putere de 2.

Pentru matrice de dimensiuni mici, multiplicarea directă este mai rapidă decât algoritmul Strassen datorită numărului mare de adunări din acesta din urmă. Limita acestor dimensiuni depinde de raportul dintre timpul de adăugare și multiplicare a elementelor și, prin urmare, poate varia în funcție de mediul hardware. În cod, constanta este responsabilă pentru scopul său TRIVIAL_MULTIPLICATION_BOUND.

din itertools import product import numpy ca np def split_to_2x2_blocks ( matrice ): listă returnată ( hartă ( rând lambda : np . hsplit ( rând , 2 ), np . vsplit ( matrice , 2 ) )) def strassen_mul_2x2 ( lb , rb ): d = strassen_mul ( lb [ 0 ][ 0 ] + lb [ 1 ][ 1 ], rb [ 0 ][ 0 ] + rb [ 1 ][ 1 ]) d_1 = strassen_mul ( lb [ 0 ][ 1 ] - lb [ 1 ][ 1 ], rb [ 1 ][ 0 ] + rb [ 1 ][ 1 ]) d_2 = strassen_mul ( lb [ 1 ][ 0 ] - lb [ 0 ][ 0 ], rb [ 0 ][ 0 ] + rb [ 0 ][ 1 ]) stânga = strassen_mul ( lb [ 1 ][ 1 ], rb [ 1 ][ 0 ] - rb [ 0 ][ 0 ]) dreapta = strassen_mul ( lb [ 0 ][ 0 ], rb [ 0 ][ 1 ] - rb [ 1 ][ 1 ]) sus = strassen_mul ( lb [ 0 ][ 0 ] + lb [ 0 ][ 1 ], rb [ 1 ][ 1 ]) jos = strassen_mul ( lb [ 1 ][ 0 ] + lb [ 1 ] [ 1 ], rb [ 0 ][ 0 ]) return [[ d + d_1 + stânga - sus , dreapta + sus ], [ stânga + jos , d + d_2 + dreapta - jos ]] def trivial_mul ( stânga , dreapta ): înălțime , mărime_medie = stânga . formă mid_size , dreapta = dreapta . forme rezultat = np . zerouri (( înălțime , lățime )) pentru rând , col , mijloc în produs ( * hartă ( interval , [ înălțime , lățime , mărime_ mijlocie ])): rezultat [ rând ][ col ] += stânga [ rând ][ mijloc ] * dreapta [ mijloc ][ col ] returnează rezultatul TRIVIAL_MULTIPLICATION_BOUND = 8 def strassen_mul ( stânga , dreapta ): assert ( stânga . formă == dreapta . formă ) assert ( stânga . formă [ 0 ] == stânga . formă [ 1 ]) daca a ramas . forma [ 0 ] <= TRIVIAL_MULTIPLICATION_BOUND : returnează trivial_mul ( stânga , dreapta ) assert ( stânga . form [ 0 ] % 2 == 0 ) return np . bloc ( strassen_mul_2x2 ( * hartă ( split_to_2x2_blocks , [ stânga , dreapta ]))) )

Dezvoltare ulterioară

Strassen a fost primul care a arătat posibilitatea înmulțirii matricelor într-un mod mai eficient decât cel standard. După publicarea lucrării sale în 1969, a început o căutare activă a unui algoritm mai rapid. Cel mai rapid algoritm asimptotic de astăzi este algoritmul Coppersmith-Winograd , care vă permite să multiplicați matrice în operații [1] , propus în 1987 și îmbunătățit în 2011 la nivelul [1] . Acest algoritm nu prezintă interes practic datorită constantei mari din punct de vedere astronomic în estimarea complexității aritmetice. Problema ratei de limitare asimptotic a înmulțirii matricei nu a fost rezolvată. Există conjectura lui Strassen că pentru suficient de mare există un algoritm pentru înmulțirea a două matrici de dimensiune în operații, în care un număr pozitiv prealocat este arbitrar mic. Această presupunere este de interes pur teoretic, deoarece dimensiunea matricelor, pentru care este cu adevărat mică, este aparent foarte mare.

Problema construirii celui mai rapid și mai stabil algoritm practic pentru multiplicarea matricelor mari rămâne, de asemenea, nerezolvată.

Algoritmul Winograd-Strassen

Există o modificare a algoritmului Strassen care necesită 7 înmulțiri și 15 adunări (în loc de 18 pentru algoritmul Strassen obișnuit).

Matricele sunt împărțite în submatrici bloc așa cum se arată mai sus.

Se calculează elementele intermediare

Elementele matricei se calculează după cum urmează:

Starea actuală a problemei

Algoritmul lui Strassen este un algoritm biliniar, coeficienții săi sunt rădăcinile sistemului cubic al ecuațiilor lui Brent . [2] Pentru clasa algoritmilor exacti <2x2x2> aceasta este o problemă minimă, a cărei soluție permite reducerea numărului de înmulțiri în inelul elementelor matriceale. [3] [4] Problema găsirii de noi algoritmi este că sistemul Brent este neliniar, numărul de necunoscute și ecuații (aceste numere nu coincid) crește rapid odată cu dimensiunea matricelor și numai soluțiile cu o valoare mare. este necesar un număr de zerouri.

În 2013, după depășirea parțială a acestor probleme, a fost posibil să se găsească primul algoritm biliniar practic pentru multiplicarea matricei, care este asimptotic mai rapid decât algoritmul Strassen. [5] Algoritmul lui Smirnov <3x3x6; 40> înmulțește o matrice 3X3 cu o matrice 3x6 folosind 40 de înmulțiri în loc de 54. Complexitatea sa asimptotică este . (Înmulțirea tensorii a algoritmului în sine cu o deplasare ciclică a argumentelor conduce la un algoritm pentru matrice pătrată <54x54x54; 64000> cu aceeași complexitate). Pentru o accelerare reală a înmulțirii, este necesară o optimizare semnificativă - eliminarea multor calcule duplicate în forme liniare.

Astăzi (2022) acesta este asimptotic cel mai rapid algoritm biliniar practic pentru un câmp arbitrar de elemente de matrice.

Pe 5 octombrie 2022, DeepMind, folosind algoritmul rețelei neuronale AlphaZero, a găsit câțiva algoritmi noi pentru multiplicarea matricelor de diferite dimensiuni. Cu toate acestea, viteza lor pentru un câmp arbitrar este departe de viteza celor mai buni algoritmi cunoscuți. Deci, pentru matrice 4X4, algoritmul Strassen necesită 49 ​​de înmulțiri, iar AlphaTensor a găsit un algoritm care necesită 47 de înmulțiri, dar funcționează doar pentru câmpul . [6] [7]

Note

  1. 1 2 Matematicienii au depășit bariera Coppersmith-Winograd . lenta.ru (12 decembrie 2011). Data accesului: 12 decembrie 2011. Arhivat din original pe 5 februarie 2012.
  2. RPBrent. Algoritmi pentru înmulțirea matricelor// Departamentul Informatică. Raport CS 157, Universitatea Stanford, 1970.
  3. Complexitatea înmulțirii matriceale. Recenzie//Cibernetică. Colectie. 1988. Problema. 25. S. 139-236.
  4. Landsberg JM Geometria și complexitatea înmulțirii matricelor // Bull. amer. Matematică. soc. 2008. V.45. p. 247-284.
  5. A. V. Smirnov, „Despre complexitatea biliniară și algoritmii practici pentru multiplicarea matricei”, Zh. Vychisl. matematica. și mat. Fiz., 53:12 (2013), 1970–1984; Calculator. Matematică. Matematică. Phys., 53:12 (2013), 1781–1795
  6. ↑ Descoperirea unor algoritmi noi cu AlphaTensor  . www.deepmind.com . Preluat: 6 octombrie 2022.
  7. Alhussein Fawzi, Matej Balog, Aja Huang, Thomas Hubert, Bernardino Romera-Paredes. Descoperirea unor algoritmi de multiplicare matrice mai rapidă cu învățare prin întărire   // Nature . — 2022-10. — Vol. 610 , iss. 7930 . — P. 47–53 . — ISSN 1476-4687 . - doi : 10.1038/s41586-022-05172-4 .

Literatură