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