PaStiX Handbook  6.3.2
elimintree.c
Go to the documentation of this file.
1 /**
2  *
3  * @file elimintree.c
4  *
5  * PaStiX analyse routines
6  * PaStiX is a software package provided by Inria Bordeaux - Sud-Ouest,
7  * LaBRI, University of Bordeaux 1 and IPB.
8  *
9  * Contains basic functions to manipulate elimination tree structure.
10  *
11  * @copyright 2004-2023 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
12  * Univ. Bordeaux. All rights reserved.
13  *
14  * @version 6.3.2
15  * @author Pascal Henon
16  * @author Mathieu Faverge
17  * @date 2023-07-21
18  *
19  * @addtogroup blend_dev_elim
20  * @{
21  *
22  **/
23 #include "common.h"
24 #include "symbol/symbol.h"
25 #include "blend/elimintree.h"
26 
27 /**
28  *******************************************************************************
29  *
30  * @brief Initialize the elimination tree structure.
31  *
32  *******************************************************************************
33  *
34  * @param[in] nodenbr
35  * TODO
36  *
37  *******************************************************************************
38  *
39  * @retval TODO
40  *
41  *******************************************************************************/
42 EliminTree *
44 {
45  EliminTree *etree;
46  eTreeNode_t *enode;
47  pastix_int_t i;
48 
49  MALLOC_INTERN(etree, 1, EliminTree);
50 
51  etree->baseval = 0;
52  etree->nodenbr = nodenbr;
53 
54  MALLOC_INTERN( etree->nodetab, nodenbr + 1, eTreeNode_t);
55  MALLOC_INTERN( etree->sonstab, nodenbr, pastix_int_t);
56  memset( etree->sonstab, 0, nodenbr * sizeof(pastix_int_t) );
57 
58  /* Initialize the structure fields */
59  enode = etree->nodetab;
60  for(i=-1; i<nodenbr; i++, enode++)
61  {
62  enode->ndecost = 0.0;
63  enode->ndepath = 0.0;
64  enode->subcost = 0.0;
65  enode->subpath = 0.0;
66  enode->ndlevel = -1;
67  enode->sonsnbr = 0;
68  enode->fathnum = -1;
69  enode->fsonnum = -1;
70  }
71 
72  /* Shift the nodetab to get the root at -1 position */
73  etree->nodetab++;
74  return etree;
75 }
76 
77 /**
78  *******************************************************************************
79  *
80  * @brief Free the elimination tree structure.
81  *
82  *******************************************************************************
83  *
84  * @param[inout] etree
85  * The pointer to the elimination tree to free.
86  *
87  *******************************************************************************/
88 void
90 {
91  if (etree != NULL) {
92  if (etree->nodetab != NULL) {
93  etree->nodetab--;
94  memFree_null(etree->nodetab);
95  }
96  memFree_null(etree->sonstab);
97  memFree_null(etree);
98  }
99 }
100 
101 /**
102  *******************************************************************************
103  *
104  * @brief Set the fsonnum fields base on the initialized sonsnbr.
105  *
106  *******************************************************************************
107  *
108  * @param[inout] etree
109  * The pointer to the elimination tree for which the fsonnum fields
110  * must be initialized.
111  *
112  *******************************************************************************/
113 static inline void
115 {
116  eTreeNode_t *enode;
117  pastix_int_t i;
118 
119  /* Set the index of the first sons */
120  enode = etree->nodetab - 1;
121  enode->fsonnum = 0;
122  for(i=0; i<etree->nodenbr; i++, enode++)
123  {
124  enode[1].fsonnum = enode[0].fsonnum + enode[0].sonsnbr;
125  }
126  assert((enode[0].fsonnum + enode[0].sonsnbr) == etree->nodenbr);
127 }
128 
129 /**
130  *******************************************************************************
131  *
132  * @brief Set the fsonnum fields base on the initialized sonsnbr.
133  *
134  *******************************************************************************
135  *
136  * @param[inout] etree
137  * The pointer to the elimination tree for which the fsonnum fields
138  * must be initialized.
139  *
140  *******************************************************************************/
141 void
143 {
144  pastix_int_t i;
145 
146  /* Set the index of the first sons */
147  etree_SetSonsIndex( etree );
148 
149  /* Fill the sonstab */
150  for(i=0; i<etree->nodenbr; i++)
151  {
152  eTreeNode_t *efather = eTreeFather(etree, i);
153  pastix_int_t node = efather->fsonnum;
154  efather->fsonnum++;
155  assert( (node >= 0) && (node < etree->nodenbr) );
156  etree->sonstab[ node ] = i;
157  }
158 
159  /* Restore fsonnum fields */
160  etree_SetSonsIndex( etree );
161 }
162 
163 /**
164  *******************************************************************************
165  *
166  * @brief Compute the number of leaves.
167  *
168  *******************************************************************************
169  *
170  * @param[in] etree
171  * The pointer to the elimination tree.
172  *
173  *******************************************************************************
174  *
175  * @return The number of leaves in the elimination tree.
176  *
177  *******************************************************************************/
180 {
181  pastix_int_t i;
182  pastix_int_t leavenbr;
183  leavenbr = 0;
184  for(i=0;i<etree->nodenbr;i++) {
185  if(etree->nodetab[i].sonsnbr == 0) {
186  leavenbr++;
187  }
188  }
189 
190  return leavenbr;
191 }
192 
193 /**
194  *******************************************************************************
195  *
196  * @brief Compute the height of the elimination tree.
197  *
198  *******************************************************************************
199  *
200  * @param[in] etree
201  * The pointer to the elimination tree.
202  *
203  *******************************************************************************
204  *
205  * @return The height of the elimination tree.
206  *
207  *******************************************************************************/
209 eTreeLevel(const EliminTree *etree)
210 {
211  pastix_int_t maxlevel;
212  pastix_int_t nodelevel;
213  pastix_int_t i;
214  maxlevel = 0;
215  for(i=0;i<etree->nodenbr;i++)
216  {
217  nodelevel = eTreeNodeLevel(etree, i);
218  if(nodelevel > maxlevel) {
219  maxlevel = nodelevel;
220  }
221  }
222 
223  return maxlevel;
224 }
225 
226 /**
227  *******************************************************************************
228  *
229  * @brief Compute the number of level existing below a given node.
230  *
231  *******************************************************************************
232  *
233  * @param[inout] etree
234  * The pointer to the elimination tree. On exit, all traversed nodes
235  * will be updated with the depth related to the given root.
236  *
237  *
238  * @param[in] rootnum
239  * The root of the tree to study.
240  *
241  * @param[in] rootlvl
242  * The level of the root node.
243  *
244  *******************************************************************************
245  *
246  * @return The maximal depth of the tree.
247  *
248  *******************************************************************************/
251 {
252  pastix_int_t sonsnbr, i, son, max;
253  pastix_int_t maxlevel;
254 
255  etree->nodetab[ rootnum ].ndlevel = rootlvl;
256  sonsnbr = etree->nodetab[ rootnum ].sonsnbr;
257 
258  maxlevel = rootlvl;
259  rootlvl++;
260  for(i=0;i<sonsnbr;i++)
261  {
262  son = eTreeSonI( etree, rootnum, i );
263  max = eTreeComputeLevels( etree, son, rootlvl );
264  maxlevel = pastix_imax( max, maxlevel );
265  }
266  return maxlevel;
267 }
268 
269 /**
270  *******************************************************************************
271  *
272  * @brief Compute the number of level existing below a given node.
273  *
274  *******************************************************************************
275  *
276  * @param[in] etree
277  * The pointer to the elimination tree.
278  *
279  *
280  * @param[in] nodenum
281  * The index of the node to study.
282  *
283  *******************************************************************************
284  *
285  * @return The number of level below the node including it.
286  *
287  *******************************************************************************/
289 eTreeNodeLevel(const EliminTree *etree, pastix_int_t nodenum )
290 {
291  pastix_int_t level;
292 
293  level = 0;
294  /* If fake root no levels */
295  if(nodenum == eTreeRoot(etree)) {
296  return 0;
297  }
298  level++;
299  while(etree->nodetab[nodenum].fathnum != eTreeRoot(etree))
300  {
301  level++;
302  nodenum = etree->nodetab[nodenum].fathnum;
303  }
304  return level;
305 }
306 
307 /**
308  *******************************************************************************
309  *
310  * @brief Print the elimination tree in a dot file.
311  *
312  *******************************************************************************
313  *
314  * @param[in] etree
315  * The pointer to the elimination tree.
316  *
317  *
318  * @param[inout] stream
319  * The file to which write the elimination tree in the dot format.
320  *
321  *******************************************************************************/
322 void
323 eTreeGenDot( const EliminTree *etree,
324  FILE *stream )
325 {
326  pastix_int_t i;
327 
328  fprintf(stream,
329  "digraph G {\n"
330  "\tcolor=white\n"
331  "rankdir=BT;\n");
332 
333  for (i=0; i < etree->nodenbr; i++)
334  {
335  fprintf(stream, "\t\"%ld\" [label=\"#%ld\\nSubtree cost: %e\\nNode cost: %e\\nNode CP: %e\"]\n",
336  (long)i, (long)i,
337  etree->nodetab[i].subcost,
338  etree->nodetab[i].ndepath,
339  etree->nodetab[i].subpath );
340 
341  if ((etree->nodetab[i]).fathnum == -1) {
342  continue;
343  }
344  fprintf( stream, "\t\"%ld\"->\"%ld\"\n",
345  (long)i,
346  (long)((etree->nodetab[i]).fathnum) );
347  }
348 
349  fprintf(stream, "}\n");
350 }
351 
352 /**
353  *******************************************************************************
354  *
355  * @brief Print the elimination tree in a human readable format.
356  *
357  * Each node is writen as:
358  * Rootnum idx number_of_sons:
359  * (son_1)
360  * (son_2)
361  * ...
362  * (son_n)
363  *
364  *******************************************************************************
365  *
366  * @param[in] etree
367  * The pointer to the elimination tree.
368  *
369  *
370  * @param[inout] stream
371  * The file to which write the elimination tree in the dot format.
372  *
373  * @param[in] rootnum
374  * The root of the subtree to write into the file.
375  *
376  *******************************************************************************/
377 void
378 eTreePrint(const EliminTree *etree, FILE *stream, pastix_int_t rootnum )
379 {
380  int i, sonsnbr;
381  pastix_int_t son;
382 
383  sonsnbr = etree->nodetab[ rootnum ].sonsnbr;
384 
385  fprintf(stream, "Rootnum %ld %d\n", (long)rootnum, sonsnbr);
386  for(i=0;i<sonsnbr;i++) {
387  fprintf(stream," (%4ld)\n", (long)eTreeSonI(etree, rootnum, i));
388  }
389 
390  for(i=0;i<sonsnbr;i++)
391  {
392  son = eTreeSonI(etree, rootnum, i);
393  if (etree->nodetab[son].sonsnbr) {
394  eTreePrint(etree, stream, son);
395  }
396  }
397 }
398 
399 /**
400  *******************************************************************************
401  *
402  * @brief Return the smallest index of the nodes belonging to the level lvl in
403  * the elimination tree.
404  *
405  * Look recursively in the elimination tree to return the smallest index of all
406  * the nodes belonging to a same level defined by lvl.
407  *
408  *******************************************************************************
409  *
410  * @param[in] etree
411  * The pointer to the elimination tree.
412  *
413  * @param[in] root
414  * The root of the subtree to study.
415  *
416  * @param[in] lvl
417  * The number of levels below root to look for.
418  *
419  * @param[in] idxmin
420  * The minimum index already discovered.
421  *
422  *******************************************************************************
423  *
424  * @return The minimum index found in the descendants of the root node, lvl
425  * levels below.
426  *
427  *******************************************************************************/
430  pastix_int_t root,
431  pastix_int_t lvl,
432  pastix_int_t idxmin )
433 {
434  int i, sonsnbr;
435  pastix_int_t idx, son;
436 
437  idx = (root == -1) ? idxmin : pastix_imin( root, idxmin );
438 
439  if ( lvl == 0 ) {
440  return idx;
441  }
442 
443  sonsnbr = etree->nodetab[ root ].sonsnbr;
444  if ( sonsnbr == 0 ) {
445  return idx;
446  }
447 
448  lvl--;
449  for(i=0;i<sonsnbr;i++)
450  {
451  son = eTreeSonI(etree, root, i);
452  idx = eTreeGetLevelMinIdx( etree, son, lvl, idx );
453  }
454  return idx;
455 }
456 
457 /**
458  *******************************************************************************
459  *
460  * @brief Build the elimination tree.
461  *
462  * The elimination tree is computed based on a given symbolic structure, and
463  * not from the tree given by the ordering library. Each father of a node is
464  * defined as the facing column block of the first off diagonal block.
465  *
466  *******************************************************************************
467  *
468  * @param[in] symbmtx
469  * The pointer to the symbol matrix from which the elimination tree is
470  * computed.
471  *
472  *******************************************************************************
473  *
474  * @return The elimination tree linked to the symbol matrix.
475  *
476  *******************************************************************************/
477 EliminTree *
479 {
480  eTreeNode_t *enode, *eroot;
481  EliminTree *etree = NULL;
482  pastix_int_t i;
483  pastix_int_t totalsonsnbr;
484 
485  etree = eTreeInit( symbmtx->cblknbr );
486  eroot = &(etree->nodetab[eTreeRoot(etree)]);
487 
488  /* Compute the fathers and the number of sons */
489  totalsonsnbr = 0;
490  enode = etree->nodetab;
491  for(i=0; i<symbmtx->cblknbr; i++, enode++)
492  {
493  /* If the cblk has at least one extra diagonal block, */
494  /* the father of the node is the facing block of the first odb */
495  if( (symbmtx->cblktab[i+1].bloknum - symbmtx->cblktab[i].bloknum) > 1 )
496  {
497  pastix_int_t fathnum = symbmtx->bloktab[ symbmtx->cblktab[i].bloknum+1 ].fcblknm;
498  enode->fathnum = fathnum;
499  etree->nodetab[fathnum].sonsnbr++;
500  totalsonsnbr++;
501  }
502  /* Otherwise this is a root, and we attach it to -1 */
503  else {
504  etree->nodetab[i].fathnum = -1;
505  eroot->sonsnbr++;
506  totalsonsnbr++;
507  }
508  }
509 
510  /* Check that we have only one root */
511  assert(totalsonsnbr == symbmtx->cblknbr);
512 
513  /* Set the sons */
514  eTreeSetSons( etree );
515 
516  return etree;
517 }
518 
519 /**
520  *@}
521  */
BEGIN_C_DECLS typedef int pastix_int_t
Definition: datatypes.h:51
double subpath
Definition: elimintree.h:29
double subcost
Definition: elimintree.h:28
double ndepath
Definition: elimintree.h:27
double ndecost
Definition: elimintree.h:26
pastix_int_t fsonnum
Definition: elimintree.h:33
pastix_int_t * sonstab
Definition: elimintree.h:43
pastix_int_t nodenbr
Definition: elimintree.h:41
pastix_int_t baseval
Definition: elimintree.h:40
eTreeNode_t * nodetab
Definition: elimintree.h:42
pastix_int_t fathnum
Definition: elimintree.h:32
static eTreeNode_t * eTreeFather(const EliminTree *etree, pastix_int_t node)
Return the father of a given node.
Definition: elimintree.h:78
static pastix_int_t eTreeRoot(const EliminTree *etree)
Return the root of the elimination tree.
Definition: elimintree.h:126
static pastix_int_t eTreeSonI(const EliminTree *etree, pastix_int_t node, pastix_int_t i)
Return the i^{th} son of a given node.
Definition: elimintree.h:105
void eTreeSetSons(EliminTree *)
Set the fsonnum fields base on the initialized sonsnbr.
Definition: elimintree.c:142
void eTreeGenDot(const EliminTree *, FILE *)
Print the elimination tree in a dot file.
Definition: elimintree.c:323
EliminTree * eTreeInit(pastix_int_t)
Initialize the elimination tree structure.
Definition: elimintree.c:43
static void etree_SetSonsIndex(EliminTree *etree)
Set the fsonnum fields base on the initialized sonsnbr.
Definition: elimintree.c:114
pastix_int_t eTreeLeavesNbr(const EliminTree *)
Compute the number of leaves.
Definition: elimintree.c:179
EliminTree * eTreeBuild(const symbol_matrix_t *)
Build the elimination tree.
Definition: elimintree.c:478
pastix_int_t eTreeGetLevelMinIdx(const EliminTree *, pastix_int_t, pastix_int_t, pastix_int_t)
Return the smallest index of the nodes belonging to the level lvl in the elimination tree.
Definition: elimintree.c:429
void eTreePrint(const EliminTree *, FILE *, pastix_int_t)
Print the elimination tree in a human readable format.
Definition: elimintree.c:378
pastix_int_t eTreeComputeLevels(EliminTree *, pastix_int_t, pastix_int_t)
Compute the number of level existing below a given node.
Definition: elimintree.c:250
pastix_int_t eTreeNodeLevel(const EliminTree *, pastix_int_t)
Compute the number of level existing below a given node.
Definition: elimintree.c:289
pastix_int_t eTreeLevel(const EliminTree *)
Compute the height of the elimination tree.
Definition: elimintree.c:209
void eTreeExit(EliminTree *)
Free the elimination tree structure.
Definition: elimintree.c:89
Node of the elimination tree.
Definition: elimintree.h:25
Elimination tree.
Definition: elimintree.h:39
pastix_int_t fcblknm
Definition: symbol.h:63
symbol_cblk_t * cblktab
Definition: symbol.h:83
pastix_int_t bloknum
Definition: symbol.h:48
symbol_blok_t * bloktab
Definition: symbol.h:84
pastix_int_t cblknbr
Definition: symbol.h:79
Symbol matrix structure.
Definition: symbol.h:77