3e2ca3b89ba8d7c0388ca6e626a983579757b05b
[platform/upstream/lapack.git] / SRC / strexc.f
1 *> \brief \b STREXC
2 *
3 *  =========== DOCUMENTATION ===========
4 *
5 * Online html documentation available at 
6 *            http://www.netlib.org/lapack/explore-html/ 
7 *
8 *> \htmlonly
9 *> Download STREXC + dependencies 
10 *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/strexc.f"> 
11 *> [TGZ]</a> 
12 *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/strexc.f"> 
13 *> [ZIP]</a> 
14 *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/strexc.f"> 
15 *> [TXT]</a>
16 *> \endhtmlonly 
17 *
18 *  Definition:
19 *  ===========
20 *
21 *       SUBROUTINE STREXC( COMPQ, N, T, LDT, Q, LDQ, IFST, ILST, WORK,
22 *                          INFO )
23
24 *       .. Scalar Arguments ..
25 *       CHARACTER          COMPQ
26 *       INTEGER            IFST, ILST, INFO, LDQ, LDT, N
27 *       ..
28 *       .. Array Arguments ..
29 *       REAL               Q( LDQ, * ), T( LDT, * ), WORK( * )
30 *       ..
31 *  
32 *
33 *> \par Purpose:
34 *  =============
35 *>
36 *> \verbatim
37 *>
38 *> STREXC reorders the real Schur factorization of a real matrix
39 *> A = Q*T*Q**T, so that the diagonal block of T with row index IFST is
40 *> moved to row ILST.
41 *>
42 *> The real Schur form T is reordered by an orthogonal similarity
43 *> transformation Z**T*T*Z, and optionally the matrix Q of Schur vectors
44 *> is updated by postmultiplying it with Z.
45 *>
46 *> T must be in Schur canonical form (as returned by SHSEQR), that is,
47 *> block upper triangular with 1-by-1 and 2-by-2 diagonal blocks; each
48 *> 2-by-2 diagonal block has its diagonal elements equal and its
49 *> off-diagonal elements of opposite sign.
50 *> \endverbatim
51 *
52 *  Arguments:
53 *  ==========
54 *
55 *> \param[in] COMPQ
56 *> \verbatim
57 *>          COMPQ is CHARACTER*1
58 *>          = 'V':  update the matrix Q of Schur vectors;
59 *>          = 'N':  do not update Q.
60 *> \endverbatim
61 *>
62 *> \param[in] N
63 *> \verbatim
64 *>          N is INTEGER
65 *>          The order of the matrix T. N >= 0.
66 *> \endverbatim
67 *>
68 *> \param[in,out] T
69 *> \verbatim
70 *>          T is REAL array, dimension (LDT,N)
71 *>          On entry, the upper quasi-triangular matrix T, in Schur
72 *>          Schur canonical form.
73 *>          On exit, the reordered upper quasi-triangular matrix, again
74 *>          in Schur canonical form.
75 *> \endverbatim
76 *>
77 *> \param[in] LDT
78 *> \verbatim
79 *>          LDT is INTEGER
80 *>          The leading dimension of the array T. LDT >= max(1,N).
81 *> \endverbatim
82 *>
83 *> \param[in,out] Q
84 *> \verbatim
85 *>          Q is REAL array, dimension (LDQ,N)
86 *>          On entry, if COMPQ = 'V', the matrix Q of Schur vectors.
87 *>          On exit, if COMPQ = 'V', Q has been postmultiplied by the
88 *>          orthogonal transformation matrix Z which reorders T.
89 *>          If COMPQ = 'N', Q is not referenced.
90 *> \endverbatim
91 *>
92 *> \param[in] LDQ
93 *> \verbatim
94 *>          LDQ is INTEGER
95 *>          The leading dimension of the array Q.  LDQ >= max(1,N).
96 *> \endverbatim
97 *>
98 *> \param[in,out] IFST
99 *> \verbatim
100 *>          IFST is INTEGER
101 *> \endverbatim
102 *>
103 *> \param[in,out] ILST
104 *> \verbatim
105 *>          ILST is INTEGER
106 *>
107 *>          Specify the reordering of the diagonal blocks of T.
108 *>          The block with row index IFST is moved to row ILST, by a
109 *>          sequence of transpositions between adjacent blocks.
110 *>          On exit, if IFST pointed on entry to the second row of a
111 *>          2-by-2 block, it is changed to point to the first row; ILST
112 *>          always points to the first row of the block in its final
113 *>          position (which may differ from its input value by +1 or -1).
114 *>          1 <= IFST <= N; 1 <= ILST <= N.
115 *> \endverbatim
116 *>
117 *> \param[out] WORK
118 *> \verbatim
119 *>          WORK is REAL array, dimension (N)
120 *> \endverbatim
121 *>
122 *> \param[out] INFO
123 *> \verbatim
124 *>          INFO is INTEGER
125 *>          = 0:  successful exit
126 *>          < 0:  if INFO = -i, the i-th argument had an illegal value
127 *>          = 1:  two adjacent blocks were too close to swap (the problem
128 *>                is very ill-conditioned); T may have been partially
129 *>                reordered, and ILST points to the first row of the
130 *>                current position of the block being moved.
131 *> \endverbatim
132 *
133 *  Authors:
134 *  ========
135 *
136 *> \author Univ. of Tennessee 
137 *> \author Univ. of California Berkeley 
138 *> \author Univ. of Colorado Denver 
139 *> \author NAG Ltd. 
140 *
141 *> \date November 2011
142 *
143 *> \ingroup realOTHERcomputational
144 *
145 *  =====================================================================
146       SUBROUTINE STREXC( COMPQ, N, T, LDT, Q, LDQ, IFST, ILST, WORK,
147      $                   INFO )
148 *
149 *  -- LAPACK computational routine (version 3.4.0) --
150 *  -- LAPACK is a software package provided by Univ. of Tennessee,    --
151 *  -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
152 *     November 2011
153 *
154 *     .. Scalar Arguments ..
155       CHARACTER          COMPQ
156       INTEGER            IFST, ILST, INFO, LDQ, LDT, N
157 *     ..
158 *     .. Array Arguments ..
159       REAL               Q( LDQ, * ), T( LDT, * ), WORK( * )
160 *     ..
161 *
162 *  =====================================================================
163 *
164 *     .. Parameters ..
165       REAL               ZERO
166       PARAMETER          ( ZERO = 0.0E+0 )
167 *     ..
168 *     .. Local Scalars ..
169       LOGICAL            WANTQ
170       INTEGER            HERE, NBF, NBL, NBNEXT
171 *     ..
172 *     .. External Functions ..
173       LOGICAL            LSAME
174       EXTERNAL           LSAME
175 *     ..
176 *     .. External Subroutines ..
177       EXTERNAL           SLAEXC, XERBLA
178 *     ..
179 *     .. Intrinsic Functions ..
180       INTRINSIC          MAX
181 *     ..
182 *     .. Executable Statements ..
183 *
184 *     Decode and test the input arguments.
185 *
186       INFO = 0
187       WANTQ = LSAME( COMPQ, 'V' )
188       IF( .NOT.WANTQ .AND. .NOT.LSAME( COMPQ, 'N' ) ) THEN
189          INFO = -1
190       ELSE IF( N.LT.0 ) THEN
191          INFO = -2
192       ELSE IF( LDT.LT.MAX( 1, N ) ) THEN
193          INFO = -4
194       ELSE IF( LDQ.LT.1 .OR. ( WANTQ .AND. LDQ.LT.MAX( 1, N ) ) ) THEN
195          INFO = -6
196       ELSE IF( IFST.LT.1 .OR. IFST.GT.N ) THEN
197          INFO = -7
198       ELSE IF( ILST.LT.1 .OR. ILST.GT.N ) THEN
199          INFO = -8
200       END IF
201       IF( INFO.NE.0 ) THEN
202          CALL XERBLA( 'STREXC', -INFO )
203          RETURN
204       END IF
205 *
206 *     Quick return if possible
207 *
208       IF( N.LE.1 )
209      $   RETURN
210 *
211 *     Determine the first row of specified block
212 *     and find out it is 1 by 1 or 2 by 2.
213 *
214       IF( IFST.GT.1 ) THEN
215          IF( T( IFST, IFST-1 ).NE.ZERO )
216      $      IFST = IFST - 1
217       END IF
218       NBF = 1
219       IF( IFST.LT.N ) THEN
220          IF( T( IFST+1, IFST ).NE.ZERO )
221      $      NBF = 2
222       END IF
223 *
224 *     Determine the first row of the final block
225 *     and find out it is 1 by 1 or 2 by 2.
226 *
227       IF( ILST.GT.1 ) THEN
228          IF( T( ILST, ILST-1 ).NE.ZERO )
229      $      ILST = ILST - 1
230       END IF
231       NBL = 1
232       IF( ILST.LT.N ) THEN
233          IF( T( ILST+1, ILST ).NE.ZERO )
234      $      NBL = 2
235       END IF
236 *
237       IF( IFST.EQ.ILST )
238      $   RETURN
239 *
240       IF( IFST.LT.ILST ) THEN
241 *
242 *        Update ILST
243 *
244          IF( NBF.EQ.2 .AND. NBL.EQ.1 )
245      $      ILST = ILST - 1
246          IF( NBF.EQ.1 .AND. NBL.EQ.2 )
247      $      ILST = ILST + 1
248 *
249          HERE = IFST
250 *
251    10    CONTINUE
252 *
253 *        Swap block with next one below
254 *
255          IF( NBF.EQ.1 .OR. NBF.EQ.2 ) THEN
256 *
257 *           Current block either 1 by 1 or 2 by 2
258 *
259             NBNEXT = 1
260             IF( HERE+NBF+1.LE.N ) THEN
261                IF( T( HERE+NBF+1, HERE+NBF ).NE.ZERO )
262      $            NBNEXT = 2
263             END IF
264             CALL SLAEXC( WANTQ, N, T, LDT, Q, LDQ, HERE, NBF, NBNEXT,
265      $                   WORK, INFO )
266             IF( INFO.NE.0 ) THEN
267                ILST = HERE
268                RETURN
269             END IF
270             HERE = HERE + NBNEXT
271 *
272 *           Test if 2 by 2 block breaks into two 1 by 1 blocks
273 *
274             IF( NBF.EQ.2 ) THEN
275                IF( T( HERE+1, HERE ).EQ.ZERO )
276      $            NBF = 3
277             END IF
278 *
279          ELSE
280 *
281 *           Current block consists of two 1 by 1 blocks each of which
282 *           must be swapped individually
283 *
284             NBNEXT = 1
285             IF( HERE+3.LE.N ) THEN
286                IF( T( HERE+3, HERE+2 ).NE.ZERO )
287      $            NBNEXT = 2
288             END IF
289             CALL SLAEXC( WANTQ, N, T, LDT, Q, LDQ, HERE+1, 1, NBNEXT,
290      $                   WORK, INFO )
291             IF( INFO.NE.0 ) THEN
292                ILST = HERE
293                RETURN
294             END IF
295             IF( NBNEXT.EQ.1 ) THEN
296 *
297 *              Swap two 1 by 1 blocks, no problems possible
298 *
299                CALL SLAEXC( WANTQ, N, T, LDT, Q, LDQ, HERE, 1, NBNEXT,
300      $                      WORK, INFO )
301                HERE = HERE + 1
302             ELSE
303 *
304 *              Recompute NBNEXT in case 2 by 2 split
305 *
306                IF( T( HERE+2, HERE+1 ).EQ.ZERO )
307      $            NBNEXT = 1
308                IF( NBNEXT.EQ.2 ) THEN
309 *
310 *                 2 by 2 Block did not split
311 *
312                   CALL SLAEXC( WANTQ, N, T, LDT, Q, LDQ, HERE, 1,
313      $                         NBNEXT, WORK, INFO )
314                   IF( INFO.NE.0 ) THEN
315                      ILST = HERE
316                      RETURN
317                   END IF
318                   HERE = HERE + 2
319                ELSE
320 *
321 *                 2 by 2 Block did split
322 *
323                   CALL SLAEXC( WANTQ, N, T, LDT, Q, LDQ, HERE, 1, 1,
324      $                         WORK, INFO )
325                   CALL SLAEXC( WANTQ, N, T, LDT, Q, LDQ, HERE+1, 1, 1,
326      $                         WORK, INFO )
327                   HERE = HERE + 2
328                END IF
329             END IF
330          END IF
331          IF( HERE.LT.ILST )
332      $      GO TO 10
333 *
334       ELSE
335 *
336          HERE = IFST
337    20    CONTINUE
338 *
339 *        Swap block with next one above
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( T( HERE-1, HERE-2 ).NE.ZERO )
348      $            NBNEXT = 2
349             END IF
350             CALL SLAEXC( WANTQ, N, T, LDT, Q, LDQ, HERE-NBNEXT, NBNEXT,
351      $                   NBF, WORK, INFO )
352             IF( INFO.NE.0 ) THEN
353                ILST = HERE
354                RETURN
355             END IF
356             HERE = HERE - NBNEXT
357 *
358 *           Test if 2 by 2 block breaks into two 1 by 1 blocks
359 *
360             IF( NBF.EQ.2 ) THEN
361                IF( T( HERE+1, HERE ).EQ.ZERO )
362      $            NBF = 3
363             END IF
364 *
365          ELSE
366 *
367 *           Current block consists of two 1 by 1 blocks each of which
368 *           must be swapped individually
369 *
370             NBNEXT = 1
371             IF( HERE.GE.3 ) THEN
372                IF( T( HERE-1, HERE-2 ).NE.ZERO )
373      $            NBNEXT = 2
374             END IF
375             CALL SLAEXC( WANTQ, N, T, LDT, Q, LDQ, HERE-NBNEXT, NBNEXT,
376      $                   1, WORK, INFO )
377             IF( INFO.NE.0 ) THEN
378                ILST = HERE
379                RETURN
380             END IF
381             IF( NBNEXT.EQ.1 ) THEN
382 *
383 *              Swap two 1 by 1 blocks, no problems possible
384 *
385                CALL SLAEXC( WANTQ, N, T, LDT, Q, LDQ, HERE, NBNEXT, 1,
386      $                      WORK, INFO )
387                HERE = HERE - 1
388             ELSE
389 *
390 *              Recompute NBNEXT in case 2 by 2 split
391 *
392                IF( T( HERE, HERE-1 ).EQ.ZERO )
393      $            NBNEXT = 1
394                IF( NBNEXT.EQ.2 ) THEN
395 *
396 *                 2 by 2 Block did not split
397 *
398                   CALL SLAEXC( WANTQ, N, T, LDT, Q, LDQ, HERE-1, 2, 1,
399      $                         WORK, INFO )
400                   IF( INFO.NE.0 ) THEN
401                      ILST = HERE
402                      RETURN
403                   END IF
404                   HERE = HERE - 2
405                ELSE
406 *
407 *                 2 by 2 Block did split
408 *
409                   CALL SLAEXC( WANTQ, N, T, LDT, Q, LDQ, HERE, 1, 1,
410      $                         WORK, INFO )
411                   CALL SLAEXC( WANTQ, N, T, LDT, Q, LDQ, HERE-1, 1, 1,
412      $                         WORK, INFO )
413                   HERE = HERE - 2
414                END IF
415             END IF
416          END IF
417          IF( HERE.GT.ILST )
418      $      GO TO 20
419       END IF
420       ILST = HERE
421 *
422       RETURN
423 *
424 *     End of STREXC
425 *
426       END