From 3bd8ff019d2a1281443de1d0102a4e9a2919df92 Mon Sep 17 00:00:00 2001 From: Florian Stecker Date: Sat, 19 Nov 2016 11:16:45 +0100 Subject: [PATCH] Callbacks --- Makefile | 2 +- bitvec.h | 2 -- generate.c | 26 ++++++++++++++----- thickenings.c | 72 +++++++++++++++++++++++++-------------------------- thickenings.h | 11 +++++--- 5 files changed, 62 insertions(+), 51 deletions(-) diff --git a/Makefile b/Makefile index 47be7af..87c1eaf 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ HEADERS=coxeter.h thickenings.h queue.h bitvec.h -OPTIONS=-O3 -m64 -march=native -flto -funroll-loops -std=gnu99 -Winline +OPTIONS=-O3 -m64 -march=native -flto -funroll-loops -std=gnu99 -D_GNU_SOURCE -Winline #OPTIONS=-m64 -march=native -O0 -g -std=gnu99 #OPTIONS=-O3 -m64 -march=native -funroll-loops -fno-inline -std=gnu99 -pg diff --git a/bitvec.h b/bitvec.h index 39331f8..0494069 100644 --- a/bitvec.h +++ b/bitvec.h @@ -12,11 +12,9 @@ * See the file LICENSE for details. ********************************************************************/ - #ifndef __BITVEC_H__ #define __BITVEC_H__ 1 -#define _GNU_SOURCE #include #include diff --git a/generate.c b/generate.c index 649f659..646b478 100644 --- a/generate.c +++ b/generate.c @@ -1,9 +1,20 @@ -#include -#include - +#include "thickenings.h" #include "coxeter.h" #include "queue.h" -#include "thickenings.h" + +#include +#include + +void balanced_thickening_callback(const bitvec_t *pos, int size, void *data) +{ + static long totcount = 0; + + if((++totcount) % 100000000 == 0) { + fprintf(stderr, "Found balanced ideal: "); + bv_print(stderr, pos, size/2); + fprintf(stderr, "\n"); + } +} int main(int argc, const char *argv[]) { @@ -63,6 +74,8 @@ int main(int argc, const char *argv[]) fprintf(stderr, "Rank: %d\tOrder: %d\tPositive Roots: %d\tCosets: %d\n", rank, order, hyperplanes, cosets); fprintf(stderr, "\n"); + + /* fprintf(stderr, "Shortest coset representatives: \n"); for(int i = 0, wl = 0; i < cosets; i++) { if(i == 0) { @@ -74,6 +87,7 @@ int main(int argc, const char *argv[]) fprintf(stderr, "%s ", alphabetize(graph[i].word, graph[i].wordlength, alphabet, string_buffer1)); } fprintf(stderr, "\n\n"); + */ fixpoints = 0; for(int i = 0; i < cosets; i++) @@ -88,14 +102,12 @@ int main(int argc, const char *argv[]) if(fixpoints > 0) { fprintf(stderr, "\n\n"); } else { - - // enumerate balanced thickenings fwrite(&type.n, sizeof(int), 1, stdout); fwrite(type.factors, sizeof(simple_type_t), type.n, stdout); fwrite(&left_invariance, sizeof(unsigned long), type.n, stdout); fwrite(&right_invariance, sizeof(unsigned long), type.n, stdout); - long count = enumerate_balanced_thickenings(type, graph, cosets, alphabet, stdout); + long count = enumerate_balanced_thickenings(graph, cosets, balanced_thickening_callback, (void*)0); fprintf(stderr, "Found %ld balanced thickenings\n\n", count); } diff --git a/thickenings.c b/thickenings.c index 5d90176..edbee2a 100644 --- a/thickenings.c +++ b/thickenings.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include #include @@ -10,8 +8,6 @@ #include "coxeter.h" #include "queue.h" -#define BV_QWORD_RANK 10 -#include "bitvec.h" char *alphabetize(int *word, int len, const char *alphabet, char *buffer) { @@ -568,30 +564,27 @@ void graph_free(semisimple_type_t type, node_t *graph) typedef struct { int size; // the size of the weyl group. We store however only the first size/2 elements - FILE *outfile; bitvec_t *principal_pos; bitvec_t *principal_neg; int *principal_is_slim; + void (*callback)(const bitvec_t *, int, void*); + void *callback_data; } enumeration_info_t; /* + This function enumerates all balanced ideals satisfying certain constraints, given by its arguments pos, neg and next_neg - pos and neg are bitvectors of size info.size/2 - they stand for the first (shortest) info.size/2 elements of the weyl group - the least siginficant bit is the identity + - 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 - at the beginning they are cleared, meaning everything is undecided + uses the bitvector functions bv_union, bv_copy, bv_set_range_except, bv_disjoint, bv_next_zero */ - -// enumerate all balanced ideals which contain everything in pos and everything strictly between known_until and next_neg, and which do not contain everything in neg, as well as next_neg -// assuming all bits up to known_until are set either in pos or in neg, but not in both -// returns number of found balanced ideals -// next_neg can be info.size/2; in that case, everything between known_until and info.size/2 is required to be in the ideal, but it does not mean that next_neg is really not contained in the ideal -// next_neg must be strictly greater than known_until, and less or equal to info.size/2 -// we use bv_union, bv_copy, bv_set_range_except, bv_disjoint, bv_next_zero - -static long enumerate_tree(const enumeration_info_t *info, const bitvec_t *pos, const bitvec_t *neg, int first_unknown, int next_neg) +static long enumerate_tree(const enumeration_info_t *info, const bitvec_t *pos, const bitvec_t *neg, int next_neg, int already_known) { static long totcount = 0; bitvec_t newpos, newneg, known; @@ -601,7 +594,8 @@ static long enumerate_tree(const enumeration_info_t *info, const bitvec_t *pos, // 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) { - // if(!info->principal_is_slim[info->size - 1 - next_neg]) // 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 + // 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]) // return 0; bv_union(&info->principal_pos[info->size - 1 - next_neg], pos, &newpos); bv_union(&info->principal_neg[info->size - 1 - next_neg], neg, &newneg); @@ -610,8 +604,8 @@ static long enumerate_tree(const enumeration_info_t *info, const bitvec_t *pos, bv_copy(neg, &newneg); } - // everything before next_neg which was unknown should be set to positive; to speed this up, we can start with first_unknown - bv_set_range_except(&newpos, neg, first_unknown, next_neg); + // 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); // check if this leads to any conflicts (equivalently, violates slimness) if(!bv_disjoint(&newpos, &newneg)) @@ -623,25 +617,32 @@ static long enumerate_tree(const enumeration_info_t *info, const bitvec_t *pos, next_next_neg = bv_next_zero(&known, next_neg + 1); if(next_next_neg >= info->size/2) { - - if((++totcount) % 100000000 == 0) { - fprintf(stderr, "Found balanced ideal: "); - bv_print(stderr, &newpos, info->size/2); - fprintf(stderr, "\n"); - } - + // there is no unknown left, so we found a balanced ideal + if(info->callback) + info->callback(&newpos, info->size, info->callback_data); return 1; } do { - count += enumerate_tree(info, &newpos, &newneg, next_neg + 1, next_next_neg); + count += enumerate_tree(info, &newpos, &newneg, next_next_neg, next_neg + 1); next_next_neg = bv_next_zero(&known, next_next_neg + 1); } while(next_next_neg <= info->size/2); return count; } -long enumerate_balanced_thickenings(semisimple_type_t type, node_t *graph, int size, const char *alphabet, FILE *outfile) +/* + 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) { signed char *level; long count = 0; @@ -651,22 +652,19 @@ long enumerate_balanced_thickenings(semisimple_type_t type, node_t *graph, int s edgelist_t *edge; info.size = size; - info.outfile = outfile; + info.callback = callback; + info.callback_data = callback_data; 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)); - // info.printstep = 0; - // if(getenv("PRINTSTEP")) - // info.printstep = atoi(getenv("PRINTSTEP")); - // 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; - // we can only handle bitvectors up to 64*BV_QWORD_RANK bits, but we only store half of the weyl group + // we can only handle bitvectors up to 64*BV_QWORD_RANK bits, but we only store half of the weyl group if(info.size > 128*BV_QWORD_RANK) return -1; @@ -705,7 +703,7 @@ long enumerate_balanced_thickenings(semisimple_type_t type, node_t *graph, int s bv_clear(&pos); bv_clear(&neg); for(int i = 0; i <= info.size/2; i++) - count += enumerate_tree(&info, &pos, &neg, 0, i); + count += enumerate_tree(&info, &pos, &neg, i, 0); free(info.principal_is_slim); free(info.principal_pos); diff --git a/thickenings.h b/thickenings.h index 7c6b5d7..25865ab 100644 --- a/thickenings.h +++ b/thickenings.h @@ -1,6 +1,9 @@ #ifndef THICKENINGS_H #define THICKENINGS_H +#define BV_QWORD_RANK 10 +#include "bitvec.h" + #include "coxeter.h" #define DEBUG(msg, ...) do{fprintf(stderr, msg, ##__VA_ARGS__); }while(0) @@ -30,13 +33,13 @@ char *alphabetize(int *word, int len, const char *alphabet, char *buffer); void print_thickening(int rank, int order, const signed char *thickening, int level, const char *alphabet, FILE *f); // generating the graph of the bruhat order +node_t *graph_alloc(semisimple_type_t type); +void graph_free(semisimple_type_t type, node_t *graph); void prepare_graph(semisimple_type_t type, node_t *graph); int prepare_simplified_graph(semisimple_type_t type, unsigned long left, unsigned long right, node_t *simplified_graph); -// enumerate balanced thickenings -long enumerate_balanced_thickenings(semisimple_type_t type, node_t *graph, int size, const char *alphabet, FILE *outfile); -node_t *graph_alloc(semisimple_type_t type); -void graph_free(semisimple_type_t type, node_t *graph); +// enumerating balanced thickenings +long enumerate_balanced_thickenings(node_t *graph, int size, void (*callback) (const bitvec_t *, int, void*), void *callback_data); // various helper functions static int compare_wordlength(const void *a, const void *b, void *gr);