LAPACK  3.6.1
LAPACK: Linear Algebra PACKage
recursive subroutine sorcsd ( character  JOBU1,
character  JOBU2,
character  JOBV1T,
character  JOBV2T,
character  TRANS,
character  SIGNS,
integer  M,
integer  P,
integer  Q,
real, dimension( ldx11, * )  X11,
integer  LDX11,
real, dimension( ldx12, * )  X12,
integer  LDX12,
real, dimension( ldx21, * )  X21,
integer  LDX21,
real, dimension( ldx22, * )  X22,
integer  LDX22,
real, dimension( * )  THETA,
real, dimension( ldu1, * )  U1,
integer  LDU1,
real, dimension( ldu2, * )  U2,
integer  LDU2,
real, dimension( ldv1t, * )  V1T,
integer  LDV1T,
real, dimension( ldv2t, * )  V2T,
integer  LDV2T,
real, dimension( * )  WORK,
integer  LWORK,
integer, dimension( * )  IWORK,
integer  INFO 
)

SORCSD

Download SORCSD + dependencies [TGZ] [ZIP] [TXT]

Purpose:
 SORCSD computes the CS decomposition of an M-by-M partitioned
 orthogonal matrix X:

                                 [  I  0  0 |  0  0  0 ]
                                 [  0  C  0 |  0 -S  0 ]
     [ X11 | X12 ]   [ U1 |    ] [  0  0  0 |  0  0 -I ] [ V1 |    ]**T
 X = [-----------] = [---------] [---------------------] [---------]   .
     [ X21 | X22 ]   [    | U2 ] [  0  0  0 |  I  0  0 ] [    | V2 ]
                                 [  0  S  0 |  0  C  0 ]
                                 [  0  0  I |  0  0  0 ]

 X11 is P-by-Q. The orthogonal matrices U1, U2, V1, and V2 are P-by-P,
 (M-P)-by-(M-P), Q-by-Q, and (M-Q)-by-(M-Q), respectively. C and S are
 R-by-R nonnegative diagonal matrices satisfying C^2 + S^2 = I, in
 which R = MIN(P,M-P,Q,M-Q).
Parameters
[in]JOBU1
          JOBU1 is CHARACTER
          = 'Y':      U1 is computed;
          otherwise:  U1 is not computed.
[in]JOBU2
          JOBU2 is CHARACTER
          = 'Y':      U2 is computed;
          otherwise:  U2 is not computed.
[in]JOBV1T
          JOBV1T is CHARACTER
          = 'Y':      V1T is computed;
          otherwise:  V1T is not computed.
[in]JOBV2T
          JOBV2T is CHARACTER
          = 'Y':      V2T is computed;
          otherwise:  V2T is not computed.
[in]TRANS
          TRANS is CHARACTER
          = 'T':      X, U1, U2, V1T, and V2T are stored in row-major
                      order;
          otherwise:  X, U1, U2, V1T, and V2T are stored in column-
                      major order.
[in]SIGNS
          SIGNS is CHARACTER
          = 'O':      The lower-left block is made nonpositive (the
                      "other" convention);
          otherwise:  The upper-right block is made nonpositive (the
                      "default" convention).
[in]M
          M is INTEGER
          The number of rows and columns in X.
[in]P
          P is INTEGER
          The number of rows in X11 and X12. 0 <= P <= M.
[in]Q
          Q is INTEGER
          The number of columns in X11 and X21. 0 <= Q <= M.
[in,out]X11
          X11 is REAL array, dimension (LDX11,Q)
          On entry, part of the orthogonal matrix whose CSD is desired.
[in]LDX11
          LDX11 is INTEGER
          The leading dimension of X11. LDX11 >= MAX(1,P).
[in,out]X12
          X12 is REAL array, dimension (LDX12,M-Q)
          On entry, part of the orthogonal matrix whose CSD is desired.
[in]LDX12
          LDX12 is INTEGER
          The leading dimension of X12. LDX12 >= MAX(1,P).
[in,out]X21
          X21 is REAL array, dimension (LDX21,Q)
          On entry, part of the orthogonal matrix whose CSD is desired.
[in]LDX21
          LDX21 is INTEGER
          The leading dimension of X11. LDX21 >= MAX(1,M-P).
[in,out]X22
          X22 is REAL array, dimension (LDX22,M-Q)
          On entry, part of the orthogonal matrix whose CSD is desired.
[in]LDX22
          LDX22 is INTEGER
          The leading dimension of X11. LDX22 >= MAX(1,M-P).
[out]THETA
          THETA is REAL array, dimension (R), in which R =
          MIN(P,M-P,Q,M-Q).
          C = DIAG( COS(THETA(1)), ... , COS(THETA(R)) ) and
          S = DIAG( SIN(THETA(1)), ... , SIN(THETA(R)) ).
[out]U1
          U1 is REAL array, dimension (P)
          If JOBU1 = 'Y', U1 contains the P-by-P orthogonal matrix U1.
[in]LDU1
          LDU1 is INTEGER
          The leading dimension of U1. If JOBU1 = 'Y', LDU1 >=
          MAX(1,P).
[out]U2
          U2 is REAL array, dimension (M-P)
          If JOBU2 = 'Y', U2 contains the (M-P)-by-(M-P) orthogonal
          matrix U2.
[in]LDU2
          LDU2 is INTEGER
          The leading dimension of U2. If JOBU2 = 'Y', LDU2 >=
          MAX(1,M-P).
[out]V1T
          V1T is REAL array, dimension (Q)
          If JOBV1T = 'Y', V1T contains the Q-by-Q matrix orthogonal
          matrix V1**T.
[in]LDV1T
          LDV1T is INTEGER
          The leading dimension of V1T. If JOBV1T = 'Y', LDV1T >=
          MAX(1,Q).
[out]V2T
          V2T is REAL array, dimension (M-Q)
          If JOBV2T = 'Y', V2T contains the (M-Q)-by-(M-Q) orthogonal
          matrix V2**T.
[in]LDV2T
          LDV2T is INTEGER
          The leading dimension of V2T. If JOBV2T = 'Y', LDV2T >=
          MAX(1,M-Q).
[out]WORK
          WORK is REAL array, dimension (MAX(1,LWORK))
          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.
          If INFO > 0 on exit, WORK(2:R) contains the values PHI(1),
          ..., PHI(R-1) that, together with THETA(1), ..., THETA(R),
          define the matrix in intermediate bidiagonal-block form
          remaining after nonconvergence. INFO specifies the number
          of nonzero PHI's.
[in]LWORK
          LWORK is INTEGER
          The dimension of the array WORK.

          If LWORK = -1, then a workspace query is assumed; the routine
          only calculates the optimal size of the WORK array, returns
          this value as the first entry of the work array, and no error
          message related to LWORK is issued by XERBLA.
[out]IWORK
          IWORK is INTEGER array, dimension (M-MIN(P, M-P, Q, M-Q))
[out]INFO
          INFO is INTEGER
          = 0:  successful exit.
          < 0:  if INFO = -i, the i-th argument had an illegal value.
          > 0:  SBBCSD did not converge. See the description of WORK
                above for details.
References:
[1] Brian D. Sutton. Computing the complete CS decomposition. Numer. Algorithms, 50(1):33-65, 2009.
Author
Univ. of Tennessee
Univ. of California Berkeley
Univ. of Colorado Denver
NAG Ltd.
Date
November 2013

Definition at line 302 of file sorcsd.f.

302 *
303 * -- LAPACK computational routine (version 3.5.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 2013
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 ) ) THEN
375  info = -11
376  ELSE IF (.NOT. colmajor .AND. ldx11 .LT. max( 1, q ) ) THEN
377  info = -11
378  ELSE IF (colmajor .AND. ldx12 .LT. max( 1, p ) ) THEN
379  info = -13
380  ELSE IF (.NOT. colmajor .AND. ldx12 .LT. max( 1, m-q ) ) THEN
381  info = -13
382  ELSE IF (colmajor .AND. ldx21 .LT. max( 1, m-p ) ) THEN
383  info = -15
384  ELSE IF (.NOT. colmajor .AND. ldx21 .LT. max( 1, q ) ) THEN
385  info = -15
386  ELSE IF (colmajor .AND. ldx22 .LT. max( 1, m-p ) ) THEN
387  info = -17
388  ELSE IF (.NOT. colmajor .AND. ldx22 .LT. max( 1, m-q ) ) THEN
389  info = -17
390  ELSE IF( wantu1 .AND. ldu1 .LT. p ) THEN
391  info = -20
392  ELSE IF( wantu2 .AND. ldu2 .LT. m-p ) THEN
393  info = -22
394  ELSE IF( wantv1t .AND. ldv1t .LT. q ) THEN
395  info = -24
396  ELSE IF( wantv2t .AND. ldv2t .LT. m-q ) THEN
397  info = -26
398  END IF
399 *
400 * Work with transpose if convenient
401 *
402  IF( info .EQ. 0 .AND. min( p, m-p ) .LT. min( q, m-q ) ) THEN
403  IF( colmajor ) THEN
404  transt = 'T'
405  ELSE
406  transt = 'N'
407  END IF
408  IF( defaultsigns ) THEN
409  signst = 'O'
410  ELSE
411  signst = 'D'
412  END IF
413  CALL sorcsd( jobv1t, jobv2t, jobu1, jobu2, transt, signst, m,
414  $ q, p, x11, ldx11, x21, ldx21, x12, ldx12, x22,
415  $ ldx22, theta, v1t, ldv1t, v2t, ldv2t, u1, ldu1,
416  $ u2, ldu2, work, lwork, iwork, info )
417  RETURN
418  END IF
419 *
420 * Work with permutation [ 0 I; I 0 ] * X * [ 0 I; I 0 ] if
421 * convenient
422 *
423  IF( info .EQ. 0 .AND. m-q .LT. q ) THEN
424  IF( defaultsigns ) THEN
425  signst = 'O'
426  ELSE
427  signst = 'D'
428  END IF
429  CALL sorcsd( jobu2, jobu1, jobv2t, jobv1t, trans, signst, m,
430  $ m-p, m-q, x22, ldx22, x21, ldx21, x12, ldx12, x11,
431  $ ldx11, theta, u2, ldu2, u1, ldu1, v2t, ldv2t, v1t,
432  $ ldv1t, work, lwork, iwork, info )
433  RETURN
434  END IF
435 *
436 * Compute workspace
437 *
438  IF( info .EQ. 0 ) THEN
439 *
440  iphi = 2
441  itaup1 = iphi + max( 1, q - 1 )
442  itaup2 = itaup1 + max( 1, p )
443  itauq1 = itaup2 + max( 1, m - p )
444  itauq2 = itauq1 + max( 1, q )
445  iorgqr = itauq2 + max( 1, m - q )
446  CALL sorgqr( m-q, m-q, m-q, dummy, max(1,m-q), dummy, work, -1,
447  $ childinfo )
448  lorgqrworkopt = int( work(1) )
449  lorgqrworkmin = max( 1, m - q )
450  iorglq = itauq2 + max( 1, m - q )
451  CALL sorglq( m-q, m-q, m-q, dummy, max(1,m-q), dummy, work, -1,
452  $ childinfo )
453  lorglqworkopt = int( work(1) )
454  lorglqworkmin = max( 1, m - q )
455  iorbdb = itauq2 + max( 1, m - q )
456  CALL sorbdb( trans, signs, m, p, q, x11, ldx11, x12, ldx12,
457  $ x21, ldx21, x22, ldx22, dummy, dummy, dummy, dummy, dummy,
458  $ dummy,work,-1,childinfo )
459  lorbdbworkopt = int( work(1) )
460  lorbdbworkmin = lorbdbworkopt
461  ib11d = itauq2 + max( 1, m - q )
462  ib11e = ib11d + max( 1, q )
463  ib12d = ib11e + max( 1, q - 1 )
464  ib12e = ib12d + max( 1, q )
465  ib21d = ib12e + max( 1, q - 1 )
466  ib21e = ib21d + max( 1, q )
467  ib22d = ib21e + max( 1, q - 1 )
468  ib22e = ib22d + max( 1, q )
469  ibbcsd = ib22e + max( 1, q - 1 )
470  CALL sbbcsd( jobu1, jobu2, jobv1t, jobv2t, trans, m, p, q,
471  $ dummy, dummy, u1, ldu1, u2, ldu2, v1t, ldv1t, v2t,
472  $ ldv2t, dummy, dummy, dummy, dummy, dummy, dummy,
473  $ dummy, dummy, work, -1, childinfo )
474  lbbcsdworkopt = int( work(1) )
475  lbbcsdworkmin = lbbcsdworkopt
476  lworkopt = max( iorgqr + lorgqrworkopt, iorglq + lorglqworkopt,
477  $ iorbdb + lorbdbworkopt, ibbcsd + lbbcsdworkopt ) - 1
478  lworkmin = max( iorgqr + lorgqrworkmin, iorglq + lorglqworkmin,
479  $ iorbdb + lorbdbworkopt, ibbcsd + lbbcsdworkmin ) - 1
480  work(1) = max(lworkopt,lworkmin)
481 *
482  IF( lwork .LT. lworkmin .AND. .NOT. lquery ) THEN
483  info = -22
484  ELSE
485  lorgqrwork = lwork - iorgqr + 1
486  lorglqwork = lwork - iorglq + 1
487  lorbdbwork = lwork - iorbdb + 1
488  lbbcsdwork = lwork - ibbcsd + 1
489  END IF
490  END IF
491 *
492 * Abort if any illegal arguments
493 *
494  IF( info .NE. 0 ) THEN
495  CALL xerbla( 'SORCSD', -info )
496  RETURN
497  ELSE IF( lquery ) THEN
498  RETURN
499  END IF
500 *
501 * Transform to bidiagonal block form
502 *
503  CALL sorbdb( trans, signs, m, p, q, x11, ldx11, x12, ldx12, x21,
504  $ ldx21, x22, ldx22, theta, work(iphi), work(itaup1),
505  $ work(itaup2), work(itauq1), work(itauq2),
506  $ work(iorbdb), lorbdbwork, childinfo )
507 *
508 * Accumulate Householder reflectors
509 *
510  IF( colmajor ) THEN
511  IF( wantu1 .AND. p .GT. 0 ) THEN
512  CALL slacpy( 'L', p, q, x11, ldx11, u1, ldu1 )
513  CALL sorgqr( p, p, q, u1, ldu1, work(itaup1), work(iorgqr),
514  $ lorgqrwork, info)
515  END IF
516  IF( wantu2 .AND. m-p .GT. 0 ) THEN
517  CALL slacpy( 'L', m-p, q, x21, ldx21, u2, ldu2 )
518  CALL sorgqr( m-p, m-p, q, u2, ldu2, work(itaup2),
519  $ work(iorgqr), lorgqrwork, info )
520  END IF
521  IF( wantv1t .AND. q .GT. 0 ) THEN
522  CALL slacpy( 'U', q-1, q-1, x11(1,2), ldx11, v1t(2,2),
523  $ ldv1t )
524  v1t(1, 1) = one
525  DO j = 2, q
526  v1t(1,j) = zero
527  v1t(j,1) = zero
528  END DO
529  CALL sorglq( q-1, q-1, q-1, v1t(2,2), ldv1t, work(itauq1),
530  $ work(iorglq), lorglqwork, info )
531  END IF
532  IF( wantv2t .AND. m-q .GT. 0 ) THEN
533  CALL slacpy( 'U', p, m-q, x12, ldx12, v2t, ldv2t )
534  CALL slacpy( 'U', m-p-q, m-p-q, x22(q+1,p+1), ldx22,
535  $ v2t(p+1,p+1), ldv2t )
536  CALL sorglq( m-q, m-q, m-q, v2t, ldv2t, work(itauq2),
537  $ work(iorglq), lorglqwork, info )
538  END IF
539  ELSE
540  IF( wantu1 .AND. p .GT. 0 ) THEN
541  CALL slacpy( 'U', q, p, x11, ldx11, u1, ldu1 )
542  CALL sorglq( p, p, q, u1, ldu1, work(itaup1), work(iorglq),
543  $ lorglqwork, info)
544  END IF
545  IF( wantu2 .AND. m-p .GT. 0 ) THEN
546  CALL slacpy( 'U', q, m-p, x21, ldx21, u2, ldu2 )
547  CALL sorglq( m-p, m-p, q, u2, ldu2, work(itaup2),
548  $ work(iorglq), lorglqwork, info )
549  END IF
550  IF( wantv1t .AND. q .GT. 0 ) THEN
551  CALL slacpy( 'L', q-1, q-1, x11(2,1), ldx11, v1t(2,2),
552  $ ldv1t )
553  v1t(1, 1) = one
554  DO j = 2, q
555  v1t(1,j) = zero
556  v1t(j,1) = zero
557  END DO
558  CALL sorgqr( q-1, q-1, q-1, v1t(2,2), ldv1t, work(itauq1),
559  $ work(iorgqr), lorgqrwork, info )
560  END IF
561  IF( wantv2t .AND. m-q .GT. 0 ) THEN
562  CALL slacpy( 'L', m-q, p, x12, ldx12, v2t, ldv2t )
563  CALL slacpy( 'L', m-p-q, m-p-q, x22(p+1,q+1), ldx22,
564  $ v2t(p+1,p+1), ldv2t )
565  CALL sorgqr( m-q, m-q, m-q, v2t, ldv2t, work(itauq2),
566  $ work(iorgqr), lorgqrwork, info )
567  END IF
568  END IF
569 *
570 * Compute the CSD of the matrix in bidiagonal-block form
571 *
572  CALL sbbcsd( jobu1, jobu2, jobv1t, jobv2t, trans, m, p, q, theta,
573  $ work(iphi), u1, ldu1, u2, ldu2, v1t, ldv1t, v2t,
574  $ ldv2t, work(ib11d), work(ib11e), work(ib12d),
575  $ work(ib12e), work(ib21d), work(ib21e), work(ib22d),
576  $ work(ib22e), work(ibbcsd), lbbcsdwork, info )
577 *
578 * Permute rows and columns to place identity submatrices in top-
579 * left corner of (1,1)-block and/or bottom-right corner of (1,2)-
580 * block and/or bottom-right corner of (2,1)-block and/or top-left
581 * corner of (2,2)-block
582 *
583  IF( q .GT. 0 .AND. wantu2 ) THEN
584  DO i = 1, q
585  iwork(i) = m - p - q + i
586  END DO
587  DO i = q + 1, m - p
588  iwork(i) = i - q
589  END DO
590  IF( colmajor ) THEN
591  CALL slapmt( .false., m-p, m-p, u2, ldu2, iwork )
592  ELSE
593  CALL slapmr( .false., m-p, m-p, u2, ldu2, iwork )
594  END IF
595  END IF
596  IF( m .GT. 0 .AND. wantv2t ) THEN
597  DO i = 1, p
598  iwork(i) = m - p - q + i
599  END DO
600  DO i = p + 1, m - q
601  iwork(i) = i - p
602  END DO
603  IF( .NOT. colmajor ) THEN
604  CALL slapmt( .false., m-q, m-q, v2t, ldv2t, iwork )
605  ELSE
606  CALL slapmr( .false., m-q, m-q, v2t, ldv2t, iwork )
607  END IF
608  END IF
609 *
610  RETURN
611 *
612 * End SORCSD
613 *
subroutine sorglq(M, N, K, A, LDA, TAU, WORK, LWORK, INFO)
SORGLQ
Definition: sorglq.f:129
subroutine slapmt(FORWRD, M, N, X, LDX, K)
SLAPMT performs a forward or backward permutation of the columns of a matrix.
Definition: slapmt.f:106
subroutine slascl(TYPE, KL, KU, CFROM, CTO, M, N, A, LDA, INFO)
SLASCL multiplies a general rectangular matrix by a real scalar defined as cto/cfrom.
Definition: slascl.f:145
subroutine sorbdb(TRANS, SIGNS, M, P, Q, X11, LDX11, X12, LDX12, X21, LDX21, X22, LDX22, THETA, PHI, TAUP1, TAUP2, TAUQ1, TAUQ2, WORK, LWORK, INFO)
SORBDB
Definition: sorbdb.f:289
recursive subroutine sorcsd(JOBU1, JOBU2, JOBV1T, JOBV2T, TRANS, SIGNS, M, P, Q, X11, LDX11, X12, LDX12, X21, LDX21, X22, LDX22, THETA, U1, LDU1, U2, LDU2, V1T, LDV1T, V2T, LDV2T, WORK, LWORK, IWORK, INFO)
SORCSD
Definition: sorcsd.f:302
subroutine xerbla(SRNAME, INFO)
XERBLA
Definition: xerbla.f:62
subroutine slacpy(UPLO, M, N, A, LDA, B, LDB)
SLACPY copies all or part of one two-dimensional array to another.
Definition: slacpy.f:105
subroutine slaset(UPLO, M, N, ALPHA, BETA, A, LDA)
SLASET initializes the off-diagonal elements and the diagonal elements of a matrix to given values...
Definition: slaset.f:112
subroutine slapmr(FORWRD, M, N, X, LDX, K)
SLAPMR rearranges rows of a matrix as specified by a permutation vector.
Definition: slapmr.f:106
subroutine sbbcsd(JOBU1, JOBU2, JOBV1T, JOBV2T, TRANS, M, P, Q, THETA, PHI, U1, LDU1, U2, LDU2, V1T, LDV1T, V2T, LDV2T, B11D, B11E, B12D, B12E, B21D, B21E, B22D, B22E, WORK, LWORK, INFO)
SBBCSD
Definition: sbbcsd.f:334
subroutine sorgqr(M, N, K, A, LDA, TAU, WORK, LWORK, INFO)
SORGQR
Definition: sorgqr.f:130
logical function lsame(CA, CB)
LSAME
Definition: lsame.f:55

Here is the call graph for this function:

Here is the caller graph for this function: