LAPACK  3.4.2
LAPACK: Linear Algebra PACKage
 All Files Functions Groups
sorcsd.f
Go to the documentation of this file.
1 *> \brief \b SORCSD
2 *
3 * =========== DOCUMENTATION ===========
4 *
5 * Online html documentation available at
6 * http://www.netlib.org/lapack/explore-html/
7 *
8 *> \htmlonly
9 *> Download SORCSD + dependencies
10 *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/sorcsd.f">
11 *> [TGZ]</a>
12 *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/sorcsd.f">
13 *> [ZIP]</a>
14 *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/sorcsd.f">
15 *> [TXT]</a>
16 *> \endhtmlonly
17 *
18 * Definition:
19 * ===========
20 *
21 * RECURSIVE SUBROUTINE SORCSD( JOBU1, JOBU2, JOBV1T, JOBV2T, TRANS,
22 * SIGNS, M, P, Q, X11, LDX11, X12,
23 * LDX12, X21, LDX21, X22, LDX22, THETA,
24 * U1, LDU1, U2, LDU2, V1T, LDV1T, V2T,
25 * LDV2T, WORK, LWORK, IWORK, INFO )
26 *
27 * .. Scalar Arguments ..
28 * CHARACTER JOBU1, JOBU2, JOBV1T, JOBV2T, SIGNS, TRANS
29 * INTEGER INFO, LDU1, LDU2, LDV1T, LDV2T, LDX11, LDX12,
30 * $ LDX21, LDX22, LWORK, M, P, Q
31 * ..
32 * .. Array Arguments ..
33 * INTEGER IWORK( * )
34 * REAL THETA( * )
35 * REAL U1( LDU1, * ), U2( LDU2, * ), V1T( LDV1T, * ),
36 * $ V2T( LDV2T, * ), WORK( * ), X11( LDX11, * ),
37 * $ X12( LDX12, * ), X21( LDX21, * ), X22( LDX22,
38 * $ * )
39 * ..
40 *
41 *
42 *> \par Purpose:
43 * =============
44 *>
45 *> \verbatim
46 *>
47 *> SORCSD computes the CS decomposition of an M-by-M partitioned
48 *> orthogonal matrix X:
49 *>
50 *> [ I 0 0 | 0 0 0 ]
51 *> [ 0 C 0 | 0 -S 0 ]
52 *> [ X11 | X12 ] [ U1 | ] [ 0 0 0 | 0 0 -I ] [ V1 | ]**T
53 *> X = [-----------] = [---------] [---------------------] [---------] .
54 *> [ X21 | X22 ] [ | U2 ] [ 0 0 0 | I 0 0 ] [ | V2 ]
55 *> [ 0 S 0 | 0 C 0 ]
56 *> [ 0 0 I | 0 0 0 ]
57 *>
58 *> X11 is P-by-Q. The orthogonal matrices U1, U2, V1, and V2 are P-by-P,
59 *> (M-P)-by-(M-P), Q-by-Q, and (M-Q)-by-(M-Q), respectively. C and S are
60 *> R-by-R nonnegative diagonal matrices satisfying C^2 + S^2 = I, in
61 *> which R = MIN(P,M-P,Q,M-Q).
62 *> \endverbatim
63 *
64 * Arguments:
65 * ==========
66 *
67 *> \param[in] JOBU1
68 *> \verbatim
69 *> JOBU1 is CHARACTER
70 *> = 'Y': U1 is computed;
71 *> otherwise: U1 is not computed.
72 *> \endverbatim
73 *>
74 *> \param[in] JOBU2
75 *> \verbatim
76 *> JOBU2 is CHARACTER
77 *> = 'Y': U2 is computed;
78 *> otherwise: U2 is not computed.
79 *> \endverbatim
80 *>
81 *> \param[in] JOBV1T
82 *> \verbatim
83 *> JOBV1T is CHARACTER
84 *> = 'Y': V1T is computed;
85 *> otherwise: V1T is not computed.
86 *> \endverbatim
87 *>
88 *> \param[in] JOBV2T
89 *> \verbatim
90 *> JOBV2T is CHARACTER
91 *> = 'Y': V2T is computed;
92 *> otherwise: V2T is not computed.
93 *> \endverbatim
94 *>
95 *> \param[in] TRANS
96 *> \verbatim
97 *> TRANS is CHARACTER
98 *> = 'T': X, U1, U2, V1T, and V2T are stored in row-major
99 *> order;
100 *> otherwise: X, U1, U2, V1T, and V2T are stored in column-
101 *> major order.
102 *> \endverbatim
103 *>
104 *> \param[in] SIGNS
105 *> \verbatim
106 *> SIGNS is CHARACTER
107 *> = 'O': The lower-left block is made nonpositive (the
108 *> "other" convention);
109 *> otherwise: The upper-right block is made nonpositive (the
110 *> "default" convention).
111 *> \endverbatim
112 *>
113 *> \param[in] M
114 *> \verbatim
115 *> M is INTEGER
116 *> The number of rows and columns in X.
117 *> \endverbatim
118 *>
119 *> \param[in] P
120 *> \verbatim
121 *> P is INTEGER
122 *> The number of rows in X11 and X12. 0 <= P <= M.
123 *> \endverbatim
124 *>
125 *> \param[in] Q
126 *> \verbatim
127 *> Q is INTEGER
128 *> The number of columns in X11 and X21. 0 <= Q <= M.
129 *> \endverbatim
130 *>
131 *> \param[in,out] X11
132 *> \verbatim
133 *> X11 is REAL array, dimension (LDX11,Q)
134 *> On entry, part of the orthogonal matrix whose CSD is desired.
135 *> \endverbatim
136 *>
137 *> \param[in] LDX11
138 *> \verbatim
139 *> LDX11 is INTEGER
140 *> The leading dimension of X11. LDX11 >= MAX(1,P).
141 *> \endverbatim
142 *>
143 *> \param[in,out] X12
144 *> \verbatim
145 *> X12 is REAL array, dimension (LDX12,M-Q)
146 *> On entry, part of the orthogonal matrix whose CSD is desired.
147 *> \endverbatim
148 *>
149 *> \param[in] LDX12
150 *> \verbatim
151 *> LDX12 is INTEGER
152 *> The leading dimension of X12. LDX12 >= MAX(1,P).
153 *> \endverbatim
154 *>
155 *> \param[in,out] X21
156 *> \verbatim
157 *> X21 is REAL array, dimension (LDX21,Q)
158 *> On entry, part of the orthogonal matrix whose CSD is desired.
159 *> \endverbatim
160 *>
161 *> \param[in] LDX21
162 *> \verbatim
163 *> LDX21 is INTEGER
164 *> The leading dimension of X11. LDX21 >= MAX(1,M-P).
165 *> \endverbatim
166 *>
167 *> \param[in,out] X22
168 *> \verbatim
169 *> X22 is REAL array, dimension (LDX22,M-Q)
170 *> On entry, part of the orthogonal matrix whose CSD is desired.
171 *> \endverbatim
172 *>
173 *> \param[in] LDX22
174 *> \verbatim
175 *> LDX22 is INTEGER
176 *> The leading dimension of X11. LDX22 >= MAX(1,M-P).
177 *> \endverbatim
178 *>
179 *> \param[out] THETA
180 *> \verbatim
181 *> THETA is REAL array, dimension (R), in which R =
182 *> MIN(P,M-P,Q,M-Q).
183 *> C = DIAG( COS(THETA(1)), ... , COS(THETA(R)) ) and
184 *> S = DIAG( SIN(THETA(1)), ... , SIN(THETA(R)) ).
185 *> \endverbatim
186 *>
187 *> \param[out] U1
188 *> \verbatim
189 *> U1 is REAL array, dimension (P)
190 *> If JOBU1 = 'Y', U1 contains the P-by-P orthogonal matrix U1.
191 *> \endverbatim
192 *>
193 *> \param[in] LDU1
194 *> \verbatim
195 *> LDU1 is INTEGER
196 *> The leading dimension of U1. If JOBU1 = 'Y', LDU1 >=
197 *> MAX(1,P).
198 *> \endverbatim
199 *>
200 *> \param[out] U2
201 *> \verbatim
202 *> U2 is REAL array, dimension (M-P)
203 *> If JOBU2 = 'Y', U2 contains the (M-P)-by-(M-P) orthogonal
204 *> matrix U2.
205 *> \endverbatim
206 *>
207 *> \param[in] LDU2
208 *> \verbatim
209 *> LDU2 is INTEGER
210 *> The leading dimension of U2. If JOBU2 = 'Y', LDU2 >=
211 *> MAX(1,M-P).
212 *> \endverbatim
213 *>
214 *> \param[out] V1T
215 *> \verbatim
216 *> V1T is REAL array, dimension (Q)
217 *> If JOBV1T = 'Y', V1T contains the Q-by-Q matrix orthogonal
218 *> matrix V1**T.
219 *> \endverbatim
220 *>
221 *> \param[in] LDV1T
222 *> \verbatim
223 *> LDV1T is INTEGER
224 *> The leading dimension of V1T. If JOBV1T = 'Y', LDV1T >=
225 *> MAX(1,Q).
226 *> \endverbatim
227 *>
228 *> \param[out] V2T
229 *> \verbatim
230 *> V2T is REAL array, dimension (M-Q)
231 *> If JOBV2T = 'Y', V2T contains the (M-Q)-by-(M-Q) orthogonal
232 *> matrix V2**T.
233 *> \endverbatim
234 *>
235 *> \param[in] LDV2T
236 *> \verbatim
237 *> LDV2T is INTEGER
238 *> The leading dimension of V2T. If JOBV2T = 'Y', LDV2T >=
239 *> MAX(1,M-Q).
240 *> \endverbatim
241 *>
242 *> \param[out] WORK
243 *> \verbatim
244 *> WORK is REAL array, dimension (MAX(1,LWORK))
245 *> On exit, if INFO = 0, WORK(1) returns the optimal LWORK.
246 *> If INFO > 0 on exit, WORK(2:R) contains the values PHI(1),
247 *> ..., PHI(R-1) that, together with THETA(1), ..., THETA(R),
248 *> define the matrix in intermediate bidiagonal-block form
249 *> remaining after nonconvergence. INFO specifies the number
250 *> of nonzero PHI's.
251 *> \endverbatim
252 *>
253 *> \param[in] LWORK
254 *> \verbatim
255 *> LWORK is INTEGER
256 *> The dimension of the array WORK.
257 *>
258 *> If LWORK = -1, then a workspace query is assumed; the routine
259 *> only calculates the optimal size of the WORK array, returns
260 *> this value as the first entry of the work array, and no error
261 *> message related to LWORK is issued by XERBLA.
262 *> \endverbatim
263 *>
264 *> \param[out] IWORK
265 *> \verbatim
266 *> IWORK is INTEGER array, dimension (M-MIN(P, M-P, Q, M-Q))
267 *> \endverbatim
268 *>
269 *> \param[out] INFO
270 *> \verbatim
271 *> INFO is INTEGER
272 *> = 0: successful exit.
273 *> < 0: if INFO = -i, the i-th argument had an illegal value.
274 *> > 0: SBBCSD did not converge. See the description of WORK
275 *> above for details.
276 *> \endverbatim
277 *
278 *> \par References:
279 * ================
280 *>
281 *> [1] Brian D. Sutton. Computing the complete CS decomposition. Numer.
282 *> Algorithms, 50(1):33-65, 2009.
283 *
284 * Authors:
285 * ========
286 *
287 *> \author Univ. of Tennessee
288 *> \author Univ. of California Berkeley
289 *> \author Univ. of Colorado Denver
290 *> \author NAG Ltd.
291 *
292 *> \date November 2011
293 *
294 *> \ingroup realOTHERcomputational
295 *
296 * =====================================================================
297  RECURSIVE SUBROUTINE sorcsd( JOBU1, JOBU2, JOBV1T, JOBV2T, TRANS,
298  $ signs, m, p, q, x11, ldx11, x12,
299  $ ldx12, x21, ldx21, x22, ldx22, theta,
300  $ u1, ldu1, u2, ldu2, v1t, ldv1t, v2t,
301  $ ldv2t, work, lwork, iwork, info )
302 *
303 * -- LAPACK computational routine (version 3.4.0) --
304 * -- LAPACK is a software package provided by Univ. of Tennessee, --
305 * -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
306 * November 2011
307 *
308 * .. Scalar Arguments ..
309  CHARACTER jobu1, jobu2, jobv1t, jobv2t, signs, trans
310  INTEGER info, ldu1, ldu2, ldv1t, ldv2t, ldx11, ldx12,
311  $ ldx21, ldx22, lwork, m, p, q
312 * ..
313 * .. Array Arguments ..
314  INTEGER iwork( * )
315  REAL theta( * )
316  REAL u1( ldu1, * ), u2( ldu2, * ), v1t( ldv1t, * ),
317  $ v2t( ldv2t, * ), work( * ), x11( ldx11, * ),
318  $ x12( ldx12, * ), x21( ldx21, * ), x22( ldx22,
319  $ * )
320 * ..
321 *
322 * ===================================================================
323 *
324 * .. Parameters ..
325  REAL one, zero
326  parameter( one = 1.0e+0,
327  $ zero = 0.0e+0 )
328 * ..
329 * .. Local Arrays ..
330  REAL dummy(1)
331 * ..
332 * .. Local Scalars ..
333  CHARACTER transt, signst
334  INTEGER childinfo, i, ib11d, ib11e, ib12d, ib12e,
335  $ ib21d, ib21e, ib22d, ib22e, ibbcsd, iorbdb,
336  $ iorglq, iorgqr, iphi, itaup1, itaup2, itauq1,
337  $ itauq2, j, lbbcsdwork, lbbcsdworkmin,
338  $ lbbcsdworkopt, lorbdbwork, lorbdbworkmin,
339  $ lorbdbworkopt, lorglqwork, lorglqworkmin,
340  $ lorglqworkopt, lorgqrwork, lorgqrworkmin,
341  $ lorgqrworkopt, lworkmin, lworkopt
342  LOGICAL colmajor, defaultsigns, lquery, wantu1, wantu2,
343  $ wantv1t, wantv2t
344 * ..
345 * .. External Subroutines ..
346  EXTERNAL sbbcsd, slacpy, slapmr, slapmt, slascl, slaset,
348 * ..
349 * .. External Functions ..
350  LOGICAL lsame
351  EXTERNAL lsame
352 * ..
353 * .. Intrinsic Functions
354  INTRINSIC int, max, min
355 * ..
356 * .. Executable Statements ..
357 *
358 * Test input arguments
359 *
360  info = 0
361  wantu1 = lsame( jobu1, 'Y' )
362  wantu2 = lsame( jobu2, 'Y' )
363  wantv1t = lsame( jobv1t, 'Y' )
364  wantv2t = lsame( jobv2t, 'Y' )
365  colmajor = .NOT. lsame( trans, 'T' )
366  defaultsigns = .NOT. lsame( signs, 'O' )
367  lquery = lwork .EQ. -1
368  IF( m .LT. 0 ) THEN
369  info = -7
370  ELSE IF( p .LT. 0 .OR. p .GT. m ) THEN
371  info = -8
372  ELSE IF( q .LT. 0 .OR. q .GT. m ) THEN
373  info = -9
374  ELSE IF( ( colmajor .AND. ldx11 .LT. max(1,p) ) .OR.
375  $ ( .NOT.colmajor .AND. ldx11 .LT. max(1,q) ) ) THEN
376  info = -11
377  ELSE IF( wantu1 .AND. ldu1 .LT. p ) THEN
378  info = -20
379  ELSE IF( wantu2 .AND. ldu2 .LT. m-p ) THEN
380  info = -22
381  ELSE IF( wantv1t .AND. ldv1t .LT. q ) THEN
382  info = -24
383  ELSE IF( wantv2t .AND. ldv2t .LT. m-q ) THEN
384  info = -26
385  END IF
386 *
387 * Work with transpose if convenient
388 *
389  IF( info .EQ. 0 .AND. min( p, m-p ) .LT. min( q, m-q ) ) THEN
390  IF( colmajor ) THEN
391  transt = 'T'
392  ELSE
393  transt = 'N'
394  END IF
395  IF( defaultsigns ) THEN
396  signst = 'O'
397  ELSE
398  signst = 'D'
399  END IF
400  CALL sorcsd( jobv1t, jobv2t, jobu1, jobu2, transt, signst, m,
401  $ q, p, x11, ldx11, x21, ldx21, x12, ldx12, x22,
402  $ ldx22, theta, v1t, ldv1t, v2t, ldv2t, u1, ldu1,
403  $ u2, ldu2, work, lwork, iwork, info )
404  return
405  END IF
406 *
407 * Work with permutation [ 0 I; I 0 ] * X * [ 0 I; I 0 ] if
408 * convenient
409 *
410  IF( info .EQ. 0 .AND. m-q .LT. q ) THEN
411  IF( defaultsigns ) THEN
412  signst = 'O'
413  ELSE
414  signst = 'D'
415  END IF
416  CALL sorcsd( jobu2, jobu1, jobv2t, jobv1t, trans, signst, m,
417  $ m-p, m-q, x22, ldx22, x21, ldx21, x12, ldx12, x11,
418  $ ldx11, theta, u2, ldu2, u1, ldu1, v2t, ldv2t, v1t,
419  $ ldv1t, work, lwork, iwork, info )
420  return
421  END IF
422 *
423 * Compute workspace
424 *
425  IF( info .EQ. 0 ) THEN
426 *
427  iphi = 2
428  itaup1 = iphi + max( 1, q - 1 )
429  itaup2 = itaup1 + max( 1, p )
430  itauq1 = itaup2 + max( 1, m - p )
431  itauq2 = itauq1 + max( 1, q )
432  iorgqr = itauq2 + max( 1, m - q )
433  CALL sorgqr( m-q, m-q, m-q, dummy, max(1,m-q), dummy, work, -1,
434  $ childinfo )
435  lorgqrworkopt = int( work(1) )
436  lorgqrworkmin = max( 1, m - q )
437  iorglq = itauq2 + max( 1, m - q )
438  CALL sorglq( m-q, m-q, m-q, dummy, max(1,m-q), dummy, work, -1,
439  $ childinfo )
440  lorglqworkopt = int( work(1) )
441  lorglqworkmin = max( 1, m - q )
442  iorbdb = itauq2 + max( 1, m - q )
443  CALL sorbdb( trans, signs, m, p, q, x11, ldx11, x12, ldx12,
444  $ x21, ldx21, x22, ldx22, dummy, dummy, dummy, dummy, dummy,
445  $ dummy,work,-1,childinfo )
446  lorbdbworkopt = int( work(1) )
447  lorbdbworkmin = lorbdbworkopt
448  ib11d = itauq2 + max( 1, m - q )
449  ib11e = ib11d + max( 1, q )
450  ib12d = ib11e + max( 1, q - 1 )
451  ib12e = ib12d + max( 1, q )
452  ib21d = ib12e + max( 1, q - 1 )
453  ib21e = ib21d + max( 1, q )
454  ib22d = ib21e + max( 1, q - 1 )
455  ib22e = ib22d + max( 1, q )
456  ibbcsd = ib22e + max( 1, q - 1 )
457  CALL sbbcsd( jobu1, jobu2, jobv1t, jobv2t, trans, m, p, q,
458  $ dummy, dummy, u1, ldu1, u2, ldu2, v1t, ldv1t, v2t,
459  $ ldv2t, dummy, dummy, dummy, dummy, dummy, dummy,
460  $ dummy, dummy, work, -1, childinfo )
461  lbbcsdworkopt = int( work(1) )
462  lbbcsdworkmin = lbbcsdworkopt
463  lworkopt = max( iorgqr + lorgqrworkopt, iorglq + lorglqworkopt,
464  $ iorbdb + lorbdbworkopt, ibbcsd + lbbcsdworkopt ) - 1
465  lworkmin = max( iorgqr + lorgqrworkmin, iorglq + lorglqworkmin,
466  $ iorbdb + lorbdbworkopt, ibbcsd + lbbcsdworkmin ) - 1
467  work(1) = max(lworkopt,lworkmin)
468 *
469  IF( lwork .LT. lworkmin .AND. .NOT. lquery ) THEN
470  info = -22
471  ELSE
472  lorgqrwork = lwork - iorgqr + 1
473  lorglqwork = lwork - iorglq + 1
474  lorbdbwork = lwork - iorbdb + 1
475  lbbcsdwork = lwork - ibbcsd + 1
476  END IF
477  END IF
478 *
479 * Abort if any illegal arguments
480 *
481  IF( info .NE. 0 ) THEN
482  CALL xerbla( 'SORCSD', -info )
483  return
484  ELSE IF( lquery ) THEN
485  return
486  END IF
487 *
488 * Transform to bidiagonal block form
489 *
490  CALL sorbdb( trans, signs, m, p, q, x11, ldx11, x12, ldx12, x21,
491  $ ldx21, x22, ldx22, theta, work(iphi), work(itaup1),
492  $ work(itaup2), work(itauq1), work(itauq2),
493  $ work(iorbdb), lorbdbwork, childinfo )
494 *
495 * Accumulate Householder reflectors
496 *
497  IF( colmajor ) THEN
498  IF( wantu1 .AND. p .GT. 0 ) THEN
499  CALL slacpy( 'L', p, q, x11, ldx11, u1, ldu1 )
500  CALL sorgqr( p, p, q, u1, ldu1, work(itaup1), work(iorgqr),
501  $ lorgqrwork, info)
502  END IF
503  IF( wantu2 .AND. m-p .GT. 0 ) THEN
504  CALL slacpy( 'L', m-p, q, x21, ldx21, u2, ldu2 )
505  CALL sorgqr( m-p, m-p, q, u2, ldu2, work(itaup2),
506  $ work(iorgqr), lorgqrwork, info )
507  END IF
508  IF( wantv1t .AND. q .GT. 0 ) THEN
509  CALL slacpy( 'U', q-1, q-1, x11(1,2), ldx11, v1t(2,2),
510  $ ldv1t )
511  v1t(1, 1) = one
512  DO j = 2, q
513  v1t(1,j) = zero
514  v1t(j,1) = zero
515  END DO
516  CALL sorglq( q-1, q-1, q-1, v1t(2,2), ldv1t, work(itauq1),
517  $ work(iorglq), lorglqwork, info )
518  END IF
519  IF( wantv2t .AND. m-q .GT. 0 ) THEN
520  CALL slacpy( 'U', p, m-q, x12, ldx12, v2t, ldv2t )
521  CALL slacpy( 'U', m-p-q, m-p-q, x22(q+1,p+1), ldx22,
522  $ v2t(p+1,p+1), ldv2t )
523  CALL sorglq( m-q, m-q, m-q, v2t, ldv2t, work(itauq2),
524  $ work(iorglq), lorglqwork, info )
525  END IF
526  ELSE
527  IF( wantu1 .AND. p .GT. 0 ) THEN
528  CALL slacpy( 'U', q, p, x11, ldx11, u1, ldu1 )
529  CALL sorglq( p, p, q, u1, ldu1, work(itaup1), work(iorglq),
530  $ lorglqwork, info)
531  END IF
532  IF( wantu2 .AND. m-p .GT. 0 ) THEN
533  CALL slacpy( 'U', q, m-p, x21, ldx21, u2, ldu2 )
534  CALL sorglq( m-p, m-p, q, u2, ldu2, work(itaup2),
535  $ work(iorglq), lorglqwork, info )
536  END IF
537  IF( wantv1t .AND. q .GT. 0 ) THEN
538  CALL slacpy( 'L', q-1, q-1, x11(2,1), ldx11, v1t(2,2),
539  $ ldv1t )
540  v1t(1, 1) = one
541  DO j = 2, q
542  v1t(1,j) = zero
543  v1t(j,1) = zero
544  END DO
545  CALL sorgqr( q-1, q-1, q-1, v1t(2,2), ldv1t, work(itauq1),
546  $ work(iorgqr), lorgqrwork, info )
547  END IF
548  IF( wantv2t .AND. m-q .GT. 0 ) THEN
549  CALL slacpy( 'L', m-q, p, x12, ldx12, v2t, ldv2t )
550  CALL slacpy( 'L', m-p-q, m-p-q, x22(p+1,q+1), ldx22,
551  $ v2t(p+1,p+1), ldv2t )
552  CALL sorgqr( m-q, m-q, m-q, v2t, ldv2t, work(itauq2),
553  $ work(iorgqr), lorgqrwork, info )
554  END IF
555  END IF
556 *
557 * Compute the CSD of the matrix in bidiagonal-block form
558 *
559  CALL sbbcsd( jobu1, jobu2, jobv1t, jobv2t, trans, m, p, q, theta,
560  $ work(iphi), u1, ldu1, u2, ldu2, v1t, ldv1t, v2t,
561  $ ldv2t, work(ib11d), work(ib11e), work(ib12d),
562  $ work(ib12e), work(ib21d), work(ib21e), work(ib22d),
563  $ work(ib22e), work(ibbcsd), lbbcsdwork, info )
564 *
565 * Permute rows and columns to place identity submatrices in top-
566 * left corner of (1,1)-block and/or bottom-right corner of (1,2)-
567 * block and/or bottom-right corner of (2,1)-block and/or top-left
568 * corner of (2,2)-block
569 *
570  IF( q .GT. 0 .AND. wantu2 ) THEN
571  DO i = 1, q
572  iwork(i) = m - p - q + i
573  END DO
574  DO i = q + 1, m - p
575  iwork(i) = i - q
576  END DO
577  IF( colmajor ) THEN
578  CALL slapmt( .false., m-p, m-p, u2, ldu2, iwork )
579  ELSE
580  CALL slapmr( .false., m-p, m-p, u2, ldu2, iwork )
581  END IF
582  END IF
583  IF( m .GT. 0 .AND. wantv2t ) THEN
584  DO i = 1, p
585  iwork(i) = m - p - q + i
586  END DO
587  DO i = p + 1, m - q
588  iwork(i) = i - p
589  END DO
590  IF( .NOT. colmajor ) THEN
591  CALL slapmt( .false., m-q, m-q, v2t, ldv2t, iwork )
592  ELSE
593  CALL slapmr( .false., m-q, m-q, v2t, ldv2t, iwork )
594  END IF
595  END IF
596 *
597  return
598 *
599 * End SORCSD
600 *
601  END
602