1: SUBROUTINE DTGEXC( WANTQ, WANTZ, N, A, LDA, B, LDB, Q, LDQ, Z,
2: $ LDZ, IFST, ILST, WORK, LWORK, INFO )
3: *
4: * -- LAPACK routine (version 3.2) --
5: * -- LAPACK is a software package provided by Univ. of Tennessee, --
6: * -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
7: * November 2006
8: *
9: * .. Scalar Arguments ..
10: LOGICAL WANTQ, WANTZ
11: INTEGER IFST, ILST, INFO, LDA, LDB, LDQ, LDZ, LWORK, N
12: * ..
13: * .. Array Arguments ..
14: DOUBLE PRECISION A( LDA, * ), B( LDB, * ), Q( LDQ, * ),
15: $ WORK( * ), Z( LDZ, * )
16: * ..
17: *
18: * Purpose
19: * =======
20: *
21: * DTGEXC reorders the generalized real Schur decomposition of a real
22: * matrix pair (A,B) using an orthogonal equivalence transformation
23: *
24: * (A, B) = Q * (A, B) * Z',
25: *
26: * so that the diagonal block of (A, B) with row index IFST is moved
27: * to row ILST.
28: *
29: * (A, B) must be in generalized real Schur canonical form (as returned
30: * by DGGES), i.e. A is block upper triangular with 1-by-1 and 2-by-2
31: * diagonal blocks. B is upper triangular.
32: *
33: * Optionally, the matrices Q and Z of generalized Schur vectors are
34: * updated.
35: *
36: * Q(in) * A(in) * Z(in)' = Q(out) * A(out) * Z(out)'
37: * Q(in) * B(in) * Z(in)' = Q(out) * B(out) * Z(out)'
38: *
39: *
40: * Arguments
41: * =========
42: *
43: * WANTQ (input) LOGICAL
44: * .TRUE. : update the left transformation matrix Q;
45: * .FALSE.: do not update Q.
46: *
47: * WANTZ (input) LOGICAL
48: * .TRUE. : update the right transformation matrix Z;
49: * .FALSE.: do not update Z.
50: *
51: * N (input) INTEGER
52: * The order of the matrices A and B. N >= 0.
53: *
54: * A (input/output) DOUBLE PRECISION array, dimension (LDA,N)
55: * On entry, the matrix A in generalized real Schur canonical
56: * form.
57: * On exit, the updated matrix A, again in generalized
58: * real Schur canonical form.
59: *
60: * LDA (input) INTEGER
61: * The leading dimension of the array A. LDA >= max(1,N).
62: *
63: * B (input/output) DOUBLE PRECISION array, dimension (LDB,N)
64: * On entry, the matrix B in generalized real Schur canonical
65: * form (A,B).
66: * On exit, the updated matrix B, again in generalized
67: * real Schur canonical form (A,B).
68: *
69: * LDB (input) INTEGER
70: * The leading dimension of the array B. LDB >= max(1,N).
71: *
72: * Q (input/output) DOUBLE PRECISION array, dimension (LDZ,N)
73: * On entry, if WANTQ = .TRUE., the orthogonal matrix Q.
74: * On exit, the updated matrix Q.
75: * If WANTQ = .FALSE., Q is not referenced.
76: *
77: * LDQ (input) INTEGER
78: * The leading dimension of the array Q. LDQ >= 1.
79: * If WANTQ = .TRUE., LDQ >= N.
80: *
81: * Z (input/output) DOUBLE PRECISION array, dimension (LDZ,N)
82: * On entry, if WANTZ = .TRUE., the orthogonal matrix Z.
83: * On exit, the updated matrix Z.
84: * If WANTZ = .FALSE., Z is not referenced.
85: *
86: * LDZ (input) INTEGER
87: * The leading dimension of the array Z. LDZ >= 1.
88: * If WANTZ = .TRUE., LDZ >= N.
89: *
90: * IFST (input/output) INTEGER
91: * ILST (input/output) INTEGER
92: * Specify the reordering of the diagonal blocks of (A, B).
93: * The block with row index IFST is moved to row ILST, by a
94: * sequence of swapping between adjacent blocks.
95: * On exit, if IFST pointed on entry to the second row of
96: * a 2-by-2 block, it is changed to point to the first row;
97: * ILST always points to the first row of the block in its
98: * final position (which may differ from its input value by
99: * +1 or -1). 1 <= IFST, ILST <= N.
100: *
101: * WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))
102: * On exit, if INFO = 0, WORK(1) returns the optimal LWORK.
103: *
104: * LWORK (input) INTEGER
105: * The dimension of the array WORK.
106: * LWORK >= 1 when N <= 1, otherwise LWORK >= 4*N + 16.
107: *
108: * If LWORK = -1, then a workspace query is assumed; the routine
109: * only calculates the optimal size of the WORK array, returns
110: * this value as the first entry of the WORK array, and no error
111: * message related to LWORK is issued by XERBLA.
112: *
113: * INFO (output) INTEGER
114: * =0: successful exit.
115: * <0: if INFO = -i, the i-th argument had an illegal value.
116: * =1: The transformed matrix pair (A, B) would be too far
117: * from generalized Schur form; the problem is ill-
118: * conditioned. (A, B) may have been partially reordered,
119: * and ILST points to the first row of the current
120: * position of the block being moved.
121: *
122: * Further Details
123: * ===============
124: *
125: * Based on contributions by
126: * Bo Kagstrom and Peter Poromaa, Department of Computing Science,
127: * Umea University, S-901 87 Umea, Sweden.
128: *
129: * [1] B. Kagstrom; A Direct Method for Reordering Eigenvalues in the
130: * Generalized Real Schur Form of a Regular Matrix Pair (A, B), in
131: * M.S. Moonen et al (eds), Linear Algebra for Large Scale and
132: * Real-Time Applications, Kluwer Academic Publ. 1993, pp 195-218.
133: *
134: * =====================================================================
135: *
136: * .. Parameters ..
137: DOUBLE PRECISION ZERO
138: PARAMETER ( ZERO = 0.0D+0 )
139: * ..
140: * .. Local Scalars ..
141: LOGICAL LQUERY
142: INTEGER HERE, LWMIN, NBF, NBL, NBNEXT
143: * ..
144: * .. External Subroutines ..
145: EXTERNAL DTGEX2, XERBLA
146: * ..
147: * .. Intrinsic Functions ..
148: INTRINSIC MAX
149: * ..
150: * .. Executable Statements ..
151: *
152: * Decode and test input arguments.
153: *
154: INFO = 0
155: LQUERY = ( LWORK.EQ.-1 )
156: IF( N.LT.0 ) THEN
157: INFO = -3
158: ELSE IF( LDA.LT.MAX( 1, N ) ) THEN
159: INFO = -5
160: ELSE IF( LDB.LT.MAX( 1, N ) ) THEN
161: INFO = -7
162: ELSE IF( LDQ.LT.1 .OR. WANTQ .AND. ( LDQ.LT.MAX( 1, N ) ) ) THEN
163: INFO = -9
164: ELSE IF( LDZ.LT.1 .OR. WANTZ .AND. ( LDZ.LT.MAX( 1, N ) ) ) THEN
165: INFO = -11
166: ELSE IF( IFST.LT.1 .OR. IFST.GT.N ) THEN
167: INFO = -12
168: ELSE IF( ILST.LT.1 .OR. ILST.GT.N ) THEN
169: INFO = -13
170: END IF
171: *
172: IF( INFO.EQ.0 ) THEN
173: IF( N.LE.1 ) THEN
174: LWMIN = 1
175: ELSE
176: LWMIN = 4*N + 16
177: END IF
178: WORK(1) = LWMIN
179: *
180: IF (LWORK.LT.LWMIN .AND. .NOT.LQUERY) THEN
181: INFO = -15
182: END IF
183: END IF
184: *
185: IF( INFO.NE.0 ) THEN
186: CALL XERBLA( 'DTGEXC', -INFO )
187: RETURN
188: ELSE IF( LQUERY ) THEN
189: RETURN
190: END IF
191: *
192: * Quick return if possible
193: *
194: IF( N.LE.1 )
195: $ RETURN
196: *
197: * Determine the first row of the specified block and find out
198: * if it is 1-by-1 or 2-by-2.
199: *
200: IF( IFST.GT.1 ) THEN
201: IF( A( IFST, IFST-1 ).NE.ZERO )
202: $ IFST = IFST - 1
203: END IF
204: NBF = 1
205: IF( IFST.LT.N ) THEN
206: IF( A( IFST+1, IFST ).NE.ZERO )
207: $ NBF = 2
208: END IF
209: *
210: * Determine the first row of the final block
211: * and find out if it is 1-by-1 or 2-by-2.
212: *
213: IF( ILST.GT.1 ) THEN
214: IF( A( ILST, ILST-1 ).NE.ZERO )
215: $ ILST = ILST - 1
216: END IF
217: NBL = 1
218: IF( ILST.LT.N ) THEN
219: IF( A( ILST+1, ILST ).NE.ZERO )
220: $ NBL = 2
221: END IF
222: IF( IFST.EQ.ILST )
223: $ RETURN
224: *
225: IF( IFST.LT.ILST ) THEN
226: *
227: * Update ILST.
228: *
229: IF( NBF.EQ.2 .AND. NBL.EQ.1 )
230: $ ILST = ILST - 1
231: IF( NBF.EQ.1 .AND. NBL.EQ.2 )
232: $ ILST = ILST + 1
233: *
234: HERE = IFST
235: *
236: 10 CONTINUE
237: *
238: * Swap with next one below.
239: *
240: IF( NBF.EQ.1 .OR. NBF.EQ.2 ) THEN
241: *
242: * Current block either 1-by-1 or 2-by-2.
243: *
244: NBNEXT = 1
245: IF( HERE+NBF+1.LE.N ) THEN
246: IF( A( HERE+NBF+1, HERE+NBF ).NE.ZERO )
247: $ NBNEXT = 2
248: END IF
249: CALL DTGEX2( WANTQ, WANTZ, N, A, LDA, B, LDB, Q, LDQ, Z,
250: $ LDZ, HERE, NBF, NBNEXT, WORK, LWORK, INFO )
251: IF( INFO.NE.0 ) THEN
252: ILST = HERE
253: RETURN
254: END IF
255: HERE = HERE + NBNEXT
256: *
257: * Test if 2-by-2 block breaks into two 1-by-1 blocks.
258: *
259: IF( NBF.EQ.2 ) THEN
260: IF( A( HERE+1, HERE ).EQ.ZERO )
261: $ NBF = 3
262: END IF
263: *
264: ELSE
265: *
266: * Current block consists of two 1-by-1 blocks, each of which
267: * must be swapped individually.
268: *
269: NBNEXT = 1
270: IF( HERE+3.LE.N ) THEN
271: IF( A( HERE+3, HERE+2 ).NE.ZERO )
272: $ NBNEXT = 2
273: END IF
274: CALL DTGEX2( WANTQ, WANTZ, N, A, LDA, B, LDB, Q, LDQ, Z,
275: $ LDZ, HERE+1, 1, NBNEXT, WORK, LWORK, INFO )
276: IF( INFO.NE.0 ) THEN
277: ILST = HERE
278: RETURN
279: END IF
280: IF( NBNEXT.EQ.1 ) THEN
281: *
282: * Swap two 1-by-1 blocks.
283: *
284: CALL DTGEX2( WANTQ, WANTZ, N, A, LDA, B, LDB, Q, LDQ, Z,
285: $ LDZ, HERE, 1, 1, WORK, LWORK, INFO )
286: IF( INFO.NE.0 ) THEN
287: ILST = HERE
288: RETURN
289: END IF
290: HERE = HERE + 1
291: *
292: ELSE
293: *
294: * Recompute NBNEXT in case of 2-by-2 split.
295: *
296: IF( A( HERE+2, HERE+1 ).EQ.ZERO )
297: $ NBNEXT = 1
298: IF( NBNEXT.EQ.2 ) THEN
299: *
300: * 2-by-2 block did not split.
301: *
302: CALL DTGEX2( WANTQ, WANTZ, N, A, LDA, B, LDB, Q, LDQ,
303: $ Z, LDZ, HERE, 1, NBNEXT, WORK, LWORK,
304: $ INFO )
305: IF( INFO.NE.0 ) THEN
306: ILST = HERE
307: RETURN
308: END IF
309: HERE = HERE + 2
310: ELSE
311: *
312: * 2-by-2 block did split.
313: *
314: CALL DTGEX2( WANTQ, WANTZ, N, A, LDA, B, LDB, Q, LDQ,
315: $ Z, LDZ, HERE, 1, 1, WORK, LWORK, INFO )
316: IF( INFO.NE.0 ) THEN
317: ILST = HERE
318: RETURN
319: END IF
320: HERE = HERE + 1
321: CALL DTGEX2( WANTQ, WANTZ, N, A, LDA, B, LDB, Q, LDQ,
322: $ Z, LDZ, HERE, 1, 1, WORK, LWORK, INFO )
323: IF( INFO.NE.0 ) THEN
324: ILST = HERE
325: RETURN
326: END IF
327: HERE = HERE + 1
328: END IF
329: *
330: END IF
331: END IF
332: IF( HERE.LT.ILST )
333: $ GO TO 10
334: ELSE
335: HERE = IFST
336: *
337: 20 CONTINUE
338: *
339: * Swap with next one below.
340: *
341: IF( NBF.EQ.1 .OR. NBF.EQ.2 ) THEN
342: *
343: * Current block either 1-by-1 or 2-by-2.
344: *
345: NBNEXT = 1
346: IF( HERE.GE.3 ) THEN
347: IF( A( HERE-1, HERE-2 ).NE.ZERO )
348: $ NBNEXT = 2
349: END IF
350: CALL DTGEX2( WANTQ, WANTZ, N, A, LDA, B, LDB, Q, LDQ, Z,
351: $ LDZ, HERE-NBNEXT, NBNEXT, NBF, WORK, LWORK,
352: $ INFO )
353: IF( INFO.NE.0 ) THEN
354: ILST = HERE
355: RETURN
356: END IF
357: HERE = HERE - NBNEXT
358: *
359: * Test if 2-by-2 block breaks into two 1-by-1 blocks.
360: *
361: IF( NBF.EQ.2 ) THEN
362: IF( A( HERE+1, HERE ).EQ.ZERO )
363: $ NBF = 3
364: END IF
365: *
366: ELSE
367: *
368: * Current block consists of two 1-by-1 blocks, each of which
369: * must be swapped individually.
370: *
371: NBNEXT = 1
372: IF( HERE.GE.3 ) THEN
373: IF( A( HERE-1, HERE-2 ).NE.ZERO )
374: $ NBNEXT = 2
375: END IF
376: CALL DTGEX2( WANTQ, WANTZ, N, A, LDA, B, LDB, Q, LDQ, Z,
377: $ LDZ, HERE-NBNEXT, NBNEXT, 1, WORK, LWORK,
378: $ INFO )
379: IF( INFO.NE.0 ) THEN
380: ILST = HERE
381: RETURN
382: END IF
383: IF( NBNEXT.EQ.1 ) THEN
384: *
385: * Swap two 1-by-1 blocks.
386: *
387: CALL DTGEX2( WANTQ, WANTZ, N, A, LDA, B, LDB, Q, LDQ, Z,
388: $ LDZ, HERE, NBNEXT, 1, WORK, LWORK, INFO )
389: IF( INFO.NE.0 ) THEN
390: ILST = HERE
391: RETURN
392: END IF
393: HERE = HERE - 1
394: ELSE
395: *
396: * Recompute NBNEXT in case of 2-by-2 split.
397: *
398: IF( A( HERE, HERE-1 ).EQ.ZERO )
399: $ NBNEXT = 1
400: IF( NBNEXT.EQ.2 ) THEN
401: *
402: * 2-by-2 block did not split.
403: *
404: CALL DTGEX2( WANTQ, WANTZ, N, A, LDA, B, LDB, Q, LDQ,
405: $ Z, LDZ, HERE-1, 2, 1, WORK, LWORK, INFO )
406: IF( INFO.NE.0 ) THEN
407: ILST = HERE
408: RETURN
409: END IF
410: HERE = HERE - 2
411: ELSE
412: *
413: * 2-by-2 block did split.
414: *
415: CALL DTGEX2( WANTQ, WANTZ, N, A, LDA, B, LDB, Q, LDQ,
416: $ Z, LDZ, HERE, 1, 1, WORK, LWORK, INFO )
417: IF( INFO.NE.0 ) THEN
418: ILST = HERE
419: RETURN
420: END IF
421: HERE = HERE - 1
422: CALL DTGEX2( WANTQ, WANTZ, N, A, LDA, B, LDB, Q, LDQ,
423: $ Z, LDZ, HERE, 1, 1, WORK, LWORK, INFO )
424: IF( INFO.NE.0 ) THEN
425: ILST = HERE
426: RETURN
427: END IF
428: HERE = HERE - 1
429: END IF
430: END IF
431: END IF
432: IF( HERE.GT.ILST )
433: $ GO TO 20
434: END IF
435: ILST = HERE
436: WORK( 1 ) = LWMIN
437: RETURN
438: *
439: * End of DTGEXC
440: *
441: END
CVSweb interface <joel.bertrand@systella.fr>