Multilevel.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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 <sfdpgen/Multilevel.h>
  11. #include <assert.h>
  12. #include <common/arith.h>
  13. #include <stddef.h>
  14. #include <stdbool.h>
  15. #include <util/alloc.h>
  16. static const int minsize = 4;
  17. static const double min_coarsen_factor = 0.75;
  18. static Multilevel Multilevel_init(SparseMatrix A) {
  19. if (!A) return NULL;
  20. assert(A->m == A->n);
  21. Multilevel grid = gv_alloc(sizeof(struct Multilevel_struct));
  22. grid->level = 0;
  23. grid->n = A->n;
  24. grid->A = A;
  25. grid->P = NULL;
  26. grid->R = NULL;
  27. grid->next = NULL;
  28. grid->prev = NULL;
  29. grid->delete_top_level_A = false;
  30. return grid;
  31. }
  32. void Multilevel_delete(Multilevel grid){
  33. if (!grid) return;
  34. if (grid->A){
  35. if (grid->level == 0) {
  36. if (grid->delete_top_level_A) {
  37. SparseMatrix_delete(grid->A);
  38. }
  39. } else {
  40. SparseMatrix_delete(grid->A);
  41. }
  42. }
  43. SparseMatrix_delete(grid->P);
  44. SparseMatrix_delete(grid->R);
  45. Multilevel_delete(grid->next);
  46. free(grid);
  47. }
  48. static void maximal_independent_edge_set_heavest_edge_pernode_supernodes_first(SparseMatrix A, int **cluster, int **clusterp, int *ncluster){
  49. int i, ii, j, *ia, *ja, m, n, *p = NULL;
  50. (void)n;
  51. double *a, amax = 0;
  52. int jamax = 0;
  53. int *matched, nz, nz0;
  54. enum {MATCHED = -1};
  55. int nsuper, *super = NULL, *superp = NULL;
  56. assert(A);
  57. assert(A->is_pattern_symmetric);
  58. ia = A->ia;
  59. ja = A->ja;
  60. m = A->m;
  61. n = A->n;
  62. assert(n == m);
  63. *cluster = gv_calloc(m, sizeof(int));
  64. *clusterp = gv_calloc(m + 1, sizeof(int));
  65. matched = gv_calloc(m, sizeof(int));
  66. for (i = 0; i < m; i++) matched[i] = i;
  67. assert(SparseMatrix_is_symmetric(A, false));
  68. assert(A->type == MATRIX_TYPE_REAL);
  69. SparseMatrix_decompose_to_supervariables(A, &nsuper, &super, &superp);
  70. *ncluster = 0;
  71. (*clusterp)[0] = 0;
  72. nz = 0;
  73. a = A->a;
  74. for (i = 0; i < nsuper; i++){
  75. if (superp[i+1] - superp[i] <= 1) continue;
  76. nz0 = (*clusterp)[*ncluster];
  77. for (j = superp[i]; j < superp[i+1]; j++){
  78. matched[super[j]] = MATCHED;
  79. (*cluster)[nz++] = super[j];
  80. if (nz - nz0 >= MAX_CLUSTER_SIZE){
  81. (*clusterp)[++(*ncluster)] = nz;
  82. nz0 = nz;
  83. }
  84. }
  85. if (nz > nz0) (*clusterp)[++(*ncluster)] = nz;
  86. }
  87. p = random_permutation(m);
  88. for (ii = 0; ii < m; ii++){
  89. i = p[ii];
  90. bool first = true;
  91. if (matched[i] == MATCHED) continue;
  92. for (j = ia[i]; j < ia[i+1]; j++){
  93. if (i == ja[j]) continue;
  94. if (matched[ja[j]] != MATCHED && matched[i] != MATCHED){
  95. if (first) {
  96. amax = a[j];
  97. jamax = ja[j];
  98. first = false;
  99. } else {
  100. if (a[j] > amax){
  101. amax = a[j];
  102. jamax = ja[j];
  103. }
  104. }
  105. }
  106. }
  107. if (!first){
  108. matched[jamax] = MATCHED;
  109. matched[i] = MATCHED;
  110. (*cluster)[nz++] = i;
  111. (*cluster)[nz++] = jamax;
  112. (*clusterp)[++(*ncluster)] = nz;
  113. }
  114. }
  115. for (i = 0; i < m; i++){
  116. if (matched[i] == i){
  117. (*cluster)[nz++] = i;
  118. (*clusterp)[++(*ncluster)] = nz;
  119. }
  120. }
  121. free(p);
  122. free(super);
  123. free(superp);
  124. free(matched);
  125. }
  126. static void Multilevel_coarsen_internal(SparseMatrix A, SparseMatrix *cA,
  127. SparseMatrix *P, SparseMatrix *R) {
  128. int nc, nzc, n, i;
  129. int *irn = NULL, *jcn = NULL;
  130. double *val = NULL;
  131. int j;
  132. int *cluster=NULL, *clusterp=NULL, ncluster;
  133. assert(A->m == A->n);
  134. *cA = NULL;
  135. *P = NULL;
  136. *R = NULL;
  137. n = A->m;
  138. maximal_independent_edge_set_heavest_edge_pernode_supernodes_first(A, &cluster, &clusterp, &ncluster);
  139. assert(ncluster <= n);
  140. nc = ncluster;
  141. if (nc == n || nc < minsize) {
  142. #ifdef DEBUG_PRINT
  143. if (Verbose)
  144. fprintf(stderr, "nc = %d, nf = %d, minsz = %d, coarsen_factor = %f coarsening stops\n",nc, n, minsize, min_coarsen_factor);
  145. #endif
  146. goto RETURN;
  147. }
  148. irn = gv_calloc(n, sizeof(int));
  149. jcn = gv_calloc(n, sizeof(int));
  150. val = gv_calloc(n, sizeof(double));
  151. nzc = 0;
  152. for (i = 0; i < ncluster; i++){
  153. for (j = clusterp[i]; j < clusterp[i+1]; j++){
  154. assert(clusterp[i+1] > clusterp[i]);
  155. irn[nzc] = cluster[j];
  156. jcn[nzc] = i;
  157. val[nzc++] = 1.;
  158. }
  159. }
  160. assert(nzc == n);
  161. *P = SparseMatrix_from_coordinate_arrays(nzc, n, nc, irn, jcn, val,
  162. MATRIX_TYPE_REAL, sizeof(double));
  163. *R = SparseMatrix_transpose(*P);
  164. *cA = SparseMatrix_multiply3(*R, A, *P);
  165. if (!*cA) goto RETURN;
  166. *R = SparseMatrix_divide_row_by_degree(*R);
  167. (*cA)->is_symmetric = true;
  168. (*cA)->is_pattern_symmetric = true;
  169. *cA = SparseMatrix_remove_diagonal(*cA);
  170. RETURN:
  171. free(irn);
  172. free(jcn);
  173. free(val);
  174. free(cluster);
  175. free(clusterp);
  176. }
  177. static void Multilevel_coarsen(SparseMatrix A, SparseMatrix *cA,
  178. SparseMatrix *P, SparseMatrix *R) {
  179. SparseMatrix cA0 = A, P0 = NULL, R0 = NULL, M;
  180. int nc = 0, n;
  181. *P = NULL; *R = NULL; *cA = NULL;
  182. n = A->n;
  183. do {/* this loop force a sufficient reduction */
  184. Multilevel_coarsen_internal(A, &cA0, &P0, &R0);
  185. if (!cA0) return;
  186. nc = cA0->n;
  187. #ifdef DEBUG_PRINT
  188. if (Verbose) fprintf(stderr,"nc=%d n = %d\n",nc,n);
  189. #endif
  190. if (*P){
  191. assert(*R);
  192. M = SparseMatrix_multiply(*P, P0);
  193. SparseMatrix_delete(*P);
  194. SparseMatrix_delete(P0);
  195. *P = M;
  196. M = SparseMatrix_multiply(R0, *R);
  197. SparseMatrix_delete(*R);
  198. SparseMatrix_delete(R0);
  199. *R = M;
  200. } else {
  201. *P = P0;
  202. *R = R0;
  203. }
  204. if (*cA) SparseMatrix_delete(*cA);
  205. *cA = cA0;
  206. A = cA0;
  207. } while (nc > min_coarsen_factor*n);
  208. }
  209. void print_padding(int n){
  210. int i;
  211. for (i = 0; i < n; i++) fputs (" ", stderr);
  212. }
  213. static Multilevel Multilevel_establish(Multilevel grid,
  214. const Multilevel_control ctrl) {
  215. Multilevel cgrid;
  216. SparseMatrix P, R, A, cA;
  217. #ifdef DEBUG_PRINT
  218. if (Verbose) {
  219. print_padding(grid->level);
  220. fprintf(stderr, "level -- %d, n = %d, nz = %d nz/n = %f\n", grid->level, grid->n, grid->A->nz, grid->A->nz/(double) grid->n);
  221. }
  222. #endif
  223. A = grid->A;
  224. if (grid->level >= ctrl.maxlevel - 1) {
  225. #ifdef DEBUG_PRINT
  226. if (Verbose) {
  227. print_padding(grid->level);
  228. fprintf(stderr, " maxlevel reached, coarsening stops\n");
  229. }
  230. #endif
  231. return grid;
  232. }
  233. Multilevel_coarsen(A, &cA, &P, &R);
  234. if (!cA) return grid;
  235. cgrid = Multilevel_init(cA);
  236. grid->next = cgrid;
  237. cgrid->level = grid->level + 1;
  238. cgrid->n = cA->m;
  239. cgrid->P = P;
  240. grid->R = R;
  241. cgrid->prev = grid;
  242. cgrid = Multilevel_establish(cgrid, ctrl);
  243. return grid;
  244. }
  245. Multilevel Multilevel_new(SparseMatrix A0,
  246. const Multilevel_control ctrl) {
  247. /* A: the weighting matrix. D: the distance matrix, could be NULL. If not null, the two matrices must have the same sparsity pattern */
  248. Multilevel grid;
  249. SparseMatrix A = A0;
  250. if (!SparseMatrix_is_symmetric(A, false) || A->type != MATRIX_TYPE_REAL){
  251. A = SparseMatrix_get_real_adjacency_matrix_symmetrized(A);
  252. }
  253. grid = Multilevel_init(A);
  254. grid = Multilevel_establish(grid, ctrl);
  255. if (A != A0) grid->delete_top_level_A = true; // be sure to clean up later
  256. return grid;
  257. }
  258. Multilevel Multilevel_get_coarsest(Multilevel grid){
  259. while (grid->next){
  260. grid = grid->next;
  261. }
  262. return grid;
  263. }