}
-#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)
{
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);
+}
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
-.TH GVGEN 1 "27 March 2008"
+.TH GVGEN 1 "5 June 2012"
.SH NAME
gvgen \- generate graphs
.SH SYNOPSIS
.B \-d?
]
[
+.BI -i n
+]
+[
.BI -c n
]
[
.BI -r x,y
]
[
+.BI -R x
+]
+[
.BI -s n
]
[
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.
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.
#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;
-k<x> : complete \n\
-b<x,y> : complete bipartite\n\
-B<x,y> : ball\n\
+ -i<n> : generate <n> random\n\
-m<x> : triangular mesh\n\
-M<x,y> : x by y Moebius strip\n\
-n<prefix> : use <prefix> in node names (\"\")\n\
-o<outfile> : put output in <outfile> (stdout)\n\
-p<x> : path \n\
-r<x>,<n> : random graph\n\
+ -R<n> : random rooted tree on <n> vertices\n\
-s<x> : star\n\
-S<x> : sierpinski\n\
-t<x> : binary tree \n\
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.
*/
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)
{
if (setTwo(optarg, opts))
errexit(c);
break;
+ case 'R':
+ graphType = randomt;
+ if (setOne(optarg, opts))
+ errexit(c);
+ break;
case 'n':
opts->pfx = optarg;
break;
if (setTwoTwoOpt(optarg, opts, 0))
errexit(c);
break;
+ case 'i':
+ if (readOne(optarg,&(opts->cnt)))
+ errexit(c);
+ break;
case 'V':
opts->Verbose = 1;
break;
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;
opts.pfx = "";
opts.name = "";
+ opts.cnt = 1;
graphType = init(argc, argv, &opts);
if (opts.directed) {
fprintf(opts.outfile, "digraph {\n");
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;