2016-06-09 19:11:20 +00:00
# include <stdio.h>
# include <limits.h>
# include <stdlib.h>
# include <malloc.h>
# include <memory.h>
2016-07-26 08:09:34 +00:00
# include "thickenings.h"
2016-11-20 22:19:08 +00:00
# include "weyl.h"
2016-06-09 19:11:20 +00:00
# include "queue.h"
2016-07-26 08:09:34 +00:00
char * alphabetize ( int * word , int len , const char * alphabet , char * buffer )
2016-06-09 19:11:20 +00:00
{
2016-10-29 12:47:55 +00:00
if ( len = = 0 ) {
buffer [ 0 ] = ' 1 ' ;
buffer [ 1 ] = 0 ;
return buffer ;
}
2016-06-09 19:11:20 +00:00
int i = 0 ;
for ( i = 0 ; i < len ; i + + )
buffer [ i ] = alphabet [ word [ i ] ] ;
buffer [ i ] = 0 ;
return buffer ;
}
2016-10-14 16:49:20 +00:00
void print_thickening ( int rank , int order , const signed char * thickening , int upto_level , const char * alphabet , FILE * f )
2016-08-26 12:56:23 +00:00
{
for ( int i = 0 ; i < order ; i + + ) {
2016-08-29 13:19:49 +00:00
if ( thickening [ i ] = = HEAD_MARKER )
2016-10-14 16:49:20 +00:00
fprintf ( f , " \ e[41;37mx \ e[0m " ) ;
else if ( thickening [ i ] < - upto_level | | thickening [ i ] > upto_level )
fprintf ( f , " " ) ;
2016-08-26 12:56:23 +00:00
else if ( thickening [ i ] < 0 & & thickening [ i ] > - 10 )
2016-10-14 16:49:20 +00:00
fprintf ( f , " \ e[47;30m%d \ e[0m " , - thickening [ i ] ) ;
2016-08-26 12:56:23 +00:00
else if ( thickening [ i ] < = - 10 )
2016-10-14 16:49:20 +00:00
fprintf ( f , " \ e[47;30m+ \ e[0m " ) ;
2016-08-26 12:56:23 +00:00
else if ( thickening [ i ] > 0 & & thickening [ i ] < 10 )
2016-10-14 16:49:20 +00:00
fprintf ( f , " \ e[40;37m%d \ e[0m " , thickening [ i ] ) ;
2016-08-26 12:56:23 +00:00
else if ( thickening [ i ] > = 10 )
2016-10-14 16:49:20 +00:00
fprintf ( f , " \ e[40;37m+ \ e[0m " ) ;
2016-08-26 12:56:23 +00:00
else
fprintf ( f , " " ) ;
}
2016-10-14 16:49:20 +00:00
fprintf ( f , " \ e[K " ) ;
2016-06-20 08:37:21 +00:00
}
2016-06-09 19:11:20 +00:00
static int compare_wordlength ( const void * a , const void * b , void * gr )
{
int i = * ( ( int * ) a ) ;
int j = * ( ( int * ) b ) ;
node_t * graph = ( node_t * ) gr ;
return graph [ i ] . wordlength - graph [ j ] . wordlength ;
}
2016-11-11 16:07:45 +00:00
void prepare_graph ( semisimple_type_t type , node_t * graph )
2016-06-09 19:11:20 +00:00
{
queue_t queue ;
2016-11-11 16:07:45 +00:00
edgelist_t * edgelists_lower , * edgelists_higher ;
int rank , order , hyperplanes ;
2016-07-26 08:09:34 +00:00
edgelist_t * edge , * previous ;
2016-11-11 16:07:45 +00:00
int edgelist_count , hyperplane_count ;
2016-07-26 08:09:34 +00:00
int current ;
2016-06-09 19:11:20 +00:00
2016-11-20 22:19:08 +00:00
weylgroup_element_t * graph_data ;
2016-07-26 08:09:34 +00:00
node_t * graph_unsorted ;
2016-11-15 17:55:30 +00:00
int * ordering , * reverse_ordering , * seen ;
2016-06-09 19:11:20 +00:00
2016-07-26 08:09:34 +00:00
// initialize
2016-06-09 19:11:20 +00:00
2016-11-20 22:19:08 +00:00
rank = weyl_rank ( type ) ;
order = weyl_order ( type ) ;
hyperplanes = weyl_hyperplanes ( type ) ;
2016-11-11 16:07:45 +00:00
edgelists_higher = graph [ 0 ] . bruhat_higher ;
edgelists_lower = & graph [ 0 ] . bruhat_higher [ order * hyperplanes / 2 ] ;
2016-06-09 19:11:20 +00:00
2016-11-20 22:19:08 +00:00
graph_data = weyl_alloc ( type ) ;
2016-07-26 08:09:34 +00:00
graph_unsorted = ( node_t * ) malloc ( order * sizeof ( node_t ) ) ;
2016-11-15 17:55:30 +00:00
ordering = ( int * ) malloc ( order * sizeof ( int ) ) ;
reverse_ordering = ( int * ) malloc ( order * sizeof ( int ) ) ;
2016-06-09 19:11:20 +00:00
seen = ( int * ) malloc ( order * sizeof ( int ) ) ;
for ( int i = 0 ; i < order ; i + + ) {
graph_unsorted [ i ] . wordlength = INT_MAX ;
2016-11-11 16:07:45 +00:00
graph [ i ] . bruhat_lower = 0 ;
graph [ i ] . bruhat_higher = 0 ;
graph [ i ] . is_hyperplane_reflection = 0 ;
2016-06-09 19:11:20 +00:00
}
2016-07-26 08:09:34 +00:00
// get coxeter graph
2016-11-20 22:19:08 +00:00
weyl_generate ( type , graph_data ) ;
fprintf ( stderr , " Weyl group generated. \n " ) ;
2016-07-26 08:09:34 +00:00
for ( int i = 0 ; i < order ; i + + )
2016-11-20 22:19:08 +00:00
for ( int j = 0 ; j < rank ; j + + ) {
graph_unsorted [ i ] . left = graph_data [ i ] . left ;
graph_unsorted [ i ] . id = graph_data [ i ] . id ;
}
2016-07-26 08:09:34 +00:00
// find wordlengths
2016-06-09 19:11:20 +00:00
graph_unsorted [ 0 ] . wordlength = 0 ;
queue_init ( & queue ) ;
queue_put ( & queue , 0 ) ;
while ( ( current = queue_get ( & queue ) ) ! = - 1 ) {
for ( int i = 0 ; i < rank ; i + + ) {
int neighbor = graph_unsorted [ current ] . left [ i ] ;
if ( graph_unsorted [ neighbor ] . wordlength > graph_unsorted [ current ] . wordlength + 1 ) {
graph_unsorted [ neighbor ] . wordlength = graph_unsorted [ current ] . wordlength + 1 ;
queue_put ( & queue , neighbor ) ;
}
}
}
2016-11-20 22:19:08 +00:00
fprintf ( stderr , " Wordlengths calculated. \n " ) ;
2016-07-26 08:09:34 +00:00
// sort by wordlength
2016-06-09 19:11:20 +00:00
for ( int i = 0 ; i < order ; i + + )
2016-11-15 17:55:30 +00:00
ordering [ i ] = i ;
qsort_r ( ordering , order , sizeof ( int ) , compare_wordlength , graph_unsorted ) ; // so ordering is a map new index -> old index
2016-06-09 19:11:20 +00:00
for ( int i = 0 ; i < order ; i + + )
2016-11-15 17:55:30 +00:00
reverse_ordering [ ordering [ i ] ] = i ; // reverse_ordering is a map old index -> new index
2016-06-09 19:11:20 +00:00
for ( int i = 0 ; i < order ; i + + ) {
2016-11-20 22:19:08 +00:00
// we have only set left, wordlength and id so far, so just copy these
2016-11-15 17:55:30 +00:00
graph [ i ] . wordlength = graph_unsorted [ ordering [ i ] ] . wordlength ;
2016-11-20 22:19:08 +00:00
graph [ i ] . id = graph_unsorted [ ordering [ i ] ] . id ;
2016-06-09 19:11:20 +00:00
for ( int j = 0 ; j < rank ; j + + )
2016-11-15 17:55:30 +00:00
graph [ i ] . left [ j ] = reverse_ordering [ graph_unsorted [ ordering [ i ] ] . left [ j ] ] ; // rewrite references
2016-06-09 19:11:20 +00:00
}
2016-11-20 22:19:08 +00:00
fprintf ( stderr , " Sorted by wordlength. \n " ) ;
2016-07-26 08:09:34 +00:00
// find words
2016-06-09 19:11:20 +00:00
2016-11-11 16:07:45 +00:00
for ( int i = 0 ; i < order ; i + + )
memset ( graph [ i ] . word , 0 , hyperplanes * sizeof ( int ) ) ;
2016-06-09 19:11:20 +00:00
queue_init ( & queue ) ;
queue_put ( & queue , 0 ) ;
while ( ( current = queue_get ( & queue ) ) ! = - 1 ) {
for ( int i = 0 ; i < rank ; i + + ) {
int neighbor = graph [ current ] . left [ i ] ;
2016-11-11 16:07:45 +00:00
if ( graph [ neighbor ] . wordlength = = graph [ current ] . wordlength + 1 & & graph [ neighbor ] . word [ 0 ] = = 0 ) {
2016-06-09 19:11:20 +00:00
memcpy ( & graph [ neighbor ] . word [ 1 ] , & graph [ current ] . word [ 0 ] , graph [ current ] . wordlength * sizeof ( int ) ) ;
graph [ neighbor ] . word [ 0 ] = i ;
queue_put ( & queue , neighbor ) ;
}
}
}
2016-11-20 22:19:08 +00:00
fprintf ( stderr , " Shortest words found. \n " ) ;
2016-07-26 08:09:34 +00:00
// generate right edges
2016-06-09 19:11:20 +00:00
for ( int i = 0 ; i < order ; i + + ) {
for ( int j = 0 ; j < rank ; j + + ) {
current = graph [ 0 ] . left [ j ] ;
for ( int k = graph [ i ] . wordlength - 1 ; k > = 0 ; k - - ) { // apply group element from right to left
current = graph [ current ] . left [ graph [ i ] . word [ k ] ] ;
}
graph [ i ] . right [ j ] = current ;
}
}
2016-11-20 22:19:08 +00:00
fprintf ( stderr , " Right edges generated. \n " ) ;
2016-07-26 08:09:34 +00:00
// find opposites
2016-06-09 19:11:20 +00:00
node_t * longest = & graph [ order - 1 ] ;
for ( int i = 0 ; i < order ; i + + ) {
current = i ;
for ( int k = longest - > wordlength - 1 ; k > = 0 ; k - - )
current = graph [ current ] . left [ longest - > word [ k ] ] ;
graph [ i ] . opposite = current ;
}
2016-11-20 22:19:08 +00:00
fprintf ( stderr , " Opposites found. \n " ) ;
2016-07-26 08:09:34 +00:00
// enumerate hyperplanes
2016-06-09 19:11:20 +00:00
hyperplane_count = 0 ;
for ( int i = 0 ; i < order ; i + + ) {
for ( int j = 0 ; j < rank ; j + + ) {
current = 0 ;
int * word1 = graph [ i ] . word ;
int word1len = graph [ i ] . wordlength ;
int * word2 = graph [ graph [ i ] . right [ j ] ] . word ; // want to calculate word2 * word1^{-1}
int word2len = graph [ graph [ i ] . right [ j ] ] . wordlength ;
for ( int k = 0 ; k < word1len ; k + + ) // apply inverse, i.e. go from left to right
current = graph [ current ] . left [ word1 [ k ] ] ;
for ( int k = word2len - 1 ; k > = 0 ; k - - ) // now from right to left
current = graph [ current ] . left [ word2 [ k ] ] ;
if ( graph [ current ] . is_hyperplane_reflection = = 0 ) {
graph [ current ] . is_hyperplane_reflection = 1 ;
hyperplane_count + + ;
}
}
}
2016-11-20 22:19:08 +00:00
fprintf ( stderr , " Hyperplanes enumerated. \n " ) ;
2016-07-26 08:09:34 +00:00
// generate folding order
2016-06-09 19:11:20 +00:00
2016-07-26 08:09:34 +00:00
edgelist_count = 0 ;
2016-06-09 19:11:20 +00:00
for ( int i = 0 ; i < order ; i + + ) {
if ( graph [ i ] . is_hyperplane_reflection ) {
for ( int j = 0 ; j < order ; j + + ) {
current = j ;
for ( int k = graph [ i ] . wordlength - 1 ; k > = 0 ; k - - ) // apply hyperplane reflection
current = graph [ current ] . left [ graph [ i ] . word [ k ] ] ;
if ( graph [ j ] . wordlength < graph [ current ] . wordlength ) { // current has higher bruhat order than j
2016-11-11 16:07:45 +00:00
edgelists_lower [ edgelist_count ] . to = j ;
edgelists_lower [ edgelist_count ] . next = graph [ current ] . bruhat_lower ;
graph [ current ] . bruhat_lower = & edgelists_lower [ edgelist_count ] ;
2016-06-09 19:11:20 +00:00
edgelist_count + + ;
} else if ( graph [ j ] . wordlength > graph [ current ] . wordlength ) { // j has higher bruhat order than current; these are already included from the other side
} else {
ERROR ( 1 , " Chambers of equal word lengths should not be folded on each other! \n " ) ;
}
}
}
}
2016-11-20 22:19:08 +00:00
fprintf ( stderr , " Bruhat order generated. \n " ) ;
2016-07-26 08:09:34 +00:00
// remove redundant edges
2016-06-09 19:11:20 +00:00
for ( int i = 0 ; i < order ; i + + ) {
memset ( seen , 0 , order * sizeof ( int ) ) ;
2016-10-29 15:02:05 +00:00
queue_init ( & queue ) ;
for ( int len = 1 ; len < = graph [ i ] . wordlength ; len + + ) {
2016-06-09 19:11:20 +00:00
// remove all edges originating from i of length len which connect to something already seen using shorter edges
edge = graph [ i ] . bruhat_lower ;
previous = ( edgelist_t * ) 0 ;
2016-10-29 15:02:05 +00:00
2016-06-09 19:11:20 +00:00
while ( edge ) {
2016-10-29 15:02:05 +00:00
if ( graph [ i ] . wordlength - graph [ edge - > to ] . wordlength ! = len ) {
previous = edge ;
} else if ( seen [ edge - > to ] ) {
2016-06-09 19:11:20 +00:00
if ( previous )
previous - > next = edge - > next ;
else
graph [ i ] . bruhat_lower = edge - > next ;
} else {
previous = edge ;
2016-10-29 15:02:05 +00:00
seen [ edge - > to ] = 1 ;
queue_put ( & queue , edge - > to ) ;
2016-06-09 19:11:20 +00:00
}
edge = edge - > next ;
}
// see which nodes we can reach using only edges up to length len, mark them as seen
while ( ( current = queue_get ( & queue ) ) ! = - 1 ) {
edge = graph [ current ] . bruhat_lower ;
while ( edge ) {
2016-10-29 15:02:05 +00:00
if ( ! seen [ edge - > to ] ) {
2016-06-09 19:11:20 +00:00
seen [ edge - > to ] = 1 ;
queue_put ( & queue , edge - > to ) ;
}
edge = edge - > next ;
}
}
}
}
2016-11-20 22:19:08 +00:00
fprintf ( stderr , " Redundant edges removed. \n " ) ;
2016-07-26 08:09:34 +00:00
// reverse folding order
2016-06-09 19:11:20 +00:00
2016-11-11 16:07:45 +00:00
edgelist_count = 0 ;
2016-06-09 19:11:20 +00:00
for ( int i = 0 ; i < order ; i + + ) {
edge = graph [ i ] . bruhat_lower ;
while ( edge ) {
2016-11-11 16:07:45 +00:00
edgelists_higher [ edgelist_count ] . to = i ;
edgelists_higher [ edgelist_count ] . next = graph [ edge - > to ] . bruhat_higher ;
graph [ edge - > to ] . bruhat_higher = & edgelists_higher [ edgelist_count ] ;
2016-06-09 19:11:20 +00:00
edgelist_count + + ;
edge = edge - > next ;
}
}
2016-11-20 22:19:08 +00:00
fprintf ( stderr , " Bruhat order reversed. \n " ) ;
2016-11-15 17:55:30 +00:00
// additional sorting step to force opposite property (opposite of j is at n - j - 1)
for ( int i = 0 ; i < order ; i + + )
reverse_ordering [ i ] = - 1 ;
for ( int i = 0 , j = 0 ; i < order ; i + + ) { // i = old index, j = new index
if ( reverse_ordering [ i ] = = - 1 ) {
reverse_ordering [ i ] = j ;
ordering [ j ] = i ;
reverse_ordering [ graph [ i ] . opposite ] = order - j - 1 ;
ordering [ order - j - 1 ] = graph [ i ] . opposite ;
j + + ;
}
}
memcpy ( graph_unsorted , graph , order * sizeof ( node_t ) ) ;
for ( int i = 0 ; i < order ; i + + ) {
graph [ i ] = graph_unsorted [ ordering [ i ] ] ;
graph [ i ] . opposite = reverse_ordering [ graph [ i ] . opposite ] ;
for ( int j = 0 ; j < rank ; j + + ) {
graph [ i ] . left [ j ] = reverse_ordering [ graph [ i ] . left [ j ] ] ;
graph [ i ] . right [ j ] = reverse_ordering [ graph [ i ] . right [ j ] ] ;
}
for ( edge = graph [ i ] . bruhat_lower ; edge ; edge = edge - > next )
edge - > to = reverse_ordering [ edge - > to ] ;
for ( edge = graph [ i ] . bruhat_higher ; edge ; edge = edge - > next )
edge - > to = reverse_ordering [ edge - > to ] ;
}
2016-11-20 22:19:08 +00:00
weyl_free ( graph_data ) ;
2016-07-26 08:09:34 +00:00
free ( graph_unsorted ) ;
2016-11-15 17:55:30 +00:00
free ( ordering ) ;
free ( reverse_ordering ) ;
2016-07-26 08:09:34 +00:00
free ( seen ) ;
}
2016-11-11 16:07:45 +00:00
static int edgelist_contains ( edgelist_t * list , int x ) {
while ( list ) {
if ( list - > to = = x )
return 1 ;
list = list - > next ;
}
return 0 ;
}
static edgelist_t * edgelist_add ( edgelist_t * list , int new , edgelist_t * storage , int * storage_index )
{
edgelist_t * new_link = & storage [ * storage_index ] ;
new_link - > next = list ;
new_link - > to = new ;
( * storage_index ) + + ;
return new_link ;
}
int prepare_simplified_graph ( semisimple_type_t type , unsigned long left , unsigned long right , node_t * simplified_graph )
{
node_t * full_graph ;
int edgelists_used ;
int rank , order , hyperplanes ;
int * reduced , * group , * simplified ;
int * seen ;
int current ;
edgelist_t * edge , * previous ;
queue_t queue ;
int ncosets ;
2016-11-20 22:19:08 +00:00
rank = weyl_rank ( type ) ;
order = weyl_order ( type ) ;
hyperplanes = weyl_hyperplanes ( type ) ;
for ( int i = 0 ; i < rank ; i + + ) {
int oppi = weyl_opposition ( type , i ) ;
if ( left & BIT ( i ) & & ! ( left & BIT ( oppi ) ) | |
left & BIT ( oppi ) & & ! ( left & BIT ( i ) ) )
return - 1 ;
}
2016-11-11 16:07:45 +00:00
edgelist_t * edgelists_higher = & simplified_graph [ 0 ] . bruhat_higher [ 0 ] ;
edgelist_t * edgelists_lower = & simplified_graph [ 0 ] . bruhat_higher [ order * hyperplanes / 2 ] ;
// get full graph
full_graph = graph_alloc ( type ) ;
prepare_graph ( type , full_graph ) ;
2016-11-20 22:19:08 +00:00
fprintf ( stderr , " Full graph generated. \n " ) ;
2016-11-11 16:07:45 +00:00
2016-11-20 22:19:08 +00:00
// initialize stuff
2016-11-11 16:07:45 +00:00
reduced = ( int * ) malloc ( order * sizeof ( int ) ) ;
group = ( int * ) malloc ( order * sizeof ( int ) ) ;
simplified = ( int * ) malloc ( order * sizeof ( int ) ) ;
for ( int i = 0 ; i < order ; i + + ) {
group [ i ] = - 1 ;
reduced [ i ] = i ;
}
// step 1: group
for ( int i = 0 ; i < order ; i + + ) {
if ( group [ i ] ! = - 1 )
continue ;
queue_init ( & queue ) ;
queue_put ( & queue , i ) ;
while ( ( current = queue_get ( & queue ) ) ! = - 1 ) {
if ( group [ current ] ! = - 1 )
continue ;
group [ current ] = i ;
for ( int j = 0 ; j < rank ; j + + ) {
if ( left & ( 1 < < j ) )
queue_put ( & queue , full_graph [ current ] . left [ j ] ) ;
if ( right & ( 1 < < j ) )
queue_put ( & queue , full_graph [ current ] . right [ j ] ) ;
}
}
}
// step 2: find minimum
for ( int i = 0 ; i < order ; i + + )
if ( full_graph [ i ] . wordlength < full_graph [ reduced [ group [ i ] ] ] . wordlength )
reduced [ group [ i ] ] = i ;
// step 3: assign minimum to all
for ( int i = 0 ; i < order ; i + + )
reduced [ i ] = reduced [ group [ i ] ] ;
// step 4: assign indices to cosets
ncosets = 0 ;
for ( int i = 0 ; i < order ; i + + )
if ( reduced [ i ] = = i )
simplified [ i ] = ncosets + + ;
for ( int i = 0 ; i < order ; i + + )
simplified [ i ] = simplified [ reduced [ i ] ] ;
// fprintf(stderr, "Number of double cosets: %d\n\n", ncosets);
// simplified_graph = (node_t*) malloc(ncosets*sizeof(node_t));
seen = ( int * ) malloc ( ncosets * sizeof ( int ) ) ;
edgelists_used = 0 ;
// step 5: set up nodes from minima
current = 0 ;
for ( int i = 0 ; i < order ; i + + )
if ( reduced [ i ] = = i ) { // is minimum
memcpy ( simplified_graph [ simplified [ i ] ] . word , full_graph [ i ] . word , full_graph [ i ] . wordlength * sizeof ( int ) ) ;
simplified_graph [ simplified [ i ] ] . wordlength = full_graph [ i ] . wordlength ;
simplified_graph [ simplified [ i ] ] . opposite = simplified [ full_graph [ i ] . opposite ] ;
simplified_graph [ simplified [ i ] ] . bruhat_lower = ( edgelist_t * ) 0 ;
simplified_graph [ simplified [ i ] ] . bruhat_higher = ( edgelist_t * ) 0 ;
for ( int j = 0 ; j < rank ; j + + ) {
simplified_graph [ simplified [ i ] ] . left [ j ] = simplified [ full_graph [ i ] . left [ j ] ] ;
simplified_graph [ simplified [ i ] ] . right [ j ] = simplified [ full_graph [ i ] . right [ j ] ] ;
}
}
// step 6: find order relations
for ( int i = 0 ; i < order ; i + + ) {
edge = full_graph [ i ] . bruhat_lower ;
while ( edge ) {
int this = simplified [ i ] ;
int that = simplified [ edge - > to ] ;
if ( this ! = that ) {
// found something
if ( ! edgelist_contains ( simplified_graph [ this ] . bruhat_lower , that ) )
simplified_graph [ this ] . bruhat_lower = edgelist_add ( simplified_graph [ this ] . bruhat_lower , that , edgelists_lower , & edgelists_used ) ;
ERROR ( simplified_graph [ this ] . wordlength < = simplified_graph [ that ] . wordlength , " The order assumption is being violated! \n " ) ;
}
edge = edge - > next ;
}
}
// step 7: remove redundant edges
for ( int i = 0 ; i < ncosets ; i + + ) {
memset ( seen , 0 , ncosets * sizeof ( int ) ) ;
queue_init ( & queue ) ;
for ( int len = 1 ; len < = simplified_graph [ i ] . wordlength ; len + + ) {
edge = simplified_graph [ i ] . bruhat_lower ;
previous = ( edgelist_t * ) 0 ;
while ( edge ) {
// only look at edges of this length now
if ( simplified_graph [ i ] . wordlength - simplified_graph [ edge - > to ] . wordlength ! = len ) {
// we only consider edges of length len in this pass
previous = edge ;
} else if ( seen [ edge - > to ] ) {
// this edge is redundant, remove it
// fprintf(stderr, "removing edge from %d to %d\n", i, edge->to);
if ( previous )
previous - > next = edge - > next ;
else
simplified_graph [ i ] . bruhat_lower = edge - > next ;
} else {
// this edge was not redundant, add to seen
previous = edge ;
seen [ edge - > to ] = 1 ;
queue_put ( & queue , edge - > to ) ;
}
edge = edge - > next ;
}
// calculate transitive closure of seen nodes
while ( ( current = queue_get ( & queue ) ) ! = - 1 ) {
edge = simplified_graph [ current ] . bruhat_lower ;
while ( edge ) {
if ( ! seen [ edge - > to ] ) {
seen [ edge - > to ] = 1 ;
queue_put ( & queue , edge - > to ) ;
}
edge = edge - > next ;
}
}
}
}
// step 8: revert order
2016-11-20 22:19:08 +00:00
edgelists_used = 0 ;
2016-11-11 16:07:45 +00:00
for ( int i = 0 ; i < ncosets ; i + + ) {
edge = simplified_graph [ i ] . bruhat_lower ;
while ( edge ) {
simplified_graph [ edge - > to ] . bruhat_higher =
edgelist_add ( simplified_graph [ edge - > to ] . bruhat_higher ,
i , edgelists_higher , & edgelists_used ) ;
edge = edge - > next ;
}
}
// output as graphviz dot file
/*
fprintf ( stdout , " difull_graph test123 { \n " ) ;
for ( int i = 0 ; i < ncosets ; i + + ) {
edge = simplified_graph [ i ] . bruhat_lower ;
while ( edge ) {
fprintf ( stdout , " %s -> %s; \n " ,
alphabetize ( simplified_graph [ i ] . word , simplified_graph [ i ] . wordlength , alphabet , buffer ) ,
alphabetize ( simplified_graph [ edge - > to ] . word , simplified_graph [ edge - > to ] . wordlength , alphabet , buffer2 ) ) ;
edge = edge - > next ;
}
}
fprintf ( stdout , " } \n " ) ; */
// some output
/* for(int i = 0; i < ncosets; i++)
fprintf ( stderr , " %s <=> %s \n " , simplified_graph [ i ] . wordlength = = 0 ? " 1 " : alphabetize ( simplified_graph [ i ] . word , simplified_graph [ i ] . wordlength , alphabet , buffer ) , simplified_graph [ simplified_graph [ i ] . opposite ] . wordlength = = 0 ? " 1 " : alphabetize ( simplified_graph [ simplified_graph [ i ] . opposite ] . word , simplified_graph [ simplified_graph [ i ] . opposite ] . wordlength , alphabet , buffer2 ) ) ; */
// fprintf(stderr, "\nAdded %d edges.\n\n", edgelists_used);
free ( seen ) ;
free ( reduced ) ;
free ( group ) ;
free ( simplified ) ;
graph_free ( type , full_graph ) ;
return ncosets ;
}
node_t * graph_alloc ( semisimple_type_t type )
{
2016-11-20 22:19:08 +00:00
int rank = weyl_rank ( type ) ;
int order = weyl_order ( type ) ;
int hyperplanes = weyl_hyperplanes ( type ) ;
2016-11-11 16:07:45 +00:00
node_t * graph = ( node_t * ) malloc ( order * sizeof ( node_t ) ) ;
int * left = ( int * ) malloc ( order * rank * sizeof ( int ) ) ;
int * right = ( int * ) malloc ( order * rank * sizeof ( int ) ) ;
edgelist_t * edgelists = ( edgelist_t * ) malloc ( order * hyperplanes * sizeof ( edgelist_t ) ) ;
int * words = ( int * ) malloc ( order * hyperplanes * sizeof ( int ) ) ;
for ( int i = 0 ; i < order ; i + + ) {
graph [ i ] . left = & left [ rank * i ] ;
graph [ i ] . right = & right [ rank * i ] ;
graph [ i ] . word = & words [ hyperplanes * i ] ;
}
graph [ 0 ] . bruhat_higher = edgelists ;
return graph ;
}
void graph_free ( semisimple_type_t type , node_t * graph )
{
free ( graph [ 0 ] . left ) ;
free ( graph [ 0 ] . right ) ;
free ( graph [ 0 ] . word ) ;
2016-11-20 22:19:08 +00:00
int order = weyl_order ( type ) ;
2016-11-11 16:07:45 +00:00
// find the head of all edgelists by just taking the one having the lowest address
edgelist_t * edgelists = graph [ 0 ] . bruhat_lower ;
for ( int i = 0 ; i < order ; i + + ) {
if ( graph [ i ] . bruhat_lower < edgelists & & graph [ i ] . bruhat_lower ! = 0 )
edgelists = graph [ i ] . bruhat_lower ;
if ( graph [ i ] . bruhat_higher < edgelists & & graph [ i ] . bruhat_higher ! = 0 )
edgelists = graph [ i ] . bruhat_higher ;
}
free ( edgelists ) ;
}
2016-10-19 14:40:03 +00:00
/*********************************** THE ACTUAL ENUMERATION ****************************************/
typedef struct {
2016-11-18 19:39:19 +00:00
int size ; // the size of the weyl group. We store however only the first size/2 elements
2016-11-15 17:55:30 +00:00
bitvec_t * principal_pos ;
bitvec_t * principal_neg ;
2016-11-18 19:39:19 +00:00
int * principal_is_slim ;
2016-11-19 10:16:45 +00:00
void ( * callback ) ( const bitvec_t * , int , void * ) ;
void * callback_data ;
2016-10-19 14:40:03 +00:00
} enumeration_info_t ;
2016-11-16 21:59:35 +00:00
/*
2016-11-19 10:16:45 +00:00
This function enumerates all balanced ideals satisfying certain constraints , given by its arguments pos , neg and next_neg
2016-11-16 21:59:35 +00:00
2016-11-19 10:16:45 +00:00
- info : constant information which just gets passed on to recursive calls , mainly contains the principal ideals
- pos : a set of elements which have to be positive ( that is , in the ideal )
- neg : a set of elements which have to be negative ( not in the ideal )
- next_neg : this element has to be the first negative one not already contained in neg ; if next_neg is info . size / 2 , then everything not in neg has to be positive
- already_known : not a constraint , but just a hint to speed things up ; tells the function that the first already_known elements are set either in neg or in pos ; must be less or equal to next_neg
- returns number of balanced ideals found
2016-11-16 21:59:35 +00:00
2016-11-19 10:16:45 +00:00
uses the bitvector functions bv_union , bv_copy , bv_set_range_except , bv_disjoint , bv_next_zero
2016-11-20 22:19:08 +00:00
2016-11-16 21:59:35 +00:00
*/
2016-11-19 10:16:45 +00:00
static long enumerate_tree ( const enumeration_info_t * info , const bitvec_t * pos , const bitvec_t * neg , int next_neg , int already_known )
2016-11-16 21:59:35 +00:00
{
2016-11-18 19:39:19 +00:00
static long totcount = 0 ;
2016-11-16 21:59:35 +00:00
bitvec_t newpos , newneg , known ;
int next_next_neg ;
long count = 0 ;
// the omission of next_neg means inclusion of info->size - 1 - next_neg
// add its principal ideal to pos and the opposite to neg
if ( next_neg ! = info - > size / 2 ) {
2016-11-19 10:16:45 +00:00
// if the principal ideal we want to add is not slim by itself, we don't even have to try; but there is not really a performance benefit, it rather makes it slower
// if(!info->principal_is_slim[info->size - 1 - next_neg])
2016-11-18 19:39:19 +00:00
// return 0;
2016-11-16 21:59:35 +00:00
bv_union ( & info - > principal_pos [ info - > size - 1 - next_neg ] , pos , & newpos ) ;
bv_union ( & info - > principal_neg [ info - > size - 1 - next_neg ] , neg , & newneg ) ;
2016-11-16 22:46:37 +00:00
} else { // or, if there is no next_neg, just copy
bv_copy ( pos , & newpos ) ;
bv_copy ( neg , & newneg ) ;
2016-11-16 21:59:35 +00:00
}
2016-11-19 10:16:45 +00:00
// everything before next_neg which was unknown should be set to positive; to speed this up, we can start with already_known
bv_set_range_except ( & newpos , neg , already_known , next_neg ) ;
2016-11-16 21:59:35 +00:00
// check if this leads to any conflicts (equivalently, violates slimness)
if ( ! bv_disjoint ( & newpos , & newneg ) )
return 0 ;
// what do we know so far?
bv_union ( & newpos , & newneg , & known ) ;
2016-11-18 19:39:19 +00:00
next_next_neg = bv_next_zero ( & known , next_neg + 1 ) ;
2016-11-16 22:46:37 +00:00
2016-11-18 19:39:19 +00:00
if ( next_next_neg > = info - > size / 2 ) {
2016-11-19 10:16:45 +00:00
// there is no unknown left, so we found a balanced ideal
if ( info - > callback )
info - > callback ( & newpos , info - > size , info - > callback_data ) ;
2016-11-16 21:59:35 +00:00
return 1 ;
}
2016-11-18 19:39:19 +00:00
do {
2016-11-19 10:16:45 +00:00
count + = enumerate_tree ( info , & newpos , & newneg , next_next_neg , next_neg + 1 ) ;
2016-11-18 19:39:19 +00:00
next_next_neg = bv_next_zero ( & known , next_next_neg + 1 ) ;
} while ( next_next_neg < = info - > size / 2 ) ;
2016-06-09 19:11:20 +00:00
2016-10-19 14:40:03 +00:00
return count ;
}
2016-11-19 10:16:45 +00:00
/*
enumerates all balanced ideals
- graph : hasse diagram of the bruhat order ( of double cosets ) with opposition pairing
- size : number of nodes in graph
- callback to call when a balanced ideal was found
- arbitrary data for callback function
returns the number of balanced ideals
*/
long enumerate_balanced_thickenings ( node_t * graph , int size , void ( * callback ) ( const bitvec_t * , int , void * ) , void * callback_data )
2016-10-19 14:40:03 +00:00
{
signed char * level ;
long count = 0 ;
enumeration_info_t info ;
queue_t queue ;
int current ;
2016-11-15 17:55:30 +00:00
edgelist_t * edge ;
2016-10-19 14:40:03 +00:00
2016-10-30 17:27:48 +00:00
info . size = size ;
2016-11-19 10:16:45 +00:00
info . callback = callback ;
info . callback_data = callback_data ;
2016-11-18 19:39:19 +00:00
info . principal_pos = ( bitvec_t * ) malloc ( info . size * sizeof ( bitvec_t ) ) ;
info . principal_neg = ( bitvec_t * ) malloc ( info . size * sizeof ( bitvec_t ) ) ;
info . principal_is_slim = ( int * ) malloc ( info . size * sizeof ( int ) ) ;
2016-10-19 14:40:03 +00:00
2016-10-30 17:27:48 +00:00
// the algorithm only works if the opposition pairing does not stabilize any element
// if this happens, there can be no balanced thickenings
for ( int i = 0 ; i < info . size ; i + + )
if ( graph [ i ] . opposite = = i )
return 0 ;
2016-10-19 14:40:03 +00:00
2016-11-19 10:16:45 +00:00
// we can only handle bitvectors up to 64*BV_QWORD_RANK bits, but we only store half of the weyl group
2016-11-16 22:46:37 +00:00
if ( info . size > 128 * BV_QWORD_RANK )
2016-11-15 17:55:30 +00:00
return - 1 ;
2016-10-30 17:27:48 +00:00
2016-11-18 19:39:19 +00:00
// generate principal ideals
int * principal = ( int * ) malloc ( info . size * sizeof ( int ) ) ;
2016-11-15 17:55:30 +00:00
for ( int i = 0 ; i < info . size ; i + + ) {
2016-11-18 19:39:19 +00:00
memset ( principal , 0 , info . size * sizeof ( int ) ) ;
principal [ i ] = 1 ;
2016-11-15 17:55:30 +00:00
queue_init ( & queue ) ;
queue_put ( & queue , i ) ;
2016-11-18 19:39:19 +00:00
while ( ( current = queue_get ( & queue ) ) ! = - 1 )
2016-11-15 17:55:30 +00:00
for ( edge = graph [ current ] . bruhat_lower ; edge ; edge = edge - > next )
2016-11-18 19:39:19 +00:00
if ( ! principal [ edge - > to ] ) {
principal [ edge - > to ] = 1 ;
2016-11-15 17:55:30 +00:00
queue_put ( & queue , edge - > to ) ;
}
2016-11-18 19:39:19 +00:00
// copy the first half into bitvectors
bv_clear ( & info . principal_pos [ i ] ) ;
bv_clear ( & info . principal_neg [ i ] ) ;
info . principal_is_slim [ i ] = 1 ;
for ( int j = 0 ; j < info . size / 2 ; j + + )
if ( principal [ j ] )
bv_set_bit ( & info . principal_pos [ i ] , j ) ;
for ( int j = 0 ; j < info . size / 2 ; j + + )
if ( principal [ info . size - 1 - j ] ) {
bv_set_bit ( & info . principal_neg [ i ] , j ) ;
if ( bv_get_bit ( & info . principal_pos [ i ] , j ) )
info . principal_is_slim [ i ] = 0 ;
}
}
free ( principal ) ;
2016-11-15 17:55:30 +00:00
2016-11-20 22:19:08 +00:00
/*
for ( int i = 0 ; i < info . size ; i + + ) {
fprintf ( stderr , " %d: " , i ) ;
bv_print_nice ( stderr , & info . principal_pos [ i ] , & info . principal_neg [ i ] , - 1 , info . size / 2 ) ;
fprintf ( stderr , " \n " ) ;
} */
2016-11-15 17:55:30 +00:00
// enumerate balanced ideals
bitvec_t pos , neg ;
bv_clear ( & pos ) ;
bv_clear ( & neg ) ;
2016-11-16 21:59:35 +00:00
for ( int i = 0 ; i < = info . size / 2 ; i + + )
2016-11-19 10:16:45 +00:00
count + = enumerate_tree ( & info , & pos , & neg , i , 0 ) ;
2016-06-09 19:11:20 +00:00
2016-11-18 19:39:19 +00:00
free ( info . principal_is_slim ) ;
free ( info . principal_pos ) ;
free ( info . principal_neg ) ;
2016-10-14 16:49:20 +00:00
return count ;
2016-06-09 19:11:20 +00:00
}