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