private static Matrix StrassenMultiply(Matrix A, Matrix B) // Smart matrix multiplication
{
if (A.cols != B.rows) throw new MException("Wrong dimension of matrix!");
Matrix R;
int msize = Math.Max(Math.Max(A.rows, A.cols), Math.Max(B.rows, B.cols));
if (msize < 32)
{
R = ZeroMatrix(A.rows, B.cols);
for (int i = 0; i < R.rows; i++)
for (int j = 0; j < R.cols; j++)
for (int k = 0; k < A.cols; k++)
R[i, j] += A[i, k] * B[k, j];
return R;
}
int size = 1; int n = 0;
while (msize > size) { size *= 2; n++; };
int h = size / 2;
Matrix[,] mField = new Matrix[n, 9];
/*
* 8x8, 8x8, 8x8, ...
* 4x4, 4x4, 4x4, ...
* 2x2, 2x2, 2x2, ...
* . . .
*/
int z;
for (int i = 0; i < n - 4; i++) // rows
{
z = (int)Math.Pow(2, n - i - 1);
for (int j = 0; j < 9; j++) mField[i, j] = new Matrix(z, z);
}
SafeAplusBintoC(A, 0, 0, A, h, h, mField[0, 0], h);
SafeAplusBintoC(B, 0, 0, B, h, h, mField[0, 1], h);
StrassenMultiplyRun(mField[0, 0], mField[0, 1], mField[0, 1 + 1], 1, mField); // (A11 + A22) * (B11 + B22);
SafeAplusBintoC(A, 0, h, A, h, h, mField[0, 0], h);
SafeACopytoC(B, 0, 0, mField[0, 1], h);
StrassenMultiplyRun(mField[0, 0], mField[0, 1], mField[0, 1 + 2], 1, mField); // (A21 + A22) * B11;
SafeACopytoC(A, 0, 0, mField[0, 0], h);
SafeAminusBintoC(B, h, 0, B, h, h, mField[0, 1], h);
StrassenMultiplyRun(mField[0, 0], mField[0, 1], mField[0, 1 + 3], 1, mField); //A11 * (B12 - B22);
SafeACopytoC(A, h, h, mField[0, 0], h);
SafeAminusBintoC(B, 0, h, B, 0, 0, mField[0, 1], h);
StrassenMultiplyRun(mField[0, 0], mField[0, 1], mField[0, 1 + 4], 1, mField); //A22 * (B21 - B11);
SafeAplusBintoC(A, 0, 0, A, h, 0, mField[0, 0], h);
SafeACopytoC(B, h, h, mField[0, 1], h);
StrassenMultiplyRun(mField[0, 0], mField[0, 1], mField[0, 1 + 5], 1, mField); //(A11 + A12) * B22;
SafeAminusBintoC(A, 0, h, A, 0, 0, mField[0, 0], h);
SafeAplusBintoC(B, 0, 0, B, h, 0, mField[0, 1], h);
StrassenMultiplyRun(mField[0, 0], mField[0, 1], mField[0, 1 + 6], 1, mField); //(A21 - A11) * (B11 + B12);
SafeAminusBintoC(A, h, 0, A, h, h, mField[0, 0], h);
SafeAplusBintoC(B, 0, h, B, h, h, mField[0, 1], h);
StrassenMultiplyRun(mField[0, 0], mField[0, 1], mField[0, 1 + 7], 1, mField); // (A12 - A22) * (B21 + B22);
R = new Matrix(A.rows, B.cols); // result
/// C11
for (int i = 0; i < Math.Min(h, R.rows); i++) // rows
for (int j = 0; j < Math.Min(h, R.cols); j++) // cols
R[i, j] = mField[0, 1 + 1][i, j] + mField[0, 1 + 4][i, j] - mField[0, 1 + 5][i, j] + mField[0, 1 + 7][i, j];
/// C12
for (int i = 0; i < Math.Min(h, R.rows); i++) // rows
for (int j = h; j < Math.Min(2 * h, R.cols); j++) // cols
R[i, j] = mField[0, 1 + 3][i, j - h] + mField[0, 1 + 5][i, j - h];
/// C21
for (int i = h; i < Math.Min(2 * h, R.rows); i++) // rows
for (int j = 0; j < Math.Min(h, R.cols); j++) // cols
R[i, j] = mField[0, 1 + 2][i - h, j] + mField[0, 1 + 4][i - h, j];
/// C22
for (int i = h; i < Math.Min(2 * h, R.rows); i++) // rows
for (int j = h; j < Math.Min(2 * h, R.cols); j++) // cols
R[i, j] = mField[0, 1 + 1][i - h, j - h] - mField[0, 1 + 2][i - h, j - h] + mField[0, 1 + 3][i - h, j - h] + mField[0, 1 + 6][i - h, j - h];
return R;
}