// compile: cc -O4 -o ucs ucs.c // start without parameters or with parameter h to get usage information // to use the processor built in popcount where available change #define and // use compiler option -mpopcnt or -msse4.2 #include #include #include #include #include #include #include #include //#include "nauty.h" #define N 8 /* uses unsigned short -- so don't increase above 16 -- for the definition of permutation don't increase above 15. */ #if N>8 #define USE_USHORT 1 #else #define USE_USHORT 0 #endif #define USE_UCHAR (!USE_USHORT) #if USE_USHORT typedef unsigned short settype; #else typedef unsigned char settype; #endif #ifdef TEST #define STATS #endif #define BIT(i) (((settype)1)<<(i-1)) #define DELBIT(a,i) ((a)&=(~BIT(i))) #define SETBIT(a,i) ((a)|=(BIT(i))) int set_is_present[1<<(N)] ={0}; // is a bit faster with int instead of char :-( #if USE_USHORT #define FIVE_MASK_VALUE (32) #define FIVE_MASK (31) #define FIRST5(x) ((x)&FIVE_MASK) #define SECOND5(x) ((x>>5)&FIVE_MASK) #define THIRD5(x) ((x>>10)&FIVE_MASK) typedef settype image[3]; typedef image permutation[FIVE_MASK_VALUE]; /* the_permutations[x][FIRST5(i)][0] will be the image of permutation number x of the first 5 bytes of the set i, the_permutations[x][SECOND5(i)][1] of the second 5, etc */ #define IMAGE(number,set) (the_permutations[number][FIRST5(set)][0] | the_permutations[number][SECOND5(set)][1]\ | the_permutations[number][THIRD5(set)][2]) #else typedef settype permutation[256]; /* the_permutations[x][y] will be the image of permutation number x of the set y */ #define IMAGE(number,set) (the_permutations[number][set]) #endif permutation *the_permutations; int number_permutations=0; unsigned int _gbu; #define FORALLELEMENTS(x,y) for (_gbu=x, y= __builtin_ffs(_gbu); y; _gbu&=(_gbu-1), y= __builtin_ffs(_gbu)) #define LESS_THAN_2BIT(a) (((a)&((a)-1))==0) settype all_subsets[N+1][1<<(N)]; int number_all_subsets[N+1]; int n; settype ucs[1<<(N)]; int number_sets, start_level[N+2]; int permutation_number_level[N+1][6000]; // restricted to at most 6000 permutations -- decrease later int number_auts[N+1]; long int structurecounter=0L; unsigned long long int labelled_structurecounter=0ULL; int nfak; // just large enough for the labelled UCS on 7 elements -- if done in one run... :-) int nfak; #ifdef STATS long int not_uc=0L, well_uc=0L, structurecounter_numbersets[1<0 the number of elements in the whole set.\n",name); fprintf(stderr,"m res mod makes that only part number res of mod parts is generated with 0<=res0) && (buffer==start_level[level])) level--; } fprintf(stdout,"("); s=ucs[j]; fprintf(stdout,"%d", __builtin_ffs(s)); s&=s-1; FORALLELEMENTS(s,i) fprintf(stdout," %d",i); fprintf(stdout,")"); } fprintf(stdout,"\n"); } void make_all_subsets() { unsigned int set; int i, size; for (i=0;i<=n;i++) number_all_subsets[i]=0; for (set=0; set<(1U<%d)",i,image[i]); //fprintf(stderr,"\n"); if (number_permutations>=0) // the first one is the identity -- that never produces smaller labellings // start with -1 #if USE_USHORT for (i=0;i< FIVE_MASK_VALUE;i++) { buffer0=buffer1=buffer2=0; FORALLELEMENTS(i,el) {//fprintf(stderr,"el=%d\n",el); buffer0 |=BIT(image[el]); buffer1 |=BIT(image[el+5]); buffer2 |=BIT(image[el]+10); } //writeset(buffer0); the_permutations[number_permutations][i][0]=buffer0; the_permutations[number_permutations][i][1]=buffer1; the_permutations[number_permutations][i][2]=buffer2; } #else for (i=0; i<256; i++) { buffer0=0; FORALLELEMENTS(i,el) buffer0 |=BIT(image[el]); the_permutations[number_permutations][i]=buffer0; } #endif number_permutations++; return; } for (i=imageof;i<=n;i++) rest[i]=rest2[i]; for (i=imageof;i<=n;i++) { image[imageof]=rest[i]; rest[i]=rest2[i-1]; go_on_permut(imageof+1,image,rest); } return; } void makepermutations(int n) // makes them in lexicographic order { int i, total; int image[N+1], rest[N+1]; for (i=2,total=1;i<=n;i++) total*=i; nfak=total; total -= 1; for (i=0; i=0; i--) { if (!set_is_present[old_base_sets[i] | new_set]) return 0; } old_base_sets[number_old_base]=new_set; return 1; } int is_uc(settype old_base_sets[], int number_old_base, settype new_base_sets[], int *number_new_base_sets, settype new_set) // it is assumed that new_set will be a base set (e.g. smallest size) in case the result is a UCS { int i, newc; settype x; /*fprintf(stderr,"---------------------------------------------------------------------\n Testing: "); write_ucs(); fprintf(stderr,"old base sets: \n"); for (i=0;i=0;i--) // small sets have a better chance to lead to contradictions (hope) { x= old_base_sets[i] | new_set; //fprintf(stderr,"Checking set (present: %d): ",set_is_present[x]); writeset(x); if (!set_is_present[x]) { #ifdef TEST not_uc++; #endif return 0; } // else MARK_SET(x); } #ifdef TEST well_uc++; #endif for (i=newc=0;i1) { for (i=0, auts=number_auts[autlevel]; iminlevel) { if (number_auts[level+1]==0) number_auts[level]=0; else number_auts[level]= -1; // as a sign to look one level higher add_next_set_2( level-1, 0, old_base_sets, number_old_base); } } // then add the next set on level "level" number_sets++; #ifdef STATS weight+=level; #endif if (level>minlevel) { for (whichset=next_to_add; whichset minlevel) add_next_set_2( level-1, 0, new_base_sets,number_new_base_sets); /* this must come first, because otherwise the automorphisms for this level are overwritten */ if (whichset minlevel) add_next_set_2( level-1, 0, new_base_sets,number_new_base_sets); /* this must come first, because otherwise the automorphisms for this level are overwritten */ if (whichset =splitlevel2); // can increase by 4 in one step, so can be > if (/*mod2 &&*/ is_splitlevel) { if (modcounter2==mod2) modcounter2=1; else { modcounter2++; return; } } if (next_to_add==0) { start_level[level]=number_sets; // first leave out level if (level>minlevel) { if (number_auts[level+1]==0) number_auts[level]=0; else number_auts[level]= -1; // as a sign to look one level higher if (is_splitlevel) add_next_set_2( level-1, 0, old_base_sets, number_old_base); else add_next_set_1( level-1, 0, old_base_sets, number_old_base); } } // then add the next set on level "level" #ifdef STATS weight+=level; #endif if (is_splitlevel) {number_sets++; for (whichset=next_to_add; whichset minlevel) add_next_set_2( level-1, 0, new_base_sets,number_new_base_sets); /* this must come first, because otherwise the automorphisms for this level are overwritten */ if (whichset minlevel) add_next_set_1( level-1, 0, new_base_sets,number_new_base_sets); /* this must come first, because otherwise the automorphisms for this level are overwritten */ if (whichset =splitlevel); // can increase by 4 in one step, so can be > if (mod && is_splitlevel) {//splitcounter++; return; if (modcounter==mod) modcounter=1; else { modcounter++; return;} } if (next_to_add==0) { start_level[level]=number_sets; // first leave out level if (level>minlevel) { if (number_auts[level+1]==0) number_auts[level]=0; else number_auts[level]= -1; // as a sign to look one level higher if (is_splitlevel) { if (mod2==0) add_next_set_2( level-1, 0, old_base_sets, number_old_base); else add_next_set_1( level-1, 0, old_base_sets, number_old_base); } else add_next_set( level-1, 0, old_base_sets, number_old_base); } } // then add the next set on level "level" #ifdef STATS weight+=level; #endif if (is_splitlevel) {number_sets++; for (whichset=next_to_add; whichset minlevel) { if (mod2==0) add_next_set_2( level-1, 0, new_base_sets,number_new_base_sets); else add_next_set_1( level-1, 0, new_base_sets,number_new_base_sets); } /* this must come first, because otherwise the automorphisms for this level are overwritten */ if (whichset minlevel) add_next_set( level-1, 0, new_base_sets,number_new_base_sets); /* this must come first, because otherwise the automorphisms for this level are overwritten */ if (whichset minlevel) add_next_set(n-1,0,base_sets,1); } /*******************MAIN********************************/ int main(int argc,char *argv[]) { int i; if ((argc<2) || !isdigit(argv[1][0])) usage(argv[0]); n= atoi(argv[1]); if (n>N) { fprintf(stderr,"Number of elements may be at most %d -- exiting.\n",N); exit(0); } if (n>7) { fprintf(stderr,"Implement other method for large group first, \n"); fprintf(stderr,"change datatype for labelled_structurecounter,\n"); fprintf(stderr,"and make sure that you have millions of years of CPU available :-) \n"); exit(0); } if (n<1) usage(argv[0]); for (i=2;i=argc) || !isdigit(argv[i+1][0]) || !isdigit(argv[i+2][0])) usage(argv[0]); rest2=atoi(argv[++i]); mod2=atoi(argv[++i]); if ((mod2<1) || (rest2>=mod2)) usage(argv[0]); if (n<=6) usage(argv[0]); else { if (n==7) splitlevel2=43; // the difference between splitlevel and splitlevel2 must be at least 4 else { fprintf(stderr,"First find good splitlevel2 for n>=8.\n"); exit(0); } } fprintf(stderr,"Splitlevel2=%d\n",splitlevel2); } else { if ((i+2>=argc) || !isdigit(argv[i+1][0]) || !isdigit(argv[i+2][0])) usage(argv[0]); rest=atoi(argv[++i]); mod=atoi(argv[++i]); if ((mod<1) || (rest>=mod)) usage(argv[0]); if (n<=6) splitlevel=11; else { if (n==7) splitlevel=18; else { fprintf(stderr,"First find good splitlevel for n>=8.\n"); exit(0); } } fprintf(stderr,"Splitlevel=%d\n",splitlevel); } } else if (argv[i][0]=='s') { if ((i+1>=argc) || !isdigit(argv[i+1][0])) usage(argv[0]); maxsets=atoi(argv[++i]); } else if (argv[i][0]=='w') { writeout=1; if (argv[i][1]=='b') writebinary=1; } else if (argv[i][0]=='e') { if ((i+1>=argc) || !isdigit(argv[i+1][0])) usage(argv[0]); minlevel=atoi(argv[++i]); if ((minlevel>n) || (minlevel<1)) usage(argv[0]); } } for (i=0;i