From: Emden Gansner Date: Tue, 5 Jun 2012 21:09:04 +0000 (-0400) Subject: Add random rooted trees to gvgen X-Git-Tag: LAST_LIBGRAPH~32^2~406 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=da90960550147b67f70e9124db5306e88191b35a;p=graphviz Add random rooted trees to gvgen --- diff --git a/cmd/tools/graph_generator.c b/cmd/tools/graph_generator.c index 7d9079721..3fc9ef31b 100644 --- a/cmd/tools/graph_generator.c +++ b/cmd/tools/graph_generator.c @@ -294,7 +294,8 @@ constructSierpinski(int v1, int v2, int v3, int depth, vtx_data* graph) } -#define N_NEW(n,t) (t*)malloc((n)*sizeof(t)) +#define NEW(t) (t*)calloc((1),sizeof(t)) +#define N_NEW(n,t) (t*)calloc((n),sizeof(t)) void makeSierpinski(int depth, edgefn ef) { @@ -461,4 +462,264 @@ void makeMobius(int w, int h, edgefn ef) ef(1,w*h); } +typedef struct { + int j, d; +} pair; + +typedef struct { + int top, root; + int* p; +} tree_t; + +static tree_t* +mkTree (int sz) +{ + tree_t* tp = NEW(tree_t); + tp->root = 0; + tp->top = 0; + tp->p = N_NEW(sz,int); + return tp; +} + +static void +freeTree (tree_t* tp) +{ + free (tp->p); + free (tp); +} + +static void +resetTree (tree_t* tp) +{ + tp->root = 0; + tp->top = 0; +} + +static int +treeRoot (tree_t* tp) +{ + return tp->root; +} + +static int +prevRoot (tree_t* tp) +{ + return tp->p[tp->root]; +} + +static int +treeSize (tree_t* tp) +{ + return (tp->top - tp->root + 1); +} + +static int +treeTop (tree_t* tp) +{ + return (tp->top); +} + +static void +treePop (tree_t* tp) +{ + tp->root = prevRoot(tp); +} + +static void +addTree (tree_t* tp, int sz) +{ + tp->p[tp->top+1] = tp->root; + tp->root = tp->top+1; + tp->top += sz; + if (sz > 1) tp->p[tp->top] = tp->top-1; +} + +static void +treeDup (tree_t* tp, int J) +{ + int M = treeSize(tp); + int L = treeRoot(tp); + int LL = prevRoot(tp); + int i, LS = L + (J-1)*M - 1; + for (i = L; i <= LS; i++) { + if ((i-L)%M == 0) tp->p[i+M] = LL; + else tp->p[i+M] = tp->p[i] + M; + } + tp->top = LS + M; +} + +/*****************/ + +typedef struct { + int top; + pair* v; +} stack; + +static stack* +mkStack (int sz) +{ + stack* sp = NEW(stack); + sp->top = 0; + sp->v = N_NEW(sz,pair); + return sp; +} + +static void +freeStack (stack* sp) +{ + free (sp->v); + free (sp); +} + +static void +resetStack (stack* sp) +{ + sp->top = 0; +} + +static void +push(stack* sp, int j, int d) +{ + sp->top++; + sp->v[sp->top].j = j; + sp->v[sp->top].d = d; +} + +static pair +pop (stack* sp) +{ + sp->top--; + return sp->v[sp->top+1]; +} + +/*****************/ + +static int* +genCnt(int NN) +{ + int* T = N_NEW(NN+1,int); + int D, I, J, TD; + int SUM; + int NLAST = 1; + T[1] = 1; + while (NN > NLAST) { + SUM = 0; + for (D = 1; D <= NLAST; D++) { + I = NLAST+1; + TD = T[D]*D; + for (J = 1; J <= NLAST; J++) { + I = I-D; + if (I <= 0) break; + SUM += T[I]*TD; + } + } + NLAST++; + T[NLAST] = SUM/(NLAST-1); + } + return T; +} + +static double +drand(void) +{ + double d; + d = rand(); + d = d / RAND_MAX; + return d; +} + +static void +genTree (int NN, int* T, stack* stack, tree_t* TREE) +{ + double v; + pair p; + int Z, D, N, J, TD, M, more; + + N = NN; + + while (1) { + while (N > 2) { + v = (N-1)*T[N]; + Z = v*drand(); + D = 0; + more = 1; + do { + D++; + TD = D*T[D]; + M = N; + J = 0; + do { + J++; + M -= D; + if (M < 1) break; + Z -= T[M]*TD; + if (Z < 0) more = 0; + } while (Z >= 0); + } while (more); + push(stack, J, D); + N = M; + } + addTree (TREE, N); + + while (1) { + p = pop(stack); + N = p.d; + if (N != 0) { + push(stack,p.j,0); + break; + } + J = p.j; + if (J > 1) treeDup (TREE, J); + if (treeTop(TREE) == NN) return; + treePop(TREE); + } + } + +} + +static void +writeTree (tree_t* tp, edgefn ef) +{ + int i; + for (i = 2; i <= tp->top; i++) + ef (tp->p[i], i); +} + +struct treegen_s { + int N; + int* T; + stack* sp; + tree_t* tp; +}; + +treegen_t* +makeTreeGen (int N) +{ + treegen_t* tg = NEW(treegen_t); + + tg->N = N; + tg->T = genCnt(N); + tg->sp = mkStack(N+1); + tg->tp = mkTree(N+1); + srand(time(0)); + + return tg; +} + +void makeRandomTree (treegen_t* tg, edgefn ef) +{ + resetStack(tg->sp); + resetTree(tg->tp); + genTree (tg->N, tg->T, tg->sp, tg->tp); + writeTree (tg->tp, ef); +} + +void +freeTreeGen(treegen_t* tg) +{ + free (tg->T); + freeStack (tg->sp); + freeTree (tg->tp); + free (tg); +} diff --git a/cmd/tools/graph_generator.h b/cmd/tools/graph_generator.h index 5f7e2ad33..8f43adc10 100644 --- a/cmd/tools/graph_generator.h +++ b/cmd/tools/graph_generator.h @@ -35,4 +35,8 @@ extern void makeTree(int, int, edgefn); extern void makeTriMesh(int, edgefn); extern void makeMobius(int, int, edgefn); +typedef struct treegen_s treegen_t; +extern treegen_t* makeTreeGen (int); +extern void makeRandomTree (treegen_t*, edgefn); +extern void freeTreeGen(treegen_t*); #endif diff --git a/cmd/tools/gvgen.1 b/cmd/tools/gvgen.1 index c473a79cf..6d452ac6d 100644 --- a/cmd/tools/gvgen.1 +++ b/cmd/tools/gvgen.1 @@ -1,4 +1,4 @@ -.TH GVGEN 1 "27 March 2008" +.TH GVGEN 1 "5 June 2012" .SH NAME gvgen \- generate graphs .SH SYNOPSIS @@ -7,6 +7,9 @@ gvgen \- generate graphs .B \-d? ] [ +.BI -i n +] +[ .BI -c n ] [ @@ -43,6 +46,9 @@ gvgen \- generate graphs .BI -r x,y ] [ +.BI -R x +] +[ .BI -s n ] [ @@ -139,6 +145,9 @@ Generate a random graph. The number of vertices will be the largest value of the form \fI2^n-1\fP less than or equal to \fIx\fP. Larger values of \fIy\fP increase the density of the graph. .TP +.BI \-R " x" +Generate a random rooted tree on \fIx\fP vertices. +.TP .BI \-s " n" Generate a star on \fIn\fP vertices. This will have \fIn-1\fP edges. @@ -169,6 +178,10 @@ the horizontal and vertical directions, respectively. Generate a path on \fIn\fP vertices. This will have \fIn-1\fP edges. .TP +.BI \-i " n" +Generate \fIn\fP graphs of the requested type. At present, only available if +the \fB-R\fP flag is used. +.TP .BI \-n " prefix" Normally, integers are used as node names. If \fIprefix\fP is specified, this will be prepended to the integer to create the name. diff --git a/cmd/tools/gvgen.c b/cmd/tools/gvgen.c index 705451237..08843424d 100644 --- a/cmd/tools/gvgen.c +++ b/cmd/tools/gvgen.c @@ -39,13 +39,14 @@ #include "graph_generator.h" typedef enum { unknown, grid, circle, complete, completeb, - path, tree, torus, cylinder, mobius, randomg, ball, + path, tree, torus, cylinder, mobius, randomg, randomt, ball, sierpinski, hypercube, star, wheel, trimesh } GraphType; typedef struct { int graphSize1; int graphSize2; + int cnt; int parm1; int parm2; int Verbose; @@ -86,6 +87,7 @@ static char *Usage = "Usage: %s [-dV?] [options]\n\ -k : complete \n\ -b : complete bipartite\n\ -B : ball\n\ + -i : generate random\n\ -m : triangular mesh\n\ -M : x by y Moebius strip\n\ -n : use in node names (\"\")\n\ @@ -93,6 +95,7 @@ static char *Usage = "Usage: %s [-dV?] [options]\n\ -o : put output in (stdout)\n\ -p : path \n\ -r, : random graph\n\ + -R : random rooted tree on vertices\n\ -s : star\n\ -S : sierpinski\n\ -t : binary tree \n\ @@ -137,6 +140,22 @@ static int readPos(char *s, char **e, int min) return d; } +/* readOne: + * Return non-zero on error. + */ +static int readOne(char *s, int* ip) +{ + int d; + char *next; + + d = readPos(s, &next, 1); + if (d > 0) { + *ip = d; + return 0; + } + else return d; +} + /* setOne: * Return non-zero on error. */ @@ -273,7 +292,7 @@ static char* setFold(char *s, opts_t* opts) return next; } -static char *optList = ":M:m:n:N:c:C:dg:G:h:k:b:B:o:p:r:s:S:t:T:Vw:"; +static char *optList = ":i:M:m:n:N:c:C:dg:G:h:k:b:B:o:p:r:R:s:S:t:T:Vw:"; static GraphType init(int argc, char *argv[], opts_t* opts) { @@ -340,6 +359,11 @@ static GraphType init(int argc, char *argv[], opts_t* opts) if (setTwo(optarg, opts)) errexit(c); break; + case 'R': + graphType = randomt; + if (setOne(optarg, opts)) + errexit(c); + break; case 'n': opts->pfx = optarg; break; @@ -374,6 +398,10 @@ static GraphType init(int argc, char *argv[], opts_t* opts) if (setTwoTwoOpt(optarg, opts, 0)) errexit(c); break; + case 'i': + if (readOne(optarg,&(opts->cnt))) + errexit(c); + break; case 'V': opts->Verbose = 1; break; @@ -422,6 +450,15 @@ static void undirfn (int t, int h) fprintf (opts.outfile, " %s%d\n", opts.pfx, t); } +static void +closeOpen () +{ + if (opts.directed) + fprintf(opts.outfile, "}\ndigraph {\n"); + else + fprintf(opts.outfile, "}\ngraph {\n"); +} + int main(int argc, char *argv[]) { GraphType graphType; @@ -429,6 +466,7 @@ int main(int argc, char *argv[]) opts.pfx = ""; opts.name = ""; + opts.cnt = 1; graphType = init(argc, argv, &opts); if (opts.directed) { fprintf(opts.outfile, "digraph {\n"); @@ -483,6 +521,18 @@ int main(int argc, char *argv[]) case randomg: makeRandom (opts.graphSize1, opts.graphSize2, ef); break; + case randomt: + { + int i; + treegen_t* tg = makeTreeGen (opts.graphSize1); + for (i = 1; i <= opts.cnt; i++) { + makeRandomTree (tg, ef); + if (i != opts.cnt) closeOpen (); + } + freeTreeGen (tg); + } + makeRandom (opts.graphSize1, opts.graphSize2, ef); + break; case completeb: makeCompleteB(opts.graphSize1, opts.graphSize2, ef); break;