github.com/gonum/lapack@v0.0.0-20181123203213-e4cdc5a0bff9/testlapack/dlaqr23.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/rand" 10 "testing" 11 12 "github.com/gonum/blas" 13 "github.com/gonum/blas/blas64" 14 ) 15 16 type Dlaqr23er interface { 17 Dlaqr23(wantt, wantz bool, n, ktop, kbot, nw int, h []float64, ldh int, iloz, ihiz int, z []float64, ldz int, sr, si []float64, v []float64, ldv int, nh int, t []float64, ldt int, nv int, wv []float64, ldwv int, work []float64, lwork int, recur int) (ns, nd int) 18 } 19 20 type dlaqr23Test struct { 21 wantt, wantz bool 22 ktop, kbot int 23 nw int 24 h blas64.General 25 iloz, ihiz int 26 27 evWant []complex128 // Optional slice with known eigenvalues. 28 } 29 30 func Dlaqr23Test(t *testing.T, impl Dlaqr23er) { 31 rnd := rand.New(rand.NewSource(1)) 32 33 for _, wantt := range []bool{true, false} { 34 for _, wantz := range []bool{true, false} { 35 for _, n := range []int{1, 2, 3, 4, 5, 6, 10, 18, 31, 100} { 36 for _, extra := range []int{0, 11} { 37 for cas := 0; cas < 30; cas++ { 38 var nw int 39 if nw <= 75 { 40 nw = rnd.Intn(n) + 1 41 } else { 42 nw = 76 + rnd.Intn(n-75) 43 } 44 ktop := rnd.Intn(n - nw + 1) 45 kbot := ktop + nw - 1 46 kbot += rnd.Intn(n - kbot) 47 h := randomHessenberg(n, n+extra, rnd) 48 if ktop-1 >= 0 { 49 h.Data[ktop*h.Stride+ktop-1] = 0 50 } 51 if kbot+1 < n { 52 h.Data[(kbot+1)*h.Stride+kbot] = 0 53 } 54 iloz := rnd.Intn(ktop + 1) 55 ihiz := kbot + rnd.Intn(n-kbot) 56 test := dlaqr23Test{ 57 wantt: wantt, 58 wantz: wantz, 59 ktop: ktop, 60 kbot: kbot, 61 nw: nw, 62 h: h, 63 iloz: iloz, 64 ihiz: ihiz, 65 } 66 testDlaqr23(t, impl, test, false, 1, rnd) 67 testDlaqr23(t, impl, test, true, 1, rnd) 68 testDlaqr23(t, impl, test, false, 0, rnd) 69 testDlaqr23(t, impl, test, true, 0, rnd) 70 } 71 } 72 } 73 } 74 } 75 76 // Tests with n=0. 77 for _, wantt := range []bool{true, false} { 78 for _, wantz := range []bool{true, false} { 79 for _, extra := range []int{0, 1, 11} { 80 test := dlaqr23Test{ 81 wantt: wantt, 82 wantz: wantz, 83 h: randomHessenberg(0, extra, rnd), 84 ktop: 0, 85 kbot: -1, 86 iloz: 0, 87 ihiz: -1, 88 nw: 0, 89 } 90 testDlaqr23(t, impl, test, true, 1, rnd) 91 testDlaqr23(t, impl, test, false, 1, rnd) 92 testDlaqr23(t, impl, test, true, 0, rnd) 93 testDlaqr23(t, impl, test, false, 0, rnd) 94 } 95 } 96 } 97 98 // Tests with explicit eigenvalues computed by Octave. 99 for _, test := range []dlaqr23Test{ 100 { 101 h: blas64.General{ 102 Rows: 1, 103 Cols: 1, 104 Stride: 1, 105 Data: []float64{7.09965484086874e-1}, 106 }, 107 ktop: 0, 108 kbot: 0, 109 iloz: 0, 110 ihiz: 0, 111 evWant: []complex128{7.09965484086874e-1}, 112 }, 113 { 114 h: blas64.General{ 115 Rows: 2, 116 Cols: 2, 117 Stride: 2, 118 Data: []float64{ 119 0, -1, 120 1, 0, 121 }, 122 }, 123 ktop: 0, 124 kbot: 1, 125 iloz: 0, 126 ihiz: 1, 127 evWant: []complex128{1i, -1i}, 128 }, 129 { 130 h: blas64.General{ 131 Rows: 2, 132 Cols: 2, 133 Stride: 2, 134 Data: []float64{ 135 6.25219991450918e-1, 8.17510791994361e-1, 136 3.31218891622294e-1, 1.24103744878131e-1, 137 }, 138 }, 139 ktop: 0, 140 kbot: 1, 141 iloz: 0, 142 ihiz: 1, 143 evWant: []complex128{9.52203547663447e-1, -2.02879811334398e-1}, 144 }, 145 { 146 h: blas64.General{ 147 Rows: 4, 148 Cols: 4, 149 Stride: 4, 150 Data: []float64{ 151 1, 0, 0, 0, 152 0, 6.25219991450918e-1, 8.17510791994361e-1, 0, 153 0, 3.31218891622294e-1, 1.24103744878131e-1, 0, 154 0, 0, 0, 1, 155 }, 156 }, 157 ktop: 1, 158 kbot: 2, 159 iloz: 0, 160 ihiz: 3, 161 evWant: []complex128{9.52203547663447e-1, -2.02879811334398e-1}, 162 }, 163 { 164 h: blas64.General{ 165 Rows: 2, 166 Cols: 2, 167 Stride: 2, 168 Data: []float64{ 169 -1.1219562276608, 6.85473513349362e-1, 170 -8.19951061145131e-1, 1.93728523178888e-1, 171 }, 172 }, 173 ktop: 0, 174 kbot: 1, 175 iloz: 0, 176 ihiz: 1, 177 evWant: []complex128{ 178 -4.64113852240958e-1 + 3.59580510817350e-1i, 179 -4.64113852240958e-1 - 3.59580510817350e-1i, 180 }, 181 }, 182 { 183 h: blas64.General{ 184 Rows: 5, 185 Cols: 5, 186 Stride: 5, 187 Data: []float64{ 188 9.57590178533658e-1, -5.10651295522708e-1, 9.24974510015869e-1, -1.30016306879522e-1, 2.92601986926954e-2, 189 -1.08084756637964, 1.77529701001213, -1.36480197632509, 2.23196371219601e-1, 1.12912853063308e-1, 190 0, -8.44075612174676e-1, 1.067867614486, -2.55782915176399e-1, -2.00598563137468e-1, 191 0, 0, -5.67097237165410e-1, 2.07205057427341e-1, 6.54998340743380e-1, 192 0, 0, 0, -1.89441413886041e-1, -4.18125416021786e-1, 193 }, 194 }, 195 ktop: 0, 196 kbot: 4, 197 iloz: 0, 198 ihiz: 4, 199 evWant: []complex128{ 200 2.94393309555622, 201 4.97029793606701e-1 + 3.63041654992384e-1i, 202 4.97029793606701e-1 - 3.63041654992384e-1i, 203 -1.74079119166145e-1 + 2.01570009462092e-1i, 204 -1.74079119166145e-1 - 2.01570009462092e-1i, 205 }, 206 }, 207 } { 208 test.wantt = true 209 test.wantz = true 210 test.nw = test.kbot - test.ktop + 1 211 testDlaqr23(t, impl, test, true, 1, rnd) 212 testDlaqr23(t, impl, test, false, 1, rnd) 213 testDlaqr23(t, impl, test, true, 0, rnd) 214 testDlaqr23(t, impl, test, false, 0, rnd) 215 } 216 } 217 218 func testDlaqr23(t *testing.T, impl Dlaqr23er, test dlaqr23Test, opt bool, recur int, rnd *rand.Rand) { 219 const tol = 1e-14 220 221 h := cloneGeneral(test.h) 222 n := h.Cols 223 extra := h.Stride - h.Cols 224 wantt := test.wantt 225 wantz := test.wantz 226 ktop := test.ktop 227 kbot := test.kbot 228 nw := test.nw 229 iloz := test.iloz 230 ihiz := test.ihiz 231 232 var z, zCopy blas64.General 233 if wantz { 234 z = eye(n, n+extra) 235 zCopy = cloneGeneral(z) 236 } 237 238 sr := nanSlice(kbot + 1) 239 si := nanSlice(kbot + 1) 240 241 v := randomGeneral(nw, nw, nw+extra, rnd) 242 var nh int 243 if nw > 0 { 244 nh = nw + rnd.Intn(nw) // nh must be at least nw. 245 } 246 tmat := randomGeneral(nw, nh, nh+extra, rnd) 247 var nv int 248 if nw > 0 { 249 nv = rnd.Intn(nw) + 1 250 } 251 wv := randomGeneral(nv, nw, nw+extra, rnd) 252 253 var work []float64 254 if opt { 255 work = nanSlice(1) 256 impl.Dlaqr23(wantt, wantz, n, ktop, kbot, nw, nil, h.Stride, iloz, ihiz, nil, z.Stride, 257 nil, nil, nil, v.Stride, tmat.Cols, nil, tmat.Stride, wv.Rows, nil, wv.Stride, work, -1, recur) 258 work = nanSlice(int(work[0])) 259 } else { 260 work = nanSlice(max(1, 2*nw)) 261 } 262 263 ns, nd := impl.Dlaqr23(wantt, wantz, n, ktop, kbot, nw, h.Data, h.Stride, iloz, ihiz, z.Data, z.Stride, 264 sr, si, v.Data, v.Stride, tmat.Cols, tmat.Data, tmat.Stride, wv.Rows, wv.Data, wv.Stride, work, len(work), recur) 265 266 prefix := fmt.Sprintf("Case wantt=%v, wantz=%v, n=%v, ktop=%v, kbot=%v, nw=%v, iloz=%v, ihiz=%v, extra=%v", 267 wantt, wantz, n, ktop, kbot, nw, iloz, ihiz, extra) 268 269 if !generalOutsideAllNaN(h) { 270 t.Errorf("%v: out-of-range write to H\n%v", prefix, h.Data) 271 } 272 if !generalOutsideAllNaN(z) { 273 t.Errorf("%v: out-of-range write to Z\n%v", prefix, z.Data) 274 } 275 if !generalOutsideAllNaN(v) { 276 t.Errorf("%v: out-of-range write to V\n%v", prefix, v.Data) 277 } 278 if !generalOutsideAllNaN(tmat) { 279 t.Errorf("%v: out-of-range write to T\n%v", prefix, tmat.Data) 280 } 281 if !generalOutsideAllNaN(wv) { 282 t.Errorf("%v: out-of-range write to WV\n%v", prefix, wv.Data) 283 } 284 if !isAllNaN(sr[:kbot-nd-ns+1]) || !isAllNaN(sr[kbot+1:]) { 285 t.Errorf("%v: out-of-range write to sr") 286 } 287 if !isAllNaN(si[:kbot-nd-ns+1]) || !isAllNaN(si[kbot+1:]) { 288 t.Errorf("%v: out-of-range write to si") 289 } 290 291 if !isUpperHessenberg(h) { 292 t.Errorf("%v: H is not upper Hessenberg", prefix) 293 } 294 295 if test.evWant != nil { 296 for i := kbot - nd + 1; i <= kbot; i++ { 297 ev := complex(sr[i], si[i]) 298 found, _ := containsComplex(test.evWant, ev, tol) 299 if !found { 300 t.Errorf("%v: unexpected eigenvalue %v", prefix, ev) 301 } 302 } 303 } 304 305 if !wantz { 306 return 307 } 308 309 var zmod bool 310 for i := 0; i < n; i++ { 311 for j := 0; j < n; j++ { 312 if z.Data[i*z.Stride+j] == zCopy.Data[i*zCopy.Stride+j] { 313 continue 314 } 315 if i < iloz || i > ihiz || j < kbot-nw+1 || j > kbot { 316 zmod = true 317 } 318 } 319 } 320 if zmod { 321 t.Errorf("%v: unexpected modification of Z", prefix) 322 } 323 if !isOrthonormal(z) { 324 t.Errorf("%v: Z is not orthogonal", prefix) 325 } 326 if wantt { 327 hu := eye(n, n) 328 blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, test.h, z, 0, hu) 329 uhu := eye(n, n) 330 blas64.Gemm(blas.Trans, blas.NoTrans, 1, z, hu, 0, uhu) 331 if !equalApproxGeneral(uhu, h, 10*tol) { 332 t.Errorf("%v: Z^T*(initial H)*Z and (final H) are not equal", prefix) 333 } 334 } 335 }