1 // Copyright ©2015 The Gonum Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
10 "golang.org/x/exp/rand"
12 "gonum.org/v1/gonum/blas"
13 "gonum.org/v1/gonum/blas/blas64"
14 "gonum.org/v1/gonum/floats"
17 type Dgetf2er interface {
18 Dgetf2(m, n int, a []float64, lda int, ipiv []int) bool
21 func Dgetf2Test(t *testing.T, impl Dgetf2er) {
22 rnd := rand.New(rand.NewSource(1))
23 for _, test := range []struct {
40 a := make([]float64, m*lda)
44 aCopy := make([]float64, len(a))
48 ipiv := make([]int, mn)
52 ok := impl.Dgetf2(m, n, a, lda, ipiv)
53 checkPLU(t, ok, m, n, lda, ipiv, a, aCopy, 1e-14, true)
56 // Test with singular matrices (random matrices are almost surely non-singular).
57 for _, test := range []struct {
83 // row 3 = row1 + 2 * row2
94 // row 3 = row1 + 2 * row2
102 if impl.Dgetf2(test.m, test.n, test.a, test.lda, make([]int, min(test.m, test.n))) {
103 t.Log("Returned ok with singular matrix.")
108 // checkPLU checks that the PLU factorization contained in factorize matches
109 // the original matrix contained in original.
110 func checkPLU(t *testing.T, ok bool, m, n, lda int, ipiv []int, factorized, original []float64, tol float64, print bool) {
111 var hasZeroDiagonal bool
112 for i := 0; i < min(m, n); i++ {
113 if factorized[i*lda+i] == 0 {
114 hasZeroDiagonal = true
118 if hasZeroDiagonal && ok {
119 t.Error("Has a zero diagonal but returned ok")
121 if !hasZeroDiagonal && !ok {
122 t.Error("Non-zero diagonal but returned !ok")
125 // Check that the LU decomposition is correct.
127 l := make([]float64, m*mn)
129 u := make([]float64, mn*n)
131 for i := 0; i < m; i++ {
132 for j := 0; j < n; j++ {
133 v := factorized[i*lda+j]
146 LU := blas64.General{
150 Data: make([]float64, m*n),
164 blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, L, U, 0, LU)
166 p := make([]float64, m*m)
168 for i := 0; i < m; i++ {
171 for i := len(ipiv) - 1; i >= 0; i-- {
173 blas64.Swap(m, blas64.Vector{Inc: 1, Data: p[i*ldp:]}, blas64.Vector{Inc: 1, Data: p[v*ldp:]})
181 aComp := blas64.General{
185 Data: make([]float64, m*lda),
187 copy(aComp.Data, factorized)
188 blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, P, LU, 0, aComp)
189 if !floats.EqualApprox(aComp.Data, original, tol) {
191 t.Errorf("PLU multiplication does not match original matrix.\nWant: %v\nGot: %v", original, aComp.Data)
194 t.Error("PLU multiplication does not match original matrix.")