func Multiply(A *matrix.Matrix, B *matrix.Matrix) *matrix.Matrix { n := A.CountRows() bigN := scaleSize(n) bigA := matrix.MakeMatrix(make([]float64, bigN*bigN), bigN, bigN) bigB := matrix.MakeMatrix(make([]float64, bigN*bigN), bigN, bigN) for i := 0; i < n; i++ { for j := 0; j < n; j++ { bigA.SetElm(i, j, A.GetElm(i, j)) bigB.SetElm(i, j, B.GetElm(i, j)) } } bigC := recurse(bigA, bigB) C := matrix.MakeMatrix(make([]float64, n*n), n, n) for i := 0; i < n; i++ { for j := 0; j < n; j++ { C.SetElm(i, j, bigC.GetElm(i, j)) } } return C }
func BenchmarkStrassen(b *testing.B) { a := make([]float64, 100000000, 100000000) c := make([]float64, 100000000, 100000000) for i := 0; i < 100000000; i++ { a[i] = float64(i) c[i] = float64(100000000 - i) } A := matrix.MakeMatrix(a, 10000, 10000) B := matrix.MakeMatrix(c, 10000, 10000) for i := 0; i < b.N; i++ { Multiply(A, B) } }
func TestStrassen(t *testing.T) { A := matrix.MakeMatrix([]float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, 4, 4) B := matrix.MakeMatrix([]float64{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, 4, 4) C := Multiply(A, B) D := matrix.Multiply(A, B) if !FloatArrayEquals(C.Elements, D.Elements) { t.Error() } A = matrix.MakeMatrix([]float64{1, 1, 1, 1}, 2, 2) B = matrix.MakeMatrix([]float64{1, 1, 1, 1}, 2, 2) C = Multiply(A, B) D = matrix.Multiply(A, B) if !FloatArrayEquals(C.Elements, D.Elements) { t.Error() } A = matrix.MakeMatrix([]float64{1, 1, 1, 1, 1, 1, 1, 1, 1}, 3, 3) B = matrix.MakeMatrix([]float64{1, 1, 1, 1, 1, 1, 1, 1, 1}, 3, 3) C = Multiply(A, B) D = matrix.Multiply(A, B) if !FloatArrayEquals(C.Elements, D.Elements) { t.Error() } }
func recurse(A *matrix.Matrix, B *matrix.Matrix) *matrix.Matrix { n := A.CountRows() newSize := n / 2 if n < 2 { return matrix.MakeMatrix([]float64{A.GetElm(0, 0) * B.GetElm(0, 0)}, 1, 1) } A11 := matrix.MakeMatrix(make([]float64, newSize*newSize), newSize, newSize) A12 := matrix.MakeMatrix(make([]float64, newSize*newSize), newSize, newSize) A21 := matrix.MakeMatrix(make([]float64, newSize*newSize), newSize, newSize) A22 := matrix.MakeMatrix(make([]float64, newSize*newSize), newSize, newSize) B11 := matrix.MakeMatrix(make([]float64, newSize*newSize), newSize, newSize) B12 := matrix.MakeMatrix(make([]float64, newSize*newSize), newSize, newSize) B21 := matrix.MakeMatrix(make([]float64, newSize*newSize), newSize, newSize) B22 := matrix.MakeMatrix(make([]float64, newSize*newSize), newSize, newSize) for i := 0; i < newSize; i++ { for j := 0; j < newSize; j++ { A11.SetElm(i, j, A.GetElm(i, j)) A12.SetElm(i, j, A.GetElm(i, j+newSize)) A21.SetElm(i, j, A.GetElm(i+newSize, j)) A22.SetElm(i, j, A.GetElm(i+newSize, j+newSize)) B11.SetElm(i, j, B.GetElm(i, j)) B12.SetElm(i, j, B.GetElm(i, j+newSize)) B21.SetElm(i, j, B.GetElm(i+newSize, j)) B22.SetElm(i, j, B.GetElm(i+newSize, j+newSize)) } } a := matrix.MakeMatrix(make([]float64, newSize*newSize), newSize, newSize) b := matrix.MakeMatrix(make([]float64, newSize*newSize), newSize, newSize) // P1 = (A11 + A22) * (B11 + B22) a = matrix.Add(A11, A22) b = matrix.Add(B11, B22) P1 := recurse(a, b) // P2 = (A21 + A22) * (B11) a = matrix.Add(A21, A22) P2 := recurse(a, B11) // P3 = (A11) * (B12 - B11) b = matrix.Substract(B12, B22) P3 := recurse(A11, b) // P4 = A22 * (B21 - B22) b = matrix.Substract(B21, B11) P4 := recurse(A22, b) // P5 = (A11 + A12) * B22 a = matrix.Add(A11, A12) P5 := recurse(a, B22) // P6 = (A21 - A11) * (B11 + B12) a = matrix.Substract(A21, A11) b = matrix.Add(B11, B12) P6 := recurse(a, b) // P7 = (A12 - A22) * (B21 + B22) a = matrix.Substract(A12, A22) b = matrix.Add(B21, B22) P7 := recurse(a, b) // Aggregates the result into C C12 := matrix.Add(P3, P5) C21 := matrix.Add(P2, P4) a = matrix.Add(P1, P4) b = matrix.Add(a, P7) C11 := matrix.Substract(b, P5) a = matrix.Add(P1, P3) b = matrix.Add(a, P6) C22 := matrix.Substract(b, P2) C := matrix.MakeMatrix(make([]float64, n*n), n, n) for i := 0; i < newSize; i++ { for j := 0; j < newSize; j++ { C.SetElm(i, j, C11.GetElm(i, j)) C.SetElm(i, j+newSize, C12.GetElm(i, j)) C.SetElm(i+newSize, j, C21.GetElm(i, j)) C.SetElm(i+newSize, j+newSize, C22.GetElm(i, j)) } } return C }