Recursion
This commit is contained in:
parent
5bcb30b5c1
commit
241065565d
2
Makefile
2
Makefile
@ -1,5 +1,5 @@
|
|||||||
HEADERS=coxeter.h thickenings.h queue.h
|
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
|
all: generate process
|
||||||
|
|
||||||
|
257
thickenings.c
257
thickenings.c
@ -275,141 +275,142 @@ void prepare_graph(semisimple_type_t type, node_t *graph, edgelist_t **edgelists
|
|||||||
free(seen);
|
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;
|
int is_slim = 1;
|
||||||
signed char *level;
|
queue_t queue;
|
||||||
long count;
|
int current;
|
||||||
int is_fat, is_slim;
|
|
||||||
int current_level, head, current;
|
|
||||||
int i;
|
|
||||||
edgelist_t *edge;
|
edgelist_t *edge;
|
||||||
|
|
||||||
queue_t queue;
|
queue_init(&queue);
|
||||||
|
level[info->graph[head].opposite] = -current_level;
|
||||||
|
queue_put(&queue, head);
|
||||||
|
|
||||||
int printstep = 0;
|
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(getenv("PRINTSTEP"))
|
if(level[i] == current_level) {
|
||||||
printstep = atoi(getenv("PRINTSTEP"));
|
is_slim = 0;
|
||||||
|
break;
|
||||||
rank = coxeter_rank(type);
|
} if(level[i] == 0) {
|
||||||
order = coxeter_order(type);
|
level[i] = -current_level;
|
||||||
|
level[info->graph[i].opposite] = current_level;
|
||||||
level = (signed char*)malloc(order*sizeof(int));
|
queue_put(&queue, info->graph[i].opposite);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
free(level);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
|
Loading…
Reference in New Issue
Block a user