計算機算法:Strassen矩陣相乘算法

引言

Strassen的矩陣相乘方法是一種典型的分治算法。目前爲止,我們已經見過一些分治策略的算法了,例如歸併排序Karatsuba大數快速乘法。現在,讓我再看看分治策略的背後是什麼。

同動態規劃不同,在動態規劃中,爲了得到最終的解決方案,我們經常需要把一個大的問題“展開”爲幾個子問題,但是這裏,我們會更多的談到如何把一些子解決方案組合到一起。這些子問題的解決方案是對等的,他們的歸併方式也是通過某種方式定義好的。

一個典型的例子就是歸併排序算法。在歸併排序中,我們有兩個有序數組,我們想要這兩個數組在合併之後仍然保持有序。當然了,在歸併排序中,最複雜的部分當屬自我合併,而原因則是,我們不得不傳遞兩個數組,A和B,然後去比較每一“對”分別來自數組A和數組B的元素。有一點離題,但是,這是歸併排序的一個弱點,雖然,它的最壞情況的時間複雜度是 O(n.log(n)),但是,快速排序卻經常是實踐中更爲有效的排序方法,因爲,它沒有“合併”的過程。快速排序僅僅把兩個子數組連接到一起,請注意,在快速排序中,子數組一般並不具有相同的長度,雖然他的最壞時間複雜度是O(n^2),但它的性能卻經常好於歸併排序。

在以上段落中,那個簡單的例子告訴我們,有時候如何合併兩個子問題的解決方案並不是一個簡單的事情。因此,當我們使用分治策略的時候,我們必須非常謹慎。

歷史

Volker Strassen是一位出生於1936年的德國數學家。他因爲在概率論上的工作而廣爲人知,但是在計算機科學和算法領域,他卻因爲矩陣相乘算法而被大部分人認識,這個算法目前仍然是比通用矩陣相乘算法性能好的主要算法之一。

Strassen在1969年第一次發表關於這個算法的文章,並證明了複雜度爲n^3的算法並不是最優算法。實際上,Strassen給出的解決方案只是會更好一點點,但是,他的貢獻卻是巨大的,因爲他的工作激發了矩陣相乘領域更多的研究,比如複雜度爲O(n^2,3737)的Coppersmith-Winograd算法

概述

兩個矩陣 A[NxN] 和 B[NxN] 相乘的通用算法是非常簡單的。雖然,矩陣相乘比兩個數字相乘要複雜得多,而且也不滿足交換律,但它仍然非常簡單——同時也很慢。

讓我們先來定義一下什麼是A[NxN]矩陣。因爲我們要說下NxN矩陣,讓我們先想象一個有N行N列的方格網。在每一行和每一列的A[i][j],我們都有一個值。

enter image description here

當然,作爲一個開發者,我們可以把一個矩陣看成一個二維數組。

// PHP two-dimensional array
$a = array(
    0 => array($v1, $v2, $v3, $v4),
    1 => array($v5, $v6, $v7, $v8),
    2 => array($v9, $v10, $v11, $v12),
);

不要忘記,一個NxN的矩陣僅僅是矩陣中的一種情況,同樣的,我們可以有其他任何大小的NxM階矩陣(N <> M)。

然而,爲了和另外的矩陣相乘,矩陣的大小是非常重要的,爲什麼?

正如我上面提到的一樣,矩陣相乘和數字相乘並不一樣。首先,這個操作並不滿足交換律。

enter image description here

第二個問題是,你用來相乘A和B的方法。

enter image description here

僅僅因爲這種方法只對NxN階矩陣有效,因此我們能看到把矩形矩陣相乘產生的問題。確實,這是不可能的,除非A矩陣的第二維和B矩陣的第一維相等。

enter image description here

不過好在我們現在正在討論的是具有相同維數的方形矩陣。

好的,現在我們知道如何把兩個方形矩陣相乘了(具有相同維數NxN),現在,讓我們一起去估算一下通用矩陣相乘算法的時間複雜度。

我們知道A.B = C,當且僅當:

C[i][j] = sum(A[i][k] * B[k][j]) for k = 0 .. n

於是,我們有一個n^3複雜度的操作。現在,讓我們盡力找一個分治策略的算法。

這個對於矩陣來說確實並不難,因爲我們知道,一個矩陣可以被分成很多更小的子矩陣。

enter image description here

現在,我們有什麼?

enter image description here

再一次——同樣的時間複雜度——我們有了8個乘積和4個和,那麼,計算量在哪?

當然, 爲了得到更快的解決方案,我們不得不看一下Strassen在1969做過的工作。他如下圖定義了P1, P2, P3, P4, P5, P6 和 P7。

enter image description here

時間複雜度

正如我以上提到過的,Strassen算法僅僅比通用矩陣相乘算法好一點點。通用矩陣相乘算法時間複雜度是O(n^3),然而Strassen算法複雜度則是O(n^2.80)。

你能在下圖觀察到,隨着n的變大,Strassen算法是如何比通用矩陣相乘算法變得更有效率的。

enter image description here

應用

雖然這個算法看起來更接近純數學領域,而不是計算機領域。但在實際應用中,在任何用到NxN數組的地方,我們都可以從矩陣相乘算法中獲益。

另一方面,Strassen算法並不比n^3複雜度的通用矩陣相乘算法快很多。這很重要,因爲對於一個很小的n(通常n<45)來說,通用矩陣相乘算法在實踐中往往是更好的選擇。然而,你可以從以上的圖片中看到,對於n>100的情況來說,這兩個算法的差別還是相當大的。

同時,當我們談到|V| = n的鄰接矩陣,以及一些依賴矩陣相乘的圖論算法的時候,NxN數組經常會在這些領域中被使用。

原文鏈接:Computer Algorithms: Strassen's Matrix Multiplication

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章