ScaLAPACK 2.1  2.1
ScaLAPACK: Scalable Linear Algebra PACKage
PB_CVMnpq.c
Go to the documentation of this file.
1 /* ---------------------------------------------------------------------
2 *
3 * -- PBLAS auxiliary routine (version 2.0) --
4 * University of Tennessee, Knoxville, Oak Ridge National Laboratory,
5 * and University of California, Berkeley.
6 * April 1, 1998
7 *
8 * ---------------------------------------------------------------------
9 */
10 /*
11 * Include files
12 */
13 #include "../pblas.h"
14 #include "../PBpblas.h"
15 #include "../PBtools.h"
16 #include "../PBblacs.h"
17 #include "../PBblas.h"
18 
19 #ifdef __STDC__
20 int PB_CVMnpq( PB_VM_T * VM )
21 #else
22 int PB_CVMnpq( VM )
23 /*
24 * .. Array Arguments ..
25 */
26  PB_VM_T * VM;
27 #endif
28 {
29 /*
30 * Purpose
31 * =======
32 *
33 * PB_CVMnpq computes the number of diagonal entries in the virtual ma-
34 * specified by VM.
35 *
36 * Arguments
37 * =========
38 *
39 * VM (local input) pointer to a PB_VM_T structure
40 * On entry, VM is a pointer to a structure of type PB_VM_T,
41 * that contains the virtual matrix information (see pblas.h).
42 *
43 * -- Written on April 1, 1998 by
44 * Antoine Petitet, University of Tennessee, Knoxville 37996, USA.
45 *
46 * ---------------------------------------------------------------------
47 */
48 /*
49 * .. Local Scalars ..
50 */
51  int GoEast, GoSouth, Pmb, Qnb, gcdb, ilow, imbloc, inbloc, iupp,
52  kmax, kmin, k1, k2, k3, lcmb, lcmp, lcmq, lcmt, lcmt00,
53  lmbloc, lnbloc, low, l1, l2, l3, m, mb, mblkd, mblks, mbloc,
54  n, nb, nblkd, nblks, nbloc, nlcmblks, npcol, npq=0, nprow,
55  tmp1, tmp2, upp;
56 /* ..
57 * .. Executable Statements ..
58 *
59 */
60  m = VM->mp; n = VM->nq;
61 /*
62 * Quick return if I don't own any data.
63 */
64  if( ( m == 0 ) || ( n == 0 ) ) return( 0 );
65 /*
66 * The only valuable shortcut is when the virtual grid and the blocks are
67 * square, and the offset is zero or the grid is 1x1.
68 */
69  mb = VM->mb; nprow = VM->nprow;
70  nb = VM->nb; npcol = VM->npcol;
71 
72  if( ( ( VM->offd == 0 ) && ( VM->imb1 == VM->inb1 ) && ( mb == nb ) &&
73  ( nprow == npcol ) ) || ( ( nprow == 1 ) && ( npcol == 1 ) ) )
74  {
75  if( VM->prow == VM->pcol ) return( MIN( m, n ) );
76  else return( 0 );
77  }
78 /*
79 * Retrieve the contents of VM structure fields
80 */
81  lcmt00 = VM->lcmt00;
82  mblks = VM->mblks; imbloc = VM->imbloc; lmbloc = VM->lmbloc;
83  iupp = VM->iupp; upp = VM->upp;
84  nblks = VM->nblks; inbloc = VM->inbloc; lnbloc = VM->lnbloc;
85  ilow = VM->ilow; low = VM->low;
86  lcmb = VM->lcmb;
87  Pmb = nprow * mb;
88  Qnb = npcol * nb;
89 /*
90 * Handle separately the first row and/or column of the LCM table. Update the
91 * LCM value of the curent block lcmt00, as well as the number of rows and
92 * columns mblks and nblks remaining in the LCM table.
93 */
94  GoSouth = ( lcmt00 > iupp );
95  GoEast = ( lcmt00 < ilow );
96 /*
97 * Go through the table looking for blocks owning diagonal entries.
98 */
99  if( !( GoSouth ) && !( GoEast ) )
100  {
101 /*
102 * The upper left block owns diagonal entries lcmt00 >= ilow && lcmt00 <= iupp
103 */
104  npq += ( lcmt00 >= 0 ?
105  ( ( tmp2 = ( tmp1 = imbloc - lcmt00 ) > 0 ? tmp1 : 0 ) < inbloc ?
106  tmp2 : inbloc ) :
107  ( ( tmp2 = ( tmp1 = inbloc + lcmt00 ) > 0 ? tmp1 : 0 ) > imbloc ?
108  imbloc : tmp2 ) );
109 /*
110 * Decide whether one should go south or east in the table: Go east if
111 * the block below the current one only owns lower entries. If this block,
112 * however, owns diagonals, then go south.
113 */
114  GoSouth = !( GoEast = ( ( lcmt00 - ( iupp - upp + Pmb ) ) < ilow ) );
115  }
116 
117  if( GoSouth )
118  {
119 /*
120 * Go one step south in the LCM table. Adjust the current LCM value.
121 */
122  lcmt00 -= iupp - upp + Pmb; mblks--;
123 /*
124 * While there are blocks remaining that own upper entries, keep going south.
125 * Adjust the current LCM value accordingly.
126 */
127  while( mblks && ( lcmt00 > upp ) ) { lcmt00 -= Pmb; mblks--; }
128 /*
129 * Return if no more row in the LCM table.
130 */
131  if( mblks <= 0 ) return( npq );
132 /*
133 * lcmt00 <= upp. The current block owns either diagonals or lower entries.
134 * Save the current position in the LCM table. After this column has been
135 * completely taken care of, re-start from this row and the next column of
136 * the LCM table.
137 */
138  lcmt = lcmt00; mblkd = mblks; mbloc = mb;
139 
140  while( mblkd && ( lcmt >= ilow ) )
141  {
142 /*
143 * A block owning diagonals lcmt00 >= ilow && lcmt00 <= upp has been found.
144 */
145  if( mblkd == 1 ) mbloc = lmbloc;
146  npq += ( lcmt >= 0 ?
147  ( ( tmp2 = ( tmp1 = mbloc - lcmt ) > 0 ? tmp1 : 0 ) < inbloc ?
148  tmp2 : inbloc ) :
149  ( ( tmp2 = ( tmp1 = inbloc + lcmt ) > 0 ? tmp1 : 0 ) > mbloc ?
150  mbloc : tmp2 ) );
151 /*
152 * Keep going south until there are no more blocks owning diagonals
153 */
154  lcmt00 = lcmt; lcmt -= Pmb; mblks = mblkd--;
155  }
156 /*
157 * I am done with the first column of the LCM table. Go to the next column.
158 */
159  lcmt00 += low - ilow + Qnb; nblks--;
160  }
161  else if( GoEast )
162  {
163 /*
164 * Go one step east in the LCM table. Adjust the current LCM value.
165 */
166  lcmt00 += low - ilow + Qnb; nblks--;
167 /*
168 * While there are blocks remaining that own lower entries, keep going east
169 * in the LCM table. Adjust the current LCM value accordingly.
170 */
171  while( nblks && ( lcmt00 < low ) ) { lcmt00 += Qnb; nblks--; }
172 /*
173 * Return if no more column in the LCM table.
174 */
175  if( nblks <= 0 ) return( npq );
176 /*
177 * lcmt00 >= low. The current block owns either diagonals or upper entries. Save
178 * the current position in the LCM table. After this row has been completely
179 * taken care of, re-start from this column and the next row of the LCM table.
180 */
181  lcmt = lcmt00; nblkd = nblks; nbloc = nb;
182 
183  while( nblkd && ( lcmt <= iupp ) )
184  {
185 /*
186 * A block owning diagonals lcmt00 >= low && lcmt00 <= iupp has been found.
187 */
188  if( nblkd == 1 ) nbloc = lnbloc;
189  npq += ( lcmt >= 0 ?
190  ( ( tmp2 = ( tmp1 = imbloc - lcmt ) > 0 ? tmp1 : 0 ) < nbloc ?
191  tmp2 : nbloc ) :
192  ( ( tmp2 = ( tmp1 = nbloc + lcmt ) > 0 ? tmp1 : 0 ) > imbloc ?
193  imbloc : tmp2 ) );
194 /*
195 * Keep going east until there are no more blocks owning diagonals.
196 */
197  lcmt00 = lcmt; lcmt += Qnb; nblks = nblkd--;
198  }
199 /*
200 * I am done with the first row of the LCM table. Go to the next row.
201 */
202  lcmt00 -= iupp - upp + Pmb; mblks--;
203  }
204 /*
205 * If the current block does not have diagonal elements, find the closest one in
206 * the LCM table having some.
207 */
208  if( lcmt00 < low || lcmt00 > upp )
209  {
210  while( mblks && nblks )
211  {
212  while( mblks && ( lcmt00 > upp ) ) { lcmt00 -= Pmb; mblks--; }
213  if( lcmt00 >= low ) break;
214  while( nblks && ( lcmt00 < low ) ) { lcmt00 += Qnb; nblks--; }
215  if( lcmt00 <= upp ) break;
216  }
217  }
218  if( !( mblks ) || !( nblks ) ) return( npq );
219 /*
220 * Figure out how many "full" lcm blocks are remaining.
221 */
222  gcdb = ( Pmb * Qnb ) / lcmb;
223 
224  if( lcmt00 > 0 )
225  {
226  kmin = - ( lcmb / gcdb );
227  kmax = ( lcmb - Qnb ) / gcdb;
228  tmp1 = ( mblks - 1 ) / ( lcmp = lcmb / Pmb );
229  tmp2 = nblks / ( lcmq = lcmb / Qnb );
230  }
231  else if( lcmt00 < 0 )
232  {
233  kmin = - ( ( lcmb - Pmb ) / gcdb );
234  kmax = lcmb / gcdb;
235  tmp1 = mblks / ( lcmp = lcmb / Pmb );
236  tmp2 = ( nblks - 1 ) / ( lcmq = lcmb / Qnb );
237  }
238  else
239  {
240  kmin = - ( ( lcmb - Pmb ) / gcdb );
241  kmax = ( lcmb - Qnb ) / gcdb;
242  tmp1 = mblks / ( lcmp = lcmb / Pmb );
243  tmp2 = nblks / ( lcmq = lcmb / Qnb );
244  }
245 /*
246 * The last block, even if it is an lcm block will be handled separately
247 */
248  nlcmblks = MIN( tmp1, tmp2 );
249  if( nlcmblks ) nlcmblks--;
250 /*
251 * Compute the lcm block part, update mblks and nblks
252 */
253  if( nlcmblks )
254  {
255  tmp2 = 0;
256 
257  k1 = -lcmt00; k1 = ICEIL( k1, gcdb ); l1 = k1 - 1;
258  l1 = MIN( l1, kmax ); k1 = MAX( k1, kmin );
259 
260  k3 = upp - lcmt00; k3 = FLOOR( k3, gcdb ); k3 = MIN( k3, kmax );
261  l3 = low - lcmt00; l3 = ICEIL( l3, gcdb ); l3 = MAX( l3, kmin );
262 
263  if( k1 <= k3 )
264  {
265  k2 = mb - nb - lcmt00;
266  k2 = ICEIL( k2, gcdb );
267 
268  if( k2 < k1 )
269  {
270 /*
271 * k2 < k1
272 */
273  tmp1 = k3 - k1 + 1;
274  tmp2 = tmp1 * ( mb - lcmt00 );
275  tmp1 *= ( k3 + k1 )*gcdb;
276  tmp2 += ( tmp1 > 0 ? -( tmp1 / 2 ) : (-tmp1) / 2 );
277  }
278  else if( k2 > k3 )
279  {
280 /*
281 * k2 = k3 + 1
282 */
283  tmp2 = ( k3 - k1 + 1 ) * nb;
284  }
285  else
286  {
287 /*
288 * k1 <= k2 <= k3
289 */
290  tmp1 = k3 - k2 + 1;
291  tmp2 = ( k2 - k1 ) * nb + tmp1 * ( mb - lcmt00 );
292  tmp1 *= ( k3 + k2 ) * gcdb;
293  tmp2 += ( tmp1 > 0 ? -( tmp1 / 2 ) : (-tmp1) / 2 );
294  }
295  }
296 
297  if( l3 <= l1 )
298  {
299  l2 = mb - nb - lcmt00;
300  l2 = FLOOR( l2, gcdb );
301 
302  if( l2 > l1 )
303  {
304 /*
305 * l2 > l1
306 */
307  tmp1 = l1 - l3 + 1;
308  tmp2 += tmp1 * ( nb + lcmt00 );
309  tmp1 *= ( l3 + l1 ) * gcdb;
310  tmp2 += ( tmp1 > 0 ? ( tmp1 / 2 ) : -( (-tmp1) / 2 ) );
311  }
312  else if( l2 < l3 )
313  {
314 /*
315 * l2 = l3 - 1
316 */
317  tmp2 += ( l1 - l3 + 1 ) * mb;
318  }
319  else
320  {
321 /*
322 * l3 <= l2 <= l1
323 */
324  tmp1 = l2 - l3 + 1;
325  tmp2 += ( l1 - l2 ) * mb + tmp1 * ( nb + lcmt00 );
326  tmp1 *= ( l3 + l2 ) * gcdb;
327  tmp2 += ( tmp1 > 0 ? ( tmp1 / 2 ) : -( (-tmp1) / 2 ) );
328  }
329  }
330  npq += nlcmblks * tmp2;
331 
332  mblks -= nlcmblks * lcmp;
333  nblks -= nlcmblks * lcmq;
334  }
335 /*
336 * Handle last partial (lcm) block separately
337 */
338  nbloc = nb;
339  while( nblks )
340  {
341 /*
342 * The current block owns diagonals. Save the current position in the LCM table.
343 * After this column has been completely taken care of, re-start from this row
344 * and the next column in the LCM table.
345 */
346  if( nblks == 1 ) nbloc = lnbloc;
347  while( mblks && lcmt00 > upp ) { lcmt00 -= Pmb; mblks--; }
348 
349  if( mblks <= 0 ) return( npq );
350 
351  lcmt = lcmt00; mblkd = mblks; mbloc = mb;
352 
353  while( mblkd && ( lcmt >= low ) )
354  {
355 /*
356 * A block owning diagonals lcmt00 >= low && lcmt00 <= upp has been found.
357 */
358  if( mblkd == 1 ) mbloc = lmbloc;
359  npq += ( lcmt >= 0 ?
360  ( ( tmp2 = ( tmp1 = mbloc - lcmt ) > 0 ? tmp1 : 0 ) < nbloc ?
361  tmp2 : nbloc ) :
362  ( ( tmp2 = ( tmp1 = nbloc + lcmt ) > 0 ? tmp1 : 0 ) > mbloc ?
363  mbloc : tmp2 ) );
364 /*
365 * Keep going south until there are no more blocks owning diagonals
366 */
367  lcmt00 = lcmt; lcmt -= Pmb; mblks = mblkd--;
368  }
369 /*
370 * I am done with this column of the LCM table. Go to the next column ...
371 */
372  lcmt00 += Qnb; nblks--;
373 /*
374 * ... until there are no more columns.
375 */
376  }
377 /*
378 * Return the number of diagonals found.
379 */
380  return( npq );
381 /*
382 * End of PB_CVMnpq
383 */
384 }
PB_VM_T::mp
int mp
Definition: pblas.h:437
ICEIL
#define ICEIL(a, b)
Definition: PBtools.h:81
PB_CVMnpq
int PB_CVMnpq(PB_VM_T *VM)
Definition: PB_CVMnpq.c:22
FLOOR
#define FLOOR(a, b)
Definition: PBtools.h:79
PB_VM_T
Definition: pblas.h:432
MIN
#define MIN(a_, b_)
Definition: PBtools.h:76
MAX
#define MAX(a_, b_)
Definition: PBtools.h:77