// svdCheck checks that the singular value decomposition correctly multiplies back // to the original matrix. func svdCheck(t *testing.T, thin bool, errStr string, m, n int, s, a, u []float64, ldu int, vt []float64, ldvt int, aCopy []float64, lda int) { sigma := blas64.General{ Rows: m, Cols: n, Stride: n, Data: make([]float64, m*n), } for i := 0; i < min(m, n); i++ { sigma.Data[i*sigma.Stride+i] = s[i] } uMat := blas64.General{ Rows: m, Cols: m, Stride: ldu, Data: u, } vTMat := blas64.General{ Rows: n, Cols: n, Stride: ldvt, Data: vt, } if thin { sigma.Rows = min(m, n) sigma.Cols = min(m, n) uMat.Cols = min(m, n) vTMat.Rows = min(m, n) } tmp := blas64.General{ Rows: m, Cols: n, Stride: n, Data: make([]float64, m*n), } ans := blas64.General{ Rows: m, Cols: n, Stride: lda, Data: make([]float64, m*lda), } copy(ans.Data, a) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, uMat, sigma, 0, tmp) blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, tmp, vTMat, 0, ans) if !floats.EqualApprox(ans.Data, aCopy, 1e-8) { t.Errorf("Decomposition mismatch. Trim = %v, %s", thin, errStr) } if !thin { // Check that U and V are orthogonal. for i := 0; i < uMat.Rows; i++ { for j := i + 1; j < uMat.Rows; j++ { dot := blas64.Dot(uMat.Cols, blas64.Vector{Inc: 1, Data: uMat.Data[i*uMat.Stride:]}, blas64.Vector{Inc: 1, Data: uMat.Data[j*uMat.Stride:]}, ) if dot > 1e-8 { t.Errorf("U not orthogonal %s", errStr) } } } for i := 0; i < vTMat.Rows; i++ { for j := i + 1; j < vTMat.Rows; j++ { dot := blas64.Dot(vTMat.Cols, blas64.Vector{Inc: 1, Data: vTMat.Data[i*vTMat.Stride:]}, blas64.Vector{Inc: 1, Data: vTMat.Data[j*vTMat.Stride:]}, ) if dot > 1e-8 { t.Errorf("V not orthogonal %s", errStr) } } } } }