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  }