github.com/gonum/lapack@v0.0.0-20181123203213-e4cdc5a0bff9/testlapack/dtrevc3.go (about) 1 // Copyright ©2016 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 "fmt" 9 "math" 10 "math/rand" 11 "testing" 12 13 "github.com/gonum/blas/blas64" 14 "github.com/gonum/floats" 15 "github.com/gonum/lapack" 16 ) 17 18 type Dtrevc3er interface { 19 Dtrevc3(side lapack.EVSide, howmny lapack.HowMany, selected []bool, n int, t []float64, ldt int, vl []float64, ldvl int, vr []float64, ldvr int, mm int, work []float64, lwork int) int 20 } 21 22 func Dtrevc3Test(t *testing.T, impl Dtrevc3er) { 23 rnd := rand.New(rand.NewSource(1)) 24 for _, side := range []lapack.EVSide{lapack.RightEV, lapack.LeftEV, lapack.RightLeftEV} { 25 for _, howmny := range []lapack.HowMany{lapack.AllEV, lapack.AllEVMulQ, lapack.SelectedEV} { 26 for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 34, 100} { 27 for _, extra := range []int{0, 11} { 28 for _, optwork := range []bool{true, false} { 29 for cas := 0; cas < 10; cas++ { 30 tmat := randomSchurCanonical(n, n+extra, rnd) 31 testDtrevc3(t, impl, side, howmny, tmat, optwork, rnd) 32 } 33 } 34 } 35 } 36 } 37 } 38 } 39 40 func testDtrevc3(t *testing.T, impl Dtrevc3er, side lapack.EVSide, howmny lapack.HowMany, tmat blas64.General, optwork bool, rnd *rand.Rand) { 41 const tol = 1e-14 42 43 n := tmat.Rows 44 extra := tmat.Stride - tmat.Cols 45 right := side != lapack.LeftEV 46 left := side != lapack.RightEV 47 48 var selected, selectedWant []bool 49 var mWant int // How many columns will the eigenvectors occupy. 50 if howmny == lapack.SelectedEV { 51 selected = make([]bool, n) 52 selectedWant = make([]bool, n) 53 // Dtrevc3 will compute only selected eigenvectors. Pick them 54 // randomly disregarding whether they are real or complex. 55 for i := range selected { 56 if rnd.Float64() < 0.5 { 57 selected[i] = true 58 } 59 } 60 // Dtrevc3 will modify (standardize) the slice selected based on 61 // whether the corresponding eigenvalues are real or complex. Do 62 // the same process here to fill selectedWant. 63 for i := 0; i < n; { 64 if i == n-1 || tmat.Data[(i+1)*tmat.Stride+i] == 0 { 65 // Real eigenvalue. 66 if selected[i] { 67 selectedWant[i] = true 68 mWant++ // Real eigenvectors occupy one column. 69 } 70 i++ 71 } else { 72 // Complex eigenvalue. 73 if selected[i] || selected[i+1] { 74 // Dtrevc3 will modify selected so that 75 // only the first element of the pair is 76 // true. 77 selectedWant[i] = true 78 mWant += 2 // Complex eigenvectors occupy two columns. 79 } 80 i += 2 81 } 82 } 83 } else { 84 // All eigenvectors occupy n columns. 85 mWant = n 86 } 87 88 var vr blas64.General 89 if right { 90 if howmny == lapack.AllEVMulQ { 91 vr = eye(n, n+extra) 92 } else { 93 // VR will be overwritten. 94 vr = nanGeneral(n, mWant, n+extra) 95 } 96 } 97 98 var vl blas64.General 99 if left { 100 if howmny == lapack.AllEVMulQ { 101 vl = eye(n, n+extra) 102 } else { 103 // VL will be overwritten. 104 vl = nanGeneral(n, mWant, n+extra) 105 } 106 } 107 108 work := make([]float64, max(1, 3*n)) 109 if optwork { 110 impl.Dtrevc3(side, howmny, nil, n, nil, 1, nil, 1, nil, 1, mWant, work, -1) 111 work = make([]float64, int(work[0])) 112 } 113 114 m := impl.Dtrevc3(side, howmny, selected, n, tmat.Data, tmat.Stride, 115 vl.Data, vl.Stride, vr.Data, vr.Stride, mWant, work, len(work)) 116 117 prefix := fmt.Sprintf("Case side=%v, howmny=%v, n=%v, extra=%v, optwk=%v", 118 side, howmny, n, extra, optwork) 119 120 if !generalOutsideAllNaN(tmat) { 121 t.Errorf("%v: out-of-range write to T", prefix) 122 } 123 if !generalOutsideAllNaN(vl) { 124 t.Errorf("%v: out-of-range write to VL", prefix) 125 } 126 if !generalOutsideAllNaN(vr) { 127 t.Errorf("%v: out-of-range write to VR", prefix) 128 } 129 130 if m != mWant { 131 t.Errorf("%v: unexpected value of m. Want %v, got %v", prefix, mWant, m) 132 } 133 134 if howmny == lapack.SelectedEV { 135 for i := range selected { 136 if selected[i] != selectedWant[i] { 137 t.Errorf("%v: unexpected selected[%v]", prefix, i) 138 } 139 } 140 } 141 142 // Check that the columns of VR and VL are actually eigenvectors and 143 // that the magnitude of their largest element is 1. 144 var k int 145 for j := 0; j < n; { 146 re := tmat.Data[j*tmat.Stride+j] 147 if j == n-1 || tmat.Data[(j+1)*tmat.Stride+j] == 0 { 148 if howmny == lapack.SelectedEV && !selected[j] { 149 j++ 150 continue 151 } 152 if right { 153 ev := columnOf(vr, k) 154 norm := floats.Norm(ev, math.Inf(1)) 155 if math.Abs(norm-1) > tol { 156 t.Errorf("%v: magnitude of largest element of VR[:,%v] not 1", prefix, k) 157 } 158 if !isRightEigenvectorOf(tmat, ev, nil, complex(re, 0), tol) { 159 t.Errorf("%v: VR[:,%v] is not real right eigenvector", prefix, k) 160 } 161 } 162 if left { 163 ev := columnOf(vl, k) 164 norm := floats.Norm(ev, math.Inf(1)) 165 if math.Abs(norm-1) > tol { 166 t.Errorf("%v: magnitude of largest element of VL[:,%v] not 1", prefix, k) 167 } 168 if !isLeftEigenvectorOf(tmat, ev, nil, complex(re, 0), tol) { 169 t.Errorf("%v: VL[:,%v] is not real left eigenvector", prefix, k) 170 } 171 } 172 k++ 173 j++ 174 continue 175 } 176 if howmny == lapack.SelectedEV && !selected[j] { 177 j += 2 178 continue 179 } 180 im := math.Sqrt(math.Abs(tmat.Data[(j+1)*tmat.Stride+j])) * 181 math.Sqrt(math.Abs(tmat.Data[j*tmat.Stride+j+1])) 182 if right { 183 evre := columnOf(vr, k) 184 evim := columnOf(vr, k+1) 185 var evmax float64 186 for i, v := range evre { 187 evmax = math.Max(evmax, math.Abs(v)+math.Abs(evim[i])) 188 } 189 if math.Abs(evmax-1) > tol { 190 t.Errorf("%v: magnitude of largest element of VR[:,%v] not 1", prefix, k) 191 } 192 if !isRightEigenvectorOf(tmat, evre, evim, complex(re, im), tol) { 193 t.Errorf("%v: VR[:,%v:%v] is not complex right eigenvector", prefix, k, k+1) 194 } 195 floats.Scale(-1, evim) 196 if !isRightEigenvectorOf(tmat, evre, evim, complex(re, -im), tol) { 197 t.Errorf("%v: VR[:,%v:%v] is not complex right eigenvector", prefix, k, k+1) 198 } 199 } 200 if left { 201 evre := columnOf(vl, k) 202 evim := columnOf(vl, k+1) 203 var evmax float64 204 for i, v := range evre { 205 evmax = math.Max(evmax, math.Abs(v)+math.Abs(evim[i])) 206 } 207 if math.Abs(evmax-1) > tol { 208 t.Errorf("%v: magnitude of largest element of VL[:,%v] not 1", prefix, k) 209 } 210 if !isLeftEigenvectorOf(tmat, evre, evim, complex(re, im), tol) { 211 t.Errorf("%v: VL[:,%v:%v] is not complex left eigenvector", prefix, k, k+1) 212 } 213 floats.Scale(-1, evim) 214 if !isLeftEigenvectorOf(tmat, evre, evim, complex(re, -im), tol) { 215 t.Errorf("%v: VL[:,%v:%v] is not complex left eigenvector", prefix, k, k+1) 216 } 217 } 218 k += 2 219 j += 2 220 } 221 }