Fortunately, when I studied Strassen for multiplication there was on the book an interesting conclusion: With this “fast” matrix multiplication, Strassen also obtained a surprising result for matrix inversion.
This very intriguing phrase bring me to the following formula:
R1 = Inverse(a11)
R2 = a21 x R1
R3 = R1 x a12
R4 = a21 x R3
R5 = R4 - a22
R6 = Inverse(R5)
c12 = R3 x R6
c21 = R6 x R2
R7 = R3 x c21
c11 = R1 - R7
c22 = -R6
So what I learned was that it is possible to obtain the matrix (multiple of 2^n) inversion from some “lighter” operations. I implemented this algorithm and compared it with the Gauss Jordan one.
Comparing those two algorithms, I obtained, using my notebook, these results:
Matrices 512x512 of Complex (double, double)
GJ; 24sec
Strassen: 19sec
20% time less
Matrices 1024x1024 of Complex (double, double)
GJ; 3min 02sec
Strassen: 2min 05sec
38% time less!
Used Invertion Methods
Gauss Jordan LU decomposition
public static Complex[,] GaussJordanInvertion(Complex[,] mat, BackgroundWorker bw = null) { //Gestione notifica progressione int iPerc = 0; int iMax = mat.GetLength(0); int iDone = 0; Complex[,] res; res = MatrixGeneric.Create<complex>(iMax); res = (Complex[,])mat.Clone(); int[,] indxc; indxc = MatrixGeneric.Create<int>(iMax, true); int[,] indxr; indxr = MatrixGeneric.Create<int>(iMax, true); int[,] ipiv; ipiv = MatrixGeneric.Create<int>(iMax, true); Complex big; Complex pivinv; Complex dum; int iRow = 1; int iCol = 1; for (int i = 1; i <= iMax; i++) ipiv[i, 1] = 0; for (int i = 1; i <= iMax; i++) { big = 0; for (int j = 1; j <= iMax; j++) if (ipiv[j, 1] != 1) for (int k = 1; k <= iMax; k++) { if (ipiv[k, 1] == 0) { if (Complex.Abs(res[j, k]) >= Complex.Abs(big)) { big = Complex.Abs(res[j, k]); iRow = j; iCol = k; } } else if (ipiv[k, 1] > 1) { //Error "Singular Matrix -1" } } ++(ipiv[iCol, 1]); if (iRow != iCol) { for (int l = 1; l <= iMax; l++) Swap(res[iRow, l], res[iCol, l]); } indxr[i, 1] = iRow; indxc[i, 1] = iCol; if (res[iCol, iCol] == 0) { //Error "Singular Matrix -2" } pivinv = 1 / res[iCol, iCol]; res[iCol, iCol] = 1; for (int l = 1; l <= iMax; l++) res[iCol, l] = res[iCol, l] * pivinv; for (int ll = 1; ll <= iMax; ll++) if (ll != iCol) { dum = res[ll, iCol]; res[ll, iCol] = 0; for (int l = 1; l <= iMax; l++) { res[ll, l] = res[ll, l] - res[iCol, l] * dum; } } } for (int l = iMax; l > 0; l--) { if (indxr[l, 1] != indxc[l, 1]) for (int k = 1; k <= iMax; k++) Swap(res[k, indxr[l, 1]], res[k, indxc[l, 1]]); } return res; }
Strassen
public static Complex[,] Inverse(Complex[,] a, int iThreshold = 128) { int iOriginalSize = a.GetLength(0); int iFmtSize = GetSize(a.GetLength(0)); Complex[,] A = a; int iSize = A.GetLength(0); int iHalfSize = iSize / 2; if (iSize <= iThreshold) { return GaussJordanInvertion(a); } Complex[,] A11 = null; Complex[,] A12 = null; Complex[,] A21 = null; Complex[,] A22 = null; Complex[,] R1 = null; Complex[,] R2 = null; Complex[,] R3 = null; Complex[,] R4 = null; Complex[,] R5 = null; Complex[,] R6 = null; Complex[,] R7 = null; Complex[,] C11 = null; Complex[,] C12 = null; Complex[,] C21 = null; Complex[,] C22 = null; A11 = GetMatrixPortion(A, iHalfSize, 1, 1); R1 = Inverse(A11); A21 = GetMatrixPortion(A, iHalfSize, iHalfSize + 1, 1); R2 = Mul_Strassen(A21, R1, iThreshold); A12 = GetMatrixPortion(A, iHalfSize, 1, iHalfSize + 1); R3 = Mul_Strassen(R1, A12, iThreshold); R4 = Mul_Strassen(A21, R3, iThreshold); A22 = GetMatrixPortion(A, iHalfSize, iHalfSize + 1, iHalfSize + 1); R5 = Subtract(R4, A22); R6 = Inverse(R5); C12 = Mul_Strassen(R3, R6, iThreshold); C21 = Mul_Strassen(R6, R2, iThreshold); R7 = Mul_Strassen(R3, C21, iThreshold); C11 = Subtract(R1, R7); C22 = Multiply(R6, -1); Complex[,] c = MatrixGeneric.Create<complex>(iSize, iSize); for (int i = 1; i <= iHalfSize; i++) { for (int j = 1; j <= iHalfSize; j++) { c[i, j] = C11[i, j]; c[i, j + iHalfSize] = C12[i, j]; c[i + iHalfSize, j] = C21[i, j]; c[i + iHalfSize, j + iHalfSize] = C22[i, j]; } } A11 = null; A12 = null; A21 = null; A22 = null; R1 = null; R2 = null; R3 = null; R4 = null; R5 = null; R6 = null; R7 = null; C11 = null; C12 = null; C21 = null; C22 = null; GC.Collect(); return c; }
Remember that the input matrix shoud be a 2^n multiple, if not! complete it with 0 and 1 on the diagonal.
No comments :
Post a Comment