Routine: PSLARZB()  File: SRC\pslarzb.f

 
 
# lines: 613
  # code: 613
  # comment: 0
  # blank:0
# Variables:85
# Callers:2
# Callings:0
# Words:316
# Keywords:178
 

 

..
     .. Array Arguments ..
     ..
  Purpose
  =======
  PSLARZB applies a real block reflector Q or its transpose Q**T to
  a real distributed M-by-N matrix sub( C ) = C(IC:IC+M-1,JC:JC+N-1)
  from the left or the right.
  Q is a product of k elementary reflectors as returned by PSTZRZF.
  Currently, only STOREV = 'R' and DIRECT = 'B' are supported.
  Notes
  =====
  Each global data object is described by an associated description
  vector.  This vector stores the information required to establish
  the mapping between an object element and its corresponding process
  and memory location.
  Let A be a generic term for any 2D block cyclicly distributed array.
  Such a global array has an associated description vector DESCA.
  In the following comments, the character _ should be read as
  "of the global array".
  NOTATION        STORED IN      EXPLANATION
  --------------- -------------- --------------------------------------
  DTYPE_A(global) DESCA( DTYPE_ )The descriptor type.  In this case,
                                 DTYPE_A = 1.
  CTXT_A (global) DESCA( CTXT_ ) The BLACS context handle, indicating
                                 the BLACS process grid A is distribu-
                                 ted over. The context itself is glo-
                                 bal, but the handle (the integer
                                 value) may vary.
  M_A    (global) DESCA( M_ )    The number of rows in the global
                                 array A.
  N_A    (global) DESCA( N_ )    The number of columns in the global
                                 array A.
  MB_A   (global) DESCA( MB_ )   The blocking factor used to distribute
                                 the rows of the array.
  NB_A   (global) DESCA( NB_ )   The blocking factor used to distribute
                                 the columns of the array.
  RSRC_A (global) DESCA( RSRC_ ) The process row over which the first
                                 row of the array A is distributed.
  CSRC_A (global) DESCA( CSRC_ ) The process column over which the
                                 first column of the array A is
                                 distributed.
  LLD_A  (local)  DESCA( LLD_ )  The leading dimension of the local
                                 array.  LLD_A >= MAX(1,LOCr(M_A)).
  Let K be the number of rows or columns of a distributed matrix,
  and assume that its process grid has dimension p x q.
  LOCr( K ) denotes the number of elements of K that a process
  would receive if K were distributed over the p processes of its
  process column.
  Similarly, LOCc( K ) denotes the number of elements of K that a
  process would receive if K were distributed over the q processes of
  its process row.
  The values of LOCr() and LOCc() may be determined via a call to the
  ScaLAPACK tool function, NUMROC:
          LOCr( M ) = NUMROC( M, MB_A, MYROW, RSRC_A, NPROW ),
          LOCc( N ) = NUMROC( N, NB_A, MYCOL, CSRC_A, NPCOL ).
  An upper bound for these quantities may be computed by:
          LOCr( M ) <= ceil( ceil(M/MB_A)/NPROW )*MB_A
          LOCc( N ) <= ceil( ceil(N/NB_A)/NPCOL )*NB_A
  Arguments
  =========
  SIDE    (global input) CHARACTER
          = 'L': apply Q or Q**T from the Left;
          = 'R': apply Q or Q**T from the Right.
  TRANS   (global input) CHARACTER
          = 'N':  No transpose, apply Q;
          = 'T':  Transpose, apply Q**T.
  DIRECT  (global input) CHARACTER
          Indicates how H is formed from a product of elementary
          reflectors
          = 'F': H = H(1) H(2) . . . H(k) (Forward, not supported yet)
          = 'B': H = H(k) . . . H(2) H(1) (Backward)
  STOREV  (global input) CHARACTER
          Indicates how the vectors which define the elementary
          reflectors are stored:
          = 'C': Columnwise                        (not supported yet)
          = 'R': Rowwise
  M       (global input) INTEGER
          The number of rows to be operated on i.e the number of rows
          of the distributed submatrix sub( C ). M >= 0.
  N       (global input) INTEGER
          The number of columns to be operated on i.e the number of
          columns of the distributed submatrix sub( C ). N >= 0.
  K       (global input) INTEGER
          The order of the matrix T (= the number of elementary
          reflectors whose product defines the block reflector).
  L       (global input) INTEGER
          The columns of the distributed submatrix sub( A ) containing
          the meaningful part of the Householder reflectors.
          If SIDE = 'L', M >= L >= 0, if SIDE = 'R', N >= L >= 0.
  V       (local input) REAL pointer into the local memory
          to an array of dimension (LLD_V, LOCc(JV+M-1)) if SIDE = 'L',
          (LLD_V, LOCc(JV+N-1)) if SIDE = 'R'. It contains the local
          pieces of the distributed vectors V representing the
          Householder transformation as returned by PSTZRZF.
          LLD_V >= LOCr(IV+K-1).
  IV      (global input) INTEGER
          The row index in the global array V indicating the first
          row of sub( V ).
  JV      (global input) INTEGER
          The column index in the global array V indicating the
          first column of sub( V ).
  DESCV   (global and local input) INTEGER array of dimension DLEN_.
          The array descriptor for the distributed matrix V.
  T       (local input) REAL array, dimension MB_V by MB_V
          The lower triangular matrix T in the representation of the
          block reflector.
  C       (local input/local output) REAL pointer into the
          local memory to an array of dimension (LLD_C,LOCc(JC+N-1)).
          On entry, the M-by-N distributed matrix sub( C ). On exit,
          sub( C ) is overwritten by Q*sub( C ) or Q'*sub( C ) or
          sub( C )*Q or sub( C )*Q'.
  IC      (global input) INTEGER
          The row index in the global array C indicating the first
          row of sub( C ).
  JC      (global input) INTEGER
          The column index in the global array C indicating the
          first column of sub( C ).
  DESCC   (global and local input) INTEGER array of dimension DLEN_.
          The array descriptor for the distributed matrix C.
  WORK    (local workspace) REAL array, dimension (LWORK)
          If STOREV = 'C',
            if SIDE = 'L',
              LWORK >= ( NqC0 + MpC0 ) * K
            else if SIDE = 'R',
              LWORK >= ( NqC0 + MAX( NpV0 + NUMROC( NUMROC( N+ICOFFC,
                         NB_V, 0, 0, NPCOL ), NB_V, 0, 0, LCMQ ),
                         MpC0 ) ) * K
            end if
          else if STOREV = 'R',
            if SIDE = 'L',
              LWORK >= ( MpC0 + MAX( MqV0 + NUMROC( NUMROC( M+IROFFC,
                         MB_V, 0, 0, NPROW ), MB_V, 0, 0, LCMP ),
                         NqC0 ) ) * K
            else if SIDE = 'R',
              LWORK >= ( MpC0 + NqC0 ) * K
            end if
          end if
          where LCMQ = LCM / NPCOL with LCM = ICLM( NPROW, NPCOL ),
          IROFFV = MOD( IV-1, MB_V ), ICOFFV = MOD( JV-1, NB_V ),
          IVROW = INDXG2P( IV, MB_V, MYROW, RSRC_V, NPROW ),
          IVCOL = INDXG2P( JV, NB_V, MYCOL, CSRC_V, NPCOL ),
          MqV0 = NUMROC( M+ICOFFV, NB_V, MYCOL, IVCOL, NPCOL ),
          NpV0 = NUMROC( N+IROFFV, MB_V, MYROW, IVROW, NPROW ),
          IROFFC = MOD( IC-1, MB_C ), ICOFFC = MOD( JC-1, NB_C ),
          ICROW = INDXG2P( IC, MB_C, MYROW, RSRC_C, NPROW ),
          ICCOL = INDXG2P( JC, NB_C, MYCOL, CSRC_C, NPCOL ),
          MpC0 = NUMROC( M+IROFFC, MB_C, MYROW, ICROW, NPROW ),
          NpC0 = NUMROC( N+ICOFFC, MB_C, MYROW, ICROW, NPROW ),
          NqC0 = NUMROC( N+ICOFFC, NB_C, MYCOL, ICCOL, NPCOL ),
          ILCM, INDXG2P and NUMROC are ScaLAPACK tool functions;
          MYROW, MYCOL, NPROW and NPCOL can be determined by calling
          the subroutine BLACS_GRIDINFO.
  Alignment requirements
  ======================
  The distributed submatrices V(IV:*, JV:*) and C(IC:IC+M-1,JC:JC+N-1)
  must verify some alignment properties, namely the following
  expressions should be true:
  If STOREV = 'Columnwise'
    If SIDE = 'Left',
      ( MB_V.EQ.MB_C .AND. IROFFV.EQ.IROFFC .AND. IVROW.EQ.ICROW )
    If SIDE = 'Right',
      ( MB_V.EQ.NB_C .AND. IROFFV.EQ.ICOFFC )
  else if STOREV = 'Rowwise'
    If SIDE = 'Left',
      ( NB_V.EQ.MB_C .AND. ICOFFV.EQ.IROFFC )
    If SIDE = 'Right',
      ( NB_V.EQ.NB_C .AND. ICOFFV.EQ.ICOFFC .AND. IVCOL.EQ.ICCOL )
  end if
  =====================================================================
     .. Parameters ..

 
Display dynamic version Find AutoScroll Reload FontSize: - + Hide Comments Hide Blanks Frame FullScreen MailPrint

 
001        SUBROUTINE PSLARZB( SIDE , TRANS , DIRECT , STOREV , M , N , K , L , V ,
002       $IV , JV , DESCV , T , C , IC , JC , DESCC , WORK )
003  
004  *     -- ScaLAPACK auxiliary routine(version 1.7) --
005  *     University of Tennessee , Knoxville , Oak Ridge National Laboratory ,
006  *     and University of California , Berkeley.
007  *     March 14 , 2000
008  
009  *     .. Scalar Arguments ..
010        CHARACTER DIRECT , SIDE , STOREV , TRANS
011        INTEGER IC , IV , JC , JV , K , L , M , N
012        INTEGER BLOCK_CYCLIC_2D , CSRC_ , CTXT_ , DLEN_ , DTYPE_ ,
013       $LLD_ , MB_ , M_ , NB_ , N_ , RSRC_
014        PARAMETER( BLOCK_CYCLIC_2D = 1 , DLEN_ = 9 , DTYPE_ = 1 ,
015       $CTXT_ = 2 , M_ = 3 , N_ = 4 , MB_ = 5 , NB_ = 6 ,
016       $RSRC_ = 7 , CSRC_ = 8 , LLD_ = 9 )
017        REAL ONE , ZERO
018        PARAMETER( ONE = 1.0E + 0 , ZERO = 0.0E + 0 )
019  *     ..
020  *     .. Local Scalars ..
021        LOGICAL LEFT
022        CHARACTER COLBTOP , TRANST
023        INTEGER ICCOL1 , ICCOL2 , ICOFFC1 , ICOFFC2 , ICOFFV ,
024       $ICROW1 , ICROW2 , ICTXT , IIBEG , IIC1 , IIC2 ,
025       $IIEND , IINXT , IIV , ILEFT , INFO , IOFFC2 , IOFFV ,
026       $IPT , IPV , IPW , IROFFC1 , IROFFC2 , ITOP , IVCOL ,
027       $IVROW , JJBEG , JJEND , JJNXT , JJC1 , JJC2 , JJV ,
028       $LDC , LDV , LV , LW , MBC , MBV , MPC1 , MPC2 , MPC20 ,
029       $MQV , MQV0 , MYCOL , MYDIST , MYROW , NBC , NBV ,
030       $NPCOL , NPROW , NQC1 , NQC2 , NQCALL , NQV
031  *     ..
032  *     .. External Subroutines ..
033        EXTERNAL BLACS_ABORT , BLACS_GRIDINFO , INFOG2L ,
034       $PBSMATADD , PBSTRAN , PB_TOPGET , PXERBLA ,
035       $SGEBR2D , SGEBS2D , SGEMM ,
036       $SGSUM2D , SLACPY , SLASET , STRBR2D ,
037       $STRBS2D , STRMM
038  *     ..
039  *     .. Intrinsic Functions ..
040        INTRINSIC MAX , MIN , MOD
041  *     ..
042  *     .. External Functions ..
043        LOGICAL LSAME
044        INTEGER ICEIL , NUMROC
045        EXTERNAL ICEIL , LSAME , NUMROC
046  *     ..
047  *     .. Executable Statements ..
048  
049  *     Quick return if possible
050  
051        IF( M.LE.0 .OR. N.LE.0 .OR. K.LE.0 )
052       $    RETURN
053  
054  *         Get grid parameters
055  
056            ICTXT = DESCC( CTXT_ )
057            CALL BLACS_GRIDINFO( ICTXT , NPROW , NPCOL , MYROW , MYCOL )
058  
059  *         Check for currently supported options
060  
061            INFO = 0
062            IF( .NOT.LSAME( DIRECT , 'B' ) ) THEN
063                INFO = - 3
064            ELSE IF( .NOT.LSAME( STOREV , 'R' ) ) THEN
065                INFO = - 4
066            END IF
067            IF( INFO.NE.0 ) THEN
068                CALL PXERBLA( ICTXT , 'PSLARZB' , - INFO )
069                CALL BLACS_ABORT( ICTXT , 1 )
070                RETURN
071            END IF
072  
073            LEFT = LSAME( SIDE , 'L' )
074            IF( LSAME( TRANS , 'N' ) ) THEN
075                TRANST = 'T'
076            ELSE
077                TRANST = 'N'
078            END IF
079  
080            CALL INFOG2L( IV , JV , DESCV , NPROW , NPCOL , MYROW , MYCOL , IIV , JJV ,
081       $    IVROW , IVCOL )
082            MBV = DESCV( MB_ )
083            NBV = DESCV( NB_ )
084            ICOFFV = MOD( JV - 1 , NBV )
085            NQV = NUMROC( L + ICOFFV , NBV , MYCOL , IVCOL , NPCOL )
086            IF( MYCOL.EQ.IVCOL )
087       $        NQV = NQV - ICOFFV
088                LDV = DESCV( LLD_ )
089                IIV = MIN( IIV , LDV )
090                JJV = MIN( JJV , MAX( 1 , NUMROC( DESCV( N_ ) , NBV , MYCOL ,
091       $        DESCV( CSRC_ ) , NPCOL ) ) )
092                IOFFV = IIV + ( JJV - 1 ) * LDV
093                MBC = DESCC( MB_ )
094                NBC = DESCC( NB_ )
095                NQCALL = NUMROC( DESCC( N_ ) , NBC , MYCOL , DESCC( CSRC_ ) , NPCOL )
096                CALL INFOG2L( IC , JC , DESCC , NPROW , NPCOL , MYROW , MYCOL , IIC1 ,
097       $        JJC1 , ICROW1 , ICCOL1 )
098                LDC = DESCC( LLD_ )
099                IIC1 = MIN( IIC1 , LDC )
100                JJC1 = MIN( JJC1 , MAX( 1 , NQCALL ) )
101  
102                IF( LEFT ) THEN
103                    IROFFC1 = MOD( IC - 1 , MBC )
104                    MPC1 = NUMROC( K + IROFFC1 , MBC , MYROW , ICROW1 , NPROW )
105                    IF( MYROW.EQ.ICROW1 )
106       $                MPC1 = MPC1 - IROFFC1
107                        ICOFFC1 = MOD( JC - 1 , NBC )
108                        NQC1 = NUMROC( N + ICOFFC1 , NBC , MYCOL , ICCOL1 , NPCOL )
109                        IF( MYCOL.EQ.ICCOL1 )
110       $                    NQC1 = NQC1 - ICOFFC1
111                            CALL INFOG2L( IC + M - L , JC , DESCC , NPROW , NPCOL , MYROW , MYCOL ,
112       $                    IIC2 , JJC2 , ICROW2 , ICCOL2 )
113                            IROFFC2 = MOD( IC + M - L - 1 , MBC )
114                            MPC2 = NUMROC( L + IROFFC2 , MBC , MYROW , ICROW2 , NPROW )
115                            IF( MYROW.EQ.ICROW2 )
116       $                        MPC2 = MPC2 - IROFFC2
117                                ICOFFC2 = ICOFFC1
118                                NQC2 = NQC1
119                            ELSE
120                                IROFFC1 = MOD( IC - 1 , MBC )
121                                MPC1 = NUMROC( M + IROFFC1 , MBC , MYROW , ICROW1 , NPROW )
122                                IF( MYROW.EQ.ICROW1 )
123       $                            MPC1 = MPC1 - IROFFC1
124                                    ICOFFC1 = MOD( JC - 1 , NBC )
125                                    NQC1 = NUMROC( K + ICOFFC1 , NBC , MYCOL , ICCOL1 , NPCOL )
126                                    IF( MYCOL.EQ.ICCOL1 )
127       $                                NQC1 = NQC1 - ICOFFC1
128                                        CALL INFOG2L( IC , JC + N - L , DESCC , NPROW , NPCOL , MYROW , MYCOL ,
129       $                                IIC2 , JJC2 , ICROW2 , ICCOL2 )
130                                        IROFFC2 = IROFFC1
131                                        MPC2 = MPC1
132                                        ICOFFC2 = MOD( JC + N - L - 1 , NBC )
133                                        NQC2 = NUMROC( L + ICOFFC2 , NBC , MYCOL , ICCOL2 , NPCOL )
134                                        IF( MYCOL.EQ.ICCOL2 )
135       $                                    NQC2 = NQC2 - ICOFFC2
136                                        END IF
137                                        IIC2 = MIN( IIC2 , LDC )
138                                        JJC2 = MIN( JJC2 , NQCALL )
139                                        IOFFC2 = IIC2 + ( JJC2 - 1 ) * LDC
140  
141                                        IF( LSAME( SIDE , 'L' ) ) THEN
142  
143  *                                         Form Q*sub( C ) or Q'*sub( C )
144  
145  *                                         IROFFC2 = ICOFFV is required by the current transposition
146  *                                         routine PBSTRAN
147  
148                                            MQV0 = NUMROC( M + ICOFFV , NBV , MYCOL , IVCOL , NPCOL )
149                                            IF( MYCOL.EQ.IVCOL ) THEN
150                                                MQV = MQV0 - ICOFFV
151                                            ELSE
152                                                MQV = MQV0
153                                            END IF
154                                            IF( MYROW.EQ.ICROW2 ) THEN
155                                                MPC20 = MPC2 + IROFFC2
156                                            ELSE
157                                                MPC20 = MPC2
158                                            END IF
159  
160  *                                         Locally V( IOFFV ) is K x MQV , C( IOFFC2 ) is MPC2 x NQC2
161  *                                         WORK( IPV ) is MPC20 x K =[ . V( IOFFV ) ]'
162  *                                         WORK( IPW ) is K x MQV0 =[ . V( IOFFV ) ]
163  *                                         WORK( IPT ) is the workspace for PBSTRAN
164  
165                                            IPV = 1
166                                            IPW = IPV + MPC20 * K
167                                            IPT = IPW + K * MQV0
168                                            LV = MAX( 1 , MPC20 )
169                                            LW = MAX( 1 , K )
170  
171                                            IF( MYROW.EQ.IVROW ) THEN
172                                                IF( MYCOL.EQ.IVCOL ) THEN
173                                                    CALL SLACPY( 'All' , K , MQV , V( IOFFV ) , LDV ,
174       $                                            WORK( IPW + ICOFFV*LW ) , LW )
175                                                ELSE
176                                                    CALL SLACPY( 'All' , K , MQV , V( IOFFV ) , LDV ,
177       $                                            WORK( IPW ) , LW )
178                                                END IF
179                                            END IF
180  
181  *                                         WORK( IPV ) = WORK( IPW )'(replicated) is MPC20 x K
182  
183                                            CALL PBSTRAN( ICTXT , 'Rowwise' , 'Transpose' , K , M + ICOFFV ,
184       $                                    DESCV( NB_ ) , WORK( IPW ) , LW , ZERO ,
185       $                                    WORK( IPV ) , LV , IVROW , IVCOL , ICROW2 , - 1 ,
186       $                                    WORK( IPT ) )
187  
188  *                                         WORK( IPV ) =( . V )' -> WORK( IPV ) = V' is MPC2 x K
189  
190                                            IF( MYROW.EQ.ICROW2 )
191       $                                        IPV = IPV + IROFFC2
192  
193  *                                             WORK( IPW ) becomes NQC2 x K = C( IOFFC2 )' * V'
194  *                                             WORK( IPW ) = C( IOFFC2 )' * V'(NQC2 x MPC2 x K) -> NQC2 x K
195  
196                                                LW = MAX( 1 , NQC2 )
197  
198                                                IF( MPC2.GT.0 ) THEN
199                                                    CALL SGEMM( 'Transpose' , 'No transpose' , NQC2 , K , MPC2 ,
200       $                                            ONE , C( IOFFC2 ) , LDC , WORK( IPV ) , LV , ZERO ,
201       $                                            WORK( IPW ) , LW )
202                                                ELSE
203                                                    CALL SLASET( 'All' , NQC2 , K , ZERO , ZERO , WORK( IPW ) , LW )
204                                                END IF
205  
206  *                                             WORK( IPW ) = WORK( IPW ) + C1( NQC1 = NQC2 )
207  
208                                                IF( MPC1.GT.0 ) THEN
209                                                    MYDIST = MOD( MYROW - ICROW1 + NPROW , NPROW )
210                                                    ITOP = MAX( 0 , MYDIST * MBC - IROFFC1 )
211                                                    IIBEG = IIC1
212                                                    IIEND = IIC1 + MPC1 - 1
213                                                    IINXT = MIN( ICEIL( IIBEG , MBC ) * MBC , IIEND )
214  
215     10 CONTINUE
216        IF( IIBEG.LE.IINXT ) THEN
217            CALL PBSMATADD( ICTXT , 'Transpose' , NQC2 , IINXT - IIBEG + 1 ,
218       $    ONE , C( IIBEG + (JJC1 - 1)*LDC ) , LDC , ONE ,
219       $    WORK( IPW + ITOP ) , LW )
220            MYDIST = MYDIST + NPROW
221            ITOP = MYDIST * MBC - IROFFC1
222            IIBEG = IINXT + 1
223            IINXT = MIN( IINXT + MBC , IIEND )
224            GO TO 10
225        END IF
226        END IF
227  
228        CALL SGSUM2D( ICTXT , 'Columnwise' , ' ' , NQC2 , K , WORK( IPW ) ,
229       $LW , IVROW , MYCOL )
230  
231  *     WORK( IPW ) = WORK( IPW ) * T' or WORK( IPW ) * T
232  
233        IF( MYROW.EQ.IVROW ) THEN
234            IF( MYCOL.EQ.IVCOL ) THEN
235  
236  *             Broadcast the block reflector to the other columns.
237  
238                CALL STRBS2D( ICTXT , 'Rowwise' , ' ' , 'Lower' , 'Non unit' ,
239       $        K , K , T , MBV )
240            ELSE
241                CALL STRBR2D( ICTXT , 'Rowwise' , ' ' , 'Lower' , 'Non unit' ,
242       $        K , K , T , MBV , MYROW , IVCOL )
243            END IF
244            CALL STRMM( 'Right' , 'Lower' , TRANST , 'Non unit' , NQC2 , K ,
245       $    ONE , T , MBV , WORK( IPW ) , LW )
246  
247            CALL SGEBS2D( ICTXT , 'Columnwise' , ' ' , NQC2 , K ,
248       $    WORK( IPW ) , LW )
249        ELSE
250            CALL SGEBR2D( ICTXT , 'Columnwise' , ' ' , NQC2 , K ,
251       $    WORK( IPW ) , LW , IVROW , MYCOL )
252        END IF
253  
254  *     C1 = C1 - WORK( IPW )
255  
256        IF( MPC1.GT.0 ) THEN
257            MYDIST = MOD( MYROW - ICROW1 + NPROW , NPROW )
258            ITOP = MAX( 0 , MYDIST * MBC - IROFFC1 )
259            IIBEG = IIC1
260            IIEND = IIC1 + MPC1 - 1
261            IINXT = MIN( ICEIL( IIBEG , MBC ) * MBC , IIEND )
262  
263     20 CONTINUE
264        IF( IIBEG.LE.IINXT ) THEN
265            CALL PBSMATADD( ICTXT , 'Transpose' , IINXT - IIBEG + 1 , NQC2 ,
266       $    - ONE , WORK( IPW + ITOP ) , LW , ONE ,
267       $    C( IIBEG + (JJC1 - 1)*LDC ) , LDC )
268            MYDIST = MYDIST + NPROW
269            ITOP = MYDIST * MBC - IROFFC1
270            IIBEG = IINXT + 1
271            IINXT = MIN( IINXT + MBC , IIEND )
272            GO TO 20
273        END IF
274        END IF
275  
276  *     C2 C2 - V' * W'
277  *     C( IOFFC2 ) = C( IOFFC2 ) - WORK( IPV ) * WORK( IPW )'
278  *     MPC2 x NQC2 MPC2 x K K x NQC2
279  
280        CALL SGEMM( 'No transpose' , 'Transpose' , MPC2 , NQC2 , K , - ONE ,
281       $WORK( IPV ) , LV , WORK( IPW ) , LW , ONE ,
282       $C( IOFFC2 ) , LDC )
283  
284        ELSE
285  
286  *         Form sub( C ) * Q or sub( C ) * Q'
287  
288  *         Locally V( IOFFV ) is K x NQV , C( IOFFC2 ) is MPC2 x NQC2
289  *         WORK( IPV ) is K x NQV = V( IOFFV ) , NQV = NQC2
290  *         WORK( IPW ) is MPC2 x K = C( IOFFC2 ) * V( IOFFV )'
291  
292            IPV = 1
293            IPW = IPV + K * NQC2
294            LV = MAX( 1 , K )
295            LW = MAX( 1 , MPC2 )
296  
297  *         Broadcast V to the other process rows.
298  
299            CALL PB_TOPGET( ICTXT , 'Broadcast' , 'Columnwise' , COLBTOP )
300            IF( MYROW.EQ.IVROW ) THEN
301                CALL SGEBS2D( ICTXT , 'Columnwise' , COLBTOP , K , NQC2 ,
302       $        V( IOFFV ) , LDV )
303                IF( MYCOL.EQ.IVCOL )
304       $            CALL STRBS2D( ICTXT , 'Columnwise' , COLBTOP , 'Lower' ,
305       $            'Non unit' , K , K , T , MBV )
306                    CALL SLACPY( 'All' , K , NQC2 , V( IOFFV ) , LDV , WORK( IPV ) ,
307       $            LV )
308                ELSE
309                    CALL SGEBR2D( ICTXT , 'Columnwise' , COLBTOP , K , NQC2 ,
310       $            WORK( IPV ) , LV , IVROW , MYCOL )
311                    IF( MYCOL.EQ.IVCOL )
312       $                CALL STRBR2D( ICTXT , 'Columnwise' , COLBTOP , 'Lower' ,
313       $                'Non unit' , K , K , T , MBV , IVROW , MYCOL )
314                    END IF
315  
316  *                 WORK( IPV ) is K x NQC2 = V = V( IOFFV )
317  *                 WORK( IPW ) = C( IOFFC2 ) * V'(MPC2 x NQC2 x K) -> MPC2 x K
318  
319                    IF( NQC2.GT.0 ) THEN
320                        CALL SGEMM( 'No Transpose' , 'Transpose' , MPC2 , K , NQC2 ,
321       $                ONE , C( IOFFC2 ) , LDC , WORK( IPV ) , LV , ZERO ,
322       $                WORK( IPW ) , LW )
323                    ELSE
324                        CALL SLASET( 'All' , MPC2 , K , ZERO , ZERO , WORK( IPW ) , LW )
325                    END IF
326  
327  *                 WORK( IPW ) = WORK( IPW ) + C1( MPC1 = MPC2 )
328  
329                    IF( NQC1.GT.0 ) THEN
330                        MYDIST = MOD( MYCOL - ICCOL1 + NPCOL , NPCOL )
331                        ILEFT = MAX( 0 , MYDIST * NBC - ICOFFC1 )
332                        JJBEG = JJC1
333                        JJEND = JJC1 + NQC1 - 1
334                        JJNXT = MIN( ICEIL( JJBEG , NBC ) * NBC , JJEND )
335  
336     30 CONTINUE
337        IF( JJBEG.LE.JJNXT ) THEN
338            CALL PBSMATADD( ICTXT , 'No transpose' , MPC2 ,
339       $    JJNXT - JJBEG + 1 , ONE ,
340       $    C( IIC1 + (JJBEG - 1)*LDC ) , LDC , ONE ,
341       $    WORK( IPW + ILEFT*LW ) , LW )
342            MYDIST = MYDIST + NPCOL
343            ILEFT = MYDIST * NBC - ICOFFC1
344            JJBEG = JJNXT + 1
345            JJNXT = MIN( JJNXT + NBC , JJEND )
346            GO TO 30
347        END IF
348        END IF
349  
350        CALL SGSUM2D( ICTXT , 'Rowwise' , ' ' , MPC2 , K , WORK( IPW ) ,
351       $LW , MYROW , IVCOL )
352  
353  *     WORK( IPW ) = WORK( IPW ) * T' or WORK( IPW ) * T
354  
355        IF( MYCOL.EQ.IVCOL ) THEN
356            CALL STRMM( 'Right' , 'Lower' , TRANS , 'Non unit' , MPC2 , K ,
357       $    ONE , T , MBV , WORK( IPW ) , LW )
358            CALL SGEBS2D( ICTXT , 'Rowwise' , ' ' , MPC2 , K , WORK( IPW ) ,
359       $    LW )
360        ELSE
361            CALL SGEBR2D( ICTXT , 'Rowwise' , ' ' , MPC2 , K , WORK( IPW ) ,
362       $    LW , MYROW , IVCOL )
363        END IF
364  
365  *     C1 = C1 - WORK( IPW )
366  
367        IF( NQC1.GT.0 ) THEN
368            MYDIST = MOD( MYCOL - ICCOL1 + NPCOL , NPCOL )
369            ILEFT = MAX( 0 , MYDIST * NBC - ICOFFC1 )
370            JJBEG = JJC1
371            JJEND = JJC1 + NQC1 - 1
372            JJNXT = MIN( ICEIL( JJBEG , NBC ) * NBC , JJEND )
373  
374     40 CONTINUE
375        IF( JJBEG.LE.JJNXT ) THEN
376            CALL PBSMATADD( ICTXT , 'No transpose' , MPC2 ,
377       $    JJNXT - JJBEG + 1 , - ONE ,
378       $    WORK( IPW + ILEFT*LW ) , LW , ONE ,
379       $    C( IIC1 + (JJBEG - 1)*LDC ) , LDC )
380            MYDIST = MYDIST + NPCOL
381            ILEFT = MYDIST * NBC - ICOFFC1
382            JJBEG = JJNXT + 1
383            JJNXT = MIN( JJNXT + NBC , JJEND )
384            GO TO 40
385        END IF
386        END IF
387  
388  *     C2 C2 - W * V
389  *     C( IOFFC ) = C( IOFFC ) - WORK( IPW ) * WORK( IPV )
390  *     MPC2 x NQC2 MPC2 x K K x NQC2
391  
392        IF( IOFFC2.GT.0 )
393       $    CALL SGEMM( 'No transpose' , 'No transpose' , MPC2 , NQC2 , K ,
394       $    - ONE , WORK( IPW ) , LW , WORK( IPV ) , LV , ONE ,
395       $    C( IOFFC2 ) , LDC )
396  
397        END IF
398  
399        RETURN
400  
401  *     End of PSLARZB
402  
403        END