compute_hierarchy.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /*************************************************************************
  2. * Copyright (c) 2011 AT&T Intellectual Property
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors: Details at https://graphviz.org
  9. *************************************************************************/
  10. #include <neatogen/digcola.h>
  11. #include <util/alloc.h>
  12. #ifdef DIGCOLA
  13. #include <neatogen/kkutils.h>
  14. /*
  15. * This function partitions the graph nodes into levels
  16. * according to the minimizer of the hierarchy energy.
  17. *
  18. * To allow more flexibility we define a new level only
  19. * when the hierarchy energy shows a significant jump
  20. * (to compensate for noise).
  21. * This is controlled by two parameters: 'abs_tol' and
  22. * 'relative_tol'. The smaller these two are, the more
  23. * levels we'll get.
  24. * More speciffically:
  25. * We never consider gaps smaller than 'abs_tol'
  26. * Additionally, we never consider gaps smaller than 'abs_tol'*<avg_gap>
  27. *
  28. * The output is an ordering of the nodes according to
  29. * their levels, as follows:
  30. * First level:
  31. * ordering[0],ordering[1],...ordering[levels[0]-1]
  32. * Second level:
  33. * ordering[levels[0]],ordering[levels[0]+1],...ordering[levels[1]-1]
  34. * ...
  35. * Last level:
  36. * ordering[levels[num_levels-1]],ordering[levels[num_levels-1]+1],...ordering[n-1]
  37. *
  38. * Hence, the nodes were partitioned into 'num_levels'+1
  39. * levels.
  40. *
  41. * Please note that 'ordering[levels[i]]' contains the first node at level i+1,
  42. * and not the last node of level i.
  43. */
  44. int
  45. compute_hierarchy(vtx_data * graph, int n, double abs_tol,
  46. double relative_tol, double *given_coords,
  47. int **orderingp, int **levelsp, int *num_levelsp)
  48. {
  49. double *y;
  50. int i, rv=0;
  51. int *ordering;
  52. int *levels;
  53. double tol; /* node 'i' precedes 'j' in hierarchy iff y[i]-y[j]>tol */
  54. double hierarchy_span;
  55. int num_levels;
  56. /* compute optimizer of hierarchy energy: 'y' */
  57. if (given_coords) {
  58. y = given_coords;
  59. } else {
  60. y = gv_calloc(n, sizeof(double));
  61. if (compute_y_coords(graph, n, y, n)) {
  62. rv = 1;
  63. goto finish;
  64. }
  65. }
  66. /* sort nodes accoridng to their y-ordering */
  67. *orderingp = ordering = gv_calloc(n, sizeof(int));
  68. for (i = 0; i < n; i++) {
  69. ordering[i] = i;
  70. }
  71. quicksort_place(y, ordering, n);
  72. /* compute tolerance
  73. * take the maximum between 'abs_tol' and a fraction of the average gap
  74. * controlled by 'relative_tol'
  75. */
  76. hierarchy_span = y[ordering[n - 1]] - y[ordering[0]];
  77. tol = MAX(abs_tol, relative_tol * hierarchy_span / (n - 1));
  78. /* 'hierarchy_span/(n-1)' - average gap between consecutive nodes */
  79. /* count how many levels the hierarchy contains (a SINGLE_LINK clustering */
  80. /* alternatively we could use COMPLETE_LINK clustering) */
  81. num_levels = 0;
  82. for (i = 1; i < n; i++) {
  83. if (y[ordering[i]] - y[ordering[i - 1]] > tol) {
  84. num_levels++;
  85. }
  86. }
  87. *num_levelsp = num_levels;
  88. if (num_levels == 0) {
  89. *levelsp = levels = gv_calloc(1, sizeof(int));
  90. levels[0] = n;
  91. } else {
  92. int count = 0;
  93. *levelsp = levels = gv_calloc(num_levels, sizeof(int));
  94. for (i = 1; i < n; i++) {
  95. if (y[ordering[i]] - y[ordering[i - 1]] > tol) {
  96. levels[count++] = i;
  97. }
  98. }
  99. }
  100. finish:
  101. if (!given_coords) {
  102. free(y);
  103. }
  104. return rv;
  105. }
  106. #endif /* DIGCOLA */