123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- /*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: Details at https://graphviz.org
- *************************************************************************/
- #include <sfdpgen/Multilevel.h>
- #include <assert.h>
- #include <common/arith.h>
- #include <stddef.h>
- #include <stdbool.h>
- #include <util/alloc.h>
- static const int minsize = 4;
- static const double min_coarsen_factor = 0.75;
- static Multilevel Multilevel_init(SparseMatrix A) {
- if (!A) return NULL;
- assert(A->m == A->n);
- Multilevel grid = gv_alloc(sizeof(struct Multilevel_struct));
- grid->level = 0;
- grid->n = A->n;
- grid->A = A;
- grid->P = NULL;
- grid->R = NULL;
- grid->next = NULL;
- grid->prev = NULL;
- grid->delete_top_level_A = false;
- return grid;
- }
- void Multilevel_delete(Multilevel grid){
- if (!grid) return;
- if (grid->A){
- if (grid->level == 0) {
- if (grid->delete_top_level_A) {
- SparseMatrix_delete(grid->A);
- }
- } else {
- SparseMatrix_delete(grid->A);
- }
- }
- SparseMatrix_delete(grid->P);
- SparseMatrix_delete(grid->R);
- Multilevel_delete(grid->next);
- free(grid);
- }
- static void maximal_independent_edge_set_heavest_edge_pernode_supernodes_first(SparseMatrix A, int **cluster, int **clusterp, int *ncluster){
- int i, ii, j, *ia, *ja, m, n, *p = NULL;
- (void)n;
- double *a, amax = 0;
- int jamax = 0;
- int *matched, nz, nz0;
- enum {MATCHED = -1};
- int nsuper, *super = NULL, *superp = NULL;
- assert(A);
- assert(A->is_pattern_symmetric);
- ia = A->ia;
- ja = A->ja;
- m = A->m;
- n = A->n;
- assert(n == m);
- *cluster = gv_calloc(m, sizeof(int));
- *clusterp = gv_calloc(m + 1, sizeof(int));
- matched = gv_calloc(m, sizeof(int));
- for (i = 0; i < m; i++) matched[i] = i;
- assert(SparseMatrix_is_symmetric(A, false));
- assert(A->type == MATRIX_TYPE_REAL);
- SparseMatrix_decompose_to_supervariables(A, &nsuper, &super, &superp);
- *ncluster = 0;
- (*clusterp)[0] = 0;
- nz = 0;
- a = A->a;
- for (i = 0; i < nsuper; i++){
- if (superp[i+1] - superp[i] <= 1) continue;
- nz0 = (*clusterp)[*ncluster];
- for (j = superp[i]; j < superp[i+1]; j++){
- matched[super[j]] = MATCHED;
- (*cluster)[nz++] = super[j];
- if (nz - nz0 >= MAX_CLUSTER_SIZE){
- (*clusterp)[++(*ncluster)] = nz;
- nz0 = nz;
- }
- }
- if (nz > nz0) (*clusterp)[++(*ncluster)] = nz;
- }
- p = random_permutation(m);
- for (ii = 0; ii < m; ii++){
- i = p[ii];
- bool first = true;
- if (matched[i] == MATCHED) continue;
- for (j = ia[i]; j < ia[i+1]; j++){
- if (i == ja[j]) continue;
- if (matched[ja[j]] != MATCHED && matched[i] != MATCHED){
- if (first) {
- amax = a[j];
- jamax = ja[j];
- first = false;
- } else {
- if (a[j] > amax){
- amax = a[j];
- jamax = ja[j];
- }
- }
- }
- }
- if (!first){
- matched[jamax] = MATCHED;
- matched[i] = MATCHED;
- (*cluster)[nz++] = i;
- (*cluster)[nz++] = jamax;
- (*clusterp)[++(*ncluster)] = nz;
- }
- }
- for (i = 0; i < m; i++){
- if (matched[i] == i){
- (*cluster)[nz++] = i;
- (*clusterp)[++(*ncluster)] = nz;
- }
- }
- free(p);
- free(super);
- free(superp);
- free(matched);
- }
- static void Multilevel_coarsen_internal(SparseMatrix A, SparseMatrix *cA,
- SparseMatrix *P, SparseMatrix *R) {
- int nc, nzc, n, i;
- int *irn = NULL, *jcn = NULL;
- double *val = NULL;
- int j;
- int *cluster=NULL, *clusterp=NULL, ncluster;
- assert(A->m == A->n);
- *cA = NULL;
- *P = NULL;
- *R = NULL;
- n = A->m;
- maximal_independent_edge_set_heavest_edge_pernode_supernodes_first(A, &cluster, &clusterp, &ncluster);
- assert(ncluster <= n);
- nc = ncluster;
- if (nc == n || nc < minsize) {
- #ifdef DEBUG_PRINT
- if (Verbose)
- fprintf(stderr, "nc = %d, nf = %d, minsz = %d, coarsen_factor = %f coarsening stops\n",nc, n, minsize, min_coarsen_factor);
- #endif
- goto RETURN;
- }
- irn = gv_calloc(n, sizeof(int));
- jcn = gv_calloc(n, sizeof(int));
- val = gv_calloc(n, sizeof(double));
- nzc = 0;
- for (i = 0; i < ncluster; i++){
- for (j = clusterp[i]; j < clusterp[i+1]; j++){
- assert(clusterp[i+1] > clusterp[i]);
- irn[nzc] = cluster[j];
- jcn[nzc] = i;
- val[nzc++] = 1.;
- }
- }
- assert(nzc == n);
- *P = SparseMatrix_from_coordinate_arrays(nzc, n, nc, irn, jcn, val,
- MATRIX_TYPE_REAL, sizeof(double));
- *R = SparseMatrix_transpose(*P);
- *cA = SparseMatrix_multiply3(*R, A, *P);
- if (!*cA) goto RETURN;
- *R = SparseMatrix_divide_row_by_degree(*R);
- (*cA)->is_symmetric = true;
- (*cA)->is_pattern_symmetric = true;
- *cA = SparseMatrix_remove_diagonal(*cA);
- RETURN:
- free(irn);
- free(jcn);
- free(val);
- free(cluster);
- free(clusterp);
- }
- static void Multilevel_coarsen(SparseMatrix A, SparseMatrix *cA,
- SparseMatrix *P, SparseMatrix *R) {
- SparseMatrix cA0 = A, P0 = NULL, R0 = NULL, M;
- int nc = 0, n;
-
- *P = NULL; *R = NULL; *cA = NULL;
- n = A->n;
- do {/* this loop force a sufficient reduction */
- Multilevel_coarsen_internal(A, &cA0, &P0, &R0);
- if (!cA0) return;
- nc = cA0->n;
- #ifdef DEBUG_PRINT
- if (Verbose) fprintf(stderr,"nc=%d n = %d\n",nc,n);
- #endif
- if (*P){
- assert(*R);
- M = SparseMatrix_multiply(*P, P0);
- SparseMatrix_delete(*P);
- SparseMatrix_delete(P0);
- *P = M;
- M = SparseMatrix_multiply(R0, *R);
- SparseMatrix_delete(*R);
- SparseMatrix_delete(R0);
- *R = M;
- } else {
- *P = P0;
- *R = R0;
- }
- if (*cA) SparseMatrix_delete(*cA);
- *cA = cA0;
- A = cA0;
- } while (nc > min_coarsen_factor*n);
- }
- void print_padding(int n){
- int i;
- for (i = 0; i < n; i++) fputs (" ", stderr);
- }
- static Multilevel Multilevel_establish(Multilevel grid,
- const Multilevel_control ctrl) {
- Multilevel cgrid;
- SparseMatrix P, R, A, cA;
- #ifdef DEBUG_PRINT
- if (Verbose) {
- print_padding(grid->level);
- 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);
- }
- #endif
- A = grid->A;
- if (grid->level >= ctrl.maxlevel - 1) {
- #ifdef DEBUG_PRINT
- if (Verbose) {
- print_padding(grid->level);
- fprintf(stderr, " maxlevel reached, coarsening stops\n");
- }
- #endif
- return grid;
- }
- Multilevel_coarsen(A, &cA, &P, &R);
- if (!cA) return grid;
- cgrid = Multilevel_init(cA);
- grid->next = cgrid;
- cgrid->level = grid->level + 1;
- cgrid->n = cA->m;
- cgrid->P = P;
- grid->R = R;
- cgrid->prev = grid;
- cgrid = Multilevel_establish(cgrid, ctrl);
- return grid;
-
- }
- Multilevel Multilevel_new(SparseMatrix A0,
- const Multilevel_control ctrl) {
- /* A: the weighting matrix. D: the distance matrix, could be NULL. If not null, the two matrices must have the same sparsity pattern */
- Multilevel grid;
- SparseMatrix A = A0;
- if (!SparseMatrix_is_symmetric(A, false) || A->type != MATRIX_TYPE_REAL){
- A = SparseMatrix_get_real_adjacency_matrix_symmetrized(A);
- }
- grid = Multilevel_init(A);
- grid = Multilevel_establish(grid, ctrl);
- if (A != A0) grid->delete_top_level_A = true; // be sure to clean up later
- return grid;
- }
- Multilevel Multilevel_get_coarsest(Multilevel grid){
- while (grid->next){
- grid = grid->next;
- }
- return grid;
- }
|