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