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