OSDN Git Service

test (#52)
[bytom/vapor.git] / vendor / gonum.org / v1 / gonum / lapack / gonum / dhseqr.go
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"
11         "gonum.org/v1/gonum/lapack"
12 )
13
14 // Dhseqr computes the eigenvalues of an n×n Hessenberg matrix H and,
15 // optionally, the matrices T and Z from the Schur decomposition
16 //  H = Z T Z^T,
17 // where T is an n×n upper quasi-triangular matrix (the Schur form), and Z is
18 // the n×n orthogonal matrix of Schur vectors.
19 //
20 // Optionally Z may be postmultiplied into an input orthogonal matrix Q so that
21 // this routine can give the Schur factorization of a matrix A which has been
22 // reduced to the Hessenberg form H by the orthogonal matrix Q:
23 //  A = Q H Q^T = (QZ) T (QZ)^T.
24 //
25 // If job == lapack.EigenvaluesOnly, only the eigenvalues will be computed.
26 // If job == lapack.EigenvaluesAndSchur, the eigenvalues and the Schur form T will
27 // be computed.
28 // For other values of job Dhseqr will panic.
29 //
30 // If compz == lapack.None, no Schur vectors will be computed and Z will not be
31 // referenced.
32 // If compz == lapack.HessEV, on return Z will contain the matrix of Schur
33 // vectors of H.
34 // If compz == lapack.OriginalEV, on entry z is assumed to contain the orthogonal
35 // matrix Q that is the identity except for the submatrix
36 // Q[ilo:ihi+1,ilo:ihi+1]. On return z will be updated to the product Q*Z.
37 //
38 // ilo and ihi determine the block of H on which Dhseqr operates. It is assumed
39 // that H is already upper triangular in rows and columns [0:ilo] and [ihi+1:n],
40 // although it will be only checked that the block is isolated, that is,
41 //  ilo == 0   or H[ilo,ilo-1] == 0,
42 //  ihi == n-1 or H[ihi+1,ihi] == 0,
43 // and Dhseqr will panic otherwise. ilo and ihi are typically set by a previous
44 // call to Dgebal, otherwise they should be set to 0 and n-1, respectively. It
45 // must hold that
46 //  0 <= ilo <= ihi < n,     if n > 0,
47 //  ilo == 0 and ihi == -1,  if n == 0.
48 //
49 // wr and wi must have length n.
50 //
51 // work must have length at least lwork and lwork must be at least max(1,n)
52 // otherwise Dhseqr will panic. The minimum lwork delivers very good and
53 // sometimes optimal performance, although lwork as large as 11*n may be
54 // required. On return, work[0] will contain the optimal value of lwork.
55 //
56 // If lwork is -1, instead of performing Dhseqr, the function only estimates the
57 // optimal workspace size and stores it into work[0]. Neither h nor z are
58 // accessed.
59 //
60 // unconverged indicates whether Dhseqr computed all the eigenvalues.
61 //
62 // If unconverged == 0, all the eigenvalues have been computed and their real
63 // and imaginary parts will be stored on return in wr and wi, respectively. If
64 // two eigenvalues are computed as a complex conjugate pair, they are stored in
65 // consecutive elements of wr and wi, say the i-th and (i+1)th, with wi[i] > 0
66 // and wi[i+1] < 0.
67 //
68 // If unconverged == 0 and job == lapack.EigenvaluesAndSchur, on return H will
69 // contain the upper quasi-triangular matrix T from the Schur decomposition (the
70 // Schur form). 2×2 diagonal blocks (corresponding to complex conjugate pairs of
71 // eigenvalues) will be returned in standard form, with
72 //  H[i,i] == H[i+1,i+1],
73 // and
74 //  H[i+1,i]*H[i,i+1] < 0.
75 // The eigenvalues will be stored in wr and wi in the same order as on the
76 // diagonal of the Schur form returned in H, with
77 //  wr[i] = H[i,i],
78 // and, if H[i:i+2,i:i+2] is a 2×2 diagonal block,
79 //  wi[i]   = sqrt(-H[i+1,i]*H[i,i+1]),
80 //  wi[i+1] = -wi[i].
81 //
82 // If unconverged == 0 and job == lapack.EigenvaluesOnly, the contents of h
83 // on return is unspecified.
84 //
85 // If unconverged > 0, some eigenvalues have not converged, and the blocks
86 // [0:ilo] and [unconverged:n] of wr and wi will contain those eigenvalues which
87 // have been successfully computed. Failures are rare.
88 //
89 // If unconverged > 0 and job == lapack.EigenvaluesOnly, on return the
90 // remaining unconverged eigenvalues are the eigenvalues of the upper Hessenberg
91 // matrix H[ilo:unconverged,ilo:unconverged].
92 //
93 // If unconverged > 0 and job == lapack.EigenvaluesAndSchur, then on
94 // return
95 //  (initial H) U = U (final H),   (*)
96 // where U is an orthogonal matrix. The final H is upper Hessenberg and
97 // H[unconverged:ihi+1,unconverged:ihi+1] is upper quasi-triangular.
98 //
99 // If unconverged > 0 and compz == lapack.OriginalEV, then on return
100 //  (final Z) = (initial Z) U,
101 // where U is the orthogonal matrix in (*) regardless of the value of job.
102 //
103 // If unconverged > 0 and compz == lapack.HessEV, then on return
104 //  (final Z) = U,
105 // where U is the orthogonal matrix in (*) regardless of the value of job.
106 //
107 // References:
108 //  [1] R. Byers. LAPACK 3.1 xHSEQR: Tuning and Implementation Notes on the
109 //      Small Bulge Multi-Shift QR Algorithm with Aggressive Early Deflation.
110 //      LAPACK Working Note 187 (2007)
111 //      URL: http://www.netlib.org/lapack/lawnspdf/lawn187.pdf
112 //  [2] K. Braman, R. Byers, R. Mathias. The Multishift QR Algorithm. Part I:
113 //      Maintaining Well-Focused Shifts and Level 3 Performance. SIAM J. Matrix
114 //      Anal. Appl. 23(4) (2002), pp. 929—947
115 //      URL: http://dx.doi.org/10.1137/S0895479801384573
116 //  [3] K. Braman, R. Byers, R. Mathias. The Multishift QR Algorithm. Part II:
117 //      Aggressive Early Deflation. SIAM J. Matrix Anal. Appl. 23(4) (2002), pp. 948—973
118 //      URL: http://dx.doi.org/10.1137/S0895479801384585
119 //
120 // Dhseqr is an internal routine. It is exported for testing purposes.
121 func (impl Implementation) Dhseqr(job lapack.EVJob, compz lapack.EVComp, n, ilo, ihi int, h []float64, ldh int, wr, wi []float64, z []float64, ldz int, work []float64, lwork int) (unconverged int) {
122         var wantt bool
123         switch job {
124         default:
125                 panic(badEVJob)
126         case lapack.EigenvaluesOnly:
127         case lapack.EigenvaluesAndSchur:
128                 wantt = true
129         }
130         var wantz bool
131         switch compz {
132         default:
133                 panic(badEVComp)
134         case lapack.None:
135         case lapack.HessEV, lapack.OriginalEV:
136                 wantz = true
137         }
138         switch {
139         case n < 0:
140                 panic(nLT0)
141         case ilo < 0 || max(0, n-1) < ilo:
142                 panic(badIlo)
143         case ihi < min(ilo, n-1) || n <= ihi:
144                 panic(badIhi)
145         case len(work) < lwork:
146                 panic(shortWork)
147         case lwork < max(1, n) && lwork != -1:
148                 panic(badWork)
149         }
150         if lwork != -1 {
151                 checkMatrix(n, n, h, ldh)
152                 switch {
153                 case wantz:
154                         checkMatrix(n, n, z, ldz)
155                 case len(wr) < n:
156                         panic("lapack: wr has insufficient length")
157                 case len(wi) < n:
158                         panic("lapack: wi has insufficient length")
159                 }
160         }
161
162         const (
163                 // Matrices of order ntiny or smaller must be processed by
164                 // Dlahqr because of insufficient subdiagonal scratch space.
165                 // This is a hard limit.
166                 ntiny = 11
167
168                 // nl is the size of a local workspace to help small matrices
169                 // through a rare Dlahqr failure. nl > ntiny is required and
170                 // nl <= nmin = Ilaenv(ispec=12,...) is recommended (the default
171                 // value of nmin is 75). Using nl = 49 allows up to six
172                 // simultaneous shifts and a 16×16 deflation window.
173                 nl = 49
174         )
175
176         // Quick return if possible.
177         if n == 0 {
178                 work[0] = 1
179                 return 0
180         }
181
182         // Quick return in case of a workspace query.
183         if lwork == -1 {
184                 impl.Dlaqr04(wantt, wantz, n, ilo, ihi, nil, 0, nil, nil, ilo, ihi, nil, 0, work, -1, 1)
185                 work[0] = math.Max(float64(n), work[0])
186                 return 0
187         }
188
189         // Copy eigenvalues isolated by Dgebal.
190         for i := 0; i < ilo; i++ {
191                 wr[i] = h[i*ldh+i]
192                 wi[i] = 0
193         }
194         for i := ihi + 1; i < n; i++ {
195                 wr[i] = h[i*ldh+i]
196                 wi[i] = 0
197         }
198
199         // Initialize Z to identity matrix if requested.
200         if compz == lapack.HessEV {
201                 impl.Dlaset(blas.All, n, n, 0, 1, z, ldz)
202         }
203
204         // Quick return if possible.
205         if ilo == ihi {
206                 wr[ilo] = h[ilo*ldh+ilo]
207                 wi[ilo] = 0
208                 return 0
209         }
210
211         // Dlahqr/Dlaqr04 crossover point.
212         nmin := impl.Ilaenv(12, "DHSEQR", string(job)+string(compz), n, ilo, ihi, lwork)
213         nmin = max(ntiny, nmin)
214
215         if n > nmin {
216                 // Dlaqr0 for big matrices.
217                 unconverged = impl.Dlaqr04(wantt, wantz, n, ilo, ihi, h, ldh, wr[:ihi+1], wi[:ihi+1],
218                         ilo, ihi, z, ldz, work, lwork, 1)
219         } else {
220                 // Dlahqr for small matrices.
221                 unconverged = impl.Dlahqr(wantt, wantz, n, ilo, ihi, h, ldh, wr[:ihi+1], wi[:ihi+1],
222                         ilo, ihi, z, ldz)
223                 if unconverged > 0 {
224                         // A rare Dlahqr failure! Dlaqr04 sometimes succeeds
225                         // when Dlahqr fails.
226                         kbot := unconverged
227                         if n >= nl {
228                                 // Larger matrices have enough subdiagonal
229                                 // scratch space to call Dlaqr04 directly.
230                                 unconverged = impl.Dlaqr04(wantt, wantz, n, ilo, kbot, h, ldh,
231                                         wr[:ihi+1], wi[:ihi+1], ilo, ihi, z, ldz, work, lwork, 1)
232                         } else {
233                                 // Tiny matrices don't have enough subdiagonal
234                                 // scratch space to benefit from Dlaqr04. Hence,
235                                 // tiny matrices must be copied into a larger
236                                 // array before calling Dlaqr04.
237                                 var hl [nl * nl]float64
238                                 impl.Dlacpy(blas.All, n, n, h, ldh, hl[:], nl)
239                                 impl.Dlaset(blas.All, nl, nl-n, 0, 0, hl[n:], nl)
240                                 var workl [nl]float64
241                                 unconverged = impl.Dlaqr04(wantt, wantz, nl, ilo, kbot, hl[:], nl,
242                                         wr[:ihi+1], wi[:ihi+1], ilo, ihi, z, ldz, workl[:], nl, 1)
243                                 work[0] = workl[0]
244                                 if wantt || unconverged > 0 {
245                                         impl.Dlacpy(blas.All, n, n, hl[:], nl, h, ldh)
246                                 }
247                         }
248                 }
249         }
250         // Zero out under the first subdiagonal, if necessary.
251         if (wantt || unconverged > 0) && n > 2 {
252                 impl.Dlaset(blas.Lower, n-2, n-2, 0, 0, h[2*ldh:], ldh)
253         }
254
255         work[0] = math.Max(float64(n), work[0])
256         return unconverged
257 }