Graphviz 13.0.0~dev.20241220.2304
Loading...
Searching...
No Matches
graph_generator.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#include <cgraph/list.h>
13#include <stdbool.h>
14#include <stdio.h>
15#include <stdint.h>
16#include <stdlib.h>
17#include <math.h>
18#include <time.h>
19#include <graph_generator.h>
20#include <util/alloc.h>
21#include <util/exit.h>
22
23void makePath(unsigned n, edgefn ef){
24 if (n == 1) {
25 ef (1, 0);
26 return;
27 }
28 for (unsigned i = 2; i <= n; i++)
29 ef (i - 1, i);
30}
31
32void makeComplete(unsigned n, edgefn ef) {
33 if (n == 1) {
34 ef (1, 0);
35 return;
36 }
37 for (unsigned i = 1; i < n; i++) {
38 for (unsigned j = i + 1; j <= n; j++) {
39 ef ( i, j);
40 }
41 }
42}
43
44void makeCircle(unsigned n, edgefn ef) {
45 if (n < 3) {
46 fprintf(stderr, "Warning: degenerate circle of %u vertices\n", n);
47 makePath(n, ef);
48 return;
49 }
50
51 for (unsigned i = 1; i < n; i++)
52 ef ( i, i + 1);
53 ef (1, n);
54}
55
56void makeStar(unsigned n, edgefn ef) {
57 if (n < 3) {
58 fprintf(stderr, "Warning: degenerate star of %u vertices\n", n);
59 makePath(n, ef);
60 return;
61 }
62
63 for (unsigned i = 2; i <= n; i++)
64 ef (1, i);
65}
66
67void makeWheel(unsigned n, edgefn ef) {
68 if (n < 4) {
69 fprintf(stderr, "Warning: degenerate wheel of %u vertices\n", n);
70 makeComplete(n, ef);
71 return;
72 }
73
74 makeStar(n, ef);
75
76 for (unsigned i = 2; i < n; i++)
77 ef( i, i + 1);
78 ef (2, n);
79}
80
81void makeCompleteB(unsigned dim1, unsigned dim2, edgefn ef) {
82 for (unsigned i = 1; i <= dim1; i++) {
83 for (unsigned j = 1; j <= dim2; j++) {
84 ef ( i, dim1 + j);
85 }
86 }
87}
88
89void makeTorus(unsigned dim1, unsigned dim2, edgefn ef) {
90 for (unsigned i = 1, n = 0; i <= dim1; i++) {
91 for (unsigned j = 1; j < dim2; j++) {
92 ef( n + j, n + j + 1);
93 }
94 ef( n + 1, n + dim2);
95 n += dim2;
96 }
97
98 for (unsigned i = 1; i <= dim2; i++) {
99 for (unsigned j = 1; j < dim1; j++) {
100 ef( dim2 * (j - 1) + i, dim2 * j + i);
101 }
102 ef( i, dim2 * (dim1 - 1) + i);
103 }
104}
105
106void makeTwistedTorus(unsigned dim1, unsigned dim2, unsigned t1, unsigned t2,
107 edgefn ef) {
108 for (unsigned i = 0; i < dim1; i++) {
109 for (unsigned j = 0; j < dim2; j++) {
110 unsigned li = (i + t1) % dim1;
111 unsigned lj = (j + 1) % dim2;
112 ef (i+j*dim1+1, li+lj*dim1+1);
113
114 li = (i + 1) % dim1;
115 lj = (j + t2) % dim2;
116 ef(i+j*dim1+1, li+lj*dim1+1);
117 }
118 }
119}
120
121void makeCylinder(unsigned dim1, unsigned dim2, edgefn ef) {
122 for (unsigned i = 1, n = 0; i <= dim1; i++) {
123 for (unsigned j = 1; j < dim2; j++) {
124 ef( n + j, n + j + 1);
125 }
126 ef( n + 1, n + dim2);
127 n += dim2;
128 }
129
130 for (unsigned i = 1; i <= dim2; i++) {
131 for (unsigned j = 1; j < dim1; j++) {
132 ef( dim2 * (j - 1) + i, dim2 * j + i);
133 }
134 }
135}
136
137#define OUTE(h) if (tl < (hd=(h))) ef( tl, hd)
138
139void makeSquareGrid(unsigned dim1, unsigned dim2, int connect_corners, int partial, edgefn ef)
140{
141 for (unsigned i = 0; i < dim1; i++)
142 for (unsigned j = 0; j < dim2; j++) {
143 // write the neighbors of the node i*dim2+j+1
144 const unsigned tl = i * dim2 + j + 1;
145 unsigned hd;
146 if (j + 1 < dim2
147 && (!partial || j < 2 * dim2 / 6 || j >= 4 * dim2 / 6
148 || i <= 2 * dim1 / 6 || i > 4 * dim1 / 6)) {
149 ef(tl, i * dim2 + j + 2);
150 }
151 if (i + 1 < dim1) {
152 ef(tl, (i + 1) * dim2 + j + 1);
153 }
154 if (connect_corners == 1) {
155 if (i == 0 && j == 0) { // upper left
156 OUTE((dim1 - 1) * dim2 + dim2);
157 } else if (i + 1 == dim1 && j == 0) { // lower left
158 OUTE(dim2);
159 } else if (i == 0 && j + 1 == dim2) { // upper right
160 OUTE((dim1 - 1) * dim2 + 1);
161 } else if (i + 1 == dim1 && j + 1 == dim2) { // lower right
162 OUTE(1);
163 }
164 } else if (connect_corners == 2) {
165 if (i == 0 && j == 0) { // upper left
166 OUTE(dim2);
167 } else if (i + 1 == dim1 && j == 0) { // lower left
168 OUTE((dim1 - 1) * dim2 + dim2);
169 } else if (i == 0 && j + 1 == dim2) { // upper right
170 OUTE(1);
171 } else if (i + 1 == dim1 && j + 1 == dim2) { // lower right
172 OUTE((dim1 - 1) * dim2 + 1);
173 }
174 }
175 }
176}
177
178void makeTree(unsigned depth, unsigned nary, edgefn ef) {
179 const double n = (pow(nary, depth) - 1) / (nary - 1); // no. of non-leaf nodes
180 unsigned idx = 2;
181
182 for (unsigned i = 1; i <= n; i++) {
183 for (unsigned j = 0; j < nary; j++) {
184 ef (i, idx++);
185 }
186 }
187}
188
189void makeBinaryTree(unsigned depth, edgefn ef) {
190 const unsigned n = (1u << depth) - 1;
191
192 for (unsigned i = 1; i <= n; i++) {
193 ef( i, 2 * i);
194 ef( i, 2 * i + 1);
195 }
196}
197
198typedef struct {
199 unsigned nedges;
200 unsigned *edges;
201} vtx_data;
202
203static void constructSierpinski(unsigned v1, unsigned v2, unsigned v3,
204 unsigned depth, vtx_data *graph) {
205 static unsigned last_used_node_name = 3;
206
207 if (depth > 0) {
208 const unsigned v4 = ++last_used_node_name;
209 const unsigned v5 = ++last_used_node_name;
210 const unsigned v6 = ++last_used_node_name;
211 constructSierpinski(v1, v4, v5, depth - 1, graph);
212 constructSierpinski(v2, v5, v6, depth - 1, graph);
213 constructSierpinski(v3, v4, v6, depth - 1, graph);
214 return;
215 }
216 // depth==0, Construct graph:
217
218 unsigned nedges = graph[v1].nedges;
219 graph[v1].edges[nedges++] = v2;
220 graph[v1].edges[nedges++] = v3;
221 graph[v1].nedges = nedges;
222
223 nedges = graph[v2].nedges;
224 graph[v2].edges[nedges++] = v1;
225 graph[v2].edges[nedges++] = v3;
226 graph[v2].nedges = nedges;
227
228 nedges = graph[v3].nedges;
229 graph[v3].edges[nedges++] = v1;
230 graph[v3].edges[nedges++] = v2;
231 graph[v3].nedges = nedges;
232}
233
234void makeSierpinski(unsigned depth, edgefn ef) {
236
237 depth--;
238 const unsigned n = 3 * (1 + ((unsigned)(pow(3.0, depth) + 0.5) - 1) / 2);
239
240 graph = gv_calloc(n + 1, sizeof(vtx_data));
241 unsigned *edges = gv_calloc(4 * n, sizeof(unsigned));
242
243 for (unsigned i = 1; i <= n; i++) {
244 graph[i].edges = edges;
245 edges += 4;
246 graph[i].nedges = 0;
247 }
248
249 constructSierpinski(1, 2, 3, depth, graph);
250
251 for (unsigned i = 1; i <= n; i++) {
252 // write the neighbors of the node i
253 for (unsigned j = 0; j < graph[i].nedges; j++) {
254 const unsigned nghbr = graph[i].edges[j];
255 if (i < nghbr) ef( i, nghbr);
256 }
257 }
258
259 free(graph[1].edges);
260 free(graph);
261}
262
263static void constructTetrix(unsigned v1, unsigned v2, unsigned v3, unsigned v4,
264 unsigned depth, vtx_data* graph) {
265 static unsigned last_used_node_name = 4;
266
267 if (depth > 0) {
268 const unsigned v5 = ++last_used_node_name;
269 const unsigned v6 = ++last_used_node_name;
270 const unsigned v7 = ++last_used_node_name;
271 const unsigned v8 = ++last_used_node_name;
272 const unsigned v9 = ++last_used_node_name;
273 const unsigned v10 = ++last_used_node_name;
274 constructTetrix(v1, v5, v6, v8, depth - 1, graph);
275 constructTetrix(v2, v6, v7, v9, depth - 1, graph);
276 constructTetrix(v3, v5, v7, v10, depth - 1, graph);
277 constructTetrix(v4, v8, v9, v10, depth - 1, graph);
278 return;
279 }
280 // depth==0, Construct graph:
281 unsigned nedges = graph[v1].nedges;
282 graph[v1].edges[nedges++] = v2;
283 graph[v1].edges[nedges++] = v3;
284 graph[v1].edges[nedges++] = v4;
285 graph[v1].nedges = nedges;
286
287 nedges = graph[v2].nedges;
288 graph[v2].edges[nedges++] = v1;
289 graph[v2].edges[nedges++] = v3;
290 graph[v2].edges[nedges++] = v4;
291 graph[v2].nedges = nedges;
292
293 nedges = graph[v3].nedges;
294 graph[v3].edges[nedges++] = v1;
295 graph[v3].edges[nedges++] = v2;
296 graph[v3].edges[nedges++] = v4;
297 graph[v3].nedges = nedges;
298
299 nedges = graph[v4].nedges;
300 graph[v4].edges[nedges++] = v1;
301 graph[v4].edges[nedges++] = v2;
302 graph[v4].edges[nedges++] = v3;
303 graph[v4].nedges = nedges;
304}
305
306void makeTetrix(unsigned depth, edgefn ef) {
308
309 depth--;
310 const unsigned n = 4 + 2 * (((unsigned)(pow(4.0, depth) + 0.5) - 1));
311
312 graph = gv_calloc(n + 1, sizeof(vtx_data));
313 unsigned *edges = gv_calloc(6 * n, sizeof(unsigned));
314
315 for (unsigned i = 1; i <= n; i++) {
316 graph[i].edges = edges;
317 edges += 6;
318 graph[i].nedges = 0;
319 }
320
321 constructTetrix(1, 2, 3, 4, depth, graph);
322
323 for (unsigned i = 1; i <= n; i++) {
324 // write the neighbors of the node i
325 for (unsigned j = 0; j < graph[i].nedges; j++) {
326 const unsigned nghbr = graph[i].edges[j];
327 if (i < nghbr) ef( i, nghbr);
328 }
329 }
330
331 free(graph[1].edges);
332 free(graph);
333}
334
335void makeHypercube(unsigned dim, edgefn ef) {
336 const unsigned n = 1u << dim;
337
338 for (unsigned i = 0; i < n; i++) {
339 for (unsigned j = 0; j < dim; j++) {
340 const unsigned neighbor = (i ^ (1u << j)) + 1;
341 if (i < neighbor)
342 ef( i + 1, neighbor);
343 }
344 }
345}
346
347void makeTriMesh(unsigned sz, edgefn ef) {
348 if (sz == 1) {
349 ef (1, 0);
350 return;
351 }
352 ef(1,2);
353 ef(1,3);
354 unsigned idx = 2;
355 for (unsigned i = 2; i < sz; i++) {
356 for (unsigned j = 1; j <= i; j++) {
357 ef(idx,idx+i);
358 ef(idx,idx+i+1);
359 if (j < i)
360 ef(idx,idx+1);
361 idx++;
362 }
363 }
364 for (unsigned j = 1; j < sz; j++) {
365 ef (idx,idx+1);
366 idx++;
367 }
368}
369
370void makeBall(unsigned w, unsigned h, edgefn ef) {
371 makeCylinder (w, h, ef);
372
373 for (unsigned i = 1; i <= h; i++)
374 ef (0, i);
375
376 const unsigned cap = w * h + 1;
377 for (unsigned i = (w - 1) * h + 1; i <= w * h; i++)
378 ef (i, cap);
379
380}
381
382/* makeRandom:
383 * No. of nodes is largest 2^n - 1 less than or equal to h.
384 */
385void makeRandom(unsigned h, unsigned w, edgefn ef) {
386 srand((unsigned)time(0));
387 const int type = rand() % 2;
388
389 unsigned size = 0;
390 unsigned depth = 0;
391 while (size <= h) {
392 size += 1u << depth;
393 depth++;
394 }
395 depth--;
396 if (size > h) {
397 size -= 1u << depth;
398 depth--;
399 }
400
401 if (type)
402 makeBinaryTree (depth, ef);
403 else
404 makePath (size, ef);
405
406 for (unsigned i = 3; i <= size; i++) {
407 for (unsigned j = 1; j + 1 < i; j++) {
408 const unsigned th = (unsigned)rand() % (size * size);
409 if ((th <= w * w && (i < 5 || (i + 4 > h && j + 4 > h))) || th <= w)
410 ef(j,i);
411 }
412 }
413}
414
415void makeMobius(unsigned w, unsigned h, edgefn ef) {
416 if (h == 1) {
417 fprintf(stderr, "Warning: degenerate Moebius strip of %u vertices\n", w);
418 makePath(w, ef);
419 return;
420 }
421 if (w == 1) {
422 fprintf(stderr, "Warning: degenerate Moebius strip of %u vertices\n", h);
423 makePath(h, ef);
424 return;
425 }
426
427 for (unsigned i = 0; i + 1 < w; i++) {
428 for (unsigned j = 1; j < h; j++){
429 ef(j + i*h, j + (i+1)*h);
430 ef(j + i*h, j+1 + i*h);
431 }
432 }
433
434 for (unsigned i = 1; i < h; i++){
435 ef (i + (w-1)*h, i+1 + (w-1)*h);
436 }
437 for (unsigned i=1; i < w; i++) {
438 ef(i*h , (i+1)*h);
439 ef(i*h, (w-i)*h+1);
440 }
441
442 ef(1,w*h);
443}
444
445typedef struct {
446 unsigned j, d;
447} pair;
448
449typedef struct {
450 unsigned top, root;
451 unsigned* p;
452} tree_t;
453
454static tree_t *mkTree(unsigned sz) {
455 tree_t* tp = gv_alloc(sizeof(tree_t));
456 tp->root = 0;
457 tp->top = 0;
458 tp->p = gv_calloc(sz, sizeof(unsigned));
459 return tp;
460}
461
462static void
464{
465 free (tp->p);
466 free (tp);
467}
468
469static void
471{
472 tp->root = 0;
473 tp->top = 0;
474}
475
476static unsigned treeRoot(tree_t* tp) {
477 return tp->root;
478}
479
480static unsigned prevRoot(tree_t *tp) {
481 return tp->p[tp->root];
482}
483
484static unsigned treeSize(tree_t *tp) {
485 return tp->top - tp->root + 1;
486}
487
488static unsigned treeTop(tree_t *tp) {
489 return tp->top;
490}
491
492static void
494{
495 tp->root = prevRoot(tp);
496}
497
498static void addTree(tree_t *tp, unsigned sz) {
499 tp->p[tp->top+1] = tp->root;
500 tp->root = tp->top+1;
501 tp->top += sz;
502 if (sz > 1) tp->p[tp->top] = tp->top-1;
503}
504
505static void treeDup(tree_t *tp, unsigned J) {
506 unsigned M = treeSize(tp);
507 unsigned L = treeRoot(tp);
508 unsigned LL = prevRoot(tp);
509 unsigned LS = L + (J-1)*M - 1;
510 for (unsigned i = L; i <= LS; i++) {
511 if ((i-L)%M == 0) tp->p[i+M] = LL;
512 else tp->p[i+M] = tp->p[i] + M;
513 }
514 tp->top = LS + M;
515}
516
517/*****************/
518
519DEFINE_LIST(int_stack, unsigned)
520
521static void push(int_stack_t *sp, unsigned j, unsigned d) {
522 int_stack_push_back(sp, j);
523 int_stack_push_back(sp, d);
524}
525
526static pair pop(int_stack_t *sp) {
527
528 // extract ints in the opposite order in which they were pushed
529 const unsigned d = int_stack_pop_back(sp);
530 const unsigned j = int_stack_pop_back(sp);
531
532 return (pair){j, d};
533}
534
535/*****************/
536
537static unsigned *genCnt(unsigned NN) {
538 unsigned* T = gv_calloc(NN + 1, sizeof(unsigned));
539 unsigned NLAST = 1;
540 T[1] = 1;
541 while (NN > NLAST) {
542 unsigned SUM = 0;
543 for (unsigned D = 1; D <= NLAST; D++) {
544 unsigned I = NLAST + 1;
545 const unsigned TD = T[D] * D;
546 for (unsigned J = 1; J <= NLAST; J++) {
547 if (I <= D) break;
548 I = I-D;
549 SUM += T[I]*TD;
550 }
551 }
552 NLAST++;
553 T[NLAST] = SUM/(NLAST-1);
554 }
555 return T;
556}
557
558static double
559drand(void)
560{
561 double d;
562 d = rand();
563 d = d / RAND_MAX;
564 return d;
565}
566
567static void genTree(unsigned NN, unsigned *T, int_stack_t *stack,
568 tree_t *TREE) {
569 double v;
570 pair p;
571 unsigned J;
572
573 unsigned N = NN;
574
575 while (1) {
576 while (N > 2) {
577 v = (N-1)*T[N];
578 double Z = floor(v * drand());
579 unsigned D = 0;
580 bool more = true;
581 unsigned M;
582 do {
583 D++;
584 const unsigned TD = D*T[D];
585 M = N;
586 J = 0;
587 do {
588 J++;
589 if (M < D + 1) break;
590 M -= D;
591 if (Z < T[M] * TD) {
592 more = false;
593 break;
594 }
595 Z -= T[M]*TD;
596 } while (true);
597 } while (more);
598 push(stack, J, D);
599 N = M;
600 }
601 addTree (TREE, N);
602
603 while (1) {
604 p = pop(stack);
605 N = p.d;
606 if (N != 0) {
607 push(stack,p.j,0);
608 break;
609 }
610 J = p.j;
611 if (J > 1) treeDup (TREE, J);
612 if (treeTop(TREE) == NN) return;
613 treePop(TREE);
614 }
615 }
616
617}
618
619static void
621{
622 for (unsigned i = 2; i <= tp->top; i++)
623 ef (tp->p[i], i);
624}
625
626struct treegen_s {
627 unsigned N;
628 unsigned* T;
629 int_stack_t sp;
631};
632
634 treegen_t* tg = gv_alloc(sizeof(treegen_t));
635
636 tg->N = N;
637 tg->T = genCnt(N);
638 tg->sp = (int_stack_t){0};
639 tg->tp = mkTree(N+1);
640 srand((unsigned)time(0));
641
642 return tg;
643}
644
646{
647 int_stack_clear(&tg->sp);
648 resetTree(tg->tp);
649 genTree(tg->N, tg->T, &tg->sp, tg->tp);
650 writeTree (tg->tp, ef);
651}
652
653void
655{
656 free (tg->T);
657 int_stack_free(&tg->sp);
658 freeTree (tg->tp);
659 free (tg);
660}
661
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 N(n)
Definition bcomps.c:58
static Agnode_t * pop(void)
Definition ccomps.c:231
expr procedure type
Definition exparse.y:208
#define I
Definition expr.h:71
static attrs_t * L
Definition gmlparse.c:93
void free(void *)
static void treePop(tree_t *tp)
void makeTriMesh(unsigned sz, edgefn ef)
static unsigned prevRoot(tree_t *tp)
void makeHypercube(unsigned dim, edgefn ef)
static void addTree(tree_t *tp, unsigned sz)
static unsigned treeSize(tree_t *tp)
static double drand(void)
static void constructSierpinski(unsigned v1, unsigned v2, unsigned v3, unsigned depth, vtx_data *graph)
void makeCircle(unsigned n, edgefn ef)
void makeTree(unsigned depth, unsigned nary, edgefn ef)
static void writeTree(tree_t *tp, edgefn ef)
void makeWheel(unsigned n, edgefn ef)
void makeSquareGrid(unsigned dim1, unsigned dim2, int connect_corners, int partial, edgefn ef)
static void genTree(unsigned NN, unsigned *T, int_stack_t *stack, tree_t *TREE)
void makeBinaryTree(unsigned depth, edgefn ef)
static void constructTetrix(unsigned v1, unsigned v2, unsigned v3, unsigned v4, unsigned depth, vtx_data *graph)
void makeComplete(unsigned n, edgefn ef)
void makeMobius(unsigned w, unsigned h, edgefn ef)
treegen_t * makeTreeGen(unsigned N)
void makeCompleteB(unsigned dim1, unsigned dim2, edgefn ef)
static void push(int_stack_t *sp, unsigned j, unsigned d)
void makeBall(unsigned w, unsigned h, edgefn ef)
void makePath(unsigned n, edgefn ef)
static unsigned treeRoot(tree_t *tp)
static void resetTree(tree_t *tp)
void makeTetrix(unsigned depth, edgefn ef)
void makeCylinder(unsigned dim1, unsigned dim2, edgefn ef)
void makeStar(unsigned n, edgefn ef)
static void treeDup(tree_t *tp, unsigned J)
void freeTreeGen(treegen_t *tg)
void makeTorus(unsigned dim1, unsigned dim2, edgefn ef)
void makeTwistedTorus(unsigned dim1, unsigned dim2, unsigned t1, unsigned t2, edgefn ef)
#define OUTE(h)
void makeRandomTree(treegen_t *tg, edgefn ef)
void makeRandom(unsigned h, unsigned w, edgefn ef)
static unsigned * genCnt(unsigned NN)
static void freeTree(tree_t *tp)
void makeSierpinski(unsigned depth, edgefn ef)
static tree_t * mkTree(unsigned sz)
static unsigned treeTop(tree_t *tp)
Agraph_t * graph(char *name)
Definition gv.cpp:30
#define D
Definition hierarchy.c:119
static Agedge_t * top(edge_stack_t *sp)
Definition tred.c:73
#define DEFINE_LIST(name, type)
Definition list.h:26
#define neighbor(t, i, edim, elist)
Definition make_map.h:41
static const int dim
#define M
Definition randomkit.c:90
static int nedges
total no. of edges used in routing
Definition routespl.c:31
unsigned j
unsigned d
unsigned top
unsigned root
unsigned * p
unsigned * T
int_stack_t sp
unsigned nedges
unsigned * edges
static mytime_t T
Definition timing.c:41
void(* edgefn)(Agraph_t *, Agedge_t *, glCompColor)