Skip to content

Commit 24c7f1f

Browse files
feat: add determinant implementation for matrix (#732)
* feat: add determinant implementation for matrix Added the Determinant method for the Matrix struct under math/matrix. This method returns the determinant of the matrix. * fix: determinant spelling and linting Fixed the spelling error in determinant.go. Fixed ineffectual error assignment in determinant_test.go. * test: add test for matrix determinant Added a test case for single-element matrix. --------- Co-authored-by: Rak Laptudirm <rak@laptudirm.com>
1 parent 662e8e9 commit 24c7f1f

File tree

2 files changed

+201
-0
lines changed

2 files changed

+201
-0
lines changed

math/matrix/determinant.go

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// determinant.go
2+
// description: This method finds the determinant of a matrix.
3+
// details: For a theoretical explanation as for what the determinant
4+
// represents, see the [Wikipedia Article](https://en.wikipedia.org/wiki/Determinant)
5+
// author [Carter907](https://github.com/Carter907)
6+
// see determinant_test.go
7+
8+
package matrix
9+
10+
import (
11+
"errors"
12+
)
13+
14+
// Calculates the determinant of the matrix.
15+
// This method only works for square matrices (e.i. matrices with equal rows and columns).
16+
func (mat Matrix[T]) Determinant() (T, error) {
17+
18+
var determinant T = 0
19+
var elements = mat.elements
20+
if mat.rows != mat.columns {
21+
22+
return 0, errors.New("Matrix rows and columns must equal in order to find the determinant.")
23+
}
24+
25+
// Specify base cases for different sized matrices.
26+
switch mat.rows {
27+
case 1:
28+
return elements[0][0], nil
29+
case 2:
30+
return elements[0][0]*elements[1][1] - elements[1][0]*elements[0][1], nil
31+
default:
32+
for i := 0; i < mat.rows; i++ {
33+
34+
var initialValue T = 0
35+
minor := New(mat.rows-1, mat.columns-1, initialValue)
36+
// Fill the contents of minor excluding the 0th row and the ith column.
37+
for j, minor_i := 1, 0; j < mat.rows && minor_i < minor.rows; j, minor_i = j+1, minor_i+1 {
38+
for k, minor_j := 0, 0; k < mat.rows && minor_j < minor.rows; k, minor_j = k+1, minor_j+1 {
39+
if k != i {
40+
minor.elements[minor_i][minor_j] = elements[j][k]
41+
} else {
42+
minor_j-- // Decrement the column of minor to account for skipping the ith column of the matrix.
43+
}
44+
}
45+
}
46+
47+
if i%2 == 0 {
48+
minor_det, _ := minor.Determinant()
49+
50+
determinant += elements[0][i] * minor_det
51+
} else {
52+
minor_det, _ := minor.Determinant()
53+
54+
determinant += elements[0][i] * minor_det
55+
}
56+
}
57+
return determinant, nil
58+
}
59+
}

math/matrix/determinant_test.go

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package matrix_test
2+
3+
import (
4+
"errors"
5+
"math"
6+
"math/rand"
7+
"testing"
8+
9+
"github.com/TheAlgorithms/Go/math/matrix"
10+
)
11+
12+
// Test different matrix contents
13+
func TestMatrixDeterminant(t *testing.T) {
14+
// Find Determinant of a 2 by 2 matrix.
15+
matrix1, err := matrix.NewFromElements([][]int{
16+
{3, 8},
17+
{4, 6},
18+
})
19+
if err != nil {
20+
t.Fatalf("Error creating 3 by 3 matrix: %v", err)
21+
}
22+
determinant, err := matrix1.Determinant()
23+
if err != nil {
24+
t.Fatalf("Error returned from 3 by 3 matrix: %v", err)
25+
}
26+
if determinant != -14 {
27+
t.Fatalf("Determinant returned for a 3 by 3 matrix was %d; wanted -14", determinant)
28+
}
29+
30+
// Find Dertminant of a 1 by 1 matrix
31+
expectedValue := rand.Intn(math.MaxInt)
32+
matrix2, err := matrix.NewFromElements([][]int{
33+
{expectedValue},
34+
})
35+
if err != nil {
36+
t.Fatalf("Error creating 1 by 1 matrix: %v", err)
37+
}
38+
determinant, err = matrix2.Determinant()
39+
if err != nil {
40+
t.Fatalf("Error returned from 1 by 1 matrix: %v", err)
41+
}
42+
if determinant != expectedValue {
43+
t.Fatalf("Determinant returned for a 1 by 1 matrix was %d; wanted %d", determinant, expectedValue)
44+
}
45+
46+
}
47+
48+
func TestEmptyMatrix(t *testing.T) {
49+
emptyElements := [][]int{}
50+
matrix, err := matrix.NewFromElements(emptyElements)
51+
52+
if err != nil {
53+
t.Fatalf("Error creating Matrix with empty elements: %v", err)
54+
}
55+
56+
determinant, err := matrix.Determinant()
57+
58+
if err != nil {
59+
t.Fatalf("Determinant returned an error for empty matrix: %v", err)
60+
}
61+
62+
// Check that 0 is returned from an empty matrix.
63+
expectedValue := 0
64+
if determinant != expectedValue {
65+
t.Errorf("Determinant returned from empty matrix was %d; wanted %d", determinant, expectedValue)
66+
}
67+
68+
}
69+
70+
func TestNonSquareMatrix(t *testing.T) {
71+
// Creating non-square matrix for testing.
72+
initialValue := 0
73+
initialRows := 4
74+
initialCols := 2
75+
76+
nonSquareMatrix := matrix.New(initialRows, initialCols, initialValue)
77+
78+
determinant, err := nonSquareMatrix.Determinant()
79+
// Check if non square matrix returns an error.
80+
if err == nil {
81+
t.Fatalf("No error was returned for a non-square matrix")
82+
}
83+
84+
// Check if the correct error was returned.
85+
expectedError := errors.New("Matrix rows and columns must equal in order to find the determinant.")
86+
87+
if err.Error() != expectedError.Error() {
88+
t.Errorf("Error returned from non-square matrix was \n\"%v\"; \nwanted \n\"%v\"", err, expectedError)
89+
}
90+
91+
// Check if the determinant of the non-square matrix is 0.
92+
if determinant != 0 {
93+
t.Errorf("Determinant of non-square matrix was not 0 but was %d", determinant)
94+
}
95+
96+
}
97+
98+
// Test matrix returned from matrix.New
99+
func TestDefaultMatrix(t *testing.T) {
100+
initialValue := 0
101+
initialRows := 3
102+
initialCols := 3
103+
defaultMatrix := matrix.New(initialRows, initialCols, initialValue)
104+
105+
determinant, err := defaultMatrix.Determinant()
106+
107+
if err != nil {
108+
t.Fatalf("Error finding the determinant of 3 by 3 default matrix: %v.", err)
109+
}
110+
expectedValue := 0
111+
if determinant != expectedValue {
112+
t.Errorf("Determinant of the default matrix with an initial value 0 was %d; wanted %d.", initialValue, expectedValue)
113+
}
114+
}
115+
116+
// Benchmark a 3 by 3 matrix for computational throughput
117+
func BenchmarkSmallMatrixDeterminant(b *testing.B) {
118+
// Create a 3 by 3 matrix for benchmarking
119+
rows := 3
120+
columns := 3
121+
initialValue := 0
122+
matrix := matrix.New(rows, columns, initialValue)
123+
124+
for i := 0; i < b.N; i++ {
125+
_, _ = matrix.Determinant()
126+
}
127+
}
128+
129+
// Benchmark a 10 by 10 matrix for computational throughput.
130+
func BenchmarkMatrixDeterminant(b *testing.B) {
131+
// Create a 10 by 10 matrix for benchmarking
132+
rows := 10
133+
columns := 10
134+
initialValue := 0
135+
matrix := matrix.New(rows, columns, initialValue)
136+
137+
b.ResetTimer()
138+
139+
for i := 0; i < b.N; i++ {
140+
_, _ = matrix.Determinant()
141+
}
142+
}

0 commit comments

Comments
 (0)