Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/GAP/pkg/grape/nauty2_8_6/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 6.8.2025 mit Größe 144 kB image not shown  

Quelle  watercluster2.c   Sprache: C

 
// cc -O4 -o water2 -DWORDSIZE=32 -DMAXN=WORDSIZE nauty.c naugraph.c nautil.c gtools.c schreier.c naurng.c watercluster2.c

/*
Reads graphs in g6 code or multicode (optional) from stdin and directs them 

options: 

ix  means: the indegree of every vertex may be at most x.

oy  means: the outdegree of every vertex may be at most y.

  S  means: allow that for every pair of vertices x,y at most one of the edges x-->y 
     and y-->x may be present. By default both of them may be present in the same graph.


  T  means: Output directed graphs in T-code. This is a simple ASCII output format. Every line
     contains one graph. First the number of vertices, then the number of 
     directed edges and then the list of directed edges with the start first 
     and the end then. E.g.: 3 2 0 1 2 1 means 3 vertices, 2 directed edges:
     0-->1 and 2-->1

  B  means: Output the directed graphs in a binary code. Every item of the code is an unsigned
     char. The first unsigned char is the number nv of vertices. The vertices are numbered 1..nv
     Then the list of vertices x for which there is a directed edge 1->x follow. This list is
     ended by a 0. Then the list of outgoing neighbours of 2 follows -- again ended with a 0, etc.
     The code is complete with the 0 ending the list of outgoing neighbours of nv.

  Z  means: Output the directed graphs in digraph6 code. See formats.txt for a complete definition.

  C  means: Do really construct all the directed graphs in memory, but don't output them. This is not
     a big difference in case of restricted in- and outdegrees, because all that is done extra is that 
     edges are directed instead of just keeping track of in- and out-degrees. This option is intended only
     for testing purposes to test also routines that are normally not used when counting. Things that would 
     speed up the counting also in some cases of restricted in- and out-degrees -- like multiplying the 
     possibilities of assigning directions to edges that can be assigned directions independent 
     of each other (depending on the degrees of the endvertices and overlaps) -- are not included. 
     In case of not restrictive bounds on the in- and out-degree it not really constructing the graphs
     can be considerably faster. In cases of restricted in- and out-degrees the only difference is that
     the graph isn't modified...
     The fact that in case of no output the graph is not modified is mainly to save time for the one 
     case of waterclusters, where large numbers were determined. If large numbers (without output)
     for other cases shall be determined, one should think about adding the multiplication routines.

   m read multicode

This program uses different labelling routines -- all based on the ideas of 

G. Brinkmann, Generating water clusters and other directed graphs,
Journal of Mathematical Chemistry 46, 1112--1121 (2009)

October 10, 2011: corrected error caused by overflow of 32bit int used as hashvalue.

Sep, 2012: PROCESS feature added by BDM.

Oct, 2017: digraph6 output added by BDM.
*/


/* PROCESS feature
 *
 * If PROCESS is defined, it must expand as the name of a procedure
 * with prototype like void PROCESS(FILE *f, graph *g, int n). This
 * procedure will be called for each output graph before it is
 * output (or before output is suppressed) with f being the output
 * file (possibly NULL).
 * It is an error if n > WORDSIZE.
 * If NOCONVERSE is also defined, the call is only made for one of
 * each digraph and its converse.
 */


/* SUMMARY feature
 *
 * If SUMMARY is defined, it must expand as the name of a procedure
 * with prototype  void SUMMARY(void).  It is called at the end after
 * the normal summary. 
 */


//#include<stdio.h>
#include "gtools.h"
#include <limits.h>
#include <string.h>

#ifdef PROCESS
extern void PROCESS(FILE*,graph*,int);
nauty_counter dg_nin,dg_nout;
#endif
#ifdef SUMMARY
extern void SUMMARY(void);
#endif

#define MAX_BOGEN ((MAXN*(MAXN-1))/2)
#define INFTY_UCHAR UCHAR_MAX
typedef int BOOG[2];

void nontrivlabels(), init_nauty_options();

BOOG edgelist[MAX_BOGEN+1]; /* de lijst van bogen */
BOOG edgelist_final[MAX_BOGEN+1]; /* de lijst van bogen die nadat er eerst nontriviale automorphismen waren die dan 
                                  verdwenen nog gericht moeten worden.*/

BOOG *laatstepositie; /* The last position in one of these lists. Global in order not to have to copy it every time */

/* all the next variables must be evaluated immediately when orbits are constructed. They are reused in the next
   iteration */

unsigned char *operations=NULL;
int *root_op=NULL, size_root=0, blocklength, orbitblocklength[MAXN], size_operations=0, number_operations=0;
/* these arrays will be dynamically allocated and extended. Operations will be an array with "blocks" of length
   "blocklength=tobedirected[vertex_in_orbit]+3". They represent an operation the following way: the first entry is the central
   vertex then the list of vertices from which only edges come in -- ended by INFTY_UCHAR, then the list of vertices 
   to which only outgoing edges go -- ended by INFTY_UCHAR. Then the list of vertices to which incoming AND outgoing 
   edges go -- ended by INFTY_UCHAR. 

   root has as many entries as there are blocks in operations. root[i]=j means that when computing the orbits of
   operations and constructing a union-find-tree, block number j is the root of the tree containing vertex i. */


unsigned char *remember_operations[MAXN]; //the nonequivalent operations that are stored for every iteration
int remember_size[MAXN]; // remember_size[i] is the number of characters allocated for remember_operations[i]

#define COPYBOOG(a,b) { (a)[0]=(b)[0]; (a)[1]=(b)[1]; }


/* OPTIONS */
boolean dummybool;
int mingerichtdeg;
int remaining_doubles=0; /* hoeveel bogen kunnen ten hoogste nog in allebei 
                            richtingen gericht worden ? */

int watermaxedges; /* what is the theoretical maximum for the number of edges which can
                      directed in a way that doesn't give a conflict with the in/out-degree
                      bounds. */

int watermaxdeg; /* maxindeg+maxoutdeg */

int is_gericht[MAX_BOGEN][MAX_BOGEN]={{0}}; /*  is_gericht[i][j]==1 als {i,j} is al gericht -- anders 0 */
int virtual_gericht[MAX_BOGEN][MAX_BOGEN]={{0}}; /*  virtual_gericht[i][j]==1 als het al vastgelegd is dat {i,j} 
                                                    i->j gericht moet worden, 2 als hij j->i gericht moet worden
                                                    en 0 als het nog niet vastgelegd is. Vastgelegd betekent door
                                                    de beperkingen van in- en outgraad moet deze boog zo gericht 
                                                    worden. */

int positie[MAXN][MAXN]; /* the value of positie[i][j] is the position of edge {1,j} in edgelist in case of
                            nontrivial automorphisms of the underlying undirected graph. */


int virtual_indeg[MAXN], virtual_outdeg[MAXN]; 
                                               /* de graden als de nog niet gerichte maar al vastgelegde 
                                                  bogen meegerekend worden -- dat mag niet voor kanoniciteit 
                                                  gebruikt worden */

int nextstep_depth; 

#define SWITCHPAR_ORBSIZE 5 // when does serial orbit labelling switch to parallel -- and stay there
#define MAXPAR_ORBSIZE 9 // maximum 16, when changing, change following MAXPAROPS too
#define MAXPAROPS 19683 // set to minimum 3^MAXPAR_ORBSIZE
unsigned int parops[MAXPAROPS];
// in the case of no degree restrictions this could in fact be permanently filled in -- only depending
// on the edge orbit size. But the time for filling it in is so small that it is simply not worth it.
int number_parops; 
// an operation is defined as follows: if edge number i in kleinste_orbit must be directed kleinste_orbit[i][0]->kleinste_orbit[i][1],
// bits 2i and 2i+1 form the number 0 (so are both 0). For kleinste_orbit[i][0]<-kleinste_orbit[i][1] they form 2, for
// a double edge they form 1 ---- so 2-type is always the inverse
#define SETOP(op,edge,type) ((op) = ((op) & ~(3<<((edge)<<1))) | (type)<<((edge)<<1))
#define GETTYPE(op,edge) (((op)>>((edge)<<1))&3)

/* for the following macros global variables _x_ and _y_ are used */
int _x_, _y_;
#define BILDBOOG_UNDIR(startboog,bildboog,permnummer) \
  { _x_=generators[permnummer][(startboog)[0]]; _y_=generators[permnummer][(startboog)[1]]; \
if (_x_<_y_) { (bildboog)[0]=_x_; (bildboog)[1]=_y_; } else  { (bildboog)[0]=_y_; (bildboog)[1]=_x_; }}
#define BILDBOOG(startboog,bildboog,permnummer) \
  { (bildboog)[0]=generators[permnummer][(startboog)[0]]; (bildboog)[1]=generators[permnummer][(startboog)[1]]; }
#define POSBILD(startboog,permnummer) \
  (positie[generators[permnummer][(startboog)[0]]][generators[permnummer][(startboog)[1]]])

/* a macro that sets numbers a and b equivalent to a */
#define SETEQUIV(a,b) { _y_=(b); while ((_x_=number[_y_])!=_y_) { number[_y_]=(a); _y_=_x_; } number[_y_]=(a); } 
/* zorgt ervoor dat nummer[a] zo is dat nummer[nummer[a]]=nummer[a] */
#define UPDATENUMBER(a) { _y_=(a); while ((_x_=number[_y_])!=_y_) { number[_y_]=number[_x_]; _y_=number[_y_]; } number[a]=number[_y_]; } 

/* the quality of a directed edge */
#define QUALITY(a,b) (((saturated[a]+saturated[b])<<6)+colour[nextstep_depth][a])
// upper bound for the quality if the in- or out-deg of one of the entries is changed by one
#define QUALITY_P1(a,b) (((saturated[a]+saturated[b]+1)<<6)+colour[nextstep_depth][a])
// quality if the in- or out-deg of one of the entries are both changed by one
#define QUALITY_P2(a,b) (((saturated[a]+saturated[b]+2)<<6)+colour[nextstep_depth][a])

int _marks[MAX_BOGEN], _markvalue=INT_MAX;
#define RESETMARKS { int i; if (_markvalue<INT_MAX) _markvalue++; else { _markvalue=1; \
                     for (i=0;i<MAX_BOGEN;i++) _marks[i]=0; } }
#define ISMARKED(i) (_marks[i]==_markvalue)
#define UNMARKED(i) (_marks[i]!=_markvalue)
#define MARK(i) {_marks[i]=_markvalue;}

long long int onlevel[MAX_BOGEN]={0};

/* variabelen voor nauty: */
int lab[MAX_BOGEN][MAXN]={{0}}, ptn[MAX_BOGEN][MAXN]={{0}}, orbits[MAX_BOGEN], colour[MAX_BOGEN][MAXN]={{0}};
/* MAX_BOGEN is zeker te veel -- maar wat zou een goede bovengrens zijn ? */
/* in the arrays lab[i][] and ptn[i][] the partition is stored after having labelled i orbits 
   completely. lab[0][] and ptn[0][] are the partitions as computed for the original graph. */

int rememberorbits[MAXN][MAXN];

int bufferlab[MAXN], bufferptn[MAXN];
graph canong[MAXN];
/* make sure these are always evaluated at once, because they are reused whenever new
   edges are directed */

graph workg[MAXN], staticg[MAXN], canong[MAXN];
graph bit_orbit[MAXN];
int deg[MAXN]={0}, outdeg[MAXN]={0}, indeg[MAXN]={0};
int tobedirected[MAXN]={0}; /* how many edges have still to be directed? This can
   also be used to detect whether an edge that is in both directions is a double edge or 
   just not yet directed in the routines for nontrivial symmetry. It is a double edge if 
   and only if one of the endpoints is ready with ready defines as: */

#define READY(i) (tobedirected[i]==0)
#define NOT_READY(i) (tobedirected[i]>0)
int aantal_toppen, aantal_bogen, aantal_gerichte_bogen;
int max_doubles;
int double_free[MAXN]={0}; /* hoeveel dubbele bogen kan top [i] nog krijgen? */

long long int addnumber=0; /* How much must the counter be increased if a graph
                              is found. Just relevant in case not all are really constructed and coded.
                              Then this gives a speedup.*/


long long int aantal_grafen_met_triv_group=0LL;
long long int aantal_gerichte_grafen=0LL;

static DEFAULTOPTIONS(options_directed);
static DEFAULTOPTIONS(options_directed_canon);
static DEFAULTOPTIONS(options);
static DEFAULTOPTIONS(options_final);
static statsblk stats;
setword workspace[100*MAXN];

int generators[MAXN][MAXN];
int number_of_generators;
int group_up_to_date=0;

int indeg_free[MAXN]={0}, outdeg_free[MAXN]={0}, saturated[MAXN]={0};

graph all; // the set of all vertices

int orbitchoices[MAXN]={0};

#define CSIZE 32768
int _colourmarks[CSIZE], _cmark=INT_MAX;
#define RESETMARKS_COLOUR { int i; \
                            if (_cmark==INT_MAX)\
                                     { for (i=0;i<CSIZE;i++) _colourmarks[i]=0; _cmark=1; }\
                            else _cmark++; }
#define MARK_COLOUR(a) {_colourmarks[a]=_cmark;}
#define ISMARKED_COLOUR(a) (_colourmarks[a]==_cmark)

void directorbit();
graph* readg();
void parallel_orbit_labelling();

//unsigned int waterclusteruse=0UL, water_v_use=0UL;

/****OPTIONS******/
int maxindeg=MAXN, maxoutdeg=MAXN, maxdirectdeg=MAXN, nodegbound=1;
int double_allowed=1, direct_output=0;

#define NEXTEL(a,b) (b)=FIRSTBIT((a)& BITMASK(b)) /*(b)++, b=FIRSTBIT((a)<<(b))+(b)*/
#define FORALLELEMENTS(x,y) for (y= FIRSTBIT(x); y<WORDSIZE; NEXTEL((x),(y)))
#define FORALLELEMENTS_BOUND(x,y,b) for (y=FIRSTBIT((x)& BITMASK(b)) ; y<WORDSIZE; NEXTEL((x),(y)))
/* Attention: bound is a lower bound and the first possible value is bound+1 ! */

#define WRITEUP() { aantal_gerichte_grafen+=addnumber; if (direct_output==1) {writeTcode(workg,aantal_toppen);\
if (addnumber==2) writeTcode_invers(workg,aantal_toppen);} else if (direct_output==3) \
{writeBcode(workg,aantal_toppen);\
if (addnumber==2) writeBcode_invers(workg,aantal_toppen);} else if (direct_output==4) \
{writeZcode(workg,aantal_toppen);\
if (addnumber==2) writeZcode_invers(workg,aantal_toppen);} }
#define WRITEUP_COUNT() { aantal_gerichte_grafen+=addnumber; }

#ifdef PROCESS
 void callprocess(graph *g, int aantal_toppen)
   { int i,j; graph gconv[MAXN];

     dg_nout = aantal_gerichte_grafen+1;
     PROCESS(stdout,g,aantal_toppen);
#ifndef NOCONVERSE
     if (addnumber==2)
       {
          EMPTYSET(gconv,aantal_toppen);
          for (i=0; i<aantal_toppen;i++)
            { 
               FORALLELEMENTS(g[i],j) ADDELEMENT(gconv+j,i);
            }
            ++dg_nout;
          PROCESS(stdout,gconv,aantal_toppen);
       }
#endif
   }
#define MAYBEPROCESS callprocess(workg,aantal_toppen)
#else
#define MAYBEPROCESS
#endif

 void writeTcode(graph *g, int aantal_toppen)
   { int i,j;

   fprintf(stdout,"%d %d",aantal_toppen,aantal_bogen+max_doubles-remaining_doubles);
   for (i=0; i<aantal_toppen;i++) 
     { 
       FORALLELEMENTS(g[i],j) fprintf(stdout," %d %d",i,j);
     }
       fprintf(stdout,"\n");
   }

 void writeTcode_invers(graph *g, int aantal_toppen)
   { int i,j;

   fprintf(stdout,"%d %d",aantal_toppen,aantal_bogen+max_doubles-remaining_doubles);
   for (i=0; i<aantal_toppen;i++) 
     { 
       FORALLELEMENTS(g[i],j) fprintf(stdout," %d %d",j,i);
     }

       fprintf(stdout,"\n");
   }

 void writeBcode(graph *g, int aantal_toppen)
   { int i,j;
   putc(aantal_toppen,stdout);
   for (i=0; i<aantal_toppen;i++) 
     { 
       FORALLELEMENTS(g[i],j) putc(j+1,stdout);
       putc(0,stdout);
     }
   }

 void writeBcode_invers(graph *g, int aantal_toppen)
   { int i,j;
     int lijst[MAXN][MAXN], lengte[MAXN];
     putc(aantal_toppen,stdout);

     for (i=0; i<aantal_toppen;i++) lengte[i]=0;
     for (i=0; i<aantal_toppen;i++) 
       { 
         FORALLELEMENTS(g[i],j) { lijst[j][lengte[j]]=i+1; lengte[j]++; }
       }
     for (i=0; i<aantal_toppen;i++)
       { for (j=0; j<lengte[i]; j++) putc(lijst[i][j],stdout);
         putc(0,stdout);
       }
   }

  void writeZcode(graph *g, int aantal_toppen)     /* BDM */
    { 
        writed6(stdout,g,1,aantal_toppen);
    }

  void writeZcode_invers(graph *g, int aantal_toppen)    /* BDM */
    { int i,j;
      setword w;
      graph h[MAXN];

      for (i = 0; i < aantal_toppen; ++i) h[i] = 0;

      for (i = 0; i < aantal_toppen; ++i)
        {
          w = g[i];
          while (w) { TAKEBIT(j,w); h[j] |= bit[i]; }
        }
      writed6(stdout,h,1,aantal_toppen);
    }

void writelab(int ptn[], int lab[])
{
  int i;

  for (i=0; i<aantal_toppen; i++) 
    { fprintf(stderr," %d ",lab[i]); if (ptn[i]==0) fprintf(stderr,"|| "); }
  fprintf(stderr,"\n");

  return;
}

void writeset(graph set)
int i;
  fprintf(stderr,"The set:\n");
  FORALLELEMENTS(set,i) fprintf(stderr,"%d ",i);
  fprintf(stderr,"\n");
}

void writeoperation(unsigned char op[])
int i,counter;

  fprintf(stderr,"Operation: ");
  for (i=counter=0; counter<3; i++)
    {
      if (op[i]==INFTY_UCHAR) { fprintf(stderr," ||"); counter++; }
      else fprintf(stderr," %d",op[i]);
    }
  fprintf(stderr,"\n");
}

void writelist(int list[])
{
  int i;

  for (i=0;list[i]>=0;i++) fprintf(stderr,"%d ",list[i]); fprintf(stderr,"\n");
}

 void writegraph(graph *g)
 // for graphs as they are used in the vertexorbit routines
   { int i,j;
     static int counter=0;
   fprintf(stderr,"---------------------------------------------------------\n");
   fprintf(stderr,"Graph number %d with %d vertices\n",++counter,aantal_toppen);
   for (i=0; i<aantal_toppen;i++) 
     { fprintf(stderr,"%d:",i);
       FORALLELEMENTS(g[i],j) 
         { fprintf(stderr," %d", j);
           if (READY(i) || READY(j)) 
             { 
               if (ISELEMENT(g+j,i)) fprintf(stderr,"[d]"); else fprintf(stderr,"[s]");
             }
               else fprintf(stderr,"[ng]");
         }
       fprintf(stderr,"\n");
     }
   fprintf(stderr,"---------------------------------------------------------\n");
   }


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

void sammle_permutationen(int count, int perm[], int orbits[],
                          int numorbits, int stabvertex, int n)
{
  memcpy(generators+number_of_generators,perm,sizeof(int)*n);

  number_of_generators++;
}


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

void init_nauty_options()
/* initialises the nauty variables */
{
 /* tc_level = 0 is not the default in the most recent
    editions of nauty.  However, it is better for very small
    graphs so we set it here. */


options.getcanon=FALSE;
options.userautomproc = sammle_permutationen;
options.defaultptn=TRUE;
options.writeautoms=FALSE;
options.writemarkers=FALSE;
options.digraph=FALSE;
options.tc_level = 0;


options_directed.getcanon=FALSE;
options_directed.userautomproc = sammle_permutationen;
options_directed.defaultptn=FALSE;
options_directed.writeautoms=FALSE;
options_directed.writemarkers=FALSE;
options_directed.digraph=TRUE;
options_directed.tc_level = 0;

options_directed_canon.getcanon=TRUE;
options_directed_canon.userautomproc = sammle_permutationen;
options_directed_canon.defaultptn=FALSE;
options_directed_canon.writeautoms=FALSE;
options_directed_canon.writemarkers=FALSE;
options_directed_canon.digraph=TRUE;
options_directed_canon.tc_level = 0;


options_final.getcanon=TRUE;
options_final.defaultptn=TRUE;
options_final.writeautoms=FALSE;
options_final.writemarkers=FALSE;
options_final.digraph=TRUE;
options_final.tc_level = 0;
}

/****************************LESE_MULTICODE************************/

int lese_multicode(unsigned char**code, int *codelaenge, FILE *fil)

/* Liest den code und gibt EOF zurueck, wenn das Ende der Datei erreicht
   ist, 1 sonst. Der Speicher fuer den code wird alloziert, falls noetig,
   was entschieden wird anhand der lokalen Variablen maxknotenzahl */

{
static int maxknotenzahl= -1;
int codel, gepuffert=0;
int knotenzahl,a=0,b=0,nuller;
unsigned char ucharpuffer;

if ((knotenzahl=getc(fil))==EOF) return EOF;
if (knotenzahl==0) { fprintf(stderr,"Umschaltung auf short noch nicht implementiert.\n");
                     exit(0);
                    } 
nuller=0; codel=1;
if (knotenzahl=='>'/* koennte ein header sein -- oder 'ne 62, also ausreichend fuer
                             unsigned char */

      { gepuffert=1;
        a=getc(fil);
        if(a==0) nuller++; 
        b=getc(fil);
        if(b==0) nuller++; 
        /* jetzt wurden 3 Zeichen gelesen */
        if ((a=='>') && (b=='m')) /*garantiert header*/
          { while ((ucharpuffer=getc(fil)) != '<') {}
            /* noch zweimal: */ ucharpuffer=getc(fil); 
            if (ucharpuffer!='<') { fprintf(stderr,"Problems with header -- single '<'\n"); exit(1); }
            if ((knotenzahl=getc(fil))==EOF) return EOF;
            /* kein graph drin */
          }
        /* else kein header */
      }


if (knotenzahl > maxknotenzahl)
  { if (*code) free(*code);
    *code=(unsigned char *)malloc((knotenzahl*(knotenzahl-1)/2+knotenzahl)*sizeof(unsigned char));
    if (code==NULL) { fprintf(stderr,"Do not get memory for code\n"); exit(0); }
    maxknotenzahl=knotenzahl;
  }

(*code)[0]=knotenzahl; if (gepuffert) { codel=3; (*code)[1]=a; (*code)[2]=b; }

while (nuller<knotenzahl-1)
  { if (((*code)[codel]=getc(fil))==0) nuller++;
    codel++; }

*codelaenge=codel;
return 1;
}


void usage(char name[])
{

  fprintf(stderr,"\nUsage: %s [ix] [oy] [m] [T] [C] [B] [Z] [S]\n",name);
  fprintf(stderr," Read undirected graphs and orient them in various ways.\n\n");
  fprintf(stderr,"The option ix restricts the maximum indegree to x.\n");
  fprintf(stderr,"The option oy restricts the maximum outdegree to y.\n");
  fprintf(stderr,"The default maximum in- and out-degrees are unlimited. \n");
  fprintf(stderr,"T means: Output directed graphs in T-code -- for details see header\n");
  fprintf(stderr,"B means: Output directed graphs in binary code -- for details see header\n");
  fprintf(stderr,"Z means: Output directed graphs in digraph6 code\n");
  fprintf(stderr,"C means: Do really construct all the directed graphs in memory,\n"
                 " but don't output them (default)\n");
  fprintf(stderr,"S means that for each edge only one direction must be chosen -- not both.\n");
  fprintf(stderr,"Default is that both are allowed\n");
  fprintf(stderr," -- so the edge a-b can become a->b AND b->a in the same output graph.\n");
  fprintf(stderr,"m means: read multicode instead of g6 code \n");
  exit(1);

}

/**********DECODE_TO_NAUTY****************************************************/

void decode_to_nauty(unsigned char *code, int codelaenge, graph *g, int degree[]) 


  /* Dekodiert multicode nach nauty bitcode */

  /* alle knotennamen muessen fuer nauty um 1 nach unten verschoben werden */

{

  int v1,v2;
  unsigned char *end;

 if (code[0]>32) { fprintf(stderr,"Not prepared for %d>32 vertices.\n",code[0]); exit(2); }
 aantal_toppen=code[0];
 aantal_bogen=codelaenge-aantal_toppen;
 for (v1=0; v1<aantal_toppen; v1++) { EMPTYSET1(g+v1,1); degree[v1]=0; }
 for (v1=0, end=code+codelaenge, code++; code<end; code++) 
   { if (*code==0) v1++;
     else { v2=(*code)-1;
            ADDELEMENT1(g+v1,v2); ADDELEMENT1(g+v2,v1); 
            degree[v1]++; degree[v2]++;
          }
   }
 aantal_gerichte_bogen=0;
 //for (v1=0; v1<aantal_toppen; v1++) tobedirected[v1]=degree[v1];

 return;
}

/****************************************INIT_FOR_G6*****************************/

void init_for_g6(graph g[],int aantal_toppen, int degree[])
{
  int i;

  if (aantal_toppen>32) { fprintf(stderr,"Not prepared for %d>32 vertices.\n",aantal_toppen); exit(2); }
  aantal_bogen=0;

  for (i=0; i<aantal_toppen; i++) { degree[i]=POPCOUNT(g[i]); aantal_bogen+=degree[i]; }
  aantal_bogen = aantal_bogen>>1;
  aantal_gerichte_bogen=0;
  return;

}


/***************************FILL_EDGELIST**************************/

void fill_edgelist()
     /* writes the edges in g into the list in a lexicographic way. 
        Is used if no bounds for in- and out-degree are given
        or few edges are left. */


{
  int i,j,end;

  for (i=j=0; i<aantal_toppen; i++) /* j is de positie in edgelist */
    { indeg_free[i]=maxindeg-indeg[i]; outdeg_free[i]=maxoutdeg-outdeg[i];
      FORALLELEMENTS_BOUND(workg[i],end,i)
        { 
          edgelist[j][0]=i; edgelist[j][1]=end; j++;
        }
    }

}

/***************************FILL_EDGELIST_ORDER**************************/


void fill_edgelist_order()
  /* writes the edges in gg into the list in a way that for i in 1...numberedges we always have
     that the starting point of edge i has the minimum degree of all vertices in the graph you get
     when removing all edges i+1...aantal_bogen from gg.
     The global variable positie is not assigned any values.
 */

{
  int last_positie,i, buffer, olddeg, newdeg, beste, start, end;
  int list[MAXN][MAXN], listlen[MAXN]={0}; /* list[i] contains the vertices with degree i at that moment */
  int toppositie[MAXN], bufferdeg[MAXN]; /* toppositie[i] is de positie van top i in de lijst */
  int buren[MAXN]; /* de buren van de top waaraan gewerkt wordt */
  graph dummy[MAXN];

  if (nodegbound) { fill_edgelist(); return; }

  memcpy(dummy,workg,aantal_toppen*sizeof(graph));

    for (i=0; i<aantal_toppen; i++) 
      { buffer=bufferdeg[i]=deg[i]; list[buffer][listlen[buffer]]=i; 
        toppositie[i]=listlen[buffer]; (listlen[buffer])++; 
        indeg_free[i]=maxindeg-indeg[i]; outdeg_free[i]=maxoutdeg-outdeg[i];}


    last_positie=aantal_bogen-1;
    while (last_positie>=0)
      {
        for (beste=1;listlen[beste]==0; beste++);
        (listlen[beste])--; /* zo wordt hij ook verwijderd */
        start=list[beste][listlen[beste]];
        for (i=0; i<beste; i++) /* alle buren opslaan*/
          { end=buren[i]=FIRSTBIT(dummy[start]); DELELEMENT(dummy+start,end); }

        for (i=0; i<beste; i++) /* alle buren */
          { 
            end=buren[i];
            edgelist[last_positie][0]=start; edgelist[last_positie][1]=end; 
            last_positie--;
            DELELEMENT(dummy+end,start);
            /* de buur verhuizen: */
            olddeg=bufferdeg[end];
            (bufferdeg[end])--;
            newdeg=bufferdeg[end];
            /* uit de oude lijst verwijderen */
            if (listlen[olddeg]==1) listlen[olddeg]=0;
            else { (listlen[olddeg])--;
            buffer= list[olddeg][listlen[olddeg]];
            list[olddeg][toppositie[end]]=buffer;
            toppositie[buffer]=toppositie[end]; }
            /* tot de nieuwe toevoegen */
            if (newdeg)
              { list[newdeg][listlen[newdeg]]=end;
                toppositie[end]=listlen[newdeg];
                (listlen[newdeg])++;
              }
          }

      }

}

/**********************************TRIVLABEL_ROUTINES****************************/

 void trivlabels_nowrite_nodouble(BOOG *positie)
   {
     int start, end;

     start=(*positie)[0]; end=(*positie)[1];

  if (positie==laatstepositie)
    {
     if (indeg_free[start] && outdeg_free[end]) /* bogen kan end->start gericht worden */
       {
         WRITEUP_COUNT();
       }
    if (indeg_free[end] && outdeg_free[start]) /* bogen kan start->end gericht worden */
       { 
         WRITEUP_COUNT();
       }

    return;
    }

  /* else -- niet op laatste positie */

     if (indeg_free[start] && outdeg_free[end]) /* bogen kan end->start gericht worden */
       { 
         (indeg_free[start])--; (outdeg_free[end])--;
         trivlabels_nowrite_nodouble(positie+1);
         (indeg_free[start])++; (outdeg_free[end])++;
       }
    if (indeg_free[end] && outdeg_free[start]) /* bogen kan start->end gericht worden */
       {
         (indeg_free[end])--; (outdeg_free[start])--;
         trivlabels_nowrite_nodouble(positie+1);
         (indeg_free[end])++; (outdeg_free[start])++;
       }
    return;
   }




 void trivlabels_nowrite(BOOG *positie)
   {
     int start, end, counter;

     if (!remaining_doubles) { trivlabels_nowrite_nodouble(positie); return; }

     start=(*positie)[0]; end=(*positie)[1];

  if (positie==laatstepositie)
    {
     if (indeg_free[start] && outdeg_free[end]) /* bogen kan end->start gericht worden */
       { counter=1;
         WRITEUP_COUNT();
       }
     else counter=0;
    if (indeg_free[end] && outdeg_free[start]) /* bogen kan start->end gericht worden */
       { counter++;
         WRITEUP_COUNT();
       }
    if (remaining_doubles && (counter==2)) WRITEUP_COUNT();

    return;
    }

  /* else -- niet op laatste positie */

     if (indeg_free[start] && outdeg_free[end]) /* bogen kan end->start gericht worden */
       { counter=1;
         (indeg_free[start])--; (outdeg_free[end])--;
         trivlabels_nowrite(positie+1);
         (indeg_free[start])++; (outdeg_free[end])++;
       }
     else counter=0;
    if (indeg_free[end] && outdeg_free[start]) /* bogen kan start->end gericht worden */
       { counter++;
         (indeg_free[end])--; (outdeg_free[start])--;
         trivlabels_nowrite(positie+1);
         (indeg_free[end])++; (outdeg_free[start])++;
       }
    if (remaining_doubles && (counter==2) && double_free[start] && double_free[end])
      {
         (indeg_free[end])--; (outdeg_free[start])--;
         (indeg_free[start])--; (outdeg_free[end])--;
         double_free[start]--; double_free[end]--;
         remaining_doubles--;
         trivlabels_nowrite(positie+1);
         remaining_doubles++;
         double_free[start]++; double_free[end]++;
         (indeg_free[end])++; (outdeg_free[start])++;
         (indeg_free[start])++; (outdeg_free[end])++;
      }
    return;
   }


 void trivlabels(BOOG *positie)
   {
     int start, end, counter;

  start=(*positie)[0]; end=(*positie)[1];

  

  if (positie==laatstepositie)
    {
     if (indeg_free[start] && outdeg_free[end]) /* bogen kan end->start gericht worden */
       { counter=1;
         //(indeg_free[start])--; (outdeg_free[end])--;
         DELELEMENT(workg+start,end);
         MAYBEPROCESS;
         WRITEUP();
         ADDELEMENT(workg+start,end);
         //(indeg_free[start])++; (outdeg_free[end])++;
       }
     else counter=0;
    if (indeg_free[end] && outdeg_free[start]) /* bogen kan start->end gericht worden */
      {  counter++;
        //(indeg_free[end])--; (outdeg_free[start])--;
         DELELEMENT(workg+end,start);
         MAYBEPROCESS;
         WRITEUP();
         ADDELEMENT(workg+end,start);
         //(indeg_free[end])++; (outdeg_free[start])++;
       }
    if (remaining_doubles && (counter==2)) { remaining_doubles--; MAYBEPROCESS; WRITEUP(); remaining_doubles++; }
    return;
    }

  /* else -- niet op laatste positie */

     if (indeg_free[start] && outdeg_free[end]) /* bogen kan end->start gericht worden */
       { counter=1;
         (indeg_free[start])--; (outdeg_free[end])--;
         DELELEMENT(workg+start,end);
         trivlabels(positie+1);
         ADDELEMENT(workg+start,end);
         (indeg_free[start])++; (outdeg_free[end])++;
       }
     else counter=0;
    if (indeg_free[end] && outdeg_free[start]) /* bogen kan start->end gericht worden */
      {  counter++;
         (indeg_free[end])--; (outdeg_free[start])--;
         DELELEMENT(workg+end,start);
         trivlabels(positie+1);
         ADDELEMENT(workg+end,start);
         (indeg_free[end])++; (outdeg_free[start])++;
       }
    if (remaining_doubles && (counter==2) && double_free[start] && double_free[end])
      {
         (indeg_free[end])--; (outdeg_free[start])--;
         (indeg_free[start])--; (outdeg_free[end])--;
         double_free[start]--; double_free[end]--;
         remaining_doubles--;
         trivlabels(positie+1);
         remaining_doubles++;
         double_free[start]++; double_free[end]++;
         (indeg_free[end])++; (outdeg_free[start])++;
         (indeg_free[start])++; (outdeg_free[end])++;
      }

    return;
   }


 void trivlabels_init(BOOG *positie)
   {
     int remember;

     if (!direct_output) 
       { if (nodegbound)
         { remember=addnumber;
           if (remaining_doubles) { for (;positie<=laatstepositie;positie++) addnumber*=3;}
           else { for (;positie<=laatstepositie;positie++) addnumber*=2;}
           WRITEUP();
           addnumber=remember;
           return;
           }
       /* else */
         if (!remaining_doubles) trivlabels_nowrite_nodouble(positie);
           else trivlabels_nowrite(positie); 
         return
       }
     /* else */
     trivlabels(positie); 
     return;
   }



/******************************DIRECT_ALL_TRIV********************************/

void direct_all_triv()
{
  int i, start, end;

  aantal_grafen_met_triv_group++; 
  if (nodegbound) fill_edgelist(); else fill_edgelist_order();
  for (i=0;i<aantal_toppen;i++) double_free[i]=maxdirectdeg-deg[i];
  laatstepositie=edgelist+aantal_bogen-1;
  if (maxoutdeg==maxindeg) /* then every valid graph for one direction is also valid with
                              the directions reversed */

    { 
      addnumber=2;
      start=edgelist[0][0]; end=edgelist[0][1];
      /* is_gericht[][] isn't used in the directing routine */
      (outdeg_free[start])--; (indeg_free[end])--;
      //virtual_outdeg[start]++; virtual_indeg[end]++;
      DELELEMENT(workg+end,start);
      aantal_gerichte_bogen=1;
      trivlabels_init(edgelist+1);
      aantal_gerichte_bogen=0;
      ADDELEMENT(workg+end,start);
      (outdeg_free[start])++; (indeg_free[end])++;
      
      if (remaining_doubles && double_free[start] && double_free[end])
        {
          addnumber=1; 
          (outdeg_free[start])--; (indeg_free[end])--;
          (outdeg_free[end])--; (indeg_free[start])--;
          double_free[start]--; double_free[end]--;
          aantal_gerichte_bogen=1;
          remaining_doubles--;
          trivlabels_init(edgelist+1);
          remaining_doubles++;
          double_free[start]++; double_free[end]++;
          (outdeg_free[start])++; (indeg_free[end])++;
          (outdeg_free[end])++; (indeg_free[start])++;
          aantal_gerichte_bogen=0;
        }
    }
  else
    {
      addnumber=1;
      aantal_gerichte_bogen=0;
      trivlabels_init(edgelist);
      aantal_gerichte_bogen=0;
    }
  return;

}

/*********************************SORT_DECREASING**********************************/

#define WISSEL(a,b) { buffer=(a); (a)=(b); (b)=buffer; }

void sort_decreasing(int list[], int number)
{
  // only very small numbers have to be sorted, so better simple

  int buffer,i,j;

  if (number==2)
    { if (list[0]<list[1]) WISSEL(list[0],list[1])
      return;
    }
  if (number==3)
    {
      if (list[0]<list[1])
        { if (list[1]<list[2]) // l0<l1<l2
            { WISSEL(list[0],list[2]) }
          else // l1>l0 l1>l2
            { if (list[0]<list[2]) // l0<l2<l1
                { buffer=list[0]; list[0]=list[1]; list[1]=list[2]; list[2]=buffer; }
              else // l2<l0<l1
                { WISSEL(list[0],list[1]) }
            }
        }
      else // l1<l0
        { if (list[0]<list[2]) // l1<l0<l2
            { buffer=list[0]; list[0]=list[2]; list[2]=list[1]; list[1]=buffer; }
          else // l1<l0 l2<l0
            { if (list[1]<list[2]) // l1<l2<l0
                { WISSEL(list[2],list[1]) }
              //else // l2<l1<l0 -- OK
            }
        }
      return;
    }
  if (number>3) //should hardly ever happen and then "number" is still small -- bubblesort
    {
      for (i=number-1; i ; i--)
        for (j=0;j<i;j++)
          if (list[j]<list[j+1]) WISSEL(list[j],list[j+1])
    }

  return;

}



/**********************************COMPUTE_IMAGE_OPERATION**************************/

int compute_image_operation(unsigned char image[], unsigned char original[], int generator[])
// returns 1 if image and original differ and 0 otherwise
{
  int in_image[MAXN], out_image[MAXN], double_image[MAXN];
  int run, num_in, num_out, num_double, change;

  change=0;

  image[0]=generator[original[0]];

  if (original[0]!=image[0]) change=1;

  for (run=1, num_in=0; original[run]!=INFTY_UCHAR; run++) 
    { in_image[num_in]=generator[original[run]]; num_in++; }

  for (run++, num_out=0; original[run]!=INFTY_UCHAR; run++) 
    { out_image[num_out]=generator[original[run]]; num_out++; }

  for (run++, num_double=0; (run<blocklength) && (original[run]!=INFTY_UCHAR); run++) 
    { double_image[num_double]=generator[original[run]]; num_double++; }

  if (num_in>1) sort_decreasing(in_image,num_in);
  if (num_out>1) sort_decreasing(out_image,num_out);
  if (num_double>1) sort_decreasing(double_image,num_double);


  for (run=1 ; num_in; run++) 
    { num_in--; image[run]=in_image[num_in]; if (original[run]!=image[run]) change=1;}
  image[run]=INFTY_UCHAR; run++;
  for ( ; num_out; run++) 
    { num_out--; image[run]=out_image[num_out]; if (original[run]!=image[run]) change=1;}
  image[run]=INFTY_UCHAR; run++;
  for ( ; num_double; run++) 
    { num_double--; image[run]=double_image[num_double]; if (original[run]!=image[run]) change=1;}
  image[run]=INFTY_UCHAR;
  //for ( ;run<blocklength;run++) image[run]=INFTY_UCHAR;

  return change;

}


/**********************************CONSTRUCT_OPERATIONS_ONE**************************/

void construct_operations_one(int center, int end, int do_inedge, int do_outedge, int do_double)
{
  static unsigned char *buffer;
  unsigned char *start;

  if (size_operations<=((number_operations+1)*blocklength)) 
    { buffer=operations;
      operations=malloc((size_t)(2*size_operations));
      if (operations==NULL) 
        { fprintf(stderr,"Can't allocate %d bytes for operations -- exiting\n",2*size_operations); 
          exit(1); }
      memcpy(operations,buffer,size_operations);
      free(buffer);
      size_operations *= 2;
    }

  if (do_inedge && (indeg[center] < maxindeg) && (outdeg[end]<maxoutdeg))
    { start=operations+(number_operations*blocklength);
      start[0]=center; start[1]=end; start[2]=start[3]=start[4]=INFTY_UCHAR;
      number_operations++;
    }

  if (do_outedge && (indeg[end] < maxindeg) && (outdeg[center]<maxoutdeg))
    { start=operations+(number_operations*blocklength);
      start[0]=center; start[2]=end; start[1]=start[3]=start[4]=INFTY_UCHAR;
      number_operations++;
    }

  if (do_double && double_free[center] && 
      (indeg[end] < maxindeg) && (indeg[center] < maxindeg) &&
      (outdeg[center]<maxoutdeg) && (outdeg[end]<maxoutdeg))
    { start=operations+(number_operations*blocklength);
      start[0]=center; start[3]=end; start[1]=start[2]=start[4]=INFTY_UCHAR;
      number_operations++;
    }

  return;

}



/**********************************CONSTRUCT_OPERATIONS_FINAL**************************/

void construct_operations_final(int list[], int decided[],unsigned char buffer_op[], 
                                int positie, int numberin, int numberout)
{
  int i, center;
  static unsigned char *buffer;

  /* here about position "positie" of the operation is decided. If "positie==blocklength"
     we are done. 

     This function decides on double edges.

  */



  if (size_operations<=((number_operations+1)*blocklength)) 
    { buffer=operations;
      operations=malloc((size_t)(2*size_operations));
      if (operations==NULL) 
        { fprintf(stderr,"Can't allocate %d bytes for operations -- exiting\n",2*size_operations); 
          exit(1); }
      memcpy(operations,buffer,size_operations);
      free(buffer);
      size_operations *= 2;
    }

  center=buffer_op[0];
  // double_free[center] must be tested inside the loop to make sure
  // that it only leads to rejection if all edges have already been assigned
  
  if (double_free[center])// otherwise the rest was filled in in the previous step
        for (i=0;list[i]>=0;i++)
          if (!decided[i])
            { 
              if ( double_free[center] && double_free[list[i]] &&
                   ((outdeg[center]+numberout < maxoutdeg) && (indeg[list[i]]<maxindeg)) &&
                   ((indeg[center]+numberin < maxindeg) && (outdeg[list[i]]<maxoutdeg)))
                {
                  buffer_op[positie]=list[i];
                  positie++; numberout++; numberin++;
                }
              else return;
            }

  buffer_op[positie]=INFTY_UCHAR; positie++;

  memcpy(operations+(number_operations*blocklength),buffer_op,positie);
  number_operations++;
  return;

}


/**********************************CONSTRUCT_OPERATIONS_OUT**************************/

void construct_operations_out(int list[],int liststart, int decided[],unsigned char buffer_op[], 
                              int positie, int numberin, int numberout, int lowerlimit_outdeg,
                              int mindouble)
{
  int i, center, buffer;
  static int outdeg_larger;

  /* here about position "positie" of the operation is decided. If "positie==blocklength"
     we are done. 

     This function decides on outgoing edges.

     liststart ensures that no earlier -- smaller -- entries are written after larger ones
     unless there has been an INFTY_UCHAR to separate them.
  */


  center=buffer_op[0];

  if (numberout==0) // just test once
    { buffer=outdeg[center] + tobedirected[center] -numberin;
      if (buffer<lowerlimit_outdeg) return;
      else
        { if (buffer>lowerlimit_outdeg) outdeg_larger=1; else outdeg_larger=0; }
    }

  if (double_free[center]) // then there is still something to decide
    { if (outdeg[center]+numberout < maxoutdeg)
        for (i=liststart;list[i]>=0;i++)
          if (!decided[i])
            { 
              if (indeg[list[i]]<maxindeg)
                { decided[i]=1;
                  buffer_op[positie]=list[i];
                  construct_operations_out(list,i+1,decided,buffer_op,positie+1,
                                             numberin, numberout+1,lowerlimit_outdeg,mindouble);
                  decided[i]=0;
                }
            }
      buffer_op[positie]=INFTY_UCHAR;
      if (outdeg_larger || 
          (indeg[center]+outdeg[center]+(tobedirected[center]<<1)-numberin-numberout-deg[center]>=mindouble))
          // looks complicated but is just the final number of double edges
      construct_operations_final(list,decided,buffer_op,positie+1,
                           numberin, numberout);
      return;
    }
  //else // all the undecided entries have to be outgoing
  
    for (i=liststart;list[i]>=0;i++)
      if (!decided[i])
        { 
          if ((outdeg[center]+numberout < maxoutdeg) && (indeg[list[i]]<maxindeg))
            { 
              buffer_op[positie]=list[i];
              positie++; numberout++;
            }
          else return;
        }
  buffer_op[positie]=INFTY_UCHAR;
  construct_operations_final(list,decided,buffer_op,positie+1,
                             numberin, numberout);
  return;
    
}





/**********************************CONSTRUCT_OPERATIONS_IN**************************/

void construct_operations_in(int list[],int liststart, int decided[],unsigned char buffer_op[], 
                             int positie, int numberin, int numberout, int lowerlimit_outdeg,
                             int mindouble)
{
  int i, center;

  /* here about position "positie" of the operation is decided. If "positie==blocklength"
     we are done. 

     This function decides on incoming edges.

     liststart ensures that no earlier -- smaller -- entries are written after larger ones
     unless there has been an INFTY_UCHAR to separate them.
  */



  center=buffer_op[0];

  if(indeg[center]+numberin < maxindeg)
    for (i=liststart;list[i]>=0;i++)
      if (!decided[i])
        { 
          if (outdeg[list[i]]<maxoutdeg)
            { decided[i]=1;
              buffer_op[positie]=list[i];
              construct_operations_in(list,i+1,decided,buffer_op,positie+1,
                                      numberin+1, numberout,lowerlimit_outdeg,mindouble);
              decided[i]=0;
            }
        }
  buffer_op[positie]=INFTY_UCHAR;
  construct_operations_out(list,0,decided,buffer_op,positie+1,
                           numberin, numberout,lowerlimit_outdeg,mindouble);
  return;
}


/**********************************CONSTRUCT_EXTENSIONS**************************/

void construct_extensions(int still_open[], int orbit[], graph touched, int first_in_orbit, graph sameorbit)
{
  int top, top2, j, end, list[MAXN], decided[MAXN], error, lowerlimit_outdeg, readylist[MAXN], *readyrun, dummy;
  int minout, do_double=0, i, mindouble;
  unsigned char buffer[MAXN+4];
  graph pre_free, tbd1, bufferg, freevertices; // tbd1 is the set of vertices with exactly one edge to be directed left
  // decided[i]=0 if and only if about list[i] is already decided //

  tbd1=(graph)0;
  pre_free= all & ~touched;
  readyrun=readylist;
  lowerlimit_outdeg=0;

  // Since either all or no vertices in the orbit have edges going to untouched vertices, one could split
  // this function to save some tests. But for the moment it should better stay like this


  // if a vertex v has at least two edges to be directed and one of them leads to a vertex in the same
  // orbit that will be ready afterwards, then directing the edges around v would not have a
  // reverse operation. So these operations must be avoided.

  // if only one edge is left to be directed and the endpoint is in the same orbit is must be directed double
  // or outgoing.

if (first_in_orbit)
  {
    for (number_operations=0; (top=(*still_open))>=0; still_open++)
      // number_operations is global, so it must not be passed to the next functions
      //if (NOT_READY(top))
      { 
        if (tobedirected[top]==1)
          {
            for (j= FIRSTBIT(workg[top]); READY(j) ; NEXTEL((workg[top]),(j))); 
            if (ISELEMENT(&sameorbit,j) && (tobedirected[j]==1)) construct_operations_one(top, j, 0, 1, double_allowed);
            else construct_operations_one(top, j, 1, 1, double_allowed);
          }
        else
          if (!(staticg[top] & tbd1))
            { 
              for (end=0, j= FIRSTBIT(workg[top]); (j<WORDSIZE); NEXTEL((workg[top]),(j))) 
                { if (NOT_READY(j)) { list[end]=j; decided[end]=0; end++; }}
              // the edge has already been directed if and only if the other top has already been finished
              list[end]= -1;
              buffer[0]= top;
              construct_operations_in(list,0,decided,buffer,1,0,0,0,0);
            }
      }
    return;
  }

// else: not first in orbit

 minout=INT_MAX;

 if (staticg[orbit[0]]& ~touched) // all operations will contain edges to free vertices
   {
     for (j=0; (top=orbit[j])>=0; j++)
       { if (NOT_READY(top)) 
           { //ADDELEMENT(&sameorbit,top);
             if (tobedirected[top]>=2) ADDELEMENT(&pre_free,top); // will stay free unless is chosen top
             else ADDELEMENT(&tbd1,top);
           }
         else // that is: ready
           { *readyrun=top; readyrun++; } // minout would not be used 
       }
   }
 else
   {
     do_double=double_allowed;
     for (j=0; (top=orbit[j])>=0; j++)
       { 
         if (NOT_READY(top)) 
           { //ADDELEMENT(&sameorbit,top);
             if (tobedirected[top]>=2) ADDELEMENT(&pre_free,top); // will stay free unless is chosen top
             else ADDELEMENT(&tbd1,top);
           }
         else // that is: ready
           { bufferg=(workg[top]&sameorbit);
             *readyrun=top; readyrun++; 
             if ((bufferg) && (outdeg[top]<minout)) { minout=outdeg[top]; do_double=double_allowed; }
             if (do_double && (outdeg[top]==minout))
               { 
                 FORALLELEMENTS(bufferg,i)
                   { if (READY(i) && !ISELEMENT(workg+i,top)) // no double edge, so double edges inside the orbit would not be accepted
                       { do_double=0; i=WORDSIZE-1; }  // BDM changed "WORDSIZE" to "WORDSIZE-1"
                   }
               }
           }
       }
   }
 *readyrun= -1;

for (number_operations=0; (top=(*still_open))>=0; still_open++)
  // number_operations is global, so it must not be passed to the next functions
  //if (NOT_READY(top))
  { 
    if (tobedirected[top]==1) // already ready vertices can't have less...
      { 
        for (j= FIRSTBIT(workg[top]); READY(j) ; NEXTEL((workg[top]),(j))); 
        if (ISELEMENT(&sameorbit,j) && (tobedirected[j]==1)) 
          { bufferg=workg[j]&sameorbit; DELELEMENT(&bufferg,top);
            if (outdeg[top]<minout)
              { if ((bufferg== (graph)0) || (outdeg[j]>outdeg[top])) // otherwise the end would be better 
                  {
                    if (outdeg[top]==minout-1) construct_operations_one(top, j, 0, 1, do_double);
                    else construct_operations_one(top, j, 0, 1, double_allowed);
                  }
                else 
                  if ((outdeg[j]==outdeg[top]) && double_allowed)
                  {
                    if (outdeg[top]==minout-1) construct_operations_one(top, j, 0, 0, do_double);
                    else construct_operations_one(top, j, 0, 0, double_allowed);
                  }
              }
          }
        else construct_operations_one(top, j, 1, 1, double_allowed);

      }
    else 
      { 
        if (!(staticg[top] & tbd1))
          {
            error=0;
            freevertices = pre_free | (tbd1 & ~staticg[top]);
            DELELEMENT1(&freevertices,top);
            // now freevertices is the set of vertices that will still be free after  the addition of top
            for (lowerlimit_outdeg=mindouble=0, readyrun=readylist; !error && (top2= *readyrun)>=0; readyrun++)
              { bufferg= freevertices & staticg[top2];
                if ((dummy=POPCOUNT(bufferg)))// will be a candidate afterwards
                  { if (dummy < tobedirected[top]) error=1;
                    else
                      { if (dummy == tobedirected[top])
                          {
                            if (outdeg[top2]>lowerlimit_outdeg) 
                              { lowerlimit_outdeg=outdeg[top2]; mindouble=indeg[top2]+outdeg[top2]-deg[top2]; }
                            else 
                              if (double_allowed && (outdeg[top2]==lowerlimit_outdeg)) 
                                {
                                  if (indeg[top2]+outdeg[top2]-deg[top2]>mindouble) 
                                    mindouble=indeg[top2]+outdeg[top2]-deg[top2];
                                }
                          }
                      }
                  }
              }
            if (!error)
              {
                for (end=0, j= FIRSTBIT(workg[top]); 
                     (j<WORDSIZE) ; NEXTEL((workg[top]),(j))) 
                  if (NOT_READY(j)) { list[end]=j; decided[end]=0; end++; }

                // the edge has already been directed if and only if the other top has already been finished
                list[end]= -1;
                buffer[0]= top;
                if (!error) construct_operations_in(list,0,decided,buffer,1,0,0,lowerlimit_outdeg,mindouble);
              }
          }
      }
  }
  return
}

int compare_op(unsigned char *op1, unsigned char *op2)
// returns 0 if operations are the same, something negative if op1
// is lexicographically smaller and something positive else
{
  int counter;

  if (*op1 != *op2) return (*op1 - *op2); // can never be INFTY_UCHAR
  op1++; op2++;
  counter=2;
  while (*op1 == *op2)
    { if (*op1 == INFTY_UCHAR) { if (!counter) return 0; counter--; }
      op1++; op2++;
    }
  return (*op1 - *op2);
}

/******************************SEARCH_OP*******************************/

int search_op(unsigned char *op)

/* searches the operation op in the list of operations and returns the index. */

{
  int min, max, center;

  min=0; max=number_operations-1; center= (min+max)/2;

  while (min<max)
    { 
      if (compare_op(op,operations+(blocklength*center))<=0)
        { max=center; center= (min+max)/2; }
      else // op strictly larger 
        { min=center+1; center= (min+max)/2; }
    }

  return min;
}

/******************************SEARCH_EDGE*******************************/

int search_edge(int start, int end, int edgelist[][2], int length)

/* searches the edge start->end in edgelist and returns the index. */

{
  int min, max, center;

  min=0; max=length-1; center= (min+max)/2;

  while (min<max)
    { 
      if ((start<edgelist[center][0]) || ((end<=edgelist[center][1]) && (start==edgelist[center][0]))) // start->end smaller or equal
        { max=center; center= (min+max)/2; }
      else // start->end strictly larger 
        { min=center+1; center= (min+max)/2; }
    }

  return min;
}


/******************************COMPUTE_ORBITS************************/

int compute_orbits()
/* compute the orbits of the group described by the global variable generators[][] on
   the operations described in the global variable operations.
   Returns the number of orbits.
*/

{
  int i,j,buffer,run, orbits, index;
  unsigned char image[MAXN+4];

  if (number_operations>size_root)
    { size_root=number_operations;
      free(root_op);
      root_op=malloc((size_t)size_root*sizeof(int));
    }
  if (root_op==NULL)  
    { fprintf(stderr,"Can't allocate %d items for root_op -- exiting.\n",size_root);
      exit(0); }

  for (i=0; i<number_operations; i++) root_op[i]=i;

  for (i=0, orbits=number_operations; i<number_operations; i++)
    for (j=0; j<number_of_generators; j++)
      { 
        if (compute_image_operation(image, operations+(i*blocklength), generators[j]))
          {
            index=search_op(image);
            //unite:
            while ((buffer=root_op[index])!=index) index=buffer; // no path compression here
            run=i;
            while ((buffer=root_op[run])!=run) { root_op[run]=index; run=buffer; }
            if (run!=index) 
              { orbits--; // the roots were different -- two trees are united
                root_op[run]=index; }
          }
      }
  return orbits;
}

/******************************COMPUTE_EDGEORBITS****************************/

#define MAKEIMAGE(a,k) {imagex=generators[k][(a)[0]]; imagey=generators[k][(a)[1]];}

void compute_edgeorbits(int edgelist[][2],int orb[], int length)

{
  int i,j, index, buffer, run;
  int imagex, imagey;

  for (i=0; i<length; i++)
    for (j=0; j<number_of_generators; j++)
      { MAKEIMAGE(edgelist[i],j);
        index=search_edge(imagex, imagey, edgelist, length);
        while ((buffer=orb[index])!=index) index=buffer; // no path compression here
        run=i;
        while ((buffer=orb[run])!=run) { orb[run]=index; run=buffer; }
        orb[run]=index;
      }
}


/******************************CANONICAL****************************/

int canonical(unsigned char operation[], int vertexorbit[], int *newgroup, int orbitid, graph touched)

// checks whether the operation is canonical in vertexorbit. Returns 1 if yes, 0 otherwise.
// In newgroup it is stored whether a new group has been computed for this (*newgroup=1) or not
// (*newgroup=0)

// If no edges go to vertices outside the set of vertices in already "finished" orbits or to vertices in
// this orbit with still undecided edges, the canonical operation is directing one edge {x,y} x->y or x<->y.
// Edges completely in this orbit and obtained by operations center x end y are chosen as follows
// First the starting point x is chosen with minimum outdegree.
// For edges with starting points with the same minimal outdegree, edges are preferred which are single. 
// If the tested operation is double and single operations exist, the operation is rejected.
// Among the remaining edges those are chosen where y has minimum indegree.
// Among the remaining those are chosen where x is in the orbit of the one with smallest canonical number
// (after the operation). y is the neighbour with smallest indegree -- and among those with the same indegree
// the one with smallest canonical number (in the same given numbering of course).

// Otherwise:
// Define a vertex to be free if it is not in an orbit that was already chosen (we call that untouched)
// or it is in such an orbit but not all edges to it are already directed (that can only be in the last orbit).
// In this case the central vertex of the canonical operation is one that is chosen in steps:
// Among all with edges to free vertices it is chosen as one with a minimum number of these.
// Among those one with max outdegree is chosen.
// Among those one with maximum number of double edges is chosen.
// Finally a more complicated artificial criterion is tested -- not suitable for a look ahead during the construction
// of possible operations
// Among the remaining, one with smallest canonical label is chosen.

int i, j, k, min, top, buffer, candidatelist[MAXN], number_candidates, center;
  graph free, candidates, bufferset, dummy, sameorbit, bit_startlist;
  int edgelistcounter, edgelist[2*MAXN*MAXN][2], orb[2*MAXN*MAXN], canoncenter, canonend, endvertex=0;
  int finished[MAXN], finishedptn[MAXN], testoutdeg;
  int startlist[MAXN], *startrun; // list of possible starts in case of no candidates
  int numberends, ends[MAXN][MAXN], endin=0, *run;
  int *colour;
  long long int buffer2, k2;



  free= all & (~touched); // in fact all ready vertices are candidates if one has a non-empty
  // intersection with this as they are all in the same orbit -- so have the same number of edges
  // to this set
  sameorbit=bit_orbit[orbitid];

  for (run=vertexorbit; (*run)>=0; run++) if (NOT_READY(*run)) ADDELEMENT(&free,(*run));

  center=operation[0];

  candidates= (graph)0;
  number_candidates=0;
  min=INFTY_UCHAR;
  for (i=0; (top=vertexorbit[i])>=0; i++) 
    if (READY(top) && (bufferset=(staticg[top] & free)))
      {
        buffer=POPCOUNT(bufferset);
        if (buffer<min) { candidates= (graph)0; ADDELEMENT(&candidates,top); 
                          candidatelist[0]=top; number_candidates=1; min=buffer; }
        else
          if (buffer==min)
            { ADDELEMENT(&candidates,top); candidatelist[number_candidates]=top; number_candidates++; }
      }
  if (number_candidates && !ISELEMENT(&candidates,center))
    { 
      return 0;
    }

  if (number_candidates==1) { *newgroup=0; return 1; }
  
  testoutdeg=outdeg[center];
  // First canonicity criterion: maximum outdegree
  if (number_candidates)
    {
      for (i=0; i<number_candidates; ) 
        { k= outdeg[candidatelist[i]]-testoutdeg;
          if (k>0) 
            { return 0;}
          else 
            { if (k<0) { DELELEMENT(&candidates,candidatelist[i]); 
                         number_candidates--; 
                         candidatelist[i]=candidatelist[number_candidates];   }
              else i++; // otherwise the new element has to be tested
            }
        }
      
      if (number_candidates==1) { *newgroup=0; return 1; }
    // end number_candidates>0

      if (remaining_doubles != max_doubles) // there are double edges
        { buffer=indeg[center]+outdeg[center]-deg[center]; // number of double edges starting at center
          for (i=0; i<number_candidates; )
            { j=candidatelist[i];
              k= indeg[j]+outdeg[j]-deg[j]-buffer; 
              if (k>0) 
                { return 0;}
              else 
                { if (k<0) { DELELEMENT(&candidates,candidatelist[i]); 
                    number_candidates--; 
                    candidatelist[i]=candidatelist[number_candidates];   }
                  else i++; // otherwise the new element has to be tested
                }
            }
        }
      if (number_candidates==1) { *newgroup=0; return 1; }
 
      //OK-- last try. A colour that can not really be used to avoid unnecessary operation in advance
      colour=rememberorbits[orbitid];
      dummy=workg[center]&(free | sameorbit);
      buffer2=1LL;
      FORALLELEMENTS(dummy,i) 
        { buffer2 *= (tobedirected[i]<<12)+(indeg[i]<<9)+(outdeg[i]<<6)+(colour[i]<<3)+deg[i]+1;
          buffer2 = buffer2%63241LL;
        }

      for (i=0; i<number_candidates; )
        { 
          dummy=workg[candidatelist[i]]&(free | sameorbit);
          k2=1LL;
          FORALLELEMENTS(dummy,j) 
            { k2 *= (tobedirected[j]<<12)+(indeg[j]<<9)+(outdeg[j]<<6)+(colour[j]<<3)+deg[j]+1;
              k2 = k2%63241LL;
            }
          k2 -= buffer2;

          if (k2>0LL) 
            { return 0;}
          else 
            { if (k2<0LL) { DELELEMENT(&candidates,candidatelist[i]); 
                number_candidates--; 
                candidatelist[i]=candidatelist[number_candidates];   }
              else i++; // otherwise the new element has to be tested
            }
        }
      
      if (number_candidates==1) { *newgroup=0; return 1; }
 


   } // end number candidates > 0


  // OK -- we have to work. First the canonical form must be computed:
  // Problem: the difference between double edges and edges that have not yet been directed cannot be 
  // detected in the datastructure graph. To this end we put "ready" vertices in an extra partition --
  // this way double edges cannot be mapped on undirected edges. This is only necessary if there are double edges.

  else // (number_candidates==0) // finished vertices in this orbit always have an internal edge!
    { startrun=startlist;
      bit_startlist=(graph)0;
      if (operation[2]==INFTY_UCHAR) // a double edge was added and all single edges starting at same outdeg are better
        { endvertex= operation[3];
          endin=indeg[endvertex];
          for (i=0; (k=vertexorbit[i])>=0; i++)
            if (READY(k) && (workg[k] & sameorbit))// has _outgoing_ edge into same orbit
              // the end points are automatically ready and all in the same orbit -- otherwise there would have been a candidate
              { 
                if (outdeg[k]<testoutdeg) return 0;
                if (outdeg[k]==testoutdeg) 
                  { numberends=0; 
                    bufferset= workg[k]&sameorbit;
                    FORALLELEMENTS(bufferset,j) 
                      { if (!ISELEMENT(workg+j,k)) return 0; // else: also double edge
                        if (indeg[j]<endin) return 0;
                        if (indeg[j]==endin) { ends[k][numberends]=j; numberends++; }
                      }
                    if (numberends)
                      { ends[k][numberends]= -1; 
                        *startrun=k; startrun++; ADDELEMENT(&bit_startlist,k); 
                      }
                  }
              }
        }
      else // het is dus een single edge
        { endvertex= operation[2];
          endin=indeg[endvertex];
          for (i=0; (k=vertexorbit[i])>=0; i++)
            if (READY(k) && (workg[k] & sameorbit))// has _outgoing_ edge into same orbit
              // the end points are automatically ready and all in the same orbit -- otherwise there would have been a candidate
              { 
                if (outdeg[k]<testoutdeg) return 0;
                if (outdeg[k]==testoutdeg) 
                  { numberends=0;
                    bufferset= workg[k]&sameorbit;
                    FORALLELEMENTS(bufferset,j) 
                      { if (!ISELEMENT(workg+j,k)) // also single
                          {
                            if (indeg[j]<endin) return 0;
                            if (indeg[j]==endin) { ends[k][numberends]=j; numberends++; }
                          }
                      }
                    if (numberends)
                      { ends[k][numberends]= -1;
                        *startrun=k; startrun++; ADDELEMENT(&bit_startlist,k); 
                      }
                  }
              }
        }
      *startrun= -1;
      dummy=workg[center] & sameorbit;
      if ((startlist[1]== -1) && (ends[center][1]== -1)) { *newgroup=0; return 1; } // maar 1 boog mogelijk
    } 


  if (double_allowed) // distinguish single and double edges for nauty()
    {
      for (i=j=k=0; i<aantal_toppen;i++)
        { top=lab[orbitid][i];
          if (READY(top)) { finished[k]=top; finishedptn[k]=1; k++; } 
          else { bufferlab[j]=top; bufferptn[j]=1; j++; }
          if (ptn[orbitid][i]==0)
            { if (j) bufferptn[j-1]=0;
              if (k) finishedptn[k-1]=0;
            }
        }
      for (i=0;i<k;i++,j++) { bufferptn[j]=finishedptn[i]; bufferlab[j]=finished[i]; } 
    }
  else
    {
      memcpy(bufferlab,lab[orbitid],aantal_toppen*sizeof(int));
      memcpy(bufferptn,ptn[orbitid],aantal_toppen*sizeof(int));
    }
  number_of_generators=0;
  nauty(workg,bufferlab,bufferptn,NULL,orbits,&options_directed_canon,&stats,workspace,100*MAXN,1,aantal_toppen,canong);
  *newgroup=1;

  //nautyuse[number_candidates]++;

  // Being a free vertex is invariant under automorphisms and the set of edges to free vertices depends only
  // on the central vertex. So the central vertex characterizes the whole operation and orbits of central
  // vertices uniquely correspond to orbits of operations.

  if (number_candidates>1)
    {      
      for (i=0; !ISELEMENT(&candidates,bufferlab[i]); i++); // zoekt candidaat met kleinste kanonische label
            
      if (orbits[center]==orbits[bufferlab[i]]) { return 1; }
      else { return 0; }
    }

// only remaining case: number_candidates=0 -- that is: only one edge between 2 vertices of vertexorbit was added

  // operation must be outgoing or double edge -- but this is guaranteed by the construction of operations

  //  for (i=0; !(READY(bufferlab[i]) && ISELEMENT(&sameorbit,bufferlab[i]) && (workg[bufferlab[i]] & sameorbit))
  for (i=0; !ISELEMENT(&bit_startlist,bufferlab[i]); i++);
  // Now we have the smallest vertex in vertexorbit with an edge to another vertex in vertexorbit

  canoncenter=bufferlab[i];

  if (orbits[center]!=orbits[canoncenter]) { return 0; }

  // Now look for the endvertex:

  min=INFTY_UCHAR;
  dummy= sameorbit & workg[canoncenter];
--> --------------------

--> maximum size reached

--> --------------------

77%


¤ Dauer der Verarbeitung: 0.32 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.