ScaLAPACK 2.1  2.1
ScaLAPACK: Scalable Linear Algebra PACKage
psgebdrv.f
Go to the documentation of this file.
1  SUBROUTINE psgebdrv( M, N, A, IA, JA, DESCA, D, E, TAUQ, TAUP,
2  $ WORK, 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 1, 1997
8 *
9 * .. Scalar Arguments ..
10  INTEGER INFO, IA, JA, M, N
11 * ..
12 * .. Array Arguments ..
13  INTEGER DESCA( * )
14  REAL A( * ), D( * ), E( * ), TAUP( * ), TAUQ( * ),
15  $ work( * )
16 * ..
17 *
18 * Purpose
19 * =======
20 *
21 * PSGEBDRV computes sub( A ) = A(IA:IA+M-1,JA:JA+N-1) from sub( A ),
22 * Q, P returned by PSGEBRD:
23 *
24 * sub( A ) := Q * B * P'.
25 *
26 * Notes
27 * =====
28 *
29 * Each global data object is described by an associated description
30 * vector. This vector stores the information required to establish
31 * the mapping between an object element and its corresponding process
32 * and memory location.
33 *
34 * Let A be a generic term for any 2D block cyclicly distributed array.
35 * Such a global array has an associated description vector DESCA.
36 * In the following comments, the character _ should be read as
37 * "of the global array".
38 *
39 * NOTATION STORED IN EXPLANATION
40 * --------------- -------------- --------------------------------------
41 * DTYPE_A(global) DESCA( DTYPE_ )The descriptor type. In this case,
42 * DTYPE_A = 1.
43 * CTXT_A (global) DESCA( CTXT_ ) The BLACS context handle, indicating
44 * the BLACS process grid A is distribu-
45 * ted over. The context itself is glo-
46 * bal, but the handle (the integer
47 * value) may vary.
48 * M_A (global) DESCA( M_ ) The number of rows in the global
49 * array A.
50 * N_A (global) DESCA( N_ ) The number of columns in the global
51 * array A.
52 * MB_A (global) DESCA( MB_ ) The blocking factor used to distribute
53 * the rows of the array.
54 * NB_A (global) DESCA( NB_ ) The blocking factor used to distribute
55 * the columns of the array.
56 * RSRC_A (global) DESCA( RSRC_ ) The process row over which the first
57 * row of the array A is distributed.
58 * CSRC_A (global) DESCA( CSRC_ ) The process column over which the
59 * first column of the array A is
60 * distributed.
61 * LLD_A (local) DESCA( LLD_ ) The leading dimension of the local
62 * array. LLD_A >= MAX(1,LOCr(M_A)).
63 *
64 * Let K be the number of rows or columns of a distributed matrix,
65 * and assume that its process grid has dimension p x q.
66 * LOCr( K ) denotes the number of elements of K that a process
67 * would receive if K were distributed over the p processes of its
68 * process column.
69 * Similarly, LOCc( K ) denotes the number of elements of K that a
70 * process would receive if K were distributed over the q processes of
71 * its process row.
72 * The values of LOCr() and LOCc() may be determined via a call to the
73 * ScaLAPACK tool function, NUMROC:
74 * LOCr( M ) = NUMROC( M, MB_A, MYROW, RSRC_A, NPROW ),
75 * LOCc( N ) = NUMROC( N, NB_A, MYCOL, CSRC_A, NPCOL ).
76 * An upper bound for these quantities may be computed by:
77 * LOCr( M ) <= ceil( ceil(M/MB_A)/NPROW )*MB_A
78 * LOCc( N ) <= ceil( ceil(N/NB_A)/NPCOL )*NB_A
79 *
80 * Arguments
81 * =========
82 *
83 * M (global input) INTEGER
84 * The number of rows to be operated on, i.e. the number of rows
85 * of the distributed submatrix sub( A ). M >= 0.
86 *
87 * N (global input) INTEGER
88 * The number of columns to be operated on, i.e. the number of
89 * columns of the distributed submatrix sub( A ). N >= 0.
90 *
91 * A (local input/local output) REAL pointer into the
92 * local memory to an array of dimension (LLD_A, LOCc(JA+N-1)).
93 * On entry, this array contains the local pieces of sub( A )
94 * as returned by PSGEBRD. On exit, the original distribu-
95 * ted matrix sub( A ) is restored.
96 *
97 * IA (global input) INTEGER
98 * The row index in the global array A indicating the first
99 * row of sub( A ).
100 *
101 * JA (global input) INTEGER
102 * The column index in the global array A indicating the
103 * first column of sub( A ).
104 *
105 * DESCA (global and local input) INTEGER array of dimension DLEN_.
106 * The array descriptor for the distributed matrix A.
107 *
108 * D (local input) REAL array, dimension
109 * LOCc(JA+MIN(M,N)-1) if M >= N; LOCr(IA+MIN(M,N)-1) otherwise.
110 * The distributed diagonal elements of the bidiagonal matrix
111 * B: D(i) = A(i,i). D is tied to the distributed matrix A.
112 *
113 * E (local input) REAL array, dimension
114 * LOCr(IA+MIN(M,N)-1) if M >= N; LOCc(JA+MIN(M,N)-2) otherwise.
115 * The distributed off-diagonal elements of the bidiagonal
116 * distributed matrix B:
117 * if m >= n, E(i) = A(i,i+1) for i = 1,2,...,n-1;
118 * if m < n, E(i) = A(i+1,i) for i = 1,2,...,m-1.
119 * E is tied to the distributed matrix A.
120 *
121 * TAUQ (local input) REAL array dimension
122 * LOCc(JA+MIN(M,N)-1). The scalar factors of the elementary
123 * reflectors which represent the orthogonal matrix Q. TAUQ
124 * is tied to the distributed matrix A. See Further Details.
125 *
126 * TAUP (local input) REAL array, dimension
127 * LOCr(IA+MIN(M,N)-1). The scalar factors of the elementary
128 * reflectors which represent the orthogonal matrix P. TAUP
129 * is tied to the distributed matrix A. See Further Details.
130 *
131 * WORK (local workspace) REAL array, dimension (LWORK)
132 * LWORK >= 2*NB*( MP + NQ + NB )
133 *
134 * where NB = MB_A = NB_A,
135 * IROFFA = MOD( IA-1, NB ), ICOFFA = MOD( JA-1, NB ),
136 * IAROW = INDXG2P( IA, NB, MYROW, RSRC_A, NPROW ),
137 * IACOL = INDXG2P( JA, NB, MYCOL, CSRC_A, NPCOL ),
138 * MP = NUMROC( M+IROFFA, NB, MYROW, IAROW, NPROW ),
139 * NQ = NUMROC( N+ICOFFA, NB, MYCOL, IACOL, NPCOL ).
140 *
141 * INDXG2P and NUMROC are ScaLAPACK tool functions;
142 * MYROW, MYCOL, NPROW and NPCOL can be determined by calling
143 * the subroutine BLACS_GRIDINFO.
144 *
145 * INFO (global output) INTEGER
146 * On exit, if INFO <> 0, a discrepancy has been found between
147 * the diagonal and off-diagonal elements of A and the copies
148 * contained in the arrays D and E.
149 *
150 * =====================================================================
151 *
152 * .. Parameters ..
153  INTEGER BLOCK_CYCLIC_2D, CSRC_, CTXT_, DLEN_, DTYPE_,
154  $ lld_, mb_, m_, nb_, n_, rsrc_
155  parameter( block_cyclic_2d = 1, dlen_ = 9, dtype_ = 1,
156  $ ctxt_ = 2, m_ = 3, n_ = 4, mb_ = 5, nb_ = 6,
157  $ rsrc_ = 7, csrc_ = 8, lld_ = 9 )
158  REAL EIGHT, ONE, ZERO
159  parameter( eight = 8.0e+0, one = 1.0e+0, zero = 0.0e+0 )
160 * ..
161 * .. Local Scalars ..
162  INTEGER I, IACOL, IAROW, ICTXT, IIA, IL, IPTP, IPTQ,
163  $ ipv, ipw, ipwk, ioff, iv, j, jb, jja, jl, jv,
164  $ k, mn, mp, mycol, myrow, nb, npcol, nprow, nq
165  REAL ADDBND, D1, D2, E1, E2
166 * ..
167 * .. Local Arrays ..
168  INTEGER DESCD( DLEN_ ), DESCE( DLEN_ ), DESCV( DLEN_ ),
169  $ descw( dlen_ )
170 * ..
171 * .. External Subroutines ..
172  EXTERNAL blacs_gridinfo, descset, igsum2d, infog2l,
174  $ pselget
175 * ..
176 * .. External Functions ..
177  INTEGER INDXG2P, NUMROC
178  REAL PSLAMCH
179  EXTERNAL indxg2p, numroc, pslamch
180 * ..
181 * .. Intrinsic Functions ..
182  INTRINSIC abs, max, min, mod
183 * ..
184 * .. Executable Statements ..
185 *
186 * Get grid parameters
187 *
188  ictxt = desca( ctxt_ )
189  CALL blacs_gridinfo( ictxt, nprow, npcol, myrow, mycol )
190 *
191  info = 0
192  nb = desca( mb_ )
193  ioff = mod( ia-1, nb )
194  CALL infog2l( ia, ja, desca, nprow, npcol, myrow, mycol, iia, jja,
195  $ iarow, iacol )
196  mp = numroc( m+ioff, nb, myrow, iarow, nprow )
197  nq = numroc( n+ioff, nb, mycol, iacol, npcol )
198  ipv = 1
199  ipw = ipv + mp*nb
200  iptp = ipw + nq*nb
201  iptq = iptp + nb*nb
202  ipwk = iptq + nb*nb
203 *
204  iv = 1
205  jv = 1
206  mn = min( m, n )
207  il = max( ( (ia+mn-2) / nb )*nb + 1, ia )
208  jl = max( ( (ja+mn-2) / nb )*nb + 1, ja )
209  iarow = indxg2p( il, nb, myrow, desca( rsrc_ ), nprow )
210  iacol = indxg2p( jl, nb, mycol, desca( csrc_ ), npcol )
211  CALL descset( descv, ia+m-il, nb, nb, nb, iarow, iacol, ictxt,
212  $ max( 1, mp ) )
213  CALL descset( descw, nb, ja+n-jl, nb, nb, iarow, iacol, ictxt,
214  $ nb )
215 *
216  addbnd = eight * pslamch( ictxt, 'eps' )
217 *
218 * When A is an upper bidiagonal form
219 *
220  IF( m.GE.n ) THEN
221 *
222  CALL descset( descd, 1, ja+mn-1, 1, desca( nb_ ), myrow,
223  $ desca( csrc_ ), desca( ctxt_ ), 1 )
224  CALL descset( desce, ia+mn-1, 1, desca( mb_ ), 1,
225  $ desca( rsrc_ ), mycol, desca( ctxt_ ),
226  $ desca( lld_ ) )
227 *
228  DO 10 j = 0, mn-1
229  d1 = zero
230  e1 = zero
231  d2 = zero
232  e2 = zero
233  CALL pselget( ' ', ' ', d2, d, 1, ja+j, descd )
234  CALL pselget( 'Columnwise', ' ', d1, a, ia+j, ja+j, desca )
235  IF( j.LT.(mn-1) ) THEN
236  CALL pselget( ' ', ' ', e2, e, ia+j, 1, desce )
237  CALL pselget( 'Rowwise', ' ', e1, a, ia+j, ja+j+1,
238  $ desca )
239  END IF
240 *
241  IF( ( abs( d1 - d2 ).GT.( abs( d2 ) * addbnd ) ) .OR.
242  $ ( abs( e1 - e2 ).GT.( abs( e2 ) * addbnd ) ) )
243  $ info = info + 1
244  10 CONTINUE
245 *
246  DO 20 j = jl, ja+nb-ioff, -nb
247  jb = min( ja+n-j, nb )
248  i = ia + j - ja
249  k = i - ia + 1
250 *
251 * Compute upper triangular matrix TQ from TAUQ.
252 *
253  CALL pslarft( 'Forward', 'Columnwise', m-k+1, jb, a, i, j,
254  $ desca, tauq, work( iptq ), work( ipwk ) )
255 *
256 * Copy Householder vectors into workspace.
257 *
258  CALL pslacpy( 'Lower', m-k+1, jb, a, i, j, desca,
259  $ work( ipv ), iv, jv, descv )
260  CALL pslaset( 'Upper', m-k+1, jb, zero, one, work( ipv ),
261  $ iv, jv, descv )
262 *
263 * Zero out the strict lower triangular part of A.
264 *
265  CALL pslaset( 'Lower', m-k, jb, zero, zero, a, i+1, j,
266  $ desca )
267 *
268 * Compute upper triangular matrix TP from TAUP.
269 *
270  CALL pslarft( 'Forward', 'Rowwise', n-k, jb, a, i, j+1,
271  $ desca, taup, work( iptp ), work( ipwk ) )
272 *
273 * Copy Householder vectors into workspace.
274 *
275  CALL pslacpy( 'Upper', jb, n-k, a, i, j+1, desca,
276  $ work( ipw ), iv, jv+1, descw )
277  CALL pslaset( 'Lower', jb, n-k, zero, one, work( ipw ), iv,
278  $ jv+1, descw )
279 *
280 * Zero out the strict+1 upper triangular part of A.
281 *
282  CALL pslaset( 'Upper', jb, n-k-1, zero, zero, a, i, j+2,
283  $ desca )
284 *
285 * Apply block Householder transformation from Left.
286 *
287  CALL pslarfb( 'Left', 'No transpose', 'Forward',
288  $ 'Columnwise', m-k+1, n-k+1, jb, work( ipv ),
289  $ iv, jv, descv, work( iptq ), a, i, j, desca,
290  $ work( ipwk ) )
291 *
292 * Apply block Householder transformation from Right.
293 *
294  CALL pslarfb( 'Right', 'Transpose', 'Forward', 'Rowwise',
295  $ m-k+1, n-k, jb, work( ipw ), iv, jv+1, descw,
296  $ work( iptp ), a, i, j+1, desca, work( ipwk ) )
297 *
298  descv( m_ ) = descv( m_ ) + nb
299  descv( rsrc_ ) = mod( descv( rsrc_ ) + nprow - 1, nprow )
300  descv( csrc_ ) = mod( descv( csrc_ ) + npcol - 1, npcol )
301  descw( n_ ) = descw( n_ ) + nb
302  descw( rsrc_ ) = descv( rsrc_ )
303  descw( csrc_ ) = descv( csrc_ )
304 *
305  20 CONTINUE
306 *
307 * Handle first block separately
308 *
309  jb = min( n, nb - ioff )
310  iv = ioff + 1
311  jv = ioff + 1
312 *
313 * Compute upper triangular matrix TQ from TAUQ.
314 *
315  CALL pslarft( 'Forward', 'Columnwise', m, jb, a, ia, ja, desca,
316  $ tauq, work( iptq ), work( ipwk ) )
317 *
318 * Copy Householder vectors into workspace.
319 *
320  CALL pslacpy( 'Lower', m, jb, a, ia, ja, desca, work( ipv ),
321  $ iv, jv, descv )
322  CALL pslaset( 'Upper', m, jb, zero, one, work( ipv ), iv, jv,
323  $ descv )
324 *
325 * Zero out the strict lower triangular part of A.
326 *
327  CALL pslaset( 'Lower', m-1, jb, zero, zero, a, ia+1, ja,
328  $ desca )
329 *
330 * Compute upper triangular matrix TP from TAUP.
331 *
332  CALL pslarft( 'Forward', 'Rowwise', n-1, jb, a, ia, ja+1,
333  $ desca, taup, work( iptp ), work( ipwk ) )
334 *
335 * Copy Householder vectors into workspace.
336 *
337  CALL pslacpy( 'Upper', jb, n-1, a, ia, ja+1, desca,
338  $ work( ipw ), iv, jv+1, descw )
339  CALL pslaset( 'Lower', jb, n-1, zero, one, work( ipw ), iv,
340  $ jv+1, descw )
341 *
342 * Zero out the strict+1 upper triangular part of A.
343 *
344  CALL pslaset( 'Upper', jb, n-2, zero, zero, a, ia, ja+2,
345  $ desca )
346 *
347 * Apply block Householder transformation from left.
348 *
349  CALL pslarfb( 'Left', 'No transpose', 'Forward', 'Columnwise',
350  $ m, n, jb, work( ipv ), iv, jv, descv,
351  $ work( iptq ), a, ia, ja, desca, work( ipwk ) )
352 *
353 * Apply block Householder transformation from right.
354 *
355  CALL pslarfb( 'Right', 'Transpose', 'Forward', 'Rowwise', m,
356  $ n-1, jb, work( ipw ), iv, jv+1, descw,
357  $ work( iptp ), a, ia, ja+1, desca, work( ipwk ) )
358 *
359  ELSE
360 *
361  CALL descset( descd, ia+mn-1, 1, desca( mb_ ), 1,
362  $ desca( rsrc_ ), mycol, desca( ctxt_ ),
363  $ desca( lld_ ) )
364  CALL descset( desce, 1, ja+mn-2, 1, desca( nb_ ), myrow,
365  $ desca( csrc_ ), desca( ctxt_ ), 1 )
366 *
367  DO 30 j = 0, mn-1
368  d1 = zero
369  e1 = zero
370  d2 = zero
371  e2 = zero
372  CALL pselget( ' ', ' ', d2, d, ia+j, 1, descd )
373  CALL pselget( 'Rowwise', ' ', d1, a, ia+j, ja+j, desca )
374  IF( j.LT.(mn-1) ) THEN
375  CALL pselget( ' ', ' ', e2, e, 1, ja+j, desce )
376  CALL pselget( 'Columnwise', ' ', e1, a, ia+j+1, ja+j,
377  $ desca )
378  END IF
379 *
380  IF( ( abs( d1 - d2 ).GT.( abs( d2 ) * addbnd ) ) .OR.
381  $ ( abs( e1 - e2 ).GT.( abs( e2 ) * addbnd ) ) )
382  $ info = info + 1
383  30 CONTINUE
384 *
385  DO 40 i = il, ia+nb-ioff, -nb
386  jb = min( ia+m-i, nb )
387  j = ja + i - ia
388  k = j - ja + 1
389 *
390 * Compute upper triangular matrix TQ from TAUQ.
391 *
392  CALL pslarft( 'Forward', 'Columnwise', m-k, jb, a, i+1, j,
393  $ desca, tauq, work( iptq ), work( ipwk ) )
394 *
395 * Copy Householder vectors into workspace.
396 *
397  CALL pslacpy( 'Lower', m-k, jb, a, i+1, j, desca,
398  $ work( ipv ), iv+1, jv, descv )
399  CALL pslaset( 'Upper', m-k, jb, zero, one, work( ipv ),
400  $ iv+1, jv, descv )
401 *
402 * Zero out the strict lower triangular part of A.
403 *
404  CALL pslaset( 'Lower', m-k-1, jb, zero, zero, a, i+2, j,
405  $ desca )
406 *
407 * Compute upper triangular matrix TP from TAUP.
408 *
409  CALL pslarft( 'Forward', 'Rowwise', n-k+1, jb, a, i, j,
410  $ desca, taup, work( iptp ), work( ipwk ) )
411 *
412 * Copy Householder vectors into workspace.
413 *
414  CALL pslacpy( 'Upper', jb, n-k+1, a, i, j, desca,
415  $ work( ipw ), iv, jv, descw )
416  CALL pslaset( 'Lower', jb, n-k+1, zero, one, work( ipw ),
417  $ iv, jv, descw )
418 *
419 * Zero out the strict+1 upper triangular part of A.
420 *
421  CALL pslaset( 'Upper', jb, n-k, zero, zero, a, i, j+1,
422  $ desca )
423 *
424 * Apply block Householder transformation from Left.
425 *
426  CALL pslarfb( 'Left', 'No transpose', 'Forward',
427  $ 'Columnwise', m-k, n-k+1, jb, work( ipv ),
428  $ iv+1, jv, descv, work( iptq ), a, i+1, j,
429  $ desca, work( ipwk ) )
430 *
431 * Apply block Householder transformation from Right.
432 *
433  CALL pslarfb( 'Right', 'Transpose', 'Forward', 'Rowwise',
434  $ m-k+1, n-k+1, jb, work( ipw ), iv, jv, descw,
435  $ work( iptp ), a, i, j, desca, work( ipwk ) )
436 *
437  descv( m_ ) = descv( m_ ) + nb
438  descv( rsrc_ ) = mod( descv( rsrc_ ) + nprow - 1, nprow )
439  descv( csrc_ ) = mod( descv( csrc_ ) + npcol - 1, npcol )
440  descw( n_ ) = descw( n_ ) + nb
441  descw( rsrc_ ) = descv( rsrc_ )
442  descw( csrc_ ) = descv( csrc_ )
443 *
444  40 CONTINUE
445 *
446 * Handle first block separately
447 *
448  jb = min( m, nb - ioff )
449  iv = ioff + 1
450  jv = ioff + 1
451 *
452 * Compute upper triangular matrix TQ from TAUQ.
453 *
454  CALL pslarft( 'Forward', 'Columnwise', m-1, jb, a, ia+1, ja,
455  $ desca, tauq, work( iptq ), work( ipwk ) )
456 *
457 * Copy Householder vectors into workspace.
458 *
459  CALL pslacpy( 'Lower', m-1, jb, a, ia+1, ja, desca,
460  $ work( ipv ), iv+1, jv, descv )
461  CALL pslaset( 'Upper', m-1, jb, zero, one, work( ipv ), iv+1,
462  $ jv, descv )
463 *
464 * Zero out the strict lower triangular part of A.
465 *
466  CALL pslaset( 'Lower', m-2, jb, zero, zero, a, ia+2, ja,
467  $ desca )
468 *
469 * Compute upper triangular matrix TP from TAUP.
470 *
471  CALL pslarft( 'Forward', 'Rowwise', n, jb, a, ia, ja, desca,
472  $ taup, work( iptp ), work( ipwk ) )
473 *
474 * Copy Householder vectors into workspace.
475 *
476  CALL pslacpy( 'Upper', jb, n, a, ia, ja, desca, work( ipw ),
477  $ iv, jv, descw )
478  CALL pslaset( 'Lower', jb, n, zero, one, work( ipw ), iv, jv,
479  $ descw )
480 *
481 * Zero out the strict+1 upper triangular part of A.
482 *
483  CALL pslaset( 'Upper', jb, n-1, zero, zero, a, ia, ja+1,
484  $ desca )
485 *
486 * Apply block Householder transformation from left
487 *
488  CALL pslarfb( 'Left', 'No transpose', 'Forward', 'Columnwise',
489  $ m-1, n, jb, work( ipv ), iv+1, jv, descv,
490  $ work( iptq ), a, ia+1, ja, desca, work( ipwk ) )
491 *
492 * Apply block Householder transformation from right
493 *
494  CALL pslarfb( 'Right', 'Transpose', 'Forward', 'Rowwise', m, n,
495  $ jb, work( ipw ), iv, jv, descw, work( iptp ),
496  $ a, ia, ja, desca, work( ipwk ) )
497  END IF
498 *
499  CALL igsum2d( ictxt, 'All', ' ', 1, 1, info, 1, -1, 0 )
500 *
501  RETURN
502 *
503 * End of PSGEBDRV
504 *
505  END
max
#define max(A, B)
Definition: pcgemr.c:180
infog2l
subroutine infog2l(GRINDX, GCINDX, DESC, NPROW, NPCOL, MYROW, MYCOL, LRINDX, LCINDX, RSRC, CSRC)
Definition: infog2l.f:3
psgebdrv
subroutine psgebdrv(M, N, A, IA, JA, DESCA, D, E, TAUQ, TAUP, WORK, INFO)
Definition: psgebdrv.f:3
pslacpy
subroutine pslacpy(UPLO, M, N, A, IA, JA, DESCA, B, IB, JB, DESCB)
Definition: pslacpy.f:3
descset
subroutine descset(DESC, M, N, MB, NB, IRSRC, ICSRC, ICTXT, LLD)
Definition: descset.f:3
pselget
subroutine pselget(SCOPE, TOP, ALPHA, A, IA, JA, DESCA)
Definition: pselget.f:2
pslarfb
subroutine pslarfb(SIDE, TRANS, DIRECT, STOREV, M, N, K, V, IV, JV, DESCV, T, C, IC, JC, DESCC, WORK)
Definition: pslarfb.f:3
pslarft
subroutine pslarft(DIRECT, STOREV, N, K, V, IV, JV, DESCV, TAU, T, WORK)
Definition: pslarft.f:3
pslaset
subroutine pslaset(UPLO, M, N, ALPHA, BETA, A, IA, JA, DESCA)
Definition: psblastst.f:6863
min
#define min(A, B)
Definition: pcgemr.c:181