gonum.org/v1/gonum@v0.14.0/lapack/testlapack/dlags2.go (about) 1 // Copyright ©2017 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 testlapack 6 7 import ( 8 "math" 9 "testing" 10 11 "golang.org/x/exp/rand" 12 13 "gonum.org/v1/gonum/blas" 14 "gonum.org/v1/gonum/blas/blas64" 15 "gonum.org/v1/gonum/floats/scalar" 16 ) 17 18 type Dlags2er interface { 19 Dlags2(upper bool, a1, a2, a3, b1, b2, b3 float64) (csu, snu, csv, snv, csq, snq float64) 20 } 21 22 func Dlags2Test(t *testing.T, impl Dlags2er) { 23 rnd := rand.New(rand.NewSource(1)) 24 for _, upper := range []bool{true, false} { 25 for i := 0; i < 100; i++ { 26 // Generate randomly the elements of a 2×2 matrix A 27 // [ a1 a2 ] or [ a1 0 ] 28 // [ 0 a3 ] [ a2 a3 ] 29 a1 := rnd.Float64() 30 a2 := rnd.Float64() 31 a3 := rnd.Float64() 32 // Generate randomly the elements of a 2×2 matrix B. 33 // [ b1 b2 ] or [ b1 0 ] 34 // [ 0 b3 ] [ b2 b3 ] 35 b1 := rnd.Float64() 36 b2 := rnd.Float64() 37 b3 := rnd.Float64() 38 39 // Compute orthogonal matrices U, V, Q 40 // U = [ csu snu ], V = [ csv snv ], Q = [ csq snq ] 41 // [ -snu csu ] [ -snv csv ] [ -snq csq ] 42 // that transform A and B. 43 csu, snu, csv, snv, csq, snq := impl.Dlags2(upper, a1, a2, a3, b1, b2, b3) 44 45 // Check that U, V, Q are orthogonal matrices (their 46 // determinant is equal to 1). 47 detU := det2x2(csu, snu, -snu, csu) 48 if !scalar.EqualWithinAbsOrRel(math.Abs(detU), 1, 1e-14, 1e-14) { 49 t.Errorf("U not orthogonal: det(U)=%v", detU) 50 } 51 detV := det2x2(csv, snv, -snv, csv) 52 if !scalar.EqualWithinAbsOrRel(math.Abs(detV), 1, 1e-14, 1e-14) { 53 t.Errorf("V not orthogonal: det(V)=%v", detV) 54 } 55 detQ := det2x2(csq, snq, -snq, csq) 56 if !scalar.EqualWithinAbsOrRel(math.Abs(detQ), 1, 1e-14, 1e-14) { 57 t.Errorf("Q not orthogonal: det(Q)=%v", detQ) 58 } 59 60 // Create U, V, Q explicitly as dense matrices. 61 u := blas64.General{ 62 Rows: 2, 63 Cols: 2, 64 Stride: 2, 65 Data: []float64{csu, snu, -snu, csu}, 66 } 67 v := blas64.General{ 68 Rows: 2, 69 Cols: 2, 70 Stride: 2, 71 Data: []float64{csv, snv, -snv, csv}, 72 } 73 q := blas64.General{ 74 Rows: 2, 75 Cols: 2, 76 Stride: 2, 77 Data: []float64{csq, snq, -snq, csq}, 78 } 79 80 // Create A and B explicitly as dense matrices. 81 a := blas64.General{Rows: 2, Cols: 2, Stride: 2} 82 b := blas64.General{Rows: 2, Cols: 2, Stride: 2} 83 if upper { 84 a.Data = []float64{a1, a2, 0, a3} 85 b.Data = []float64{b1, b2, 0, b3} 86 } else { 87 a.Data = []float64{a1, 0, a2, a3} 88 b.Data = []float64{b1, 0, b2, b3} 89 } 90 91 tmp := blas64.General{Rows: 2, Cols: 2, Stride: 2, Data: make([]float64, 4)} 92 // Transform A as Uᵀ*A*Q. 93 blas64.Gemm(blas.Trans, blas.NoTrans, 1, u, a, 0, tmp) 94 blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, tmp, q, 0, a) 95 // Transform B as Vᵀ*A*Q. 96 blas64.Gemm(blas.Trans, blas.NoTrans, 1, v, b, 0, tmp) 97 blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, tmp, q, 0, b) 98 99 // Extract elements of transformed A and B that should be equal to zero. 100 var gotA, gotB float64 101 if upper { 102 gotA = a.Data[1] 103 gotB = b.Data[1] 104 } else { 105 gotA = a.Data[2] 106 gotB = b.Data[2] 107 } 108 // Check that they are indeed zero. 109 if !scalar.EqualWithinAbsOrRel(gotA, 0, 1e-14, 1e-14) { 110 t.Errorf("unexpected non-zero value for zero triangle of Uᵀ*A*Q: %v", gotA) 111 } 112 if !scalar.EqualWithinAbsOrRel(gotB, 0, 1e-14, 1e-14) { 113 t.Errorf("unexpected non-zero value for zero triangle of Vᵀ*B*Q: %v", gotB) 114 } 115 } 116 } 117 } 118 119 func det2x2(a, b, c, d float64) float64 { return a*d - b*c }