Beispiel #1
0
static boolean
fromsort(FILE *f, char **cdstr, char **dstr, unsigned long *index)
/* read one graph from sort process */
{
        int j;
        char *s;

	if ((s = getline(f)) == NULL) return FALSE;

	*cdstr = s;
        for (j = 0; s[j] != ' ' && s[j] != '\t' && s[j] != '\n'; ++j) {}

        if (s[j] == ' ')
        {
	    s[j] = '\0';
	    *dstr = &s[j+1];
            for (++j; s[j] != '\t' && s[j] != '\n'; ++j) {}
        }
        else
            *dstr = NULL;

        if (s[j] == '\t')
        {
            if (sscanf(&s[j+1],"%lu",index) != 1)
                gt_abort(">E shortg: index field corrupted\n");
        }
        else
            *index = 0;
	s[j] = '\0';

        return TRUE;
}
Beispiel #2
0
void
writegre(FILE *f, graph *g, int n1, int n2)
/* write graph g (n1+n2 vertices) to file f in Greechie diagram format */
{
    static char atomname[] = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz!\"#$%&'()*-/:;<=>?@[\\]^_`{|}~";
    char grestr[MAXN*MAXN+MAXN+5];
    int i,j,k;
    setword gi;

    k = 0;
    for (i = n1; i < n1+n2; ++i)
    {
        if (i > n1) grestr[k++] = ',';
        gi = g[i];
        while (gi)
        {
            TAKEBIT(j,gi);
            grestr[k++] = atomname[j];
        }
    }
    grestr[k++] = '.';
    grestr[k++] = '\n';
    grestr[k] = '\0';
    if (fputs(grestr,f) == EOF || ferror(f))
    {
        fprintf(stderr,">E genbg : error on writing file\n");
        gt_abort(NULL);
    }
}
Beispiel #3
0
long
cyclecount(graph *g, int m, int n)
/* The total number of cycles in g (assumed no loops) */
{
    if (m == 1) return cyclecount1(g,n);

    gt_abort("cycle counting is only implemented for n <= WORDSIZE");
    return 0;
}
static int
trythisone(grouprec *group, int ne, int n)
{
    int i,k;
    boolean accept;

    first = TRUE;

    ADDBIG(ngen,1);
    nix = ne;
    newgroupsize = 1;

    if (!group || groupsize == 1)
	accept = TRUE;
    else if (lastrejok && !ismax(lastreject,n))
	accept = FALSE;
    else if (lastrejok && groupsize == 2)
	accept = TRUE;
    else
    {
	newgroupsize = 1;
	if (allgroup2(group,testmax) == 0)
	    accept = TRUE;
        else
	    accept = FALSE;
    }

    if (accept)
    {

#ifdef GROUPTEST
	if (groupsize % newgroupsize != 0)
			gt_abort("group size error\n");
	totallab += groupsize/newgroupsize;
#endif

	ADDBIG(nout,1);

	if (outfile)
	{
	    fprintf(outfile,"%d %ld",n,ne);
	    if (Gswitch) fprintf(outfile," %lu",newgroupsize);

            for (i = -1; (i = nextelement(x,me,i)) >= 0; )
	    {
	        k = i >> 1;
	        if (i & 1) fprintf(outfile," %d %d",v1[k],v0[k]);
	        else       fprintf(outfile," %d %d",v0[k],v1[k]);
	    }
            fprintf(outfile,"\n");
	}
        return MAXNE+1;
    }
    else
	return rejectlevel;
Beispiel #5
0
static pid_t
beginsort(FILE **sortin, FILE **sortout, char *tempdir,
          boolean vdswitch, boolean keep)
/* begin sort process, open streams for i/o to it, and return its pid */
{
    int pid;
    int inpipe[2],outpipe[2];

    if (pipe(inpipe) < 0 || pipe(outpipe) < 0)
        gt_abort(">E shortg: can't create pipes to sort process\n");

    if ((pid = fork()) < 0) gt_abort(">E shortg: can't fork\n");

    if (pid > 0)            /* parent */
    {
        close(inpipe[0]);
        close(outpipe[1]);
        if ((*sortin = fdopen(inpipe[1],"w")) == NULL)
            gt_abort(">E shortg: can't open stream to sort process\n");
        if ((*sortout = fdopen(outpipe[0],"r")) == NULL)
            gt_abort(">E shortg: can't open stream from sort process\n");
    }
    else                   /* child */
    {
        SET_C_COLLATION;

        close(inpipe[1]);
        close(outpipe[0]);
        if (dup2(inpipe[0],0) < 0 || dup2(outpipe[1],1) < 0)
            gt_abort(">E shortg: dup2 failed\n");

        if (tempdir == NULL)
        {
            if (vdswitch)
                if (keep) execlp(VSORTCOMMAND2,NULL);
                else      execlp(VSORTCOMMAND1,NULL);
            else
                execlp(SORTCOMMAND,NULL);
        }
        else
        {
            if (vdswitch)
                if (keep) execlp(VSORTCOMMANDT2,NULL);
                else      execlp(VSORTCOMMANDT1,NULL);
            else
                execlp(SORTCOMMANDT,NULL);
        }
        gt_abort(">E shortg: can't start sort process\n");
    }

    return pid;
}
Beispiel #6
0
void
write_ascii(FILE *f, graph *g, int n)
/* write tournament g (n vertices) to file f in ascii format */
{
	char s[MAXN*(MAXN-1)/2+2];
	int i,j;
	size_t k;

	k = 0;
	for (i = 0; i < n-1; ++i)
	    for (j = i+1; j < n; ++j)
		if ((g[i] & bit[j])) s[k++] = '1'; else s[k++] = '0';

	s[k++] = '\n';
	s[k] = '\0';

        if (fwrite(s,1,k,f) != k || ferror(f))
            gt_abort(">E write_ascii : error on writing\n");
}
Beispiel #7
0
static boolean
fromsort(FILE *f, char **cdstr, char **dstr, nauty_counter *index)
/* read one graph from sort process */
{
    int j;
    char *s;

    if ((s = gtools_getline(f)) == NULL) return FALSE;

    *cdstr = s;
    for (j = 0; s[j] != ' ' && s[j] != '\t' && s[j] != '\n'; ++j) {}

    if (s[j] == ' ')
    {
        s[j] = '\0';
        *dstr = &s[j+1];
        for (++j; s[j] != '\t' && s[j] != '\n'; ++j) {}
    }
    else
        *dstr = NULL;

    if (s[j] == '\t')
    {
#if LONG_LONG_COUNTERS
        if (sscanf(&s[j+1],"%llu",index) != 1)
#else
        if (sscanf(&s[j+1],"%lu",index) != 1)
#endif
            gt_abort(">E shortg: index field corrupted\n");
    }
    else
        *index = 0;
    s[j] = '\0';

    return TRUE;
}
Beispiel #8
0
static int
trythisone(grouprec *group, int ne, int n)
{
    int i,k;
    boolean accept;
#ifdef PROCESS
    graph g[WORDSIZE];
#endif

    first = TRUE;

    ++gd_ngen;
    nix = ne;
    newgroupsize = 1;
    ntgroup = FALSE;

    if (!group || groupsize == 1)
        accept = TRUE;
    else if (lastrejok && !ismax(lastreject,n))
        accept = FALSE;
    else if (lastrejok && groupsize == 2)
        accept = TRUE;
    else
    {
        newgroupsize = 1;
        ntgroup = FALSE;
        if (allgroup2(group,testmax) == 0)
            accept = TRUE;
        else
            accept = FALSE;
    }

    if (accept)
    {

#ifdef GROUPTEST
        if (groupsize % newgroupsize != 0)
                        gt_abort("group size error\n");
        totallab += groupsize/newgroupsize;
#endif

        if (Vswitch && !ntisol && !ntgroup) return MAXNE+1;

        ++dg_nout;

#ifdef PROCESS
	EMPTYSET(g,n);
	for (i = -1; (i = nextelement(x,me,i)) >= 0; )
        {
            k = i >> 1;
            if (i & 1) g[v1[k]] |= bit[v0[k]];
            else       g[v0[k]] |= bit[v1[k]];
        }
	PROCESS(outfile,g,n);
#endif

        if (outfile)
        {
            fprintf(outfile,"%d %d",n,ne);
            if (Gswitch) fprintf(outfile," %lu",newgroupsize);
    
            for (i = -1; (i = nextelement(x,me,i)) >= 0; )
            {
                k = i >> 1;
                if (i & 1) fprintf(outfile," %d %d",v1[k],v0[k]);
                else       fprintf(outfile," %d %d",v0[k],v1[k]);
            }
            fprintf(outfile,"\n");
        }
        return MAXNE+1;
    }
    else
        return rejectlevel;
Beispiel #9
0
static int
p4decomposition(sparsegraph sg, int vertex, boolean vertical)
/* Test which non-triangular P4s extend to a decomposition.
   Return -2: timeout
          -1: not decomposable at all
          >=0: number of P4s missed
   If 0 <= vertex < n, only P4s starting at that vertex are considered.
   If vertical (only for prisms), the central edge must be vertical.
   The paths missed can be found in p4list[].
*/
{
    int i,j,k,l,n,c;
    int ans,status;
    int imin,imax,nump4;
    int v1,v2,v3,v4,e1,e2,e3,j1,j2,j3;

    n = sg.nv;
    if (vertex >= n) gt_abort(">E vertex given to -t is too large");

    status = isdecomposable(sg,FALSE,FALSE);
    if (status == NO) return -1;
    else if (status == TIMEOUT) return -2;

    if (vertex >= 0)
    {
        imin = imax = vertex; 
        DYNALLOC1(p4,p4list,p4list_sz,36,"malloc");
    }
    else
    {
	imin = 0; imax = n-1;
        DYNALLOC1(p4,p4list,p4list_sz,18*n,"malloc");
    }

    nump4 = 0;
    for (v1 = imin; v1 <= imax; ++v1)
    for (j1 = 0; j1 < 4; ++j1)
    {
	v2 = sg.e[4*v1+j1];
	e1 = eno[4*v1+j1];
	for (j2 = 0; j2 < 4; ++j2)
	{
	    v3 = sg.e[4*v2+j2];
	    if (v3 == v1) continue;
	    if (vertical && (v2|1) != (v3|1)) continue;
	    e2 = eno[4*v2+j2];
	    for (j3 = 0; j3 < 4; ++j3)
	    {
		v4 = sg.e[4*v3+j3];
		if (v4 == v1 || v4 == v2) continue;
		e3 = eno[4*v3+j3];
		if (vertex >= 0 || v1 < v4)
		{
		    p4list[nump4].v1 = v1;
		    p4list[nump4].v2 = v2;
		    p4list[nump4].v3 = v3;
		    p4list[nump4].v4 = v4;
		    p4list[nump4].e1 = e1;
		    p4list[nump4].e2 = e2;
		    p4list[nump4].e3 = e3;
		    p4list[nump4].ok = FALSE;
		    ++nump4;
		}
	    }
	}
    }

    for (i = 0; i < nump4; ++i)
        if (colour[p4list[i].e1] == colour[p4list[i].e2] &&
	    colour[p4list[i].e1] == colour[p4list[i].e3])
	    p4list[i].ok = TRUE;

    for (i = 0; i < nump4; ++i)
        if (!p4list[i].ok)
	{
	    initialise_colouring(n);
	    if (makeblue(p4list[i].e1,FALSE) &&
	        makeblue(p4list[i].e2,n==2) &&
		makeblue(p4list[i].e3,n==3))
	    {
		status = dispatchsearch(n,sg.e,3,0);
		if (status == TIMEOUT) return -2;
		if (status == YES)
		{
    		    for (k = 0; k < nump4; ++k)
    		    {
			if (p4list[k].ok) continue;
			if (colour[p4list[k].e1] == colour[p4list[k].e2]
                         && colour[p4list[k].e1] == colour[p4list[k].e3])
                           p4list[k].ok = TRUE;
                    }
		}
	    }
	}

    ans = 0;
    for (i = 0; i < nump4; ++i) if (!p4list[i].ok) ++ans;

    return ans;
}
Beispiel #10
0
static int
iscrossdecomposable(sparsegraph sg, int vertex)
/* Test if sg is decomposable as two hamiltonian cycles
   in all ways through each vertex (or the given vertex if it
   is >= 0.  Details left in cross[].
   Return -1: not decomposable at all
           0: misses some 2-paths including two at some vertices
           1: misses some 2-paths but at most one per vertex
           2: fully decomposable
           3: timeout
*/
{
    int i,j,k,l,n,c;
    int ans,status;
    int imin,imax;

    n = sg.nv;
    DYNALLOC1(int,cross,cross_sz,4*n,"malloc");

    if (vertex >= n) gt_abort(">E vertex given to -t is too large");

    for (i = 0; i < 4*n; ++i) cross[i] = 0;

    status = isdecomposable(sg,FALSE,FALSE);
    if (status == NO) return -1;
    else if (status == TIMEOUT) return 3;

    for (i = 0; i < n; ++i)
    {
	c = colour[eno[4*i]];
	for (j = 1; j < 4; ++j)
	    if (colour[eno[4*i+j]] == c) cross[4*i+j] = 1;
    }

    ans = 2;

    if (vertex >= 0) { imin = imax = vertex; }
    else             { imin = 0; imax = n-1; }

    for (i = imin; i <= imax; ++i)
    for (j = 1; j < 4; ++j)
        if (!cross[4*i+j])
	{
	    initialise_colouring(n);
	    if (makeblue(eno[4*i],FALSE) && makeblue(eno[4*i+j],n==2))
	    {
		status = dispatchsearch(n,sg.e,2,0);
		if (status == TIMEOUT) return 3;
		if (status == YES)
		{
    		    for (k = 0; k < n; ++k)
    		    {
		        c = colour[eno[4*k]];
		        for (l = 1; l < 4; ++l)
	                if (colour[eno[4*k+l]] == c) cross[4*k+l] = 1;
                    }
		}
		else
		    ans = 1;
	    }
	    else
	        ans = 1;
	}

    if (ans == 1)
        for (i = 0; i < n; ++i)
	{
	    if (cross[4*i+1] + cross[4*i+2] + cross[4*i+3] <= 1)
		ans = 0;
	}

    return ans;
}
Beispiel #11
0
static void
initialise_g(int n, int *e)
/* Allocate all and initialise eno[],v1[],v2[]
   e is a vector like sg.e */
{
    int ne,i,j,k,l;
 
    DYNALLOC1(addrval,valstack,valstack_sz,10*n,"malloc");
    DYNALLOC1(int,bluefarend,bluefarend_sz,n,"malloc");
    DYNALLOC1(int,redfarend,redfarend_sz,n,"malloc");
    DYNALLOC1(int,eno,eno_sz,4*n,"malloc"); 
    DYNALLOC1(int,v1,v1_sz,2*n,"malloc");
    DYNALLOC1(int,v2,v2_sz,2*n,"malloc");
    DYNALLOC1(int,colour,colour_sz,2*n,"malloc");
    DYNALLOC1(int,bluedeg,bluedeg_sz,n,"malloc");
    DYNALLOC1(int,reddeg,reddeg_sz,n,"malloc");
    DYNALLOC1(int,vstack,vstack_sz,n,"malloc");
    DYNALLOC1(boolean,onstack,onstack_sz,n,"malloc");
    DYNALLOC1(int,beste,beste_sz,2*n,"malloc");

  /* Randomize e; seems to be no purpose for this any more. */

    for (i = 0; i < n; ++i)
    {
	j = KRAN(4);
	k = e[4*i+j]; e[4*i+j] = e[4*i+3]; e[4*i+3] = k; 
	j = KRAN(3);
	k = e[4*i+j]; e[4*i+j] = e[4*i+2]; e[4*i+2] = k;
	j = KRAN(2);
	k = e[4*i+j]; e[4*i+j] = e[4*i+1]; e[4*i+1] = k;
    }

    ne = 0;
    for (i = 0; i < n; ++i)
    {
	for (j = 0; j < 4; ++j)
	{
	    k = e[4*i+j];
	    if (k > i)
	    {
		v1[ne] = i;
		v2[ne] = k;
		eno[4*i+j] = ne++;
            }
	    else    /* Note: this code assumes a simple graph */
	    {
		for (l = 0; l < 4; ++l)
		    if (e[4*k+l] == i) break;
		eno[4*i+j] = eno[4*k+l];
	    }
	}
    }
    if (ne != 2*n) gt_abort(">E ne is incorrect");

#if DEBUG
    { int ii;
        printf("===== n=%d === ne=%d ===================\n",n,ne);
    
        for (ii = 0; ii < n; ++ii)
	    printf("%2d: %2d %2d %2d %2d    %2d %2d %2d %2d\n",
	       ii,e[4*ii],e[4*ii+1],e[4*ii+2],e[4*ii+3],
                  eno[4*ii],eno[4*ii+1],eno[4*ii+2],eno[4*ii+3]);
    }
#endif
}
Beispiel #12
0
int
main(int argc, char *argv[])
{
    FILE *infile;
    int j;
    SG_DECL(g);
    size_t flen;
    boolean ispipe;
    char zcmd[515];

    HELP;

    if (argc == 1)
    {
	if (!readblissgraph(stdin,&g))
	{
	    fprintf(stderr,">E Bliss error in file %s\n","stdin");
	    gt_abort(NULL);
	}
	else
	    writes6_sg(stdout,&g);
    }
    else
    {
        for (j = 1; j < argc; ++j)
	{
	    flen = strlen(argv[j]);
            if (flen >= 3 && strcmp(argv[j]+flen-3,".gz") == 0)
            {
                sprintf(zcmd,"%s \"%s\"",ZCAT,argv[j]);
                if ((infile = popen(zcmd,"r")) == NULL)
                {
                    fprintf(stderr,
                         ">E blisstog: cannot open zcat pipe for \"%s\"\n",
                         argv[j]);
                    gt_abort(NULL);
                }
		ispipe = TRUE;
            }
            else
            {
	        if ((infile = fopen(argv[j],"r")) == NULL)
	        {
	            fprintf(stderr,">E Can't open file %s\n",argv[j]);
		    gt_abort(NULL);
	        }
		ispipe = FALSE;
	    }

	    if (!readblissgraph(infile,&g))
	    {
	        fprintf(stderr,">E Bliss error in file %s\n",argv[j]);
		gt_abort(NULL);
	    }
	    else
	        writes6_sg(stdout,&g);

	    if (ispipe) pclose(infile); else fclose(infile);
        }
    }

    exit(0);
}    
Beispiel #13
0
static void
trythisone(grouprec *group,
       boolean lswitch, int *deg, int maxdeg, int ne, int n)
/* Try one solution, accept if minimal. */
{
    int i,ne2;
    boolean accept;

    nix = ne;
    newgroupsize = 1;

    if (!group || groupsize == 1)
        accept = TRUE;
    else if (lastrejok && !ismax(lastreject,n))
        accept = FALSE;
    else if (lastrejok && groupsize == 2)
        accept = TRUE;
    else
    {
        newgroupsize = 1;
        first = TRUE;

        if (allgroup2(group,testmax) == 0)
            accept = TRUE;
        else
            accept = FALSE;
    }

    if (accept)
    {
#ifdef GROUPTEST
        if (groupsize % newgroupsize != 0)
                    gt_abort("group size error\n");
        totallab += groupsize/newgroupsize;
#endif

        ++mg_nout;

        if (outfile)
        {
            ne2 = ne;
            if (lswitch)
                for (i = 0; i < n; ++i)
                    if (deg[i] < maxdeg)
                    {
                        v0[ne2] = v1[ne2] = i;
                        ix[ne2] = (maxdeg-deg[i])/2;
                        ++ne2;
                    }
#ifdef OUTPROC
            OUTPROC(outfile,n,ne2,newgroupsize,v0,v1,ix);
#else
            if (Aswitch || Bswitch)
                printam(outfile,n,ne2,ix);
            else
            {
                fprintf(outfile,"%d %d",n,ne2);
                if (Gswitch) fprintf(outfile," %lu",newgroupsize);
    
                for (i = 0; i < ne2; ++i)
                    fprintf(outfile," %d %d %d",v0[i],v1[i],ix[i]);
                fprintf(outfile,"\n");
            }
#endif
        }
        return;
    }
    else
        return;
}
Beispiel #14
0
static void
subdivisiongraph(sparsegraph *g, int k, sparsegraph *h)
/* h := subdivision graph of g, k new vertices per edge */
{
    DYNALLSTAT(size_t,eno,eno_sz);   /* edge number */
    int *ge,*gd,*he,*hd;
    size_t *gv,*hv;
    int gnv,hnv;
    size_t i,j,l,gnde,hnde,num;
    size_t hi,lo,mid,w;

    if (k == 0)
    {
	copy_sg(g,h);
	return;
    }

    sortlists_sg(g);
    SG_VDE(g,gv,gd,ge);
    gnv = g->nv;
    gnde = g->nde;
    DYNALLOC1(size_t,eno,eno_sz,gnde,"subdivideg");

    hnv = gnv + k*(gnde/2);
    if (hnv <= 0 || (gnde > 0 && ((size_t)(hnv-gnv))/(gnde/2) != k))
        gt_abort(">E subdivideg: output graph too large\n");
    hnde = gnde * (k+1);
    if (hnde/(k+1) != gnde)
        gt_abort(">E subdivideg: output graph too large\n");

    num = 0;
    for (i = 0; i < gnv; ++i)
    {
        for (j = gv[i]; j < gv[i]+gd[i]; ++j)
        {
            if (ge[j] == i)
                gt_abort(">E subdivideg can't handle undirected loops\n");
            else if (ge[j] > i)
                eno[j] = num++;
            else
            {
                lo = gv[ge[j]];
                hi = lo + gd[ge[j]] - 1;
                while (lo <= hi)
                {
                    mid = lo + (hi-lo)/2;
                    if (ge[mid] == i) break;
                    else if  (ge[mid] < i) lo = mid+1;
                    else hi = mid-1;
                }
		if (lo > hi)
		    gt_abort(">E subdivideg : binary search failed\n");
                eno[j] = eno[mid];
            }
        }
    }

    SG_ALLOC(*h,hnv,hnde,"subdivideg");
    h->nv = hnv;
    h->nde = hnde;
    SG_VDE(h,hv,hd,he);

    for (i = 0; i < gnv; ++i)
    {
        hd[i] = gd[i];
        hv[i] = gv[i];
    }
    for (i = gnv; i < hnv; ++i)
    {
	hd[i] = 2;
        hv[i] = gnde + 2*(i-gnv);
    }

    for (i = 0; i < gnv; ++i)
    {
        for (j = gv[i]; j < gv[i]+gd[i]; ++j)
            if (ge[j] > i)
	    {
		w = gnv + k*eno[j];
		he[j] = w;
		he[hv[w]] = i;
		for (l = 1; l < k; ++l)
		{
		    he[hv[w]+1] = w+1;
		    he[hv[w+1]] = w;
		    ++w;
		}
	    }
	    else
	    {
		w = gnv + k*eno[j] + k - 1;
		he[j] = w;
		he[hv[w]+1] = i;
	    }
    }
}
Beispiel #15
0
static void
linegraph(sparsegraph *g, sparsegraph *h)
/* h := linegraph of g */
{
    DYNALLSTAT(size_t,eno,eno_sz);   /* edge number */
    int *ge,*gd,*he,*hd;
    size_t *gv,*hv;
    int gnv,hnv;
    size_t i,j,k,gnde,hnde,xhnde,num;
    size_t hi,lo,mid,v,w;

    sortlists_sg(g);
    SG_VDE(g,gv,gd,ge);
    gnv = g->nv;
    gnde = g->nde;
    DYNALLOC1(size_t,eno,eno_sz,gnde,"linegraphg");

    hnv = gnde/2;
    if (hnv != gnde/2) gt_abort(">E linegraphg: too many input edges\n");

    hnde = 0;
    num = 0;
    for (i = 0; i < gnv; ++i)
    {
        xhnde = hnde;
        hnde += gd[i]*((size_t)gd[i]-1);
        if (hnde < xhnde) gt_abort(">E linegraphg: too many output edges\n");

        for (j = gv[i]; j < gv[i]+gd[i]; ++j)
        {
            if (ge[j] == i)
                gt_abort(">E linegraphg can't handle loops\n");
            else if (ge[j] > i)
                eno[j] = num++;
            else
            {
                lo = gv[ge[j]];
                hi = lo + gd[ge[j]] - 1;
                while (lo <= hi)
                {
                    mid = lo + (hi-lo)/2;
                    if (ge[mid] == i) break;
                    else if  (ge[mid] < i) lo = mid+1;
                    else hi = mid-1;
                }
		if (lo > hi)
		    gt_abort(">E linegraphg : binary search failed\n");
                eno[j] = eno[mid];
            }
        }
    }

    SG_ALLOC(*h,hnv,hnde,"linegraphg");
    h->nv = hnv;
    h->nde = hnde;
    SG_VDE(h,hv,hd,he);

    for (i = 0; i < hnv; ++i) hd[i] = 0;
    for (i = 0; i < gnv; ++i)
    {
        for (j = gv[i]; j < gv[i]+gd[i]; ++j)
            hd[eno[j]] += gd[i]-1;
    }

    hv[0] = 0;
    for (i = 1; i < hnv; ++i) hv[i] = hv[i-1] + hd[i-1];
    for (i = 0; i < hnv; ++i) hd[i] = 0;

    for (i = 0; i < gnv; ++i)
    {
        for (j = gv[i]; j < gv[i]+gd[i]-1; ++j)
        for (k = j+1; k < gv[i]+gd[i]; ++k)
        {
            v = eno[j]; w = eno[k];
            he[hv[v]+(hd[v]++)] = w;
            he[hv[w]+(hd[w]++)] = v;
        }
    }
}