001:       SUBROUTINE ZLA_GEAMV ( TRANS, M, N, ALPHA, A, LDA, X, INCX, BETA,
002:      $                       Y, INCY )
003: *
004: *     -- LAPACK routine (version 3.2.1)                                 --
005: *     -- Contributed by James Demmel, Deaglan Halligan, Yozo Hida and --
006: *     -- Jason Riedy of Univ. of California Berkeley.                 --
007: *     -- April 2009                                                   --
008: *
009: *     -- LAPACK is a software package provided by Univ. of Tennessee, --
010: *     -- Univ. of California Berkeley and NAG Ltd.                    --
011: *
012:       IMPLICIT NONE
013: *     ..
014: *     .. Scalar Arguments ..
015:       DOUBLE PRECISION   ALPHA, BETA
016:       INTEGER            INCX, INCY, LDA, M, N
017:       INTEGER            TRANS
018: *     ..
019: *     .. Array Arguments ..
020:       COMPLEX*16         A( LDA, * ), X( * )
021:       DOUBLE PRECISION   Y( * )
022: *     ..
023: *
024: *  Purpose
025: *  =======
026: *
027: *  ZLA_GEAMV  performs one of the matrix-vector operations
028: *
029: *          y := alpha*abs(A)*abs(x) + beta*abs(y),
030: *     or   y := alpha*abs(A)'*abs(x) + beta*abs(y),
031: *
032: *  where alpha and beta are scalars, x and y are vectors and A is an
033: *  m by n matrix.
034: *
035: *  This function is primarily used in calculating error bounds.
036: *  To protect against underflow during evaluation, components in
037: *  the resulting vector are perturbed away from zero by (N+1)
038: *  times the underflow threshold.  To prevent unnecessarily large
039: *  errors for block-structure embedded in general matrices,
040: *  "symbolically" zero components are not perturbed.  A zero
041: *  entry is considered "symbolic" if all multiplications involved
042: *  in computing that entry have at least one zero multiplicand.
043: *
044: *  Arguments
045: *  ==========
046: *
047: *  TRANS  - INTEGER
048: *           On entry, TRANS specifies the operation to be performed as
049: *           follows:
050: *
051: *             BLAS_NO_TRANS      y := alpha*abs(A)*abs(x) + beta*abs(y)
052: *             BLAS_TRANS         y := alpha*abs(A')*abs(x) + beta*abs(y)
053: *             BLAS_CONJ_TRANS    y := alpha*abs(A')*abs(x) + beta*abs(y)
054: *
055: *           Unchanged on exit.
056: *
057: *  M      - INTEGER
058: *           On entry, M specifies the number of rows of the matrix A.
059: *           M must be at least zero.
060: *           Unchanged on exit.
061: *
062: *  N      - INTEGER
063: *           On entry, N specifies the number of columns of the matrix A.
064: *           N must be at least zero.
065: *           Unchanged on exit.
066: *
067: *  ALPHA  - DOUBLE PRECISION
068: *           On entry, ALPHA specifies the scalar alpha.
069: *           Unchanged on exit.
070: *
071: *  A      - COMPLEX*16         array of DIMENSION ( LDA, n )
072: *           Before entry, the leading m by n part of the array A must
073: *           contain the matrix of coefficients.
074: *           Unchanged on exit.
075: *
076: *  LDA    - INTEGER
077: *           On entry, LDA specifies the first dimension of A as declared
078: *           in the calling (sub) program. LDA must be at least
079: *           max( 1, m ).
080: *           Unchanged on exit.
081: *
082: *  X      - COMPLEX*16         array of DIMENSION at least
083: *           ( 1 + ( n - 1 )*abs( INCX ) ) when TRANS = 'N' or 'n'
084: *           and at least
085: *           ( 1 + ( m - 1 )*abs( INCX ) ) otherwise.
086: *           Before entry, the incremented array X must contain the
087: *           vector x.
088: *           Unchanged on exit.
089: *
090: *  INCX   - INTEGER
091: *           On entry, INCX specifies the increment for the elements of
092: *           X. INCX must not be zero.
093: *           Unchanged on exit.
094: *
095: *  BETA   - DOUBLE PRECISION
096: *           On entry, BETA specifies the scalar beta. When BETA is
097: *           supplied as zero then Y need not be set on input.
098: *           Unchanged on exit.
099: *
100: *  Y      - DOUBLE PRECISION   array of DIMENSION at least
101: *           ( 1 + ( m - 1 )*abs( INCY ) ) when TRANS = 'N' or 'n'
102: *           and at least
103: *           ( 1 + ( n - 1 )*abs( INCY ) ) otherwise.
104: *           Before entry with BETA non-zero, the incremented array Y
105: *           must contain the vector y. On exit, Y is overwritten by the
106: *           updated vector y.
107: *
108: *  INCY   - INTEGER
109: *           On entry, INCY specifies the increment for the elements of
110: *           Y. INCY must not be zero.
111: *           Unchanged on exit.
112: *
113: *
114: *  Level 2 Blas routine.
115: *
116: *  =====================================================================
117: *
118: *     .. Parameters ..
119:       COMPLEX*16         ONE, ZERO
120:       PARAMETER          ( ONE = 1.0D+0, ZERO = 0.0D+0 )
121: *     ..
122: *     .. Local Scalars ..
123:       LOGICAL            SYMB_ZERO
124:       DOUBLE PRECISION   TEMP, SAFE1
125:       INTEGER            I, INFO, IY, J, JX, KX, KY, LENX, LENY
126:       COMPLEX*16         CDUM
127: *     ..
128: *     .. External Subroutines ..
129:       EXTERNAL           XERBLA, DLAMCH
130:       DOUBLE PRECISION   DLAMCH
131: *     ..
132: *     .. External Functions ..
133:       EXTERNAL           ILATRANS
134:       INTEGER            ILATRANS
135: *     ..
136: *     .. Intrinsic Functions ..
137:       INTRINSIC          MAX, ABS, REAL, DIMAG, SIGN
138: *     ..
139: *     .. Statement Functions ..
140:       DOUBLE PRECISION   CABS1
141: *     ..
142: *     .. Statement Function Definitions ..
143:       CABS1( CDUM ) = ABS( DBLE( CDUM ) ) + ABS( DIMAG( CDUM ) )
144: *     ..
145: *     .. Executable Statements ..
146: *
147: *     Test the input parameters.
148: *
149:       INFO = 0
150:       IF     ( .NOT.( ( TRANS.EQ.ILATRANS( 'N' ) )
151:      $           .OR. ( TRANS.EQ.ILATRANS( 'T' ) )
152:      $           .OR. ( TRANS.EQ.ILATRANS( 'C' ) ) ) ) THEN
153:          INFO = 1
154:       ELSE IF( M.LT.0 )THEN
155:          INFO = 2
156:       ELSE IF( N.LT.0 )THEN
157:          INFO = 3
158:       ELSE IF( LDA.LT.MAX( 1, M ) )THEN
159:          INFO = 6
160:       ELSE IF( INCX.EQ.0 )THEN
161:          INFO = 8
162:       ELSE IF( INCY.EQ.0 )THEN
163:          INFO = 11
164:       END IF
165:       IF( INFO.NE.0 )THEN
166:          CALL XERBLA( 'ZLA_GEAMV ', INFO )
167:          RETURN
168:       END IF
169: *
170: *     Quick return if possible.
171: *
172:       IF( ( M.EQ.0 ).OR.( N.EQ.0 ).OR.
173:      $    ( ( ALPHA.EQ.ZERO ).AND.( BETA.EQ.ONE ) ) )
174:      $   RETURN
175: *
176: *     Set  LENX  and  LENY, the lengths of the vectors x and y, and set
177: *     up the start points in  X  and  Y.
178: *
179:       IF( TRANS.EQ.ILATRANS( 'N' ) )THEN
180:          LENX = N
181:          LENY = M
182:       ELSE
183:          LENX = M
184:          LENY = N
185:       END IF
186:       IF( INCX.GT.0 )THEN
187:          KX = 1
188:       ELSE
189:          KX = 1 - ( LENX - 1 )*INCX
190:       END IF
191:       IF( INCY.GT.0 )THEN
192:          KY = 1
193:       ELSE
194:          KY = 1 - ( LENY - 1 )*INCY
195:       END IF
196: *
197: *     Set SAFE1 essentially to be the underflow threshold times the
198: *     number of additions in each row.
199: *
200:       SAFE1 = DLAMCH( 'Safe minimum' )
201:       SAFE1 = (N+1)*SAFE1
202: *
203: *     Form  y := alpha*abs(A)*abs(x) + beta*abs(y).
204: *
205: *     The O(M*N) SYMB_ZERO tests could be replaced by O(N) queries to
206: *     the inexact flag.  Still doesn't help change the iteration order
207: *     to per-column.
208: *
209:       IY = KY
210:       IF ( INCX.EQ.1 ) THEN
211:          IF( TRANS.EQ.ILATRANS( 'N' ) )THEN
212:             DO I = 1, LENY
213:                IF ( BETA .EQ. 0.0D+0 ) THEN
214:                   SYMB_ZERO = .TRUE.
215:                   Y( IY ) = 0.0D+0
216:                ELSE IF ( Y( IY ) .EQ. 0.0D+0 ) THEN
217:                   SYMB_ZERO = .TRUE.
218:                ELSE
219:                   SYMB_ZERO = .FALSE.
220:                   Y( IY ) = BETA * ABS( Y( IY ) )
221:                END IF
222:                IF ( ALPHA .NE. 0.0D+0 ) THEN
223:                   DO J = 1, LENX
224:                      TEMP = CABS1( A( I, J ) )
225:                      SYMB_ZERO = SYMB_ZERO .AND.
226:      $                    ( X( J ) .EQ. ZERO .OR. TEMP .EQ. ZERO )
227: 
228:                      Y( IY ) = Y( IY ) + ALPHA*CABS1( X( J ) )*TEMP
229:                   END DO
230:                END IF
231: 
232:                IF ( .NOT.SYMB_ZERO ) Y( IY ) =
233:      $              Y( IY ) + SIGN( SAFE1, Y( IY ) )
234: 
235:                IY = IY + INCY
236:             END DO
237:          ELSE
238:             DO I = 1, LENY
239:                IF ( BETA .EQ. 0.0D+0 ) THEN
240:                   SYMB_ZERO = .TRUE.
241:                   Y( IY ) = 0.0D+0
242:                ELSE IF ( Y( IY ) .EQ. 0.0D+0 ) THEN
243:                   SYMB_ZERO = .TRUE.
244:                ELSE
245:                   SYMB_ZERO = .FALSE.
246:                   Y( IY ) = BETA * ABS( Y( IY ) )
247:                END IF
248:                IF ( ALPHA .NE. 0.0D+0 ) THEN
249:                   DO J = 1, LENX
250:                      TEMP = CABS1( A( J, I ) )
251:                      SYMB_ZERO = SYMB_ZERO .AND.
252:      $                    ( X( J ) .EQ. ZERO .OR. TEMP .EQ. ZERO )
253: 
254:                      Y( IY ) = Y( IY ) + ALPHA*CABS1( X( J ) )*TEMP
255:                   END DO
256:                END IF
257: 
258:                IF ( .NOT.SYMB_ZERO ) Y( IY ) =
259:      $              Y( IY ) + SIGN( SAFE1, Y( IY ) )
260: 
261:                IY = IY + INCY
262:             END DO
263:          END IF
264:       ELSE
265:          IF( TRANS.EQ.ILATRANS( 'N' ) )THEN
266:             DO I = 1, LENY
267:                IF ( BETA .EQ. 0.0D+0 ) THEN
268:                   SYMB_ZERO = .TRUE.
269:                   Y( IY ) = 0.0D+0
270:                ELSE IF ( Y( IY ) .EQ. 0.0D+0 ) THEN
271:                   SYMB_ZERO = .TRUE.
272:                ELSE
273:                   SYMB_ZERO = .FALSE.
274:                   Y( IY ) = BETA * ABS( Y( IY ) )
275:                END IF
276:                IF ( ALPHA .NE. 0.0D+0 ) THEN
277:                   JX = KX
278:                   DO J = 1, LENX
279:                      TEMP = CABS1( A( I, J ) )
280:                      SYMB_ZERO = SYMB_ZERO .AND.
281:      $                    ( X( JX ) .EQ. ZERO .OR. TEMP .EQ. ZERO )
282: 
283:                      Y( IY ) = Y( IY ) + ALPHA*CABS1( X( JX ) )*TEMP
284:                      JX = JX + INCX
285:                   END DO
286:                END IF
287: 
288:                IF ( .NOT.SYMB_ZERO ) Y( IY ) =
289:      $              Y( IY ) + SIGN( SAFE1, Y( IY ) )
290: 
291:                IY = IY + INCY
292:             END DO
293:          ELSE
294:             DO I = 1, LENY
295:                IF ( BETA .EQ. 0.0D+0 ) THEN
296:                   SYMB_ZERO = .TRUE.
297:                   Y( IY ) = 0.0D+0
298:                ELSE IF ( Y( IY ) .EQ. 0.0D+0 ) THEN
299:                   SYMB_ZERO = .TRUE.
300:                ELSE
301:                   SYMB_ZERO = .FALSE.
302:                   Y( IY ) = BETA * ABS( Y( IY ) )
303:                END IF
304:                IF ( ALPHA .NE. 0.0D+0 ) THEN
305:                   JX = KX
306:                   DO J = 1, LENX
307:                      TEMP = CABS1( A( J, I ) )
308:                      SYMB_ZERO = SYMB_ZERO .AND.
309:      $                    ( X( JX ) .EQ. ZERO .OR. TEMP .EQ. ZERO )
310: 
311:                      Y( IY ) = Y( IY ) + ALPHA*CABS1( X( JX ) )*TEMP
312:                      JX = JX + INCX
313:                   END DO
314:                END IF
315: 
316:                IF ( .NOT.SYMB_ZERO ) Y( IY ) =
317:      $              Y( IY ) + SIGN( SAFE1, Y( IY ) )
318: 
319:                IY = IY + INCY
320:             END DO
321:          END IF
322: 
323:       END IF
324: *
325:       RETURN
326: *
327: *     End of ZLA_GEAMV
328: *
329:       END
330: