]> granicus.if.org Git - graphviz/commitdiff
Add random rooted trees to gvgen
authorEmden Gansner <erg@research.att.com>
Tue, 5 Jun 2012 21:09:04 +0000 (17:09 -0400)
committerEmden Gansner <erg@research.att.com>
Tue, 5 Jun 2012 21:09:04 +0000 (17:09 -0400)
cmd/tools/graph_generator.c
cmd/tools/graph_generator.h
cmd/tools/gvgen.1
cmd/tools/gvgen.c

index 7d9079721221652d686f55e8e8b1977664a6438e..3fc9ef31b2b75fab55a7725362bd7c58c8c21540 100644 (file)
@@ -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);
+}
 
index 5f7e2ad337e07452c80a8060282ca53b115f429e..8f43adc106a9fd08bbcb6a3b36882ba2db1fec6e 100644 (file)
@@ -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
index c473a79cfda6bc99275123c4e4e8a82767c654d5..6d452ac6d781e7a118ddafe41246580dfc19105d 100644 (file)
@@ -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.
index 7054512370e9c03c9d2727b2dd319d4677ddc13d..08843424d6c34c9737ddc9c391b16a4c5d2af93c 100644 (file)
 #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<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\
@@ -93,6 +95,7 @@ static char *Usage = "Usage: %s [-dV?] [options]\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\
@@ -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;