Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implement Matrix , its Methods and Some Functions including Strassen Matrix Multiplication in Go #662

Merged
merged 20 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
6a9aa2c
feat: Implement Strassen Matrix Multiplication
mohit07raghav19 Sep 30, 2023
b6fa85e
This commit introduces the Strassen matrix multiplication algorithm
mohit07raghav19 Oct 2, 2023
bcc7475
refactor: Rename functions and add implement new functionality
mohit07raghav19 Oct 3, 2023
400e75a
Implement Matrix as a struct type
mohit07raghav19 Oct 4, 2023
b1e4e01
Implement StrassenMatrixMultiply and Matrix Methods
mohit07raghav19 Oct 4, 2023
24fe1a6
Refactor to Use Value Type `Matrix` and Add Benchmarks
mohit07raghav19 Oct 5, 2023
7923f0b
Fixed Golang CI lint errors for file copy_test.go & submatrix_test.go
mohit07raghav19 Oct 6, 2023
f810d01
Merge branch 'TheAlgorithms:master' into master
mohit07raghav19 Oct 11, 2023
3fab688
refactor: Change type variable T to constraints.Integer, rename SameD…
mohit07raghav19 Oct 11, 2023
4d67ed9
refractor: Implement goroutines in Add, CheckEqual, Copy, New, Multip…
mohit07raghav19 Oct 11, 2023
910bb85
Merge branch 'TheAlgorithms:master' into master
mohit07raghav19 Oct 14, 2023
20bb9ee
refractor : Handled error in StrassenMatrixMultiply method instead of…
mohit07raghav19 Oct 14, 2023
dec410b
refractor : Handle errors gracefully by returning an error message in…
mohit07raghav19 Oct 16, 2023
a7e43d2
refractor : Updated the 'copy' function to return an empty matrix if …
mohit07raghav19 Oct 16, 2023
cabf07b
Merge branch 'TheAlgorithms:master' into master
mohit07raghav19 Oct 25, 2023
3c787c7
Updated Documentation in README.md
Oct 25, 2023
fc232f2
refactor: matrix operations to use context and sync packages
mohit07raghav19 Oct 25, 2023
382b49f
refactor: matrix operations to use context and sync packages
mohit07raghav19 Oct 25, 2023
51206f7
Updated Documentation in README.md
Oct 25, 2023
24dcb8f
chore: Add empty commit to trigger actions
mohit07raghav19 Oct 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions math/matrix/addmatrices.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package matrix

import (
"errors"

"github.com/TheAlgorithms/Go/constraints"
)

type Number interface {
mohit07raghav19 marked this conversation as resolved.
Show resolved Hide resolved
constraints.Integer
}

func AddMatrices[T Number](matrix1, matrix2 [][]T) ([][]T, error) {
// Check if the matrices have the same dimensions.
if len(matrix1) != len(matrix2) || len(matrix1[0]) != len(matrix2[0]) {
return nil, errors.New("matrices are not compatible for addition")
}

result := make([][]T, len(matrix1))
for i := range result {
result[i] = make([]T, len(matrix1[i]))
for j := range result[i] {
result[i][j] = matrix1[i][j] + matrix2[i][j]
}
}
return result, nil
}
70 changes: 70 additions & 0 deletions math/matrix/addmatrices_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package matrix_test

import (
"reflect"
"testing"

"github.com/TheAlgorithms/Go/math/matrix"
)

func TestAddMatricesInt(t *testing.T) {
matrix1 := [][]int{
{1, 2, 3},
{4, 5, 6},
}

matrix2 := [][]int{
{7, 8, 9},
{10, 11, 12},
}

expectedResult := [][]int{
{8, 10, 12},
{14, 16, 18},
}

result, err := matrix.AddMatrices(matrix1, matrix2)
if err != nil {
t.Errorf("Error: %v", err)
}

if !reflect.DeepEqual(result, expectedResult) {
t.Errorf("Result matrix does not match the expected result.")
}
// null matrix test
matrix3 := [][]int{{}}

matrix4 := [][]int{{}}

expectedResult1 := [][]int{{}}

result1, err1 := matrix.AddMatrices(matrix3, matrix4)
if err != nil {
t.Errorf("Error: %v", err1)
}

if !reflect.DeepEqual(result1, expectedResult1) {
t.Errorf("Result matrix does not match the expected result.")
}
}

func TestAddMatricesIncompatibleDimensions(t *testing.T) {
matrix1 := [][]int{
{1, 2},
{3, 4},
}

matrix2 := [][]int{
{1, 2, 3},
{4, 5, 6},
}

result, err := matrix.AddMatrices(matrix1, matrix2)
if err == nil {
t.Error("Expected an error for incompatible matrix dimensions, but got nil.")
}

if result != nil {
t.Error("Result matrix should be nil when dimensions are incompatible.")
}
}
15 changes: 15 additions & 0 deletions math/matrix/equalmatrix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package matrix

func MatrixEqual[T comparable](mat1, mat2 [][]T) bool {
mohit07raghav19 marked this conversation as resolved.
Show resolved Hide resolved
if len(mat1) != len(mat2) || len(mat1[0]) != len(mat2[0]) {
return false
}
for i := range mat1 {
for j := range mat1[i] {
if mat1[i][j] != mat2[i][j] {
return false
}
}
}
return true
}
94 changes: 94 additions & 0 deletions math/matrix/equalmatrix_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package matrix_test

import (
"testing"

"github.com/TheAlgorithms/Go/math/matrix"
)

func TestMatrixEqual(t *testing.T) {
// Test case with equal matrices
t.Run("Equal Null Matrices", func(t *testing.T) {
mat1 := [][]int{{}}
mat2 := [][]int{{}}

if !matrix.MatrixEqual(mat1, mat2) {
t.Errorf("Expected matrices to be equal, but they are not")
}
})
// Test case with equal matrices
t.Run("Equal Matrices", func(t *testing.T) {
mat1 := [][]int{{1, 2}, {3, 4}}
mat2 := [][]int{{1, 2}, {3, 4}}

if !matrix.MatrixEqual(mat1, mat2) {
t.Errorf("Expected matrices to be equal, but they are not")
}
})

// Test case with matrices of different dimensions
t.Run("Different Dimensions", func(t *testing.T) {
mat1 := [][]int{{1, 2}, {3, 4}}
mat2 := [][]int{{1, 2, 3}, {4, 5, 6}}

if matrix.MatrixEqual(mat1, mat2) {
t.Errorf("Expected matrices to have different dimensions, but they are equal")
}
})

// Test case with matrices that are not equal
t.Run("Different Matrices", func(t *testing.T) {
mat1 := [][]int{{1, 2}, {3, 4}}
mat2 := [][]int{{1, 2}, {5, 6}}

if matrix.MatrixEqual(mat1, mat2) {
t.Errorf("Expected matrices to be different, but they are equal")
}
})
// Test case with equal matrices of type bool
t.Run("Equal Bool Matrices", func(t *testing.T) {
mat1 := [][]bool{{true, false}, {false, true}}
mat2 := [][]bool{{true, false}, {false, true}}

if !matrix.MatrixEqual(mat1, mat2) {
t.Errorf("Expected matrices to be equal, but they are not")
}
})

// Test case with equal matrices of type string
t.Run("Equal String Matrices", func(t *testing.T) {
mat1 := [][]string{{"apple", "banana"}, {"cherry", "date"}}
mat2 := [][]string{{"apple", "banana"}, {"cherry", "date"}}

if !matrix.MatrixEqual(mat1, mat2) {
t.Errorf("Expected matrices to be equal, but they are not")
}
})
// Test case with unequal matrices of type string
t.Run("Different string Matrices", func(t *testing.T) {
mat1 := [][]string{{"apple", "banana"}, {"cherry", "date"}}
mat2 := [][]string{{"Apple", "BanAna"}, {"cHerry", "dAte"}}

if matrix.MatrixEqual(mat1, mat2) {
t.Errorf("Expected matrices to be different, but they are equal")
}
})
// Test case with equal matrices of type float64
t.Run("Equal Float Matrices", func(t *testing.T) {
mat1 := [][]float64{{1.1, 2.2}, {3.3, 4.4}}
mat2 := [][]float64{{1.1, 2.2}, {3.3, 4.4}}

if !matrix.MatrixEqual(mat1, mat2) {
t.Errorf("Expected matrices to be equal, but they are not")
}
})
// Test case with unequal matrices of type float64
t.Run("Different Float Matrices", func(t *testing.T) {
mat1 := [][]float64{{1.1, 2.2}, {3.3, 4.4}}
mat2 := [][]float64{{3.3, 2.2, 3.3}, {3.3, 4.4, 5.5}}

if matrix.MatrixEqual(mat1, mat2) {
t.Errorf("Expected matrices to be different, but they are equal")
}
})
}
34 changes: 34 additions & 0 deletions math/matrix/matrixmultiply.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package matrix

import (
"errors"
)

// MultiplyMatrices multiplies two matrices of compatible types.
func MultiplyMatrices[T Number](matrix1, matrix2 [][]T) ([][]T, error) {
// Check if the matrices are compatible for multiplication.
if len(matrix1[0]) == len(matrix2[0]) && len(matrix1[0]) == 0 {
return make([][]T, len(matrix1)), nil
}
if len(matrix1[0]) != len(matrix2) {
return nil, errors.New("matrices are not compatible for multiplication")
}

// Create the result matrix with appropriate dimensions.
result := make([][]T, len(matrix1))
for i := range result {
result[i] = make([]T, len(matrix2[0]))
}

// Perform matrix multiplication.
for i := 0; i < len(matrix1); i++ {
for j := 0; j < len(matrix2[0]); j++ {
var sum T
for k := 0; k < len(matrix2); k++ {
sum += matrix1[i][k] * matrix2[k][j]
}
result[i][j] = sum
}
}
return result, nil
}
65 changes: 65 additions & 0 deletions math/matrix/matrixmultiply_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package matrix_test

import (
"testing"

"github.com/TheAlgorithms/Go/math/matrix"
)

func TestMultiplyMatrix(t *testing.T) {
// Test case with compatible NULL matrices
t.Run("NULL Matrices", func(t *testing.T) {
mat1 := [][]int{{}}
mat2 := [][]int{{}}

result, err := matrix.MultiplyMatrices(mat1, mat2)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}

expected := [][]int{{}}
if !matrix.MatrixEqual(result, expected) {
t.Errorf("Expected %v, got %v", expected, result)
}
})
// Test case with compatible matrices
t.Run("Compatible Matrices", func(t *testing.T) {
mat1 := [][]int{{1, 2, 3}, {4, 5, 6}}
mat2 := [][]int{{7, 8}, {9, 10}, {11, 12}}

result, err := matrix.MultiplyMatrices(mat1, mat2)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}

expected := [][]int{{58, 64}, {139, 154}}
if !matrix.MatrixEqual(result, expected) {
t.Errorf("Expected %v, got %v", expected, result)
}
})


Check failure on line 41 in math/matrix/matrixmultiply_test.go

View workflow job for this annotation

GitHub Actions / Code style and tests

File is not `gofmt`-ed with `-s` (gofmt)
}

func TestMultiplyIncompatibleMatrix(t *testing.T) {
// Test case with incompatible matrices
t.Run("Incompatible Matrices", func(t *testing.T) {
mat1 := [][]int{{1, 2, 3}, {4, 5, 6}}
mat2 := [][]int{{7, 8}, {9, 10}}

_, err := matrix.MultiplyMatrices(mat1, mat2)
if err == nil {
t.Error("Expected an error, but got none")
}
})

t.Run("Incompatible Matrices", func(t *testing.T) {
mat1 := [][]int{{1, 2}}
mat2 := [][]int{{}}

_, err := matrix.MultiplyMatrices(mat1, mat2)
if err == nil {
t.Error("Expected an error, but got none")
}
})
}
30 changes: 30 additions & 0 deletions math/matrix/printmatrix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package matrix

import (
"fmt"
"reflect"
)

// PrintMatrix prints a 2D matrix of any type.
func PrintMatrix(matrix interface{}) {
mohit07raghav19 marked this conversation as resolved.
Show resolved Hide resolved
value := reflect.ValueOf(matrix)

if value.Kind() != reflect.Slice {
fmt.Println("Input is not a matrix.")
return
}

for i := 0; i < value.Len(); i++ {
row := value.Index(i)
if row.Kind() != reflect.Slice {
fmt.Println("Invalid matrix structure.")
return
}

for j := 0; j < row.Len(); j++ {
element := row.Index(j)
fmt.Printf("%v ", element.Interface())
}
fmt.Println()
}
}
39 changes: 39 additions & 0 deletions math/matrix/printmatrix_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package matrix_test

import (
"testing"

"github.com/TheAlgorithms/Go/math/matrix"
)

func TestPrintMatrix(t *testing.T) {
type args struct {
matrix interface{}
}
tests := []struct {
name string
args args
}{
{name: "1", args: args{matrix: [][]string{
{"apple", "banana", "cherry"},
{"dog", "elephant", "fox"},
}},
}, {name: "2", args: args{matrix: [][]int{
{1, 2, 3},
{4, 5, 6},
}},
}, {name: "3", args: args{matrix: [][]float32{
{12.3, 12.2},
}},
}, {name: "4", args: args{matrix: [][]bool{
{true, false},
{false, false},
{true, false},
}},
}, {name: "5", args: args{matrix: [][]int16{}}}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
matrix.PrintMatrix(tt.args.matrix)
})
}
}
Loading
Loading