PaStiX Handbook  6.3.2
symbol.c
Go to the documentation of this file.
1 /**
2  *
3  * @file symbol.c
4  *
5  * PaStiX symbol structure routines
6  *
7  * @copyright 2004-2023 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
8  * Univ. Bordeaux. All rights reserved.
9  *
10  * @version 6.3.2
11  * @author David Goudin
12  * @author Francois Pellegrini
13  * @author Mathieu Faverge
14  * @author Pascal Henon
15  * @author Pierre Ramet
16  * @author Tony Delarue
17  * @date 2023-07-21
18  *
19  **/
20 #include "common.h"
21 #include "graph/graph.h"
22 #include "pastix/order.h"
23 #include "symbol/symbol.h"
24 
25 /**
26  *******************************************************************************
27  *
28  * @ingroup symbol_dev
29  *
30  * @brief Add a dof array to the symbol matrix if any.
31  *
32  * If the dof parameter is variadic, then a permuted version of the initial dof
33  * array is constructed to match the symbol matrix that is working the permuted
34  * matrix A.
35  *
36  *******************************************************************************
37  *
38  * @param[in] graph
39  * The original graph of the matrix
40  *
41  * @param[in] order
42  * The ordering structure describing the permutation of the unknowns in
43  * the compressed form.
44  *
45  * @param[inout] symbptr
46  * The symbol structure to which dof array must be added.
47  *
48  *******************************************************************************/
49 static inline void
50 symbol_init_adddofs( const pastix_graph_t *graph,
51  const pastix_order_t *order,
52  symbol_matrix_t *symbptr )
53 {
54  symbptr->dof = graph->dof;
55  symbptr->dofs = NULL;
56 
57  if ( symbptr->dof < 1 ) {
58  pastix_int_t symbbase = symbptr->baseval;
59  pastix_int_t ordebase = order->baseval;
60  pastix_int_t i, ip, n, d, *dofs;
61 
62  n = graph->gN;
63 
64  MALLOC_INTERN( symbptr->dofs, n+1, pastix_int_t );
65 
66  dofs = symbptr->dofs;
67  dofs[0] = symbbase;
68 
69  for(ip=0; ip<n; ip++, dofs++) {
70  i = order->peritab[ip] - ordebase;
71 
72  assert( i < n );
73  d = graph->dofs[i+1] - graph->dofs[i];
74 
75  dofs[1] = dofs[0] + d;
76  }
77  assert( (symbptr->dofs[n] - symbbase) == (graph->dofs[n] - graph->dofs[0]) );
78  }
79 
80  return;
81 }
82 
83 /**
84  *******************************************************************************
85  *
86  * @brief Initialize the symbol structure.
87  *
88  * Initialized the permuted dof array if graph and order are provided. The
89  * symbol is considered as dof = 1 otherwise.
90  *
91  *******************************************************************************
92  *
93  * @param[in] graph
94  * The original graph of the matrix
95  *
96  * @param[in] order
97  * The ordering structure describing the permutation of the unknowns in
98  * the compressed form.
99  *
100  * @param[inout] symbptr
101  * The symbol structure to initialize.
102  *
103  *******************************************************************************/
104 void
105 pastixSymbolInit ( const pastix_graph_t *graph,
106  const pastix_order_t *order,
107  symbol_matrix_t *symbptr )
108 {
109  memset (symbptr, 0, sizeof (symbol_matrix_t));
110  symbptr->dof = 1;
111  symbptr->schurfcol = -1;
112 
113  if ( (graph != NULL) && (order != NULL) ) {
114  symbol_init_adddofs( graph, order, symbptr );
115  }
116 
117  return;
118 }
119 
120 /**
121  *******************************************************************************
122  *
123  * @brief Free the content of symbolic matrix.
124  *
125  * All the arrays from the structure are freed and the structure is memset to 0
126  * at exit, but the symbol itself is not freed. It will require a new call to
127  * pastixSymbolInit() if the memory space area needs to be reused for a new
128  * symbol matrix.
129  *
130  *******************************************************************************
131  *
132  * @param[inout] symbptr
133  * The pointer to the structure to free.
134  *
135  *******************************************************************************/
136 void
138 {
139  if (symbptr->dofs != NULL) {
140  memFree_null( symbptr->dofs );
141  }
142  if (symbptr->cblktab != NULL) {
143  memFree_null( symbptr->cblktab );
144  }
145  if (symbptr->bloktab != NULL) {
146  memFree_null( symbptr->bloktab );
147  }
148  if (symbptr->browtab != NULL) {
149  memFree_null( symbptr->browtab );
150  }
151  pastixSymbolInit( NULL, NULL, symbptr );
152 }
153 
154 /**
155  *******************************************************************************
156  *
157  * @brief Reallocate the data structure to optimize the memory alignment.
158  *
159  * This function is used when the symbol need to be shrinked to a smaller or
160  * larger set of blocks and column blocks. The original data is copied in the
161  * new arrays.
162  *
163  *******************************************************************************
164  *
165  * @param[inout] symbptr
166  * The pointer to the structure that needs to be reallocated.
167  *
168  *******************************************************************************/
169 void
171 {
172  symbol_cblk_t *cblktab = NULL;
173  symbol_blok_t *bloktab = NULL;
174 
175  /* Move column block array */
176  MALLOC_INTERN( cblktab, symbptr->cblknbr+1, symbol_cblk_t );
177  memcpy(cblktab, symbptr->cblktab, (symbptr->cblknbr + 1) * sizeof (symbol_cblk_t));
178  memFree(symbptr->cblktab);
179  symbptr->cblktab = cblktab;
180 
181  /* Move block array */
182  MALLOC_INTERN( bloktab, symbptr->bloknbr, symbol_blok_t );
183  memcpy(bloktab, symbptr->bloktab, (symbptr->bloknbr) * sizeof (symbol_blok_t));
184  memFree(symbptr->bloktab);
185  symbptr->bloktab = bloktab;
186 }
187 
188 /**
189  *******************************************************************************
190  *
191  * @brief Search the targeted block C for a couple of blocks A and B.
192  *
193  * When executing the simulation run to map the data on the cores, it requires
194  * to compute dependencies of each block. In that case for each couple of blocks
195  * A (defined by bloknum), and B (defined by bloksrc), we need to find the block
196  * that will receive the contribution for the matrix-matrix product. To speedup
197  * the search, the startsearch parameter can be given to specify that the index
198  * of the block searched is larger than this parameter. It returns the index of
199  * the C block when found, or -1 if no block is facing the update. This happens,
200  * only if ILU(k) factorization is applied and ricar is set to true. Otherwise,
201  * returning -1 is an error.
202  *
203  *******************************************************************************
204  *
205  * @param[in] symbptr
206  * The pointer to the structure that needs to be reallocated.
207  *
208  * @param[in] bloksrc
209  * Index of the block used as A in teh matrix-matrix product.
210  *
211  * @param[in] bloknum
212  * Index of the block used as B in teh matrix-matrix product.
213  *
214  * @param[in] startsearch
215  * Index of a block belonging to the facing cblk of B used as a
216  * starting point to find the index of C.
217  *
218  * @param[in] ricar
219  * Booleen to enable ILU(k) factorization or not
220  *
221  *******************************************************************************
222  *
223  * @retval -1 No block where found. This is an error if ricar is disabled,
224  * otherwise it means that the path is longer than the k parameter in
225  * the ILU(k) factorization.
226  *
227  * @retval i The index of the block C that will receive the contribution from
228  * A * B^t
229  *
230  *******************************************************************************/
233  pastix_int_t bloksrc,
234  pastix_int_t bloknum,
235  pastix_int_t startsearch,
236  int ricar )
237 {
238  symbol_blok_t *bsrc;
239  symbol_blok_t *bdst;
240  pastix_int_t i, fcblknum, fbloknum, lbloknum;
241 
242  fcblknum = symbptr->bloktab[bloksrc].fcblknm;
243  fbloknum = symbptr->cblktab[fcblknum].bloknum;
244  lbloknum = symbptr->cblktab[fcblknum+1].bloknum;
245 
246  if(startsearch < fbloknum )
247  startsearch = fbloknum;
248 
249  assert( startsearch < lbloknum );
250 
251  /* Block in original column block */
252  bsrc = (symbptr->bloktab) + bloknum;
253 
254  /* Search for the facing block in the facing column block */
255  bdst = (symbptr->bloktab) + startsearch;
256 
257  if(ricar == 0)
258  {
259  for(i=startsearch; i<lbloknum; i++, bdst++ )
260  if( bdst->lrownum >= bsrc->frownum)
261  break;
262 
263  /* We should always exit the loop in non ilu(k) mode */
264  assert( (bdst->frownum <= bsrc->frownum) &&
265  (bdst->lrownum >= bsrc->lrownum) );
266 
267  return i;
268  }
269  else
270  {
271  for(i=startsearch; i<lbloknum; i++, bdst++)
272  {
273  if( ((bsrc->frownum >= bdst->frownum) && (bsrc->frownum <= bdst->lrownum)) ||
274  ((bsrc->lrownum >= bdst->frownum) && (bsrc->lrownum <= bdst->lrownum)) ||
275  ((bsrc->frownum <= bdst->frownum) && (bsrc->lrownum >= bdst->lrownum)) )
276  return i; /** We found the first block that matches **/
277 
278  if(bsrc->lrownum < bdst->frownum)
279  {
280  return -1;
281  }
282  }
283  }
284  return -1;
285 }
286 
287 /**
288  *******************************************************************************
289  *
290  * @brief Construct the browtab array that stores the blocks in a CSR way.
291  *
292  * The browtab is an equivalent of the columns array in a CSR for the symbolic
293  * structure in terms of block indexes.
294  *
295  *******************************************************************************
296  *
297  * @param[inout] symbptr
298  * The pointer to the symbolic structure to update.
299  *
300  *******************************************************************************/
301 void
303 {
304  symbol_cblk_t *cblk;
305  symbol_blok_t *blok;
306  pastix_int_t *innbr, *intmp, *browtab;
307  pastix_int_t itercblk;
308  pastix_int_t cblknbr;
309  pastix_int_t edgenbr = symbptr->bloknbr - symbptr->cblknbr;
310 
311  symbptr->browmax = 0;
312  cblknbr = symbptr->cblknbr;
313 
314  MALLOC_INTERN(innbr, cblknbr, pastix_int_t );
315  memset( innbr, 0, cblknbr * sizeof(pastix_int_t) );
316 
317  /* Count the number of input edge per cblk */
318  cblk = symbptr->cblktab;
319  blok = symbptr->bloktab;
320  for(itercblk=0; itercblk<cblknbr; itercblk++, cblk++)
321  {
322  pastix_int_t iterblok = cblk[0].bloknum + 1;
323  pastix_int_t lbloknum = cblk[1].bloknum;
324 
325  /* Skip diagonal block */
326  blok++;
327 
328  /* Off-diagonal blocks */
329  for( ; iterblok < lbloknum; iterblok++, blok++)
330  {
331  innbr[ blok->fcblknm ]++;
332  }
333  }
334 
335  /* Initialize the brownum fields */
336  cblk = symbptr->cblktab;
337  cblk->brownum = 0;
338  for(itercblk=0; itercblk<cblknbr; itercblk++, cblk++)
339  {
340  symbptr->browmax = pastix_imax( symbptr->browmax, innbr[ itercblk ] );
341  cblk[1].brownum = cblk[0].brownum + innbr[ itercblk ];
342  innbr[itercblk] = cblk[0].brownum;
343  }
344  assert( cblk[0].brownum == edgenbr );
345 
346  /* Initialize the browtab */
347  MALLOC_INTERN( browtab, edgenbr, pastix_int_t );
348 
349  cblk = symbptr->cblktab;
350  blok = symbptr->bloktab;
351  for(itercblk=0; itercblk<cblknbr; itercblk++, cblk++)
352  {
353  pastix_int_t iterblok = cblk[0].bloknum + 1;
354  pastix_int_t lbloknum = cblk[1].bloknum;
355 
356  /* Skip diagonal block */
357  blok++;
358 
359  /* Off-diagonal blocks */
360  for( ; iterblok < lbloknum; iterblok++, blok++)
361  {
362  intmp = innbr + blok->fcblknm;
363  browtab[ *intmp ] = iterblok;
364  (*intmp)++;
365  }
366  }
367 
368  if (symbptr->browtab == NULL) {
369  memFree(symbptr->browtab);
370  }
371  symbptr->browtab = browtab;
372 
373  memFree( innbr );
374  return;
375 }
376 
377 /**
378  *******************************************************************************
379  *
380  * @brief Print statistical information about the symbolic matrix structure
381  *
382  *******************************************************************************
383  *
384  * @param[in] symbptr
385  * The pointer to the symbolic structure.
386  *
387  *******************************************************************************/
388 void
390 {
391  symbol_cblk_t *cblk;
392  symbol_blok_t *blok;
393  pastix_int_t itercblk, dof;
394  pastix_int_t cblknbr, bloknbr, cblksel;
395  pastix_int_t cblkmin, cblkmax;
396  pastix_int_t blokmin, blokmax;
397  double cblkavg1, blokavg1;
398  double cblkavg2, blokavg2;
399  size_t mem = 0;
400 
401  cblknbr = symbptr->cblknbr;
402  cblksel = 0;
403  bloknbr = symbptr->bloknbr - cblknbr;
404  cblkmin = PASTIX_INT_MAX;
405  cblkmax = 0;
406  cblkavg1 = 0;
407  cblkavg2 = 0;
408  blokmin = PASTIX_INT_MAX;
409  blokmax = 0;
410  blokavg1 = 0;
411  blokavg2 = 0;
412 
413  cblk = symbptr->cblktab;
414  blok = symbptr->bloktab;
415 
416  for(itercblk=0; itercblk<cblknbr; itercblk++, cblk++)
417  {
418  pastix_int_t iterblok = cblk[0].bloknum + 1;
419  pastix_int_t lbloknum = cblk[1].bloknum;
420 
421  pastix_int_t colnbr = cblk->lcolnum - cblk->fcolnum + 1;
422 
423  cblksel += cblk->selevtx;
424  cblkmin = pastix_imin( cblkmin, colnbr );
425  cblkmax = pastix_imax( cblkmax, colnbr );
426  cblkavg1 += colnbr;
427  cblkavg2 += colnbr * colnbr;
428  blok++;
429 
430  /* Only extra diagonal */
431  for( ; iterblok < lbloknum; iterblok++, blok++)
432  {
433  pastix_int_t rownbr = blok->lrownum - blok->frownum + 1;
434 
435  blokmin = pastix_imin( blokmin, rownbr );
436  blokmax = pastix_imax( blokmax, rownbr );
437  blokavg1 += rownbr;
438  blokavg2 += rownbr * rownbr;
439  }
440  }
441 
442  dof = symbptr->dof;
443  cblkmin *= dof;
444  cblkmax *= dof;
445  cblkavg1 = (cblkavg1 * (double)dof ) / (double)cblknbr;
446  cblkavg2 = sqrt( ((cblkavg2 * (double)dof * (double)dof) / (double)cblknbr) - cblkavg1 * cblkavg1 );
447 
448  /* Check if we have at least one off-diagonal block */
449  if ( bloknbr > 0 ) {
450  blokmin *= dof;
451  blokmax *= dof;
452  blokavg1 = (blokavg1 * (double)dof ) / (double)bloknbr;
453  blokavg2 = sqrt( ((blokavg2 * (double)dof * (double)dof) / (double)bloknbr) - blokavg1 * blokavg1 );
454  }
455  else {
456  blokmin = 0;
457  blokmax = 0;
458  blokavg1 = 0.;
459  blokavg2 = 0.;
460  }
461 
462  /* Compute symbol matrix space */
463  mem = sizeof( symbol_matrix_t );
464  mem += sizeof( symbol_cblk_t ) * (cblknbr + 1);
465  mem += sizeof( symbol_blok_t ) * symbptr->bloknbr;
466  mem += sizeof( pastix_int_t ) * bloknbr;
467 
468  fprintf(stdout,
469  " Symbol Matrix statistics:\n"
470  " Number of cblk %10ld\n"
471  " Number of blok %10ld\n"
472  " Cblk width min %10ld\n"
473  " Cblk width max %10ld\n"
474  " Cblk width avg %11.2lf\n"
475  " Cblk width stdev %11.2lf\n"
476  " Blok height min %10ld\n"
477  " Blok height max %10ld\n"
478  " Blok height avg %11.2lf\n"
479  " Blok height stdev %11.2lf\n"
480  " Memory space %11.2lf %co\n",
481  (long)cblknbr, (long)bloknbr,
482  (long)cblkmin, (long)cblkmax, cblkavg1, cblkavg2,
483  (long)blokmin, (long)blokmax, blokavg1, blokavg2,
484  pastix_print_value( mem ),
485  pastix_print_unit( mem ) );
486 
487  if ( cblksel > 0 ) {
488  fprintf( stdout,
489  " Number of selected cblk %10ld\n",
490  (long)cblksel );
491  }
492 }
BEGIN_C_DECLS typedef int pastix_int_t
Definition: datatypes.h:51
pastix_int_t baseval
Definition: order.h:48
pastix_int_t * peritab
Definition: order.h:52
Order structure.
Definition: order.h:47
pastix_int_t fcblknm
Definition: symbol.h:63
pastix_int_t frownum
Definition: symbol.h:60
pastix_int_t lrownum
Definition: symbol.h:61
pastix_int_t bloknbr
Definition: symbol.h:80
pastix_int_t * browtab
Definition: symbol.h:85
pastix_int_t baseval
Definition: symbol.h:78
symbol_cblk_t * cblktab
Definition: symbol.h:83
pastix_int_t schurfcol
Definition: symbol.h:82
pastix_int_t browmax
Definition: symbol.h:86
pastix_int_t bloknum
Definition: symbol.h:48
pastix_int_t brownum
Definition: symbol.h:49
pastix_int_t fcolnum
Definition: symbol.h:46
pastix_int_t lcolnum
Definition: symbol.h:47
pastix_int_t dof
Definition: symbol.h:87
symbol_blok_t * bloktab
Definition: symbol.h:84
pastix_int_t * dofs
Definition: symbol.h:89
pastix_int_t cblknbr
Definition: symbol.h:79
void pastixSymbolRealloc(symbol_matrix_t *symbptr)
Reallocate the data structure to optimize the memory alignment.
Definition: symbol.c:170
void pastixSymbolInit(const pastix_graph_t *graph, const pastix_order_t *order, symbol_matrix_t *symbptr)
Initialize the symbol structure.
Definition: symbol.c:105
void pastixSymbolPrintStats(const symbol_matrix_t *symbptr)
Print statistical information about the symbolic matrix structure.
Definition: symbol.c:389
struct symbol_matrix_s symbol_matrix_t
Symbol matrix structure.
void pastixSymbolBuildRowtab(symbol_matrix_t *symbptr)
Construct the browtab array that stores the blocks in a CSR way.
Definition: symbol.c:302
pastix_int_t pastixSymbolGetFacingBloknum(const symbol_matrix_t *symbptr, pastix_int_t bloksrc, pastix_int_t bloknum, pastix_int_t startsearch, int ricar)
Search the targeted block C for a couple of blocks A and B.
Definition: symbol.c:232
struct symbol_blok_s symbol_blok_t
Symbol block structure.
struct symbol_cblk_s symbol_cblk_t
Symbol column block structure.
void pastixSymbolExit(symbol_matrix_t *symbptr)
Free the content of symbolic matrix.
Definition: symbol.c:137
Symbol block structure.
Definition: symbol.h:59
Symbol column block structure.
Definition: symbol.h:45
Symbol matrix structure.
Definition: symbol.h:77
static void symbol_init_adddofs(const pastix_graph_t *graph, const pastix_order_t *order, symbol_matrix_t *symbptr)
Add a dof array to the symbol matrix if any.
Definition: symbol.c:50