func (mat *MatMxN) ApproxEqual(m2 *MatMxN) bool {
	if mat == m2 {
		return true
	}
	if mat.m != m2.m || mat.n != m2.n {
		return false
	}
	for i, el := range mat.dat {
		if !FloatEqual(el, m2.dat[i]) {
			return false
		}
	}
	return true
}
ApproxEqual returns whether the two vectors are approximately equal (See
FloatEqual).
package mgl32
import (
	"math"
)
type MatMxN struct {
	m, n int
	dat  []float32
}
func NewMatrix(m, n int) (mat *MatMxN) {
	if shouldPool {
		return &MatMxN{m: m, n: n, dat: grabFromPool(m * n)}
	} else {
		return &MatMxN{m: m, n: n, dat: make([]float32, m*n)}
	}
}
func NewMatrixFromData(src []float32, m, n int) *MatMxN {
	var internal []float32
	if shouldPool {
		internal = grabFromPool(m * n)
	} else {
		internal = make([]float32, m*n)
	}
	copy(internal, src[:m*n])
	return &MatMxN{m: m, n: n, dat: internal}
}
func CopyMatMN(dst, src *MatMxN) {
	if dst == nil || src == nil {
		return
	}
	dst.Reshape(src.m, src.n)
	copy(dst.dat, src.dat)
}
func IdentN(dst *MatMxN, n int) *MatMxN {
	dst = dst.Reshape(n, n)
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			if i == j {
				dst.Set(i, j, 1)
			} else {
				dst.Set(i, j, 0)
			}
		}
	}
	return dst
}
func DiagN(dst *MatMxN, diag *VecN) *MatMxN {
	dst = dst.Reshape(len(diag.vec), len(diag.vec))
	n := len(diag.vec)
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			if i == j {
				dst.Set(i, j, diag.vec[i])
			} else {
				dst.Set(i, j, 0)
			}
		}
	}
	return dst
}
func (mat *MatMxN) Zero(m, n int) {
	if mat == nil {
		return
	}
	mat.Reshape(m, n)
	for i := range mat.dat {
		mat.dat[i] = 0
	}
}
func (mat *MatMxN) destroy() {
	if mat == nil {
		return
	}
	if shouldPool && mat.dat != nil {
		returnToPool(mat.dat)
	}
	mat.m, mat.n = 0, 0
	mat.dat = nil
}
func (mat *MatMxN) Reshape(m, n int) *MatMxN {
	if mat == nil {
		return NewMatrix(m, n)
	}
	if m*n <= cap(mat.dat) {
		if mat.dat != nil {
			mat.dat = mat.dat[:m*n]
		} else {
			mat.dat = []float32{}
		}
		mat.m, mat.n = m, n
		return mat
	}
	if shouldPool && mat.dat != nil {
		returnToPool(mat.dat)
	}
	(*mat) = (*NewMatrix(m, n))
	return mat
}
func (mat *MatMxN) InferMatrix(m interface{}) (*MatMxN, error) {
	switch raw := m.(type) {
	case Mat2:
		return NewMatrixFromData(raw[:], 2, 2), nil
	case Mat2x3:
		return NewMatrixFromData(raw[:], 2, 3), nil
	case Mat2x4:
		return NewMatrixFromData(raw[:], 2, 4), nil
	case Mat3:
		return NewMatrixFromData(raw[:], 3, 3), nil
	case Mat3x2:
		return NewMatrixFromData(raw[:], 3, 2), nil
	case Mat3x4:
		return NewMatrixFromData(raw[:], 3, 4), nil
	case Mat4:
		return NewMatrixFromData(raw[:], 4, 4), nil
	case Mat4x2:
		return NewMatrixFromData(raw[:], 4, 2), nil
	case Mat4x3:
		return NewMatrixFromData(raw[:], 4, 3), nil
	default:
		return nil, InferMatrixError{}
	}
}
func (mat *MatMxN) Trace() float32 {
	if mat == nil || mat.m != mat.n {
		return float32(math.NaN())
	}
	var out float32
	for i := 0; i < mat.m; i++ {
		out += mat.At(i, i)
	}
	return out
}
func (mat *MatMxN) Transpose(dst *MatMxN) (t *MatMxN) {
	if mat == nil {
		return nil
	}
	if dst == mat {
		dst = NewMatrix(mat.n, mat.m)
		defer func() {
			copy(mat.dat, dst.dat)
			mat.m, mat.n = mat.n, mat.m
			dst.destroy()
			t = mat
		}()
		return mat
	} else {
		dst = dst.Reshape(mat.n, mat.m)
	}
	for r := 0; r < mat.m; r++ {
		for c := 0; c < mat.n; c++ {
			dst.dat[r*dst.m+c] = mat.dat[c*mat.m+r]
		}
	}
	return dst
}
func (mat *MatMxN) Raw() []float32 {
	if mat == nil {
		return nil
	}
	return mat.dat
}
func (mat *MatMxN) NumRows() int {
	return mat.m
}
func (mat *MatMxN) NumCols() int {
	return mat.n
}
func (mat *MatMxN) NumRowCols() (rows, cols int) {
	return mat.m, mat.n
}
func (mat *MatMxN) At(row, col int) float32 {
	return mat.dat[col*mat.m+row]
}
func (mat *MatMxN) Set(row, col int, val float32) {
	mat.dat[col*mat.m+row] = val
}
func (mat *MatMxN) Add(dst *MatMxN, addend *MatMxN) *MatMxN {
	if mat == nil || addend == nil || mat.m != addend.m || mat.n != addend.n {
		return nil
	}
	dst = dst.Reshape(mat.m, mat.n)
	for i, el := range mat.dat {
		dst.dat[i] = el + addend.dat[i]
	}
	return dst
}
func (mat *MatMxN) Sub(dst *MatMxN, subtrahend *MatMxN) *MatMxN {
	if mat == nil || subtrahend == nil || mat.m != subtrahend.m || mat.n != subtrahend.n {
		return nil
	}
	dst = dst.Reshape(mat.m, mat.n)
	for i, el := range mat.dat {
		dst.dat[i] = el - subtrahend.dat[i]
	}
	return dst
}
func (mat *MatMxN) MulMxN(dst *MatMxN, mul *MatMxN) *MatMxN {
	if mat == nil || mul == nil || mat.n != mul.m {
		return nil
	}
	if dst == mul {
		mul = NewMatrix(mul.m, mul.n)
		copy(mul.dat, dst.dat)
		if mat == dst {
			mat = mul
		}
		defer mul.destroy()
	} else if dst == mat {
		mat = NewMatrix(mat.m, mat.n)
		copy(mat.dat, dst.dat)
		defer mat.destroy()
	}
	dst = dst.Reshape(mat.m, mul.n)
	for r1 := 0; r1 < mat.m; r1++ {
		for c2 := 0; c2 < mul.n; c2++ {
			dst.dat[c2*mat.m+r1] = 0
			for i := 0; i < mat.n; i++ {
				dst.dat[c2*mat.m+r1] += mat.dat[i*mat.m+r1] * mul.dat[c2*mul.m+i]
			}
		}
	}
	return dst
}
func (mat *MatMxN) Mul(dst *MatMxN, c float32) *MatMxN {
	if mat == nil {
		return nil
	}
	dst = dst.Reshape(mat.m, mat.n)
	for i, el := range mat.dat {
		dst.dat[i] = el * c
	}
	return dst
}
func (mat *MatMxN) MulNx1(dst, v *VecN) *VecN {
	if mat == nil || v == nil || mat.n != len(v.vec) {
		return nil
	}
	if dst == v {
		v = NewVecN(len(v.vec))
		copy(v.vec, dst.vec)
		defer v.destroy()
	}
	dst = dst.Resize(mat.m)
	for r := 0; r < mat.m; r++ {
		dst.vec[r] = 0
		for c := 0; c < mat.n; c++ {
			dst.vec[r] += mat.At(r, c) * v.vec[c]
		}
	}
	return dst
}