Strassen 矩阵相乘算法(转)
偶尔在算法课本上面看到矩阵相乘的算法,联想到自己曾经在蓝桥杯系统上曾经做过一道矩阵相乘的题目,当时用的是普通的矩阵相乘的方法,效率极低,勉强通过编译。所以决定研究一下Strassen矩阵相乘算法,由于本人比较懒,所以就从网上找了一些相关的资料供大家参考;
下面内容均转自 https://i.cnblogs.com/EditPosts.aspx?opt=1 ,如需转载请注明出处,https://www.cnblogs.com/zhuchenglin/p/6555495.html
题目描述
请编程实现矩阵乘法,并考虑当矩阵规模较大时的优化方法。
思路分析
根据wikipedia上的介绍:两个矩阵的乘法仅当第一个矩阵B的列数和另一个矩阵A的行数相等时才能定义。如A是m×n矩阵和B是n×p矩阵,它们的乘积AB是一个m×p矩阵,它的一个元素其中 1 ≤ i ≤ m, 1 ≤ j ≤ p。
值得一提的是,矩阵乘法满足结合律和分配率,但并不满足交换律,如下图所示的这个例子,两个矩阵交换相乘后,结果变了:
下面咱们来具体解决这个矩阵相乘的问题。
解法一、暴力解法
其实,通过前面的分析,我们已经很明显的看出,两个具有相同维数的矩阵相乘,其复杂度为O(n^3),参考代码如下:
- //矩阵乘法,3个for循环搞定
- void Mul(int** matrixA, int** matrixB, int** matrixC)
- {
- for(int i = 0; i < 2; ++i)
- {
- for(int j = 0; j < 2; ++j)
- {
- matrixC[i][j] = 0;
- for(int k = 0; k < 2; ++k)
- {
- matrixC[i][j] += matrixA[i][k] * matrixB[k][j];
- }
- }
- }
- }
解法二、Strassen算法
在解法一中,我们用了3个for循环搞定矩阵乘法,但当两个矩阵的维度变得很大时,O(n^3)的时间复杂度将会变得很大,于是,我们需要找到一种更优的解法。
一般说来,当数据量一大时,我们往往会把大的数据分割成小的数据,各个分别处理。遵此思路,如果丢给我们一个很大的两个矩阵呢,是否可以考虑分治的方法循序渐进处理各个小矩阵的相乘,因为我们知道一个矩阵是可以分成更多小的矩阵的。
如下图,当给定一个两个二维矩阵A B时:
这两个矩阵A B相乘时,我们发现在相乘的过程中,有8次乘法运算,4次加法运算:
矩阵乘法的复杂度主要就是体现在相乘上,而多一两次的加法并不会让复杂度上升太多。故此,我们思考,是否可以让矩阵乘法的运算过程中乘法的运算次数减少,从而达到降低矩阵乘法的复杂度呢?答案是肯定的。
1969年,德国的一位数学家Strassen证明O(N^3)的解法并不是矩阵乘法的最优算法,他做了一系列工作使得最终的时间复杂度降低到了O(n^2.80)。
他是怎么做到的呢?还是用上文A B两个矩阵相乘的例子,他定义了7个变量:
如此,Strassen算法的流程如下:
- 两个矩阵A B相乘时,将A, B, C分成相等大小的方块矩阵:
;
- 可以看出C是这么得来的:
- 现在定义7个新矩阵(读者可以思考下,这7个新矩阵是如何想到的):
- 而最后的结果矩阵C 可以通过组合上述7个新矩阵得到:
表面上看,Strassen算法仅仅比通用矩阵相乘算法好一点,因为通用矩阵相乘算法时间复杂度是,而Strassen算法复杂度只是
。但随着n的变大,比如当n >> 100时,Strassen算法是比通用矩阵相乘算法变得更有效率。
具体实现的伪代码如下:
Strassen (N,MatrixA,MatrixB,MatrixResult)
//splitting input Matrixes, into 4 submatrices each.
for i <- 0 to N/2
for j <- 0 to N/2
A11[i][j] <- MatrixA[i][j]; //a矩阵块
A12[i][j] <- MatrixA[i][j + N / 2]; //b矩阵块
A21[i][j] <- MatrixA[i + N / 2][j]; //c矩阵块
A22[i][j] <- MatrixA[i + N / 2][j + N / 2];//d矩阵块
B11[i][j] <- MatrixB[i][j]; //e 矩阵块
B12[i][j] <- MatrixB[i][j + N / 2]; //f 矩阵块
B21[i][j] <- MatrixB[i + N / 2][j]; //g 矩阵块
B22[i][j] <- MatrixB[i + N / 2][j + N / 2]; //h矩阵块
//here we calculate M1..M7 matrices .
//递归求M1
HalfSize <- N/2
AResult <- A11+A22
BResult <- B11+B22
Strassen( HalfSize, AResult, BResult, M1 ); //M1=(A11+A22)*(B11+B22) p5=(a+d)*(e+h)
//递归求M2
AResult <- A21+A22
Strassen(HalfSize, AResult, B11, M2); //M2=(A21+A22)B11 p3=(c+d)*e
//递归求M3
BResult <- B12 - B22
Strassen(HalfSize, A11, BResult, M3); //M3=A11(B12-B22) p1=a*(f-h)
//递归求M4
BResult <- B21 - B11
Strassen(HalfSize, A22, BResult, M4); //M4=A22(B21-B11) p4=d*(g-e)
//递归求M5
AResult <- A11+A12
Strassen(HalfSize, AResult, B22, M5); //M5=(A11+A12)B22 p2=(a+b)*h
//递归求M6
AResult <- A21-A11
BResult <- B11+B12
Strassen( HalfSize, AResult, BResult, M6); //M6=(A21-A11)(B11+B12) p7=(c-a)(e+f)
//递归求M7
AResult <- A12-A22
BResult <- B21+B22
Strassen(HalfSize, AResult, BResult, M7); //M7=(A12-A22)(B21+B22) p6=(b-d)*(g+h)
//计算结果子矩阵
C11 <- M1 + M4 - M5 + M7;
C12 <- M3 + M5;
C21 <- M2 + M4;
C22 <- M1 + M3 - M2 + M6;
//at this point , we have calculated the c11..c22 matrices, and now we are going to
//put them together and make a unit matrix which would describe our resulting Matrix.
for i <- 0 to N/2
for j <- 0 to N/2
MatrixResult[i][j] <- C11[i][j];
MatrixResult[i][j + N / 2] <- C12[i][j];
MatrixResult[i + N / 2][j] <- C21[i][j];
MatrixResult[i + N / 2][j + N / 2] <- C22[i][j];
Strassen 矩阵相乘算法(转)的更多相关文章
- Java实验项目四——多线程矩阵相乘算法的设计
Program:多线程矩阵相乘算法的设计 Description:利用多线程实现矩阵相乘,因为各个线程的运算互不影响, 所以不用使用锁,代码如下: thread.OperateMatrix类,实现矩阵 ...
- C语言 · 矩阵相乘 · 算法提高
算法提高 矩阵相乘 时间限制:1.0s 内存限制:256.0MB 问题描述 小明最近在为线性代数而头疼,线性代数确实很抽象(也很无聊),可惜他的老师正在讲这矩阵乘法这一段内容. 当然 ...
- 实现两个矩阵相乘的C语言程序
程序功能:实现两个矩阵相乘的C语言程序,并将其输出 代码如下: #include "stdafx.h" #include "windows.h" void Mu ...
- Java实现 蓝桥杯 算法提高 矩阵相乘
算法提高 矩阵相乘 时间限制:1.0s 内存限制:256.0MB 问题描述 小明最近在为线性代数而头疼,线性代数确实很抽象(也很无聊),可惜他的老师正在讲这矩阵乘法这一段内容. 当然,小明上课打瞌睡也 ...
- 利用Hadoop实现超大矩阵相乘之我见(二)
前文 在<利用Hadoop实现超大矩阵相乘之我见(一)>中我们所介绍的方法有着“计算过程中文件占用存储空间大”这个缺陷,本文中我们着重解决这个问题. 矩阵相乘计算思想 传统的矩阵相乘方法为 ...
- 利用Hadoop实现超大矩阵相乘之我见(一)
前记 最近,公司一位挺优秀的总务离职,欢送宴上,她对我说“你是一位挺优秀的程序员”,刚说完,立马道歉说“对不起,我说你是程序员是不是侮辱你了?”我挺诧异,程序员现在是很低端,很被人瞧不起的工作吗?或许 ...
- Python+MapReduce实现矩阵相乘
算法原理 map阶段 在map阶段,需要做的是进行数据准备.把来自矩阵A的元素aij,标识成p条<key, value>的形式,key="i,k",(其中k=1,2,. ...
- java 写一个 map reduce 矩阵相乘的案例
1.写一个工具类用来生成 map reduce 实验 所需 input 文件 下面两个是原始文件 matrix1.txt 1 2 -2 0 3 3 4 -3 -2 0 2 3 5 3 -1 2 -4 ...
- dp方法论——由矩阵相乘问题学习dp解题思路
前篇戳:dp入门——由分杆问题认识动态规划 导语 刷过一些算法题,就会十分珍惜“方法论”这种东西.Leetcode上只有题目.讨论和答案,没有方法论.往往答案看起来十分切中要害,但是从看题目到得到思路 ...
随机推荐
- html提交表单到Servlet
源码地址 https://github.com/YouXianMing/Java-Web-Study/tree/master/Servlet-Form 演示效果(注意post与get提交方式浏览器地址 ...
- 09、高级编程之基于排序机制的wordcount程序
package sparkcore.java; import java.util.Arrays; import java.util.Iterator; import org.apache.spark. ...
- FakeUserAgentError('Maximum amount of retries reached') 彻底解决办法
报错: FakeUserAgentError('Maximum amount of retries reached') 禁用服务器缓存: ua = UserAgent(use_cache_server ...
- 下载网络文件HttpURLConnection.getContentLength()大小为 0
HttpURLConnection conn = (HttpURLConnection)url.openConnection(); conn.setRequestProperty("Acce ...
- C# System.IO.FileStream
为文件提供 Stream,既支持同步读写操作,也支持异步读写操作. using System; using System.IO; using System.Text; class Test { pub ...
- 【一天一个shell命令】【cut】
1. 命令简介 cut根据指定的定界符,切分文件,并将选中的列输出到标准输出. 2. 用法 cut [选项]... [文件]... 打印输入行的选中的parts 到标准输出 3. 选项 4. 示例 以 ...
- C#语法——泛型的多种应用 C#语法——await与async的正确打开方式 C#线程安全使用(五) C#语法——元组类型 好好耕耘 redis和memcached的区别
C#语法——泛型的多种应用 本篇文章主要介绍泛型的应用. 泛型是.NET Framework 2.0 版类库就已经提供的语法,主要用于提高代码的可重用性.类型安全性和效率. 泛型的定义 下面定义了 ...
- Linux内核调试方法总结
Linux内核调试方法总结 一 调试前的准备 二 内核中的bug 三 内核调试配置选项 1 内核配置 2 调试原子操作 四 引发bug并打印信息 1 BUG()和BUG_ON() 2 ...
- 20.2.翻译系列:EF 6中基于代码的数据库迁移技术【EF 6 Code-First系列】
原文链接:https://www.entityframeworktutorial.net/code-first/code-based-migration-in-code-first.aspx EF 6 ...
- SNF软件开发机器人-子系统-导出-导入功能-多人合作时这个功能经常用到
导出 导出可以将资源表和子系统导出并形成一个json文件. 1.效果展示: 2.使用说明: 点击导出按钮后会弹出一个导出页面.页面的左侧可以选择功能,右侧可以选择资源表,选择功能的同时右侧中功能所需的 ...