Strassenin algoritmi on suunniteltu nopeaan matriisin kertomiseen . Sen kehitti Volker Strassen vuonna 1969, ja se on yleistys Karatsuban matriisin kertolaskumenetelmästä.
Toisin kuin perinteinen ajassa ajava matriisin kertolaskualgoritmi (kaavan mukaan ) , Strassen-algoritmi kertoo matriiseja ajassa , mikä antaa vahvistuksen suurille tiheille matriiseille.
Huolimatta siitä, että Strassenin algoritmi ei ole asymptoottisesti nopein olemassa olevista nopeista matriisin kertolaskualgoritmeista, se on helpompi ohjelmoida ja tehokkaampi kertoessaan suhteellisen pieniä matriiseja, joten se on käytännössä eniten käytetty.
Jos lisäämme samat nollarivit ja sarakkeet matriiseihin , niiden tulo tulee yhtä suureksi kuin matriisi , jossa on samat lisätyt rivit ja sarakkeet. Siksi vain matriiseja, joiden koko on , voidaan ottaa huomioon , ja muut tapaukset voidaan pienentää tähän lisäämällä nollia, jotka voivat vain kaksinkertaistua.
Antaa olla kokoisia matriiseja . Ne voidaan esittää lohkomatriiseina , joiden koko on -matriiseista :
Lohkon kertolaskuperiaatteen mukaan matriisi ilmaistaan niiden tulona
jossa oikealla puolella on kahdeksan koon matriisien kertolaskua . Koska matriisit muodostavat renkaan , niin mikä tahansa algoritmi -matriisien kertomiseen , joka käyttää vain yhteen-, vähennys- ja kertolaskuja, sopii oikean puolen laskemiseen. Strassen ehdotti seuraavaa algoritmia seitsemällä kertolaskulla:
Jokainen kertolasku voidaan tehdä rekursiivisesti käyttämällä samaa menettelyä, ja yhteenlasku voidaan tehdä triviaalisti lisäämällä elementtejä. Sitten algoritmin ajoaika arvioidaan rekursiivisen suhteen avulla :
Alla on esimerkki Python -algoritmin toteutuksesta, joka käyttää NumPy- kirjastoa alimatriisien nopeaan ottamiseksi. Päätoiminto on strassen_mul. Kaikkien matriisien oletetaan olevan neliömäisiä, joita edustaa tyyppi numpy.array, ja niiden koko on potenssi 2.
Pienillä matriisikokoilla suora kertolasku on nopeampi kuin Strassen-algoritmi, koska jälkimmäisessä on paljon yhteenlaskuja. Tällaisten kokojen raja riippuu elementtien lisäys- ja kertomisajan suhteesta ja voi siksi vaihdella laitteistoympäristön mukaan. Koodissa vakio vastaa tarkoituksestaan TRIVIAL_MULTIPLICATION_BOUND.
itertoolsista tuonti tuotteen tuonti numpy as np _ def split_to_2x2_blocks ( matriisi ): paluuluettelo ( kartta ( lambda rivi : np . hsplit ( rivi , 2 ), np . vsplit ( matriisi , 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 ]) vasen = strassen_mul ( lb [ 1 ][ 1 ], rb [ 1 ][ 0 ] - rb [ 0 ][ 0 ]) oikea = strassen_mul ( lb [ 0 ][ 0 ], rb [ 0 ][ 1 ] - rb [ 1 ][ 1 ]) top = strassen_mul ( lb [ 0 ][ 0 ] + lb [ 0 ][ 1 ], rb [ 1 ][ 1 ]) alaosa = strassen_mul ( lb [ 1 ][ 0 ] + lb [ 1 ] [ 1 ], rb [ 0 ][ 0 ]) paluu [[ d + d_1 + vasen - ylhäällä , oikea + ylhäällä ], [ vasen + alaosa , d + d_2 + oikea - alhaalla ]] def trivial_mul ( vasen , oikea ): korkeus , mid_size = vasen . muoto mid_size , oikea = oikea . muodot tulos = np . nollat (( korkeus , leveys )) riville , sarakkeeseen , tuotteen keskipisteeseen ( * kartta ( alue , [ korkeus , leveys , keskikoko ] )): tulos [ rivi ][ sarake ] += vasen [ rivi ] [ keskikohta ] * oikea [ puoliväli ][ sarake ] palauttaa tuloksen TRIVIAL_MULTIPLICATION_BOUND = 8 def strassen_mul ( vasen , oikea ): assert ( vasen . muoto == oikea . muoto ) assert ( vasen . muoto [ 0 ] == vasen . muoto [ 1 ]) jos jätetään . muoto [ 0 ] <= TRIVIAL_MULTIPLICATION_BOUND : return trivial_mul ( vasen , oikea ) väittää ( vasen . muoto [ 0 ] % 2 == 0 ) return np . lohko ( strassen_mul_2x2 ( * kartta ( split_to_2x2_blocks , [ vasen , oikea ]))) )Strassen osoitti ensimmäisenä mahdollisuuden kertoa matriiseja tehokkaammalla tavalla kuin tavallinen. Hänen teoksensa julkaisun jälkeen vuonna 1969 aloitettiin aktiivinen nopeamman algoritmin etsiminen. Asymptoottisesti nopein algoritmi nykyään on Coppersmith-Winograd-algoritmi , jonka avulla voit kertoa matriiseja operaatioissa [1] , ehdotettu vuonna 1987 ja parannettu vuonna 2011 tasolle [1] . Tällä algoritmilla ei ole käytännön merkitystä, koska aritmeettisen monimutkaisuuden arvioinnissa on tähtitieteellisesti suuri vakio. Kysymys asymptoottisesti rajoittavasta matriisin kertolaskunopeudesta ei ole ratkaistu. On olemassa Strassenin olettamus, että riittävän suurelle on olemassa algoritmi kahden koon matriisin kertomiseksi operaatioissa , joissa ennalta määrätty positiivinen luku on mielivaltaisen pieni. Tämä olettamus on puhtaasti teoreettisesti kiinnostava, koska matriisien koko, jolle se on todella pieni, on ilmeisesti erittäin suuri.
Myös kysymys nopeimman ja vakaimman käytännön algoritmin rakentamisesta suurten matriisien kertomiseen on edelleen ratkaisematta.
Strassen-algoritmiin on tehty 7 kertolaskua ja 15 yhteenlaskua (tavallisen Strassen-algoritmin 18 sijaan).
Matriisit on jaettu lohkoalimatriiseihin, kuten yllä on esitetty.
Välielementit lasketaan
Matriisielementit lasketaan seuraavasti:
Strassenin algoritmi on bilineaarinen algoritmi, jonka kertoimet ovat Brentin yhtälöiden kuutiojärjestelmän juuria . [2] Tarkkojen algoritmien luokalle <2x2x2> tämä on minimaalinen ongelma, jonka ratkaisun avulla voidaan vähentää kertolaskujen määrää matriisielementtien renkaassa. [3] [4] Uusien algoritmien löytämisen ongelmana on, että Brent-järjestelmä on epälineaarinen, tuntemattomien ja yhtälöiden määrä (nämä luvut eivät täsmää) kasvaa nopeasti matriisien koon mukaan ja vain ratkaisut, joilla on suuri vaaditaan useita nollia.
Vuonna 2013 näiden ongelmien osittaisen voittamisen jälkeen oli mahdollista löytää ensimmäinen käytännöllinen bilineaarinen matriisin kertolaskualgoritmi, joka on asymptoottisesti nopeampi kuin Strassen-algoritmi. [5] Smirnovin algoritmi <3x3x6; 40> kertoo 3x3-matriisin 3x6-matriisilla käyttämällä 40 kertolaskua 54:n sijaan. Sen asymptoottinen monimutkaisuus on . (Algoritmin tensorikerto itsellään argumenttien syklisellä siirrolla johtaa algoritmiin neliömatriiseille <54x54x54; 64000>, jolla on sama monimutkaisuus). Kertomisen todellinen kiihtyvyys edellyttää merkittävää optimointia - monien päällekkäisten laskelmien poistamista lineaarisissa muodoissa.
Nykyään (2022) tämä on asymptoottisesti nopein käytännöllinen bilineaarinen algoritmi mielivaltaiselle matriisielementtien kentälle .
5. lokakuuta 2022 DeepMind löysi AlphaZero-hermoverkkoalgoritmia käyttämällä useita uusia algoritmeja eri ulottuvuuksien matriisien kertomiseen. Niiden nopeus mielivaltaisessa kentässä on kuitenkin kaukana tunnettujen parhaiden algoritmien nopeudesta. Joten 4X4-matriiseille Strassen-algoritmi vaatii 49 kertolaskua, ja AlphaTensor löysi algoritmin, joka vaatii 47 kertolaskua, mutta se toimii vain kentällä . [6] [7]