/* cubhamg.c : pick those inputs that are nonhamiltonian and
                have max degree <= 3.

 Usage:
cubhamg [-#] [-v|-V] [-n#-#|-y#-#|-i|-I|-o|-x|-e|-E] [-b|-t] [infile [outfile]]

        infile is the name of the input file in graph6/sparse6 format
        outfile is the name of the output file in the same format

	stdin and stdout are the defaults for infile and outfile

	The output file will have a header >>graph6<< or >>sparse6<<
        if and only if the input file does.

        Optional switches:

        -#  A parameter useful for tuning (default 100)
	-v  Report nonhamiltonian graphs and noncubic graphs
	-V  .. in addition give a cycle for the hamiltonian ones
	-n#-#  If the two numbers are v and i, then the i-th edge
	    out of vertex v is required to be not in the cycle.
	    It must be that i=1..3 and v=0..n-1.
	-y#-#  If the two numbers are v and i, then the i-th edge
	    out of vertex v is required to be in the cycle.
	    It must be that i=1..3 and v=0..n-1.
            You can use any number of -n/-y switches to force
            edges.  Out of range first arguments are ignored.
            If -y and -n give same edge, -y wins.
        -i  Test + property: for each edge e, there is a hamiltonian
            cycle using e.
	-I  Test ++ property: for each pair of edges e,e', there is
            a hamiltonian cycle which uses both e and e'.
        -o  Test - property: for each edge e, there is a hamiltonian 
            cycle avoiding e.
        -x  Test +- property: for each pair of edges e,e', there is
            a hamiltonian cycle which uses e but avoids e'.
        -e  Test 3/4 property: for each edge e, at least 3 of the 4
            paths of length 3 passing through e lie on hamiltonian cycles.
        -E  Test 3/4+ property: for each edge e failing the 3/4 property,
            all three ways of joining e to the rest of the graph are
            hamiltonian avoiding e.
        -T# Specify a timeout, being a limit on how many search tree
            nodes are made.  If the timeout occurs, the graph is 
            written to the output as if it is nonhamiltonian.
        -R# Specify the number of repeat attempts for each stage.
        -F  Analyze covering paths from 2 or 4 vertices of degree 2.

	-b  Require biconnectivity
        -t  Require triconnectivity  (note: quadratic algorithm)

        -y, -n, -#, -R and -T are ignored for -i, -I, -x, -o, -e, -E, -F

	B. D. McKay, Nov 1995 + Aug 1996 + Feb 2002 + Jul 2008 + Nov 2015

**************************************************************************/

#ifndef MAXN
#define MAXN 30002  /* 2 more than largest graph size! */
#endif

#if MAXN==0
#error MAXN cannot be zero for cubhamg
#endif

#include "gtools.h" 
#include "naurng.h"

/**************************************************************************/

#define RANPERM TRUE

/* cubham.h */

#define MAXNE ((3 * MAXN) / 2)
#define FALSE 0
#define TRUE 1
#define YES 1
#define DUNNO 0
#define NO (-1)
#define HABORT 5

#define BADLIM 100  /* limit on number of bad things to report per graph */
#define MAXA  100   /* max number of -y or -n switches */

typedef int cubgraph[MAXN][4];
typedef int vertvec[MAXN];
typedef int edgevec[MAXNE+1];
static long nodecount,maxnodes,totalnodes;
static long timeout;
static long repeats;
static int verbose;

#define NO_LIMIT 0x7FFFFFFFL

static long standard[]
  = {30,40,50,60,100,200,300,400,500,1000,2000,3000,5000,
     10000,20000,30000,100000,300000,1000000};
#define NUMMAXNODES (sizeof(standard)/sizeof(long))
static nauty_counter numtries[NUMMAXNODES+1];

/* cubham.c */

/***************************************************************************

        *****   Instructions for using cubham.  *****

    cubham can find hamiltonian cycles in graphs of maximum 
    degree at most 3, with specifed edges either required or forbidden.  
    To use it:

    (1) Check that MAXN (defined in cubham.h) is at least equal to the
    number of vertices.

    (2) #include cubham.h.

    (3) The cubic graph must be stored in an object of type cubgraph.  Say
    you call it g.  The vertices are numbered 0,1,..., and the neighbours of
    vertex i are g[i][0], g[i][1] and g[i][2].  Entries of the form g[i][3]
    are unused.  If the degree is less than 3, -1 is used as padding.

    (4) Call   cubinit(g,eno,v1,v2,nv,&ne), where
        g     = the cubic graph                         (input)
        eno   = another object of type cubgraph         (output)
        v1,v2 = objects of type edgevec                 (output)
        nv    = the number of vertices                  (input)
	ne    = the number of edges                     (output)

    This numbers the edges 0,1,...ne-1, and defines
        eno[i][j]      = the number of the edge {i, g[i][j]}
        {v1[j], v2[j]} = the vertices of the j-th edge.

    (5) Call  cubham(g,eno,initclass,v1,v2,cycle,outclass,nv,ne), where
        g,eno,v1,v2,nv = as above                       (input)
        initclass = initial edge classification         (input)
        outclass = final edge classifiction             (output)
        cycle = the hamiltonian cycle found, if any     (output)

    The value returned by cubham is either YES (hamiltonian cycle found)
        or NO (there isn't any).

    The initial edge classification is specified by you in the edgevec
    initclass[].  For each edge j, (0 <= j < 3*nv/2), set
    initclass[j] = NO, YES or DUNNO, if edge j must not be in the cycle,
    must be in the cycle, or don't care, respectively.  Passing NULL as
    the initclass parameter is equivalent to setting each edge to DUNNO.
    All initial classifications are legal, even those clearly impossible.

    The final edge classification is set by cubham in the edgevec
    outclass[], if a hamiltonian cycle is found.  Each entry should be
    either NO or YES.  No final classification is provided if NULL is passed
    as the outclass parameter.

    The hamiltonian cycle itself, if any, is returned as cycle[0], cycle[1],
    ..., cycle[nv-1], cycle[0].  If the cycle is not needed, you can pass
    NULL for this parameter.

    Step (4) need not be repeated if the same graph is processed again with
    a different initial classification.

****************************************************************************/

#define POP(x) (onstack[x = *(--stackptr)] = 0)
#define PUSH(x) if(onstack[x]!=stacklev){onstack[x]=stacklev;*(stackptr++)=x;}
#define RESETSTACK {stacklev++; stackptr = stack;}

typedef struct
{
    edgevec class;
    vertvec din,dout,farend;
} nodedata;

static nodedata hcnodat;
static cubgraph eno;
static vertvec onstack,stack;       /* stack contains vertex numbers */
static int *stackptr,stacklev;      /* stackptr points above top */
static int classstack[4*MAXNE];      /* stack of classifications */
   /* x >= 0        : edge number
     (x < 0 above y : farend[-x-1] = y  */
static int *classstackptr;       /* points above top of classstack */
static int classout(cubgraph,nodedata*,int,int,int);
static int classin(cubgraph,cubgraph,nodedata*,int,int,int,int*,int);

#define MAXES 0

#if MAXES
static int maxlevel,maxclassstack;
#endif

static void
dummy(void)
{
}

static void
check_it(int index, cubgraph g, cubgraph eno, edgevec v1, edgevec v2,
         int *din, int *dout, int *class, int *farend, int nin, int nv,
         int stable)
/* Check some things */
{
    int xdin[MAXN],xdout[MAXN],xnin,v,i,j,k,l,*gv,xin,xout,has1;

    for (i = 0; i < nv; ++i) xdin[i] = xdout[i] = 0;
    xnin = has1 = 0;

    for (v = 0; v < nv; ++v)
    {
	gv = g[v];
	xin = xout = 0;
	for (i = 0; i < 3; ++i)
	    if (gv[i] >= 0)
	    {
		j = eno[v][i];
		if (class[j] == NO) ++xout;
		if (class[j] == YES) ++xin;
	    }
	if (xout != dout[v] || xin != din[v])
	{
	    fprintf(stderr,">E%d degrees of %d: din,dout=%d,%d really %d,%d\n",
			index,v,din[v],dout[v],xin,xout);
	    dummy();
	}
	if (xin == 1) ++has1;
	xnin += xin;
    }

    xnin /= 2;
    if (xnin != nin)
    {
        fprintf(stderr,">E%d nin=%d actually %d\n",index,nin,xnin);
        dummy();
    }
    if (nin != 0 && !has1)
    {
        fprintf(stderr,">E%d nin=%d has no in=1\n",index,nin);
        dummy();
    }

    for (i = 0; i < nv; ++i)
	if (din[i] == 0)
	{
            if (farend[i] != i)
    	    {
        	fprintf(stderr,">E%d farend[isolate %d]=%d\n",
			index,i,farend[i]);
        	dummy();
	    }
	}
	else if (din[i] == 1)
	{
	    k = -1;
	    j = i;
	    do
	    {
	        for (l = 0; l < 3; ++l)
		    if (g[j][l] >= 0 && g[j][l] != k && class[eno[j][l]] == YES)
			break;
		k = j;
		if (l < 3) j = g[j][l];
	    } while (l < 3);
            if (farend[i] != j)
    	    {
        	fprintf(stderr,">E%d farend[%d]=%d really %d\n",
			index,i,farend[i],j);
        	dummy();
	    }
        }

    if (stable)
	for (i = 0; i < nv; ++i)
	    if ((dout[i] == 1 && din[i] != 2) || (din[i] == 2 && dout[i] != 1)
		|| dout[i] > 1 || din[i] > 2)
	    {
		fprintf(stderr,">E%d din[%d]=%d dout[%d]=%d\n",
		        index,i,din[i],i,dout[i]);
		dummy();
	    }
}

static void
cubinit(cubgraph g, cubgraph eno, edgevec v1, edgevec v2, int nv, int ne)
/* initialise edge numbers, etc. */
{
        int *gpx,*gpy,*enop,x,y,i,j,n,en;

        n = nv;
        en = 0;
        for (x = 0; x < n; ++x)
        {
            gpx = g[x];
            enop = eno[x];
            for (i = 0; i < 3; ++i)
                if ((y = gpx[i]) < 0)
		    enop[i] = ne;
		else if (y > x)
                {
                    v1[en] = x;
                    v2[en] = y;
                    enop[i] = en++;
                }
                else
                {
                    gpy = g[y];
                    for (j = 0; gpy[j] != x; j++)
                        {}
                    enop[i] = eno[y][j];
                }
        }

        if (en != ne)
            fprintf(stderr,"%% cubinit got en=%d when ne=%d\n",en,ne);
}

static int
propagate(cubgraph g, cubgraph eno, nodedata *ndptr, int *nin, int nv)
/* propagate classifications: */
/*   ans = YES, NO or DUNNO */
{
        int v,w,i,status;
        nodedata *np;
        int *gp,*enop,*class,*din,*dout;

        status = DUNNO;
        np = ndptr;
        class = np->class;
        din = np->din;
        dout = np->dout;

        while (status == DUNNO && stackptr > stack)
        {
            POP(v);
            gp = g[v];
            enop = eno[v];
            if (dout[v] == 0)
            {
                if (din[v] == 2)
                {
                    if (class[enop[0]] == DUNNO)      i = 0;
                    else if (class[enop[1]] == DUNNO) i = 1;
                    else                              i = 2;
                    w = gp[i];
                    status = classout(g,np,v,w,enop[i]);
                    PUSH(w);
                }
                else if (din[v] == 3)
                    status = NO;
            }
            else if (dout[v] == 1)
            {
                for (i = 0; i < 3; ++i)
                if (class[enop[i]] == DUNNO)
                {
                    w = gp[i];
                    if ((status = classin(g,eno,np,v,w,enop[i],nin,nv))
                                                                 != DUNNO)
                        break;
                    else
                        PUSH(w);
                }
            }
            else
                status = NO;
        }

        if (status != NO && *nin == nv) return YES;
        else			        return status;
}

static int
classout(cubgraph g, nodedata *nodat, int v, int w, int en) 
/* classify edge en = vw out */
{
        nodedata *np;

        np = nodat;
        ++np->dout[v];
        ++np->dout[w];
        np->class[en] = NO;
	*classstackptr++ = en;
#if MAXES
	if (classstackptr-classstack > maxclassstack)
	    maxclassstack = classstackptr-classstack;
#endif

        return DUNNO;
}

static int
classin(cubgraph g, cubgraph eno, nodedata *nodat,
                                    int v, int w, int en, int *nin, int nv)
/* classify edge en = vw in */
{
        nodedata *np;
        int *farend,*gp,fv,fw,i;

        np = nodat;
        ++np->din[v];
        ++np->din[w];
        np->class[en] = YES;
	*classstackptr++ = en; 
#if MAXES
	if (classstackptr-classstack > maxclassstack)
	    maxclassstack = classstackptr-classstack;
#endif

        ++*nin;
        if (*nin == nv)
	{
	    return DUNNO;
	}

        farend = np->farend;
        fv = farend[v];
        fw = farend[w];
	*classstackptr++ = farend[fv];
	*classstackptr++ = -fv-1;
	*classstackptr++ = farend[fw];
	*classstackptr++ = -fw-1;
#if MAXES
	if (classstackptr-classstack > maxclassstack)
	    maxclassstack = classstackptr-classstack;
#endif
        farend[fv] = fw;
        farend[fw] = fv;

        gp = g[fv];
        if      (gp[0] == fw) i = 0;
        else if (gp[1] == fw) i = 1;
        else if (gp[2] == fw) i = 2;
        else                  return DUNNO;

        i = eno[fv][i];
        if (np->class[i] == DUNNO)
        {
            PUSH(fv);
            PUSH(fw);
            if (*nin == nv - 1)
                return classin(g,eno,np,fv,fw,i,nin,nv);
            else
                return classout(g,np,fv,fw,i);
        }

        return DUNNO;
}

static int
hamnode(cubgraph g, cubgraph eno, edgevec v1, edgevec v2,
	nodedata *nodat, int level, int nin, int nv)
/* main node for recursion */
{
        int i,p,q,status;
        int v,w,en,*gv,*enov;
	int *csptr;

#if MAXES
	if (level > maxlevel) maxlevel = level;
#endif

        if (++nodecount > maxnodes && maxnodes != NO_LIMIT) return HABORT;
        status = propagate(g,eno,nodat,&nin,nv);

        if (status != DUNNO) return status;

        for (v = nv; --v >= 0;)
            if (nodat->din[v] == 1) break;

        if (v < 0) v = 0;

        gv = g[v];
        enov = eno[v];

        for (i = 0; i < 3; ++i)
        {
            en = enov[i];
            if (nodat->class[en] == DUNNO)
            {
                w = gv[i];
                csptr = classstackptr;
                status = classout(g,nodat,v,w,en);
                if (status == YES) break;
	 	if (status == NO)
		{
		    while (classstackptr > csptr)
		    {
			p = *--classstackptr;
			if (p >= 0)
			{
			    if (nodat->class[p] == YES)
			    {
				--nodat->din[v1[p]];
				--nodat->din[v2[p]];
			    }
			    else
			    {
				--nodat->dout[v1[p]];
				--nodat->dout[v2[p]];
			    }
			    nodat->class[p] = DUNNO;
			}
			else
			{
			    q = *--classstackptr;
			    nodat->farend[-p-1] = q;
			}
		    }
                    continue;
		}
                RESETSTACK;
                PUSH(v);
                PUSH(w);
                status = hamnode(g,eno,v1,v2,nodat,level+1,nin,nv);
                if (status == YES) break;
		while (classstackptr > csptr)
		{
		    p = *--classstackptr;
		    if (p >= 0)
		    {
		        if (nodat->class[p] == YES)
		        {
		    	    --nodat->din[v1[p]];
		    	    --nodat->din[v2[p]];
		        }
		        else
		        {
		    	    --nodat->dout[v1[p]];
		    	    --nodat->dout[v2[p]];
		        }
		        nodat->class[p] = DUNNO;
		    }
		    else
		    {
			q = *--classstackptr;
			nodat->farend[-p-1] = q;
		    }
		}
                if (status == HABORT) return HABORT;
            }
        }

        if (status == DUNNO)
            fprintf(stderr,"hamnode returning DUNNO, this can't happen\n");
        return status;
}

static int
cubham(cubgraph g, cubgraph eno, edgevec initclass, edgevec v1, edgevec v2,
       vertvec cycle, edgevec outclass, int nv, int ne) 
/* external interface */
{
        int i,j,status,nin,v,w;

        for (i = ne; --i >= 0;)
            hcnodat.class[i] = DUNNO;
	if (3*nv > 2*ne) hcnodat.class[ne] = NO;

        for (i = nv; --i >= 0;)
        {
            hcnodat.din[i] = hcnodat.dout[i] = 0;
            hcnodat.farend[i] = i;
            onstack[i] = 0;
        }
        nin = 0;
        stacklev = 0;
        RESETSTACK;

	for (i = nv; --i >= 0;)
	{
	    if (g[i][1] < 0) return NO;
	    if (g[i][2] < 0)
	    {
		hcnodat.dout[i] = 1;
		PUSH(i);
	    }
	}

        status = DUNNO;
	classstackptr = classstack;
        if (initclass)
            for (i = 0; i < ne; ++i)
                if (initclass[i] != DUNNO)
                {
                    v = v1[i];
                    w = v2[i];
                    if (initclass[i] == NO)
                    {
                        if (hcnodat.class[i] == YES)
                            status = NO;
                        else if (hcnodat.class[i] == DUNNO)
                        {
                            if (hcnodat.dout[v] == 0)
                            {
                                status = classout(g,&hcnodat,v,w,i);
                                PUSH(v);
                                PUSH(w);
                            }
                            else
                                status = NO;
			}
                    }
                    else if (initclass[i] == YES)
                    {
                        if (hcnodat.class[i] == NO)
                            status = NO;
                        else if (hcnodat.class[i] == DUNNO)
			{
                            if (hcnodat.din[v] < 2)
                            {
                                status = classin(g,eno,&hcnodat,v,w,i,&nin,nv);
                                PUSH(v);
                                PUSH(w);
                            }
                            else
                                status = NO;
			}
                    }

                    if (status != DUNNO) break;
                }

        if (status == DUNNO)
            status = hamnode(g,eno,v1,v2,&hcnodat,0,nin,nv);

        if (status == YES && cycle)
        {
            w = -1;
            v = 0;
            cycle[0] = 0;
            for (i = 1; i < nv; ++i)
            {
                for (j = 0; g[v][j] == w || hcnodat.class[eno[v][j]] != YES; ++j)
                    {}
                w = v;
                v = g[v][j];
                cycle[i] = v;
            }
        }
        if (status == YES && outclass)
            for (i = 0; i < ne; ++i)
                outclass[i] = hcnodat.class[i];

        return status;
}

/********************************************************************/

static int
isham(cubgraph cub,
      int n, int ne, int weight,
      int *vv, int *vi, int nvv,
      int *yy, int *yi, int nyy, int *cyc)
/* test if hamiltonian; optionally return a cycle 
   Forbid the vi[i]-th nbr of vv[i], for i=0..nvv-1 
   Force the yi[i]-th nbr of yy[i], for i=0..nyy-1 
     WARNING: vi[i]/yi[i] is numbered starting at 1  */
{
        int i,j,k;
        int nmax,ch;
        cubgraph cubcopy;
        edgevec v1,v2,initclass,outclass;
        int perm[MAXN],pinv[MAXN];
	double tmp;

#if !RANPERM

        maxnodes = NO_LIMIT;
        nodecount = 0;
        cubinit(cub,eno,v1,v2,n,ne);

        for (i = 0; i < ne; ++i)
            initclass[i] = DUNNO;

	for (i = 0; i < nvv; ++i)
	    if (vv[i] < n) initclass[eno[vv[i]][vi[i]-1]] = NO;
	for (i = 0; i < nyy; ++i)
	    if (yy[i] < n) initclass[eno[yy[i]][yi[i]-1]] = YES;

        ch = cubham(cub,eno,initclass,v1,v2,cyc,outclass,n,ne);

        totalnodes += nodecount;
        ++numtries[0];
       
#else
        ch = HABORT;
	maxnodes = -1;
        for (nmax = 0; ch == HABORT && maxnodes != timeout; ++nmax)
        {
            if (nmax/repeats < NUMMAXNODES)
            {
		tmp = (double)standard[nmax/repeats] * (double)weight 
                                             * (double)n/ 10000.0;
		if (tmp >= (double)NO_LIMIT) maxnodes = NO_LIMIT;
		else                        maxnodes = tmp;
		if (timeout > 0 && timeout < maxnodes) maxnodes = timeout;
            }
            else if (timeout > 0)
		maxnodes = timeout;
	    else
                maxnodes = NO_LIMIT;

	    if (nmax != 0)
	    {
                for (i = n; --i > 0;)
                {
                    k = KRAN(i+1);
                    j = perm[i];
                    perm[i] = perm[k];
                    perm[k] = j;
                }
	    }
	    else
	    {
		for (i = 0; i < n; ++i)
		    perm[i] = i;
	    }

            for (i = 0; i < n; ++i)
            {
                j = perm[i];
                cubcopy[j][0] = cub[i][0] < 0 ? -1 : perm[cub[i][0]];
                cubcopy[j][1] = cub[i][1] < 0 ? -1 : perm[cub[i][1]];
                cubcopy[j][2] = cub[i][2] < 0 ? -1 : perm[cub[i][2]];
            }

            cubinit(cubcopy,eno,v1,v2,n,ne);
            nodecount = 0;

            for (i = 0; i < ne; ++i)
                initclass[i] = DUNNO;

            for (i = 0; i < nvv; ++i)
                if (vv[i] < n) initclass[eno[perm[vv[i]]][vi[i]-1]] = NO;
            for (i = 0; i < nyy; ++i)
                if (yy[i] < n) initclass[eno[perm[yy[i]]][yi[i]-1]] = YES;

            ch = cubham(cubcopy,eno,initclass,v1,v2,cyc,outclass,n,ne);
            totalnodes += nodecount;
            ++numtries[nmax/repeats];
        }

	if (cyc != NULL && ch == YES)
	{
	    for (i = 0; i < n; ++i)
		pinv[perm[i]] = i;
	    for (i = 0; i < n; ++i)
		cyc[i] = pinv[cyc[i]];
	}
#endif

        return ch;
}

/**************************************************************************/

static int
optadd(cubgraph cub, int v1, int v2)
/* v1 and v2 must have degree 2 and be distinct.
   Add edge v1-v2 if not already present; return index of edge in cub[v1]. */
{
    if (cub[v1][0] == v2) return 0;
    if (cub[v1][1] == v2) return 1;
    cub[v1][2] = v2;
    cub[v2][2] = v1;
    return 2;
}

/**************************************************************************/

static void
dofragment(nauty_counter id, cubgraph cub, int n, int ne, int weight)
/* Test for coverage by one or two paths between vertices of degree 2 */
{
    int i,i1,i2,i3,i4;
    int v1,v2,v3,v4,j1,j3;
    int deg2[MAXN],ndeg2;
    int yy[3],yi[3],newne;
    int cyc[MAXN];
    int status;

    ndeg2 = 0;
    for (i = 0; i < n; ++i)
    {
        if (cub[i][0] < 0 || cub[i][1] < 0)
            gt_abort(">E -F forbids degree 0,1\n");

	if (cub[i][2] < 0) deg2[ndeg2++] = i;
    }

    printf("Input " COUNTER_FMT ":",id);
    for (i = 0; i < ndeg2; ++i) printf(" %d",deg2[i]);
    printf("\n");

    printf(" Pairs: ");
    for (i1 = 0; i1 < ndeg2; ++i1)
    for (i2 = i1+1; i2 < ndeg2; ++i2)
    {
	v1 = deg2[i1]; v2 = deg2[i2];
	j1 = optadd(cub,v1,v2);
	yy[0] = v1; yi[0] = j1+1;
	newne = ne + (j1==2);
	status = isham(cub,n,newne,weight,NULL,NULL,0,yy,yi,1,cyc);
        if (status == HABORT)
	    printf(" T%d-%d",v1,v2);
        if (status == NO)
	    printf(" N%d-%d",v1,v2);
        else 
        {
	    printf(" Y%d-%d",v1,v2);
            if (verbose > 1)
	    {
		printf("[");
	        for (i = 0; i < n; ++i) printf(" %d",cyc[i]);
	        printf("]\n");
	    }
        }
	cub[v1][2] = cub[v2][2] = -1;
    }
    printf("\n");

    printf(" Quartets: ");
    for (i1 = 0; i1 < ndeg2; ++i1)
    for (i2 = i1+1; i2 < ndeg2; ++i2)
    for (i3 = i1+1; i3 < ndeg2; ++i3)
    for (i4 = i3+1; i4 < ndeg2; ++i4)
    {
        if (i3 == i2 || i4 == i2) continue;

	v1 = deg2[i1]; v2 = deg2[i2];
	j1 = optadd(cub,v1,v2);
	v3 = deg2[i3]; v4 = deg2[i4];
	j3 = optadd(cub,v3,v4);
	yy[0] = v1; yi[0] = j1+1;
        yy[1] = v3; yi[1] = j3+1;
	newne = ne + (j1==2) + (j3==2);
	status = isham(cub,n,newne,weight,NULL,NULL,0,yy,yi,2,cyc);
        if (status == HABORT)
	    printf(" T%d-%d,%d-%d",v1,v2,v3,v4);
        if (status == NO)
	    printf(" N%d-%d,%d-%d",v1,v2,v3,v4);
        else
        {
	    printf(" Y%d-%d,%d-%d",v1,v2,v3,v4);
	    if (verbose > 1)
	    {
		printf("[");
	        for (i = 0; i < n; ++i) printf(" %d",cyc[i]);
	        printf("]\n");
	    }
        }
	cub[v1][2] = cub[v2][2] = -1;
	cub[v3][2] = cub[v4][2] = -1;
    }
    printf("\n");
}

/********************************************************************/

static int
hasinout(cubgraph cub,
         int n, int ne, int *x0, int *x1, int *y0, int *y1, int limit)
/* test if cub has in-out (+-) property */
{
	edgevec v1,v2,initclass,outclass;
	set *d0,*di,*dii;
	int i,ii,j,jj;
	int me,nbad;
        DYNALLSTAT(graph,done,done_sz);
	
	me = (ne + WORDSIZE - 1) / WORDSIZE;

        DYNALLOC2(graph,done,done_sz,ne,me,"hasinout");

	d0 = (set*)done;
	EMPTYSET(d0,me);
	for (j = 0; j < ne; ++j)
	    ADDELEMENT(d0,j);

	for (i = 1, di = d0 + me; i < ne; ++i, di += me)
	{
	    for (j = 0; j < me; ++j)
		di[j] = d0[j];
	    DELELEMENT(di,i);
	}
	DELELEMENT(d0,0);

	cubinit(cub,eno,v1,v2,n,ne);
	for (i = 0; i < ne; ++i)
	    initclass[i] = DUNNO;

	maxnodes = NO_LIMIT;
	nbad = 0;

	for (i = 0, di = (set*)done; i < ne; ++i, di += me)
	    for (j = -1; (j = nextelement(di,me,j)) >= 0;)
	    {
		initclass[i] = NO;
		initclass[j] = YES;
		++numtries[0];
		if (cubham(cub,eno,initclass,v1,v2,NULL,
							outclass,n,ne) == NO)
		{
		    x0[nbad] = v1[i]; x1[nbad] = v2[i];
		    y0[nbad] = v1[j]; y1[nbad] = v2[j];
		    ++nbad;
		    if (nbad >= limit) return nbad;
		}
		else
		{
                    for (ii = i, dii = di; ii < ne; ++ii, dii += me)
                    if (outclass[ii] == NO)
                        for (jj = 0; jj < ne; ++jj)
                            if (outclass[jj] == YES)
                                DELELEMENT(dii,jj);
		}

		initclass[i] = DUNNO;
		initclass[j] = DUNNO;
	    }

	return nbad;
}

/**************************************************************************/

static int
hasinin(cubgraph cub,
        int n, int ne, int *x0, int *x1, int *y0, int *y1, int limit)
/* test if cub has in-in (++) property */
{
        edgevec v1,v2,initclass,outclass;
	set *d0,*di,*dii;
	int i,ii,j,jj;
	int me,nbad;
        DYNALLSTAT(graph,done,done_sz);
	
	me = (ne + WORDSIZE - 1) / WORDSIZE;

        DYNALLOC2(graph,done,done_sz,ne,me,"hasinin");

	d0 = (set*)done;
	EMPTYSET(d0,me);
	for (j = 0; j < ne; ++j)
	    ADDELEMENT(d0,j);

	for (i = 1, di = d0 + me; i < ne; ++i, di += me)
	{
	    for (j = 0; j < me; ++j)
		di[j] = d0[j];
	    DELELEMENT(di,i);
	}
	DELELEMENT(d0,0);

	cubinit(cub,eno,v1,v2,n,ne);
	for (i = 0; i < ne; ++i)
	    initclass[i] = DUNNO;

	maxnodes = NO_LIMIT;
	nbad = 0;

	for (i = 0, di = (set*)done; i < ne; ++i, di += me)
	    for (j = i; (j = nextelement(di,me,j)) >= 0;)
	    {
		initclass[i] = YES;
		initclass[j] = YES;
		++numtries[0];
		if (cubham(cub,eno,initclass,v1,v2,NULL,outclass,n,ne) == NO)
		{
                    x0[nbad] = v1[i]; x1[nbad] = v2[i];
                    y0[nbad] = v1[j]; y1[nbad] = v2[j];
                    ++nbad;
                    if (nbad >= limit) return nbad;
		}
		else
	 	{
                    for (ii = i, dii = di; ii < ne; ++ii, dii += me)
                    if (outclass[ii] == YES)
                        for (jj = ii; jj < ne; ++jj)
                            if (outclass[jj] == YES)
                                DELELEMENT(dii,jj);
		}

		initclass[i] = DUNNO;
		initclass[j] = DUNNO;
	    }
	return nbad;
}

/**************************************************************************/

static int
hasin(cubgraph cub, int n, int ne, int *x0, int *x1, int limit)
/* test if cub has "in" property */
{
	edgevec v1,v2,initclass,outclass;
	boolean done[MAXNE];
	int i,ii;
	int nbad;
	
	cubinit(cub,eno,v1,v2,n,ne);
	for (i = 0; i < ne; ++i)
	{
	    initclass[i] = DUNNO;
	    done[i] = FALSE;
	}

	maxnodes = NO_LIMIT;
	nbad = 0;

	for (i = 0; i < ne; ++i)
	    if (!done[i])
	    {
		initclass[i] = YES;
		++numtries[0];
		if (cubham(cub,eno,initclass,v1,v2,NULL,outclass,n,ne) == NO)
		{
		    x0[nbad] = v1[i]; x1[nbad] = v2[i];
		    ++nbad;
		    if (nbad >= limit) return nbad;
		}
		else
		{
                    for (ii = i; ii < ne; ++ii)
                    if (outclass[ii] == YES) done[ii] = TRUE;
		}

		initclass[i] = DUNNO;
	    }
	return nbad;
}

/**************************************************************************/

static boolean
eplus(cubgraph acub, int n, int ne, int x, int y, int *pwhy)
{
        cubgraph cub;
        edgevec v1,v2,initclass;
	int i,a,b,c,d,xy,why;

	if (3*n != 2*ne)
	{
	    fprintf(stderr,
		"cubhamg: eplus() not implemented for noncubic graphs\n");
	    exit(1);
	}

        for (i = 0; i < n; ++i)
        {
            cub[i][0] = acub[i][0];
            cub[i][1] = acub[i][1];
            cub[i][2] = acub[i][2];
        }

	if      (cub[x][0] == y) 
	{
	    xy = 0;
	    a = cub[x][1];
	    b = cub[x][2];
	}
	else if (cub[x][1] == y)
        {
            xy = 1;
            a = cub[x][0];
            b = cub[x][2];
        }
	else
        {
            xy = 2;
            a = cub[x][0];
            b = cub[x][1];
        }

	if      (cub[y][0] == x)
        {
            c = cub[y][1];
            d = cub[y][2];
        }
        else if (cub[y][1] == x)
        {
            c = cub[y][0];
            d = cub[y][2];
        }
        else
        {
            c = cub[y][0];
            d = cub[y][1];
        }

	for (i = 0; i < ne; ++i)
	    initclass[i] = DUNNO;

	why = 0;
	cubinit(cub,eno,v1,v2,n,ne);
	initclass[eno[x][xy]] = NO;
	if (cubham(cub,eno,initclass,v1,v2,NULL,NULL,n,ne) == YES)
	    why |= 1;
	initclass[eno[x][xy]] = DUNNO;

#define CHANGE(z,p,q) if (cub[z][0]==p) cub[z][0]=q;\
     else if (cub[z][1]==p) cub[z][1]=q; else cub[z][2]=q;

	CHANGE(x,b,c);
	CHANGE(y,c,b);
	CHANGE(b,x,y);
	CHANGE(c,y,x);

        cubinit(cub,eno,v1,v2,n,ne);
        initclass[eno[x][xy]] = NO;
        if (cubham(cub,eno,initclass,v1,v2,NULL,NULL,n,ne) == YES)
            why |= 2;
        initclass[eno[x][xy]] = DUNNO;

	CHANGE(x,c,d);
	CHANGE(y,d,c);
	CHANGE(c,x,y);
	CHANGE(d,y,x);

        cubinit(cub,eno,v1,v2,n,ne);
        initclass[eno[x][xy]] = NO;
        if (cubham(cub,eno,initclass,v1,v2,NULL,NULL,n,ne) == YES)
            why |= 4;

	*pwhy = why;
	return why == 7;
}

/**************************************************************************/

static int
hase34(cubgraph cub,
       int n, int ne, int *x0, int *x1, int *why, boolean plus, int limit)
/* test if cub has "e34" property */
{
	edgevec v1,v2,initclass,outclass;
	int ea[4*MAXNE],eb[4*MAXNE],ec[4*MAXNE];
	boolean done[4*MAXNE];
	int count[MAXNE];
	int i,ii;
	int vi,nbad,pluswhy;
	static int pop[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
	
	if (3*n != 2*ne)
	{
	    fprintf(stderr,
		"cubhamg: hase34() not implemented for noncubic graphs\n");
	    exit(1);
	}
	cubinit(cub,eno,v1,v2,n,ne);
	for (i = 0; i < ne; ++i)
	{
	    initclass[i] = DUNNO;
	    count[i] = 0;
	}

	for (i = ii = 0; i < ne; ++i)
	{
	    eb[ii] = eb[ii+1] = eb[ii+2] = eb[ii+3] = i;
	    done[ii] = done[ii+1] = done[ii+2] = done[ii+3] = FALSE;
	    
	    vi = v1[i];
	    if (eno[vi][0] != i) ea[ii++] = eno[vi][0];
	    if (eno[vi][1] != i) ea[ii++] = eno[vi][1];
	    if (eno[vi][2] != i) ea[ii++] = eno[vi][2];
	    ea[ii] = ea[ii-2];
	    ea[ii+1] = ea[ii-1];
	
	    vi = v2[i];
            if (eno[vi][0] != i) ec[ii++] = eno[vi][0];
            if (eno[vi][1] != i) ec[ii++] = eno[vi][1];
            if (eno[vi][2] != i) ec[ii++] = eno[vi][2];
            ec[ii-4] = ec[ii-3] = ec[ii-2]; 
            ec[ii-2] = ec[ii-1];
	}

	maxnodes = NO_LIMIT;
	nbad = 0;

	for (i = 0; i < 4*ne; ++i)
	    if (!done[i])
	    {
		initclass[ea[i]] = YES;
		initclass[eb[i]] = YES;
		initclass[ec[i]] = YES;
		++numtries[0];
		if (cubham(cub,eno,initclass,v1,v2,NULL,
						outclass,n,ne) == YES)
		    for (ii = i; ii < 4*ne; ++ii)
			if (!done[ii] && outclass[ea[ii]] == YES &&
			    outclass[eb[ii]] == YES && outclass[ec[ii]] == YES)
			{
			    done[ii] = TRUE;
			    count[eb[ii]] |= 1 << (ii & 3);
			}
		++numtries[0];
		initclass[ea[i]] = DUNNO;
                initclass[eb[i]] = DUNNO;
                initclass[ec[i]] = DUNNO;
	    }

	pluswhy = 0;
	for (i = 0; i < ne; ++i)
	    if (pop[count[i]] < 3 
                && (!plus || !eplus(cub,n,ne,v1[i],v2[i],&pluswhy)))
	    {
                x0[nbad] = v1[i]; x1[nbad] = v2[i];
		why[nbad] = (pluswhy << 4) | count[i];
                ++nbad;
                if (nbad >= limit) return nbad;
            }

	return nbad;
}

/**************************************************************************/

#if 0
static int
oldhasout(cubgraph cub, int n, int ne, int *x0, int *x1, int limit)
/* test if cub has "out" property */
{
        edgevec v1,v2,initclass,outclass;
        boolean done[MAXNE];
        int i,ii;
        int nbad;
        
        cubinit(cub,eno,v1,v2,n,ne);
        for (i = 0; i < ne; ++i)
        {
            initclass[i] = DUNNO;
            done[i] = FALSE;
        }
 
        maxnodes = NO_LIMIT;
	nbad = 0;
 
        for (i = 0; i < ne; ++i)
            if (!done[i])
            {
                initclass[i] = NO;
                ++numtries[0];
                if (cubham(cub,eno,initclass,v1,v2,NULL,outclass,n,ne) == NO)
                {
                    x0[nbad] = v1[i]; x1[nbad] = v2[i];
                    ++nbad;
                    if (nbad >= limit) return nbad;
                }
		else
		{
		    for (ii = i; ii < ne; ++ii)
                    if (outclass[ii] == NO) done[ii] = TRUE;
		}
 
                initclass[i] = DUNNO;
            }
        return nbad;
}
#endif

/**************************************************************************/

static int
hasout(cubgraph cub, int n, int ne, int weight, int *x0, int *x1, int limit)
/* test if cub has "out" property 
   Returns are -2 for timeout, -1 for nonhamiltonian, otherwise
   number of edges not present in any cycle */
{
	cubgraph done;
	int cyc[MAXN];
        int vv[2],vi[2];
        int nbad,ch;
	int i,j,ii,jj,x,y,z;
 
	nbad = 0;
 
	for (i = 0; i < n; ++i) done[i][0] = done[i][1] = done[i][2] = 0;

	ch = isham(cub,n,ne,weight,vv,vi,0,NULL,NULL,0,cyc);
	if (ch == HABORT) return -2;
	if (ch == NO) return -1;

	for (i = 0; i < n; ++i)
	{
	    x = cyc[i];
            y = cyc[i==n-1?0:i+1];
	    z = cyc[i==0?n-1:i-1];
	    for (j = 0; j < 3; ++j)
		if (cub[x][j] >= 0 &&
		    cub[x][j] != y && cub[x][j] != z) break;
	    if (j < 3) done[x][j] = 1;
	}

	for (ii = 0; ii < n; ++ii)
	for (jj = 0; jj < 3; ++jj)
	{
	    if (cub[ii][jj] > ii && !done[ii][jj])
	    {
		vv[0] = ii;
		vi[0] = jj+1;
		ch = isham(cub,n,ne,weight,vv,vi,1,NULL,NULL,0,cyc);
                if (ch == HABORT) return -2;
		if (ch == NO)
		{
		    x0[nbad] = ii;
		    x1[nbad] = cub[ii][jj];
		    ++nbad;
		}
		else
		{
		    for (i = 0; i < n; ++i)
		    {
	    	        x = cyc[i];
            	        y = cyc[i==n-1?0:i+1];
	    	        z = cyc[i==0?n-1:i-1];
	    	        for (j = 0; j < 3; ++j)
			    if (cub[x][j] >= 0 &&
		    	    cub[x][j] != y && cub[x][j] != z) break;
	    	        if (j < 3) done[x][j] = 1;
		    }

		}
	    }
	}

        return nbad;
}

/**************************************************************************/

static boolean
biconnected_cub(cubgraph cub, int n)
/* test whether cub is biconnected */
{
        int i,sp,v,w,x;
        set visited[MAXM];
        int numvis,num[MAXN],lp[MAXN],stack[MAXN];
	int m,*gv;

        if (n <= 2) return FALSE;

	m = (n + WORDSIZE - 1) / WORDSIZE;
	EMPTYSET(visited,m);
	ADDELEMENT(visited,0);

        stack[0] = 0;
        num[0] = 0;
        lp[0] = 0;
        numvis = 1;
        sp = 0;
        v = 0;
	gv = (int*)cub[v];

        for (;;)
        {
	    for (i = 0; i < 3; ++i)
		if (gv[i] >= 0 && !ISELEMENT(visited,gv[i])) break;

            if (i < 3)
            {
                w = v;
                v = gv[i];  /* visit next child */
                stack[++sp] = v;
		gv = (int*)cub[v];
                ADDELEMENT(visited,v);
                lp[v] = num[v] = numvis++;

                for (i = 0; i < 3; ++i)
		{
		    x = gv[i];
		    if (x >= 0 && x != w && ISELEMENT(visited,x))
			if (num[x] < lp[v])  lp[v] = num[x];
		}
            }
            else
            {
                w = v;                  /* back up to parent */
                if (sp <= 1)          return numvis == n;
                v = stack[--sp];
		gv = (int*)cub[v];
                if (lp[w] >= num[v])  return FALSE;
                if (lp[w] < lp[v])    lp[v] = lp[w];
            }
        }
}

/**************************************************************************/

static boolean
biconnected_cub_v(cubgraph cub, int vv, int n)
/* test whether cub-vv is biconnected */
{
        int i,sp,v,w,x,start;
        set visited[MAXM];
        int numvis,num[MAXN],lp[MAXN],stack[MAXN];
	int m,*gv;

        if (n <= 3) return FALSE;
	start = (vv == 0 ? 1 : 0);

	m = (n + WORDSIZE - 1) / WORDSIZE;
	EMPTYSET(visited,m);
	ADDELEMENT(visited,start);
	ADDELEMENT(visited,vv);

        stack[0] = start;
        num[start] = 0;
        lp[start] = 0;
        numvis = 1;
        sp = 0;
        v = start;
	gv = (int*)cub[v];

        for (;;)
        {
	    for (i = 0; i < 3; ++i)
		if (gv[i] >= 0 && !ISELEMENT(visited,gv[i])) break;

            if (i < 3)
            {
                w = v;
                v = gv[i];  /* visit next child */
                stack[++sp] = v;
		gv = (int*)cub[v];
                ADDELEMENT(visited,v);
                lp[v] = num[v] = numvis++;

                for (i = 0; i < 3; ++i)
		{
		    x = gv[i];
		    if (x >= 0 && x != w && x != vv && ISELEMENT(visited,x))
			if (num[x] < lp[v])  lp[v] = num[x];
		}
            }
            else
            {
                w = v;                  /* back up to parent */
                if (sp <= 1)          return numvis == n-1;
                v = stack[--sp];
		gv = (int*)cub[v];
                if (lp[w] >= num[v])  return FALSE;
                if (lp[w] < lp[v])    lp[v] = lp[w];
            }
        }
}

/**************************************************************************/

static boolean
biconnected_v(graph *g, int vv, int m, int n)
/* test whether g-vv is biconnected */
/* version for arbitrary sizes */
{
        int i,sp,v,w;
	setword ww;
        set sw[MAXM],visited[MAXM];
        int numvis,num[MAXN],lp[MAXN],stack[MAXN];
	int start;
	set *gv;

        if (n <= 3) return FALSE;

	start = vv == 0 ? 1 : 0;
	EMPTYSET(visited,m);
	ADDELEMENT(visited,start);
	ADDELEMENT(visited,vv);

        stack[0] = start;
        num[start] = 0;
        lp[start] = 0;
        numvis = 1;
        sp = 0;
        v = start;
	gv = (set*)g + m*v;

        for (;;)
        {
	    for (i = 0; i < m; ++i)
		if ((ww = gv[i] & ~visited[i])) break; /* = */

            if (i < m)
            {
                w = v;
                v = TIMESWORDSIZE(i) + FIRSTBIT(ww);   /* visit next child */
                stack[++sp] = v;
		gv = (set*)g + m*v;
                ADDELEMENT(visited,v);
                lp[v] = num[v] = numvis++;
		for (i = 0; i < m; ++i)
		    sw[i] = gv[i] & visited[i];
		DELELEMENT(sw,w);
		DELELEMENT(sw,vv);

                for (i = 0; i < m; ++i)
		{
		    ww = sw[i];
                    while (ww)
                    {
			TAKEBIT(w,ww);
			w += TIMESWORDSIZE(i);
                        if (num[w] < lp[v])  lp[v] = num[w];
                    }
		}
            }
            else
            {
                w = v;                  /* back up to parent */
                if (sp <= 1)     return numvis == n-1;
                v = stack[--sp];
		gv = (set*)g + m*v;
                if (lp[w] >= num[v])  return FALSE;
                if (lp[w] < lp[v])    lp[v] = lp[w];
            }
        }
}

/**************************************************************************/

static boolean
triconnected_cub(cubgraph cub, int n)
/* test whether triconnected; awfully inefficient */
{
	int vv;

	if (n <= 3) return FALSE;

	for (vv = n-1; --vv >= 0;)
	    if (!biconnected_cub_v(cub,vv,n)) return FALSE;

	return TRUE;
}

/**************************************************************************/

static boolean
gtocub(graph *g, int m, int n, cubgraph cub, int *pne)
/* Convert nauty-format graph into cubgraph.  Returns FALSE if there
 * are any vertices of degree 4 or more.
 */
{
	int i,j,nde;
	set *gi;

	nde = 0;
	for (i = 0, gi = (set*)g; i < n; ++i, gi += m)
	{
	    cub[i][0] = cub[i][1] = cub[i][2] = -1;
	    j = nextelement(gi,m,-1);
	    if (j < 0) continue;
	    cub[i][0] = j;
	    ++nde;
	    j = nextelement(gi,m,j);
            if (j < 0) continue;
            cub[i][1] = j;
	    ++nde;
	    j = nextelement(gi,m,j);
            if (j < 0) continue;
            cub[i][2] = j;
	    ++nde;
	    if (nextelement(gi,m,j) >= 0) return FALSE;
	}

	*pne = nde / 2;
	return TRUE;
}

/**************************************************************************/

static boolean
sgtocub(sparsegraph *sg, cubgraph cub, int *pne)
/* Convert sparse-format graph into cubgraph.  Returns FALSE if there
 * are any vertices of degree 4 or more.
 */
{
	int *d,*e;
	size_t *v;
	int n,i,j,vi;
	unsigned long int nde;

	nde = 0;
	n = sg->nv;
	SG_VDE(sg,v,d,e);
	for (i = 0; i < n; ++i)
	{
	    if (d[i] >= 4) return FALSE;
	    vi = v[i];

	    cub[i][0] = cub[i][1] = cub[i][2] = -1;
	    for (j = 0; j < d[i]; ++j)
	       cub[i][j] = e[vi+j];
	    nde += d[i];
	}

	*pne = nde / 2;
	return TRUE;
}

/**************************************************************************/

int
main(int argc, char *argv[])
{
        char *infilename,*outfilename;
        FILE *infile,*outfile,*msgfile;
        boolean badargs,biconn,triconn,fragment;
	boolean in,out,inin,inout,e34,e34plus,testing;
        nauty_counter numread,noncub,nonham,nonconn,numto;
        int ch,weight,m,n,ne,i,namesgot,nl;
	int nbad,limit,x0[BADLIM],x1[BADLIM],y0[BADLIM],y1[BADLIM];
	sparsegraph sg;
	int vv[MAXA],vi[MAXA],nvv,cyc[MAXN];
        int yy[MAXA],yi[MAXA],nyy;
	double t0,t1;
	cubgraph cub;
        char *arg;
	int codetype;

        infilename = outfilename = NULL;
        badargs = FALSE;
	e34plus = e34 = in = out = inin = inout = FALSE;
	fragment = biconn = triconn = testing = FALSE;
	verbose = 0;
	weight = 100;
	nvv = nyy = 0;
	timeout = 0;
	repeats = 1;

     /* parse argument list */

        namesgot = 0;
        for (i = 1; i < argc && !badargs; ++i)
        {
            arg = argv[i];
            if (arg[0] == '-' && arg[1] != '\0')
            {
                if (arg[1] == 'v')
                    verbose = (verbose == 0 ? 1 : verbose);
		else if (arg[1] == 'V')
		    verbose = 2;
                else if (arg[1] == 'i')
                    in = TRUE;
                else if (arg[1] == 'I')
                    inin = TRUE;
                else if (arg[1] == 'o')
                    out = TRUE;
		else if (arg[1] == 'x')
		    inout = TRUE;
		else if (arg[1] == 'e')
		    e34 = TRUE;
		else if (arg[1] == 'E')
		    e34 = e34plus = TRUE;
                else if (arg[1] == 'b')
                    biconn = TRUE;
                else if (arg[1] == 't')
                    triconn = TRUE;
                else if (arg[1] == 'Q')
                    testing = TRUE;
                else if (arg[1] == 'F')
                    fragment = TRUE;
		else if (arg[1] == 'n')
		{
		    if (nvv == MAXA)
		    {
			fprintf(stderr,">E cubhamg : too many -n switches\n");
			exit(1);
		    }
		    if (sscanf(arg+2,"%d-%d",&vv[nvv],&vi[nvv]) != 2)
			badargs = TRUE;
		    else if (vi[nvv] < 1 || vi[nvv] > 3)
		    {
			fprintf(stderr,
                               ">E cubhamg : second arg of -n must be 1..3\n");
			exit(1);
		    }
		    ++nvv;
		}
		else if (arg[1] == 'y')
		{
		    if (nyy == MAXA)
		    {
			fprintf(stderr,">E cubhamg : too many -y switches\n");
			exit(1);
		    }
		    if (sscanf(arg+2,"%d-%d",&yy[nyy],&yi[nyy]) != 2)
			badargs = TRUE;
		    else if (yi[nyy] < 1 || yi[nyy] > 3)
		    {
			fprintf(stderr,
                               ">E cubhamg : second arg of -y must be 1..3\n");
			exit(1);
		    }
		    ++nyy;
		}
		else if (arg[1] >= '0' && arg[1] <= '9')
		    sscanf(arg+1,"%d",&weight);
		else if (arg[1] == 'T')
		{
		    if (sscanf(arg+2,"%ld",&timeout) != 1 || timeout < 0)
		    {
			fprintf(stderr,">E cubhamg : bad -T value\n");
			exit(1);
		    }
		    else if (timeout > NO_LIMIT-1)
			timeout = NO_LIMIT - 1;
		}
		else if (arg[1] == 'R')
		{
		    if (sscanf(arg+2,"%ld",&repeats) != 1 || repeats < 1)
		    {
			fprintf(stderr,">E cubhamg : bad -R value\n");
			exit(1);
		    }
		}
		else
		    badargs = TRUE;
            }
            else
            {
                if (namesgot == 0)
                {
                    namesgot = 1;
                    infilename = arg;
                }
                else if (namesgot == 1)
                {
                    namesgot = 2;
                    outfilename = arg;
                }
                else
                    badargs = TRUE;
            }
        }

	if (badargs)
	{
	    fprintf(stderr,
         ">E Usage: cubhamg [-#] [-v | -V] [-n#-#] [-y#-#] [infile [outfile]]\n");
	    exit(1);
	}

     /* open input file */

        if (infilename && infilename[0] == '-') infilename = NULL;
        infile = opengraphfile(infilename,&codetype,FALSE,1);
        if (!infile) exit(1);
        if (!infilename) infilename = "stdin";
 
        if (infilename == NULL) infilename = "stdin";

        NODIGRAPHSYET(codetype);

     /* open output file */

        if (outfilename == NULL || outfilename[0] == '-')
        {
            outfile = stdout;
            outfilename = "stdout";
            msgfile = stderr;
        }
        else
        {
            msgfile = stdout;
            if ((outfile = fopen(outfilename,"w")) == NULL)
            {
                fprintf(stderr,
                    ">E cubhamg: can't open %s for writing\n",outfilename);
                ABORT(">E cubhamg");
            }
        }

	if (triconn) biconn = FALSE;
	if (e34) in = out = inin = inout = FALSE;
	if (inout) in = out = inin = FALSE;
	if (inin) in = out = FALSE;
	if (out) in = FALSE;
	if (testing) out = TRUE;

	if (codetype&HAS_HEADER)
        {
            if (codetype&SPARSE6) writeline(outfile,SPARSE6_HEADER);
            else                  writeline(outfile,GRAPH6_HEADER);
        }

//if (codetype&SPARSE6) outproc = writes6;
//else                  outproc = writeg6;

	numread = noncub = nonham = nonconn = 0;
	numto = 0;
	INITRANBYTIME;
	t0 = CPUTIME;

	limit = verbose ? BADLIM : 1;

	SG_INIT(sg);
	while (read_sg(infile,&sg))
	{
	    ++numread;
	    n = sg.nv;

	    if (n >= MAXN-1)
	    {
		fprintf(stderr,
                    ">E cubhamg: input " COUNTER_FMT " too big\n",numread);
		exit(1);
	    }
#if MAXM==1
	    if (3*n >= 2*WORDSIZE)
	    {
		fprintf(stderr,
                    ">E cubhamg: must compile with MAXM>1 for ne>WORDSIZE\n");
		exit(1);
	    }
#endif

	    if (!sgtocub(&sg,cub,&ne))
	    {
		if (verbose)
		    fprintf(msgfile,"Input " COUNTER_FMT
                                    " has maxdeg>3.\n",numread);
		++noncub;
	    }
	    else if (biconn && !biconnected_cub(cub,n))
		++nonconn;
	    else if (triconn && !triconnected_cub(cub,n))
		++nonconn;
            else if (e34)
            {
                if ((nbad = hase34(cub,n,ne,x0,x1,y0,e34plus,limit)) > 0)
                {
                    if (verbose)
		    {
                        fprintf(msgfile,"Input " COUNTER_FMT
                                        " fails property e34%s:",
                                               numread,e34plus ? "+" : "");
			if (e34plus)
			    for (i = 0; i < nbad; ++i)
			        fprintf(msgfile," %d-%d[%02x]",
						x0[i],x1[i],y0[i]);
			else
			    for (i = 0; i < nbad; ++i)
			        fprintf(msgfile," %d-%d",x0[i],x1[i]);
			fprintf(msgfile,"\n");
		    }
                    ++nonham;
                    writelast(outfile);
                }
            }
	    else if (inout)
	    {
		if ((nbad = hasinout(cub,n,ne,x0,x1,y0,y1,limit)) > 0)
		{
		    if (verbose)
                    { 
                        fprintf(msgfile,"Input " COUNTER_FMT
                                        " fails property -+:",numread);
                        for (i = 0; i < nbad; ++i) 
                            fprintf(msgfile," %d-%d/%d-%d",
				    x0[i],x1[i],y0[i],y1[i]); 
                        fprintf(msgfile,"\n");
                    }
		    ++nonham;
                    writelast(outfile);
		}
	    }
            else if (inin)
            {
                if ((nbad = hasinin(cub,n,ne,x0,x1,y0,y1,limit)) > 0)
                {
                    if (verbose)
		    {  
                        fprintf(msgfile,"Input " COUNTER_FMT
                                        " fails property ++:",numread); 
                        for (i = 0; i < nbad; ++i) 
                            fprintf(msgfile," %d-%d/%d-%d",
                                    x0[i],x1[i],y0[i],y1[i]);
                        fprintf(msgfile,"\n"); 
                    }
                    ++nonham;
                    writelast(outfile);
                }
            }
            else if (out)
            { 
                if ((nbad = hasout(cub,n,ne,weight,x0,x1,limit)) != 0)
                { 
                    if (verbose) 
		    {
			if (nbad == -2)
                            fprintf(msgfile,"Input " COUNTER_FMT
                                        " timed out\n",numread);
			else if (nbad == -1)
                            fprintf(msgfile,"Input " COUNTER_FMT
                                        " is nonhamiltonian\n",numread);
			else
			{
                            fprintf(msgfile,"Input " COUNTER_FMT
                                            " fails property -:",numread);
                            for (i = 0; i < nbad; ++i)
                                fprintf(msgfile," %d-%d",x0[i],x1[i]);
                            fprintf(msgfile,"\n");
		 	}
                    }
		    if (nbad != -1)
		    {
                        ++nonham; 
                        writelast(outfile);
		    }
                } 
            }
            else if (in)
            {
                if ((nbad = hasin(cub,n,ne,x0,x1,limit)) > 0)
                {
                    if (verbose)
                    {    
                        fprintf(msgfile,"Input " COUNTER_FMT
                                        " fails property +:",numread); 
                        for (i = 0; i < nbad; ++i) 
                            fprintf(msgfile," %d-%d",x0[i],x1[i]); 
                        fprintf(msgfile,"\n"); 
                    }
                    ++nonham;
                    writelast(outfile);
                }
            }
	    else if (fragment)
            {
		dofragment(numread,cub,n,ne,weight);
            }
	    else if ((ch = isham(cub,n,ne,weight,vv,vi,nvv,yy,yi,nyy,cyc)) == NO)
	    {
	   	if (verbose)
                    fprintf(msgfile,"Input " COUNTER_FMT
                                    " is not hamiltonian.\n",numread);
                ++nonham;
		writelast(outfile);
	    }
	    else if (ch == HABORT)
	    {
                if (verbose)
                    fprintf(msgfile,"Input " COUNTER_FMT " timed out.\n",numread);
                ++numto;
                 writelast(outfile);
            }
	    else if (verbose >= 2)
	    {
		fprintf(msgfile,"Cycle in input " COUNTER_FMT ":\n",numread);
		if (n <= 100) nl = 26;
		else          nl = 19;
		for (i = 0; i < n; ++i)
	 	{
		    if (i > 0 && i % nl == 0) fprintf(msgfile,"\n ");
		    fprintf(msgfile," %d",cyc[i]);
		}
		fprintf(msgfile,"\n");
	    }
	}
	t1 = CPUTIME;

	fprintf(msgfile,">C " COUNTER_FMT
                        " graphs read from %s\n",numread,infilename);
	if (noncub > 0)
	    fprintf(msgfile,">C " COUNTER_FMT " graphs with maxdeg > 3\n",noncub);
	if (nonconn > 0)
	    fprintf(msgfile,">C " COUNTER_FMT " graphs not %sconnected\n",
			    nonconn,biconn ? "bi" : "tri");
	if (numto > 0)
	    fprintf(msgfile,">C " COUNTER_FMT " graphs timed out\n",numto);
	fprintf(msgfile,
 	    ">Z " COUNTER_FMT " %s graphs written to %s; %3.2f sec\n",
              nonham+numto, e34 ? (e34plus ? "non-e34+" : "non-e34") :
	            inout ? "non-inout" : 
                        out ? "non-out" :
		            in ? "non-in" : "nonhamiltonian",
                outfilename,t1-t0);
	if (verbose)
	{
	    fprintf(msgfile,"Tries:"); 
	    for (i = 0; i <= NUMMAXNODES && numtries[i] > 0; ++i)
		fprintf(msgfile," " COUNTER_FMT,numtries[i]);
	    fprintf(msgfile,"\n");
	}
#if MAXES
	fprintf(msgfile,"Maximum level = %d; Maximum classstack = %d\n",
		maxlevel,maxclassstack);
#endif

	return 0;
}
