1      SUBROUTINE PCGELQF( M, N, A, IA, JA, DESCA, TAU, WORK, LWORK,
2     $                    INFO )
3*
4*  -- ScaLAPACK routine (version 1.7) --
5*     University of Tennessee, Knoxville, Oak Ridge National Laboratory,
6*     and University of California, Berkeley.
7*     May 25, 2001
8*
9*     .. Scalar Arguments ..
10      INTEGER             IA, INFO, JA, LWORK, M, N
11*     ..
12*     .. Array Arguments ..
13      INTEGER            DESCA( * )
14      COMPLEX            A( * ), TAU( * ), WORK( * )
15*     ..
16*
17*  Purpose
18*  =======
19*
20*  PCGELQF computes a LQ factorization of a complex distributed M-by-N
21*  matrix sub( A ) = A(IA:IA+M-1,JA:JA+N-1) = L * Q.
22*
23*  Notes
24*  =====
25*
26*  Each global data object is described by an associated description
27*  vector.  This vector stores the information required to establish
28*  the mapping between an object element and its corresponding process
29*  and memory location.
30*
31*  Let A be a generic term for any 2D block cyclicly distributed array.
32*  Such a global array has an associated description vector DESCA.
33*  In the following comments, the character _ should be read as
34*  "of the global array".
35*
36*  NOTATION        STORED IN      EXPLANATION
37*  --------------- -------------- --------------------------------------
38*  DTYPE_A(global) DESCA( DTYPE_ )The descriptor type.  In this case,
39*                                 DTYPE_A = 1.
40*  CTXT_A (global) DESCA( CTXT_ ) The BLACS context handle, indicating
41*                                 the BLACS process grid A is distribu-
42*                                 ted over. The context itself is glo-
43*                                 bal, but the handle (the integer
44*                                 value) may vary.
45*  M_A    (global) DESCA( M_ )    The number of rows in the global
46*                                 array A.
47*  N_A    (global) DESCA( N_ )    The number of columns in the global
48*                                 array A.
49*  MB_A   (global) DESCA( MB_ )   The blocking factor used to distribute
50*                                 the rows of the array.
51*  NB_A   (global) DESCA( NB_ )   The blocking factor used to distribute
52*                                 the columns of the array.
53*  RSRC_A (global) DESCA( RSRC_ ) The process row over which the first
54*                                 row of the array A is distributed.
55*  CSRC_A (global) DESCA( CSRC_ ) The process column over which the
56*                                 first column of the array A is
57*                                 distributed.
58*  LLD_A  (local)  DESCA( LLD_ )  The leading dimension of the local
59*                                 array.  LLD_A >= MAX(1,LOCr(M_A)).
60*
61*  Let K be the number of rows or columns of a distributed matrix,
62*  and assume that its process grid has dimension p x q.
63*  LOCr( K ) denotes the number of elements of K that a process
64*  would receive if K were distributed over the p processes of its
65*  process column.
66*  Similarly, LOCc( K ) denotes the number of elements of K that a
67*  process would receive if K were distributed over the q processes of
68*  its process row.
69*  The values of LOCr() and LOCc() may be determined via a call to the
70*  ScaLAPACK tool function, NUMROC:
71*          LOCr( M ) = NUMROC( M, MB_A, MYROW, RSRC_A, NPROW ),
72*          LOCc( N ) = NUMROC( N, NB_A, MYCOL, CSRC_A, NPCOL ).
73*  An upper bound for these quantities may be computed by:
74*          LOCr( M ) <= ceil( ceil(M/MB_A)/NPROW )*MB_A
75*          LOCc( N ) <= ceil( ceil(N/NB_A)/NPCOL )*NB_A
76*
77*  Arguments
78*  =========
79*
80*  M       (global input) INTEGER
81*          The number of rows to be operated on, i.e. the number of rows
82*          of the distributed submatrix sub( A ). M >= 0.
83*
84*  N       (global input) INTEGER
85*          The number of columns to be operated on, i.e. the number of
86*          columns of the distributed submatrix sub( A ). N >= 0.
87*
88*  A       (local input/local output) COMPLEX pointer into the
89*          local memory to an array of dimension (LLD_A, LOCc(JA+N-1)).
90*          On entry, the local pieces of the M-by-N distributed matrix
91*          sub( A ) which is to be factored. On exit, the elements on
92*          and below the diagonal of sub( A ) contain the M by min(M,N)
93*          lower trapezoidal matrix L (L is lower triangular if M <= N);
94*          the elements above the diagonal, with the array TAU, repre-
95*          sent the unitary matrix Q as a product of elementary
96*          reflectors (see Further Details).
97*
98*  IA      (global input) INTEGER
99*          The row index in the global array A indicating the first
100*          row of sub( A ).
101*
102*  JA      (global input) INTEGER
103*          The column index in the global array A indicating the
104*          first column of sub( A ).
105*
106*  DESCA   (global and local input) INTEGER array of dimension DLEN_.
107*          The array descriptor for the distributed matrix A.
108*
109*  TAU     (local output) COMPLEX, array, dimension
110*          LOCr(IA+MIN(M,N)-1).  This array contains the scalar factors
111*          of the elementary reflectors. TAU is tied to the distributed
112*          matrix A.
113*
114*  WORK    (local workspace/local output) COMPLEX array,
115*                                                     dimension (LWORK)
116*          On exit, WORK(1) returns the minimal and optimal LWORK.
117*
118*  LWORK   (local or global input) INTEGER
119*          The dimension of the array WORK.
120*          LWORK is local input and must be at least
121*          LWORK >= MB_A * ( Mp0 + Nq0 + MB_A ), where
122*
123*          IROFF = MOD( IA-1, MB_A ), ICOFF = MOD( JA-1, NB_A ),
124*          IAROW = INDXG2P( IA, MB_A, MYROW, RSRC_A, NPROW ),
125*          IACOL = INDXG2P( JA, NB_A, MYCOL, CSRC_A, NPCOL ),
126*          Mp0   = NUMROC( M+IROFF, MB_A, MYROW, IAROW, NPROW ),
127*          Nq0   = NUMROC( N+ICOFF, NB_A, MYCOL, IACOL, NPCOL ),
128*
129*          and NUMROC, INDXG2P are ScaLAPACK tool functions;
130*          MYROW, MYCOL, NPROW and NPCOL can be determined by calling
131*          the subroutine BLACS_GRIDINFO.
132*
133*          If LWORK = -1, then LWORK is global input and a workspace
134*          query is assumed; the routine only calculates the minimum
135*          and optimal size for all work arrays. Each of these
136*          values is returned in the first entry of the corresponding
137*          work array, and no error message is issued by PXERBLA.
138*
139*  INFO    (global output) INTEGER
140*          = 0:  successful exit
141*          < 0:  If the i-th argument is an array and the j-entry had
142*                an illegal value, then INFO = -(i*100+j), if the i-th
143*                argument is a scalar and had an illegal value, then
144*                INFO = -i.
145*
146*  Further Details
147*  ===============
148*
149*  The matrix Q is represented as a product of elementary reflectors
150*
151*     Q = H(ia+k-1)' H(ia+k-2)' . . . H(ia)', where k = min(m,n).
152*
153*  Each H(i) has the form
154*
155*     H(i) = I - tau * v * v'
156*
157*  where tau is a complex scalar, and v is a complex vector with
158*  v(1:i-1) = 0 and v(i) = 1; conjg(v(i+1:n)) is stored on exit in
159*  A(ia+i-1,ja+i:ja+n-1), and tau in TAU(ia+i-1).
160*
161*  =====================================================================
162*
163*     .. Parameters ..
164      INTEGER            BLOCK_CYCLIC_2D, CSRC_, CTXT_, DLEN_, DTYPE_,
165     $                   LLD_, MB_, M_, NB_, N_, RSRC_
166      PARAMETER          ( BLOCK_CYCLIC_2D = 1, DLEN_ = 9, DTYPE_ = 1,
167     $                     CTXT_ = 2, M_ = 3, N_ = 4, MB_ = 5, NB_ = 6,
168     $                     RSRC_ = 7, CSRC_ = 8, LLD_ = 9 )
169*     ..
170*     .. Local Scalars ..
171      LOGICAL            LQUERY
172      CHARACTER          COLBTOP, ROWBTOP
173      INTEGER            I, IACOL, IAROW, IB, ICTXT, IINFO, IN, IPW,
174     $                   IROFF, J, K, LWMIN, MP0, MYCOL, MYROW, NPCOL,
175     $                   NPROW, NQ0
176*     ..
177*     .. Local Arrays ..
178      INTEGER            IDUM1( 1 ), IDUM2( 1 )
179*     ..
180*     .. External Subroutines ..
181      EXTERNAL           BLACS_GRIDINFO, CHK1MAT, PCHK1MAT, PCGELQ2,
182     $                   PCLARFB, PCLARFT, PB_TOPGET, PB_TOPSET, PXERBLA
183*     ..
184*     .. External Functions ..
185      INTEGER            ICEIL, INDXG2P, NUMROC
186      EXTERNAL           ICEIL, INDXG2P, NUMROC
187*     ..
188*     .. Intrinsic Functions ..
189      INTRINSIC          CMPLX, MIN, MOD, REAL
190*     ..
191*     .. Executable Statements ..
192*
193*     Get grid parameters
194*
195      ICTXT = DESCA( CTXT_ )
196      CALL BLACS_GRIDINFO( ICTXT, NPROW, NPCOL, MYROW, MYCOL )
197*
198*     Test the input parameters
199*
200      INFO = 0
201      IF( NPROW.EQ.-1 ) THEN
202         INFO = -(600+CTXT_)
203      ELSE
204         CALL CHK1MAT( M, 1, N, 2, IA, JA, DESCA, 6, INFO )
205         IF( INFO.EQ.0 ) THEN
206            IROFF = MOD( IA-1, DESCA( MB_ ) )
207            IAROW = INDXG2P( IA, DESCA( MB_ ), MYROW, DESCA( RSRC_ ),
208     $                       NPROW )
209            IACOL = INDXG2P( JA, DESCA( NB_ ), MYCOL, DESCA( CSRC_ ),
210     $                       NPCOL )
211            MP0 = NUMROC( M+IROFF, DESCA( MB_ ), MYROW, IAROW, NPROW )
212            NQ0 = NUMROC( N+MOD( JA-1, DESCA( NB_ ) ), DESCA( NB_ ),
213     $                    MYCOL, IACOL, NPCOL )
214            LWMIN = DESCA( MB_ ) * ( MP0 + NQ0 + DESCA( MB_ ) )
215*
216            WORK( 1 ) = CMPLX( REAL( LWMIN ) )
217            LQUERY = ( LWORK.EQ.-1 )
218            IF( LWORK.LT.LWMIN .AND. .NOT.LQUERY )
219     $         INFO = -9
220         END IF
221         IF( LWORK.EQ.-1 ) THEN
222            IDUM1( 1 ) = -1
223         ELSE
224            IDUM1( 1 ) = 1
225         END IF
226         IDUM2( 1 ) = 9
227         CALL PCHK1MAT( M, 1, N, 2, IA, JA, DESCA, 6, 1, IDUM1, IDUM2,
228     $                  INFO )
229      END IF
230*
231      IF( INFO.NE.0 ) THEN
232         CALL PXERBLA( ICTXT, 'PCGELQF', -INFO )
233         RETURN
234      ELSE IF( LQUERY ) THEN
235         RETURN
236      END IF
237*
238*     Quick return if possible
239*
240      IF( M.EQ.0 .OR. N.EQ.0 )
241     $   RETURN
242*
243      K = MIN( M, N )
244      IPW = DESCA( MB_ ) * DESCA( MB_ ) + 1
245      CALL PB_TOPGET( ICTXT, 'Broadcast', 'Rowwise', ROWBTOP )
246      CALL PB_TOPGET( ICTXT, 'Broadcast', 'Columnwise', COLBTOP )
247      CALL PB_TOPSET( ICTXT, 'Broadcast', 'Rowwise', ' ' )
248      CALL PB_TOPSET( ICTXT, 'Broadcast', 'Columnwise', 'I-ring' )
249*
250*     Handle the first block of rows separately
251*
252      IN = MIN( ICEIL( IA, DESCA( MB_ ) ) * DESCA( MB_ ), IA+K-1 )
253      IB = IN - IA + 1
254*
255*     Compute the LQ factorization of the first block A(ia:in:ja:ja+n-1)
256*
257      CALL PCGELQ2( IB, N, A, IA, JA, DESCA, TAU, WORK, LWORK, IINFO )
258*
259      IF( IA+IB.LE.IA+M-1 ) THEN
260*
261*        Form the triangular factor of the block reflector
262*        H = H(ia) H(ia+1) . . . H(in)
263*
264         CALL PCLARFT( 'Forward', 'Rowwise', N, IB, A, IA, JA, DESCA,
265     $                 TAU, WORK, WORK( IPW ) )
266*
267*        Apply H to A(ia+ib:ia+m-1,ja:ja+n-1) from the right
268*
269         CALL PCLARFB( 'Right', 'No transpose', 'Forward', 'Rowwise',
270     $                 M-IB, N, IB, A, IA, JA, DESCA, WORK, A, IA+IB,
271     $                 JA, DESCA, WORK( IPW ) )
272      END IF
273*
274*     Loop over the remaining blocks of rows
275*
276      DO 10 I = IN+1, IA+K-1, DESCA( MB_ )
277         IB = MIN( K-I+IA, DESCA( MB_ ) )
278         J = JA + I - IA
279*
280*        Compute the LQ factorization of the current block
281*        A(i:i+ib-1:j:ja+n-1)
282*
283         CALL PCGELQ2( IB, N-I+IA, A, I, J, DESCA, TAU, WORK, LWORK,
284     $                 IINFO )
285*
286         IF( I+IB.LE.IA+M-1 ) THEN
287*
288*           Form the triangular factor of the block reflector
289*           H = H(i) H(i+1) . . . H(i+ib-1)
290*
291            CALL PCLARFT( 'Forward', 'Rowwise', N-I+IA, IB, A, I, J,
292     $                    DESCA, TAU, WORK, WORK( IPW ) )
293*
294*           Apply H to A(i+ib:ia+m-1,j:ja+n-1) from the right
295*
296            CALL PCLARFB( 'Right', 'No transpose', 'Forward', 'Rowwise',
297     $                     M-I-IB+IA, N-J+JA, IB, A, I, J, DESCA, WORK,
298     $                     A, I+IB, J, DESCA, WORK( IPW ) )
299         END IF
300*
301   10 CONTINUE
302*
303      CALL PB_TOPSET( ICTXT, 'Broadcast', 'Rowwise', ROWBTOP )
304      CALL PB_TOPSET( ICTXT, 'Broadcast', 'Columnwise', COLBTOP )
305*
306      WORK( 1 ) = CMPLX( REAL( LWMIN ) )
307*
308      RETURN
309*
310*     End of PCGELQF
311*
312      END
313