PaStiX Handbook  6.3.2
graph_isolate.c
Go to the documentation of this file.
1 /**
2  *
3  * @file graph_isolate.c
4  *
5  * PaStiX graph isolate routine
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 Xavier Lacoste
12  * @author Pierre Ramet
13  * @author Mathieu Faverge
14  * @author Tony Delarue
15  * @date 2023-07-21
16  *
17  **/
18 #include "common.h"
19 #include "pastix/order.h"
20 #include "blend/extendVector.h"
21 #include "graph/graph.h"
22 
23 /**
24  *******************************************************************************
25  *
26  * @brief Assign the new pointer to the temporary one
27  *
28  *******************************************************************************
29  *
30  * @param[in] newptr
31  * TODO
32  *
33  * @param[in] tmpptr
34  * TODO
35  *
36  *******************************************************************************/
37 static inline void
39  pastix_int_t *tmpptr )
40 {
41  if ( newptr != NULL ) {
42  *newptr = tmpptr;
43  } else {
44  memFree_null( tmpptr );
45  }
46 }
47 
48 /**
49  *******************************************************************************
50  * @brief If isolate_n == n, everything needs to be isolated.
51  * That means that we just need an id permuation.
52  *
53  *******************************************************************************
54  *
55  * @param[in] n
56  * TODO
57  *
58  * @param[in] newperm
59  * TODO
60  *
61  * @param[in] newinvp
62  * TODO
63  *
64  *******************************************************************************/
65 static inline void
67  pastix_int_t **newperm,
68  pastix_int_t **newinvp )
69 {
70  pastix_int_t i;
71 
72  if( newperm != NULL ) {
73  pastix_int_t *perm;
74 
75  MALLOC_INTERN( *newperm, n, pastix_int_t );
76 
77  perm = *newperm;
78  for (i = 0; i < n; i++, perm++) {
79  *perm = i;
80  }
81  }
82  if( newinvp != NULL ) {
83  pastix_int_t *invp;
84 
85  MALLOC_INTERN( *newinvp, n, pastix_int_t );
86 
87  invp = *newinvp;
88  for (i = 0; i < n; i++, invp++) {
89  *invp = i;
90  }
91  }
92 }
93 
94 /**
95  *******************************************************************************
96  *
97  * @brief Init and fill the inverse permutation array.
98  *
99  *******************************************************************************
100  *
101  * @param[in] n
102  * TODO
103  *
104  * @param[in] isolate_n
105  * TODO
106  *
107  * @param[in] isolate_list
108  * TODO
109  *
110  * @param[in] permtab
111  * TODO
112  *
113  * @param[in] invptab
114  * TODO
115  *
116  * @param[in] baseval
117  * TODO
118  *
119  *******************************************************************************/
120 static inline void
122  pastix_int_t isolate_n,
123  const pastix_int_t *isolate_list,
124  pastix_int_t *permtab,
125  pastix_int_t *invptab,
126  pastix_int_t baseval )
127 {
128  pastix_int_t *invp_isolate, *invp_nonisol;
129  pastix_int_t i;
130 
131  /* First, fill inverse permutations array */
132  invp_nonisol = invptab;
133  invp_isolate = invptab + (n - isolate_n);
134  for (i=0; i<n; i++)
135  {
136  if ( ((invp_isolate - invptab) < n) &&
137  (i == (*isolate_list - baseval)) )
138  {
139  *invp_isolate = i;
140  invp_isolate++;
141  isolate_list++;
142  }
143  else {
144  *invp_nonisol = i;
145  invp_nonisol++;
146  }
147  }
148  assert( (invp_nonisol - invptab) == (n - isolate_n) );
149  assert( (invp_isolate - invptab) == n );
150 
151  /* Second, fill permutation array */
152  invp_nonisol = invptab;
153  for( i = 0; i < n; i++, invp_nonisol++ )
154  {
155  permtab[ *invp_nonisol ] = i;
156  }
157 
158 #if defined(PASTIX_DEBUG_GRAPH)
159  for(i = 0; i < n; i++)
160  {
161  assert(permtab[i] < n );
162  assert(permtab[i] > -1);
163  }
164 #endif
165 }
166 
167 /**
168  *******************************************************************************
169  *
170  * @brief Compress the local copy of the graph with only the kept unknowns.
171  *
172  *******************************************************************************
173  *
174  * @param[in] oldgraph
175  * TODO
176  *
177  * @param[in] newgraph
178  * TODO
179  *
180  * @param[in] new_gn
181  * TODO
182  *
183  * @param[in] permtab
184  * TODO
185  *
186  *******************************************************************************/
187 static inline void
188 graph_isolate_compress( const pastix_graph_t *oldgraph,
189  pastix_graph_t *newgraph,
190  pastix_int_t new_gn,
191  const pastix_int_t *permtab )
192 {
193  pastix_int_t *newcol = newgraph->colptr;
194  pastix_int_t *oldcol = oldgraph->colptr;
195  pastix_int_t *newrow = newgraph->rowptr;
196  pastix_int_t *oldrow = oldgraph->rowptr;
197  pastix_int_t *newdof = newgraph->dofs;
198  pastix_int_t *olddof = oldgraph->dofs;
199  pastix_int_t *newl2g = newgraph->loc2glob;
200  pastix_int_t *oldl2g = oldgraph->loc2glob;
201  pastix_int_t baseval = oldgraph->baseval;
202 
203  pastix_int_t i, j, k, ip, jp;
204  pastix_int_t nbrows;
205  pastix_int_t n = oldgraph->n;
206 
207  /* Make sure the glob2loc is destroyed */
208  if ( newgraph->glob2loc ) {
209  free( newgraph->glob2loc );
210  newgraph->glob2loc = NULL;
211  }
212 
213  /* Initial values */
214  *newcol = baseval;
215  if ( oldgraph->dofs ) {
216  *newdof = baseval;
217  }
218 
219  for ( i=0; i<n; i++, oldcol++, olddof++, oldl2g++ )
220  {
221  /* Get the new global index after permutation */
222  k = oldgraph->loc2glob ? *oldl2g : i;
223  ip = permtab[k];
224 
225  /* The vertex is isolated, we remove the full column */
226  if( ip >= new_gn ) {
227  oldrow += (oldcol[1] - oldcol[0]);
228  continue;
229  }
230 
231  nbrows = 0;
232  for( k=oldcol[0]; k<oldcol[1]; k++, oldrow++ )
233  {
234  j = *oldrow - baseval;
235  jp = permtab[j];
236 
237  /* Copy only edges that are kept */
238  if( jp < new_gn ) {
239  *newrow = jp + baseval;
240  newrow++;
241  nbrows++;
242  }
243  }
244 
245  /* Update the new colptr */
246  newcol[1] = newcol[0] + nbrows;
247  newcol++;
248 
249  /* Update the new loc2glob if any */
250  if ( oldgraph->loc2glob ) {
251  *newl2g = ip;
252  newl2g++;
253  }
254 
255  /* Update the new dofs if any */
256  if ( oldgraph->dofs ) {
257  newdof[1] = newdof[0] + (olddof[1] - olddof[0]);
258  newdof++;
259  }
260  }
261 
262  /* Update sizes */
263  {
264  pastix_int_t new_n, new_nnz;
265  new_n = newcol - newgraph->colptr;
266  new_nnz = *newcol - baseval;
267 
268  assert( new_n <= new_gn );
269  assert( new_nnz <= oldgraph->nnz );
270 
271  newgraph->n = new_n;
272  newgraph->nnz = new_nnz;
273 
274  graphUpdateComputedFields( newgraph );
275  }
276 
277  /* Realloc what needs to be */
278  newgraph->colptr = realloc( newgraph->colptr, (newgraph->n+1) * sizeof(pastix_int_t) );
279  newgraph->rowptr = realloc( newgraph->rowptr, newgraph->nnz * sizeof(pastix_int_t) );
280  if ( newgraph->loc2glob ) {
281  newgraph->loc2glob = realloc( newgraph->loc2glob, newgraph->n * sizeof(pastix_int_t) );
282  }
283  if ( newgraph->dofs ) {
284  newgraph->dofs = realloc( newgraph->dofs, (newgraph->gN+1) * sizeof(pastix_int_t) );
285  }
286 }
287 
288 /**
289  *******************************************************************************
290  *
291  * @ingroup pastix_graph
292  *
293  * @brief Isolate a subset of vertices from a given graph.
294  *
295  * Return a new graph cleaned from those vertices.
296  *
297  *******************************************************************************
298  *
299  * @param[in] ingraph
300  * TODO
301  *
302  * @param[in] outgraph
303  * TODO
304  *
305  * @param[in] isolate_n
306  * The number of columns to isolate from the original graph.
307  *
308  * @param[inout] isolate_list
309  * Array of size isolate_n.
310  * List of columns to isolate. On exit, the list is sorted by ascending
311  * indexes. Must be based as the graph.
312  *
313  * @param[out] new_perm
314  * Array of size n-isolate_n.
315  * Contains permutation generated to isolate the columns at the end of
316  * the graph that is 0-based.
317  * If new_perm == NULL, nothing is returned, otherwise the pointer to
318  * the allocated structure.
319  *
320  * @param[out] new_invp
321  * Array of size n-isolate_n.
322  * Contains the inverse permutation generated to isolate the columns
323  * at the end of the graph that is 0-based.
324  * If new_invp == NULL, nothing is returned, otherwise the pointer to
325  * the allocated structure.
326  *
327  *******************************************************************************
328  *
329  * @retval PASTIX_SUCCESS on success,
330  * @retval PASTIX_ERR_ALLOC if allocation went wrong,
331  * @retval PASTIX_ERR_BADPARAMETER if incorrect parameters are given.
332  *
333  *******************************************************************************/
334 int graphIsolate( const pastix_graph_t *ingraph,
335  pastix_graph_t *outgraph,
336  pastix_int_t isolate_n,
337  pastix_int_t *isolate_list,
338  pastix_int_t **new_perm,
339  pastix_int_t **new_invp )
340 {
341  pastix_int_t *tmpperm = NULL;
342  pastix_int_t *tmpinvp = NULL;
343  pastix_int_t baseval = ingraph->baseval;
344  pastix_int_t gN = ingraph->gN;
345  pastix_int_t new_n = gN - isolate_n;
346 
347  if ( (isolate_n > gN) || (isolate_n < 0) ) {
348  pastix_print_warning( "Number of columns to isolate greater than the columns in the graph matrix\n" );
350  }
351 
352  /* For the moment, make sure the graph is 0 based */
353  assert( baseval == 0 );
354 
355  /* We isolate the whole graph, so the new graph is empty */
356  if ( isolate_n == gN )
357  {
358  graphInitEmpty( outgraph, ingraph->comm );
359  graph_isolate_everything( gN, new_perm, new_invp );
360  return PASTIX_SUCCESS;
361  }
362 
363  graphCopy( outgraph, ingraph );
364 
365  /* Quick Return */
366  if ( isolate_n == 0 ) {
367  pastix_print_warning( "graphIsolate: the graph is beeing duplicated to isolate no unknowns, are you sure you wanted to do that ?\n" );
368  return PASTIX_SUCCESS;
369  }
370 
371  /* Sort the list of vertices */
372  intSort1asc1( isolate_list, isolate_n );
373 
374  /* Init invp and perm array */
375  MALLOC_INTERN( tmpinvp, gN, pastix_int_t );
376  MALLOC_INTERN( tmpperm, gN, pastix_int_t );
377  graph_isolate_permutations( gN, isolate_n, isolate_list,
378  tmpperm, tmpinvp, baseval );
379 
380  /* Create the new graph */
381  graph_isolate_compress( ingraph, outgraph, new_n, tmpperm );
382 
383  /* Backup the permutation is asked by the caller */
384  graph_isolate_assign_ptr( new_perm, tmpperm );
385  graph_isolate_assign_ptr( new_invp, tmpinvp );
386 
387  return PASTIX_SUCCESS;
388 }
389 
390 /**
391  *******************************************************************************
392  *
393  * @brief Fill the isolated colptr and rowptr.
394  *
395  *******************************************************************************
396  *
397  * @param[in] graph
398  * The original graph associated from which vertices and edges must be
399  * extracted.
400  *
401  * @param[in] order
402  * The ordering structure associated to the graph.
403  *
404  * @param[in] vec
405  * TODO
406  *
407  * @param[inout] out_colptr
408  * TODO
409  *
410  * @param[inout] out_rowptr
411  * TODO
412  *
413  * @param[in] fnode
414  * The index of the first node to extract in the inverse permutation.
415  *
416  * @param[in] lnode
417  * The index (+1) of the last node to extract in the inverse permutation.
418  *
419  * @param[in] distance
420  * Distance considered in number of edges to create an edge in isolated
421  * graph.
422  *
423  *******************************************************************************/
424 static inline void
425 graph_iRange_fill_outptr( const pastix_graph_t *graph,
426  const pastix_order_t *order,
427  ExtendVectorINT *vec,
428  pastix_int_t *out_colptr,
429  pastix_int_t *out_rowptr,
430  pastix_int_t fnode,
431  pastix_int_t lnode,
432  pastix_int_t distance )
433 {
434  pastix_int_t *out_connected;
435  pastix_int_t *colptr ,*rowptr, *rowtmp;
436  pastix_int_t *perm = order->permtab;
437  pastix_int_t *invp = order->peritab;
438  pastix_int_t out_n = lnode - fnode;
439  pastix_int_t ip, jp, k, jj, i, j;
440  pastix_int_t d, sze, baseval;
441 
442  MALLOC_INTERN( out_connected, out_n, pastix_int_t );
443 
444  /* The first loop counts the number of edges */
445  baseval = graph->baseval;
446  colptr = graph->colptr;
447  rowptr = graph->rowptr - baseval;
448  rowtmp = out_rowptr;
449  for( ip=fnode; ip<lnode; ip++ )
450  {
451  /* Clear the previous computations */
452  extendint_Clear( vec );
453  memset(out_connected, 0, out_n * sizeof(pastix_int_t));
454  out_connected[ip-fnode] = 1;
455 
456  /* i^th vertex in the initial numbering */
457  extendint_Add( vec, invp[ip] );
458  sze = 1;
459  d = -1;
460  k = 0;
461 
462  while( d < distance ) {
463  for(; k<sze; k++) {
464  i = extendint_Read( vec, k );
465 
466  for (jj = colptr[i]; jj < colptr[i+1]; jj++)
467  {
468  j = rowptr[jj] - baseval;
469  jp = perm[j];
470 
471  /* Count edges in each column of the new graph */
472  if ( ( jp >= fnode ) && ( jp < lnode ) ) {
473  if (out_connected[jp-fnode] == 0){
474  out_connected[jp-fnode] = 1;
475 
476  /* Fill the out_colptr */
477  out_colptr[ip-fnode+1]++;
478 
479  /* Fill the out_rowptr */
480  *rowtmp = jp-fnode;
481  rowtmp++;
482  }
483  }
484  else {
485  extendint_Add( vec, j );
486  }
487  }
488  }
489  d++;
490  sze = extendint_Size( vec );
491  }
492  }
493  free(out_connected);
494 }
495 
496 /**
497  *******************************************************************************
498  *
499  * @ingroup pastix_graph
500  *
501  * @brief Isolate the subgraph associated to a range of unknowns in the permuted
502  * graph.
503  *
504  * This routine isolates a continuous subset of vertices from a given graph, and
505  * returns a new graph made of those vertices and internal connexions. Extra
506  * edges are created between vertices if they are connected through a halo at a
507  * distance d given in parameter.
508  *
509  *******************************************************************************
510  *
511  * @param[in] graph
512  * The original graph associated from which vertices and edges must be
513  * extracted.
514  *
515  * @param[in] order
516  * The ordering structure associated to the graph.
517  *
518  * @param[inout] out_graph
519  * The extracted graph. If the graph is allocated, it is freed before usage.
520  * On exit, contains the subgraph of the vertices invp[fnode] to invp[lnode-1].
521  *
522  * @param[in] fnode
523  * The index of the first node to extract in the inverse permutation.
524  *
525  * @param[in] lnode
526  * The index (+1) of the last node to extract in the inverse permutation.
527  *
528  * @param[in] distance
529  * Distance considered in number of edges to create an edge in isolated
530  * graph.
531  *
532  *******************************************************************************
533  *
534  * @retval PASTIX_SUCCESS on success.
535  * @retval PASTIX_ERR_ALLOC if allocation went wrong.
536  * @retval PASTIX_ERR_BADPARAMETER if incorrect parameters are given.
537  *
538  *******************************************************************************/
539 int
540 graphIsolateRange( const pastix_graph_t *graph,
541  const pastix_order_t *order,
542  pastix_graph_t *out_graph,
543  pastix_int_t fnode,
544  pastix_int_t lnode,
545  pastix_int_t distance )
546 {
547  ExtendVectorINT vec;
548  pastix_int_t *out_rowptr;
549  pastix_int_t *out_colptr;
550  pastix_int_t baseval = graph->baseval;
551  pastix_int_t n = graph->n;
552  pastix_int_t out_n = lnode - fnode;
553  pastix_int_t i;
554 
555  if ( out_graph == NULL ) {
556  pastix_print_warning( "graphIsolateSupernode: Incorrect pointer for the output graph\n" );
558  }
559 
560  n = graph->n;
561  out_graph->n = out_n;
562 
563  /* Copy dofs datas, as they are global */
564  out_graph->dof = graph->dof;
565  if( out_graph->dof < 0 ) {
566  MALLOC_INTERN( out_graph->dofs, graph->gN, pastix_int_t );
567  memcpy( out_graph->dofs, graph->dofs, graph->gN * sizeof(pastix_int_t) );
568  }
569 
570  if ( out_n == 0 ) {
571  pastix_print_warning( "graphIsolateSupernode: Empty supernode\n" );
573  }
574 
575  /* For the moment, make sure the graph is 0 based */
576  assert( baseval == 0 );
577 
578  /* Quick Return */
579  if ( out_n == n ) {
580  /* Only one supernode */
581  assert( order->cblknbr == 1 );
582  graphCopy( out_graph, graph );
583  return PASTIX_SUCCESS;
584  }
585 
586  /* Create the new_colptr array */
587  MALLOC_INTERN( out_graph->colptr, out_n + 1, pastix_int_t );
588  memset( out_graph->colptr, 0, (out_n + 1) * sizeof(pastix_int_t) );
589  out_colptr = out_graph->colptr;
590 
591  /* Create the new_rowptr array, will be reallocated later */
592  MALLOC_INTERN( out_graph->rowptr, graph->nnz, pastix_int_t );
593  out_rowptr = out_graph->rowptr;
594 
595  /*
596  * (i,j) in permutated ordering
597  * (ip,jp) in initial ordering
598  */
599  out_graph->baseval = baseval;
600  out_colptr[0] = baseval;
601 
602  extendint_Init( &vec, 100 );
603 
604  /* Fill the out_colptr and the out_rowptr */
605  graph_iRange_fill_outptr( graph, order, &vec,
606  out_colptr, out_rowptr,
607  fnode, lnode, distance );
608 
609  /* Update the colptr */
610  for (i = 0; i < out_n; i++){
611  out_colptr[i+1] += out_colptr[i];
612  }
613 
614  out_graph->nnz = out_colptr[out_n] - out_colptr[0];
615 
616  /* Allocation will fail if matrix is diagonal and no off-diagonal elements are found */
617  if ( out_graph->nnz == 0 ){
618  fprintf( stderr, "Diagonal matrix cannot be correcly managed here!\n" );
619  return EXIT_FAILURE;
620  }
621 
622  /* Create the new rowptr array */
623  out_graph->rowptr =
624  (pastix_int_t *) memRealloc( out_graph->rowptr, out_graph->nnz * sizeof(pastix_int_t) );
625 
626  extendint_Exit( &vec );
627  graphBase( out_graph, 0 );
628 
629  /* Update mainly gN and gnnz */
630  graphUpdateComputedFields( out_graph );
631 
632  return PASTIX_SUCCESS;
633 }
BEGIN_C_DECLS typedef int pastix_int_t
Definition: datatypes.h:51
static void graph_isolate_compress(const pastix_graph_t *oldgraph, pastix_graph_t *newgraph, pastix_int_t new_gn, const pastix_int_t *permtab)
Compress the local copy of the graph with only the kept unknowns.
static void graph_isolate_permutations(pastix_int_t n, pastix_int_t isolate_n, const pastix_int_t *isolate_list, pastix_int_t *permtab, pastix_int_t *invptab, pastix_int_t baseval)
Init and fill the inverse permutation array.
static void graph_isolate_everything(pastix_int_t n, pastix_int_t **newperm, pastix_int_t **newinvp)
If isolate_n == n, everything needs to be isolated. That means that we just need an id permuation.
Definition: graph_isolate.c:66
static void graph_isolate_assign_ptr(pastix_int_t **newptr, pastix_int_t *tmpptr)
Assign the new pointer to the temporary one.
Definition: graph_isolate.c:38
static void graph_iRange_fill_outptr(const pastix_graph_t *graph, const pastix_order_t *order, ExtendVectorINT *vec, pastix_int_t *out_colptr, pastix_int_t *out_rowptr, pastix_int_t fnode, pastix_int_t lnode, pastix_int_t distance)
Fill the isolated colptr and rowptr.
pastix_int_t extendint_Size(const ExtendVectorINT *)
Return the number of element stored in the vector.
Definition: extendVector.c:112
void extendint_Clear(ExtendVectorINT *)
Cleanup the vector.
Definition: extendVector.c:220
pastix_int_t extendint_Read(const ExtendVectorINT *, pastix_int_t)
Return the element of index eltnum.
Definition: extendVector.c:136
pastix_int_t * extendint_Init(ExtendVectorINT *, pastix_int_t)
Initialize the extendVector structure with the initial size given.
Definition: extendVector.c:45
void extendint_Add(ExtendVectorINT *, pastix_int_t)
Add an element elt to the end of the vector.
Definition: extendVector.c:90
void extendint_Exit(ExtendVectorINT *)
Free the extendVector structure.
Definition: extendVector.c:66
The extend integer array structure.
Definition: extendVector.h:29
@ PASTIX_SUCCESS
Definition: api.h:367
@ PASTIX_ERR_BADPARAMETER
Definition: api.h:374
int graphUpdateComputedFields(pastix_graph_t *graph)
Update dofs, nnz, nnzexp, gnnz, n, nexp, gN of a given graph.
Definition: graph.c:338
int graphIsolate(const pastix_graph_t *ingraph, pastix_graph_t *outgraph, pastix_int_t isolate_n, pastix_int_t *isolate_list, pastix_int_t **new_perm, pastix_int_t **new_invp)
Isolate a subset of vertices from a given graph.
int graphCopy(pastix_graph_t *graphdst, const pastix_graph_t *graphsrc)
This routine copy a given ordering in a new one.
Definition: graph.c:151
int graphIsolateRange(const pastix_graph_t *graphIn, const pastix_order_t *order, pastix_graph_t *graphOut, pastix_int_t fnode, pastix_int_t lnode, pastix_int_t distance)
Isolate the subgraph associated to a range of unknowns in the permuted graph.
void graphInitEmpty(pastix_graph_t *graph, PASTIX_Comm comm)
Initialize an empty graph.
Definition: graph.c:48
void graphBase(pastix_graph_t *graph, pastix_int_t baseval)
Rebase the graph to the given value.
Definition: graph.c:102
pastix_int_t * permtab
Definition: order.h:51
pastix_int_t * peritab
Definition: order.h:52
pastix_int_t cblknbr
Definition: order.h:50
Order structure.
Definition: order.h:47