Recursion
This commit is contained in:
		
							
								
								
									
										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;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user