#算法學習錄#Strassen矩陣乘法

今天我們談談一個“土豪”算法——Strasen矩陣算法
之說以說它“土豪”就是因為其帶來了巨大的空間開銷。
先來考察一個問題:請用三次實數乘法計算復數a+bi和c+di相乘。
由于:
a×(c+d)=ac+ad=s1 ;
b×(c-d)=bc-bd=s2 ;
d×(a+b)=ad+bd=s3 ;
故有實部:s1 -s3 =ac-bd,
虛部:s2+ s3 =ad+bc。
這樣,四次的乘法就變成三次乘法。

Strassen矩陣乘法也是如此,把A,B,C矩陣分解為n/2×n/2子矩陣,進行7次遞歸計算n/2×n/2矩陣的乘法,其運行時間的遞歸式:

T(n)= Θ(1)???????????? if n=1;

??????7T(n/2)+Θ(n^2 )??? if n>1;

令:
S1=B12-B22;
S2=A11+A12;
S3=A21+A22;
S4=B21-B22;
S5=A11+A22;
S6=B11+B22;
S7=A12-A22;
S8=B21+B22;
S9=A11-A21;
S10=B11+B12;
那么:?P1= A11·S1 = A11·(B12-B22)
P2= B22·S2 = B22·(A11+A12)
P3= B11·S3 = B11·(A21+A22)
P4= A22·S4 = A22·(B21-B22)
P5= S5·S6 = (A11+A22)·(B11+B22)
P6= S7·S8 = (A12-A22)·(B21+B22)
P7= S9·S10 = (A11-A21)·(B11+B12)

C11= P5 + P4 - P2 + P6=A11×B11+A12×B21
C12= P1 + P2=A11×B12+A12×B22
C21= P3 + P4=A21×B11+A22×B21
C22= P5 + P1 – P3 – P7=A21×B21+A22×B22

Strassen算法的具體實現(C語言):
int Strassen(int **A, int **B, int **Result, int Size){
?if (Size == 1){
??//直接計算C11
??Result[0][0] = A[0][0] * B[0][0];
??return 0;
?}
?int NewSize = Size / 2;
?/*分塊矩陣*/
?int **A11, **A12, **A21, **A22;
?int **B11, **B12, **B21, **B22;
?int **C11, **C12, **C21, **C22;

?int **P1, **P2, **P3, **P4, **P5, **P6, **P7;
?/*存放數組A、B(i、j)的臨時變量*/
?int **AResult, **BResult;

?A11 = new int*[NewSize];
?A12 = new int*[NewSize];
?A21 = new int*[NewSize];
?A22 = new int*[NewSize];

?B11 = new int*[NewSize];
?B12 = new int*[NewSize];
?B21 = new int*[NewSize];
?B22 = new int*[NewSize];

?C11 = new int*[NewSize];
?C12 = new int*[NewSize];
?C21 = new int*[NewSize];
?C22 = new int*[NewSize];

?P1 = new int*[NewSize];
?P2 = new int*[NewSize];
?P3 = new int*[NewSize];
?P4 = new int*[NewSize];
?P5 = new int*[NewSize];
?P6 = new int*[NewSize];
?P7 = new int*[NewSize];

?AResult = new int*[NewSize];
?BResult = new int*[NewSize];

?for (int i = 0; i < NewSize; i++)
?{
??A11[i] = new int[NewSize];
??A12[i] = new int[NewSize];
??A21[i] = new int[NewSize];
??A22[i] = new int[NewSize];

??B11[i] = new int[NewSize];
??B12[i] = new int[NewSize];
??B21[i] = new int[NewSize];
??B22[i] = new int[NewSize];

??C11[i] = new int[NewSize];
??C12[i] = new int[NewSize];
??C21[i] = new int[NewSize];
??C22[i] = new int[NewSize];

??P1[i] = new int[NewSize];
??P2[i] = new int[NewSize];
??P3[i] = new int[NewSize];
??P4[i] = new int[NewSize];
??P5[i] = new int[NewSize];
??P6[i] = new int[NewSize];
??P7[i] = new int[NewSize];

??AResult[i] = new int[NewSize];
??BResult[i] = new int[NewSize];


?}

?//對分塊矩陣賦值
?for (int i = 0; i < NewSize; i++)
?{
??for (int j = 0; j < NewSize; j++)
??{
???A11[i][j] = A[i][j];
???A12[i][j] = A[i][j + NewSize];
???A21[i][j] = A[i + NewSize][j];
???A22[i][j] = A[i + NewSize][j + NewSize];

???B11[i][j] = B[i][j];
???B12[i][j] = B[i][j + NewSize];
???B21[i][j] = B[i + NewSize][j];
???B22[i][j] = B[i + NewSize][j + NewSize];

??}
?}

?//計算P1 = A11*(B12-B22)
?Sub(B12, B22, BResult, NewSize);
?Strassen(A11, BResult, P1, NewSize);

?//計算P2 = (A11+A12)*B22
?Add(A11, A12, AResult, NewSize);
?Strassen(AResult, B22, P2, NewSize);

?//計算P3 = (A21+A22)*B11
?Add(A21, A22, AResult, NewSize);
?Strassen(AResult, B11, P3, NewSize);

?//計算P4 = A22*(B21-B11)
?Sub(B21, B11, BResult, NewSize);
?Strassen(A22, BResult, P4, NewSize);

?//計算P5 = (A11+A22)*(B11+B22)
?Add(A11, A22, AResult, NewSize);
?Add(B11, B22, BResult, NewSize);
?Strassen(AResult, BResult, P5, NewSize);

?//計算P6 = (A12-A22)*(B21+B22)
?Sub(A12, A22, AResult, NewSize);
?Add(B21, B22, BResult, NewSize);
?Strassen(AResult, BResult, P6, NewSize);

?//計算P7 = (A11-A21)*(B11+B12)
?Sub(A11, A21, AResult, NewSize);
?Add(B11, B12, BResult, NewSize);
?Strassen(AResult, BResult, P7, NewSize);

?//計算C11,C12,C21,C22
?//C11 = P5 + P4 - P2 + P6;
?Add(P5, P4, AResult, NewSize);
?Sub(AResult, P2, BResult, NewSize);
?Add(BResult, P6, C11, NewSize);

?//C12=P1+P2
?Add(P1, P2, C12, NewSize);

?//C21=P3+P4
?Add(P3, P4, C21, NewSize);

?//C22=P5+P1-P3-P7
?Add(P5, P1, C22, NewSize);
?Sub(C22, P3, C22, NewSize);
?Sub(C22, P7, C22, NewSize);

?//合并C11,C12,C21,C22
?for (int i = 0; i < NewSize; i++)
?{
??for (int j = 0; j < NewSize; j++)
??{
???Result[i][j] = C11[i][j];
???Result[i][j + NewSize] = C12[i][j];
???Result[i + NewSize][j] = C21[i][j];
???Result[i + NewSize][j + NewSize] = C22[i][j];
??}
?}

?//刪除數組,回收資源
?for (int i = 0; i < NewSize; i++){
??delete[] A11[i]; delete[] A12[i]; delete[] A21[i]; delete[] A22[i];
??delete[] B11[i]; delete[] B12[i]; delete[] B21[i]; delete[] B22[i];
??delete[] C11[i]; delete[] C12[i]; delete[] C21[i]; delete[] C22[i];
??delete[] P1[i]; delete[] P2[i]; delete[] P3[i]; delete[] P4[i]; delete[] P5[i]; delete[] P6[i]; delete[] P7[i];
??delete[] AResult[i]; delete[] BResult[i];
?}
?delete[] A11; delete[] A12; delete[] A21; delete[] A22;
?delete[] B11; delete[] B12; delete[] B21; delete[] B22;
?delete[] C11; delete[] C12; delete[] C21; delete[] C22;
?delete[] P1; delete[] P2; delete[] P3; delete[] P4; delete[] P5; delete[] P6; delete[] P7;
?delete[] AResult; delete[] BResult;
?return 0;
}


//矩陣相加
void Add(int **A, int **B, int **Q, int Size){
?for (int i = 0; i < Size; i++){
??for (int j = 0; j < Size; j++){
???Q[i][j] = A[i][j] + B[i][j];
??}
?}
}

//矩陣相減
void Sub(int**A, int**B, int **Q, int Size){
?for (int i = 0; i < Size; i++){
??for (int j = 0; j < Size; j++){
???Q[i][j] = A[i][j] - B[i][j];
??}
?}
}
演示結果:
?


與暴力求解相比:
?? for(i=0;i<m;i++)
???? for(j=0;j<m;j++){
???????? C[i][j]=0;
???? ?for(k=0;k<n;k++)
??????????? C[i][j]+=A[i][k]*B[k][j];????????????
}???
其運行時間(n^lg7,2.80<lg7<2.81)比暴力求解(n3)稍快,但其精度較低(在處理小數計算時),且消耗了大量存儲空間。

最后附上源代碼:https://github.com/LRC-cheng/Algorithms_Practise.git

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容

  • 貪心算法 貪心算法總是作出在當前看來最好的選擇。也就是說貪心算法并不從整體最優考慮,它所作出的選擇只是在某種意義上...
    fredal閱讀 9,266評論 3 52
  • 閱讀經典——《算法導論》03 矩陣乘法是種極其耗時的運算。 以C = A ? B為例,其中A和B都是 n x n ...
    金戈大王閱讀 27,195評論 10 24
  • 背景 一年多以前我在知乎上答了有關LeetCode的問題, 分享了一些自己做題目的經驗。 張土汪:刷leetcod...
    土汪閱讀 12,765評論 0 33
  • C++運算符重載-下篇 本章內容:1. 運算符重載的概述2. 重載算術運算符3. 重載按位運算符和二元邏輯運算符4...
    Haley_2013閱讀 1,457評論 0 49
  • 一早醒來,頓悟昨晚電話中為何忽生反感: 你自然而然流露出的優越感!縱然在談論失敗可能性時也透著一種先見之明的優越感...
    蝎思君閱讀 280評論 1 4