gonum.org/v1/gonum@v0.15.1-0.20240517103525-f853624cb1bb/mat/lq_test.go (about) 1 // Copyright ©2013 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. 4 5 package mat 6 7 import ( 8 "testing" 9 10 "golang.org/x/exp/rand" 11 ) 12 13 func TestLQ(t *testing.T) { 14 t.Parallel() 15 const tol = 1e-14 16 rnd := rand.New(rand.NewSource(1)) 17 for cas, test := range []struct { 18 m, n int 19 }{ 20 {5, 5}, 21 {5, 10}, 22 } { 23 m := test.m 24 n := test.n 25 a := NewDense(m, n, nil) 26 for i := 0; i < m; i++ { 27 for j := 0; j < n; j++ { 28 a.Set(i, j, rnd.NormFloat64()) 29 } 30 } 31 var want Dense 32 want.CloneFrom(a) 33 34 var lq LQ 35 lq.Factorize(a) 36 37 if !EqualApprox(a, &lq, tol) { 38 t.Errorf("case %d: A and LQ are not equal", cas) 39 } 40 41 var l, q Dense 42 lq.QTo(&q) 43 44 if !isOrthonormal(&q, tol) { 45 t.Errorf("Q is not orthonormal: m = %v, n = %v", m, n) 46 } 47 48 lq.LTo(&l) 49 50 var got Dense 51 got.Mul(&l, &q) 52 if !EqualApprox(&got, &want, tol) { 53 t.Errorf("LQ does not equal original matrix. \nWant: %v\nGot: %v", want, got) 54 } 55 } 56 } 57 58 func TestLQSolveTo(t *testing.T) { 59 t.Parallel() 60 rnd := rand.New(rand.NewSource(1)) 61 for _, trans := range []bool{false, true} { 62 for _, test := range []struct { 63 m, n, bc int 64 }{ 65 {5, 5, 1}, 66 {5, 10, 1}, 67 {5, 5, 3}, 68 {5, 10, 3}, 69 } { 70 m := test.m 71 n := test.n 72 bc := test.bc 73 a := NewDense(m, n, nil) 74 for i := 0; i < m; i++ { 75 for j := 0; j < n; j++ { 76 a.Set(i, j, rnd.Float64()) 77 } 78 } 79 br := m 80 if trans { 81 br = n 82 } 83 b := NewDense(br, bc, nil) 84 for i := 0; i < br; i++ { 85 for j := 0; j < bc; j++ { 86 b.Set(i, j, rnd.Float64()) 87 } 88 } 89 var x Dense 90 lq := &LQ{} 91 lq.Factorize(a) 92 err := lq.SolveTo(&x, trans, b) 93 if err != nil { 94 t.Errorf("unexpected error from LQ solve: %v", err) 95 } 96 97 // Test that the normal equations hold. 98 // Aᵀ * A * x = Aᵀ * b if !trans 99 // A * Aᵀ * x = A * b if trans 100 var lhs Dense 101 var rhs Dense 102 if trans { 103 var tmp Dense 104 tmp.Mul(a, a.T()) 105 lhs.Mul(&tmp, &x) 106 rhs.Mul(a, b) 107 } else { 108 var tmp Dense 109 tmp.Mul(a.T(), a) 110 lhs.Mul(&tmp, &x) 111 rhs.Mul(a.T(), b) 112 } 113 if !EqualApprox(&lhs, &rhs, 1e-10) { 114 t.Errorf("Normal equations do not hold.\nLHS: %v\n, RHS: %v\n", lhs, rhs) 115 } 116 } 117 } 118 // TODO(btracey): Add in testOneInput when it exists. 119 } 120 121 func TestLQSolveToVec(t *testing.T) { 122 t.Parallel() 123 rnd := rand.New(rand.NewSource(1)) 124 for _, trans := range []bool{false, true} { 125 for _, test := range []struct { 126 m, n int 127 }{ 128 {5, 5}, 129 {5, 10}, 130 } { 131 m := test.m 132 n := test.n 133 a := NewDense(m, n, nil) 134 for i := 0; i < m; i++ { 135 for j := 0; j < n; j++ { 136 a.Set(i, j, rnd.Float64()) 137 } 138 } 139 br := m 140 if trans { 141 br = n 142 } 143 b := NewVecDense(br, nil) 144 for i := 0; i < br; i++ { 145 b.SetVec(i, rnd.Float64()) 146 } 147 var x VecDense 148 lq := &LQ{} 149 lq.Factorize(a) 150 err := lq.SolveVecTo(&x, trans, b) 151 if err != nil { 152 t.Errorf("unexpected error from LQ solve: %v", err) 153 } 154 155 // Test that the normal equations hold. 156 // Aᵀ * A * x = Aᵀ * b if !trans 157 // A * Aᵀ * x = A * b if trans 158 var lhs Dense 159 var rhs Dense 160 if trans { 161 var tmp Dense 162 tmp.Mul(a, a.T()) 163 lhs.Mul(&tmp, &x) 164 rhs.Mul(a, b) 165 } else { 166 var tmp Dense 167 tmp.Mul(a.T(), a) 168 lhs.Mul(&tmp, &x) 169 rhs.Mul(a.T(), b) 170 } 171 if !EqualApprox(&lhs, &rhs, 1e-10) { 172 t.Errorf("Normal equations do not hold.\nLHS: %v\n, RHS: %v\n", lhs, rhs) 173 } 174 } 175 } 176 // TODO(btracey): Add in testOneInput when it exists. 177 } 178 179 func TestLQSolveToCond(t *testing.T) { 180 t.Parallel() 181 for _, test := range []*Dense{ 182 NewDense(2, 2, []float64{1, 0, 0, 1e-20}), 183 NewDense(2, 3, []float64{1, 0, 0, 0, 1e-20, 0}), 184 } { 185 m, _ := test.Dims() 186 var lq LQ 187 lq.Factorize(test) 188 b := NewDense(m, 2, nil) 189 var x Dense 190 if err := lq.SolveTo(&x, false, b); err == nil { 191 t.Error("No error for near-singular matrix in matrix solve.") 192 } 193 194 bvec := NewVecDense(m, nil) 195 var xvec VecDense 196 if err := lq.SolveVecTo(&xvec, false, bvec); err == nil { 197 t.Error("No error for near-singular matrix in matrix solve.") 198 } 199 } 200 }