diff --git a/Makefile b/Makefile index 2d444a5..f0ed9e0 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ HEADERS=coxeter.h thickenings.h queue.h -OPTIONS=-O3 -m64 -flto -funroll-loops -std=gnu99 +OPTIONS=-O3 -m64 -march=native -flto -funroll-loops -std=gnu99 -pg all: generate process diff --git a/thickenings.c b/thickenings.c index e172f15..c6a0d8b 100644 --- a/thickenings.c +++ b/thickenings.c @@ -275,141 +275,142 @@ void prepare_graph(semisimple_type_t type, node_t *graph, edgelist_t **edgelists free(seen); } -long enumerate_balanced_thickenings(semisimple_type_t type, node_t *graph, const char *alphabet, FILE *outfile) +/*********************************** THE ACTUAL ENUMERATION ****************************************/ + +typedef struct { + int rank; + int order; + const node_t *graph; + int printstep; + const char *alphabet; + FILE *outfile; +} enumeration_info_t; + +// calculate transitive closure; that is, fill current_level in every spot which must be marked with the current head (but was not already marked before), and -current_level in every opposite spot (including opposite to the head) +static int transitive_closure(const enumeration_info_t *info, signed char *level, int head, int current_level) { - int rank, order; - signed char *level; - long count; - int is_fat, is_slim; - int current_level, head, current; - int i; + int is_slim = 1; + queue_t queue; + int current; edgelist_t *edge; - queue_t queue; + queue_init(&queue); + level[info->graph[head].opposite] = -current_level; + queue_put(&queue, head); - int printstep = 0; - if(getenv("PRINTSTEP")) - printstep = atoi(getenv("PRINTSTEP")); - - rank = coxeter_rank(type); - order = coxeter_order(type); - - level = (signed char*)malloc(order*sizeof(int)); - - count = 0; - memset(level, 0, order*sizeof(int)); - current_level = 1; - head = order - 1; - level[head] = HEAD_MARKER; - while(current_level > 0) { - - // calculate transitive closure; that is, fill current_level in every spot which must be marked with the current head (but was not already marked before), and -current_level in every opposite spot (including opposite to the head) - is_slim = 1; - queue_init(&queue); - level[graph[head].opposite] = -current_level; - queue_put(&queue, head); - for(int i = head + 1; level[i] != HEAD_MARKER && i < order; i++) { // everything which is right to the head and empty will not get marked in this or higher levels, so we can mark its opposite - if(level[i] == current_level) { - is_slim = 0; - break; - } if(level[i] == 0) { - level[i] = -current_level; - level[graph[i].opposite] = current_level; - queue_put(&queue, graph[i].opposite); - } + for(int i = head + 1; level[i] != HEAD_MARKER && i < info->order; i++) { // everything which is right to the head and empty will not get marked in this or higher levels, so we can mark its opposite + if(level[i] == current_level) { + is_slim = 0; + break; + } if(level[i] == 0) { + level[i] = -current_level; + level[info->graph[i].opposite] = current_level; + queue_put(&queue, info->graph[i].opposite); } - - if(is_slim) { - while((current = queue_get(&queue)) != -1) { - edge = graph[current].bruhat_lower; - while(edge) { - if(level[edge->to] < 0) { - is_slim = 0; - break; - } else if(level[edge->to] == 0) { - level[edge->to] = current_level; - level[graph[edge->to].opposite] = -current_level; - queue_put(&queue, edge->to); - } - edge = edge->next; - } - } - } - - // now we have something, check if it is a balanced thickening; if so, write to stdout - if(is_slim) { - is_fat = 1; - for(int i = 0; i < order; i++) { - if(level[i] == 0) { - is_fat = 0; - break; - } - } - - if(is_fat) { - // ERROR(count >= MAX_THICKENINGS, "Too many balanced thickenings! Increase MAX_THICKENINGS\n"); - fwrite(level, sizeof(signed char), order, outfile); - count++; - } - } - - // if printstep is set accordingly, write state to stderr - if(is_slim && is_fat && printstep > 0 && (count + 1) % printstep == 0) { - print_thickening(rank, order, level, current_level, alphabet, stderr); - fprintf(stderr, "\n"); - } - else if(printstep < 0) { - print_thickening(rank, order, level, current_level - !is_slim, alphabet, stderr); - fprintf(stderr, " "); - if(is_slim) { - fprintf(stderr, "S"); - if(is_fat) - fprintf(stderr, "F"); - } - fprintf(stderr, "\n"); - } - - // now find the next one! - - // try to find empty spot to the left of "head", but only if it is slim, as otherwise there is no point in adding even more - if(is_slim) { - for(i = head - 1; i >= 0; i--) - if(level[i] == 0) - break; - if(i >= 0) { - head = i; - level[head] = HEAD_MARKER; - current_level++; - ERROR(current_level >= HEAD_MARKER, "HEAD_MARKER to small!\n"); - continue; - } - } - - // if none was found, try to move "head" to the left - while(current_level > 0) { - for(i = head - 1; i >= 0; i--) - if(level[i] == 0 || level[i] >= current_level || level[i] <= -current_level) - break; - if(i >= 0) { // if this was successful, just move head - level[head] = 0; - head = i; - level[head] = HEAD_MARKER; - break; - } else { // if moving the head is not possible, take the next head to the right - current_level--; - level[head] = 0; - do { - head++; - } while(head < order && level[head] != HEAD_MARKER); - } - } - - // clean up - for(int i = 0; i < order; i++) - if(level[i] >= current_level && level[i] != HEAD_MARKER || level[i] <= -current_level) - level[i] = 0; } + if(is_slim) { + while((current = queue_get(&queue)) != -1) { + edge = info->graph[current].bruhat_lower; + while(edge) { + if(level[edge->to] < 0) { + is_slim = 0; + break; + } else if(level[edge->to] == 0) { + level[edge->to] = current_level; + level[info->graph[edge->to].opposite] = -current_level; + queue_put(&queue, edge->to); + } + edge = edge->next; + } + } + } + + return is_slim; +} + +static inline void output_thickening(const enumeration_info_t *info, signed char *level, int current_level, int is_slim, int is_fat, long count) +{ + // if printstep is set accordingly, write state to stderr + if(is_slim && is_fat && info->printstep > 0 && (count + 1) % info->printstep == 0) { + print_thickening(info->rank, info->order, level, current_level, info->alphabet, stderr); + fprintf(stderr, "\n"); + } + else if(info->printstep < 0) { + print_thickening(info->rank, info->order, level, current_level - !is_slim, info->alphabet, stderr); + fprintf(stderr, " "); + if(is_slim) { + fprintf(stderr, "S"); + if(is_fat) + fprintf(stderr, "F"); + } + fprintf(stderr, "\n"); + } +} + +static long enumerate_tree(const enumeration_info_t *info, signed char *level, int current_level, int head) +{ + ERROR(current_level >= HEAD_MARKER, "HEAD_MARKER too small!\n"); + + level[head] = HEAD_MARKER; + + int is_slim = transitive_closure(info, level, head, current_level); + int is_fat; + int count = 0; + + // we have a candidate, check if it is a balanced thickening; if so, write to stdout + if(is_slim) { + is_fat = 1; + for(int i = head - 1; i >= 0; i--) + if(level[i] == 0) + is_fat = 0; + + output_thickening(info, level, current_level, is_slim, is_fat, count); + + if(is_fat) { + count++; + fwrite(level, sizeof(signed char), info->order, info->outfile); + } else { + for(int i = head - 1; i >= 0; i--) + if(level[i] == 0) + count += enumerate_tree(info, level, current_level + 1, i); + } + } + + // clean up + level[head] = 0; + for(int i = 0; i < info->order; i++) + if(level[i] >= current_level && level[i] != HEAD_MARKER || level[i] <= -current_level) + level[i] = 0; + + return count; +} + +long enumerate_balanced_thickenings(semisimple_type_t type, node_t *graph, const char *alphabet, FILE *outfile) +{ + // int rank, order; + signed char *level; + long count = 0; + enumeration_info_t info; + queue_t queue; + int current; + + info.rank = coxeter_rank(type); + info.order = coxeter_order(type); + info.graph = graph; + info.alphabet = (char*)alphabet; + info.outfile = outfile; + + info.printstep = 0; + if(getenv("PRINTSTEP")) + info.printstep = atoi(getenv("PRINTSTEP")); + + level = (signed char*)malloc(info.order*sizeof(int)); + memset(level, 0, info.order*sizeof(int)); + + for(int i = info.order - 1; i >= 0; i--) + count += enumerate_tree(&info, level, 1, i); + free(level); return count;