Mat2 and Mat3 determinant and inverse matrices

This commit is contained in:
bloeys
2024-05-04 04:49:27 +04:00
parent 41307a8c5b
commit ca55a67100
4 changed files with 182 additions and 1 deletions

View File

@ -84,7 +84,6 @@ func (m *Mat2) Eq(m2 *Mat2) bool {
} }
func (m *Mat2) Transpose() *Mat2 { func (m *Mat2) Transpose() *Mat2 {
m.Data = [2][2]float32{ m.Data = [2][2]float32{
{m.Data[0][0], m.Data[1][0]}, {m.Data[0][0], m.Data[1][0]},
{m.Data[0][1], m.Data[1][1]}, {m.Data[0][1], m.Data[1][1]},
@ -93,6 +92,27 @@ func (m *Mat2) Transpose() *Mat2 {
return m return m
} }
func (m *Mat2) Determinant() float32 {
return (m.Data[0][0] * m.Data[1][1]) - (m.Data[0][1] * m.Data[1][0])
}
// Invert inverts this matrix.
//
// Note that the inverse is not defined if the determinant is zero or extremely small.
// In the case the determinant is zero the matrix will (usually) get filled with infinities
func (m *Mat2) Invert() *Mat2 {
// https://www.cuemath.com/algebra/inverse-of-2x2-matrix/
inverseDet := 1 / m.Determinant()
m.Data = [2][2]float32{
{m.Data[1][1] * inverseDet, -m.Data[0][1] * inverseDet}, // Col0
{-m.Data[1][0] * inverseDet, m.Data[0][0] * inverseDet}, // Col1
}
return m
}
// AddMat2 m3 = m1 + m2 // AddMat2 m3 = m1 + m2
func AddMat2(m1, m2 *Mat2) *Mat2 { func AddMat2(m1, m2 *Mat2) *Mat2 {
return &Mat2{ return &Mat2{

View File

@ -179,6 +179,56 @@ func TestTransposeMat2(t *testing.T) {
} }
} }
func TestDeterminantMat2(t *testing.T) {
m := gglm.NewMat2Id()
ans := float32(1)
if m.Determinant() != ans {
t.Errorf("Got: %f; Expected: %f", m.Determinant(), ans)
}
m = &gglm.Mat2{
Data: [2][2]float32{
{1, 8},
{5, 31},
},
}
ans = -9
if m.Determinant() != ans {
t.Errorf("Got: %f; Expected: %f", m.Determinant(), ans)
}
}
func TestInverseMat2(t *testing.T) {
m := gglm.NewMat2Id()
ans := gglm.NewMat2Id()
if !m.Invert().Eq(ans) {
t.Errorf("Got: %v; Expected: %v", m.String(), ans.String())
}
m = &gglm.Mat2{
Data: [2][2]float32{
{1, 8},
{5, 31},
},
}
ans = &gglm.Mat2{
Data: [2][2]float32{
{-31 / 9.0, 8 / 9.0},
{5 / 9.0, -1 / 9.0},
},
}
if !m.Invert().Eq(ans) {
t.Errorf("Got: %v; Expected: %v", m.String(), ans.String())
}
}
func BenchmarkMulMat2(b *testing.B) { func BenchmarkMulMat2(b *testing.B) {
m1 := gglm.NewMat2Id() m1 := gglm.NewMat2Id()

View File

@ -145,6 +145,64 @@ func (m *Mat3) Transpose() *Mat3 {
return m return m
} }
func (m *Mat3) Determinant() float32 {
x := m.Data[0][0] * (m.Data[1][1]*m.Data[2][2] - m.Data[2][1]*m.Data[1][2])
y := m.Data[1][0] * (m.Data[2][1]*m.Data[0][2] - m.Data[0][1]*m.Data[2][2])
z := m.Data[2][0] * (m.Data[0][1]*m.Data[1][2] - m.Data[1][1]*m.Data[0][2])
return x + y + z
}
// Invert inverts this matrix.
//
// Note that the inverse is not defined if the determinant is zero or extremely small.
// In the case the determinant is zero the matrix will (usually) get filled with infinities
func (m *Mat3) Invert() *Mat3 {
// https://www.cuemath.com/algebra/inverse-of-3x3-matrix/
// Manually inline the determinant function because go doesn't
x := m.Data[0][0] * (m.Data[1][1]*m.Data[2][2] - m.Data[2][1]*m.Data[1][2])
y := m.Data[1][0] * (m.Data[2][1]*m.Data[0][2] - m.Data[0][1]*m.Data[2][2])
z := m.Data[2][0] * (m.Data[0][1]*m.Data[1][2] - m.Data[1][1]*m.Data[0][2])
inverseDet := 1 / (x + y + z)
// Inverse[0][0] = + (m[1][1] * m[2][2] - m[2][1] * m[1][2]) * OneOverDeterminant;
// Inverse[1][0] = - (m[1][0] * m[2][2] - m[2][0] * m[1][2]) * OneOverDeterminant;
// Inverse[2][0] = + (m[1][0] * m[2][1] - m[2][0] * m[1][1]) * OneOverDeterminant;
// Inverse[0][1] = - (m[0][1] * m[2][2] - m[2][1] * m[0][2]) * OneOverDeterminant;
// Inverse[1][1] = + (m[0][0] * m[2][2] - m[2][0] * m[0][2]) * OneOverDeterminant;
// Inverse[2][1] = - (m[0][0] * m[2][1] - m[2][0] * m[0][1]) * OneOverDeterminant;
// Inverse[0][2] = + (m[0][1] * m[1][2] - m[1][1] * m[0][2]) * OneOverDeterminant;
// Inverse[1][2] = - (m[0][0] * m[1][2] - m[1][0] * m[0][2]) * OneOverDeterminant;
// Inverse[2][2] = + (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * OneOverDeterminant;
m.Data = [3][3]float32{
// Col0
{
(m.Data[1][1]*m.Data[2][2] - m.Data[2][1]*m.Data[1][2]) * inverseDet,
-(m.Data[0][1]*m.Data[2][2] - m.Data[2][1]*m.Data[0][2]) * inverseDet,
(m.Data[0][1]*m.Data[1][2] - m.Data[1][1]*m.Data[0][2]) * inverseDet,
},
// Col1
{
-(m.Data[1][0]*m.Data[2][2] - m.Data[2][0]*m.Data[1][2]) * inverseDet,
(m.Data[0][0]*m.Data[2][2] - m.Data[2][0]*m.Data[0][2]) * inverseDet,
-(m.Data[0][0]*m.Data[1][2] - m.Data[1][0]*m.Data[0][2]) * inverseDet,
},
// Col2
{
(m.Data[1][0]*m.Data[2][1] - m.Data[2][0]*m.Data[1][1]) * inverseDet,
-(m.Data[0][0]*m.Data[2][1] - m.Data[2][0]*m.Data[0][1]) * inverseDet,
(m.Data[0][0]*m.Data[1][1] - m.Data[1][0]*m.Data[0][1]) * inverseDet,
},
}
return m
}
// AddMat3 m3 = m1 + m2 // AddMat3 m3 = m1 + m2
func AddMat3(m1, m2 *Mat3) *Mat3 { func AddMat3(m1, m2 *Mat3) *Mat3 {
return &Mat3{ return &Mat3{

View File

@ -196,6 +196,59 @@ func TestTransposeMat3(t *testing.T) {
} }
} }
func TestDeterminantMat3(t *testing.T) {
m := gglm.NewMat3Id()
ans := float32(1)
if m.Determinant() != ans {
t.Errorf("Got: %f; Expected: %f", m.Determinant(), ans)
}
m = &gglm.Mat3{
Data: [3][3]float32{
{1, 8, 2},
{5, 3, 5},
{9, 6, 7},
},
}
ans = 77
if m.Determinant() != ans {
t.Errorf("Got: %f; Expected: %f", m.Determinant(), ans)
}
}
func TestInverseMat3(t *testing.T) {
m := gglm.NewMat3Id()
ans := gglm.NewMat3Id()
if !m.Invert().Eq(ans) {
t.Errorf("Got: %v; Expected: %v", m.String(), ans.String())
}
m = &gglm.Mat3{
Data: [3][3]float32{
{1, 8, 2},
{5, 3, 5},
{9, 6, 7},
},
}
ans = &gglm.Mat3{
Data: [3][3]float32{
{-9 / 77.0, -4 / 7.0, 34 / 77.0},
{10 / 77.0, -1 / 7.0, 5 / 77.0},
{3 / 77.0, 6 / 7.0, -37 / 77.0},
},
}
if !m.Invert().Eq(ans) {
t.Errorf("Got: %v; Expected: %v", m.String(), ans.String())
}
}
func BenchmarkMulMat3(b *testing.B) { func BenchmarkMulMat3(b *testing.B) {
m1 := gglm.NewMat3Id() m1 := gglm.NewMat3Id()