分治算法_Strassen矩阵乘法

算法的主要思想是一种分治思想,即将一个2n的方阵分解成4个2n-1的小方阵。

借助这种办法,任何有穷方阵都可以简化为有限个2×2方阵,所以今天我们主要介绍斯特拉森算法在2×2方阵上的应用。

首先我们假设有两个2×2矩阵,A,B.

A = a11 a12        B = b11  b12

      a21  a22              b21 b22

我们设矩阵相乘的结果矩阵为C。则

C = c11 c12

      c21 c22

由斯特拉森算法可得7

  1. m1 = (a12 - a22)(b21 + b22)
  2. m2 = (a11 + a22)(b11 + b22)
  3. m3 = (a21-a11)(b11+b12)
  4. m4 = (a11+a12) * b22
  5. m5 = a11 * (b12 - b22)
  6. m6 = a22 * (b21 - b11)
  7. m7 = (a21 + a22) * b11

易得

  1. c11 = m6 + m1 + m2 - m4
  2. c12 = m5 + m4
  3. c21 = m6 + m7
  4. c22 = m5 + m3 + m2 - m7

 

应用该种方法可将花费的时间由最开始的Ω(n3 )变成了O(nlg7)又因为lg7在2.80和2.81之间,所以其运行时间为O(n2.81),相比一开始有较为明显的优化(尤其是在处理较大的矩阵时)。

 

#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<cmath>
//实现Strassen 最简单的2x2 矩阵乘法
using namespace std;
const int MAXN = 2;

typedef long long ll;

int main(){

    ll a[MAXN][MAXN];
    ll b[MAXN][MAXN];
   ll c[MAXN][MAXN];
   for(int i=0;i<2;i++)
      for(int j=0;j<2;j++) cin>>a[i][j];
    for(int i=0;i<2;i++)
      for(int j=0;j<2;j++) cin>>b[i][j];


  ll M1 = (a[0][1] - a[1][1]) * (b[1][0] + b[1][1]),
     M2 = (a[0][0] + a[1][1]) * (b[0][0] + b[1][1]),
     M3 = (a[1][0] - a[0][0]) * (b[0][0] + b[0][1]),
     M4 = (a[0][0] + a[0][1]) * b[1][1],
     M5 = a[0][0] * (b[0][1] - b[1][1]),
     M6 = a[1][1] * (b[1][0] - b[0][0]),
     M7 = (a[1][0] + a[1][1]) * b[0][0];
    c[0][0] = M6 + M2 + M1 - M4;
    c[0][1] = M5 + M4;
    c[1][0] = M6 + M7;
    c[1][1] = M5 + M3 + M2 - M7;


    for(int i=0;i<2;i++)
    {
         for(int j=0;j<2;j++) cout<<c[i][j]<<" ";
         cout<<endl;
    }
   return 0;
}

 

另附:  

/*
Strassen Algorithm Implementation in C++
Coded By: Seyyed Hossein Hasan Pour MatiKolaee in May 5 2010 .
Mazandaran University of Science and Technology,Babol,Mazandaran,Iran
--------------------------------------------
Email : Master.huricane@gmail.com
YM    : Deathmaster_nemessis@yahoo.com
Updated may 09 2010.
*/
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <ctime>
#include <windows.h>
using namespace std;
 
int Strassen(int n, int** MatrixA, int ** MatrixB, int ** MatrixC);//Multiplies Two Matrices recrusively.
int ADD(int** MatrixA, int** MatrixB, int** MatrixResult, int length );//Adds two Matrices, and places the result in another Matrix
int SUB(int** MatrixA, int** MatrixB, int** MatrixResult, int length );//subtracts two Matrices , and places  the result in another Matrix
int MUL(int** MatrixA, int** MatrixB, int** MatrixResult, int length );//Multiplies two matrices in conventional way.
void FillMatrix( int** matrix1, int** matrix2, int length);//Fills Matrices with random numbers.
void PrintMatrix( int **MatrixA, int MatrixSize );//prints the Matrix content.
 
int main()
{
 
    int MatrixSize = 0;
 
    int** MatrixA;
    int** MatrixB;
    int** MatrixC;
 
    clock_t startTime_For_Normal_Multipilication ;
    clock_t endTime_For_Normal_Multipilication ;
 
    clock_t startTime_For_Strassen ;
    clock_t endTime_For_Strassen ;
 
    time_t start,end;
 
    srand(time(0));
 
    cout<<setw(45)<<"In the name of GOD";
    cout<<endl<<setw(60)<<"Strassen Algorithm Implementation in C++ "
        <<endl<<endl<<setw(50)<<"By Seyyed Hossein Hasan Pour"
        <<endl<<setw(60)<<"Mazandaran University of Science and Technology"
        <<endl<<setw(40)<<"May 9 2010";
 
    cout<<"\nPlease Enter your Matrix Size(must be in a power of two(eg:32,64,512,..): ";
    cin>>MatrixSize;
 
    int N = MatrixSize;//for readiblity.
 
 
    MatrixA = new int *[MatrixSize];
    MatrixB = new int *[MatrixSize];
    MatrixC = new int *[MatrixSize];
 
    for (int i = 0; i < MatrixSize; i++)
    {
        MatrixA[i] = new int [MatrixSize];
        MatrixB[i] = new int [MatrixSize];
        MatrixC[i] = new int [MatrixSize];
    }
 
    FillMatrix(MatrixA,MatrixB,MatrixSize);
 
  //*******************conventional multiplication test
        cout<<"Phase I started:  "<< (startTime_For_Normal_Multipilication = clock());
 
		MUL(MatrixA,MatrixB,MatrixC,MatrixSize);
 
        cout<<"\nPhase I ended: "<< (endTime_For_Normal_Multipilication = clock());
 
		cout<<"\nMatrix Result... \n";
	    PrintMatrix(MatrixC,MatrixSize);
 
  //*******************Strassen multiplication test
        cout<<"\nMultiplication started: "<< (startTime_For_Strassen = clock());
 
		Strassen( N, MatrixA, MatrixB, MatrixC );
 
		cout<<"\nMultiplication: "<<(endTime_For_Strassen = clock());
 
 
	cout<<"\nMatrix Result... \n";
	PrintMatrix(MatrixC,MatrixSize);
 
	cout<<"Matrix size "<<MatrixSize;
	cout<<"\nNormal mode "<<(endTime_For_Normal_Multipilication - startTime_For_Normal_Multipilication)<<" Clocks.."<<(endTime_For_Normal_Multipilication - startTime_For_Normal_Multipilication)/CLOCKS_PER_SEC<<" Sec";
	cout<<"\nStrassen mode "<<(endTime_For_Strassen - startTime_For_Strassen)<<" Clocks.."<<(endTime_For_Strassen - startTime_For_Strassen)/CLOCKS_PER_SEC<<" Sec\n";
    system("Pause");
    return 0;
 
}
/*
in order to be able to create a matrix without any limitaion in c++,
one way is to create it using pointers.
as you see by using a pointer to pointer strategy we can make a multi-
dimensional Matrix of any size . The notation also makes us capable of
creating a matrix with VARIABLE size at runtime ,meaning we can resize
the size of our matrix at runtime , shrink it or increase it , your choice.
what we do is simple , first we make a pointer of pointer variable , this
means that our first pointer will point to another pointer which again
this pointer ,points to sth else(we can make it point to an array) .
int **A;
will declare the variable , we now need to expand it .
now make a pointer based array and allocate the memory dynamicly
A = new int *[desired_array_row];
this gives us a one diminsional pointer based array,now you want a 2D array?
big deal,lets make one.
we use for() to achieve this goal , remember when i said we are going to make
a variable which is a pointer of pointer ? which meant any location pointed to somewhere else
, we made a pointer based array , a one diminsional one , just up there ,
and you know this fatct that an array is consits of individual blocks right?
and the fact that each block can be used just like a solo variable.
so simply if we could write
A = new int *[any_size];
cant we do it to all of our indiviual array blocks which are just like the solo variable ?
so this means that if we could do it with A, and get an array , we can use the same method
to make different arrays for different block of the array we made in first place.
we use for() to iterate through all of the blocks of the previously made array, and
then for each block we create a single array .
for ( int i = 0; i < desired_array_row; i++)
A[i] = new int [desired_column_size];
after this for , we can enjoy our 2D array wich can be access like any ordinary array we know.
just use the conventional notation for accessing array blocks for either reading or writing.( A[i][j])
and remember to free the space we allocated for our 2D array at the end of the program .
we do such a thing this way:
for ( int i = 0; i < your_array_row; i++)
{
    delete [] A[i];
}
delete[] A;
.using this method you can make any N-diminsional array, you just need to use for with right iteration.
*/
int Strassen(int N, int **MatrixA, int **MatrixB, int **MatrixC)
{
 
        int HalfSize = N/2;
        int newSize = N/2;
 
        if ( N <= 64 )//choosing the threshhold is extremely important, try N<=2 to see the result
        {
            MUL(MatrixA,MatrixB,MatrixC,N);
        }
        else
        {
			int** A11;
			int** A12;
			int** A21;
			int** A22;
 
			int** B11;
			int** B12;
			int** B21;
			int** B22;
 
			int** C11;
			int** C12;
			int** C21;
			int** C22;
 
			int** M1;
			int** M2;
			int** M3;
			int** M4;
			int** M5;
			int** M6;
			int** M7;
			int** AResult;
			int** BResult;
 
            //making a 1 diminsional pointer based array.
			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];
 
			M1 = new int *[newSize];
			M2 = new int *[newSize];
			M3 = new int *[newSize];
			M4 = new int *[newSize];
			M5 = new int *[newSize];
			M6 = new int *[newSize];
			M7 = new int *[newSize];
 
			AResult = new int *[newSize];
			BResult = new int *[newSize];
 
			int newLength = newSize;
 
            //making that 1 diminsional pointer based array , a 2D pointer based array
			for ( int i = 0; i < newSize; i++)
			{
				A11[i] = new int[newLength];
				A12[i] = new int[newLength];
				A21[i] = new int[newLength];
				A22[i] = new int[newLength];
 
				B11[i] = new int[newLength];
				B12[i] = new int[newLength];
				B21[i] = new int[newLength];
				B22[i] = new int[newLength];
 
				C11[i] = new int[newLength];
				C12[i] = new int[newLength];
				C21[i] = new int[newLength];
				C22[i] = new int[newLength];
 
				M1[i] = new int[newLength];
				M2[i] = new int[newLength];
				M3[i] = new int[newLength];
				M4[i] = new int[newLength];
				M5[i] = new int[newLength];
				M6[i] = new int[newLength];
				M7[i] = new int[newLength];
 
				AResult[i] = new int[newLength];
				BResult[i] = new int[newLength];
 
 
			}
			//splitting input Matrixes, into 4 submatrices each.
            for (int i = 0; i < N / 2; i++)
            {
                for (int j = 0; j < N / 2; j++)
                {
                    A11[i][j] = MatrixA[i][j];
                    A12[i][j] = MatrixA[i][j + N / 2];
                    A21[i][j] = MatrixA[i + N / 2][j];
                    A22[i][j] = MatrixA[i + N / 2][j + N / 2];
 
                    B11[i][j] = MatrixB[i][j];
                    B12[i][j] = MatrixB[i][j + N / 2];
                    B21[i][j] = MatrixB[i + N / 2][j];
                    B22[i][j] = MatrixB[i + N / 2][j + N / 2];
 
                }
            }
 
            //here we calculate M1..M7 matrices .
            //M1[][]
            ADD( A11,A22,AResult, HalfSize);
            ADD( B11,B22,BResult, HalfSize);
            Strassen( HalfSize, AResult, BResult, M1 ); //now that we need to multiply this , we use the strassen itself .
 
 
            //M2[][]
            ADD( A21,A22,AResult, HalfSize);              //M2=(A21+A22)B11
            Strassen(HalfSize, AResult, B11, M2);       //Mul(AResult,B11,M2);
 
            //M3[][]
            SUB( B12,B22,BResult, HalfSize);              //M3=A11(B12-B22)
            Strassen(HalfSize, A11, BResult, M3);       //Mul(A11,BResult,M3);
 
            //M4[][]
            SUB( B21, B11, BResult, HalfSize);           //M4=A22(B21-B11)
            Strassen(HalfSize, A22, BResult, M4);       //Mul(A22,BResult,M4);
 
            //M5[][]
            ADD( A11, A12, AResult, HalfSize);           //M5=(A11+A12)B22
            Strassen(HalfSize, AResult, B22, M5);       //Mul(AResult,B22,M5);
 
 
            //M6[][]
            SUB( A21, A11, AResult, HalfSize);
            ADD( B11, B12, BResult, HalfSize);             //M6=(A21-A11)(B11+B12)
            Strassen( HalfSize, AResult, BResult, M6);    //Mul(AResult,BResult,M6);
 
            //M7[][]
            SUB(A12, A22, AResult, HalfSize);
            ADD(B21, B22, BResult, HalfSize);             //M7=(A12-A22)(B21+B22)
            Strassen(HalfSize, AResult, BResult, M7);     //Mul(AResult,BResult,M7);
 
            //C11 = M1 + M4 - M5 + M7;
            ADD( M1, M4, AResult, HalfSize);
            SUB( M7, M5, BResult, HalfSize);
            ADD( AResult, BResult, C11, HalfSize);
 
            //C12 = M3 + M5;
            ADD( M3, M5, C12, HalfSize);
 
            //C21 = M2 + M4;
            ADD( M2, M4, C21, HalfSize);
 
            //C22 = M1 + M3 - M2 + M6;
            ADD( M1, M3, AResult, HalfSize);
            SUB( M6, M2, BResult, HalfSize);
            ADD( AResult, BResult, C22, HalfSize);
 
 
            //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 (int i = 0; i < N/2 ; i++)
            {
                for (int j = 0 ; j < N/2 ; j++)
                {
                    MatrixC[i][j] = C11[i][j];
                    MatrixC[i][j + N / 2] = C12[i][j];
                    MatrixC[i + N / 2][j] = C21[i][j];
                    MatrixC[i + N / 2][j + N / 2] = C22[i][j];
                }
            }
 
            // dont forget to free the space we alocated for matrices,
			for (int i = 0; i < newLength; 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[] M1[i];delete[] M2[i];delete[] M3[i];delete[] M4[i];
				delete[] M5[i];delete[] M6[i];delete[] M7[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[] M1;delete[] M2;delete[] M3;delete[] M4;delete[] M5;
				delete[] M6;delete[] M7;
				delete[] AResult;
				delete[] BResult ;
 
 
        }//end of else
 
 
	return 0;
}
 
int ADD(int** MatrixA, int** MatrixB, int** MatrixResult, int MatrixSize )
{
    for ( int i = 0; i < MatrixSize; i++)
    {
        for ( int j = 0; j < MatrixSize; j++)
        {
            MatrixResult[i][j] =  MatrixA[i][j] + MatrixB[i][j];
        }
    }
	return 0;
}
 
int SUB(int** MatrixA, int** MatrixB, int** MatrixResult, int MatrixSize )
{
    for ( int i = 0; i < MatrixSize; i++)
    {
        for ( int j = 0; j < MatrixSize; j++)
        {
            MatrixResult[i][j] =  MatrixA[i][j] - MatrixB[i][j];
        }
    }
	return 0;
}
 
int MUL( int** MatrixA, int** MatrixB, int** MatrixResult, int MatrixSize )
{
    for (int i=0;i<MatrixSize ;i++)
        {
              for (int j=0;j<MatrixSize ;j++)
              {
                   MatrixResult[i][j]=0;
                   for (int k=0;k<MatrixSize ;k++)
                   {
                          MatrixResult[i][j]=MatrixResult[i][j]+MatrixA[i][k]*MatrixB[k][j];
                   }
              }
        }
	return 0;
}
 
void FillMatrix( int** MatrixA, int** MatrixB, int length)
{
    for(int row = 0; row<length; row++)
    {
        for(int column = 0; column<length; column++)
        {
 
           MatrixB[row][column] = (MatrixA[row][column] = rand() %5);
            //matrix2[row][column] = rand() % 2;//ba hazfe in khat 50% afzayeshe soorat khahim dasht
        }
 
    }
}
void PrintMatrix(int **MatrixA,int MatrixSize)
{
	cout<<endl;
	   for(int row = 0; row<MatrixSize; row++)
		{
			for(int column = 0; column<MatrixSize; column++)
			{
 
 
				cout<<MatrixA[row][column]<<"\t";
				if ((column+1)%((MatrixSize)) == 0)
					cout<<endl;
			}
 
		}
	   cout<<endl;
}

 

 

 

 

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
矩阵乘法是计算机科学中非常基础的一种算法,它在图像处理、人工智能等领域都有广泛的应用。而分治法是一种常见的算法,它可以将一个问题分成多个子问题,再将子问题的结果合并起来得到最终结果。本文将介绍如何使用分治法实现矩阵乘法。 首先,我们来回顾一下矩阵乘法的定义。对于矩阵A和B,它们的乘积C的第i行第j列的元素可以表示为: C[i][j] = sum(A[i][k] * B[k][j]), k = 1,2,...,n 其中n为矩阵的大小。 接下来,我们将使用分治法来实现矩阵乘法。具体思路如下: 1.将矩阵A和B分别划分成4个子矩阵,即A11、A12、A21、A22和B11、B12、B21、B22。 2.递归地计算子矩阵的乘积,得到C11、C12、C21和C22。 3.将C11、C12、C21和C22合并成一个大的矩阵C。 下面是Python代码实现: ```python def matrix_multiply(A, B): # 判断矩阵大小是否相等 assert len(A[0]) == len(B) # 矩阵大小为1x1的情况 if len(A) == 1 and len(A[0]) == 1 and len(B) == 1 and len(B[0]) == 1: return [[A[0][0] * B[0][0]]] # 将矩阵A和B分成4个子矩阵 A11, A12, A21, A22 = split_matrix(A) B11, B12, B21, B22 = split_matrix(B) # 递归地计算子矩阵的乘积 C11 = matrix_add(matrix_multiply(A11, B11), matrix_multiply(A12, B21)) C12 = matrix_add(matrix_multiply(A11, B12), matrix_multiply(A12, B22)) C21 = matrix_add(matrix_multiply(A21, B11), matrix_multiply(A22, B21)) C22 = matrix_add(matrix_multiply(A21, B12), matrix_multiply(A22, B22)) # 合并C11、C12、C21和C22成一个大的矩阵C return merge_matrix(C11, C12, C21, C22) def split_matrix(matrix): # 将矩阵按行、列均分为两个子矩阵 n = len(matrix) m = len(matrix[0]) A = [[matrix[i][j] for j in range(m // 2)] for i in range(n // 2)] B = [[matrix[i][j] for j in range(m // 2, m)] for i in range(n // 2)] C = [[matrix[i][j] for j in range(m // 2)] for i in range(n // 2, n)] D = [[matrix[i][j] for j in range(m // 2, m)] for i in range(n // 2, n)] return A, B, C, D def merge_matrix(A, B, C, D): # 将四个子矩阵合并成一个大的矩阵 n = len(A) + len(C) m = len(A[0]) + len(B[0]) matrix = [[0] * m for i in range(n)] for i in range(len(A)): for j in range(len(A[0])): matrix[i][j] = A[i][j] for i in range(len(C)): for j in range(len(C[0])): matrix[i + len(A)][j] = C[i][j] for i in range(len(B)): for j in range(len(B[0])): matrix[i][j + len(A[0])] = B[i][j] for i in range(len(D)): for j in range(len(D[0])): matrix[i + len(A)][j + len(A[0])] = D[i][j] return matrix def matrix_add(A, B): # 矩阵加法 n = len(A) m = len(A[0]) matrix = [[0] * m for i in range(n)] for i in range(n): for j in range(m): matrix[i][j] = A[i][j] + B[i][j] return matrix ``` 可以使用以下代码进行测试: ```python A = [[1, 2], [3, 4]] B = [[5, 6], [7, 8]] C = matrix_multiply(A, B) print(C) # [[19, 22], [43, 50]] ``` 上面的代码实现了分治法实现矩阵乘法的基本思路,但是它的时间复杂度依然是O(n^3),因为我们在合并子问题的结果时需要遍历整个矩阵。实际上,我们可以在递归计算子问题时将子矩阵的结果直接传递到合并函数中,这样可以避免重复计算,从而将时间复杂度优化到O(n^2.81)。感兴趣的读者可以自行了解 Strassen 算法的实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值