gonum.org/v1/gonum@v0.14.0/lapack/gonum/dlahqr.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 gonum 6 7 import ( 8 "math" 9 10 "gonum.org/v1/gonum/blas/blas64" 11 ) 12 13 // Dlahqr computes the eigenvalues and Schur factorization of a block of an n×n 14 // upper Hessenberg matrix H, using the double-shift/single-shift QR algorithm. 15 // 16 // h and ldh represent the matrix H. Dlahqr works primarily with the Hessenberg 17 // submatrix H[ilo:ihi+1,ilo:ihi+1], but applies transformations to all of H if 18 // wantt is true. It is assumed that H[ihi+1:n,ihi+1:n] is already upper 19 // quasi-triangular, although this is not checked. 20 // 21 // It must hold that 22 // 23 // 0 <= ilo <= max(0,ihi), and ihi < n, 24 // 25 // and that 26 // 27 // H[ilo,ilo-1] == 0, if ilo > 0, 28 // 29 // otherwise Dlahqr will panic. 30 // 31 // If unconverged is zero on return, wr[ilo:ihi+1] and wi[ilo:ihi+1] will contain 32 // respectively the real and imaginary parts of the computed eigenvalues ilo 33 // to ihi. If two eigenvalues are computed as a complex conjugate pair, they are 34 // stored in consecutive elements of wr and wi, say the i-th and (i+1)th, with 35 // wi[i] > 0 and wi[i+1] < 0. If wantt is true, the eigenvalues are stored in 36 // the same order as on the diagonal of the Schur form returned in H, with 37 // wr[i] = H[i,i], and, if H[i:i+2,i:i+2] is a 2×2 diagonal block, 38 // wi[i] = sqrt(abs(H[i+1,i]*H[i,i+1])) and wi[i+1] = -wi[i]. 39 // 40 // wr and wi must have length ihi+1. 41 // 42 // z and ldz represent an n×n matrix Z. If wantz is true, the transformations 43 // will be applied to the submatrix Z[iloz:ihiz+1,ilo:ihi+1] and it must hold that 44 // 45 // 0 <= iloz <= ilo, and ihi <= ihiz < n. 46 // 47 // If wantz is false, z is not referenced. 48 // 49 // unconverged indicates whether Dlahqr computed all the eigenvalues ilo to ihi 50 // in a total of 30 iterations per eigenvalue. 51 // 52 // If unconverged is zero, all the eigenvalues ilo to ihi have been computed and 53 // will be stored on return in wr[ilo:ihi+1] and wi[ilo:ihi+1]. 54 // 55 // If unconverged is zero and wantt is true, H[ilo:ihi+1,ilo:ihi+1] will be 56 // overwritten on return by upper quasi-triangular full Schur form with any 57 // 2×2 diagonal blocks in standard form. 58 // 59 // If unconverged is zero and if wantt is false, the contents of h on return is 60 // unspecified. 61 // 62 // If unconverged is positive, some eigenvalues have not converged, and 63 // wr[unconverged:ihi+1] and wi[unconverged:ihi+1] contain those eigenvalues 64 // which have been successfully computed. 65 // 66 // If unconverged is positive and wantt is true, then on return 67 // 68 // (initial H)*U = U*(final H), (*) 69 // 70 // where U is an orthogonal matrix. The final H is upper Hessenberg and 71 // H[unconverged:ihi+1,unconverged:ihi+1] is upper quasi-triangular. 72 // 73 // If unconverged is positive and wantt is false, on return the remaining 74 // unconverged eigenvalues are the eigenvalues of the upper Hessenberg matrix 75 // H[ilo:unconverged,ilo:unconverged]. 76 // 77 // If unconverged is positive and wantz is true, then on return 78 // 79 // (final Z) = (initial Z)*U, 80 // 81 // where U is the orthogonal matrix in (*) regardless of the value of wantt. 82 // 83 // Dlahqr is an internal routine. It is exported for testing purposes. 84 func (impl Implementation) Dlahqr(wantt, wantz bool, n, ilo, ihi int, h []float64, ldh int, wr, wi []float64, iloz, ihiz int, z []float64, ldz int) (unconverged int) { 85 switch { 86 case n < 0: 87 panic(nLT0) 88 case ilo < 0, max(0, ihi) < ilo: 89 panic(badIlo) 90 case ihi >= n: 91 panic(badIhi) 92 case ldh < max(1, n): 93 panic(badLdH) 94 case wantz && (iloz < 0 || ilo < iloz): 95 panic(badIloz) 96 case wantz && (ihiz < ihi || n <= ihiz): 97 panic(badIhiz) 98 case ldz < 1, wantz && ldz < n: 99 panic(badLdZ) 100 } 101 102 // Quick return if possible. 103 if n == 0 { 104 return 0 105 } 106 107 switch { 108 case len(h) < (n-1)*ldh+n: 109 panic(shortH) 110 case len(wr) != ihi+1: 111 panic(shortWr) 112 case len(wi) != ihi+1: 113 panic(shortWi) 114 case wantz && len(z) < (n-1)*ldz+n: 115 panic(shortZ) 116 case ilo > 0 && h[ilo*ldh+ilo-1] != 0: 117 panic(notIsolated) 118 } 119 120 if ilo == ihi { 121 wr[ilo] = h[ilo*ldh+ilo] 122 wi[ilo] = 0 123 return 0 124 } 125 126 // Clear out the trash. 127 for j := ilo; j < ihi-2; j++ { 128 h[(j+2)*ldh+j] = 0 129 h[(j+3)*ldh+j] = 0 130 } 131 if ilo <= ihi-2 { 132 h[ihi*ldh+ihi-2] = 0 133 } 134 135 nh := ihi - ilo + 1 136 nz := ihiz - iloz + 1 137 138 // Set machine-dependent constants for the stopping criterion. 139 ulp := dlamchP 140 smlnum := float64(nh) / ulp * dlamchS 141 142 // i1 and i2 are the indices of the first row and last column of H to 143 // which transformations must be applied. If eigenvalues only are being 144 // computed, i1 and i2 are set inside the main loop. 145 var i1, i2 int 146 if wantt { 147 i1 = 0 148 i2 = n - 1 149 } 150 151 itmax := 30 * max(10, nh) // Total number of QR iterations allowed. 152 153 // kdefl counts the number of iterations since a deflation. 154 kdefl := 0 155 156 // The main loop begins here. i is the loop index and decreases from ihi 157 // to ilo in steps of 1 or 2. Each iteration of the loop works with the 158 // active submatrix in rows and columns l to i. Eigenvalues i+1 to ihi 159 // have already converged. Either l = ilo or H[l,l-1] is negligible so 160 // that the matrix splits. 161 bi := blas64.Implementation() 162 i := ihi 163 for i >= ilo { 164 l := ilo 165 166 // Perform QR iterations on rows and columns ilo to i until a 167 // submatrix of order 1 or 2 splits off at the bottom because a 168 // subdiagonal element has become negligible. 169 converged := false 170 for its := 0; its <= itmax; its++ { 171 // Look for a single small subdiagonal element. 172 var k int 173 for k = i; k > l; k-- { 174 if math.Abs(h[k*ldh+k-1]) <= smlnum { 175 break 176 } 177 tst := math.Abs(h[(k-1)*ldh+k-1]) + math.Abs(h[k*ldh+k]) 178 if tst == 0 { 179 if k-2 >= ilo { 180 tst += math.Abs(h[(k-1)*ldh+k-2]) 181 } 182 if k+1 <= ihi { 183 tst += math.Abs(h[(k+1)*ldh+k]) 184 } 185 } 186 // The following is a conservative small 187 // subdiagonal deflation criterion due to Ahues 188 // & Tisseur (LAWN 122, 1997). It has better 189 // mathematical foundation and improves accuracy 190 // in some cases. 191 if math.Abs(h[k*ldh+k-1]) <= ulp*tst { 192 ab := math.Max(math.Abs(h[k*ldh+k-1]), math.Abs(h[(k-1)*ldh+k])) 193 ba := math.Min(math.Abs(h[k*ldh+k-1]), math.Abs(h[(k-1)*ldh+k])) 194 aa := math.Max(math.Abs(h[k*ldh+k]), math.Abs(h[(k-1)*ldh+k-1]-h[k*ldh+k])) 195 bb := math.Min(math.Abs(h[k*ldh+k]), math.Abs(h[(k-1)*ldh+k-1]-h[k*ldh+k])) 196 s := aa + ab 197 if ab/s*ba <= math.Max(smlnum, aa/s*bb*ulp) { 198 break 199 } 200 } 201 } 202 l = k 203 if l > ilo { 204 // H[l,l-1] is negligible. 205 h[l*ldh+l-1] = 0 206 } 207 if l >= i-1 { 208 // Break the loop because a submatrix of order 1 209 // or 2 has split off. 210 converged = true 211 break 212 } 213 kdefl++ 214 215 // Now the active submatrix is in rows and columns l to 216 // i. If eigenvalues only are being computed, only the 217 // active submatrix need be transformed. 218 if !wantt { 219 i1 = l 220 i2 = i 221 } 222 223 const ( 224 dat1 = 0.75 225 dat2 = -0.4375 226 kexsh = 10 227 ) 228 var h11, h21, h12, h22 float64 229 switch { 230 case kdefl%(2*kexsh) == 0: // Exceptional shift. 231 s := math.Abs(h[i*ldh+i-1]) + math.Abs(h[(i-1)*ldh+i-2]) 232 h11 = dat1*s + h[i*ldh+i] 233 h12 = dat2 * s 234 h21 = s 235 h22 = h11 236 case kdefl%kexsh == 0: // Exceptional shift. 237 s := math.Abs(h[(l+1)*ldh+l]) + math.Abs(h[(l+2)*ldh+l+1]) 238 h11 = dat1*s + h[l*ldh+l] 239 h12 = dat2 * s 240 h21 = s 241 h22 = h11 242 default: // Prepare to use Francis' double shift (i.e., 243 // 2nd degree generalized Rayleigh quotient). 244 h11 = h[(i-1)*ldh+i-1] 245 h21 = h[i*ldh+i-1] 246 h12 = h[(i-1)*ldh+i] 247 h22 = h[i*ldh+i] 248 } 249 s := math.Abs(h11) + math.Abs(h12) + math.Abs(h21) + math.Abs(h22) 250 var ( 251 rt1r, rt1i float64 252 rt2r, rt2i float64 253 ) 254 if s != 0 { 255 h11 /= s 256 h21 /= s 257 h12 /= s 258 h22 /= s 259 tr := (h11 + h22) / 2 260 det := (h11-tr)*(h22-tr) - h12*h21 261 rtdisc := math.Sqrt(math.Abs(det)) 262 if det >= 0 { 263 // Complex conjugate shifts. 264 rt1r = tr * s 265 rt2r = rt1r 266 rt1i = rtdisc * s 267 rt2i = -rt1i 268 } else { 269 // Real shifts (use only one of them). 270 rt1r = tr + rtdisc 271 rt2r = tr - rtdisc 272 if math.Abs(rt1r-h22) <= math.Abs(rt2r-h22) { 273 rt1r *= s 274 rt2r = rt1r 275 } else { 276 rt2r *= s 277 rt1r = rt2r 278 } 279 rt1i = 0 280 rt2i = 0 281 } 282 } 283 284 // Look for two consecutive small subdiagonal elements. 285 var m int 286 var v [3]float64 287 for m = i - 2; m >= l; m-- { 288 // Determine the effect of starting the 289 // double-shift QR iteration at row m, and see 290 // if this would make H[m,m-1] negligible. The 291 // following uses scaling to avoid overflows and 292 // most underflows. 293 h21s := h[(m+1)*ldh+m] 294 s := math.Abs(h[m*ldh+m]-rt2r) + math.Abs(rt2i) + math.Abs(h21s) 295 h21s /= s 296 v[0] = h21s*h[m*ldh+m+1] + (h[m*ldh+m]-rt1r)*((h[m*ldh+m]-rt2r)/s) - rt2i/s*rt1i 297 v[1] = h21s * (h[m*ldh+m] + h[(m+1)*ldh+m+1] - rt1r - rt2r) 298 v[2] = h21s * h[(m+2)*ldh+m+1] 299 s = math.Abs(v[0]) + math.Abs(v[1]) + math.Abs(v[2]) 300 v[0] /= s 301 v[1] /= s 302 v[2] /= s 303 if m == l { 304 break 305 } 306 dsum := math.Abs(h[(m-1)*ldh+m-1]) + math.Abs(h[m*ldh+m]) + math.Abs(h[(m+1)*ldh+m+1]) 307 if math.Abs(h[m*ldh+m-1])*(math.Abs(v[1])+math.Abs(v[2])) <= ulp*math.Abs(v[0])*dsum { 308 break 309 } 310 } 311 312 // Double-shift QR step. 313 for k := m; k < i; k++ { 314 // The first iteration of this loop determines a 315 // reflection G from the vector V and applies it 316 // from left and right to H, thus creating a 317 // non-zero bulge below the subdiagonal. 318 // 319 // Each subsequent iteration determines a 320 // reflection G to restore the Hessenberg form 321 // in the (k-1)th column, and thus chases the 322 // bulge one step toward the bottom of the 323 // active submatrix. nr is the order of G. 324 325 nr := min(3, i-k+1) 326 if k > m { 327 bi.Dcopy(nr, h[k*ldh+k-1:], ldh, v[:], 1) 328 } 329 var t0 float64 330 v[0], t0 = impl.Dlarfg(nr, v[0], v[1:], 1) 331 if k > m { 332 h[k*ldh+k-1] = v[0] 333 h[(k+1)*ldh+k-1] = 0 334 if k < i-1 { 335 h[(k+2)*ldh+k-1] = 0 336 } 337 } else if m > l { 338 // Use the following instead of H[k,k-1] = -H[k,k-1] 339 // to avoid a bug when v[1] and v[2] underflow. 340 h[k*ldh+k-1] *= 1 - t0 341 } 342 t1 := t0 * v[1] 343 if nr == 3 { 344 t2 := t0 * v[2] 345 346 // Apply G from the left to transform 347 // the rows of the matrix in columns k 348 // to i2. 349 for j := k; j <= i2; j++ { 350 sum := h[k*ldh+j] + v[1]*h[(k+1)*ldh+j] + v[2]*h[(k+2)*ldh+j] 351 h[k*ldh+j] -= sum * t0 352 h[(k+1)*ldh+j] -= sum * t1 353 h[(k+2)*ldh+j] -= sum * t2 354 } 355 356 // Apply G from the right to transform 357 // the columns of the matrix in rows i1 358 // to min(k+3,i). 359 for j := i1; j <= min(k+3, i); j++ { 360 sum := h[j*ldh+k] + v[1]*h[j*ldh+k+1] + v[2]*h[j*ldh+k+2] 361 h[j*ldh+k] -= sum * t0 362 h[j*ldh+k+1] -= sum * t1 363 h[j*ldh+k+2] -= sum * t2 364 } 365 366 if wantz { 367 // Accumulate transformations in the matrix Z. 368 for j := iloz; j <= ihiz; j++ { 369 sum := z[j*ldz+k] + v[1]*z[j*ldz+k+1] + v[2]*z[j*ldz+k+2] 370 z[j*ldz+k] -= sum * t0 371 z[j*ldz+k+1] -= sum * t1 372 z[j*ldz+k+2] -= sum * t2 373 } 374 } 375 } else if nr == 2 { 376 // Apply G from the left to transform 377 // the rows of the matrix in columns k 378 // to i2. 379 for j := k; j <= i2; j++ { 380 sum := h[k*ldh+j] + v[1]*h[(k+1)*ldh+j] 381 h[k*ldh+j] -= sum * t0 382 h[(k+1)*ldh+j] -= sum * t1 383 } 384 385 // Apply G from the right to transform 386 // the columns of the matrix in rows i1 387 // to min(k+3,i). 388 for j := i1; j <= i; j++ { 389 sum := h[j*ldh+k] + v[1]*h[j*ldh+k+1] 390 h[j*ldh+k] -= sum * t0 391 h[j*ldh+k+1] -= sum * t1 392 } 393 394 if wantz { 395 // Accumulate transformations in the matrix Z. 396 for j := iloz; j <= ihiz; j++ { 397 sum := z[j*ldz+k] + v[1]*z[j*ldz+k+1] 398 z[j*ldz+k] -= sum * t0 399 z[j*ldz+k+1] -= sum * t1 400 } 401 } 402 } 403 } 404 } 405 406 if !converged { 407 // The QR iteration finished without splitting off a 408 // submatrix of order 1 or 2. 409 return i + 1 410 } 411 412 if l == i { 413 // H[i,i-1] is negligible: one eigenvalue has converged. 414 wr[i] = h[i*ldh+i] 415 wi[i] = 0 416 } else if l == i-1 { 417 // H[i-1,i-2] is negligible: a pair of eigenvalues have converged. 418 419 // Transform the 2×2 submatrix to standard Schur form, 420 // and compute and store the eigenvalues. 421 var cs, sn float64 422 a, b := h[(i-1)*ldh+i-1], h[(i-1)*ldh+i] 423 c, d := h[i*ldh+i-1], h[i*ldh+i] 424 a, b, c, d, wr[i-1], wi[i-1], wr[i], wi[i], cs, sn = impl.Dlanv2(a, b, c, d) 425 h[(i-1)*ldh+i-1], h[(i-1)*ldh+i] = a, b 426 h[i*ldh+i-1], h[i*ldh+i] = c, d 427 428 if wantt { 429 // Apply the transformation to the rest of H. 430 if i2 > i { 431 bi.Drot(i2-i, h[(i-1)*ldh+i+1:], 1, h[i*ldh+i+1:], 1, cs, sn) 432 } 433 bi.Drot(i-i1-1, h[i1*ldh+i-1:], ldh, h[i1*ldh+i:], ldh, cs, sn) 434 } 435 436 if wantz { 437 // Apply the transformation to Z. 438 bi.Drot(nz, z[iloz*ldz+i-1:], ldz, z[iloz*ldz+i:], ldz, cs, sn) 439 } 440 } 441 442 // Reset deflation counter. 443 kdefl = 0 444 445 // Return to start of the main loop with new value of i. 446 i = l - 1 447 } 448 return 0 449 }